diff --git a/.mailmap b/.mailmap index afaad605284a8be6b9aa96f0157716fdf869453b..edcac87e76c8c7fe9020943bdce012f7e47dc962 100644 --- a/.mailmap +++ b/.mailmap @@ -47,6 +47,8 @@ Boris Brezillon Boris Brezillon Brian Avery Brian King +Chao Yu +Chao Yu Christoph Hellwig Christophe Ricard Corey Minyard @@ -63,6 +65,7 @@ Dengcheng Zhu Dengcheng Zhu Dengcheng Zhu Dengcheng Zhu + Dmitry Eremin-Solenikov Dmitry Safonov <0x7f454c46@gmail.com> Dmitry Safonov <0x7f454c46@gmail.com> @@ -80,6 +83,8 @@ Frank Rowand Frank Rowand Frank Rowand Frank Zago +Gao Xiang +Gao Xiang Greg Kroah-Hartman Greg Kroah-Hartman Greg Kroah-Hartman @@ -90,6 +95,9 @@ Henrik Kretzschmar Henrik Rydberg Herbert Xu Jacob Shin +Jaegeuk Kim +Jaegeuk Kim +Jaegeuk Kim James Bottomley James Bottomley James E Wilson @@ -178,8 +186,14 @@ Morten Welinder Morten Welinder Mythri P K Nguyen Anh Quynh +Nicolas Ferre Nicolas Pitre Nicolas Pitre +Oleksij Rempel +Oleksij Rempel +Oleksij Rempel +Oleksij Rempel +Oleksij Rempel Paolo 'Blaisorblade' Giarrusso Patrick Mochel Paul Burton @@ -190,11 +204,7 @@ Pratyush Anand Praveen BP Punit Agrawal Qais Yousef -Oleksij Rempel -Oleksij Rempel -Oleksij Rempel -Oleksij Rempel -Oleksij Rempel +Quentin Perret Rajesh Shah Ralf Baechle Ralf Wildenhues @@ -229,6 +239,7 @@ Sumit Semwal Tejun Heo Thomas Graf Thomas Pedersen +Todor Tomov Tony Luck TripleX Chung TripleX Chung diff --git a/CREDITS b/CREDITS index a7387605fbdca5b04a9b58c16cc59af96c0a4c81..8b67a85844b55d88b27ea761ec0711c871ca6fa0 100644 --- a/CREDITS +++ b/CREDITS @@ -751,7 +751,7 @@ S: Santa Cruz, California S: USA N: Luis Correia -E: lfcorreia@users.sf.net +E: luisfcorreia@gmail.com D: Ralink rt2x00 WLAN driver S: Belas, Portugal diff --git a/Documentation/ABI/stable/sysfs-bus-w1 b/Documentation/ABI/stable/sysfs-bus-w1 index 140d85b4ae92faff6d3646735b04974c530c604b..992dfb183ed0221edd6562544c78dfcd0a2d0d7f 100644 --- a/Documentation/ABI/stable/sysfs-bus-w1 +++ b/Documentation/ABI/stable/sysfs-bus-w1 @@ -6,6 +6,6 @@ Description: Bus scanning interval, microseconds component. control systems are attached/generate presence for as short as 100 ms - hence the tens-to-hundreds milliseconds scan intervals are required. - see Documentation/w1/w1.generic for detailed information. + see Documentation/w1/w1-generic.rst for detailed information. Users: any user space application which wants to know bus scanning interval diff --git a/Documentation/ABI/stable/sysfs-driver-w1_ds28e04 b/Documentation/ABI/stable/sysfs-driver-w1_ds28e04 index 26579ee868c9374ba92d3c1121c94310aacc38b4..3e1c1fa8d54d36e03a72c2f541652e73bfdd5a34 100644 --- a/Documentation/ABI/stable/sysfs-driver-w1_ds28e04 +++ b/Documentation/ABI/stable/sysfs-driver-w1_ds28e04 @@ -2,7 +2,7 @@ What: /sys/bus/w1/devices/.../pio Date: May 2012 Contact: Markus Franke Description: read/write the contents of the two PIO's of the DS28E04-100 - see Documentation/w1/slaves/w1_ds28e04 for detailed information + see Documentation/w1/slaves/w1_ds28e04.rst for detailed information Users: any user space application which wants to communicate with DS28E04-100 @@ -11,5 +11,5 @@ What: /sys/bus/w1/devices/.../eeprom Date: May 2012 Contact: Markus Franke Description: read/write the contents of the EEPROM memory of the DS28E04-100 - see Documentation/w1/slaves/w1_ds28e04 for detailed information + see Documentation/w1/slaves/w1_ds28e04.rst for detailed information Users: any user space application which wants to communicate with DS28E04-100 diff --git a/Documentation/ABI/stable/sysfs-driver-w1_ds28ea00 b/Documentation/ABI/stable/sysfs-driver-w1_ds28ea00 index e928def14f28c7487e7a319f94a9c1527aaecd8d..534e63731a4985238db03c2716fe63fb1a866b27 100644 --- a/Documentation/ABI/stable/sysfs-driver-w1_ds28ea00 +++ b/Documentation/ABI/stable/sysfs-driver-w1_ds28ea00 @@ -2,5 +2,5 @@ What: /sys/bus/w1/devices/.../w1_seq Date: Apr 2015 Contact: Matt Campbell Description: Support for the DS28EA00 chain sequence function - see Documentation/w1/slaves/w1_therm for detailed information + see Documentation/w1/slaves/w1_therm.rst for detailed information Users: any user space application which wants to communicate with DS28EA00 diff --git a/Documentation/ABI/testing/debugfs-hisi-zip b/Documentation/ABI/testing/debugfs-hisi-zip new file mode 100644 index 0000000000000000000000000000000000000000..a7c63e6c4bc3b96adc29f38bbc856359d0cae3a6 --- /dev/null +++ b/Documentation/ABI/testing/debugfs-hisi-zip @@ -0,0 +1,50 @@ +What: /sys/kernel/debug/hisi_zip//comp_core[01]/regs +Date: Nov 2018 +Contact: linux-crypto@vger.kernel.org +Description: Dump of compression cores related debug registers. + Only available for PF. + +What: /sys/kernel/debug/hisi_zip//decomp_core[0-5]/regs +Date: Nov 2018 +Contact: linux-crypto@vger.kernel.org +Description: Dump of decompression cores related debug registers. + Only available for PF. + +What: /sys/kernel/debug/hisi_zip//clear_enable +Date: Nov 2018 +Contact: linux-crypto@vger.kernel.org +Description: Compression/decompression core debug registers read clear + control. 1 means enable register read clear, otherwise 0. + Writing to this file has no functional effect, only enable or + disable counters clear after reading of these registers. + Only available for PF. + +What: /sys/kernel/debug/hisi_zip//current_qm +Date: Nov 2018 +Contact: linux-crypto@vger.kernel.org +Description: One ZIP controller has one PF and multiple VFs, each function + has a QM. Select the QM which below qm refers to. + Only available for PF. + +What: /sys/kernel/debug/hisi_zip//qm/qm_regs +Date: Nov 2018 +Contact: linux-crypto@vger.kernel.org +Description: Dump of QM related debug registers. + Available for PF and VF in host. VF in guest currently only + has one debug register. + +What: /sys/kernel/debug/hisi_zip//qm/current_q +Date: Nov 2018 +Contact: linux-crypto@vger.kernel.org +Description: One QM may contain multiple queues. Select specific queue to + show its debug registers in above qm_regs. + Only available for PF. + +What: /sys/kernel/debug/hisi_zip//qm/clear_enable +Date: Nov 2018 +Contact: linux-crypto@vger.kernel.org +Description: QM debug registers(qm_regs) read clear control. 1 means enable + register read clear, otherwise 0. + Writing to this file has no functional effect, only enable or + disable counters clear after reading of these registers. + Only available for PF. diff --git a/Documentation/ABI/testing/debugfs-moxtet b/Documentation/ABI/testing/debugfs-moxtet new file mode 100644 index 0000000000000000000000000000000000000000..67b1717794d879022e36da5d0b6f69b5dec0fde9 --- /dev/null +++ b/Documentation/ABI/testing/debugfs-moxtet @@ -0,0 +1,23 @@ +What: /sys/kernel/debug/moxtet/input +Date: March 2019 +KernelVersion: 5.3 +Contact: Marek Behún +Description: (R) Read input from the shift registers, in hexadecimal. + Returns N+1 bytes, where N is the number of Moxtet connected + modules. The first byte is from the CPU board itself. + Example: 101214 + 10: CPU board with SD card + 12: 2 = PCIe module, 1 = IRQ not active + 14: 4 = Peridot module, 1 = IRQ not active + +What: /sys/kernel/debug/moxtet/output +Date: March 2019 +KernelVersion: 5.3 +Contact: Marek Behún +Description: (RW) Read last written value to the shift registers, in + hexadecimal, or write values to the shift registers, also + in hexadecimal. + Example: 0102 + 01: 01 was last written, or is to be written, to the + first module's shift register + 02: the same for second module diff --git a/Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 b/Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 index da9822309f0757bdf9b1d1d617a2ee8921fe7ca5..0e66ae9b0071e80b245796aa5b04bf2b461e39b6 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 +++ b/Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 @@ -13,4 +13,4 @@ Description: error on writing If DFSDM input is SPI Slave: Reading returns value previously set. - Writing value before starting conversions. \ No newline at end of file + Writing value before starting conversions. diff --git a/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 b/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 index 161c147d3c40323a7f21aa323c27f31efa223f22..b7259234ad70081172e26dd3b9ccc19ef62556d0 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 +++ b/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 @@ -91,29 +91,6 @@ Description: When counting down the counter start from preset value and fire event when reach 0. -What: /sys/bus/iio/devices/iio:deviceX/in_count_quadrature_mode_available -KernelVersion: 4.12 -Contact: benjamin.gaignard@st.com -Description: - Reading returns the list possible quadrature modes. - -What: /sys/bus/iio/devices/iio:deviceX/in_count0_quadrature_mode -KernelVersion: 4.12 -Contact: benjamin.gaignard@st.com -Description: - Configure the device counter quadrature modes: - channel_A: - Encoder A input servers as the count input and B as - the UP/DOWN direction control input. - - channel_B: - Encoder B input serves as the count input and A as - the UP/DOWN direction control input. - - quadrature: - Encoder A and B inputs are mixed to get direction - and count with a scale of 0.25. - What: /sys/bus/iio/devices/iio:deviceX/in_count_enable_mode_available KernelVersion: 4.12 Contact: benjamin.gaignard@st.com diff --git a/Documentation/ABI/testing/sysfs-bus-intel_th-devices-msc b/Documentation/ABI/testing/sysfs-bus-intel_th-devices-msc index f54ae244f3f1716d8f997dc124b3edbf2bb52069..456cb62b384c2a138d8076dfc3c4fa0325b170db 100644 --- a/Documentation/ABI/testing/sysfs-bus-intel_th-devices-msc +++ b/Documentation/ABI/testing/sysfs-bus-intel_th-devices-msc @@ -12,7 +12,8 @@ Description: (RW) Configure MSC operating mode: - "single", for contiguous buffer mode (high-order alloc); - "multi", for multiblock mode; - "ExI", for DCI handler mode; - - "debug", for debug mode. + - "debug", for debug mode; + - any of the currently loaded buffer sinks. If operating mode changes, existing buffer is deallocated, provided there are no active users and tracing is not enabled, otherwise the write will fail. diff --git a/Documentation/ABI/testing/sysfs-bus-moxtet-devices b/Documentation/ABI/testing/sysfs-bus-moxtet-devices new file mode 100644 index 0000000000000000000000000000000000000000..355958527fa357b51576c574ca46a68b6d01f2df --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-moxtet-devices @@ -0,0 +1,17 @@ +What: /sys/bus/moxtet/devices/moxtet-./module_description +Date: March 2019 +KernelVersion: 5.3 +Contact: Marek Behún +Description: (R) Moxtet module description. Format: string + +What: /sys/bus/moxtet/devices/moxtet-./module_id +Date: March 2019 +KernelVersion: 5.3 +Contact: Marek Behún +Description: (R) Moxtet module ID. Format: %x + +What: /sys/bus/moxtet/devices/moxtet-./module_name +Date: March 2019 +KernelVersion: 5.3 +Contact: Marek Behún +Description: (R) Moxtet module name. Format: string diff --git a/Documentation/ABI/testing/sysfs-class-mic.txt b/Documentation/ABI/testing/sysfs-class-mic similarity index 100% rename from Documentation/ABI/testing/sysfs-class-mic.txt rename to Documentation/ABI/testing/sysfs-class-mic diff --git a/Documentation/ABI/testing/sysfs-class-wakeup b/Documentation/ABI/testing/sysfs-class-wakeup new file mode 100644 index 0000000000000000000000000000000000000000..754aab8b6dcd6005b8ab64c38282c54df481d3a6 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-wakeup @@ -0,0 +1,76 @@ +What: /sys/class/wakeup/ +Date: June 2019 +Contact: Tri Vo +Description: + The /sys/class/wakeup/ directory contains pointers to all + wakeup sources in the kernel at that moment in time. + +What: /sys/class/wakeup/.../name +Date: June 2019 +Contact: Tri Vo +Description: + This file contains the name of the wakeup source. + +What: /sys/class/wakeup/.../active_count +Date: June 2019 +Contact: Tri Vo +Description: + This file contains the number of times the wakeup source was + activated. + +What: /sys/class/wakeup/.../event_count +Date: June 2019 +Contact: Tri Vo +Description: + This file contains the number of signaled wakeup events + associated with the wakeup source. + +What: /sys/class/wakeup/.../wakeup_count +Date: June 2019 +Contact: Tri Vo +Description: + This file contains the number of times the wakeup source might + abort suspend. + +What: /sys/class/wakeup/.../expire_count +Date: June 2019 +Contact: Tri Vo +Description: + This file contains the number of times the wakeup source's + timeout has expired. + +What: /sys/class/wakeup/.../active_time_ms +Date: June 2019 +Contact: Tri Vo +Description: + This file contains the amount of time the wakeup source has + been continuously active, in milliseconds. If the wakeup + source is not active, this file contains '0'. + +What: /sys/class/wakeup/.../total_time_ms +Date: June 2019 +Contact: Tri Vo +Description: + This file contains the total amount of time this wakeup source + has been active, in milliseconds. + +What: /sys/class/wakeup/.../max_time_ms +Date: June 2019 +Contact: Tri Vo +Description: + This file contains the maximum amount of time this wakeup + source has been continuously active, in milliseconds. + +What: /sys/class/wakeup/.../last_change_ms +Date: June 2019 +Contact: Tri Vo +Description: + This file contains the monotonic clock time when the wakeup + source was touched last time, in milliseconds. + +What: /sys/class/wakeup/.../prevent_suspend_time_ms +Date: June 2019 +Contact: Tri Vo +Description: + The file contains the total amount of time this wakeup source + has been preventing autosleep, in milliseconds. diff --git a/Documentation/ABI/testing/sysfs-devices-platform-stratix10-rsu b/Documentation/ABI/testing/sysfs-devices-platform-stratix10-rsu new file mode 100644 index 0000000000000000000000000000000000000000..ae9af984471a87c1565427bd0cb36ae1cbf04395 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-platform-stratix10-rsu @@ -0,0 +1,128 @@ + Intel Stratix10 Remote System Update (RSU) device attributes + +What: /sys/devices/platform/stratix10-rsu.0/current_image +Date: August 2019 +KernelVersion: 5.4 +Contact: Richard Gong +Description: + (RO) the address in flash of currently running image. + +What: /sys/devices/platform/stratix10-rsu.0/fail_image +Date: August 2019 +KernelVersion: 5.4 +Contact: Richard Gong +Description: + (RO) the address in flash of failed image. + +What: /sys/devices/platform/stratix10-rsu.0/state +Date: August 2019 +KernelVersion: 5.4 +Contact: Richard Gong +Description: + (RO) the state of RSU system. + The state field has two parts: major error code in + upper 16 bits and minor error code in lower 16 bits. + + b[15:0] + Currently used only when major error is 0xF006 + (CPU watchdog timeout), in which case the minor + error code is the value reported by CPU to + firmware through the RSU notify command before + the watchdog timeout occurs. + + b[31:16] + 0xF001 bitstream error + 0xF002 hardware access failure + 0xF003 bitstream corruption + 0xF004 internal error + 0xF005 device error + 0xF006 CPU watchdog timeout + 0xF007 internal unknown error + +What: /sys/devices/platform/stratix10-rsu.0/version +Date: August 2019 +KernelVersion: 5.4 +Contact: Richard Gong +Description: + (RO) the version number of RSU firmware. 19.3 or late + version includes information about the firmware which + reported the error. + + pre 19.3: + b[31:0] + 0x0 version number + + 19.3 or late: + b[15:0] + 0x1 version number + b[31:16] + 0x0 no error + 0x0DCF Decision CMF error + 0x0ACF Application CMF error + +What: /sys/devices/platform/stratix10-rsu.0/error_location +Date: August 2019 +KernelVersion: 5.4 +Contact: Richard Gong +Description: + (RO) the error offset inside the image that failed. + +What: /sys/devices/platform/stratix10-rsu.0/error_details +Date: August 2019 +KernelVersion: 5.4 +Contact: Richard Gong +Description: + (RO) error code. + +What: /sys/devices/platform/stratix10-rsu.0/retry_counter +Date: August 2019 +KernelVersion: 5.4 +Contact: Richard Gong +Description: + (RO) the current image's retry counter, which is used by + user to know how many times the images is still allowed + to reload itself before giving up and starting RSU + fail-over flow. + +What: /sys/devices/platform/stratix10-rsu.0/reboot_image +Date: August 2019 +KernelVersion: 5.4 +Contact: Richard Gong +Description: + (WO) the address in flash of image to be loaded on next + reboot command. + +What: /sys/devices/platform/stratix10-rsu.0/notify +Date: August 2019 +KernelVersion: 5.4 +Contact: Richard Gong +Description: + (WO) client to notify firmware with different actions. + + b[15:0] + inform firmware the current software execution + stage. + 0 the first stage bootloader didn't run or + didn't reach the point of launching second + stage bootloader. + 1 failed in second bootloader or didn't get + to the point of launching the operating + system. + 2 both first and second stage bootloader ran + and the operating system launch was + attempted. + + b[16] + 1 firmware to reset current image retry + counter. + 0 no action. + + b[17] + 1 firmware to clear RSU log + 0 no action. + + b[18] + this is negative logic + 1 no action + 0 firmware record the notify code defined + in b[15:0]. diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power index 80a00f7b666709d7edf3c0296753959dd802bcf9..1763e64dd152e834de2c47d21fe6e48090886044 100644 --- a/Documentation/ABI/testing/sysfs-devices-power +++ b/Documentation/ABI/testing/sysfs-devices-power @@ -260,3 +260,12 @@ Description: This attribute has no effect on system-wide suspend/resume and hibernation. + +What: /sys/devices/.../power/runtime_status +Date: April 2010 +Contact: Rafael J. Wysocki +Description: + The /sys/devices/.../power/runtime_status attribute contains + the current runtime PM status of the device, which may be + "suspended", "suspending", "resuming", "active", "error" (fatal + error), or "unsupported" (runtime PM is disabled). diff --git a/Documentation/ABI/testing/sysfs-devices-soc b/Documentation/ABI/testing/sysfs-devices-soc index 6d9cc253f2b292844bc51c3b0eed1096e34ab056..ba3a3fac0ee11002076eb8ebac935016d8b5c185 100644 --- a/Documentation/ABI/testing/sysfs-devices-soc +++ b/Documentation/ABI/testing/sysfs-devices-soc @@ -26,6 +26,13 @@ Description: Read-only attribute common to all SoCs. Contains SoC family name (e.g. DB8500). +What: /sys/devices/socX/serial_number +Date: January 2019 +contact: Bjorn Andersson +Description: + Read-only attribute supported by most SoCs. Contains the SoC's + serial number, if available. + What: /sys/devices/socX/soc_id Date: January 2012 contact: Lee Jones diff --git a/Documentation/ABI/testing/sysfs-driver-habanalabs b/Documentation/ABI/testing/sysfs-driver-habanalabs index f433fc6db3c69f790107846bf79b924ede4f8165..782df74042ed21f908ef84d8010f33c3367658ed 100644 --- a/Documentation/ABI/testing/sysfs-driver-habanalabs +++ b/Documentation/ABI/testing/sysfs-driver-habanalabs @@ -57,6 +57,7 @@ KernelVersion: 5.1 Contact: oded.gabbay@gmail.com Description: Allows the user to set the maximum clock frequency for MME, TPC and IC when the power management profile is set to "automatic". + This property is valid only for the Goya ASIC family What: /sys/class/habanalabs/hl/ic_clk Date: Jan 2019 @@ -127,8 +128,8 @@ Description: Power management profile. Values are "auto", "manual". In "auto" the max clock frequency to a low value when there are no user processes that are opened on the device's file. In "manual" mode, the user sets the maximum clock frequency by writing to - ic_clk, mme_clk and tpc_clk - + ic_clk, mme_clk and tpc_clk. This property is valid only for + the Goya ASIC family What: /sys/class/habanalabs/hl/preboot_btl_ver Date: Jan 2019 @@ -186,11 +187,4 @@ What: /sys/class/habanalabs/hl/uboot_ver Date: Jan 2019 KernelVersion: 5.1 Contact: oded.gabbay@gmail.com -Description: Version of the u-boot running on the device's CPU - -What: /sys/class/habanalabs/hl/write_open_cnt -Date: Jan 2019 -KernelVersion: 5.1 -Contact: oded.gabbay@gmail.com -Description: Displays the total number of user processes that are currently - opened on the device's file +Description: Version of the u-boot running on the device's CPU \ No newline at end of file diff --git a/Documentation/ABI/testing/sysfs-firmware-efi b/Documentation/ABI/testing/sysfs-firmware-efi index e794eac32a90a51c4d01577affe71466cde99a1f..5e4d0b27cdfe00707e29a836c7c48ff6a0a48e5b 100644 --- a/Documentation/ABI/testing/sysfs-firmware-efi +++ b/Documentation/ABI/testing/sysfs-firmware-efi @@ -28,3 +28,11 @@ Description: Displays the physical addresses of all EFI Configuration versions are always printed first, i.e. ACPI20 comes before ACPI. Users: dmidecode + +What: /sys/firmware/efi/tables/rci2 +Date: July 2019 +Contact: Narendra K , linux-bugs@dell.com +Description: Displays the content of the Runtime Configuration Interface + Table version 2 on Dell EMC PowerEdge systems in binary format +Users: It is used by Dell EMC OpenManage Server Administrator tool to + populate BIOS setup page. diff --git a/Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm b/Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm new file mode 100644 index 0000000000000000000000000000000000000000..15595fab88d18469030d5f7f2d500cca44afdbf1 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm @@ -0,0 +1,37 @@ +What: /sys/firmware/turris-mox-rwtm/board_version +Date: August 2019 +KernelVersion: 5.4 +Contact: Marek Behún +Description: (R) Board version burned into eFuses of this Turris Mox board. + Format: %i + +What: /sys/firmware/turris-mox-rwtm/mac_address* +Date: August 2019 +KernelVersion: 5.4 +Contact: Marek Behún +Description: (R) MAC addresses burned into eFuses of this Turris Mox board. + Format: %pM + +What: /sys/firmware/turris-mox-rwtm/pubkey +Date: August 2019 +KernelVersion: 5.4 +Contact: Marek Behún +Description: (R) ECDSA public key (in pubkey hex compressed form) computed + as pair to the ECDSA private key burned into eFuses of this + Turris Mox Board. + Format: string + +What: /sys/firmware/turris-mox-rwtm/ram_size +Date: August 2019 +KernelVersion: 5.4 +Contact: Marek Behún +Description: (R) RAM size in MiB of this Turris Mox board as was detected + during manufacturing and burned into eFuses. Can be 512 or 1024. + Format: %i + +What: /sys/firmware/turris-mox-rwtm/serial_number +Date: August 2019 +KernelVersion: 5.4 +Contact: Marek Behún +Description: (R) Serial number burned into eFuses of this Turris Mox device. + Format: %016X diff --git a/Documentation/ABI/testing/sysfs-kernel-btf b/Documentation/ABI/testing/sysfs-kernel-btf new file mode 100644 index 0000000000000000000000000000000000000000..2c9744b2cd59fa5c7a054651efd7bb1edc960363 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-kernel-btf @@ -0,0 +1,17 @@ +What: /sys/kernel/btf +Date: Aug 2019 +KernelVersion: 5.5 +Contact: bpf@vger.kernel.org +Description: + Contains BTF type information and related data for kernel and + kernel modules. + +What: /sys/kernel/btf/vmlinux +Date: Aug 2019 +KernelVersion: 5.5 +Contact: bpf@vger.kernel.org +Description: + Read-only binary attribute exposing kernel's own BTF type + information with description of all internal kernel types. See + Documentation/bpf/btf.rst for detailed description of format + itself. diff --git a/Documentation/ABI/testing/sysfs-platform-dfl-fme b/Documentation/ABI/testing/sysfs-platform-dfl-fme index 8fa4febfa4b212a0edf60fda818bfdb923418303..72634d3ae4f4ebb14e576691ccc2b79879b910ce 100644 --- a/Documentation/ABI/testing/sysfs-platform-dfl-fme +++ b/Documentation/ABI/testing/sysfs-platform-dfl-fme @@ -21,3 +21,88 @@ Contact: Wu Hao Description: Read-only. It returns Bitstream (static FPGA region) meta data, which includes the synthesis date, seed and other information of this static FPGA region. + +What: /sys/bus/platform/devices/dfl-fme.0/cache_size +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-only. It returns cache size of this FPGA device. + +What: /sys/bus/platform/devices/dfl-fme.0/fabric_version +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-only. It returns fabric version of this FPGA device. + Userspace applications need this information to select + best data channels per different fabric design. + +What: /sys/bus/platform/devices/dfl-fme.0/socket_id +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-only. It returns socket_id to indicate which socket + this FPGA belongs to, only valid for integrated solution. + User only needs this information, in case standard numa node + can't provide correct information. + +What: /sys/bus/platform/devices/dfl-fme.0/errors/pcie0_errors +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-Write. Read this file for errors detected on pcie0 link. + Write this file to clear errors logged in pcie0_errors. Write + fails with -EINVAL if input parsing fails or input error code + doesn't match. + +What: /sys/bus/platform/devices/dfl-fme.0/errors/pcie1_errors +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-Write. Read this file for errors detected on pcie1 link. + Write this file to clear errors logged in pcie1_errors. Write + fails with -EINVAL if input parsing fails or input error code + doesn't match. + +What: /sys/bus/platform/devices/dfl-fme.0/errors/nonfatal_errors +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-only. It returns non-fatal errors detected. + +What: /sys/bus/platform/devices/dfl-fme.0/errors/catfatal_errors +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-only. It returns catastrophic and fatal errors detected. + +What: /sys/bus/platform/devices/dfl-fme.0/errors/inject_errors +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-Write. Read this file to check errors injected. Write this + file to inject errors for testing purpose. Write fails with + -EINVAL if input parsing fails or input inject error code isn't + supported. + +What: /sys/bus/platform/devices/dfl-fme.0/errors/fme_errors +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-Write. Read this file to get errors detected on FME. + Write this file to clear errors logged in fme_errors. Write + fials with -EINVAL if input parsing fails or input error code + doesn't match. + +What: /sys/bus/platform/devices/dfl-fme.0/errors/first_error +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-only. Read this file to get the first error detected by + hardware. + +What: /sys/bus/platform/devices/dfl-fme.0/errors/next_error +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-only. Read this file to get the second error detected by + hardware. diff --git a/Documentation/ABI/testing/sysfs-platform-dfl-port b/Documentation/ABI/testing/sysfs-platform-dfl-port index 6a92dda517b05120b0447629743d81372ecd1662..65658267fcc094c876fc67cd1e701e66d3497a7b 100644 --- a/Documentation/ABI/testing/sysfs-platform-dfl-port +++ b/Documentation/ABI/testing/sysfs-platform-dfl-port @@ -14,3 +14,88 @@ Description: Read-only. User can program different PR bitstreams to FPGA Accelerator Function Unit (AFU) for different functions. It returns uuid which could be used to identify which PR bitstream is programmed in this AFU. + +What: /sys/bus/platform/devices/dfl-port.0/power_state +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-only. It reports the APx (AFU Power) state, different APx + means different throttling level. When reading this file, it + returns "0" - Normal / "1" - AP1 / "2" - AP2 / "6" - AP6. + +What: /sys/bus/platform/devices/dfl-port.0/ap1_event +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-write. Read this file for AP1 (AFU Power State 1) event. + It's used to indicate transient AP1 state. Write 1 to this + file to clear AP1 event. + +What: /sys/bus/platform/devices/dfl-port.0/ap2_event +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-write. Read this file for AP2 (AFU Power State 2) event. + It's used to indicate transient AP2 state. Write 1 to this + file to clear AP2 event. + +What: /sys/bus/platform/devices/dfl-port.0/ltr +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-write. Read or set AFU latency tolerance reporting value. + Set ltr to 1 if the AFU can tolerate latency >= 40us or set it + to 0 if it is latency sensitive. + +What: /sys/bus/platform/devices/dfl-port.0/userclk_freqcmd +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Write-only. User writes command to this interface to set + userclock to AFU. + +What: /sys/bus/platform/devices/dfl-port.0/userclk_freqsts +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-only. Read this file to get the status of issued command + to userclck_freqcmd. + +What: /sys/bus/platform/devices/dfl-port.0/userclk_freqcntrcmd +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Write-only. User writes command to this interface to set + userclock counter. + +What: /sys/bus/platform/devices/dfl-port.0/userclk_freqcntrsts +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-only. Read this file to get the status of issued command + to userclck_freqcntrcmd. + +What: /sys/bus/platform/devices/dfl-port.0/errors/errors +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-Write. Read this file to get errors detected on port and + Accelerated Function Unit (AFU). Write error code to this file + to clear errors. Write fails with -EINVAL if input parsing + fails or input error code doesn't match. Write fails with + -EBUSY or -ETIMEDOUT if error can't be cleared as hardware + in low power state (-EBUSY) or not respoding (-ETIMEDOUT). + +What: /sys/bus/platform/devices/dfl-port.0/errors/first_error +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-only. Read this file to get the first error detected by + hardware. + +What: /sys/bus/platform/devices/dfl-port.0/errors/first_malformed_req +Date: August 2019 +KernelVersion: 5.4 +Contact: Wu Hao +Description: Read-only. Read this file to get the first malformed request + captured by hardware. diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power index 3c51303550118474389bec304ef5f1f7c7c4b1e2..6f87b9dd384b8b7faf72be043625df5dba5d7afc 100644 --- a/Documentation/ABI/testing/sysfs-power +++ b/Documentation/ABI/testing/sysfs-power @@ -301,3 +301,109 @@ Description: Using this sysfs file will override any values that were set using the kernel command line for disk offset. + +What: /sys/power/suspend_stats +Date: July 2019 +Contact: Kalesh Singh +Description: + The /sys/power/suspend_stats directory contains suspend related + statistics. + +What: /sys/power/suspend_stats/success +Date: July 2019 +Contact: Kalesh Singh +Description: + The /sys/power/suspend_stats/success file contains the number + of times entering system sleep state succeeded. + +What: /sys/power/suspend_stats/fail +Date: July 2019 +Contact: Kalesh Singh +Description: + The /sys/power/suspend_stats/fail file contains the number + of times entering system sleep state failed. + +What: /sys/power/suspend_stats/failed_freeze +Date: July 2019 +Contact: Kalesh Singh +Description: + The /sys/power/suspend_stats/failed_freeze file contains the + number of times freezing processes failed. + +What: /sys/power/suspend_stats/failed_prepare +Date: July 2019 +Contact: Kalesh Singh +Description: + The /sys/power/suspend_stats/failed_prepare file contains the + number of times preparing all non-sysdev devices for + a system PM transition failed. + +What: /sys/power/suspend_stats/failed_resume +Date: July 2019 +Contact: Kalesh Singh +Description: + The /sys/power/suspend_stats/failed_resume file contains the + number of times executing "resume" callbacks of + non-sysdev devices failed. + +What: /sys/power/suspend_stats/failed_resume_early +Date: July 2019 +Contact: Kalesh Singh +Description: + The /sys/power/suspend_stats/failed_resume_early file contains + the number of times executing "early resume" callbacks + of devices failed. + +What: /sys/power/suspend_stats/failed_resume_noirq +Date: July 2019 +Contact: Kalesh Singh +Description: + The /sys/power/suspend_stats/failed_resume_noirq file contains + the number of times executing "noirq resume" callbacks + of devices failed. + +What: /sys/power/suspend_stats/failed_suspend +Date: July 2019 +Contact: Kalesh Singh +Description: + The /sys/power/suspend_stats/failed_suspend file contains + the number of times executing "suspend" callbacks + of all non-sysdev devices failed. + +What: /sys/power/suspend_stats/failed_suspend_late +Date: July 2019 +Contact: Kalesh Singh +Description: + The /sys/power/suspend_stats/failed_suspend_late file contains + the number of times executing "late suspend" callbacks + of all devices failed. + +What: /sys/power/suspend_stats/failed_suspend_noirq +Date: July 2019 +Contact: Kalesh Singh +Description: + The /sys/power/suspend_stats/failed_suspend_noirq file contains + the number of times executing "noirq suspend" callbacks + of all devices failed. + +What: /sys/power/suspend_stats/last_failed_dev +Date: July 2019 +Contact: Kalesh Singh +Description: + The /sys/power/suspend_stats/last_failed_dev file contains + the last device for which a suspend/resume callback failed. + +What: /sys/power/suspend_stats/last_failed_errno +Date: July 2019 +Contact: Kalesh Singh +Description: + The /sys/power/suspend_stats/last_failed_errno file contains + the errno of the last failed attempt at entering + system sleep state. + +What: /sys/power/suspend_stats/last_failed_step +Date: July 2019 +Contact: Kalesh Singh +Description: + The /sys/power/suspend_stats/last_failed_step file contains + the last failed step in the suspend/resume path. diff --git a/Documentation/PCI/pci-error-recovery.rst b/Documentation/PCI/pci-error-recovery.rst index e5d450df06b4dedd91aa0507ea39181ebb845f6a..13beee23cb04fbf330994527a4e8f94128b61783 100644 --- a/Documentation/PCI/pci-error-recovery.rst +++ b/Documentation/PCI/pci-error-recovery.rst @@ -421,7 +421,6 @@ That is, the recovery API only requires that: - drivers/net/ixgbe - drivers/net/cxgb3 - drivers/net/s2io.c - - drivers/net/qlge The End ------- diff --git a/Documentation/RCU/Design/Requirements/Requirements.html b/Documentation/RCU/Design/Requirements/Requirements.html index 5a9238a2883c6a689fb9c271afd815189369d74e..467251f7fef69d7d418407d2a7bf0a3514382733 100644 --- a/Documentation/RCU/Design/Requirements/Requirements.html +++ b/Documentation/RCU/Design/Requirements/Requirements.html @@ -2129,6 +2129,8 @@ Some of the relevant points of interest are as follows:
  • Hotplug CPU.
  • Scheduler and RCU.
  • Tracing and RCU. +
  • +Accesses to User Memory and RCU.
  • Energy Efficiency.
  • Scheduling-Clock Interrupts and RCU. @@ -2512,7 +2514,7 @@ disabled across the entire RCU read-side critical section.

    It is possible to use tracing on RCU code, but tracing itself uses RCU. -For this reason, rcu_dereference_raw_notrace() +For this reason, rcu_dereference_raw_check() is provided for use by tracing, which avoids the destructive recursion that could otherwise ensue. This API is also used by virtualization in some architectures, @@ -2521,6 +2523,75 @@ cannot be used. The tracing folks both located the requirement and provided the needed fix, so this surprise requirement was relatively painless. +

    +Accesses to User Memory and RCU

    + +

    +The kernel needs to access user-space memory, for example, to access +data referenced by system-call parameters. +The get_user() macro does this job. + +

    +However, user-space memory might well be paged out, which means +that get_user() might well page-fault and thus block while +waiting for the resulting I/O to complete. +It would be a very bad thing for the compiler to reorder +a get_user() invocation into an RCU read-side critical +section. +For example, suppose that the source code looked like this: + +

    +
    + 1 rcu_read_lock();
    + 2 p = rcu_dereference(gp);
    + 3 v = p->value;
    + 4 rcu_read_unlock();
    + 5 get_user(user_v, user_p);
    + 6 do_something_with(v, user_v);
    +
    +
    + +

    +The compiler must not be permitted to transform this source code into +the following: + +

    +
    + 1 rcu_read_lock();
    + 2 p = rcu_dereference(gp);
    + 3 get_user(user_v, user_p); // BUG: POSSIBLE PAGE FAULT!!!
    + 4 v = p->value;
    + 5 rcu_read_unlock();
    + 6 do_something_with(v, user_v);
    +
    +
    + +

    +If the compiler did make this transformation in a +CONFIG_PREEMPT=n kernel build, and if get_user() did +page fault, the result would be a quiescent state in the middle +of an RCU read-side critical section. +This misplaced quiescent state could result in line 4 being +a use-after-free access, which could be bad for your kernel's +actuarial statistics. +Similar examples can be constructed with the call to get_user() +preceding the rcu_read_lock(). + +

    +Unfortunately, get_user() doesn't have any particular +ordering properties, and in some architectures the underlying asm +isn't even marked volatile. +And even if it was marked volatile, the above access to +p->value is not volatile, so the compiler would not have any +reason to keep those two accesses in order. + +

    +Therefore, the Linux-kernel definitions of rcu_read_lock() +and rcu_read_unlock() must act as compiler barriers, +at least for outermost instances of rcu_read_lock() and +rcu_read_unlock() within a nested set of RCU read-side critical +sections. +

    Energy Efficiency

    diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt index 13e88fc00f01aaca0039701377737a94e583f615..f48f4621ccbc2b261e6e9e924ca19b9f508c02a5 100644 --- a/Documentation/RCU/stallwarn.txt +++ b/Documentation/RCU/stallwarn.txt @@ -57,6 +57,12 @@ o A CPU-bound real-time task in a CONFIG_PREEMPT_RT kernel that CONFIG_PREEMPT_RCU case, you might see stall-warning messages. + You can use the rcutree.kthread_prio kernel boot parameter to + increase the scheduling priority of RCU's kthreads, which can + help avoid this problem. However, please note that doing this + can increase your system's context-switch rate and thus degrade + performance. + o A periodic interrupt whose handler takes longer than the time interval between successive pairs of interrupts. This can prevent RCU's kthreads and softirq handlers from running. diff --git a/Documentation/admin-guide/auxdisplay/cfag12864b.rst b/Documentation/admin-guide/auxdisplay/cfag12864b.rst new file mode 100644 index 0000000000000000000000000000000000000000..18c2865bd322303b2c8abd91f1f91988f0a9454a --- /dev/null +++ b/Documentation/admin-guide/auxdisplay/cfag12864b.rst @@ -0,0 +1,98 @@ +=================================== +cfag12864b LCD Driver Documentation +=================================== + +:License: GPLv2 +:Author & Maintainer: Miguel Ojeda Sandonis +:Date: 2006-10-27 + + + +.. INDEX + + 1. DRIVER INFORMATION + 2. DEVICE INFORMATION + 3. WIRING + 4. USERSPACE PROGRAMMING + +1. Driver Information +--------------------- + +This driver supports a cfag12864b LCD. + + +2. Device Information +--------------------- + +:Manufacturer: Crystalfontz +:Device Name: Crystalfontz 12864b LCD Series +:Device Code: cfag12864b +:Webpage: http://www.crystalfontz.com +:Device Webpage: http://www.crystalfontz.com/products/12864b/ +:Type: LCD (Liquid Crystal Display) +:Width: 128 +:Height: 64 +:Colors: 2 (B/N) +:Controller: ks0108 +:Controllers: 2 +:Pages: 8 each controller +:Addresses: 64 each page +:Data size: 1 byte each address +:Memory size: 2 * 8 * 64 * 1 = 1024 bytes = 1 Kbyte + + +3. Wiring +--------- + +The cfag12864b LCD Series don't have official wiring. + +The common wiring is done to the parallel port as shown:: + + Parallel Port cfag12864b + + Name Pin# Pin# Name + + Strobe ( 1)------------------------------(17) Enable + Data 0 ( 2)------------------------------( 4) Data 0 + Data 1 ( 3)------------------------------( 5) Data 1 + Data 2 ( 4)------------------------------( 6) Data 2 + Data 3 ( 5)------------------------------( 7) Data 3 + Data 4 ( 6)------------------------------( 8) Data 4 + Data 5 ( 7)------------------------------( 9) Data 5 + Data 6 ( 8)------------------------------(10) Data 6 + Data 7 ( 9)------------------------------(11) Data 7 + (10) [+5v]---( 1) Vdd + (11) [GND]---( 2) Ground + (12) [+5v]---(14) Reset + (13) [GND]---(15) Read / Write + Line (14)------------------------------(13) Controller Select 1 + (15) + Init (16)------------------------------(12) Controller Select 2 + Select (17)------------------------------(16) Data / Instruction + Ground (18)---[GND] [+5v]---(19) LED + + Ground (19)---[GND] + Ground (20)---[GND] E A Values: + Ground (21)---[GND] [GND]---[P1]---(18) Vee - R = Resistor = 22 ohm + Ground (22)---[GND] | - P1 = Preset = 10 Kohm + Ground (23)---[GND] ---- S ------( 3) V0 - P2 = Preset = 1 Kohm + Ground (24)---[GND] | | + Ground (25)---[GND] [GND]---[P2]---[R]---(20) LED - + + +4. Userspace Programming +------------------------ + +The cfag12864bfb describes a framebuffer device (/dev/fbX). + +It has a size of 1024 bytes = 1 Kbyte. +Each bit represents one pixel. If the bit is high, the pixel will +turn on. If the pixel is low, the pixel will turn off. + +You can use the framebuffer as a file: fopen, fwrite, fclose... +Although the LCD won't get updated until the next refresh time arrives. + +Also, you can mmap the framebuffer: open & mmap, munmap & close... +which is the best option for most uses. + +Check samples/auxdisplay/cfag12864b-example.c +for a real working userspace complete program with usage examples. diff --git a/Documentation/admin-guide/auxdisplay/index.rst b/Documentation/admin-guide/auxdisplay/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..e466f05952482043f6893c20b17ce372e814fc2f --- /dev/null +++ b/Documentation/admin-guide/auxdisplay/index.rst @@ -0,0 +1,16 @@ +========================= +Auxiliary Display Support +========================= + +.. toctree:: + :maxdepth: 1 + + ks0108.rst + cfag12864b.rst + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/admin-guide/auxdisplay/ks0108.rst b/Documentation/admin-guide/auxdisplay/ks0108.rst new file mode 100644 index 0000000000000000000000000000000000000000..c0b7faf73136129b6d86873763b534281f82316f --- /dev/null +++ b/Documentation/admin-guide/auxdisplay/ks0108.rst @@ -0,0 +1,50 @@ +========================================== +ks0108 LCD Controller Driver Documentation +========================================== + +:License: GPLv2 +:Author & Maintainer: Miguel Ojeda Sandonis +:Date: 2006-10-27 + + + +.. INDEX + + 1. DRIVER INFORMATION + 2. DEVICE INFORMATION + 3. WIRING + + +1. Driver Information +--------------------- + +This driver supports the ks0108 LCD controller. + + +2. Device Information +--------------------- + +:Manufacturer: Samsung +:Device Name: KS0108 LCD Controller +:Device Code: ks0108 +:Webpage: - +:Device Webpage: - +:Type: LCD Controller (Liquid Crystal Display Controller) +:Width: 64 +:Height: 64 +:Colors: 2 (B/N) +:Pages: 8 +:Addresses: 64 each page +:Data size: 1 byte each address +:Memory size: 8 * 64 * 1 = 512 bytes + + +3. Wiring +--------- + +The driver supports data parallel port wiring. + +If you aren't building LCD related hardware, you should check +your LCD specific wiring information in the same folder. + +For example, check Documentation/admin-guide/auxdisplay/cfag12864b.rst diff --git a/Documentation/admin-guide/cgroup-v1/blkio-controller.rst b/Documentation/admin-guide/cgroup-v1/blkio-controller.rst index 1d7d962933bef4b3cae6818976ea98a00a2aa07e..36d43ae7dc130ece68582661984956fde089142e 100644 --- a/Documentation/admin-guide/cgroup-v1/blkio-controller.rst +++ b/Documentation/admin-guide/cgroup-v1/blkio-controller.rst @@ -130,12 +130,6 @@ Proportional weight policy files dev weight 8:16 300 -- blkio.leaf_weight[_device] - - Equivalents of blkio.weight[_device] for the purpose of - deciding how much weight tasks in the given cgroup has while - competing with the cgroup's child cgroups. For details, - please refer to Documentation/block/cfq-iosched.txt. - - blkio.time - disk time allocated to cgroup per device in milliseconds. First two fields specify the major and minor number of the device and diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst index 3b29005aa9810d98a6604bed10e1d4c98dde6360..0fa8c0e615c2853587e2a87fa396fb5dbac321bb 100644 --- a/Documentation/admin-guide/cgroup-v2.rst +++ b/Documentation/admin-guide/cgroup-v2.rst @@ -951,6 +951,13 @@ controller implements weight and absolute bandwidth limit models for normal scheduling policy and absolute bandwidth allocation model for realtime scheduling policy. +In all the above models, cycles distribution is defined only on a temporal +base and it does not account for the frequency at which tasks are executed. +The (optional) utilization clamping support allows to hint the schedutil +cpufreq governor about the minimum desired frequency which should always be +provided by a CPU, as well as the maximum desired frequency, which should not +be exceeded by a CPU. + WARNING: cgroup2 doesn't yet support control of realtime processes and the cpu controller can only be enabled when all RT processes are in the root cgroup. Be aware that system management software may already @@ -1016,6 +1023,33 @@ All time durations are in microseconds. Shows pressure stall information for CPU. See Documentation/accounting/psi.rst for details. + cpu.uclamp.min + A read-write single value file which exists on non-root cgroups. + The default is "0", i.e. no utilization boosting. + + The requested minimum utilization (protection) as a percentage + rational number, e.g. 12.34 for 12.34%. + + This interface allows reading and setting minimum utilization clamp + values similar to the sched_setattr(2). This minimum utilization + value is used to clamp the task specific minimum utilization clamp. + + The requested minimum utilization (protection) is always capped by + the current value for the maximum utilization (limit), i.e. + `cpu.uclamp.max`. + + cpu.uclamp.max + A read-write single value file which exists on non-root cgroups. + The default is "max". i.e. no utilization capping + + The requested maximum utilization (limit) as a percentage rational + number, e.g. 98.76 for 98.76%. + + This interface allows reading and setting maximum utilization clamp + values similar to the sched_setattr(2). This maximum utilization + value is used to clamp the task specific maximum utilization clamp. + + Memory ------ @@ -1435,6 +1469,103 @@ IO Interface Files 8:16 rbytes=1459200 wbytes=314773504 rios=192 wios=353 dbytes=0 dios=0 8:0 rbytes=90430464 wbytes=299008000 rios=8950 wios=1252 dbytes=50331648 dios=3021 + io.cost.qos + A read-write nested-keyed file with exists only on the root + cgroup. + + This file configures the Quality of Service of the IO cost + model based controller (CONFIG_BLK_CGROUP_IOCOST) which + currently implements "io.weight" proportional control. Lines + are keyed by $MAJ:$MIN device numbers and not ordered. The + line for a given device is populated on the first write for + the device on "io.cost.qos" or "io.cost.model". The following + nested keys are defined. + + ====== ===================================== + enable Weight-based control enable + ctrl "auto" or "user" + rpct Read latency percentile [0, 100] + rlat Read latency threshold + wpct Write latency percentile [0, 100] + wlat Write latency threshold + min Minimum scaling percentage [1, 10000] + max Maximum scaling percentage [1, 10000] + ====== ===================================== + + The controller is disabled by default and can be enabled by + setting "enable" to 1. "rpct" and "wpct" parameters default + to zero and the controller uses internal device saturation + state to adjust the overall IO rate between "min" and "max". + + When a better control quality is needed, latency QoS + parameters can be configured. For example:: + + 8:16 enable=1 ctrl=auto rpct=95.00 rlat=75000 wpct=95.00 wlat=150000 min=50.00 max=150.0 + + shows that on sdb, the controller is enabled, will consider + the device saturated if the 95th percentile of read completion + latencies is above 75ms or write 150ms, and adjust the overall + IO issue rate between 50% and 150% accordingly. + + The lower the saturation point, the better the latency QoS at + the cost of aggregate bandwidth. The narrower the allowed + adjustment range between "min" and "max", the more conformant + to the cost model the IO behavior. Note that the IO issue + base rate may be far off from 100% and setting "min" and "max" + blindly can lead to a significant loss of device capacity or + control quality. "min" and "max" are useful for regulating + devices which show wide temporary behavior changes - e.g. a + ssd which accepts writes at the line speed for a while and + then completely stalls for multiple seconds. + + When "ctrl" is "auto", the parameters are controlled by the + kernel and may change automatically. Setting "ctrl" to "user" + or setting any of the percentile and latency parameters puts + it into "user" mode and disables the automatic changes. The + automatic mode can be restored by setting "ctrl" to "auto". + + io.cost.model + A read-write nested-keyed file with exists only on the root + cgroup. + + This file configures the cost model of the IO cost model based + controller (CONFIG_BLK_CGROUP_IOCOST) which currently + implements "io.weight" proportional control. Lines are keyed + by $MAJ:$MIN device numbers and not ordered. The line for a + given device is populated on the first write for the device on + "io.cost.qos" or "io.cost.model". The following nested keys + are defined. + + ===== ================================ + ctrl "auto" or "user" + model The cost model in use - "linear" + ===== ================================ + + When "ctrl" is "auto", the kernel may change all parameters + dynamically. When "ctrl" is set to "user" or any other + parameters are written to, "ctrl" become "user" and the + automatic changes are disabled. + + When "model" is "linear", the following model parameters are + defined. + + ============= ======================================== + [r|w]bps The maximum sequential IO throughput + [r|w]seqiops The maximum 4k sequential IOs per second + [r|w]randiops The maximum 4k random IOs per second + ============= ======================================== + + From the above, the builtin linear model determines the base + costs of a sequential and random IO and the cost coefficient + for the IO size. While simple, this model can cover most + common device classes acceptably. + + The IO cost model isn't expected to be accurate in absolute + sense and is scaled to the device behavior dynamically. + + If needed, tools/cgroup/iocost_coef_gen.py can be used to + generate device-specific coefficients. + io.weight A read-write flat-keyed file which exists on non-root cgroups. The default is "default 100". diff --git a/Documentation/filesystems/cifs/AUTHORS b/Documentation/admin-guide/cifs/authors.rst similarity index 60% rename from Documentation/filesystems/cifs/AUTHORS rename to Documentation/admin-guide/cifs/authors.rst index 75865da2ce1475c27bea1050b3e80ff7160f6d6f..b02d6dd6c070eb0770bff460e3eef51def58a1c1 100644 --- a/Documentation/filesystems/cifs/AUTHORS +++ b/Documentation/admin-guide/cifs/authors.rst @@ -1,5 +1,10 @@ +======= +Authors +======= + Original Author -=============== +--------------- + Steve French (sfrench@samba.org) The author wishes to express his appreciation and thanks to: @@ -12,7 +17,7 @@ side of the original CIFS Unix extensions and reviewing and implementing portions of the newer CIFS POSIX extensions into the Samba 3 file server. Thank Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client) for proving years ago that very good smb/cifs clients could be done on Unix-like -operating systems. Volker Lendecke, Andrew Tridgell, Urban Widmark, John +operating systems. Volker Lendecke, Andrew Tridgell, Urban Widmark, John Newbigin and others for their work on the Linux smbfs module. Thanks to the other members of the Storage Network Industry Association CIFS Technical Workgroup for their work specifying this highly complex protocol and finally @@ -20,33 +25,34 @@ thanks to the Samba team for their technical advice and encouragement. Patch Contributors ------------------ -Zwane Mwaikambo -Andi Kleen -Amrut Joshi -Shobhit Dayal -Sergey Vlasov -Richard Hughes -Yury Umanets -Mark Hamzy (for some of the early cifs IPv6 work) -Domen Puncer -Jesper Juhl (in particular for lots of whitespace/formatting cleanup) -Vince Negri and Dave Stahl (for finding an important caching bug) -Adrian Bunk (kcalloc cleanups) -Miklos Szeredi -Kazeon team for various fixes especially for 2.4 version. -Asser Ferno (Change Notify support) -Shaggy (Dave Kleikamp) for innumerable small fs suggestions and some good cleanup -Gunter Kukkukk (testing and suggestions for support of old servers) -Igor Mammedov (DFS support) -Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code) -Scott Lovenberg -Pavel Shilovsky (for great work adding SMB2 support, and various SMB3 features) -Aurelien Aptel (for DFS SMB3 work and some key bug fixes) -Ronnie Sahlberg (for SMB3 xattr work, bug fixes, and lots of great work on compounding) -Shirish Pargaonkar (for many ACL patches over the years) -Sachin Prabhu (many bug fixes, including for reconnect, copy offload and security) -Paulo Alcantara -Long Li (some great work on RDMA, SMB Direct) + +- Zwane Mwaikambo +- Andi Kleen +- Amrut Joshi +- Shobhit Dayal +- Sergey Vlasov +- Richard Hughes +- Yury Umanets +- Mark Hamzy (for some of the early cifs IPv6 work) +- Domen Puncer +- Jesper Juhl (in particular for lots of whitespace/formatting cleanup) +- Vince Negri and Dave Stahl (for finding an important caching bug) +- Adrian Bunk (kcalloc cleanups) +- Miklos Szeredi +- Kazeon team for various fixes especially for 2.4 version. +- Asser Ferno (Change Notify support) +- Shaggy (Dave Kleikamp) for innumerable small fs suggestions and some good cleanup +- Gunter Kukkukk (testing and suggestions for support of old servers) +- Igor Mammedov (DFS support) +- Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code) +- Scott Lovenberg +- Pavel Shilovsky (for great work adding SMB2 support, and various SMB3 features) +- Aurelien Aptel (for DFS SMB3 work and some key bug fixes) +- Ronnie Sahlberg (for SMB3 xattr work, bug fixes, and lots of great work on compounding) +- Shirish Pargaonkar (for many ACL patches over the years) +- Sachin Prabhu (many bug fixes, including for reconnect, copy offload and security) +- Paulo Alcantara +- Long Li (some great work on RDMA, SMB Direct) Test case and Bug Report contributors diff --git a/Documentation/filesystems/cifs/CHANGES b/Documentation/admin-guide/cifs/changes.rst similarity index 91% rename from Documentation/filesystems/cifs/CHANGES rename to Documentation/admin-guide/cifs/changes.rst index 1df7f4910eb22d793ae9dd1e8e56add9626c46bf..71f2ecb62299316f1799c9f9c769b9a3a610fda3 100644 --- a/Documentation/filesystems/cifs/CHANGES +++ b/Documentation/admin-guide/cifs/changes.rst @@ -1,3 +1,7 @@ +======= +Changes +======= + See https://wiki.samba.org/index.php/LinuxCIFSKernel for summary information (that may be easier to read than parsing the output of "git log fs/cifs") about fixes/improvements to CIFS/SMB2/SMB3 support (changes diff --git a/Documentation/admin-guide/cifs/index.rst b/Documentation/admin-guide/cifs/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..fad5268635f55f01a57fdb4073774d135c5b5ac4 --- /dev/null +++ b/Documentation/admin-guide/cifs/index.rst @@ -0,0 +1,21 @@ +.. SPDX-License-Identifier: GPL-2.0 + +==== +CIFS +==== + +.. toctree:: + :maxdepth: 2 + + introduction + usage + todo + changes + authors + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/filesystems/cifs/cifs.txt b/Documentation/admin-guide/cifs/introduction.rst similarity index 98% rename from Documentation/filesystems/cifs/cifs.txt rename to Documentation/admin-guide/cifs/introduction.rst index 1be3d21c286ece45d9024dfe9d718d46b5de66e0..0b98f672d36fb782015dfd38ad16525cb41d7c9f 100644 --- a/Documentation/filesystems/cifs/cifs.txt +++ b/Documentation/admin-guide/cifs/introduction.rst @@ -1,3 +1,7 @@ +============ +Introduction +============ + This is the client VFS module for the SMB3 NAS protocol as well as for older dialects such as the Common Internet File System (CIFS) protocol which was the successor to the Server Message Block @@ -33,7 +37,9 @@ tools (including smbinfo and setcifsacl) that can be obtained from https://git.samba.org/?p=cifs-utils.git + or + git://git.samba.org/cifs-utils.git mount.cifs should be installed in the directory with the other mount helpers. @@ -41,5 +47,7 @@ For more information on the module see the project wiki page at https://wiki.samba.org/index.php/LinuxCIFS + and + https://wiki.samba.org/index.php/LinuxCIFS_utils diff --git a/Documentation/filesystems/cifs/TODO b/Documentation/admin-guide/cifs/todo.rst similarity index 54% rename from Documentation/filesystems/cifs/TODO rename to Documentation/admin-guide/cifs/todo.rst index edbbccda1942e4c84bf5b3dd3e5d3c1bd7959b32..084c25f92dcb00fb43e879453e2443a8a2eef0a0 100644 --- a/Documentation/filesystems/cifs/TODO +++ b/Documentation/admin-guide/cifs/todo.rst @@ -1,3 +1,7 @@ +==== +TODO +==== + Version 2.14 December 21, 2018 A Partial List of Missing Features @@ -8,55 +12,58 @@ for visible, important contributions to this module. Here is a partial list of the known problems and missing features: a) SMB3 (and SMB3.1.1) missing optional features: + - multichannel (started), integration with RDMA - directory leases (improved metadata caching), started (root dir only) - T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl currently the only two server side copy mechanisms supported) b) improved sparse file support (fiemap and SEEK_HOLE are implemented -but additional features would be supportable by the protocol). + but additional features would be supportable by the protocol). c) Directory entry caching relies on a 1 second timer, rather than -using Directory Leases, currently only the root file handle is cached longer + using Directory Leases, currently only the root file handle is cached longer d) quota support (needs minor kernel change since quota calls -to make it to network filesystems or deviceless filesystems) + to make it to network filesystems or deviceless filesystems) -e) Additional use cases can be optimized to use "compounding" -(e.g. open/query/close and open/setinfo/close) to reduce the number -of roundtrips to the server and improve performance. Various cases -(stat, statfs, create, unlink, mkdir) already have been improved by -using compounding but more can be done. In addition we could significantly -reduce redundant opens by using deferred close (with handle caching leases) -and better using reference counters on file handles. +e) Additional use cases can be optimized to use "compounding" (e.g. + open/query/close and open/setinfo/close) to reduce the number of + roundtrips to the server and improve performance. Various cases + (stat, statfs, create, unlink, mkdir) already have been improved by + using compounding but more can be done. In addition we could + significantly reduce redundant opens by using deferred close (with + handle caching leases) and better using reference counters on file + handles. f) Finish inotify support so kde and gnome file list windows -will autorefresh (partially complete by Asser). Needs minor kernel -vfs change to support removing D_NOTIFY on a file. + will autorefresh (partially complete by Asser). Needs minor kernel + vfs change to support removing D_NOTIFY on a file. g) Add GUI tool to configure /proc/fs/cifs settings and for display of -the CIFS statistics (started) + the CIFS statistics (started) h) implement support for security and trusted categories of xattrs -(requires minor protocol extension) to enable better support for SELINUX + (requires minor protocol extension) to enable better support for SELINUX i) Add support for tree connect contexts (see MS-SMB2) a new SMB3.1.1 protocol feature (may be especially useful for virtualization). j) Create UID mapping facility so server UIDs can be mapped on a per -mount or a per server basis to client UIDs or nobody if no mapping -exists. Also better integration with winbind for resolving SID owners + mount or a per server basis to client UIDs or nobody if no mapping + exists. Also better integration with winbind for resolving SID owners k) Add tools to take advantage of more smb3 specific ioctls and features -(passthrough ioctl/fsctl is now implemented in cifs.ko to allow sending -various SMB3 fsctls and query info and set info calls directly from user space) -Add tools to make setting various non-POSIX metadata attributes easier -from tools (e.g. extending what was done in smb-info tool). + (passthrough ioctl/fsctl is now implemented in cifs.ko to allow + sending various SMB3 fsctls and query info and set info calls + directly from user space) Add tools to make setting various non-POSIX + metadata attributes easier from tools (e.g. extending what was done + in smb-info tool). l) encrypted file support m) improved stats gathering tools (perhaps integration with nfsometer?) -to extend and make easier to use what is currently in /proc/fs/cifs/Stats + to extend and make easier to use what is currently in /proc/fs/cifs/Stats n) Add support for claims based ACLs ("DAC") @@ -69,57 +76,58 @@ p) Add support for witness protocol (perhaps ioctl to cifs.ko from user space different servers, and the server we are connected to has gone down. q) Allow mount.cifs to be more verbose in reporting errors with dialect -or unsupported feature errors. + or unsupported feature errors. r) updating cifs documentation, and user guide. s) Addressing bugs found by running a broader set of xfstests in standard -file system xfstest suite. + file system xfstest suite. t) split cifs and smb3 support into separate modules so legacy (and less -secure) CIFS dialect can be disabled in environments that don't need it -and simplify the code. + secure) CIFS dialect can be disabled in environments that don't need it + and simplify the code. v) POSIX Extensions for SMB3.1.1 (started, create and mkdir support added -so far). + so far). w) Add support for additional strong encryption types, and additional spnego -authentication mechanisms (see MS-SMB2) + authentication mechanisms (see MS-SMB2) x) Finish support for SMB3.1.1 compression -KNOWN BUGS -==================================== +Known Bugs +========== + See http://bugzilla.samba.org - search on product "CifsVFS" for current bug list. Also check http://bugzilla.kernel.org (Product = File System, Component = CIFS) 1) existing symbolic links (Windows reparse points) are recognized but -can not be created remotely. They are implemented for Samba and those that -support the CIFS Unix extensions, although earlier versions of Samba -overly restrict the pathnames. + can not be created remotely. They are implemented for Samba and those that + support the CIFS Unix extensions, although earlier versions of Samba + overly restrict the pathnames. 2) follow_link and readdir code does not follow dfs junctions -but recognizes them + but recognizes them Misc testing to do ================== 1) check out max path names and max path name components against various server -types. Try nested symlinks (8 deep). Return max path name in stat -f information + types. Try nested symlinks (8 deep). Return max path name in stat -f information 2) Improve xfstest's cifs/smb3 enablement and adapt xfstests where needed to test -cifs/smb3 better + cifs/smb3 better -3) Additional performance testing and optimization using iozone and similar - -there are some easy changes that can be done to parallelize sequential writes, -and when signing is disabled to request larger read sizes (larger than -negotiated size) and send larger write sizes to modern servers. +3) Additional performance testing and optimization using iozone and similar - + there are some easy changes that can be done to parallelize sequential writes, + and when signing is disabled to request larger read sizes (larger than + negotiated size) and send larger write sizes to modern servers. 4) More exhaustively test against less common servers 5) Continue to extend the smb3 "buildbot" which does automated xfstesting -against Windows, Samba and Azure currently - to add additional tests and -to allow the buildbot to execute the tests faster. The URL for the -buildbot is: http://smb3-test-rhel-75.southcentralus.cloudapp.azure.com + against Windows, Samba and Azure currently - to add additional tests and + to allow the buildbot to execute the tests faster. The URL for the + buildbot is: http://smb3-test-rhel-75.southcentralus.cloudapp.azure.com 6) Address various coverity warnings (most are not bugs per-se, but -the more warnings are addressed, the easier it is to spot real -problems that static analyzers will point out in the future). + the more warnings are addressed, the easier it is to spot real + problems that static analyzers will point out in the future). diff --git a/Documentation/filesystems/cifs/README b/Documentation/admin-guide/cifs/usage.rst similarity index 72% rename from Documentation/filesystems/cifs/README rename to Documentation/admin-guide/cifs/usage.rst index 4a804619cff288f55326ef7737616abee3214922..d3fb67b8a976068cad41b37b2b3592576479f686 100644 --- a/Documentation/filesystems/cifs/README +++ b/Documentation/admin-guide/cifs/usage.rst @@ -1,53 +1,61 @@ +===== +Usage +===== + This module supports the SMB3 family of advanced network protocols (as well as older dialects, originally called "CIFS" or SMB1). The CIFS VFS module for Linux supports many advanced network filesystem features such as hierarchical DFS like namespace, hardlinks, locking and more. -It was designed to comply with the SNIA CIFS Technical Reference (which -supersedes the 1992 X/Open SMB Standard) as well as to perform best practice -practical interoperability with Windows 2000, Windows XP, Samba and equivalent +It was designed to comply with the SNIA CIFS Technical Reference (which +supersedes the 1992 X/Open SMB Standard) as well as to perform best practice +practical interoperability with Windows 2000, Windows XP, Samba and equivalent servers. This code was developed in participation with the Protocol Freedom Information Foundation. CIFS and now SMB3 has now become a defacto standard for interoperating between Macs and Windows and major NAS appliances. Please see - MS-SMB2 (for detailed SMB2/SMB3/SMB3.1.1 protocol specification) - http://protocolfreedom.org/ and - http://samba.org/samba/PFIF/ +MS-SMB2 (for detailed SMB2/SMB3/SMB3.1.1 protocol specification) +http://protocolfreedom.org/ and +http://samba.org/samba/PFIF/ for more details. For questions or bug reports please contact: + smfrench@gmail.com See the project page at: https://wiki.samba.org/index.php/LinuxCIFS_utils -Build instructions: +Build instructions ================== + For Linux: + 1) Download the kernel (e.g. from http://www.kernel.org) -and change directory into the top of the kernel directory tree -(e.g. /usr/src/linux-2.5.73) + and change directory into the top of the kernel directory tree + (e.g. /usr/src/linux-2.5.73) 2) make menuconfig (or make xconfig) 3) select cifs from within the network filesystem choices 4) save and exit 5) make -Installation instructions: +Installation instructions ========================= + If you have built the CIFS vfs as module (successfully) simply -type "make modules_install" (or if you prefer, manually copy the file to +type ``make modules_install`` (or if you prefer, manually copy the file to the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.ko). If you have built the CIFS vfs into the kernel itself, follow the instructions for your distribution on how to install a new kernel (usually you -would simply type "make install"). +would simply type ``make install``). If you do not have the utility mount.cifs (in the Samba 4.x source tree and on the CIFS VFS web site) copy it to the same directory in which mount helpers reside (usually /sbin). Although the helper software is not -required, mount.cifs is recommended. Most distros include a "cifs-utils" +required, mount.cifs is recommended. Most distros include a ``cifs-utils`` package that includes this utility so it is recommended to install this. Note that running the Winbind pam/nss module (logon service) on all of your @@ -57,13 +65,16 @@ found at cifs-utils.git on git.samba.org If cifs is built as a module, then the size and number of network buffers and maximum number of simultaneous requests to one server can be configured. -Changing these from their defaults is not recommended. By executing modinfo +Changing these from their defaults is not recommended. By executing modinfo:: + modinfo kernel/fs/cifs/cifs.ko + on kernel/fs/cifs/cifs.ko the list of configuration changes that can be made at module initialization time (by running insmod cifs.ko) can be seen. Recommendations =============== + To improve security the SMB2.1 dialect or later (usually will get SMB3) is now the new default. To use old dialects (e.g. to mount Windows XP) use "vers=1.0" on mount (or vers=2.0 for Windows Vista). Note that the CIFS (vers=1.0) is @@ -72,156 +83,168 @@ many advanced security features such as downgrade attack detection and encrypted shares and stronger signing and authentication algorithms. There are additional mount options that may be helpful for SMB3 to get improved POSIX behavior (NB: can use vers=3.0 to force only SMB3, never 2.1): - "mfsymlinks" and "cifsacl" and "idsfromsid" + + ``mfsymlinks`` and ``cifsacl`` and ``idsfromsid`` Allowing User Mounts ==================== + To permit users to mount and unmount over directories they own is possible with the cifs vfs. A way to enable such mounting is to mark the mount.cifs -utility as suid (e.g. "chmod +s /sbin/mount.cifs). To enable users to +utility as suid (e.g. ``chmod +s /sbin/mount.cifs``). To enable users to umount shares they mount requires + 1) mount.cifs version 1.4 or later 2) an entry for the share in /etc/fstab indicating that a user may -unmount it e.g. -//server/usersharename /mnt/username cifs user 0 0 + unmount it e.g.:: + + //server/usersharename /mnt/username cifs user 0 0 -Note that when the mount.cifs utility is run suid (allowing user mounts), -in order to reduce risks, the "nosuid" mount flag is passed in on mount to +Note that when the mount.cifs utility is run suid (allowing user mounts), +in order to reduce risks, the ``nosuid`` mount flag is passed in on mount to disallow execution of an suid program mounted on the remote target. When mount is executed as root, nosuid is not passed in by default, and execution of suid programs on the remote target would be enabled -by default. This can be changed, as with nfs and other filesystems, -by simply specifying "nosuid" among the mount options. For user mounts -though to be able to pass the suid flag to mount requires rebuilding +by default. This can be changed, as with nfs and other filesystems, +by simply specifying ``nosuid`` among the mount options. For user mounts +though to be able to pass the suid flag to mount requires rebuilding mount.cifs with the following flag: CIFS_ALLOW_USR_SUID There is a corresponding manual page for cifs mounting in the Samba 3.0 and -later source tree in docs/manpages/mount.cifs.8 +later source tree in docs/manpages/mount.cifs.8 Allowing User Unmounts ====================== + To permit users to ummount directories that they have user mounted (see above), -the utility umount.cifs may be used. It may be invoked directly, or if +the utility umount.cifs may be used. It may be invoked directly, or if umount.cifs is placed in /sbin, umount can invoke the cifs umount helper (at least for most versions of the umount utility) for umount of cifs mounts, unless umount is invoked with -i (which will avoid invoking a umount helper). As with mount.cifs, to enable user unmounts umount.cifs must be marked -as suid (e.g. "chmod +s /sbin/umount.cifs") or equivalent (some distributions +as suid (e.g. ``chmod +s /sbin/umount.cifs``) or equivalent (some distributions allow adding entries to a file to the /etc/permissions file to achieve the equivalent suid effect). For this utility to succeed the target path must be a cifs mount, and the uid of the current user must match the uid of the user who mounted the resource. -Also note that the customary way of allowing user mounts and unmounts is +Also note that the customary way of allowing user mounts and unmounts is (instead of using mount.cifs and unmount.cifs as suid) to add a line to the file /etc/fstab for each //server/share you wish to mount, but this can become unwieldy when potential mount targets include many or unpredictable UNC names. -Samba Considerations +Samba Considerations ==================== + Most current servers support SMB2.1 and SMB3 which are more secure, but there are useful protocol extensions for the older less secure CIFS dialect, so to get the maximum benefit if mounting using the older dialect (CIFS/SMB1), we recommend using a server that supports the SNIA CIFS Unix Extensions standard (e.g. almost any version of Samba ie version 2.2.5 or later) but the CIFS vfs works fine with a wide variety of CIFS servers. -Note that uid, gid and file permissions will display default values if you do -not have a server that supports the Unix extensions for CIFS (such as Samba -2.2.5 or later). To enable the Unix CIFS Extensions in the Samba server, add -the line: +Note that uid, gid and file permissions will display default values if you do +not have a server that supports the Unix extensions for CIFS (such as Samba +2.2.5 or later). To enable the Unix CIFS Extensions in the Samba server, add +the line:: unix extensions = yes - -to your smb.conf file on the server. Note that the following smb.conf settings -are also useful (on the Samba server) when the majority of clients are Unix or -Linux: + +to your smb.conf file on the server. Note that the following smb.conf settings +are also useful (on the Samba server) when the majority of clients are Unix or +Linux:: case sensitive = yes - delete readonly = yes + delete readonly = yes ea support = yes Note that server ea support is required for supporting xattrs from the Linux -cifs client, and that EA support is present in later versions of Samba (e.g. +cifs client, and that EA support is present in later versions of Samba (e.g. 3.0.6 and later (also EA support works in all versions of Windows, at least to shares on NTFS filesystems). Extended Attribute (xattr) support is an optional feature of most Linux filesystems which may require enabling via make menuconfig. Client support for extended attributes (user xattr) can be -disabled on a per-mount basis by specifying "nouser_xattr" on mount. +disabled on a per-mount basis by specifying ``nouser_xattr`` on mount. The CIFS client can get and set POSIX ACLs (getfacl, setfacl) to Samba servers -version 3.10 and later. Setting POSIX ACLs requires enabling both XATTR and +version 3.10 and later. Setting POSIX ACLs requires enabling both XATTR and then POSIX support in the CIFS configuration options when building the cifs module. POSIX ACL support can be disabled on a per mount basic by specifying -"noacl" on mount. - -Some administrators may want to change Samba's smb.conf "map archive" and -"create mask" parameters from the default. Unless the create mask is changed +``noacl`` on mount. + +Some administrators may want to change Samba's smb.conf ``map archive`` and +``create mask`` parameters from the default. Unless the create mask is changed newly created files can end up with an unnecessarily restrictive default mode, which may not be what you want, although if the CIFS Unix extensions are enabled on the server and client, subsequent setattr calls (e.g. chmod) can -fix the mode. Note that creating special devices (mknod) remotely -may require specifying a mkdev function to Samba if you are not using +fix the mode. Note that creating special devices (mknod) remotely +may require specifying a mkdev function to Samba if you are not using Samba 3.0.6 or later. For more information on these see the manual pages -("man smb.conf") on the Samba server system. Note that the cifs vfs, -unlike the smbfs vfs, does not read the smb.conf on the client system -(the few optional settings are passed in on mount via -o parameters instead). +(``man smb.conf``) on the Samba server system. Note that the cifs vfs, +unlike the smbfs vfs, does not read the smb.conf on the client system +(the few optional settings are passed in on mount via -o parameters instead). Note that Samba 2.2.7 or later includes a fix that allows the CIFS VFS to delete -open files (required for strict POSIX compliance). Windows Servers already +open files (required for strict POSIX compliance). Windows Servers already supported this feature. Samba server does not allow symlinks that refer to files outside of the share, so in Samba versions prior to 3.0.6, most symlinks to -files with absolute paths (ie beginning with slash) such as: +files with absolute paths (ie beginning with slash) such as:: + ln -s /mnt/foo bar -would be forbidden. Samba 3.0.6 server or later includes the ability to create -such symlinks safely by converting unsafe symlinks (ie symlinks to server + +would be forbidden. Samba 3.0.6 server or later includes the ability to create +such symlinks safely by converting unsafe symlinks (ie symlinks to server files that are outside of the share) to a samba specific format on the server that is ignored by local server applications and non-cifs clients and that will not be traversed by the Samba server). This is opaque to the Linux client application using the cifs vfs. Absolute symlinks will work to Samba 3.0.5 or later, but only for remote clients using the CIFS Unix extensions, and will be invisbile to Windows clients and typically will not affect local -applications running on the same server as Samba. +applications running on the same server as Samba. -Use instructions: +Use instructions ================ -Once the CIFS VFS support is built into the kernel or installed as a module + +Once the CIFS VFS support is built into the kernel or installed as a module (cifs.ko), you can use mount syntax like the following to access Samba or -Mac or Windows servers: +Mac or Windows servers:: mount -t cifs //9.53.216.11/e$ /mnt -o username=myname,password=mypassword Before -o the option -v may be specified to make the mount.cifs -mount helper display the mount steps more verbosely. +mount helper display the mount steps more verbosely. After -o the following commonly used cifs vfs specific options -are supported: +are supported:: username= password= domain= - + Other cifs mount options are described below. Use of TCP names (in addition to ip addresses) is available if the mount helper (mount.cifs) is installed. If you do not trust the server to which are mounted, or if you do not have cifs signing enabled (and the physical network is insecure), consider use -of the standard mount options "noexec" and "nosuid" to reduce the risk of +of the standard mount options ``noexec`` and ``nosuid`` to reduce the risk of running an altered binary on your local system (downloaded from a hostile server or altered by a hostile router). Although mounting using format corresponding to the CIFS URL specification is not possible in mount.cifs yet, it is possible to use an alternate format for the server and sharename (which is somewhat similar to NFS style mount -syntax) instead of the more widely used UNC format (i.e. \\server\share): +syntax) instead of the more widely used UNC format (i.e. \\server\share):: + mount -t cifs tcp_name_of_server:share_name /mnt -o user=myname,pass=mypasswd When using the mount helper mount.cifs, passwords may be specified via alternate -mechanisms, instead of specifying it after -o using the normal "pass=" syntax +mechanisms, instead of specifying it after -o using the normal ``pass=`` syntax on the command line: 1) By including it in a credential file. Specify credentials=filename as one -of the mount options. Credential files contain two lines - username=someuser - password=your_password +of the mount options. Credential files contain two lines:: + + username=someuser + password=your_password + 2) By specifying the password in the PASSWD environment variable (similarly -the user name can be taken from the USER environment variable). + the user name can be taken from the USER environment variable). 3) By specifying the password in a file by name via PASSWD_FILE 4) By specifying the password in a file by file descriptor via PASSWD_FD @@ -229,39 +252,47 @@ If no password is provided, mount.cifs will prompt for password entry Restrictions ============ -Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC -1001/1002 support for "Netbios-Over-TCP/IP." This is not likely to be a + +Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC +1001/1002 support for "Netbios-Over-TCP/IP." This is not likely to be a problem as most servers support this. Valid filenames differ between Windows and Linux. Windows typically restricts -filenames which contain certain reserved characters (e.g.the character : +filenames which contain certain reserved characters (e.g.the character : which is used to delimit the beginning of a stream name by Windows), while Linux allows a slightly wider set of valid characters in filenames. Windows servers can remap such characters when an explicit mapping is specified in -the Server's registry. Samba starting with version 3.10 will allow such +the Server's registry. Samba starting with version 3.10 will allow such filenames (ie those which contain valid Linux characters, which normally would be forbidden for Windows/CIFS semantics) as long as the server is configured for Unix Extensions (and the client has not disabled /proc/fs/cifs/LinuxExtensionsEnabled). In addition the mount option -"mapposix" can be used on CIFS (vers=1.0) to force the mapping of +``mapposix`` can be used on CIFS (vers=1.0) to force the mapping of illegal Windows/NTFS/SMB characters to a remap range (this mount parm -is the default for SMB3). This remap ("mapposix") range is also +is the default for SMB3). This remap (``mapposix``) range is also compatible with Mac (and "Services for Mac" on some older Windows). CIFS VFS Mount Options ====================== A partial list of the supported mount options follows: - username The user name to use when trying to establish + + username + The user name to use when trying to establish the CIFS session. - password The user password. If the mount helper is + password + The user password. If the mount helper is installed, the user will be prompted for password if not supplied. - ip The ip address of the target server - unc The target server Universal Network Name (export) to - mount. - domain Set the SMB/CIFS workgroup name prepended to the + ip + The ip address of the target server + unc + The target server Universal Network Name (export) to + mount. + domain + Set the SMB/CIFS workgroup name prepended to the username during CIFS session establishment - forceuid Set the default uid for inodes to the uid + forceuid + Set the default uid for inodes to the uid passed in on mount. For mounts to servers which do support the CIFS Unix extensions, such as a properly configured Samba server, the server provides @@ -276,32 +307,39 @@ A partial list of the supported mount options follows: extensions, the default uid (and gid) returned on lookup of existing files will be the uid (gid) of the person who executed the mount (root, except when mount.cifs - is configured setuid for user mounts) unless the "uid=" + is configured setuid for user mounts) unless the ``uid=`` (gid) mount option is specified. Also note that permission checks (authorization checks) on accesses to a file occur at the server, but there are cases in which an administrator may want to restrict at the client as well. For those servers which do not report a uid/gid owner (such as Windows), permissions can also be checked at the - client, and a crude form of client side permission checking - can be enabled by specifying file_mode and dir_mode on + client, and a crude form of client side permission checking + can be enabled by specifying file_mode and dir_mode on the client. (default) - forcegid (similar to above but for the groupid instead of uid) (default) - noforceuid Fill in file owner information (uid) by requesting it from + forcegid + (similar to above but for the groupid instead of uid) (default) + noforceuid + Fill in file owner information (uid) by requesting it from the server if possible. With this option, the value given in the uid= option (on mount) will only be used if the server can not support returning uids on inodes. - noforcegid (similar to above but for the group owner, gid, instead of uid) - uid Set the default uid for inodes, and indicate to the + noforcegid + (similar to above but for the group owner, gid, instead of uid) + uid + Set the default uid for inodes, and indicate to the cifs kernel driver which local user mounted. If the server supports the unix extensions the default uid is not used to fill in the owner fields of inodes (files) - unless the "forceuid" parameter is specified. - gid Set the default gid for inodes (similar to above). - file_mode If CIFS Unix extensions are not supported by the server + unless the ``forceuid`` parameter is specified. + gid + Set the default gid for inodes (similar to above). + file_mode + If CIFS Unix extensions are not supported by the server this overrides the default mode for file inodes. - fsc Enable local disk caching using FS-Cache (off by default). This - option could be useful to improve performance on a slow link, + fsc + Enable local disk caching using FS-Cache (off by default). This + option could be useful to improve performance on a slow link, heavily loaded server and/or network where reading from the disk is faster than reading from the server (over the network). This could also impact scalability positively as the @@ -310,18 +348,22 @@ A partial list of the supported mount options follows: type workloads. So, you need to consider carefully your workload/scenario before using this option. Currently, local disk caching is functional for CIFS files opened as read-only. - dir_mode If CIFS Unix extensions are not supported by the server + dir_mode + If CIFS Unix extensions are not supported by the server this overrides the default mode for directory inodes. - port attempt to contact the server on this tcp port, before + port + attempt to contact the server on this tcp port, before trying the usual ports (port 445, then 139). - iocharset Codepage used to convert local path names to and from + iocharset + Codepage used to convert local path names to and from Unicode. Unicode is used by default for network path names if the server supports it. If iocharset is not specified then the nls_default specified during the local client kernel build will be used. If server does not support Unicode, this parameter is unused. - rsize default read size (usually 16K). The client currently + rsize + default read size (usually 16K). The client currently can not use rsize larger than CIFSMaxBufSize. CIFSMaxBufSize defaults to 16K and may be changed (from 8K to the maximum kmalloc size allowed by your kernel) at module install time @@ -333,10 +375,12 @@ A partial list of the supported mount options follows: newer servers (e.g. Samba 3.0.26 or later) do. rsize can be set from a minimum of 2048 to a maximum of 130048 (127K or CIFSMaxBufSize, whichever is smaller) - wsize default write size (default 57344) + wsize + default write size (default 57344) maximum wsize currently allowed by CIFS is 57344 (fourteen 4096 byte pages) - actimeo=n attribute cache timeout in seconds (default 1 second). + actimeo=n + attribute cache timeout in seconds (default 1 second). After this timeout, the cifs client requests fresh attribute information from the server. This option allows to tune the attribute cache timeout to suit the workload needs. Shorter @@ -345,49 +389,67 @@ A partial list of the supported mount options follows: of calls to the server at the expense of less stricter cache coherency checks (i.e. incorrect attribute cache for a short period of time). - rw mount the network share read-write (note that the + rw + mount the network share read-write (note that the server may still consider the share read-only) - ro mount network share read-only - version used to distinguish different versions of the + ro + mount network share read-only + version + used to distinguish different versions of the mount helper utility (not typically needed) - sep if first mount option (after the -o), overrides + sep + if first mount option (after the -o), overrides the comma as the separator between the mount - parms. e.g. + parms. e.g.:: + -o user=myname,password=mypassword,domain=mydom - could be passed instead with period as the separator by + + could be passed instead with period as the separator by:: + -o sep=.user=myname.password=mypassword.domain=mydom + this might be useful when comma is contained within username or password or domain. This option is less important when the cifs mount helper cifs.mount (version 1.1 or later) is used. - nosuid Do not allow remote executables with the suid bit + nosuid + Do not allow remote executables with the suid bit program to be executed. This is only meaningful for mounts to servers such as Samba which support the CIFS Unix Extensions. If you do not trust the servers in your network (your mount targets) it is recommended that you specify this option for greater security. - exec Permit execution of binaries on the mount. - noexec Do not permit execution of binaries on the mount. - dev Recognize block devices on the remote mount. - nodev Do not recognize devices on the remote mount. - suid Allow remote files on this mountpoint with suid enabled to + exec + Permit execution of binaries on the mount. + noexec + Do not permit execution of binaries on the mount. + dev + Recognize block devices on the remote mount. + nodev + Do not recognize devices on the remote mount. + suid + Allow remote files on this mountpoint with suid enabled to be executed (default for mounts when executed as root, nosuid is default for user mounts). - credentials Although ignored by the cifs kernel component, it is used by + credentials + Although ignored by the cifs kernel component, it is used by the mount helper, mount.cifs. When mount.cifs is installed it - opens and reads the credential file specified in order + opens and reads the credential file specified in order to obtain the userid and password arguments which are passed to the cifs vfs. - guest Although ignored by the kernel component, the mount.cifs + guest + Although ignored by the kernel component, the mount.cifs mount helper will not prompt the user for a password if guest is specified on the mount options. If no password is specified a null password will be used. - perm Client does permission checks (vfs_permission check of uid + perm + Client does permission checks (vfs_permission check of uid and gid of the file against the mode and desired operation), Note that this is in addition to the normal ACL check on the - target machine done by the server software. + target machine done by the server software. Client permission checking is enabled by default. - noperm Client does not do permission checks. This can expose + noperm + Client does not do permission checks. This can expose files on this mount to access by other users on the local client system. It is typically only needed when the server supports the CIFS Unix Extensions but the UIDs/GIDs on the @@ -399,7 +461,8 @@ A partial list of the supported mount options follows: Note that this does not affect the normal ACL check on the target machine done by the server software (of the server ACL against the user name provided at mount time). - serverino Use server's inode numbers instead of generating automatically + serverino + Use server's inode numbers instead of generating automatically incrementing inode numbers on the client. Although this will make it easier to spot hardlinked files (as they will have the same inode numbers) and inode numbers may be persistent, @@ -412,14 +475,16 @@ A partial list of the supported mount options follows: or the CIFS Unix Extensions equivalent and for those this mount option will have no effect. Exporting cifs mounts under nfsd requires this mount option on the cifs mount. - This is now the default if server supports the + This is now the default if server supports the required network operation. - noserverino Client generates inode numbers (rather than using the actual one + noserverino + Client generates inode numbers (rather than using the actual one from the server). These inode numbers will vary after unmount or reboot which can confuse some applications, but not all server filesystems support unique inode numbers. - setuids If the CIFS Unix extensions are negotiated with the server + setuids + If the CIFS Unix extensions are negotiated with the server the client will attempt to set the effective uid and gid of the local process on newly created files, directories, and devices (create, mkdir, mknod). If the CIFS Unix Extensions @@ -427,9 +492,10 @@ A partial list of the supported mount options follows: instead of using the default uid and gid specified on the mount, cache the new file's uid and gid locally which means that the uid for the file can change when the inode is - reloaded (or the user remounts the share). - nosetuids The client will not attempt to set the uid and gid on - on newly created files, directories, and devices (create, + reloaded (or the user remounts the share). + nosetuids + The client will not attempt to set the uid and gid on + on newly created files, directories, and devices (create, mkdir, mknod) which will result in the server setting the uid and gid to the default (usually the server uid of the user who mounted the share). Letting the server (rather than @@ -437,38 +503,49 @@ A partial list of the supported mount options follows: Unix Extensions are not negotiated then the uid and gid for new files will appear to be the uid (gid) of the mounter or the uid (gid) parameter specified on the mount. - netbiosname When mounting to servers via port 139, specifies the RFC1001 - source name to use to represent the client netbios machine + netbiosname + When mounting to servers via port 139, specifies the RFC1001 + source name to use to represent the client netbios machine name when doing the RFC1001 netbios session initialize. - direct Do not do inode data caching on files opened on this mount. + direct + Do not do inode data caching on files opened on this mount. This precludes mmapping files on this mount. In some cases with fast networks and little or no caching benefits on the client (e.g. when the application is doing large sequential - reads bigger than page size without rereading the same data) + reads bigger than page size without rereading the same data) this can provide better performance than the default - behavior which caches reads (readahead) and writes - (writebehind) through the local Linux client pagecache + behavior which caches reads (readahead) and writes + (writebehind) through the local Linux client pagecache if oplock (caching token) is granted and held. Note that direct allows write operations larger than page size to be sent to the server. - strictcache Use for switching on strict cache mode. In this mode the + strictcache + Use for switching on strict cache mode. In this mode the client read from the cache all the time it has Oplock Level II, otherwise - read from the server. All written data are stored in the cache, but if the client doesn't have Exclusive Oplock, it writes the data to the server. - rwpidforward Forward pid of a process who opened a file to any read or write + rwpidforward + Forward pid of a process who opened a file to any read or write operation on that file. This prevent applications like WINE from failing on read and write if we use mandatory brlock style. - acl Allow setfacl and getfacl to manage posix ACLs if server + acl + Allow setfacl and getfacl to manage posix ACLs if server supports them. (default) - noacl Do not allow setfacl and getfacl calls on this mount - user_xattr Allow getting and setting user xattrs (those attributes whose - name begins with "user." or "os2.") as OS/2 EAs (extended + noacl + Do not allow setfacl and getfacl calls on this mount + user_xattr + Allow getting and setting user xattrs (those attributes whose + name begins with ``user.`` or ``os2.``) as OS/2 EAs (extended attributes) to the server. This allows support of the setfattr and getfattr utilities. (default) - nouser_xattr Do not allow getfattr/setfattr to get/set/list xattrs - mapchars Translate six of the seven reserved characters (not backslash) + nouser_xattr + Do not allow getfattr/setfattr to get/set/list xattrs + mapchars + Translate six of the seven reserved characters (not backslash):: + *?<>|: + to the remap range (above 0xF000), which also allows the CIFS client to recognize files created with such characters by Windows's POSIX emulation. This can @@ -477,39 +554,47 @@ A partial list of the supported mount options follows: whose names contain any of these seven characters). This has no effect if the server does not support Unicode on the wire. - nomapchars Do not translate any of these seven characters (default). - nocase Request case insensitive path name matching (case + nomapchars + Do not translate any of these seven characters (default). + nocase + Request case insensitive path name matching (case sensitive is the default if the server supports it). - (mount option "ignorecase" is identical to "nocase") - posixpaths If CIFS Unix extensions are supported, attempt to + (mount option ``ignorecase`` is identical to ``nocase``) + posixpaths + If CIFS Unix extensions are supported, attempt to negotiate posix path name support which allows certain characters forbidden in typical CIFS filenames, without requiring remapping. (default) - noposixpaths If CIFS Unix extensions are supported, do not request + noposixpaths + If CIFS Unix extensions are supported, do not request posix path name support (this may cause servers to reject creatingfile with certain reserved characters). - nounix Disable the CIFS Unix Extensions for this mount (tree + nounix + Disable the CIFS Unix Extensions for this mount (tree connection). This is rarely needed, but it may be useful in order to turn off multiple settings all at once (ie posix acls, posix locks, posix paths, symlink support and retrieving uids/gids/mode from the server) or to work around a bug in server which implement the Unix Extensions. - nobrl Do not send byte range lock requests to the server. + nobrl + Do not send byte range lock requests to the server. This is necessary for certain applications that break with cifs style mandatory byte range locks (and most cifs servers do not yet support requesting advisory byte range locks). - forcemandatorylock Even if the server supports posix (advisory) byte range + forcemandatorylock + Even if the server supports posix (advisory) byte range locking, send only mandatory lock requests. For some (presumably rare) applications, originally coded for DOS/Windows, which require Windows style mandatory byte range locking, they may be able to take advantage of this option, forcing the cifs client to only send mandatory locks even if the cifs server would support posix advisory locks. - "forcemand" is accepted as a shorter form of this mount + ``forcemand`` is accepted as a shorter form of this mount option. - nostrictsync If this mount option is set, when an application does an + nostrictsync + If this mount option is set, when an application does an fsync call then the cifs client does not send an SMB Flush to the server (to force the server to write all dirty data for this file immediately to disk), although cifs still sends @@ -522,41 +607,50 @@ A partial list of the supported mount options follows: crash. If this mount option is not set, by default cifs will send an SMB flush request (and wait for a response) on every fsync call. - nodfs Disable DFS (global name space support) even if the + nodfs + Disable DFS (global name space support) even if the server claims to support it. This can help work around a problem with parsing of DFS paths with Samba server versions 3.0.24 and 3.0.25. - remount remount the share (often used to change from ro to rw mounts - or vice versa) - cifsacl Report mode bits (e.g. on stat) based on the Windows ACL for - the file. (EXPERIMENTAL) - servern Specify the server 's netbios name (RFC1001 name) to use - when attempting to setup a session to the server. + remount + remount the share (often used to change from ro to rw mounts + or vice versa) + cifsacl + Report mode bits (e.g. on stat) based on the Windows ACL for + the file. (EXPERIMENTAL) + servern + Specify the server 's netbios name (RFC1001 name) to use + when attempting to setup a session to the server. This is needed for mounting to some older servers (such as OS/2 or Windows 98 and Windows ME) since they do not support a default server name. A server name can be up to 15 characters long and is usually uppercased. - sfu When the CIFS Unix Extensions are not negotiated, attempt to + sfu + When the CIFS Unix Extensions are not negotiated, attempt to create device files and fifos in a format compatible with Services for Unix (SFU). In addition retrieve bits 10-12 of the mode via the SETFILEBITS extended attribute (as SFU does). In the future the bottom 9 bits of the mode also will be emulated using queries of the security descriptor (ACL). - mfsymlinks Enable support for Minshall+French symlinks + mfsymlinks + Enable support for Minshall+French symlinks (see http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks) This option is ignored when specified together with the 'sfu' option. Minshall+French symlinks are used even if the server supports the CIFS Unix Extensions. - sign Must use packet signing (helps avoid unwanted data modification + sign + Must use packet signing (helps avoid unwanted data modification by intermediate systems in the route). Note that signing does not work with lanman or plaintext authentication. - seal Must seal (encrypt) all data on this mounted share before + seal + Must seal (encrypt) all data on this mounted share before sending on the network. Requires support for Unix Extensions. Note that this differs from the sign mount option in that it causes encryption of data sent over this mounted share but other shares mounted to the same server are unaffected. - locallease This option is rarely needed. Fcntl F_SETLEASE is + locallease + This option is rarely needed. Fcntl F_SETLEASE is used by some applications such as Samba and NFSv4 server to check to see whether a file is cacheable. CIFS has no way to explicitly request a lease, but can check whether a file @@ -569,51 +663,73 @@ A partial list of the supported mount options follows: will allow the cifs client to check for leases (only) locally for files which are not oplocked instead of denying leases in that case. (EXPERIMENTAL) - sec Security mode. Allowed values are: - none attempt to connection as a null user (no name) - krb5 Use Kerberos version 5 authentication - krb5i Use Kerberos authentication and packet signing - ntlm Use NTLM password hashing (default) - ntlmi Use NTLM password hashing with signing (if + sec + Security mode. Allowed values are: + + none + attempt to connection as a null user (no name) + krb5 + Use Kerberos version 5 authentication + krb5i + Use Kerberos authentication and packet signing + ntlm + Use NTLM password hashing (default) + ntlmi + Use NTLM password hashing with signing (if /proc/fs/cifs/PacketSigningEnabled on or if - server requires signing also can be the default) - ntlmv2 Use NTLMv2 password hashing - ntlmv2i Use NTLMv2 password hashing with packet signing - lanman (if configured in kernel config) use older + server requires signing also can be the default) + ntlmv2 + Use NTLMv2 password hashing + ntlmv2i + Use NTLMv2 password hashing with packet signing + lanman + (if configured in kernel config) use older lanman hash -hard Retry file operations if server is not responding -soft Limit retries to unresponsive servers (usually only + hard + Retry file operations if server is not responding + soft + Limit retries to unresponsive servers (usually only one retry) before returning an error. (default) The mount.cifs mount helper also accepts a few mount options before -o including: +=============== =============================================================== -S take password from stdin (equivalent to setting the environment - variable "PASSWD_FD=0" + variable ``PASSWD_FD=0`` -V print mount.cifs version -? display simple usage information +=============== =============================================================== With most 2.6 kernel versions of modutils, the version of the cifs kernel module can be displayed via modinfo. Misc /proc/fs/cifs Flags and Debug Info ======================================= + Informational pseudo-files: + +======================= ======================================================= DebugData Displays information about active CIFS sessions and shares, features enabled as well as the cifs.ko version. Stats Lists summary resource usage information as well as per share statistics. +======================= ======================================================= Configuration pseudo-files: + +======================= ======================================================= SecurityFlags Flags which control security negotiation and also packet signing. Authentication (may/must) flags (e.g. for NTLM and/or NTLMv2) may be combined with the signing flags. Specifying two different password - hashing mechanisms (as "must use") on the other hand - does not make much sense. Default flags are - 0x07007 - (NTLM, NTLMv2 and packet signing allowed). The maximum + hashing mechanisms (as "must use") on the other hand + does not make much sense. Default flags are:: + + 0x07007 + + (NTLM, NTLMv2 and packet signing allowed). The maximum allowable flags if you want to allow mounts to servers using weaker password hashes is 0x37037 (lanman, plaintext, ntlm, ntlmv2, signing allowed). Some @@ -626,21 +742,21 @@ SecurityFlags Flags which control security negotiation and laintext passwords using the older lanman dialect form of the session setup SMB. (e.g. for authentication using plain text passwords, set the SecurityFlags - to 0x30030): - - may use packet signing 0x00001 - must use packet signing 0x01001 - may use NTLM (most common password hash) 0x00002 - must use NTLM 0x02002 - may use NTLMv2 0x00004 - must use NTLMv2 0x04004 - may use Kerberos security 0x00008 - must use Kerberos 0x08008 - may use lanman (weak) password hash 0x00010 - must use lanman password hash 0x10010 - may use plaintext passwords 0x00020 - must use plaintext passwords 0x20020 - (reserved for future packet encryption) 0x00040 + to 0x30030):: + + may use packet signing 0x00001 + must use packet signing 0x01001 + may use NTLM (most common password hash) 0x00002 + must use NTLM 0x02002 + may use NTLMv2 0x00004 + must use NTLMv2 0x04004 + may use Kerberos security 0x00008 + must use Kerberos 0x08008 + may use lanman (weak) password hash 0x00010 + must use lanman password hash 0x10010 + may use plaintext passwords 0x00020 + must use plaintext passwords 0x20020 + (reserved for future packet encryption) 0x00040 cifsFYI If set to non-zero value, additional debug information will be logged to the system error log. This field @@ -650,14 +766,19 @@ cifsFYI If set to non-zero value, additional debug information Some debugging statements are not compiled into the cifs kernel unless CONFIG_CIFS_DEBUG2 is enabled in the kernel configuration. cifsFYI may be set to one or - nore of the following flags (7 sets them all): - - log cifs informational messages 0x01 - log return codes from cifs entry points 0x02 - log slow responses (ie which take longer than 1 second) - CONFIG_CIFS_STATS2 must be enabled in .config 0x04 - - + nore of the following flags (7 sets them all):: + + +-----------------------------------------------+------+ + | log cifs informational messages | 0x01 | + +-----------------------------------------------+------+ + | log return codes from cifs entry points | 0x02 | + +-----------------------------------------------+------+ + | log slow responses | 0x04 | + | (ie which take longer than 1 second) | | + | | | + | CONFIG_CIFS_STATS2 must be enabled in .config | | + +-----------------------------------------------+------+ + traceSMB If set to one, debug information is logged to the system error log with the start of smb requests and responses (default 0) @@ -671,24 +792,25 @@ LinuxExtensionsEnabled If set to one then the client will attempt to as support symbolic links. If you use servers such as Samba that support the CIFS Unix extensions but do not want to use symbolic link - support and want to map the uid and gid fields - to values supplied at mount (rather than the + 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) +======================= ======================================================= -These experimental features and tracing can be enabled by changing flags in -/proc/fs/cifs (after the cifs module has been installed or built into the -kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable -tracing to the kernel message log type: +These experimental features and tracing can be enabled by changing flags in +/proc/fs/cifs (after the cifs module has been installed or built into the +kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable +tracing to the kernel message log type:: echo 7 > /proc/fs/cifs/cifsFYI - + cifsFYI functions as a bit mask. Setting it to 1 enables additional kernel logging of various informational messages. 2 enables logging of non-zero SMB return codes while 4 enables logging of requests that take longer -than one second to complete (except for byte range lock requests). +than one second to complete (except for byte range lock requests). Setting it to 4 requires CONFIG_CIFS_STATS2 to be set in kernel configuration (.config). Setting it to seven enables all three. Finally, tracing -the start of smb requests and responses can be enabled via: +the start of smb requests and responses can be enabled via:: echo 1 > /proc/fs/cifs/traceSMB @@ -700,10 +822,10 @@ server) SMB3 (or cifs) requests grouped by request type (read, write, close etc. Also recorded is the total bytes read and bytes written to the server for that share. Note that due to client caching effects this can be less than the number of bytes read and written by the application running on the client. -Statistics can be reset to zero by "echo 0 > /proc/fs/cifs/Stats" which may be +Statistics can be reset to zero by ``echo 0 > /proc/fs/cifs/Stats`` which may be useful if comparing performance of two different scenarios. - -Also note that "cat /proc/fs/cifs/DebugData" will display information about + +Also note that ``cat /proc/fs/cifs/DebugData`` will display information about the active sessions and the shares that are mounted. Enabling Kerberos (extended security) works but requires version 1.2 or later @@ -725,19 +847,23 @@ space to ease network configuration and improve reliability. To use cifs Kerberos and DFS support, the Linux keyutils package should be installed and something like the following lines should be added to the -/etc/request-key.conf file: +/etc/request-key.conf file:: -create cifs.spnego * * /usr/local/sbin/cifs.upcall %k -create dns_resolver * * /usr/local/sbin/cifs.upcall %k + create cifs.spnego * * /usr/local/sbin/cifs.upcall %k + create dns_resolver * * /usr/local/sbin/cifs.upcall %k CIFS kernel module parameters ============================= These module parameters can be specified or modified either during the time of -module loading or during the runtime by using the interface +module loading or during the runtime by using the interface:: + /proc/module/cifs/parameters/ -i.e. echo "value" > /sys/module/cifs/parameters/ +i.e.:: -1. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default. - [Y/y/1]. To disable use any of [N/n/0]. + echo "value" > /sys/module/cifs/parameters/ +================= ========================================================== +1. enable_oplocks Enable or disable oplocks. Oplocks are enabled by default. + [Y/y/1]. To disable use any of [N/n/0]. +================= ========================================================== diff --git a/Documentation/filesystems/cifs/winucase_convert.pl b/Documentation/admin-guide/cifs/winucase_convert.pl similarity index 100% rename from Documentation/filesystems/cifs/winucase_convert.pl rename to Documentation/admin-guide/cifs/winucase_convert.pl diff --git a/Documentation/admin-guide/devices.txt b/Documentation/admin-guide/devices.txt index e56e00655153a7ac3ebef87c3d4cd85f0aa56961..1c5d2281efc9744df8427f34b99cb6b3883877c4 100644 --- a/Documentation/admin-guide/devices.txt +++ b/Documentation/admin-guide/devices.txt @@ -1647,8 +1647,17 @@ 0 = /dev/comedi0 First comedi device 1 = /dev/comedi1 Second comedi device ... + 47 = /dev/comedi47 48th comedi device - See http://stm.lbl.gov/comedi. + Minors 48 to 255 are reserved for comedi subdevices with + pathnames of the form "/dev/comediX_subdY", where "X" is the + minor number of the associated comedi device and "Y" is the + subdevice number. These subdevice minors are assigned + dynamically, so there is no fixed mapping from subdevice + pathnames to minor numbers. + + See http://www.comedi.org/ for information about the Comedi + project. 98 block User-mode virtual block device 0 = /dev/ubda First user-mode block device diff --git a/Documentation/admin-guide/index.rst b/Documentation/admin-guide/index.rst index 33feab2f40840c426f55a545c14ede4e6a079b5c..34cc20ee7f3a3b2bb4fc5c342ebbcc0cd7bfa029 100644 --- a/Documentation/admin-guide/index.rst +++ b/Documentation/admin-guide/index.rst @@ -77,7 +77,10 @@ configure specific aspects of kernel behavior to your liking. blockdev/index ext4 binderfs + cifs/index xfs + jfs + ufs pm/index thunderbolt LSM/index @@ -98,6 +101,7 @@ configure specific aspects of kernel behavior to your liking. iostats kernel-per-CPU-kthreads laptops/index + auxdisplay/index lcd-panel-cgram ldm lockup-watchdogs @@ -105,6 +109,7 @@ configure specific aspects of kernel behavior to your liking. pnp rtc svga + wimax/index video-output .. only:: subproject and html diff --git a/Documentation/filesystems/jfs.txt b/Documentation/admin-guide/jfs.rst similarity index 51% rename from Documentation/filesystems/jfs.txt rename to Documentation/admin-guide/jfs.rst index 41fd757997b3cc13199e72571cb70512f0db3cdd..9e12d936bc9059a098b461d06a68bc40fdb6e9a7 100644 --- a/Documentation/filesystems/jfs.txt +++ b/Documentation/admin-guide/jfs.rst @@ -1,45 +1,59 @@ +=========================================== IBM's Journaled File System (JFS) for Linux +=========================================== JFS Homepage: http://jfs.sourceforge.net/ The following mount options are supported: + (*) == default -iocharset=name Character set to use for converting from Unicode to +iocharset=name + Character set to use for converting from Unicode to ASCII. The default is to do no conversion. Use iocharset=utf8 for UTF-8 translations. This requires CONFIG_NLS_UTF8 to be set in the kernel .config file. iocharset=none specifies the default behavior explicitly. -resize=value Resize the volume to blocks. JFS only supports +resize=value + Resize the volume to blocks. JFS only supports growing a volume, not shrinking it. This option is only valid during a remount, when the volume is mounted read-write. The resize keyword with no value will grow the volume to the full size of the partition. -nointegrity Do not write to the journal. The primary use of this option +nointegrity + Do not write to the journal. The primary use of this option is to allow for higher performance when restoring a volume from backup media. The integrity of the volume is not guaranteed if the system abnormally abends. -integrity(*) Commit metadata changes to the journal. Use this option to +integrity(*) + Commit metadata changes to the journal. Use this option to remount a volume where the nointegrity option was previously specified in order to restore normal behavior. -errors=continue Keep going on a filesystem error. -errors=remount-ro(*) Remount the filesystem read-only on an error. -errors=panic Panic and halt the machine if an error occurs. +errors=continue + Keep going on a filesystem error. +errors=remount-ro(*) + Remount the filesystem read-only on an error. +errors=panic + Panic and halt the machine if an error occurs. -uid=value Override on-disk uid with specified value -gid=value Override on-disk gid with specified value -umask=value Override on-disk umask with specified octal value. For - directories, the execute bit will be set if the corresponding +uid=value + Override on-disk uid with specified value +gid=value + Override on-disk gid with specified value +umask=value + Override on-disk umask with specified octal value. For + directories, the execute bit will be set if the corresponding read bit is set. -discard=minlen This enables/disables the use of discard/TRIM commands. -discard The discard/TRIM commands are sent to the underlying -nodiscard(*) block device when blocks are freed. This is useful for SSD - devices and sparse/thinly-provisioned LUNs. The FITRIM ioctl +discard=minlen, discard/nodiscard(*) + This enables/disables the use of discard/TRIM commands. + The discard/TRIM commands are sent to the underlying + block device when blocks are freed. This is useful for SSD + devices and sparse/thinly-provisioned LUNs. The FITRIM ioctl command is also available together with the nodiscard option. The value of minlen specifies the minimum blockcount, when a TRIM command to the block device is considered useful. diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 4c1971960afa30484cfe0d2533e9cf28d003662c..782e9072407b94f6f39d4135c5adc361b622d45b 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1044,6 +1044,10 @@ specified address. The serial port must already be setup and configured. Options are not yet supported. + sbi + Use RISC-V SBI (Supervisor Binary Interface) for early + console. + smh Use ARM semihosting calls for early console. s3c2410, @@ -1090,6 +1094,12 @@ the framebuffer, pass the 'ram' option so that it is mapped with the correct attributes. + linflex, + Use early console provided by Freescale LinFlex UART + serial driver for NXP S32V234 SoCs. A valid base + address must be provided, and the serial port must + already be setup and configured. + earlyprintk= [X86,SH,ARM,M68k,S390] earlyprintk=vga earlyprintk=sclp @@ -1197,12 +1207,6 @@ See comment before function elanfreq_setup() in arch/x86/kernel/cpu/cpufreq/elanfreq.c. - elevator= [IOSCHED] - Format: { "mq-deadline" | "kyber" | "bfq" } - See Documentation/block/deadline-iosched.rst, - Documentation/block/kyber-iosched.rst and - Documentation/block/bfq-iosched.rst for details. - elfcorehdr=[size[KMG]@]offset[KMG] [IA64,PPC,SH,X86,S390] Specifies physical address of start of kernel core image elf header and optionally the size. Generally @@ -1732,6 +1736,11 @@ Note that using this option lowers the security provided by tboot because it makes the system vulnerable to DMA attacks. + nobounce [Default off] + Disable bounce buffer for unstrusted devices such as + the Thunderbolt devices. This will treat the untrusted + devices as the trusted ones, hence might expose security + risks of DMA attacks. intel_idle.max_cstate= [KNL,HW,ACPI,X86] 0 disables intel_idle and fall back on acpi_idle. @@ -1811,7 +1820,7 @@ synchronously. iommu.passthrough= - [ARM64] Configure DMA to bypass the IOMMU by default. + [ARM64, X86] Configure DMA to bypass the IOMMU by default. Format: { "0" | "1" } 0 - Use IOMMU translation for DMA. 1 - Bypass the IOMMU for DMA. @@ -2373,7 +2382,7 @@ machvec= [IA-64] Force the use of a particular machine-vector (machvec) in a generic kernel. - Example: machvec=hpzx1_swiotlb + Example: machvec=hpzx1 machtype= [Loongson] Share the same kernel image file between different yeeloong laptop. @@ -3837,12 +3846,13 @@ RCU_BOOST is not set, valid values are 0-99 and the default is zero (non-realtime operation). - rcutree.rcu_nocb_leader_stride= [KNL] - Set the number of NOCB kthread groups, which - defaults to the square root of the number of - CPUs. Larger numbers reduces the wakeup overhead - on the per-CPU grace-period kthreads, but increases - that same overhead on each group's leader. + rcutree.rcu_nocb_gp_stride= [KNL] + Set the number of NOCB callback kthreads in + each group, which defaults to the square root + of the number of CPUs. Larger numbers reduce + the wakeup overhead on the global grace-period + kthread, but increases that same overhead on + each group's NOCB grace-period kthread. rcutree.qhimark= [KNL] Set threshold of queued RCU callbacks beyond which @@ -4047,6 +4057,10 @@ rcutorture.verbose= [KNL] Enable additional printk() statements. + rcupdate.rcu_cpu_stall_ftrace_dump= [KNL] + Dump ftrace buffer after reporting RCU CPU + stall warning. + rcupdate.rcu_cpu_stall_suppress= [KNL] Suppress RCU CPU stall warning messages. diff --git a/Documentation/admin-guide/kernel-per-CPU-kthreads.rst b/Documentation/admin-guide/kernel-per-CPU-kthreads.rst index 4f18456dd3b19942ae3c22567729e9b6a70faf3c..baeeba8762ae4325be2eec70af80f36b50a56b45 100644 --- a/Documentation/admin-guide/kernel-per-CPU-kthreads.rst +++ b/Documentation/admin-guide/kernel-per-CPU-kthreads.rst @@ -274,9 +274,7 @@ To reduce its OS jitter, do any of the following: (based on an earlier one from Gilad Ben-Yossef) that reduces or even eliminates vmstat overhead for some workloads at https://lkml.org/lkml/2013/9/4/379. - e. Boot with "elevator=noop" to avoid workqueue use by - the block layer. - f. If running on high-end powerpc servers, build with + e. If running on high-end powerpc servers, build with CONFIG_PPC_RTAS_DAEMON=n. This prevents the RTAS daemon from running on each CPU every second or so. (This will require editing Kconfig files and will defeat @@ -284,12 +282,12 @@ To reduce its OS jitter, do any of the following: due to the rtas_event_scan() function. WARNING: Please check your CPU specifications to make sure that this is safe on your particular system. - g. If running on Cell Processor, build your kernel with + f. If running on Cell Processor, build your kernel with CBE_CPUFREQ_SPU_GOVERNOR=n to avoid OS jitter from spu_gov_work(). WARNING: Please check your CPU specifications to make sure that this is safe on your particular system. - h. If running on PowerMAC, build your kernel with + g. If running on PowerMAC, build your kernel with CONFIG_PMAC_RACKMETER=n to disable the CPU-meter, avoiding OS jitter from rackmeter_do_timer(). diff --git a/Documentation/admin-guide/laptops/thinkpad-acpi.rst b/Documentation/admin-guide/laptops/thinkpad-acpi.rst index adea0bf2acc5e5a00a9e93ce260bf2d69c2bb069..822907dcc84532eafaf75c00ca3a9df68d7fabc1 100644 --- a/Documentation/admin-guide/laptops/thinkpad-acpi.rst +++ b/Documentation/admin-guide/laptops/thinkpad-acpi.rst @@ -49,6 +49,7 @@ detailed description): - Fan control and monitoring: fan speed, fan enable/disable - WAN enable and disable - UWB enable and disable + - LCD Shadow (PrivacyGuard) enable and disable A compatibility table by model and feature is maintained on the web site, http://ibm-acpi.sf.net/. I appreciate any success or failure @@ -1409,6 +1410,28 @@ Sysfs notes Documentation/driver-api/rfkill.rst for details. +LCD Shadow control +------------------ + +procfs: /proc/acpi/ibm/lcdshadow + +Some newer T480s and T490s ThinkPads provide a feature called +PrivacyGuard. By turning this feature on, the usable vertical and +horizontal viewing angles of the LCD can be limited (as if some privacy +screen was applied manually in front of the display). + +procfs notes +^^^^^^^^^^^^ + +The available commands are:: + + echo '0' >/proc/acpi/ibm/lcdshadow + echo '1' >/proc/acpi/ibm/lcdshadow + +The first command ensures the best viewing angle and the latter one turns +on the feature, restricting the viewing angles. + + EXPERIMENTAL: UWB ----------------- diff --git a/Documentation/admin-guide/perf/imx-ddr.rst b/Documentation/admin-guide/perf/imx-ddr.rst new file mode 100644 index 0000000000000000000000000000000000000000..517a205abad6bbce5298d71e5dd74ea55f25c6e1 --- /dev/null +++ b/Documentation/admin-guide/perf/imx-ddr.rst @@ -0,0 +1,52 @@ +===================================================== +Freescale i.MX8 DDR Performance Monitoring Unit (PMU) +===================================================== + +There are no performance counters inside the DRAM controller, so performance +signals are brought out to the edge of the controller where a set of 4 x 32 bit +counters is implemented. This is controlled by the CSV modes programed in counter +control register which causes a large number of PERF signals to be generated. + +Selection of the value for each counter is done via the config registers. There +is one register for each counter. Counter 0 is special in that it always counts +“time” and when expired causes a lock on itself and the other counters and an +interrupt is raised. If any other counter overflows, it continues counting, and +no interrupt is raised. + +The "format" directory describes format of the config (event ID) and config1 +(AXI filtering) fields of the perf_event_attr structure, see /sys/bus/event_source/ +devices/imx8_ddr0/format/. The "events" directory describes the events types +hardware supported that can be used with perf tool, see /sys/bus/event_source/ +devices/imx8_ddr0/events/. + e.g.:: + perf stat -a -e imx8_ddr0/cycles/ cmd + perf stat -a -e imx8_ddr0/read/,imx8_ddr0/write/ cmd + +AXI filtering is only used by CSV modes 0x41 (axid-read) and 0x42 (axid-write) +to count reading or writing matches filter setting. Filter setting is various +from different DRAM controller implementations, which is distinguished by quirks +in the driver. + +* With DDR_CAP_AXI_ID_FILTER quirk. + Filter is defined with two configuration parts: + --AXI_ID defines AxID matching value. + --AXI_MASKING defines which bits of AxID are meaningful for the matching. + 0:corresponding bit is masked. + 1: corresponding bit is not masked, i.e. used to do the matching. + + AXI_ID and AXI_MASKING are mapped on DPCR1 register in performance counter. + When non-masked bits are matching corresponding AXI_ID bits then counter is + incremented. Perf counter is incremented if + AxID && AXI_MASKING == AXI_ID && AXI_MASKING + + This filter doesn't support filter different AXI ID for axid-read and axid-write + event at the same time as this filter is shared between counters. + e.g.:: + perf stat -a -e imx8_ddr0/axid-read,axi_mask=0xMMMM,axi_id=0xDDDD/ cmd + perf stat -a -e imx8_ddr0/axid-write,axi_mask=0xMMMM,axi_id=0xDDDD/ cmd + + NOTE: axi_mask is inverted in userspace(i.e. set bits are bits to mask), and + it will be reverted in driver automatically. so that the user can just specify + axi_id to monitor a specific id, rather than having to specify axi_mask. + e.g.:: + perf stat -a -e imx8_ddr0/axid-read,axi_id=0x12/ cmd, which will monitor ARID=0x12 diff --git a/Documentation/admin-guide/sysrq.rst b/Documentation/admin-guide/sysrq.rst index 7b9035c01a2e1c01d68336d891402f54362cdb13..72b2cfb066f455833410d665210d6d164910f2e1 100644 --- a/Documentation/admin-guide/sysrq.rst +++ b/Documentation/admin-guide/sysrq.rst @@ -171,22 +171,20 @@ It seems others find it useful as (System Attention Key) which is useful when you want to exit a program that will not let you switch consoles. (For example, X or a svgalib program.) -``reboot(b)`` is good when you're unable to shut down. But you should also -``sync(s)`` and ``umount(u)`` first. +``reboot(b)`` is good when you're unable to shut down, it is an equivalent +of pressing the "reset" button. ``crash(c)`` can be used to manually trigger a crashdump when the system is hung. Note that this just triggers a crash if there is no dump mechanism available. -``sync(s)`` is great when your system is locked up, it allows you to sync your -disks and will certainly lessen the chance of data loss and fscking. Note -that the sync hasn't taken place until you see the "OK" and "Done" appear -on the screen. (If the kernel is really in strife, you may not ever get the -OK or Done message...) +``sync(s)`` is handy before yanking removable medium or after using a rescue +shell that provides no graceful shutdown -- it will ensure your data is +safely written to the disk. Note that the sync hasn't taken place until you see +the "OK" and "Done" appear on the screen. -``umount(u)`` is basically useful in the same ways as ``sync(s)``. I generally -``sync(s)``, ``umount(u)``, then ``reboot(b)`` when my system locks. It's saved -me many a fsck. Again, the unmount (remount read-only) hasn't taken place until -you see the "OK" and "Done" message appear on the screen. +``umount(u)`` can be used to mark filesystems as properly unmounted. From the +running system's point of view, they will be remounted read-only. The remount +isn't complete until you see the "OK" and "Done" message appear on the screen. The loglevels ``0``-``9`` are useful when your console is being flooded with kernel messages you do not want to see. Selecting ``0`` will prevent all but diff --git a/Documentation/filesystems/ufs.txt b/Documentation/admin-guide/ufs.rst similarity index 69% rename from Documentation/filesystems/ufs.txt rename to Documentation/admin-guide/ufs.rst index 7a602adeca2b7399f04b50232c838a9aec305712..55d15297f8d700c5db777f33fedd1421da0e561a 100644 --- a/Documentation/filesystems/ufs.txt +++ b/Documentation/admin-guide/ufs.rst @@ -1,37 +1,45 @@ -USING UFS +========= +Using UFS ========= mount -t ufs -o ufstype=type_of_ufs device dir -UFS OPTIONS +UFS Options =========== ufstype=type_of_ufs UFS is a file system widely used in different operating systems. The problem are differences among implementations. Features of some implementations are undocumented, so its hard to recognize - type of ufs automatically. That's why user must specify type of + type of ufs automatically. That's why user must specify type of ufs manually by mount option ufstype. Possible values are: - old old format of ufs + old + old format of ufs default value, supported as read-only - 44bsd used in FreeBSD, NetBSD, OpenBSD + 44bsd + used in FreeBSD, NetBSD, OpenBSD supported as read-write - ufs2 used in FreeBSD 5.x + ufs2 + used in FreeBSD 5.x supported as read-write - 5xbsd synonym for ufs2 + 5xbsd + synonym for ufs2 - sun used in SunOS (Solaris) + sun + used in SunOS (Solaris) supported as read-write - sunx86 used in SunOS for Intel (Solarisx86) + sunx86 + used in SunOS for Intel (Solarisx86) supported as read-write - hp used in HP-UX + hp + used in HP-UX supported as read-only nextstep @@ -47,14 +55,14 @@ ufstype=type_of_ufs supported as read-only -POSSIBLE PROBLEMS -================= +Possible Problems +----------------- See next section, if you have any. -BUG REPORTS -=========== +Bug Reports +----------- Any ufs bug report you can send to daniel.pirkl@email.cz or to dushistov@mail.ru (do not send partition tables bug reports). diff --git a/Documentation/wimax/README.i2400m b/Documentation/admin-guide/wimax/i2400m.rst similarity index 69% rename from Documentation/wimax/README.i2400m rename to Documentation/admin-guide/wimax/i2400m.rst index 7dffd8919cb0fbe74e25483794d8d2be74f744b0..194388c0c3513a4e523820a0701a720141ae231c 100644 --- a/Documentation/wimax/README.i2400m +++ b/Documentation/admin-guide/wimax/i2400m.rst @@ -1,18 +1,23 @@ +.. include:: - Driver for the Intel Wireless Wimax Connection 2400m +==================================================== +Driver for the Intel Wireless Wimax Connection 2400m +==================================================== - (C) 2008 Intel Corporation < linux-wimax@intel.com > +: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 @@ -22,8 +27,10 @@ + 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 @@ -36,37 +43,39 @@ Compile and install your kernel as usual. 2.2. Compilation of the drivers distributed as an standalone module +------------------------------------------------------------------- - To compile + To compile:: -$ cd source/directory -$ make + $ 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): + when the device is plugged):: -$ make install -$ depmod -a + $ 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: + currently running one, set KDIR to the right location:: -$ make KDIR=/path/to/kernel/dev/tree + $ 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 + 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 @@ -76,6 +85,7 @@ $ cp FIRMWAREFILE.sbcf /lib/firmware/i2400m-fw-BUSTYPE-1.3.sbcf with other types. 4. Design +========= This package contains two major parts: a WiMAX kernel stack and a driver for the Intel i2400m. @@ -102,16 +112,17 @@ $ cp FIRMWAREFILE.sbcf /lib/firmware/i2400m-fw-BUSTYPE-1.3.sbcf 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: + /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 + ... + 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. @@ -120,38 +131,42 @@ i2400m_usb 5-4:1.0: WiMAX interface wmx0 (00:1d:e1:01:94:2c) ready 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: + echoing values:: -$ echo VALUE > /sys/module/MODULENAME/parameters/PARAMETERNAME + $ 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: + also create a file named /etc/modprobe.d/i2400m containing:: -options i2400m idle_mode_disabled=1 + options i2400m idle_mode_disabled=1 - To find which parameters are supported by a module, run: + To find which parameters are supported by a module, run:: -$ modinfo path/to/module.ko + $ modinfo path/to/module.ko During kernel bootup (if the driver is linked in the kernel), specify - the following to the kernel command line: + the following to the kernel command line:: -i2400m.PARAMETER=VALUE + 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 @@ -163,52 +178,55 @@ i2400m.PARAMETER=VALUE /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 + 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: + engine, just write:: -$ echo 3 > /sys/kernel/debug/wimax:wmx0/i2400m/dl_tx + $ 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: + data reception/delivery from the device:: -$ cat /sys/kernel/debug/wimax:wmx0/i2400m/rx_stats -45 1 3 34 3104 48 480 + $ cat /sys/kernel/debug/wimax:wmx0/i2400m/rx_stats + 45 1 3 34 3104 48 480 + + The numbers reported are: - 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 @@ -216,9 +234,9 @@ $ cat /sys/kernel/debug/wimax:wmx0/i2400m/rx_stats 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: + To clear the statistics back to 0, write anything to the rx_stats file:: -$ echo 1 > /sys/kernel/debug/wimax:wmx0/i2400m_rx_stats + $ echo 1 > /sys/kernel/debug/wimax:wmx0/i2400m_rx_stats Likewise for TX. @@ -227,14 +245,16 @@ $ echo 1 > /sys/kernel/debug/wimax:wmx0/i2400m_rx_stats 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 + 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 @@ -242,18 +262,21 @@ $ echo 1 > /sys/kernel/debug/wimax:wmx0/i2400m/trace_msg_from_user (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' +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: + log:: -i2400m_usb 5-4:1.0: fw i2400m-fw-usb-1.3.sbcf: request failed: -2 + 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 diff --git a/Documentation/admin-guide/wimax/index.rst b/Documentation/admin-guide/wimax/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..fdf7c1f99ff568da6bb14346c606692a0d9fba1c --- /dev/null +++ b/Documentation/admin-guide/wimax/index.rst @@ -0,0 +1,19 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=============== +WiMAX subsystem +=============== + +.. toctree:: + :maxdepth: 2 + + wimax + + i2400m + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/wimax/README.wimax b/Documentation/admin-guide/wimax/wimax.rst similarity index 74% rename from Documentation/wimax/README.wimax rename to Documentation/admin-guide/wimax/wimax.rst index b78c4378084e551651e45d6b3dea8d658a0a3108..817ee8ba2732257ea727f3bdbf1b88a8381bb326 100644 --- a/Documentation/wimax/README.wimax +++ b/Documentation/admin-guide/wimax/wimax.rst @@ -1,12 +1,16 @@ +.. include:: - Linux kernel WiMAX stack +======================== +Linux kernel WiMAX stack +======================== - (C) 2008 Intel Corporation < linux-wimax@intel.com > +: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. @@ -31,6 +35,7 @@ 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. @@ -40,6 +45,7 @@ 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. @@ -52,20 +58,22 @@ 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 + 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 @@ -74,7 +82,7 @@ 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 + $ 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 diff --git a/Documentation/admin-guide/xfs.rst b/Documentation/admin-guide/xfs.rst index e76665a8f2f258c0c1b34fd2d76a3d24baa5f66b..fb5b39f73059d15fdcba0ce922f85006193f098c 100644 --- a/Documentation/admin-guide/xfs.rst +++ b/Documentation/admin-guide/xfs.rst @@ -337,11 +337,12 @@ None at present. Removed Sysctls =============== +============================= ======= Name Removed - ---- ------- +============================= ======= fs.xfs.xfsbufd_centisec v4.0 fs.xfs.age_buffer_centisecs v4.0 - +============================= ======= Error handling ============== diff --git a/Documentation/arm/sa1100/adsbitsy.rst b/Documentation/arm/sa1100/adsbitsy.rst deleted file mode 100644 index c179cb26b6822b9213cbbc5c526a917bbe89e1ff..0000000000000000000000000000000000000000 --- a/Documentation/arm/sa1100/adsbitsy.rst +++ /dev/null @@ -1,51 +0,0 @@ -=============================== -ADS Bitsy Single Board Computer -=============================== - -(It is different from Bitsy(iPAQ) of Compaq) - -For more details, contact Applied Data Systems or see -http://www.applieddata.net/products.html - -The Linux support for this product has been provided by -Woojung Huh - -Use 'make adsbitsy_config' before any 'make config'. -This will set up defaults for ADS Bitsy support. - -The kernel zImage is linked to be loaded and executed at 0xc0400000. - -Linux can be used with the ADS BootLoader that ships with the -newer rev boards. See their documentation on how to load Linux. - -Supported peripherals -===================== - -- SA1100 LCD frame buffer (8/16bpp...sort of) -- SA1111 USB Master -- SA1100 serial port -- pcmcia, compact flash -- touchscreen(ucb1200) -- console on LCD screen -- serial ports (ttyS[0-2]) - - ttyS0 is default for serial console - -To do -===== - -- everything else! :-) - -Notes -===== - -- The flash on board is divided into 3 partitions. - You should be careful to use flash on board. - Its partition is different from GraphicsClient Plus and GraphicsMaster - -- 16bpp mode requires a different cable than what ships with the board. - Contact ADS or look through the manual to wire your own. Currently, - if you compile with 16bit mode support and switch into a lower bpp - mode, the timing is off so the image is corrupted. This will be - fixed soon. - -Any contribution can be sent to nico@fluxnic.net and will be greatly welcome! diff --git a/Documentation/arm/sa1100/assabet.rst b/Documentation/arm/sa1100/assabet.rst index 3e704831c311ab047ae5290bab3ddeea85748b06..a761e128fb086b4965a68d683877a01b92ce38e7 100644 --- a/Documentation/arm/sa1100/assabet.rst +++ b/Documentation/arm/sa1100/assabet.rst @@ -14,7 +14,7 @@ Building the kernel To build the kernel with current defaults:: - make assabet_config + make assabet_defconfig make oldconfig make zImage diff --git a/Documentation/arm/sa1100/brutus.rst b/Documentation/arm/sa1100/brutus.rst deleted file mode 100644 index e1a23bee6d4486f3bdcb6c84dac714a6c1f86cdb..0000000000000000000000000000000000000000 --- a/Documentation/arm/sa1100/brutus.rst +++ /dev/null @@ -1,69 +0,0 @@ -====== -Brutus -====== - -Brutus is an evaluation platform for the SA1100 manufactured by Intel. -For more details, see: - -http://developer.intel.com - -To compile for Brutus, you must issue the following commands:: - - make brutus_config - make config - [accept all the defaults] - make zImage - -The resulting kernel will end up in linux/arch/arm/boot/zImage. This file -must be loaded at 0xc0008000 in Brutus's memory and execution started at -0xc0008000 as well with the value of registers r0 = 0 and r1 = 16 upon -entry. - -But prior to execute the kernel, a ramdisk image must also be loaded in -memory. Use memory address 0xd8000000 for this. Note that the file -containing the (compressed) ramdisk image must not exceed 4 MB. - -Typically, you'll need angelboot to load the kernel. -The following angelboot.opt file should be used:: - - base 0xc0008000 - entry 0xc0008000 - r0 0x00000000 - r1 0x00000010 - device /dev/ttyS0 - options "9600 8N1" - baud 115200 - otherfile ramdisk_img.gz - otherbase 0xd8000000 - -Then load the kernel and ramdisk with:: - - angelboot -f angelboot.opt zImage - -The first Brutus serial port (assumed to be linked to /dev/ttyS0 on your -host PC) is used by angel to load the kernel and ramdisk image. The serial -console is provided through the second Brutus serial port. To access it, -you may use minicom configured with /dev/ttyS1, 9600 baud, 8N1, no flow -control. - -Currently supported -=================== - - - RS232 serial ports - - audio output - - LCD screen - - keyboard - -The actual Brutus support may not be complete without extra patches. -If such patches exist, they should be found from -ftp.netwinder.org/users/n/nico. - -A full PCMCIA support is still missing, although it's possible to hack -some drivers in order to drive already inserted cards at boot time with -little modifications. - -Any contribution is welcome. - -Please send patches to nico@fluxnic.net - -Have Fun ! diff --git a/Documentation/arm/sa1100/freebird.rst b/Documentation/arm/sa1100/freebird.rst deleted file mode 100644 index 81043d0c6d640172ac14f89a0d44ef10b45d3849..0000000000000000000000000000000000000000 --- a/Documentation/arm/sa1100/freebird.rst +++ /dev/null @@ -1,25 +0,0 @@ -======== -Freebird -======== - -Freebird-1.1 is produced by Legend(C), Inc. -`http://web.archive.org/web/*/http://www.legend.com.cn` -and software/linux maintained by Coventive(C), Inc. -(http://www.coventive.com) - -Based on the Nicolas's strongarm kernel tree. - -Maintainer: - -Chester Kuo - - - - - -Author: - -- Tim wu -- CIH -- Eric Peng -- Jeff Lee -- Allen Cheng -- Tony Liu diff --git a/Documentation/arm/sa1100/graphicsclient.rst b/Documentation/arm/sa1100/graphicsclient.rst deleted file mode 100644 index a73d61c3ce9178e5a2ba4264ab18450286b14d67..0000000000000000000000000000000000000000 --- a/Documentation/arm/sa1100/graphicsclient.rst +++ /dev/null @@ -1,102 +0,0 @@ -============================================= -ADS GraphicsClient Plus Single Board Computer -============================================= - -For more details, contact Applied Data Systems or see -http://www.applieddata.net/products.html - -The original Linux support for this product has been provided by -Nicolas Pitre . Continued development work by -Woojung Huh - -It's currently possible to mount a root filesystem via NFS providing a -complete Linux environment. Otherwise a ramdisk image may be used. The -board supports MTD/JFFS, so you could also mount something on there. - -Use 'make graphicsclient_config' before any 'make config'. This will set up -defaults for GraphicsClient Plus support. - -The kernel zImage is linked to be loaded and executed at 0xc0200000. -Also the following registers should have the specified values upon entry:: - - r0 = 0 - r1 = 29 (this is the GraphicsClient architecture number) - -Linux can be used with the ADS BootLoader that ships with the -newer rev boards. See their documentation on how to load Linux. -Angel is not available for the GraphicsClient Plus AFAIK. - -There is a board known as just the GraphicsClient that ADS used to -produce but has end of lifed. This code will not work on the older -board with the ADS bootloader, but should still work with Angel, -as outlined below. In any case, if you're planning on deploying -something en masse, you should probably get the newer board. - -If using Angel on the older boards, here is a typical angel.opt option file -if the kernel is loaded through the Angel Debug Monitor:: - - base 0xc0200000 - entry 0xc0200000 - r0 0x00000000 - r1 0x0000001d - device /dev/ttyS1 - options "38400 8N1" - baud 115200 - #otherfile ramdisk.gz - #otherbase 0xc0800000 - exec minicom - -Then the kernel (and ramdisk if otherfile/otherbase lines above are -uncommented) would be loaded with:: - - angelboot -f angelboot.opt zImage - -Here it is assumed that the board is connected to ttyS1 on your PC -and that minicom is preconfigured with /dev/ttyS1, 38400 baud, 8N1, no flow -control by default. - -If any other bootloader is used, ensure it accomplish the same, especially -for r0/r1 register values before jumping into the kernel. - - -Supported peripherals -===================== - -- SA1100 LCD frame buffer (8/16bpp...sort of) -- on-board SMC 92C96 ethernet NIC -- SA1100 serial port -- flash memory access (MTD/JFFS) -- pcmcia -- touchscreen(ucb1200) -- ps/2 keyboard -- console on LCD screen -- serial ports (ttyS[0-2]) - - ttyS0 is default for serial console -- Smart I/O (ADC, keypad, digital inputs, etc) - See http://www.eurotech-inc.com/linux-sbc.asp for IOCTL documentation - and example user space code. ps/2 keybd is multiplexed through this driver - -To do -===== - -- UCB1200 audio with new ucb_generic layer -- everything else! :-) - -Notes -===== - -- The flash on board is divided into 3 partitions. mtd0 is where - the ADS boot ROM and zImage is stored. It's been marked as - read-only to keep you from blasting over the bootloader. :) mtd1 is - for the ramdisk.gz image. mtd2 is user flash space and can be - utilized for either JFFS or if you're feeling crazy, running ext2 - on top of it. If you're not using the ADS bootloader, you're - welcome to blast over the mtd1 partition also. - -- 16bpp mode requires a different cable than what ships with the board. - Contact ADS or look through the manual to wire your own. Currently, - if you compile with 16bit mode support and switch into a lower bpp - mode, the timing is off so the image is corrupted. This will be - fixed soon. - -Any contribution can be sent to nico@fluxnic.net and will be greatly welcome! diff --git a/Documentation/arm/sa1100/graphicsmaster.rst b/Documentation/arm/sa1100/graphicsmaster.rst deleted file mode 100644 index e39892514f0c26c91910969dd0e7dd9127a5088c..0000000000000000000000000000000000000000 --- a/Documentation/arm/sa1100/graphicsmaster.rst +++ /dev/null @@ -1,60 +0,0 @@ -======================================== -ADS GraphicsMaster Single Board Computer -======================================== - -For more details, contact Applied Data Systems or see -http://www.applieddata.net/products.html - -The original Linux support for this product has been provided by -Nicolas Pitre . Continued development work by -Woojung Huh - -Use 'make graphicsmaster_config' before any 'make config'. -This will set up defaults for GraphicsMaster support. - -The kernel zImage is linked to be loaded and executed at 0xc0400000. - -Linux can be used with the ADS BootLoader that ships with the -newer rev boards. See their documentation on how to load Linux. - -Supported peripherals -===================== - -- SA1100 LCD frame buffer (8/16bpp...sort of) -- SA1111 USB Master -- on-board SMC 92C96 ethernet NIC -- SA1100 serial port -- flash memory access (MTD/JFFS) -- pcmcia, compact flash -- touchscreen(ucb1200) -- ps/2 keyboard -- console on LCD screen -- serial ports (ttyS[0-2]) - - ttyS0 is default for serial console -- Smart I/O (ADC, keypad, digital inputs, etc) - See http://www.eurotech-inc.com/linux-sbc.asp for IOCTL documentation - and example user space code. ps/2 keybd is multiplexed through this driver - -To do -===== - -- everything else! :-) - -Notes -===== - -- The flash on board is divided into 3 partitions. mtd0 is where - the zImage is stored. It's been marked as read-only to keep you - from blasting over the bootloader. :) mtd1 is - for the ramdisk.gz image. mtd2 is user flash space and can be - utilized for either JFFS or if you're feeling crazy, running ext2 - on top of it. If you're not using the ADS bootloader, you're - welcome to blast over the mtd1 partition also. - -- 16bpp mode requires a different cable than what ships with the board. - Contact ADS or look through the manual to wire your own. Currently, - if you compile with 16bit mode support and switch into a lower bpp - mode, the timing is off so the image is corrupted. This will be - fixed soon. - -Any contribution can be sent to nico@fluxnic.net and will be greatly welcome! diff --git a/Documentation/arm/sa1100/huw_webpanel.rst b/Documentation/arm/sa1100/huw_webpanel.rst deleted file mode 100644 index 1dc7ccb165f00f7fadcb3bfe08c2f455b3033770..0000000000000000000000000000000000000000 --- a/Documentation/arm/sa1100/huw_webpanel.rst +++ /dev/null @@ -1,21 +0,0 @@ -======================= -Hoeft & Wessel Webpanel -======================= - -The HUW_WEBPANEL is a product of the german company Hoeft & Wessel AG - -If you want more information, please visit -http://www.hoeft-wessel.de - -To build the kernel:: - - make huw_webpanel_config - make oldconfig - [accept all defaults] - make zImage - -Mostly of the work is done by: -Roman Jordan jor@hoeft-wessel.de -Christoph Schulz schu@hoeft-wessel.de - -2000/12/18/ diff --git a/Documentation/arm/sa1100/index.rst b/Documentation/arm/sa1100/index.rst index 68c2a280a74540aeab26da278475afd0bf101936..c9aed43280fff91318ab87f55d1269dbd5a4b7a2 100644 --- a/Documentation/arm/sa1100/index.rst +++ b/Documentation/arm/sa1100/index.rst @@ -7,19 +7,7 @@ Intel StrongARM 1100 .. toctree:: :maxdepth: 1 - adsbitsy assabet - brutus cerf - freebird - graphicsclient - graphicsmaster - huw_webpanel - itsy lart - nanoengine - pangolin - pleb serial_uart - tifon - yopy diff --git a/Documentation/arm/sa1100/itsy.rst b/Documentation/arm/sa1100/itsy.rst deleted file mode 100644 index f49896ba3ef1cc89b7fdf7216ac6546d55edf558..0000000000000000000000000000000000000000 --- a/Documentation/arm/sa1100/itsy.rst +++ /dev/null @@ -1,47 +0,0 @@ -==== -Itsy -==== - -Itsy is a research project done by the Western Research Lab, and Systems -Research Center in Palo Alto, CA. The Itsy project is one of several -research projects at Compaq that are related to pocket computing. - -For more information, see: - - http://www.hpl.hp.com/downloads/crl/itsy/ - -Notes on initial 2.4 Itsy support (8/27/2000) : - -The port was done on an Itsy version 1.5 machine with a daughtercard with -64 Meg of DRAM and 32 Meg of Flash. The initial work includes support for -serial console (to see what you're doing). No other devices have been -enabled. - -To build, do a "make menuconfig" (or xmenuconfig) and select Itsy support. -Disable Flash and LCD support. and then do a make zImage. -Finally, you will need to cd to arch/arm/boot/tools and execute a make there -to build the params-itsy program used to boot the kernel. - -In order to install the port of 2.4 to the itsy, You will need to set the -configuration parameters in the monitor as follows:: - - Arg 1:0x08340000, Arg2: 0xC0000000, Arg3:18 (0x12), Arg4:0 - -Make sure the start-routine address is set to 0x00060000. - -Next, flash the params-itsy program to 0x00060000 ("p 1 0x00060000" in the -flash menu) Flash the kernel in arch/arm/boot/zImage into 0x08340000 -("p 1 0x00340000"). Finally flash an initial ramdisk into 0xC8000000 -("p 2 0x0") We used ramdisk-2-30.gz from the 0.11 version directory on -handhelds.org. - -The serial connection we established was at: - -8-bit data, no parity, 1 stop bit(s), 115200.00 b/s. in the monitor, in the -params-itsy program, and in the kernel itself. This can be changed, but -not easily. The monitor parameters are easily changed, the params program -setup is assembly outl's, and the kernel is a configuration item specific to -the itsy. (i.e. grep for CONFIG_SA1100_ITSY and you'll find where it is.) - - -This should get you a properly booting 2.4 kernel on the itsy. diff --git a/Documentation/arm/sa1100/nanoengine.rst b/Documentation/arm/sa1100/nanoengine.rst deleted file mode 100644 index 47f1a14cf98a5e2588a076e8eaed1ad1f6a95356..0000000000000000000000000000000000000000 --- a/Documentation/arm/sa1100/nanoengine.rst +++ /dev/null @@ -1,11 +0,0 @@ -========== -nanoEngine -========== - -"nanoEngine" is a SA1110 based single board computer from -Bright Star Engineering Inc. See www.brightstareng.com/arm -for more info. -(Ref: Stuart Adams ) - -Also visit Larry Doolittle's "Linux for the nanoEngine" site: -http://www.brightstareng.com/arm/nanoeng.htm diff --git a/Documentation/arm/sa1100/pangolin.rst b/Documentation/arm/sa1100/pangolin.rst deleted file mode 100644 index f0c5c1618553ad0a41849217387a0de2da2cf099..0000000000000000000000000000000000000000 --- a/Documentation/arm/sa1100/pangolin.rst +++ /dev/null @@ -1,29 +0,0 @@ -======== -Pangolin -======== - -Pangolin is a StrongARM 1110-based evaluation platform produced -by Dialogue Technology (http://www.dialogue.com.tw/). -It has EISA slots for ease of configuration with SDRAM/Flash -memory card, USB/Serial/Audio card, Compact Flash card, -PCMCIA/IDE card and TFT-LCD card. - -To compile for Pangolin, you must issue the following commands:: - - make pangolin_config - make oldconfig - make zImage - -Supported peripherals -===================== - -- SA1110 serial port (UART1/UART2/UART3) -- flash memory access -- compact flash driver -- UDA1341 sound driver -- SA1100 LCD controller for 800x600 16bpp TFT-LCD -- MQ-200 driver for 800x600 16bpp TFT-LCD -- Penmount(touch panel) driver -- PCMCIA driver -- SMC91C94 LAN driver -- IDE driver (experimental) diff --git a/Documentation/arm/sa1100/pleb.rst b/Documentation/arm/sa1100/pleb.rst deleted file mode 100644 index d5b732967aa36b024b2209d8b30525b13d935118..0000000000000000000000000000000000000000 --- a/Documentation/arm/sa1100/pleb.rst +++ /dev/null @@ -1,13 +0,0 @@ -==== -PLEB -==== - -The PLEB project was started as a student initiative at the School of -Computer Science and Engineering, University of New South Wales to make a -pocket computer capable of running the Linux Kernel. - -PLEB support has yet to be fully integrated. - -For more information, see: - - http://www.cse.unsw.edu.au diff --git a/Documentation/arm/sa1100/tifon.rst b/Documentation/arm/sa1100/tifon.rst deleted file mode 100644 index c26e910b9ea7224da3caf58d4dd17eec9f05fed5..0000000000000000000000000000000000000000 --- a/Documentation/arm/sa1100/tifon.rst +++ /dev/null @@ -1,7 +0,0 @@ -===== -Tifon -===== - -More info has to come... - -Contact: Peter Danielsson diff --git a/Documentation/arm/sa1100/yopy.rst b/Documentation/arm/sa1100/yopy.rst deleted file mode 100644 index 5b35a5f61a440cfc6ebf709be9de2b803150e2fa..0000000000000000000000000000000000000000 --- a/Documentation/arm/sa1100/yopy.rst +++ /dev/null @@ -1,5 +0,0 @@ -==== -Yopy -==== - -See http://www.yopydeveloper.org for more. diff --git a/Documentation/arm/samsung-s3c24xx/index.rst b/Documentation/arm/samsung-s3c24xx/index.rst index 5b8a7f9398d8a85707bdfa5322c2b4db4d51c42d..ccb951a0bedbce451405eca212539d2e90880cb7 100644 --- a/Documentation/arm/samsung-s3c24xx/index.rst +++ b/Documentation/arm/samsung-s3c24xx/index.rst @@ -1,6 +1,6 @@ .. SPDX-License-Identifier: GPL-2.0 -========================== +========================== Samsung S3C24XX SoC Family ========================== diff --git a/Documentation/arm/sh-mobile/.gitignore b/Documentation/arm/sh-mobile/.gitignore deleted file mode 100644 index c928dbf3cc8806e28a65d3302e3e21b654ac39e1..0000000000000000000000000000000000000000 --- a/Documentation/arm/sh-mobile/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vrl4 diff --git a/Documentation/arm64/index.rst b/Documentation/arm64/index.rst index 96b696ba4e6cb70a2411a3876f4b2f828743975c..5c0c69dc58aa3887e52453f3630afdb9ed8e2bd1 100644 --- a/Documentation/arm64/index.rst +++ b/Documentation/arm64/index.rst @@ -16,6 +16,7 @@ ARM64 Architecture pointer-authentication silicon-errata sve + tagged-address-abi tagged-pointers .. only:: subproject and html diff --git a/Documentation/arm64/kasan-offsets.sh b/Documentation/arm64/kasan-offsets.sh new file mode 100644 index 0000000000000000000000000000000000000000..2b7a021db363abcff632eeeaf4d2527b9911d0d5 --- /dev/null +++ b/Documentation/arm64/kasan-offsets.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# Print out the KASAN_SHADOW_OFFSETS required to place the KASAN SHADOW +# start address at the mid-point of the kernel VA space + +print_kasan_offset () { + printf "%02d\t" $1 + printf "0x%08x00000000\n" $(( (0xffffffff & (-1 << ($1 - 1 - 32))) \ + + (1 << ($1 - 32 - $2)) \ + - (1 << (64 - 32 - $2)) )) +} + +echo KASAN_SHADOW_SCALE_SHIFT = 3 +printf "VABITS\tKASAN_SHADOW_OFFSET\n" +print_kasan_offset 48 3 +print_kasan_offset 47 3 +print_kasan_offset 42 3 +print_kasan_offset 39 3 +print_kasan_offset 36 3 +echo +echo KASAN_SHADOW_SCALE_SHIFT = 4 +printf "VABITS\tKASAN_SHADOW_OFFSET\n" +print_kasan_offset 48 4 +print_kasan_offset 47 4 +print_kasan_offset 42 4 +print_kasan_offset 39 4 +print_kasan_offset 36 4 diff --git a/Documentation/arm64/memory.rst b/Documentation/arm64/memory.rst index 464b880fc4b7c2966a6c923241b3acb709caccff..b040909e45f81d7ab9108cfd1286338fdd0d1471 100644 --- a/Documentation/arm64/memory.rst +++ b/Documentation/arm64/memory.rst @@ -14,6 +14,10 @@ with the 4KB page configuration, allowing 39-bit (512GB) or 48-bit 64KB pages, only 2 levels of translation tables, allowing 42-bit (4TB) virtual address, are used but the memory layout is the same. +ARMv8.2 adds optional support for Large Virtual Address space. This is +only available when running with a 64KB page size and expands the +number of descriptors in the first level of translation. + User addresses have bits 63:48 set to 0 while the kernel addresses have the same bits set to 1. TTBRx selection is given by bit 63 of the virtual address. The swapper_pg_dir contains only kernel (global) @@ -22,40 +26,43 @@ The swapper_pg_dir address is written to TTBR1 and never written to TTBR0. -AArch64 Linux memory layout with 4KB pages + 3 levels:: - - Start End Size Use - ----------------------------------------------------------------------- - 0000000000000000 0000007fffffffff 512GB user - ffffff8000000000 ffffffffffffffff 512GB kernel - - -AArch64 Linux memory layout with 4KB pages + 4 levels:: +AArch64 Linux memory layout with 4KB pages + 4 levels (48-bit):: Start End Size Use ----------------------------------------------------------------------- 0000000000000000 0000ffffffffffff 256TB user - ffff000000000000 ffffffffffffffff 256TB kernel - - -AArch64 Linux memory layout with 64KB pages + 2 levels:: + ffff000000000000 ffff7fffffffffff 128TB kernel logical memory map + ffff800000000000 ffff9fffffffffff 32TB kasan shadow region + ffffa00000000000 ffffa00007ffffff 128MB bpf jit region + ffffa00008000000 ffffa0000fffffff 128MB modules + ffffa00010000000 fffffdffbffeffff ~93TB vmalloc + fffffdffbfff0000 fffffdfffe5f8fff ~998MB [guard region] + fffffdfffe5f9000 fffffdfffe9fffff 4124KB fixed mappings + fffffdfffea00000 fffffdfffebfffff 2MB [guard region] + fffffdfffec00000 fffffdffffbfffff 16MB PCI I/O space + fffffdffffc00000 fffffdffffdfffff 2MB [guard region] + fffffdffffe00000 ffffffffffdfffff 2TB vmemmap + ffffffffffe00000 ffffffffffffffff 2MB [guard region] + + +AArch64 Linux memory layout with 64KB pages + 3 levels (52-bit with HW support):: Start End Size Use ----------------------------------------------------------------------- - 0000000000000000 000003ffffffffff 4TB user - fffffc0000000000 ffffffffffffffff 4TB kernel - - -AArch64 Linux memory layout with 64KB pages + 3 levels:: - - Start End Size Use - ----------------------------------------------------------------------- - 0000000000000000 0000ffffffffffff 256TB user - ffff000000000000 ffffffffffffffff 256TB kernel - - -For details of the virtual kernel memory layout please see the kernel -booting log. + 0000000000000000 000fffffffffffff 4PB user + fff0000000000000 fff7ffffffffffff 2PB kernel logical memory map + fff8000000000000 fffd9fffffffffff 1440TB [gap] + fffda00000000000 ffff9fffffffffff 512TB kasan shadow region + ffffa00000000000 ffffa00007ffffff 128MB bpf jit region + ffffa00008000000 ffffa0000fffffff 128MB modules + ffffa00010000000 fffff81ffffeffff ~88TB vmalloc + fffff81fffff0000 fffffc1ffe58ffff ~3TB [guard region] + fffffc1ffe590000 fffffc1ffe9fffff 4544KB fixed mappings + fffffc1ffea00000 fffffc1ffebfffff 2MB [guard region] + fffffc1ffec00000 fffffc1fffbfffff 16MB PCI I/O space + fffffc1fffc00000 fffffc1fffdfffff 2MB [guard region] + fffffc1fffe00000 ffffffffffdfffff 3968GB vmemmap + ffffffffffe00000 ffffffffffffffff 2MB [guard region] Translation table lookup with 4KB pages:: @@ -83,7 +90,8 @@ Translation table lookup with 64KB pages:: | | | | [15:0] in-page offset | | | +----------> [28:16] L3 index | | +--------------------------> [41:29] L2 index - | +-------------------------------> [47:42] L1 index + | +-------------------------------> [47:42] L1 index (48-bit) + | [51:42] L1 index (52-bit) +-------------------------------------------------> [63] TTBR0/1 @@ -96,3 +104,62 @@ ARM64_HARDEN_EL2_VECTORS is selected for particular CPUs. When using KVM with the Virtualization Host Extensions, no additional mappings are created, since the host kernel runs directly in EL2. + +52-bit VA support in the kernel +------------------------------- +If the ARMv8.2-LVA optional feature is present, and we are running +with a 64KB page size; then it is possible to use 52-bits of address +space for both userspace and kernel addresses. However, any kernel +binary that supports 52-bit must also be able to fall back to 48-bit +at early boot time if the hardware feature is not present. + +This fallback mechanism necessitates the kernel .text to be in the +higher addresses such that they are invariant to 48/52-bit VAs. Due +to the kasan shadow being a fraction of the entire kernel VA space, +the end of the kasan shadow must also be in the higher half of the +kernel VA space for both 48/52-bit. (Switching from 48-bit to 52-bit, +the end of the kasan shadow is invariant and dependent on ~0UL, +whilst the start address will "grow" towards the lower addresses). + +In order to optimise phys_to_virt and virt_to_phys, the PAGE_OFFSET +is kept constant at 0xFFF0000000000000 (corresponding to 52-bit), +this obviates the need for an extra variable read. The physvirt +offset and vmemmap offsets are computed at early boot to enable +this logic. + +As a single binary will need to support both 48-bit and 52-bit VA +spaces, the VMEMMAP must be sized large enough for 52-bit VAs and +also must be sized large enought to accommodate a fixed PAGE_OFFSET. + +Most code in the kernel should not need to consider the VA_BITS, for +code that does need to know the VA size the variables are +defined as follows: + +VA_BITS constant the *maximum* VA space size + +VA_BITS_MIN constant the *minimum* VA space size + +vabits_actual variable the *actual* VA space size + + +Maximum and minimum sizes can be useful to ensure that buffers are +sized large enough or that addresses are positioned close enough for +the "worst" case. + +52-bit userspace VAs +-------------------- +To maintain compatibility with software that relies on the ARMv8.0 +VA space maximum size of 48-bits, the kernel will, by default, +return virtual addresses to userspace from a 48-bit range. + +Software can "opt-in" to receiving VAs from a 52-bit space by +specifying an mmap hint parameter that is larger than 48-bit. +For example: + maybe_high_address = mmap(~0UL, size, prot, flags,...); + +It is also possible to build a debug kernel that returns addresses +from a 52-bit space by enabling the following kernel config options: + CONFIG_EXPERT=y && CONFIG_ARM64_FORCE_52BIT=y + +Note that this option is only intended for debugging applications +and should not be used in production. diff --git a/Documentation/arm64/silicon-errata.rst b/Documentation/arm64/silicon-errata.rst index 3e57d09246e668c14fb44c6b949494df273b29ae..17ea3fecddaa50ac1a1e8af59f222105622b1720 100644 --- a/Documentation/arm64/silicon-errata.rst +++ b/Documentation/arm64/silicon-errata.rst @@ -115,6 +115,8 @@ stable kernels. +----------------+-----------------+-----------------+-----------------------------+ | Hisilicon | Hip0{6,7} | #161010701 | N/A | +----------------+-----------------+-----------------+-----------------------------+ +| Hisilicon | Hip0{6,7} | #161010803 | N/A | ++----------------+-----------------+-----------------+-----------------------------+ | Hisilicon | Hip07 | #161600802 | HISILICON_ERRATUM_161600802 | +----------------+-----------------+-----------------+-----------------------------+ | Hisilicon | Hip08 SMMU PMCG | #162001800 | N/A | diff --git a/Documentation/arm64/tagged-address-abi.rst b/Documentation/arm64/tagged-address-abi.rst new file mode 100644 index 0000000000000000000000000000000000000000..d4a85d535bf99e09cfe5c3dc41652eaa3b64f21b --- /dev/null +++ b/Documentation/arm64/tagged-address-abi.rst @@ -0,0 +1,156 @@ +========================== +AArch64 TAGGED ADDRESS ABI +========================== + +Authors: Vincenzo Frascino + Catalin Marinas + +Date: 21 August 2019 + +This document describes the usage and semantics of the Tagged Address +ABI on AArch64 Linux. + +1. Introduction +--------------- + +On AArch64 the ``TCR_EL1.TBI0`` bit is set by default, allowing +userspace (EL0) to perform memory accesses through 64-bit pointers with +a non-zero top byte. This document describes the relaxation of the +syscall ABI that allows userspace to pass certain tagged pointers to +kernel syscalls. + +2. AArch64 Tagged Address ABI +----------------------------- + +From the kernel syscall interface perspective and for the purposes of +this document, a "valid tagged pointer" is a pointer with a potentially +non-zero top-byte that references an address in the user process address +space obtained in one of the following ways: + +- ``mmap()`` syscall where either: + + - flags have the ``MAP_ANONYMOUS`` bit set or + - the file descriptor refers to a regular file (including those + returned by ``memfd_create()``) or ``/dev/zero`` + +- ``brk()`` syscall (i.e. the heap area between the initial location of + the program break at process creation and its current location). + +- any memory mapped by the kernel in the address space of the process + 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 +how the user addresses are used by the kernel: + +1. User addresses not accessed by the kernel but used for address space + management (e.g. ``mmap()``, ``mprotect()``, ``madvise()``). The use + of valid tagged pointers in this context is always allowed. + +2. User addresses accessed by the kernel (e.g. ``write()``). This ABI + relaxation is disabled by default and the application thread needs to + explicitly enable it via ``prctl()`` as follows: + + - ``PR_SET_TAGGED_ADDR_CTRL``: enable or disable the AArch64 Tagged + Address ABI for the calling thread. + + The ``(unsigned int) arg2`` argument is a bit mask describing the + control mode used: + + - ``PR_TAGGED_ADDR_ENABLE``: enable AArch64 Tagged Address ABI. + Default status is disabled. + + Arguments ``arg3``, ``arg4``, and ``arg5`` must be 0. + + - ``PR_GET_TAGGED_ADDR_CTRL``: get the status of the AArch64 Tagged + Address ABI for the calling thread. + + Arguments ``arg2``, ``arg3``, ``arg4``, and ``arg5`` must be 0. + + The ABI properties described above are thread-scoped, inherited on + clone() and fork() and cleared on exec(). + + Calling ``prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0)`` + returns ``-EINVAL`` if the AArch64 Tagged Address ABI is globally + disabled by ``sysctl abi.tagged_addr_disabled=1``. The default + ``sysctl abi.tagged_addr_disabled`` configuration is 0. + +When the AArch64 Tagged Address ABI is enabled for a thread, the +following behaviours are guaranteed: + +- All syscalls except the cases mentioned in section 3 can accept any + valid tagged pointer. + +- The syscall behaviour is undefined for invalid tagged pointers: it may + result in an error code being returned, a (fatal) signal being raised, + or other modes of failure. + +- The syscall behaviour for a valid tagged pointer is the same as for + the corresponding untagged pointer. + + +A definition of the meaning of tagged pointers on AArch64 can be found +in Documentation/arm64/tagged-pointers.rst. + +3. AArch64 Tagged Address ABI Exceptions +----------------------------------------- + +The following system call parameters must be untagged regardless of the +ABI relaxation: + +- ``prctl()`` other than pointers to user data either passed directly or + indirectly as arguments to be accessed by the kernel. + +- ``ioctl()`` other than pointers to user data either passed directly or + indirectly as arguments to be accessed by the kernel. + +- ``shmat()`` and ``shmdt()``. + +Any attempt to use non-zero tagged pointers may result in an error code +being returned, a (fatal) signal being raised, or other modes of +failure. + +4. Example of correct usage +--------------------------- +.. code-block:: c + + #include + #include + #include + #include + #include + + #define PR_SET_TAGGED_ADDR_CTRL 55 + #define PR_TAGGED_ADDR_ENABLE (1UL << 0) + + #define TAG_SHIFT 56 + + int main(void) + { + int tbi_enabled = 0; + unsigned long tag = 0; + char *ptr; + + /* check/enable the tagged address ABI */ + if (!prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0)) + tbi_enabled = 1; + + /* memory allocation */ + ptr = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ptr == MAP_FAILED) + return 1; + + /* set a non-zero tag if the ABI is available */ + if (tbi_enabled) + tag = rand() & 0xff; + ptr = (char *)((unsigned long)ptr | (tag << TAG_SHIFT)); + + /* memory access to a tagged address */ + strcpy(ptr, "tagged pointer\n"); + + /* syscall with a tagged pointer */ + write(1, ptr, strlen(ptr)); + + return 0; + } diff --git a/Documentation/arm64/tagged-pointers.rst b/Documentation/arm64/tagged-pointers.rst index 2acdec3ebbeb869c9f93536152364e75232eb45d..eab4323609b97fd8dafa962404713aab8c8c04e9 100644 --- a/Documentation/arm64/tagged-pointers.rst +++ b/Documentation/arm64/tagged-pointers.rst @@ -20,7 +20,9 @@ Passing tagged addresses to the kernel -------------------------------------- All interpretation of userspace memory addresses by the kernel assumes -an address tag of 0x00. +an address tag of 0x00, unless the application enables the AArch64 +Tagged Address ABI explicitly +(Documentation/arm64/tagged-address-abi.rst). This includes, but is not limited to, addresses found in: @@ -33,13 +35,15 @@ This includes, but is not limited to, addresses found in: - the frame pointer (x29) and frame records, e.g. when interpreting them to generate a backtrace or call graph. -Using non-zero address tags in any of these locations may result in an -error code being returned, a (fatal) signal being raised, or other modes -of failure. +Using non-zero address tags in any of these locations when the +userspace application did not enable the AArch64 Tagged Address ABI may +result in an error code being returned, a (fatal) signal being raised, +or other modes of failure. -For these reasons, passing non-zero address tags to the kernel via -system calls is forbidden, and using a non-zero address tag for sp is -strongly discouraged. +For these reasons, when the AArch64 Tagged Address ABI is disabled, +passing non-zero address tags to the kernel via system calls is +forbidden, and using a non-zero address tag for sp is strongly +discouraged. Programs maintaining a frame pointer and frame records that use non-zero address tags may suffer impaired or inaccurate debug and profiling @@ -59,6 +63,9 @@ be preserved. The architecture prevents the use of a tagged PC, so the upper byte will be set to a sign-extension of bit 55 on exception return. +This behaviour is maintained when the AArch64 Tagged Address ABI is +enabled. + Other considerations -------------------- diff --git a/Documentation/auxdisplay/cfag12864b b/Documentation/auxdisplay/cfag12864b deleted file mode 100644 index 12fd51b8de757cac99cf07e330059cf3fb88243f..0000000000000000000000000000000000000000 --- a/Documentation/auxdisplay/cfag12864b +++ /dev/null @@ -1,105 +0,0 @@ - =================================== - cfag12864b LCD Driver Documentation - =================================== - -License: GPLv2 -Author & Maintainer: Miguel Ojeda Sandonis -Date: 2006-10-27 - - - --------- -0. INDEX --------- - - 1. DRIVER INFORMATION - 2. DEVICE INFORMATION - 3. WIRING - 4. USERSPACE PROGRAMMING - - ---------------------- -1. DRIVER INFORMATION ---------------------- - -This driver supports a cfag12864b LCD. - - ---------------------- -2. DEVICE INFORMATION ---------------------- - -Manufacturer: Crystalfontz -Device Name: Crystalfontz 12864b LCD Series -Device Code: cfag12864b -Webpage: http://www.crystalfontz.com -Device Webpage: http://www.crystalfontz.com/products/12864b/ -Type: LCD (Liquid Crystal Display) -Width: 128 -Height: 64 -Colors: 2 (B/N) -Controller: ks0108 -Controllers: 2 -Pages: 8 each controller -Addresses: 64 each page -Data size: 1 byte each address -Memory size: 2 * 8 * 64 * 1 = 1024 bytes = 1 Kbyte - - ---------- -3. WIRING ---------- - -The cfag12864b LCD Series don't have official wiring. - -The common wiring is done to the parallel port as shown: - -Parallel Port cfag12864b - - Name Pin# Pin# Name - -Strobe ( 1)------------------------------(17) Enable -Data 0 ( 2)------------------------------( 4) Data 0 -Data 1 ( 3)------------------------------( 5) Data 1 -Data 2 ( 4)------------------------------( 6) Data 2 -Data 3 ( 5)------------------------------( 7) Data 3 -Data 4 ( 6)------------------------------( 8) Data 4 -Data 5 ( 7)------------------------------( 9) Data 5 -Data 6 ( 8)------------------------------(10) Data 6 -Data 7 ( 9)------------------------------(11) Data 7 - (10) [+5v]---( 1) Vdd - (11) [GND]---( 2) Ground - (12) [+5v]---(14) Reset - (13) [GND]---(15) Read / Write - Line (14)------------------------------(13) Controller Select 1 - (15) - Init (16)------------------------------(12) Controller Select 2 -Select (17)------------------------------(16) Data / Instruction -Ground (18)---[GND] [+5v]---(19) LED + -Ground (19)---[GND] -Ground (20)---[GND] E A Values: -Ground (21)---[GND] [GND]---[P1]---(18) Vee - R = Resistor = 22 ohm -Ground (22)---[GND] | - P1 = Preset = 10 Kohm -Ground (23)---[GND] ---- S ------( 3) V0 - P2 = Preset = 1 Kohm -Ground (24)---[GND] | | -Ground (25)---[GND] [GND]---[P2]---[R]---(20) LED - - - ------------------------- -4. USERSPACE PROGRAMMING ------------------------- - -The cfag12864bfb describes a framebuffer device (/dev/fbX). - -It has a size of 1024 bytes = 1 Kbyte. -Each bit represents one pixel. If the bit is high, the pixel will -turn on. If the pixel is low, the pixel will turn off. - -You can use the framebuffer as a file: fopen, fwrite, fclose... -Although the LCD won't get updated until the next refresh time arrives. - -Also, you can mmap the framebuffer: open & mmap, munmap & close... -which is the best option for most uses. - -Check samples/auxdisplay/cfag12864b-example.c -for a real working userspace complete program with usage examples. diff --git a/Documentation/auxdisplay/ks0108 b/Documentation/auxdisplay/ks0108 deleted file mode 100644 index 8ddda0c8ceefa485f5fe1743a75d79e961e47174..0000000000000000000000000000000000000000 --- a/Documentation/auxdisplay/ks0108 +++ /dev/null @@ -1,55 +0,0 @@ - ========================================== - ks0108 LCD Controller Driver Documentation - ========================================== - -License: GPLv2 -Author & Maintainer: Miguel Ojeda Sandonis -Date: 2006-10-27 - - - --------- -0. INDEX --------- - - 1. DRIVER INFORMATION - 2. DEVICE INFORMATION - 3. WIRING - - ---------------------- -1. DRIVER INFORMATION ---------------------- - -This driver supports the ks0108 LCD controller. - - ---------------------- -2. DEVICE INFORMATION ---------------------- - -Manufacturer: Samsung -Device Name: KS0108 LCD Controller -Device Code: ks0108 -Webpage: - -Device Webpage: - -Type: LCD Controller (Liquid Crystal Display Controller) -Width: 64 -Height: 64 -Colors: 2 (B/N) -Pages: 8 -Addresses: 64 each page -Data size: 1 byte each address -Memory size: 8 * 64 * 1 = 512 bytes - - ---------- -3. WIRING ---------- - -The driver supports data parallel port wiring. - -If you aren't building LCD related hardware, you should check -your LCD specific wiring information in the same folder. - -For example, check Documentation/auxdisplay/cfag12864b. diff --git a/Documentation/block/null_blk.rst b/Documentation/block/null_blk.rst index 31451d80783cf18453fc27c4103205bbcede1f56..edbbab2f12f8c7b99f6a7059acbfa3760b1ac98e 100644 --- a/Documentation/block/null_blk.rst +++ b/Documentation/block/null_blk.rst @@ -1,19 +1,16 @@ +.. SPDX-License-Identifier: GPL-2.0 + ======================== Null block device driver ======================== -1. Overview -=========== +Overview +======== -The null block device (/dev/nullb*) is used for benchmarking the various +The null block device (``/dev/nullb*``) is used for benchmarking the various block-layer implementations. It emulates a block device of X gigabytes in size. -The following instances are possible: - - Single-queue block-layer - - - Request-based. - - Single submission queue per device. - - Implements IO scheduling algorithms (CFQ, Deadline, noop). +It does not execute any read/write operation, just mark them as complete in +the request queue. The following instances are possible: Multi-queue block-layer @@ -27,15 +24,15 @@ The following instances are possible: All of them have a completion queue for each core in the system. -2. Module parameters applicable for all instances -================================================= +Module parameters +================= queue_mode=[0-2]: Default: 2-Multi-queue Selects which block-layer the module should instantiate with. = ============ 0 Bio-based - 1 Single-queue + 1 Single-queue (deprecated) 2 Multi-queue = ============ @@ -67,7 +64,7 @@ irqmode=[0-2]: Default: 1-Soft-irq completion_nsec=[ns]: Default: 10,000ns Combined with irqmode=2 (timer). The time each completion event must wait. -submit_queues=[1..nr_cpus]: +submit_queues=[1..nr_cpus]: Default: 1 The number of submission queues attached to the device driver. If unset, it defaults to 1. For multi-queue, it is ignored when use_per_node_hctx module parameter is 1. @@ -75,9 +72,11 @@ submit_queues=[1..nr_cpus]: hw_queue_depth=[0..qdepth]: Default: 64 The hardware queue depth of the device. -III: Multi-queue specific parameters +Multi-queue specific parameters +------------------------------- use_per_node_hctx=[0/1]: Default: 0 + Number of hardware context queues. = ===================================================================== 0 The number of submit queues are set to the value of the submit_queues @@ -87,6 +86,7 @@ use_per_node_hctx=[0/1]: Default: 0 = ===================================================================== no_sched=[0/1]: Default: 0 + Enable/disable the io scheduler. = ====================================== 0 nullb* use default blk-mq io scheduler @@ -94,6 +94,7 @@ no_sched=[0/1]: Default: 0 = ====================================== blocking=[0/1]: Default: 0 + Blocking behavior of the request queue. = =============================================================== 0 Register as a non-blocking blk-mq driver device. @@ -103,6 +104,7 @@ blocking=[0/1]: Default: 0 = =============================================================== shared_tags=[0/1]: Default: 0 + Sharing tags between devices. = ================================================================ 0 Tag set is not shared. @@ -111,6 +113,7 @@ shared_tags=[0/1]: Default: 0 = ================================================================ zoned=[0/1]: Default: 0 + Device is a random-access or a zoned block device. = ====================================================================== 0 Block device is exposed as a random-access block device. diff --git a/Documentation/block/switching-sched.rst b/Documentation/block/switching-sched.rst index 42042417380ebc05c7f88c9adb773f0e8ee98606..520f6b857544ee09d1bdea1f6467da378938907f 100644 --- a/Documentation/block/switching-sched.rst +++ b/Documentation/block/switching-sched.rst @@ -2,10 +2,6 @@ Switching Scheduler =================== -To choose IO schedulers at boot time, use the argument 'elevator=deadline'. -'noop' and 'cfq' (the default) are also available. IO schedulers are assigned -globally at boot time only presently. - Each io queue has a set of io scheduler tunables associated with it. These tunables control how the io scheduler works. You can find these entries in:: diff --git a/Documentation/bpf/prog_flow_dissector.rst b/Documentation/bpf/prog_flow_dissector.rst index ed343abe541e120738acf8501eab3a02510af76b..a78bf036cadd4c48f6a5165a9880d2beab3d2922 100644 --- a/Documentation/bpf/prog_flow_dissector.rst +++ b/Documentation/bpf/prog_flow_dissector.rst @@ -26,6 +26,7 @@ The inputs are: * ``nhoff`` - initial offset of the networking header * ``thoff`` - initial offset of the transport header, initialized to nhoff * ``n_proto`` - L3 protocol type, parsed out of L2 header + * ``flags`` - optional flags Flow dissector BPF program should fill out the rest of the ``struct bpf_flow_keys`` fields. Input arguments ``nhoff/thoff/n_proto`` should be @@ -101,6 +102,23 @@ can be called for both cases and would have to be written carefully to handle both cases. +Flags +===== + +``flow_keys->flags`` might contain optional input flags that work as follows: + +* ``BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG`` - tells BPF flow dissector to + continue parsing first fragment; the default expected behavior is that + flow dissector returns as soon as it finds out that the packet is fragmented; + used by ``eth_get_headlen`` to estimate length of all headers for GRO. +* ``BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL`` - tells BPF flow dissector to + stop parsing as soon as it reaches IPv6 flow label; used by + ``___skb_get_hash`` and ``__skb_get_hash_symmetric`` to get flow hash. +* ``BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP`` - tells BPF flow dissector to stop + parsing as soon as it reaches encapsulated headers; used by routing + infrastructure. + + Reference Implementation ======================== diff --git a/Documentation/core-api/index.rst b/Documentation/core-api/index.rst index da0ed972d22440f5115e6d104a2b44b4cb1b9a41..fa16a0538dcbf4f091cb45bb72949219ed92e4f4 100644 --- a/Documentation/core-api/index.rst +++ b/Documentation/core-api/index.rst @@ -25,6 +25,7 @@ Core utilities librs genalloc errseq + packing printk-formats circular-buffers generic-radix-tree @@ -48,7 +49,7 @@ Interfaces for kernel debugging debug-objects tracepoint -.. only:: subproject +.. only:: subproject and html Indices ======= diff --git a/Documentation/packing.txt b/Documentation/core-api/packing.rst similarity index 61% rename from Documentation/packing.txt rename to Documentation/core-api/packing.rst index f830c98645f103e43bc294e090abe07842f2f447..d8c341fe383e58ea0ef6d96003b79036705201dc 100644 --- a/Documentation/packing.txt +++ b/Documentation/core-api/packing.rst @@ -30,6 +30,7 @@ The solution ------------ This API deals with 2 basic operations: + - Packing a CPU-usable number into a memory buffer (with hardware constraints/quirks) - Unpacking a memory buffer (which has hardware constraints/quirks) @@ -49,10 +50,12 @@ What the examples show is where the logical bytes and bits sit. 1. Normally (no quirks), we would do it like this: -63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 -7 6 5 4 -31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -3 2 1 0 +:: + + 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 + 7 6 5 4 + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + 3 2 1 0 That is, the MSByte (7) of the CPU-usable u64 sits at memory offset 0, and the LSByte (0) of the u64 sits at memory offset 7. @@ -63,10 +66,12 @@ comments as "logical" notation. 2. If QUIRK_MSB_ON_THE_RIGHT is set, we do it like this: -56 57 58 59 60 61 62 63 48 49 50 51 52 53 54 55 40 41 42 43 44 45 46 47 32 33 34 35 36 37 38 39 -7 6 5 4 -24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 -3 2 1 0 +:: + + 56 57 58 59 60 61 62 63 48 49 50 51 52 53 54 55 40 41 42 43 44 45 46 47 32 33 34 35 36 37 38 39 + 7 6 5 4 + 24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 + 3 2 1 0 That is, QUIRK_MSB_ON_THE_RIGHT does not affect byte positioning, but inverts bit offsets inside a byte. @@ -74,10 +79,12 @@ inverts bit offsets inside a byte. 3. If QUIRK_LITTLE_ENDIAN is set, we do it like this: -39 38 37 36 35 34 33 32 47 46 45 44 43 42 41 40 55 54 53 52 51 50 49 48 63 62 61 60 59 58 57 56 -4 5 6 7 -7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24 -0 1 2 3 +:: + + 39 38 37 36 35 34 33 32 47 46 45 44 43 42 41 40 55 54 53 52 51 50 49 48 63 62 61 60 59 58 57 56 + 4 5 6 7 + 7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24 + 0 1 2 3 Therefore, QUIRK_LITTLE_ENDIAN means that inside the memory region, every byte from each 4-byte word is placed at its mirrored position compared to @@ -86,18 +93,22 @@ the boundary of that word. 4. If QUIRK_MSB_ON_THE_RIGHT and QUIRK_LITTLE_ENDIAN are both set, we do it like this: -32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 -4 5 6 7 -0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 -0 1 2 3 +:: + + 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 + 4 5 6 7 + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 + 0 1 2 3 5. If just QUIRK_LSW32_IS_FIRST is set, we do it like this: -31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -3 2 1 0 -63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 -7 6 5 4 +:: + + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + 3 2 1 0 + 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 + 7 6 5 4 In this case the 8 byte memory region is interpreted as follows: first 4 bytes correspond to the least significant 4-byte word, next 4 bytes to @@ -107,28 +118,34 @@ the more significant 4-byte word. 6. If QUIRK_LSW32_IS_FIRST and QUIRK_MSB_ON_THE_RIGHT are set, we do it like this: -24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 -3 2 1 0 -56 57 58 59 60 61 62 63 48 49 50 51 52 53 54 55 40 41 42 43 44 45 46 47 32 33 34 35 36 37 38 39 -7 6 5 4 +:: + + 24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 + 3 2 1 0 + 56 57 58 59 60 61 62 63 48 49 50 51 52 53 54 55 40 41 42 43 44 45 46 47 32 33 34 35 36 37 38 39 + 7 6 5 4 7. If QUIRK_LSW32_IS_FIRST and QUIRK_LITTLE_ENDIAN are set, it looks like this: -7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24 -0 1 2 3 -39 38 37 36 35 34 33 32 47 46 45 44 43 42 41 40 55 54 53 52 51 50 49 48 63 62 61 60 59 58 57 56 -4 5 6 7 +:: + + 7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24 + 0 1 2 3 + 39 38 37 36 35 34 33 32 47 46 45 44 43 42 41 40 55 54 53 52 51 50 49 48 63 62 61 60 59 58 57 56 + 4 5 6 7 8. If QUIRK_LSW32_IS_FIRST, QUIRK_LITTLE_ENDIAN and QUIRK_MSB_ON_THE_RIGHT are set, it looks like this: -0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 -0 1 2 3 -32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 -4 5 6 7 +:: + + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 + 0 1 2 3 + 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 + 4 5 6 7 We always think of our offsets as if there were no quirk, and we translate diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst index c6224d039bcbe98d7e05bb434a746772638993e0..ecbebf4ca8e7e74641ce6d0bf247a0e9aaade724 100644 --- a/Documentation/core-api/printk-formats.rst +++ b/Documentation/core-api/printk-formats.rst @@ -13,10 +13,10 @@ Integer types If variable is of Type, use printk format specifier: ------------------------------------------------------------ - char %hhd or %hhx - unsigned char %hhu or %hhx - short int %hd or %hx - unsigned short int %hu or %hx + char %d or %x + unsigned char %u or %x + short int %d or %x + unsigned short int %u or %x int %d or %x unsigned int %u or %x long %ld or %lx @@ -25,10 +25,10 @@ Integer types unsigned long long %llu or %llx size_t %zu or %zx ssize_t %zd or %zx - s8 %hhd or %hhx - u8 %hhu or %hhx - s16 %hd or %hx - u16 %hu or %hx + s8 %d or %x + u8 %u or %x + s16 %d or %x + u16 %u or %x s32 %d or %x u32 %u or %x s64 %lld or %llx diff --git a/Documentation/cpu-freq/core.txt b/Documentation/cpu-freq/core.txt index 55193e680250933ef9d16ea3fa6d75a464e74528..ed577d9c154b630f7d6e801abe7b749e455ac750 100644 --- a/Documentation/cpu-freq/core.txt +++ b/Documentation/cpu-freq/core.txt @@ -57,19 +57,11 @@ transition notifiers. 2.1 CPUFreq policy notifiers ---------------------------- -These are notified when a new policy is intended to be set. Each -CPUFreq policy notifier is called twice for a policy transition: +These are notified when a new policy is created or removed. -1.) During CPUFREQ_ADJUST all CPUFreq notifiers may change the limit if - they see a need for this - may it be thermal considerations or - hardware limitations. - -2.) And during CPUFREQ_NOTIFY all notifiers are informed of the new policy - - if two hardware drivers failed to agree on a new policy before this - stage, the incompatible hardware shall be shut down, and the user - informed of this. - -The phase is specified in the second argument to the notifier. +The phase is specified in the second argument to the notifier. The phase is +CPUFREQ_CREATE_POLICY when the policy is first created and it is +CPUFREQ_REMOVE_POLICY when the policy is removed. The third argument, a void *pointer, points to a struct cpufreq_policy consisting of several values, including min, max (the lower and upper diff --git a/Documentation/crypto/crypto_engine.rst b/Documentation/crypto/crypto_engine.rst index 236c674d68978c9e22c5e99b3f5ebdbd0828da2f..3baa23c2cd08052f9788973577969a54d3e6db30 100644 --- a/Documentation/crypto/crypto_engine.rst +++ b/Documentation/crypto/crypto_engine.rst @@ -1,4 +1,5 @@ .. SPDX-License-Identifier: GPL-2.0 + Crypto Engine ============= diff --git a/Documentation/devicetree/bindings/arm/amlogic.yaml b/Documentation/devicetree/bindings/arm/amlogic.yaml index 325c6fd3566d4f3c6ea0476bb8fbde45e6732c27..99015cef8bb14e971845eca12dc49412b23d66f5 100644 --- a/Documentation/devicetree/bindings/arm/amlogic.yaml +++ b/Documentation/devicetree/bindings/arm/amlogic.yaml @@ -91,13 +91,11 @@ properties: - description: Boards with the Amlogic Meson GXL S905X SoC items: - enum: - - amediatech,x96-max - amlogic,p212 - hwacom,amazetv - khadas,vim - libretech,cc - nexbox,a95x - - seirobotics,sei510 - const: amlogic,s905x - const: amlogic,meson-gxl @@ -129,16 +127,33 @@ properties: - const: amlogic,a113d - const: amlogic,meson-axg - - description: Boards with the Amlogic Meson G12A S905D2 SoC + - description: Boards with the Amlogic Meson G12A S905D2/X2/Y2 SoC items: - enum: + - amediatech,x96-max - amlogic,u200 + - seirobotics,sei510 - const: amlogic,g12a + - description: Boards with the Amlogic Meson G12B A311D SoC + items: + - enum: + - khadas,vim3 + - const: amlogic,a311d + - const: amlogic,g12b + - description: Boards with the Amlogic Meson G12B S922X SoC items: - enum: - hardkernel,odroid-n2 + - khadas,vim3 + - const: amlogic,s922x - const: amlogic,g12b + - description: Boards with the Amlogic Meson SM1 S905X3/D3/Y3 SoC + items: + - enum: + - seirobotics,sei610 + - khadas,vim3l + - const: amlogic,sm1 ... diff --git a/Documentation/devicetree/bindings/arm/arm,scmi.txt b/Documentation/devicetree/bindings/arm/arm,scmi.txt index 317a2fc3667a91d51cd45a6162e96e2b014b90ed..083dbf96ee00c5324c0cdd877f3fd3f91ee169ec 100644 --- a/Documentation/devicetree/bindings/arm/arm,scmi.txt +++ b/Documentation/devicetree/bindings/arm/arm,scmi.txt @@ -73,6 +73,16 @@ Required properties: as used by the firmware. Refer to platform details for your implementation for the IDs to use. +Reset signal bindings for the reset domains based on SCMI Message Protocol +------------------------------------------------------------ + +This binding for the SCMI reset domain providers uses the generic reset +signal binding[5]. + +Required properties: + - #reset-cells : Should be 1. Contains the reset domain ID value used + by SCMI commands. + SRAM and Shared Memory for SCMI ------------------------------- @@ -93,6 +103,7 @@ Required sub-node properties: [2] Documentation/devicetree/bindings/power/power_domain.txt [3] Documentation/devicetree/bindings/thermal/thermal.txt [4] Documentation/devicetree/bindings/sram/sram.txt +[5] Documentation/devicetree/bindings/reset/reset.txt Example: @@ -152,6 +163,11 @@ firmware { reg = <0x15>; #thermal-sensor-cells = <1>; }; + + scmi_reset: protocol@16 { + reg = <0x16>; + #reset-cells = <1>; + }; }; }; @@ -166,6 +182,7 @@ hdlcd@7ff60000 { reg = <0 0x7ff60000 0 0x1000>; clocks = <&scmi_clk 4>; power-domains = <&scmi_devpd 1>; + resets = <&scmi_reset 10>; }; thermal-zones { diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml index aa40b074b8648345ba944f3426b41c787d477e13..727e0ffc702bfcc7ef99353fc57aaadbecabd7d9 100644 --- a/Documentation/devicetree/bindings/arm/cpus.yaml +++ b/Documentation/devicetree/bindings/arm/cpus.yaml @@ -175,6 +175,7 @@ properties: - amlogic,meson8-smp - amlogic,meson8b-smp - arm,realview-smp + - aspeed,ast2600-smp - brcm,bcm11351-cpu-method - brcm,bcm23550 - brcm,bcm2836-smp diff --git a/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt b/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt index a575e42f7fecc1a60e3dda93ccb2544e13590406..c149fadc6f47f38f45d13edfd638d7e16c6c5af2 100644 --- a/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt +++ b/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt @@ -136,7 +136,9 @@ Required properties: OCOTP bindings based on SCU Message Protocol ------------------------------------------------------------ Required properties: -- compatible: Should be "fsl,imx8qxp-scu-ocotp" +- compatible: Should be one of: + "fsl,imx8qm-scu-ocotp", + "fsl,imx8qxp-scu-ocotp". - #address-cells: Must be 1. Contains byte index - #size-cells: Must be 1. Contains byte length diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml index 7294ac36f4c0be99557a1d6b7dca331d97222d80..1b4b4e6573b59d5206f789691bb2919b815c76b2 100644 --- a/Documentation/devicetree/bindings/arm/fsl.yaml +++ b/Documentation/devicetree/bindings/arm/fsl.yaml @@ -161,6 +161,20 @@ properties: items: - enum: - fsl,imx6ul-14x14-evk # i.MX6 UltraLite 14x14 EVK Board + - kontron,imx6ul-n6310-som # Kontron N6310 SOM + - const: fsl,imx6ul + + - description: Kontron N6310 S Board + items: + - const: kontron,imx6ul-n6310-s + - const: kontron,imx6ul-n6310-som + - const: fsl,imx6ul + + - description: Kontron N6310 S 43 Board + items: + - const: kontron,imx6ul-n6310-s-43 + - const: kontron,imx6ul-n6310-s + - const: kontron,imx6ul-n6310-som - const: fsl,imx6ul - description: i.MX6ULL based Boards @@ -188,6 +202,7 @@ properties: - fsl,imx7d-sdb # i.MX7 SabreSD Board - novtech,imx7d-meerkat96 # i.MX7 Meerkat96 Board - tq,imx7d-mba7 # i.MX7D TQ MBa7 with TQMa7D SoM + - zii,imx7d-rmu2 # ZII RMU2 Board - zii,imx7d-rpu2 # ZII RPU2 Board - const: fsl,imx7d @@ -214,16 +229,26 @@ properties: - fsl,imx8mm-evk # i.MX8MM EVK Board - const: fsl,imx8mm + - description: i.MX8MN based Boards + items: + - enum: + - fsl,imx8mn-ddr4-evk # i.MX8MN DDR4 EVK Board + - const: fsl,imx8mn + - description: i.MX8MQ based Boards items: - enum: + - boundary,imx8mq-nitrogen8m # i.MX8MQ NITROGEN Board - fsl,imx8mq-evk # i.MX8MQ EVK Board - purism,librem5-devkit # Purism Librem5 devkit + - solidrun,hummingboard-pulse # SolidRun Hummingboard Pulse + - technexion,pico-pi-imx8m # TechNexion PICO-PI-8M evk - const: fsl,imx8mq - description: i.MX8QXP based Boards items: - enum: + - einfochips,imx8qxp-ai_ml # i.MX8QXP AI_ML Board - fsl,imx8qxp-mek # i.MX8QXP MEK Board - const: fsl,imx8qxp @@ -283,6 +308,7 @@ properties: - description: LS1046A based Boards items: - enum: + - fsl,ls1046a-frwy - fsl,ls1046a-qds - fsl,ls1046a-rdb - const: fsl,ls1046a diff --git a/Documentation/devicetree/bindings/arm/mediatek.yaml b/Documentation/devicetree/bindings/arm/mediatek.yaml index a4ad2eb926f99d73ae834030b672ff98f295ffa2..4043c504644181d511b7e1f4145b783ae38d4e00 100644 --- a/Documentation/devicetree/bindings/arm/mediatek.yaml +++ b/Documentation/devicetree/bindings/arm/mediatek.yaml @@ -46,6 +46,10 @@ properties: - enum: - mediatek,mt6765-evb - const: mediatek,mt6765 + - items: + - enum: + - mediatek,mt6779-evb + - const: mediatek,mt6779 - items: - enum: - mediatek,mt6795-evb diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,sgmiisys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,sgmiisys.txt index f5518f26a91440a549250f976de2e2395e41ed1d..30cb645c0e5483a35206f9495df0ba787ea04940 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,sgmiisys.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,sgmiisys.txt @@ -9,8 +9,6 @@ Required Properties: - "mediatek,mt7622-sgmiisys", "syscon" - "mediatek,mt7629-sgmiisys", "syscon" - #clock-cells: Must be 1 -- mediatek,physpeed: Should be one of "auto", "1000" or "2500" to match up - the capability of the target PHY. The SGMIISYS controller uses the common clk binding from Documentation/devicetree/bindings/clock/clock-bindings.txt diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index 54ef6b6b9189bf26524ad7f093c5466b5fe7e118..e39d8f02e33c12968fd7c40ca1ed791548d9823b 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -45,6 +45,7 @@ description: | mtp sbc hk01 + qrd The 'soc_version' and 'board_version' elements take the form of v. where the minor number may be omitted when it's zero, i.e. v1.0 is the same @@ -115,6 +116,13 @@ properties: - const: qcom,msm8916-mtp - const: qcom,msm8916 + - items: + - enum: + - longcheer,l8150 + - samsung,a3u-eur + - samsung,a5u-eur + - const: qcom,msm8916 + - items: - const: qcom,msm8996-mtp diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml index 34865042f4e458077c7a32c9b7394467c2f3f33e..c82c5e57d44c828c979eddd9ec43eaaf4e5fd53b 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.yaml +++ b/Documentation/devicetree/bindings/arm/rockchip.yaml @@ -128,6 +128,21 @@ properties: - const: google,veyron - const: rockchip,rk3288 + - description: Google Fievel (AOPEN Chromebox Mini) + items: + - const: google,veyron-fievel-rev8 + - const: google,veyron-fievel-rev7 + - const: google,veyron-fievel-rev6 + - const: google,veyron-fievel-rev5 + - const: google,veyron-fievel-rev4 + - const: google,veyron-fievel-rev3 + - const: google,veyron-fievel-rev2 + - const: google,veyron-fievel-rev1 + - const: google,veyron-fievel-rev0 + - const: google,veyron-fievel + - const: google,veyron + - const: rockchip,rk3288 + - description: Google Gru (dev-board) items: - const: google,gru-rev15 @@ -311,6 +326,21 @@ properties: - const: google,veyron - const: rockchip,rk3288 + - description: Google Tiger (AOpen Chromebase Mini) + items: + - const: google,veyron-tiger-rev8 + - const: google,veyron-tiger-rev7 + - const: google,veyron-tiger-rev6 + - const: google,veyron-tiger-rev5 + - const: google,veyron-tiger-rev4 + - const: google,veyron-tiger-rev3 + - const: google,veyron-tiger-rev2 + - const: google,veyron-tiger-rev1 + - const: google,veyron-tiger-rev0 + - const: google,veyron-tiger + - const: google,veyron + - const: rockchip,rk3288 + - description: Haoyu MarsBoard RK3066 items: - const: haoyu,marsboard-rk3066 @@ -329,6 +359,16 @@ properties: - khadas,edge-v - const: rockchip,rk3399 + - description: Mecer Xtreme Mini S6 + items: + - const: mecer,xms6 + - const: rockchip,rk3229 + + - description: Leez RK3399 P710 + items: + - const: leez,p710 + - const: rockchip,rk3399 + - description: mqmaker MiQi items: - const: mqmaker,miqi @@ -424,11 +464,6 @@ properties: - rockchip,rk3288-evb-rk808 - const: rockchip,rk3288 - - description: Rockchip RK3288 Fennec - items: - - const: rockchip,rk3288-fennec - - const: rockchip,rk3288 - - description: Rockchip RK3328 Evaluation board items: - const: rockchip,rk3328-evb diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml b/Documentation/devicetree/bindings/arm/sunxi.yaml index 000a00d12d6a44267ef86e0c0d39d8c215721f5a..972b1e9ee80487f5a158fe23ab28f5da6ef08e38 100644 --- a/Documentation/devicetree/bindings/arm/sunxi.yaml +++ b/Documentation/devicetree/bindings/arm/sunxi.yaml @@ -353,6 +353,12 @@ properties: - const: licheepi,licheepi-zero - const: allwinner,sun8i-v3s + - description: Lichee Zero Plus (with S3, without eMMC/SPI Flash) + items: + - const: sipeed,lichee-zero-plus + - const: sochip,s3 + - const: allwinner,sun8i-v3 + - description: Linksprite PCDuino items: - const: linksprite,a10-pcduino @@ -568,6 +574,11 @@ properties: - const: olimex,a64-olinuxino - const: allwinner,sun50i-a64 + - description: Olimex A64-OlinuXino (with eMMC) + items: + - const: olimex,a64-olinuxino-emmc + - const: allwinner,sun50i-a64 + - description: Olimex A64 Teres-I items: - const: olimex,a64-teres-i @@ -671,6 +682,11 @@ properties: - const: sinlinx,sina33 - const: allwinner,sun8i-a33 + - description: Tanix TX6 + items: + - const: oranth,tanix-tx6 + - const: allwinner,sun50i-h6 + - description: TBS A711 Tablet items: - const: tbs-biometrics,a711 diff --git a/Documentation/devicetree/bindings/bus/imx-weim.txt b/Documentation/devicetree/bindings/bus/imx-weim.txt index dda7d6d6647987fc0ef46ad38dd6b1de4c44c9d5..1b1d1c5c21ea1e40e61a01a2d1cc34402394117d 100644 --- a/Documentation/devicetree/bindings/bus/imx-weim.txt +++ b/Documentation/devicetree/bindings/bus/imx-weim.txt @@ -44,6 +44,10 @@ Optional properties: what bootloader sets up in IOMUXC_GPR1[11:0] will be used. + - fsl,burst-clk-enable For "fsl,imx50-weim" and "fsl,imx6q-weim" type of + devices, the presence of this property indicates that + the weim bus should operate in Burst Clock Mode. + Timing property for child nodes. It is mandatory, not optional. - fsl,weim-cs-timing: The timing array, contains timing values for the diff --git a/Documentation/devicetree/bindings/bus/moxtet.txt b/Documentation/devicetree/bindings/bus/moxtet.txt new file mode 100644 index 0000000000000000000000000000000000000000..fb50fc865336890792e941d0845f4b264ef6a859 --- /dev/null +++ b/Documentation/devicetree/bindings/bus/moxtet.txt @@ -0,0 +1,46 @@ +Turris Mox module status and configuration bus (over SPI) + +Required properties: + - compatible : Should be "cznic,moxtet" + - #address-cells : Has to be 1 + - #size-cells : Has to be 0 + - spi-cpol : Required inverted clock polarity + - spi-cpha : Required shifted clock phase + - interrupts : Must contain reference to the shared interrupt line + - interrupt-controller : Required + - #interrupt-cells : Has to be 1 + +For other required and optional properties of SPI slave nodes please refer to +../spi/spi-bus.txt. + +Required properties of subnodes: + - reg : Should be position on the Moxtet bus (how many Moxtet + modules are between this module and CPU module, so + either 0 or a positive integer) + +The driver finds the devices connected to the bus by itself, but it may be +needed to reference some of them from other parts of the device tree. In that +case the devices can be defined as subnodes of the moxtet node. + +Example: + + moxtet@1 { + compatible = "cznic,moxtet"; + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + spi-max-frequency = <10000000>; + spi-cpol; + spi-cpha; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gpiosb>; + interrupts = <5 IRQ_TYPE_EDGE_FALLING>; + + moxtet_sfp: gpio@0 { + compatible = "cznic,moxtet-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0>; + } + }; diff --git a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt index 0f777749f4f1e3b82fceed4788e48bc738adbe3f..b3957d10d241fb434aead20f3e9b3586f0f3d060 100644 --- a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt +++ b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt @@ -22,6 +22,7 @@ Required Properties: components. - resets : phandle of the internal reset line - #clock-cells : should be 1. +- #reset-cells : should be 1 on the g12a (and following) soc family Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. All available clocks are defined as diff --git a/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt index 6eaa52092313915d5dcb30590f4deee2640a0368..7ccecd5c02c1730fa953631b5e4b8f02250d83e2 100644 --- a/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt +++ b/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt @@ -11,6 +11,7 @@ Required Properties: "amlogic,axg-clkc" for AXG SoC. "amlogic,g12a-clkc" for G12A SoC. "amlogic,g12b-clkc" for G12B SoC. + "amlogic,sm1-clkc" for SM1 SoC. - clocks : list of clock phandle, one for each entry clock-names. - clock-names : should contain the following: * "xtal": the platform xtal diff --git a/Documentation/devicetree/bindings/clock/imx8mn-clock.yaml b/Documentation/devicetree/bindings/clock/imx8mn-clock.yaml new file mode 100644 index 0000000000000000000000000000000000000000..622f3658bd9f6484c7a82d32cf84b21e50cd03cf --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx8mn-clock.yaml @@ -0,0 +1,112 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/bindings/clock/imx8mn-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP i.MX8M Nano Clock Control Module Binding + +maintainers: + - Anson Huang + +description: | + NXP i.MX8M Nano clock control module is an integrated clock controller, which + generates and supplies to all modules. + +properties: + compatible: + const: fsl,imx8mn-ccm + + reg: + maxItems: 1 + + clocks: + items: + - description: 32k osc + - description: 24m osc + - description: ext1 clock input + - description: ext2 clock input + - description: ext3 clock input + - description: ext4 clock input + + clock-names: + items: + - const: osc_32k + - const: osc_24m + - const: clk_ext1 + - const: clk_ext2 + - const: clk_ext3 + - const: clk_ext4 + + '#clock-cells': + const: 1 + description: | + The clock consumer should specify the desired clock by having the clock + ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mn-clock.h + for the full list of i.MX8M Nano clock IDs. + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + +examples: + # Clock Control Module node: + - | + clk: clock-controller@30380000 { + compatible = "fsl,imx8mn-ccm"; + reg = <0x0 0x30380000 0x0 0x10000>; + #clock-cells = <1>; + clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, + <&clk_ext2>, <&clk_ext3>, <&clk_ext4>; + clock-names = "osc_32k", "osc_24m", "clk_ext1", + "clk_ext2", "clk_ext3", "clk_ext4"; + }; + + # Required external clocks for Clock Control Module node: + - | + osc_32k: clock-osc-32k { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + clock-output-names = "osc_32k"; + }; + + osc_24m: clock-osc-24m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "osc_24m"; + }; + + clk_ext1: clock-ext1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <133000000>; + clock-output-names = "clk_ext1"; + }; + + clk_ext2: clock-ext2 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <133000000>; + clock-output-names = "clk_ext2"; + }; + + clk_ext3: clock-ext3 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <133000000>; + clock-output-names = "clk_ext3"; + }; + + clk_ext4: clock-ext4 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency= <133000000>; + clock-output-names = "clk_ext4"; + }; + +... diff --git a/Documentation/devicetree/bindings/connector/usb-connector.txt b/Documentation/devicetree/bindings/connector/usb-connector.txt index cef556d4e5ee0b39b5229f860277974aca589383..d357987181ee014f92afe0937e07bec66dfc52be 100644 --- a/Documentation/devicetree/bindings/connector/usb-connector.txt +++ b/Documentation/devicetree/bindings/connector/usb-connector.txt @@ -17,6 +17,20 @@ Optional properties: - self-powered: Set this property if the usb device that has its own power source. +Optional properties for usb-b-connector: +- id-gpios: an input gpio for USB ID pin. +- vbus-gpios: an input gpio for USB VBUS pin, used to detect presence of + VBUS 5V. + see gpio/gpio.txt. +- vbus-supply: a phandle to the regulator for USB VBUS if needed when host + mode or dual role mode is supported. + Particularly, if use an output GPIO to control a VBUS regulator, should + model it as a regulator. + see regulator/fixed-regulator.yaml +- pinctrl-names : a pinctrl state named "default" is optional +- pinctrl-0 : pin control group + see pinctrl/pinctrl-bindings.txt + Optional properties for usb-c-connector: - power-role: should be one of "source", "sink" or "dual"(DRP) if typec connector has power support. diff --git a/Documentation/devicetree/bindings/arm/topology.txt b/Documentation/devicetree/bindings/cpu/cpu-topology.txt similarity index 66% rename from Documentation/devicetree/bindings/arm/topology.txt rename to Documentation/devicetree/bindings/cpu/cpu-topology.txt index b0d80c0fb2653bb9abc17bcfd8b22e89a8196c0d..99918189403cabefacd1466611d9452dc7c66f96 100644 --- a/Documentation/devicetree/bindings/arm/topology.txt +++ b/Documentation/devicetree/bindings/cpu/cpu-topology.txt @@ -1,21 +1,19 @@ =========================================== -ARM topology binding description +CPU topology binding description =========================================== =========================================== 1 - Introduction =========================================== -In an ARM system, the hierarchy of CPUs is defined through three entities that +In a SMP system, the hierarchy of CPUs is defined through three entities that are used to describe the layout of physical CPUs in the system: +- socket - cluster - core - thread -The cpu nodes (bindings defined in [1]) represent the devices that -correspond to physical CPUs and are to be mapped to the hierarchy levels. - The bottom hierarchy level sits at core or thread level depending on whether symmetric multi-threading (SMT) is supported or not. @@ -24,33 +22,31 @@ threads existing in the system and map to the hierarchy level "thread" above. In systems where SMT is not supported "cpu" nodes represent all cores present in the system and map to the hierarchy level "core" above. -ARM topology bindings allow one to associate cpu nodes with hierarchical groups +CPU topology bindings allow one to associate cpu nodes with hierarchical groups corresponding to the system hierarchy; syntactically they are defined as device tree nodes. -The remainder of this document provides the topology bindings for ARM, based -on the Devicetree Specification, available from: +Currently, only ARM/RISC-V intend to use this cpu topology binding but it may be +used for any other architecture as well. -https://www.devicetree.org/specifications/ +The cpu nodes, as per bindings defined in [4], represent the devices that +correspond to physical CPUs and are to be mapped to the hierarchy levels. -If not stated otherwise, whenever a reference to a cpu node phandle is made its -value must point to a cpu node compliant with the cpu node bindings as -documented in [1]. A topology description containing phandles to cpu nodes that are not compliant -with bindings standardized in [1] is therefore considered invalid. +with bindings standardized in [4] is therefore considered invalid. =========================================== 2 - cpu-map node =========================================== -The ARM CPU topology is defined within the cpu-map node, which is a direct +The ARM/RISC-V CPU topology is defined within the cpu-map node, which is a direct child of the cpus node and provides a container where the actual topology nodes are listed. - cpu-map node - Usage: Optional - On ARM SMP systems provide CPUs topology to the OS. - ARM uniprocessor systems do not require a topology + Usage: Optional - On SMP systems provide CPUs topology to the OS. + Uniprocessor systems do not require a topology description and therefore should not define a cpu-map node. @@ -63,21 +59,23 @@ nodes are listed. The cpu-map node's child nodes can be: - - one or more cluster nodes + - one or more cluster nodes or + - one or more socket nodes in a multi-socket system Any other configuration is considered invalid. -The cpu-map node can only contain three types of child nodes: +The cpu-map node can only contain 4 types of child nodes: +- socket node - cluster node - core node - thread node whose bindings are described in paragraph 3. -The nodes describing the CPU topology (cluster/core/thread) can only -be defined within the cpu-map node and every core/thread in the system -must be defined within the topology. Any other configuration is +The nodes describing the CPU topology (socket/cluster/core/thread) can +only be defined within the cpu-map node and every core/thread in the +system must be defined within the topology. Any other configuration is invalid and therefore must be ignored. =========================================== @@ -85,26 +83,44 @@ invalid and therefore must be ignored. =========================================== cpu-map child nodes must follow a naming convention where the node name -must be "clusterN", "coreN", "threadN" depending on the node type (ie -cluster/core/thread) (where N = {0, 1, ...} is the node number; nodes which -are siblings within a single common parent node must be given a unique and +must be "socketN", "clusterN", "coreN", "threadN" depending on the node type +(ie socket/cluster/core/thread) (where N = {0, 1, ...} is the node number; nodes +which are siblings within a single common parent node must be given a unique and sequential N value, starting from 0). cpu-map child nodes which do not share a common parent node can have the same name (ie same number N as other cpu-map child nodes at different device tree levels) since name uniqueness will be guaranteed by the device tree hierarchy. =========================================== -3 - cluster/core/thread node bindings +3 - socket/cluster/core/thread node bindings =========================================== -Bindings for cluster/cpu/thread nodes are defined as follows: +Bindings for socket/cluster/cpu/thread nodes are defined as follows: + +- socket node + + Description: must be declared within a cpu-map node, one node + per physical socket in the system. A system can + contain single or multiple physical socket. + The association of sockets and NUMA nodes is beyond + the scope of this bindings, please refer [2] for + NUMA bindings. + + This node is optional for a single socket system. + + The socket node name must be "socketN" as described in 2.1 above. + A socket node can not be a leaf node. + + A socket node's child nodes must be one or more cluster nodes. + + Any other configuration is considered invalid. - cluster node Description: must be declared within a cpu-map node, one node per cluster. A system can contain several layers of - clustering and cluster nodes can be contained in parent - cluster nodes. + clustering within a single physical socket and cluster + nodes can be contained in parent cluster nodes. The cluster node name must be "clusterN" as described in 2.1 above. A cluster node can not be a leaf node. @@ -164,90 +180,93 @@ Bindings for cluster/cpu/thread nodes are defined as follows: 4 - Example dts =========================================== -Example 1 (ARM 64-bit, 16-cpu system, two clusters of clusters): +Example 1 (ARM 64-bit, 16-cpu system, two clusters of clusters in a single +physical socket): cpus { #size-cells = <0>; #address-cells = <2>; cpu-map { - cluster0 { + socket0 { cluster0 { - core0 { - thread0 { - cpu = <&CPU0>; + cluster0 { + core0 { + thread0 { + cpu = <&CPU0>; + }; + thread1 { + cpu = <&CPU1>; + }; }; - thread1 { - cpu = <&CPU1>; - }; - }; - core1 { - thread0 { - cpu = <&CPU2>; - }; - thread1 { - cpu = <&CPU3>; + core1 { + thread0 { + cpu = <&CPU2>; + }; + thread1 { + cpu = <&CPU3>; + }; }; }; - }; - cluster1 { - core0 { - thread0 { - cpu = <&CPU4>; - }; - thread1 { - cpu = <&CPU5>; + cluster1 { + core0 { + thread0 { + cpu = <&CPU4>; + }; + thread1 { + cpu = <&CPU5>; + }; }; - }; - core1 { - thread0 { - cpu = <&CPU6>; - }; - thread1 { - cpu = <&CPU7>; - }; - }; - }; - }; - - cluster1 { - cluster0 { - core0 { - thread0 { - cpu = <&CPU8>; - }; - thread1 { - cpu = <&CPU9>; - }; - }; - core1 { - thread0 { - cpu = <&CPU10>; - }; - thread1 { - cpu = <&CPU11>; + core1 { + thread0 { + cpu = <&CPU6>; + }; + thread1 { + cpu = <&CPU7>; + }; }; }; }; cluster1 { - core0 { - thread0 { - cpu = <&CPU12>; + cluster0 { + core0 { + thread0 { + cpu = <&CPU8>; + }; + thread1 { + cpu = <&CPU9>; + }; }; - thread1 { - cpu = <&CPU13>; + core1 { + thread0 { + cpu = <&CPU10>; + }; + thread1 { + cpu = <&CPU11>; + }; }; }; - core1 { - thread0 { - cpu = <&CPU14>; + + cluster1 { + core0 { + thread0 { + cpu = <&CPU12>; + }; + thread1 { + cpu = <&CPU13>; + }; }; - thread1 { - cpu = <&CPU15>; + core1 { + thread0 { + cpu = <&CPU14>; + }; + thread1 { + cpu = <&CPU15>; + }; }; }; }; @@ -470,6 +489,65 @@ cpus { }; }; +Example 3: HiFive Unleashed (RISC-V 64 bit, 4 core system) + +{ + #address-cells = <2>; + #size-cells = <2>; + compatible = "sifive,fu540g", "sifive,fu500"; + model = "sifive,hifive-unleashed-a00"; + + ... + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu-map { + socket0 { + cluster0 { + core0 { + cpu = <&CPU1>; + }; + core1 { + cpu = <&CPU2>; + }; + core2 { + cpu0 = <&CPU2>; + }; + core3 { + cpu0 = <&CPU3>; + }; + }; + }; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "sifive,rocket0", "riscv"; + reg = <0x1>; + } + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "sifive,rocket0", "riscv"; + reg = <0x2>; + } + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "sifive,rocket0", "riscv"; + reg = <0x3>; + } + CPU4: cpu@4 { + device_type = "cpu"; + compatible = "sifive,rocket0", "riscv"; + reg = <0x4>; + } + } +}; =============================================================================== [1] ARM Linux kernel documentation Documentation/devicetree/bindings/arm/cpus.yaml +[2] Devicetree NUMA binding description + Documentation/devicetree/bindings/numa.txt +[3] RISC-V Linux kernel documentation + Documentation/devicetree/bindings/riscv/cpus.txt +[4] https://www.devicetree.org/specifications/ diff --git a/Documentation/devicetree/bindings/dma/allwinner,sun4i-a10-dma.yaml b/Documentation/devicetree/bindings/dma/allwinner,sun4i-a10-dma.yaml new file mode 100644 index 0000000000000000000000000000000000000000..15abc0f9429fcd8b813d620d8e8a0f115b70a6de --- /dev/null +++ b/Documentation/devicetree/bindings/dma/allwinner,sun4i-a10-dma.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/allwinner,sun4i-a10-dma.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A10 DMA Controller Device Tree Bindings + +maintainers: + - Chen-Yu Tsai + - Maxime Ripard + +allOf: + - $ref: "dma-controller.yaml#" + +properties: + "#dma-cells": + const: 2 + description: + The first cell is either 0 or 1, the former to use the normal + DMA, 1 for dedicated DMA. The second cell is the request line + number. + + compatible: + const: allwinner,sun4i-a10-dma + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - "#dma-cells" + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + dma: dma-controller@1c02000 { + compatible = "allwinner,sun4i-a10-dma"; + reg = <0x01c02000 0x1000>; + interrupts = <27>; + clocks = <&ahb_gates 6>; + #dma-cells = <2>; + }; + +... diff --git a/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml b/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4cb9d6b9313894b9cc88a3d98e66926c517f4c0c --- /dev/null +++ b/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/allwinner,sun50i-a64-dma.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A64 DMA Controller Device Tree Bindings + +maintainers: + - Chen-Yu Tsai + - Maxime Ripard + +allOf: + - $ref: "dma-controller.yaml#" + +properties: + "#dma-cells": + const: 1 + description: The cell is the request line number. + + compatible: + enum: + - allwinner,sun50i-a64-dma + - allwinner,sun50i-h6-dma + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + items: + - const: bus + - const: mbus + + resets: + maxItems: 1 + +required: + - "#dma-cells" + - compatible + - reg + - interrupts + - clocks + - resets + - dma-channels + +if: + properties: + compatible: + const: allwinner,sun50i-h6-dma + +then: + properties: + clocks: + maxItems: 2 + + required: + - clock-names + +else: + properties: + clocks: + maxItems: 1 + +# FIXME: We should set it, but it would report all the generic +# properties as additional properties. +# additionalProperties: false + +examples: + - | + dma: dma-controller@1c02000 { + compatible = "allwinner,sun50i-a64-dma"; + reg = <0x01c02000 0x1000>; + interrupts = <0 50 4>; + clocks = <&ccu 30>; + dma-channels = <8>; + dma-requests = <27>; + resets = <&ccu 7>; + #dma-cells = <1>; + }; + +... diff --git a/Documentation/devicetree/bindings/dma/allwinner,sun6i-a31-dma.yaml b/Documentation/devicetree/bindings/dma/allwinner,sun6i-a31-dma.yaml new file mode 100644 index 0000000000000000000000000000000000000000..740b7f9b535b29267d834e35181d9782f24b5280 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/allwinner,sun6i-a31-dma.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/allwinner,sun6i-a31-dma.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A31 DMA Controller Device Tree Bindings + +maintainers: + - Chen-Yu Tsai + - Maxime Ripard + +allOf: + - $ref: "dma-controller.yaml#" + +properties: + "#dma-cells": + const: 1 + description: The cell is the request line number. + + compatible: + oneOf: + - const: allwinner,sun6i-a31-dma + - const: allwinner,sun8i-a23-dma + - const: allwinner,sun8i-a83t-dma + - const: allwinner,sun8i-h3-dma + - const: allwinner,sun8i-v3s-dma + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + +required: + - "#dma-cells" + - compatible + - reg + - interrupts + - clocks + - resets + +additionalProperties: false + +examples: + - | + dma: dma-controller@1c02000 { + compatible = "allwinner,sun6i-a31-dma"; + reg = <0x01c02000 0x1000>; + interrupts = <0 50 4>; + clocks = <&ahb1_gates 6>; + resets = <&ahb1_rst 6>; + #dma-cells = <1>; + }; + +... diff --git a/Documentation/devicetree/bindings/dma/dma-common.yaml b/Documentation/devicetree/bindings/dma/dma-common.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ed0a49a6f02080dbd16423f3cc278594a4f2a8b8 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/dma-common.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/dma-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: DMA Engine Generic Binding + +maintainers: + - Vinod Koul + +description: + Generic binding to provide a way for a driver using DMA Engine to + retrieve the DMA request or channel information that goes from a + hardware device to a DMA controller. + +select: false + +properties: + "#dma-cells": + minimum: 1 + # Should be enough + maximum: 255 + description: + Used to provide DMA controller specific information. + + dma-channel-mask: + $ref: /schemas/types.yaml#definitions/uint32 + description: + Bitmask of available DMA channels in ascending order that are + not reserved by firmware and are available to the + kernel. i.e. first channel corresponds to LSB. + + dma-channels: + $ref: /schemas/types.yaml#definitions/uint32 + description: + Number of DMA channels supported by the controller. + + dma-requests: + $ref: /schemas/types.yaml#definitions/uint32 + description: + Number of DMA request signals supported by the controller. + +required: + - "#dma-cells" diff --git a/Documentation/devicetree/bindings/dma/dma-controller.yaml b/Documentation/devicetree/bindings/dma/dma-controller.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c39f6de76670d32db8e25c653d71700adb7cf219 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/dma-controller.yaml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/dma-controller.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: DMA Controller Generic Binding + +maintainers: + - Vinod Koul + +allOf: + - $ref: "dma-common.yaml#" + +# Everything else is described in the common file +properties: + $nodename: + pattern: "^dma-controller(@.*)?$" + +examples: + - | + dma: dma-controller@48000000 { + compatible = "ti,omap-sdma"; + reg = <0x48000000 0x1000>; + interrupts = <0 12 0x4 + 0 13 0x4 + 0 14 0x4 + 0 15 0x4>; + #dma-cells = <1>; + dma-channels = <32>; + dma-requests = <127>; + dma-channel-mask = <0xfffe>; + }; + +... diff --git a/Documentation/devicetree/bindings/dma/dma-router.yaml b/Documentation/devicetree/bindings/dma/dma-router.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5b5f07393135d18f0b993b6c400b9433c801cae5 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/dma-router.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/dma-router.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: DMA Router Generic Binding + +maintainers: + - Vinod Koul + +allOf: + - $ref: "dma-common.yaml#" + +description: + DMA routers are transparent IP blocks used to route DMA request + lines from devices to the DMA controller. Some SoCs (like TI DRA7x) + have more peripherals integrated with DMA requests than what the DMA + controller can handle directly. + +properties: + $nodename: + pattern: "^dma-router(@.*)?$" + + dma-masters: + $ref: /schemas/types.yaml#definitions/phandle-array + description: + Array of phandles to the DMA controllers the router can direct + the signal to. + + dma-requests: + description: + Number of incoming request lines the router can handle. + +required: + - "#dma-cells" + - dma-masters + +examples: + - | + sdma_xbar: dma-router@4a002b78 { + compatible = "ti,dra7-dma-crossbar"; + reg = <0x4a002b78 0xfc>; + #dma-cells = <1>; + dma-requests = <205>; + ti,dma-safe-map = <0>; + dma-masters = <&sdma>; + }; + +... diff --git a/Documentation/devicetree/bindings/dma/dma.txt b/Documentation/devicetree/bindings/dma/dma.txt index eeb4e4d1771ed42c33951d6f326f434b0607fb5a..90a67a016a48837386976b938019c2306700782a 100644 --- a/Documentation/devicetree/bindings/dma/dma.txt +++ b/Documentation/devicetree/bindings/dma/dma.txt @@ -1,113 +1 @@ -* Generic DMA Controller and DMA request bindings - -Generic binding to provide a way for a driver using DMA Engine to retrieve the -DMA request or channel information that goes from a hardware device to a DMA -controller. - - -* DMA controller - -Required property: -- #dma-cells: Must be at least 1. Used to provide DMA controller - specific information. See DMA client binding below for - more details. - -Optional properties: -- dma-channels: Number of DMA channels supported by the controller. -- dma-requests: Number of DMA request signals supported by the - controller. -- dma-channel-mask: Bitmask of available DMA channels in ascending order - that are not reserved by firmware and are available to - the kernel. i.e. first channel corresponds to LSB. - -Example: - - dma: dma@48000000 { - compatible = "ti,omap-sdma"; - reg = <0x48000000 0x1000>; - interrupts = <0 12 0x4 - 0 13 0x4 - 0 14 0x4 - 0 15 0x4>; - #dma-cells = <1>; - dma-channels = <32>; - dma-requests = <127>; - dma-channel-mask = <0xfffe> - }; - -* DMA router - -DMA routers are transparent IP blocks used to route DMA request lines from -devices to the DMA controller. Some SoCs (like TI DRA7x) have more peripherals -integrated with DMA requests than what the DMA controller can handle directly. - -Required property: -- dma-masters: phandle of the DMA controller or list of phandles for - the DMA controllers the router can direct the signal to. -- #dma-cells: Must be at least 1. Used to provide DMA router specific - information. See DMA client binding below for more - details. - -Optional properties: -- dma-requests: Number of incoming request lines the router can handle. -- In the node pointed by the dma-masters: - - dma-requests: The router driver might need to look for this in order - to configure the routing. - -Example: - sdma_xbar: dma-router@4a002b78 { - compatible = "ti,dra7-dma-crossbar"; - reg = <0x4a002b78 0xfc>; - #dma-cells = <1>; - dma-requests = <205>; - ti,dma-safe-map = <0>; - dma-masters = <&sdma>; - }; - -* DMA client - -Client drivers should specify the DMA property using a phandle to the controller -followed by DMA controller specific data. - -Required property: -- dmas: List of one or more DMA specifiers, each consisting of - - A phandle pointing to DMA controller node - - A number of integer cells, as determined by the - #dma-cells property in the node referenced by phandle - containing DMA controller specific information. This - typically contains a DMA request line number or a - channel number, but can contain any data that is - required for configuring a channel. -- dma-names: Contains one identifier string for each DMA specifier in - the dmas property. The specific strings that can be used - are defined in the binding of the DMA client device. - Multiple DMA specifiers can be used to represent - alternatives and in this case the dma-names for those - DMA specifiers must be identical (see examples). - -Examples: - -1. A device with one DMA read channel, one DMA write channel: - - i2c1: i2c@1 { - ... - dmas = <&dma 2 /* read channel */ - &dma 3>; /* write channel */ - dma-names = "rx", "tx"; - ... - }; - -2. A single read-write channel with three alternative DMA controllers: - - dmas = <&dma1 5 - &dma2 7 - &dma3 2>; - dma-names = "rx-tx", "rx-tx", "rx-tx"; - -3. A device with three channels, one of which has two alternatives: - - dmas = <&dma1 2 /* read channel */ - &dma1 3 /* write channel */ - &dma2 0 /* error read */ - &dma3 0>; /* alternative error read */ - dma-names = "rx", "tx", "error", "error"; +This file has been moved to dma-controller.yaml. diff --git a/Documentation/devicetree/bindings/dma/nbpfaxi.txt b/Documentation/devicetree/bindings/dma/renesas,nbpfaxi.txt similarity index 100% rename from Documentation/devicetree/bindings/dma/nbpfaxi.txt rename to Documentation/devicetree/bindings/dma/renesas,nbpfaxi.txt diff --git a/Documentation/devicetree/bindings/dma/shdma.txt b/Documentation/devicetree/bindings/dma/renesas,shdma.txt similarity index 100% rename from Documentation/devicetree/bindings/dma/shdma.txt rename to Documentation/devicetree/bindings/dma/renesas,shdma.txt diff --git a/Documentation/devicetree/bindings/dma/sun4i-dma.txt b/Documentation/devicetree/bindings/dma/sun4i-dma.txt deleted file mode 100644 index 8ad556aca70b56dad0177dba779fa8b8cee2c888..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/dma/sun4i-dma.txt +++ /dev/null @@ -1,45 +0,0 @@ -Allwinner A10 DMA Controller - -This driver follows the generic DMA bindings defined in dma.txt. - -Required properties: - -- compatible: Must be "allwinner,sun4i-a10-dma" -- reg: Should contain the registers base address and length -- interrupts: Should contain a reference to the interrupt used by this device -- clocks: Should contain a reference to the parent AHB clock -- #dma-cells : Should be 2, first cell denoting normal or dedicated dma, - second cell holding the request line number. - -Example: - dma: dma-controller@1c02000 { - compatible = "allwinner,sun4i-a10-dma"; - reg = <0x01c02000 0x1000>; - interrupts = <27>; - clocks = <&ahb_gates 6>; - #dma-cells = <2>; - }; - -Clients: - -DMA clients connected to the Allwinner A10 DMA controller must use the -format described in the dma.txt file, using a three-cell specifier for -each channel: a phandle plus two integer cells. -The three cells in order are: - -1. A phandle pointing to the DMA controller. -2. Whether it is using normal (0) or dedicated (1) channels -3. The port ID as specified in the datasheet - -Example: - spi2: spi@1c17000 { - compatible = "allwinner,sun4i-a10-spi"; - reg = <0x01c17000 0x1000>; - interrupts = <0 12 4>; - clocks = <&ahb_gates 22>, <&spi2_clk>; - clock-names = "ahb", "mod"; - dmas = <&dma 1 29>, <&dma 1 28>; - dma-names = "rx", "tx"; - #address-cells = <1>; - #size-cells = <0>; - }; diff --git a/Documentation/devicetree/bindings/dma/sun6i-dma.txt b/Documentation/devicetree/bindings/dma/sun6i-dma.txt deleted file mode 100644 index cae31f4e77ba964853f7a297421360d24a914c32..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/dma/sun6i-dma.txt +++ /dev/null @@ -1,81 +0,0 @@ -Allwinner A31 DMA Controller - -This driver follows the generic DMA bindings defined in dma.txt. - -Required properties: - -- compatible: Must be one of - "allwinner,sun6i-a31-dma" - "allwinner,sun8i-a23-dma" - "allwinner,sun8i-a83t-dma" - "allwinner,sun8i-h3-dma" - "allwinner,sun8i-v3s-dma" -- reg: Should contain the registers base address and length -- interrupts: Should contain a reference to the interrupt used by this device -- clocks: Should contain a reference to the parent AHB clock -- resets: Should contain a reference to the reset controller asserting - this device in reset -- #dma-cells : Should be 1, a single cell holding a line request number - -Example: - dma: dma-controller@1c02000 { - compatible = "allwinner,sun6i-a31-dma"; - reg = <0x01c02000 0x1000>; - interrupts = <0 50 4>; - clocks = <&ahb1_gates 6>; - resets = <&ahb1_rst 6>; - #dma-cells = <1>; - }; - ------------------------------------------------------------------------------- -For A64 and H6 DMA controller: - -Required properties: -- compatible: Must be one of - "allwinner,sun50i-a64-dma" - "allwinner,sun50i-h6-dma" -- dma-channels: Number of DMA channels supported by the controller. - Refer to Documentation/devicetree/bindings/dma/dma.txt -- clocks: In addition to parent AHB clock, it should also contain mbus - clock (H6 only) -- clock-names: Should contain "bus" and "mbus" (H6 only) -- all properties above, i.e. reg, interrupts, clocks, resets and #dma-cells - -Optional properties: -- dma-requests: Number of DMA request signals supported by the controller. - Refer to Documentation/devicetree/bindings/dma/dma.txt - -Example: - dma: dma-controller@1c02000 { - compatible = "allwinner,sun50i-a64-dma"; - reg = <0x01c02000 0x1000>; - interrupts = ; - clocks = <&ccu CLK_BUS_DMA>; - dma-channels = <8>; - dma-requests = <27>; - resets = <&ccu RST_BUS_DMA>; - #dma-cells = <1>; - }; ------------------------------------------------------------------------------- - -Clients: - -DMA clients connected to the A31 DMA controller must use the format -described in the dma.txt file, using a two-cell specifier for each -channel: a phandle plus one integer cells. -The two cells in order are: - -1. A phandle pointing to the DMA controller. -2. The port ID as specified in the datasheet - -Example: -spi2: spi@1c6a000 { - compatible = "allwinner,sun6i-a31-spi"; - reg = <0x01c6a000 0x1000>; - interrupts = <0 67 4>; - clocks = <&ahb1_gates 22>, <&spi2_clk>; - clock-names = "ahb", "mod"; - dmas = <&dma 25>, <&dma 25>; - dma-names = "rx", "tx"; - resets = <&ahb1_rst 22>; -}; diff --git a/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml b/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3248595dc93c3a44e9efbf13d3fee3e19da503bb --- /dev/null +++ b/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dsp/fsl,dsp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP i.MX8 DSP core + +maintainers: + - Daniel Baluta + +description: | + Some boards from i.MX8 family contain a DSP core used for + advanced pre- and post- audio processing. + +properties: + compatible: + enum: + - fsl,imx8qxp-dsp + + reg: + description: Should contain register location and length + + clocks: + items: + - description: ipg clock + - description: ocram clock + - description: core clock + + clock-names: + items: + - const: ipg + - const: ocram + - const: core + + power-domains: + description: + List of phandle and PM domain specifier as documented in + Documentation/devicetree/bindings/power/power_domain.txt + maxItems: 4 + + mboxes: + description: + List of <&phandle type channel> - 2 channels for TXDB, 2 channels for RXDB + (see mailbox/fsl,mu.txt) + maxItems: 4 + + mbox-names: + items: + - const: txdb0 + - const: txdb1 + - const: rxdb0 + - const: rxdb1 + + memory-region: + description: + phandle to a node describing reserved memory (System RAM memory) + used by DSP (see bindings/reserved-memory/reserved-memory.txt) + maxItems: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - power-domains + - mboxes + - mbox-names + - memory-region + +examples: + - | + #include + #include + 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>; + }; diff --git a/Documentation/devicetree/bindings/eeprom/at25.txt b/Documentation/devicetree/bindings/eeprom/at25.txt index b3bde97dc19913ea7e552a0206aa0f6e6fe4c093..42577dd113ddf939ca2910a57c6f53c1830ab298 100644 --- a/Documentation/devicetree/bindings/eeprom/at25.txt +++ b/Documentation/devicetree/bindings/eeprom/at25.txt @@ -3,6 +3,7 @@ EEPROMs (SPI) compatible with Atmel at25. Required properties: - compatible : Should be ",", and generic value "atmel,at25". Example "," values: + "anvo,anv32e61w" "microchip,25lc040" "st,m95m02" "st,m95256" diff --git a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt index 7f3d94ae81ffb64f5b9de085d9f1015eca5b7b8a..208daaff0be4ff48968b20cf227882e51183bca7 100644 --- a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt +++ b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt @@ -72,5 +72,5 @@ codec: wm8280@0 { 1 2 1 /* MICDET2 MICBIAS2 GPIO=high */ >; - wlf,gpsw = <0>; + wlf,gpsw = ; }; diff --git a/Documentation/devicetree/bindings/extcon/extcon-fsa9480.txt b/Documentation/devicetree/bindings/extcon/extcon-fsa9480.txt index d592c21245f2953b22eaba229d30f7d3c8d07324..624bd76f468e9a3565babc12b5fbca8b786deef2 100644 --- a/Documentation/devicetree/bindings/extcon/extcon-fsa9480.txt +++ b/Documentation/devicetree/bindings/extcon/extcon-fsa9480.txt @@ -5,7 +5,9 @@ controlled using I2C and enables USB data, stereo and mono audio, video, microphone, and UART data to use a common connector port. Required properties: - - compatible : Must be "fcs,fsa9480" + - compatible : Must be one of + "fcs,fsa9480" + "fcs,fsa880" - reg : Specifies i2c slave address. Must be 0x25. - interrupts : Should contain one entry specifying interrupt signal of interrupt parent to which interrupt pin of the chip is connected. diff --git a/Documentation/devicetree/bindings/firmware/cznic,turris-mox-rwtm.txt b/Documentation/devicetree/bindings/firmware/cznic,turris-mox-rwtm.txt new file mode 100644 index 0000000000000000000000000000000000000000..338169dea7bbb69cf005d964d20d69fdb9b3c7a8 --- /dev/null +++ b/Documentation/devicetree/bindings/firmware/cznic,turris-mox-rwtm.txt @@ -0,0 +1,19 @@ +Turris Mox rWTM firmware driver + +Required properties: + - compatible : Should be "cznic,turris-mox-rwtm" + - mboxes : Must contain a reference to associated mailbox + +This device tree node should be used on Turris Mox, or potentially another A3700 +compatible device running the Mox's rWTM firmware in the secure processor (for +example it is possible to flash this firmware into EspressoBin). + +Example: + + firmware { + turris-mox-rwtm { + compatible = "cznic,turris-mox-rwtm"; + mboxes = <&rwtm 0>; + status = "okay"; + }; + }; diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.txt b/Documentation/devicetree/bindings/firmware/qcom,scm.txt index 41f133a4e2fa72014b37083437fdf99b09710172..3f29ea04b5fe93d0319e88e7ec46f7928578b7b1 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.txt +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.txt @@ -9,14 +9,16 @@ Required properties: - compatible: must contain one of the following: * "qcom,scm-apq8064" * "qcom,scm-apq8084" + * "qcom,scm-ipq4019" * "qcom,scm-msm8660" * "qcom,scm-msm8916" * "qcom,scm-msm8960" * "qcom,scm-msm8974" * "qcom,scm-msm8996" * "qcom,scm-msm8998" - * "qcom,scm-ipq4019" + * "qcom,scm-sc7180" * "qcom,scm-sdm845" + * "qcom,scm-sm8150" and: * "qcom,scm" - clocks: Specifies clocks needed by the SCM interface, if any: diff --git a/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt index 817a8d4bf9037ef136fb980c90fb30621047201a..5dd0ff0f7b4efec5940e7e0efdf2081420fd4066 100644 --- a/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt +++ b/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt @@ -3,10 +3,7 @@ Altera FPGA To SDRAM Bridge Driver Required properties: - compatible : Should contain "altr,socfpga-fpga2sdram-bridge" -Optional properties: -- bridge-enable : 0 if driver should disable bridge at startup - 1 if driver should enable bridge at startup - Default is to leave bridge in current state. +See Documentation/devicetree/bindings/fpga/fpga-bridge.txt for generic bindings. Example: fpga_bridge3: fpga-bridge@ffc25080 { diff --git a/Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt index f8e288c71b2decf719dc7c6f7c8504170c56ca50..8b26fbcff3c62b06090b970a1cfa8a8f1a614012 100644 --- a/Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt +++ b/Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt @@ -10,10 +10,7 @@ Required properties: - compatible : Should contain "altr,freeze-bridge-controller" - regs : base address and size for freeze bridge module -Optional properties: -- bridge-enable : 0 if driver should disable bridge at startup - 1 if driver should enable bridge at startup - Default is to leave bridge in current state. +See Documentation/devicetree/bindings/fpga/fpga-bridge.txt for generic bindings. Example: freeze-controller@100000450 { diff --git a/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt index 6406f9337eeba24ddc45a67f349b0ec54bb91b2b..68cce3945b103d49bd8b41e7ab7991d087502186 100644 --- a/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt +++ b/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt @@ -9,10 +9,7 @@ Required properties: - resets : Phandle and reset specifier for this bridge's reset - clocks : Clocks used by this module. -Optional properties: -- bridge-enable : 0 if driver should disable bridge at startup. - 1 if driver should enable bridge at startup. - Default is to leave bridge in its current state. +See Documentation/devicetree/bindings/fpga/fpga-bridge.txt for generic bindings. Example: fpga_bridge0: fpga-bridge@ff400000 { diff --git a/Documentation/devicetree/bindings/fpga/fpga-bridge.txt b/Documentation/devicetree/bindings/fpga/fpga-bridge.txt new file mode 100644 index 0000000000000000000000000000000000000000..72e06917288aa211949250a8fb5212e25e528091 --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/fpga-bridge.txt @@ -0,0 +1,13 @@ +FPGA Bridge Device Tree Binding + +Optional properties: +- bridge-enable : 0 if driver should disable bridge at startup + 1 if driver should enable bridge at startup + Default is to leave bridge in current state. + +Example: + fpga_bridge3: fpga-bridge@ffc25080 { + compatible = "altr,socfpga-fpga2sdram-bridge"; + reg = <0xffc25080 0x4>; + bridge-enable = <0>; + }; diff --git a/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt b/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt index 8dcfba926bc78c7d577ef0491a062b0c6e741ad9..4284d293fa6135bf757d53f2bc8faeb29b86e8e2 100644 --- a/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt +++ b/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt @@ -18,12 +18,8 @@ Required properties: - clocks : input clock to IP - clock-names : should contain "aclk" -Optional properties: -- bridge-enable : 0 if driver should disable bridge at startup - 1 if driver should enable bridge at startup - Default is to leave bridge in current state. - -See Documentation/devicetree/bindings/fpga/fpga-region.txt for generic bindings. +See Documentation/devicetree/bindings/fpga/fpga-region.txt and +Documentation/devicetree/bindings/fpga/fpga-bridge.txt for generic bindings. Example: fpga-bridge@100000450 { diff --git a/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt b/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt index 7e9b586770b0599e7c4e88b45d03e692b46e9a78..b2033fc3a71a6e0988cdd7dab1b5b42ff49649c2 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt @@ -2,7 +2,8 @@ Aspeed GPIO controller Device Tree Bindings ------------------------------------------- Required properties: -- compatible : Either "aspeed,ast2400-gpio" or "aspeed,ast2500-gpio" +- compatible : Either "aspeed,ast2400-gpio", "aspeed,ast2500-gpio", + or "aspeed,ast2600-gpio". - #gpio-cells : Should be two - First cell is the GPIO line number @@ -17,7 +18,9 @@ Required properties: Optional properties: -- clocks : A phandle to the clock to use for debounce timings +- clocks : A phandle to the clock to use for debounce timings +- ngpios : Number of GPIOs controlled by this controller. Should be set + when there are multiple GPIO controllers on a SoC (ast2600). The gpio and interrupt properties are further described in their respective bindings documentation: diff --git a/Documentation/devicetree/bindings/gpio/gpio-davinci.txt b/Documentation/devicetree/bindings/gpio/gpio-davinci.txt index bc6b4b62df839ec8fff9b5fd44c3e0bc7094379e..cd91d61eac31492bcb8ce34d92a9a3912105bb1b 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-davinci.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-davinci.txt @@ -6,6 +6,7 @@ Required Properties: 66AK2E SoCs "ti,k2g-gpio", "ti,keystone-gpio": for 66AK2G "ti,am654-gpio", "ti,keystone-gpio": for TI K3 AM654 + "ti,j721e-gpio", "ti,keystone-gpio": for J721E SoCs - reg: Physical base address of the controller and the size of memory mapped registers. diff --git a/Documentation/devicetree/bindings/gpio/gpio-moxtet.txt b/Documentation/devicetree/bindings/gpio/gpio-moxtet.txt new file mode 100644 index 0000000000000000000000000000000000000000..410759de9f09567749b74fa2b9c5fb7d1083f02c --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-moxtet.txt @@ -0,0 +1,18 @@ +Turris Mox Moxtet GPIO expander via Moxtet bus + +Required properties: + - compatible : Should be "cznic,moxtet-gpio". + - gpio-controller : Marks the device node as a GPIO controller. + - #gpio-cells : Should be two. For consumer use see gpio.txt. + +Other properties are required for a Moxtet bus device, please refer to +Documentation/devicetree/bindings/bus/moxtet.txt. + +Example: + + moxtet_sfp: gpio@0 { + compatible = "cznic,moxtet-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0>; + } diff --git a/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt b/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt index 69d46162d0f5ba385da868a0ce9240e2b34b06ee..cd28e932bf50e45b0c1ee554f848d6b597a1a499 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt @@ -4,7 +4,7 @@ Required properties: - compatible : Should be "fsl,-gpio" The following s are known to be supported: mpc5121, mpc5125, mpc8349, mpc8572, mpc8610, pq3, qoriq, - ls1021a, ls1043a, ls2080a. + ls1021a, ls1043a, ls2080a, ls1028a, ls1088a. - reg : Address and length of the register set for the device - interrupts : Should be the port interrupt shared by all 32 pins. - #gpio-cells : Should be two. The first cell is the pin number and @@ -37,3 +37,17 @@ gpio0: gpio@2300000 { interrupt-controller; #interrupt-cells = <2>; }; + + +Example of gpio-controller node for a ls1028a/ls1088a SoC: + +gpio1: gpio@2300000 { + compatible = "fsl,ls1028a-gpio", "fsl,ls1088a-gpio", "fsl,qoriq-gpio"; + reg = <0x0 0x2300000 0x0 0x10000>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + little-endian; +}; diff --git a/Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt b/Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt new file mode 100644 index 0000000000000000000000000000000000000000..d4d83916c09dd97a11bfa3f5afa815efade7b861 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt @@ -0,0 +1,45 @@ +Aspeed SGPIO controller Device Tree Bindings +-------------------------------------------- + +This SGPIO controller is for ASPEED AST2500 SoC, it supports up to 80 full +featured Serial GPIOs. Each of the Serial GPIO pins can be programmed to +support the following options: +- Support interrupt option for each input port and various interrupt + sensitivity option (level-high, level-low, edge-high, edge-low) +- Support reset tolerance option for each output port +- Directly connected to APB bus and its shift clock is from APB bus clock + divided by a programmable value. +- Co-work with external signal-chained TTL components (74LV165/74LV595) + +Required properties: + +- compatible : Should be one of + "aspeed,ast2400-sgpio", "aspeed,ast2500-sgpio" +- #gpio-cells : Should be 2, see gpio.txt +- reg : Address and length of the register set for the device +- gpio-controller : Marks the device node as a GPIO controller +- interrupts : Interrupt specifier, see interrupt-controller/interrupts.txt +- interrupt-controller : Mark the GPIO controller as an interrupt-controller +- ngpios : number of GPIO lines, see gpio.txt + (should be multiple of 8, up to 80 pins) +- clocks : A phandle to the APB clock for SGPM clock division +- bus-frequency : SGPM CLK frequency + +The sgpio and interrupt properties are further described in their respective +bindings documentation: + +- Documentation/devicetree/bindings/gpio/gpio.txt +- Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + + Example: + sgpio: sgpio@1e780200 { + #gpio-cells = <2>; + compatible = "aspeed,ast2500-sgpio"; + gpio-controller; + interrupts = <40>; + reg = <0x1e780200 0x0100>; + clocks = <&syscon ASPEED_CLK_APB>; + interrupt-controller; + ngpios = <8>; + bus-frequency = <12000000>; + }; diff --git a/Documentation/devicetree/bindings/hwmon/as370.txt b/Documentation/devicetree/bindings/hwmon/as370.txt new file mode 100644 index 0000000000000000000000000000000000000000..d102fe7651249ea549043e7b279209425cd4f03b --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/as370.txt @@ -0,0 +1,11 @@ +Bindings for Synaptics AS370 PVT sensors + +Required properties: +- compatible : "syna,as370-hwmon" +- reg : address and length of the register set. + +Example: + hwmon@ea0810 { + compatible = "syna,as370-hwmon"; + reg = <0xea0810 0xc>; + }; diff --git a/Documentation/devicetree/bindings/hwmon/ibm,cffps1.txt b/Documentation/devicetree/bindings/hwmon/ibm,cffps1.txt index f68a0a68fc524cdc1ee547313892a34e78248800..1036f65fb778eeb54d6e600d0722c5c6a1746680 100644 --- a/Documentation/devicetree/bindings/hwmon/ibm,cffps1.txt +++ b/Documentation/devicetree/bindings/hwmon/ibm,cffps1.txt @@ -1,8 +1,10 @@ -Device-tree bindings for IBM Common Form Factor Power Supply Version 1 ----------------------------------------------------------------------- +Device-tree bindings for IBM Common Form Factor Power Supply Versions 1 and 2 +----------------------------------------------------------------------------- Required properties: - - compatible = "ibm,cffps1"; + - compatible : Must be one of the following: + "ibm,cffps1" + "ibm,cffps2" - reg = < I2C bus address >; : Address of the power supply on the I2C bus. diff --git a/Documentation/devicetree/bindings/hwmon/lm75.txt b/Documentation/devicetree/bindings/hwmon/lm75.txt index 586b5ed70be7a0f2ff21e49c60ba2ae072645083..273616702c51b5f089c521dd49d734b42879aa29 100644 --- a/Documentation/devicetree/bindings/hwmon/lm75.txt +++ b/Documentation/devicetree/bindings/hwmon/lm75.txt @@ -15,6 +15,7 @@ Required properties: "maxim,max31725", "maxim,max31726", "maxim,mcp980x", + "nxp,pct2075", "st,stds75", "st,stlm75", "microchip,tcn75", diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-gpmux.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-gpmux.txt index 2907dab562987ee210790242ac283a5f6028a879..8b444b94e92fde83967f032e0602fb7a68000a43 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mux-gpmux.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-gpmux.txt @@ -42,7 +42,7 @@ Optional properties: This means that no unrelated I2C transactions are allowed on the parent I2C adapter for the complete multiplexed I2C transaction. The properties of mux-locked and parent-locked multiplexers are discussed - in more detail in Documentation/i2c/i2c-topology. + in more detail in Documentation/i2c/i2c-topology.rst. For each i2c child node, an I2C child bus will be created. They will be numbered based on their order in the device tree. diff --git a/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml b/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml index 001f2b7abad0bc26d96e40329ed6701c82940886..c779000515d6759a4917a5656dc1d73ac9a67b4a 100644 --- a/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml +++ b/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml @@ -26,6 +26,9 @@ properties: - items: - const: allwinner,sun50i-a64-i2c - const: allwinner,sun6i-a31-i2c + - items: + - const: allwinner,sun50i-h6-i2c + - const: allwinner,sun6i-a31-i2c - const: marvell,mv64xxx-i2c - const: marvell,mv78230-i2c diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml new file mode 100644 index 0000000000000000000000000000000000000000..676ec42e143819665215bf79ffad2b2c148690f8 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml @@ -0,0 +1,121 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2019 Analog Devices Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/bindings/iio/adc/adi,ad7192.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD7192 ADC device driver + +maintainers: + - Michael Hennerich + +description: | + Bindings for the Analog Devices AD7192 ADC device. Datasheet can be + found here: + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7192.pdf + +properties: + compatible: + enum: + - adi,ad7190 + - adi,ad7192 + - adi,ad7193 + - adi,ad7195 + + reg: + maxItems: 1 + + spi-cpol: true + + spi-cpha: true + + clocks: + maxItems: 1 + description: phandle to the master clock (mclk) + + clock-names: + items: + - const: mclk + + interrupts: + maxItems: 1 + + dvdd-supply: + description: DVdd voltage supply + items: + - const: dvdd + + avdd-supply: + description: AVdd voltage supply + items: + - const: avdd + + adi,rejection-60-Hz-enable: + description: | + This bit enables a notch at 60 Hz when the first notch of the sinc + filter is at 50 Hz. When REJ60 is set, a filter notch is placed at + 60 Hz when the sinc filter first notch is at 50 Hz. This allows + simultaneous 50 Hz/ 60 Hz rejection. + type: boolean + + adi,refin2-pins-enable: + description: | + External reference applied between the P1/REFIN2(+) and P0/REFIN2(−) pins. + type: boolean + + adi,buffer-enable: + description: | + Enables the buffer on the analog inputs. If cleared, the analog inputs + are unbuffered, lowering the power consumption of the device. If this + bit is set, the analog inputs are buffered, allowing the user to place + source impedances on the front end without contributing gain errors to + the system. + type: boolean + + adi,burnout-currents-enable: + description: | + When this bit is set to 1, the 500 nA current sources in the signal + path are enabled. When BURN = 0, the burnout currents are disabled. + The burnout currents can be enabled only when the buffer is active + and when chop is disabled. + type: boolean + + bipolar: + description: see Documentation/devicetree/bindings/iio/adc/adc.txt + type: boolean + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - dvdd-supply + - avdd-supply + - spi-cpol + - spi-cpha + +examples: + - | + spi0 { + adc@0 { + compatible = "adi,ad7192"; + reg = <0>; + spi-max-frequency = <1000000>; + spi-cpol; + spi-cpha; + clocks = <&ad7192_mclk>; + clock-names = "mclk"; + #interrupt-cells = <2>; + interrupts = <25 0x2>; + interrupt-parent = <&gpio>; + dvdd-supply = <&dvdd>; + avdd-supply = <&avdd>; + + adi,refin2-pins-enable; + adi,rejection-60-Hz-enable; + adi,buffer-enable; + adi,burnout-currents-enable; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt deleted file mode 100644 index d8652460198ee65197f72b28cc88103fe4a32226..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt +++ /dev/null @@ -1,66 +0,0 @@ -Analog Devices AD7606 Simultaneous Sampling ADC - -Required properties for the AD7606: - -- compatible: Must be one of - * "adi,ad7605-4" - * "adi,ad7606-8" - * "adi,ad7606-6" - * "adi,ad7606-4" - * "adi,ad7616" -- reg: SPI chip select number for the device -- spi-max-frequency: Max SPI frequency to use - see: Documentation/devicetree/bindings/spi/spi-bus.txt -- spi-cpha: See Documentation/devicetree/bindings/spi/spi-bus.txt -- avcc-supply: phandle to the Avcc power supply -- interrupts: IRQ line for the ADC - see: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt -- adi,conversion-start-gpios: must be the device tree identifier of the CONVST pin. - This logic input is used to initiate conversions on the analog - input channels. As the line is active high, it should be marked - GPIO_ACTIVE_HIGH. - -Optional properties: - -- reset-gpios: must be the device tree identifier of the RESET pin. If specified, - it will be asserted during driver probe. As the line is active high, - it should be marked GPIO_ACTIVE_HIGH. -- standby-gpios: must be the device tree identifier of the STBY pin. This pin is used - to place the AD7606 into one of two power-down modes, Standby mode or - Shutdown mode. As the line is active low, it should be marked - GPIO_ACTIVE_LOW. -- adi,first-data-gpios: must be the device tree identifier of the FRSTDATA pin. - The FRSTDATA output indicates when the first channel, V1, is - being read back on either the parallel, byte or serial interface. - As the line is active high, it should be marked GPIO_ACTIVE_HIGH. -- adi,range-gpios: must be the device tree identifier of the RANGE pin. The polarity on - this pin determines the input range of the analog input channels. If - this pin is tied to a logic high, the analog input range is ±10V for - all channels. If this pin is tied to a logic low, the analog input range - is ±5V for all channels. As the line is active high, it should be marked - GPIO_ACTIVE_HIGH. -- adi,oversampling-ratio-gpios: must be the device tree identifier of the over-sampling - mode pins. As the line is active high, it should be marked - GPIO_ACTIVE_HIGH. - -Example: - - adc@0 { - compatible = "adi,ad7606-8"; - reg = <0>; - spi-max-frequency = <1000000>; - spi-cpol; - - avcc-supply = <&adc_vref>; - - interrupts = <25 IRQ_TYPE_EDGE_FALLING>; - interrupt-parent = <&gpio>; - - adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>; - adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; - adi,oversampling-ratio-gpios = <&gpio 18 GPIO_ACTIVE_HIGH - &gpio 23 GPIO_ACTIVE_HIGH - &gpio 26 GPIO_ACTIVE_HIGH>; - standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>; - }; diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml new file mode 100644 index 0000000000000000000000000000000000000000..cc544fdc38bea6f1c3c08e779f7aaa39655e7d89 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml @@ -0,0 +1,138 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7606.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD7606 Simultaneous Sampling ADC + +maintainers: + - Beniamin Bia + - Stefan Popa + +description: | + Analog Devices AD7606 Simultaneous Sampling ADC + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606_7606-6_7606-4.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7606B.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7616.pdf + +properties: + compatible: + enum: + - adi,ad7605-4 + - adi,ad7606-8 + - adi,ad7606-6 + - adi,ad7606-4 + - adi,ad7606b + - adi,ad7616 + + reg: + maxItems: 1 + + spi-cpha: true + + avcc-supply: + description: + Phandle to the Avcc power supply + maxItems: 1 + + interrupts: + maxItems: 1 + + adi,conversion-start-gpios: + description: + Must be the device tree identifier of the CONVST pin. + This logic input is used to initiate conversions on the analog + input channels. As the line is active high, it should be marked + GPIO_ACTIVE_HIGH. + maxItems: 1 + + reset-gpios: + description: + Must be the device tree identifier of the RESET pin. If specified, + it will be asserted during driver probe. As the line is active high, + it should be marked GPIO_ACTIVE_HIGH. + maxItems: 1 + + standby-gpios: + description: + Must be the device tree identifier of the STBY pin. This pin is used + to place the AD7606 into one of two power-down modes, Standby mode or + Shutdown mode. As the line is active low, it should be marked + GPIO_ACTIVE_LOW. + maxItems: 1 + + adi,first-data-gpios: + description: + Must be the device tree identifier of the FRSTDATA pin. + The FRSTDATA output indicates when the first channel, V1, is + being read back on either the parallel, byte or serial interface. + As the line is active high, it should be marked GPIO_ACTIVE_HIGH. + maxItems: 1 + + adi,range-gpios: + description: + Must be the device tree identifier of the RANGE pin. The polarity on + this pin determines the input range of the analog input channels. If + this pin is tied to a logic high, the analog input range is ±10V for + all channels. If this pin is tied to a logic low, the analog input range + is ±5V for all channels. As the line is active high, it should be marked + GPIO_ACTIVE_HIGH. + maxItems: 1 + + adi,oversampling-ratio-gpios: + description: + Must be the device tree identifier of the over-sampling + mode pins. As the line is active high, it should be marked + GPIO_ACTIVE_HIGH. + maxItems: 1 + + adi,sw-mode: + description: + Software mode of operation, so far available only for ad7616 and ad7606b. + It is enabled when all three oversampling mode pins are connected to + high level. The device is configured by the corresponding registers. If the + adi,oversampling-ratio-gpios property is defined, then the driver will set the + oversampling gpios to high. Otherwise, it is assumed that the pins are hardwired + to VDD. + type: boolean + +required: + - compatible + - reg + - spi-cpha + - avcc-supply + - interrupts + - adi,conversion-start-gpios + +examples: + - | + #include + #include + spi0 { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,ad7606-8"; + reg = <0>; + spi-max-frequency = <1000000>; + spi-cpol; + spi-cpha; + + avcc-supply = <&adc_vref>; + + interrupts = <25 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpio>; + + adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>; + adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; + adi,oversampling-ratio-gpios = <&gpio 18 GPIO_ACTIVE_HIGH + &gpio 23 GPIO_ACTIVE_HIGH + &gpio 26 GPIO_ACTIVE_HIGH>; + standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>; + adi,sw-mode; + }; + }; +... diff --git a/Documentation/devicetree/bindings/hwmon/ads1015.txt b/Documentation/devicetree/bindings/iio/adc/ads1015.txt similarity index 100% rename from Documentation/devicetree/bindings/hwmon/ads1015.txt rename to Documentation/devicetree/bindings/iio/adc/ads1015.txt diff --git a/Documentation/devicetree/bindings/iio/adc/allwinner,sun8i-a33-ths.yaml b/Documentation/devicetree/bindings/iio/adc/allwinner,sun8i-a33-ths.yaml new file mode 100644 index 0000000000000000000000000000000000000000..d74962c0f5ae367a8a023a24277b356f5e9b317e --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/allwinner,sun8i-a33-ths.yaml @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/allwinner,sun8i-a33-ths.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A33 Thermal Sensor Device Tree Bindings + +maintainers: + - Chen-Yu Tsai + - Maxime Ripard + +properties: + "#io-channel-cells": + const: 0 + + "#thermal-sensor-cells": + const: 0 + + compatible: + const: allwinner,sun8i-a33-ths + + reg: + maxItems: 1 + +required: + - "#io-channel-cells" + - "#thermal-sensor-cells" + - compatible + - reg + +additionalProperties: false + +examples: + - | + ths: ths@1c25000 { + compatible = "allwinner,sun8i-a33-ths"; + reg = <0x01c25000 0x100>; + #thermal-sensor-cells = <0>; + #io-channel-cells = <0>; + }; + +... diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt index 93a0bd2efc058281e65b29ceb37170a1fa1e0718..4c0da8c74bb2c571c28a31cee4ba17864d0bb7ad 100644 --- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt @@ -47,6 +47,12 @@ Required properties: Optional properties: - A pinctrl state named "default" for each ADC channel may be defined to set inX ADC pins in mode of operation for analog input on external pin. +- booster-supply: Phandle to the embedded booster regulator that can be used + to supply ADC analog input switches on stm32h7 and stm32mp1. +- vdd-supply: Phandle to the vdd input voltage. It can be used to supply ADC + analog input switches on stm32mp1. +- st,syscfg: Phandle to system configuration controller. It can be used to + control the analog circuitry on stm32mp1. Contents of a stm32 adc child node: ----------------------------------- diff --git a/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.txt b/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.txt deleted file mode 100644 index c52ea2126eaa7252ea16d6a2ba62f128d40a1b8f..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.txt +++ /dev/null @@ -1,26 +0,0 @@ -* Plantower PMS7003 particulate matter sensor - -Required properties: -- compatible: must one of: - "plantower,pms1003" - "plantower,pms3003" - "plantower,pms5003" - "plantower,pms6003" - "plantower,pms7003" - "plantower,pmsa003" -- vcc-supply: phandle to the regulator that provides power to the sensor - -Optional properties: -- plantower,set-gpios: phandle to the GPIO connected to the SET line -- reset-gpios: phandle to the GPIO connected to the RESET line - -Refer to serial/slave-device.txt for generic serial attached device bindings. - -Example: - -&uart0 { - air-pollution-sensor { - compatible = "plantower,pms7003"; - vcc-supply = <®_vcc5v0>; - }; -}; diff --git a/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml b/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml new file mode 100644 index 0000000000000000000000000000000000000000..a551d3101f93a5eecc15efb5a7ed43b9bc111d77 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/chemical/plantower,pms7003.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Plantower PMS7003 air pollution sensor + +maintainers: + - Tomasz Duszynski + +description: | + Air pollution sensor capable of measuring mass concentration of dust + particles. + +properties: + compatible: + enum: + - plantower,pms1003 + - plantower,pms3003 + - plantower,pms5003 + - plantower,pms6003 + - plantower,pms7003 + - plantower,pmsa003 + + vcc-supply: + description: regulator that provides power to the sensor + maxItems: 1 + + plantower,set-gpios: + description: GPIO connected to the SET line + maxItems: 1 + + reset-gpios: + description: GPIO connected to the RESET line + maxItems: 1 + +required: + - compatible + - vcc-supply + +examples: + - | + serial { + air-pollution-sensor { + compatible = "plantower,pms7003"; + vcc-supply = <®_vcc5v0>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0c53009ba7d60aab1f50bba5b9f7c14d195f8cec --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/imu/adi,adis16460.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADIS16460 and similar IMUs + +maintainers: + - Dragos Bogdan + +description: | + Analog Devices ADIS16460 and similar IMUs + https://www.analog.com/media/en/technical-documentation/data-sheets/ADIS16460.pdf + +properties: + compatible: + enum: + - adi,adis16460 + + reg: + maxItems: 1 + + spi-cpha: true + + spi-cpol: true + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +examples: + - | + #include + #include + spi0 { + #address-cells = <1>; + #size-cells = <0>; + + imu@0 { + compatible = "adi,adis16460"; + reg = <0>; + spi-max-frequency = <5000000>; + spi-cpol; + spi-cpha; + interrupt-parent = <&gpio0>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt index efec9ece034a07efd0d09db5797eefd0e197b022..6d0c050d89fe57d21c764cbdb6405d449a84dba9 100644 --- a/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt +++ b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt @@ -11,6 +11,9 @@ Required properties: "st,asm330lhh" "st,lsm6dsox" "st,lsm6dsr" + "st,lsm6ds3tr-c" + "st,ism330dhcx" + "st,lsm9ds1-imu" - reg: i2c address of the sensor / spi cs line Optional properties: diff --git a/Documentation/devicetree/bindings/iio/light/noa1305.yaml b/Documentation/devicetree/bindings/iio/light/noa1305.yaml new file mode 100644 index 0000000000000000000000000000000000000000..17e7f140b69b2808f38c1844ed2f89ce418d19d2 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/noa1305.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/light/noa1305.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ON Semiconductor NOA1305 Ambient Light Sensor + +maintainers: + - Martyn Welch + +description: | + Ambient sensing with an i2c interface. + + https://www.onsemi.com/pub/Collateral/NOA1305-D.PDF + +properties: + compatible: + enum: + - onnn,noa1305 + + reg: + maxItems: 1 + + vin-supply: + description: Regulator that provides power to the sensor + +required: + - compatible + - reg + +examples: + - | + i2c { + + #address-cells = <1>; + #size-cells = <0>; + + light@39 { + compatible = "onnn,noa1305"; + reg = <0x39>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/light/isl29501.txt b/Documentation/devicetree/bindings/iio/light/renesas,isl29501.txt similarity index 100% rename from Documentation/devicetree/bindings/iio/light/isl29501.txt rename to Documentation/devicetree/bindings/iio/light/renesas,isl29501.txt diff --git a/Documentation/devicetree/bindings/iio/light/stk33xx.yaml b/Documentation/devicetree/bindings/iio/light/stk33xx.yaml new file mode 100644 index 0000000000000000000000000000000000000000..aae8a6d627c9f869bd0099839ab1d77879cc4055 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/stk33xx.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/light/stk33xx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: | + Sensortek STK33xx I2C Ambient Light and Proximity sensor + +maintainers: + - Jonathan Cameron + +description: | + Ambient light and proximity sensor over an i2c interface. + +properties: + compatible: + enum: + - sensortek,stk3310 + - sensortek,stk3311 + - sensortek,stk3335 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + +examples: + - | + #include + + i2c { + + #address-cells = <1>; + #size-cells = <0>; + + stk3310@48 { + compatible = "sensortek,stk3310"; + reg = <0x48>; + interrupt-parent = <&gpio1>; + interrupts = <5 IRQ_TYPE_LEVEL_LOW>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/mount-matrix.txt b/Documentation/devicetree/bindings/iio/mount-matrix.txt new file mode 100644 index 0000000000000000000000000000000000000000..c3344ab509a36c31a0a9977b4f2c5835758101dc --- /dev/null +++ b/Documentation/devicetree/bindings/iio/mount-matrix.txt @@ -0,0 +1,203 @@ +For discussion. Unclear are: +* is the definition of +/- values practical or counterintuitive? +* are the definitions unambiguous and easy to follow? +* are the examples correct? +* should we have HOWTO engineer a correct matrix for a new device (without comparing to a different one)? + +==== + + +Mounting matrix + +The mounting matrix is a device tree property used to orient any device +that produce three-dimensional data in relation to the world where it is +deployed. + +The purpose of the mounting matrix is to translate the sensor frame of +reference into the device frame of reference using a translation matrix as +defined in linear algebra. + +The typical usecase is that where a component has an internal representation +of the (x,y,z) triplets, such as different registers to read these coordinates, +and thus implying that the component should be mounted in a certain orientation +relative to some specific device frame of reference. + +For example a device with some kind of screen, where the user is supposed to +interact with the environment using an accelerometer, gyroscope or magnetometer +mounted on the same chassis as this screen, will likely take the screen as +reference to (x,y,z) orientation, with (x,y) corresponding to these axes on the +screen and (z) being depth, the axis perpendicular to the screen. + +For a screen you probably want (x) coordinates to go from negative on the left +to positive on the right, (y) from negative on the bottom to positive on top +and (z) depth to be negative under the screen and positive in front of it, +toward the face of the user. + +A sensor can be mounted in any angle along the axes relative to the frame of +reference. This means that the sensor may be flipped upside-down, left-right, +or tilted at any angle relative to the frame of reference. + +Another frame of reference is how the device with its sensor relates to the +external world, the environment where the device is deployed. Usually the data +from the sensor is used to figure out how the device is oriented with respect +to this world. When using the mounting matrix, the sensor and device orientation +becomes identical and we can focus on the data as it relates to the surrounding +world. + +Device-to-world examples for some three-dimensional sensor types: + +- Accelerometers have their world frame of reference toward the center of + gravity, usually to the core of the planet. A reading of the (x,y,z) values + from the sensor will give a projection of the gravity vector through the + device relative to the center of the planet, i.e. relative to its surface at + this point. Up and down in the world relative to the device frame of + reference can thus be determined. and users would likely expect a value of + 9.81 m/s^2 upwards along the (z) axis, i.e. out of the screen when the device + is held with its screen flat on the planets surface and 0 on the other axes, + as the gravity vector is projected 1:1 onto the sensors (z)-axis. + + If you tilt the device, the g vector virtually coming out of the display + is projected onto the (x,y) plane of the display panel. + + Example: + + ^ z: +g ^ z: > 0 + ! /! + ! x=y=0 / ! x: > 0 + +--------+ +--------+ + ! ! ! ! + +--------+ +--------+ + ! / + ! / + v v + center of center of + gravity gravity + + + If the device is tilted to the left, you get a positive x value. If you point + its top towards surface, you get a negative y axis. + + (---------) + ! ! y: -g + ! ! ^ + ! ! ! + ! ! + ! ! x: +g <- z: +g -> x: -g + ! 1 2 3 ! + ! 4 5 6 ! ! + ! 7 8 9 ! v + ! * 0 # ! y: +g + (---------) + + +- Magnetometers (compasses) have their world frame of reference relative to the + geomagnetic field. The system orientation vis-a-vis the world is defined with + respect to the local earth geomagnetic reference frame where (y) is in the + ground plane and positive towards magnetic North, (x) is in the ground plane, + perpendicular to the North axis and positive towards the East and (z) is + perpendicular to the ground plane and positive upwards. + + + ^^^ North: y > 0 + + (---------) + ! ! + ! ! + ! ! + ! ! > + ! ! > North: x > 0 + ! 1 2 3 ! > + ! 4 5 6 ! + ! 7 8 9 ! + ! * 0 # ! + (---------) + + Since the geomagnetic field is not uniform this definition fails if we come + closer to the poles. + + Sensors and driver can not and should not take care of this because there + are complex calculations and empirical data to be taken care of. We leave + this up to user space. + + The definition we take: + + If the device is placed at the equator and the top is pointing north, the + display is readable by a person standing upright on the earth surface, this + defines a positive y value. + + +- Gyroscopes detects the movement relative the device itself. The angular + velocity is defined as orthogonal to the plane of rotation, so if you put the + device on a flat surface and spin it around the z axis (such as rotating a + device with a screen lying flat on a table), you should get a negative value + along the (z) axis if rotated clockwise, and a positive value if rotated + counter-clockwise according to the right-hand rule. + + + (---------) y > 0 + ! ! v---\ + ! ! + ! ! + ! ! <--\ + ! ! ! z > 0 + ! 1 2 3 ! --/ + ! 4 5 6 ! + ! 7 8 9 ! + ! * 0 # ! + (---------) + + +So unless the sensor is ideally mounted, we need a means to indicate the +relative orientation of any given sensor of this type with respect to the +frame of reference. + +To achieve this, use the device tree property "mount-matrix" for the sensor. + +This supplies a 3x3 rotation matrix in the strict linear algebraic sense, +to orient the senor axes relative to a desired point of reference. This means +the resulting values from the sensor, after scaling to proper units, should be +multiplied by this matrix to give the proper vectors values in three-dimensional +space, relative to the device or world point of reference. + +For more information, consult: +https://en.wikipedia.org/wiki/Rotation_matrix + +The mounting matrix has the layout: + + (mxx, myx, mzx) + (mxy, myy, mzy) + (mxz, myz, mzz) + +Values are intended to be multiplied as: + + x' = mxx * x + myx * y + mzx * z + y' = mxy * x + myy * y + mzy * z + z' = mxz * x + myz * y + mzz * z + +It is represented as an array of strings containing the real values for +producing the transformation matrix. + +Examples: + +Identity matrix (nothing happens to the coordinates, which means the device was +mechanically mounted in an ideal way and we need no transformation): + +mount-matrix = "1", "0", "0", + "0", "1", "0", + "0", "0", "1"; + +The sensor is mounted 30 degrees (Pi/6 radians) tilted along the X axis, so we +compensate by performing a -30 degrees rotation around the X axis: + +mount-matrix = "1", "0", "0", + "0", "0.866", "0.5", + "0", "-0.5", "0.866"; + +The sensor is flipped 180 degrees (Pi radians) around the Z axis, i.e. mounted +upside-down: + +mount-matrix = "0.998", "0.054", "0", + "-0.054", "0.998", "0", + "0", "0", "1"; + +???: this does not match "180 degrees" - factors indicate ca. 3 degrees compensation diff --git a/Documentation/devicetree/bindings/iio/potentiometer/max5432.yaml b/Documentation/devicetree/bindings/iio/potentiometer/max5432.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5082f919df2a58912204135d3ad1d21bb012f898 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/potentiometer/max5432.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/potentiometer/max5432.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim Integrated MAX5432-MAX5435 Digital Potentiometers + +maintainers: + - Martin Kaiser + +description: | + Maxim Integrated MAX5432-MAX5435 Digital Potentiometers connected via I2C + + Datasheet: + https://datasheets.maximintegrated.com/en/ds/MAX5432-MAX5435.pdf + +properties: + compatible: + enum: + - maxim,max5432 + - maxim,max5433 + - maxim,max5434 + - maxim,max5435 + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + max5434@28 { + compatible = "maxim,max5434"; + reg = <0x28>; + }; + }; diff --git a/Documentation/devicetree/bindings/interconnect/qcom,qcs404.txt b/Documentation/devicetree/bindings/interconnect/qcom,qcs404.txt new file mode 100644 index 0000000000000000000000000000000000000000..c07d89812b73b334ab74de0dc905c2a0f7d8bfef --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,qcs404.txt @@ -0,0 +1,45 @@ +Qualcomm QCS404 Network-On-Chip interconnect driver binding +----------------------------------------------------------- + +Required properties : +- compatible : shall contain only one of the following: + "qcom,qcs404-bimc" + "qcom,qcs404-pcnoc" + "qcom,qcs404-snoc" +- #interconnect-cells : should contain 1 + +reg : specifies the physical base address and size of registers +clocks : list of phandles and specifiers to all interconnect bus clocks +clock-names : clock names should include both "bus" and "bus_a" + +Example: + +soc { + ... + bimc: interconnect@400000 { + reg = <0x00400000 0x80000>; + compatible = "qcom,qcs404-bimc"; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a"; + clocks = <&rpmcc RPM_SMD_BIMC_CLK>, + <&rpmcc RPM_SMD_BIMC_A_CLK>; + }; + + pnoc: interconnect@500000 { + reg = <0x00500000 0x15080>; + compatible = "qcom,qcs404-pcnoc"; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a"; + clocks = <&rpmcc RPM_SMD_PNOC_CLK>, + <&rpmcc RPM_SMD_PNOC_A_CLK>; + }; + + snoc: interconnect@580000 { + reg = <0x00580000 0x23080>; + compatible = "qcom,qcs404-snoc"; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a"; + clocks = <&rpmcc RPM_SMD_SNOC_CLK>, + <&rpmcc RPM_SMD_SNOC_A_CLK>; + }; +}; diff --git a/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt index 7d531d5fff2936601d93a09665046bb7f13f5c56..684bb1cd75eca4495249626b33e88ee90c638d4f 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt @@ -16,6 +16,7 @@ Required properties: "amlogic,meson-gxl-gpio-intc" for GXL SoCs (S905X, S912) "amlogic,meson-axg-gpio-intc" for AXG SoCs (A113D, A113X) "amlogic,meson-g12a-gpio-intc" for G12A SoCs (S905D2, S905X2, S905Y2) + "amlogic,meson-sm1-gpio-intc" for SM1 SoCs (S905D3, S905X3, S905Y3) - reg : Specifies base physical address and size of the registers. - interrupt-controller : Identifies the node as an interrupt controller. - #interrupt-cells : Specifies the number of cells needed to encode an diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml index c34df35a25fcc6a42a791060fa3da6bf7507befc..1fe147daca4cb1e014edb9388f0590aa99f25bc9 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml @@ -44,11 +44,13 @@ properties: be at least 4. The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI - interrupts. Other values are reserved for future use. + interrupts, 2 for interrupts in the Extended SPI range, 3 for the + Extended PPI range. Other values are reserved for future use. The 2nd cell contains the interrupt number for the interrupt type. SPI interrupts are in the range [0-987]. PPI interrupts are in the - range [0-15]. + range [0-15]. Extented SPI interrupts are in the range [0-1023]. + Extended PPI interrupts are in the range [0-127]. The 3rd cell is the flags, encoded as follows: bits[3:0] trigger type and level flags. diff --git a/Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt b/Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt index 0e312fea2a5dee12ae04c8328f3b701aab2a0476..84ced3f4179b9a8fa9a3387007f8969ecfc61efb 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt @@ -15,6 +15,7 @@ Required properties: "mediatek,mt7629-sysirq", "mediatek,mt6577-sysirq": for MT7629 "mediatek,mt6795-sysirq", "mediatek,mt6577-sysirq": for MT6795 "mediatek,mt6797-sysirq", "mediatek,mt6577-sysirq": for MT6797 + "mediatek,mt6779-sysirq", "mediatek,mt6577-sysirq": for MT6779 "mediatek,mt6765-sysirq", "mediatek,mt6577-sysirq": for MT6765 "mediatek,mt6755-sysirq", "mediatek,mt6577-sysirq": for MT6755 "mediatek,mt6592-sysirq", "mediatek,mt6577-sysirq": for MT6592 diff --git a/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt index 6922db598deface3f76f32e605499cf096060968..ce59a505f5a4c21ea288688b4d967e061274bc83 100644 --- a/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt +++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt @@ -11,10 +11,23 @@ ARM Short-Descriptor translation table format for address translation. | m4u (Multimedia Memory Management Unit) | + +--------+ + | | + gals0-rx gals1-rx (Global Async Local Sync rx) + | | + | | + gals0-tx gals1-tx (Global Async Local Sync tx) + | | Some SoCs may have GALS. + +--------+ + | SMI Common(Smart Multimedia Interface Common) | +----------------+------- | | + | gals-rx There may be GALS in some larbs. + | | + | | + | gals-tx | | SMI larb0 SMI larb1 ... SoCs have several SMI local arbiter(larb). (display) (vdec) @@ -36,6 +49,10 @@ each local arbiter. like display, video decode, and camera. And there are different ports in each larb. Take a example, There are many ports like MC, PP, VLD in the video decode local arbiter, all these ports are according to the video HW. + In some SoCs, there may be a GALS(Global Async Local Sync) module between +smi-common and m4u, and additional GALS module between smi-larb and +smi-common. GALS can been seen as a "asynchronous fifo" which could help +synchronize for the modules in different clock frequency. Required properties: - compatible : must be one of the following string: @@ -44,18 +61,25 @@ Required properties: "mediatek,mt7623-m4u", "mediatek,mt2701-m4u" for mt7623 which uses generation one m4u HW. "mediatek,mt8173-m4u" for mt8173 which uses generation two m4u HW. + "mediatek,mt8183-m4u" for mt8183 which uses generation two m4u HW. - reg : m4u register base and size. - interrupts : the interrupt of m4u. - clocks : must contain one entry for each clock-names. -- clock-names : must be "bclk", It is the block clock of m4u. +- clock-names : Only 1 optional clock: + - "bclk": the block clock of m4u. + Here is the list which require this "bclk": + - mt2701, mt2712, mt7623 and mt8173. + Note that m4u use the EMI clock which always has been enabled before kernel + if there is no this "bclk". - mediatek,larbs : List of phandle to the local arbiters in the current Socs. Refer to bindings/memory-controllers/mediatek,smi-larb.txt. It must sort according to the local arbiter index, like larb0, larb1, larb2... - iommu-cells : must be 1. This is the mtk_m4u_id according to the HW. Specifies the mtk_m4u_id as defined in dt-binding/memory/mt2701-larb-port.h for mt2701, mt7623 - dt-binding/memory/mt2712-larb-port.h for mt2712, and - dt-binding/memory/mt8173-larb-port.h for mt8173. + dt-binding/memory/mt2712-larb-port.h for mt2712, + dt-binding/memory/mt8173-larb-port.h for mt8173, and + dt-binding/memory/mt8183-larb-port.h for mt8183. Example: iommu: iommu@10205000 { diff --git a/Documentation/devicetree/bindings/leds/ams,as3645a.txt b/Documentation/devicetree/bindings/leds/ams,as3645a.txt index fdc40e354a64dd582d86841afac520a73d6fa5f0..4af2987b25e92394ebd46456e30002d3ae3a6101 100644 --- a/Documentation/devicetree/bindings/leds/ams,as3645a.txt +++ b/Documentation/devicetree/bindings/leds/ams,as3645a.txt @@ -39,7 +39,9 @@ ams,input-max-microamp: Maximum flash controller input current. The Optional properties of the flash child node =========================================== -label : The label of the flash LED. +function : See Documentation/devicetree/bindings/leds/common.txt. +color : See Documentation/devicetree/bindings/leds/common.txt. +label : See Documentation/devicetree/bindings/leds/common.txt (deprecated). Required properties of the indicator child node (1) @@ -52,28 +54,32 @@ led-max-microamp: Maximum indicator current. The allowed values are Optional properties of the indicator child node =============================================== -label : The label of the indicator LED. +function : See Documentation/devicetree/bindings/leds/common.txt. +color : See Documentation/devicetree/bindings/leds/common.txt. +label : See Documentation/devicetree/bindings/leds/common.txt (deprecated). Example ======= +#include + as3645a@30 { - #address-cells: 1 - #size-cells: 0 + #address-cells = <1>; + #size-cells = <0>; reg = <0x30>; compatible = "ams,as3645a"; - flash@0 { + led@0 { reg = <0x0>; flash-timeout-us = <150000>; flash-max-microamp = <320000>; led-max-microamp = <60000>; ams,input-max-microamp = <1750000>; - label = "as3645a:flash"; + function = LED_FUNCTION_FLASH; }; - indicator@1 { + led@1 { reg = <0x1>; led-max-microamp = <10000>; - label = "as3645a:indicator"; + function = LED_FUNCTION_INDICATOR; }; }; diff --git a/Documentation/devicetree/bindings/leds/common.txt b/Documentation/devicetree/bindings/leds/common.txt index 70876ac11367c9b8c369bd219e193ceb7d1e9581..9fa6f9795d50c8e9eb9abd116af81eaaaa3d3c58 100644 --- a/Documentation/devicetree/bindings/leds/common.txt +++ b/Documentation/devicetree/bindings/leds/common.txt @@ -10,14 +10,30 @@ can influence the way of the LED device initialization, the LED components have to be tightly coupled with the LED device binding. They are represented by child nodes of the parent LED device binding. + Optional properties for child nodes: - led-sources : List of device current outputs the LED is connected to. The outputs are identified by the numbers that must be defined in the LED device binding documentation. + +- function: LED functon. Use one of the LED_FUNCTION_* prefixed definitions + from the header include/dt-bindings/leds/common.h. + If there is no matching LED_FUNCTION available, add a new one. + +- color : Color of the LED. Use one of the LED_COLOR_ID_* prefixed definitions + from the header include/dt-bindings/leds/common.h. + If there is no matching LED_COLOR_ID available, add a new one. + +- function-enumerator: Integer to be used when more than one instance + of the same function is needed, differing only with + an ordinal number. + - label : The label for this LED. If omitted, the label is taken from the node name (excluding the unit address). It has to uniquely identify a device, i.e. no other LED class device can be assigned the same - label. + label. This property is deprecated - use 'function' and 'color' + properties instead. function-enumerator has no effect when this + property is present. - default-state : The initial state of the LED. Valid values are "on", "off", and "keep". If the LED is already on or off and the default-state property is @@ -99,29 +115,59 @@ Required properties for trigger source: * Examples -gpio-leds { +#include + +led-controller@0 { compatible = "gpio-leds"; - system-status { - label = "Status"; + led0 { + function = LED_FUNCTION_STATUS; linux,default-trigger = "heartbeat"; gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; }; - usb { + led1 { + function = LED_FUNCTION_USB; gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; trigger-sources = <&ohci_port1>, <&ehci_port1>; }; }; -max77693-led { +led-controller@0 { compatible = "maxim,max77693-led"; - camera-flash { - label = "Flash"; + led { + function = LED_FUNCTION_FLASH; + color = ; led-sources = <0>, <1>; led-max-microamp = <50000>; flash-max-microamp = <320000>; flash-max-timeout-us = <500000>; }; }; + +led-controller@30 { + compatible = "panasonic,an30259a"; + reg = <0x30>; + #address-cells = <1>; + #size-cells = <0>; + + led@1 { + reg = <1>; + linux,default-trigger = "heartbeat"; + function = LED_FUNCTION_INDICATOR; + function-enumerator = <1>; + }; + + led@2 { + reg = <2>; + function = LED_FUNCTION_INDICATOR; + function-enumerator = <2>; + }; + + led@3 { + reg = <3>; + function = LED_FUNCTION_INDICATOR; + function-enumerator = <3>; + }; +}; diff --git a/Documentation/devicetree/bindings/leds/leds-aat1290.txt b/Documentation/devicetree/bindings/leds/leds-aat1290.txt index 85c0c58617f6da50d3ac0f7f4177df3d9aeb68ab..62ed17ec075b7d2913a3740a7119b474deb04e3f 100644 --- a/Documentation/devicetree/bindings/leds/leds-aat1290.txt +++ b/Documentation/devicetree/bindings/leds/leds-aat1290.txt @@ -32,15 +32,18 @@ Required properties of the LED child node: formula: T = 8.82 * 10^9 * Ct. Optional properties of the LED child node: -- label : see Documentation/devicetree/bindings/leds/common.txt +- function : see Documentation/devicetree/bindings/leds/common.txt +- color : see Documentation/devicetree/bindings/leds/common.txt +- label : see Documentation/devicetree/bindings/leds/common.txt (deprecated) Example (by Ct = 220nF, Rset = 160kohm and exynos4412-trats2 board with a switch that allows for routing strobe signal either from the host or from the camera sensor): #include "exynos4412.dtsi" +#include -aat1290 { +led-controller { compatible = "skyworks,aat1290"; flen-gpios = <&gpj1 1 GPIO_ACTIVE_HIGH>; enset-gpios = <&gpj1 2 GPIO_ACTIVE_HIGH>; @@ -50,8 +53,9 @@ aat1290 { pinctrl-1 = <&camera_flash_host>; pinctrl-2 = <&camera_flash_isp>; - camera_flash: flash-led { - label = "aat1290-flash"; + camera_flash: led { + function = LED_FUNCTION_FLASH; + color = ; led-max-microamp = <520833>; flash-max-microamp = <1012500>; flash-max-timeout-us = <1940000>; diff --git a/Documentation/devicetree/bindings/leds/leds-an30259a.txt b/Documentation/devicetree/bindings/leds/leds-an30259a.txt index 6ffb861083c029bdb2bc7ddb62255d05eca1d878..cbd833906b2b549c623cb1507f590834696f7a56 100644 --- a/Documentation/devicetree/bindings/leds/leds-an30259a.txt +++ b/Documentation/devicetree/bindings/leds/leds-an30259a.txt @@ -15,10 +15,19 @@ Required sub-node properties: - reg: Pin that the LED is connected to. Must be 1, 2, or 3. Optional sub-node properties: - - label: see Documentation/devicetree/bindings/leds/common.txt - - linux,default-trigger: see Documentation/devicetree/bindings/leds/common.txt + - function : + see Documentation/devicetree/bindings/leds/common.txt + - color : + see Documentation/devicetree/bindings/leds/common.txt + - label : + see Documentation/devicetree/bindings/leds/common.txt (deprecated) + - linux,default-trigger : + see Documentation/devicetree/bindings/leds/common.txt Example: + +#include + led-controller@30 { compatible = "panasonic,an30259a"; reg = <0x30>; @@ -28,16 +37,19 @@ led-controller@30 { led@1 { reg = <1>; linux,default-trigger = "heartbeat"; - label = "red:indicator"; + function = LED_FUNCTION_INDICATOR; + color = ; }; led@2 { reg = <2>; - label = "green:indicator"; + function = LED_FUNCTION_INDICATOR; + color = ; }; led@3 { reg = <3>; - label = "blue:indicator"; + function = LED_FUNCTION_INDICATOR; + color = ; }; }; diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt index 4255b19ad25cf597efdd99bf3591810d4432d707..f8de7516a39b080f6600660bba344e4471623a44 100644 --- a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt +++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt @@ -11,14 +11,20 @@ Property rules described in Documentation/devicetree/bindings/spi/spi-bus.txt apply. In particular, "reg" and "spi-max-frequency" properties must be given. LED sub-node properties: -- label : +- function : + see Documentation/devicetree/bindings/leds/common.txt +- color : see Documentation/devicetree/bindings/leds/common.txt +- label : + see Documentation/devicetree/bindings/leds/common.txt (deprecated) - linux,default-trigger : (optional) see Documentation/devicetree/bindings/leds/common.txt Example ------- +#include + led-controller@0 { compatible = "crane,cr0014114"; reg = <0>; @@ -28,27 +34,33 @@ led-controller@0 { led@0 { reg = <0>; - label = "red:coin"; + function = "coin"; + color = ; }; led@1 { reg = <1>; - label = "green:coin"; + function = "coin"; + color = ; }; led@2 { reg = <2>; - label = "blue:coin"; + function = "coin"; + color = ; }; led@3 { reg = <3>; - label = "red:bill"; + function = "bill"; + color = ; }; led@4 { reg = <4>; - label = "green:bill"; + function = "bill"; + color = ; }; led@5 { reg = <5>; - label = "blue:bill"; + function = "bill"; + color = ; }; ... }; diff --git a/Documentation/devicetree/bindings/leds/leds-gpio.txt b/Documentation/devicetree/bindings/leds/leds-gpio.txt index a48dda268f81b4f3fcb3cceeb8dea6ff536bceb9..d21281b63d3800709551179f5fe807b22c67c69c 100644 --- a/Documentation/devicetree/bindings/leds/leds-gpio.txt +++ b/Documentation/devicetree/bindings/leds/leds-gpio.txt @@ -10,8 +10,12 @@ LED sub-node properties: - gpios : Should specify the LED's GPIO, see "gpios property" in Documentation/devicetree/bindings/gpio/gpio.txt. Active low LEDs should be indicated using flags in the GPIO specifier. -- label : (optional) +- function : (optional) + see Documentation/devicetree/bindings/leds/common.txt +- color : (optional) see Documentation/devicetree/bindings/leds/common.txt +- label : (optional) + see Documentation/devicetree/bindings/leds/common.txt (deprecated) - linux,default-trigger : (optional) see Documentation/devicetree/bindings/leds/common.txt - default-state: (optional) The initial state of the LED. @@ -27,30 +31,34 @@ LED sub-node properties: Examples: #include +#include leds { compatible = "gpio-leds"; - hdd { - label = "Disk Activity"; + led0 { gpios = <&mcu_pio 0 GPIO_ACTIVE_LOW>; linux,default-trigger = "disk-activity"; + function = LED_FUNCTION_DISK; }; - fault { + led1 { gpios = <&mcu_pio 1 GPIO_ACTIVE_HIGH>; /* Keep LED on if BIOS detected hardware fault */ default-state = "keep"; + function = LED_FUNCTION_FAULT; }; }; run-control { compatible = "gpio-leds"; - red { + led0 { gpios = <&mpc8572 6 GPIO_ACTIVE_HIGH>; + color = ; default-state = "off"; }; - green { + led1 { gpios = <&mpc8572 7 GPIO_ACTIVE_HIGH>; + color = ; default-state = "on"; }; }; @@ -58,9 +66,10 @@ run-control { leds { compatible = "gpio-leds"; - charger-led { + led0 { gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; linux,default-trigger = "max8903-charger-charging"; retain-state-suspended; + function = LED_FUNCTION_CHARGE; }; }; diff --git a/Documentation/devicetree/bindings/leds/leds-lm3532.txt b/Documentation/devicetree/bindings/leds/leds-lm3532.txt index c087f85ddddc6e82f9442eeeae1208a1292cbd71..53793213dd52edb5b52b68a4c4bc4cebd7f026a5 100644 --- a/Documentation/devicetree/bindings/leds/leds-lm3532.txt +++ b/Documentation/devicetree/bindings/leds/leds-lm3532.txt @@ -62,6 +62,9 @@ Optional LED child properties: - label : see Documentation/devicetree/bindings/leds/common.txt - linux,default-trigger : see Documentation/devicetree/bindings/leds/common.txt + - led-max-microamp : Defines the full scale current value for each control + bank. The range is from 5000uA-29800uA in increments + of 800uA. Example: led-controller@38 { @@ -85,6 +88,7 @@ led-controller@38 { reg = <0>; led-sources = <2>; ti,led-mode = <1>; + led-max-microamp = <21800>; label = ":backlight"; linux,default-trigger = "backlight"; }; diff --git a/Documentation/devicetree/bindings/leds/leds-lm3601x.txt b/Documentation/devicetree/bindings/leds/leds-lm3601x.txt index a88b2c41e75b7f81d5a7a8e95261d0a5f907b03b..095dafb6ec7fba8f3f7913752f48c329c6ff2e57 100644 --- a/Documentation/devicetree/bindings/leds/leds-lm3601x.txt +++ b/Documentation/devicetree/bindings/leds/leds-lm3601x.txt @@ -22,9 +22,14 @@ Required properties for flash LED child nodes: - led-max-microamp : Range from 2.4mA - 376mA Optional child properties: - - label : see Documentation/devicetree/bindings/leds/common.txt + - function : see Documentation/devicetree/bindings/leds/common.txt + - color : see Documentation/devicetree/bindings/leds/common.txt + - label : see Documentation/devicetree/bindings/leds/common.txt (deprecated) Example: + +#include + led-controller@64 { compatible = "ti,lm36010"; #address-cells = <1>; @@ -33,7 +38,8 @@ led-controller@64 { led@0 { reg = <1>; - label = "white:torch"; + function = LED_FUNCTION_TORCH; + color = ; led-max-microamp = <376000>; flash-max-microamp = <1500000>; flash-max-timeout-us = <1600000>; diff --git a/Documentation/devicetree/bindings/leds/leds-lm3692x.txt b/Documentation/devicetree/bindings/leds/leds-lm3692x.txt index 08b352840bd7f8f05099015dc3637b85b64bbb5f..4c2d923f8758b0434a3d97552bbe7ff563f1a6de 100644 --- a/Documentation/devicetree/bindings/leds/leds-lm3692x.txt +++ b/Documentation/devicetree/bindings/leds/leds-lm3692x.txt @@ -26,12 +26,16 @@ Required child properties: 3 - Will enable the LED3 sync (LM36923 only) Optional child properties: - - label : see Documentation/devicetree/bindings/leds/common.txt + - function : see Documentation/devicetree/bindings/leds/common.txt + - color : see Documentation/devicetree/bindings/leds/common.txt + - label : see Documentation/devicetree/bindings/leds/common.txt (deprecated) - linux,default-trigger : see Documentation/devicetree/bindings/leds/common.txt Example: +#include + led-controller@36 { compatible = "ti,lm3692x"; reg = <0x36>; @@ -43,7 +47,8 @@ led-controller@36 { led@0 { reg = <0>; - label = "white:backlight_cluster"; + function = LED_FUNCTION_BACKLIGHT; + color = ; linux,default-trigger = "backlight"; }; } diff --git a/Documentation/devicetree/bindings/leds/leds-lp8860.txt b/Documentation/devicetree/bindings/leds/leds-lp8860.txt index 5f0e892ad7592480ef220c26fb31fe7b88b01f77..9863220db4ba6f8611c742269c806e09cc14b622 100644 --- a/Documentation/devicetree/bindings/leds/leds-lp8860.txt +++ b/Documentation/devicetree/bindings/leds/leds-lp8860.txt @@ -20,12 +20,16 @@ Required child properties: - reg : 0 Optional child properties: - - label : see Documentation/devicetree/bindings/leds/common.txt + - function : see Documentation/devicetree/bindings/leds/common.txt + - color : see Documentation/devicetree/bindings/leds/common.txt + - label : see Documentation/devicetree/bindings/leds/common.txt (deprecated) - linux,default-trigger : see Documentation/devicetree/bindings/leds/common.txt Example: +#include + led-controller@2d { compatible = "ti,lp8860"; #address-cells = <1>; @@ -36,7 +40,8 @@ led-controller@2d { led@0 { reg = <0>; - label = "white:backlight"; + function = LED_FUNCTION_BACKLIGHT; + color = ; linux,default-trigger = "backlight"; }; } diff --git a/Documentation/devicetree/bindings/leds/leds-lt3593.txt b/Documentation/devicetree/bindings/leds/leds-lt3593.txt index 6b2cabc36c0cd6ed2956e223dd903d3fad4a7535..24eccdaa6322e2b7b0c81247251059e8beaed4db 100644 --- a/Documentation/devicetree/bindings/leds/leds-lt3593.txt +++ b/Documentation/devicetree/bindings/leds/leds-lt3593.txt @@ -9,8 +9,10 @@ The hardware supports only one LED. The properties of this LED are configured in a sub-node in the device node. Optional sub-node properties: -- label: A label for the LED. If none is given, the LED will be - named "lt3595::". +- function: See Documentation/devicetree/bindings/leds/common.txt +- color: See Documentation/devicetree/bindings/leds/common.txt +- label: A label for the LED. If none is given, the LED will be + named "lt3595::" (deprecated) - linux,default-trigger: The default trigger for the LED. See Documentation/devicetree/bindings/leds/common.txt - default-state: The initial state of the LED. @@ -21,12 +23,15 @@ be handled by its own device node. Example: +#include + led-controller { compatible = "lltc,lt3593"; lltc,ctrl-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; led { - label = "white:backlight"; + function = LED_FUNCTION_BACKLIGHT; + color = ; default-state = "on"; }; }; diff --git a/Documentation/devicetree/bindings/leds/leds-sc27xx-bltc.txt b/Documentation/devicetree/bindings/leds/leds-sc27xx-bltc.txt index dddf84f9c7ea5d1cad32715731e5ddf5640b6ad0..df2b4e1c492be09c088a9f96bbde8979c9a24e74 100644 --- a/Documentation/devicetree/bindings/leds/leds-sc27xx-bltc.txt +++ b/Documentation/devicetree/bindings/leds/leds-sc27xx-bltc.txt @@ -14,7 +14,9 @@ Required child properties: - reg: Port this LED is connected to. Optional child properties: -- label: See Documentation/devicetree/bindings/leds/common.txt. +- function: See Documentation/devicetree/bindings/leds/common.txt. +- color: See Documentation/devicetree/bindings/leds/common.txt. +- label: See Documentation/devicetree/bindings/leds/common.txt (deprecated). Examples: @@ -25,17 +27,17 @@ led-controller@200 { reg = <0x200>; led@0 { - label = "red"; + color = ; reg = <0x0>; }; led@1 { - label = "green"; + color = ; reg = <0x1>; }; led@2 { - label = "blue"; + color = ; reg = <0x2>; }; }; diff --git a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml new file mode 100644 index 0000000000000000000000000000000000000000..27f38eed389e4830b8fb37794ac1fc89f6c962a4 --- /dev/null +++ b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml @@ -0,0 +1,109 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/allwinner,sun4i-a10-csi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A10 CMOS Sensor Interface (CSI) Device Tree Bindings + +maintainers: + - Chen-Yu Tsai + - Maxime Ripard + +description: |- + The Allwinner A10 and later has a CMOS Sensor Interface to retrieve + frames from a parallel or BT656 sensor. + +properties: + compatible: + const: allwinner,sun7i-a20-csi0 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: The CSI interface clock + - description: The CSI module clock + - description: The CSI ISP clock + - description: The CSI DRAM clock + + clock-names: + items: + - const: bus + - const: mod + - const: isp + - const: ram + + resets: + maxItems: 1 + + # See ./video-interfaces.txt for details + port: + type: object + additionalProperties: false + + properties: + endpoint: + type: object + + properties: + bus-width: + enum: [8, 16] + + data-active: true + hsync-active: true + pclk-sample: true + remote-endpoint: true + vsync-active: true + + required: + - bus-width + - data-active + - hsync-active + - pclk-sample + - remote-endpoint + - vsync-active + + required: + - endpoint + +required: + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + #include + #include + #include + + csi0: csi@1c09000 { + compatible = "allwinner,sun7i-a20-csi0"; + reg = <0x01c09000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_AHB_CSI0>, <&ccu CLK_CSI0>, + <&ccu CLK_CSI_SCLK>, <&ccu CLK_DRAM_CSI0>; + clock-names = "bus", "mod", "isp", "ram"; + resets = <&ccu RST_CSI0>; + + port { + csi_from_ov5640: endpoint { + remote-endpoint = <&ov5640_to_csi>; + bus-width = <8>; + hsync-active = <1>; /* Active high */ + vsync-active = <0>; /* Active low */ + data-active = <1>; /* Active high */ + pclk-sample = <1>; /* Rising */ + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-ir.yaml b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-ir.yaml new file mode 100644 index 0000000000000000000000000000000000000000..98c1bdde9a868c88bba43be4e9bdf8538a712e08 --- /dev/null +++ b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-ir.yaml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/allwinner,sun4i-a10-ir.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A10 Infrared Controller Device Tree Bindings + +maintainers: + - Chen-Yu Tsai + - Maxime Ripard + +allOf: + - $ref: "rc.yaml#" + +properties: + compatible: + oneOf: + - const: allwinner,sun4i-a10-ir + - const: allwinner,sun5i-a13-ir + - items: + - const: allwinner,sun8i-a83t-ir + - const: allwinner,sun6i-a31-ir + - const: allwinner,sun6i-a31-ir + - items: + - const: allwinner,sun50i-a64-ir + - const: allwinner,sun6i-a31-ir + - items: + - const: allwinner,sun50i-h6-ir + - const: allwinner,sun6i-a31-ir + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Bus Clock + - description: Module Clock + + clock-names: + items: + - const: apb + - const: ir + + resets: + maxItems: 1 + + clock-frequency: + default: 8000000 + description: + IR Receiver clock frequency, in Hertz. + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +# FIXME: We should set it, but it would report all the generic +# properties as additional properties. +# additionalProperties: false + +examples: + - | + ir0: ir@1c21800 { + compatible = "allwinner,sun4i-a10-ir"; + clocks = <&apb0_gates 6>, <&ir0_clk>; + clock-names = "apb", "ir"; + clock-frequency = <3000000>; + resets = <&apb0_rst 1>; + interrupts = <0 5 1>; + reg = <0x01C21800 0x40>; + linux,rc-map-name = "rc-rc6-mce"; + }; + +... diff --git a/Documentation/devicetree/bindings/media/amlogic,vdec.txt b/Documentation/devicetree/bindings/media/amlogic,vdec.txt index aabdd01bcf32b4ca5d1af2cecdd000dbc6cf1233..9b6aace86ca7e185ba4b6a3428067a2cd7ab7e46 100644 --- a/Documentation/devicetree/bindings/media/amlogic,vdec.txt +++ b/Documentation/devicetree/bindings/media/amlogic,vdec.txt @@ -26,6 +26,7 @@ Required properties: - GXBB (S905) : "amlogic,gxbb-vdec" - GXL (S905X, S905D) : "amlogic,gxl-vdec" - GXM (S912) : "amlogic,gxm-vdec" + followed by the common "amlogic,gx-vdec" - reg: base address and size of he following memory-mapped regions : - dos - esparser @@ -47,8 +48,8 @@ Required properties: Example: -vdec: video-decoder@c8820000 { - compatible = "amlogic,gxbb-vdec"; +vdec: video-codec@c8820000 { + compatible = "amlogic,gxbb-vdec", "amlogic,gx-vdec"; reg = <0x0 0xc8820000 0x0 0x10000>, <0x0 0xc110a580 0x0 0xe4>; reg-names = "dos", "esparser"; diff --git a/Documentation/devicetree/bindings/media/cdns,csi2tx.txt b/Documentation/devicetree/bindings/media/cdns,csi2tx.txt index 459c6e332f5290a9a746306041ab2a848286a0f3..751b9edf12471d86f3bfe899b541dc66e75c4e9f 100644 --- a/Documentation/devicetree/bindings/media/cdns,csi2tx.txt +++ b/Documentation/devicetree/bindings/media/cdns,csi2tx.txt @@ -5,7 +5,8 @@ The Cadence MIPI-CSI2 TX controller is a CSI-2 bridge supporting up to 4 CSI lanes in output, and up to 4 different pixel streams in input. Required properties: - - compatible: must be set to "cdns,csi2tx" + - compatible: must be set to "cdns,csi2tx" or "cdns,csi2tx-1.3" + for version 1.3 of the controller, "cdns,csi2tx-2.1" for v2.1 - reg: base address and size of the memory mapped region - clocks: phandles to the clocks driving the controller - clock-names: must contain: diff --git a/Documentation/devicetree/bindings/media/imx7-csi.txt b/Documentation/devicetree/bindings/media/imx7-csi.txt index 443aef07356e9882b9130ebac332059423913ab5..d80ceefa0c00c03d6f299a76eee3de160d92faa5 100644 --- a/Documentation/devicetree/bindings/media/imx7-csi.txt +++ b/Documentation/devicetree/bindings/media/imx7-csi.txt @@ -9,7 +9,7 @@ to connect directly to external CMOS image sensors. Required properties: -- compatible : "fsl,imx7-csi"; +- compatible : "fsl,imx7-csi" or "fsl,imx6ul-csi"; - reg : base address and length of the register set for the device; - interrupts : should contain CSI interrupt; - clocks : list of clock specifiers, see diff --git a/Documentation/devicetree/bindings/media/meson-ao-cec.txt b/Documentation/devicetree/bindings/media/meson-ao-cec.txt index c67fc41d4aa23bebd1c84107bd3fd27491b6c719..ad92ee41c0dd2de4a0a70054f27128f67d0deeaf 100644 --- a/Documentation/devicetree/bindings/media/meson-ao-cec.txt +++ b/Documentation/devicetree/bindings/media/meson-ao-cec.txt @@ -5,10 +5,12 @@ to handle communication between HDMI connected devices over the CEC bus. Required properties: - compatible : value should be following depending on the SoC : - For GXBB, GXL, GXM and G12A (AO_CEC_A module) : + For GXBB, GXL, GXM, G12A and SM1 (AO_CEC_A module) : "amlogic,meson-gx-ao-cec" For G12A (AO_CEC_B module) : "amlogic,meson-g12a-ao-cec" + For SM1 (AO_CEC_B module) : + "amlogic,meson-sm1-ao-cec" - reg : Physical base address of the IP registers and length of memory mapped region. @@ -16,9 +18,9 @@ Required properties: - interrupts : AO-CEC interrupt number to the CPU. - clocks : from common clock binding: handle to AO-CEC clock. - clock-names : from common clock binding, must contain : - For GXBB, GXL, GXM and G12A (AO_CEC_A module) : + For GXBB, GXL, GXM, G12A and SM1 (AO_CEC_A module) : - "core" - For G12A (AO_CEC_B module) : + For G12A, SM1 (AO_CEC_B module) : - "oscin" corresponding to entry in the clocks property. - hdmi-phandle: phandle to the HDMI controller diff --git a/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt b/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt index 7302e949e662cb8070fb0a32b9f77d75bd249c62..602169b8aa1986a9d9c215c3ca764c16376e364f 100644 --- a/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt +++ b/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt @@ -35,6 +35,7 @@ Optional properties: - resets : Must contain an entry for each entry in reset-names. - reset-names : Must include the following entries: - mc +- iommus: Must contain phandle to the IOMMU device node. Example: @@ -59,4 +60,5 @@ video-codec@6001a000 { clocks = <&tegra_car TEGRA20_CLK_VDE>; reset-names = "vde", "mc"; resets = <&tegra_car 61>, <&mc TEGRA20_MC_RESET_VDE>; + iommus = <&mc TEGRA_SWGROUP_VDE>; }; diff --git a/Documentation/devicetree/bindings/media/rc.txt b/Documentation/devicetree/bindings/media/rc.txt index d3e7a012bfda15ef2121e4ee3af7930cb5a3f3a4..be629f7fa77ee8bcf0e48cc7e4b3741df082b5ec 100644 --- a/Documentation/devicetree/bindings/media/rc.txt +++ b/Documentation/devicetree/bindings/media/rc.txt @@ -1,117 +1 @@ -The following properties are common to the infrared remote controllers: - -- linux,rc-map-name: string, specifies the scancode/key mapping table - defined in-kernel for the remote controller. Support values are: - * "rc-adstech-dvb-t-pci" - * "rc-alink-dtu-m" - * "rc-anysee" - * "rc-apac-viewcomp" - * "rc-asus-pc39" - * "rc-asus-ps3-100" - * "rc-ati-tv-wonder-hd-600" - * "rc-ati-x10" - * "rc-avermedia-a16d" - * "rc-avermedia-cardbus" - * "rc-avermedia-dvbt" - * "rc-avermedia-m135a" - * "rc-avermedia-m733a-rm-k6" - * "rc-avermedia-rm-ks" - * "rc-avermedia" - * "rc-avertv-303" - * "rc-azurewave-ad-tu700" - * "rc-behold-columbus" - * "rc-behold" - * "rc-budget-ci-old" - * "rc-cec" - * "rc-cinergy-1400" - * "rc-cinergy" - * "rc-delock-61959" - * "rc-dib0700-nec" - * "rc-dib0700-rc5" - * "rc-digitalnow-tinytwin" - * "rc-digittrade" - * "rc-dm1105-nec" - * "rc-dntv-live-dvbt-pro" - * "rc-dntv-live-dvb-t" - * "rc-dtt200u" - * "rc-dvbsky" - * "rc-empty" - * "rc-em-terratec" - * "rc-encore-enltv2" - * "rc-encore-enltv-fm53" - * "rc-encore-enltv" - * "rc-evga-indtube" - * "rc-eztv" - * "rc-flydvb" - * "rc-flyvideo" - * "rc-fusionhdtv-mce" - * "rc-gadmei-rm008z" - * "rc-geekbox" - * "rc-genius-tvgo-a11mce" - * "rc-gotview7135" - * "rc-hauppauge" - * "rc-imon-mce" - * "rc-imon-pad" - * "rc-iodata-bctv7e" - * "rc-it913x-v1" - * "rc-it913x-v2" - * "rc-kaiomy" - * "rc-kworld-315u" - * "rc-kworld-pc150u" - * "rc-kworld-plus-tv-analog" - * "rc-leadtek-y04g0051" - * "rc-lirc" - * "rc-lme2510" - * "rc-manli" - * "rc-medion-x10" - * "rc-medion-x10-digitainer" - * "rc-medion-x10-or2x" - * "rc-msi-digivox-ii" - * "rc-msi-digivox-iii" - * "rc-msi-tvanywhere-plus" - * "rc-msi-tvanywhere" - * "rc-nebula" - * "rc-nec-terratec-cinergy-xs" - * "rc-norwood" - * "rc-npgtech" - * "rc-pctv-sedna" - * "rc-pinnacle-color" - * "rc-pinnacle-grey" - * "rc-pinnacle-pctv-hd" - * "rc-pixelview-new" - * "rc-pixelview" - * "rc-pixelview-002t" - * "rc-pixelview-mk12" - * "rc-powercolor-real-angel" - * "rc-proteus-2309" - * "rc-purpletv" - * "rc-pv951" - * "rc-hauppauge" - * "rc-rc5-tv" - * "rc-rc6-mce" - * "rc-real-audio-220-32-keys" - * "rc-reddo" - * "rc-snapstream-firefly" - * "rc-streamzap" - * "rc-tbs-nec" - * "rc-technisat-ts35" - * "rc-technisat-usb2" - * "rc-terratec-cinergy-c-pci" - * "rc-terratec-cinergy-s2-hd" - * "rc-terratec-cinergy-xs" - * "rc-terratec-slim" - * "rc-terratec-slim-2" - * "rc-tevii-nec" - * "rc-tivo" - * "rc-total-media-in-hand" - * "rc-total-media-in-hand-02" - * "rc-trekstor" - * "rc-tt-1500" - * "rc-twinhan-dtv-cab-ci" - * "rc-twinhan1027" - * "rc-videomate-k100" - * "rc-videomate-s350" - * "rc-videomate-tv-pvr" - * "rc-winfast" - * "rc-winfast-usbii-deluxe" - * "rc-su3000" +This file has been moved to rc.yaml. diff --git a/Documentation/devicetree/bindings/media/rc.yaml b/Documentation/devicetree/bindings/media/rc.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3d5c154fd23024169dc9664d3b8679ce2fbe3e54 --- /dev/null +++ b/Documentation/devicetree/bindings/media/rc.yaml @@ -0,0 +1,145 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/rc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic Infrared Remote Controller Device Tree Bindings + +maintainers: + - Mauro Carvalho Chehab + - Sean Young + +properties: + $nodename: + pattern: "^ir(@[a-f0-9]+)?$" + + linux,rc-map-name: + description: + Specifies the scancode/key mapping table defined in-kernel for + the remote controller. + allOf: + - $ref: '/schemas/types.yaml#/definitions/string' + - enum: + - rc-adstech-dvb-t-pci + - rc-alink-dtu-m + - rc-anysee + - rc-apac-viewcomp + - rc-astrometa-t2hybrid + - rc-asus-pc39 + - rc-asus-ps3-100 + - rc-ati-tv-wonder-hd-600 + - rc-ati-x10 + - rc-avermedia + - rc-avermedia-a16d + - rc-avermedia-cardbus + - rc-avermedia-dvbt + - rc-avermedia-m135a + - rc-avermedia-m733a-rm-k6 + - rc-avermedia-rm-ks + - rc-avertv-303 + - rc-azurewave-ad-tu700 + - rc-behold + - rc-behold-columbus + - rc-budget-ci-old + - rc-cec + - rc-cinergy + - rc-cinergy-1400 + - rc-d680-dmb + - rc-delock-61959 + - rc-dib0700-nec + - rc-dib0700-rc5 + - rc-digitalnow-tinytwin + - rc-digittrade + - rc-dm1105-nec + - rc-dntv-live-dvb-t + - rc-dntv-live-dvbt-pro + - rc-dtt200u + - rc-dvbsky + - rc-dvico-mce + - rc-dvico-portable + - rc-em-terratec + - rc-empty + - rc-encore-enltv + - rc-encore-enltv-fm53 + - rc-encore-enltv2 + - rc-evga-indtube + - rc-eztv + - rc-flydvb + - rc-flyvideo + - rc-fusionhdtv-mce + - rc-gadmei-rm008z + - rc-geekbox + - rc-genius-tvgo-a11mce + - rc-gotview7135 + - rc-hauppauge + - rc-hauppauge + - rc-hisi-poplar + - rc-hisi-tv-demo + - rc-imon-mce + - rc-imon-pad + - rc-imon-rsc + - rc-iodata-bctv7e + - rc-it913x-v1 + - rc-it913x-v2 + - rc-kaiomy + - rc-kworld-315u + - rc-kworld-pc150u + - rc-kworld-plus-tv-analog + - rc-leadtek-y04g0051 + - rc-lme2510 + - rc-manli + - rc-medion-x10 + - rc-medion-x10-digitainer + - rc-medion-x10-or2x + - rc-msi-digivox-ii + - rc-msi-digivox-iii + - rc-msi-tvanywhere + - rc-msi-tvanywhere-plus + - rc-nebula + - rc-nec-terratec-cinergy-xs + - rc-norwood + - rc-npgtech + - rc-pctv-sedna + - rc-pinnacle-color + - rc-pinnacle-grey + - rc-pinnacle-pctv-hd + - rc-pixelview + - rc-pixelview-002t + - rc-pixelview-mk12 + - rc-pixelview-new + - rc-powercolor-real-angel + - rc-proteus-2309 + - rc-purpletv + - rc-pv951 + - rc-rc5-tv + - rc-rc6-mce + - rc-real-audio-220-32-keys + - rc-reddo + - rc-snapstream-firefly + - rc-streamzap + - rc-su3000 + - rc-tango + - rc-tbs-nec + - rc-technisat-ts35 + - rc-technisat-usb2 + - rc-terratec-cinergy-c-pci + - rc-terratec-cinergy-s2-hd + - rc-terratec-cinergy-xs + - rc-terratec-slim + - rc-terratec-slim-2 + - rc-tevii-nec + - rc-tivo + - rc-total-media-in-hand + - rc-total-media-in-hand-02 + - rc-trekstor + - rc-tt-1500 + - rc-twinhan-dtv-cab-ci + - rc-twinhan1027 + - rc-videomate-k100 + - rc-videomate-s350 + - rc-videomate-tv-pvr + - rc-winfast + - rc-winfast-usbii-deluxe + - rc-xbox-dvd + - rc-zx-irdec diff --git a/Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt b/Documentation/devicetree/bindings/media/renesas,csi2.txt similarity index 100% rename from Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt rename to Documentation/devicetree/bindings/media/renesas,csi2.txt diff --git a/Documentation/devicetree/bindings/media/rcar_imr.txt b/Documentation/devicetree/bindings/media/renesas,imr.txt similarity index 100% rename from Documentation/devicetree/bindings/media/rcar_imr.txt rename to Documentation/devicetree/bindings/media/renesas,imr.txt diff --git a/Documentation/devicetree/bindings/media/rcar_vin.txt b/Documentation/devicetree/bindings/media/renesas,vin.txt similarity index 100% rename from Documentation/devicetree/bindings/media/rcar_vin.txt rename to Documentation/devicetree/bindings/media/renesas,vin.txt diff --git a/Documentation/devicetree/bindings/media/rockchip-vpu.txt b/Documentation/devicetree/bindings/media/rockchip-vpu.txt index 35dc464ad7c8619297e840425e2ae7b4a92286ed..339252d9c5157fda507f49a8884adaf04957d9e6 100644 --- a/Documentation/devicetree/bindings/media/rockchip-vpu.txt +++ b/Documentation/devicetree/bindings/media/rockchip-vpu.txt @@ -1,14 +1,17 @@ device-tree bindings for rockchip VPU codec Rockchip (Video Processing Unit) present in various Rockchip platforms, -such as RK3288 and RK3399. +such as RK3288, RK3328 and RK3399. Required properties: - compatible: value should be one of the following "rockchip,rk3288-vpu"; + "rockchip,rk3328-vpu"; "rockchip,rk3399-vpu"; - interrupts: encoding and decoding interrupt specifiers -- interrupt-names: should be "vepu" and "vdpu" +- interrupt-names: should be + "vepu", "vdpu" on RK3288 and RK3399, + "vdpu" on RK3328. - clocks: phandle to VPU aclk, hclk clocks - clock-names: should be "aclk" and "hclk" - power-domains: phandle to power domain node @@ -27,3 +30,14 @@ SoC-specific DT entry: power-domains = <&power RK3288_PD_VIDEO>; iommus = <&vpu_mmu>; }; + + vpu: video-codec@ff350000 { + compatible = "rockchip,rk3328-vpu"; + reg = <0x0 0xff350000 0x0 0x800>; + interrupts = ; + interrupt-names = "vdpu"; + clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; + clock-names = "aclk", "hclk"; + power-domains = <&power RK3328_PD_VPU>; + iommus = <&vpu_mmu>; + }; diff --git a/Documentation/devicetree/bindings/media/sunxi-ir.txt b/Documentation/devicetree/bindings/media/sunxi-ir.txt deleted file mode 100644 index 278098987edbd5990850d50e6992f7091dd0d392..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/media/sunxi-ir.txt +++ /dev/null @@ -1,28 +0,0 @@ -Device-Tree bindings for SUNXI IR controller found in sunXi SoC family - -Required properties: -- compatible : "allwinner,sun4i-a10-ir" or "allwinner,sun5i-a13-ir" -- clocks : list of clock specifiers, corresponding to - entries in clock-names property; -- clock-names : should contain "apb" and "ir" entries; -- interrupts : should contain IR IRQ number; -- reg : should contain IO map address for IR. - -Optional properties: -- linux,rc-map-name: see rc.txt file in the same directory. -- resets : phandle + reset specifier pair -- clock-frequency : IR Receiver clock frequency, in Hertz. Defaults to 8 MHz - if missing. - -Example: - -ir0: ir@1c21800 { - compatible = "allwinner,sun4i-a10-ir"; - clocks = <&apb0_gates 6>, <&ir0_clk>; - clock-names = "apb", "ir"; - clock-frequency = <3000000>; - resets = <&apb0_rst 1>; - interrupts = <0 5 1>; - reg = <0x01C21800 0x40>; - linux,rc-map-name = "rc-rc6-mce"; -}; diff --git a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt index e937ddd871a6bffe58f4c536eea311f4be445349..b478ade4da654e3c1206a209db6f58dff6b7ee07 100644 --- a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt +++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt @@ -2,9 +2,10 @@ SMI (Smart Multimedia Interface) Common The hardware block diagram please check bindings/iommu/mediatek,iommu.txt -Mediatek SMI have two generations of HW architecture, mt2712 and mt8173 use -the second generation of SMI HW while mt2701 uses the first generation HW of -SMI. +Mediatek SMI have two generations of HW architecture, here is the list +which generation the SoCs use: +generation 1: mt2701 and mt7623. +generation 2: mt2712, mt8173 and mt8183. There's slight differences between the two SMI, for generation 2, the register which control the iommu port is at each larb's register base. But @@ -19,6 +20,7 @@ Required properties: "mediatek,mt2712-smi-common" "mediatek,mt7623-smi-common", "mediatek,mt2701-smi-common" "mediatek,mt8173-smi-common" + "mediatek,mt8183-smi-common" - reg : the register and size of the SMI block. - power-domains : a phandle to the power domain of this local arbiter. - clocks : Must contain an entry for each entry in clock-names. @@ -30,6 +32,10 @@ Required properties: They may be the same if both source clocks are the same. - "async" : asynchronous clock, it help transform the smi clock into the emi clock domain, this clock is only needed by generation 1 smi HW. + and these 2 option clocks for generation 2 smi HW: + - "gals0": the path0 clock of GALS(Global Async Local Sync). + - "gals1": the path1 clock of GALS(Global Async Local Sync). + Here is the list which has this GALS: mt8183. Example: smi_common: smi@14022000 { diff --git a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt index 94eddcae77ab5f08af6b13885c3a3122cd53ce41..4b369b3e1a69b1d421fbca8492b2bcd2bc40e111 100644 --- a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt +++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt @@ -8,6 +8,7 @@ Required properties: "mediatek,mt2712-smi-larb" "mediatek,mt7623-smi-larb", "mediatek,mt2701-smi-larb" "mediatek,mt8173-smi-larb" + "mediatek,mt8183-smi-larb" - reg : the register and size of this local arbiter. - mediatek,smi : a phandle to the smi_common node. - power-domains : a phandle to the power domain of this local arbiter. @@ -16,6 +17,9 @@ Required properties: - "apb" : Advanced Peripheral Bus clock, It's the clock for setting the register. - "smi" : It's the clock for transfer data and command. + and this optional clock name: + - "gals": the clock for GALS(Global Async Local Sync). + Here is the list which has this GALS: mt8183. Required property for mt2701, mt2712 and mt7623: - mediatek,larb-id :the hardware id of this larb. diff --git a/Documentation/devicetree/bindings/memory-controllers/renesas-memory-controllers.txt b/Documentation/devicetree/bindings/memory-controllers/renesas,dbsc.txt similarity index 100% rename from Documentation/devicetree/bindings/memory-controllers/renesas-memory-controllers.txt rename to Documentation/devicetree/bindings/memory-controllers/renesas,dbsc.txt diff --git a/Documentation/devicetree/bindings/mfd/allwinner,sun4i-a10-ts.yaml b/Documentation/devicetree/bindings/mfd/allwinner,sun4i-a10-ts.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4b1a09acb98b7e59c61437221d95e2e2fff3c4d1 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/allwinner,sun4i-a10-ts.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/allwinner,sun4i-a10-ts.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A10 Resistive Touchscreen Controller Device Tree Bindings + +maintainers: + - Chen-Yu Tsai + - Maxime Ripard + +properties: + "#thermal-sensor-cells": + const: 0 + + compatible: + enum: + - allwinner,sun4i-a10-ts + - allwinner,sun5i-a13-ts + - allwinner,sun6i-a31-ts + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + allwinner,ts-attached: + $ref: /schemas/types.yaml#/definitions/flag + description: A touchscreen is attached to the controller + + allwinner,tp-sensitive-adjust: + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - minimum: 0 + maximum: 15 + default: 15 + description: Sensitivity of pen down detection + + allwinner,filter-type: + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - minimum: 0 + maximum: 3 + default: 1 + description: | + Select median and averaging filter. Sample used for median / + averaging filter: + 0: 4/2 + 1: 5/3 + 2: 8/4 + 3: 16/8 + +required: + - "#thermal-sensor-cells" + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + rtp: rtp@1c25000 { + compatible = "allwinner,sun4i-a10-ts"; + reg = <0x01c25000 0x100>; + interrupts = <29>; + allwinner,ts-attached; + #thermal-sensor-cells = <0>; + /* sensitive/noisy touch panel */ + allwinner,tp-sensitive-adjust = <0>; + allwinner,filter-type = <3>; + }; + +... diff --git a/Documentation/devicetree/bindings/mfd/sun4i-gpadc.txt b/Documentation/devicetree/bindings/mfd/sun4i-gpadc.txt deleted file mode 100644 index 86dd8191b04c5e5787a5961b9129a5824089657a..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/mfd/sun4i-gpadc.txt +++ /dev/null @@ -1,59 +0,0 @@ -Allwinner SoCs' GPADC Device Tree bindings ------------------------------------------- -The Allwinner SoCs all have an ADC that can also act as a thermal sensor -and sometimes as a touchscreen controller. - -Required properties: - - compatible: "allwinner,sun8i-a33-ths", - - reg: mmio address range of the chip, - - #thermal-sensor-cells: shall be 0, - - #io-channel-cells: shall be 0, - -Example: - ths: ths@1c25000 { - compatible = "allwinner,sun8i-a33-ths"; - reg = <0x01c25000 0x100>; - #thermal-sensor-cells = <0>; - #io-channel-cells = <0>; - }; - -sun4i, sun5i and sun6i SoCs are also supported via the older binding: - -sun4i resistive touchscreen controller --------------------------------------- - -Required properties: - - compatible: "allwinner,sun4i-a10-ts", "allwinner,sun5i-a13-ts" or - "allwinner,sun6i-a31-ts" - - reg: mmio address range of the chip - - interrupts: interrupt to which the chip is connected - - #thermal-sensor-cells: shall be 0 - -Optional properties: - - allwinner,ts-attached : boolean indicating that an actual touchscreen - is attached to the controller - - allwinner,tp-sensitive-adjust : integer (4 bits) - adjust sensitivity of pen down detection - between 0 (least sensitive) and 15 - (defaults to 15) - - allwinner,filter-type : integer (2 bits) - select median and averaging filter - samples used for median / averaging filter - 0: 4/2 - 1: 5/3 - 2: 8/4 - 3: 16/8 - (defaults to 1) - -Example: - - rtp: rtp@1c25000 { - compatible = "allwinner,sun4i-a10-ts"; - reg = <0x01c25000 0x100>; - interrupts = <29>; - allwinner,ts-attached; - #thermal-sensor-cells = <0>; - /* sensitive/noisy touch panel */ - allwinner,tp-sensitive-adjust = <0>; - allwinner,filter-type = <3>; - }; diff --git a/Documentation/devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml b/Documentation/devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml index df0280edef974b86d0d94e59c7127ba00a1065e1..d2d4308596b86899515dae8497639f21e50b3d93 100644 --- a/Documentation/devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml +++ b/Documentation/devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml @@ -30,16 +30,22 @@ properties: - const: allwinner,sun8i-a83t-mmc - const: allwinner,sun7i-a20-mmc - items: - - const: allwinner,sun50i-h6-emmc + - const: allwinner,sun8i-r40-emmc - const: allwinner,sun50i-a64-emmc - items: - - const: allwinner,sun50i-h6-mmc + - const: allwinner,sun8i-r40-mmc - const: allwinner,sun50i-a64-mmc - items: - - const: allwinner,sun8i-r40-emmc + - const: allwinner,sun50i-h5-emmc - const: allwinner,sun50i-a64-emmc - items: - - const: allwinner,sun8i-r40-mmc + - const: allwinner,sun50i-h5-mmc + - const: allwinner,sun50i-a64-mmc + - items: + - const: allwinner,sun50i-h6-emmc + - const: allwinner,sun50i-a64-emmc + - items: + - const: allwinner,sun50i-h6-mmc - const: allwinner,sun50i-a64-mmc reg: diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt index 1edbb049cccb10cead46f0c969ccd08de684b11f..7ca0aa7ccc0bfd73dd0303a2a8181bca2acb8d37 100644 --- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt @@ -17,6 +17,8 @@ Required Properties: For this device it is strongly suggested to include arasan,soc-ctl-syscon. - "ti,am654-sdhci-5.1", "arasan,sdhci-5.1": TI AM654 MMC PHY Note: This binding has been deprecated and moved to [5]. + - "intel,lgm-sdhci-5.1-emmc", "arasan,sdhci-5.1": Intel LGM eMMC PHY + For this device it is strongly suggested to include arasan,soc-ctl-syscon. [5] Documentation/devicetree/bindings/mmc/sdhci-am654.txt @@ -80,3 +82,18 @@ Example: phy-names = "phy_arasan"; #clock-cells = <0>; }; + + emmc: sdhci@ec700000 { + compatible = "intel,lgm-sdhci-5.1-emmc", "arasan,sdhci-5.1"; + reg = <0xec700000 0x300>; + interrupt-parent = <&ioapic1>; + interrupts = <44 1>; + clocks = <&cgu0 LGM_CLK_EMMC5>, <&cgu0 LGM_CLK_NGI>, + <&cgu0 LGM_GCLK_EMMC>; + clock-names = "clk_xin", "clk_ahb", "gate"; + clock-output-names = "emmc_cardclock"; + #clock-cells = <0>; + phys = <&emmc_phy>; + phy-names = "phy_arasan"; + arasan,soc-ctl-syscon = <&sysconf>; + }; diff --git a/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml b/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml new file mode 100644 index 0000000000000000000000000000000000000000..200de9396036b437ec8f07505bf743d756e44a2e --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright 2019 IBM Corp. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mmc/aspeed,sdhci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ASPEED SD/SDIO/MMC Controller + +maintainers: + - Andrew Jeffery + - Ryan Chen + +description: |+ + The ASPEED SD/SDIO/eMMC controller exposes two slots implementing the SDIO + Host Specification v2.00, with 1 or 4 bit data buses, or an 8 bit data bus if + only a single slot is enabled. + + The two slots are supported by a common configuration area. As the SDHCIs for + the slots are dependent on the common configuration area, they are described + as child nodes. + +properties: + compatible: + enum: + - aspeed,ast2400-sd-controller + - aspeed,ast2500-sd-controller + - aspeed,ast2600-sd-controller + reg: + maxItems: 1 + description: Common configuration registers + "#address-cells": + const: 1 + "#size-cells": + const: 1 + ranges: true + clocks: + maxItems: 1 + description: The SD/SDIO controller clock gate + +patternProperties: + "^sdhci@[0-9a-f]+$": + type: object + allOf: + - $ref: mmc-controller.yaml + properties: + compatible: + enum: + - aspeed,ast2400-sdhci + - aspeed,ast2500-sdhci + - aspeed,ast2600-sdhci + reg: + maxItems: 1 + description: The SDHCI registers + clocks: + maxItems: 1 + description: The SD bus clock + interrupts: + maxItems: 1 + description: The SD interrupt shared between both slots + sdhci,auto-cmd12: + type: boolean + description: Specifies that controller should use auto CMD12 + required: + - compatible + - reg + - clocks + - interrupts + +additionalProperties: false + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + - ranges + - clocks + +examples: + - | + #include + sdc@1e740000 { + compatible = "aspeed,ast2500-sd-controller"; + reg = <0x1e740000 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1e740000 0x20000>; + clocks = <&syscon ASPEED_CLK_GATE_SDCLK>; + + sdhci0: sdhci@100 { + compatible = "aspeed,ast2500-sdhci"; + reg = <0x100 0x100>; + interrupts = <26>; + sdhci,auto-cmd12; + clocks = <&syscon ASPEED_CLK_SDIO>; + }; + + sdhci1: sdhci@200 { + compatible = "aspeed,ast2500-sdhci"; + reg = <0x200 0x100>; + interrupts = <26>; + sdhci,auto-cmd12; + clocks = <&syscon ASPEED_CLK_SDIO>; + }; + }; diff --git a/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt b/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt index fa90d253dc7ea00f79de2b7cb99477a87f1682b7..09d87cc1182aa9ee2deaac406e05402871bdbcbb 100644 --- a/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt +++ b/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt @@ -6,10 +6,12 @@ by mmc.txt and the properties that represent the IPROC SDHCI controller. Required properties: - compatible : Should be one of the following "brcm,bcm2835-sdhci" + "brcm,bcm2711-emmc2" "brcm,sdhci-iproc-cygnus" "brcm,sdhci-iproc" -Use brcm2835-sdhci for Rasperry PI. +Use brcm2835-sdhci for the eMMC controller on the BCM2835 (Raspberry Pi) and +bcm2711-emmc2 for the additional eMMC2 controller on BCM2711. Use sdhci-iproc-cygnus for Broadcom SDHCI Controllers restricted to 32bit host accesses to SDHCI registers. diff --git a/Documentation/devicetree/bindings/net/adi,adin.yaml b/Documentation/devicetree/bindings/net/adi,adin.yaml new file mode 100644 index 0000000000000000000000000000000000000000..69375cb28e92074022bc3867a3244217c5aa45f7 --- /dev/null +++ b/Documentation/devicetree/bindings/net/adi,adin.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: GPL-2.0+ +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/adi,adin.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADIN1200/ADIN1300 PHY + +maintainers: + - Alexandru Ardelean + +description: | + Bindings for Analog Devices Industrial Ethernet PHYs + +allOf: + - $ref: ethernet-phy.yaml# + +properties: + adi,rx-internal-delay-ps: + description: | + RGMII RX Clock Delay used only when PHY operates in RGMII mode with + internal delay (phy-mode is 'rgmii-id' or 'rgmii-rxid') in pico-seconds. + enum: [ 1600, 1800, 2000, 2200, 2400 ] + default: 2000 + + adi,tx-internal-delay-ps: + description: | + RGMII TX Clock Delay used only when PHY operates in RGMII mode with + internal delay (phy-mode is 'rgmii-id' or 'rgmii-txid') in pico-seconds. + enum: [ 1600, 1800, 2000, 2200, 2400 ] + default: 2000 + + adi,fifo-depth-bits: + description: | + When operating in RMII mode, this option configures the FIFO depth. + enum: [ 4, 8, 12, 16, 20, 24 ] + default: 8 + + adi,disable-energy-detect: + description: | + Disables Energy Detect Powerdown Mode (default disabled, i.e energy detect + is enabled if this property is unspecified) + type: boolean + +examples: + - | + ethernet { + #address-cells = <1>; + #size-cells = <0>; + + phy-mode = "rgmii-id"; + + ethernet-phy@0 { + reg = <0>; + + adi,rx-internal-delay-ps = <1800>; + adi,tx-internal-delay-ps = <2200>; + }; + }; + - | + ethernet { + #address-cells = <1>; + #size-cells = <0>; + + phy-mode = "rmii"; + + ethernet-phy@1 { + reg = <1>; + + adi,fifo-depth-bits = <16>; + adi,disable-energy-detect; + }; + }; diff --git a/Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml b/Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml index 06b1cc8bea14f83f91671b35eefde1c21242d6c3..ef446ae166f34a4e637b962588c79dffed7ccfdc 100644 --- a/Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml +++ b/Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml @@ -17,6 +17,9 @@ properties: compatible: const: allwinner,sun7i-a20-gmac + reg: + maxItems: 1 + interrupts: maxItems: 1 diff --git a/Documentation/devicetree/bindings/net/amlogic,meson-dwmac.yaml b/Documentation/devicetree/bindings/net/amlogic,meson-dwmac.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ae91aa9d86164b0b2b1477ce9e2641601a4f8601 --- /dev/null +++ b/Documentation/devicetree/bindings/net/amlogic,meson-dwmac.yaml @@ -0,0 +1,113 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2019 BayLibre, SAS +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/net/amlogic,meson-dwmac.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Amlogic Meson DWMAC Ethernet controller + +maintainers: + - Neil Armstrong + - Martin Blumenstingl + +# We need a select here so we don't match all nodes with 'snps,dwmac' +select: + properties: + compatible: + contains: + enum: + - amlogic,meson6-dwmac + - amlogic,meson8b-dwmac + - amlogic,meson8m2-dwmac + - amlogic,meson-gxbb-dwmac + - amlogic,meson-axg-dwmac + required: + - compatible + +allOf: + - $ref: "snps,dwmac.yaml#" + - if: + properties: + compatible: + contains: + enum: + - amlogic,meson8b-dwmac + - amlogic,meson8m2-dwmac + - amlogic,meson-gxbb-dwmac + - amlogic,meson-axg-dwmac + + then: + properties: + clocks: + items: + - description: GMAC main clock + - description: First parent clock of the internal mux + - description: Second parent clock of the internal mux + + clock-names: + minItems: 3 + maxItems: 3 + items: + - const: stmmaceth + - const: clkin0 + - const: clkin1 + + amlogic,tx-delay-ns: + $ref: /schemas/types.yaml#definitions/uint32 + description: + The internal RGMII TX clock delay (provided by this driver) in + nanoseconds. Allowed values are 0ns, 2ns, 4ns, 6ns. + When phy-mode is set to "rgmii" then the TX delay should be + explicitly configured. When not configured a fallback of 2ns is + used. When the phy-mode is set to either "rgmii-id" or "rgmii-txid" + the TX clock delay is already provided by the PHY. In that case + this property should be set to 0ns (which disables the TX clock + delay in the MAC to prevent the clock from going off because both + PHY and MAC are adding a delay). + Any configuration is ignored when the phy-mode is set to "rmii". + +properties: + compatible: + additionalItems: true + maxItems: 3 + items: + - enum: + - amlogic,meson6-dwmac + - amlogic,meson8b-dwmac + - amlogic,meson8m2-dwmac + - amlogic,meson-gxbb-dwmac + - amlogic,meson-axg-dwmac + contains: + enum: + - snps,dwmac-3.70a + - snps,dwmac + + reg: + items: + - description: + The first register range should be the one of the DWMAC controller + - description: + The second range is is for the Amlogic specific configuration + (for example the PRG_ETHERNET register range on Meson8b and newer) + +required: + - compatible + - reg + - interrupts + - interrupt-names + - clocks + - clock-names + - phy-mode + +examples: + - | + ethmac: ethernet@c9410000 { + compatible = "amlogic,meson-gxbb-dwmac", "snps,dwmac"; + reg = <0xc9410000 0x10000>, <0xc8834540 0x8>; + interrupts = <8>; + interrupt-names = "macirq"; + clocks = <&clk_eth>, <&clkc_fclk_div2>, <&clk_mpll2>; + clock-names = "stmmaceth", "clkin0", "clkin1"; + phy-mode = "rgmii"; + }; diff --git a/Documentation/devicetree/bindings/net/aspeed,ast2600-mdio.yaml b/Documentation/devicetree/bindings/net/aspeed,ast2600-mdio.yaml new file mode 100644 index 0000000000000000000000000000000000000000..71808e78a495ee7056f23f24b33699fe93e0a1f9 --- /dev/null +++ b/Documentation/devicetree/bindings/net/aspeed,ast2600-mdio.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/aspeed,ast2600-mdio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ASPEED AST2600 MDIO Controller + +maintainers: + - Andrew Jeffery + +description: |+ + The ASPEED AST2600 MDIO controller is the third iteration of ASPEED's MDIO + bus register interface, this time also separating out the controller from the + MAC. + +allOf: + - $ref: "mdio.yaml#" + +properties: + compatible: + const: aspeed,ast2600-mdio + reg: + maxItems: 1 + description: The register range of the MDIO controller instance + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + +examples: + - | + mdio0: mdio@1e650000 { + compatible = "aspeed,ast2600-mdio"; + reg = <0x1e650000 0x8>; + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/net/broadcom-bluetooth.txt b/Documentation/devicetree/bindings/net/broadcom-bluetooth.txt index c26f4e11037cb4507f8f01cfa5205738e079a992..4fa00e2eafcfb5b4c60997c703c04fdbff6c8225 100644 --- a/Documentation/devicetree/bindings/net/broadcom-bluetooth.txt +++ b/Documentation/devicetree/bindings/net/broadcom-bluetooth.txt @@ -13,6 +13,7 @@ Required properties: * "brcm,bcm20702a1" * "brcm,bcm4330-bt" * "brcm,bcm43438-bt" + * "brcm,bcm4345c5" Optional properties: diff --git a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt index bc77477c6878ac6af373f51b92cfb8a31371d826..94c0f8bf4deb3007363f59043456d868a24eba71 100644 --- a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt +++ b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt @@ -32,6 +32,15 @@ Optional properties: ack_gpr is the gpr register offset of CAN stop acknowledge. ack_bit is the bit offset of CAN stop acknowledge. +- fsl,clk-source: Select the clock source to the CAN Protocol Engine (PE). + It's SoC Implementation dependent. Refer to RM for detailed + definition. If this property is not set in device tree node + then driver selects clock source 1 by default. + 0: clock source 0 (oscillator clock) + 1: clock source 1 (peripheral clock) + +- wakeup-source: enable CAN remote wakeup + Example: can@1c000 { @@ -40,4 +49,5 @@ Example: interrupts = <48 0x2>; interrupt-parent = <&mpic>; clock-frequency = <200000000>; // filled in by bootloader + fsl,clk-source = <0>; // select clock source 0 for PE }; diff --git a/Documentation/devicetree/bindings/net/can/rcar_can.txt b/Documentation/devicetree/bindings/net/can/rcar_can.txt index b463e1268ac4f253a4f3704af511c7c490319747..19e4a7d9151137fa947c6b1c3ace2b9c11dbf847 100644 --- a/Documentation/devicetree/bindings/net/can/rcar_can.txt +++ b/Documentation/devicetree/bindings/net/can/rcar_can.txt @@ -5,6 +5,7 @@ Required properties: - compatible: "renesas,can-r8a7743" if CAN controller is a part of R8A7743 SoC. "renesas,can-r8a7744" if CAN controller is a part of R8A7744 SoC. "renesas,can-r8a7745" if CAN controller is a part of R8A7745 SoC. + "renesas,can-r8a77470" if CAN controller is a part of R8A77470 SoC. "renesas,can-r8a774a1" if CAN controller is a part of R8A774A1 SoC. "renesas,can-r8a774c0" if CAN controller is a part of R8A774C0 SoC. "renesas,can-r8a7778" if CAN controller is a part of R8A7778 SoC. @@ -17,6 +18,8 @@ Required properties: "renesas,can-r8a7795" if CAN controller is a part of R8A7795 SoC. "renesas,can-r8a7796" if CAN controller is a part of R8A7796 SoC. "renesas,can-r8a77965" if CAN controller is a part of R8A77965 SoC. + "renesas,can-r8a77990" if CAN controller is a part of R8A77990 SoC. + "renesas,can-r8a77995" if CAN controller is a part of R8A77995 SoC. "renesas,rcar-gen1-can" for a generic R-Car Gen1 compatible device. "renesas,rcar-gen2-can" for a generic R-Car Gen2 or RZ/G1 compatible device. @@ -33,7 +36,8 @@ Required properties: - pinctrl-0: pin control group to be used for this controller. - pinctrl-names: must be "default". -Required properties for R8A7795, R8A7796 and R8A77965: +Required properties for R8A774A1, R8A774C0, R8A7795, R8A7796, R8A77965, +R8A77990, and R8A77995: For the denoted SoCs, "clkp2" can be CANFD clock. This is a div6 clock and can be used by both CAN and CAN FD controller at the same time. It needs to be scaled to maximum frequency if any of these controllers use it. This is done diff --git a/Documentation/devicetree/bindings/net/can/rcar_canfd.txt b/Documentation/devicetree/bindings/net/can/rcar_canfd.txt index 32f051f6d338ee74d7af3361f7a9cee3313fac94..a901cd9be29e9025ac43f609c8b2026607c87ad6 100644 --- a/Documentation/devicetree/bindings/net/can/rcar_canfd.txt +++ b/Documentation/devicetree/bindings/net/can/rcar_canfd.txt @@ -4,6 +4,7 @@ Renesas R-Car CAN FD controller Device Tree Bindings Required properties: - compatible: Must contain one or more of the following: - "renesas,rcar-gen3-canfd" for R-Car Gen3 and RZ/G2 compatible controllers. + - "renesas,r8a774a1-canfd" for R8A774A1 (RZ/G2M) compatible controller. - "renesas,r8a774c0-canfd" for R8A774C0 (RZ/G2E) compatible controller. - "renesas,r8a7795-canfd" for R8A7795 (R-Car H3) compatible controller. - "renesas,r8a7796-canfd" for R8A7796 (R-Car M3-W) compatible controller. @@ -11,6 +12,7 @@ Required properties: - "renesas,r8a77970-canfd" for R8A77970 (R-Car V3M) compatible controller. - "renesas,r8a77980-canfd" for R8A77980 (R-Car V3H) compatible controller. - "renesas,r8a77990-canfd" for R8A77990 (R-Car E3) compatible controller. + - "renesas,r8a77995-canfd" for R8A77995 (R-Car D3) compatible controller. When compatible with the generic version, nodes must list the SoC-specific version corresponding to the platform first, followed by the @@ -29,13 +31,12 @@ The name of the child nodes are "channel0" and "channel1" respectively. Each child node supports the "status" property only, which is used to enable/disable the respective channel. -Required properties for "renesas,r8a774c0-canfd", "renesas,r8a7795-canfd", -"renesas,r8a7796-canfd", "renesas,r8a77965-canfd", and "renesas,r8a77990-canfd" -compatible: -In R8A774C0, R8A7795, R8A7796, R8A77965, and R8A77990 SoCs, canfd clock is a -div6 clock and can be used by both CAN and CAN FD controller at the same time. -It needs to be scaled to maximum frequency if any of these controllers use it. -This is done using the below properties: +Required properties for R8A774A1, R8A774C0, R8A7795, R8A7796, R8A77965, +R8A77990, and R8A77995: +In the denoted SoCs, canfd clock is a div6 clock and can be used by both CAN +and CAN FD controller at the same time. It needs to be scaled to maximum +frequency if any of these controllers use it. This is done using the below +properties: - assigned-clocks: phandle of canfd clock. - assigned-clock-rates: maximum frequency of this clock. diff --git a/Documentation/devicetree/bindings/net/can/tcan4x5x.txt b/Documentation/devicetree/bindings/net/can/tcan4x5x.txt new file mode 100644 index 0000000000000000000000000000000000000000..27e1b4cebfbd42ad0923bf6bd90521a50a7a925b --- /dev/null +++ b/Documentation/devicetree/bindings/net/can/tcan4x5x.txt @@ -0,0 +1,40 @@ +Texas Instruments TCAN4x5x CAN Controller +================================================ + +This file provides device node information for the TCAN4x5x interface contains. + +Required properties: + - compatible: "ti,tcan4x5x" + - reg: 0 + - #address-cells: 1 + - #size-cells: 0 + - spi-max-frequency: Maximum frequency of the SPI bus the chip can + operate at should be less than or equal to 18 MHz. + - device-wake-gpios: Wake up GPIO to wake up the TCAN device. + - interrupt-parent: the phandle to the interrupt controller which provides + the interrupt. + - interrupts: interrupt specification for data-ready. + +See Documentation/devicetree/bindings/net/can/m_can.txt for additional +required property details. + +Optional properties: + - reset-gpios: Hardwired output GPIO. If not defined then software + reset. + - device-state-gpios: Input GPIO that indicates if the device is in + a sleep state or if the device is active. + +Example: +tcan4x5x: tcan4x5x@0 { + compatible = "ti,tcan4x5x"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <10000000>; + bosch,mram-cfg = <0x0 0 0 32 0 0 1 1>; + interrupt-parent = <&gpio1>; + interrupts = <14 GPIO_ACTIVE_LOW>; + device-state-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + device-wake-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio1 27 GPIO_ACTIVE_LOW>; +}; diff --git a/Documentation/devicetree/bindings/net/dsa/ksz.txt b/Documentation/devicetree/bindings/net/dsa/ksz.txt index 113e7ac79aad59259e035ea2179a51e4c62fbba4..95e91e84151c33920c8f0ac0bd86404abca767ca 100644 --- a/Documentation/devicetree/bindings/net/dsa/ksz.txt +++ b/Documentation/devicetree/bindings/net/dsa/ksz.txt @@ -5,6 +5,9 @@ Required properties: - compatible: For external switch chips, compatible string must be exactly one of the following: + - "microchip,ksz8765" + - "microchip,ksz8794" + - "microchip,ksz8795" - "microchip,ksz9477" - "microchip,ksz9897" - "microchip,ksz9896" diff --git a/Documentation/devicetree/bindings/net/dsa/marvell.txt b/Documentation/devicetree/bindings/net/dsa/marvell.txt index 6f9538974bb9dba1d17c47a8207ac870cb72bc7e..30c11fea491bda4855036f8b124f0c265d16682f 100644 --- a/Documentation/devicetree/bindings/net/dsa/marvell.txt +++ b/Documentation/devicetree/bindings/net/dsa/marvell.txt @@ -22,7 +22,7 @@ which is at a different MDIO base address in different switch families. - "marvell,mv88e6190" : Switch has base address 0x00. Use with models: 6190, 6190X, 6191, 6290, 6390, 6390X - "marvell,mv88e6250" : Switch has base address 0x08 or 0x18. Use with model: - 6250 + 6220, 6250 Required properties: - compatible : Should be one of "marvell,mv88e6085", diff --git a/Documentation/devicetree/bindings/net/dsa/mt7530.txt b/Documentation/devicetree/bindings/net/dsa/mt7530.txt index 47aa205ee0bd3ec7ba94821fd72acda15a51e7a3..c5ed5d25f6420e5291baeed53e512ab18b462b66 100644 --- a/Documentation/devicetree/bindings/net/dsa/mt7530.txt +++ b/Documentation/devicetree/bindings/net/dsa/mt7530.txt @@ -35,6 +35,42 @@ Required properties for the child nodes within ports container: - phy-mode: String, must be either "trgmii" or "rgmii" for port labeled "cpu". +Port 5 of the switch is muxed between: +1. GMAC5: GMAC5 can interface with another external MAC or PHY. +2. PHY of port 0 or port 4: PHY interfaces with an external MAC like 2nd GMAC + of the SOC. Used in many setups where port 0/4 becomes the WAN port. + Note: On a MT7621 SOC with integrated switch: 2nd GMAC can only connected to + GMAC5 when the gpios for RGMII2 (GPIO 22-33) are not used and not + connected to external component! + +Port 5 modes/configurations: +1. Port 5 is disabled and isolated: An external phy can interface to the 2nd + GMAC of the SOC. + In the case of a build-in MT7530 switch, port 5 shares the RGMII bus with 2nd + GMAC and an optional external phy. Mind the GPIO/pinctl settings of the SOC! +2. Port 5 is muxed to PHY of port 0/4: Port 0/4 interfaces with 2nd GMAC. + It is a simple MAC to PHY interface, port 5 needs to be setup for xMII mode + and RGMII delay. +3. Port 5 is muxed to GMAC5 and can interface to an external phy. + Port 5 becomes an extra switch port. + Only works on platform where external phy TX<->RX lines are swapped. + Like in the Ubiquiti ER-X-SFP. +4. Port 5 is muxed to GMAC5 and interfaces with the 2nd GAMC as 2nd CPU port. + Currently a 2nd CPU port is not supported by DSA code. + +Depending on how the external PHY is wired: +1. normal: The PHY can only connect to 2nd GMAC but not to the switch +2. swapped: RGMII TX, RX are swapped; external phy interface with the switch as + a ethernet port. But can't interface to the 2nd GMAC. + +Based on the DT the port 5 mode is configured. + +Driver tries to lookup the phy-handle of the 2nd GMAC of the master device. +When phy-handle matches PHY of port 0 or 4 then port 5 set-up as mode 2. +phy-mode must be set, see also example 2 below! + * mt7621: phy-mode = "rgmii-txid"; + * mt7623: phy-mode = "rgmii"; + See Documentation/devicetree/bindings/net/dsa/dsa.txt for a list of additional required, optional properties and how the integrated switch subnodes must be specified. @@ -94,3 +130,181 @@ Example: }; }; }; + +Example 2: MT7621: Port 4 is WAN port: 2nd GMAC -> Port 5 -> PHY port 4. + +ð { + gmac0: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-mode = "rgmii"; + + fixed-link { + speed = <1000>; + full-duplex; + pause; + }; + }; + + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + phy-mode = "rgmii-txid"; + phy-handle = <&phy4>; + }; + + mdio: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + + /* Internal phy */ + phy4: ethernet-phy@4 { + reg = <4>; + }; + + mt7530: switch@1f { + compatible = "mediatek,mt7621"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x1f>; + pinctrl-names = "default"; + mediatek,mcm; + + resets = <&rstctrl 2>; + reset-names = "mcm"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + label = "lan0"; + }; + + port@1 { + reg = <1>; + label = "lan1"; + }; + + port@2 { + reg = <2>; + label = "lan2"; + }; + + port@3 { + reg = <3>; + label = "lan3"; + }; + +/* Commented out. Port 4 is handled by 2nd GMAC. + port@4 { + reg = <4>; + label = "lan4"; + }; +*/ + + cpu_port0: port@6 { + reg = <6>; + label = "cpu"; + ethernet = <&gmac0>; + phy-mode = "rgmii"; + + fixed-link { + speed = <1000>; + full-duplex; + pause; + }; + }; + }; + }; + }; +}; + +Example 3: MT7621: Port 5 is connected to external PHY: Port 5 -> external PHY. + +ð { + gmac0: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-mode = "rgmii"; + + fixed-link { + speed = <1000>; + full-duplex; + pause; + }; + }; + + mdio: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + + /* External phy */ + ephy5: ethernet-phy@7 { + reg = <7>; + }; + + mt7530: switch@1f { + compatible = "mediatek,mt7621"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x1f>; + pinctrl-names = "default"; + mediatek,mcm; + + resets = <&rstctrl 2>; + reset-names = "mcm"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + label = "lan0"; + }; + + port@1 { + reg = <1>; + label = "lan1"; + }; + + port@2 { + reg = <2>; + label = "lan2"; + }; + + port@3 { + reg = <3>; + label = "lan3"; + }; + + port@4 { + reg = <4>; + label = "lan4"; + }; + + port@5 { + reg = <5>; + label = "lan5"; + phy-mode = "rgmii"; + phy-handle = <&ephy5>; + }; + + cpu_port0: port@6 { + reg = <6>; + label = "cpu"; + ethernet = <&gmac0>; + phy-mode = "rgmii"; + + fixed-link { + speed = <1000>; + full-duplex; + pause; + }; + }; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/net/fsl-enetc.txt b/Documentation/devicetree/bindings/net/fsl-enetc.txt index 25fc687419dbc0d4cda98a2ceb0a9934abbf93ad..b7034ccbc1bdf2003f3c48187aa2fe15f8c4a270 100644 --- a/Documentation/devicetree/bindings/net/fsl-enetc.txt +++ b/Documentation/devicetree/bindings/net/fsl-enetc.txt @@ -11,7 +11,9 @@ Required properties: to parent node bindings. - compatible : Should be "fsl,enetc". -1) The ENETC external port is connected to a MDIO configurable phy: +1. The ENETC external port is connected to a MDIO configurable phy + +1.1. Using the local ENETC Port MDIO interface In this case, the ENETC node should include a "mdio" sub-node that in turn should contain the "ethernet-phy" node describing the @@ -47,8 +49,42 @@ Example: }; }; -2) The ENETC port is an internal port or has a fixed-link external -connection: +1.2. Using the central MDIO PCIe endpoint device + +In this case, the mdio node should be defined as another PCIe +endpoint node, at the same level with the ENETC port nodes. + +Required properties: + +- reg : Specifies PCIe Device Number and Function + Number of the ENETC endpoint device, according + to parent node bindings. +- compatible : Should be "fsl,enetc-mdio". + +The remaining required mdio bus properties are standard, their bindings +already defined in Documentation/devicetree/bindings/net/mdio.txt. + +Example: + + ethernet@0,0 { + compatible = "fsl,enetc"; + reg = <0x000000 0 0 0 0>; + phy-handle = <&sgmii_phy0>; + phy-connection-type = "sgmii"; + }; + + mdio@0,3 { + compatible = "fsl,enetc-mdio"; + reg = <0x000300 0 0 0 0>; + #address-cells = <1>; + #size-cells = <0>; + sgmii_phy0: ethernet-phy@2 { + reg = <0x2>; + }; + }; + +2. The ENETC port is an internal port or has a fixed-link external +connection In this case, the ENETC port node defines a fixed link connection, as specified by Documentation/devicetree/bindings/net/fixed-link.txt. diff --git a/Documentation/devicetree/bindings/net/mediatek-net.txt b/Documentation/devicetree/bindings/net/mediatek-net.txt index 770ff98d4524e3c7c171de30f6672c0abb02b5ee..72d03e07cf7c663b339c514c39620d3bd6788c80 100644 --- a/Documentation/devicetree/bindings/net/mediatek-net.txt +++ b/Documentation/devicetree/bindings/net/mediatek-net.txt @@ -12,6 +12,7 @@ Required properties: "mediatek,mt7623-eth", "mediatek,mt2701-eth": for MT7623 SoC "mediatek,mt7622-eth": for MT7622 SoC "mediatek,mt7629-eth": for MT7629 SoC + "ralink,rt5350-eth": for Ralink Rt5350F and MT7628/88 SoC - reg: Address and length of the register set for the device - interrupts: Should contain the three frame engines interrupts in numeric order. These are fe_int0, fe_int1 and fe_int2. diff --git a/Documentation/devicetree/bindings/net/meson-dwmac.txt b/Documentation/devicetree/bindings/net/meson-dwmac.txt deleted file mode 100644 index 1321bb194ed99e455b9a1105fbf8dade63767b45..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/net/meson-dwmac.txt +++ /dev/null @@ -1,71 +0,0 @@ -* Amlogic Meson DWMAC Ethernet controller - -The device inherits all the properties of the dwmac/stmmac devices -described in the file stmmac.txt in the current directory with the -following changes. - -Required properties on all platforms: - -- compatible: Depending on the platform this should be one of: - - "amlogic,meson6-dwmac" - - "amlogic,meson8b-dwmac" - - "amlogic,meson8m2-dwmac" - - "amlogic,meson-gxbb-dwmac" - - "amlogic,meson-axg-dwmac" - Additionally "snps,dwmac" and any applicable more - detailed version number described in net/stmmac.txt - should be used. - -- reg: The first register range should be the one of the DWMAC - controller. The second range is is for the Amlogic specific - configuration (for example the PRG_ETHERNET register range - on Meson8b and newer) - -Required properties on Meson8b, Meson8m2, GXBB and newer: -- clock-names: Should contain the following: - - "stmmaceth" - see stmmac.txt - - "clkin0" - first parent clock of the internal mux - - "clkin1" - second parent clock of the internal mux - -Optional properties on Meson8b, Meson8m2, GXBB and newer: -- amlogic,tx-delay-ns: The internal RGMII TX clock delay (provided - by this driver) in nanoseconds. Allowed values - are: 0ns, 2ns, 4ns, 6ns. - When phy-mode is set to "rgmii" then the TX - delay should be explicitly configured. When - not configured a fallback of 2ns is used. - When the phy-mode is set to either "rgmii-id" - or "rgmii-txid" the TX clock delay is already - provided by the PHY. In that case this - property should be set to 0ns (which disables - the TX clock delay in the MAC to prevent the - clock from going off because both PHY and MAC - are adding a delay). - Any configuration is ignored when the phy-mode - is set to "rmii". - -Example for Meson6: - - ethmac: ethernet@c9410000 { - compatible = "amlogic,meson6-dwmac", "snps,dwmac"; - reg = <0xc9410000 0x10000 - 0xc1108108 0x4>; - interrupts = <0 8 1>; - interrupt-names = "macirq"; - clocks = <&clk81>; - clock-names = "stmmaceth"; - } - -Example for GXBB: - ethmac: ethernet@c9410000 { - compatible = "amlogic,meson-gxbb-dwmac", "snps,dwmac"; - reg = <0x0 0xc9410000 0x0 0x10000>, - <0x0 0xc8834540 0x0 0x8>; - interrupts = <0 8 1>; - interrupt-names = "macirq"; - clocks = <&clkc CLKID_ETH>, - <&clkc CLKID_FCLK_DIV2>, - <&clkc CLKID_MPLL2>; - clock-names = "stmmaceth", "clkin0", "clkin1"; - phy-mode = "rgmii"; - }; diff --git a/Documentation/devicetree/bindings/net/mscc-ocelot.txt b/Documentation/devicetree/bindings/net/mscc-ocelot.txt index 9e5c17d426ceca2361fd5b28b8bdfa105ab6202e..3b6290b45ce51a29b0722bef6eea771baa93ff40 100644 --- a/Documentation/devicetree/bindings/net/mscc-ocelot.txt +++ b/Documentation/devicetree/bindings/net/mscc-ocelot.txt @@ -12,13 +12,15 @@ Required properties: - "sys" - "rew" - "qs" + - "ptp" (optional due to backward compatibility) - "qsys" - "ana" - "portX" with X from 0 to the number of last port index available on that switch -- interrupts: Should contain the switch interrupts for frame extraction and - frame injection -- interrupt-names: should contain the interrupt names: "xtr", "inj" +- interrupts: Should contain the switch interrupts for frame extraction, + frame injection and PTP ready. +- interrupt-names: should contain the interrupt names: "xtr", "inj". Can contain + "ptp_rdy" which is optional due to backward compatibility. - ethernet-ports: A container for child nodes representing switch ports. The ethernet-ports container has the following properties @@ -44,6 +46,7 @@ Example: reg = <0x1010000 0x10000>, <0x1030000 0x10000>, <0x1080000 0x100>, + <0x10e0000 0x10000>, <0x11e0000 0x100>, <0x11f0000 0x100>, <0x1200000 0x100>, @@ -57,11 +60,12 @@ Example: <0x1280000 0x100>, <0x1800000 0x80000>, <0x1880000 0x10000>; - reg-names = "sys", "rew", "qs", "port0", "port1", "port2", - "port3", "port4", "port5", "port6", "port7", - "port8", "port9", "port10", "qsys", "ana"; - interrupts = <21 22>; - interrupt-names = "xtr", "inj"; + reg-names = "sys", "rew", "qs", "ptp", "port0", "port1", + "port2", "port3", "port4", "port5", "port6", + "port7", "port8", "port9", "port10", "qsys", + "ana"; + interrupts = <18 21 22>; + interrupt-names = "ptp_rdy", "xtr", "inj"; ethernet-ports { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml index 76fea2be66ac556deed2bdca695bca76f1309806..ebe4537a7cce43589c10e8c08cbde29b4295dcc1 100644 --- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml +++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml @@ -50,6 +50,11 @@ properties: - allwinner,sun8i-r40-emac - allwinner,sun8i-v3s-emac - allwinner,sun50i-a64-emac + - amlogic,meson6-dwmac + - amlogic,meson8b-dwmac + - amlogic,meson8m2-dwmac + - amlogic,meson-gxbb-dwmac + - amlogic,meson-axg-dwmac - snps,dwmac - snps,dwmac-3.50a - snps,dwmac-3.610 @@ -61,7 +66,8 @@ properties: - snps,dwxgmac-2.10 reg: - maxItems: 1 + minItems: 1 + maxItems: 2 interrupts: minItems: 1 @@ -106,6 +112,14 @@ properties: reset-names: const: stmmaceth + mac-mode: + maxItems: 1 + description: + The property is identical to 'phy-mode', and assumes that there is mode + converter in-between the MAC & PHY (e.g. GMII-to-RGMII). This converter + can be passive (no SW requirement), and requires that the MAC operate + in a different mode than the PHY in order to function. + snps,axi-config: $ref: /schemas/types.yaml#definitions/phandle description: diff --git a/Documentation/devicetree/bindings/net/ti,dp83867.txt b/Documentation/devicetree/bindings/net/ti,dp83867.txt index db6aa3f2215be1ca6ca09966bdb399236fe2b269..388ff48f53aee64992ebe05764d8c2ca03cd345e 100644 --- a/Documentation/devicetree/bindings/net/ti,dp83867.txt +++ b/Documentation/devicetree/bindings/net/ti,dp83867.txt @@ -37,6 +37,10 @@ Optional property: for applicable values. The CLK_OUT pin can also be disabled by this property. When omitted, the PHY's default will be left as is. + - ti,sgmii-ref-clock-output-enable - This denotes which + SGMII configuration is used (4 or 6-wire modes). + Some MACs work with differential SGMII clock. + See data manual for details. Note: ti,min-output-impedance and ti,max-output-impedance are mutually exclusive. When both properties are present ti,max-output-impedance diff --git a/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt b/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt index 96ffd06d2ca8707b2d3a0b831b600c977633daca..904dadf3d07bb173d716f9d96141474b00af1573 100644 --- a/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt +++ b/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt @@ -2,7 +2,7 @@ Freescale i.MX6 On-Chip OTP Controller (OCOTP) device tree bindings This binding represents the on-chip eFuse OTP controller found on i.MX6Q/D, i.MX6DL/S, i.MX6SL, i.MX6SX, i.MX6UL, i.MX6ULL/ULZ, i.MX6SLL, -i.MX7D/S, i.MX7ULP and i.MX8MQ SoCs. +i.MX7D/S, i.MX7ULP, i.MX8MQ, i.MX8MM and i.MX8MN SoCs. Required properties: - compatible: should be one of @@ -16,6 +16,7 @@ Required properties: "fsl,imx7ulp-ocotp" (i.MX7ULP), "fsl,imx8mq-ocotp" (i.MX8MQ), "fsl,imx8mm-ocotp" (i.MX8MM), + "fsl,imx8mn-ocotp" (i.MX8MN), followed by "syscon". - #address-cells : Should be 1 - #size-cells : Should be 1 diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt index 76b6c79604a5b6e68814a26bcd88e1b48926d3be..68592271461f641d7c98bae0a45d01732d9263fd 100644 --- a/Documentation/devicetree/bindings/opp/opp.txt +++ b/Documentation/devicetree/bindings/opp/opp.txt @@ -140,8 +140,8 @@ Optional properties: frequency for a short duration of time limited by the device's power, current and thermal limits. -- opp-suspend: Marks the OPP to be used during device suspend. Only one OPP in - the table should have this. +- opp-suspend: Marks the OPP to be used during device suspend. If multiple OPPs + in the table have this, the OPP with highest opp-hz will be used. - opp-supported-hw: This enables us to select only a subset of OPPs from the larger OPP table, based on what version of the hardware we are running on. We diff --git a/Documentation/devicetree/bindings/opp/kryo-cpufreq.txt b/Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt similarity index 87% rename from Documentation/devicetree/bindings/opp/kryo-cpufreq.txt rename to Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt index c2127b96805a3e7b3c723fbb432bbcebaacbd545..4751029b9b7433a7371c007a21c54fe21345a287 100644 --- a/Documentation/devicetree/bindings/opp/kryo-cpufreq.txt +++ b/Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt @@ -1,25 +1,38 @@ -Qualcomm Technologies, Inc. KRYO CPUFreq and OPP bindings +Qualcomm Technologies, Inc. NVMEM CPUFreq and OPP bindings =================================== -In Certain Qualcomm Technologies, Inc. SoCs like apq8096 and msm8996 -that have KRYO processors, the CPU ferequencies subset and voltage value -of each OPP varies based on the silicon variant in use. +In Certain Qualcomm Technologies, Inc. SoCs like apq8096 and msm8996, +the CPU frequencies subset and voltage value of each OPP varies based on +the silicon variant in use. Qualcomm Technologies, Inc. Process Voltage Scaling Tables defines the voltage and frequency value based on the msm-id in SMEM and speedbin blown in the efuse combination. -The qcom-cpufreq-kryo driver reads the msm-id and efuse value from the SoC +The qcom-cpufreq-nvmem driver reads the msm-id and efuse value from the SoC to provide the OPP framework with required information (existing HW bitmap). This is used to determine the voltage and frequency value for each OPP of operating-points-v2 table when it is parsed by the OPP framework. Required properties: -------------------- -In 'cpus' nodes: +In 'cpu' nodes: - operating-points-v2: Phandle to the operating-points-v2 table to use. In 'operating-points-v2' table: - compatible: Should be - 'operating-points-v2-kryo-cpu' for apq8096 and msm8996. + +Optional properties: +-------------------- +In 'cpu' nodes: +- power-domains: A phandle pointing to the PM domain specifier which provides + the performance states available for active state management. + Please refer to the power-domains bindings + Documentation/devicetree/bindings/power/power_domain.txt + and also examples below. +- power-domain-names: Should be + - 'cpr' for qcs404. + +In 'operating-points-v2' table: - nvmem-cells: A phandle pointing to a nvmem-cells node representing the efuse registers that has information about the speedbin that is used to select the right frequency/voltage @@ -678,3 +691,105 @@ soc { }; }; }; + +Example 2: +--------- + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + CPU0: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x100>; + .... + clocks = <&apcs_glb>; + operating-points-v2 = <&cpu_opp_table>; + power-domains = <&cpr>; + power-domain-names = "cpr"; + }; + + CPU1: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x101>; + .... + clocks = <&apcs_glb>; + operating-points-v2 = <&cpu_opp_table>; + power-domains = <&cpr>; + power-domain-names = "cpr"; + }; + + CPU2: cpu@102 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x102>; + .... + clocks = <&apcs_glb>; + operating-points-v2 = <&cpu_opp_table>; + power-domains = <&cpr>; + power-domain-names = "cpr"; + }; + + CPU3: cpu@103 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x103>; + .... + clocks = <&apcs_glb>; + operating-points-v2 = <&cpu_opp_table>; + power-domains = <&cpr>; + power-domain-names = "cpr"; + }; + }; + + cpu_opp_table: cpu-opp-table { + compatible = "operating-points-v2-kryo-cpu"; + opp-shared; + + opp-1094400000 { + opp-hz = /bits/ 64 <1094400000>; + required-opps = <&cpr_opp1>; + }; + opp-1248000000 { + opp-hz = /bits/ 64 <1248000000>; + required-opps = <&cpr_opp2>; + }; + opp-1401600000 { + opp-hz = /bits/ 64 <1401600000>; + required-opps = <&cpr_opp3>; + }; + }; + + cpr_opp_table: cpr-opp-table { + compatible = "operating-points-v2-qcom-level"; + + cpr_opp1: opp1 { + opp-level = <1>; + qcom,opp-fuse-level = <1>; + }; + cpr_opp2: opp2 { + opp-level = <2>; + qcom,opp-fuse-level = <2>; + }; + cpr_opp3: opp3 { + opp-level = <3>; + qcom,opp-fuse-level = <3>; + }; + }; + +.... + +soc { +.... + cpr: power-controller@b018000 { + compatible = "qcom,qcs404-cpr", "qcom,cpr"; + reg = <0x0b018000 0x1000>; + .... + vdd-apc-supply = <&pms405_s3>; + #power-domain-cells = <0>; + operating-points-v2 = <&cpr_opp_table>; + .... + }; +}; diff --git a/Documentation/devicetree/bindings/opp/qcom-opp.txt b/Documentation/devicetree/bindings/opp/qcom-opp.txt new file mode 100644 index 0000000000000000000000000000000000000000..32eb0793c7e6e495c6aa79b1273445a6d4372c43 --- /dev/null +++ b/Documentation/devicetree/bindings/opp/qcom-opp.txt @@ -0,0 +1,19 @@ +Qualcomm OPP bindings to describe OPP nodes + +The bindings are based on top of the operating-points-v2 bindings +described in Documentation/devicetree/bindings/opp/opp.txt +Additional properties are described below. + +* OPP Table Node + +Required properties: +- compatible: Allow OPPs to express their compatibility. It should be: + "operating-points-v2-qcom-level" + +* OPP Node + +Required properties: +- qcom,opp-fuse-level: A positive value representing the fuse corner/level + associated with this OPP node. Sometimes several corners/levels shares + a certain fuse corner/level. A fuse corner/level contains e.g. ref uV, + min uV, and max uV. diff --git a/Documentation/devicetree/bindings/opp/sun50i-nvmem-cpufreq.txt b/Documentation/devicetree/bindings/opp/sun50i-nvmem-cpufreq.txt new file mode 100644 index 0000000000000000000000000000000000000000..7deae57a587b5ecdd02c5e40d3ece7d67f953273 --- /dev/null +++ b/Documentation/devicetree/bindings/opp/sun50i-nvmem-cpufreq.txt @@ -0,0 +1,167 @@ +Allwinner Technologies, Inc. NVMEM CPUFreq and OPP bindings +=================================== + +For some SoCs, the CPU frequency subset and voltage value of each OPP +varies based on the silicon variant in use. Allwinner Process Voltage +Scaling Tables defines the voltage and frequency value based on the +speedbin blown in the efuse combination. The sun50i-cpufreq-nvmem driver +reads the efuse value from the SoC to provide the OPP framework with +required information. + +Required properties: +-------------------- +In 'cpus' nodes: +- operating-points-v2: Phandle to the operating-points-v2 table to use. + +In 'operating-points-v2' table: +- compatible: Should be + - 'allwinner,sun50i-h6-operating-points'. +- nvmem-cells: A phandle pointing to a nvmem-cells node representing the + efuse registers that has information about the speedbin + that is used to select the right frequency/voltage value + pair. Please refer the for nvmem-cells bindings + Documentation/devicetree/bindings/nvmem/nvmem.txt and + also examples below. + +In every OPP node: +- opp-microvolt-: Voltage in micro Volts. + At runtime, the platform can pick a and + matching opp-microvolt- property. + [See: opp.txt] + HW: : + sun50i-h6 speed0 speed1 speed2 + +Example 1: +--------- + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <0>; + enable-method = "psci"; + clocks = <&ccu CLK_CPUX>; + clock-latency-ns = <244144>; /* 8 32k periods */ + operating-points-v2 = <&cpu_opp_table>; + #cooling-cells = <2>; + }; + + cpu1: cpu@1 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <1>; + enable-method = "psci"; + clocks = <&ccu CLK_CPUX>; + clock-latency-ns = <244144>; /* 8 32k periods */ + operating-points-v2 = <&cpu_opp_table>; + #cooling-cells = <2>; + }; + + cpu2: cpu@2 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <2>; + enable-method = "psci"; + clocks = <&ccu CLK_CPUX>; + clock-latency-ns = <244144>; /* 8 32k periods */ + operating-points-v2 = <&cpu_opp_table>; + #cooling-cells = <2>; + }; + + cpu3: cpu@3 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <3>; + enable-method = "psci"; + clocks = <&ccu CLK_CPUX>; + clock-latency-ns = <244144>; /* 8 32k periods */ + operating-points-v2 = <&cpu_opp_table>; + #cooling-cells = <2>; + }; + }; + + cpu_opp_table: opp_table { + compatible = "allwinner,sun50i-h6-operating-points"; + nvmem-cells = <&speedbin_efuse>; + opp-shared; + + opp@480000000 { + clock-latency-ns = <244144>; /* 8 32k periods */ + opp-hz = /bits/ 64 <480000000>; + + opp-microvolt-speed0 = <880000>; + opp-microvolt-speed1 = <820000>; + opp-microvolt-speed2 = <800000>; + }; + + opp@720000000 { + clock-latency-ns = <244144>; /* 8 32k periods */ + opp-hz = /bits/ 64 <720000000>; + + opp-microvolt-speed0 = <880000>; + opp-microvolt-speed1 = <820000>; + opp-microvolt-speed2 = <800000>; + }; + + opp@816000000 { + clock-latency-ns = <244144>; /* 8 32k periods */ + opp-hz = /bits/ 64 <816000000>; + + opp-microvolt-speed0 = <880000>; + opp-microvolt-speed1 = <820000>; + opp-microvolt-speed2 = <800000>; + }; + + opp@888000000 { + clock-latency-ns = <244144>; /* 8 32k periods */ + opp-hz = /bits/ 64 <888000000>; + + opp-microvolt-speed0 = <940000>; + opp-microvolt-speed1 = <820000>; + opp-microvolt-speed2 = <800000>; + }; + + opp@1080000000 { + clock-latency-ns = <244144>; /* 8 32k periods */ + opp-hz = /bits/ 64 <1080000000>; + + opp-microvolt-speed0 = <1060000>; + opp-microvolt-speed1 = <880000>; + opp-microvolt-speed2 = <840000>; + }; + + opp@1320000000 { + clock-latency-ns = <244144>; /* 8 32k periods */ + opp-hz = /bits/ 64 <1320000000>; + + opp-microvolt-speed0 = <1160000>; + opp-microvolt-speed1 = <940000>; + opp-microvolt-speed2 = <900000>; + }; + + opp@1488000000 { + clock-latency-ns = <244144>; /* 8 32k periods */ + opp-hz = /bits/ 64 <1488000000>; + + opp-microvolt-speed0 = <1160000>; + opp-microvolt-speed1 = <1000000>; + opp-microvolt-speed2 = <960000>; + }; + }; +.... +soc { +.... + sid: sid@3006000 { + compatible = "allwinner,sun50i-h6-sid"; + reg = <0x03006000 0x400>; + #address-cells = <1>; + #size-cells = <1>; + .... + speedbin_efuse: speed@1c { + reg = <0x1c 4>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/pci/pci-armada8k.txt b/Documentation/devicetree/bindings/pci/pci-armada8k.txt index 9e3fc15e1af88d0853e07b78ebc0b5e62a9d064a..8324a4ee6f06651f6b25d0bd1ddf476fa458d6f7 100644 --- a/Documentation/devicetree/bindings/pci/pci-armada8k.txt +++ b/Documentation/devicetree/bindings/pci/pci-armada8k.txt @@ -17,6 +17,14 @@ Required properties: name must be "core" for the first clock and "reg" for the second one +Optional properties: +- phys: phandle(s) to PHY node(s) following the generic PHY bindings. + Either 1, 2 or 4 PHYs might be needed depending on the number of + PCIe lanes. +- phy-names: names of the PHYs corresponding to the number of lanes. + Must be "cp0-pcie0-x4-lane0-phy", "cp0-pcie0-x4-lane1-phy" for + 2 PHYs. + Example: pcie@f2600000 { diff --git a/Documentation/devicetree/bindings/phy/lantiq,vrx200-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/lantiq,vrx200-pcie-phy.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8a56a8526cef7e2a45d2935bd5d5dbbc7ca35dc6 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/lantiq,vrx200-pcie-phy.yaml @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/lantiq,vrx200-pcie-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Lantiq VRX200 and ARX300 PCIe PHY Device Tree Bindings + +maintainers: + - Martin Blumenstingl + +properties: + "#phy-cells": + const: 1 + description: selects the PHY mode as defined in + + compatible: + enum: + - lantiq,vrx200-pcie-phy + - lantiq,arx300-pcie-phy + + reg: + maxItems: 1 + + clocks: + items: + - description: PHY module clock + - description: PDI register clock + + clock-names: + items: + - const: phy + - const: pdi + + resets: + items: + - description: exclusive PHY reset line + - description: shared reset line between the PCIe PHY and PCIe controller + + resets-names: + items: + - const: phy + - const: pcie + + lantiq,rcu: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle to the RCU syscon + + lantiq,rcu-endian-offset: + $ref: /schemas/types.yaml#/definitions/uint32 + description: the offset of the endian registers for this PHY instance in the RCU syscon + + lantiq,rcu-big-endian-mask: + $ref: /schemas/types.yaml#/definitions/uint32 + description: the mask to set the PDI (PHY) registers for this PHY instance to big endian + + big-endian: + description: Configures the PDI (PHY) registers in big-endian mode + type: boolean + + little-endian: + description: Configures the PDI (PHY) registers in big-endian mode + type: boolean + +required: + - "#phy-cells" + - compatible + - reg + - clocks + - clock-names + - resets + - reset-names + - lantiq,rcu + - lantiq,rcu-endian-offset + - lantiq,rcu-big-endian-mask + +additionalProperties: false + +examples: + - | + pcie0_phy: phy@106800 { + compatible = "lantiq,vrx200-pcie-phy"; + reg = <0x106800 0x100>; + lantiq,rcu = <&rcu0>; + lantiq,rcu-endian-offset = <0x4c>; + lantiq,rcu-big-endian-mask = <0x80>; /* bit 7 */ + big-endian; + clocks = <&pmu 32>, <&pmu 36>; + clock-names = "phy", "pdi"; + resets = <&reset0 12 24>, <&reset0 22 22>; + reset-names = "phy", "pcie"; + #phy-cells = <1>; + }; + +... diff --git a/Documentation/devicetree/bindings/phy/phy-mvebu-comphy.txt b/Documentation/devicetree/bindings/phy/phy-mvebu-comphy.txt index cf2cd86db2674c62cfe162675abb572f262eca84..8c60e69859505b6aab3a219e7b8be9ed6d31e37e 100644 --- a/Documentation/devicetree/bindings/phy/phy-mvebu-comphy.txt +++ b/Documentation/devicetree/bindings/phy/phy-mvebu-comphy.txt @@ -25,6 +25,13 @@ Required properties: - #address-cells: should be 1. - #size-cells: should be 0. +Optional properlties: + +- clocks: pointers to the reference clocks for this device (CP110 only), + consequently: MG clock, MG Core clock, AXI clock. +- clock-names: names of used clocks for CP110 only, must be : + "mg_clk", "mg_core_clk" and "axi_clk". + A sub-node is required for each comphy lane provided by the comphy. Required properties (child nodes): @@ -39,6 +46,9 @@ Examples: compatible = "marvell,comphy-cp110"; reg = <0x120000 0x6000>; marvell,system-controller = <&cpm_syscon0>; + clocks = <&CP110_LABEL(clk) 1 5>, <&CP110_LABEL(clk) 1 6>, + <&CP110_LABEL(clk) 1 18>; + clock-names = "mg_clk", "mg_core_clk", "axi_clk"; #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml b/Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml new file mode 100644 index 0000000000000000000000000000000000000000..aab70e8b681e489bb5213747b607bc77ef3a30a6 --- /dev/null +++ b/Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2019 BayLibre, SAS +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/power/amlogic,meson-ee-pwrc.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Amlogic Meson Everything-Else Power Domains + +maintainers: + - Neil Armstrong + +description: |+ + The Everything-Else Power Domains node should be the child of a syscon + node with the required property: + + - compatible: Should be the following: + "amlogic,meson-gx-hhi-sysctrl", "simple-mfd", "syscon" + + Refer to the the bindings described in + Documentation/devicetree/bindings/mfd/syscon.txt + +properties: + compatible: + enum: + - amlogic,meson-g12a-pwrc + - amlogic,meson-sm1-pwrc + + clocks: + minItems: 2 + + clock-names: + items: + - const: vpu + - const: vapb + + resets: + minItems: 11 + + reset-names: + items: + - const: viu + - const: venc + - const: vcbus + - const: bt656 + - const: rdma + - const: venci + - const: vencp + - const: vdac + - const: vdi6 + - const: vencl + - const: vid_lock + + "#power-domain-cells": + const: 1 + + amlogic,ao-sysctrl: + description: phandle to the AO sysctrl node + allOf: + - $ref: /schemas/types.yaml#/definitions/phandle + +required: + - compatible + - clocks + - clock-names + - resets + - reset-names + - "#power-domain-cells" + - amlogic,ao-sysctrl + +examples: + - | + pwrc: power-controller { + compatible = "amlogic,meson-sm1-pwrc"; + #power-domain-cells = <1>; + amlogic,ao-sysctrl = <&rti>; + resets = <&reset_viu>, + <&reset_venc>, + <&reset_vcbus>, + <&reset_bt656>, + <&reset_rdma>, + <&reset_venci>, + <&reset_vencp>, + <&reset_vdac>, + <&reset_vdi6>, + <&reset_vencl>, + <&reset_vid_lock>; + reset-names = "viu", "venc", "vcbus", "bt656", + "rdma", "venci", "vencp", "vdac", + "vdi6", "vencl", "vid_lock"; + clocks = <&clk_vpu>, <&clk_vapb>; + clock-names = "vpu", "vapb"; + }; diff --git a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt index 3ae9f1088845ba4fecf43b90102256317f4b71e8..b9f58e480349896655d2d6d97881c641a2666fcb 100644 --- a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt @@ -34,6 +34,9 @@ Optional input supply properties: - inl67-supply: The input supply for LDO_REG3 and LDO_REG4 Any standard regulator properties can be used to configure the single regulator. +regulator-initial-mode, regulator-allowed-modes and regulator-mode could be specified +for act8865 using mode values from dt-bindings/regulator/active-semi,8865-regulator.h +file. The valid names for regulators are: - for act8846: @@ -47,6 +50,8 @@ The valid names for regulators are: Example: -------- +#include + i2c1: i2c@f0018000 { pmic: act8865@5b { compatible = "active-semi,act8865"; @@ -65,9 +70,19 @@ Example: regulator-name = "VCC_1V2"; regulator-min-microvolt = <1100000>; regulator-max-microvolt = <1300000>; - regulator-suspend-mem-microvolt = <1150000>; - regulator-suspend-standby-microvolt = <1150000>; regulator-always-on; + + regulator-allowed-modes = , + ; + regulator-initial-mode = ; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-min-microvolt = <1150000>; + regulator-suspend-max-microvolt = <1150000>; + regulator-changeable-in-suspend; + regulator-mode = ; + }; }; vcc_3v3_reg: DCDC_REG3 { @@ -82,6 +97,14 @@ Example: regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; + + regulator-allowed-modes = , + ; + regulator-initial-mode = ; + + regulator-state-mem { + regulator-off-in-suspend; + }; }; vddfuse_reg: LDO_REG2 { diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml b/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml index a650b457085de27f96a56dffd0026e8016cafb66..a78150c47aa2a67b8759c7a7c450e9edd20a375b 100644 --- a/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml @@ -19,9 +19,19 @@ description: allOf: - $ref: "regulator.yaml#" +if: + properties: + compatible: + contains: + const: regulator-fixed-clock + required: + - clocks + properties: compatible: - const: regulator-fixed + enum: + - const: regulator-fixed + - const: regulator-fixed-clock regulator-name: true @@ -29,6 +39,13 @@ properties: description: gpio to use for enable control maxItems: 1 + clocks: + description: + clock to use for enable control. This binding is only available if + the compatible is chosen to regulator-fixed-clock. The clock binding + is mandatory if compatible is chosen to regulator-fixed-clock. + maxItems: 1 + startup-delay-us: description: startup time in microseconds $ref: /schemas/types.yaml#/definitions/uint32 diff --git a/Documentation/devicetree/bindings/regulator/mt6358-regulator.txt b/Documentation/devicetree/bindings/regulator/mt6358-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..9a90a92f2d7e15a15159d570c91239b35eafe31e --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/mt6358-regulator.txt @@ -0,0 +1,358 @@ +MediaTek MT6358 Regulator + +All voltage regulators provided by the MT6358 PMIC are described as the +subnodes of the MT6358 regulators node. Each regulator is named according +to its regulator type, buck_ and ldo_. The definition for each +of these nodes is defined using the standard binding for regulators at +Documentation/devicetree/bindings/regulator/regulator.txt. + +The valid names for regulators are:: +BUCK: + buck_vdram1, buck_vcore, buck_vpa, buck_vproc11, buck_vproc12, buck_vgpu, + buck_vs2, buck_vmodem, buck_vs1 +LDO: + ldo_vdram2, ldo_vsim1, ldo_vibr, ldo_vrf12, ldo_vio18, ldo_vusb, ldo_vcamio, + ldo_vcamd, ldo_vcn18, ldo_vfe28, ldo_vsram_proc11, ldo_vcn28, ldo_vsram_others, + ldo_vsram_gpu, ldo_vxo22, ldo_vefuse, ldo_vaux18, ldo_vmch, ldo_vbif28, + ldo_vsram_proc12, ldo_vcama1, ldo_vemc, ldo_vio28, ldo_va12, ldo_vrf18, + ldo_vcn33_bt, ldo_vcn33_wifi, ldo_vcama2, ldo_vmc, ldo_vldo28, ldo_vaud28, + ldo_vsim2 + +Example: + + pmic { + compatible = "mediatek,mt6358"; + + mt6358regulator: mt6358regulator { + compatible = "mediatek,mt6358-regulator"; + + mt6358_vdram1_reg: buck_vdram1 { + regulator-compatible = "buck_vdram1"; + regulator-name = "vdram1"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <2087500>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <0>; + regulator-always-on; + }; + + mt6358_vcore_reg: buck_vcore { + regulator-name = "vcore"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1293750>; + regulator-ramp-delay = <6250>; + regulator-enable-ramp-delay = <200>; + regulator-always-on; + }; + + mt6358_vpa_reg: buck_vpa { + regulator-name = "vpa"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <3650000>; + regulator-ramp-delay = <50000>; + regulator-enable-ramp-delay = <250>; + }; + + mt6358_vproc11_reg: buck_vproc11 { + regulator-name = "vproc11"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1293750>; + regulator-ramp-delay = <6250>; + regulator-enable-ramp-delay = <200>; + regulator-always-on; + }; + + mt6358_vproc12_reg: buck_vproc12 { + regulator-name = "vproc12"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1293750>; + regulator-ramp-delay = <6250>; + regulator-enable-ramp-delay = <200>; + regulator-always-on; + }; + + mt6358_vgpu_reg: buck_vgpu { + regulator-name = "vgpu"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1293750>; + regulator-ramp-delay = <6250>; + regulator-enable-ramp-delay = <200>; + }; + + mt6358_vs2_reg: buck_vs2 { + regulator-name = "vs2"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <2087500>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <0>; + regulator-always-on; + }; + + mt6358_vmodem_reg: buck_vmodem { + regulator-name = "vmodem"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1293750>; + regulator-ramp-delay = <6250>; + regulator-enable-ramp-delay = <900>; + regulator-always-on; + }; + + mt6358_vs1_reg: buck_vs1 { + regulator-name = "vs1"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <2587500>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <0>; + regulator-always-on; + }; + + mt6358_vdram2_reg: ldo_vdram2 { + regulator-name = "vdram2"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <3300>; + }; + + mt6358_vsim1_reg: ldo_vsim1 { + regulator-name = "vsim1"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <3100000>; + regulator-enable-ramp-delay = <540>; + }; + + mt6358_vibr_reg: ldo_vibr { + regulator-name = "vibr"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <60>; + }; + + mt6358_vrf12_reg: ldo_vrf12 { + compatible = "regulator-fixed"; + regulator-name = "vrf12"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-enable-ramp-delay = <120>; + }; + + mt6358_vio18_reg: ldo_vio18 { + compatible = "regulator-fixed"; + regulator-name = "vio18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <2700>; + regulator-always-on; + }; + + mt6358_vusb_reg: ldo_vusb { + regulator-name = "vusb"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3100000>; + regulator-enable-ramp-delay = <270>; + regulator-always-on; + }; + + mt6358_vcamio_reg: ldo_vcamio { + compatible = "regulator-fixed"; + regulator-name = "vcamio"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <270>; + }; + + mt6358_vcamd_reg: ldo_vcamd { + regulator-name = "vcamd"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <270>; + }; + + mt6358_vcn18_reg: ldo_vcn18 { + compatible = "regulator-fixed"; + regulator-name = "vcn18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <270>; + }; + + mt6358_vfe28_reg: ldo_vfe28 { + compatible = "regulator-fixed"; + regulator-name = "vfe28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <270>; + }; + + mt6358_vsram_proc11_reg: ldo_vsram_proc11 { + regulator-name = "vsram_proc11"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1293750>; + regulator-ramp-delay = <6250>; + regulator-enable-ramp-delay = <240>; + regulator-always-on; + }; + + mt6358_vcn28_reg: ldo_vcn28 { + compatible = "regulator-fixed"; + regulator-name = "vcn28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <270>; + }; + + mt6358_vsram_others_reg: ldo_vsram_others { + regulator-name = "vsram_others"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1293750>; + regulator-ramp-delay = <6250>; + regulator-enable-ramp-delay = <240>; + regulator-always-on; + }; + + mt6358_vsram_gpu_reg: ldo_vsram_gpu { + regulator-name = "vsram_gpu"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1293750>; + regulator-ramp-delay = <6250>; + regulator-enable-ramp-delay = <240>; + }; + + mt6358_vxo22_reg: ldo_vxo22 { + compatible = "regulator-fixed"; + regulator-name = "vxo22"; + regulator-min-microvolt = <2200000>; + regulator-max-microvolt = <2200000>; + regulator-enable-ramp-delay = <120>; + regulator-always-on; + }; + + mt6358_vefuse_reg: ldo_vefuse { + regulator-name = "vefuse"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + regulator-enable-ramp-delay = <270>; + }; + + mt6358_vaux18_reg: ldo_vaux18 { + compatible = "regulator-fixed"; + regulator-name = "vaux18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <270>; + }; + + mt6358_vmch_reg: ldo_vmch { + regulator-name = "vmch"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <60>; + }; + + mt6358_vbif28_reg: ldo_vbif28 { + compatible = "regulator-fixed"; + regulator-name = "vbif28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <270>; + }; + + mt6358_vsram_proc12_reg: ldo_vsram_proc12 { + regulator-name = "vsram_proc12"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1293750>; + regulator-ramp-delay = <6250>; + regulator-enable-ramp-delay = <240>; + regulator-always-on; + }; + + mt6358_vcama1_reg: ldo_vcama1 { + regulator-name = "vcama1"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <270>; + }; + + mt6358_vemc_reg: ldo_vemc { + regulator-name = "vemc"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <60>; + regulator-always-on; + }; + + mt6358_vio28_reg: ldo_vio28 { + compatible = "regulator-fixed"; + regulator-name = "vio28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <270>; + }; + + mt6358_va12_reg: ldo_va12 { + compatible = "regulator-fixed"; + regulator-name = "va12"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-enable-ramp-delay = <270>; + regulator-always-on; + }; + + mt6358_vrf18_reg: ldo_vrf18 { + compatible = "regulator-fixed"; + regulator-name = "vrf18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <120>; + }; + + mt6358_vcn33_bt_reg: ldo_vcn33_bt { + regulator-name = "vcn33_bt"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3500000>; + regulator-enable-ramp-delay = <270>; + }; + + mt6358_vcn33_wifi_reg: ldo_vcn33_wifi { + regulator-name = "vcn33_wifi"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3500000>; + regulator-enable-ramp-delay = <270>; + }; + + mt6358_vcama2_reg: ldo_vcama2 { + regulator-name = "vcama2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <270>; + }; + + mt6358_vmc_reg: ldo_vmc { + regulator-name = "vmc"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <60>; + }; + + mt6358_vldo28_reg: ldo_vldo28 { + regulator-name = "vldo28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <270>; + }; + + mt6358_vaud28_reg: ldo_vaud28 { + compatible = "regulator-fixed"; + regulator-name = "vaud28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <270>; + }; + + mt6358_vsim2_reg: ldo_vsim2 { + regulator-name = "vsim2"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <3100000>; + regulator-enable-ramp-delay = <540>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt index 14d2eee96b3d5e075ed90af0ca9e042eae0ee065..bab9f71140b835161fba4895c7fddca8df786598 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt @@ -22,9 +22,12 @@ 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 PM8998: smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2 PMI8998: bob - PM8005: smps1 - smps4 ======================== First Level Nodes - PMIC @@ -33,9 +36,13 @@ First Level Nodes - PMIC - compatible Usage: required Value type: - Definition: Must be one of: "qcom,pm8998-rpmh-regulators", - "qcom,pmi8998-rpmh-regulators" or - "qcom,pm8005-rpmh-regulators". + Definition: Must be one of below: + "qcom,pm8005-rpmh-regulators" + "qcom,pm8009-rpmh-regulators" + "qcom,pm8150-rpmh-regulators" + "qcom,pm8150l-rpmh-regulators" + "qcom,pm8998-rpmh-regulators" + "qcom,pmi8998-rpmh-regulators" - qcom,pmic-id Usage: required diff --git a/Documentation/devicetree/bindings/regulator/sy8824x.txt b/Documentation/devicetree/bindings/regulator/sy8824x.txt new file mode 100644 index 0000000000000000000000000000000000000000..c5e95850c42771eec8baa23fde02a5c1d2026a87 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/sy8824x.txt @@ -0,0 +1,24 @@ +SY8824C/SY8824E/SY20276 Voltage regulator + +Required properties: +- compatible: Must be one of the following. + "silergy,sy8824c" + "silergy,sy8824e" + "silergy,sy20276" + "silergy,sy20278" +- reg: I2C slave address + +Any property defined as part of the core regulator binding, defined in +./regulator.txt, can also be used. + +Example: + + vcore: regulator@00 { + compatible = "silergy,sy8824c"; + reg = <0x66>; + regulator-name = "vcore"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1150000>; + regulator-boot-on; + regulator-always-on; + }; diff --git a/Documentation/devicetree/bindings/regulator/twl-regulator.txt b/Documentation/devicetree/bindings/regulator/twl-regulator.txt index 74a91c4f8530a4cd17cb5d184554c6cd283163e8..549f80436debca8eed1558f547264967cba89a42 100644 --- a/Documentation/devicetree/bindings/regulator/twl-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/twl-regulator.txt @@ -71,3 +71,10 @@ Example: regulator-min-microvolt = <1000000>; regulator-max-microvolt = <3000000>; }; + +For twl6030 regulators/LDOs: + + - ti,retain-on-reset: Does not turn off the supplies during warm + reset. Could be needed for VMMC, as TWL6030 + reset sequence for this signal does not comply + with the SD specification. diff --git a/Documentation/devicetree/bindings/regulator/uniphier-regulator.txt b/Documentation/devicetree/bindings/regulator/uniphier-regulator.txt index c9919f4b92d2121ef25471c1f22df69f621a911c..94fd38b0d163fdcedc20085c442e3c510ed4f292 100644 --- a/Documentation/devicetree/bindings/regulator/uniphier-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/uniphier-regulator.txt @@ -13,6 +13,7 @@ this layer. These clocks and resets should be described in each property. Required properties: - compatible: Should be "socionext,uniphier-pro4-usb3-regulator" - for Pro4 SoC + "socionext,uniphier-pro5-usb3-regulator" - for Pro5 SoC "socionext,uniphier-pxs2-usb3-regulator" - for PXs2 SoC "socionext,uniphier-ld20-usb3-regulator" - for LD20 SoC "socionext,uniphier-pxs3-usb3-regulator" - for PXs3 SoC @@ -20,12 +21,12 @@ Required properties: - clocks: A list of phandles to the clock gate for USB3 glue layer. According to the clock-names, appropriate clocks are required. - clock-names: Should contain - "gio", "link" - for Pro4 SoC + "gio", "link" - for Pro4 and Pro5 SoCs "link" - for others - resets: A list of phandles to the reset control for USB3 glue layer. According to the reset-names, appropriate resets are required. - reset-names: Should contain - "gio", "link" - for Pro4 SoC + "gio", "link" - for Pro4 and Pro5 SoCs "link" - for others See Documentation/devicetree/bindings/regulator/regulator.txt diff --git a/Documentation/devicetree/bindings/reset/fsl,imx7-src.txt b/Documentation/devicetree/bindings/reset/fsl,imx7-src.txt index 13e095182db4c6e305e7e7f6b05f3fd87e83ec15..c2489e41a8012f24590f2df0bf78abde86331f39 100644 --- a/Documentation/devicetree/bindings/reset/fsl,imx7-src.txt +++ b/Documentation/devicetree/bindings/reset/fsl,imx7-src.txt @@ -8,6 +8,7 @@ Required properties: - compatible: - For i.MX7 SoCs should be "fsl,imx7d-src", "syscon" - For i.MX8MQ SoCs should be "fsl,imx8mq-src", "syscon" + - For i.MX8MM SoCs should be "fsl,imx8mm-src", "fsl,imx8mq-src", "syscon" - reg: should be register base and length as documented in the datasheet - interrupts: Should contain SRC interrupt @@ -46,5 +47,6 @@ Example: For list of all valid reset indices see - for i.MX7 and - for i.MX8MQ + for i.MX7, + for i.MX8MQ and + for i.MX8MM diff --git a/Documentation/devicetree/bindings/reset/snps,dw-reset.txt b/Documentation/devicetree/bindings/reset/snps,dw-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..f94f911dd98db6376502a45a2680762709df26bb --- /dev/null +++ b/Documentation/devicetree/bindings/reset/snps,dw-reset.txt @@ -0,0 +1,30 @@ +Synopsys DesignWare Reset controller +======================================= + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: + +- compatible: should be one of the following. + "snps,dw-high-reset" - for active high configuration + "snps,dw-low-reset" - for active low configuration + +- reg: physical base address of the controller and length of memory mapped + region. + +- #reset-cells: must be 1. + +example: + + dw_rst_1: reset-controller@0000 { + compatible = "snps,dw-high-reset"; + reg = <0x0000 0x4>; + #reset-cells = <1>; + }; + + dw_rst_2: reset-controller@1000 {i + compatible = "snps,dw-low-reset"; + reg = <0x1000 0x8>; + #reset-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/rng/timeriomem_rng.txt b/Documentation/devicetree/bindings/rng/timeriomem_rng.txt index 214940093b550cc9c756fc72c0201921a3f1b31f..fb4846160047804b8a1943077d47b799fb0e447b 100644 --- a/Documentation/devicetree/bindings/rng/timeriomem_rng.txt +++ b/Documentation/devicetree/bindings/rng/timeriomem_rng.txt @@ -12,7 +12,7 @@ Optional properties: which disables using this rng to automatically fill the kernel's entropy pool. -N.B. currently 'reg' must be four bytes wide and aligned +N.B. currently 'reg' must be at least four bytes wide and 32-bit aligned Example: diff --git a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.txt b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.txt new file mode 100644 index 0000000000000000000000000000000000000000..f1bbe0826be533a13b22ad1c2c6b7f77d311c09e --- /dev/null +++ b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.txt @@ -0,0 +1,22 @@ +* Freescale LINFlexD UART + +The LINFlexD controller implements several LIN protocol versions, as well as +support for full-duplex UART communication through 8-bit and 9-bit frames. + +See chapter 47 ("LINFlexD") in the reference manual[1]. + +Required properties: +- compatible : + - "fsl,s32v234-linflexuart" for LINFlexD configured in UART mode, which + is compatible with the one integrated on S32V234 SoC +- reg : Address and length of the register set for the device +- interrupts : Should contain uart interrupt + +Example: +uart0: serial@40053000 { + compatible = "fsl,s32v234-linflexuart"; + reg = <0x0 0x40053000 0x0 0x1000>; + interrupts = <0 59 4>; +}; + +[1] https://www.nxp.com/webapp/Download?colCode=S32V234RM diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt index 21483ba820bc22f456058b5c0ccb86224f16c995..3495eee81d5308c0005dd0afdf595678f668a592 100644 --- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt +++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt @@ -13,7 +13,10 @@ Required properties: - reg : Address and length of the register set for the device - interrupts : Should contain uart interrupt - clocks : phandle + clock specifier pairs, one for each entry in clock-names -- clock-names : should contain: "ipg" - the uart clock +- clock-names : For vf610/ls1021a/imx7ulp, "ipg" clock is for uart bus/baud + clock. For imx8qxp lpuart, "ipg" clock is bus clock that is used to access + lpuart controller registers, it also requires "baud" clock for module to + receive/transmit data. Optional properties: - dmas: A list of two dma specifiers, one for each entry in dma-names. diff --git a/Documentation/devicetree/bindings/serial/mtk-uart.txt b/Documentation/devicetree/bindings/serial/mtk-uart.txt index 6fdffb735fb98e77ece85951d0c4e5e0307f4dbb..3a3b57079f0ded82dcb939c132fbe9f23c59b76d 100644 --- a/Documentation/devicetree/bindings/serial/mtk-uart.txt +++ b/Documentation/devicetree/bindings/serial/mtk-uart.txt @@ -9,6 +9,7 @@ Required properties: * "mediatek,mt6589-uart" for MT6589 compatible UARTS * "mediatek,mt6755-uart" for MT6755 compatible UARTS * "mediatek,mt6765-uart" for MT6765 compatible UARTS + * "mediatek,mt6779-uart" for MT6779 compatible UARTS * "mediatek,mt6795-uart" for MT6795 compatible UARTS * "mediatek,mt6797-uart" for MT6797 compatible UARTS * "mediatek,mt7622-uart" for MT7622 compatible UARTS diff --git a/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt b/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt index d7edf732eb7f5716f8feb5e9d8398cb8a3ac1dbc..f709304036c23a05c3ba2fe2fbc57fe6c37e475e 100644 --- a/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt +++ b/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt @@ -1,7 +1,12 @@ NVIDIA Tegra20/Tegra30 high speed (DMA based) UART controller driver. Required properties: -- compatible : should be "nvidia,tegra30-hsuart", "nvidia,tegra20-hsuart". +- compatible : should be, + "nvidia,tegra20-hsuart" for Tegra20, + "nvidia,tegra30-hsuart" for Tegra30, + "nvidia,tegra186-hsuart" for Tegra186, + "nvidia,tegra194-hsuart" for Tegra194. + - reg: Should contain UART controller registers location and length. - interrupts: Should contain UART controller interrupts. - clocks: Must contain one entry, for the module clock. @@ -19,6 +24,37 @@ Required properties: Optional properties: - nvidia,enable-modem-interrupt: Enable modem interrupts. Should be enable only if all 8 lines of UART controller are pinmuxed. +- nvidia,adjust-baud-rates: List of entries providing percentage of baud rate + adjustment within a range. + Each entry contains sets of 3 values. Range low/high and adjusted rate. + + When baud rate set on controller falls within the range mentioned in this + field, baud rate will be adjusted by percentage mentioned here. + Ex: <9600 115200 200> + Increase baud rate by 2% when set baud rate falls within range 9600 to 115200 + +Baud Rate tolerance: + Standard UART devices are expected to have tolerance for baud rate error by + -4 to +4 %. All Tegra devices till Tegra210 had this support. However, + Tegra186 chip has a known hardware issue. UART Rx baud rate tolerance level + is 0% to +4% in 1-stop config. Otherwise, the received data will have + corruption/invalid framing errors. Parker errata suggests adjusting baud + rate to be higher than the deviations observed in Tx. + + Tx deviation of connected device can be captured over scope (or noted from + its spec) for valid range and Tegra baud rate has to be set above actual + Tx baud rate observed. To do this we use nvidia,adjust-baud-rates + + As an example, consider there is deviation observed in Tx for baud rates as + listed below. + 0 to 9600 has 1% deviation + 9600 to 115200 2% deviation + This slight deviation is expcted and Tegra UART is expected to handle it. Due + to the issue stated above, baud rate on Tegra UART should be set equal to or + above deviation observed for avoiding frame errors. + Property should be set like this + nvidia,adjust-baud-rates = <0 9600 100>, + <9600 115200 200>; Example: @@ -33,4 +69,5 @@ serial@70006000 { reset-names = "serial"; dmas = <&apbdma 8>, <&apbdma 8>; dma-names = "rx", "tx"; + nvidia,adjust-baud-rates = <1000000 4000000 136>; /* 1.36% shift */ }; diff --git a/Documentation/devicetree/bindings/serial/sifive-serial.txt b/Documentation/devicetree/bindings/serial/sifive-serial.txt deleted file mode 100644 index c86b1e524159a0ee6dc4e8e3f363fbb65682fd68..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/serial/sifive-serial.txt +++ /dev/null @@ -1,33 +0,0 @@ -SiFive asynchronous serial interface (UART) - -Required properties: - -- compatible: should be something similar to - "sifive,-uart" for the UART as integrated - on a particular chip, and "sifive,uart" for the - general UART IP block programming model. Supported - compatible strings as of the date of this writing are: - "sifive,fu540-c000-uart" for the SiFive UART v0 as - integrated onto the SiFive FU540 chip, or "sifive,uart0" - for the SiFive UART v0 IP block with no chip integration - tweaks (if any) -- reg: address and length of the register space -- interrupts: Should contain the UART interrupt identifier -- clocks: Should contain a clock identifier for the UART's parent clock - - -UART HDL that corresponds to the IP block version numbers can be found -here: - -https://github.com/sifive/sifive-blocks/tree/master/src/main/scala/devices/uart - - -Example: - -uart0: serial@10010000 { - compatible = "sifive,fu540-c000-uart", "sifive,uart0"; - interrupt-parent = <&plic0>; - interrupts = <80>; - reg = <0x0 0x10010000 0x0 0x1000>; - clocks = <&prci PRCI_CLK_TLCLK>; -}; diff --git a/Documentation/devicetree/bindings/serial/sifive-serial.yaml b/Documentation/devicetree/bindings/serial/sifive-serial.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e8d3aeda12023dce2c8f9580daf7859b57b90dfe --- /dev/null +++ b/Documentation/devicetree/bindings/serial/sifive-serial.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/sifive-serial.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SiFive asynchronous serial interface (UART) + +maintainers: + - Pragnesh Patel + - Paul Walmsley + - Palmer Dabbelt + +allOf: + - $ref: /schemas/serial.yaml# + +properties: + compatible: + items: + - const: sifive,fu540-c000-uart + - const: sifive,uart0 + + description: + Should be something similar to "sifive,-uart" + for the UART as integrated on a particular chip, + and "sifive,uart" for the general UART IP + block programming model. + + UART HDL that corresponds to the IP block version + numbers can be found here - + + https://github.com/sifive/sifive-blocks/tree/master/src/main/scala/devices/uart + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + #include + serial@10010000 { + compatible = "sifive,fu540-c000-uart", "sifive,uart0"; + interrupt-parent = <&plic0>; + interrupts = <80>; + reg = <0x0 0x10010000 0x0 0x1000>; + clocks = <&prci PRCI_CLK_TLCLK>; + }; + +... diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt index a6b19485c9dc09ba2c88091164e96ca33f2f59a7..8620f7fcbd50f10fd9ee2cffa14c4a0cbf68260d 100644 --- a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt +++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt @@ -20,6 +20,11 @@ Optional properties: linux,rs485-enabled-at-boot-time: see rs485.txt. - dmas: phandle(s) to DMA controller node(s). Refer to stm32-dma.txt - dma-names: "rx" and/or "tx" +- wakeup-source: bool flag to indicate this device has wakeup capabilities +- interrupt-names, if optional wake-up interrupt is used, should be: + - "event": the name for the interrupt line of the USART instance + - "wakeup" the name for the optional wake-up interrupt + Examples: usart4: serial@40004c00 { diff --git a/Documentation/devicetree/bindings/soc/amlogic/clk-measure.txt b/Documentation/devicetree/bindings/soc/amlogic/clk-measure.txt index 6bf6b43f8dd863fb41b9b8b54c837a9be966b562..3dd563cec794e45f5135b6519c050081b8d1215d 100644 --- a/Documentation/devicetree/bindings/soc/amlogic/clk-measure.txt +++ b/Documentation/devicetree/bindings/soc/amlogic/clk-measure.txt @@ -11,6 +11,7 @@ Required properties: "amlogic,meson8b-clk-measure" for Meson8b SoCs "amlogic,meson-axg-clk-measure" for AXG SoCs "amlogic,meson-g12a-clk-measure" for G12a SoCs + "amlogic,meson-sm1-clk-measure" for SM1 SoCs - reg: base address and size of the Clock Measurer register space. Example: diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe.txt b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe.txt index d7afaff5faffb8c3e5d0bf6393984ddb3fa78af8..05ec2a838c54b58ce84aee5f7129e002339781ef 100644 --- a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe.txt +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe.txt @@ -18,7 +18,8 @@ Required properties: - reg : offset and length of the device registers. - bus-frequency : the clock frequency for QUICC Engine. - fsl,qe-num-riscs: define how many RISC engines the QE has. -- fsl,qe-num-snums: define how many serial number(SNUM) the QE can use for the +- fsl,qe-snums: This property has to be specified as '/bits/ 8' value, + defining the array of serial number (SNUM) values for the virtual threads. Optional properties: @@ -34,6 +35,11 @@ Recommended properties - brg-frequency : the internal clock source frequency for baud-rate generators in Hz. +Deprecated properties +- fsl,qe-num-snums: define how many serial number(SNUM) the QE can use + for the threads. Use fsl,qe-snums instead to not only specify the + number of snums, but also their values. + Example: qe@e0100000 { #address-cells = <1>; @@ -44,6 +50,11 @@ Example: reg = ; brg-frequency = <0>; bus-frequency = <179A7B00>; + fsl,qe-snums = /bits/ 8 < + 0x04 0x05 0x0C 0x0D 0x14 0x15 0x1C 0x1D + 0x24 0x25 0x2C 0x2D 0x34 0x35 0x88 0x89 + 0x98 0x99 0xA8 0xA9 0xB8 0xB9 0xC8 0xC9 + 0xD8 0xD9 0xE8 0xE9>; } * Multi-User RAM (MURAM) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.txt index 954ffee0a9c45f182527b219d629b6928913305e..4fc571e78f0180f73411c46e7e8ec82a6b5f154d 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.txt @@ -15,7 +15,10 @@ power-domains. - compatible: Usage: required Value type: - Definition: must be "qcom,sdm845-aoss-qmp" + Definition: must be one of: + "qcom,sc7180-aoss-qmp" + "qcom,sdm845-aoss-qmp" + "qcom,sm8150-aoss-qmp" - reg: Usage: required diff --git a/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt b/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt index f7b00a7c0f68944b7b29a9f515f342bd96d3da63..f541d1f776a2c234956c5f752f7617c4e61bc6d8 100644 --- a/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt +++ b/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt @@ -19,8 +19,15 @@ child of the pmmc node. Required Properties: -------------------- - compatible: should be "ti,sci-pm-domain" -- #power-domain-cells: Must be 1 so that an id can be provided in each - device node. +- #power-domain-cells: Can be one of the following: + 1: Containing the device id of each node + 2: First entry should be device id + Second entry should be one of the floowing: + TI_SCI_PD_EXCLUSIVE: To allow device to be + exclusively controlled by + the requesting hosts. + TI_SCI_PD_SHARED: To allow device to be shared + by multiple hosts. Example (K2G): ------------- diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml index e0284d8c3b636f0db2097cb3bdf316bb53c95ef5..38d4cede0860dd5aed5402e4cdb34dff5f39a677 100644 --- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml +++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml @@ -70,7 +70,9 @@ allOf: properties: compatible: contains: - const: allwinner,sun8i-h3-spdif + enum: + - allwinner,sun8i-h3-spdif + - allwinner,sun50i-h6-spdif then: properties: diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun50i-a64-codec-analog.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun50i-a64-codec-analog.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f290eb72a8781e7b0f2138ac74271cd087583716 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/allwinner,sun50i-a64-codec-analog.yaml @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/allwinner,sun50i-a64-codec-analog.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A64 Analog Codec Device Tree Bindings + +maintainers: + - Chen-Yu Tsai + - Maxime Ripard + +properties: + compatible: + const: allwinner,sun50i-a64-codec-analog + + reg: + maxItems: 1 + + cpvdd-supply: + description: + Regulator for the headphone amplifier + +required: + - compatible + - reg + - cpvdd-supply + +additionalProperties: false + +examples: + - | + codec_analog: codec-analog@1f015c0 { + compatible = "allwinner,sun50i-a64-codec-analog"; + reg = <0x01f015c0 0x4>; + cpvdd-supply = <®_eldo1>; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5e7cc05bbff1dc5f3705b58930f3674f89e67e15 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/allwinner,sun8i-a33-codec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A33 Codec Device Tree Bindings + +maintainers: + - Chen-Yu Tsai + - Maxime Ripard + +properties: + "#sound-dai-cells": + const: 0 + + compatible: + const: allwinner,sun8i-a33-codec + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Bus Clock + - description: Module Clock + + clock-names: + items: + - const: bus + - const: mod + +required: + - "#sound-dai-cells" + - compatible + - reg + - interrupts + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + audio-codec@1c22e00 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-a33-codec"; + reg = <0x01c22e00 0x400>; + interrupts = <0 29 4>; + clocks = <&ccu 47>, <&ccu 92>; + clock-names = "bus", "mod"; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt index 4330fc9dca6d87dee2ce5d27df472eeb0ed13767..3080979350a07aa384971741dc1b3bf10bca44dc 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt +++ b/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt @@ -4,13 +4,18 @@ Required properties: - compatible: 'amlogic,axg-toddr' or 'amlogic,axg-toddr' or 'amlogic,g12a-frddr' or - 'amlogic,g12a-toddr' + 'amlogic,g12a-toddr' or + 'amlogic,sm1-frddr' or + 'amlogic,sm1-toddr' - reg: physical base address of the controller and length of memory mapped region. - interrupts: interrupt specifier for the fifo. - clocks: phandle to the fifo peripheral clock provided by the audio clock controller. -- resets: phandle to memory ARB line provided by the arb reset controller. +- resets: list of reset phandle, one for each entry reset-names. +- reset-names: should contain the following: + * "arb" : memory ARB line (required) + * "rst" : dedicated device reset line (optional) - #sound-dai-cells: must be 0. Example of FRDDR A on the A113 SoC: diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt index 73f473a9365f73061257d5163bfd69eca5f83cf6..716878107a2423b03abf24cb81c826c6fe58bae2 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt +++ b/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt @@ -2,7 +2,8 @@ Required properties: - compatible: 'amlogic,axg-pdm' or - 'amlogic,g12a-pdm' + 'amlogic,g12a-pdm' or + 'amlogic,sm1-pdm' - reg: physical base address of the controller and length of memory mapped region. - clocks: list of clock phandle, one for each entry clock-names. @@ -12,6 +13,9 @@ Required properties: * "sysclk" : dsp system clock - #sound-dai-cells: must be 0. +Optional property: +- resets: phandle to the dedicated reset line of the pdm input. + Example of PDM on the A113 SoC: pdm: audio-controller@ff632000 { diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt index 0b82504fa419068b0e497f514feb6288bfb1d801..df92a4ecf2883152acdf3c366b4afcd869756506 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt +++ b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt @@ -2,7 +2,8 @@ Required properties: - compatible: 'amlogic,axg-spdifin' or - 'amlogic,g12a-spdifin' + 'amlogic,g12a-spdifin' or + 'amlogic,sm1-spdifin' - interrupts: interrupt specifier for the spdif input. - clocks: list of clock phandle, one for each entry clock-names. - clock-names: should contain the following: @@ -10,6 +11,9 @@ Required properties: * "refclk" : spdif input reference clock - #sound-dai-cells: must be 0. +Optional property: +- resets: phandle to the dedicated reset line of the spdif input. + Example on the A113 SoC: spdifin: audio-controller@400 { diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt index 826152730508e2a7100485f26200e58d2bbb02f5..28381dd1f633f203e0506efbb3e94629c2a28502 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt +++ b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt @@ -2,13 +2,17 @@ Required properties: - compatible: 'amlogic,axg-spdifout' or - 'amlogic,g12a-spdifout' + 'amlogic,g12a-spdifout' or + 'amlogic,sm1-spdifout' - clocks: list of clock phandle, one for each entry clock-names. - clock-names: should contain the following: * "pclk" : peripheral clock. * "mclk" : master clock - #sound-dai-cells: must be 0. +Optional property: +- resets: phandle to the dedicated reset line of the spdif output. + Example on the A113 SoC: spdifout: audio-controller@480 { diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt index 8835a43edfbbc78647d64e0a9a7111bd60a52067..5996c0cd89c29eced5230432b435cca2ffb8e75f 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt +++ b/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt @@ -4,7 +4,9 @@ Required properties: - compatible: 'amlogic,axg-tdmin' or 'amlogic,axg-tdmout' or 'amlogic,g12a-tdmin' or - 'amlogic,g12a-tdmout' + 'amlogic,g12a-tdmout' or + 'amlogic,sm1-tdmin' or + 'amlogic,sm1-tdmout - reg: physical base address of the controller and length of memory mapped region. - clocks: list of clock phandle, one for each entry clock-names. diff --git a/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt b/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt index aa6c35570d318b1c4e3bb4114ecb998209e27029..4e8cd7eb7cec458225bb765315e0a0983a0633fa 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt +++ b/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt @@ -1,10 +1,12 @@ * Amlogic HDMI Tx control glue Required properties: -- compatible: "amlogic,g12a-tohdmitx" +- compatible: "amlogic,g12a-tohdmitx" or + "amlogic,sm1-tohdmitx" - reg: physical base address of the controller and length of memory mapped region. - #sound-dai-cells: should be 1. +- resets: phandle to the dedicated reset line of the hdmitx glue. Example on the S905X2 SoC: @@ -12,6 +14,7 @@ tohdmitx: audio-controller@744 { compatible = "amlogic,g12a-tohdmitx"; reg = <0x0 0x744 0x0 0x4>; #sound-dai-cells = <1>; + resets = <&clkc_audio AUD_RESET_TOHDMITX>; }; Example of an 'amlogic,axg-sound-card': diff --git a/Documentation/devicetree/bindings/sound/everest,es8316.txt b/Documentation/devicetree/bindings/sound/everest,es8316.txt new file mode 100644 index 0000000000000000000000000000000000000000..1bf03c5f2af4d06ea8a202db3416a55300669c90 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/everest,es8316.txt @@ -0,0 +1,23 @@ +Everest ES8316 audio CODEC + +This device supports both I2C and SPI. + +Required properties: + + - compatible : should be "everest,es8316" + - reg : the I2C address of the device for I2C + +Optional properties: + + - clocks : a list of phandle, should contain entries for clock-names + - clock-names : should include as follows: + "mclk" : master clock (MCLK) of the device + +Example: + +es8316: codec@11 { + compatible = "everest,es8316"; + reg = <0x11>; + clocks = <&clks 10>; + clock-names = "mclk"; +}; diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt index 5b9914367610315d8aaab3a614dd318de9408c6d..0e6e2166f76cdf767e36fbcb8a94dd73c33a1b3e 100644 --- a/Documentation/devicetree/bindings/sound/fsl,esai.txt +++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt @@ -7,8 +7,11 @@ other DSPs. It has up to six transmitters and four receivers. Required properties: - - compatible : Compatible list, must contain "fsl,imx35-esai" or - "fsl,vf610-esai" + - compatible : Compatible list, should contain one of the following + compatibles: + "fsl,imx35-esai", + "fsl,vf610-esai", + "fsl,imx6ull-esai", - reg : Offset and length of the register set for the device. diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt index 2e726b9838450f3284bca7db95c0a876382625c4..0dc83cc4a236b890a2235c97e0ddef6b91664d68 100644 --- a/Documentation/devicetree/bindings/sound/fsl-sai.txt +++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt @@ -8,7 +8,9 @@ codec/DSP interfaces. Required properties: - compatible : Compatible list, contains "fsl,vf610-sai", - "fsl,imx6sx-sai" or "fsl,imx6ul-sai" + "fsl,imx6sx-sai", "fsl,imx6ul-sai", + "fsl,imx7ulp-sai", "fsl,imx8mq-sai" or + "fsl,imx8qm-sai". - reg : Offset and length of the register set for the device. diff --git a/Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt b/Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt deleted file mode 100644 index 056a098495ccec8a9bd7d725199b0d951d4054e6..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt +++ /dev/null @@ -1,14 +0,0 @@ -* Allwinner A64 Codec Analog Controls - -Required properties: -- compatible: must be one of the following compatibles: - - "allwinner,sun50i-a64-codec-analog" -- reg: must contain the registers location and length -- cpvdd-supply: Regulator supply for the headphone amplifier - -Example: - codec_analog: codec-analog@1f015c0 { - compatible = "allwinner,sun50i-a64-codec-analog"; - reg = <0x01f015c0 0x4>; - cpvdd-supply = <®_eldo1>; - }; diff --git a/Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt b/Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt deleted file mode 100644 index 2ca3d138528ec340526704e3cb7c865c3f486b70..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt +++ /dev/null @@ -1,63 +0,0 @@ -Allwinner SUN8I audio codec ------------------------------------- - -On Sun8i-A33 SoCs, the audio is separated in different parts: - - A DAI driver. It uses the "sun4i-i2s" driver which is - documented here: - Documentation/devicetree/bindings/sound/sun4i-i2s.txt - - An analog part of the codec which is handled as PRCM registers. - See Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt - - An digital part of the codec which is documented in this current - binding documentation. - - And finally, an audio card which links all the above components. - The simple-audio card will be used. - See Documentation/devicetree/bindings/sound/simple-card.txt - -This bindings documentation exposes Sun8i codec (digital part). - -Required properties: -- compatible: must be "allwinner,sun8i-a33-codec" -- reg: must contain the registers location and length -- interrupts: must contain the codec interrupt -- clocks: a list of phandle + clock-specifer pairs, one for each entry - in clock-names. -- clock-names: should contain followings: - - "bus": the parent APB clock for this controller - - "mod": the parent module clock - -Here is an example to add a sound card and the codec binding on sun8i SoCs that -are similar to A33 using simple-card: - - sound { - compatible = "simple-audio-card"; - simple-audio-card,name = "sun8i-a33-audio"; - simple-audio-card,format = "i2s"; - simple-audio-card,frame-master = <&link_codec>; - simple-audio-card,bitclock-master = <&link_codec>; - simple-audio-card,mclk-fs = <512>; - simple-audio-card,aux-devs = <&codec_analog>; - simple-audio-card,routing = - "Left DAC", "Digital Left DAC", - "Right DAC", "Digital Right DAC"; - - simple-audio-card,cpu { - sound-dai = <&dai>; - }; - - link_codec: simple-audio-card,codec { - sound-dai = <&codec>; - }; - - soc@1c00000 { - [...] - - audio-codec@1c22e00 { - #sound-dai-cells = <0>; - compatible = "allwinner,sun8i-a33-codec"; - reg = <0x01c22e00 0x400>; - interrupts = ; - clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>; - clock-names = "bus", "mod"; - }; - }; - diff --git a/Documentation/devicetree/bindings/sound/uda1334.txt b/Documentation/devicetree/bindings/sound/uda1334.txt new file mode 100644 index 0000000000000000000000000000000000000000..f64071b25e8d271f764cd6c419bc21085ea3766c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/uda1334.txt @@ -0,0 +1,17 @@ +UDA1334 audio CODEC + +This device uses simple GPIO pins for controlling codec settings. + +Required properties: + + - compatible : "nxp,uda1334" + - nxp,mute-gpios: a GPIO spec for the MUTE pin. + - nxp,deemph-gpios: a GPIO spec for the De-emphasis pin + +Example: + +uda1334: audio-codec { + compatible = "nxp,uda1334"; + nxp,mute-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; + nxp,deemph-gpios = <&gpio3 3 GPIO_ACTIVE_LOW>; +}; diff --git a/Documentation/devicetree/bindings/spi/nuvoton,npcm-fiu.txt b/Documentation/devicetree/bindings/spi/nuvoton,npcm-fiu.txt new file mode 100644 index 0000000000000000000000000000000000000000..a388005842adaa6a1a25e6e8563e140169e1c75c --- /dev/null +++ b/Documentation/devicetree/bindings/spi/nuvoton,npcm-fiu.txt @@ -0,0 +1,47 @@ +* Nuvoton FLASH Interface Unit (FIU) SPI Controller + +NPCM FIU supports single, dual and quad communication interface. + +The NPCM7XX supports three FIU modules, +FIU0 and FIUx supports two chip selects, +FIU3 support four chip select. + +Required properties: + - compatible : "nuvoton,npcm750-fiu" for the NPCM7XX BMC + - #address-cells : should be 1. + - #size-cells : should be 0. + - 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 "control" and "memory" + - clocks : phandle of FIU reference clock. + +Required properties in case the pins can be muxed: + - pinctrl-names : a pinctrl state named "default" must be defined. + - pinctrl-0 : phandle referencing pin configuration of the device. + +Optional property: + - nuvoton,spix-mode: enable spix-mode for an expansion bus to an ASIC or CPLD. + +Aliases: +- All the FIU controller nodes should be represented in the aliases node using + the following format 'fiu{n}' where n is a unique number for the alias. + In the NPCM7XX BMC: + fiu0 represent fiu 0 controller + fiu1 represent fiu 3 controller + fiu2 represent fiu x controller + +Example: +fiu3: spi@c00000000 { + compatible = "nuvoton,npcm750-fiu"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xfb000000 0x1000>, <0x80000000 0x10000000>; + reg-names = "control", "memory"; + clocks = <&clk NPCM7XX_CLK_AHB>; + pinctrl-names = "default"; + pinctrl-0 = <&spi3_pins>; + spi-nor@0 { + ... + }; +}; + diff --git a/Documentation/devicetree/bindings/spi/spi-controller.yaml b/Documentation/devicetree/bindings/spi/spi-controller.yaml index a02e2fe2bfb22350773759da4b27fc13800f1c49..732339275848c12a52c438656f97e3e74a44b9ff 100644 --- a/Documentation/devicetree/bindings/spi/spi-controller.yaml +++ b/Documentation/devicetree/bindings/spi/spi-controller.yaml @@ -31,7 +31,7 @@ properties: If that property is used, the number of chip selects will be increased automatically with max(cs-gpios, hardware chip selects). - So if, for example, the controller has 2 CS lines, and the + So if, for example, the controller has 4 CS lines, and the cs-gpios looks like this cs-gpios = <&gpio1 0 0>, <0>, <&gpio1 1 0>, <&gpio1 2 0>; diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt index dcc7eaada5118a5e61c23499d5f46f5f324e5c43..162e024b95a0c6a3152a50bf065d9c429118ae33 100644 --- a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt +++ b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt @@ -6,6 +6,7 @@ Required properties: or "fsl,ls2080a-dspi" followed by "fsl,ls2085a-dspi" "fsl,ls1012a-dspi" followed by "fsl,ls1021a-v1.0-dspi" + "fsl,ls1088a-dspi" followed by "fsl,ls1021a-v1.0-dspi" - reg : Offset and length of the register set for the device - interrupts : Should contain SPI controller interrupt - clocks: from common clock binding: handle to dspi clock. diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-qspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-qspi.txt index e8f1d627d2885cd2ae8729705427fcb7c085beef..69dc5d57b1efbe73324b6e17df474317e1ef684a 100644 --- a/Documentation/devicetree/bindings/spi/spi-fsl-qspi.txt +++ b/Documentation/devicetree/bindings/spi/spi-fsl-qspi.txt @@ -3,9 +3,8 @@ Required properties: - compatible : Should be "fsl,vf610-qspi", "fsl,imx6sx-qspi", "fsl,imx7d-qspi", "fsl,imx6ul-qspi", - "fsl,ls1021a-qspi" + "fsl,ls1021a-qspi", "fsl,ls2080a-qspi" or - "fsl,ls2080a-qspi" followed by "fsl,ls1021a-qspi", "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 @@ -34,7 +33,11 @@ qspi0: quadspi@40044000 { 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>; }; }; diff --git a/Documentation/devicetree/bindings/spi/spi-mt65xx.txt b/Documentation/devicetree/bindings/spi/spi-mt65xx.txt index c0f6c8ecfa2e2ff963fbb440ae04524a8f85c669..3a8079eb18c8d7971a2cc5553d4a6f59ccf7210e 100644 --- a/Documentation/devicetree/bindings/spi/spi-mt65xx.txt +++ b/Documentation/devicetree/bindings/spi/spi-mt65xx.txt @@ -5,6 +5,7 @@ Required properties: - mediatek,mt2701-spi: for mt2701 platforms - mediatek,mt2712-spi: for mt2712 platforms - mediatek,mt6589-spi: for mt6589 platforms + - mediatek,mt6765-spi: for mt6765 platforms - mediatek,mt7622-spi: for mt7622 platforms - "mediatek,mt7629-spi", "mediatek,mt7622-spi": for mt7629 platforms - mediatek,mt8135-spi: for mt8135 platforms diff --git a/Documentation/devicetree/bindings/spi/spi-sprd-adi.txt b/Documentation/devicetree/bindings/spi/spi-sprd-adi.txt index 8de589b376ce1b72a83ab2c088c811ed0af9f360..2567c829e2dcf10e97ddfa0675acca3b94b122e5 100644 --- a/Documentation/devicetree/bindings/spi/spi-sprd-adi.txt +++ b/Documentation/devicetree/bindings/spi/spi-sprd-adi.txt @@ -25,18 +25,23 @@ data by ADI software channels at the same time, or two parallel routine of setti ADI registers will make ADI controller registers chaos to lead incorrect results. Then we need one hardware spinlock to synchronize between the multiple subsystems. +The new version ADI controller supplies multiple master channels for different +subsystem accessing, that means no need to add hardware spinlock to synchronize, +thus change the hardware spinlock support to be optional to keep backward +compatibility. + Required properties: - compatible: Should be "sprd,sc9860-adi". - reg: Offset and length of ADI-SPI controller register space. -- hwlocks: Reference to a phandle of a hwlock provider node. -- hwlock-names: Reference to hwlock name strings defined in the same order - as the hwlocks, should be "adi". - #address-cells: Number of cells required to define a chip select address on the ADI-SPI bus. Should be set to 1. - #size-cells: Size of cells required to define a chip select address size on the ADI-SPI bus. Should be set to 0. Optional properties: +- hwlocks: Reference to a phandle of a hwlock provider node. +- hwlock-names: Reference to hwlock name strings defined in the same order + as the hwlocks, should be "adi". - sprd,hw-channels: This is an array of channel values up to 49 channels. The first value specifies the hardware channel id which is used to transfer data triggered by hardware automatically, and the second diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun4i-a10-timer.yaml b/Documentation/devicetree/bindings/timer/allwinner,sun4i-a10-timer.yaml new file mode 100644 index 0000000000000000000000000000000000000000..20adc1c8e9cccb33a94f385966c02df961f0fa59 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/allwinner,sun4i-a10-timer.yaml @@ -0,0 +1,102 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/timer/allwinner,sun4i-a10-timer.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A10 Timer Device Tree Bindings + +maintainers: + - Chen-Yu Tsai + - Maxime Ripard + +properties: + compatible: + enum: + - allwinner,sun4i-a10-timer + - allwinner,sun8i-a23-timer + - allwinner,sun8i-v3s-timer + - allwinner,suniv-f1c100s-timer + + reg: + maxItems: 1 + + interrupts: + description: + List of timers interrupts + + clocks: + maxItems: 1 + +allOf: + - if: + properties: + compatible: + items: + const: allwinner,sun4i-a10-timer + + then: + properties: + interrupts: + minItems: 6 + maxItems: 6 + + - if: + properties: + compatible: + items: + const: allwinner,sun8i-a23-timer + + then: + properties: + interrupts: + minItems: 2 + maxItems: 2 + + - if: + properties: + compatible: + items: + const: allwinner,sun8i-v3s-timer + + then: + properties: + interrupts: + minItems: 3 + maxItems: 3 + + - if: + properties: + compatible: + items: + const: allwinner,suniv-f1c100s-timer + + then: + properties: + interrupts: + minItems: 3 + maxItems: 3 + +required: + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + timer { + compatible = "allwinner,sun4i-a10-timer"; + reg = <0x01c20c00 0x400>; + interrupts = <22>, + <23>, + <24>, + <25>, + <67>, + <68>; + clocks = <&osc>; + }; + +... diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt b/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt deleted file mode 100644 index 3da9d515c03a9e54d8f775913281676ddbcb7860..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt +++ /dev/null @@ -1,19 +0,0 @@ -Allwinner A1X SoCs Timer Controller - -Required properties: - -- compatible : should be one of the following: - "allwinner,sun4i-a10-timer" - "allwinner,suniv-f1c100s-timer" -- reg : Specifies base physical address and size of the registers. -- interrupts : The interrupt of the first timer -- clocks: phandle to the source clock (usually a 24 MHz fixed clock) - -Example: - -timer { - compatible = "allwinner,sun4i-a10-timer"; - reg = <0x01c20c00 0x400>; - interrupts = <22>; - clocks = <&osc>; -}; diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt deleted file mode 100644 index 2c5c1be7836015c9cfc6ef4e653eb5d846d48dad..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt +++ /dev/null @@ -1,26 +0,0 @@ -Allwinner SoCs High Speed Timer Controller - -Required properties: - -- compatible : should be "allwinner,sun5i-a13-hstimer" or - "allwinner,sun7i-a20-hstimer" -- reg : Specifies base physical address and size of the registers. -- interrupts : The interrupts of these timers (2 for the sun5i IP, 4 for the sun7i - one) -- clocks: phandle to the source clock (usually the AHB clock) - -Optional properties: -- resets: phandle to a reset controller asserting the timer - -Example: - -timer@1c60000 { - compatible = "allwinner,sun7i-a20-hstimer"; - reg = <0x01c60000 0x1000>; - interrupts = <0 51 1>, - <0 52 1>, - <0 53 1>, - <0 54 1>; - clocks = <&ahb1_gates 19>; - resets = <&ahb1rst 19>; -}; diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.yaml b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.yaml new file mode 100644 index 0000000000000000000000000000000000000000..dfa0c41fd261d166b95af163f195f45358798bc8 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.yaml @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/timer/allwinner,sun5i-a13-hstimer.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A13 High-Speed Timer Device Tree Bindings + +maintainers: + - Chen-Yu Tsai + - Maxime Ripard + +properties: + compatible: + oneOf: + - const: allwinner,sun5i-a13-hstimer + - const: allwinner,sun7i-a20-hstimer + - items: + - const: allwinner,sun6i-a31-hstimer + - const: allwinner,sun7i-a20-hstimer + + reg: + maxItems: 1 + + interrupts: + minItems: 2 + maxItems: 4 + items: + - description: Timer 0 Interrupt + - description: Timer 1 Interrupt + - description: Timer 2 Interrupt + - description: Timer 3 Interrupt + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +if: + properties: + compatible: + items: + const: allwinner,sun5i-a13-hstimer + +then: + properties: + interrupts: + minItems: 2 + maxItems: 2 + +else: + properties: + interrupts: + minItems: 4 + maxItems: 4 + +additionalProperties: false + +examples: + - | + timer@1c60000 { + compatible = "allwinner,sun7i-a20-hstimer"; + reg = <0x01c60000 0x1000>; + interrupts = <0 51 1>, + <0 52 1>, + <0 53 1>, + <0 54 1>; + clocks = <&ahb1_gates 19>; + resets = <&ahb1rst 19>; + }; + +... diff --git a/Documentation/devicetree/bindings/timer/renesas,cmt.txt b/Documentation/devicetree/bindings/timer/renesas,cmt.txt index c5220bcd852b5a5949d9439cb0d0883b64d7436b..a444cfc5852a6ab6c02f3ec84dd8153ab6fbf67c 100644 --- a/Documentation/devicetree/bindings/timer/renesas,cmt.txt +++ b/Documentation/devicetree/bindings/timer/renesas,cmt.txt @@ -12,16 +12,13 @@ datasheets. Required Properties: - compatible: must contain one or more of the following: - - "renesas,cmt-48-sh73a0" for the sh73A0 48-bit CMT - (CMT1) - - "renesas,cmt-48-r8a7740" for the r8a7740 48-bit CMT - (CMT1) - - "renesas,cmt-48" for all non-second generation 48-bit CMT - (CMT1 on sh73a0 and r8a7740) - This is a fallback for the above renesas,cmt-48-* entries. - - "renesas,r8a73a4-cmt0" for the 32-bit CMT0 device included in r8a73a4. - "renesas,r8a73a4-cmt1" for the 48-bit CMT1 device included in r8a73a4. + - "renesas,r8a7740-cmt0" for the 32-bit CMT0 device included in r8a7740. + - "renesas,r8a7740-cmt1" for the 48-bit CMT1 device included in r8a7740. + - "renesas,r8a7740-cmt2" for the 32-bit CMT2 device included in r8a7740. + - "renesas,r8a7740-cmt3" for the 32-bit CMT3 device included in r8a7740. + - "renesas,r8a7740-cmt4" for the 32-bit CMT4 device included in r8a7740. - "renesas,r8a7743-cmt0" for the 32-bit CMT0 device included in r8a7743. - "renesas,r8a7743-cmt1" for the 48-bit CMT1 device included in r8a7743. - "renesas,r8a7744-cmt0" for the 32-bit CMT0 device included in r8a7744. @@ -31,29 +28,38 @@ Required Properties: - "renesas,r8a77470-cmt0" for the 32-bit CMT0 device included in r8a77470. - "renesas,r8a77470-cmt1" for the 48-bit CMT1 device included in r8a77470. - "renesas,r8a774a1-cmt0" for the 32-bit CMT0 device included in r8a774a1. - - "renesas,r8a774a1-cmt1" for the 48-bit CMT1 device included in r8a774a1. + - "renesas,r8a774a1-cmt1" for the 48-bit CMT devices included in r8a774a1. - "renesas,r8a774c0-cmt0" for the 32-bit CMT0 device included in r8a774c0. - - "renesas,r8a774c0-cmt1" for the 48-bit CMT1 device included in r8a774c0. + - "renesas,r8a774c0-cmt1" for the 48-bit CMT devices included in r8a774c0. - "renesas,r8a7790-cmt0" for the 32-bit CMT0 device included in r8a7790. - "renesas,r8a7790-cmt1" for the 48-bit CMT1 device included in r8a7790. - "renesas,r8a7791-cmt0" for the 32-bit CMT0 device included in r8a7791. - "renesas,r8a7791-cmt1" for the 48-bit CMT1 device included in r8a7791. + - "renesas,r8a7792-cmt0" for the 32-bit CMT0 device included in r8a7792. + - "renesas,r8a7792-cmt1" for the 48-bit CMT1 device included in r8a7792. - "renesas,r8a7793-cmt0" for the 32-bit CMT0 device included in r8a7793. - "renesas,r8a7793-cmt1" for the 48-bit CMT1 device included in r8a7793. - "renesas,r8a7794-cmt0" for the 32-bit CMT0 device included in r8a7794. - "renesas,r8a7794-cmt1" for the 48-bit CMT1 device included in r8a7794. - "renesas,r8a7795-cmt0" for the 32-bit CMT0 device included in r8a7795. - - "renesas,r8a7795-cmt1" for the 48-bit CMT1 device included in r8a7795. + - "renesas,r8a7795-cmt1" for the 48-bit CMT devices included in r8a7795. - "renesas,r8a7796-cmt0" for the 32-bit CMT0 device included in r8a7796. - - "renesas,r8a7796-cmt1" for the 48-bit CMT1 device included in r8a7796. + - "renesas,r8a7796-cmt1" for the 48-bit CMT devices included in r8a7796. - "renesas,r8a77965-cmt0" for the 32-bit CMT0 device included in r8a77965. - - "renesas,r8a77965-cmt1" for the 48-bit CMT1 device included in r8a77965. + - "renesas,r8a77965-cmt1" for the 48-bit CMT devices included in r8a77965. - "renesas,r8a77970-cmt0" for the 32-bit CMT0 device included in r8a77970. - - "renesas,r8a77970-cmt1" for the 48-bit CMT1 device included in r8a77970. + - "renesas,r8a77970-cmt1" for the 48-bit CMT devices included in r8a77970. - "renesas,r8a77980-cmt0" for the 32-bit CMT0 device included in r8a77980. - - "renesas,r8a77980-cmt1" for the 48-bit CMT1 device included in r8a77980. + - "renesas,r8a77980-cmt1" for the 48-bit CMT devices included in r8a77980. - "renesas,r8a77990-cmt0" for the 32-bit CMT0 device included in r8a77990. - - "renesas,r8a77990-cmt1" for the 48-bit CMT1 device included in r8a77990. + - "renesas,r8a77990-cmt1" for the 48-bit CMT devices included in r8a77990. + - "renesas,r8a77995-cmt0" for the 32-bit CMT0 device included in r8a77995. + - "renesas,r8a77995-cmt1" for the 48-bit CMT devices included in r8a77995. + - "renesas,sh73a0-cmt0" for the 32-bit CMT0 device included in sh73a0. + - "renesas,sh73a0-cmt1" for the 48-bit CMT1 device included in sh73a0. + - "renesas,sh73a0-cmt2" for the 32-bit CMT2 device included in sh73a0. + - "renesas,sh73a0-cmt3" for the 32-bit CMT3 device included in sh73a0. + - "renesas,sh73a0-cmt4" for the 32-bit CMT4 device included in sh73a0. - "renesas,rcar-gen2-cmt0" for 32-bit CMT0 devices included in R-Car Gen2 and RZ/G1. @@ -63,7 +69,7 @@ Required Properties: listed above. - "renesas,rcar-gen3-cmt0" for 32-bit CMT0 devices included in R-Car Gen3 and RZ/G2. - - "renesas,rcar-gen3-cmt1" for 48-bit CMT1 devices included in R-Car Gen3 + - "renesas,rcar-gen3-cmt1" for 48-bit CMT devices included in R-Car Gen3 and RZ/G2. These are fallbacks for R-Car Gen3 and RZ/G2 entries listed above. diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 2e742d399e87b039cc77f04c53ff33634e94c177..870ac52d2225923961712ced3a51c030cba0a386 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -104,6 +104,8 @@ properties: - infineon,slb9645tt # Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor - infineon,tlv493d-a1b6 + # Inspur Power System power supply unit version 1 + - inspur,ipsps1 # Intersil ISL29028 Ambient Light and Proximity Sensor - isil,isl29028 # Intersil ISL29030 Ambient Light and Proximity Sensor diff --git a/Documentation/devicetree/bindings/usb/cdns-usb3.txt b/Documentation/devicetree/bindings/usb/cdns-usb3.txt new file mode 100644 index 0000000000000000000000000000000000000000..b7dc606d37b5244054d8d1a40fc63986170492a8 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/cdns-usb3.txt @@ -0,0 +1,45 @@ +Binding for the Cadence USBSS-DRD controller + +Required properties: + - reg: Physical base address and size of the controller's register areas. + Controller has 3 different regions: + - HOST registers area + - DEVICE registers area + - OTG/DRD registers area + - reg-names - register memory area names: + "xhci" - for HOST registers space + "dev" - for DEVICE registers space + "otg" - for OTG/DRD registers space + - compatible: Should contain: "cdns,usb3" + - interrupts: Interrupts used by cdns3 controller: + "host" - interrupt used by XHCI driver. + "peripheral" - interrupt used by device driver + "otg" - interrupt used by DRD/OTG part of driver + +Optional properties: + - maximum-speed : valid arguments are "super-speed", "high-speed" and + "full-speed"; refer to usb/generic.txt + - dr_mode: Should be one of "host", "peripheral" or "otg". + - phys: reference to the USB PHY + - phy-names: from the *Generic PHY* bindings; + Supported names are: + - cdns3,usb2-phy + - cdns3,usb3-phy + + - cdns,on-chip-buff-size : size of memory intended as internal memory for endpoints + buffers expressed in KB + +Example: + usb@f3000000 { + compatible = "cdns,usb3"; + interrupts = , + , + ; + interrupt-names = "host", "peripheral", "otg"; + reg = <0xf3000000 0x10000>, /* memory area for HOST registers */ + <0xf3010000 0x10000>, /* memory area for DEVICE registers */ + <0xf3020000 0x10000>; /* memory area for OTG/DRD registers */ + reg-names = "xhci", "dev", "otg"; + phys = <&usb2_phy>, <&usb3_phy>; + phy-names = "cdns3,usb2-phy", "cnds3,usb3-phy"; + }; diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt index a254386a91ad609f8e874b7101a6599b165da6ad..cfc9f40ab641980ee7460f29924d11658f77908b 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt @@ -10,6 +10,7 @@ Required properties: "fsl,imx6sx-usb" "fsl,imx6ul-usb" "fsl,imx7d-usb" + "fsl,imx7ulp-usb" "lsi,zevio-usb" "qcom,ci-hdrc" "chipidea,usb2" diff --git a/Documentation/devicetree/bindings/usb/exynos-usb.txt b/Documentation/devicetree/bindings/usb/exynos-usb.txt index b7111f43fa5995e31fa4543e0e0770f15ddd19bb..66c394f9e11f2317653fe24c9c20b0137119eb71 100644 --- a/Documentation/devicetree/bindings/usb/exynos-usb.txt +++ b/Documentation/devicetree/bindings/usb/exynos-usb.txt @@ -12,13 +12,11 @@ Required properties: - interrupts: interrupt number to the cpu. - clocks: from common clock binding: handle to usb clock. - clock-names: from common clock binding: Shall be "usbhost". - - port: if in the SoC there are EHCI phys, they should be listed here. - One phy per port. Each port should have following entries: - - reg: port number on EHCI controller, e.g - On Exynos5250, port 0 is USB2.0 otg phy - port 1 is HSIC phy0 - port 2 is HSIC phy1 - - phys: from the *Generic PHY* bindings; specifying phy used by port. + - phys: from the *Generic PHY* bindings; array specifying phy(s) used + by the root port. + - phy-names: from the *Generic PHY* bindings; array of the names for + each phy for the root ports, must be a subset of the following: + "host", "hsic0", "hsic1". Optional properties: - samsung,vbus-gpio: if present, specifies the GPIO that @@ -35,12 +33,8 @@ Example: clocks = <&clock 285>; clock-names = "usbhost"; - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - phys = <&usb2phy 1>; - }; + phys = <&usb2phy 1>; + phy-names = "host"; }; OHCI @@ -52,13 +46,11 @@ Required properties: - interrupts: interrupt number to the cpu. - clocks: from common clock binding: handle to usb clock. - clock-names: from common clock binding: Shall be "usbhost". - - port: if in the SoC there are OHCI phys, they should be listed here. - One phy per port. Each port should have following entries: - - reg: port number on OHCI controller, e.g - On Exynos5250, port 0 is USB2.0 otg phy - port 1 is HSIC phy0 - port 2 is HSIC phy1 - - phys: from the *Generic PHY* bindings, specifying phy used by port. + - phys: from the *Generic PHY* bindings; array specifying phy(s) used + by the root port. + - phy-names: from the *Generic PHY* bindings; array of the names for + each phy for the root ports, must be a subset of the following: + "host", "hsic0", "hsic1". Example: usb@12120000 { @@ -69,13 +61,8 @@ Example: clocks = <&clock 285>; clock-names = "usbhost"; - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - phys = <&usb2phy 1>; - }; - + phys = <&usb2phy 1>; + phy-names = "host"; }; DWC3 diff --git a/Documentation/devicetree/bindings/usb/fcs,fusb302.txt b/Documentation/devicetree/bindings/usb/fcs,fusb302.txt index a5d011d2efc8eda036a2858d8261c550b1f64a02..ba2e32d500c02f7f7c68a4d1e379dd41864543df 100644 --- a/Documentation/devicetree/bindings/usb/fcs,fusb302.txt +++ b/Documentation/devicetree/bindings/usb/fcs,fusb302.txt @@ -11,13 +11,6 @@ Required sub-node: Documentation/devicetree/bindings/connector/usb-connector.txt -Deprecated properties : -- fcs,max-sink-microvolt : Maximum sink voltage accepted by port controller -- fcs,max-sink-microamp : Maximum sink current accepted by port controller -- fcs,max-sink-microwatt : Maximum sink power accepted by port controller -- fcs,operating-sink-microwatt : Minimum amount of power accepted from a sink - when negotiating - Example: diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt index 0a74ab8dfdc2f369979232e4fc90b4c660cf6b3a..cf5a1ad456e6c740def77a3cf3041ab9f10aea14 100644 --- a/Documentation/devicetree/bindings/usb/generic.txt +++ b/Documentation/devicetree/bindings/usb/generic.txt @@ -30,6 +30,10 @@ Optional properties: optional for OTG device. - adp-disable: tells OTG controllers we want to disable OTG ADP, ADP is optional for OTG device. + - usb-role-switch: boolean, indicates that the device is capable of assigning + the USB data role (USB host or USB device) for a given + USB connector, such as Type-C, Type-B(micro). + see connector/usb-connector.txt. This is an attribute to a USB controller such as: diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt index 266c2d917a2894afe8bccff05e95756d7a5b3a9a..f3e4acecabe83f4f8e438273795702439dcb216e 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt @@ -30,7 +30,8 @@ Required properties: the following ones are optional: "ref_ck": reference clock used by low power mode etc, "mcu_ck": mcu_bus clock for register access, - "dma_ck": dma_bus clock for data transfer by DMA + "dma_ck": dma_bus clock for data transfer by DMA, + "xhci_ck": controller clock - phys : see usb-hcd.txt in the current directory @@ -100,7 +101,7 @@ Required properties: - clocks : a list of phandle + clock-specifier pairs, one for each entry in clock-names - clock-names : must contain "sys_ck", and the following ones are optional: - "ref_ck", "mcu_ck" and "dma_ck" + "ref_ck", "mcu_ck" and "dma_ck", "xhci_ck" Optional properties: - vbus-supply : reference to the VBUS regulator; diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt b/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt index 3382b5cb471d748dad74c9780dff600e5a384587..b9af7f5ee91d6f7dbb73f050c4ef3af947e29d90 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt +++ b/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt @@ -16,7 +16,7 @@ Required properties: entry in clock-names - clock-names : must contain "sys_ck" for clock of controller, the following clocks are optional: - "ref_ck", "mcu_ck" and "dam_ck"; + "ref_ck", "mcu_ck" and "dma_ck"; - phys : see usb-hcd.txt in the current directory - dr_mode : should be one of "host", "peripheral" or "otg", refer to usb/generic.txt @@ -28,8 +28,13 @@ Optional properties: parent's address space - extcon : external connector for vbus and idpin changes detection, needed when supports dual-role mode. + it's considered valid for compatibility reasons, not allowed for + new bindings, and use "usb-role-switch" property instead. - vbus-supply : reference to the VBUS regulator, needed when supports dual-role mode. + it's considered valid for compatibility reasons, not allowed for + new bindings, and put into a usb-connector node. + see connector/usb-connector.txt. - pinctrl-names : a pinctrl state named "default" is optional, and need be defined if auto drd switch is enabled, that means the property dr_mode is set as "otg", and meanwhile the property "mediatek,enable-manual-drd" @@ -39,6 +44,8 @@ Optional properties: - maximum-speed : valid arguments are "super-speed", "high-speed" and "full-speed"; refer to usb/generic.txt + - usb-role-switch : use USB Role Switch to support dual-role switch, but + not extcon; see usb/generic.txt. - enable-manual-drd : supports manual dual-role switch via debugfs; usually used when receptacle is TYPE-A and also wants to support dual-role mode. @@ -61,6 +68,9 @@ The xhci should be added as subnode to mtu3 as shown in the following example if host mode is enabled. The DT binding details of xhci can be found in: Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt +The port would be added as subnode if use "usb-role-switch" property. + see graph.txt + Example: ssusb: usb@11271000 { compatible = "mediatek,mt8173-mtu3"; diff --git a/Documentation/devicetree/bindings/usb/renesas,usb3.txt b/Documentation/devicetree/bindings/usb/renesas,usb3-peri.txt similarity index 100% rename from Documentation/devicetree/bindings/usb/renesas,usb3.txt rename to Documentation/devicetree/bindings/usb/renesas,usb3-peri.txt diff --git a/Documentation/devicetree/bindings/usb/usb-conn-gpio.txt b/Documentation/devicetree/bindings/usb/usb-conn-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..3d05ae56cb0dc892f67d03ecd0c23c2c509b65dd --- /dev/null +++ b/Documentation/devicetree/bindings/usb/usb-conn-gpio.txt @@ -0,0 +1,30 @@ +USB GPIO Based Connection Detection + +This is typically used to switch dual role mode from the USB ID pin connected +to an input GPIO, and also used to enable/disable device mode from the USB +Vbus pin connected to an input GPIO. + +Required properties: +- compatible : should include "gpio-usb-b-connector" and "usb-b-connector". +- id-gpios, vbus-gpios : input gpios, either one of them must be present, + and both can be present as well. + see connector/usb-connector.txt + +Optional properties: +- vbus-supply : can be present if needed when supports dual role mode. + see connector/usb-connector.txt + +- Sub-nodes: + - port : can be present. + see graph.txt + +Example: + +&mtu3 { + connector { + compatible = "gpio-usb-b-connector", "usb-b-connector"; + type = "micro"; + id-gpios = <&pio 12 GPIO_ACTIVE_HIGH>; + vbus-supply = <&usb_p0_vbus>; + }; +}; diff --git a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt index a85a631ec434c6f1a6cf47c7e68d608e24734319..b353b9816487e6d8daeccde9d65b51eaf386e16d 100644 --- a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt +++ b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt @@ -7,6 +7,7 @@ Required properties: "fsl,vf610-usbmisc" for Vybrid vf610 "fsl,imx6sx-usbmisc" for imx6sx "fsl,imx7d-usbmisc" for imx7d + "fsl,imx7ulp-usbmisc" for imx7ulp - reg: Should contain registers location and length Examples: diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 6992bbbbffab6a57b185a244048ea9d03d60ea15..329b668dac0a4c58e37157d54dc37f9dadc5d6d9 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -27,6 +27,8 @@ patternProperties: description: Abilis Systems "^abracon,.*": description: Abracon Corporation + "^acme,.*": + description: Acme Systems srl "^actions,.*": description: Actions Semiconductor Co., Ltd. "^active-semi,.*": @@ -81,6 +83,8 @@ patternProperties: description: Analogix Semiconductor, Inc. "^andestech,.*": description: Andes Technology Corporation + "^anvo,.*": + description: Anvo-Systems Dresden GmbH "^apm,.*": description: Applied Micro Circuits Corporation (APM) "^aptina,.*": @@ -269,6 +273,8 @@ patternProperties: description: Emerging Display Technologies "^eeti,.*": description: eGalax_eMPIA Technology Inc + "^einfochips,.*": + description: Einfochips "^elan,.*": description: Elan Microelectronic Corp. "^elgin,.*": @@ -503,6 +509,8 @@ patternProperties: description: Lantiq Semiconductor "^lattice,.*": description: Lattice Semiconductor + "^leez,.*": + description: Leez "^lego,.*": description: LEGO Systems A/S "^lemaker,.*": @@ -529,6 +537,8 @@ patternProperties: description: Linear Technology Corporation "^logicpd,.*": description: Logic PD, Inc. + "^longcheer,.*": + description: Longcheer Technology (Shanghai) Co., Ltd. "^lsi,.*": description: LSI Corp. (LSI Logic) "^lwn,.*": @@ -549,6 +559,8 @@ patternProperties: description: mCube "^meas,.*": description: Measurement Specialties + "^mecer,.*": + description: Mustek Limited "^mediatek,.*": description: MediaTek Inc. "^megachips,.*": @@ -575,6 +587,8 @@ patternProperties: description: Micro Crystal AG "^micron,.*": description: Micron Technology Inc. + "^microsoft,.*": + description: Microsoft Corporation "^mikroe,.*": description: MikroElektronika d.o.o. "^miniand,.*": @@ -813,6 +827,8 @@ patternProperties: description: Semtech Corporation "^sensirion,.*": description: Sensirion AG + "^sensortek,.*": + description: Sensortek Technology Corporation "^sff,.*": description: Small Form Factor Committee "^sgd,.*": diff --git a/Documentation/devicetree/writing-schema.md b/Documentation/devicetree/writing-schema.md deleted file mode 100644 index dc032db36262791112e9e726258979244e7ab2af..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/writing-schema.md +++ /dev/null @@ -1,130 +0,0 @@ -# Writing DeviceTree Bindings in json-schema - -Devicetree bindings are written using json-schema vocabulary. Schema files are -written in a JSON compatible subset of YAML. YAML is used instead of JSON as it -considered more human readable and has some advantages such as allowing -comments (Prefixed with '#'). - -## Schema Contents - -Each schema doc is a structured json-schema which is defined by a set of -top-level properties. Generally, there is one binding defined per file. The -top-level json-schema properties used are: - -- __$id__ - A json-schema unique identifier string. The string must be a valid -URI typically containing the binding's filename and path. For DT schema, it must -begin with "http://devicetree.org/schemas/". The URL is used in constructing -references to other files specified in schema "$ref" properties. A $ref values -with a leading '/' will have the hostname prepended. A $ref value a relative -path or filename only will be prepended with the hostname and path components -of the current schema file's '$id' value. A URL is used even for local files, -but there may not actually be files present at those locations. - -- __$schema__ - Indicates the meta-schema the schema file adheres to. - -- __title__ - A one line description on the contents of the binding schema. - -- __maintainers__ - A DT specific property. Contains a list of email address(es) -for maintainers of this binding. - -- __description__ - Optional. A multi-line text block containing any detailed -information about this binding. It should contain things such as what the block -or device does, standards the device conforms to, and links to datasheets for -more information. - -- __select__ - Optional. A json-schema used to match nodes for applying the -schema. By default without 'select', nodes are matched against their possible -compatible string values or node name. Most bindings should not need select. - -- __allOf__ - Optional. A list of other schemas to include. This is used to -include other schemas the binding conforms to. This may be schemas for a -particular class of devices such as I2C or SPI controllers. - -- __properties__ - A set of sub-schema defining all the DT properties for the -binding. The exact schema syntax depends on whether properties are known, -common properties (e.g. 'interrupts') or are binding/vendor specific properties. - - A property can also define a child DT node with child properties defined -under it. - - For more details on properties sections, see 'Property Schema' section. - -- __patternProperties__ - Optional. Similar to 'properties', but names are regex. - -- __required__ - A list of DT properties from the 'properties' section that -must always be present. - -- __examples__ - Optional. A list of one or more DTS hunks implementing the -binding. Note: YAML doesn't allow leading tabs, so spaces must be used instead. - -Unless noted otherwise, all properties are required. - -## Property Schema - -The 'properties' section of the schema contains all the DT properties for a -binding. Each property contains a set of constraints using json-schema -vocabulary for that property. The properties schemas are what is used for -validation of DT files. - -For common properties, only additional constraints not covered by the common -binding schema need to be defined such as how many values are valid or what -possible values are valid. - -Vendor specific properties will typically need more detailed schema. With the -exception of boolean properties, they should have a reference to a type in -schemas/types.yaml. A "description" property is always required. - -The Devicetree schemas don't exactly match the YAML encoded DT data produced by -dtc. They are simplified to make them more compact and avoid a bunch of -boilerplate. The tools process the schema files to produce the final schema for -validation. There are currently 2 transformations the tools perform. - -The default for arrays in json-schema is they are variable sized and allow more -entries than explicitly defined. This can be restricted by defining 'minItems', -'maxItems', and 'additionalItems'. However, for DeviceTree Schemas, a fixed -size is desired in most cases, so these properties are added based on the -number of entries in an 'items' list. - -The YAML Devicetree format also makes all string values an array and scalar -values a matrix (in order to define groupings) even when only a single value -is present. Single entries in schemas are fixed up to match this encoding. - -## Testing - -### Dependencies - -The DT schema project must be installed in order to validate the DT schema -binding documents and validate DTS files using the DT schema. The DT schema -project can be installed with pip: - -`pip3 install git+https://github.com/devicetree-org/dt-schema.git@master` - -dtc must also be built with YAML output support enabled. This requires that -libyaml and its headers be installed on the host system. - -### Running checks - -The DT schema binding documents must be validated using the meta-schema (the -schema for the schema) to ensure they are both valid json-schema and valid -binding schema. All of the DT binding documents can be validated using the -`dt_binding_check` target: - -`make dt_binding_check` - -In order to perform validation of DT source files, use the `dtbs_check` target: - -`make dtbs_check` - -This will first run the `dt_binding_check` which generates the processed schema. - -It is also possible to run checks with a single schema file by setting the -'DT_SCHEMA_FILES' variable to a specific schema file. - -`make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/trivial-devices.yaml` - - -## json-schema Resources - -[JSON-Schema Specifications](http://json-schema.org/) - -[Using JSON Schema Book](http://usingjsonschema.com/) diff --git a/Documentation/devicetree/writing-schema.rst b/Documentation/devicetree/writing-schema.rst new file mode 100644 index 0000000000000000000000000000000000000000..8f71d1e2ac5242eb32ca150c93cbcc2d741a7475 --- /dev/null +++ b/Documentation/devicetree/writing-schema.rst @@ -0,0 +1,153 @@ +:orphan: + +Writing DeviceTree Bindings in json-schema +========================================== + +Devicetree bindings are written using json-schema vocabulary. Schema files are +written in a JSON compatible subset of YAML. YAML is used instead of JSON as it +considered more human readable and has some advantages such as allowing +comments (Prefixed with '#'). + +Schema Contents +--------------- + +Each schema doc is a structured json-schema which is defined by a set of +top-level properties. Generally, there is one binding defined per file. The +top-level json-schema properties used are: + +$id + A json-schema unique identifier string. The string must be a valid + URI typically containing the binding's filename and path. For DT schema, it must + begin with "http://devicetree.org/schemas/". The URL is used in constructing + references to other files specified in schema "$ref" properties. A $ref values + with a leading '/' will have the hostname prepended. A $ref value a relative + path or filename only will be prepended with the hostname and path components + of the current schema file's '$id' value. A URL is used even for local files, + but there may not actually be files present at those locations. + +$schema + Indicates the meta-schema the schema file adheres to. + +title + A one line description on the contents of the binding schema. + +maintainers + A DT specific property. Contains a list of email address(es) + for maintainers of this binding. + +description + Optional. A multi-line text block containing any detailed + information about this binding. It should contain things such as what the block + or device does, standards the device conforms to, and links to datasheets for + more information. + +select + Optional. A json-schema used to match nodes for applying the + schema. By default without 'select', nodes are matched against their possible + compatible string values or node name. Most bindings should not need select. + + allOf + Optional. A list of other schemas to include. This is used to + include other schemas the binding conforms to. This may be schemas for a + particular class of devices such as I2C or SPI controllers. + + properties + A set of sub-schema defining all the DT properties for the + binding. The exact schema syntax depends on whether properties are known, + common properties (e.g. 'interrupts') or are binding/vendor specific properties. + +A property can also define a child DT node with child properties defined +under it. + +For more details on properties sections, see 'Property Schema' section. + +patternProperties + Optional. Similar to 'properties', but names are regex. + +required + A list of DT properties from the 'properties' section that + must always be present. + +examples + Optional. A list of one or more DTS hunks implementing the + binding. Note: YAML doesn't allow leading tabs, so spaces must be used instead. + +Unless noted otherwise, all properties are required. + +Property Schema +--------------- + +The 'properties' section of the schema contains all the DT properties for a +binding. Each property contains a set of constraints using json-schema +vocabulary for that property. The properties schemas are what is used for +validation of DT files. + +For common properties, only additional constraints not covered by the common +binding schema need to be defined such as how many values are valid or what +possible values are valid. + +Vendor specific properties will typically need more detailed schema. With the +exception of boolean properties, they should have a reference to a type in +schemas/types.yaml. A "description" property is always required. + +The Devicetree schemas don't exactly match the YAML encoded DT data produced by +dtc. They are simplified to make them more compact and avoid a bunch of +boilerplate. The tools process the schema files to produce the final schema for +validation. There are currently 2 transformations the tools perform. + +The default for arrays in json-schema is they are variable sized and allow more +entries than explicitly defined. This can be restricted by defining 'minItems', +'maxItems', and 'additionalItems'. However, for DeviceTree Schemas, a fixed +size is desired in most cases, so these properties are added based on the +number of entries in an 'items' list. + +The YAML Devicetree format also makes all string values an array and scalar +values a matrix (in order to define groupings) even when only a single value +is present. Single entries in schemas are fixed up to match this encoding. + +Testing +------- + +Dependencies +~~~~~~~~~~~~ + +The DT schema project must be installed in order to validate the DT schema +binding documents and validate DTS files using the DT schema. The DT schema +project can be installed with pip:: + + pip3 install git+https://github.com/devicetree-org/dt-schema.git@master + +dtc must also be built with YAML output support enabled. This requires that +libyaml and its headers be installed on the host system. + +Running checks +~~~~~~~~~~~~~~ + +The DT schema binding documents must be validated using the meta-schema (the +schema for the schema) to ensure they are both valid json-schema and valid +binding schema. All of the DT binding documents can be validated using the +``dt_binding_check`` target:: + + make dt_binding_check + +In order to perform validation of DT source files, use the `dtbs_check` target:: + + make dtbs_check + +This will first run the `dt_binding_check` which generates the processed schema. + +It is also possible to run checks with a single schema file by setting the +``DT_SCHEMA_FILES`` variable to a specific schema file. + +:: + + make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/trivial-devices.yaml + + +json-schema Resources +--------------------- + + +`JSON-Schema Specifications `_ + +`Using JSON Schema Book `_ diff --git a/Documentation/driver-api/device_link.rst b/Documentation/driver-api/device_link.rst index ae1e3d0394b091be307d1b08de55a982c1054421..1b5020ec6517b06ae01e0f57db976bc41ce81d5b 100644 --- a/Documentation/driver-api/device_link.rst +++ b/Documentation/driver-api/device_link.rst @@ -78,8 +78,8 @@ typically deleted in its ``->remove`` callback for symmetry. That way, if the driver is compiled as a module, the device link is added on module load and orderly deleted on unload. The same restrictions that apply to device link addition (e.g. exclusion of a parallel suspend/resume transition) apply equally -to deletion. Device links with ``DL_FLAG_STATELESS`` unset (i.e. managed -device links) are deleted automatically by the driver core. +to deletion. Device links managed by the driver core are deleted automatically +by it. Several flags may be specified on device link addition, two of which have already been mentioned above: ``DL_FLAG_STATELESS`` to express that no diff --git a/Documentation/driver-api/dmaengine/index.rst b/Documentation/driver-api/dmaengine/index.rst index 3026fa975937e63ab854ed8b2e625db501bff562..b9df904d0a79dc67ada7418ec50dc933b8ba7ccb 100644 --- a/Documentation/driver-api/dmaengine/index.rst +++ b/Documentation/driver-api/dmaengine/index.rst @@ -47,7 +47,7 @@ This book adds some notes about PXA DMA pxa_dma -.. only:: subproject +.. only:: subproject and html Indices ======= diff --git a/Documentation/driver-api/gpio/driver.rst b/Documentation/driver-api/gpio/driver.rst index 921c71a3d6839234b04f84d072c3aa1129dd4cdc..3fdb32422f8ac11d9459f7237f9616e22b4468ea 100644 --- a/Documentation/driver-api/gpio/driver.rst +++ b/Documentation/driver-api/gpio/driver.rst @@ -69,9 +69,9 @@ driver code: The code implementing a gpio_chip should support multiple instances of the controller, preferably using the driver model. That code will configure each -gpio_chip and issue ``gpiochip_add[_data]()`` or ``devm_gpiochip_add_data()``. -Removing a GPIO controller should be rare; use ``[devm_]gpiochip_remove()`` -when it is unavoidable. +gpio_chip and issue gpiochip_add(), gpiochip_add_data(), or +devm_gpiochip_add_data(). Removing a GPIO controller should be rare; use +gpiochip_remove() when it is unavoidable. Often a gpio_chip is part of an instance-specific structure with states not exposed by the GPIO interfaces, such as addressing, power management, and more. @@ -259,7 +259,7 @@ most often cascaded off a parent interrupt controller, and in some special cases the GPIO logic is melded with a SoC's primary interrupt controller. The IRQ portions of the GPIO block are implemented using an irq_chip, using -the header . So basically such a driver is utilizing two sub- +the header . So this combined driver is utilizing two sub- systems simultaneously: gpio and irq. It is legal for any IRQ consumer to request an IRQ from any irqchip even if it @@ -391,25 +391,119 @@ Infrastructure helpers for GPIO irqchips ---------------------------------------- To help out in handling the set-up and management of GPIO irqchips and the -associated irqdomain and resource allocation callbacks, the gpiolib has -some helpers that can be enabled by selecting the GPIOLIB_IRQCHIP Kconfig -symbol: - -- gpiochip_irqchip_add(): adds a chained cascaded irqchip to a gpiochip. It - will pass the struct gpio_chip* for the chip to all IRQ callbacks, so the - callbacks need to embed the gpio_chip in its state container and obtain a - pointer to the container using container_of(). - (See Documentation/driver-api/driver-model/design-patterns.rst) +associated irqdomain and resource allocation callbacks. These are activated +by selecting the Kconfig symbol GPIOLIB_IRQCHIP. If the symbol +IRQ_DOMAIN_HIERARCHY is also selected, hierarchical helpers will also be +provided. A big portion of overhead code will be managed by gpiolib, +under the assumption that your interrupts are 1-to-1-mapped to the +GPIO line index: + + GPIO line offset Hardware IRQ + 0 0 + 1 1 + 2 2 + ... ... + ngpio-1 ngpio-1 + +If some GPIO lines do not have corresponding IRQs, the bitmask valid_mask +and the flag need_valid_mask in gpio_irq_chip can be used to mask off some +lines as invalid for associating with IRQs. + +The preferred way to set up the helpers is to fill in the +struct gpio_irq_chip inside struct gpio_chip before adding the gpio_chip. +If you do this, the additional irq_chip will be set up by gpiolib at the +same time as setting up the rest of the GPIO functionality. The following +is a typical example of a cascaded interrupt handler using gpio_irq_chip: + + /* Typical state container with dynamic irqchip */ + struct my_gpio { + struct gpio_chip gc; + struct irq_chip irq; + }; + + int irq; /* from platform etc */ + struct my_gpio *g; + struct gpio_irq_chip *girq; + + /* Set up the irqchip dynamically */ + g->irq.name = "my_gpio_irq"; + g->irq.irq_ack = my_gpio_ack_irq; + g->irq.irq_mask = my_gpio_mask_irq; + g->irq.irq_unmask = my_gpio_unmask_irq; + g->irq.irq_set_type = my_gpio_set_irq_type; + + /* Get a pointer to the gpio_irq_chip */ + girq = &g->gc.irq; + girq->chip = &g->irq; + girq->parent_handler = ftgpio_gpio_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + girq->parents[0] = irq; + + return devm_gpiochip_add_data(dev, &g->gc, g); + +The helper support using hierarchical interrupt controllers as well. +In this case the typical set-up will look like this: + + /* Typical state container with dynamic irqchip */ + struct my_gpio { + struct gpio_chip gc; + struct irq_chip irq; + struct fwnode_handle *fwnode; + }; + + int irq; /* from platform etc */ + struct my_gpio *g; + struct gpio_irq_chip *girq; + + /* Set up the irqchip dynamically */ + g->irq.name = "my_gpio_irq"; + g->irq.irq_ack = my_gpio_ack_irq; + g->irq.irq_mask = my_gpio_mask_irq; + g->irq.irq_unmask = my_gpio_unmask_irq; + g->irq.irq_set_type = my_gpio_set_irq_type; + + /* Get a pointer to the gpio_irq_chip */ + girq = &g->gc.irq; + girq->chip = &g->irq; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + girq->fwnode = g->fwnode; + girq->parent_domain = parent; + girq->child_to_parent_hwirq = my_gpio_child_to_parent_hwirq; + + return devm_gpiochip_add_data(dev, &g->gc, g); + +As you can see pretty similar, but you do not supply a parent handler for +the IRQ, instead a parent irqdomain, an fwnode for the hardware and +a funcion .child_to_parent_hwirq() that has the purpose of looking up +the parent hardware irq from a child (i.e. this gpio chip) hardware irq. +As always it is good to look at examples in the kernel tree for advice +on how to find the required pieces. + +The old way of adding irqchips to gpiochips after registration is also still +available but we try to move away from this: + +- DEPRECATED: gpiochip_irqchip_add(): adds a chained cascaded irqchip to a + gpiochip. It will pass the struct gpio_chip* for the chip to all IRQ + callbacks, so the callbacks need to embed the gpio_chip in its state + container and obtain a pointer to the container using container_of(). + (See Documentation/driver-model/design-patterns.txt) - gpiochip_irqchip_add_nested(): adds a nested cascaded irqchip to a gpiochip, as discussed above regarding different types of cascaded irqchips. The cascaded irq has to be handled by a threaded interrupt handler. Apart from that it works exactly like the chained irqchip. -- gpiochip_set_chained_irqchip(): sets up a chained cascaded irq handler for a - gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler - data. Notice that we pass is as the handler data, since the irqchip data is - likely used by the parent irqchip. +- DEPRECATED: gpiochip_set_chained_irqchip(): sets up a chained cascaded irq + handler for a gpio_chip from a parent IRQ and passes the struct gpio_chip* + as handler data. Notice that we pass is as the handler data, since the + irqchip data is likely used by the parent irqchip. - gpiochip_set_nested_irqchip(): sets up a nested cascaded irq handler for a gpio_chip from a parent IRQ. As the parent IRQ has usually been @@ -418,11 +512,11 @@ symbol: If there is a need to exclude certain GPIO lines from the IRQ domain handled by these helpers, we can set .irq.need_valid_mask of the gpiochip before -``[devm_]gpiochip_add_data()`` is called. This allocates an .irq.valid_mask with as -many bits set as there are GPIO lines in the chip, each bit representing line -0..n-1. Drivers can exclude GPIO lines by clearing bits from this mask. The mask -must be filled in before gpiochip_irqchip_add() or gpiochip_irqchip_add_nested() -is called. +devm_gpiochip_add_data() or gpiochip_add_data() is called. This allocates an +.irq.valid_mask with as many bits set as there are GPIO lines in the chip, each +bit representing line 0..n-1. Drivers can exclude GPIO lines by clearing bits +from this mask. The mask must be filled in before gpiochip_irqchip_add() or +gpiochip_irqchip_add_nested() is called. To use the helpers please keep the following in mind: diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst index d12a80f386a656d97553940f15c91c06baf20f6b..38e638abe3ebcee44d990bb74da7089a6421b1fc 100644 --- a/Documentation/driver-api/index.rst +++ b/Documentation/driver-api/index.rst @@ -65,6 +65,7 @@ available subsections can be seen below. dmaengine/index slimbus soundwire/index + thermal/index fpga/index acpi/index backlight/lp855x-driver.rst @@ -75,6 +76,7 @@ available subsections can be seen below. dell_rbu edid eisa + ipmb isa isapnp generic-counter diff --git a/Documentation/driver-api/ipmb.rst b/Documentation/driver-api/ipmb.rst index 7e2265144157c111b496294327443d19f9b796b7..3ec3baed84c4490a724e4aef92f098664e689913 100644 --- a/Documentation/driver-api/ipmb.rst +++ b/Documentation/driver-api/ipmb.rst @@ -83,7 +83,7 @@ Instantiate the device ---------------------- After loading the driver, you can instantiate the device as -described in 'Documentation/i2c/instantiating-devices'. +described in 'Documentation/i2c/instantiating-devices.rst'. If you have multiple BMCs, each connected to your Satellite MC via a different I2C bus, you can instantiate a device for each of those BMCs. diff --git a/Documentation/driver-api/mtd/spi-nor.rst b/Documentation/driver-api/mtd/spi-nor.rst index f5333e3bf486490aa50d752b3ee16785500f2e93..1f0437676762b991b141efa51343e81e09955d0c 100644 --- a/Documentation/driver-api/mtd/spi-nor.rst +++ b/Documentation/driver-api/mtd/spi-nor.rst @@ -59,7 +59,7 @@ Part III - How can drivers use the framework? The main API is spi_nor_scan(). Before you call the hook, a driver should initialize the necessary fields for spi_nor{}. Please see -drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to fsl-quadspi.c +drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to spi-fsl-qspi.c when you want to write a new driver for a SPI NOR controller. Another API is spi_nor_restore(), this is used to restore the status of SPI flash chip such as addressing mode. Call it whenever detach the driver from diff --git a/Documentation/driver-api/serial/n_gsm.rst b/Documentation/driver-api/serial/n_gsm.rst index f3ad9fd26408c3d19512216181df29124df936c1..286e7ff4d2d9e38ca244f5dceb57cad53be6caf7 100644 --- a/Documentation/driver-api/serial/n_gsm.rst +++ b/Documentation/driver-api/serial/n_gsm.rst @@ -18,18 +18,22 @@ How to use it 2. switch the serial line to using the n_gsm line discipline by using TIOCSETD ioctl, 3. configure the mux using GSMIOC_GETCONF / GSMIOC_SETCONF ioctl, +4. obtain base gsmtty number for the used serial port, Major parts of the initialization program : (a good starting point is util-linux-ng/sys-utils/ldattach.c):: + #include + #include #include - #define N_GSM0710 21 /* GSM 0710 Mux */ + #include #define DEFAULT_SPEED B115200 #define SERIAL_PORT /dev/ttyS0 int ldisc = N_GSM0710; struct gsm_config c; struct termios configuration; + uint32_t first; /* open the serial port connected to the modem */ fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY); @@ -58,21 +62,14 @@ Major parts of the initialization program : c.mtu = 127; /* set the new configuration */ ioctl(fd, GSMIOC_SETCONF, &c); + /* get first gsmtty device node */ + ioctl(fd, GSMIOC_GETFIRST, &first); + printf("first muxed line: /dev/gsmtty%i\n", first); /* and wait for ever to keep the line discipline enabled */ daemon(0,0); pause(); -4. create the devices corresponding to the "virtual" serial ports (take care, - each modem has its configuration and some DLC have dedicated functions, - for example GPS), starting with minor 1 (DLC0 is reserved for the management - of the mux):: - - MAJOR=`cat /proc/devices |grep gsmtty | awk '{print $1}` - for i in `seq 1 4`; do - mknod /dev/ttygsm$i c $MAJOR $i - done - 5. use these devices as plain serial ports. for example, it's possible: diff --git a/Documentation/driver-api/sgi-ioc4.rst b/Documentation/driver-api/sgi-ioc4.rst deleted file mode 100644 index 72709222d3c0f3983a4d55239df608622f5fcb7a..0000000000000000000000000000000000000000 --- a/Documentation/driver-api/sgi-ioc4.rst +++ /dev/null @@ -1,49 +0,0 @@ -==================================== -SGI IOC4 PCI (multi function) device -==================================== - -The SGI IOC4 PCI device is a bit of a strange beast, so some notes on -it are in order. - -First, even though the IOC4 performs multiple functions, such as an -IDE controller, a serial controller, a PS/2 keyboard/mouse controller, -and an external interrupt mechanism, it's not implemented as a -multifunction device. The consequence of this from a software -standpoint is that all these functions share a single IRQ, and -they can't all register to own the same PCI device ID. To make -matters a bit worse, some of the register blocks (and even registers -themselves) present in IOC4 are mixed-purpose between these several -functions, meaning that there's no clear "owning" device driver. - -The solution is to organize the IOC4 driver into several independent -drivers, "ioc4", "sgiioc4", and "ioc4_serial". Note that there is no -PS/2 controller driver as this functionality has never been wired up -on a shipping IO card. - -ioc4 -==== -This is the core (or shim) driver for IOC4. It is responsible for -initializing the basic functionality of the chip, and allocating -the PCI resources that are shared between the IOC4 functions. - -This driver also provides registration functions that the other -IOC4 drivers can call to make their presence known. Each driver -needs to provide a probe and remove function, which are invoked -by the core driver at appropriate times. The interface of these -IOC4 function probe and remove operations isn't precisely the same -as PCI device probe and remove operations, but is logically the -same operation. - -sgiioc4 -======= -This is the IDE driver for IOC4. Its name isn't very descriptive -simply for historical reasons (it used to be the only IOC4 driver -component). There's not much to say about it other than it hooks -up to the ioc4 driver via the appropriate registration, probe, and -remove functions. - -ioc4_serial -=========== -This is the serial driver for IOC4. There's not much to say about it -other than it hooks up to the ioc4 driver via the appropriate registration, -probe, and remove functions. diff --git a/Documentation/driver-api/soundwire/index.rst b/Documentation/driver-api/soundwire/index.rst index 6db026028f273b27dfe2a78253e78eaa4180c8b6..234911a0db9905039a6764df1fbda50c055892ce 100644 --- a/Documentation/driver-api/soundwire/index.rst +++ b/Documentation/driver-api/soundwire/index.rst @@ -10,7 +10,7 @@ SoundWire Documentation error_handling locking -.. only:: subproject +.. only:: subproject and html Indices ======= diff --git a/Documentation/thermal/cpu-cooling-api.rst b/Documentation/driver-api/thermal/cpu-cooling-api.rst similarity index 100% rename from Documentation/thermal/cpu-cooling-api.rst rename to Documentation/driver-api/thermal/cpu-cooling-api.rst diff --git a/Documentation/thermal/exynos_thermal.rst b/Documentation/driver-api/thermal/exynos_thermal.rst similarity index 100% rename from Documentation/thermal/exynos_thermal.rst rename to Documentation/driver-api/thermal/exynos_thermal.rst diff --git a/Documentation/thermal/exynos_thermal_emulation.rst b/Documentation/driver-api/thermal/exynos_thermal_emulation.rst similarity index 100% rename from Documentation/thermal/exynos_thermal_emulation.rst rename to Documentation/driver-api/thermal/exynos_thermal_emulation.rst diff --git a/Documentation/thermal/index.rst b/Documentation/driver-api/thermal/index.rst similarity index 86% rename from Documentation/thermal/index.rst rename to Documentation/driver-api/thermal/index.rst index 8c1c00146cad6cf390962184f49906c1d5646e62..5ba61d19c6aebd738b05a62af3044cb479e328e7 100644 --- a/Documentation/thermal/index.rst +++ b/Documentation/driver-api/thermal/index.rst @@ -1,4 +1,4 @@ -:orphan: +.. SPDX-License-Identifier: GPL-2.0 ======= Thermal diff --git a/Documentation/thermal/intel_powerclamp.rst b/Documentation/driver-api/thermal/intel_powerclamp.rst similarity index 100% rename from Documentation/thermal/intel_powerclamp.rst rename to Documentation/driver-api/thermal/intel_powerclamp.rst diff --git a/Documentation/thermal/nouveau_thermal.rst b/Documentation/driver-api/thermal/nouveau_thermal.rst similarity index 100% rename from Documentation/thermal/nouveau_thermal.rst rename to Documentation/driver-api/thermal/nouveau_thermal.rst diff --git a/Documentation/thermal/power_allocator.rst b/Documentation/driver-api/thermal/power_allocator.rst similarity index 100% rename from Documentation/thermal/power_allocator.rst rename to Documentation/driver-api/thermal/power_allocator.rst diff --git a/Documentation/thermal/sysfs-api.rst b/Documentation/driver-api/thermal/sysfs-api.rst similarity index 98% rename from Documentation/thermal/sysfs-api.rst rename to Documentation/driver-api/thermal/sysfs-api.rst index e4930761d3e532ac1e2402b4fb1c74f4ab1463f3..fab2c9b36d084fd00020fee8f7c97a98b084b70c 100644 --- a/Documentation/thermal/sysfs-api.rst +++ b/Documentation/driver-api/thermal/sysfs-api.rst @@ -552,7 +552,7 @@ emul_temp sustainable_power An estimate of the sustained power that can be dissipated by the thermal zone. Used by the power allocator governor. For - more information see Documentation/thermal/power_allocator.rst + more information see Documentation/driver-api/thermal/power_allocator.rst Unit: milliwatts @@ -563,7 +563,7 @@ k_po controller during temperature overshoot. Temperature overshoot is when the current temperature is above the "desired temperature" trip point. For more information see - Documentation/thermal/power_allocator.rst + Documentation/driver-api/thermal/power_allocator.rst RW, Optional @@ -572,7 +572,7 @@ k_pu controller during temperature undershoot. Temperature undershoot is when the current temperature is below the "desired temperature" trip point. For more information see - Documentation/thermal/power_allocator.rst + Documentation/driver-api/thermal/power_allocator.rst RW, Optional @@ -580,14 +580,14 @@ k_i The integral term of the power allocator governor's PID controller. This term allows the PID controller to compensate for long term drift. For more information see - Documentation/thermal/power_allocator.rst + Documentation/driver-api/thermal/power_allocator.rst RW, Optional k_d The derivative term of the power allocator governor's PID controller. For more information see - Documentation/thermal/power_allocator.rst + Documentation/driver-api/thermal/power_allocator.rst RW, Optional @@ -598,7 +598,7 @@ integral_cutoff example, if integral_cutoff is 0, then the integral term only accumulates error when temperature is above the desired temperature trip point. For more information see - Documentation/thermal/power_allocator.rst + Documentation/driver-api/thermal/power_allocator.rst Unit: millidegree Celsius diff --git a/Documentation/thermal/x86_pkg_temperature_thermal.rst b/Documentation/driver-api/thermal/x86_pkg_temperature_thermal.rst similarity index 94% rename from Documentation/thermal/x86_pkg_temperature_thermal.rst rename to Documentation/driver-api/thermal/x86_pkg_temperature_thermal.rst index f134dbd3f5a97d513692ee3b908070dfac7c7711..2ac42ccd236f6b384c26a8fbe5ccc08e9e1b4000 100644 --- a/Documentation/thermal/x86_pkg_temperature_thermal.rst +++ b/Documentation/driver-api/thermal/x86_pkg_temperature_thermal.rst @@ -40,7 +40,7 @@ This contains two trip points: - trip_point_1_temp User can set any temperature between 0 to TJ-Max temperature. Temperature units -are in milli-degree Celsius. Refer to "Documentation/thermal/sysfs-api.rst" for +are in milli-degree Celsius. Refer to "Documentation/driver-api/thermal/sysfs-api.rst" for thermal sys-fs details. Any value other than 0 in these trip points, can trigger thermal notifications. diff --git a/Documentation/driver-api/uio-howto.rst b/Documentation/driver-api/uio-howto.rst index 8fecfa11d4ff9074f940dcbcb5dc2b78d5e4a543..84091cd25dc4b3737db1906ba19afafc60c99d3a 100644 --- a/Documentation/driver-api/uio-howto.rst +++ b/Documentation/driver-api/uio-howto.rst @@ -408,6 +408,13 @@ handler code. You also do not need to know anything about the chip's internal registers to create the kernel part of the driver. All you need to know is the irq number of the pin the chip is connected to. +When used in a device-tree enabled system, the driver needs to be +probed with the ``"of_id"`` module parameter set to the ``"compatible"`` +string of the node the driver is supposed to handle. By default, the +node's name (without the unit address) is exposed as name for the +UIO device in userspace. To set a custom name, a property named +``"linux,uio-name"`` may be specified in the DT node. + Using uio_dmem_genirq for platform devices ------------------------------------------ diff --git a/Documentation/features/core/jump-labels/arch-support.txt b/Documentation/features/core/jump-labels/arch-support.txt index 7fc2e243dee9a37296667ea9bb9bf223f9d590cc..cae7be2f772502211dffdb6f69bc57f71c4bf1d9 100644 --- a/Documentation/features/core/jump-labels/arch-support.txt +++ b/Documentation/features/core/jump-labels/arch-support.txt @@ -21,7 +21,7 @@ | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | - | parisc: | TODO | + | parisc: | ok | | powerpc: | ok | | riscv: | TODO | | s390: | ok | diff --git a/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt b/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt index 68f266944d5fce3aecd8a85e7e3f5717bdfba778..4fae0464ddff27807da70c2fcc664fa2ba8f8680 100644 --- a/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt +++ b/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt @@ -21,7 +21,7 @@ | nds32: | TODO | | nios2: | TODO | | openrisc: | TODO | - | parisc: | TODO | + | parisc: | ok | | powerpc: | ok | | riscv: | TODO | | s390: | TODO | diff --git a/Documentation/features/locking/queued-rwlocks/arch-support.txt b/Documentation/features/locking/queued-rwlocks/arch-support.txt index c683da198f31930fc0556be6b71886ee8b64cdfa..ee922746a64c5ca0a14395d726308105dbe9e52b 100644 --- a/Documentation/features/locking/queued-rwlocks/arch-support.txt +++ b/Documentation/features/locking/queued-rwlocks/arch-support.txt @@ -30,5 +30,5 @@ | um: | TODO | | unicore32: | TODO | | x86: | ok | - | xtensa: | TODO | + | xtensa: | ok | ----------------------- diff --git a/Documentation/features/locking/queued-spinlocks/arch-support.txt b/Documentation/features/locking/queued-spinlocks/arch-support.txt index e3080b82aefd65fccacbac3caaff835e2a782370..c52116c1a0495d110de61069404dc3987bf1eed1 100644 --- a/Documentation/features/locking/queued-spinlocks/arch-support.txt +++ b/Documentation/features/locking/queued-spinlocks/arch-support.txt @@ -9,7 +9,7 @@ | alpha: | TODO | | arc: | TODO | | arm: | TODO | - | arm64: | TODO | + | arm64: | ok | | c6x: | TODO | | csky: | TODO | | h8300: | TODO | @@ -30,5 +30,5 @@ | um: | TODO | | unicore32: | TODO | | x86: | ok | - | xtensa: | TODO | + | xtensa: | ok | ----------------------- diff --git a/Documentation/features/locking/rwsem-optimized/arch-support.txt b/Documentation/features/locking/rwsem-optimized/arch-support.txt deleted file mode 100644 index 7521d7500fbea2c02decfdba2ef4125ec1b16825..0000000000000000000000000000000000000000 --- a/Documentation/features/locking/rwsem-optimized/arch-support.txt +++ /dev/null @@ -1,34 +0,0 @@ -# -# Feature name: rwsem-optimized -# Kconfig: !RWSEM_GENERIC_SPINLOCK -# description: arch provides optimized rwsem APIs -# - ----------------------- - | arch |status| - ----------------------- - | alpha: | ok | - | arc: | TODO | - | arm: | ok | - | arm64: | ok | - | c6x: | TODO | - | csky: | TODO | - | h8300: | TODO | - | hexagon: | TODO | - | ia64: | ok | - | m68k: | TODO | - | microblaze: | TODO | - | mips: | TODO | - | nds32: | TODO | - | nios2: | TODO | - | openrisc: | TODO | - | parisc: | TODO | - | powerpc: | TODO | - | riscv: | TODO | - | s390: | ok | - | sh: | ok | - | sparc: | ok | - | um: | ok | - | unicore32: | TODO | - | x86: | ok | - | xtensa: | ok | - ----------------------- diff --git a/Documentation/filesystems/coda.txt b/Documentation/filesystems/coda.txt index 545262c167c33f2e1c9f28e4bf86be28c12f2264..1711ad48e38a694c0c0738f21b89f52db60998c4 100644 --- a/Documentation/filesystems/coda.txt +++ b/Documentation/filesystems/coda.txt @@ -421,14 +421,14 @@ kernel support. The CodaCred structure defines a variety of user and group ids as - they are set for the calling process. The vuid_t and guid_t are 32 bit + they are set for the calling process. The vuid_t and vgid_t are 32 bit unsigned integers. It also defines group membership in an array. On Unix the CodaCred has proven sufficient to implement good security semantics for Coda but the structure may have to undergo modification for the Windows environment when these mature. struct CodaCred { - vuid_t cr_uid, cr_euid, cr_suid, cr_fsuid; /* Real, effective, set, fs uid*/ + vuid_t cr_uid, cr_euid, cr_suid, cr_fsuid; /* Real, effective, set, fs uid */ vgid_t cr_gid, cr_egid, cr_sgid, cr_fsgid; /* same for groups */ vgid_t cr_groups[NGROUPS]; /* Group membership for caller */ }; diff --git a/Documentation/filesystems/directory-locking b/Documentation/filesystems/directory-locking.rst similarity index 86% rename from Documentation/filesystems/directory-locking rename to Documentation/filesystems/directory-locking.rst index 4e32cb961e5b7ff60f0abf3864702e01008a5aa2..de12016ee4198964141da824be50fdac78838646 100644 --- a/Documentation/filesystems/directory-locking +++ b/Documentation/filesystems/directory-locking.rst @@ -1,12 +1,17 @@ - Locking scheme used for directory operations is based on two +================= +Directory Locking +================= + + +Locking scheme used for directory operations is based on two kinds of locks - per-inode (->i_rwsem) and per-filesystem (->s_vfs_rename_mutex). - When taking the i_rwsem on multiple non-directory objects, we +When taking the i_rwsem on multiple non-directory objects, we always acquire the locks in order by increasing address. We'll call that "inode pointer" order in the following. - For our purposes all operations fall in 5 classes: +For our purposes all operations fall in 5 classes: 1) read access. Locking rules: caller locks directory we are accessing. The lock is taken shared. @@ -27,25 +32,29 @@ NB: we might get away with locking the the source (and target in exchange case) shared. 5) link creation. Locking rules: + * lock parent * check that source is not a directory * lock source * call the method. + All locks are exclusive. 6) cross-directory rename. The trickiest in the whole bunch. Locking rules: + * lock the filesystem * lock parents in "ancestors first" order. * find source and target. * if old parent is equal to or is a descendent of target - fail with -ENOTEMPTY + fail with -ENOTEMPTY * if new parent is equal to or is a descendent of source - fail with -ELOOP + fail with -ELOOP * If it's an exchange, lock both the source and the target. * If the target exists, lock it. If the source is a non-directory, lock it. If we need to lock both, do so in inode pointer order. * call the method. + All ->i_rwsem are taken exclusive. Again, we might get away with locking the the source (and target in exchange case) shared. @@ -54,10 +63,11 @@ read, modified or removed by method will be locked by caller. If no directory is its own ancestor, the scheme above is deadlock-free. + Proof: First of all, at any moment we have a partial ordering of the -objects - A < B iff A is an ancestor of B. + objects - A < B iff A is an ancestor of B. That ordering can change. However, the following is true: @@ -77,32 +87,32 @@ objects - A < B iff A is an ancestor of B. non-directory object, except renames, which take locks on source and target in inode pointer order in the case they are not directories.) - Now consider the minimal deadlock. Each process is blocked on +Now consider the minimal deadlock. Each process is blocked on attempt to acquire some lock and already holds at least one lock. Let's consider the set of contended locks. First of all, filesystem lock is not contended, since any process blocked on it is not holding any locks. Thus all processes are blocked on ->i_rwsem. - By (3), any process holding a non-directory lock can only be +By (3), any process holding a non-directory lock can only be waiting on another non-directory lock with a larger address. Therefore the process holding the "largest" such lock can always make progress, and non-directory objects are not included in the set of contended locks. - Thus link creation can't be a part of deadlock - it can't be +Thus link creation can't be a part of deadlock - it can't be blocked on source and it means that it doesn't hold any locks. - Any contended object is either held by cross-directory rename or +Any contended object is either held by cross-directory rename or has a child that is also contended. Indeed, suppose that it is held by operation other than cross-directory rename. Then the lock this operation is blocked on belongs to child of that object due to (1). - It means that one of the operations is cross-directory rename. +It means that one of the operations is cross-directory rename. Otherwise the set of contended objects would be infinite - each of them would have a contended child and we had assumed that no object is its own descendent. Moreover, there is exactly one cross-directory rename (see above). - Consider the object blocking the cross-directory rename. One +Consider the object blocking the cross-directory rename. One of its descendents is locked by cross-directory rename (otherwise we would again have an infinite set of contended objects). But that means that cross-directory rename is taking locks out of order. Due @@ -112,7 +122,7 @@ try to acquire lock on descendent before the lock on ancestor. Contradiction. I.e. deadlock is impossible. Q.E.D. - These operations are guaranteed to avoid loop creation. Indeed, +These operations are guaranteed to avoid loop creation. Indeed, the only operation that could introduce loops is cross-directory rename. Since the only new (parent, child) pair added by rename() is (new parent, source), such loop would have to contain these objects and the rest of it @@ -123,13 +133,13 @@ new parent had been equal to or a descendent of source since the moment when we had acquired filesystem lock and rename() would fail with -ELOOP in that case. - While this locking scheme works for arbitrary DAGs, it relies on +While this locking scheme works for arbitrary DAGs, it relies on ability to check that directory is a descendent of another object. Current implementation assumes that directory graph is a tree. This assumption is also preserved by all operations (cross-directory rename on a tree that would not introduce a cycle will leave it a tree and link() fails for directories). - Notice that "directory" in the above == "anything that might have +Notice that "directory" in the above == "anything that might have children", so if we are going to introduce hybrid objects we will need either to make sure that link(2) doesn't work for them or to make changes in is_subdir() that would make it work even in presence of such beasts. diff --git a/drivers/staging/erofs/Documentation/filesystems/erofs.txt b/Documentation/filesystems/erofs.txt similarity index 92% rename from drivers/staging/erofs/Documentation/filesystems/erofs.txt rename to Documentation/filesystems/erofs.txt index 74cf84ac48a36e1477b116c79d546a46e4848ad4..b0c085326e2e68f4ead9063af48beeda0b48dcf9 100644 --- a/drivers/staging/erofs/Documentation/filesystems/erofs.txt +++ b/Documentation/filesystems/erofs.txt @@ -49,22 +49,23 @@ Bugs and patches are welcome, please kindly help us and send to the following linux-erofs mailing list: >> linux-erofs mailing list -Note that EROFS is still working in progress as a Linux staging driver, -Cc the staging mailing list as well is highly recommended: ->> Linux Driver Project Developer List - Mount options ============= -fault_injection=%d Enable fault injection in all supported types with - specified injection rate. Supported injection type: - Type_Name Type_Value - FAULT_KMALLOC 0x000000001 - FAULT_READ_IO 0x000000002 (no)user_xattr Setup Extended User Attributes. Note: xattr is enabled by default if CONFIG_EROFS_FS_XATTR is selected. (no)acl Setup POSIX Access Control List. Note: acl is enabled by default if CONFIG_EROFS_FS_POSIX_ACL is selected. +cache_strategy=%s Select a strategy for cached decompression from now on: + disabled: In-place I/O decompression only; + readahead: Cache the last incomplete compressed physical + cluster for further reading. It still does + in-place I/O decompression for the rest + compressed physical clusters; + readaround: Cache the both ends of incomplete compressed + physical clusters for further reading. + It still does in-place I/O decompression + for the rest compressed physical clusters. On-disk details =============== diff --git a/Documentation/filesystems/ext4/inodes.rst b/Documentation/filesystems/ext4/inodes.rst index 6bd35e506b6fd6db29400874006f56b4dd9fce03..e851e6ca31fa0e3952e95616e6da350b332206f8 100644 --- a/Documentation/filesystems/ext4/inodes.rst +++ b/Documentation/filesystems/ext4/inodes.rst @@ -277,6 +277,8 @@ The ``i_flags`` field is a combination of these values: - This is a huge file (EXT4\_HUGE\_FILE\_FL). * - 0x80000 - Inode uses extents (EXT4\_EXTENTS\_FL). + * - 0x100000 + - Verity protected file (EXT4\_VERITY\_FL). * - 0x200000 - Inode stores a large extended attribute value in its data blocks (EXT4\_EA\_INODE\_FL). @@ -299,9 +301,9 @@ The ``i_flags`` field is a combination of these values: - Reserved for ext4 library (EXT4\_RESERVED\_FL). * - - Aggregate flags: - * - 0x4BDFFF + * - 0x705BDFFF - User-visible flags. - * - 0x4B80FF + * - 0x604BC0FF - User-modifiable flags. Note that while EXT4\_JOURNAL\_DATA\_FL and EXT4\_EXTENTS\_FL can be set with setattr, they are not in the kernel's EXT4\_FL\_USER\_MODIFIABLE mask, since it needs to handle the setting of diff --git a/Documentation/filesystems/ext4/overview.rst b/Documentation/filesystems/ext4/overview.rst index cbab18baba1211e07e6f1a4865618bf1965ffc5b..123ebfde47ee1d815d2a01c600466bcb1f11057c 100644 --- a/Documentation/filesystems/ext4/overview.rst +++ b/Documentation/filesystems/ext4/overview.rst @@ -24,3 +24,4 @@ order. .. include:: bigalloc.rst .. include:: inlinedata.rst .. include:: eainode.rst +.. include:: verity.rst diff --git a/Documentation/filesystems/ext4/super.rst b/Documentation/filesystems/ext4/super.rst index 04ff079a2acf8009925efc9ad43399dde89ed89e..6eae9205482787a7d9ecb86f956fe5871ffaf8c0 100644 --- a/Documentation/filesystems/ext4/super.rst +++ b/Documentation/filesystems/ext4/super.rst @@ -696,6 +696,8 @@ the following: (RO\_COMPAT\_READONLY) * - 0x2000 - Filesystem tracks project quotas. (RO\_COMPAT\_PROJECT) + * - 0x8000 + - Verity inodes may be present on the filesystem. (RO\_COMPAT\_VERITY) .. _super_def_hash: diff --git a/Documentation/filesystems/ext4/verity.rst b/Documentation/filesystems/ext4/verity.rst new file mode 100644 index 0000000000000000000000000000000000000000..3e4c0ee0e06839ab350e2b01d753ce9bf8639e76 --- /dev/null +++ b/Documentation/filesystems/ext4/verity.rst @@ -0,0 +1,41 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Verity files +------------ + +ext4 supports fs-verity, which is a filesystem feature that provides +Merkle tree based hashing for individual readonly files. Most of +fs-verity is common to all filesystems that support it; see +:ref:`Documentation/filesystems/fsverity.rst ` for the +fs-verity documentation. However, the on-disk layout of the verity +metadata is filesystem-specific. On ext4, the verity metadata is +stored after the end of the file data itself, in the following format: + +- Zero-padding to the next 65536-byte boundary. This padding need not + actually be allocated on-disk, i.e. it may be a hole. + +- The Merkle tree, as documented in + :ref:`Documentation/filesystems/fsverity.rst + `, with the tree levels stored in order from + root to leaf, and the tree blocks within each level stored in their + natural order. + +- Zero-padding to the next filesystem block boundary. + +- The verity descriptor, as documented in + :ref:`Documentation/filesystems/fsverity.rst `, + with optionally appended signature blob. + +- Zero-padding to the next offset that is 4 bytes before a filesystem + block boundary. + +- The size of the verity descriptor in bytes, as a 4-byte little + endian integer. + +Verity inodes have EXT4_VERITY_FL set, and they must use extents, i.e. +EXT4_EXTENTS_FL must be set and EXT4_INLINE_DATA_FL must be clear. +They can have EXT4_ENCRYPT_FL set, in which case the verity metadata +is encrypted as well as the data itself. + +Verity files cannot have blocks allocated past the end of the verity +metadata. diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst index 82efa41b0e6c02eccfe4620a07e0ffa4f693dbb3..8a0700af959672568b7713dbb6e2f8c82449e200 100644 --- a/Documentation/filesystems/fscrypt.rst +++ b/Documentation/filesystems/fscrypt.rst @@ -72,6 +72,9 @@ Online attacks fscrypt (and storage encryption in general) can only provide limited protection, if any at all, against online attacks. In detail: +Side-channel attacks +~~~~~~~~~~~~~~~~~~~~ + fscrypt is only resistant to side-channel attacks, such as timing or electromagnetic attacks, to the extent that the underlying Linux Cryptographic API algorithms are. If a vulnerable algorithm is used, @@ -80,29 +83,90 @@ attacker to mount a side channel attack against the online system. Side channel attacks may also be mounted against applications consuming decrypted data. -After an encryption key has been provided, fscrypt is not designed to -hide the plaintext file contents or filenames from other users on the -same system, regardless of the visibility of the keyring key. -Instead, existing access control mechanisms such as file mode bits, -POSIX ACLs, LSMs, or mount namespaces should be used for this purpose. -Also note that as long as the encryption keys are *anywhere* in -memory, an online attacker can necessarily compromise them by mounting -a physical attack or by exploiting any kernel security vulnerability -which provides an arbitrary memory read primitive. - -While it is ostensibly possible to "evict" keys from the system, -recently accessed encrypted files will remain accessible at least -until the filesystem is unmounted or the VFS caches are dropped, e.g. -using ``echo 2 > /proc/sys/vm/drop_caches``. Even after that, if the -RAM is compromised before being powered off, it will likely still be -possible to recover portions of the plaintext file contents, if not -some of the encryption keys as well. (Since Linux v4.12, all -in-kernel keys related to fscrypt are sanitized before being freed. -However, userspace would need to do its part as well.) - -Currently, fscrypt does not prevent a user from maliciously providing -an incorrect key for another user's existing encrypted files. A -protection against this is planned. +Unauthorized file access +~~~~~~~~~~~~~~~~~~~~~~~~ + +After an encryption key has been added, fscrypt does not hide the +plaintext file contents or filenames from other users on the same +system. Instead, existing access control mechanisms such as file mode +bits, POSIX ACLs, LSMs, or namespaces should be used for this purpose. + +(For the reasoning behind this, understand that while the key is +added, the confidentiality of the data, from the perspective of the +system itself, is *not* protected by the mathematical properties of +encryption but rather only by the correctness of the kernel. +Therefore, any encryption-specific access control checks would merely +be enforced by kernel *code* and therefore would be largely redundant +with the wide variety of access control mechanisms already available.) + +Kernel memory compromise +~~~~~~~~~~~~~~~~~~~~~~~~ + +An attacker who compromises the system enough to read from arbitrary +memory, e.g. by mounting a physical attack or by exploiting a kernel +security vulnerability, can compromise all encryption keys that are +currently in use. + +However, fscrypt allows encryption keys to be removed from the kernel, +which may protect them from later compromise. + +In more detail, the FS_IOC_REMOVE_ENCRYPTION_KEY ioctl (or the +FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS ioctl) can wipe a master +encryption key from kernel memory. If it does so, it will also try to +evict all cached inodes which had been "unlocked" using the key, +thereby wiping their per-file keys and making them once again appear +"locked", i.e. in ciphertext or encrypted form. + +However, these ioctls have some limitations: + +- Per-file keys for in-use files will *not* be removed or wiped. + Therefore, for maximum effect, userspace should close the relevant + encrypted files and directories before removing a master key, as + well as kill any processes whose working directory is in an affected + encrypted directory. + +- The kernel cannot magically wipe copies of the master key(s) that + userspace might have as well. Therefore, userspace must wipe all + copies of the master key(s) it makes as well; normally this should + be done immediately after FS_IOC_ADD_ENCRYPTION_KEY, without waiting + for FS_IOC_REMOVE_ENCRYPTION_KEY. Naturally, the same also applies + to all higher levels in the key hierarchy. Userspace should also + follow other security precautions such as mlock()ing memory + containing keys to prevent it from being swapped out. + +- In general, decrypted contents and filenames in the kernel VFS + caches are freed but not wiped. Therefore, portions thereof may be + recoverable from freed memory, even after the corresponding key(s) + were wiped. To partially solve this, you can set + CONFIG_PAGE_POISONING=y in your kernel config and add page_poison=1 + to your kernel command line. However, this has a performance cost. + +- Secret keys might still exist in CPU registers, in crypto + accelerator hardware (if used by the crypto API to implement any of + the algorithms), or in other places not explicitly considered here. + +Limitations of v1 policies +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +v1 encryption policies have some weaknesses with respect to online +attacks: + +- There is no verification that the provided master key is correct. + Therefore, a malicious user can temporarily associate the wrong key + with another user's encrypted files to which they have read-only + access. Because of filesystem caching, the wrong key will then be + used by the other user's accesses to those files, even if the other + user has the correct key in their own keyring. This violates the + meaning of "read-only access". + +- A compromise of a per-file key also compromises the master key from + which it was derived. + +- Non-root users cannot securely remove encryption keys. + +All the above problems are fixed with v2 encryption policies. For +this reason among others, it is recommended to use v2 encryption +policies on all new encrypted directories. Key hierarchy ============= @@ -123,11 +187,52 @@ appropriate master key. There can be any number of master keys, each of which protects any number of directory trees on any number of filesystems. -Userspace should generate master keys either using a cryptographically -secure random number generator, or by using a KDF (Key Derivation -Function). Note that whenever a KDF is used to "stretch" a -lower-entropy secret such as a passphrase, it is critical that a KDF -designed for this purpose be used, such as scrypt, PBKDF2, or Argon2. +Master keys must be real cryptographic keys, i.e. indistinguishable +from random bytestrings of the same length. This implies that users +**must not** directly use a password as a master key, zero-pad a +shorter key, or repeat a shorter key. Security cannot be guaranteed +if userspace makes any such error, as the cryptographic proofs and +analysis would no longer apply. + +Instead, users should generate master keys either using a +cryptographically secure random number generator, or by using a KDF +(Key Derivation Function). The kernel does not do any key stretching; +therefore, if userspace derives the key from a low-entropy secret such +as a passphrase, it is critical that a KDF designed for this purpose +be used, such as scrypt, PBKDF2, or Argon2. + +Key derivation function +----------------------- + +With one exception, fscrypt never uses the master key(s) for +encryption directly. Instead, they are only used as input to a KDF +(Key Derivation Function) to derive the actual keys. + +The KDF used for a particular master key differs depending on whether +the key is used for v1 encryption policies or for v2 encryption +policies. Users **must not** use the same key for both v1 and v2 +encryption policies. (No real-world attack is currently known on this +specific case of key reuse, but its security cannot be guaranteed +since the cryptographic proofs and analysis would no longer apply.) + +For v1 encryption policies, the KDF only supports deriving per-file +encryption keys. It works by encrypting the master key with +AES-128-ECB, using the file's 16-byte nonce as the AES key. The +resulting ciphertext is used as the derived key. If the ciphertext is +longer than needed, then it is truncated to the needed length. + +For v2 encryption policies, the KDF is HKDF-SHA512. The master key is +passed as the "input keying material", no salt is used, and a distinct +"application-specific information string" is used for each distinct +key to be derived. For example, when a per-file encryption key is +derived, the application-specific information string is the file's +nonce prefixed with "fscrypt\\0" and a context byte. Different +context bytes are used for other types of derived keys. + +HKDF-SHA512 is preferred to the original AES-128-ECB based KDF because +HKDF is more flexible, is nonreversible, and evenly distributes +entropy from the master key. HKDF is also standardized and widely +used by other software, whereas the AES-128-ECB based KDF is ad-hoc. Per-file keys ------------- @@ -138,29 +243,9 @@ files doesn't map to the same ciphertext, or vice versa. In most cases, fscrypt does this by deriving per-file keys. When a new encrypted inode (regular file, directory, or symlink) is created, fscrypt randomly generates a 16-byte nonce and stores it in the -inode's encryption xattr. Then, it uses a KDF (Key Derivation -Function) to derive the file's key from the master key and nonce. - -The Adiantum encryption mode (see `Encryption modes and usage`_) is -special, since it accepts longer IVs and is suitable for both contents -and filenames encryption. For it, a "direct key" option is offered -where the file's nonce is included in the IVs and the master key is -used for encryption directly. This improves performance; however, -users must not use the same master key for any other encryption mode. - -Below, the KDF and design considerations are described in more detail. - -The current KDF works by encrypting the master key with AES-128-ECB, -using the file's nonce as the AES key. The output is used as the -derived key. If the output is longer than needed, then it is -truncated to the needed length. - -Note: this KDF meets the primary security requirement, which is to -produce unique derived keys that preserve the entropy of the master -key, assuming that the master key is already a good pseudorandom key. -However, it is nonstandard and has some problems such as being -reversible, so it is generally considered to be a mistake! It may be -replaced with HKDF or another more standard KDF in the future. +inode's encryption xattr. Then, it uses a KDF (as described in `Key +derivation function`_) to derive the file's key from the master key +and nonce. Key derivation was chosen over key wrapping because wrapped keys would require larger xattrs which would be less likely to fit in-line in the @@ -176,6 +261,37 @@ rejected as it would have prevented ext4 filesystems from being resized, and by itself still wouldn't have been sufficient to prevent the same key from being directly reused for both XTS and CTS-CBC. +DIRECT_KEY and per-mode keys +---------------------------- + +The Adiantum encryption mode (see `Encryption modes and usage`_) is +suitable for both contents and filenames encryption, and it accepts +long IVs --- long enough to hold both an 8-byte logical block number +and a 16-byte per-file nonce. Also, the overhead of each Adiantum key +is greater than that of an AES-256-XTS key. + +Therefore, to improve performance and save memory, for Adiantum a +"direct key" configuration is supported. When the user has enabled +this by setting FSCRYPT_POLICY_FLAG_DIRECT_KEY in the fscrypt policy, +per-file keys are not used. Instead, whenever any data (contents or +filenames) is encrypted, the file's 16-byte nonce is included in the +IV. Moreover: + +- For v1 encryption policies, the encryption is done directly with the + master key. Because of this, users **must not** use the same master + key for any other purpose, even for other v1 policies. + +- For v2 encryption policies, the encryption is done with a per-mode + key derived using the KDF. Users may use the same master key for + other v2 encryption policies. + +Key identifiers +--------------- + +For master keys used for v2 encryption policies, a unique 16-byte "key +identifier" is also derived using the KDF. This value is stored in +the clear, since it is needed to reliably identify the key itself. + Encryption modes and usage ========================== @@ -225,9 +341,10 @@ a little endian number, except that: is encrypted with AES-256 where the AES-256 key is the SHA-256 hash of the file's data encryption key. -- In the "direct key" configuration (FS_POLICY_FLAG_DIRECT_KEY set in - the fscrypt_policy), the file's nonce is also appended to the IV. - Currently this is only allowed with the Adiantum encryption mode. +- In the "direct key" configuration (FSCRYPT_POLICY_FLAG_DIRECT_KEY + set in the fscrypt_policy), the file's nonce is also appended to the + IV. Currently this is only allowed with the Adiantum encryption + mode. Filenames encryption -------------------- @@ -269,49 +386,77 @@ User API Setting an encryption policy ---------------------------- +FS_IOC_SET_ENCRYPTION_POLICY +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + The FS_IOC_SET_ENCRYPTION_POLICY ioctl sets an encryption policy on an empty directory or verifies that a directory or regular file already has the specified encryption policy. It takes in a pointer to a -:c:type:`struct fscrypt_policy`, defined as follows:: +:c:type:`struct fscrypt_policy_v1` or a :c:type:`struct +fscrypt_policy_v2`, defined as follows:: - #define FS_KEY_DESCRIPTOR_SIZE 8 + #define FSCRYPT_POLICY_V1 0 + #define FSCRYPT_KEY_DESCRIPTOR_SIZE 8 + struct fscrypt_policy_v1 { + __u8 version; + __u8 contents_encryption_mode; + __u8 filenames_encryption_mode; + __u8 flags; + __u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE]; + }; + #define fscrypt_policy fscrypt_policy_v1 - struct fscrypt_policy { + #define FSCRYPT_POLICY_V2 2 + #define FSCRYPT_KEY_IDENTIFIER_SIZE 16 + struct fscrypt_policy_v2 { __u8 version; __u8 contents_encryption_mode; __u8 filenames_encryption_mode; __u8 flags; - __u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE]; + __u8 __reserved[4]; + __u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]; }; This structure must be initialized as follows: -- ``version`` must be 0. +- ``version`` must be FSCRYPT_POLICY_V1 (0) if the struct is + :c:type:`fscrypt_policy_v1` or FSCRYPT_POLICY_V2 (2) if the struct + is :c:type:`fscrypt_policy_v2`. (Note: we refer to the original + policy version as "v1", though its version code is really 0.) For + new encrypted directories, use v2 policies. - ``contents_encryption_mode`` and ``filenames_encryption_mode`` must - be set to constants from ```` which identify the - encryption modes to use. If unsure, use - FS_ENCRYPTION_MODE_AES_256_XTS (1) for ``contents_encryption_mode`` - and FS_ENCRYPTION_MODE_AES_256_CTS (4) for - ``filenames_encryption_mode``. + be set to constants from ```` which identify the + encryption modes to use. If unsure, use FSCRYPT_MODE_AES_256_XTS + (1) for ``contents_encryption_mode`` and FSCRYPT_MODE_AES_256_CTS + (4) for ``filenames_encryption_mode``. -- ``flags`` must contain a value from ```` which +- ``flags`` must contain a value from ```` which identifies the amount of NUL-padding to use when encrypting - filenames. If unsure, use FS_POLICY_FLAGS_PAD_32 (0x3). - In addition, if the chosen encryption modes are both - FS_ENCRYPTION_MODE_ADIANTUM, this can contain - FS_POLICY_FLAG_DIRECT_KEY to specify that the master key should be - used directly, without key derivation. - -- ``master_key_descriptor`` specifies how to find the master key in - the keyring; see `Adding keys`_. It is up to userspace to choose a - unique ``master_key_descriptor`` for each master key. The e4crypt - and fscrypt tools use the first 8 bytes of + filenames. If unsure, use FSCRYPT_POLICY_FLAGS_PAD_32 (0x3). + Additionally, if the encryption modes are both + FSCRYPT_MODE_ADIANTUM, this can contain + FSCRYPT_POLICY_FLAG_DIRECT_KEY; see `DIRECT_KEY and per-mode keys`_. + +- For v2 encryption policies, ``__reserved`` must be zeroed. + +- For v1 encryption policies, ``master_key_descriptor`` specifies how + to find the master key in a keyring; see `Adding keys`_. It is up + to userspace to choose a unique ``master_key_descriptor`` for each + master key. The e4crypt and fscrypt tools use the first 8 bytes of ``SHA-512(SHA-512(master_key))``, but this particular scheme is not required. Also, the master key need not be in the keyring yet when FS_IOC_SET_ENCRYPTION_POLICY is executed. However, it must be added before any files can be created in the encrypted directory. + For v2 encryption policies, ``master_key_descriptor`` has been + replaced with ``master_key_identifier``, which is longer and cannot + be arbitrarily chosen. Instead, the key must first be added using + `FS_IOC_ADD_ENCRYPTION_KEY`_. Then, the ``key_spec.u.identifier`` + the kernel returned in the :c:type:`struct fscrypt_add_key_arg` must + be used as the ``master_key_identifier`` in the :c:type:`struct + fscrypt_policy_v2`. + If the file is not yet encrypted, then FS_IOC_SET_ENCRYPTION_POLICY verifies that the file is an empty directory. If so, the specified encryption policy is assigned to the directory, turning it into an @@ -327,6 +472,15 @@ policy exactly matches the actual one. If they match, then the ioctl returns 0. Otherwise, it fails with EEXIST. This works on both regular files and directories, including nonempty directories. +When a v2 encryption policy is assigned to a directory, it is also +required that either the specified key has been added by the current +user or that the caller has CAP_FOWNER in the initial user namespace. +(This is needed to prevent a user from encrypting their data with +another user's key.) The key must remain added while +FS_IOC_SET_ENCRYPTION_POLICY is executing. However, if the new +encrypted directory does not need to be accessed immediately, then the +key can be removed right away afterwards. + Note that the ext4 filesystem does not allow the root directory to be encrypted, even if it is empty. Users who want to encrypt an entire filesystem with one key should consider using dm-crypt instead. @@ -339,7 +493,11 @@ FS_IOC_SET_ENCRYPTION_POLICY can fail with the following errors: - ``EEXIST``: the file is already encrypted with an encryption policy different from the one specified - ``EINVAL``: an invalid encryption policy was specified (invalid - version, mode(s), or flags) + version, mode(s), or flags; or reserved bits were set) +- ``ENOKEY``: a v2 encryption policy was specified, but the key with + the specified ``master_key_identifier`` has not been added, nor does + the process have the CAP_FOWNER capability in the initial user + namespace - ``ENOTDIR``: the file is unencrypted and is a regular file, not a directory - ``ENOTEMPTY``: the file is unencrypted and is a nonempty directory @@ -358,25 +516,79 @@ FS_IOC_SET_ENCRYPTION_POLICY can fail with the following errors: Getting an encryption policy ---------------------------- -The FS_IOC_GET_ENCRYPTION_POLICY ioctl retrieves the :c:type:`struct -fscrypt_policy`, if any, for a directory or regular file. See above -for the struct definition. No additional permissions are required -beyond the ability to open the file. +Two ioctls are available to get a file's encryption policy: + +- `FS_IOC_GET_ENCRYPTION_POLICY_EX`_ +- `FS_IOC_GET_ENCRYPTION_POLICY`_ + +The extended (_EX) version of the ioctl is more general and is +recommended to use when possible. However, on older kernels only the +original ioctl is available. Applications should try the extended +version, and if it fails with ENOTTY fall back to the original +version. + +FS_IOC_GET_ENCRYPTION_POLICY_EX +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The FS_IOC_GET_ENCRYPTION_POLICY_EX ioctl retrieves the encryption +policy, if any, for a directory or regular file. No additional +permissions are required beyond the ability to open the file. It +takes in a pointer to a :c:type:`struct fscrypt_get_policy_ex_arg`, +defined as follows:: + + struct fscrypt_get_policy_ex_arg { + __u64 policy_size; /* input/output */ + union { + __u8 version; + struct fscrypt_policy_v1 v1; + struct fscrypt_policy_v2 v2; + } policy; /* output */ + }; + +The caller must initialize ``policy_size`` to the size available for +the policy struct, i.e. ``sizeof(arg.policy)``. + +On success, the policy struct is returned in ``policy``, and its +actual size is returned in ``policy_size``. ``policy.version`` should +be checked to determine the version of policy returned. Note that the +version code for the "v1" policy is actually 0 (FSCRYPT_POLICY_V1). -FS_IOC_GET_ENCRYPTION_POLICY can fail with the following errors: +FS_IOC_GET_ENCRYPTION_POLICY_EX can fail with the following errors: - ``EINVAL``: the file is encrypted, but it uses an unrecognized - encryption context format + encryption policy version - ``ENODATA``: the file is not encrypted -- ``ENOTTY``: this type of filesystem does not implement encryption +- ``ENOTTY``: this type of filesystem does not implement encryption, + or this kernel is too old to support FS_IOC_GET_ENCRYPTION_POLICY_EX + (try FS_IOC_GET_ENCRYPTION_POLICY instead) - ``EOPNOTSUPP``: the kernel was not configured with encryption - support for this filesystem + support for this filesystem, or the filesystem superblock has not + had encryption enabled on it +- ``EOVERFLOW``: the file is encrypted and uses a recognized + encryption policy version, but the policy struct does not fit into + the provided buffer Note: if you only need to know whether a file is encrypted or not, on most filesystems it is also possible to use the FS_IOC_GETFLAGS ioctl and check for FS_ENCRYPT_FL, or to use the statx() system call and check for STATX_ATTR_ENCRYPTED in stx_attributes. +FS_IOC_GET_ENCRYPTION_POLICY +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The FS_IOC_GET_ENCRYPTION_POLICY ioctl can also retrieve the +encryption policy, if any, for a directory or regular file. However, +unlike `FS_IOC_GET_ENCRYPTION_POLICY_EX`_, +FS_IOC_GET_ENCRYPTION_POLICY only supports the original policy +version. It takes in a pointer directly to a :c:type:`struct +fscrypt_policy_v1` rather than a :c:type:`struct +fscrypt_get_policy_ex_arg`. + +The error codes for FS_IOC_GET_ENCRYPTION_POLICY are the same as those +for FS_IOC_GET_ENCRYPTION_POLICY_EX, except that +FS_IOC_GET_ENCRYPTION_POLICY also returns ``EINVAL`` if the file is +encrypted using a newer encryption policy version. + Getting the per-filesystem salt ------------------------------- @@ -392,8 +604,115 @@ generate and manage any needed salt(s) in userspace. Adding keys ----------- -To provide a master key, userspace must add it to an appropriate -keyring using the add_key() system call (see: +FS_IOC_ADD_ENCRYPTION_KEY +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The FS_IOC_ADD_ENCRYPTION_KEY ioctl adds a master encryption key to +the filesystem, making all files on the filesystem which were +encrypted using that key appear "unlocked", i.e. in plaintext form. +It can be executed on any file or directory on the target filesystem, +but using the filesystem's root directory is recommended. It takes in +a pointer to a :c:type:`struct fscrypt_add_key_arg`, defined as +follows:: + + struct fscrypt_add_key_arg { + struct fscrypt_key_specifier key_spec; + __u32 raw_size; + __u32 __reserved[9]; + __u8 raw[]; + }; + + #define FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR 1 + #define FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER 2 + + struct fscrypt_key_specifier { + __u32 type; /* one of FSCRYPT_KEY_SPEC_TYPE_* */ + __u32 __reserved; + union { + __u8 __reserved[32]; /* reserve some extra space */ + __u8 descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE]; + __u8 identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]; + } u; + }; + +:c:type:`struct fscrypt_add_key_arg` must be zeroed, then initialized +as follows: + +- If the key is being added for use by v1 encryption policies, then + ``key_spec.type`` must contain FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR, and + ``key_spec.u.descriptor`` must contain the descriptor of the key + being added, corresponding to the value in the + ``master_key_descriptor`` field of :c:type:`struct + fscrypt_policy_v1`. To add this type of key, the calling process + must have the CAP_SYS_ADMIN capability in the initial user + namespace. + + Alternatively, if the key is being added for use by v2 encryption + policies, then ``key_spec.type`` must contain + FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER, and ``key_spec.u.identifier`` is + an *output* field which the kernel fills in with a cryptographic + hash of the key. To add this type of key, the calling process does + not need any privileges. However, the number of keys that can be + added is limited by the user's quota for the keyrings service (see + ``Documentation/security/keys/core.rst``). + +- ``raw_size`` must be the size of the ``raw`` key provided, in bytes. + +- ``raw`` is a variable-length field which must contain the actual + key, ``raw_size`` bytes long. + +For v2 policy keys, the kernel keeps track of which user (identified +by effective user ID) added the key, and only allows the key to be +removed by that user --- or by "root", if they use +`FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS`_. + +However, if another user has added the key, it may be desirable to +prevent that other user from unexpectedly removing it. Therefore, +FS_IOC_ADD_ENCRYPTION_KEY may also be used to add a v2 policy key +*again*, even if it's already added by other user(s). In this case, +FS_IOC_ADD_ENCRYPTION_KEY will just install a claim to the key for the +current user, rather than actually add the key again (but the raw key +must still be provided, as a proof of knowledge). + +FS_IOC_ADD_ENCRYPTION_KEY returns 0 if either the key or a claim to +the key was either added or already exists. + +FS_IOC_ADD_ENCRYPTION_KEY can fail with the following errors: + +- ``EACCES``: FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR was specified, but the + caller does not have the CAP_SYS_ADMIN capability in the initial + user namespace +- ``EDQUOT``: the key quota for this user would be exceeded by adding + the key +- ``EINVAL``: invalid key size or key specifier type, or reserved bits + were set +- ``ENOTTY``: this type of filesystem does not implement encryption +- ``EOPNOTSUPP``: the kernel was not configured with encryption + support for this filesystem, or the filesystem superblock has not + had encryption enabled on it + +Legacy method +~~~~~~~~~~~~~ + +For v1 encryption policies, a master encryption key can also be +provided by adding it to a process-subscribed keyring, e.g. to a +session keyring, or to a user keyring if the user keyring is linked +into the session keyring. + +This method is deprecated (and not supported for v2 encryption +policies) for several reasons. First, it cannot be used in +combination with FS_IOC_REMOVE_ENCRYPTION_KEY (see `Removing keys`_), +so for removing a key a workaround such as keyctl_unlink() in +combination with ``sync; echo 2 > /proc/sys/vm/drop_caches`` would +have to be used. Second, it doesn't match the fact that the +locked/unlocked status of encrypted files (i.e. whether they appear to +be in plaintext form or in ciphertext form) is global. This mismatch +has caused much confusion as well as real problems when processes +running under different UIDs, such as a ``sudo`` command, need to +access encrypted files. + +Nevertheless, to add a key to one of the process-subscribed keyrings, +the add_key() system call can be used (see: ``Documentation/security/keys/core.rst``). The key type must be "logon"; keys of this type are kept in kernel memory and cannot be read back by userspace. The key description must be "fscrypt:" @@ -401,12 +720,12 @@ followed by the 16-character lower case hex representation of the ``master_key_descriptor`` that was set in the encryption policy. The key payload must conform to the following structure:: - #define FS_MAX_KEY_SIZE 64 + #define FSCRYPT_MAX_KEY_SIZE 64 struct fscrypt_key { - u32 mode; - u8 raw[FS_MAX_KEY_SIZE]; - u32 size; + __u32 mode; + __u8 raw[FSCRYPT_MAX_KEY_SIZE]; + __u32 size; }; ``mode`` is ignored; just set it to 0. The actual key is provided in @@ -418,26 +737,194 @@ with a filesystem-specific prefix such as "ext4:". However, the filesystem-specific prefixes are deprecated and should not be used in new programs. -There are several different types of keyrings in which encryption keys -may be placed, such as a session keyring, a user session keyring, or a -user keyring. Each key must be placed in a keyring that is "attached" -to all processes that might need to access files encrypted with it, in -the sense that request_key() will find the key. Generally, if only -processes belonging to a specific user need to access a given -encrypted directory and no session keyring has been installed, then -that directory's key should be placed in that user's user session -keyring or user keyring. Otherwise, a session keyring should be -installed if needed, and the key should be linked into that session -keyring, or in a keyring linked into that session keyring. - -Note: introducing the complex visibility semantics of keyrings here -was arguably a mistake --- especially given that by design, after any -process successfully opens an encrypted file (thereby setting up the -per-file key), possessing the keyring key is not actually required for -any process to read/write the file until its in-memory inode is -evicted. In the future there probably should be a way to provide keys -directly to the filesystem instead, which would make the intended -semantics clearer. +Removing keys +------------- + +Two ioctls are available for removing a key that was added by +`FS_IOC_ADD_ENCRYPTION_KEY`_: + +- `FS_IOC_REMOVE_ENCRYPTION_KEY`_ +- `FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS`_ + +These two ioctls differ only in cases where v2 policy keys are added +or removed by non-root users. + +These ioctls don't work on keys that were added via the legacy +process-subscribed keyrings mechanism. + +Before using these ioctls, read the `Kernel memory compromise`_ +section for a discussion of the security goals and limitations of +these ioctls. + +FS_IOC_REMOVE_ENCRYPTION_KEY +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The FS_IOC_REMOVE_ENCRYPTION_KEY ioctl removes a claim to a master +encryption key from the filesystem, and possibly removes the key +itself. It can be executed on any file or directory on the target +filesystem, but using the filesystem's root directory is recommended. +It takes in a pointer to a :c:type:`struct fscrypt_remove_key_arg`, +defined as follows:: + + struct fscrypt_remove_key_arg { + struct fscrypt_key_specifier key_spec; + #define FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY 0x00000001 + #define FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS 0x00000002 + __u32 removal_status_flags; /* output */ + __u32 __reserved[5]; + }; + +This structure must be zeroed, then initialized as follows: + +- The key to remove is specified by ``key_spec``: + + - To remove a key used by v1 encryption policies, set + ``key_spec.type`` to FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR and fill + in ``key_spec.u.descriptor``. To remove this type of key, the + calling process must have the CAP_SYS_ADMIN capability in the + initial user namespace. + + - To remove a key used by v2 encryption policies, set + ``key_spec.type`` to FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER and fill + in ``key_spec.u.identifier``. + +For v2 policy keys, this ioctl is usable by non-root users. However, +to make this possible, it actually just removes the current user's +claim to the key, undoing a single call to FS_IOC_ADD_ENCRYPTION_KEY. +Only after all claims are removed is the key really removed. + +For example, if FS_IOC_ADD_ENCRYPTION_KEY was called with uid 1000, +then the key will be "claimed" by uid 1000, and +FS_IOC_REMOVE_ENCRYPTION_KEY will only succeed as uid 1000. Or, if +both uids 1000 and 2000 added the key, then for each uid +FS_IOC_REMOVE_ENCRYPTION_KEY will only remove their own claim. Only +once *both* are removed is the key really removed. (Think of it like +unlinking a file that may have hard links.) + +If FS_IOC_REMOVE_ENCRYPTION_KEY really removes the key, it will also +try to "lock" all files that had been unlocked with the key. It won't +lock files that are still in-use, so this ioctl is expected to be used +in cooperation with userspace ensuring that none of the files are +still open. However, if necessary, this ioctl can be executed again +later to retry locking any remaining files. + +FS_IOC_REMOVE_ENCRYPTION_KEY returns 0 if either the key was removed +(but may still have files remaining to be locked), the user's claim to +the key was removed, or the key was already removed but had files +remaining to be the locked so the ioctl retried locking them. In any +of these cases, ``removal_status_flags`` is filled in with the +following informational status flags: + +- ``FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY``: set if some file(s) + are still in-use. Not guaranteed to be set in the case where only + the user's claim to the key was removed. +- ``FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS``: set if only the + user's claim to the key was removed, not the key itself + +FS_IOC_REMOVE_ENCRYPTION_KEY can fail with the following errors: + +- ``EACCES``: The FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR key specifier type + was specified, but the caller does not have the CAP_SYS_ADMIN + capability in the initial user namespace +- ``EINVAL``: invalid key specifier type, or reserved bits were set +- ``ENOKEY``: the key object was not found at all, i.e. it was never + added in the first place or was already fully removed including all + files locked; or, the user does not have a claim to the key (but + someone else does). +- ``ENOTTY``: this type of filesystem does not implement encryption +- ``EOPNOTSUPP``: the kernel was not configured with encryption + support for this filesystem, or the filesystem superblock has not + had encryption enabled on it + +FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS is exactly the same as +`FS_IOC_REMOVE_ENCRYPTION_KEY`_, except that for v2 policy keys, the +ALL_USERS version of the ioctl will remove all users' claims to the +key, not just the current user's. I.e., the key itself will always be +removed, no matter how many users have added it. This difference is +only meaningful if non-root users are adding and removing keys. + +Because of this, FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS also requires +"root", namely the CAP_SYS_ADMIN capability in the initial user +namespace. Otherwise it will fail with EACCES. + +Getting key status +------------------ + +FS_IOC_GET_ENCRYPTION_KEY_STATUS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The FS_IOC_GET_ENCRYPTION_KEY_STATUS ioctl retrieves the status of a +master encryption key. It can be executed on any file or directory on +the target filesystem, but using the filesystem's root directory is +recommended. It takes in a pointer to a :c:type:`struct +fscrypt_get_key_status_arg`, defined as follows:: + + struct fscrypt_get_key_status_arg { + /* input */ + struct fscrypt_key_specifier key_spec; + __u32 __reserved[6]; + + /* output */ + #define FSCRYPT_KEY_STATUS_ABSENT 1 + #define FSCRYPT_KEY_STATUS_PRESENT 2 + #define FSCRYPT_KEY_STATUS_INCOMPLETELY_REMOVED 3 + __u32 status; + #define FSCRYPT_KEY_STATUS_FLAG_ADDED_BY_SELF 0x00000001 + __u32 status_flags; + __u32 user_count; + __u32 __out_reserved[13]; + }; + +The caller must zero all input fields, then fill in ``key_spec``: + + - To get the status of a key for v1 encryption policies, set + ``key_spec.type`` to FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR and fill + in ``key_spec.u.descriptor``. + + - To get the status of a key for v2 encryption policies, set + ``key_spec.type`` to FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER and fill + in ``key_spec.u.identifier``. + +On success, 0 is returned and the kernel fills in the output fields: + +- ``status`` indicates whether the key is absent, present, or + incompletely removed. Incompletely removed means that the master + secret has been removed, but some files are still in use; i.e., + `FS_IOC_REMOVE_ENCRYPTION_KEY`_ returned 0 but set the informational + status flag FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY. + +- ``status_flags`` can contain the following flags: + + - ``FSCRYPT_KEY_STATUS_FLAG_ADDED_BY_SELF`` indicates that the key + has added by the current user. This is only set for keys + identified by ``identifier`` rather than by ``descriptor``. + +- ``user_count`` specifies the number of users who have added the key. + This is only set for keys identified by ``identifier`` rather than + by ``descriptor``. + +FS_IOC_GET_ENCRYPTION_KEY_STATUS can fail with the following errors: + +- ``EINVAL``: invalid key specifier type, or reserved bits were set +- ``ENOTTY``: this type of filesystem does not implement encryption +- ``EOPNOTSUPP``: the kernel was not configured with encryption + support for this filesystem, or the filesystem superblock has not + had encryption enabled on it + +Among other use cases, FS_IOC_GET_ENCRYPTION_KEY_STATUS can be useful +for determining whether the key for a given encrypted directory needs +to be added before prompting the user for the passphrase needed to +derive the key. + +FS_IOC_GET_ENCRYPTION_KEY_STATUS can only get the status of keys in +the filesystem-level keyring, i.e. the keyring managed by +`FS_IOC_ADD_ENCRYPTION_KEY`_ and `FS_IOC_REMOVE_ENCRYPTION_KEY`_. It +cannot get the status of a key that has only been added for use by v1 +encryption policies using the legacy mechanism involving +process-subscribed keyrings. Access semantics ================ @@ -500,7 +987,7 @@ Without the key Some filesystem operations may be performed on encrypted regular files, directories, and symlinks even before their encryption key has -been provided: +been added, or after their encryption key has been removed: - File metadata may be read, e.g. using stat(). @@ -565,33 +1052,44 @@ Encryption context ------------------ An encryption policy is represented on-disk by a :c:type:`struct -fscrypt_context`. It is up to individual filesystems to decide where -to store it, but normally it would be stored in a hidden extended -attribute. It should *not* be exposed by the xattr-related system -calls such as getxattr() and setxattr() because of the special -semantics of the encryption xattr. (In particular, there would be -much confusion if an encryption policy were to be added to or removed -from anything other than an empty directory.) The struct is defined -as follows:: - - #define FS_KEY_DESCRIPTOR_SIZE 8 +fscrypt_context_v1` or a :c:type:`struct fscrypt_context_v2`. It is +up to individual filesystems to decide where to store it, but normally +it would be stored in a hidden extended attribute. It should *not* be +exposed by the xattr-related system calls such as getxattr() and +setxattr() because of the special semantics of the encryption xattr. +(In particular, there would be much confusion if an encryption policy +were to be added to or removed from anything other than an empty +directory.) These structs are defined as follows:: + #define FS_KEY_DERIVATION_NONCE_SIZE 16 - struct fscrypt_context { - u8 format; + #define FSCRYPT_KEY_DESCRIPTOR_SIZE 8 + struct fscrypt_context_v1 { + u8 version; + u8 contents_encryption_mode; + u8 filenames_encryption_mode; + u8 flags; + u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE]; + u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE]; + }; + + #define FSCRYPT_KEY_IDENTIFIER_SIZE 16 + struct fscrypt_context_v2 { + u8 version; u8 contents_encryption_mode; u8 filenames_encryption_mode; u8 flags; - u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE]; + u8 __reserved[4]; + u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]; u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE]; }; -Note that :c:type:`struct fscrypt_context` contains the same -information as :c:type:`struct fscrypt_policy` (see `Setting an -encryption policy`_), except that :c:type:`struct fscrypt_context` -also contains a nonce. The nonce is randomly generated by the kernel -and is used to derive the inode's encryption key as described in -`Per-file keys`_. +The context structs contain the same information as the corresponding +policy structs (see `Setting an encryption policy`_), except that the +context structs also contain a nonce. The nonce is randomly generated +by the kernel and is used as KDF input or as a tweak to cause +different files to be encrypted differently; see `Per-file keys`_ and +`DIRECT_KEY and per-mode keys`_. Data path changes ----------------- diff --git a/Documentation/filesystems/fsverity.rst b/Documentation/filesystems/fsverity.rst new file mode 100644 index 0000000000000000000000000000000000000000..42a0b6dd9e0b68539b0ec92db3a7bd455410b145 --- /dev/null +++ b/Documentation/filesystems/fsverity.rst @@ -0,0 +1,726 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. _fsverity: + +======================================================= +fs-verity: read-only file-based authenticity protection +======================================================= + +Introduction +============ + +fs-verity (``fs/verity/``) is a support layer that filesystems can +hook into to support transparent integrity and authenticity protection +of read-only files. Currently, it is supported by the ext4 and f2fs +filesystems. Like fscrypt, not too much filesystem-specific code is +needed to support fs-verity. + +fs-verity is similar to `dm-verity +`_ +but works on files rather than block devices. On regular files on +filesystems supporting fs-verity, userspace can execute an ioctl that +causes the filesystem to build a Merkle tree for the file and persist +it to a filesystem-specific location associated with the file. + +After this, the file is made readonly, and all reads from the file are +automatically verified against the file's Merkle tree. Reads of any +corrupted data, including mmap reads, will fail. + +Userspace can use another ioctl to retrieve the root hash (actually +the "file measurement", which is a hash that includes the root hash) +that fs-verity is enforcing for the file. This ioctl executes in +constant time, regardless of the file size. + +fs-verity is essentially a way to hash a file in constant time, +subject to the caveat that reads which would violate the hash will +fail at runtime. + +Use cases +========= + +By itself, the base fs-verity feature only provides integrity +protection, i.e. detection of accidental (non-malicious) corruption. + +However, because fs-verity makes retrieving the file hash extremely +efficient, it's primarily meant to be used as a tool to support +authentication (detection of malicious modifications) or auditing +(logging file hashes before use). + +Trusted userspace code (e.g. operating system code running on a +read-only partition that is itself authenticated by dm-verity) can +authenticate the contents of an fs-verity file by using the +`FS_IOC_MEASURE_VERITY`_ ioctl to retrieve its hash, then verifying a +digital signature of it. + +A standard file hash could be used instead of fs-verity. However, +this is inefficient if the file is large and only a small portion may +be accessed. This is often the case for Android application package +(APK) files, for example. These typically contain many translations, +classes, and other resources that are infrequently or even never +accessed on a particular device. It would be slow and wasteful to +read and hash the entire file before starting the application. + +Unlike an ahead-of-time hash, fs-verity also re-verifies data each +time it's paged in. This ensures that malicious disk firmware can't +undetectably change the contents of the file at runtime. + +fs-verity does not replace or obsolete dm-verity. dm-verity should +still be used on read-only filesystems. fs-verity is for files that +must live on a read-write filesystem because they are independently +updated and potentially user-installed, so dm-verity cannot be used. + +The base fs-verity feature is a hashing mechanism only; actually +authenticating the files is up to userspace. However, to meet some +users' needs, fs-verity optionally supports a simple signature +verification mechanism where users can configure the kernel to require +that all fs-verity files be signed by a key loaded into a keyring; see +`Built-in signature verification`_. Support for fs-verity file hashes +in IMA (Integrity Measurement Architecture) policies is also planned. + +User API +======== + +FS_IOC_ENABLE_VERITY +-------------------- + +The FS_IOC_ENABLE_VERITY ioctl enables fs-verity on a file. It takes +in a pointer to a :c:type:`struct fsverity_enable_arg`, defined as +follows:: + + struct fsverity_enable_arg { + __u32 version; + __u32 hash_algorithm; + __u32 block_size; + __u32 salt_size; + __u64 salt_ptr; + __u32 sig_size; + __u32 __reserved1; + __u64 sig_ptr; + __u64 __reserved2[11]; + }; + +This structure contains the parameters of the Merkle tree to build for +the file, and optionally contains a signature. It must be initialized +as follows: + +- ``version`` must be 1. +- ``hash_algorithm`` must be the identifier for the hash algorithm to + use for the Merkle tree, such as FS_VERITY_HASH_ALG_SHA256. See + ``include/uapi/linux/fsverity.h`` for the list of possible values. +- ``block_size`` must be the Merkle tree block size. Currently, this + must be equal to the system page size, which is usually 4096 bytes. + Other sizes may be supported in the future. This value is not + necessarily the same as the filesystem block size. +- ``salt_size`` is the size of the salt in bytes, or 0 if no salt is + provided. The salt is a value that is prepended to every hashed + block; it can be used to personalize the hashing for a particular + file or device. Currently the maximum salt size is 32 bytes. +- ``salt_ptr`` is the pointer to the salt, or NULL if no salt is + provided. +- ``sig_size`` is the size of the signature in bytes, or 0 if no + signature is provided. Currently the signature is (somewhat + arbitrarily) limited to 16128 bytes. See `Built-in signature + verification`_ for more information. +- ``sig_ptr`` is the pointer to the signature, or NULL if no + signature is provided. +- All reserved fields must be zeroed. + +FS_IOC_ENABLE_VERITY causes the filesystem to build a Merkle tree for +the file and persist it to a filesystem-specific location associated +with the file, then mark the file as a verity file. This ioctl may +take a long time to execute on large files, and it is interruptible by +fatal signals. + +FS_IOC_ENABLE_VERITY checks for write access to the inode. However, +it must be executed on an O_RDONLY file descriptor and no processes +can have the file open for writing. Attempts to open the file for +writing while this ioctl is executing will fail with ETXTBSY. (This +is necessary to guarantee that no writable file descriptors will exist +after verity is enabled, and to guarantee that the file's contents are +stable while the Merkle tree is being built over it.) + +On success, FS_IOC_ENABLE_VERITY returns 0, and the file becomes a +verity file. On failure (including the case of interruption by a +fatal signal), no changes are made to the file. + +FS_IOC_ENABLE_VERITY can fail with the following errors: + +- ``EACCES``: the process does not have write access to the file +- ``EBADMSG``: the signature is malformed +- ``EBUSY``: this ioctl is already running on the file +- ``EEXIST``: the file already has verity enabled +- ``EFAULT``: the caller provided inaccessible memory +- ``EINTR``: the operation was interrupted by a fatal signal +- ``EINVAL``: unsupported version, hash algorithm, or block size; or + reserved bits are set; or the file descriptor refers to neither a + regular file nor a directory. +- ``EISDIR``: the file descriptor refers to a directory +- ``EKEYREJECTED``: the signature doesn't match the file +- ``EMSGSIZE``: the salt or signature is too long +- ``ENOKEY``: the fs-verity keyring doesn't contain the certificate + needed to verify the signature +- ``ENOPKG``: fs-verity recognizes the hash algorithm, but it's not + available in the kernel's crypto API as currently configured (e.g. + for SHA-512, missing CONFIG_CRYPTO_SHA512). +- ``ENOTTY``: this type of filesystem does not implement fs-verity +- ``EOPNOTSUPP``: the kernel was not configured with fs-verity + support; or the filesystem superblock has not had the 'verity' + feature enabled on it; or the filesystem does not support fs-verity + on this file. (See `Filesystem support`_.) +- ``EPERM``: the file is append-only; or, a signature is required and + one was not provided. +- ``EROFS``: the filesystem is read-only +- ``ETXTBSY``: someone has the file open for writing. This can be the + caller's file descriptor, another open file descriptor, or the file + reference held by a writable memory map. + +FS_IOC_MEASURE_VERITY +--------------------- + +The FS_IOC_MEASURE_VERITY ioctl retrieves the measurement of a verity +file. The file measurement is a digest that cryptographically +identifies the file contents that are being enforced on reads. + +This ioctl takes in a pointer to a variable-length structure:: + + struct fsverity_digest { + __u16 digest_algorithm; + __u16 digest_size; /* input/output */ + __u8 digest[]; + }; + +``digest_size`` is an input/output field. On input, it must be +initialized to the number of bytes allocated for the variable-length +``digest`` field. + +On success, 0 is returned and the kernel fills in the structure as +follows: + +- ``digest_algorithm`` will be the hash algorithm used for the file + measurement. It will match ``fsverity_enable_arg::hash_algorithm``. +- ``digest_size`` will be the size of the digest in bytes, e.g. 32 + for SHA-256. (This can be redundant with ``digest_algorithm``.) +- ``digest`` will be the actual bytes of the digest. + +FS_IOC_MEASURE_VERITY is guaranteed to execute in constant time, +regardless of the size of the file. + +FS_IOC_MEASURE_VERITY can fail with the following errors: + +- ``EFAULT``: the caller provided inaccessible memory +- ``ENODATA``: the file is not a verity file +- ``ENOTTY``: this type of filesystem does not implement fs-verity +- ``EOPNOTSUPP``: the kernel was not configured with fs-verity + support, or the filesystem superblock has not had the 'verity' + feature enabled on it. (See `Filesystem support`_.) +- ``EOVERFLOW``: the digest is longer than the specified + ``digest_size`` bytes. Try providing a larger buffer. + +FS_IOC_GETFLAGS +--------------- + +The existing ioctl FS_IOC_GETFLAGS (which isn't specific to fs-verity) +can also be used to check whether a file has fs-verity enabled or not. +To do so, check for FS_VERITY_FL (0x00100000) in the returned flags. + +The verity flag is not settable via FS_IOC_SETFLAGS. You must use +FS_IOC_ENABLE_VERITY instead, since parameters must be provided. + +Accessing verity files +====================== + +Applications can transparently access a verity file just like a +non-verity one, with the following exceptions: + +- Verity files are readonly. They cannot be opened for writing or + truncate()d, even if the file mode bits allow it. Attempts to do + one of these things will fail with EPERM. However, changes to + metadata such as owner, mode, timestamps, and xattrs are still + allowed, since these are not measured by fs-verity. Verity files + can also still be renamed, deleted, and linked to. + +- Direct I/O is not supported on verity files. Attempts to use direct + I/O on such files will fall back to buffered I/O. + +- DAX (Direct Access) is not supported on verity files, because this + would circumvent the data verification. + +- Reads of data that doesn't match the verity Merkle tree will fail + with EIO (for read()) or SIGBUS (for mmap() reads). + +- If the sysctl "fs.verity.require_signatures" is set to 1 and the + file's verity measurement is not signed by a key in the fs-verity + keyring, then opening the file will fail. See `Built-in signature + verification`_. + +Direct access to the Merkle tree is not supported. Therefore, if a +verity file is copied, or is backed up and restored, then it will lose +its "verity"-ness. fs-verity is primarily meant for files like +executables that are managed by a package manager. + +File measurement computation +============================ + +This section describes how fs-verity hashes the file contents using a +Merkle tree to produce the "file measurement" which cryptographically +identifies the file contents. This algorithm is the same for all +filesystems that support fs-verity. + +Userspace only needs to be aware of this algorithm if it needs to +compute the file measurement itself, e.g. in order to sign the file. + +.. _fsverity_merkle_tree: + +Merkle tree +----------- + +The file contents is divided into blocks, where the block size is +configurable but is usually 4096 bytes. The end of the last block is +zero-padded if needed. Each block is then hashed, producing the first +level of hashes. Then, the hashes in this first level are grouped +into 'blocksize'-byte blocks (zero-padding the ends as needed) and +these blocks are hashed, producing the second level of hashes. This +proceeds up the tree until only a single block remains. The hash of +this block is the "Merkle tree root hash". + +If the file fits in one block and is nonempty, then the "Merkle tree +root hash" is simply the hash of the single data block. If the file +is empty, then the "Merkle tree root hash" is all zeroes. + +The "blocks" here are not necessarily the same as "filesystem blocks". + +If a salt was specified, then it's zero-padded to the closest multiple +of the input size of the hash algorithm's compression function, e.g. +64 bytes for SHA-256 or 128 bytes for SHA-512. The padded salt is +prepended to every data or Merkle tree block that is hashed. + +The purpose of the block padding is to cause every hash to be taken +over the same amount of data, which simplifies the implementation and +keeps open more possibilities for hardware acceleration. The purpose +of the salt padding is to make the salting "free" when the salted hash +state is precomputed, then imported for each hash. + +Example: in the recommended configuration of SHA-256 and 4K blocks, +128 hash values fit in each block. Thus, each level of the Merkle +tree is approximately 128 times smaller than the previous, and for +large files the Merkle tree's size converges to approximately 1/127 of +the original file size. However, for small files, the padding is +significant, making the space overhead proportionally more. + +.. _fsverity_descriptor: + +fs-verity descriptor +-------------------- + +By itself, the Merkle tree root hash is ambiguous. For example, it +can't a distinguish a large file from a small second file whose data +is exactly the top-level hash block of the first file. Ambiguities +also arise from the convention of padding to the next block boundary. + +To solve this problem, the verity file measurement is actually +computed as a hash of the following structure, which contains the +Merkle tree root hash as well as other fields such as the file size:: + + struct fsverity_descriptor { + __u8 version; /* must be 1 */ + __u8 hash_algorithm; /* Merkle tree hash algorithm */ + __u8 log_blocksize; /* log2 of size of data and tree blocks */ + __u8 salt_size; /* size of salt in bytes; 0 if none */ + __le32 sig_size; /* must be 0 */ + __le64 data_size; /* size of file the Merkle tree is built over */ + __u8 root_hash[64]; /* Merkle tree root hash */ + __u8 salt[32]; /* salt prepended to each hashed block */ + __u8 __reserved[144]; /* must be 0's */ + }; + +Note that the ``sig_size`` field must be set to 0 for the purpose of +computing the file measurement, even if a signature was provided (or +will be provided) to `FS_IOC_ENABLE_VERITY`_. + +Built-in signature verification +=============================== + +With CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y, fs-verity supports putting +a portion of an authentication policy (see `Use cases`_) in the +kernel. Specifically, it adds support for: + +1. At fs-verity module initialization time, a keyring ".fs-verity" is + created. The root user can add trusted X.509 certificates to this + keyring using the add_key() system call, then (when done) + optionally use keyctl_restrict_keyring() to prevent additional + certificates from being added. + +2. `FS_IOC_ENABLE_VERITY`_ accepts a pointer to a PKCS#7 formatted + detached signature in DER format of the file measurement. On + success, this signature is persisted alongside the Merkle tree. + Then, any time the file is opened, the kernel will verify the + file's actual measurement against this signature, using the + certificates in the ".fs-verity" keyring. + +3. A new sysctl "fs.verity.require_signatures" is made available. + When set to 1, the kernel requires that all verity files have a + correctly signed file measurement as described in (2). + +File measurements must be signed in the following format, which is +similar to the structure used by `FS_IOC_MEASURE_VERITY`_:: + + struct fsverity_signed_digest { + char magic[8]; /* must be "FSVerity" */ + __le16 digest_algorithm; + __le16 digest_size; + __u8 digest[]; + }; + +fs-verity's built-in signature verification support is meant as a +relatively simple mechanism that can be used to provide some level of +authenticity protection for verity files, as an alternative to doing +the signature verification in userspace or using IMA-appraisal. +However, with this mechanism, userspace programs still need to check +that the verity bit is set, and there is no protection against verity +files being swapped around. + +Filesystem support +================== + +fs-verity is currently supported by the ext4 and f2fs filesystems. +The CONFIG_FS_VERITY kconfig option must be enabled to use fs-verity +on either filesystem. + +``include/linux/fsverity.h`` declares the interface between the +``fs/verity/`` support layer and filesystems. Briefly, filesystems +must provide an ``fsverity_operations`` structure that provides +methods to read and write the verity metadata to a filesystem-specific +location, including the Merkle tree blocks and +``fsverity_descriptor``. Filesystems must also call functions in +``fs/verity/`` at certain times, such as when a file is opened or when +pages have been read into the pagecache. (See `Verifying data`_.) + +ext4 +---- + +ext4 supports fs-verity since Linux TODO and e2fsprogs v1.45.2. + +To create verity files on an ext4 filesystem, the filesystem must have +been formatted with ``-O verity`` or had ``tune2fs -O verity`` run on +it. "verity" is an RO_COMPAT filesystem feature, so once set, old +kernels will only be able to mount the filesystem readonly, and old +versions of e2fsck will be unable to check the filesystem. Moreover, +currently ext4 only supports mounting a filesystem with the "verity" +feature when its block size is equal to PAGE_SIZE (often 4096 bytes). + +ext4 sets the EXT4_VERITY_FL on-disk inode flag on verity files. It +can only be set by `FS_IOC_ENABLE_VERITY`_, and it cannot be cleared. + +ext4 also supports encryption, which can be used simultaneously with +fs-verity. In this case, the plaintext data is verified rather than +the ciphertext. This is necessary in order to make the file +measurement meaningful, since every file is encrypted differently. + +ext4 stores the verity metadata (Merkle tree and fsverity_descriptor) +past the end of the file, starting at the first 64K boundary beyond +i_size. This approach works because (a) verity files are readonly, +and (b) pages fully beyond i_size aren't visible to userspace but can +be read/written internally by ext4 with only some relatively small +changes to ext4. This approach avoids having to depend on the +EA_INODE feature and on rearchitecturing ext4's xattr support to +support paging multi-gigabyte xattrs into memory, and to support +encrypting xattrs. Note that the verity metadata *must* be encrypted +when the file is, since it contains hashes of the plaintext data. + +Currently, ext4 verity only supports the case where the Merkle tree +block size, filesystem block size, and page size are all the same. It +also only supports extent-based files. + +f2fs +---- + +f2fs supports fs-verity since Linux TODO and f2fs-tools v1.11.0. + +To create verity files on an f2fs filesystem, the filesystem must have +been formatted with ``-O verity``. + +f2fs sets the FADVISE_VERITY_BIT on-disk inode flag on verity files. +It can only be set by `FS_IOC_ENABLE_VERITY`_, and it cannot be +cleared. + +Like ext4, f2fs stores the verity metadata (Merkle tree and +fsverity_descriptor) past the end of the file, starting at the first +64K boundary beyond i_size. See explanation for ext4 above. +Moreover, f2fs supports at most 4096 bytes of xattr entries per inode +which wouldn't be enough for even a single Merkle tree block. + +Currently, f2fs verity only supports a Merkle tree block size of 4096. +Also, f2fs doesn't support enabling verity on files that currently +have atomic or volatile writes pending. + +Implementation details +====================== + +Verifying data +-------------- + +fs-verity ensures that all reads of a verity file's data are verified, +regardless of which syscall is used to do the read (e.g. mmap(), +read(), pread()) and regardless of whether it's the first read or a +later read (unless the later read can return cached data that was +already verified). Below, we describe how filesystems implement this. + +Pagecache +~~~~~~~~~ + +For filesystems using Linux's pagecache, the ``->readpage()`` and +``->readpages()`` methods must be modified to verify pages before they +are marked Uptodate. Merely hooking ``->read_iter()`` would be +insufficient, since ``->read_iter()`` is not used for memory maps. + +Therefore, fs/verity/ provides a function fsverity_verify_page() which +verifies a page that has been read into the pagecache of a verity +inode, but is still locked and not Uptodate, so it's not yet readable +by userspace. As needed to do the verification, +fsverity_verify_page() will call back into the filesystem to read +Merkle tree pages via fsverity_operations::read_merkle_tree_page(). + +fsverity_verify_page() returns false if verification failed; in this +case, the filesystem must not set the page Uptodate. Following this, +as per the usual Linux pagecache behavior, attempts by userspace to +read() from the part of the file containing the page will fail with +EIO, and accesses to the page within a memory map will raise SIGBUS. + +fsverity_verify_page() currently only supports the case where the +Merkle tree block size is equal to PAGE_SIZE (often 4096 bytes). + +In principle, fsverity_verify_page() verifies the entire path in the +Merkle tree from the data page to the root hash. However, for +efficiency the filesystem may cache the hash pages. Therefore, +fsverity_verify_page() only ascends the tree reading hash pages until +an already-verified hash page is seen, as indicated by the PageChecked +bit being set. It then verifies the path to that page. + +This optimization, which is also used by dm-verity, results in +excellent sequential read performance. This is because usually (e.g. +127 in 128 times for 4K blocks and SHA-256) the hash page from the +bottom level of the tree will already be cached and checked from +reading a previous data page. However, random reads perform worse. + +Block device based filesystems +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Block device based filesystems (e.g. ext4 and f2fs) in Linux also use +the pagecache, so the above subsection applies too. However, they +also usually read many pages from a file at once, grouped into a +structure called a "bio". To make it easier for these types of +filesystems to support fs-verity, fs/verity/ also provides a function +fsverity_verify_bio() which verifies all pages in a bio. + +ext4 and f2fs also support encryption. If a verity file is also +encrypted, the pages must be decrypted before being verified. To +support this, these filesystems allocate a "post-read context" for +each bio and store it in ``->bi_private``:: + + struct bio_post_read_ctx { + struct bio *bio; + struct work_struct work; + unsigned int cur_step; + unsigned int enabled_steps; + }; + +``enabled_steps`` is a bitmask that specifies whether decryption, +verity, or both is enabled. After the bio completes, for each needed +postprocessing step the filesystem enqueues the bio_post_read_ctx on a +workqueue, and then the workqueue work does the decryption or +verification. Finally, pages where no decryption or verity error +occurred are marked Uptodate, and the pages are unlocked. + +Files on ext4 and f2fs may contain holes. Normally, ``->readpages()`` +simply zeroes holes and sets the corresponding pages Uptodate; no bios +are issued. To prevent this case from bypassing fs-verity, these +filesystems use fsverity_verify_page() to verify hole pages. + +ext4 and f2fs disable direct I/O on verity files, since otherwise +direct I/O would bypass fs-verity. (They also do the same for +encrypted files.) + +Userspace utility +================= + +This document focuses on the kernel, but a userspace utility for +fs-verity can be found at: + + https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/fsverity-utils.git + +See the README.md file in the fsverity-utils source tree for details, +including examples of setting up fs-verity protected files. + +Tests +===== + +To test fs-verity, use xfstests. For example, using `kvm-xfstests +`_:: + + kvm-xfstests -c ext4,f2fs -g verity + +FAQ +=== + +This section answers frequently asked questions about fs-verity that +weren't already directly answered in other parts of this document. + +:Q: Why isn't fs-verity part of IMA? +:A: fs-verity and IMA (Integrity Measurement Architecture) have + different focuses. fs-verity is a filesystem-level mechanism for + hashing individual files using a Merkle tree. In contrast, IMA + specifies a system-wide policy that specifies which files are + hashed and what to do with those hashes, such as log them, + authenticate them, or add them to a measurement list. + + IMA is planned to support the fs-verity hashing mechanism as an + alternative to doing full file hashes, for people who want the + performance and security benefits of the Merkle tree based hash. + But it doesn't make sense to force all uses of fs-verity to be + through IMA. As a standalone filesystem feature, fs-verity + already meets many users' needs, and it's testable like other + filesystem features e.g. with xfstests. + +:Q: Isn't fs-verity useless because the attacker can just modify the + hashes in the Merkle tree, which is stored on-disk? +:A: To verify the authenticity of an fs-verity file you must verify + the authenticity of the "file measurement", which is basically the + root hash of the Merkle tree. See `Use cases`_. + +:Q: Isn't fs-verity useless because the attacker can just replace a + verity file with a non-verity one? +:A: See `Use cases`_. In the initial use case, it's really trusted + userspace code that authenticates the files; fs-verity is just a + tool to do this job efficiently and securely. The trusted + userspace code will consider non-verity files to be inauthentic. + +:Q: Why does the Merkle tree need to be stored on-disk? Couldn't you + store just the root hash? +:A: If the Merkle tree wasn't stored on-disk, then you'd have to + compute the entire tree when the file is first accessed, even if + just one byte is being read. This is a fundamental consequence of + how Merkle tree hashing works. To verify a leaf node, you need to + verify the whole path to the root hash, including the root node + (the thing which the root hash is a hash of). But if the root + node isn't stored on-disk, you have to compute it by hashing its + children, and so on until you've actually hashed the entire file. + + That defeats most of the point of doing a Merkle tree-based hash, + since if you have to hash the whole file ahead of time anyway, + then you could simply do sha256(file) instead. That would be much + simpler, and a bit faster too. + + It's true that an in-memory Merkle tree could still provide the + advantage of verification on every read rather than just on the + first read. However, it would be inefficient because every time a + hash page gets evicted (you can't pin the entire Merkle tree into + memory, since it may be very large), in order to restore it you + again need to hash everything below it in the tree. This again + defeats most of the point of doing a Merkle tree-based hash, since + a single block read could trigger re-hashing gigabytes of data. + +:Q: But couldn't you store just the leaf nodes and compute the rest? +:A: See previous answer; this really just moves up one level, since + one could alternatively interpret the data blocks as being the + leaf nodes of the Merkle tree. It's true that the tree can be + computed much faster if the leaf level is stored rather than just + the data, but that's only because each level is less than 1% the + size of the level below (assuming the recommended settings of + SHA-256 and 4K blocks). For the exact same reason, by storing + "just the leaf nodes" you'd already be storing over 99% of the + tree, so you might as well simply store the whole tree. + +:Q: Can the Merkle tree be built ahead of time, e.g. distributed as + part of a package that is installed to many computers? +:A: This isn't currently supported. It was part of the original + design, but was removed to simplify the kernel UAPI and because it + wasn't a critical use case. Files are usually installed once and + used many times, and cryptographic hashing is somewhat fast on + most modern processors. + +:Q: Why doesn't fs-verity support writes? +:A: Write support would be very difficult and would require a + completely different design, so it's well outside the scope of + fs-verity. Write support would require: + + - A way to maintain consistency between the data and hashes, + including all levels of hashes, since corruption after a crash + (especially of potentially the entire file!) is unacceptable. + The main options for solving this are data journalling, + copy-on-write, and log-structured volume. But it's very hard to + retrofit existing filesystems with new consistency mechanisms. + Data journalling is available on ext4, but is very slow. + + - Rebuilding the the Merkle tree after every write, which would be + extremely inefficient. Alternatively, a different authenticated + dictionary structure such as an "authenticated skiplist" could + be used. However, this would be far more complex. + + Compare it to dm-verity vs. dm-integrity. dm-verity is very + simple: the kernel just verifies read-only data against a + read-only Merkle tree. In contrast, dm-integrity supports writes + but is slow, is much more complex, and doesn't actually support + full-device authentication since it authenticates each sector + independently, i.e. there is no "root hash". It doesn't really + make sense for the same device-mapper target to support these two + very different cases; the same applies to fs-verity. + +:Q: Since verity files are immutable, why isn't the immutable bit set? +:A: The existing "immutable" bit (FS_IMMUTABLE_FL) already has a + specific set of semantics which not only make the file contents + read-only, but also prevent the file from being deleted, renamed, + linked to, or having its owner or mode changed. These extra + properties are unwanted for fs-verity, so reusing the immutable + bit isn't appropriate. + +:Q: Why does the API use ioctls instead of setxattr() and getxattr()? +:A: Abusing the xattr interface for basically arbitrary syscalls is + heavily frowned upon by most of the Linux filesystem developers. + An xattr should really just be an xattr on-disk, not an API to + e.g. magically trigger construction of a Merkle tree. + +:Q: Does fs-verity support remote filesystems? +:A: Only ext4 and f2fs support is implemented currently, but in + principle any filesystem that can store per-file verity metadata + can support fs-verity, regardless of whether it's local or remote. + Some filesystems may have fewer options of where to store the + verity metadata; one possibility is to store it past the end of + the file and "hide" it from userspace by manipulating i_size. The + data verification functions provided by ``fs/verity/`` also assume + that the filesystem uses the Linux pagecache, but both local and + remote filesystems normally do so. + +:Q: Why is anything filesystem-specific at all? Shouldn't fs-verity + be implemented entirely at the VFS level? +:A: There are many reasons why this is not possible or would be very + difficult, including the following: + + - To prevent bypassing verification, pages must not be marked + Uptodate until they've been verified. Currently, each + filesystem is responsible for marking pages Uptodate via + ``->readpages()``. Therefore, currently it's not possible for + the VFS to do the verification on its own. Changing this would + require significant changes to the VFS and all filesystems. + + - It would require defining a filesystem-independent way to store + the verity metadata. Extended attributes don't work for this + because (a) the Merkle tree may be gigabytes, but many + filesystems assume that all xattrs fit into a single 4K + filesystem block, and (b) ext4 and f2fs encryption doesn't + encrypt xattrs, yet the Merkle tree *must* be encrypted when the + file contents are, because it stores hashes of the plaintext + file contents. + + So the verity metadata would have to be stored in an actual + file. Using a separate file would be very ugly, since the + metadata is fundamentally part of the file to be protected, and + it could cause problems where users could delete the real file + but not the metadata file or vice versa. On the other hand, + having it be in the same file would break applications unless + filesystems' notion of i_size were divorced from the VFS's, + which would be complex and require changes to all filesystems. + + - It's desirable that FS_IOC_ENABLE_VERITY uses the filesystem's + transaction mechanism so that either the file ends up with + verity enabled, or no changes were made. Allowing intermediate + states to occur after a crash may cause problems. diff --git a/Documentation/filesystems/index.rst b/Documentation/filesystems/index.rst index 2de2fe2ab07862ba458da8715b1e819f8e9309ec..fd2bcf99cda0aabb88fed924bcaddc48e39a4c8f 100644 --- a/Documentation/filesystems/index.rst +++ b/Documentation/filesystems/index.rst @@ -20,6 +20,10 @@ algorithms work. path-lookup api-summary splice + locking + directory-locking + + porting Filesystem support layers ========================= @@ -32,3 +36,4 @@ filesystem implementations. journalling fscrypt + fsverity diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/locking.rst similarity index 79% rename from Documentation/filesystems/Locking rename to Documentation/filesystems/locking.rst index 204dd3ea36bb3a5989eda6e62c4162afed57ae94..fc3a0704553cf5fd7f67cc842cc41d6bae891414 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/locking.rst @@ -1,14 +1,22 @@ - The text below describes the locking rules for VFS-related methods. +======= +Locking +======= + +The text below describes the locking rules for VFS-related methods. It is (believed to be) up-to-date. *Please*, if you change anything in prototypes or locking protocols - update this file. And update the relevant instances in the tree, don't leave that to maintainers of filesystems/devices/ etc. At the very least, put the list of dubious cases in the end of this file. Don't turn it into log - maintainers of out-of-the-tree code are supposed to be able to use diff(1). - Thing currently missing here: socket operations. Alexey? ---------------------------- dentry_operations -------------------------- -prototypes: +Thing currently missing here: socket operations. Alexey? + +dentry_operations +================= + +prototypes:: + int (*d_revalidate)(struct dentry *, unsigned int); int (*d_weak_revalidate)(struct dentry *, unsigned int); int (*d_hash)(const struct dentry *, struct qstr *); @@ -24,23 +32,30 @@ prototypes: struct dentry *(*d_real)(struct dentry *, const struct inode *); locking rules: - rename_lock ->d_lock may block rcu-walk -d_revalidate: no no yes (ref-walk) maybe -d_weak_revalidate:no no yes no -d_hash no no no maybe -d_compare: yes no no maybe -d_delete: no yes no no -d_init: no no yes no -d_release: no no yes no -d_prune: no yes no no -d_iput: no no yes no -d_dname: no no no no -d_automount: no no yes no -d_manage: no no yes (ref-walk) maybe -d_real no no yes no - ---------------------------- inode_operations --------------------------- -prototypes: + +================== =========== ======== ============== ======== +ops rename_lock ->d_lock may block rcu-walk +================== =========== ======== ============== ======== +d_revalidate: no no yes (ref-walk) maybe +d_weak_revalidate: no no yes no +d_hash no no no maybe +d_compare: yes no no maybe +d_delete: no yes no no +d_init: no no yes no +d_release: no no yes no +d_prune: no yes no no +d_iput: no no yes no +d_dname: no no no no +d_automount: no no yes no +d_manage: no no yes (ref-walk) maybe +d_real no no yes no +================== =========== ======== ============== ======== + +inode_operations +================ + +prototypes:: + int (*create) (struct inode *,struct dentry *,umode_t, bool); struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int); int (*link) (struct dentry *,struct inode *,struct dentry *); @@ -68,7 +83,10 @@ prototypes: locking rules: all may block - i_rwsem(inode) + +============ ============================================= +ops i_rwsem(inode) +============ ============================================= lookup: shared create: exclusive link: exclusive (both) @@ -89,17 +107,21 @@ fiemap: no update_time: no atomic_open: exclusive tmpfile: no +============ ============================================= Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_rwsem exclusive on victim. cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem. -See Documentation/filesystems/directory-locking for more detailed discussion +See Documentation/filesystems/directory-locking.rst for more detailed discussion of the locking scheme for directory operations. ------------------------ xattr_handler operations ----------------------- -prototypes: +xattr_handler operations +======================== + +prototypes:: + bool (*list)(struct dentry *dentry); int (*get)(const struct xattr_handler *handler, struct dentry *dentry, struct inode *inode, const char *name, void *buffer, @@ -110,13 +132,20 @@ prototypes: locking rules: all may block - i_rwsem(inode) + +===== ============== +ops i_rwsem(inode) +===== ============== list: no get: no set: exclusive +===== ============== + +super_operations +================ + +prototypes:: ---------------------------- super_operations --------------------------- -prototypes: struct inode *(*alloc_inode)(struct super_block *sb); void (*free_inode)(struct inode *); void (*destroy_inode)(struct inode *); @@ -138,7 +167,10 @@ prototypes: locking rules: All may block [not true, see below] - s_umount + +====================== ============ ======================== +ops s_umount note +====================== ============ ======================== alloc_inode: free_inode: called from RCU callback destroy_inode: @@ -157,6 +189,7 @@ show_options: no (namespace_sem) quota_read: no (see below) quota_write: no (see below) bdev_try_to_free_page: no (see below) +====================== ============ ======================== ->statfs() has s_umount (shared) when called by ustat(2) (native or compat), but that's an accident of bad API; s_umount is used to pin @@ -164,31 +197,44 @@ the superblock down when we only have dev_t given us by userland to identify the superblock. Everything else (statfs(), fstatfs(), etc.) doesn't hold it when calling ->statfs() - superblock is pinned down by resolving the pathname passed to syscall. + ->quota_read() and ->quota_write() functions are both guaranteed to be the only ones operating on the quota file by the quota code (via dqio_sem) (unless an admin really wants to screw up something and writes to quota files with quotas on). For other details about locking see also dquot_operations section. + ->bdev_try_to_free_page is called from the ->releasepage handler of the block device inode. See there for more details. ---------------------------- file_system_type --------------------------- -prototypes: +file_system_type +================ + +prototypes:: + struct dentry *(*mount) (struct file_system_type *, int, const char *, void *); void (*kill_sb) (struct super_block *); + locking rules: - may block + +======= ========= +ops may block +======= ========= mount yes kill_sb yes +======= ========= ->mount() returns ERR_PTR or the root dentry; its superblock should be locked on return. + ->kill_sb() takes a write-locked superblock, does all shutdown work on it, unlocks and drops the reference. ---------------------------- address_space_operations -------------------------- -prototypes: +address_space_operations +======================== +prototypes:: + int (*writepage)(struct page *page, struct writeback_control *wbc); int (*readpage)(struct file *, struct page *); int (*writepages)(struct address_space *, struct writeback_control *); @@ -218,14 +264,16 @@ prototypes: locking rules: All except set_page_dirty and freepage may block - PageLocked(page) i_rwsem +====================== ======================== ========= +ops PageLocked(page) i_rwsem +====================== ======================== ========= writepage: yes, unlocks (see below) readpage: yes, unlocks writepages: set_page_dirty no readpages: -write_begin: locks the page exclusive -write_end: yes, unlocks exclusive +write_begin: locks the page exclusive +write_end: yes, unlocks exclusive bmap: invalidatepage: yes releasepage: yes @@ -239,17 +287,18 @@ is_partially_uptodate: yes error_remove_page: yes swap_activate: no swap_deactivate: no +====================== ======================== ========= - ->write_begin(), ->write_end() and ->readpage() may be called from +->write_begin(), ->write_end() and ->readpage() may be called from the request handler (/dev/loop). - ->readpage() unlocks the page, either synchronously or via I/O +->readpage() unlocks the page, either synchronously or via I/O completion. - ->readpages() populates the pagecache with the passed pages and starts +->readpages() populates the pagecache with the passed pages and starts I/O against them. They come unlocked upon I/O completion. - ->writepage() is used for two purposes: for "memory cleansing" and for +->writepage() is used for two purposes: for "memory cleansing" and for "sync". These are quite different operations and the behaviour may differ depending upon the mode. @@ -297,70 +346,81 @@ will leave the page itself marked clean but it will be tagged as dirty in the radix tree. This incoherency can lead to all sorts of hard-to-debug problems in the filesystem like having dirty inodes at umount and losing written data. - ->writepages() is used for periodic writeback and for syscall-initiated +->writepages() is used for periodic writeback and for syscall-initiated sync operations. The address_space should start I/O against at least -*nr_to_write pages. *nr_to_write must be decremented for each page which is -written. The address_space implementation may write more (or less) pages -than *nr_to_write asks for, but it should try to be reasonably close. If -nr_to_write is NULL, all dirty pages must be written. +``*nr_to_write`` pages. ``*nr_to_write`` must be decremented for each page +which is written. The address_space implementation may write more (or less) +pages than ``*nr_to_write`` asks for, but it should try to be reasonably close. +If nr_to_write is NULL, all dirty pages must be written. writepages should _only_ write pages which are present on mapping->io_pages. - ->set_page_dirty() is called from various places in the kernel +->set_page_dirty() is called from various places in the kernel when the target page is marked as needing writeback. It may be called under spinlock (it cannot block) and is sometimes called with the page not locked. - ->bmap() is currently used by legacy ioctl() (FIBMAP) provided by some +->bmap() is currently used by legacy ioctl() (FIBMAP) provided by some filesystems and by the swapper. The latter will eventually go away. Please, keep it that way and don't breed new callers. - ->invalidatepage() is called when the filesystem must attempt to drop +->invalidatepage() is called when the filesystem must attempt to drop some or all of the buffers from the page when it is being truncated. It returns zero on success. If ->invalidatepage is zero, the kernel uses block_invalidatepage() instead. - ->releasepage() is called when the kernel is about to try to drop the +->releasepage() is called when the kernel is about to try to drop the buffers from the page in preparation for freeing it. It returns zero to indicate that the buffers are (or may be) freeable. If ->releasepage is zero, the kernel assumes that the fs has no private interest in the buffers. - ->freepage() is called when the kernel is done dropping the page +->freepage() is called when the kernel is done dropping the page from the page cache. - ->launder_page() may be called prior to releasing a page if +->launder_page() may be called prior to releasing a page if it is still found to be dirty. It returns zero if the page was successfully cleaned, or an error value if not. Note that in order to prevent the page getting mapped back in and redirtied, it needs to be kept locked across the entire operation. - ->swap_activate will be called with a non-zero argument on +->swap_activate will be called with a non-zero argument on files backing (non block device backed) swapfiles. A return value of zero indicates success, in which case this file can be used for backing swapspace. The swapspace operations will be proxied to the address space operations. - ->swap_deactivate() will be called in the sys_swapoff() +->swap_deactivate() will be called in the sys_swapoff() path after ->swap_activate() returned success. ------------------------ file_lock_operations ------------------------------ -prototypes: +file_lock_operations +==================== + +prototypes:: + void (*fl_copy_lock)(struct file_lock *, struct file_lock *); void (*fl_release_private)(struct file_lock *); locking rules: - inode->i_lock may block + +=================== ============= ========= +ops inode->i_lock may block +=================== ============= ========= fl_copy_lock: yes no -fl_release_private: maybe maybe[1] +fl_release_private: maybe maybe[1]_ +=================== ============= ========= + +.. [1]: + ->fl_release_private for flock or POSIX locks is currently allowed + to block. Leases however can still be freed while the i_lock is held and + so fl_release_private called on a lease should not block. -[1]: ->fl_release_private for flock or POSIX locks is currently allowed -to block. Leases however can still be freed while the i_lock is held and -so fl_release_private called on a lease should not block. +lock_manager_operations +======================= + +prototypes:: ------------------------ lock_manager_operations --------------------------- -prototypes: void (*lm_notify)(struct file_lock *); /* unblock callback */ int (*lm_grant)(struct file_lock *, struct file_lock *, int); void (*lm_break)(struct file_lock *); /* break_lease callback */ @@ -368,24 +428,33 @@ prototypes: locking rules: - inode->i_lock blocked_lock_lock may block +========== ============= ================= ========= +ops inode->i_lock blocked_lock_lock may block +========== ============= ================= ========= lm_notify: yes yes no lm_grant: no no no lm_break: yes no no lm_change yes no no +========== ============= ================= ========= + +buffer_head +=========== + +prototypes:: ---------------------------- buffer_head ----------------------------------- -prototypes: void (*b_end_io)(struct buffer_head *bh, int uptodate); locking rules: - called from interrupts. In other words, extreme care is needed here. + +called from interrupts. In other words, extreme care is needed here. bh is locked, but that's all warranties we have here. Currently only RAID1, highmem, fs/buffer.c, and fs/ntfs/aops.c are providing these. Block devices call this method upon the IO completion. ---------------------------- block_device_operations ----------------------- -prototypes: +block_device_operations +======================= +prototypes:: + int (*open) (struct block_device *, fmode_t); int (*release) (struct gendisk *, fmode_t); int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); @@ -399,7 +468,10 @@ prototypes: void (*swap_slot_free_notify) (struct block_device *, unsigned long); locking rules: - bd_mutex + +======================= =================== +ops bd_mutex +======================= =================== open: yes release: yes ioctl: no @@ -410,6 +482,7 @@ unlock_native_capacity: no revalidate_disk: no getgeo: no swap_slot_free_notify: no (see below) +======================= =================== media_changed, unlock_native_capacity and revalidate_disk are called only from check_disk_change(). @@ -418,8 +491,11 @@ swap_slot_free_notify is called with swap_lock and sometimes the page lock held. ---------------------------- file_operations ------------------------------- -prototypes: +file_operations +=============== + +prototypes:: + loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); @@ -455,7 +531,6 @@ prototypes: size_t, unsigned int); int (*setlease)(struct file *, long, struct file_lock **, void **); long (*fallocate)(struct file *, int, loff_t, loff_t); -}; locking rules: All may block. @@ -490,8 +565,11 @@ in sys_read() and friends. the lease within the individual filesystem to record the result of the operation ---------------------------- dquot_operations ------------------------------- -prototypes: +dquot_operations +================ + +prototypes:: + int (*write_dquot) (struct dquot *); int (*acquire_dquot) (struct dquot *); int (*release_dquot) (struct dquot *); @@ -503,20 +581,26 @@ a proper locking wrt the filesystem and call the generic quota operations. What filesystem should expect from the generic quota functions: - FS recursion Held locks when called +============== ============ ========================= +ops FS recursion Held locks when called +============== ============ ========================= write_dquot: yes dqonoff_sem or dqptr_sem acquire_dquot: yes dqonoff_sem or dqptr_sem release_dquot: yes dqonoff_sem or dqptr_sem mark_dirty: no - write_info: yes dqonoff_sem +============== ============ ========================= FS recursion means calling ->quota_read() and ->quota_write() from superblock operations. More details about quota locking can be found in fs/dquot.c. ---------------------------- vm_operations_struct ----------------------------- -prototypes: +vm_operations_struct +==================== + +prototypes:: + void (*open)(struct vm_area_struct*); void (*close)(struct vm_area_struct*); vm_fault_t (*fault)(struct vm_area_struct*, struct vm_fault *); @@ -525,7 +609,10 @@ prototypes: int (*access)(struct vm_area_struct *, unsigned long, void*, int, int); locking rules: - mmap_sem PageLocked(page) + +============= ======== =========================== +ops mmap_sem PageLocked(page) +============= ======== =========================== open: yes close: yes fault: yes can return with page locked @@ -533,8 +620,9 @@ map_pages: yes page_mkwrite: yes can return with page locked pfn_mkwrite: yes access: yes +============= ======== =========================== - ->fault() is called when a previously not present pte is about +->fault() is called when a previously not present pte is about to be faulted in. The filesystem must find and return the page associated with the passed in "pgoff" in the vm_fault structure. If it is possible that the page may be truncated and/or invalidated, then the filesystem must lock @@ -542,7 +630,7 @@ the page, then ensure it is not already truncated (the page lock will block subsequent truncate), and then return with VM_FAULT_LOCKED, and the page locked. The VM will unlock the page. - ->map_pages() is called when VM asks to map easy accessible pages. +->map_pages() is called when VM asks to map easy accessible pages. Filesystem should find and map pages associated with offsets from "start_pgoff" till "end_pgoff". ->map_pages() is called with page table locked and must not block. If it's not possible to reach a page without blocking, @@ -551,25 +639,26 @@ page table entry. Pointer to entry associated with the page is passed in "pte" field in vm_fault structure. Pointers to entries for other offsets should be calculated relative to "pte". - ->page_mkwrite() is called when a previously read-only pte is +->page_mkwrite() is called when a previously read-only pte is about to become writeable. The filesystem again must ensure that there are no truncate/invalidate races, and then return with the page locked. If the page has been truncated, the filesystem should not look up a new page like the ->fault() handler, but simply return with VM_FAULT_NOPAGE, which will cause the VM to retry the fault. - ->pfn_mkwrite() is the same as page_mkwrite but when the pte is +->pfn_mkwrite() is the same as page_mkwrite but when the pte is VM_PFNMAP or VM_MIXEDMAP with a page-less entry. Expected return is VM_FAULT_NOPAGE. Or one of the VM_FAULT_ERROR types. The default behavior after this call is to make the pte read-write, unless pfn_mkwrite returns an error. - ->access() is called when get_user_pages() fails in +->access() is called when get_user_pages() fails in access_process_vm(), typically used to debug a process through /proc/pid/mem or ptrace. This function is needed only for VM_IO | VM_PFNMAP VMAs. -================================================================================ +-------------------------------------------------------------------------------- + Dubious stuff (if you break something or notice that it is broken and do not fix it yourself diff --git a/Documentation/filesystems/mandatory-locking.txt b/Documentation/filesystems/mandatory-locking.txt index 0979d1d2ca8bb94b21d15f7a0c193ac7ce9f4f9f..a251ca33164ae9d2e8902f94aeb680e7038faeae 100644 --- a/Documentation/filesystems/mandatory-locking.txt +++ b/Documentation/filesystems/mandatory-locking.txt @@ -169,3 +169,13 @@ havoc if they lock crucial files. The way around it is to change the file permissions (remove the setgid bit) before trying to read or write to it. Of course, that might be a bit tricky if the system is hung :-( +7. The "mand" mount option +-------------------------- +Mandatory locking is disabled on all filesystems by default, and must be +administratively enabled by mounting with "-o mand". That mount option +is only allowed if the mounting task has the CAP_SYS_ADMIN capability. + +Since kernel v4.5, it is possible to disable mandatory locking +altogether by setting CONFIG_MANDATORY_FILE_LOCKING to "n". A kernel +with this disabled will reject attempts to mount filesystems with the +"mand" mount option with the error status EPERM. diff --git a/Documentation/filesystems/nfs/Exporting b/Documentation/filesystems/nfs/exporting.rst similarity index 91% rename from Documentation/filesystems/nfs/Exporting rename to Documentation/filesystems/nfs/exporting.rst index 63889149f5322faa8173a8eda3ca235dd2eca68a..33d588a01ace108b081845d267a3ee2d715abe0b 100644 --- a/Documentation/filesystems/nfs/Exporting +++ b/Documentation/filesystems/nfs/exporting.rst @@ -1,3 +1,4 @@ +:orphan: Making Filesystems Exportable ============================= @@ -42,9 +43,9 @@ filehandle fragment, there is no automatic creation of a path prefix for the object. This leads to two related but distinct features of the dcache that are not needed for normal filesystem access. -1/ The dcache must sometimes contain objects that are not part of the +1. The dcache must sometimes contain objects that are not part of the proper prefix. i.e that are not connected to the root. -2/ The dcache must be prepared for a newly found (via ->lookup) directory +2. The dcache must be prepared for a newly found (via ->lookup) directory to already have a (non-connected) dentry, and must be able to move that dentry into place (based on the parent and name in the ->lookup). This is particularly needed for directories as @@ -52,7 +53,7 @@ the dcache that are not needed for normal filesystem access. To implement these features, the dcache has: -a/ A dentry flag DCACHE_DISCONNECTED which is set on +a. A dentry flag DCACHE_DISCONNECTED which is set on any dentry that might not be part of the proper prefix. This is set when anonymous dentries are created, and cleared when a dentry is noticed to be a child of a dentry which is in the proper @@ -71,48 +72,52 @@ a/ A dentry flag DCACHE_DISCONNECTED which is set on dentries. That guarantees that we won't need to hunt them down upon umount. -b/ A primitive for creation of secondary roots - d_obtain_root(inode). +b. A primitive for creation of secondary roots - d_obtain_root(inode). Those do _not_ bear DCACHE_DISCONNECTED. They are placed on the per-superblock list (->s_roots), so they can be located at umount time for eviction purposes. -c/ Helper routines to allocate anonymous dentries, and to help attach +c. Helper routines to allocate anonymous dentries, and to help attach loose directory dentries at lookup time. They are: + d_obtain_alias(inode) will return a dentry for the given inode. If the inode already has a dentry, one of those is returned. + If it doesn't, a new anonymous (IS_ROOT and - DCACHE_DISCONNECTED) dentry is allocated and attached. + DCACHE_DISCONNECTED) dentry is allocated and attached. + In the case of a directory, care is taken that only one dentry can ever be attached. + d_splice_alias(inode, dentry) will introduce a new dentry into the tree; either the passed-in dentry or a preexisting alias for the given inode (such as an anonymous one created by d_obtain_alias), if appropriate. It returns NULL when the passed-in dentry is used, following the calling convention of ->lookup. - + Filesystem Issues ----------------- For a filesystem to be exportable it must: - - 1/ provide the filehandle fragment routines described below. - 2/ make sure that d_splice_alias is used rather than d_add + + 1. provide the filehandle fragment routines described below. + 2. make sure that d_splice_alias is used rather than d_add when ->lookup finds an inode for a given parent and name. - If inode is NULL, d_splice_alias(inode, dentry) is equivalent to + If inode is NULL, d_splice_alias(inode, dentry) is equivalent to:: d_add(dentry, inode), NULL Similarly, d_splice_alias(ERR_PTR(err), dentry) = ERR_PTR(err) - Typically the ->lookup routine will simply end with a: + Typically the ->lookup routine will simply end with a:: return d_splice_alias(inode, dentry); } - A file system implementation declares that instances of the filesystem +A file system implementation declares that instances of the filesystem are exportable by setting the s_export_op field in the struct super_block. This field must point to a "struct export_operations" struct which has the following members: diff --git a/Documentation/filesystems/overlayfs.txt b/Documentation/filesystems/overlayfs.txt index 1da2f1668f0891a9151cd27218f4e1f6ca5c3732..845d689e0fd711672416669e501f68757e498a8f 100644 --- a/Documentation/filesystems/overlayfs.txt +++ b/Documentation/filesystems/overlayfs.txt @@ -302,7 +302,7 @@ beneath or above the path of another overlay lower layer path. Using an upper layer path and/or a workdir path that are already used by another overlay mount is not allowed and may fail with EBUSY. Using -partially overlapping paths is not allowed but will not fail with EBUSY. +partially overlapping paths is not allowed and may fail with EBUSY. If files are accessed from two overlayfs mounts which share or overlap the upper layer and/or workdir path the behavior of the overlay is undefined, though it will not result in a crash or deadlock. diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting deleted file mode 100644 index 6b7a41cfcaed05f9847553afb169181419599a85..0000000000000000000000000000000000000000 --- a/Documentation/filesystems/porting +++ /dev/null @@ -1,686 +0,0 @@ -Changes since 2.5.0: - ---- -[recommended] - -New helpers: sb_bread(), sb_getblk(), sb_find_get_block(), set_bh(), - sb_set_blocksize() and sb_min_blocksize(). - -Use them. - -(sb_find_get_block() replaces 2.4's get_hash_table()) - ---- -[recommended] - -New methods: ->alloc_inode() and ->destroy_inode(). - -Remove inode->u.foo_inode_i -Declare - struct foo_inode_info { - /* fs-private stuff */ - struct inode vfs_inode; - }; - static inline struct foo_inode_info *FOO_I(struct inode *inode) - { - return list_entry(inode, struct foo_inode_info, vfs_inode); - } - -Use FOO_I(inode) instead of &inode->u.foo_inode_i; - -Add foo_alloc_inode() and foo_destroy_inode() - the former should allocate -foo_inode_info and return the address of ->vfs_inode, the latter should free -FOO_I(inode) (see in-tree filesystems for examples). - -Make them ->alloc_inode and ->destroy_inode in your super_operations. - -Keep in mind that now you need explicit initialization of private data -typically between calling iget_locked() and unlocking the inode. - -At some point that will become mandatory. - ---- -[mandatory] - -Change of file_system_type method (->read_super to ->get_sb) - -->read_super() is no more. Ditto for DECLARE_FSTYPE and DECLARE_FSTYPE_DEV. - -Turn your foo_read_super() into a function that would return 0 in case of -success and negative number in case of error (-EINVAL unless you have more -informative error value to report). Call it foo_fill_super(). Now declare - -int foo_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) -{ - return get_sb_bdev(fs_type, flags, dev_name, data, foo_fill_super, - mnt); -} - -(or similar with s/bdev/nodev/ or s/bdev/single/, depending on the kind of -filesystem). - -Replace DECLARE_FSTYPE... with explicit initializer and have ->get_sb set as -foo_get_sb. - ---- -[mandatory] - -Locking change: ->s_vfs_rename_sem is taken only by cross-directory renames. -Most likely there is no need to change anything, but if you relied on -global exclusion between renames for some internal purpose - you need to -change your internal locking. Otherwise exclusion warranties remain the -same (i.e. parents and victim are locked, etc.). - ---- -[informational] - -Now we have the exclusion between ->lookup() and directory removal (by -->rmdir() and ->rename()). If you used to need that exclusion and do -it by internal locking (most of filesystems couldn't care less) - you -can relax your locking. - ---- -[mandatory] - -->lookup(), ->truncate(), ->create(), ->unlink(), ->mknod(), ->mkdir(), -->rmdir(), ->link(), ->lseek(), ->symlink(), ->rename() -and ->readdir() are called without BKL now. Grab it on entry, drop upon return -- that will guarantee the same locking you used to have. If your method or its -parts do not need BKL - better yet, now you can shift lock_kernel() and -unlock_kernel() so that they would protect exactly what needs to be -protected. - ---- -[mandatory] - -BKL is also moved from around sb operations. BKL should have been shifted into -individual fs sb_op functions. If you don't need it, remove it. - ---- -[informational] - -check for ->link() target not being a directory is done by callers. Feel -free to drop it... - ---- -[informational] - -->link() callers hold ->i_mutex on the object we are linking to. Some of your -problems might be over... - ---- -[mandatory] - -new file_system_type method - kill_sb(superblock). If you are converting -an existing filesystem, set it according to ->fs_flags: - FS_REQUIRES_DEV - kill_block_super - FS_LITTER - kill_litter_super - neither - kill_anon_super -FS_LITTER is gone - just remove it from fs_flags. - ---- -[mandatory] - - FS_SINGLE is gone (actually, that had happened back when ->get_sb() -went in - and hadn't been documented ;-/). Just remove it from fs_flags -(and see ->get_sb() entry for other actions). - ---- -[mandatory] - -->setattr() is called without BKL now. Caller _always_ holds ->i_mutex, so -watch for ->i_mutex-grabbing code that might be used by your ->setattr(). -Callers of notify_change() need ->i_mutex now. - ---- -[recommended] - -New super_block field "struct export_operations *s_export_op" for -explicit support for exporting, e.g. via NFS. The structure is fully -documented at its declaration in include/linux/fs.h, and in -Documentation/filesystems/nfs/Exporting. - -Briefly it allows for the definition of decode_fh and encode_fh operations -to encode and decode filehandles, and allows the filesystem to use -a standard helper function for decode_fh, and provide file-system specific -support for this helper, particularly get_parent. - -It is planned that this will be required for exporting once the code -settles down a bit. - -[mandatory] - -s_export_op is now required for exporting a filesystem. -isofs, ext2, ext3, resierfs, fat -can be used as examples of very different filesystems. - ---- -[mandatory] - -iget4() and the read_inode2 callback have been superseded by iget5_locked() -which has the following prototype, - - struct inode *iget5_locked(struct super_block *sb, unsigned long ino, - int (*test)(struct inode *, void *), - int (*set)(struct inode *, void *), - void *data); - -'test' is an additional function that can be used when the inode -number is not sufficient to identify the actual file object. 'set' -should be a non-blocking function that initializes those parts of a -newly created inode to allow the test function to succeed. 'data' is -passed as an opaque value to both test and set functions. - -When the inode has been created by iget5_locked(), it will be returned with the -I_NEW flag set and will still be locked. The filesystem then needs to finalize -the initialization. Once the inode is initialized it must be unlocked by -calling unlock_new_inode(). - -The filesystem is responsible for setting (and possibly testing) i_ino -when appropriate. There is also a simpler iget_locked function that -just takes the superblock and inode number as arguments and does the -test and set for you. - -e.g. - inode = iget_locked(sb, ino); - if (inode->i_state & I_NEW) { - err = read_inode_from_disk(inode); - if (err < 0) { - iget_failed(inode); - return err; - } - unlock_new_inode(inode); - } - -Note that if the process of setting up a new inode fails, then iget_failed() -should be called on the inode to render it dead, and an appropriate error -should be passed back to the caller. - ---- -[recommended] - -->getattr() finally getting used. See instances in nfs, minix, etc. - ---- -[mandatory] - -->revalidate() is gone. If your filesystem had it - provide ->getattr() -and let it call whatever you had as ->revlidate() + (for symlinks that -had ->revalidate()) add calls in ->follow_link()/->readlink(). - ---- -[mandatory] - -->d_parent changes are not protected by BKL anymore. Read access is safe -if at least one of the following is true: - * filesystem has no cross-directory rename() - * we know that parent had been locked (e.g. we are looking at -->d_parent of ->lookup() argument). - * we are called from ->rename(). - * the child's ->d_lock is held -Audit your code and add locking if needed. Notice that any place that is -not protected by the conditions above is risky even in the old tree - you -had been relying on BKL and that's prone to screwups. Old tree had quite -a few holes of that kind - unprotected access to ->d_parent leading to -anything from oops to silent memory corruption. - ---- -[mandatory] - - FS_NOMOUNT is gone. If you use it - just set SB_NOUSER in flags -(see rootfs for one kind of solution and bdev/socket/pipe for another). - ---- -[recommended] - - Use bdev_read_only(bdev) instead of is_read_only(kdev). The latter -is still alive, but only because of the mess in drivers/s390/block/dasd.c. -As soon as it gets fixed is_read_only() will die. - ---- -[mandatory] - -->permission() is called without BKL now. Grab it on entry, drop upon -return - that will guarantee the same locking you used to have. If -your method or its parts do not need BKL - better yet, now you can -shift lock_kernel() and unlock_kernel() so that they would protect -exactly what needs to be protected. - ---- -[mandatory] - -->statfs() is now called without BKL held. BKL should have been -shifted into individual fs sb_op functions where it's not clear that -it's safe to remove it. If you don't need it, remove it. - ---- -[mandatory] - - is_read_only() is gone; use bdev_read_only() instead. - ---- -[mandatory] - - destroy_buffers() is gone; use invalidate_bdev(). - ---- -[mandatory] - - fsync_dev() is gone; use fsync_bdev(). NOTE: lvm breakage is -deliberate; as soon as struct block_device * is propagated in a reasonable -way by that code fixing will become trivial; until then nothing can be -done. - -[mandatory] - - block truncatation on error exit from ->write_begin, and ->direct_IO -moved from generic methods (block_write_begin, cont_write_begin, -nobh_write_begin, blockdev_direct_IO*) to callers. Take a look at -ext2_write_failed and callers for an example. - -[mandatory] - - ->truncate is gone. The whole truncate sequence needs to be -implemented in ->setattr, which is now mandatory for filesystems -implementing on-disk size changes. Start with a copy of the old inode_setattr -and vmtruncate, and the reorder the vmtruncate + foofs_vmtruncate sequence to -be in order of zeroing blocks using block_truncate_page or similar helpers, -size update and on finally on-disk truncation which should not fail. -setattr_prepare (which used to be inode_change_ok) now includes the size checks -for ATTR_SIZE and must be called in the beginning of ->setattr unconditionally. - -[mandatory] - - ->clear_inode() and ->delete_inode() are gone; ->evict_inode() should -be used instead. It gets called whenever the inode is evicted, whether it has -remaining links or not. Caller does *not* evict the pagecache or inode-associated -metadata buffers; the method has to use truncate_inode_pages_final() to get rid -of those. Caller makes sure async writeback cannot be running for the inode while -(or after) ->evict_inode() is called. - - ->drop_inode() returns int now; it's called on final iput() with -inode->i_lock held and it returns true if filesystems wants the inode to be -dropped. As before, generic_drop_inode() is still the default and it's been -updated appropriately. generic_delete_inode() is also alive and it consists -simply of return 1. Note that all actual eviction work is done by caller after -->drop_inode() returns. - - As before, clear_inode() must be called exactly once on each call of -->evict_inode() (as it used to be for each call of ->delete_inode()). Unlike -before, if you are using inode-associated metadata buffers (i.e. -mark_buffer_dirty_inode()), it's your responsibility to call -invalidate_inode_buffers() before clear_inode(). - - NOTE: checking i_nlink in the beginning of ->write_inode() and bailing out -if it's zero is not *and* *never* *had* *been* enough. Final unlink() and iput() -may happen while the inode is in the middle of ->write_inode(); e.g. if you blindly -free the on-disk inode, you may end up doing that while ->write_inode() is writing -to it. - ---- -[mandatory] - - .d_delete() now only advises the dcache as to whether or not to cache -unreferenced dentries, and is now only called when the dentry refcount goes to -0. Even on 0 refcount transition, it must be able to tolerate being called 0, -1, or more times (eg. constant, idempotent). - ---- -[mandatory] - - .d_compare() calling convention and locking rules are significantly -changed. Read updated documentation in Documentation/filesystems/vfs.rst (and -look at examples of other filesystems) for guidance. - ---- -[mandatory] - - .d_hash() calling convention and locking rules are significantly -changed. Read updated documentation in Documentation/filesystems/vfs.rst (and -look at examples of other filesystems) for guidance. - ---- -[mandatory] - dcache_lock is gone, replaced by fine grained locks. See fs/dcache.c -for details of what locks to replace dcache_lock with in order to protect -particular things. Most of the time, a filesystem only needs ->d_lock, which -protects *all* the dcache state of a given dentry. - --- -[mandatory] - - Filesystems must RCU-free their inodes, if they can have been accessed -via rcu-walk path walk (basically, if the file can have had a path name in the -vfs namespace). - - Even though i_dentry and i_rcu share storage in a union, we will -initialize the former in inode_init_always(), so just leave it alone in -the callback. It used to be necessary to clean it there, but not anymore -(starting at 3.2). - --- -[recommended] - vfs now tries to do path walking in "rcu-walk mode", which avoids -atomic operations and scalability hazards on dentries and inodes (see -Documentation/filesystems/path-lookup.txt). d_hash and d_compare changes -(above) are examples of the changes required to support this. For more complex -filesystem callbacks, the vfs drops out of rcu-walk mode before the fs call, so -no changes are required to the filesystem. However, this is costly and loses -the benefits of rcu-walk mode. We will begin to add filesystem callbacks that -are rcu-walk aware, shown below. Filesystems should take advantage of this -where possible. - --- -[mandatory] - d_revalidate is a callback that is made on every path element (if -the filesystem provides it), which requires dropping out of rcu-walk mode. This -may now be called in rcu-walk mode (nd->flags & LOOKUP_RCU). -ECHILD should be -returned if the filesystem cannot handle rcu-walk. See -Documentation/filesystems/vfs.rst for more details. - - permission is an inode permission check that is called on many or all -directory inodes on the way down a path walk (to check for exec permission). It -must now be rcu-walk aware (mask & MAY_NOT_BLOCK). See -Documentation/filesystems/vfs.rst for more details. - --- -[mandatory] - In ->fallocate() you must check the mode option passed in. If your -filesystem does not support hole punching (deallocating space in the middle of a -file) you must return -EOPNOTSUPP if FALLOC_FL_PUNCH_HOLE is set in mode. -Currently you can only have FALLOC_FL_PUNCH_HOLE with FALLOC_FL_KEEP_SIZE set, -so the i_size should not change when hole punching, even when puching the end of -a file off. - --- -[mandatory] - ->get_sb() is gone. Switch to use of ->mount(). Typically it's just -a matter of switching from calling get_sb_... to mount_... and changing the -function type. If you were doing it manually, just switch from setting ->mnt_root -to some pointer to returning that pointer. On errors return ERR_PTR(...). - --- -[mandatory] - ->permission() and generic_permission()have lost flags -argument; instead of passing IPERM_FLAG_RCU we add MAY_NOT_BLOCK into mask. - generic_permission() has also lost the check_acl argument; ACL checking -has been taken to VFS and filesystems need to provide a non-NULL ->i_op->get_acl -to read an ACL from disk. - --- -[mandatory] - If you implement your own ->llseek() you must handle SEEK_HOLE and -SEEK_DATA. You can hanle this by returning -EINVAL, but it would be nicer to -support it in some way. The generic handler assumes that the entire file is -data and there is a virtual hole at the end of the file. So if the provided -offset is less than i_size and SEEK_DATA is specified, return the same offset. -If the above is true for the offset and you are given SEEK_HOLE, return the end -of the file. If the offset is i_size or greater return -ENXIO in either case. - -[mandatory] - If you have your own ->fsync() you must make sure to call -filemap_write_and_wait_range() so that all dirty pages are synced out properly. -You must also keep in mind that ->fsync() is not called with i_mutex held -anymore, so if you require i_mutex locking you must make sure to take it and -release it yourself. - --- -[mandatory] - d_alloc_root() is gone, along with a lot of bugs caused by code -misusing it. Replacement: d_make_root(inode). On success d_make_root(inode) -allocates and returns a new dentry instantiated with the passed in inode. -On failure NULL is returned and the passed in inode is dropped so the reference -to inode is consumed in all cases and failure handling need not do any cleanup -for the inode. If d_make_root(inode) is passed a NULL inode it returns NULL -and also requires no further error handling. Typical usage is: - - inode = foofs_new_inode(....); - s->s_root = d_make_root(inode); - if (!s->s_root) - /* Nothing needed for the inode cleanup */ - return -ENOMEM; - ... - --- -[mandatory] - The witch is dead! Well, 2/3 of it, anyway. ->d_revalidate() and -->lookup() do *not* take struct nameidata anymore; just the flags. --- -[mandatory] - ->create() doesn't take struct nameidata *; unlike the previous -two, it gets "is it an O_EXCL or equivalent?" boolean argument. Note that -local filesystems can ignore tha argument - they are guaranteed that the -object doesn't exist. It's remote/distributed ones that might care... --- -[mandatory] - FS_REVAL_DOT is gone; if you used to have it, add ->d_weak_revalidate() -in your dentry operations instead. --- -[mandatory] - vfs_readdir() is gone; switch to iterate_dir() instead --- -[mandatory] - ->readdir() is gone now; switch to ->iterate() -[mandatory] - vfs_follow_link has been removed. Filesystems must use nd_set_link - from ->follow_link for normal symlinks, or nd_jump_link for magic - /proc/ style links. --- -[mandatory] - iget5_locked()/ilookup5()/ilookup5_nowait() test() callback used to be - called with both ->i_lock and inode_hash_lock held; the former is *not* - taken anymore, so verify that your callbacks do not rely on it (none - of the in-tree instances did). inode_hash_lock is still held, - of course, so they are still serialized wrt removal from inode hash, - as well as wrt set() callback of iget5_locked(). --- -[mandatory] - d_materialise_unique() is gone; d_splice_alias() does everything you - need now. Remember that they have opposite orders of arguments ;-/ --- -[mandatory] - f_dentry is gone; use f_path.dentry, or, better yet, see if you can avoid - it entirely. --- -[mandatory] - never call ->read() and ->write() directly; use __vfs_{read,write} or - wrappers; instead of checking for ->write or ->read being NULL, look for - FMODE_CAN_{WRITE,READ} in file->f_mode. --- -[mandatory] - do _not_ use new_sync_{read,write} for ->read/->write; leave it NULL - instead. --- -[mandatory] - ->aio_read/->aio_write are gone. Use ->read_iter/->write_iter. ---- -[recommended] - for embedded ("fast") symlinks just set inode->i_link to wherever the - symlink body is and use simple_follow_link() as ->follow_link(). --- -[mandatory] - calling conventions for ->follow_link() have changed. Instead of returning - cookie and using nd_set_link() to store the body to traverse, we return - the body to traverse and store the cookie using explicit void ** argument. - nameidata isn't passed at all - nd_jump_link() doesn't need it and - nd_[gs]et_link() is gone. --- -[mandatory] - calling conventions for ->put_link() have changed. It gets inode instead of - dentry, it does not get nameidata at all and it gets called only when cookie - is non-NULL. Note that link body isn't available anymore, so if you need it, - store it as cookie. --- -[mandatory] - any symlink that might use page_follow_link_light/page_put_link() must - have inode_nohighmem(inode) called before anything might start playing with - its pagecache. No highmem pages should end up in the pagecache of such - symlinks. That includes any preseeding that might be done during symlink - creation. __page_symlink() will honour the mapping gfp flags, so once - you've done inode_nohighmem() it's safe to use, but if you allocate and - insert the page manually, make sure to use the right gfp flags. --- -[mandatory] - ->follow_link() is replaced with ->get_link(); same API, except that - * ->get_link() gets inode as a separate argument - * ->get_link() may be called in RCU mode - in that case NULL - dentry is passed --- -[mandatory] - ->get_link() gets struct delayed_call *done now, and should do - set_delayed_call() where it used to set *cookie. - ->put_link() is gone - just give the destructor to set_delayed_call() - in ->get_link(). --- -[mandatory] - ->getxattr() and xattr_handler.get() get dentry and inode passed separately. - dentry might be yet to be attached to inode, so do _not_ use its ->d_inode - in the instances. Rationale: !@#!@# security_d_instantiate() needs to be - called before we attach dentry to inode. --- -[mandatory] - symlinks are no longer the only inodes that do *not* have i_bdev/i_cdev/ - i_pipe/i_link union zeroed out at inode eviction. As the result, you can't - assume that non-NULL value in ->i_nlink at ->destroy_inode() implies that - it's a symlink. Checking ->i_mode is really needed now. In-tree we had - to fix shmem_destroy_callback() that used to take that kind of shortcut; - watch out, since that shortcut is no longer valid. --- -[mandatory] - ->i_mutex is replaced with ->i_rwsem now. inode_lock() et.al. work as - they used to - they just take it exclusive. However, ->lookup() may be - called with parent locked shared. Its instances must not - * use d_instantiate) and d_rehash() separately - use d_add() or - d_splice_alias() instead. - * use d_rehash() alone - call d_add(new_dentry, NULL) instead. - * in the unlikely case when (read-only) access to filesystem - data structures needs exclusion for some reason, arrange it - yourself. None of the in-tree filesystems needed that. - * rely on ->d_parent and ->d_name not changing after dentry has - been fed to d_add() or d_splice_alias(). Again, none of the - in-tree instances relied upon that. - We are guaranteed that lookups of the same name in the same directory - will not happen in parallel ("same" in the sense of your ->d_compare()). - Lookups on different names in the same directory can and do happen in - parallel now. --- -[recommended] - ->iterate_shared() is added; it's a parallel variant of ->iterate(). - Exclusion on struct file level is still provided (as well as that - between it and lseek on the same struct file), but if your directory - has been opened several times, you can get these called in parallel. - Exclusion between that method and all directory-modifying ones is - still provided, of course. - - Often enough ->iterate() can serve as ->iterate_shared() without any - changes - it is a read-only operation, after all. If you have any - per-inode or per-dentry in-core data structures modified by ->iterate(), - you might need something to serialize the access to them. If you - do dcache pre-seeding, you'll need to switch to d_alloc_parallel() for - that; look for in-tree examples. - - Old method is only used if the new one is absent; eventually it will - be removed. Switch while you still can; the old one won't stay. --- -[mandatory] - ->atomic_open() calls without O_CREAT may happen in parallel. --- -[mandatory] - ->setxattr() and xattr_handler.set() get dentry and inode passed separately. - dentry might be yet to be attached to inode, so do _not_ use its ->d_inode - in the instances. Rationale: !@#!@# security_d_instantiate() needs to be - called before we attach dentry to inode and !@#!@##!@$!$#!@#$!@$!@$ smack - ->d_instantiate() uses not just ->getxattr() but ->setxattr() as well. --- -[mandatory] - ->d_compare() doesn't get parent as a separate argument anymore. If you - used it for finding the struct super_block involved, dentry->d_sb will - work just as well; if it's something more complicated, use dentry->d_parent. - Just be careful not to assume that fetching it more than once will yield - the same value - in RCU mode it could change under you. --- -[mandatory] - ->rename() has an added flags argument. Any flags not handled by the - filesystem should result in EINVAL being returned. --- -[recommended] - ->readlink is optional for symlinks. Don't set, unless filesystem needs - to fake something for readlink(2). --- -[mandatory] - ->getattr() is now passed a struct path rather than a vfsmount and - dentry separately, and it now has request_mask and query_flags arguments - to specify the fields and sync type requested by statx. Filesystems not - supporting any statx-specific features may ignore the new arguments. --- -[mandatory] - ->atomic_open() calling conventions have changed. Gone is int *opened, - along with FILE_OPENED/FILE_CREATED. In place of those we have - FMODE_OPENED/FMODE_CREATED, set in file->f_mode. Additionally, return - value for 'called finish_no_open(), open it yourself' case has become - 0, not 1. Since finish_no_open() itself is returning 0 now, that part - does not need any changes in ->atomic_open() instances. --- -[mandatory] - alloc_file() has become static now; two wrappers are to be used instead. - alloc_file_pseudo(inode, vfsmount, name, flags, ops) is for the cases - when dentry needs to be created; that's the majority of old alloc_file() - users. Calling conventions: on success a reference to new struct file - is returned and callers reference to inode is subsumed by that. On - failure, ERR_PTR() is returned and no caller's references are affected, - so the caller needs to drop the inode reference it held. - alloc_file_clone(file, flags, ops) does not affect any caller's references. - On success you get a new struct file sharing the mount/dentry with the - original, on failure - ERR_PTR(). --- -[mandatory] - ->clone_file_range() and ->dedupe_file_range have been replaced with - ->remap_file_range(). See Documentation/filesystems/vfs.rst for more - information. --- -[recommended] - ->lookup() instances doing an equivalent of - if (IS_ERR(inode)) - return ERR_CAST(inode); - return d_splice_alias(inode, dentry); - don't need to bother with the check - d_splice_alias() will do the - right thing when given ERR_PTR(...) as inode. Moreover, passing NULL - inode to d_splice_alias() will also do the right thing (equivalent of - d_add(dentry, NULL); return NULL;), so that kind of special cases - also doesn't need a separate treatment. --- -[strongly recommended] - take the RCU-delayed parts of ->destroy_inode() into a new method - - ->free_inode(). If ->destroy_inode() becomes empty - all the better, - just get rid of it. Synchronous work (e.g. the stuff that can't - be done from an RCU callback, or any WARN_ON() where we want the - stack trace) *might* be movable to ->evict_inode(); however, - that goes only for the things that are not needed to balance something - done by ->alloc_inode(). IOW, if it's cleaning up the stuff that - might have accumulated over the life of in-core inode, ->evict_inode() - might be a fit. - - Rules for inode destruction: - * if ->destroy_inode() is non-NULL, it gets called - * if ->free_inode() is non-NULL, it gets scheduled by call_rcu() - * combination of NULL ->destroy_inode and NULL ->free_inode is - treated as NULL/free_inode_nonrcu, to preserve the compatibility. - - Note that the callback (be it via ->free_inode() or explicit call_rcu() - in ->destroy_inode()) is *NOT* ordered wrt superblock destruction; - as the matter of fact, the superblock and all associated structures - might be already gone. The filesystem driver is guaranteed to be still - there, but that's it. Freeing memory in the callback is fine; doing - more than that is possible, but requires a lot of care and is best - avoided. --- -[mandatory] - DCACHE_RCUACCESS is gone; having an RCU delay on dentry freeing is the - default. DCACHE_NORCU opts out, and only d_alloc_pseudo() has any - business doing so. --- -[mandatory] - d_alloc_pseudo() is internal-only; uses outside of alloc_file_pseudo() are - very suspect (and won't work in modules). Such uses are very likely to - be misspelled d_alloc_anon(). diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst new file mode 100644 index 0000000000000000000000000000000000000000..f18506083ced831cf0ceef4870d964144152cd99 --- /dev/null +++ b/Documentation/filesystems/porting.rst @@ -0,0 +1,852 @@ +==================== +Changes since 2.5.0: +==================== + +--- + +**recommended** + +New helpers: sb_bread(), sb_getblk(), sb_find_get_block(), set_bh(), +sb_set_blocksize() and sb_min_blocksize(). + +Use them. + +(sb_find_get_block() replaces 2.4's get_hash_table()) + +--- + +**recommended** + +New methods: ->alloc_inode() and ->destroy_inode(). + +Remove inode->u.foo_inode_i + +Declare:: + + struct foo_inode_info { + /* fs-private stuff */ + struct inode vfs_inode; + }; + static inline struct foo_inode_info *FOO_I(struct inode *inode) + { + return list_entry(inode, struct foo_inode_info, vfs_inode); + } + +Use FOO_I(inode) instead of &inode->u.foo_inode_i; + +Add foo_alloc_inode() and foo_destroy_inode() - the former should allocate +foo_inode_info and return the address of ->vfs_inode, the latter should free +FOO_I(inode) (see in-tree filesystems for examples). + +Make them ->alloc_inode and ->destroy_inode in your super_operations. + +Keep in mind that now you need explicit initialization of private data +typically between calling iget_locked() and unlocking the inode. + +At some point that will become mandatory. + +--- + +**mandatory** + +Change of file_system_type method (->read_super to ->get_sb) + +->read_super() is no more. Ditto for DECLARE_FSTYPE and DECLARE_FSTYPE_DEV. + +Turn your foo_read_super() into a function that would return 0 in case of +success and negative number in case of error (-EINVAL unless you have more +informative error value to report). Call it foo_fill_super(). Now declare:: + + int foo_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) + { + return get_sb_bdev(fs_type, flags, dev_name, data, foo_fill_super, + mnt); + } + +(or similar with s/bdev/nodev/ or s/bdev/single/, depending on the kind of +filesystem). + +Replace DECLARE_FSTYPE... with explicit initializer and have ->get_sb set as +foo_get_sb. + +--- + +**mandatory** + +Locking change: ->s_vfs_rename_sem is taken only by cross-directory renames. +Most likely there is no need to change anything, but if you relied on +global exclusion between renames for some internal purpose - you need to +change your internal locking. Otherwise exclusion warranties remain the +same (i.e. parents and victim are locked, etc.). + +--- + +**informational** + +Now we have the exclusion between ->lookup() and directory removal (by +->rmdir() and ->rename()). If you used to need that exclusion and do +it by internal locking (most of filesystems couldn't care less) - you +can relax your locking. + +--- + +**mandatory** + +->lookup(), ->truncate(), ->create(), ->unlink(), ->mknod(), ->mkdir(), +->rmdir(), ->link(), ->lseek(), ->symlink(), ->rename() +and ->readdir() are called without BKL now. Grab it on entry, drop upon return +- that will guarantee the same locking you used to have. If your method or its +parts do not need BKL - better yet, now you can shift lock_kernel() and +unlock_kernel() so that they would protect exactly what needs to be +protected. + +--- + +**mandatory** + +BKL is also moved from around sb operations. BKL should have been shifted into +individual fs sb_op functions. If you don't need it, remove it. + +--- + +**informational** + +check for ->link() target not being a directory is done by callers. Feel +free to drop it... + +--- + +**informational** + +->link() callers hold ->i_mutex on the object we are linking to. Some of your +problems might be over... + +--- + +**mandatory** + +new file_system_type method - kill_sb(superblock). If you are converting +an existing filesystem, set it according to ->fs_flags:: + + FS_REQUIRES_DEV - kill_block_super + FS_LITTER - kill_litter_super + neither - kill_anon_super + +FS_LITTER is gone - just remove it from fs_flags. + +--- + +**mandatory** + +FS_SINGLE is gone (actually, that had happened back when ->get_sb() +went in - and hadn't been documented ;-/). Just remove it from fs_flags +(and see ->get_sb() entry for other actions). + +--- + +**mandatory** + +->setattr() is called without BKL now. Caller _always_ holds ->i_mutex, so +watch for ->i_mutex-grabbing code that might be used by your ->setattr(). +Callers of notify_change() need ->i_mutex now. + +--- + +**recommended** + +New super_block field ``struct export_operations *s_export_op`` for +explicit support for exporting, e.g. via NFS. The structure is fully +documented at its declaration in include/linux/fs.h, and in +Documentation/filesystems/nfs/exporting.rst. + +Briefly it allows for the definition of decode_fh and encode_fh operations +to encode and decode filehandles, and allows the filesystem to use +a standard helper function for decode_fh, and provide file-system specific +support for this helper, particularly get_parent. + +It is planned that this will be required for exporting once the code +settles down a bit. + +**mandatory** + +s_export_op is now required for exporting a filesystem. +isofs, ext2, ext3, resierfs, fat +can be used as examples of very different filesystems. + +--- + +**mandatory** + +iget4() and the read_inode2 callback have been superseded by iget5_locked() +which has the following prototype:: + + struct inode *iget5_locked(struct super_block *sb, unsigned long ino, + int (*test)(struct inode *, void *), + int (*set)(struct inode *, void *), + void *data); + +'test' is an additional function that can be used when the inode +number is not sufficient to identify the actual file object. 'set' +should be a non-blocking function that initializes those parts of a +newly created inode to allow the test function to succeed. 'data' is +passed as an opaque value to both test and set functions. + +When the inode has been created by iget5_locked(), it will be returned with the +I_NEW flag set and will still be locked. The filesystem then needs to finalize +the initialization. Once the inode is initialized it must be unlocked by +calling unlock_new_inode(). + +The filesystem is responsible for setting (and possibly testing) i_ino +when appropriate. There is also a simpler iget_locked function that +just takes the superblock and inode number as arguments and does the +test and set for you. + +e.g.:: + + inode = iget_locked(sb, ino); + if (inode->i_state & I_NEW) { + err = read_inode_from_disk(inode); + if (err < 0) { + iget_failed(inode); + return err; + } + unlock_new_inode(inode); + } + +Note that if the process of setting up a new inode fails, then iget_failed() +should be called on the inode to render it dead, and an appropriate error +should be passed back to the caller. + +--- + +**recommended** + +->getattr() finally getting used. See instances in nfs, minix, etc. + +--- + +**mandatory** + +->revalidate() is gone. If your filesystem had it - provide ->getattr() +and let it call whatever you had as ->revlidate() + (for symlinks that +had ->revalidate()) add calls in ->follow_link()/->readlink(). + +--- + +**mandatory** + +->d_parent changes are not protected by BKL anymore. Read access is safe +if at least one of the following is true: + + * filesystem has no cross-directory rename() + * we know that parent had been locked (e.g. we are looking at + ->d_parent of ->lookup() argument). + * we are called from ->rename(). + * the child's ->d_lock is held + +Audit your code and add locking if needed. Notice that any place that is +not protected by the conditions above is risky even in the old tree - you +had been relying on BKL and that's prone to screwups. Old tree had quite +a few holes of that kind - unprotected access to ->d_parent leading to +anything from oops to silent memory corruption. + +--- + +**mandatory** + +FS_NOMOUNT is gone. If you use it - just set SB_NOUSER in flags +(see rootfs for one kind of solution and bdev/socket/pipe for another). + +--- + +**recommended** + +Use bdev_read_only(bdev) instead of is_read_only(kdev). The latter +is still alive, but only because of the mess in drivers/s390/block/dasd.c. +As soon as it gets fixed is_read_only() will die. + +--- + +**mandatory** + +->permission() is called without BKL now. Grab it on entry, drop upon +return - that will guarantee the same locking you used to have. If +your method or its parts do not need BKL - better yet, now you can +shift lock_kernel() and unlock_kernel() so that they would protect +exactly what needs to be protected. + +--- + +**mandatory** + +->statfs() is now called without BKL held. BKL should have been +shifted into individual fs sb_op functions where it's not clear that +it's safe to remove it. If you don't need it, remove it. + +--- + +**mandatory** + +is_read_only() is gone; use bdev_read_only() instead. + +--- + +**mandatory** + +destroy_buffers() is gone; use invalidate_bdev(). + +--- + +**mandatory** + +fsync_dev() is gone; use fsync_bdev(). NOTE: lvm breakage is +deliberate; as soon as struct block_device * is propagated in a reasonable +way by that code fixing will become trivial; until then nothing can be +done. + +**mandatory** + +block truncatation on error exit from ->write_begin, and ->direct_IO +moved from generic methods (block_write_begin, cont_write_begin, +nobh_write_begin, blockdev_direct_IO*) to callers. Take a look at +ext2_write_failed and callers for an example. + +**mandatory** + +->truncate is gone. The whole truncate sequence needs to be +implemented in ->setattr, which is now mandatory for filesystems +implementing on-disk size changes. Start with a copy of the old inode_setattr +and vmtruncate, and the reorder the vmtruncate + foofs_vmtruncate sequence to +be in order of zeroing blocks using block_truncate_page or similar helpers, +size update and on finally on-disk truncation which should not fail. +setattr_prepare (which used to be inode_change_ok) now includes the size checks +for ATTR_SIZE and must be called in the beginning of ->setattr unconditionally. + +**mandatory** + +->clear_inode() and ->delete_inode() are gone; ->evict_inode() should +be used instead. It gets called whenever the inode is evicted, whether it has +remaining links or not. Caller does *not* evict the pagecache or inode-associated +metadata buffers; the method has to use truncate_inode_pages_final() to get rid +of those. Caller makes sure async writeback cannot be running for the inode while +(or after) ->evict_inode() is called. + +->drop_inode() returns int now; it's called on final iput() with +inode->i_lock held and it returns true if filesystems wants the inode to be +dropped. As before, generic_drop_inode() is still the default and it's been +updated appropriately. generic_delete_inode() is also alive and it consists +simply of return 1. Note that all actual eviction work is done by caller after +->drop_inode() returns. + +As before, clear_inode() must be called exactly once on each call of +->evict_inode() (as it used to be for each call of ->delete_inode()). Unlike +before, if you are using inode-associated metadata buffers (i.e. +mark_buffer_dirty_inode()), it's your responsibility to call +invalidate_inode_buffers() before clear_inode(). + +NOTE: checking i_nlink in the beginning of ->write_inode() and bailing out +if it's zero is not *and* *never* *had* *been* enough. Final unlink() and iput() +may happen while the inode is in the middle of ->write_inode(); e.g. if you blindly +free the on-disk inode, you may end up doing that while ->write_inode() is writing +to it. + +--- + +**mandatory** + +.d_delete() now only advises the dcache as to whether or not to cache +unreferenced dentries, and is now only called when the dentry refcount goes to +0. Even on 0 refcount transition, it must be able to tolerate being called 0, +1, or more times (eg. constant, idempotent). + +--- + +**mandatory** + +.d_compare() calling convention and locking rules are significantly +changed. Read updated documentation in Documentation/filesystems/vfs.rst (and +look at examples of other filesystems) for guidance. + +--- + +**mandatory** + +.d_hash() calling convention and locking rules are significantly +changed. Read updated documentation in Documentation/filesystems/vfs.rst (and +look at examples of other filesystems) for guidance. + +--- + +**mandatory** + +dcache_lock is gone, replaced by fine grained locks. See fs/dcache.c +for details of what locks to replace dcache_lock with in order to protect +particular things. Most of the time, a filesystem only needs ->d_lock, which +protects *all* the dcache state of a given dentry. + +--- + +**mandatory** + +Filesystems must RCU-free their inodes, if they can have been accessed +via rcu-walk path walk (basically, if the file can have had a path name in the +vfs namespace). + +Even though i_dentry and i_rcu share storage in a union, we will +initialize the former in inode_init_always(), so just leave it alone in +the callback. It used to be necessary to clean it there, but not anymore +(starting at 3.2). + +--- + +**recommended** + +vfs now tries to do path walking in "rcu-walk mode", which avoids +atomic operations and scalability hazards on dentries and inodes (see +Documentation/filesystems/path-lookup.txt). d_hash and d_compare changes +(above) are examples of the changes required to support this. For more complex +filesystem callbacks, the vfs drops out of rcu-walk mode before the fs call, so +no changes are required to the filesystem. However, this is costly and loses +the benefits of rcu-walk mode. We will begin to add filesystem callbacks that +are rcu-walk aware, shown below. Filesystems should take advantage of this +where possible. + +--- + +**mandatory** + +d_revalidate is a callback that is made on every path element (if +the filesystem provides it), which requires dropping out of rcu-walk mode. This +may now be called in rcu-walk mode (nd->flags & LOOKUP_RCU). -ECHILD should be +returned if the filesystem cannot handle rcu-walk. See +Documentation/filesystems/vfs.rst for more details. + +permission is an inode permission check that is called on many or all +directory inodes on the way down a path walk (to check for exec permission). It +must now be rcu-walk aware (mask & MAY_NOT_BLOCK). See +Documentation/filesystems/vfs.rst for more details. + +--- + +**mandatory** + +In ->fallocate() you must check the mode option passed in. If your +filesystem does not support hole punching (deallocating space in the middle of a +file) you must return -EOPNOTSUPP if FALLOC_FL_PUNCH_HOLE is set in mode. +Currently you can only have FALLOC_FL_PUNCH_HOLE with FALLOC_FL_KEEP_SIZE set, +so the i_size should not change when hole punching, even when puching the end of +a file off. + +--- + +**mandatory** + +->get_sb() is gone. Switch to use of ->mount(). Typically it's just +a matter of switching from calling ``get_sb_``... to ``mount_``... and changing +the function type. If you were doing it manually, just switch from setting +->mnt_root to some pointer to returning that pointer. On errors return +ERR_PTR(...). + +--- + +**mandatory** + +->permission() and generic_permission()have lost flags +argument; instead of passing IPERM_FLAG_RCU we add MAY_NOT_BLOCK into mask. + +generic_permission() has also lost the check_acl argument; ACL checking +has been taken to VFS and filesystems need to provide a non-NULL ->i_op->get_acl +to read an ACL from disk. + +--- + +**mandatory** + +If you implement your own ->llseek() you must handle SEEK_HOLE and +SEEK_DATA. You can hanle this by returning -EINVAL, but it would be nicer to +support it in some way. The generic handler assumes that the entire file is +data and there is a virtual hole at the end of the file. So if the provided +offset is less than i_size and SEEK_DATA is specified, return the same offset. +If the above is true for the offset and you are given SEEK_HOLE, return the end +of the file. If the offset is i_size or greater return -ENXIO in either case. + +**mandatory** + +If you have your own ->fsync() you must make sure to call +filemap_write_and_wait_range() so that all dirty pages are synced out properly. +You must also keep in mind that ->fsync() is not called with i_mutex held +anymore, so if you require i_mutex locking you must make sure to take it and +release it yourself. + +--- + +**mandatory** + +d_alloc_root() is gone, along with a lot of bugs caused by code +misusing it. Replacement: d_make_root(inode). On success d_make_root(inode) +allocates and returns a new dentry instantiated with the passed in inode. +On failure NULL is returned and the passed in inode is dropped so the reference +to inode is consumed in all cases and failure handling need not do any cleanup +for the inode. If d_make_root(inode) is passed a NULL inode it returns NULL +and also requires no further error handling. Typical usage is:: + + inode = foofs_new_inode(....); + s->s_root = d_make_root(inode); + if (!s->s_root) + /* Nothing needed for the inode cleanup */ + return -ENOMEM; + ... + +--- + +**mandatory** + +The witch is dead! Well, 2/3 of it, anyway. ->d_revalidate() and +->lookup() do *not* take struct nameidata anymore; just the flags. + +--- + +**mandatory** + +->create() doesn't take ``struct nameidata *``; unlike the previous +two, it gets "is it an O_EXCL or equivalent?" boolean argument. Note that +local filesystems can ignore tha argument - they are guaranteed that the +object doesn't exist. It's remote/distributed ones that might care... + +--- + +**mandatory** + +FS_REVAL_DOT is gone; if you used to have it, add ->d_weak_revalidate() +in your dentry operations instead. + +--- + +**mandatory** + +vfs_readdir() is gone; switch to iterate_dir() instead + +--- + +**mandatory** + +->readdir() is gone now; switch to ->iterate() + +**mandatory** + +vfs_follow_link has been removed. Filesystems must use nd_set_link +from ->follow_link for normal symlinks, or nd_jump_link for magic +/proc/ style links. + +--- + +**mandatory** + +iget5_locked()/ilookup5()/ilookup5_nowait() test() callback used to be +called with both ->i_lock and inode_hash_lock held; the former is *not* +taken anymore, so verify that your callbacks do not rely on it (none +of the in-tree instances did). inode_hash_lock is still held, +of course, so they are still serialized wrt removal from inode hash, +as well as wrt set() callback of iget5_locked(). + +--- + +**mandatory** + +d_materialise_unique() is gone; d_splice_alias() does everything you +need now. Remember that they have opposite orders of arguments ;-/ + +--- + +**mandatory** + +f_dentry is gone; use f_path.dentry, or, better yet, see if you can avoid +it entirely. + +--- + +**mandatory** + +never call ->read() and ->write() directly; use __vfs_{read,write} or +wrappers; instead of checking for ->write or ->read being NULL, look for +FMODE_CAN_{WRITE,READ} in file->f_mode. + +--- + +**mandatory** + +do _not_ use new_sync_{read,write} for ->read/->write; leave it NULL +instead. + +--- + +**mandatory** + ->aio_read/->aio_write are gone. Use ->read_iter/->write_iter. + +--- + +**recommended** + +for embedded ("fast") symlinks just set inode->i_link to wherever the +symlink body is and use simple_follow_link() as ->follow_link(). + +--- + +**mandatory** + +calling conventions for ->follow_link() have changed. Instead of returning +cookie and using nd_set_link() to store the body to traverse, we return +the body to traverse and store the cookie using explicit void ** argument. +nameidata isn't passed at all - nd_jump_link() doesn't need it and +nd_[gs]et_link() is gone. + +--- + +**mandatory** + +calling conventions for ->put_link() have changed. It gets inode instead of +dentry, it does not get nameidata at all and it gets called only when cookie +is non-NULL. Note that link body isn't available anymore, so if you need it, +store it as cookie. + +--- + +**mandatory** + +any symlink that might use page_follow_link_light/page_put_link() must +have inode_nohighmem(inode) called before anything might start playing with +its pagecache. No highmem pages should end up in the pagecache of such +symlinks. That includes any preseeding that might be done during symlink +creation. __page_symlink() will honour the mapping gfp flags, so once +you've done inode_nohighmem() it's safe to use, but if you allocate and +insert the page manually, make sure to use the right gfp flags. + +--- + +**mandatory** + +->follow_link() is replaced with ->get_link(); same API, except that + + * ->get_link() gets inode as a separate argument + * ->get_link() may be called in RCU mode - in that case NULL + dentry is passed + +--- + +**mandatory** + +->get_link() gets struct delayed_call ``*done`` now, and should do +set_delayed_call() where it used to set ``*cookie``. + +->put_link() is gone - just give the destructor to set_delayed_call() +in ->get_link(). + +--- + +**mandatory** + +->getxattr() and xattr_handler.get() get dentry and inode passed separately. +dentry might be yet to be attached to inode, so do _not_ use its ->d_inode +in the instances. Rationale: !@#!@# security_d_instantiate() needs to be +called before we attach dentry to inode. + +--- + +**mandatory** + +symlinks are no longer the only inodes that do *not* have i_bdev/i_cdev/ +i_pipe/i_link union zeroed out at inode eviction. As the result, you can't +assume that non-NULL value in ->i_nlink at ->destroy_inode() implies that +it's a symlink. Checking ->i_mode is really needed now. In-tree we had +to fix shmem_destroy_callback() that used to take that kind of shortcut; +watch out, since that shortcut is no longer valid. + +--- + +**mandatory** + +->i_mutex is replaced with ->i_rwsem now. inode_lock() et.al. work as +they used to - they just take it exclusive. However, ->lookup() may be +called with parent locked shared. Its instances must not + + * use d_instantiate) and d_rehash() separately - use d_add() or + d_splice_alias() instead. + * use d_rehash() alone - call d_add(new_dentry, NULL) instead. + * in the unlikely case when (read-only) access to filesystem + data structures needs exclusion for some reason, arrange it + yourself. None of the in-tree filesystems needed that. + * rely on ->d_parent and ->d_name not changing after dentry has + been fed to d_add() or d_splice_alias(). Again, none of the + in-tree instances relied upon that. + +We are guaranteed that lookups of the same name in the same directory +will not happen in parallel ("same" in the sense of your ->d_compare()). +Lookups on different names in the same directory can and do happen in +parallel now. + +--- + +**recommended** + +->iterate_shared() is added; it's a parallel variant of ->iterate(). +Exclusion on struct file level is still provided (as well as that +between it and lseek on the same struct file), but if your directory +has been opened several times, you can get these called in parallel. +Exclusion between that method and all directory-modifying ones is +still provided, of course. + +Often enough ->iterate() can serve as ->iterate_shared() without any +changes - it is a read-only operation, after all. If you have any +per-inode or per-dentry in-core data structures modified by ->iterate(), +you might need something to serialize the access to them. If you +do dcache pre-seeding, you'll need to switch to d_alloc_parallel() for +that; look for in-tree examples. + +Old method is only used if the new one is absent; eventually it will +be removed. Switch while you still can; the old one won't stay. + +--- + +**mandatory** + +->atomic_open() calls without O_CREAT may happen in parallel. + +--- + +**mandatory** + +->setxattr() and xattr_handler.set() get dentry and inode passed separately. +dentry might be yet to be attached to inode, so do _not_ use its ->d_inode +in the instances. Rationale: !@#!@# security_d_instantiate() needs to be +called before we attach dentry to inode and !@#!@##!@$!$#!@#$!@$!@$ smack +->d_instantiate() uses not just ->getxattr() but ->setxattr() as well. + +--- + +**mandatory** + +->d_compare() doesn't get parent as a separate argument anymore. If you +used it for finding the struct super_block involved, dentry->d_sb will +work just as well; if it's something more complicated, use dentry->d_parent. +Just be careful not to assume that fetching it more than once will yield +the same value - in RCU mode it could change under you. + +--- + +**mandatory** + +->rename() has an added flags argument. Any flags not handled by the +filesystem should result in EINVAL being returned. + +--- + + +**recommended** + +->readlink is optional for symlinks. Don't set, unless filesystem needs +to fake something for readlink(2). + +--- + +**mandatory** + +->getattr() is now passed a struct path rather than a vfsmount and +dentry separately, and it now has request_mask and query_flags arguments +to specify the fields and sync type requested by statx. Filesystems not +supporting any statx-specific features may ignore the new arguments. + +--- + +**mandatory** + +->atomic_open() calling conventions have changed. Gone is ``int *opened``, +along with FILE_OPENED/FILE_CREATED. In place of those we have +FMODE_OPENED/FMODE_CREATED, set in file->f_mode. Additionally, return +value for 'called finish_no_open(), open it yourself' case has become +0, not 1. Since finish_no_open() itself is returning 0 now, that part +does not need any changes in ->atomic_open() instances. + +--- + +**mandatory** + +alloc_file() has become static now; two wrappers are to be used instead. +alloc_file_pseudo(inode, vfsmount, name, flags, ops) is for the cases +when dentry needs to be created; that's the majority of old alloc_file() +users. Calling conventions: on success a reference to new struct file +is returned and callers reference to inode is subsumed by that. On +failure, ERR_PTR() is returned and no caller's references are affected, +so the caller needs to drop the inode reference it held. +alloc_file_clone(file, flags, ops) does not affect any caller's references. +On success you get a new struct file sharing the mount/dentry with the +original, on failure - ERR_PTR(). + +--- + +**mandatory** + +->clone_file_range() and ->dedupe_file_range have been replaced with +->remap_file_range(). See Documentation/filesystems/vfs.rst for more +information. + +--- + +**recommended** + +->lookup() instances doing an equivalent of:: + + if (IS_ERR(inode)) + return ERR_CAST(inode); + return d_splice_alias(inode, dentry); + +don't need to bother with the check - d_splice_alias() will do the +right thing when given ERR_PTR(...) as inode. Moreover, passing NULL +inode to d_splice_alias() will also do the right thing (equivalent of +d_add(dentry, NULL); return NULL;), so that kind of special cases +also doesn't need a separate treatment. + +--- + +**strongly recommended** + +take the RCU-delayed parts of ->destroy_inode() into a new method - +->free_inode(). If ->destroy_inode() becomes empty - all the better, +just get rid of it. Synchronous work (e.g. the stuff that can't +be done from an RCU callback, or any WARN_ON() where we want the +stack trace) *might* be movable to ->evict_inode(); however, +that goes only for the things that are not needed to balance something +done by ->alloc_inode(). IOW, if it's cleaning up the stuff that +might have accumulated over the life of in-core inode, ->evict_inode() +might be a fit. + +Rules for inode destruction: + + * if ->destroy_inode() is non-NULL, it gets called + * if ->free_inode() is non-NULL, it gets scheduled by call_rcu() + * combination of NULL ->destroy_inode and NULL ->free_inode is + treated as NULL/free_inode_nonrcu, to preserve the compatibility. + +Note that the callback (be it via ->free_inode() or explicit call_rcu() +in ->destroy_inode()) is *NOT* ordered wrt superblock destruction; +as the matter of fact, the superblock and all associated structures +might be already gone. The filesystem driver is guaranteed to be still +there, but that's it. Freeing memory in the callback is fine; doing +more than that is possible, but requires a lot of care and is best +avoided. + +--- + +**mandatory** + +DCACHE_RCUACCESS is gone; having an RCU delay on dentry freeing is the +default. DCACHE_NORCU opts out, and only d_alloc_pseudo() has any +business doing so. + +--- + +**mandatory** + +d_alloc_pseudo() is internal-only; uses outside of alloc_file_pseudo() are +very suspect (and won't work in modules). Such uses are very likely to +be misspelled d_alloc_anon(). diff --git a/Documentation/filesystems/ubifs-authentication.md b/Documentation/filesystems/ubifs-authentication.rst similarity index 95% rename from Documentation/filesystems/ubifs-authentication.md rename to Documentation/filesystems/ubifs-authentication.rst index 23e69816714172a3825bd239ccd94f9f343eb64e..6a9584f6ff4677e8a974c1f27f7b223b405ffb25 100644 --- a/Documentation/filesystems/ubifs-authentication.md +++ b/Documentation/filesystems/ubifs-authentication.rst @@ -1,8 +1,11 @@ -% UBIFS Authentication -% sigma star gmbh -% 2018 +:orphan: -# Introduction +.. UBIFS Authentication +.. sigma star gmbh +.. 2018 + +Introduction +============ UBIFS utilizes the fscrypt framework to provide confidentiality for file contents and file names. This prevents attacks where an attacker is able to @@ -33,7 +36,8 @@ existing features like key derivation can be utilized. It should however also be possible to use UBIFS authentication without using encryption. -## MTD, UBI & UBIFS +MTD, UBI & UBIFS +---------------- On Linux, the MTD (Memory Technology Devices) subsystem provides a uniform interface to access raw flash devices. One of the more prominent subsystems that @@ -47,7 +51,7 @@ UBIFS is a filesystem for raw flash which operates on top of UBI. Thus, wear leveling and some flash specifics are left to UBI, while UBIFS focuses on scalability, performance and recoverability. - +:: +------------+ +*******+ +-----------+ +-----+ | | * UBIFS * | UBI-BLOCK | | ... | @@ -84,7 +88,8 @@ persisted onto the flash directly. More details on UBIFS can also be found in [UBIFS-WP]. -### UBIFS Index & Tree Node Cache +UBIFS Index & Tree Node Cache +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Basic on-flash UBIFS entities are called *nodes*. UBIFS knows different types of nodes. Eg. data nodes (`struct ubifs_data_node`) which store chunks of file @@ -118,17 +123,18 @@ on-flash filesystem structures like the index. On every commit, the TNC nodes marked as dirty are written to the flash to update the persisted index. -### Journal +Journal +~~~~~~~ To avoid wearing out the flash, the index is only persisted (*commited*) when -certain conditions are met (eg. `fsync(2)`). The journal is used to record +certain conditions are met (eg. ``fsync(2)``). The journal is used to record any changes (in form of inode nodes, data nodes etc.) between commits of the index. During mount, the journal is read from the flash and replayed onto the TNC (which will be created on-demand from the on-flash index). UBIFS reserves a bunch of LEBs just for the journal called *log area*. The amount of log area LEBs is configured on filesystem creation (using -`mkfs.ubifs`) and stored in the superblock node. The log area contains only +``mkfs.ubifs``) and stored in the superblock node. The log area contains only two types of nodes: *reference nodes* and *commit start nodes*. A commit start node is written whenever an index commit is performed. Reference nodes are written on every journal update. Each reference node points to the position of @@ -152,6 +158,7 @@ done for the last referenced LEB of the journal. Only this can become corrupt because of a power cut. If the recovery fails, UBIFS will not mount. An error for every other LEB will directly cause UBIFS to fail the mount operation. +:: | ---- LOG AREA ---- | ---------- MAIN AREA ------------ | @@ -172,10 +179,11 @@ for every other LEB will directly cause UBIFS to fail the mount operation. containing their buds -### LEB Property Tree/Table +LEB Property Tree/Table +~~~~~~~~~~~~~~~~~~~~~~~ The LEB property tree is used to store per-LEB information. This includes the -LEB type and amount of free and *dirty* (old, obsolete content) space [1] on +LEB type and amount of free and *dirty* (old, obsolete content) space [1]_ on the LEB. The type is important, because UBIFS never mixes index nodes with data nodes on a single LEB and thus each LEB has a specific purpose. This again is useful for free space calculations. See [UBIFS-WP] for more details. @@ -185,19 +193,21 @@ index. Due to its smaller size it is always written as one chunk on every commit. Thus, saving the LPT is an atomic operation. -[1] Since LEBs can only be appended and never overwritten, there is a -difference between free space ie. the remaining space left on the LEB to be -written to without erasing it and previously written content that is obsolete -but can't be overwritten without erasing the full LEB. +.. [1] Since LEBs can only be appended and never overwritten, there is a + difference between free space ie. the remaining space left on the LEB to be + written to without erasing it and previously written content that is obsolete + but can't be overwritten without erasing the full LEB. -# UBIFS Authentication +UBIFS Authentication +==================== This chapter introduces UBIFS authentication which enables UBIFS to verify the authenticity and integrity of metadata and file contents stored on flash. -## Threat Model +Threat Model +------------ UBIFS authentication enables detection of offline data modification. While it does not prevent it, it enables (trusted) code to check the integrity and @@ -224,7 +234,8 @@ Additional measures like secure boot and trusted boot have to be taken to ensure that only trusted code is executed on a device. -## Authentication +Authentication +-------------- To be able to fully trust data read from flash, all UBIFS data structures stored on flash are authenticated. That is: @@ -236,7 +247,8 @@ stored on flash are authenticated. That is: - The LPT which stores UBI LEB metadata which UBIFS uses for free space accounting -### Index Authentication +Index Authentication +~~~~~~~~~~~~~~~~~~~~ Through UBIFS' concept of a wandering tree, it already takes care of only updating and persisting changed parts from leaf node up to the root node @@ -260,6 +272,7 @@ include a hash. All other types of nodes will remain unchanged. This reduces the storage overhead which is precious for users of UBIFS (ie. embedded devices). +:: +---------------+ | Master Node | @@ -303,7 +316,8 @@ hashes to index nodes does not change this since each hash will be persisted atomically together with its respective node. -### Journal Authentication +Journal Authentication +~~~~~~~~~~~~~~~~~~~~~~ The journal is authenticated too. Since the journal is continuously written it is necessary to also add authentication information frequently to the @@ -316,7 +330,7 @@ of the hash chain. That way a journal can be authenticated up to the last authentication node. The tail of the journal which may not have a authentication node cannot be authenticated and is skipped during journal replay. -We get this picture for journal authentication: +We get this picture for journal authentication:: ,,,,,,,, ,......,........................................... @@ -352,7 +366,8 @@ the superblock struct. The superblock node is stored in LEB 0 and is only modified on feature flag or similar changes, but never on file changes. -### LPT Authentication +LPT Authentication +~~~~~~~~~~~~~~~~~~ The location of the LPT root node on the flash is stored in the UBIFS master node. Since the LPT is written and read atomically on every commit, there is @@ -363,7 +378,8 @@ be verified by verifying the authenticity of the master node and comparing the LTP hash stored there with the hash computed from the read on-flash LPT. -## Key Management +Key Management +-------------- For simplicity, UBIFS authentication uses a single key to compute the HMACs of superblock, master, commit start and reference nodes. This key has to be @@ -399,7 +415,8 @@ approach is similar to the approach proposed for fscrypt encryption policy v2 [FSCRYPT-POLICY2]. -# Future Extensions +Future Extensions +================= In certain cases where a vendor wants to provide an authenticated filesystem image to customers, it should be possible to do so without sharing the secret @@ -411,7 +428,8 @@ to the way the IMA/EVM subsystem deals with such situations. The HMAC key will then have to be provided beforehand in the normal way. -# References +References +========== [CRYPTSETUP2] http://www.saout.de/pipermail/dm-crypt/2017-November/005745.html diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst index 0f85ab21c2ca44ed225bebc73a76488e862e0bc5..7d4d09dd5e6dec98bfb062da7e11d9996dd106d5 100644 --- a/Documentation/filesystems/vfs.rst +++ b/Documentation/filesystems/vfs.rst @@ -20,7 +20,7 @@ kernel which allows different filesystem implementations to coexist. VFS system calls open(2), stat(2), read(2), write(2), chmod(2) and so on are called from a process context. Filesystem locking is described in -the document Documentation/filesystems/Locking. +the document Documentation/filesystems/locking.rst. Directory Entry Cache (dcache) diff --git a/Documentation/acpi/dsd/leds.txt b/Documentation/firmware-guide/acpi/dsd/leds.rst similarity index 90% rename from Documentation/acpi/dsd/leds.txt rename to Documentation/firmware-guide/acpi/dsd/leds.rst index cc58b1a574c55a5d751c58aafae4edff1fe07809..946efe2b2936a5a4121627fb37a09e07c5ce1fd4 100644 --- a/Documentation/acpi/dsd/leds.txt +++ b/Documentation/firmware-guide/acpi/dsd/leds.rst @@ -1,4 +1,9 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: + +======================================== Describing and referring to LEDs in ACPI +======================================== Individual LEDs are described by hierarchical data extension [6] nodes under the device node, the LED driver chip. The "reg" property in the LED specific nodes @@ -25,8 +30,12 @@ entry shall contain the string "led@" followed by the number of the LED, followed by the referred object name. That object shall be named "LED" followed by the number of the LED. -An ASL example of a camera sensor device and a LED driver device for two LEDs. -Objects not relevant for LEDs or the references to them have been omitted. +Example +======= + +An ASL example of a camera sensor device and a LED driver device for two LEDs is +show below. Objects not relevant for LEDs or the references to them have been +omitted. :: Device (LED) { @@ -71,12 +80,15 @@ Objects not relevant for LEDs or the references to them have been omitted. } where +:: LED LED driver device LED0 First LED LED1 Second LED - SEN Camera sensor device (or another device the LED is - related to) + SEN Camera sensor device (or another device the LED is related to) + +References +========== [1] Device tree. , referenced 2019-02-21. diff --git a/Documentation/firmware-guide/acpi/index.rst b/Documentation/firmware-guide/acpi/index.rst index 90c90d42d9ad6284dbf0a2126d5025cc31d1c491..ad3b5afdae77e869ca8d685c4de1ed2f80ee67b0 100644 --- a/Documentation/firmware-guide/acpi/index.rst +++ b/Documentation/firmware-guide/acpi/index.rst @@ -10,6 +10,7 @@ ACPI Support namespace dsd/graph dsd/data-node-references + dsd/leds enumeration osi method-customizing diff --git a/Documentation/fpga/dfl.rst b/Documentation/fpga/dfl.rst index 2f125abd777f520b51ee257ef609e23cefd26bba..6fa483fc823eb6b37dfe95b6da1fb3d672978b7a 100644 --- a/Documentation/fpga/dfl.rst +++ b/Documentation/fpga/dfl.rst @@ -87,6 +87,8 @@ The following functions are exposed through ioctls: - Get driver API version (DFL_FPGA_GET_API_VERSION) - Check for extensions (DFL_FPGA_CHECK_EXTENSION) - Program bitstream (DFL_FPGA_FME_PORT_PR) +- Assign port to PF (DFL_FPGA_FME_PORT_ASSIGN) +- Release port from PF (DFL_FPGA_FME_PORT_RELEASE) More functions are exposed through sysfs (/sys/class/fpga_region/regionX/dfl-fme.n/): @@ -102,6 +104,10 @@ More functions are exposed through sysfs one FPGA device may have more than one port, this sysfs interface indicates how many ports the FPGA device has. + Global error reporting management (errors/) + error reporting sysfs interfaces allow user to read errors detected by the + hardware, and clear the logged errors. + FIU - PORT ========== @@ -143,6 +149,10 @@ More functions are exposed through sysfs: Read Accelerator GUID (afu_id) afu_id indicates which PR bitstream is programmed to this AFU. + Error reporting (errors/) + error reporting sysfs interfaces allow user to read port/afu errors + detected by the hardware, and clear the logged errors. + DFL Framework Overview ====================== @@ -218,6 +228,101 @@ the compat_id exposed by the target FPGA region. This check is usually done by userspace before calling the reconfiguration IOCTL. +FPGA virtualization - PCIe SRIOV +================================ +This section describes the virtualization support on DFL based FPGA device to +enable accessing an accelerator from applications running in a virtual machine +(VM). This section only describes the PCIe based FPGA device with SRIOV support. + +Features supported by the particular FPGA device are exposed through Device +Feature Lists, as illustrated below: + +:: + + +-------------------------------+ +-------------+ + | PF | | VF | + +-------------------------------+ +-------------+ + ^ ^ ^ ^ + | | | | + +-----|------------|---------|--------------|-------+ + | | | | | | + | +-----+ +-------+ +-------+ +-------+ | + | | FME | | Port0 | | Port1 | | Port2 | | + | +-----+ +-------+ +-------+ +-------+ | + | ^ ^ ^ | + | | | | | + | +-------+ +------+ +-------+ | + | | AFU | | AFU | | AFU | | + | +-------+ +------+ +-------+ | + | | + | DFL based FPGA PCIe Device | + +---------------------------------------------------+ + +FME is always accessed through the physical function (PF). + +Ports (and related AFUs) are accessed via PF by default, but could be exposed +through virtual function (VF) devices via PCIe SRIOV. Each VF only contains +1 Port and 1 AFU for isolation. Users could assign individual VFs (accelerators) +created via PCIe SRIOV interface, to virtual machines. + +The driver organization in virtualization case is illustrated below: +:: + + +-------++------++------+ | + | FME || FME || FME | | + | FPGA || FPGA || FPGA | | + |Manager||Bridge||Region| | + +-------++------++------+ | + +-----------------------+ +--------+ | +--------+ + | FME | | AFU | | | AFU | + | Module | | Module | | | Module | + +-----------------------+ +--------+ | +--------+ + +-----------------------+ | +-----------------------+ + | FPGA Container Device | | | FPGA Container Device | + | (FPGA Base Region) | | | (FPGA Base Region) | + +-----------------------+ | +-----------------------+ + +------------------+ | +------------------+ + | FPGA PCIE Module | | Virtual | FPGA PCIE Module | + +------------------+ Host | Machine +------------------+ + -------------------------------------- | ------------------------------ + +---------------+ | +---------------+ + | PCI PF Device | | | PCI VF Device | + +---------------+ | +---------------+ + +FPGA PCIe device driver is always loaded first once a FPGA PCIe PF or VF device +is detected. It: + +* Finishes enumeration on both FPGA PCIe PF and VF device using common + interfaces from DFL framework. +* Supports SRIOV. + +The FME device driver plays a management role in this driver architecture, it +provides ioctls to release Port from PF and assign Port to PF. After release +a port from PF, then it's safe to expose this port through a VF via PCIe SRIOV +sysfs interface. + +To enable accessing an accelerator from applications running in a VM, the +respective AFU's port needs to be assigned to a VF using the following steps: + +#. The PF owns all AFU ports by default. Any port that needs to be + reassigned to a VF must first be released through the + DFL_FPGA_FME_PORT_RELEASE ioctl on the FME device. + +#. Once N ports are released from PF, then user can use command below + to enable SRIOV and VFs. Each VF owns only one Port with AFU. + + :: + + echo N > $PCI_DEVICE_PATH/sriov_numvfs + +#. Pass through the VFs to VMs + +#. The AFU under VF is accessible from applications in VM (using the + same driver inside the VF). + +Note that an FME can't be assigned to a VF, thus PR and other management +functions are only available via the PF. + Device enumeration ================== This section introduces how applications enumerate the fpga device from diff --git a/Documentation/hwmon/adm1021.rst b/Documentation/hwmon/adm1021.rst index 6cbb0f75fe00e26919f208888fde81efb6df8140..116fb201995688495995a47a824786111383dadb 100644 --- a/Documentation/hwmon/adm1021.rst +++ b/Documentation/hwmon/adm1021.rst @@ -142,7 +142,7 @@ loading the adm1021 module, then things are good. If nothing happens when loading the adm1021 module, and you are certain that your specific Xeon processor model includes compatible sensors, you will have to explicitly instantiate the sensor chips from user-space. See -method 4 in Documentation/i2c/instantiating-devices. Possible slave +method 4 in Documentation/i2c/instantiating-devices.rst. Possible slave addresses are 0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e. It is likely that only temp2 will be correct and temp1 will have to be ignored. diff --git a/Documentation/hwmon/adm1275.rst b/Documentation/hwmon/adm1275.rst index 9a1913e5b4d929e9d1bddc3bf2606a2230125b19..49966ed70ec682fdb1f02187cccb2139f26ca96e 100644 --- a/Documentation/hwmon/adm1275.rst +++ b/Documentation/hwmon/adm1275.rst @@ -75,7 +75,7 @@ Usage Notes ----------- This driver does not auto-detect devices. You will have to instantiate the -devices explicitly. Please see Documentation/i2c/instantiating-devices for +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for details. The ADM1075, unlike many other PMBus devices, does not support internal voltage diff --git a/Documentation/hwmon/ads1015.rst b/Documentation/hwmon/ads1015.rst deleted file mode 100644 index e0951c4e57bb51b17f376ba36d6bc82ae258e878..0000000000000000000000000000000000000000 --- a/Documentation/hwmon/ads1015.rst +++ /dev/null @@ -1,90 +0,0 @@ -Kernel driver ads1015 -===================== - -Supported chips: - - * Texas Instruments ADS1015 - - Prefix: 'ads1015' - - Datasheet: Publicly available at the Texas Instruments website: - - http://focus.ti.com/lit/ds/symlink/ads1015.pdf - - * Texas Instruments ADS1115 - - Prefix: 'ads1115' - - Datasheet: Publicly available at the Texas Instruments website: - - http://focus.ti.com/lit/ds/symlink/ads1115.pdf - -Authors: - Dirk Eibach, Guntermann & Drunck GmbH - -Description ------------ - -This driver implements support for the Texas Instruments ADS1015/ADS1115. - -This device is a 12/16-bit A-D converter with 4 inputs. - -The inputs can be used single ended or in certain differential combinations. - -The inputs can be made available by 8 sysfs input files in0_input - in7_input: - - - in0: Voltage over AIN0 and AIN1. - - in1: Voltage over AIN0 and AIN3. - - in2: Voltage over AIN1 and AIN3. - - in3: Voltage over AIN2 and AIN3. - - in4: Voltage over AIN0 and GND. - - in5: Voltage over AIN1 and GND. - - in6: Voltage over AIN2 and GND. - - in7: Voltage over AIN3 and GND. - -Which inputs are available can be configured using platform data or devicetree. - -By default all inputs are exported. - -Platform Data -------------- - -In linux/platform_data/ads1015.h platform data is defined, channel_data contains -configuration data for the used input combinations: - -- pga is the programmable gain amplifier (values are full scale) - - - 0: +/- 6.144 V - - 1: +/- 4.096 V - - 2: +/- 2.048 V - - 3: +/- 1.024 V - - 4: +/- 0.512 V - - 5: +/- 0.256 V - -- data_rate in samples per second - - - 0: 128 - - 1: 250 - - 2: 490 - - 3: 920 - - 4: 1600 - - 5: 2400 - - 6: 3300 - -Example:: - - struct ads1015_platform_data data = { - .channel_data = { - [2] = { .enabled = true, .pga = 1, .data_rate = 0 }, - [4] = { .enabled = true, .pga = 4, .data_rate = 5 }, - } - }; - -In this case only in2_input (FS +/- 4.096 V, 128 SPS) and in4_input -(FS +/- 0.512 V, 2400 SPS) would be created. - -Devicetree ----------- - -Configuration is also possible via devicetree: -Documentation/devicetree/bindings/hwmon/ads1015.txt diff --git a/Documentation/hwmon/hih6130.rst b/Documentation/hwmon/hih6130.rst index 649bd4be4fc28f6519f9a8f874868e8a00e2f10c..e95d373eb6936b586cb3b399b337446a4b664d78 100644 --- a/Documentation/hwmon/hih6130.rst +++ b/Documentation/hwmon/hih6130.rst @@ -27,7 +27,7 @@ The devices communicate with the I2C protocol. All sensors are set to the same I2C address 0x27 by default, so an entry with I2C_BOARD_INFO("hih6130", 0x27) can be used in the board setup code. -Please see Documentation/i2c/instantiating-devices for details on how to +Please see Documentation/i2c/instantiating-devices.rst for details on how to instantiate I2C devices. sysfs-Interface diff --git a/Documentation/hwmon/ibm-cffps.rst b/Documentation/hwmon/ibm-cffps.rst index 52e74e39463ad513388b9a28bde860e2c3a70c56..ef8f3f806968195e07c0620e549cb97350f011c6 100644 --- a/Documentation/hwmon/ibm-cffps.rst +++ b/Documentation/hwmon/ibm-cffps.rst @@ -17,7 +17,7 @@ Usage Notes ----------- This driver does not auto-detect devices. You will have to instantiate the -devices explicitly. Please see Documentation/i2c/instantiating-devices for +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for details. Sysfs entries diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index ee090e51653a65d6302cf979baaf51ff660e62f0..8147c3f218bfb11167ca160ebc69c3d33b5b07f4 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -30,7 +30,6 @@ Hardware Monitoring Kernel Drivers adm1031 adm1275 adm9240 - ads1015 ads7828 adt7410 adt7411 @@ -130,6 +129,7 @@ Hardware Monitoring Kernel Drivers pcf8591 pmbus powr1220 + pxe1610 pwm-fan raspberrypi-hwmon sch5627 diff --git a/Documentation/hwmon/inspur-ipsps1.rst b/Documentation/hwmon/inspur-ipsps1.rst new file mode 100644 index 0000000000000000000000000000000000000000..2b871ae3448f289d433cb932d3be641e3748f608 --- /dev/null +++ b/Documentation/hwmon/inspur-ipsps1.rst @@ -0,0 +1,79 @@ +Kernel driver inspur-ipsps1 +======================= + +Supported chips: + + * Inspur Power System power supply unit + +Author: John Wang + +Description +----------- + +This driver supports Inspur Power System power supplies. This driver +is a client to the core PMBus driver. + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +devices explicitly. Please see Documentation/i2c/instantiating-devices for +details. + +Sysfs entries +------------- + +The following attributes are supported: + +======================= ====================================================== +curr1_input Measured input current +curr1_label "iin" +curr1_max Maximum current +curr1_max_alarm Current high alarm +curr2_input Measured output current in mA. +curr2_label "iout1" +curr2_crit Critical maximum current +curr2_crit_alarm Current critical high alarm +curr2_max Maximum current +curr2_max_alarm Current high alarm + +fan1_alarm Fan 1 warning. +fan1_fault Fan 1 fault. +fan1_input Fan 1 speed in RPM. + +in1_alarm Input voltage under-voltage alarm. +in1_input Measured input voltage in mV. +in1_label "vin" +in2_input Measured output voltage in mV. +in2_label "vout1" +in2_lcrit Critical minimum output voltage +in2_lcrit_alarm Output voltage critical low alarm +in2_max Maximum output voltage +in2_max_alarm Output voltage high alarm +in2_min Minimum output voltage +in2_min_alarm Output voltage low alarm + +power1_alarm Input fault or alarm. +power1_input Measured input power in uW. +power1_label "pin" +power1_max Input power limit +power2_max_alarm Output power high alarm +power2_max Output power limit +power2_input Measured output power in uW. +power2_label "pout" + +temp[1-3]_input Measured temperature +temp[1-2]_max Maximum temperature +temp[1-3]_max_alarm Temperature high alarm + +vendor Manufacturer name +model Product model +part_number Product part number +serial_number Product serial number +fw_version Firmware version +hw_version Hardware version +mode Work mode. Can be set to active or + standby, when set to standby, PSU will + automatically switch between standby + and redundancy mode. +======================= ====================================================== diff --git a/Documentation/hwmon/lm25066.rst b/Documentation/hwmon/lm25066.rst index da15e3094c8c12f6d03d5b1289a5dd47f81539b1..30e6e77fb3c8f0437694d42ddf13a46bee7accbe 100644 --- a/Documentation/hwmon/lm25066.rst +++ b/Documentation/hwmon/lm25066.rst @@ -76,7 +76,7 @@ Usage Notes ----------- This driver does not auto-detect devices. You will have to instantiate the -devices explicitly. Please see Documentation/i2c/instantiating-devices for +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for details. diff --git a/Documentation/hwmon/lm75.rst b/Documentation/hwmon/lm75.rst index ba8acbd2a6cb3f0c1945e3f9fa4d5b2699fcc27e..e749f827c00236ba7d5ada47d4ec34b1d1c86db6 100644 --- a/Documentation/hwmon/lm75.rst +++ b/Documentation/hwmon/lm75.rst @@ -119,9 +119,9 @@ Supported chips: http://www.ti.com/product/tmp275 - * NXP LM75B + * NXP LM75B, PCT2075 - Prefix: 'lm75b' + Prefix: 'lm75b', 'pct2075' Addresses scanned: none @@ -129,6 +129,8 @@ Supported chips: http://www.nxp.com/documents/data_sheet/LM75B.pdf + http://www.nxp.com/docs/en/data-sheet/PCT2075.pdf + Author: Frodo Looijaard Description diff --git a/Documentation/hwmon/max16064.rst b/Documentation/hwmon/max16064.rst index 6d5e9538991f87a0c9a78d8088ca0fcb7b1659cd..c06249292557a03935cd9f28329d61b4c25d1e58 100644 --- a/Documentation/hwmon/max16064.rst +++ b/Documentation/hwmon/max16064.rst @@ -28,7 +28,7 @@ Usage Notes ----------- This driver does not auto-detect devices. You will have to instantiate the -devices explicitly. Please see Documentation/i2c/instantiating-devices for +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for details. diff --git a/Documentation/hwmon/max16065.rst b/Documentation/hwmon/max16065.rst index fa5c852a178cc4f45307f0b6a3c91547559ee1af..45f69f334f252c5c346ccc4cff86047891e00fc5 100644 --- a/Documentation/hwmon/max16065.rst +++ b/Documentation/hwmon/max16065.rst @@ -79,7 +79,7 @@ Usage Notes This driver does not probe for devices, since there is no register which can be safely used to identify the chip. You will have to instantiate -the devices explicitly. Please see Documentation/i2c/instantiating-devices for +the devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for details. WARNING: Do not access chip registers using the i2cdump command, and do not use diff --git a/Documentation/hwmon/max20751.rst b/Documentation/hwmon/max20751.rst index aa4469be6674f297ffed116c6f5fed85059d18f2..fe701e07eaf50e2e568ae260f4f8ec54108406c2 100644 --- a/Documentation/hwmon/max20751.rst +++ b/Documentation/hwmon/max20751.rst @@ -30,7 +30,7 @@ Usage Notes ----------- This driver does not auto-detect devices. You will have to instantiate the -devices explicitly. Please see Documentation/i2c/instantiating-devices for +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for details. diff --git a/Documentation/hwmon/max34440.rst b/Documentation/hwmon/max34440.rst index 939138e12b02ceb865ef26c325055ab5e06f49b3..5744df100a5dbdf2a04d4609cb398348898e90c4 100644 --- a/Documentation/hwmon/max34440.rst +++ b/Documentation/hwmon/max34440.rst @@ -83,7 +83,7 @@ Usage Notes ----------- This driver does not auto-detect devices. You will have to instantiate the -devices explicitly. Please see Documentation/i2c/instantiating-devices for +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for details. For MAX34446, the value of the currX_crit attribute determines if current or diff --git a/Documentation/hwmon/max6650.rst b/Documentation/hwmon/max6650.rst index 253482add08261d71814c2c254e825fe7ce78380..7952b6ecaa2df79ef256b8d48662c9b717069f84 100644 --- a/Documentation/hwmon/max6650.rst +++ b/Documentation/hwmon/max6650.rst @@ -55,7 +55,7 @@ Usage notes ----------- This driver does not auto-detect devices. You will have to instantiate the -devices explicitly. Please see Documentation/i2c/instantiating-devices for +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for details. Module parameters diff --git a/Documentation/hwmon/max8688.rst b/Documentation/hwmon/max8688.rst index 009487759c61dcb5252f3fa39352b8a343e9b134..71e7f2cbe2e20c533bf1b112776b2a5f4dc03388 100644 --- a/Documentation/hwmon/max8688.rst +++ b/Documentation/hwmon/max8688.rst @@ -28,7 +28,7 @@ Usage Notes ----------- This driver does not auto-detect devices. You will have to instantiate the -devices explicitly. Please see Documentation/i2c/instantiating-devices for +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for details. diff --git a/Documentation/hwmon/menf21bmc.rst b/Documentation/hwmon/menf21bmc.rst index 1f0c6b2235ab33f9150415e7111da9da9d12f002..978691d5956dbfef72bb89b7a6d485d213bfbed7 100644 --- a/Documentation/hwmon/menf21bmc.rst +++ b/Documentation/hwmon/menf21bmc.rst @@ -28,7 +28,7 @@ Usage Notes This driver is part of the MFD driver named "menf21bmc" and does not auto-detect devices. You will have to instantiate the MFD driver explicitly. -Please see Documentation/i2c/instantiating-devices for +Please see Documentation/i2c/instantiating-devices.rst for details. Sysfs entries diff --git a/Documentation/hwmon/pcf8591.rst b/Documentation/hwmon/pcf8591.rst index e98bd542a441d7c3351fe2634532f7e1d9199104..5c4e85f531777a8b7970bb5ea6d9de7dd16a5ab9 100644 --- a/Documentation/hwmon/pcf8591.rst +++ b/Documentation/hwmon/pcf8591.rst @@ -68,7 +68,7 @@ Accessing PCF8591 via /sys interface The PCF8591 is plainly impossible to detect! Thus the driver won't even try. You have to explicitly instantiate the device at the relevant address (in the interval [0x48..0x4f]) either through platform data, or -using the sysfs interface. See Documentation/i2c/instantiating-devices +using the sysfs interface. See Documentation/i2c/instantiating-devices.rst for details. Directories are being created for each instantiated PCF8591: diff --git a/Documentation/hwmon/pxe1610 b/Documentation/hwmon/pxe1610.rst similarity index 82% rename from Documentation/hwmon/pxe1610 rename to Documentation/hwmon/pxe1610.rst index 211cedeefb444e8e90ec083e032e4239eea9ec5e..4f2388840d06ca27f0a65c71b388842a0d5aaa24 100644 --- a/Documentation/hwmon/pxe1610 +++ b/Documentation/hwmon/pxe1610.rst @@ -2,19 +2,29 @@ Kernel driver pxe1610 ===================== Supported chips: + * Infineon PXE1610 + Prefix: 'pxe1610' + Addresses scanned: - + Datasheet: Datasheet is not publicly available. * Infineon PXE1110 + Prefix: 'pxe1110' + Addresses scanned: - + Datasheet: Datasheet is not publicly available. * Infineon PXM1310 + Prefix: 'pxm1310' + Addresses scanned: - + Datasheet: Datasheet is not publicly available. Author: Vijay Khemka @@ -25,14 +35,19 @@ Description PXE1610/PXE1110 are Multi-rail/Multiphase Digital Controllers and compliant to - -- Intel VR13 DC-DC converter specifications. - -- Intel SVID protocol. + + - Intel VR13 DC-DC converter specifications. + - Intel SVID protocol. + Used for Vcore power regulation for Intel VR13 based microprocessors - -- Servers, Workstations, and High-end desktops + + - Servers, Workstations, and High-end desktops PXM1310 is a Multi-rail Controller and it is compliant to - -- Intel VR13 DC-DC converter specifications. - -- Intel SVID protocol. + + - Intel VR13 DC-DC converter specifications. + - Intel SVID protocol. + Used for DDR3/DDR4 Memory power regulation for Intel VR13 and IMVP8 based systems @@ -44,10 +59,10 @@ This driver does not probe for PMBus devices. You will have to instantiate devices explicitly. Example: the following commands will load the driver for an PXE1610 -at address 0x70 on I2C bus #4: +at address 0x70 on I2C bus #4:: -# modprobe pxe1610 -# echo pxe1610 0x70 > /sys/bus/i2c/devices/i2c-4/new_device + # modprobe pxe1610 + # echo pxe1610 0x70 > /sys/bus/i2c/devices/i2c-4/new_device It can also be instantiated by declaring in device tree @@ -55,6 +70,7 @@ It can also be instantiated by declaring in device tree Sysfs attributes ---------------- +====================== ==================================== curr1_label "iin" curr1_input Measured input current curr1_alarm Current high alarm @@ -88,3 +104,4 @@ temp[1-3]_crit Critical high temperature temp[1-3]_crit_alarm Chip temperature critical high alarm temp[1-3]_max Maximum temperature temp[1-3]_max_alarm Chip temperature high alarm +====================== ==================================== diff --git a/Documentation/hwmon/sht3x.rst b/Documentation/hwmon/sht3x.rst index 978a7117e4b28c1e200d2039f86281f364cd04f3..95a850d5b2c1d7b15b98ff2a800d46e93f6816c6 100644 --- a/Documentation/hwmon/sht3x.rst +++ b/Documentation/hwmon/sht3x.rst @@ -26,7 +26,7 @@ scaled by 1000, i.e. the value for 31.5 degrees celsius is 31500. The device communicates with the I2C protocol. Sensors can have the I2C addresses 0x44 or 0x45, depending on the wiring. See -Documentation/i2c/instantiating-devices for methods to instantiate the device. +Documentation/i2c/instantiating-devices.rst for methods to instantiate the device. There are two options configurable by means of sht3x_platform_data: diff --git a/Documentation/hwmon/shtc1.rst b/Documentation/hwmon/shtc1.rst index aa116332ba26087a35f72b1541ee388ac21b7d1f..08380f21ab6a052a954d6261ca470670297ab2d2 100644 --- a/Documentation/hwmon/shtc1.rst +++ b/Documentation/hwmon/shtc1.rst @@ -19,7 +19,17 @@ Supported chips: Addresses scanned: none - Datasheet: Not publicly available + Datasheet: http://www.sensirion.com/file/datasheet_shtw1 + + + + * Sensirion SHTC3 + + Prefix: 'shtc3' + + Addresses scanned: none + + Datasheet: http://www.sensirion.com/file/datasheet_shtc3 @@ -30,13 +40,12 @@ Author: Description ----------- -This driver implements support for the Sensirion SHTC1 chip, a humidity and -temperature sensor. Temperature is measured in degrees celsius, relative -humidity is expressed as a percentage. Driver can be used as well for SHTW1 -chip, which has the same electrical interface. +This driver implements support for the Sensirion SHTC1, SHTW1, and SHTC3 +chips, a humidity and temperature sensor. Temperature is measured in degrees +celsius, relative humidity is expressed as a percentage. The device communicates with the I2C protocol. All sensors are set to I2C -address 0x70. See Documentation/i2c/instantiating-devices for methods to +address 0x70. See Documentation/i2c/instantiating-devices.rst for methods to instantiate the device. There are two options configurable by means of shtc1_platform_data: diff --git a/Documentation/hwmon/submitting-patches.rst b/Documentation/hwmon/submitting-patches.rst index 452fc28d8e0bb3f7efefc6f20c5a0786ae72b22e..9a218ea996d8633e8705d4f9e8f41f0e90f3b2ad 100644 --- a/Documentation/hwmon/submitting-patches.rst +++ b/Documentation/hwmon/submitting-patches.rst @@ -20,6 +20,10 @@ increase the chances of your change being accepted. errors, no warnings, and few if any check messages. If there are any messages, please be prepared to explain. +* Please use the standard multi-line comment style. Do not mix C and C++ + style comments in a single driver (with the exception of the SPDX license + identifier). + * If your patch generates checkpatch errors, warnings, or check messages, please refrain from explanations such as "I prefer that coding style". Keep in mind that each unnecessary message helps hiding a real problem, @@ -120,8 +124,8 @@ increase the chances of your change being accepted. completely initialize your chip and your driver first, then register with the hwmon subsystem. -* Use devm_hwmon_device_register_with_groups() or, if your driver needs a remove - function, hwmon_device_register_with_groups() to register your driver with the +* Use devm_hwmon_device_register_with_info() or, if your driver needs a remove + function, hwmon_device_register_with_info() to register your driver with the hwmon subsystem. Try using devm_add_action() instead of a remove function if possible. Do not use hwmon_device_register(). diff --git a/Documentation/hwmon/tmp103.rst b/Documentation/hwmon/tmp103.rst index 15d25806d585877ce1846a27f0b17581f486a5e9..205de6148fcb8afcec6bccbea19486fc31c3a868 100644 --- a/Documentation/hwmon/tmp103.rst +++ b/Documentation/hwmon/tmp103.rst @@ -30,4 +30,4 @@ The driver provides the common sysfs-interface for temperatures (see Documentation/hwmon/sysfs-interface.rst under Temperatures). Please refer how to instantiate this driver: -Documentation/i2c/instantiating-devices +Documentation/i2c/instantiating-devices.rst diff --git a/Documentation/hwmon/tps40422.rst b/Documentation/hwmon/tps40422.rst index b691e30479ddf641d82453e8ad22104852580649..8fe3e1c3572e2aacee2c6519d05ad04ec3e40fa1 100644 --- a/Documentation/hwmon/tps40422.rst +++ b/Documentation/hwmon/tps40422.rst @@ -28,7 +28,7 @@ Usage Notes ----------- This driver does not auto-detect devices. You will have to instantiate the -devices explicitly. Please see Documentation/i2c/instantiating-devices for +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for details. diff --git a/Documentation/hwmon/ucd9000.rst b/Documentation/hwmon/ucd9000.rst index ebc4f2b3bfea7ca4e5d239c731225ca6f0a50b97..746f21fcb48ccc9c77f74f3fd0e435622bb31425 100644 --- a/Documentation/hwmon/ucd9000.rst +++ b/Documentation/hwmon/ucd9000.rst @@ -64,7 +64,7 @@ Usage Notes ----------- This driver does not auto-detect devices. You will have to instantiate the -devices explicitly. Please see Documentation/i2c/instantiating-devices for +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for details. diff --git a/Documentation/hwmon/ucd9200.rst b/Documentation/hwmon/ucd9200.rst index b819dfd75f71aa321bc65bb31c95ecef17161bc4..4f0e7c3ca6f44bfe42701ebf34109ec99f05cc93 100644 --- a/Documentation/hwmon/ucd9200.rst +++ b/Documentation/hwmon/ucd9200.rst @@ -40,7 +40,7 @@ Usage Notes ----------- This driver does not auto-detect devices. You will have to instantiate the -devices explicitly. Please see Documentation/i2c/instantiating-devices for +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for details. diff --git a/Documentation/hwmon/via686a.rst b/Documentation/hwmon/via686a.rst index a343c35df740e1dd2974ae9ac94522cb8aedc488..7ab9ddebcf7920a19f633cdd2f19a37e5a3e9e01 100644 --- a/Documentation/hwmon/via686a.rst +++ b/Documentation/hwmon/via686a.rst @@ -40,7 +40,7 @@ all as a 686A. The Via 686a southbridge has integrated hardware monitor functionality. It also has an I2C bus, but this driver only supports the hardware monitor. -For the I2C bus driver, see +For the I2C bus driver, see The Via 686a implements three temperature sensors, two fan rotation speed sensors, five voltage sensors and alarms. diff --git a/Documentation/hwmon/zl6100.rst b/Documentation/hwmon/zl6100.rst index 41513bb7fe51daa00afba7d64fdd4b336c05b274..968aff10ce0aa1447519ac905b539c62944e4cfc 100644 --- a/Documentation/hwmon/zl6100.rst +++ b/Documentation/hwmon/zl6100.rst @@ -121,7 +121,7 @@ Usage Notes ----------- This driver does not auto-detect devices. You will have to instantiate the -devices explicitly. Please see Documentation/i2c/instantiating-devices for +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for details. .. warning:: diff --git a/Documentation/i2c/busses/i2c-ali1535 b/Documentation/i2c/busses/i2c-ali1535.rst similarity index 82% rename from Documentation/i2c/busses/i2c-ali1535 rename to Documentation/i2c/busses/i2c-ali1535.rst index 5d46342e486a97125be5c5d1caa453a8eeb9cb8f..6941064730dc80e2ec60d8fcd2ab76d3a8a70f94 100644 --- a/Documentation/i2c/busses/i2c-ali1535 +++ b/Documentation/i2c/busses/i2c-ali1535.rst @@ -1,16 +1,19 @@ +========================= Kernel driver i2c-ali1535 +========================= Supported adapters: * Acer Labs, Inc. ALI 1535 (south bridge) + Datasheet: Now under NDA http://www.ali.com.tw/ Authors: - Frodo Looijaard , - Philip Edelbrock , - Mark D. Studebaker , - Dan Eaton , - Stephen Rousset + - Frodo Looijaard , + - Philip Edelbrock , + - Mark D. Studebaker , + - Dan Eaton , + - Stephen Rousset Description ----------- diff --git a/Documentation/i2c/busses/i2c-ali1563 b/Documentation/i2c/busses/i2c-ali1563.rst similarity index 93% rename from Documentation/i2c/busses/i2c-ali1563 rename to Documentation/i2c/busses/i2c-ali1563.rst index 41b1a077e4c7aaa5b8002448c182f4b39f6a9cad..eec32c3ba92a47232f67cd3ed330c963db38d9d8 100644 --- a/Documentation/i2c/busses/i2c-ali1563 +++ b/Documentation/i2c/busses/i2c-ali1563.rst @@ -1,7 +1,10 @@ +========================= Kernel driver i2c-ali1563 +========================= Supported adapters: * Acer Labs, Inc. ALI 1563 (south bridge) + Datasheet: Now under NDA http://www.ali.com.tw/ diff --git a/Documentation/i2c/busses/i2c-ali15x3 b/Documentation/i2c/busses/i2c-ali15x3.rst similarity index 72% rename from Documentation/i2c/busses/i2c-ali15x3 rename to Documentation/i2c/busses/i2c-ali15x3.rst index 42888d8ac1249d6232ebb2bd3e3b96fda87612ee..d4c1a2a419cb8399a98b9411e40b9e2d36bb03a1 100644 --- a/Documentation/i2c/busses/i2c-ali15x3 +++ b/Documentation/i2c/busses/i2c-ali15x3.rst @@ -1,20 +1,23 @@ +========================= Kernel driver i2c-ali15x3 +========================= Supported adapters: * Acer Labs, Inc. ALI 1533 and 1543C (south bridge) + Datasheet: Now under NDA http://www.ali.com.tw/ Authors: - Frodo Looijaard , - Philip Edelbrock , - Mark D. Studebaker + - Frodo Looijaard , + - Philip Edelbrock , + - Mark D. Studebaker Module Parameters ----------------- * force_addr: int - Initialize the base address of the i2c controller + Initialize the base address of the i2c controller Notes @@ -25,7 +28,9 @@ the BIOS. Does not do a PCI force; the device must still be present in lspci. Don't use this unless the driver complains that the base address is not set. -Example: 'modprobe i2c-ali15x3 force_addr=0xe800' +Example:: + + modprobe i2c-ali15x3 force_addr=0xe800 SMBus periodically hangs on ASUS P5A motherboards and can only be cleared by a power cycle. Cause unknown (see Issues below). @@ -38,47 +43,53 @@ This is the driver for the SMB Host controller on Acer Labs Inc. (ALI) M1541 and M1543C South Bridges. The M1543C is a South bridge for desktop systems. + The M1541 is a South bridge for portable systems. + They are part of the following ALI chipsets: * "Aladdin Pro 2" includes the M1621 Slot 1 North bridge with AGP and - 100MHz CPU Front Side bus + 100MHz CPU Front Side bus * "Aladdin V" includes the M1541 Socket 7 North bridge with AGP and 100MHz - CPU Front Side bus + CPU Front Side bus + Some Aladdin V motherboards: - Asus P5A - Atrend ATC-5220 - BCM/GVC VP1541 - Biostar M5ALA - Gigabyte GA-5AX (** Generally doesn't work because the BIOS doesn't - enable the 7101 device! **) - Iwill XA100 Plus - Micronics C200 - Microstar (MSI) MS-5169 + - Asus P5A + - Atrend ATC-5220 + - BCM/GVC VP1541 + - Biostar M5ALA + - Gigabyte GA-5AX (Generally doesn't work because the BIOS doesn't + enable the 7101 device!) + - Iwill XA100 Plus + - Micronics C200 + - Microstar (MSI) MS-5169 * "Aladdin IV" includes the M1541 Socket 7 North bridge - with host bus up to 83.3 MHz. + with host bus up to 83.3 MHz. For an overview of these chips see http://www.acerlabs.com. At this time the full data sheets on the web site are password protected, however if you contact the ALI office in San Jose they may give you the password. The M1533/M1543C devices appear as FOUR separate devices on the PCI bus. An -output of lspci will show something similar to the following: +output of lspci will show something similar to the following:: 00:02.0 USB Controller: Acer Laboratories Inc. M5237 (rev 03) 00:03.0 Bridge: Acer Laboratories Inc. M7101 <= THIS IS THE ONE WE NEED 00:07.0 ISA bridge: Acer Laboratories Inc. M1533 (rev c3) 00:0f.0 IDE interface: Acer Laboratories Inc. M5229 (rev c1) -** IMPORTANT ** -** If you have a M1533 or M1543C on the board and you get -** "ali15x3: Error: Can't detect ali15x3!" -** then run lspci. -** If you see the 1533 and 5229 devices but NOT the 7101 device, -** then you must enable ACPI, the PMU, SMB, or something similar -** in the BIOS. -** The driver won't work if it can't find the M7101 device. +.. important:: + + If you have a M1533 or M1543C on the board and you get + "ali15x3: Error: Can't detect ali15x3!" + then run lspci. + + If you see the 1533 and 5229 devices but NOT the 7101 device, + then you must enable ACPI, the PMU, SMB, or something similar + in the BIOS. + + The driver won't work if it can't find the M7101 device. The SMB controller is part of the M7101 device, which is an ACPI-compliant Power Management Unit (PMU). @@ -109,4 +120,3 @@ There may be electrical problems on this board. On the P5A, the W83781D sensor chip is on both the ISA and SMBus. Therefore the SMBus hangs can generally be avoided by accessing the W83781D on the ISA bus only. - diff --git a/Documentation/i2c/busses/i2c-amd-mp2 b/Documentation/i2c/busses/i2c-amd-mp2 deleted file mode 100644 index 6571487171f447688dc4b218d013a269bfb08e9a..0000000000000000000000000000000000000000 --- a/Documentation/i2c/busses/i2c-amd-mp2 +++ /dev/null @@ -1,23 +0,0 @@ -Kernel driver i2c-amd-mp2 - -Supported adapters: - * AMD MP2 PCIe interface - -Datasheet: not publicly available. - -Authors: - Shyam Sundar S K - Nehal Shah - Elie Morisse - -Description ------------ - -The MP2 is an ARM processor programmed as an I2C controller and communicating -with the x86 host through PCI. - -If you see something like this: - -03:00.7 MP2 I2C controller: Advanced Micro Devices, Inc. [AMD] Device 15e6 - -in your 'lspci -v', then this driver is for your device. diff --git a/Documentation/i2c/busses/i2c-amd-mp2.rst b/Documentation/i2c/busses/i2c-amd-mp2.rst new file mode 100644 index 0000000000000000000000000000000000000000..ebc2fa8993259b986124fcf1cd35ec1fe0ee1e43 --- /dev/null +++ b/Documentation/i2c/busses/i2c-amd-mp2.rst @@ -0,0 +1,25 @@ +========================= +Kernel driver i2c-amd-mp2 +========================= + +Supported adapters: + * AMD MP2 PCIe interface + +Datasheet: not publicly available. + +Authors: + - Shyam Sundar S K + - Nehal Shah + - Elie Morisse + +Description +----------- + +The MP2 is an ARM processor programmed as an I2C controller and communicating +with the x86 host through PCI. + +If you see something like this:: + + 03:00.7 MP2 I2C controller: Advanced Micro Devices, Inc. [AMD] Device 15e6 + +in your ``lspci -v``, then this driver is for your device. diff --git a/Documentation/i2c/busses/i2c-amd756 b/Documentation/i2c/busses/i2c-amd756.rst similarity index 79% rename from Documentation/i2c/busses/i2c-amd756 rename to Documentation/i2c/busses/i2c-amd756.rst index 67f30874d0bfbdd59e6f49645336094d63b7123e..bc93f392a4fc70c61f471bac7c0c3697749e0ca4 100644 --- a/Documentation/i2c/busses/i2c-amd756 +++ b/Documentation/i2c/busses/i2c-amd756.rst @@ -1,18 +1,22 @@ +======================== Kernel driver i2c-amd756 +======================== Supported adapters: * AMD 756 * AMD 766 * AMD 768 * AMD 8111 + Datasheets: Publicly available on AMD website * nVidia nForce + Datasheet: Unavailable Authors: - Frodo Looijaard , - Philip Edelbrock + - Frodo Looijaard , + - Philip Edelbrock Description ----------- diff --git a/Documentation/i2c/busses/i2c-amd8111 b/Documentation/i2c/busses/i2c-amd8111.rst similarity index 66% rename from Documentation/i2c/busses/i2c-amd8111 rename to Documentation/i2c/busses/i2c-amd8111.rst index 460dd6635fd26c916fb8cab16e46e6473aa3142d..d08bf0a7f0ac550ca78a1aaf4d87727cf5e444c7 100644 --- a/Documentation/i2c/busses/i2c-amd8111 +++ b/Documentation/i2c/busses/i2c-amd8111.rst @@ -1,4 +1,6 @@ +========================= Kernel driver i2c-adm8111 +========================= Supported adapters: * AMD-8111 SMBus 2.0 PCI interface @@ -13,14 +15,14 @@ Author: Vojtech Pavlik Description ----------- -If you see something like this: +If you see something like this:: -00:07.2 SMBus: Advanced Micro Devices [AMD] AMD-8111 SMBus 2.0 (rev 02) - Subsystem: Advanced Micro Devices [AMD] AMD-8111 SMBus 2.0 - Flags: medium devsel, IRQ 19 - I/O ports at d400 [size=32] + 00:07.2 SMBus: Advanced Micro Devices [AMD] AMD-8111 SMBus 2.0 (rev 02) + Subsystem: Advanced Micro Devices [AMD] AMD-8111 SMBus 2.0 + Flags: medium devsel, IRQ 19 + I/O ports at d400 [size=32] -in your 'lspci -v', then this driver is for your chipset. +in your ``lspci -v``, then this driver is for your chipset. Process Call Support -------------------- diff --git a/Documentation/i2c/busses/i2c-diolan-u2c b/Documentation/i2c/busses/i2c-diolan-u2c.rst similarity index 91% rename from Documentation/i2c/busses/i2c-diolan-u2c rename to Documentation/i2c/busses/i2c-diolan-u2c.rst index 0d6018c316c741f9cc0cf3b0391457b880b58234..c18cbdcdf73c19a8f02b9a1535487aca60f0a79e 100644 --- a/Documentation/i2c/busses/i2c-diolan-u2c +++ b/Documentation/i2c/busses/i2c-diolan-u2c.rst @@ -1,7 +1,10 @@ +============================ Kernel driver i2c-diolan-u2c +============================ Supported adapters: * Diolan U2C-12 I2C-USB adapter + Documentation: http://www.diolan.com/i2c/u2c12.html diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801.rst similarity index 89% rename from Documentation/i2c/busses/i2c-i801 rename to Documentation/i2c/busses/i2c-i801.rst index f426c13c63a99b43d10d33bc056b49451e8cb2db..2a570c214880d3ef8b952e7e84860b23f11cfb4a 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801.rst @@ -1,4 +1,7 @@ +====================== Kernel driver i2c-i801 +====================== + Supported adapters: * Intel 82801AA and 82801AB (ICH and ICH0 - part of the @@ -39,28 +42,33 @@ Supported adapters: * Intel Comet Lake (PCH) * Intel Elkhart Lake (PCH) * Intel Tiger Lake (PCH) + Datasheets: Publicly available at the Intel website On Intel Patsburg and later chipsets, both the normal host SMBus controller and the additional 'Integrated Device Function' controllers are supported. -Authors: - Mark Studebaker - Jean Delvare +Authors: + - Mark Studebaker + - Jean Delvare Module Parameters ----------------- * disable_features (bit vector) + Disable selected features normally supported by the device. This makes it possible to work around possible driver or hardware bugs if the feature in question doesn't work as intended for whatever reason. Bit values: + + ==== ========================================= 0x01 disable SMBus PEC 0x02 disable the block buffer 0x08 disable the I2C block read functionality 0x10 don't use interrupts 0x20 disable SMBus Host Notify + ==== ========================================= Description @@ -73,7 +81,7 @@ Pentium-based PCs, '815E' chipset, and others. The ICH chips contain at least SEVEN separate PCI functions in TWO logical PCI devices. An output of lspci will show something similar to the -following: +following:: 00:1e.0 PCI bridge: Intel Corporation: Unknown device 2418 (rev 01) 00:1f.0 ISA bridge: Intel Corporation: Unknown device 2410 (rev 01) @@ -139,14 +147,14 @@ and you think there's something interesting on the SMBus (e.g. a hardware monitoring chip), you need to add your board to the list. The motherboard is identified using the subvendor and subdevice IDs of the -host bridge PCI device. Get yours with "lspci -n -v -s 00:00.0": +host bridge PCI device. Get yours with ``lspci -n -v -s 00:00.0``:: -00:00.0 Class 0600: 8086:2570 (rev 02) - Subsystem: 1043:80f2 - Flags: bus master, fast devsel, latency 0 - Memory at fc000000 (32-bit, prefetchable) [size=32M] - Capabilities: [e4] #09 [2106] - Capabilities: [a0] AGP version 3.0 + 00:00.0 Class 0600: 8086:2570 (rev 02) + Subsystem: 1043:80f2 + Flags: bus master, fast devsel, latency 0 + Memory at fc000000 (32-bit, prefetchable) [size=32M] + Capabilities: [e4] #09 [2106] + Capabilities: [a0] AGP version 3.0 Here the host bridge ID is 2570 (82865G/PE/P), the subvendor ID is 1043 (Asus) and the subdevice ID is 80f2 (P4P800-X). You can find the symbolic @@ -165,7 +173,8 @@ kernel. It's very convenient if you just want to check if there's anything interesting on your hidden ICH SMBus. -********************** +---------------------------------------------------------------------------- + The lm_sensors project gratefully acknowledges the support of Texas Instruments in the initial development of this driver. diff --git a/Documentation/i2c/busses/i2c-ismt b/Documentation/i2c/busses/i2c-ismt.rst similarity index 81% rename from Documentation/i2c/busses/i2c-ismt rename to Documentation/i2c/busses/i2c-ismt.rst index 737355822c0be98e9dc9474d9fe1f7c385cf9f39..8e74919a3fdf911f783a089c0263eb0f459ccde9 100644 --- a/Documentation/i2c/busses/i2c-ismt +++ b/Documentation/i2c/busses/i2c-ismt.rst @@ -1,4 +1,7 @@ +====================== Kernel driver i2c-ismt +====================== + Supported adapters: * Intel S12xx series SOCs @@ -11,16 +14,21 @@ Module Parameters ----------------- * bus_speed (unsigned int) + Allows changing of the bus speed. Normally, the bus speed is set by the BIOS and never needs to be changed. However, some SMBus analyzers are too slow for monitoring the bus during debug, thus the need for this module parameter. Specify the bus speed in kHz. + Available bus frequency settings: - 0 no change - 80 kHz - 100 kHz - 400 kHz - 1000 kHz + + ==== ========= + 0 no change + 80 kHz + 100 kHz + 400 kHz + 1000 kHz + ==== ========= Description @@ -30,7 +38,7 @@ The S12xx series of SOCs have a pair of integrated SMBus 2.0 controllers targeted primarily at the microserver and storage markets. The S12xx series contain a pair of PCI functions. An output of lspci will show -something similar to the following: +something similar to the following:: 00:13.0 System peripheral: Intel Corporation Centerton SMBus 2.0 Controller 0 00:13.1 System peripheral: Intel Corporation Centerton SMBus 2.0 Controller 1 diff --git a/Documentation/i2c/busses/i2c-mlxcpld b/Documentation/i2c/busses/i2c-mlxcpld.rst similarity index 88% rename from Documentation/i2c/busses/i2c-mlxcpld rename to Documentation/i2c/busses/i2c-mlxcpld.rst index 925904aa9b57c787c750e83cdc3975cc1862e5d8..9a0b2916aa7128284dd738fc92b2087d79db2384 100644 --- a/Documentation/i2c/busses/i2c-mlxcpld +++ b/Documentation/i2c/busses/i2c-mlxcpld.rst @@ -1,9 +1,12 @@ +================== Driver i2c-mlxcpld +================== Author: Michael Shych This is the Mellanox I2C controller logic, implemented in Lattice CPLD device. + Device supports: - Master mode. - One physical bus. @@ -20,6 +23,8 @@ The next transaction types are supported: - Write Byte/Block. Registers: + +=============== === ======================================================================= CPBLTY 0x0 - capability reg. Bits [6:5] - transaction length. b01 - 72B is supported, 36B in other case. @@ -49,3 +54,4 @@ DATAx 0xa - 0x54 - 68 bytes data buffer regs. For read transactions address is sent in a separate transaction and specified in the four first bytes (DATA0 - DATA3). Data is read starting from DATA0. +=============== === ======================================================================= diff --git a/Documentation/i2c/busses/i2c-nforce2 b/Documentation/i2c/busses/i2c-nforce2.rst similarity index 58% rename from Documentation/i2c/busses/i2c-nforce2 rename to Documentation/i2c/busses/i2c-nforce2.rst index 9698c396b830a0383c66e3346a9d459262eff53c..83181445268f962827b1e9b58d82d2425879530c 100644 --- a/Documentation/i2c/busses/i2c-nforce2 +++ b/Documentation/i2c/busses/i2c-nforce2.rst @@ -1,10 +1,12 @@ +========================= Kernel driver i2c-nforce2 +========================= Supported adapters: - * nForce2 MCP 10de:0064 - * nForce2 Ultra 400 MCP 10de:0084 - * nForce3 Pro150 MCP 10de:00D4 - * nForce3 250Gb MCP 10de:00E4 + * nForce2 MCP 10de:0064 + * nForce2 Ultra 400 MCP 10de:0084 + * nForce3 Pro150 MCP 10de:00D4 + * nForce3 250Gb MCP 10de:00E4 * nForce4 MCP 10de:0052 * nForce4 MCP-04 10de:0034 * nForce MCP51 10de:0264 @@ -16,26 +18,27 @@ Supported adapters: * nForce MCP78S 10de:0752 * nForce MCP79 10de:0AA2 -Datasheet: not publicly available, but seems to be similar to the +Datasheet: + not publicly available, but seems to be similar to the AMD-8111 SMBus 2.0 adapter. Authors: - Hans-Frieder Vogt , - Thomas Leibold , - Patrick Dreker - + - Hans-Frieder Vogt , + - Thomas Leibold , + - Patrick Dreker + Description ----------- i2c-nforce2 is a driver for the SMBuses included in the nVidia nForce2 MCP. -If your 'lspci -v' listing shows something like the following, +If your ``lspci -v`` listing shows something like the following:: -00:01.1 SMBus: nVidia Corporation: Unknown device 0064 (rev a2) - Subsystem: Asustek Computer, Inc.: Unknown device 0c11 - Flags: 66Mhz, fast devsel, IRQ 5 - I/O ports at c000 [size=32] - Capabilities: + 00:01.1 SMBus: nVidia Corporation: Unknown device 0064 (rev a2) + Subsystem: Asustek Computer, Inc.: Unknown device 0c11 + Flags: 66Mhz, fast devsel, IRQ 5 + I/O ports at c000 [size=32] + Capabilities: then this driver should support the SMBuses of your motherboard. diff --git a/Documentation/i2c/busses/i2c-nvidia-gpu b/Documentation/i2c/busses/i2c-nvidia-gpu.rst similarity index 63% rename from Documentation/i2c/busses/i2c-nvidia-gpu rename to Documentation/i2c/busses/i2c-nvidia-gpu.rst index 31884d2b2eb5a9e1f9756c7affa952c85e6c1be3..38fb8a4c8756d213fda77c837430616410392d7f 100644 --- a/Documentation/i2c/busses/i2c-nvidia-gpu +++ b/Documentation/i2c/busses/i2c-nvidia-gpu.rst @@ -1,4 +1,6 @@ +============================ Kernel driver i2c-nvidia-gpu +============================ Datasheet: not publicly available. @@ -11,8 +13,8 @@ Description i2c-nvidia-gpu is a driver for I2C controller included in NVIDIA Turing and later GPUs and it is used to communicate with Type-C controller on GPUs. -If your 'lspci -v' listing shows something like the following, +If your ``lspci -v`` listing shows something like the following:: -01:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad9 (rev a1) + 01:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad9 (rev a1) then this driver should support the I2C controller of your GPU. diff --git a/Documentation/i2c/busses/i2c-ocores b/Documentation/i2c/busses/i2c-ocores.rst similarity index 82% rename from Documentation/i2c/busses/i2c-ocores rename to Documentation/i2c/busses/i2c-ocores.rst index 9caaf7df1b2ff5ae6044c843b8ee2b111731fd7e..f5e175f2a2a62e0618456d6b90a89bf7367f0bde 100644 --- a/Documentation/i2c/busses/i2c-ocores +++ b/Documentation/i2c/busses/i2c-ocores.rst @@ -1,4 +1,6 @@ +======================== Kernel driver i2c-ocores +======================== Supported adapters: * OpenCores.org I2C controller by Richard Herveille (see datasheet link) @@ -23,9 +25,9 @@ distance between registers and the input clock speed. There is also a possibility to attach a list of i2c_board_info which the i2c-ocores driver will add to the bus upon creation. -E.G. something like: +E.G. something like:: -static struct resource ocores_resources[] = { + static struct resource ocores_resources[] = { [0] = { .start = MYI2C_BASEADDR, .end = MYI2C_BASEADDR + 8, @@ -36,10 +38,10 @@ static struct resource ocores_resources[] = { .end = MYI2C_IRQ, .flags = IORESOURCE_IRQ, }, -}; + }; -/* optional board info */ -struct i2c_board_info ocores_i2c_board_info[] = { + /* optional board info */ + struct i2c_board_info ocores_i2c_board_info[] = { { I2C_BOARD_INFO("tsc2003", 0x48), .platform_data = &tsc2003_platform_data, @@ -49,20 +51,20 @@ struct i2c_board_info ocores_i2c_board_info[] = { I2C_BOARD_INFO("adv7180", 0x42 >> 1), .irq = ADV_IRQ } -}; + }; -static struct ocores_i2c_platform_data myi2c_data = { + static struct ocores_i2c_platform_data myi2c_data = { .regstep = 2, /* two bytes between registers */ .clock_khz = 50000, /* input clock of 50MHz */ .devices = ocores_i2c_board_info, /* optional table of devices */ .num_devices = ARRAY_SIZE(ocores_i2c_board_info), /* table size */ -}; + }; -static struct platform_device myi2c = { + static struct platform_device myi2c = { .name = "ocores-i2c", .dev = { .platform_data = &myi2c_data, }, .num_resources = ARRAY_SIZE(ocores_resources), .resource = ocores_resources, -}; + }; diff --git a/Documentation/i2c/busses/i2c-parport b/Documentation/i2c/busses/i2c-parport deleted file mode 100644 index c3dbb3bfd8141f300346aa262a496b72320254b3..0000000000000000000000000000000000000000 --- a/Documentation/i2c/busses/i2c-parport +++ /dev/null @@ -1,178 +0,0 @@ -Kernel driver i2c-parport - -Author: Jean Delvare - -This is a unified driver for several i2c-over-parallel-port adapters, -such as the ones made by Philips, Velleman or ELV. This driver is -meant as a replacement for the older, individual drivers: - * i2c-philips-par - * i2c-elv - * i2c-velleman - * video/i2c-parport (NOT the same as this one, dedicated to home brew - teletext adapters) - -It currently supports the following devices: - * (type=0) Philips adapter - * (type=1) home brew teletext adapter - * (type=2) Velleman K8000 adapter - * (type=3) ELV adapter - * (type=4) Analog Devices ADM1032 evaluation board - * (type=5) Analog Devices evaluation boards: ADM1025, ADM1030, ADM1031 - * (type=6) Barco LPT->DVI (K5800236) adapter - * (type=7) One For All JP1 parallel port adapter - * (type=8) VCT-jig - -These devices use different pinout configurations, so you have to tell -the driver what you have, using the type module parameter. There is no -way to autodetect the devices. Support for different pinout configurations -can be easily added when needed. - -Earlier kernels defaulted to type=0 (Philips). But now, if the type -parameter is missing, the driver will simply fail to initialize. - -SMBus alert support is available on adapters which have this line properly -connected to the parallel port's interrupt pin. - - -Building your own adapter -------------------------- - -If you want to build you own i2c-over-parallel-port adapter, here is -a sample electronics schema (credits go to Sylvain Munaut): - -Device PC -Side ___________________Vdd (+) Side - | | | - --- --- --- - | | | | | | - |R| |R| |R| - | | | | | | - --- --- --- - | | | - | | /| | -SCL ----------x--------o |-----------x------------------- pin 2 - | \| | | - | | | - | |\ | | -SDA ----------x----x---| o---x--------------------------- pin 13 - | |/ | - | | - | /| | - ---------o |----------------x-------------- pin 3 - \| | | - | | - --- --- - | | | | - |R| |R| - | | | | - --- --- - | | - ### ### - GND GND - -Remarks: - - This is the exact pinout and electronics used on the Analog Devices - evaluation boards. - /| - - All inverters -o |- must be 74HC05, they must be open collector output. - \| - - All resitors are 10k. - - Pins 18-25 of the parallel port connected to GND. - - Pins 4-9 (D2-D7) could be used as VDD is the driver drives them high. - The ADM1032 evaluation board uses D4-D7. Beware that the amount of - current you can draw from the parallel port is limited. Also note that - all connected lines MUST BE driven at the same state, else you'll short - circuit the output buffers! So plugging the I2C adapter after loading - the i2c-parport module might be a good safety since data line state - prior to init may be unknown. - - This is 5V! - - Obviously you cannot read SCL (so it's not really standard-compliant). - Pretty easy to add, just copy the SDA part and use another input pin. - That would give (ELV compatible pinout): - - -Device PC -Side ______________________________Vdd (+) Side - | | | | - --- --- --- --- - | | | | | | | | - |R| |R| |R| |R| - | | | | | | | | - --- --- --- --- - | | | | - | | |\ | | -SCL ----------x--------x--| o---x------------------------ pin 15 - | | |/ | - | | | - | | /| | - | ---o |-------------x-------------- pin 2 - | \| | | - | | | - | | | - | |\ | | -SDA ---------------x---x--| o--------x------------------- pin 10 - | |/ | - | | - | /| | - ---o |------------------x--------- pin 3 - \| | | - | | - --- --- - | | | | - |R| |R| - | | | | - --- --- - | | - ### ### - GND GND - - -If possible, you should use the same pinout configuration as existing -adapters do, so you won't even have to change the code. - - -Similar (but different) drivers -------------------------------- - -This driver is NOT the same as the i2c-pport driver found in the i2c -package. The i2c-pport driver makes use of modern parallel port features so -that you don't need additional electronics. It has other restrictions -however, and was not ported to Linux 2.6 (yet). - -This driver is also NOT the same as the i2c-pcf-epp driver found in the -lm_sensors package. The i2c-pcf-epp driver doesn't use the parallel port as -an I2C bus directly. Instead, it uses it to control an external I2C bus -master. That driver was not ported to Linux 2.6 (yet) either. - - -Legacy documentation for Velleman adapter ------------------------------------------ - -Useful links: -Velleman http://www.velleman.be/ -Velleman K8000 Howto http://howto.htlw16.ac.at/k8000-howto.html - -The project has lead to new libs for the Velleman K8000 and K8005: - LIBK8000 v1.99.1 and LIBK8005 v0.21 -With these libs, you can control the K8000 interface card and the K8005 -stepper motor card with the simple commands which are in the original -Velleman software, like SetIOchannel, ReadADchannel, SendStepCCWFull and -many more, using /dev/velleman. - http://home.wanadoo.nl/hihihi/libk8000.htm - http://home.wanadoo.nl/hihihi/libk8005.htm - http://struyve.mine.nu:8080/index.php?block=k8000 - http://sourceforge.net/projects/libk8005/ - - -One For All JP1 parallel port adapter -------------------------------------- - -The JP1 project revolves around a set of remote controls which expose -the I2C bus their internal configuration EEPROM lives on via a 6 pin -jumper in the battery compartment. More details can be found at: - -http://www.hifi-remote.com/jp1/ - -Details of the simple parallel port hardware can be found at: - -http://www.hifi-remote.com/jp1/hardware.shtml diff --git a/Documentation/i2c/busses/i2c-parport-light b/Documentation/i2c/busses/i2c-parport-light.rst similarity index 91% rename from Documentation/i2c/busses/i2c-parport-light rename to Documentation/i2c/busses/i2c-parport-light.rst index 7071b8ba0af4c88b9b73c100d1a0766a2ca20618..e73af975d2c847d59edc5a37c3d77b5a46e3e561 100644 --- a/Documentation/i2c/busses/i2c-parport-light +++ b/Documentation/i2c/busses/i2c-parport-light.rst @@ -1,13 +1,15 @@ +=============================== Kernel driver i2c-parport-light +=============================== Author: Jean Delvare -This driver is a light version of i2c-parport. It doesn't depend +This driver is a light version of i2c-parport. It doesn't depend on the parport driver, and uses direct I/O access instead. This might be preferred on embedded systems where wasting memory for the clean but heavy parport handling is not an option. The drawback is a reduced portability -and the impossibility to daisy-chain other parallel port devices. - +and the impossibility to daisy-chain other parallel port devices. + Please see i2c-parport for documentation. Module parameters: diff --git a/Documentation/i2c/busses/i2c-parport.rst b/Documentation/i2c/busses/i2c-parport.rst new file mode 100644 index 0000000000000000000000000000000000000000..a9b4e8133700b6380bc896ae7a11f41af0168190 --- /dev/null +++ b/Documentation/i2c/busses/i2c-parport.rst @@ -0,0 +1,190 @@ +========================= +Kernel driver i2c-parport +========================= + +Author: Jean Delvare + +This is a unified driver for several i2c-over-parallel-port adapters, +such as the ones made by Philips, Velleman or ELV. This driver is +meant as a replacement for the older, individual drivers: + + * i2c-philips-par + * i2c-elv + * i2c-velleman + * video/i2c-parport + (NOT the same as this one, dedicated to home brew teletext adapters) + +It currently supports the following devices: + + * (type=0) Philips adapter + * (type=1) home brew teletext adapter + * (type=2) Velleman K8000 adapter + * (type=3) ELV adapter + * (type=4) Analog Devices ADM1032 evaluation board + * (type=5) Analog Devices evaluation boards: ADM1025, ADM1030, ADM1031 + * (type=6) Barco LPT->DVI (K5800236) adapter + * (type=7) One For All JP1 parallel port adapter + * (type=8) VCT-jig + +These devices use different pinout configurations, so you have to tell +the driver what you have, using the type module parameter. There is no +way to autodetect the devices. Support for different pinout configurations +can be easily added when needed. + +Earlier kernels defaulted to type=0 (Philips). But now, if the type +parameter is missing, the driver will simply fail to initialize. + +SMBus alert support is available on adapters which have this line properly +connected to the parallel port's interrupt pin. + + +Building your own adapter +------------------------- + +If you want to build you own i2c-over-parallel-port adapter, here is +a sample electronics schema (credits go to Sylvain Munaut):: + + Device PC + Side ___________________Vdd (+) Side + | | | + --- --- --- + | | | | | | + |R| |R| |R| + | | | | | | + --- --- --- + | | | + | | /| | + SCL ----------x--------o |-----------x------------------- pin 2 + | \| | | + | | | + | |\ | | + SDA ----------x----x---| o---x--------------------------- pin 13 + | |/ | + | | + | /| | + ---------o |----------------x-------------- pin 3 + \| | | + | | + --- --- + | | | | + |R| |R| + | | | | + --- --- + | | + ### ### + GND GND + +Remarks: + - This is the exact pinout and electronics used on the Analog Devices + evaluation boards. + - All inverters:: + + /| + -o |- + \| + + must be 74HC05, they must be open collector output. + - All resitors are 10k. + - Pins 18-25 of the parallel port connected to GND. + - Pins 4-9 (D2-D7) could be used as VDD is the driver drives them high. + The ADM1032 evaluation board uses D4-D7. Beware that the amount of + current you can draw from the parallel port is limited. Also note that + all connected lines MUST BE driven at the same state, else you'll short + circuit the output buffers! So plugging the I2C adapter after loading + the i2c-parport module might be a good safety since data line state + prior to init may be unknown. + - This is 5V! + - Obviously you cannot read SCL (so it's not really standard-compliant). + Pretty easy to add, just copy the SDA part and use another input pin. + That would give (ELV compatible pinout):: + + + Device PC + Side ______________________________Vdd (+) Side + | | | | + --- --- --- --- + | | | | | | | | + |R| |R| |R| |R| + | | | | | | | | + --- --- --- --- + | | | | + | | |\ | | + SCL ----------x--------x--| o---x------------------------ pin 15 + | | |/ | + | | | + | | /| | + | ---o |-------------x-------------- pin 2 + | \| | | + | | | + | | | + | |\ | | + SDA ---------------x---x--| o--------x------------------- pin 10 + | |/ | + | | + | /| | + ---o |------------------x--------- pin 3 + \| | | + | | + --- --- + | | | | + |R| |R| + | | | | + --- --- + | | + ### ### + GND GND + + +If possible, you should use the same pinout configuration as existing +adapters do, so you won't even have to change the code. + + +Similar (but different) drivers +------------------------------- + +This driver is NOT the same as the i2c-pport driver found in the i2c +package. The i2c-pport driver makes use of modern parallel port features so +that you don't need additional electronics. It has other restrictions +however, and was not ported to Linux 2.6 (yet). + +This driver is also NOT the same as the i2c-pcf-epp driver found in the +lm_sensors package. The i2c-pcf-epp driver doesn't use the parallel port as +an I2C bus directly. Instead, it uses it to control an external I2C bus +master. That driver was not ported to Linux 2.6 (yet) either. + + +Legacy documentation for Velleman adapter +----------------------------------------- + +Useful links: + +- Velleman http://www.velleman.be/ +- Velleman K8000 Howto http://howto.htlw16.ac.at/k8000-howto.html + +The project has lead to new libs for the Velleman K8000 and K8005: + + LIBK8000 v1.99.1 and LIBK8005 v0.21 + +With these libs, you can control the K8000 interface card and the K8005 +stepper motor card with the simple commands which are in the original +Velleman software, like SetIOchannel, ReadADchannel, SendStepCCWFull and +many more, using /dev/velleman. + + - http://home.wanadoo.nl/hihihi/libk8000.htm + - http://home.wanadoo.nl/hihihi/libk8005.htm + - http://struyve.mine.nu:8080/index.php?block=k8000 + - http://sourceforge.net/projects/libk8005/ + + +One For All JP1 parallel port adapter +------------------------------------- + +The JP1 project revolves around a set of remote controls which expose +the I2C bus their internal configuration EEPROM lives on via a 6 pin +jumper in the battery compartment. More details can be found at: + +http://www.hifi-remote.com/jp1/ + +Details of the simple parallel port hardware can be found at: + +http://www.hifi-remote.com/jp1/hardware.shtml diff --git a/Documentation/i2c/busses/i2c-pca-isa b/Documentation/i2c/busses/i2c-pca-isa.rst similarity index 72% rename from Documentation/i2c/busses/i2c-pca-isa rename to Documentation/i2c/busses/i2c-pca-isa.rst index b044e52654886c05dd37d16212a4cd2cf80419a3..a254010c805532778f418d79ddbba31044db4348 100644 --- a/Documentation/i2c/busses/i2c-pca-isa +++ b/Documentation/i2c/busses/i2c-pca-isa.rst @@ -1,6 +1,9 @@ +========================= Kernel driver i2c-pca-isa +========================= Supported adapters: + This driver supports ISA boards using the Philips PCA 9564 Parallel bus to I2C bus controller @@ -10,11 +13,11 @@ Module Parameters ----------------- * base int - I/O base address + I/O base address * irq int - IRQ interrupt + IRQ interrupt * clock int - Clock rate as described in table 1 of PCA9564 datasheet + Clock rate as described in table 1 of PCA9564 datasheet Description ----------- diff --git a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4.rst similarity index 92% rename from Documentation/i2c/busses/i2c-piix4 rename to Documentation/i2c/busses/i2c-piix4.rst index 2703bc3acad07ba5e1e61b2607ae9c6954e2dfea..cc900025922309f0bd86658e99b021f7b2bc8c38 100644 --- a/Documentation/i2c/busses/i2c-piix4 +++ b/Documentation/i2c/busses/i2c-piix4.rst @@ -1,4 +1,6 @@ +======================= Kernel driver i2c-piix4 +======================= Supported adapters: * Intel 82371AB PIIX4 and PIIX4E @@ -20,9 +22,9 @@ Supported adapters: * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge Datasheet: Publicly available at the SMSC website http://www.smsc.com -Authors: - Frodo Looijaard - Philip Edelbrock +Authors: + - Frodo Looijaard + - Philip Edelbrock Module Parameters @@ -39,16 +41,16 @@ Description The PIIX4 (properly known as the 82371AB) is an Intel chip with a lot of functionality. Among other things, it implements the PCI bus. One of its -minor functions is implementing a System Management Bus. This is a true +minor functions is implementing a System Management Bus. This is a true SMBus - you can not access it on I2C levels. The good news is that it natively understands SMBus commands and you do not have to worry about timing problems. The bad news is that non-SMBus devices connected to it can confuse it mightily. Yes, this is known to happen... -Do 'lspci -v' and see whether it contains an entry like this: +Do ``lspci -v`` and see whether it contains an entry like this:: -0000:00:02.3 Bridge: Intel Corp. 82371AB/EB/MB PIIX4 ACPI (rev 02) - Flags: medium devsel, IRQ 9 + 0000:00:02.3 Bridge: Intel Corp. 82371AB/EB/MB PIIX4 ACPI (rev 02) + Flags: medium devsel, IRQ 9 Bus and device numbers may differ, but the function number must be identical (like many PCI devices, the PIIX4 incorporates a number of @@ -91,7 +93,7 @@ the SMI mode. device is located at 00:0f.0. 2) Now you just need to change the value in 0xD2 register. Get it first with command: lspci -xxx -s 00:0f.0 - If the value is 0x3 then you need to change it to 0x1 + If the value is 0x3 then you need to change it to 0x1: setpci -s 00:0f.0 d2.b=1 Please note that you don't need to do that in all cases, just when the SMBus is diff --git a/Documentation/i2c/busses/i2c-sis5595 b/Documentation/i2c/busses/i2c-sis5595.rst similarity index 74% rename from Documentation/i2c/busses/i2c-sis5595 rename to Documentation/i2c/busses/i2c-sis5595.rst index ecd21fb49a8f0c7cd780def05f3ca5408983c3c5..b85630c84a96eebfb13d8bd25fc5540c437c54e2 100644 --- a/Documentation/i2c/busses/i2c-sis5595 +++ b/Documentation/i2c/busses/i2c-sis5595.rst @@ -1,9 +1,11 @@ +========================= Kernel driver i2c-sis5595 +========================= Authors: - Frodo Looijaard , - Mark D. Studebaker , - Philip Edelbrock + - Frodo Looijaard , + - Mark D. Studebaker , + - Philip Edelbrock Supported adapters: * Silicon Integrated Systems Corp. SiS5595 Southbridge @@ -11,14 +13,19 @@ Supported adapters: Note: all have mfr. ID 0x1039. + ========= ====== SUPPORTED PCI ID + ========= ====== 5595 0008 + ========= ====== Note: these chips contain a 0008 device which is incompatible with the 5595. We recognize these by the presence of the listed "blacklist" PCI ID and refuse to load. + ============= ====== ================ NOT SUPPORTED PCI ID BLACKLIST PCI ID + ============= ====== ================ 540 0008 0540 550 0008 0550 5513 0008 5511 @@ -36,15 +43,18 @@ Note: all have mfr. ID 0x1039. 735 0008 0735 745 0008 0745 746 0008 0746 + ============= ====== ================ Module Parameters ----------------- -* force_addr=0xaddr Set the I/O base address. Useful for boards +================== ===================================================== +force_addr=0xaddr Set the I/O base address. Useful for boards that don't set the address in the BIOS. Does not do a PCI force; the device must still be present in lspci. Don't use this unless the driver complains that the base address is not set. +================== ===================================================== Description ----------- @@ -56,4 +66,3 @@ WARNING: If you are trying to access the integrated sensors on the SiS5595 chip, you want the sis5595 driver for those, not this driver. This driver is a BUS driver, not a CHIP driver. A BUS driver is used by other CHIP drivers to access chips on the bus. - diff --git a/Documentation/i2c/busses/i2c-sis630 b/Documentation/i2c/busses/i2c-sis630 deleted file mode 100644 index ee7943631074d0f21199421c1d0fbda8b4b8e002..0000000000000000000000000000000000000000 --- a/Documentation/i2c/busses/i2c-sis630 +++ /dev/null @@ -1,58 +0,0 @@ -Kernel driver i2c-sis630 - -Supported adapters: - * Silicon Integrated Systems Corp (SiS) - 630 chipset (Datasheet: available at http://www.sfr-fresh.com/linux) - 730 chipset - 964 chipset - * Possible other SiS chipsets ? - -Author: Alexander Malysh - Amaury Decrême - SiS964 support - -Module Parameters ------------------ - -* force = [1|0] Forcibly enable the SIS630. DANGEROUS! - This can be interesting for chipsets not named - above to check if it works for you chipset, but DANGEROUS! - -* high_clock = [1|0] Forcibly set Host Master Clock to 56KHz (default, - what your BIOS use). DANGEROUS! This should be a bit - faster, but freeze some systems (i.e. my Laptop). - SIS630/730 chip only. - - -Description ------------ - -This SMBus only driver is known to work on motherboards with the above -named chipsets. - -If you see something like this: - -00:00.0 Host bridge: Silicon Integrated Systems [SiS] 630 Host (rev 31) -00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513 - -or like this: - -00:00.0 Host bridge: Silicon Integrated Systems [SiS] 730 Host (rev 02) -00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513 - -or like this: - -00:00.0 Host bridge: Silicon Integrated Systems [SiS] 760/M760 Host (rev 02) -00:02.0 ISA bridge: Silicon Integrated Systems [SiS] SiS964 [MuTIOL Media IO] - LPC Controller (rev 36) - -in your 'lspci' output , then this driver is for your chipset. - -Thank You ---------- -Philip Edelbrock -- testing SiS730 support -Mark M. Hoffman -- bug fixes - -To anyone else which I forgot here ;), thanks! - diff --git a/Documentation/i2c/busses/i2c-sis630.rst b/Documentation/i2c/busses/i2c-sis630.rst new file mode 100644 index 0000000000000000000000000000000000000000..9fcd74b18781c5fb21ce1a9bdfb3f44ace69c2c5 --- /dev/null +++ b/Documentation/i2c/busses/i2c-sis630.rst @@ -0,0 +1,63 @@ +======================== +Kernel driver i2c-sis630 +======================== + +Supported adapters: + * Silicon Integrated Systems Corp (SiS) + 630 chipset (Datasheet: available at http://www.sfr-fresh.com/linux) + 730 chipset + 964 chipset + * Possible other SiS chipsets ? + +Author: + - Alexander Malysh + - Amaury Decrême - SiS964 support + +Module Parameters +----------------- + +================== ===================================================== +force = [1|0] Forcibly enable the SIS630. DANGEROUS! + This can be interesting for chipsets not named + above to check if it works for you chipset, + but DANGEROUS! + +high_clock = [1|0] Forcibly set Host Master Clock to 56KHz (default, + what your BIOS use). DANGEROUS! This should be a bit + faster, but freeze some systems (i.e. my Laptop). + SIS630/730 chip only. +================== ===================================================== + + +Description +----------- + +This SMBus only driver is known to work on motherboards with the above +named chipsets. + +If you see something like this:: + + 00:00.0 Host bridge: Silicon Integrated Systems [SiS] 630 Host (rev 31) + 00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513 + +or like this:: + + 00:00.0 Host bridge: Silicon Integrated Systems [SiS] 730 Host (rev 02) + 00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513 + +or like this:: + + 00:00.0 Host bridge: Silicon Integrated Systems [SiS] 760/M760 Host (rev 02) + 00:02.0 ISA bridge: Silicon Integrated Systems [SiS] SiS964 [MuTIOL Media IO] + LPC Controller (rev 36) + +in your ``lspci`` output , then this driver is for your chipset. + +Thank You +--------- +Philip Edelbrock +- testing SiS730 support +Mark M. Hoffman +- bug fixes + +To anyone else which I forgot here ;), thanks! diff --git a/Documentation/i2c/busses/i2c-sis96x b/Documentation/i2c/busses/i2c-sis96x.rst similarity index 74% rename from Documentation/i2c/busses/i2c-sis96x rename to Documentation/i2c/busses/i2c-sis96x.rst index 0b979f3252a48dfc65c1557248122acd5753b395..437cc1d89588d67f39ea58c2152daeaf2125c352 100644 --- a/Documentation/i2c/busses/i2c-sis96x +++ b/Documentation/i2c/busses/i2c-sis96x.rst @@ -1,13 +1,18 @@ +======================== Kernel driver i2c-sis96x +======================== Replaces 2.4.x i2c-sis645 Supported adapters: + * Silicon Integrated Systems Corp (SiS) + Any combination of these host bridges: 645, 645DX (aka 646), 648, 650, 651, 655, 735, 745, 746 + and these south bridges: - 961, 962, 963(L) + 961, 962, 963(L) Author: Mark M. Hoffman @@ -21,17 +26,17 @@ those of the SiS630, although they are located in a completely different place. Thanks to Alexander Malysh for providing the SiS630 datasheet (and driver). -The command "lspci" as root should produce something like these lines: +The command ``lspci`` as root should produce something like these lines:: -00:00.0 Host bridge: Silicon Integrated Systems [SiS]: Unknown device 0645 -00:02.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513 -00:02.1 SMBus: Silicon Integrated Systems [SiS]: Unknown device 0016 + 00:00.0 Host bridge: Silicon Integrated Systems [SiS]: Unknown device 0645 + 00:02.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513 + 00:02.1 SMBus: Silicon Integrated Systems [SiS]: Unknown device 0016 -or perhaps this... +or perhaps this:: -00:00.0 Host bridge: Silicon Integrated Systems [SiS]: Unknown device 0645 -00:02.0 ISA bridge: Silicon Integrated Systems [SiS]: Unknown device 0961 -00:02.1 SMBus: Silicon Integrated Systems [SiS]: Unknown device 0016 + 00:00.0 Host bridge: Silicon Integrated Systems [SiS]: Unknown device 0645 + 00:02.0 ISA bridge: Silicon Integrated Systems [SiS]: Unknown device 0961 + 00:02.1 SMBus: Silicon Integrated Systems [SiS]: Unknown device 0016 (kernel versions later than 2.4.18 may fill in the "Unknown"s) @@ -50,7 +55,7 @@ TO DOs ------ * The driver does not support SMBus block reads/writes; I may add them if a -scenario is found where they're needed. + scenario is found where they're needed. Thank You @@ -58,16 +63,20 @@ Thank You Mark D. Studebaker - design hints and bug fixes + Alexander Maylsh - ditto, plus an important datasheet... almost the one I really wanted + Hans-Günter Lütke Uphues - patch for SiS735 + Robert Zwerus - testing for SiS645DX + Kianusch Sayah Karadji - patch for SiS645DX/962 + Ken Healy - patch for SiS655 To anyone else who has written w/ feedback, thanks! - diff --git a/Documentation/i2c/busses/i2c-taos-evm b/Documentation/i2c/busses/i2c-taos-evm.rst similarity index 91% rename from Documentation/i2c/busses/i2c-taos-evm rename to Documentation/i2c/busses/i2c-taos-evm.rst index 60299555dcf01f44d1f3324691e44b642829573e..f342e313ee3def7082dcfb84317f956cbe63d81f 100644 --- a/Documentation/i2c/busses/i2c-taos-evm +++ b/Documentation/i2c/busses/i2c-taos-evm.rst @@ -1,4 +1,6 @@ +========================== Kernel driver i2c-taos-evm +========================== Author: Jean Delvare @@ -23,10 +25,10 @@ Using this driver In order to use this driver, you'll need the serport driver, and the inputattach tool, which is part of the input-utils package. The following commands will tell the kernel that you have a TAOS EVM on the first -serial port: +serial port:: -# modprobe serport -# inputattach --taos-evm /dev/ttyS0 + # modprobe serport + # inputattach --taos-evm /dev/ttyS0 Technical details diff --git a/Documentation/i2c/busses/i2c-via b/Documentation/i2c/busses/i2c-via.rst similarity index 54% rename from Documentation/i2c/busses/i2c-via rename to Documentation/i2c/busses/i2c-via.rst index 343870661ac3d01a7d89187629b7690f1d90263d..846aa17d80a24ae73c538c3b184b5a04a8b9dcea 100644 --- a/Documentation/i2c/busses/i2c-via +++ b/Documentation/i2c/busses/i2c-via.rst @@ -1,4 +1,6 @@ +===================== Kernel driver i2c-via +===================== Supported adapters: * VIA Technologies, InC. VT82C586B @@ -12,23 +14,27 @@ Description i2c-via is an i2c bus driver for motherboards with VIA chipset. The following VIA pci chipsets are supported: - - MVP3, VP3, VP2/97, VPX/97 + - MVP3, VP3, VP2/97, VPX/97 - others with South bridge VT82C586B -Your lspci listing must show this : +Your ``lspci`` listing must show this :: Bridge: VIA Technologies, Inc. VT82C586B ACPI (rev 10) - Problems? - - Q: You have VT82C586B on the motherboard, but not in the listing. - - A: Go to your BIOS setup, section PCI devices or similar. - Turn USB support on, and try again. +Problems? +--------- - Q: No error messages, but still i2c doesn't seem to work. + Q: + You have VT82C586B on the motherboard, but not in the listing. - A: This can happen. This driver uses the pins VIA recommends in their + A: + Go to your BIOS setup, section PCI devices or similar. + Turn USB support on, and try again. + + Q: + No error messages, but still i2c doesn't seem to work. + + A: + This can happen. This driver uses the pins VIA recommends in their datasheets, but there are several ways the motherboard manufacturer can actually wire the lines. - diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro.rst similarity index 87% rename from Documentation/i2c/busses/i2c-viapro rename to Documentation/i2c/busses/i2c-viapro.rst index ab64ce21c25442f68a262c19cf64aa5167bdfdbb..1762f0cf93d07ec18fd212f38f2ed075eadc3957 100644 --- a/Documentation/i2c/busses/i2c-viapro +++ b/Documentation/i2c/busses/i2c-viapro.rst @@ -1,4 +1,6 @@ +======================== Kernel driver i2c-viapro +======================== Supported adapters: * VIA Technologies, Inc. VT82C596A/B @@ -26,9 +28,9 @@ Supported adapters: Datasheet: available on http://linux.via.com.tw Authors: - Kyösti Mälkki , - Mark D. Studebaker , - Jean Delvare + - Kyösti Mälkki , + - Mark D. Studebaker , + - Jean Delvare Module Parameters ----------------- @@ -44,8 +46,9 @@ Description i2c-viapro is a true SMBus host driver for motherboards with one of the supported VIA south bridges. -Your lspci -n listing must show one of these : +Your ``lspci -n`` listing must show one of these : + ================ ====================== device 1106:3050 (VT82C596A function 3) device 1106:3051 (VT82C596B function 3) device 1106:3057 (VT82C686 function 4) @@ -61,6 +64,7 @@ Your lspci -n listing must show one of these : device 1106:8353 (VX800/VX820) device 1106:8409 (VX855/VX875) device 1106:8410 (VX900) + ================ ====================== If none of these show up, you should look in the BIOS for settings like enable ACPI / SMBus or even USB. diff --git a/Documentation/i2c/busses/index.rst b/Documentation/i2c/busses/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..97ca4d510816993a1019badc2d9779cbb7e16ef7 --- /dev/null +++ b/Documentation/i2c/busses/index.rst @@ -0,0 +1,33 @@ +. SPDX-License-Identifier: GPL-2.0 + +=============== +I2C Bus Drivers +=============== + +.. toctree:: + :maxdepth: 1 + + i2c-ali1535 + i2c-ali1563 + i2c-ali15x3 + i2c-amd756 + i2c-amd8111 + i2c-amd-mp2 + i2c-diolan-u2c + i2c-i801 + i2c-ismt + i2c-mlxcpld + i2c-nforce2 + i2c-nvidia-gpu + i2c-ocores + i2c-parport-light + i2c-parport + i2c-pca-isa + i2c-piix4 + i2c-sis5595 + i2c-sis630 + i2c-sis96x + i2c-taos-evm + i2c-viapro + i2c-via + scx200_acb diff --git a/Documentation/i2c/busses/scx200_acb b/Documentation/i2c/busses/scx200_acb.rst similarity index 86% rename from Documentation/i2c/busses/scx200_acb rename to Documentation/i2c/busses/scx200_acb.rst index ce83c871fe95046b5f1731189a6640cacbc0645e..8dc7c352508c791d426a817473dfe4b503ae0088 100644 --- a/Documentation/i2c/busses/scx200_acb +++ b/Documentation/i2c/busses/scx200_acb.rst @@ -1,4 +1,6 @@ +======================== Kernel driver scx200_acb +======================== Author: Christer Weinigel @@ -25,8 +27,11 @@ Device-specific notes The SC1100 WRAP boards are known to use base addresses 0x810 and 0x820. If the scx200_acb driver is built into the kernel, add the following -parameter to your boot command line: +parameter to your boot command line:: + scx200_acb.base=0x810,0x820 + If the scx200_acb driver is built as a module, add the following line to -a configuration file in /etc/modprobe.d/ instead: +a configuration file in /etc/modprobe.d/ instead:: + options scx200_acb base=0x810,0x820 diff --git a/Documentation/i2c/dev-interface b/Documentation/i2c/dev-interface.rst similarity index 71% rename from Documentation/i2c/dev-interface rename to Documentation/i2c/dev-interface.rst index fbed645ccd7563e90e86796d13cae7cfa7329748..69c23a3c2b1b2c5a2263a84f893de3775a14da56 100644 --- a/Documentation/i2c/dev-interface +++ b/Documentation/i2c/dev-interface.rst @@ -1,3 +1,7 @@ +==================== +I2C Device Interface +==================== + Usually, i2c devices are controlled by a kernel driver. But it is also possible to access all devices on an adapter from userspace, through the /dev interface. You need to load module i2c-dev for this. @@ -18,7 +22,7 @@ C example ========= So let's say you want to access an i2c adapter from a C program. -First, you need to include these two headers: +First, you need to include these two headers:: #include #include @@ -28,7 +32,7 @@ inspect /sys/class/i2c-dev/ or run "i2cdetect -l" to decide this. Adapter numbers are assigned somewhat dynamically, so you can not assume much about them. They can even change from one boot to the next. -Next thing, open the device file, as follows: +Next thing, open the device file, as follows:: int file; int adapter_nr = 2; /* probably dynamically determined */ @@ -42,7 +46,7 @@ Next thing, open the device file, as follows: } When you have opened the device, you must specify with what device -address you want to communicate: +address you want to communicate:: int addr = 0x40; /* The I2C address */ @@ -53,7 +57,7 @@ address you want to communicate: Well, you are all set up now. You can now use SMBus commands or plain I2C to communicate with your device. SMBus commands are preferred if -the device supports them. Both are illustrated below. +the device supports them. Both are illustrated below:: __u8 reg = 0x10; /* Device register to access */ __s32 res; @@ -100,35 +104,35 @@ Full interface description The following IOCTLs are defined: -ioctl(file, I2C_SLAVE, long addr) +``ioctl(file, I2C_SLAVE, long addr)`` Change slave address. The address is passed in the 7 lower bits of the argument (except for 10 bit addresses, passed in the 10 lower bits in this case). -ioctl(file, I2C_TENBIT, long select) +``ioctl(file, I2C_TENBIT, long select)`` Selects ten bit addresses if select not equals 0, selects normal 7 bit addresses if select equals 0. Default 0. This request is only valid if the adapter has I2C_FUNC_10BIT_ADDR. -ioctl(file, I2C_PEC, long select) +``ioctl(file, I2C_PEC, long select)`` Selects SMBus PEC (packet error checking) generation and verification if select not equals 0, disables if select equals 0. Default 0. Used only for SMBus transactions. This request only has an effect if the the adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just doesn't have any effect. -ioctl(file, I2C_FUNCS, unsigned long *funcs) - Gets the adapter functionality and puts it in *funcs. +``ioctl(file, I2C_FUNCS, unsigned long *funcs)`` + Gets the adapter functionality and puts it in ``*funcs``. -ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset) +``ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)`` Do combined read/write transaction without stop in between. Only valid if the adapter has I2C_FUNC_I2C. The argument is - a pointer to a + a pointer to a:: - struct i2c_rdwr_ioctl_data { + struct i2c_rdwr_ioctl_data { struct i2c_msg *msgs; /* ptr to array of simple messages */ int nmsgs; /* number of messages to exchange */ - } + } The msgs[] themselves contain further pointers into data buffers. The function will write or read data to or from that buffers depending @@ -136,8 +140,8 @@ ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset) The slave address and whether to use ten bit address mode has to be set in each message, overriding the values set with the above ioctl's. -ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args) - If possible, use the provided i2c_smbus_* methods described below instead +``ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)`` + If possible, use the provided ``i2c_smbus_*`` methods described below instead of issuing direct ioctls. You can do plain i2c transactions by using read(2) and write(2) calls. @@ -145,7 +149,8 @@ You do not need to pass the address byte; instead, set it through ioctl I2C_SLAVE before you try to access the device. You can do SMBus level transactions (see documentation file smbus-protocol -for details) through the following functions: +for details) through the following functions:: + __s32 i2c_smbus_write_quick(int file, __u8 value); __s32 i2c_smbus_read_byte(int file); __s32 i2c_smbus_write_byte(int file, __u8 value); @@ -157,6 +162,7 @@ for details) through the following functions: __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values); __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, __u8 *values); + All these transactions return -1 on failure; you can read errno to see what happened. The 'write' transactions return 0 on success; the 'read' transactions return the read value, except for read_block, which @@ -174,39 +180,39 @@ Implementation details For the interested, here's the code flow which happens inside the kernel when you use the /dev interface to I2C: -1* Your program opens /dev/i2c-N and calls ioctl() on it, as described in -section "C example" above. - -2* These open() and ioctl() calls are handled by the i2c-dev kernel -driver: see i2c-dev.c:i2cdev_open() and i2c-dev.c:i2cdev_ioctl(), -respectively. You can think of i2c-dev as a generic I2C chip driver -that can be programmed from user-space. - -3* Some ioctl() calls are for administrative tasks and are handled by -i2c-dev directly. Examples include I2C_SLAVE (set the address of the -device you want to access) and I2C_PEC (enable or disable SMBus error -checking on future transactions.) - -4* Other ioctl() calls are converted to in-kernel function calls by -i2c-dev. Examples include I2C_FUNCS, which queries the I2C adapter -functionality using i2c.h:i2c_get_functionality(), and I2C_SMBUS, which -performs an SMBus transaction using i2c-core-smbus.c:i2c_smbus_xfer(). - -The i2c-dev driver is responsible for checking all the parameters that -come from user-space for validity. After this point, there is no -difference between these calls that came from user-space through i2c-dev -and calls that would have been performed by kernel I2C chip drivers -directly. This means that I2C bus drivers don't need to implement -anything special to support access from user-space. - -5* These i2c.h functions are wrappers to the actual implementation of -your I2C bus driver. Each adapter must declare callback functions -implementing these standard calls. i2c.h:i2c_get_functionality() calls -i2c_adapter.algo->functionality(), while -i2c-core-smbus.c:i2c_smbus_xfer() calls either -adapter.algo->smbus_xfer() if it is implemented, or if not, -i2c-core-smbus.c:i2c_smbus_xfer_emulated() which in turn calls -i2c_adapter.algo->master_xfer(). +1) Your program opens /dev/i2c-N and calls ioctl() on it, as described in + section "C example" above. + +2) These open() and ioctl() calls are handled by the i2c-dev kernel + driver: see i2c-dev.c:i2cdev_open() and i2c-dev.c:i2cdev_ioctl(), + respectively. You can think of i2c-dev as a generic I2C chip driver + that can be programmed from user-space. + +3) Some ioctl() calls are for administrative tasks and are handled by + i2c-dev directly. Examples include I2C_SLAVE (set the address of the + device you want to access) and I2C_PEC (enable or disable SMBus error + checking on future transactions.) + +4) Other ioctl() calls are converted to in-kernel function calls by + i2c-dev. Examples include I2C_FUNCS, which queries the I2C adapter + functionality using i2c.h:i2c_get_functionality(), and I2C_SMBUS, which + performs an SMBus transaction using i2c-core-smbus.c:i2c_smbus_xfer(). + + The i2c-dev driver is responsible for checking all the parameters that + come from user-space for validity. After this point, there is no + difference between these calls that came from user-space through i2c-dev + and calls that would have been performed by kernel I2C chip drivers + directly. This means that I2C bus drivers don't need to implement + anything special to support access from user-space. + +5) These i2c.h functions are wrappers to the actual implementation of + your I2C bus driver. Each adapter must declare callback functions + implementing these standard calls. i2c.h:i2c_get_functionality() calls + i2c_adapter.algo->functionality(), while + i2c-core-smbus.c:i2c_smbus_xfer() calls either + adapter.algo->smbus_xfer() if it is implemented, or if not, + i2c-core-smbus.c:i2c_smbus_xfer_emulated() which in turn calls + i2c_adapter.algo->master_xfer(). After your I2C bus driver has processed these requests, execution runs up the call chain, with almost no processing done, except by i2c-dev to diff --git a/Documentation/i2c/DMA-considerations b/Documentation/i2c/dma-considerations.rst similarity index 100% rename from Documentation/i2c/DMA-considerations rename to Documentation/i2c/dma-considerations.rst diff --git a/Documentation/i2c/fault-codes b/Documentation/i2c/fault-codes.rst similarity index 98% rename from Documentation/i2c/fault-codes rename to Documentation/i2c/fault-codes.rst index 0cee0fc545b44cadd343448a1e59b0b6aa566ff6..80b14e718b525de73915941b0f0a622a41e9f8b3 100644 --- a/Documentation/i2c/fault-codes +++ b/Documentation/i2c/fault-codes.rst @@ -1,3 +1,7 @@ +===================== +I2C/SMBUS Fault Codes +===================== + This is a summary of the most important conventions for use of fault codes in the I2C/SMBus stack. @@ -125,4 +129,3 @@ ETIMEDOUT when a slave stretches clocks too far. I2C has no such timeouts, but it's normal for I2C adapters to impose some arbitrary limits (much longer than SMBus!) too. - diff --git a/Documentation/i2c/functionality b/Documentation/i2c/functionality.rst similarity index 91% rename from Documentation/i2c/functionality rename to Documentation/i2c/functionality.rst index 4aae8ed15873d1d3c1cc8fc9d80d3ef9b42e5654..377507c56162ae79a8cf866035fc51fff0e5afe3 100644 --- a/Documentation/i2c/functionality +++ b/Documentation/i2c/functionality.rst @@ -1,11 +1,15 @@ +======================= +I2C/SMBus Functionality +======================= + INTRODUCTION ------------ -Because not every I2C or SMBus adapter implements everything in the +Because not every I2C or SMBus adapter implements everything in the I2C specifications, a client can not trust that everything it needs is implemented when it is given the option to attach to an adapter: the client needs some way to check whether an adapter has the needed -functionality. +functionality. FUNCTIONALITY CONSTANTS @@ -14,6 +18,7 @@ FUNCTIONALITY CONSTANTS For the most up-to-date list of functionality constants, please check ! + =============================== ============================================== I2C_FUNC_I2C Plain i2c-level commands (Pure SMBus adapters typically can not do these) I2C_FUNC_10BIT_ADDR Handles the 10-bit address extensions @@ -33,9 +38,11 @@ For the most up-to-date list of functionality constants, please check I2C_FUNC_SMBUS_WRITE_BLOCK_DATA Handles the SMBus write_block_data command I2C_FUNC_SMBUS_READ_I2C_BLOCK Handles the SMBus read_i2c_block_data command I2C_FUNC_SMBUS_WRITE_I2C_BLOCK Handles the SMBus write_i2c_block_data command + =============================== ============================================== A few combinations of the above flags are also defined for your convenience: + ========================= ====================================== I2C_FUNC_SMBUS_BYTE Handles the SMBus read_byte and write_byte commands I2C_FUNC_SMBUS_BYTE_DATA Handles the SMBus read_byte_data @@ -49,6 +56,7 @@ A few combinations of the above flags are also defined for your convenience: I2C_FUNC_SMBUS_EMUL Handles all SMBus commands that can be emulated by a real I2C adapter (using the transparent emulation layer) + ========================= ====================================== In kernel versions prior to 3.5 I2C_FUNC_NOSTART was implemented as part of I2C_FUNC_PROTOCOL_MANGLING. @@ -58,11 +66,11 @@ ADAPTER IMPLEMENTATION ---------------------- When you write a new adapter driver, you will have to implement a -function callback `functionality'. Typical implementations are given +function callback ``functionality``. Typical implementations are given below. A typical SMBus-only adapter would list all the SMBus transactions it -supports. This example comes from the i2c-piix4 driver: +supports. This example comes from the i2c-piix4 driver:: static u32 piix4_func(struct i2c_adapter *adapter) { @@ -72,7 +80,7 @@ supports. This example comes from the i2c-piix4 driver: } A typical full-I2C adapter would use the following (from the i2c-pxa -driver): +driver):: static u32 i2c_pxa_functionality(struct i2c_adapter *adap) { @@ -94,7 +102,7 @@ CLIENT CHECKING Before a client tries to attach to an adapter, or even do tests to check whether one of the devices it supports is present on an adapter, it should check whether the needed functionality is present. The typical way to do -this is (from the lm75 driver): +this is (from the lm75 driver):: static int lm75_detect(...) { @@ -129,7 +137,7 @@ If you try to access an adapter from a userspace program, you will have to use the /dev interface. You will still have to check whether the functionality you need is supported, of course. This is done using the I2C_FUNCS ioctl. An example, adapted from the i2cdetect program, is -below: +below:: int file; if (file = open("/dev/i2c-0", O_RDWR) < 0) { diff --git a/Documentation/i2c/gpio-fault-injection b/Documentation/i2c/gpio-fault-injection.rst similarity index 97% rename from Documentation/i2c/gpio-fault-injection rename to Documentation/i2c/gpio-fault-injection.rst index c87f416d53dd2073dce412c0b3b674f2bb5c840c..9dca6ec7d2661542f5463a4d921a972054295dc2 100644 --- a/Documentation/i2c/gpio-fault-injection +++ b/Documentation/i2c/gpio-fault-injection.rst @@ -104,10 +104,10 @@ There doesn't need to be a device at this address because arbitration lost should be detected beforehand. Also note, that SCL going down is monitored using interrupts, so the interrupt latency might cause the first bits to be not corrupted. A good starting point for using this fault injector on an otherwise -idle bus is: +idle bus is:: -# echo 200 > lose_arbitration & -# i2cget -y 0x3f + # echo 200 > lose_arbitration & + # i2cget -y 0x3f Panic during transfer ===================== @@ -127,10 +127,10 @@ The calling process will then sleep and wait for the next bus clock. The process is interruptible, though. Start of a transfer is detected by waiting for SCL going down by the master -under test. A good starting point for using this fault injector is: +under test. A good starting point for using this fault injector is:: -# echo 0 > inject_panic & -# i2cget -y + # echo 0 > inject_panic & + # i2cget -y Note that there doesn't need to be a device listening to the address you are using. Results may vary depending on that, though. diff --git a/Documentation/i2c/i2c-protocol b/Documentation/i2c/i2c-protocol.rst similarity index 83% rename from Documentation/i2c/i2c-protocol rename to Documentation/i2c/i2c-protocol.rst index ff6d6cee6c7e17a684d9cad757f74d719c7bfb82..2f8fcf671b2e487932936aaf4ff873462b4966d1 100644 --- a/Documentation/i2c/i2c-protocol +++ b/Documentation/i2c/i2c-protocol.rst @@ -1,8 +1,13 @@ +============ +I2C Protocol +============ + This document describes the i2c protocol. Or will, when it is finished :-) Key to symbols ============== +=============== ============================================================= S (1 bit) : Start bit P (1 bit) : Stop bit Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0. @@ -15,33 +20,35 @@ Data (8 bits): A plain data byte. Sometimes, I write DataLow, DataHigh for 16 bit data. Count (8 bits): A data byte containing the length of a block operation. -[..]: Data sent by I2C device, as opposed to data sent by the host adapter. +[..]: Data sent by I2C device, as opposed to data sent by the + host adapter. +=============== ============================================================= Simple send transaction -====================== +======================= -This corresponds to i2c_master_send. +This corresponds to i2c_master_send:: S Addr Wr [A] Data [A] Data [A] ... [A] Data [A] P Simple receive transaction -=========================== +========================== -This corresponds to i2c_master_recv +This corresponds to i2c_master_recv:: S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P Combined transactions -==================== +===================== This corresponds to i2c_transfer They are just like the above transactions, but instead of a stop bit P a start bit S is sent and the transaction continues. An example of -a byte read, followed by a byte write: +a byte read, followed by a byte write:: S Addr Rd [A] [Data] NA S Addr Wr [A] Data [A] P @@ -65,8 +72,10 @@ I2C_M_NO_RD_ACK: I2C_M_NOSTART: In a combined transaction, no 'S Addr Wr/Rd [A]' is generated at some point. For example, setting I2C_M_NOSTART on the second partial message - generates something like: + generates something like:: + S Addr Rd [A] [Data] NA Data [A] P + If you set the I2C_M_NOSTART variable for the first partial message, we do not generate Addr, but we do generate the startbit S. This will probably confuse all other clients on your bus, so don't try this. @@ -79,7 +88,8 @@ I2C_M_NOSTART: I2C_M_REV_DIR_ADDR: This toggles the Rd/Wr flag. That is, if you want to do a write, but need to emit an Rd instead of a Wr, or vice versa, you set this - flag. For example: + flag. For example:: + S Addr Rd [A] Data [A] Data [A] ... [A] Data [A] P I2C_M_STOP: diff --git a/Documentation/i2c/i2c-stub b/Documentation/i2c/i2c-stub.rst similarity index 93% rename from Documentation/i2c/i2c-stub rename to Documentation/i2c/i2c-stub.rst index a16924fbd289e0262702ceece411ef6f12e36293..a6fc6916d6bc76d15748f0dd823f2ae6a2bf8b26 100644 --- a/Documentation/i2c/i2c-stub +++ b/Documentation/i2c/i2c-stub.rst @@ -1,6 +1,9 @@ -MODULE: i2c-stub +======== +i2c-stub +======== -DESCRIPTION: +Description +=========== This module is a very simple fake I2C/SMBus driver. It implements six types of SMBus commands: write quick, (r/w) byte, (r/w) byte data, (r/w) @@ -28,6 +31,7 @@ SMBus block operations. Writes can be partial. Block read commands always return the number of bytes selected with the largest write so far. The typical use-case is like this: + 1. load this module 2. use i2cset (from the i2c-tools project) to pre-load some data 3. load the target chip driver module @@ -36,7 +40,8 @@ The typical use-case is like this: There's a script named i2c-stub-from-dump in the i2c-tools package which can load register values automatically from a chip dump. -PARAMETERS: +Parameters +========== int chip_addr[10]: The SMBus addresses to emulate chips at. @@ -47,18 +52,15 @@ unsigned long functionality: value 0x1f0000 would only enable the quick, byte and byte data commands. -u8 bank_reg[10] -u8 bank_mask[10] -u8 bank_start[10] -u8 bank_end[10]: +u8 bank_reg[10], u8 bank_mask[10], u8 bank_start[10], u8 bank_end[10]: Optional bank settings. They tell which bits in which register select the active bank, as well as the range of banked registers. -CAVEATS: +Caveats +======= If your target driver polls some byte or word waiting for it to change, the stub could lock it up. Use i2cset to unlock it. If you spam it hard enough, printk can be lossy. This module really wants something like relayfs. - diff --git a/Documentation/i2c/i2c-topology b/Documentation/i2c/i2c-topology.rst similarity index 89% rename from Documentation/i2c/i2c-topology rename to Documentation/i2c/i2c-topology.rst index f74d78b53d4d98f11aa2537c5ff94b17864aaa09..0c1ae95f6a97b0c5d985f5eb0f8b56a22fadb0c6 100644 --- a/Documentation/i2c/i2c-topology +++ b/Documentation/i2c/i2c-topology.rst @@ -1,3 +1,4 @@ +============ I2C topology ============ @@ -14,6 +15,7 @@ than a straight-forward i2c bus with one adapter and one or more devices. that has to be operated before the device can be accessed. Etc +=== These constructs are represented as i2c adapter trees by Linux, where each adapter has a parent adapter (except the root adapter) and zero or @@ -37,7 +39,9 @@ mux-locked or parent-locked muxes. As is evident from below, it can be useful to know if a mux is mux-locked or if it is parent-locked. The following list was correct at the time of writing: -In drivers/i2c/muxes/ +In drivers/i2c/muxes/: + +====================== ============================================= i2c-arb-gpio-challenge Parent-locked i2c-mux-gpio Normally parent-locked, mux-locked iff all involved gpio pins are controlled by the @@ -52,18 +56,25 @@ i2c-mux-pinctrl Normally parent-locked, mux-locked iff all involved pinctrl devices are controlled by the same i2c root adapter that they mux. i2c-mux-reg Parent-locked +====================== ============================================= + +In drivers/iio/: -In drivers/iio/ +====================== ============================================= gyro/mpu3050 Mux-locked imu/inv_mpu6050/ Mux-locked +====================== ============================================= -In drivers/media/ +In drivers/media/: + +======================= ============================================= dvb-frontends/lgdt3306a Mux-locked dvb-frontends/m88ds3103 Parent-locked dvb-frontends/rtl2830 Parent-locked dvb-frontends/rtl2832 Mux-locked dvb-frontends/si2168 Mux-locked usb/cx231xx/ Parent-locked +======================= ============================================= Mux-locked muxes @@ -78,6 +89,7 @@ full transaction, unrelated i2c transfers may interleave the different stages of the transaction. This has the benefit that the mux driver may be easier and cleaner to implement, but it has some caveats. +==== ===================================================================== ML1. If you build a topology with a mux-locked mux being the parent of a parent-locked mux, this might break the expectation from the parent-locked mux that the root adapter is locked during the @@ -105,11 +117,15 @@ ML4. If any non-i2c operation in the mux driver changes the i2c mux state, Otherwise garbage may appear on the bus as seen from devices behind the mux, when an unrelated i2c transfer is in flight during the non-i2c mux-changing operation. +==== ===================================================================== Mux-locked Example ------------------ + +:: + .----------. .--------. .--------. | mux- |-----| dev D1 | | root |--+--| locked | '--------' @@ -148,6 +164,7 @@ adapter during the transaction are unlocked i2c transfers (using e.g. __i2c_transfer), or a deadlock will follow. There are a couple of caveats. +==== ==================================================================== PL1. If you build a topology with a parent-locked mux being the child of another mux, this might break a possible assumption from the child mux that the root adapter is unused between its select op @@ -161,11 +178,14 @@ PL2. If select/deselect calls out to other subsystems such as gpio, caused by these subsystems are unlocked. This can be convoluted to accomplish, maybe even impossible if an acceptably clean solution is sought. +==== ==================================================================== Parent-locked Example --------------------- +:: + .----------. .--------. .--------. | parent- |-----| dev D1 | | root |--+--| locked | '--------' @@ -177,20 +197,20 @@ Parent-locked Example When there is an access to D1, this happens: - 1. Someone issues an i2c-transfer to D1. - 2. M1 locks muxes on its parent (the root adapter in this case). - 3. M1 locks its parent adapter. - 4. M1 calls ->select to ready the mux. - 5. If M1 does any i2c-transfers (on this root adapter) as part of - its select, those transfers must be unlocked i2c-transfers so - that they do not deadlock the root adapter. - 6. M1 feeds the i2c-transfer from step 1 to the root adapter as an - unlocked i2c-transfer, so that it does not deadlock the parent - adapter. - 7. M1 calls ->deselect, if it has one. - 8. Same rules as in step 5, but for ->deselect. - 9. M1 unlocks its parent adapter. -10. M1 unlocks muxes on its parent. + 1. Someone issues an i2c-transfer to D1. + 2. M1 locks muxes on its parent (the root adapter in this case). + 3. M1 locks its parent adapter. + 4. M1 calls ->select to ready the mux. + 5. If M1 does any i2c-transfers (on this root adapter) as part of + its select, those transfers must be unlocked i2c-transfers so + that they do not deadlock the root adapter. + 6. M1 feeds the i2c-transfer from step 1 to the root adapter as an + unlocked i2c-transfer, so that it does not deadlock the parent + adapter. + 7. M1 calls ->deselect, if it has one. + 8. Same rules as in step 5, but for ->deselect. + 9. M1 unlocks its parent adapter. + 10. M1 unlocks muxes on its parent. This means that accesses to both D2 and D3 are locked out for the full @@ -203,7 +223,7 @@ Complex Examples Parent-locked mux as parent of parent-locked mux ------------------------------------------------ -This is a useful topology, but it can be bad. +This is a useful topology, but it can be bad:: .----------. .----------. .--------. .--------. | parent- |-----| parent- |-----| dev D1 | @@ -227,7 +247,7 @@ through and be seen by the M2 adapter, thus closing M2 prematurely. Mux-locked mux as parent of mux-locked mux ------------------------------------------ -This is a good topology. +This is a good topology:: .----------. .----------. .--------. .--------. | mux- |-----| mux- |-----| dev D1 | @@ -248,7 +268,7 @@ are still possibly interleaved. Mux-locked mux as parent of parent-locked mux --------------------------------------------- -This is probably a bad topology. +This is probably a bad topology:: .----------. .----------. .--------. .--------. | mux- |-----| parent- |-----| dev D1 | @@ -282,7 +302,7 @@ auto-closing, the topology is fine. Parent-locked mux as parent of mux-locked mux --------------------------------------------- -This is a good topology. +This is a good topology:: .----------. .----------. .--------. .--------. | parent- |-----| mux- |-----| dev D1 | @@ -306,7 +326,7 @@ adapter is locked directly. Two mux-locked sibling muxes ---------------------------- -This is a good topology. +This is a good topology:: .--------. .----------. .--| dev D1 | @@ -330,7 +350,7 @@ accesses to D5 may be interleaved at any time. Two parent-locked sibling muxes ------------------------------- -This is a good topology. +This is a good topology:: .--------. .----------. .--| dev D1 | @@ -354,7 +374,7 @@ out. Mux-locked and parent-locked sibling muxes ------------------------------------------ -This is a good topology. +This is a good topology:: .--------. .----------. .--| dev D1 | diff --git a/Documentation/i2c/index.rst b/Documentation/i2c/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..cd8d020f7ac5795a98cea34cd1e8261a1d193d8b --- /dev/null +++ b/Documentation/i2c/index.rst @@ -0,0 +1,37 @@ +. SPDX-License-Identifier: GPL-2.0 + +=================== +I2C/SMBus Subsystem +=================== + +.. toctree:: + :maxdepth: 1 + + dev-interface + dma-considerations + fault-codes + functionality + gpio-fault-injection + i2c-protocol + i2c-stub + i2c-topology + instantiating-devices + old-module-parameters + slave-eeprom-backend + slave-interface + smbus-protocol + summary + ten-bit-addresses + upgrading-clients + writing-clients + + muxes/i2c-mux-gpio + + busses/index + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/i2c/instantiating-devices b/Documentation/i2c/instantiating-devices.rst similarity index 93% rename from Documentation/i2c/instantiating-devices rename to Documentation/i2c/instantiating-devices.rst index 345e9ea8281a70ee23fb9e4573a371c057efa768..1238f1fa3382051874c33128f77a993890d5ac30 100644 --- a/Documentation/i2c/instantiating-devices +++ b/Documentation/i2c/instantiating-devices.rst @@ -1,3 +1,4 @@ +============================== How to instantiate I2C devices ============================== @@ -17,9 +18,9 @@ which is known in advance. It is thus possible to pre-declare the I2C devices which live on this bus. This is done with an array of struct i2c_board_info which is registered by calling i2c_register_board_info(). -Example (from omap2 h4): +Example (from omap2 h4):: -static struct i2c_board_info h4_i2c_board_info[] __initdata = { + static struct i2c_board_info h4_i2c_board_info[] __initdata = { { I2C_BOARD_INFO("isp1301_omap", 0x2d), .irq = OMAP_GPIO_IRQ(125), @@ -32,15 +33,15 @@ static struct i2c_board_info h4_i2c_board_info[] __initdata = { I2C_BOARD_INFO("24c01", 0x57), .platform_data = &m24c01, }, -}; + }; -static void __init omap_h4_init(void) -{ + static void __init omap_h4_init(void) + { (...) i2c_register_board_info(1, h4_i2c_board_info, ARRAY_SIZE(h4_i2c_board_info)); (...) -} + } The above code declares 3 devices on I2C bus 1, including their respective addresses and custom data needed by their drivers. When the I2C bus in @@ -57,7 +58,7 @@ Method 1b: Declare the I2C devices via devicetree This method has the same implications as method 1a. The declaration of I2C devices is here done via devicetree as subnodes of the master controller. -Example: +Example:: i2c1: i2c@400a0000 { /* ... master properties skipped ... */ @@ -99,20 +100,20 @@ bus in advance, so the method 1 described above can't be used. Instead, you can instantiate your I2C devices explicitly. This is done by filling a struct i2c_board_info and calling i2c_new_device(). -Example (from the sfe4001 network driver): +Example (from the sfe4001 network driver):: -static struct i2c_board_info sfe4001_hwmon_info = { + static struct i2c_board_info sfe4001_hwmon_info = { I2C_BOARD_INFO("max6647", 0x4e), -}; + }; -int sfe4001_init(struct efx_nic *efx) -{ + int sfe4001_init(struct efx_nic *efx) + { (...) efx->board_info.hwmon_client = i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info); (...) -} + } The above code instantiates 1 I2C device on the I2C bus which is on the network adapter in question. @@ -124,12 +125,12 @@ it may have different addresses from one board to the next (manufacturer changing its design without notice). In this case, you can call i2c_new_probed_device() instead of i2c_new_device(). -Example (from the nxp OHCI driver): +Example (from the nxp OHCI driver):: -static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; + static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; -static int usb_hcd_nxp_probe(struct platform_device *pdev) -{ + static int usb_hcd_nxp_probe(struct platform_device *pdev) + { (...) struct i2c_adapter *i2c_adap; struct i2c_board_info i2c_info; @@ -142,7 +143,7 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev) normal_i2c, NULL); i2c_put_adapter(i2c_adap); (...) -} + } The above code instantiates up to 1 I2C device on the I2C bus which is on the OHCI adapter in question. It first tries at address 0x2c, if nothing @@ -172,6 +173,7 @@ explicitly. Instead, i2c-core will probe for such devices as soon as their drivers are loaded, and if any is found, an I2C device will be instantiated automatically. In order to prevent any misbehavior of this mechanism, the following restrictions apply: + * The I2C device driver must implement the detect() method, which identifies a supported device by reading from arbitrary registers. * Only buses which are likely to have a supported device and agree to be @@ -189,6 +191,7 @@ first. Those of you familiar with the i2c subsystem of 2.4 kernels and early 2.6 kernels will find out that this method 3 is essentially similar to what was done there. Two significant differences are: + * Probing is only one way to instantiate I2C devices now, while it was the only way back then. Where possible, methods 1 and 2 should be preferred. Method 3 should only be used when there is no other way, as it can have @@ -224,11 +227,13 @@ device. As no two devices can live at the same address on a given I2C segment, the address is sufficient to uniquely identify the device to be deleted. -Example: -# echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-3/new_device +Example:: + + # echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-3/new_device While this interface should only be used when in-kernel device declaration can't be done, there is a variety of cases where it can be helpful: + * The I2C driver usually detects devices (method 3 above) but the bus segment your device lives on doesn't have the proper class bit set and thus detection doesn't trigger. diff --git a/Documentation/i2c/muxes/i2c-mux-gpio b/Documentation/i2c/muxes/i2c-mux-gpio.rst similarity index 85% rename from Documentation/i2c/muxes/i2c-mux-gpio rename to Documentation/i2c/muxes/i2c-mux-gpio.rst index 893ecdfe6e43c3e297f725237f6a3fe8b93e7d61..7d27444035c3e18d8e2f910ca7334f6a05d5facf 100644 --- a/Documentation/i2c/muxes/i2c-mux-gpio +++ b/Documentation/i2c/muxes/i2c-mux-gpio.rst @@ -1,4 +1,6 @@ +========================== Kernel driver i2c-mux-gpio +========================== Author: Peter Korsgaard @@ -8,7 +10,7 @@ Description i2c-mux-gpio is an i2c mux driver providing access to I2C bus segments from a master I2C bus and a hardware MUX controlled through GPIO pins. -E.G.: +E.G.:: ---------- ---------- Bus segment 1 - - - - - | | SCL/SDA | |-------------- | | @@ -33,20 +35,20 @@ bus, the number of bus segments to create and the GPIO pins used to control it. See include/linux/platform_data/i2c-mux-gpio.h for details. E.G. something like this for a MUX providing 4 bus segments -controlled through 3 GPIO pins: +controlled through 3 GPIO pins:: -#include -#include + #include + #include -static const unsigned myboard_gpiomux_gpios[] = { + static const unsigned myboard_gpiomux_gpios[] = { AT91_PIN_PC26, AT91_PIN_PC25, AT91_PIN_PC24 -}; + }; -static const unsigned myboard_gpiomux_values[] = { + static const unsigned myboard_gpiomux_values[] = { 0, 1, 2, 3 -}; + }; -static struct i2c_mux_gpio_platform_data myboard_i2cmux_data = { + static struct i2c_mux_gpio_platform_data myboard_i2cmux_data = { .parent = 1, .base_nr = 2, /* optional */ .values = myboard_gpiomux_values, @@ -54,15 +56,15 @@ static struct i2c_mux_gpio_platform_data myboard_i2cmux_data = { .gpios = myboard_gpiomux_gpios, .n_gpios = ARRAY_SIZE(myboard_gpiomux_gpios), .idle = 4, /* optional */ -}; + }; -static struct platform_device myboard_i2cmux = { + static struct platform_device myboard_i2cmux = { .name = "i2c-mux-gpio", .id = 0, .dev = { .platform_data = &myboard_i2cmux_data, }, -}; + }; If you don't know the absolute GPIO pin numbers at registration time, you can instead provide a chip name (.chip_name) and relative GPIO pin diff --git a/Documentation/i2c/old-module-parameters b/Documentation/i2c/old-module-parameters.rst similarity index 75% rename from Documentation/i2c/old-module-parameters rename to Documentation/i2c/old-module-parameters.rst index 8e2b629d533cee6cfd26e6a73ccd7e4025505a66..a1939512ad66313dae1f90d35bef980b7dca1aca 100644 --- a/Documentation/i2c/old-module-parameters +++ b/Documentation/i2c/old-module-parameters.rst @@ -1,3 +1,4 @@ +================================================= I2C device driver binding control from user-space ================================================= @@ -19,23 +20,27 @@ Below is a mapping from the old module parameters to the new interface. Attaching a driver to an I2C device ----------------------------------- -Old method (module parameters): -# modprobe probe=1,0x2d -# modprobe force=1,0x2d -# modprobe force_=1,0x2d +Old method (module parameters):: + + # modprobe probe=1,0x2d + # modprobe force=1,0x2d + # modprobe force_=1,0x2d + +New method (sysfs interface):: -New method (sysfs interface): -# echo 0x2d > /sys/bus/i2c/devices/i2c-1/new_device + # echo 0x2d > /sys/bus/i2c/devices/i2c-1/new_device Preventing a driver from attaching to an I2C device --------------------------------------------------- -Old method (module parameters): -# modprobe ignore=1,0x2f +Old method (module parameters):: + + # modprobe ignore=1,0x2f + +New method (sysfs interface):: -New method (sysfs interface): -# echo dummy 0x2f > /sys/bus/i2c/devices/i2c-1/new_device -# modprobe + # echo dummy 0x2f > /sys/bus/i2c/devices/i2c-1/new_device + # modprobe Of course, it is important to instantiate the "dummy" device before loading the driver. The dummy device will be handled by i2c-core itself, preventing diff --git a/Documentation/i2c/slave-eeprom-backend b/Documentation/i2c/slave-eeprom-backend.rst similarity index 90% rename from Documentation/i2c/slave-eeprom-backend rename to Documentation/i2c/slave-eeprom-backend.rst index 04f8d8a9b817dbfb1d693c0796bd918ddda9af35..0b8cd83698e0f00d944c08f174a266ff93720b4f 100644 --- a/Documentation/i2c/slave-eeprom-backend +++ b/Documentation/i2c/slave-eeprom-backend.rst @@ -1,3 +1,4 @@ +============================== Linux I2C slave eeprom backend ============================== @@ -5,10 +6,9 @@ by Wolfram Sang in 2014-15 This is a proof-of-concept backend which acts like an EEPROM on the connected I2C bus. The memory contents can be modified from userspace via this file -located in sysfs: +located in sysfs:: /sys/bus/i2c/devices//slave-eeprom As of 2015, Linux doesn't support poll on binary sysfs files, so there is no notification when another master changed the content. - diff --git a/Documentation/i2c/slave-interface b/Documentation/i2c/slave-interface.rst similarity index 94% rename from Documentation/i2c/slave-interface rename to Documentation/i2c/slave-interface.rst index 7e2a228f21bccd8ab12cec93bda73831f66827cb..c769bd6a15bf5f0d13f2577fc2dd91a37da8da83 100644 --- a/Documentation/i2c/slave-interface +++ b/Documentation/i2c/slave-interface.rst @@ -1,3 +1,4 @@ +===================================== Linux I2C slave interface description ===================================== @@ -12,7 +13,7 @@ EEPROM, the Linux I2C slave can access the content via sysfs and handle data as needed. The backend driver and the I2C bus driver communicate via events. Here is a small graph visualizing the data flow and the means by which data is transported. The dotted line marks only one example. The backend could also -use a character device, be in-kernel only, or something completely different: +use a character device, be in-kernel only, or something completely different:: e.g. sysfs I2C slave events I/O registers @@ -35,7 +36,7 @@ them as described in the document 'instantiating-devices'. The only difference is that i2c slave backends have their own address space. So, you have to add 0x1000 to the address you would originally request. An example for instantiating the slave-eeprom driver from userspace at the 7 bit address 0x64 -on bus 1: +on bus 1:: # echo slave-24c02 0x1064 > /sys/bus/i2c/devices/i2c-1/new_device @@ -54,7 +55,7 @@ drivers and writing backends will be given. I2C slave events ---------------- -The bus driver sends an event to the backend using the following function: +The bus driver sends an event to the backend using the following function:: ret = i2c_slave_event(client, event, &val) @@ -69,8 +70,9 @@ Event types: * I2C_SLAVE_WRITE_REQUESTED (mandatory) -'val': unused -'ret': always 0 + 'val': unused + + 'ret': always 0 Another I2C master wants to write data to us. This event should be sent once our own address and the write bit was detected. The data did not arrive yet, so @@ -79,8 +81,9 @@ to be done, though. * I2C_SLAVE_READ_REQUESTED (mandatory) -'val': backend returns first byte to be sent -'ret': always 0 + 'val': backend returns first byte to be sent + + 'ret': always 0 Another I2C master wants to read data from us. This event should be sent once our own address and the read bit was detected. After returning, the bus driver @@ -88,8 +91,9 @@ should transmit the first byte. * I2C_SLAVE_WRITE_RECEIVED (mandatory) -'val': bus driver delivers received byte -'ret': 0 if the byte should be acked, some errno if the byte should be nacked + 'val': bus driver delivers received byte + + 'ret': 0 if the byte should be acked, some errno if the byte should be nacked Another I2C master has sent a byte to us which needs to be set in 'val'. If 'ret' is zero, the bus driver should ack this byte. If 'ret' is an errno, then the byte @@ -97,8 +101,9 @@ should be nacked. * I2C_SLAVE_READ_PROCESSED (mandatory) -'val': backend returns next byte to be sent -'ret': always 0 + 'val': backend returns next byte to be sent + + 'ret': always 0 The bus driver requests the next byte to be sent to another I2C master in 'val'. Important: This does not mean that the previous byte has been acked, it @@ -111,8 +116,9 @@ your backend, though. * I2C_SLAVE_STOP (mandatory) -'val': unused -'ret': always 0 + 'val': unused + + 'ret': always 0 A stop condition was received. This can happen anytime and the backend should reset its state machine for I2C transfers to be able to receive new requests. @@ -190,4 +196,3 @@ this time of writing. Some points to keep in mind when using buffers: * A master can send STOP at any time. For partially transferred buffers, this means additional code to handle this exception. Such code tends to be error-prone. - diff --git a/Documentation/i2c/smbus-protocol b/Documentation/i2c/smbus-protocol.rst similarity index 82% rename from Documentation/i2c/smbus-protocol rename to Documentation/i2c/smbus-protocol.rst index 092d474f5843d1a731834a166be8191b4a8cd8d0..e30eb1d274c6841c7ab3f7aa1bad6a696c8cdc17 100644 --- a/Documentation/i2c/smbus-protocol +++ b/Documentation/i2c/smbus-protocol.rst @@ -1,3 +1,4 @@ +====================== SMBus Protocol Summary ====================== @@ -27,17 +28,18 @@ Each transaction type corresponds to a functionality flag. Before calling a transaction function, a device driver should always check (just once) for the corresponding functionality flag to ensure that the underlying I2C adapter supports the transaction in question. See - for the details. + for the details. Key to symbols ============== +=============== ============================================================= S (1 bit) : Start bit P (1 bit) : Stop bit Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0. -A, NA (1 bit) : Accept and reverse accept bit. -Addr (7 bits): I2C 7 bit address. Note that this can be expanded as usual to +A, NA (1 bit) : Accept and reverse accept bit. +Addr (7 bits): I2C 7 bit address. Note that this can be expanded as usual to get a 10 bit I2C address. Comm (8 bits): Command byte, a data byte which often selects a register on the device. @@ -45,15 +47,17 @@ Data (8 bits): A plain data byte. Sometimes, I write DataLow, DataHigh for 16 bit data. Count (8 bits): A data byte containing the length of a block operation. -[..]: Data sent by I2C device, as opposed to data sent by the host adapter. +[..]: Data sent by I2C device, as opposed to data sent by the host + adapter. +=============== ============================================================= SMBus Quick Command =================== -This sends a single bit to the device, at the place of the Rd/Wr bit. +This sends a single bit to the device, at the place of the Rd/Wr bit:: -A Addr Rd/Wr [A] P + A Addr Rd/Wr [A] P Functionality flag: I2C_FUNC_SMBUS_QUICK @@ -64,9 +68,9 @@ SMBus Receive Byte: i2c_smbus_read_byte() This reads a single byte from a device, without specifying a device register. Some devices are so simple that this interface is enough; for others, it is a shorthand if you want to read the same register as in -the previous SMBus command. +the previous SMBus command:: -S Addr Rd [A] [Data] NA P + S Addr Rd [A] [Data] NA P Functionality flag: I2C_FUNC_SMBUS_READ_BYTE @@ -77,7 +81,9 @@ SMBus Send Byte: i2c_smbus_write_byte() This operation is the reverse of Receive Byte: it sends a single byte to a device. See Receive Byte for more information. -S Addr Wr [A] Data [A] P +:: + + S Addr Wr [A] Data [A] P Functionality flag: I2C_FUNC_SMBUS_WRITE_BYTE @@ -86,9 +92,9 @@ SMBus Read Byte: i2c_smbus_read_byte_data() ============================================ This reads a single byte from a device, from a designated register. -The register is specified through the Comm byte. +The register is specified through the Comm byte:: -S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P + S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P Functionality flag: I2C_FUNC_SMBUS_READ_BYTE_DATA @@ -98,9 +104,9 @@ SMBus Read Word: i2c_smbus_read_word_data() This operation is very like Read Byte; again, data is read from a device, from a designated register that is specified through the Comm -byte. But this time, the data is a complete word (16 bits). +byte. But this time, the data is a complete word (16 bits):: -S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P + S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P Functionality flag: I2C_FUNC_SMBUS_READ_WORD_DATA @@ -116,7 +122,9 @@ This writes a single byte to a device, to a designated register. The register is specified through the Comm byte. This is the opposite of the Read Byte operation. -S Addr Wr [A] Comm [A] Data [A] P +:: + + S Addr Wr [A] Comm [A] Data [A] P Functionality flag: I2C_FUNC_SMBUS_WRITE_BYTE_DATA @@ -126,9 +134,9 @@ SMBus Write Word: i2c_smbus_write_word_data() This is the opposite of the Read Word operation. 16 bits of data is written to a device, to the designated register that is -specified through the Comm byte. +specified through the Comm byte.:: -S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P + S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P Functionality flag: I2C_FUNC_SMBUS_WRITE_WORD_DATA @@ -141,10 +149,10 @@ SMBus Process Call: =================== This command selects a device register (through the Comm byte), sends -16 bits of data to it, and reads 16 bits of data in return. +16 bits of data to it, and reads 16 bits of data in return:: -S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] - S Addr Rd [A] [DataLow] A [DataHigh] NA P + S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] + S Addr Rd [A] [DataLow] A [DataHigh] NA P Functionality flag: I2C_FUNC_SMBUS_PROC_CALL @@ -152,12 +160,14 @@ Functionality flag: I2C_FUNC_SMBUS_PROC_CALL SMBus Block Read: i2c_smbus_read_block_data() ============================================== -This command reads a block of up to 32 bytes from a device, from a +This command reads a block of up to 32 bytes from a device, from a designated register that is specified through the Comm byte. The amount of data is specified by the device in the Count byte. -S Addr Wr [A] Comm [A] - S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P +:: + + S Addr Wr [A] Comm [A] + S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P Functionality flag: I2C_FUNC_SMBUS_READ_BLOCK_DATA @@ -165,11 +175,13 @@ Functionality flag: I2C_FUNC_SMBUS_READ_BLOCK_DATA SMBus Block Write: i2c_smbus_write_block_data() ================================================ -The opposite of the Block Read command, this writes up to 32 bytes to +The opposite of the Block Read command, this writes up to 32 bytes to a device, to a designated register that is specified through the Comm byte. The amount of data is specified in the Count byte. -S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P +:: + + S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P Functionality flag: I2C_FUNC_SMBUS_WRITE_BLOCK_DATA @@ -181,10 +193,10 @@ SMBus Block Write - Block Read Process Call was introduced in Revision 2.0 of the specification. This command selects a device register (through the Comm byte), sends -1 to 31 bytes of data to it, and reads 1 to 31 bytes of data in return. +1 to 31 bytes of data to it, and reads 1 to 31 bytes of data in return:: -S Addr Wr [A] Comm [A] Count [A] Data [A] ... - S Addr Rd [A] [Count] A [Data] ... A P + S Addr Wr [A] Comm [A] Count [A] Data [A] ... + S Addr Rd [A] [Count] A [Data] ... A P Functionality flag: I2C_FUNC_SMBUS_BLOCK_PROC_CALL @@ -197,9 +209,12 @@ SMBus host acting as a slave. It is the same form as Write Word, with the command code replaced by the alerting device's address. -[S] [HostAddr] [Wr] A [DevAddr] A [DataLow] A [DataHigh] A [P] +:: + + [S] [HostAddr] [Wr] A [DevAddr] A [DataLow] A [DataHigh] A [P] This is implemented in the following way in the Linux kernel: + * I2C bus drivers which support SMBus Host Notify should report I2C_FUNC_SMBUS_HOST_NOTIFY. * I2C bus drivers trigger SMBus Host Notify by a call to @@ -241,6 +256,7 @@ single interrupt pin on the SMBus master, while still allowing the master to know which slave triggered the interrupt. This is implemented the following way in the Linux kernel: + * I2C bus drivers which support SMBus alert should call i2c_setup_smbus_alert() to setup SMBus alert support. * I2C drivers for devices which can trigger SMBus alerts should implement @@ -261,11 +277,11 @@ but the SMBus layer places a limit of 32 bytes. I2C Block Read: i2c_smbus_read_i2c_block_data() ================================================ -This command reads a block of bytes from a device, from a -designated register that is specified through the Comm byte. +This command reads a block of bytes from a device, from a +designated register that is specified through the Comm byte:: -S Addr Wr [A] Comm [A] - S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P + S Addr Wr [A] Comm [A] + S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P Functionality flag: I2C_FUNC_SMBUS_READ_I2C_BLOCK @@ -273,11 +289,13 @@ Functionality flag: I2C_FUNC_SMBUS_READ_I2C_BLOCK I2C Block Write: i2c_smbus_write_i2c_block_data() ================================================== -The opposite of the Block Read command, this writes bytes to +The opposite of the Block Read command, this writes bytes to a device, to a designated register that is specified through the Comm byte. Note that command lengths of 0, 2, or more bytes are supported as they are indistinguishable from data. -S Addr Wr [A] Comm [A] Data [A] Data [A] ... [A] Data [A] P +:: + + S Addr Wr [A] Comm [A] Data [A] Data [A] ... [A] Data [A] P Functionality flag: I2C_FUNC_SMBUS_WRITE_I2C_BLOCK diff --git a/Documentation/i2c/summary b/Documentation/i2c/summary.rst similarity index 96% rename from Documentation/i2c/summary rename to Documentation/i2c/summary.rst index 809541ab352f03a6a9c3cb8570f52157f1d73054..3a24eac1737562a17e089ba9f4feafe175a79b13 100644 --- a/Documentation/i2c/summary +++ b/Documentation/i2c/summary.rst @@ -1,7 +1,8 @@ +============= I2C and SMBus ============= -I2C (pronounce: I squared C) is a protocol developed by Philips. It is a +I2C (pronounce: I squared C) is a protocol developed by Philips. It is a slow two-wire protocol (variable speed, up to 400 kHz), with a high speed extension (3.4 MHz). It provides an inexpensive bus for connecting many types of devices with infrequent or low bandwidth communications needs. @@ -24,7 +25,8 @@ implement all the common SMBus protocol semantics or messages. Terminology =========== -When we talk about I2C, we use the following terms: +When we talk about I2C, we use the following terms:: + Bus -> Algorithm Adapter Device -> Driver diff --git a/Documentation/i2c/ten-bit-addresses b/Documentation/i2c/ten-bit-addresses.rst similarity index 95% rename from Documentation/i2c/ten-bit-addresses rename to Documentation/i2c/ten-bit-addresses.rst index 7b2d11e53a49f14c09190449172d539c4725e503..5c765aff16d56ab7dd5822f1b48bc18f9d29bd3d 100644 --- a/Documentation/i2c/ten-bit-addresses +++ b/Documentation/i2c/ten-bit-addresses.rst @@ -1,3 +1,7 @@ +===================== +I2C Ten-bit Addresses +===================== + The I2C protocol knows about two kinds of device addresses: normal 7 bit addresses, and an extended set of 10 bit addresses. The sets of addresses do not intersect: the 7 bit address 0x10 is not the same as the 10 bit @@ -12,6 +16,7 @@ See the I2C specification for the details. The current 10 bit address support is minimal. It should work, however you can expect some problems along the way: + * Not all bus drivers support 10-bit addresses. Some don't because the hardware doesn't support them (SMBus doesn't require 10-bit address support for example), some don't because nobody bothered adding the diff --git a/Documentation/i2c/upgrading-clients b/Documentation/i2c/upgrading-clients.rst similarity index 54% rename from Documentation/i2c/upgrading-clients rename to Documentation/i2c/upgrading-clients.rst index 96392cc5b5c7455261df2f61c2c46e031533c889..27d29032c138b77bf342e8ec6b29d47df7729b01 100644 --- a/Documentation/i2c/upgrading-clients +++ b/Documentation/i2c/upgrading-clients.rst @@ -1,3 +1,4 @@ +================================================= Upgrading I2C Drivers to the new 2.6 Driver Model ================================================= @@ -13,21 +14,22 @@ the old to the new new binding methods. Example old-style driver ------------------------ +:: -struct example_state { + struct example_state { struct i2c_client client; .... -}; + }; -static struct i2c_driver example_driver; + static struct i2c_driver example_driver; -static unsigned short ignore[] = { I2C_CLIENT_END }; -static unsigned short normal_addr[] = { OUR_ADDR, I2C_CLIENT_END }; + static unsigned short ignore[] = { I2C_CLIENT_END }; + static unsigned short normal_addr[] = { OUR_ADDR, I2C_CLIENT_END }; -I2C_CLIENT_INSMOD; + I2C_CLIENT_INSMOD; -static int example_attach(struct i2c_adapter *adap, int addr, int kind) -{ + static int example_attach(struct i2c_adapter *adap, int addr, int kind) + { struct example_state *state; struct device *dev = &adap->dev; /* to use for dev_ reports */ int ret; @@ -59,31 +61,31 @@ static int example_attach(struct i2c_adapter *adap, int addr, int kind) dev_info(dev, "example client created\n"); return 0; -} + } -static int example_detach(struct i2c_client *client) -{ + static int example_detach(struct i2c_client *client) + { struct example_state *state = i2c_get_clientdata(client); i2c_detach_client(client); kfree(state); return 0; -} + } -static int example_attach_adapter(struct i2c_adapter *adap) -{ + static int example_attach_adapter(struct i2c_adapter *adap) + { return i2c_probe(adap, &addr_data, example_attach); -} + } -static struct i2c_driver example_driver = { - .driver = { + static struct i2c_driver example_driver = { + .driver = { .owner = THIS_MODULE, .name = "example", .pm = &example_pm_ops, }, .attach_adapter = example_attach_adapter, .detach_client = example_detach, -}; + }; Updating the client @@ -93,38 +95,38 @@ The new style binding model will check against a list of supported devices and their associated address supplied by the code registering the busses. This means that the driver .attach_adapter and .detach_client methods can be removed, along with the addr_data, -as follows: +as follows:: -- static struct i2c_driver example_driver; + - static struct i2c_driver example_driver; -- static unsigned short ignore[] = { I2C_CLIENT_END }; -- static unsigned short normal_addr[] = { OUR_ADDR, I2C_CLIENT_END }; + - static unsigned short ignore[] = { I2C_CLIENT_END }; + - static unsigned short normal_addr[] = { OUR_ADDR, I2C_CLIENT_END }; -- I2C_CLIENT_INSMOD; + - I2C_CLIENT_INSMOD; -- static int example_attach_adapter(struct i2c_adapter *adap) -- { -- return i2c_probe(adap, &addr_data, example_attach); -- } + - static int example_attach_adapter(struct i2c_adapter *adap) + - { + - return i2c_probe(adap, &addr_data, example_attach); + - } - static struct i2c_driver example_driver = { -- .attach_adapter = example_attach_adapter, -- .detach_client = example_detach, - } + static struct i2c_driver example_driver = { + - .attach_adapter = example_attach_adapter, + - .detach_client = example_detach, + } -Add the probe and remove methods to the i2c_driver, as so: +Add the probe and remove methods to the i2c_driver, as so:: - static struct i2c_driver example_driver = { -+ .probe = example_probe, -+ .remove = example_remove, - } + static struct i2c_driver example_driver = { + + .probe = example_probe, + + .remove = example_remove, + } Change the example_attach method to accept the new parameters -which include the i2c_client that it will be working with: +which include the i2c_client that it will be working with:: -- static int example_attach(struct i2c_adapter *adap, int addr, int kind) -+ static int example_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) + - static int example_attach(struct i2c_adapter *adap, int addr, int kind) + + static int example_probe(struct i2c_client *client, + + const struct i2c_device_id *id) Change the name of example_attach to example_probe to align it with the i2c_driver entry names. The rest of the probe routine will now need to be @@ -132,57 +134,59 @@ changed as the i2c_client has already been setup for use. The necessary client fields have already been setup before the probe function is called, so the following client setup -can be removed: +can be removed:: -- example->client.addr = addr; -- example->client.flags = 0; -- example->client.adapter = adap; -- -- strscpy(client->i2c_client.name, "example", sizeof(client->i2c_client.name)); + - example->client.addr = addr; + - example->client.flags = 0; + - example->client.adapter = adap; + - + - strscpy(client->i2c_client.name, "example", sizeof(client->i2c_client.name)); -The i2c_set_clientdata is now: +The i2c_set_clientdata is now:: -- i2c_set_clientdata(&state->client, state); -+ i2c_set_clientdata(client, state); + - i2c_set_clientdata(&state->client, state); + + i2c_set_clientdata(client, state); The call to i2c_attach_client is no longer needed, if the probe routine exits successfully, then the driver will be automatically -attached by the core. Change the probe routine as so: +attached by the core. Change the probe routine as so:: -- ret = i2c_attach_client(&state->i2c_client); -- if (ret < 0) { -- dev_err(dev, "failed to attach client\n"); -- kfree(state); -- return ret; -- } + - ret = i2c_attach_client(&state->i2c_client); + - if (ret < 0) { + - dev_err(dev, "failed to attach client\n"); + - kfree(state); + - return ret; + - } Remove the storage of 'struct i2c_client' from the 'struct example_state' as we are provided with the i2c_client in our example_probe. Instead we store a pointer to it for when it is needed. -struct example_state { -- struct i2c_client client; -+ struct i2c_client *client; +:: + + struct example_state { + - struct i2c_client client; + + struct i2c_client *client; -the new i2c client as so: +the new i2c client as so:: -- struct device *dev = &adap->dev; /* to use for dev_ reports */ -+ struct device *dev = &i2c_client->dev; /* to use for dev_ reports */ + - struct device *dev = &adap->dev; /* to use for dev_ reports */ + + struct device *dev = &i2c_client->dev; /* to use for dev_ reports */ And remove the change after our client is attached, as the driver no -longer needs to register a new client structure with the core: +longer needs to register a new client structure with the core:: -- dev = &state->i2c_client.dev; + - dev = &state->i2c_client.dev; In the probe routine, ensure that the new state has the client stored -in it: +in it:: -static int example_probe(struct i2c_client *i2c_client, + static int example_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) -{ + { struct example_state *state; - struct device *dev = &i2c_client->dev; + struct device *dev = &i2c_client->dev; int ret; state = kzalloc(sizeof(struct example_state), GFP_KERNEL); @@ -191,48 +195,50 @@ static int example_probe(struct i2c_client *i2c_client, return -ENOMEM; } -+ state->client = i2c_client; + + state->client = i2c_client; Update the detach method, by changing the name to _remove and to delete the i2c_detach_client call. It is possible that you can also remove the ret variable as it is not needed for any of the core functions. -- static int example_detach(struct i2c_client *client) -+ static int example_remove(struct i2c_client *client) -{ +:: + + - static int example_detach(struct i2c_client *client) + + static int example_remove(struct i2c_client *client) + { struct example_state *state = i2c_get_clientdata(client); -- i2c_detach_client(client); + - i2c_detach_client(client); And finally ensure that we have the correct ID table for the i2c-core -and other utilities: +and other utilities:: -+ struct i2c_device_id example_idtable[] = { -+ { "example", 0 }, -+ { } -+}; -+ -+MODULE_DEVICE_TABLE(i2c, example_idtable); + + struct i2c_device_id example_idtable[] = { + + { "example", 0 }, + + { } + +}; + + + +MODULE_DEVICE_TABLE(i2c, example_idtable); -static struct i2c_driver example_driver = { - .driver = { + static struct i2c_driver example_driver = { + .driver = { .owner = THIS_MODULE, .name = "example", }, -+ .id_table = example_ids, + + .id_table = example_ids, -Our driver should now look like this: +Our driver should now look like this:: -struct example_state { + struct example_state { struct i2c_client *client; .... -}; + }; -static int example_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ + static int example_probe(struct i2c_client *client, + const struct i2c_device_id *id) + { struct example_state *state; struct device *dev = &client->dev; @@ -250,25 +256,25 @@ static int example_probe(struct i2c_client *client, dev_info(dev, "example client created\n"); return 0; -} + } -static int example_remove(struct i2c_client *client) -{ + static int example_remove(struct i2c_client *client) + { struct example_state *state = i2c_get_clientdata(client); kfree(state); return 0; -} + } -static struct i2c_device_id example_idtable[] = { + static struct i2c_device_id example_idtable[] = { { "example", 0 }, { } -}; + }; -MODULE_DEVICE_TABLE(i2c, example_idtable); + MODULE_DEVICE_TABLE(i2c, example_idtable); -static struct i2c_driver example_driver = { - .driver = { + static struct i2c_driver example_driver = { + .driver = { .owner = THIS_MODULE, .name = "example", .pm = &example_pm_ops, @@ -276,4 +282,4 @@ static struct i2c_driver example_driver = { .id_table = example_idtable, .probe = example_probe, .remove = example_remove, -}; + }; diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients.rst similarity index 91% rename from Documentation/i2c/writing-clients rename to Documentation/i2c/writing-clients.rst index a755b141fa4a8946409750b99e8713e1d6ebb5f2..dddf0a14ab7cb07be816d7a5a0d0aa27621fe688 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients.rst @@ -1,3 +1,7 @@ +=================== +Writing I2C Clients +=================== + This is a small guide for those who want to write kernel drivers for I2C or SMBus devices, using Linux as the protocol host/master (not slave). @@ -12,7 +16,7 @@ General remarks Try to keep the kernel namespace as clean as possible. The best way to do this is to use a unique prefix for all global symbols. This is especially important for exported symbols, but it is a good idea to do -it for non-exported symbols too. We will use the prefix `foo_' in this +it for non-exported symbols too. We will use the prefix ``foo_`` in this tutorial. @@ -25,15 +29,17 @@ routines, and should be zero-initialized except for fields with data you provide. A client structure holds device-specific information like the driver model device node, and its I2C address. -static struct i2c_device_id foo_idtable[] = { +:: + + static struct i2c_device_id foo_idtable[] = { { "foo", my_id_for_foo }, { "bar", my_id_for_bar }, { } -}; + }; -MODULE_DEVICE_TABLE(i2c, foo_idtable); + MODULE_DEVICE_TABLE(i2c, foo_idtable); -static struct i2c_driver foo_driver = { + static struct i2c_driver foo_driver = { .driver = { .name = "foo", .pm = &foo_pm_ops, /* optional */ @@ -49,7 +55,7 @@ static struct i2c_driver foo_driver = { .shutdown = foo_shutdown, /* optional */ .command = foo_command, /* optional, deprecated */ -} + } The name field is the driver name, and must not contain spaces. It should match the module name (if the driver can be compiled as a module), @@ -64,16 +70,18 @@ below. Extra client data ================= -Each client structure has a special `data' field that can point to any +Each client structure has a special ``data`` field that can point to any structure at all. You should use this to keep device-specific data. +:: + /* store the value */ void i2c_set_clientdata(struct i2c_client *client, void *data); /* retrieve the value */ void *i2c_get_clientdata(const struct i2c_client *client); -Note that starting with kernel 2.6.34, you don't have to set the `data' field +Note that starting with kernel 2.6.34, you don't have to set the ``data`` field to NULL in remove() or if probe() failed anymore. The i2c-core does this automatically on these occasions. Those are also the only times the core will touch this field. @@ -92,25 +100,25 @@ but many chips have some kind of register-value idea that can easily be encapsulated. The below functions are simple examples, and should not be copied -literally. +literally:: -int foo_read_value(struct i2c_client *client, u8 reg) -{ + int foo_read_value(struct i2c_client *client, u8 reg) + { if (reg < 0x10) /* byte-sized register */ return i2c_smbus_read_byte_data(client, reg); else /* word-sized register */ return i2c_smbus_read_word_data(client, reg); -} + } -int foo_write_value(struct i2c_client *client, u8 reg, u16 value) -{ + int foo_write_value(struct i2c_client *client, u8 reg, u16 value) + { if (reg == 0x10) /* Impossible to write - driver error! */ return -EINVAL; else if (reg < 0x10) /* byte-sized register */ return i2c_smbus_write_byte_data(client, reg, value); else /* word-sized register */ return i2c_smbus_write_word_data(client, reg, value); -} + } Probing and attaching @@ -145,6 +153,8 @@ I2C device drivers using this binding model work just like any other kind of driver in Linux: they provide a probe() method to bind to those devices, and a remove() method to unbind. +:: + static int foo_probe(struct i2c_client *client, const struct i2c_device_id *id); static int foo_remove(struct i2c_client *client); @@ -240,37 +250,41 @@ When the kernel is booted, or when your foo driver module is inserted, you have to do some initializing. Fortunately, just registering the driver module is usually enough. -static int __init foo_init(void) -{ +:: + + static int __init foo_init(void) + { return i2c_add_driver(&foo_driver); -} -module_init(foo_init); + } + module_init(foo_init); -static void __exit foo_cleanup(void) -{ + static void __exit foo_cleanup(void) + { i2c_del_driver(&foo_driver); -} -module_exit(foo_cleanup); + } + module_exit(foo_cleanup); -The module_i2c_driver() macro can be used to reduce above code. + The module_i2c_driver() macro can be used to reduce above code. -module_i2c_driver(foo_driver); + module_i2c_driver(foo_driver); -Note that some functions are marked by `__init'. These functions can +Note that some functions are marked by ``__init``. These functions can be removed after kernel booting (or module loading) is completed. -Likewise, functions marked by `__exit' are dropped by the compiler when +Likewise, functions marked by ``__exit`` are dropped by the compiler when the code is built into the kernel, as they would never be called. Driver Information ================== -/* Substitute your own name and email address */ -MODULE_AUTHOR("Frodo Looijaard " -MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices"); +:: -/* a few non-GPL license types are also allowed */ -MODULE_LICENSE("GPL"); + /* Substitute your own name and email address */ + MODULE_AUTHOR("Frodo Looijaard " + MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices"); + + /* a few non-GPL license types are also allowed */ + MODULE_LICENSE("GPL"); Power Management @@ -323,6 +337,8 @@ commands, but only some of them understand plain I2C! Plain I2C communication ----------------------- +:: + int i2c_master_send(struct i2c_client *client, const char *buf, int count); int i2c_master_recv(struct i2c_client *client, char *buf, int count); @@ -334,6 +350,8 @@ to read/write (must be less than the length of the buffer, also should be less than 64k since msg.len is u16.) Returned is the actual number of bytes read/written. +:: + int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num); @@ -343,13 +361,15 @@ stop bit is sent between transaction. The i2c_msg structure contains for each message the client address, the number of bytes of the message and the message data itself. -You can read the file `i2c-protocol' for more information about the +You can read the file ``i2c-protocol`` for more information about the actual I2C protocol. SMBus communication ------------------- +:: + s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data); @@ -357,6 +377,8 @@ SMBus communication This is the generic SMBus function. All functions below are implemented in terms of it. Never use this function directly! +:: + s32 i2c_smbus_read_byte(struct i2c_client *client); s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value); s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command); @@ -376,7 +398,7 @@ in terms of it. Never use this function directly! const u8 *values); These ones were removed from i2c-core because they had no users, but could -be added back later if needed: +be added back later if needed:: s32 i2c_smbus_write_quick(struct i2c_client *client, u8 value); s32 i2c_smbus_process_call(struct i2c_client *client, @@ -389,7 +411,7 @@ transactions return 0 on success; the 'read' transactions return the read value, except for block transactions, which return the number of values read. The block buffers need not be longer than 32 bytes. -You can read the file `smbus-protocol' for more information about the +You can read the file ``smbus-protocol`` for more information about the actual SMBus protocol. @@ -397,7 +419,7 @@ General purpose routines ======================== Below all general purpose routines are listed, that were not mentioned -before. +before:: /* Return the adapter number for a specific adapter */ int i2c_adapter_id(struct i2c_adapter *adap); diff --git a/Documentation/index.rst b/Documentation/index.rst index 2df5a3da563c2d2bfefa017eca5c7e84b3c85076..b5fd87e7dbee453225d99d7b89ca13a2a7468126 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -104,7 +104,9 @@ needed). fb/index fpga/index hid/index + i2c/index iio/index + isdn/index infiniband/index leds/index media/index @@ -114,8 +116,10 @@ needed). power/index target/index timers/index + spi/index + w1/index watchdog/index - virtual/index + virt/index input/index hwmon/index gpu/index @@ -146,6 +150,10 @@ implementation. ia64/index m68k/index powerpc/index + mips/index + nios2/nios2 + openrisc/index + parisc/index riscv/index s390/index sh/index diff --git a/Documentation/input/multi-touch-protocol.rst b/Documentation/input/multi-touch-protocol.rst index 6be70342e7097013a6120730efbd53391103d986..307fe22d96686464be5705952eec370444309f34 100644 --- a/Documentation/input/multi-touch-protocol.rst +++ b/Documentation/input/multi-touch-protocol.rst @@ -23,7 +23,7 @@ devices capable of tracking identifiable contacts (type B), the protocol describes how to send updates for individual contacts via event slots. .. note:: - MT potocol type A is obsolete, all kernel drivers have been + MT protocol type A is obsolete, all kernel drivers have been converted to use type B. Protocol Usage diff --git a/Documentation/ioctl/ioctl-number.rst b/Documentation/ioctl/ioctl-number.rst index 7f8dcae7a2308519d2fc35308b9ec5c825ac053a..bef79cd4c6b4d35566a629059c5d7304b4c34e13 100644 --- a/Documentation/ioctl/ioctl-number.rst +++ b/Documentation/ioctl/ioctl-number.rst @@ -233,6 +233,7 @@ Code Seq# Include File Comments 'f' 00-0F fs/ext4/ext4.h conflict! 'f' 00-0F linux/fs.h conflict! 'f' 00-0F fs/ocfs2/ocfs2_fs.h conflict! +'f' 81-8F linux/fsverity.h 'g' 00-0F linux/usb/gadgetfs.h 'g' 20-2F linux/usb/g_printer.h 'h' 00-7F conflict! Charon filesystem diff --git a/Documentation/isdn/README.avmb1 b/Documentation/isdn/avmb1.rst similarity index 50% rename from Documentation/isdn/README.avmb1 rename to Documentation/isdn/avmb1.rst index 9e075484ef1e03e22385465c02ee9dbab61d2480..de3961e67553c299dce83012386c1d769b1cc316 100644 --- a/Documentation/isdn/README.avmb1 +++ b/Documentation/isdn/avmb1.rst @@ -1,4 +1,6 @@ -Driver for active AVM Controller. +================================ +Driver for active AVM Controller +================================ The driver provides a kernel capi2.0 Interface (kernelcapi) and on top of this a User-Level-CAPI2.0-interface (capi) @@ -11,25 +13,28 @@ The command avmcapictrl is part of the isdn4k-utils. t4-files can be found at ftp://ftp.avm.de/cardware/b1/linux/firmware Currently supported cards: - B1 ISA (all versions) - B1 PCI - T1/T1B (HEMA card) - M1 - M2 - B1 PCMCIA + + - B1 ISA (all versions) + - B1 PCI + - T1/T1B (HEMA card) + - M1 + - M2 + - B1 PCMCIA Installing ---------- You need at least /dev/capi20 to load the firmware. -mknod /dev/capi20 c 68 0 -mknod /dev/capi20.00 c 68 1 -mknod /dev/capi20.01 c 68 2 -. -. -. -mknod /dev/capi20.19 c 68 20 +:: + + mknod /dev/capi20 c 68 0 + mknod /dev/capi20.00 c 68 1 + mknod /dev/capi20.01 c 68 2 + . + . + . + mknod /dev/capi20.19 c 68 20 Running ------- @@ -38,45 +43,58 @@ To use the card you need the t4-files to download the firmware. AVM GmbH provides several t4-files for the different D-channel protocols (b1.t4 for Euro-ISDN). Install these file in /lib/isdn. -if you configure as modules load the modules this way: +if you configure as modules load the modules this way:: + + insmod /lib/modules/current/misc/capiutil.o + insmod /lib/modules/current/misc/b1.o + insmod /lib/modules/current/misc/kernelcapi.o + insmod /lib/modules/current/misc/capidrv.o + insmod /lib/modules/current/misc/capi.o -insmod /lib/modules/current/misc/capiutil.o -insmod /lib/modules/current/misc/b1.o -insmod /lib/modules/current/misc/kernelcapi.o -insmod /lib/modules/current/misc/capidrv.o -insmod /lib/modules/current/misc/capi.o +if you have an B1-PCI card load the module b1pci.o:: -if you have an B1-PCI card load the module b1pci.o -insmod /lib/modules/current/misc/b1pci.o -and load the firmware with -avmcapictrl load /lib/isdn/b1.t4 1 + insmod /lib/modules/current/misc/b1pci.o + +and load the firmware with:: + + avmcapictrl load /lib/isdn/b1.t4 1 if you have an B1-ISA card load the module b1isa.o -and add the card by calling -avmcapictrl add 0x150 15 -and load the firmware by calling -avmcapictrl load /lib/isdn/b1.t4 1 +and add the card by calling:: + + avmcapictrl add 0x150 15 + +and load the firmware by calling:: + + avmcapictrl load /lib/isdn/b1.t4 1 if you have an T1-ISA card load the module t1isa.o -and add the card by calling -avmcapictrl add 0x450 15 T1 0 -and load the firmware by calling -avmcapictrl load /lib/isdn/t1.t4 1 +and add the card by calling:: + + avmcapictrl add 0x450 15 T1 0 + +and load the firmware by calling:: + + avmcapictrl load /lib/isdn/t1.t4 1 if you have an PCMCIA card (B1/M1/M2) load the module b1pcmcia.o before you insert the card. Leased Lines with B1 -------------------- + Init card and load firmware. + For an D64S use "FV: 1" as phone number + For an D64S2 use "FV: 1" and "FV: 2" for multilink or "FV: 1,2" to use CAPI channel bundling. /proc-Interface ----------------- -/proc/capi: +/proc/capi:: + dr-xr-xr-x 2 root root 0 Jul 1 14:03 . dr-xr-xr-x 82 root root 0 Jun 30 19:08 .. -r--r--r-- 1 root root 0 Jul 1 14:03 applications @@ -91,84 +109,124 @@ or "FV: 1,2" to use CAPI channel bundling. /proc/capi/applications: applid level3cnt datablkcnt datablklen ncci-cnt recvqueuelen - level3cnt: capi_register parameter - datablkcnt: capi_register parameter - ncci-cnt: current number of nccis (connections) - recvqueuelen: number of messages on receive queue - for example: -1 -2 16 2048 1 0 -2 2 7 2048 1 0 + level3cnt: + capi_register parameter + datablkcnt: + capi_register parameter + ncci-cnt: + current number of nccis (connections) + recvqueuelen: + number of messages on receive queue + + for example:: + + 1 -2 16 2048 1 0 + 2 2 7 2048 1 0 /proc/capi/applstats: applid recvctlmsg nrecvdatamsg nsentctlmsg nsentdatamsg - recvctlmsg: capi messages received without DATA_B3_IND - recvdatamsg: capi DATA_B3_IND received - sentctlmsg: capi messages sent without DATA_B3_REQ - sentdatamsg: capi DATA_B3_REQ sent - for example: -1 2057 1699 1721 1699 + recvctlmsg: + capi messages received without DATA_B3_IND + recvdatamsg: + capi DATA_B3_IND received + sentctlmsg: + capi messages sent without DATA_B3_REQ + sentdatamsg: + capi DATA_B3_REQ sent + + for example:: + + 1 2057 1699 1721 1699 /proc/capi/capi20: statistics of capi.o (/dev/capi20) minor nopen nrecvdropmsg nrecvctlmsg nrecvdatamsg sentctlmsg sentdatamsg - minor: minor device number of capi device - nopen: number of calls to devices open - nrecvdropmsg: capi messages dropped (messages in recvqueue in close) - nrecvctlmsg: capi messages received without DATA_B3_IND - nrecvdatamsg: capi DATA_B3_IND received - nsentctlmsg: capi messages sent without DATA_B3_REQ - nsentdatamsg: capi DATA_B3_REQ sent - - for example: -1 2 18 0 16 2 + minor: + minor device number of capi device + nopen: + number of calls to devices open + nrecvdropmsg: + capi messages dropped (messages in recvqueue in close) + nrecvctlmsg: + capi messages received without DATA_B3_IND + nrecvdatamsg: + capi DATA_B3_IND received + nsentctlmsg: + capi messages sent without DATA_B3_REQ + nsentdatamsg: + capi DATA_B3_REQ sent + + for example:: + + 1 2 18 0 16 2 /proc/capi/capidrv: statistics of capidrv.o (capi messages) nrecvctlmsg nrecvdatamsg sentctlmsg sentdatamsg - nrecvctlmsg: capi messages received without DATA_B3_IND - nrecvdatamsg: capi DATA_B3_IND received - nsentctlmsg: capi messages sent without DATA_B3_REQ - nsentdatamsg: capi DATA_B3_REQ sent + nrecvctlmsg: + capi messages received without DATA_B3_IND + nrecvdatamsg: + capi DATA_B3_IND received + nsentctlmsg: + capi messages sent without DATA_B3_REQ + nsentdatamsg: + capi DATA_B3_REQ sent + for example: -2780 2226 2256 2226 + 2780 2226 2256 2226 /proc/capi/controller: controller drivername state cardname controllerinfo - for example: -1 b1pci running b1pci-e000 B1 3.07-01 0xe000 19 -2 t1isa running t1isa-450 B1 3.07-01 0x450 11 0 -3 b1pcmcia running m2-150 B1 3.07-01 0x150 5 + + for example:: + + 1 b1pci running b1pci-e000 B1 3.07-01 0xe000 19 + 2 t1isa running t1isa-450 B1 3.07-01 0x450 11 0 + 3 b1pcmcia running m2-150 B1 3.07-01 0x150 5 /proc/capi/contrstats: controller nrecvctlmsg nrecvdatamsg sentctlmsg sentdatamsg - nrecvctlmsg: capi messages received without DATA_B3_IND - nrecvdatamsg: capi DATA_B3_IND received - nsentctlmsg: capi messages sent without DATA_B3_REQ - nsentdatamsg: capi DATA_B3_REQ sent - for example: -1 2845 2272 2310 2274 -2 2 0 2 0 -3 2 0 2 0 + nrecvctlmsg: + capi messages received without DATA_B3_IND + nrecvdatamsg: + capi DATA_B3_IND received + nsentctlmsg: + capi messages sent without DATA_B3_REQ + nsentdatamsg: + capi DATA_B3_REQ sent + + for example:: + + 1 2845 2272 2310 2274 + 2 2 0 2 0 + 3 2 0 2 0 /proc/capi/driver: drivername ncontroller - for example: -b1pci 1 -t1isa 1 -b1pcmcia 1 -b1isa 0 + + for example:: + + b1pci 1 + t1isa 1 + b1pcmcia 1 + b1isa 0 /proc/capi/ncci: apllid ncci winsize sendwindow - for example: -1 0x10101 8 0 + + for example:: + + 1 0x10101 8 0 /proc/capi/users: kernelmodules that use the kernelcapi. name - for example: -capidrv -capi20 + + for example:: + + capidrv + capi20 Questions --------- + Check out the FAQ (ftp.isdn4linux.de) or subscribe to the linux-avmb1@calle.in-berlin.de mailing list by sending a mail to majordomo@calle.in-berlin.de with @@ -178,9 +236,10 @@ in the body. German documentation and several scripts can be found at ftp://ftp.avm.de/cardware/b1/linux/ -Bugs +Bugs ---- -If you find any please let me know. + +If you find any please let me know. Enjoy, diff --git a/Documentation/isdn/CREDITS b/Documentation/isdn/credits.rst similarity index 96% rename from Documentation/isdn/CREDITS rename to Documentation/isdn/credits.rst index c1679e913fca4668584be5c5e2e296bc75f40ada..319323f2091fa528d616408527c536b8ba08fa96 100644 --- a/Documentation/isdn/CREDITS +++ b/Documentation/isdn/credits.rst @@ -1,3 +1,7 @@ +======= +Credits +======= + I want to thank all who contributed to this project and especially to: (in alphabetical order) @@ -19,7 +23,7 @@ Matthias Hessler (hessler@isdn4linux.de) For creating and maintaining the FAQ. Bernhard Hailer (Bernhard.Hailer@lrz.uni-muenchen.de) - For creating the FAQ, and the leafsite HOWTO. + For creating the FAQ, and the leafsite HOWTO. Michael 'Ghandi' Herold (michael@abadonna.franken.de) For contribution of the vbox answering machine. @@ -67,4 +71,3 @@ Gerhard 'Fido' Schneider (fido@wuff.mayn.de) Thomas Uhl (uhl@think.de) For distributing the cards. For pushing me to work ;-) - diff --git a/Documentation/isdn/README.gigaset b/Documentation/isdn/gigaset.rst similarity index 74% rename from Documentation/isdn/README.gigaset rename to Documentation/isdn/gigaset.rst index f6184b637182dd7b2966ce08761e6370ce39b3e0..98b4ec521c519d5f401c021c35aa8421a1e2013c 100644 --- a/Documentation/isdn/README.gigaset +++ b/Documentation/isdn/gigaset.rst @@ -1,33 +1,36 @@ +========================== GigaSet 307x Device Driver ========================== 1. Requirements - ------------ +================= + 1.1. Hardware - -------- +------------- + This driver supports the connection of the Gigaset 307x/417x family of ISDN DECT bases via Gigaset M101 Data, Gigaset M105 Data or direct USB connection. The following devices are reported to be compatible: Bases: - Siemens Gigaset 3070/3075 isdn - Siemens Gigaset 4170/4175 isdn - Siemens Gigaset SX205/255 - Siemens Gigaset SX353 - T-Com Sinus 45 [AB] isdn - T-Com Sinus 721X[A] [SE] - Vox Chicago 390 ISDN (KPN Telecom) + - Siemens Gigaset 3070/3075 isdn + - Siemens Gigaset 4170/4175 isdn + - Siemens Gigaset SX205/255 + - Siemens Gigaset SX353 + - T-Com Sinus 45 [AB] isdn + - T-Com Sinus 721X[A] [SE] + - Vox Chicago 390 ISDN (KPN Telecom) RS232 data boxes: - Siemens Gigaset M101 Data - T-Com Sinus 45 Data 1 + - Siemens Gigaset M101 Data + - T-Com Sinus 45 Data 1 USB data boxes: - Siemens Gigaset M105 Data - Siemens Gigaset USB Adapter DECT - T-Com Sinus 45 Data 2 - T-Com Sinus 721 data - Chicago 390 USB (KPN) + - Siemens Gigaset M105 Data + - Siemens Gigaset USB Adapter DECT + - T-Com Sinus 45 Data 2 + - T-Com Sinus 721 data + - Chicago 390 USB (KPN) See also http://www.erbze.info/sinus_gigaset.htm (archived at https://web.archive.org/web/20100717020421/http://www.erbze.info:80/sinus_gigaset.htm ) and @@ -37,17 +40,21 @@ GigaSet 307x Device Driver with SX 100 and CX 100 ISDN bases (only in unimodem mode, see section 2.5.) If you have another device that works with our driver, please let us know. - Chances of getting an USB device to work are good if the output of - lsusb - at the command line contains one of the following: - ID 0681:0001 - ID 0681:0002 - ID 0681:0009 - ID 0681:0021 - ID 0681:0022 + Chances of getting an USB device to work are good if the output of:: + + lsusb + + at the command line contains one of the following:: + + ID 0681:0001 + ID 0681:0002 + ID 0681:0009 + ID 0681:0021 + ID 0681:0022 1.2. Software - -------- +------------- + The driver works with the Kernel CAPI subsystem and can be used with any software which is able to use CAPI 2.0 for ISDN connections (voice or data). @@ -58,9 +65,11 @@ GigaSet 307x Device Driver 2. How to use the driver - --------------------- +========================== + 2.1. Modules - ------- +------------ + For the devices to work, the proper kernel modules have to be loaded. This normally happens automatically when the system detects the USB device (base, M105) or when the line discipline is attached (M101). It @@ -71,13 +80,17 @@ GigaSet 307x Device Driver which uses the regular serial port driver to access the device, and must therefore be attached to the serial device to which the M101 is connected. The ldattach(8) command (included in util-linux-ng release 2.14 or later) - can be used for that purpose, for example: + can be used for that purpose, for example:: + ldattach GIGASET_M101 /dev/ttyS1 + This will open the device file, attach the line discipline to it, and then sleep in the background, keeping the device open so that the line discipline remains active. To deactivate it, kill the daemon, for example - with + with:: + killall ldattach + before disconnecting the device. To have this happen automatically at system startup/shutdown on an LSB compatible system, create and activate an appropriate LSB startup script /etc/init.d/gigaset. (The init name @@ -86,9 +99,10 @@ GigaSet 307x Device Driver The modules accept the following parameters: - Module Parameter Meaning + =============== ========== ========================================== + Module Parameter Meaning - gigaset debug debug level (see section 3.2.) + gigaset debug debug level (see section 3.2.) startmode initial operation mode (see section 2.5.): bas_gigaset ) 1=CAPI (default), 0=Unimodem @@ -96,11 +110,14 @@ GigaSet 307x Device Driver usb_gigaset ) cidmode initial Call-ID mode setting (see section 2.5.): 1=on (default), 0=off + =============== ========== ========================================== + Depending on your distribution you may want to create a separate module configuration file like /etc/modprobe.d/gigaset.conf for these. 2.2. Device nodes for user space programs - ------------------------------------ +----------------------------------------- + The device can be accessed from user space (eg. by the user space tools mentioned in 1.2.) through the device nodes: @@ -113,46 +130,56 @@ GigaSet 307x Device Driver You can also set a "default device" for the user space tools to use when no device node is given as parameter, by creating a symlink /dev/ttyG to - one of them, eg.: + one of them, eg.:: ln -s /dev/ttyGB0 /dev/ttyG The devices accept the following device specific ioctl calls (defined in gigaset_dev.h): - ioctl(int fd, GIGASET_REDIR, int *cmd); + ``ioctl(int fd, GIGASET_REDIR, int *cmd);`` + If cmd==1, the device is set to be controlled exclusively through the character device node; access from the ISDN subsystem is blocked. + If cmd==0, the device is set to be used from the ISDN subsystem and does not communicate through the character device node. - ioctl(int fd, GIGASET_CONFIG, int *cmd); + ``ioctl(int fd, GIGASET_CONFIG, int *cmd);`` + (ser_gigaset and usb_gigaset only) + If cmd==1, the device is set to adapter configuration mode where commands are interpreted by the M10x DECT adapter itself instead of being forwarded to the base station. In this mode, the device accepts the commands described in Siemens document "AT-Kommando Alignment M10x Data" for setting the operation mode, associating with a base station and querying parameters like field strengh and signal quality. + Note that there is no ioctl command for leaving adapter configuration mode and returning to regular operation. In order to leave adapter configuration mode, write the command ATO to the device. - ioctl(int fd, GIGASET_BRKCHARS, unsigned char brkchars[6]); + ``ioctl(int fd, GIGASET_BRKCHARS, unsigned char brkchars[6]);`` + (usb_gigaset only) + Set the break characters on an M105's internal serial adapter to the six bytes stored in brkchars[]. Unused bytes should be set to zero. ioctl(int fd, GIGASET_VERSION, unsigned version[4]); Retrieve version information from the driver. version[0] must be set to one of: + - GIGVER_DRIVER: retrieve driver version - GIGVER_COMPAT: retrieve interface compatibility version - GIGVER_FWBASE: retrieve the firmware version of the base + Upon return, version[] is filled with the requested version information. 2.3. CAPI - ---- +--------- + The devices will show up as CAPI controllers as soon as the corresponding driver module is loaded, and can then be used with CAPI 2.0 kernel and user space applications. For user space access, @@ -165,21 +192,22 @@ GigaSet 307x Device Driver driver. 2.5. Unimodem mode - ------------- +------------------ + In this mode the device works like a modem connected to a serial port - (the /dev/ttyGU0, ... mentioned above) which understands the commands - - ATZ init, reset - => OK or ERROR - ATD - ATDT dial - => OK, CONNECT, - BUSY, - NO DIAL TONE, - NO CARRIER, - NO ANSWER - +++ change to command mode when connected - ATH hangup + (the /dev/ttyGU0, ... mentioned above) which understands the commands:: + + ATZ init, reset + => OK or ERROR + ATD + ATDT dial + => OK, CONNECT, + BUSY, + NO DIAL TONE, + NO CARRIER, + NO ANSWER + +++ change to command mode when connected + ATH hangup You can use some configuration tool of your distribution to configure this "modem" or configure pppd/wvdial manually. There are some example ppp @@ -189,40 +217,52 @@ GigaSet 307x Device Driver control lines. This means you must use "Stupid Mode" if you are using wvdial or you should use the nocrtscts option of pppd. You must also assure that the ppp_async module is loaded with the parameter - flag_time=0. You can do this e.g. by adding a line like + flag_time=0. You can do this e.g. by adding a line like:: + + options ppp_async flag_time=0 - options ppp_async flag_time=0 + to an appropriate module configuration file, like:: - to an appropriate module configuration file, like - /etc/modprobe.d/gigaset.conf. + /etc/modprobe.d/gigaset.conf. Unimodem mode is needed for making some devices [e.g. SX100] work which do not support the regular Gigaset command set. If debug output (see - section 3.2.) shows something like this when dialing: - CMD Received: ERROR - Available Params: 0 - Connection State: 0, Response: -1 - gigaset_process_response: resp_code -1 in ConState 0 ! - Timeout occurred + section 3.2.) shows something like this when dialing:: + + CMD Received: ERROR + Available Params: 0 + Connection State: 0, Response: -1 + gigaset_process_response: resp_code -1 in ConState 0 ! + Timeout occurred + then switching to unimodem mode may help. If you have installed the command line tool gigacontr, you can enter - unimodem mode using - gigacontr --mode unimodem - You can switch back using - gigacontr --mode isdn + unimodem mode using:: + + gigacontr --mode unimodem + + You can switch back using:: + + gigacontr --mode isdn You can also put the driver directly into Unimodem mode when it's loaded, by passing the module parameter startmode=0 to the hardware specific - module, e.g. + module, e.g.:: + modprobe usb_gigaset startmode=0 - or by adding a line like + + or by adding a line like:: + options usb_gigaset startmode=0 - to an appropriate module configuration file, like - /etc/modprobe.d/gigaset.conf + + to an appropriate module configuration file, like:: + + /etc/modprobe.d/gigaset.conf 2.6. Call-ID (CID) mode - ------------------ +----------------------- + Call-IDs are numbers used to tag commands to, and responses from, the Gigaset base in order to support the simultaneous handling of multiple ISDN calls. Their use can be enabled ("CID mode") or disabled ("Unimodem @@ -238,6 +278,7 @@ GigaSet 307x Device Driver During active operation, the driver switches to the necessary mode automatically. However, for the reasons above, the mode chosen when the device is not in use (idle) can be selected by the user. + - If you want to receive incoming calls, you can use the default settings (CID mode). - If you have several DECT data devices (M10x) which you want to use @@ -247,25 +288,27 @@ GigaSet 307x Device Driver If you want both of these at once, you are out of luck. You can also use the tty class parameter "cidmode" of the device to - change its CID mode while the driver is loaded, eg. - echo 0 > /sys/class/tty/ttyGU0/cidmode + change its CID mode while the driver is loaded, eg.:: + + echo 0 > /sys/class/tty/ttyGU0/cidmode 2.7. Dialing Numbers - --------------- - The called party number provided by an application for dialing out must +-------------------- +provided by an application for dialing out must be a public network number according to the local dialing plan, without any dial prefix for getting an outside line. Internal calls can be made by providing an internal extension number - prefixed with "**" (two asterisks) as the called party number. So to dial - eg. the first registered DECT handset, give "**11" as the called party - number. Dialing "***" (three asterisks) calls all extensions + prefixed with ``**`` (two asterisks) as the called party number. So to dial + eg. the first registered DECT handset, give ``**11`` as the called party + number. Dialing ``***`` (three asterisks) calls all extensions simultaneously (global call). Unimodem mode does not support internal calls. 2.8. Unregistered Wireless Devices (M101/M105) - ----------------------------------------- +---------------------------------------------- + The main purpose of the ser_gigaset and usb_gigaset drivers is to allow the M101 and M105 wireless devices to be used as ISDN devices for ISDN connections through a Gigaset base. Therefore they assume that the device @@ -279,73 +322,91 @@ GigaSet 307x Device Driver modes. See the gigacontr(8) manpage for details. 3. Troubleshooting - --------------- +==================== + 3.1. Solutions to frequently reported problems - ----------------------------------------- +---------------------------------------------- + Problem: - You have a slow provider and isdn4linux gives up dialing too early. + You have a slow provider and isdn4linux gives up dialing too early. Solution: - Load the isdn module using the dialtimeout option. You can do this e.g. - by adding a line like + Load the isdn module using the dialtimeout option. You can do this e.g. + by adding a line like:: - options isdn dialtimeout=15 + options isdn dialtimeout=15 - to /etc/modprobe.d/gigaset.conf or a similar file. + to /etc/modprobe.d/gigaset.conf or a similar file. Problem: - The isdnlog program emits error messages or just doesn't work. + The isdnlog program emits error messages or just doesn't work. Solution: - Isdnlog supports only the HiSax driver. Do not attempt to use it with + Isdnlog supports only the HiSax driver. Do not attempt to use it with other drivers such as Gigaset. Problem: - You have two or more DECT data adapters (M101/M105) and only the - first one you turn on works. + You have two or more DECT data adapters (M101/M105) and only the + first one you turn on works. Solution: - Select Unimodem mode for all DECT data adapters. (see section 2.5.) + Select Unimodem mode for all DECT data adapters. (see section 2.5.) Problem: - Messages like this: + Messages like this:: + usb_gigaset 3-2:1.0: Could not initialize the device. + appear in your syslog. Solution: Check whether your M10x wireless device is correctly registered to the Gigaset base. (see section 2.7.) 3.2. Telling the driver to provide more information - ---------------------------------------------- +--------------------------------------------------- Building the driver with the "Gigaset debugging" kernel configuration option (CONFIG_GIGASET_DEBUG) gives it the ability to produce additional information useful for debugging. You can control the amount of debugging information the driver produces by - writing an appropriate value to /sys/module/gigaset/parameters/debug, e.g. - echo 0 > /sys/module/gigaset/parameters/debug + writing an appropriate value to /sys/module/gigaset/parameters/debug, + e.g.:: + + echo 0 > /sys/module/gigaset/parameters/debug + switches off debugging output completely, - echo 0x302020 > /sys/module/gigaset/parameters/debug + + :: + + echo 0x302020 > /sys/module/gigaset/parameters/debug + enables a reasonable set of debugging output messages. These values are bit patterns where every bit controls a certain type of debugging output. See the constants DEBUG_* in the source file gigaset.h for details. The initial value can be set using the debug parameter when loading the - module "gigaset", e.g. by adding a line - options gigaset debug=0 + module "gigaset", e.g. by adding a line:: + + options gigaset debug=0 + to your module configuration file, eg. /etc/modprobe.d/gigaset.conf Generated debugging information can be found - - as output of the command - dmesg + - as output of the command:: + + dmesg + - in system log files written by your syslog daemon, usually in /var/log/, e.g. /var/log/messages. 3.3. Reporting problems and bugs - --------------------------- +-------------------------------- If you can't solve problems with the driver on your own, feel free to use one of the forums, bug trackers, or mailing lists on - https://sourceforge.net/projects/gigaset307x + + https://sourceforge.net/projects/gigaset307x + or write an electronic mail to the maintainers. Try to provide as much information as possible, such as + - distribution - kernel version (uname -r) - gcc version (gcc --version) @@ -362,7 +423,7 @@ GigaSet 307x Device Driver appropriate forums and newsgroups. 3.4. Reporting problem solutions - --------------------------- +-------------------------------- If you solved a problem with our drivers, wrote startup scripts for your distribution, ... feel free to contact us (using one of the places mentioned in 3.3.). We'd like to add scripts, hints, documentation @@ -370,34 +431,35 @@ GigaSet 307x Device Driver 4. Links, other software - --------------------- +========================== + - Sourceforge project developing this driver and associated tools - https://sourceforge.net/projects/gigaset307x + https://sourceforge.net/projects/gigaset307x - Yahoo! Group on the Siemens Gigaset family of devices - https://de.groups.yahoo.com/group/Siemens-Gigaset + https://de.groups.yahoo.com/group/Siemens-Gigaset - Siemens Gigaset/T-Sinus compatibility table - http://www.erbze.info/sinus_gigaset.htm + http://www.erbze.info/sinus_gigaset.htm (archived at https://web.archive.org/web/20100717020421/http://www.erbze.info:80/sinus_gigaset.htm ) 5. Credits - ------- +============ + Thanks to Karsten Keil - for his help with isdn4linux + for his help with isdn4linux Deti Fliegl - for his base driver code + for his base driver code Dennis Dietrich - for his kernel 2.6 patches + for his kernel 2.6 patches Andreas Rummel - for his work and logs to get unimodem mode working + for his work and logs to get unimodem mode working Andreas Degert - for his logs and patches to get cx 100 working + for his logs and patches to get cx 100 working Dietrich Feist - for his generous donation of one M105 and two M101 cordless adapters + for his generous donation of one M105 and two M101 cordless adapters Christoph Schweers - for his generous donation of a M34 device + for his generous donation of a M34 device and all the other people who sent logs and other information. - diff --git a/Documentation/isdn/README.hysdn b/Documentation/isdn/hysdn.rst similarity index 80% rename from Documentation/isdn/README.hysdn rename to Documentation/isdn/hysdn.rst index eeca11f00ccd0287a67036a4ccf7a90f4ae15f62..0a168d1cbffc23d61d38384d222f12cc21ffa54e 100644 --- a/Documentation/isdn/README.hysdn +++ b/Documentation/isdn/hysdn.rst @@ -1,4 +1,7 @@ -$Id: README.hysdn,v 1.3.6.1 2001/02/10 14:41:19 kai Exp $ +============ +Hysdn Driver +============ + The hysdn driver has been written by Werner Cornelius (werner@isdn4linux.de or werner@titro.de) for Hypercope GmbH Aachen Germany. Hypercope agreed to publish this driver @@ -22,28 +25,28 @@ for Hypercope GmbH Aachen, Germany. along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -Table of contents -================= +.. Table of contents -1. About the driver + 1. About the driver -2. Loading/Unloading the driver + 2. Loading/Unloading the driver -3. Entries in the /proc filesystem + 3. Entries in the /proc filesystem -4. The /proc/net/hysdn/cardconfX file + 4. The /proc/net/hysdn/cardconfX file -5. The /proc/net/hysdn/cardlogX file + 5. The /proc/net/hysdn/cardlogX file -6. Where to get additional info and help + 6. Where to get additional info and help 1. About the driver +=================== - The drivers/isdn/hysdn subdir contains a driver for HYPERCOPEs active + The drivers/isdn/hysdn subdir contains a driver for HYPERCOPEs active PCI isdn cards Champ, Ergo and Metro. To enable support for this cards enable ISDN support in the kernel config and support for HYSDN cards in - the active cards submenu. The driver may only be compiled and used if + the active cards submenu. The driver may only be compiled and used if support for loadable modules and the process filesystem have been enabled. These cards provide two different interfaces to the kernel. Without the @@ -52,22 +55,23 @@ Table of contents handlers for various protocols like ppp and others as well as config info and firmware may be fetched from Hypercopes WWW-Site www.hypercope.de. - With CAPI 2.0 support enabled, the card can also be used as a CAPI 2.0 - compliant devices with either CAPI 2.0 applications + With CAPI 2.0 support enabled, the card can also be used as a CAPI 2.0 + compliant devices with either CAPI 2.0 applications (check isdn4k-utils) or -using the capidrv module- as a regular - isdn4linux device. This is done via the same mechanism as with the + isdn4linux device. This is done via the same mechanism as with the active AVM cards and in fact uses the same module. - + 2. Loading/Unloading the driver +=============================== The module has no command line parameters and auto detects up to 10 cards in the id-range 0-9. If a loaded driver shall be unloaded all open files in the /proc/net/hysdn - subdir need to be closed and all ethernet interfaces allocated by this + subdir need to be closed and all ethernet interfaces allocated by this driver must be shut down. Otherwise the module counter will avoid a module unload. - + If you are using the CAPI 2.0-interface, make sure to load/modprobe the kernelcapi-module first. @@ -76,52 +80,57 @@ Table of contents any avm-specific modules). 3. Entries in the /proc filesystem +================================== - When the module has been loaded it adds the directory hysdn in the - /proc/net tree. This directory contains exactly 2 file entries for each + When the module has been loaded it adds the directory hysdn in the + /proc/net tree. This directory contains exactly 2 file entries for each card. One is called cardconfX and the other cardlogX, where X is the - card id number from 0 to 9. + card id number from 0 to 9. The cards are numbered in the order found in the PCI config data. 4. The /proc/net/hysdn/cardconfX file +===================================== - This file may be read to get by everyone to get info about the cards type, + This file may be read to get by everyone to get info about the cards type, actual state, available features and used resources. The first 3 entries (id, bus and slot) are PCI info fields, the following type field gives the information about the cards type: - 4 -> Ergo card (server card with 2 b-chans) - 5 -> Metro card (server card with 4 or 8 b-chans) - 6 -> Champ card (client card with 2 b-chans) + - 4 -> Ergo card (server card with 2 b-chans) + - 5 -> Metro card (server card with 4 or 8 b-chans) + - 6 -> Champ card (client card with 2 b-chans) The following 3 fields show the hardware assignments for irq, iobase and the dual ported memory (dp-mem). + The fields b-chans and fax-chans announce the available card resources of this types for the user. + The state variable indicates the actual drivers state for this card with the following assignments. - 0 -> card has not been booted since driver load - 1 -> card booting is actually in progess - 2 -> card is in an error state due to a previous boot failure - 3 -> card is booted and active + - 0 -> card has not been booted since driver load + - 1 -> card booting is actually in progess + - 2 -> card is in an error state due to a previous boot failure + - 3 -> card is booted and active And the last field (device) shows the name of the ethernet device assigned to this card. Up to the first successful boot this field only shows a - to tell that no net device has been allocated up to now. Once a net device has been allocated it remains assigned to this card, even if a card is - rebooted and an boot error occurs. + rebooted and an boot error occurs. - Writing to the cardconfX file boots the card or transfers config lines to - the cards firmware. The type of data is automatically detected when the + Writing to the cardconfX file boots the card or transfers config lines to + the cards firmware. The type of data is automatically detected when the first data is written. Only root has write access to this file. The firmware boot files are normally called hyclient.pof for client cards and hyserver.pof for server cards. After successfully writing the boot file, complete config files or single config lines may be copied to this file. - If an error occurs the return value given to the writing process has the + If an error occurs the return value given to the writing process has the following additional codes (decimal): + ==== ============================================ 1000 Another process is currently bootng the card 1001 Invalid firmware header 1002 Boards dual-port RAM test failed @@ -131,34 +140,39 @@ Table of contents 1006 Second boot stage failure 1007 Timeout waiting for card ready during boot 1008 Operation only allowed in booted state - 1009 Config line too long - 1010 Invalid channel number + 1009 Config line too long + 1010 Invalid channel number 1011 Timeout sending config data + ==== ============================================ - Additional info about error reasons may be fetched from the log output. + Additional info about error reasons may be fetched from the log output. 5. The /proc/net/hysdn/cardlogX file - - The cardlogX file entry may be opened multiple for reading by everyone to +==================================== + + The cardlogX file entry may be opened multiple for reading by everyone to get the cards and drivers log data. Card messages always start with the - keyword LOG. All other lines are output from the driver. - The driver log data may be redirected to the syslog by selecting the + keyword LOG. All other lines are output from the driver. + The driver log data may be redirected to the syslog by selecting the appropriate bitmask. The cards log messages will always be send to this interface but never to the syslog. A root user may write a decimal or hex (with 0x) value t this file to select - desired output options. As mentioned above the cards log dat is always + desired output options. As mentioned above the cards log dat is always written to the cardlog file independent of the following options only used to check and debug the driver itself: - For example: - echo "0x34560078" > /proc/net/hysdn/cardlog0 + For example:: + + echo "0x34560078" > /proc/net/hysdn/cardlog0 + to output the hex log mask 34560078 for card 0. - - The written value is regarded as an unsigned 32-Bit value, bit ored for + + The written value is regarded as an unsigned 32-Bit value, bit ored for desired output. The following bits are already assigned: - 0x80000000 All driver log data is alternatively via syslog + ========== ============================================================ + 0x80000000 All driver log data is alternatively via syslog 0x00000001 Log memory allocation errors 0x00000010 Firmware load start and close are logged 0x00000020 Log firmware record parser @@ -171,25 +185,12 @@ Table of contents 0x00100000 Log all open and close actions to /proc/net/hysdn/card files 0x00200000 Log all actions from /proc file entries 0x00010000 Log network interface init and deinit - + ========== ============================================================ + 6. Where to get additional info and help +======================================== - If you have any problems concerning the driver or configuration contact + If you have any problems concerning the driver or configuration contact the Hypercope support team (support@hypercope.de) and or the authors Werner Cornelius (werner@isdn4linux or cornelius@titro.de) or Ulrich Albrecht (ualbrecht@hypercope.de). - - - - - - - - - - - - - - - diff --git a/Documentation/isdn/index.rst b/Documentation/isdn/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..407e74b7837238047d4e94909d0b248343082c2d --- /dev/null +++ b/Documentation/isdn/index.rst @@ -0,0 +1,24 @@ +.. SPDX-License-Identifier: GPL-2.0 + +==== +ISDN +==== + +.. toctree:: + :maxdepth: 2 + + interface_capi + + avmb1 + gigaset + hysdn + m_isdn + + credits + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/isdn/INTERFACE.CAPI b/Documentation/isdn/interface_capi.rst similarity index 75% rename from Documentation/isdn/INTERFACE.CAPI rename to Documentation/isdn/interface_capi.rst index 021aa9cf139d9155b25d96f8de709c2cbf5a2824..01a4b5ade9a4aaf862d87756078ed47c1e6e050d 100644 --- a/Documentation/isdn/INTERFACE.CAPI +++ b/Documentation/isdn/interface_capi.rst @@ -1,7 +1,9 @@ +========================================= Kernel CAPI Interface to Hardware Drivers ------------------------------------------ +========================================= 1. Overview +=========== From the CAPI 2.0 specification: COMMON-ISDN-API (CAPI) is an application programming interface standard used @@ -22,6 +24,7 @@ This standard is freely available from https://www.capi.org. 2. Driver and Device Registration +================================= CAPI drivers optionally register themselves with Kernel CAPI by calling the Kernel CAPI function register_capi_driver() with a pointer to a struct @@ -50,6 +53,7 @@ callback functions by Kernel CAPI. 3. Application Registration and Communication +============================================= Kernel CAPI forwards registration requests from applications (calls to CAPI operation CAPI_REGISTER) to an appropriate hardware driver by calling its @@ -71,23 +75,26 @@ messages for that application may be passed to or from the device anymore. 4. Data Structures +================== 4.1 struct capi_driver +---------------------- This structure describes a Kernel CAPI driver itself. It is used in the register_capi_driver() and unregister_capi_driver() functions, and contains the following non-private fields, all to be set by the driver before calling register_capi_driver(): -char name[32] +``char name[32]`` the name of the driver, as a zero-terminated ASCII string -char revision[32] +``char revision[32]`` the revision number of the driver, as a zero-terminated ASCII string -int (*add_card)(struct capi_driver *driver, capicardparams *data) +``int (*add_card)(struct capi_driver *driver, capicardparams *data)`` a callback function pointer (may be NULL) 4.2 struct capi_ctr +------------------- This structure describes an ISDN device (controller) handled by a Kernel CAPI driver. After registration via the attach_capi_ctr() function it is passed to @@ -96,88 +103,109 @@ identify the controller to operate on. It contains the following non-private fields: -- to be set by the driver before calling attach_capi_ctr(): +to be set by the driver before calling attach_capi_ctr(): +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -struct module *owner +``struct module *owner`` pointer to the driver module owning the device -void *driverdata +``void *driverdata`` an opaque pointer to driver specific data, not touched by Kernel CAPI -char name[32] +``char name[32]`` the name of the controller, as a zero-terminated ASCII string -char *driver_name +``char *driver_name`` the name of the driver, as a zero-terminated ASCII string -int (*load_firmware)(struct capi_ctr *ctrlr, capiloaddata *ldata) +``int (*load_firmware)(struct capi_ctr *ctrlr, capiloaddata *ldata)`` (optional) pointer to a callback function for sending firmware and configuration data to the device + The function may return before the operation has completed. + Completion must be signalled by a call to capi_ctr_ready(). + Return value: 0 on success, error code on error Called in process context. -void (*reset_ctr)(struct capi_ctr *ctrlr) +``void (*reset_ctr)(struct capi_ctr *ctrlr)`` (optional) pointer to a callback function for stopping the device, releasing all registered applications + The function may return before the operation has completed. + Completion must be signalled by a call to capi_ctr_down(). + Called in process context. -void (*register_appl)(struct capi_ctr *ctrlr, u16 applid, - capi_register_params *rparam) -void (*release_appl)(struct capi_ctr *ctrlr, u16 applid) - pointers to callback functions for registration and deregistration of +``void (*register_appl)(struct capi_ctr *ctrlr, u16 applid, capi_register_params *rparam)`` + pointers to callback function for registration of applications with the device + Calls to these functions are serialized by Kernel CAPI so that only one call to any of them is active at any time. -u16 (*send_message)(struct capi_ctr *ctrlr, struct sk_buff *skb) +``void (*release_appl)(struct capi_ctr *ctrlr, u16 applid)`` + pointers to callback functions deregistration of + applications with the device + + Calls to these functions are serialized by Kernel CAPI so that only + one call to any of them is active at any time. + +``u16 (*send_message)(struct capi_ctr *ctrlr, struct sk_buff *skb)`` pointer to a callback function for sending a CAPI message to the device + Return value: CAPI error code + If the method returns 0 (CAPI_NOERROR) the driver has taken ownership of the skb and the caller may no longer access it. If it returns a non-zero (error) value then ownership of the skb returns to the caller who may reuse or free it. + The return value should only be used to signal problems with respect to accepting or queueing the message. Errors occurring during the actual processing of the message should be signaled with an appropriate reply message. + May be called in process or interrupt context. + Calls to this function are not serialized by Kernel CAPI, ie. it must be prepared to be re-entered. -char *(*procinfo)(struct capi_ctr *ctrlr) +``char *(*procinfo)(struct capi_ctr *ctrlr)`` pointer to a callback function returning the entry for the device in the CAPI controller info table, /proc/capi/controller -const struct file_operations *proc_fops +``const struct file_operations *proc_fops`` pointers to callback functions for the device's proc file system entry, /proc/capi/controllers/; pointer to the device's capi_ctr structure is available from struct proc_dir_entry::data which is available from struct inode. -Note: Callback functions except send_message() are never called in interrupt -context. +Note: + Callback functions except send_message() are never called in interrupt + context. -- to be filled in before calling capi_ctr_ready(): +to be filled in before calling capi_ctr_ready(): +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -u8 manu[CAPI_MANUFACTURER_LEN] +``u8 manu[CAPI_MANUFACTURER_LEN]`` value to return for CAPI_GET_MANUFACTURER -capi_version version +``capi_version version`` value to return for CAPI_GET_VERSION -capi_profile profile +``capi_profile profile`` value to return for CAPI_GET_PROFILE -u8 serial[CAPI_SERIAL_LEN] +``u8 serial[CAPI_SERIAL_LEN]`` value to return for CAPI_GET_SERIAL 4.3 SKBs +-------- CAPI messages are passed between Kernel CAPI and the driver via send_message() and capi_ctr_handle_message(), stored in the data portion of a socket buffer @@ -192,6 +220,7 @@ instead of 30. 4.4 The _cmsg Structure +----------------------- (declared in ) @@ -216,6 +245,7 @@ Members are named after the CAPI 2.0 standard names of the parameters they represent. See for the exact spelling. Member data types are: +=========== ================================================================= u8 for CAPI parameters of type 'byte' u16 for CAPI parameters of type 'word' @@ -235,6 +265,7 @@ _cmstruct alternative representation for CAPI parameters of type 'struct' CAPI_COMPOSE: The parameter is present. Subparameter values are stored individually in the corresponding _cmsg structure members. +=========== ================================================================= Functions capi_cmsg2message() and capi_message2cmsg() are provided to convert messages between their transport encoding described in the CAPI 2.0 standard @@ -244,51 +275,71 @@ sure it is big enough to accommodate the resulting CAPI message. 5. Lower Layer Interface Functions +================================== (declared in ) -void register_capi_driver(struct capi_driver *drvr) -void unregister_capi_driver(struct capi_driver *drvr) - register/unregister a driver with Kernel CAPI +:: + + void register_capi_driver(struct capi_driver *drvr) + void unregister_capi_driver(struct capi_driver *drvr) + +register/unregister a driver with Kernel CAPI + +:: + + int attach_capi_ctr(struct capi_ctr *ctrlr) + int detach_capi_ctr(struct capi_ctr *ctrlr) + +register/unregister a device (controller) with Kernel CAPI -int attach_capi_ctr(struct capi_ctr *ctrlr) -int detach_capi_ctr(struct capi_ctr *ctrlr) - register/unregister a device (controller) with Kernel CAPI +:: -void capi_ctr_ready(struct capi_ctr *ctrlr) -void capi_ctr_down(struct capi_ctr *ctrlr) - signal controller ready/not ready + void capi_ctr_ready(struct capi_ctr *ctrlr) + void capi_ctr_down(struct capi_ctr *ctrlr) -void capi_ctr_suspend_output(struct capi_ctr *ctrlr) -void capi_ctr_resume_output(struct capi_ctr *ctrlr) - signal suspend/resume +signal controller ready/not ready -void capi_ctr_handle_message(struct capi_ctr * ctrlr, u16 applid, - struct sk_buff *skb) - pass a received CAPI message to Kernel CAPI - for forwarding to the specified application +:: + + void capi_ctr_suspend_output(struct capi_ctr *ctrlr) + void capi_ctr_resume_output(struct capi_ctr *ctrlr) + +signal suspend/resume + +:: + + void capi_ctr_handle_message(struct capi_ctr * ctrlr, u16 applid, + struct sk_buff *skb) + +pass a received CAPI message to Kernel CAPI +for forwarding to the specified application 6. Helper Functions and Macros +============================== Library functions (from ): -void capilib_new_ncci(struct list_head *head, u16 applid, +:: + + void capilib_new_ncci(struct list_head *head, u16 applid, u32 ncci, u32 winsize) -void capilib_free_ncci(struct list_head *head, u16 applid, u32 ncci) -void capilib_release_appl(struct list_head *head, u16 applid) -void capilib_release(struct list_head *head) -void capilib_data_b3_conf(struct list_head *head, u16 applid, + void capilib_free_ncci(struct list_head *head, u16 applid, u32 ncci) + void capilib_release_appl(struct list_head *head, u16 applid) + void capilib_release(struct list_head *head) + void capilib_data_b3_conf(struct list_head *head, u16 applid, u32 ncci, u16 msgid) -u16 capilib_data_b3_req(struct list_head *head, u16 applid, + u16 capilib_data_b3_req(struct list_head *head, u16 applid, u32 ncci, u16 msgid) Macros to extract/set element values from/in a CAPI message header (from ): +====================== ============================= ==================== Get Macro Set Macro Element (Type) - +====================== ============================= ==================== CAPIMSG_LEN(m) CAPIMSG_SETLEN(m, len) Total Length (u16) CAPIMSG_APPID(m) CAPIMSG_SETAPPID(m, applid) ApplID (u16) CAPIMSG_COMMAND(m) CAPIMSG_SETCOMMAND(m,cmd) Command (u8) @@ -300,31 +351,31 @@ CAPIMSG_MSGID(m) CAPIMSG_SETMSGID(m, msgid) Message Number (u16) CAPIMSG_CONTROL(m) CAPIMSG_SETCONTROL(m, contr) Controller/PLCI/NCCI (u32) CAPIMSG_DATALEN(m) CAPIMSG_SETDATALEN(m, len) Data Length (u16) +====================== ============================= ==================== Library functions for working with _cmsg structures (from ): -unsigned capi_cmsg2message(_cmsg *cmsg, u8 *msg) - Assembles a CAPI 2.0 message from the parameters in *cmsg, storing the - result in *msg. +``unsigned capi_cmsg2message(_cmsg *cmsg, u8 *msg)`` + Assembles a CAPI 2.0 message from the parameters in ``*cmsg``, + storing the result in ``*msg``. -unsigned capi_message2cmsg(_cmsg *cmsg, u8 *msg) - Disassembles the CAPI 2.0 message in *msg, storing the parameters in - *cmsg. +``unsigned capi_message2cmsg(_cmsg *cmsg, u8 *msg)`` + Disassembles the CAPI 2.0 message in ``*msg``, storing the parameters + in ``*cmsg``. -unsigned capi_cmsg_header(_cmsg *cmsg, u16 ApplId, u8 Command, u8 Subcommand, - u16 Messagenumber, u32 Controller) - Fills the header part and address field of the _cmsg structure *cmsg +``unsigned capi_cmsg_header(_cmsg *cmsg, u16 ApplId, u8 Command, u8 Subcommand, u16 Messagenumber, u32 Controller)`` + Fills the header part and address field of the _cmsg structure ``*cmsg`` with the given values, zeroing the remainder of the structure so only parameters with non-default values need to be changed before sending the message. -void capi_cmsg_answer(_cmsg *cmsg) - Sets the low bit of the Subcommand field in *cmsg, thereby converting - _REQ to _CONF and _IND to _RESP. +``void capi_cmsg_answer(_cmsg *cmsg)`` + Sets the low bit of the Subcommand field in ``*cmsg``, thereby + converting ``_REQ`` to ``_CONF`` and ``_IND`` to ``_RESP``. -char *capi_cmd2str(u8 Command, u8 Subcommand) +``char *capi_cmd2str(u8 Command, u8 Subcommand)`` Returns the CAPI 2.0 message name corresponding to the given command and subcommand values, as a static ASCII string. The return value may be NULL if the command/subcommand is not one of those defined in the @@ -332,6 +383,7 @@ char *capi_cmd2str(u8 Command, u8 Subcommand) 7. Debugging +============ The module kernelcapi has a module parameter showcapimsgs controlling some debugging output produced by the module. It can only be set when the module is diff --git a/Documentation/isdn/README.mISDN b/Documentation/isdn/m_isdn.rst similarity index 89% rename from Documentation/isdn/README.mISDN rename to Documentation/isdn/m_isdn.rst index cd8bf920e77bcac0ec8d4068db18441bd28083d5..9957de349e695e2a3ea0cc036f65909172571b3e 100644 --- a/Documentation/isdn/README.mISDN +++ b/Documentation/isdn/m_isdn.rst @@ -1,6 +1,9 @@ +============ +mISDN Driver +============ + mISDN is a new modular ISDN driver, in the long term it should replace the old I4L driver architecture for passiv ISDN cards. It was designed to allow a broad range of applications and interfaces but only have the basic function in kernel, the interface to the user space is based on sockets with a own address family AF_ISDN. - diff --git a/Documentation/kbuild/index.rst b/Documentation/kbuild/index.rst index e323a3f2cc81757a27ed3e8ebd47c4057359f155..0f144fad99a6a482173d887b68567b31a820c0b3 100644 --- a/Documentation/kbuild/index.rst +++ b/Documentation/kbuild/index.rst @@ -18,6 +18,7 @@ Kernel Build System headers_install issues + reproducible-builds .. only:: subproject and html diff --git a/Documentation/kbuild/reproducible-builds.rst b/Documentation/kbuild/reproducible-builds.rst new file mode 100644 index 0000000000000000000000000000000000000000..ab92e98c89c86cfc8bb5ef428167121b5f5290d6 --- /dev/null +++ b/Documentation/kbuild/reproducible-builds.rst @@ -0,0 +1,122 @@ +=================== +Reproducible builds +=================== + +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. This makes it possible to verify that the build +infrastructure for a binary distribution or embedded system has not +been subverted. This can also make it easier to verify that a source +or tool change does not make any difference to the resulting binaries. + +The `Reproducible Builds project`_ has more information about this +general topic. This document covers the various reasons why building +the kernel may be unreproducible, and how to avoid them. + +Timestamps +---------- + +The kernel embeds a timestamp in two places: + +* The version string exposed by ``uname()`` and included in + ``/proc/version`` + +* File timestamps in the embedded initramfs + +By default the timestamp is the current time. This must be overridden +using the `KBUILD_BUILD_TIMESTAMP`_ variable. If you are building +from a git commit, you could use its commit date. + +The kernel does *not* use the ``__DATE__`` and ``__TIME__`` macros, +and enables warnings if they are used. If you incorporate external +code that does use these, you must override the timestamp they +correspond to by setting the `SOURCE_DATE_EPOCH`_ environment +variable. + +User, host +---------- + +The kernel embeds the building user and host names in +``/proc/version``. These must be overridden using the +`KBUILD_BUILD_USER and KBUILD_BUILD_HOST`_ variables. If you are +building from a git commit, you could use its committer address. + +Absolute filenames +------------------ + +When the kernel is built out-of-tree, debug information may include +absolute filenames for the source files. This must be overridden by +including the ``-fdebug-prefix-map`` option in the `KCFLAGS`_ variable. + +Depending on the compiler used, the ``__FILE__`` macro may also expand +to an absolute filename in an out-of-tree build. Kbuild automatically +uses the ``-fmacro-prefix-map`` option to prevent this, if it is +supported. + +The Reproducible Builds web site has more information about these +`prefix-map options`_. + +Generated files in source packages +---------------------------------- + +The build processes for some programs under the ``tools/`` +subdirectory do not completely support out-of-tree builds. This may +cause a later source package build using e.g. ``make rpm-pkg`` to +include generated files. You should ensure the source tree is +pristine by running ``make mrproper`` or ``git clean -d -f -x`` before +building a source package. + +Module signing +-------------- + +If you enable ``CONFIG_MODULE_SIG_ALL``, the default behaviour is to +generate a different temporary key for each build, resulting in the +modules being unreproducible. However, including a signing key with +your source would presumably defeat the purpose of signing modules. + +One approach to this is to divide up the build process so that the +unreproducible parts can be treated as sources: + +1. Generate a persistent signing key. Add the certificate for the key + to the kernel source. + +2. Set the ``CONFIG_SYSTEM_TRUSTED_KEYS`` symbol to include the + signing key's certificate, set ``CONFIG_MODULE_SIG_KEY`` to an + empty string, and disable ``CONFIG_MODULE_SIG_ALL``. + Build the kernel and modules. + +3. Create detached signatures for the modules, and publish them as + sources. + +4. Perform a second build that attaches the module signatures. It + can either rebuild the modules or use the output of step 2. + +Structure randomisation +----------------------- + +If you enable ``CONFIG_GCC_PLUGIN_RANDSTRUCT``, you will need to +pre-generate the random seed in +``scripts/gcc-plgins/randomize_layout_seed.h`` so the same value +is used in rebuilds. + +Debug info conflicts +-------------------- + +This is not a problem of unreproducibility, but of generated files +being *too* reproducible. + +Once you set all the necessary variables for a reproducible build, a +vDSO's debug information may be identical even for different kernel +versions. This can result in file conflicts between debug information +packages for the different kernel versions. + +To avoid this, you can make the vDSO different for different +kernel versions by including an arbitrary string of "salt" in it. +This is specified by the Kconfig symbol ``CONFIG_BUILD_SALT``. + +.. _KBUILD_BUILD_TIMESTAMP: kbuild.html#kbuild-build-timestamp +.. _KBUILD_BUILD_USER and KBUILD_BUILD_HOST: kbuild.html#kbuild-build-user-kbuild-build-host +.. _KCFLAGS: kbuild.html#kcflags +.. _prefix-map options: https://reproducible-builds.org/docs/build-path/ +.. _Reproducible Builds project: https://reproducible-builds.org/ +.. _SOURCE_DATE_EPOCH: https://reproducible-builds.org/docs/source-date-epoch/ diff --git a/Documentation/leds/leds-class.rst b/Documentation/leds/leds-class.rst index df0120a1ee3c0779176ee2290ac0f5fd16436b3d..a0708d3f3d0bafa04019a3c624d3c3b68354640f 100644 --- a/Documentation/leds/leds-class.rst +++ b/Documentation/leds/leds-class.rst @@ -43,9 +43,73 @@ LED Device Naming Is currently of the form: - "devicename:colour:function" - -There have been calls for LED properties such as colour to be exported as + "devicename:color:function" + +- devicename: + it should refer to a unique identifier created by the kernel, + like e.g. phyN for network devices or inputN for input devices, rather + than to the hardware; the information related to the product and the bus + to which given device is hooked is available in sysfs and can be + retrieved using get_led_device_info.sh script from tools/leds; generally + this section is expected mostly for LEDs that are somehow associated with + other devices. + +- color: + one of LED_COLOR_ID_* definitions from the header + include/dt-bindings/leds/common.h. + +- function: + one of LED_FUNCTION_* definitions from the header + include/dt-bindings/leds/common.h. + +If required color or function is missing, please submit a patch +to linux-leds@vger.kernel.org. + +It is possible that more than one LED with the same color and function will +be required for given platform, differing only with an ordinal number. +In this case it is preferable to just concatenate the predefined LED_FUNCTION_* +name with required "-N" suffix in the driver. fwnode based drivers can use +function-enumerator property for that and then the concatenation will be handled +automatically by the LED core upon LED class device registration. + +LED subsystem has also a protection against name clash, that may occur +when LED class device is created by a driver of hot-pluggable device and +it doesn't provide unique devicename section. In this case numerical +suffix (e.g. "_1", "_2", "_3" etc.) is added to the requested LED class +device name. + +There might be still LED class drivers around using vendor or product name +for devicename, but this approach is now deprecated as it doesn't convey +any added value. Product information can be found in other places in sysfs +(see tools/leds/get_led_device_info.sh). + +Examples of proper LED names: + + - "red:disk" + - "white:flash" + - "red:indicator" + - "phy1:green:wlan" + - "phy3::wlan" + - ":kbd_backlight" + - "input5::kbd_backlight" + - "input3::numlock" + - "input3::scrolllock" + - "input3::capslock" + - "mmc1::status" + - "white:status" + +get_led_device_info.sh script can be used for verifying if the LED name +meets the requirements pointed out here. It performs validation of the LED class +devicename sections and gives hints on expected value for a section in case +the validation fails for it. So far the script supports validation +of associations between LEDs and following types of devices: + + - input devices + - ieee80211 compliant USB devices + +The script is open to extensions. + +There have been calls for LED properties such as color to be exported as individual led class attributes. As a solution which doesn't incur as much overhead, I suggest these become part of the device name. The naming scheme above leaves scope for further attributes should they be needed. If sections diff --git a/Documentation/locking/spinlocks.rst b/Documentation/locking/spinlocks.rst index e93ec6645238286fe29bf359b619e193928181a5..66e3792f8a366dba64ce79e9650a19a120ed63d1 100644 --- a/Documentation/locking/spinlocks.rst +++ b/Documentation/locking/spinlocks.rst @@ -139,18 +139,6 @@ on other CPU's, because an interrupt on another CPU doesn't interrupt the CPU that holds the lock, so the lock-holder can continue and eventually releases the lock). -Note that you can be clever with read-write locks and interrupts. For -example, if you know that the interrupt only ever gets a read-lock, then -you can use a non-irq version of read locks everywhere - because they -don't block on each other (and thus there is no dead-lock wrt interrupts. -But when you do the write-lock, you have to use the irq-safe version. - -For an example of being clever with rw-locks, see the "waitqueue_lock" -handling in kernel/sched/core.c - nothing ever _changes_ a wait-queue from -within an interrupt, they only read the queue in order to know whom to -wake up. So read-locks are safe (which is good: they are very common -indeed), while write-locks need to protect themselves against interrupts. - Linus ---- diff --git a/Documentation/m68k/README.buddha b/Documentation/m68k/buddha-driver.rst similarity index 73% rename from Documentation/m68k/README.buddha rename to Documentation/m68k/buddha-driver.rst index 3ea9827ba3c797e51b6d531364f5bfb529f5ed05..20e4014139911dc8b9d788981c10534ca3838db6 100644 --- a/Documentation/m68k/README.buddha +++ b/Documentation/m68k/buddha-driver.rst @@ -1,3 +1,6 @@ +===================================== +Amiga Buddha and Catweasel IDE Driver +===================================== The Amiga Buddha and Catweasel IDE Driver (part of ide.c) was written by Geert Uytterhoeven based on the following specifications: @@ -12,12 +15,12 @@ described in their manuals, no tricks have been used (for example leaving some address lines out of the equations...). If you want to configure the board yourself (for example let a Linux kernel configure the card), look at the Commodore -Docs. Reading the nibbles should give this information: +Docs. Reading the nibbles should give this information:: -Vendor number: 4626 ($1212) -product number: 0 (42 for Catweasel Z-II) -Serial number: 0 -Rom-vector: $1000 + Vendor number: 4626 ($1212) + product number: 0 (42 for Catweasel Z-II) + Serial number: 0 + Rom-vector: $1000 The card should be a Z-II board, size 64K, not for freemem list, Rom-Vektor is valid, no second Autoconfig-board on the @@ -34,6 +37,7 @@ otherwise your chance is only 1:16 to find the board :-). The local memory-map is even active when mapped to $e8: +============== =========================================== $0-$7e Autokonfig-space, see Z-II docs. $80-$7fd reserved @@ -50,50 +54,51 @@ $a00-$aff IDE-Select 2 (Port 1, Register set 0) $b00-$bff IDE-Select 3 (Port 1, Register set 1) $c00-$cff IDE-Select 4 (Port 2, Register set 0, - Catweasel only!) + Catweasel only!) $d00-$dff IDE-Select 5 (Port 3, Register set 1, - Catweasel only!) + Catweasel only!) -$e00-$eff local expansion port, on Catweasel Z-II the +$e00-$eff local expansion port, on Catweasel Z-II the Catweasel registers are also mapped here. Never touch, use multidisk.device! - -$f00 read only, Byte-access: Bit 7 shows the - level of the IRQ-line of IDE port 0. + +$f00 read only, Byte-access: Bit 7 shows the + level of the IRQ-line of IDE port 0. $f01-$f3f mirror of $f00 -$f40 read only, Byte-access: Bit 7 shows the - level of the IRQ-line of IDE port 1. +$f40 read only, Byte-access: Bit 7 shows the + level of the IRQ-line of IDE port 1. $f41-$f7f mirror of $f40 -$f80 read only, Byte-access: Bit 7 shows the - level of the IRQ-line of IDE port 2. +$f80 read only, Byte-access: Bit 7 shows the + level of the IRQ-line of IDE port 2. (Catweasel only!) $f81-$fbf mirror of $f80 $fc0 write-only: Writing any value to this - register enables IRQs to be passed from the - IDE ports to the Zorro bus. This mechanism - has been implemented to be compatible with + register enables IRQs to be passed from the + IDE ports to the Zorro bus. This mechanism + has been implemented to be compatible with harddisks that are either defective or have - a buggy firmware and pull the IRQ line up - while starting up. If interrupts would - always be passed to the bus, the computer - might not start up. Once enabled, this flag - can not be disabled again. The level of the - flag can not be determined by software + a buggy firmware and pull the IRQ line up + while starting up. If interrupts would + always be passed to the bus, the computer + might not start up. Once enabled, this flag + can not be disabled again. The level of the + flag can not be determined by software (what for? Write to me if it's necessary!). $fc1-$fff mirror of $fc0 $1000-$ffff Buddha-Rom with offset $1000 in the rom - chip. The addresses $0 to $fff of the rom + chip. The addresses $0 to $fff of the rom chip cannot be read. Rom is Byte-wide and mapped to even addresses. +============== =========================================== The IDE ports issue an INT2. You can read the level of the IRQ-lines of the IDE-ports by reading from the three (two @@ -128,7 +133,8 @@ must always be set to 1 to be compatible with later Buddha versions (if I'll ever update this one). I presume that I'll never use the lower four bits, but they have to be set to 1 by definition. - The values in this table have to be shifted 5 bits to the + +The values in this table have to be shifted 5 bits to the left and or'd with $1f (this sets the lower 5 bits). All the timings have in common: Select and IOR/IOW rise at @@ -138,44 +144,36 @@ values are no multiple of 71. One clock-cycle is 71ns long (exactly 70,5 at 14,18 Mhz on PAL systems). value 0 (Default after reset) - -497ns Select (7 clock cycles) , IOR/IOW after 172ns (2 clock cycles) -(same timing as the Amiga 1200 does on it's IDE port without -accelerator card) + 497ns Select (7 clock cycles) , IOR/IOW after 172ns (2 clock cycles) + (same timing as the Amiga 1200 does on it's IDE port without + accelerator card) value 1 - -639ns Select (9 clock cycles), IOR/IOW after 243ns (3 clock cycles) + 639ns Select (9 clock cycles), IOR/IOW after 243ns (3 clock cycles) value 2 - -781ns Select (11 clock cycles), IOR/IOW after 314ns (4 clock cycles) + 781ns Select (11 clock cycles), IOR/IOW after 314ns (4 clock cycles) value 3 - -355ns Select (5 clock cycles), IOR/IOW after 101ns (1 clock cycle) + 355ns Select (5 clock cycles), IOR/IOW after 101ns (1 clock cycle) value 4 - -355ns Select (5 clock cycles), IOR/IOW after 172ns (2 clock cycles) + 355ns Select (5 clock cycles), IOR/IOW after 172ns (2 clock cycles) value 5 - -355ns Select (5 clock cycles), IOR/IOW after 243ns (3 clock cycles) + 355ns Select (5 clock cycles), IOR/IOW after 243ns (3 clock cycles) value 6 - -1065ns Select (15 clock cycles), IOR/IOW after 314ns (4 clock cycles) + 1065ns Select (15 clock cycles), IOR/IOW after 314ns (4 clock cycles) value 7 - -355ns Select, (5 clock cycles), IOR/IOW after 101ns (1 clock cycle) + 355ns Select, (5 clock cycles), IOR/IOW after 101ns (1 clock cycle) When accessing IDE registers with A6=1 (for example $84x), the timing will always be mode 0 8-bit compatible, no matter what you have selected in the speed register: -781ns select, IOR/IOW after 4 clock cycles (=314ns) aktive. +781ns select, IOR/IOW after 4 clock cycles (=314ns) aktive. All the timings with a very short select-signal (the 355ns fast accesses) depend on the accelerator card used in the @@ -204,7 +202,8 @@ always shows a "no IRQ here" on the Buddha, and accesses to the third IDE port are going into data's Nirwana on the Buddha. - Jens Schönfeld february 19th, 1997 - updated may 27th, 1997 - eMail: sysop@nostlgic.tng.oche.de +Jens Schönfeld february 19th, 1997 + +updated may 27th, 1997 +eMail: sysop@nostlgic.tng.oche.de diff --git a/Documentation/m68k/index.rst b/Documentation/m68k/index.rst index 3a5ba7fe1703dd452e875ae1e9c751159654a716..b89cb6a86d9bef551735d93b9c7972641f6fa3a6 100644 --- a/Documentation/m68k/index.rst +++ b/Documentation/m68k/index.rst @@ -8,6 +8,7 @@ m68k Architecture :maxdepth: 2 kernel-options + buddha-driver .. only:: subproject and html diff --git a/Documentation/maintainer/pull-requests.rst b/Documentation/maintainer/pull-requests.rst index 22b271de030474c1dbbcadd7cfdef88b95a5766e..1a2f99b67d25ad101f4bdc24e94cc4ff500ec7df 100644 --- a/Documentation/maintainer/pull-requests.rst +++ b/Documentation/maintainer/pull-requests.rst @@ -29,7 +29,7 @@ request to. In order to create the pull request you must first tag the branch that you have just created. It is recommended that you choose a meaningful tag name, in a way that you and others can understand, even after some time. A good -practice is to include in the name an indicator of the sybsystem of origin +practice is to include in the name an indicator of the subsystem of origin and the target kernel version. Greg offers the following. A pull request with miscellaneous stuff for diff --git a/Documentation/media/kapi/csi2.rst b/Documentation/media/kapi/csi2.rst index a7e75e2eba85a1cbd2e405d678c5ee8685aa8575..030a5c41ec75c48bb1c5ae5a113a798bc77b6d04 100644 --- a/Documentation/media/kapi/csi2.rst +++ b/Documentation/media/kapi/csi2.rst @@ -49,9 +49,13 @@ where The transmitter drivers must, if possible, configure the CSI-2 transmitter to *LP-11 mode* whenever the transmitter is powered on but -not active. Some transmitters do this automatically but some have to -be explicitly programmed to do so, and some are unable to do so -altogether due to hardware constraints. +not active, and maintain *LP-11 mode* until stream on. Only at stream +on should the transmitter activate the clock on the clock lane and +transition to *HS mode*. + +Some transmitters do this automatically but some have to be explicitly +programmed to do so, and some are unable to do so altogether due to +hardware constraints. Stopping the transmitter ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,3 +76,10 @@ the transmitter up by using the :c:type:`v4l2_subdev_core_ops`->s_power() callback. This may take place either indirectly by using :c:func:`v4l2_pipeline_pm_use` or directly. + +Formats +------- + +The media bus pixel codes document parallel formats. Should the pixel data be +transported over a serial bus, the media bus pixel code that describes a +parallel format that transfers a sample on a single clock cycle is used. diff --git a/Documentation/media/kapi/v4l2-dev.rst b/Documentation/media/kapi/v4l2-dev.rst index b359f1804bbe26674ed274f98a65eb751384ac32..4c5a15c53dbfb01872d63ce5bd9126de0049a9b5 100644 --- a/Documentation/media/kapi/v4l2-dev.rst +++ b/Documentation/media/kapi/v4l2-dev.rst @@ -288,6 +288,7 @@ Mask Description 0x08 Log the read and write file operations and the VIDIOC_QBUF and VIDIOC_DQBUF ioctls. 0x10 Log the poll file operation. +0x20 Log error and messages in the control operations. ===== ================================================================ Video device cleanup diff --git a/Documentation/media/uapi/rc/lirc-dev-intro.rst b/Documentation/media/uapi/rc/lirc-dev-intro.rst index 1a901d8e1797c764d312749f5828ee32bb23c5f6..b68c01693939a6348b3935cc283ef282794f1c22 100644 --- a/Documentation/media/uapi/rc/lirc-dev-intro.rst +++ b/Documentation/media/uapi/rc/lirc-dev-intro.rst @@ -20,6 +20,9 @@ data between userspace and kernelspace. Fundamentally, it is just a chardev file_operations defined on it. With respect to transporting raw IR and decoded scancodes to and fro, the essential fops are read, write and ioctl. +It is also possible to attach a BPF program to a LIRC device for decoding +raw IR into scancodes. + Example dmesg output upon a driver registering w/LIRC: .. code-block:: none @@ -34,6 +37,16 @@ What you should see for a chardev: $ ls -l /dev/lirc* crw-rw---- 1 root root 248, 0 Jul 2 22:20 /dev/lirc0 +Note that the package `v4l-utils `_ +contains tools for working with LIRC devices: + + - ir-ctl: can receive raw IR and transmit IR, as well as query LIRC + device features. + + - ir-keytable: can load keymaps; allows you to set IR kernel protocols; load + BPF IR decoders and test IR decoding. Some BPF IR decoders are also + provided. + .. _lirc_modes: ********** @@ -53,11 +66,12 @@ on the following table. For transmitting (aka sending), create a ``struct lirc_scancode`` with the desired scancode set in the ``scancode`` member, :c:type:`rc_proto` - set the IR protocol, and all other members set to 0. Write this struct to - the lirc device. + set to the :ref:`IR protocol `, and all other + members set to 0. Write this struct to the lirc device. - For receiving, you read ``struct lirc_scancode`` from the lirc device, - with ``scancode`` set to the received scancode and the IR protocol + For receiving, you read ``struct lirc_scancode`` from the LIRC device. + The ``scancode`` field is set to the received scancode and the + :ref:`IR protocol ` is set in :c:type:`rc_proto`. If the scancode maps to a valid key code, this is set in the ``keycode`` field, else it is set to ``KEY_RESERVED``. @@ -129,12 +143,29 @@ on the following table. This mode is used only for IR send. - -************************** -Remote Controller protocol -************************** - -An enum :c:type:`rc_proto` in the :ref:`lirc_header` lists all the -supported IR protocols: - -.. kernel-doc:: include/uapi/linux/lirc.h +******************** +BPF based IR decoder +******************** + +The kernel has support for decoding the most common +:ref:`IR protocols `, but there +are many protocols which are not supported. To support these, it is possible +to load an BPF program which does the decoding. This can only be done on +LIRC devices which support reading raw IR. + +First, using the `bpf(2)`_ syscall with the ``BPF_LOAD_PROG`` argument, +program must be loaded of type ``BPF_PROG_TYPE_LIRC_MODE2``. Once attached +to the LIRC device, this program will be called for each pulse, space or +timeout event on the LIRC device. The context for the BPF program is a +pointer to a unsigned int, which is a :ref:`LIRC_MODE_MODE2 ` +value. When the program has decoded the scancode, it can be submitted using +the BPF functions ``bpf_rc_keydown()`` or ``bpf_rc_repeat()``. Mouse or pointer +movements can be reported using ``bpf_rc_pointer_rel()``. + +Once you have the file descriptor for the ``BPF_PROG_TYPE_LIRC_MODE2`` BPF +program, it can be attached to the LIRC device using the `bpf(2)`_ syscall. +The target must be the file descriptor for the LIRC device, and the +attach type must be ``BPF_LIRC_MODE2``. No more than 64 BPF programs can be +attached to a single LIRC device at a time. + +.. _bpf(2): http://man7.org/linux/man-pages/man2/bpf.2.html diff --git a/Documentation/media/uapi/rc/lirc-read.rst b/Documentation/media/uapi/rc/lirc-read.rst index a8fedfaaf0ab303b5b5fc45945716c0a0b2da3b4..256e520bc27ee306022ce9e9ef98c867928796f7 100644 --- a/Documentation/media/uapi/rc/lirc-read.rst +++ b/Documentation/media/uapi/rc/lirc-read.rst @@ -62,7 +62,8 @@ read from the chardev. Alternatively, :ref:`LIRC_MODE_SCANCODE ` can be available, in this mode scancodes which are either decoded by software decoders, or by hardware decoders. The :c:type:`rc_proto` member is set to the -protocol used for transmission, and ``scancode`` to the decoded scancode, +:ref:`IR protocol ` +used for transmission, and ``scancode`` to the decoded scancode, and the ``keycode`` set to the keycode or ``KEY_RESERVED``. diff --git a/Documentation/media/uapi/rc/lirc-write.rst b/Documentation/media/uapi/rc/lirc-write.rst index 6adf5ddbac9948c844962fb8e555e99c44b1f83b..eafe13203ea35e2772c06b7623f67d01864a0f86 100644 --- a/Documentation/media/uapi/rc/lirc-write.rst +++ b/Documentation/media/uapi/rc/lirc-write.rst @@ -64,7 +64,8 @@ driver returns ``EINVAL``. When in :ref:`LIRC_MODE_SCANCODE ` mode, one ``struct lirc_scancode`` must be written to the chardev at a time, else ``EINVAL`` is returned. Set the desired scancode in the ``scancode`` member, -and the protocol in the :c:type:`rc_proto`: member. All other members must be +and the :ref:`IR protocol ` in the +:c:type:`rc_proto`: member. All other members must be set to 0, else ``EINVAL`` is returned. If there is no protocol encoder for the protocol or the scancode is not valid for the specified protocol, ``EINVAL`` is returned. The write function blocks until the scancode diff --git a/Documentation/media/uapi/rc/rc-protos.rst b/Documentation/media/uapi/rc/rc-protos.rst new file mode 100644 index 0000000000000000000000000000000000000000..b250ebe301d555b208b806b2a5c2a8c541e08bc9 --- /dev/null +++ b/Documentation/media/uapi/rc/rc-protos.rst @@ -0,0 +1,456 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. +.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections + +.. _Remote_controllers_Protocols: + +***************************************** +Remote Controller Protocols and Scancodes +***************************************** + +IR is encoded as a series of pulses and spaces, using a protocol. These +protocols can encode e.g. an address (which device should respond) and a +command: what it should do. The values for these are not always consistent +across different devices for a given protocol. + +Therefore out the output of the IR decoder is a scancode; a single u32 +value. Using keymap tables this can be mapped to linux key codes. + +Other things can be encoded too. Some IR protocols encode a toggle bit; this +is to distinguish whether the same button is being held down, or has been +released and pressed again. If has been released and pressed again, the +toggle bit will invert from one IR message to the next. + +Some remotes have a pointer-type device which can used to control the +mouse; some air conditioning systems can have their target temperature +target set in IR. + +The following are the protocols the kernel knows about and also lists +how scancodes are encoded for each protocol. + +rc-5 (RC_PROTO_RC5) +------------------- + +This IR protocol uses manchester encoding to encode 14 bits. There is a +detailed description here https://www.sbprojects.net/knowledge/ir/rc5.php. + +The scancode encoding is *not* consistent with the lirc daemon (lircd) rc5 +protocol, or the manchester BPF decoder. + +.. flat-table:: rc5 bits scancode mapping + :widths: 1 1 2 + + * - rc-5 bit + + - scancode bit + + - description + + * - 1 + + - none + + - Start bit, always set + + * - 1 + + - 6 (inverted) + + - 2nd start bit in rc5, re-used as 6th command bit + + * - 1 + + - none + + - Toggle bit + + * - 5 + + - 8 to 13 + + - Address + + * - 6 + + - 0 to 5 + + - Command + +There is a variant of rc5 called either rc5x or extended rc5 +where there the second stop bit is the 6th commmand bit, but inverted. +This is done so it the scancodes and encoding is compatible with existing +schemes. This bit is stored in bit 6 of the scancode, inverted. This is +done to keep it compatible with plain rc-5 where there are two start bits. + +rc-5-sz (RC_PROTO_RC5_SZ) +------------------------- +This is much like rc-5 but one bit longer. The scancode is encoded +differently. + +.. flat-table:: rc-5-sz bits scancode mapping + :widths: 1 1 2 + + * - rc-5-sz bits + + - scancode bit + + - description + + * - 1 + + - none + + - Start bit, always set + + * - 1 + + - 13 + + - Address bit + + * - 1 + + - none + + - Toggle bit + + * - 6 + + - 6 to 11 + + - Address + + * - 6 + + - 0 to 5 + + - Command + +rc-5x-20 (RC_PROTO_RC5X_20) +--------------------------- + +This rc-5 extended to encoded 20 bits. The is a 3555 microseconds space +after the 8th bit. + +.. flat-table:: rc-5x-20 bits scancode mapping + :widths: 1 1 2 + + * - rc-5-sz bits + + - scancode bit + + - description + + * - 1 + + - none + + - Start bit, always set + + * - 1 + + - 14 + + - Address bit + + * - 1 + + - none + + - Toggle bit + + * - 5 + + - 16 to 20 + + - Address + + * - 6 + + - 8 to 13 + + - Address + + * - 6 + + - 0 to 5 + + - Command + + +jvc (RC_PROTO_JVC) +------------------ + +The jvc protocol is much like nec, without the inverted values. It is +described here https://www.sbprojects.net/knowledge/ir/jvc.php. + +The scancode is a 16 bits value, where the address is the lower 8 bits +and the command the higher 8 bits; this is reversed from IR order. + +sony-12 (RC_PROTO_SONY12) +------------------------- + +The sony protocol is a pulse-width encoding. There are three variants, +which just differ in number of bits and scancode encoding. + +.. flat-table:: sony-12 bits scancode mapping + :widths: 1 1 2 + + * - sony-12 bits + + - scancode bit + + - description + + * - 5 + + - 16 to 20 + + - device + + * - 7 + + - 0 to 6 + + - function + +sony-15 (RC_PROTO_SONY15) +------------------------- + +The sony protocol is a pulse-width encoding. There are three variants, +which just differ in number of bits and scancode encoding. + +.. flat-table:: sony-12 bits scancode mapping + :widths: 1 1 2 + + * - sony-12 bits + + - scancode bit + + - description + + * - 8 + + - 16 to 23 + + - device + + * - 7 + + - 0 to 6 + + - function + +sony-20 (RC_PROTO_SONY20) +------------------------- + +The sony protocol is a pulse-width encoding. There are three variants, +which just differ in number of bits and scancode encoding. + +.. flat-table:: sony-20 bits scancode mapping + :widths: 1 1 2 + + * - sony-20 bits + + - scancode bit + + - description + + * - 5 + + - 16 to 20 + + - device + + * - 7 + + - 0 to 7 + + - device + + * - 8 + + - 8 to 15 + + - extended bits + +nec (RC_PROTO_NEC) +------------------ + +The nec protocol encodes an 8 bit address and an 8 bit command. It is +described here https://www.sbprojects.net/knowledge/ir/nec.php. Note +that the protocol sends least significant bit first. + +As a check, the nec protocol sends the address and command twice; the +second time it is inverted. This is done for verification. + +A plain nec IR message has 16 bits; the high 8 bits are the address +and the low 8 bits are the command. + +nec-x (RC_PROTO_NECX) +--------------------- + +Extended nec has a 16 bit address and a 8 bit command. This is encoded +as a 24 bit value as you would expect, with the lower 8 bits the command +and the upper 16 bits the address. + +nec-32 (RC_PROTO_NEC32) +----------------------- + +nec-32 does not send an inverted address or an inverted command; the +entire message, all 32 bits, are used. + +For this to be decoded correctly, the second 8 bits must not be the +inverted value of the first, and also the last 8 bits must not be the +inverted value of the third 8 bit value. + +The scancode has a somewhat unusual encoding. + +.. flat-table:: nec-32 bits scancode mapping + + * - nec-32 bits + + - scancode bit + + * - First 8 bits + + - 16 to 23 + + * - Second 8 bits + + - 24 to 31 + + * - Third 8 bits + + - 0 to 7 + + * - Fourth 8 bits + + - 8 to 15 + +sanyo (RC_PROTO_SANYO) +---------------------- + +The sanyo protocol is like the nec protocol, but with 13 bits address +rather than 8 bits. Both the address and the command are followed by +their inverted versions, but these are not present in the scancodes. + +Bis 8 to 20 of the scancode is the 13 bits address, and the lower 8 +bits are the command. + +mcir2-kbd (RC_PROTO_MCIR2_KBD) +------------------------------ + +This protocol is generated by the Microsoft MCE keyboard for keyboard +events. Refer to the ir-mce_kbd-decoder.c to see how it is encoded. + +mcir2-mse (RC_PROTO_MCIR2_MSE) +------------------------------ + +This protocol is generated by the Microsoft MCE keyboard for pointer +events. Refer to the ir-mce_kbd-decoder.c to see how it is encoded. + +rc-6-0 (RC_PROTO_RC6_0) +----------------------- + +This is the rc-6 in mode 0. rc-6 is described here +https://www.sbprojects.net/knowledge/ir/rc6.php. +The scancode is the exact 16 bits as in the protocol. There is also a +toggle bit. + +rc-6-6a-20 (RC_PROTO_RC6_6A_20) +------------------------------- + +This is the rc-6 in mode 6a, 20 bits. rc-6 is described here +https://www.sbprojects.net/knowledge/ir/rc6.php. +The scancode is the exact 20 bits +as in the protocol. There is also a toggle bit. + +rc-6-6a-24 (RC_PROTO_RC6_6A_24) +------------------------------- + +This is the rc-6 in mode 6a, 24 bits. rc-6 is described here +https://www.sbprojects.net/knowledge/ir/rc6.php. +The scancode is the exact 24 bits +as in the protocol. There is also a toggle bit. + +rc-6-6a-32 (RC_PROTO_RC6_6A_32) +------------------------------- + +This is the rc-6 in mode 6a, 32 bits. rc-6 is described here +https://www.sbprojects.net/knowledge/ir/rc6.php. +The upper 16 bits are the vendor, +and the lower 16 bits are the vendor-specific bits. This protocol is +for the non-Microsoft MCE variant (vendor != 0x800f). + + +rc-6-mce (RC_PROTO_RC6_MCE) +--------------------------- + +This is the rc-6 in mode 6a, 32 bits. The upper 16 bits are the vendor, +and the lower 16 bits are the vendor-specific bits. This protocol is +for the Microsoft MCE variant (vendor = 0x800f). The toggle bit in the +protocol itself is ignored, and the 16th bit should be takes as the toggle +bit. + +sharp (RC_PROTO_SHARP) +---------------------- + +This is a protocol used by Sharp VCRs, is described here +https://www.sbprojects.net/knowledge/ir/sharp.php. There is a very long +(40ms) space between the normal and inverted values, and some IR receivers +cannot decode this. + +There is a 5 bit address and a 8 bit command. In the scancode the address is +in bits 8 to 12, and the command in bits 0 to 7. + +xmp (RC_PROTO_XMP) +------------------ + +This protocol has several versions and only version 1 is supported. Refer +to the decoder (ir-xmp-decoder.c) to see how it is encoded. + + +cec (RC_PROTO_CEC) +------------------ + +This is not an IR protocol, this is a protocol over CEC. The CEC +infrastructure uses rc-core for handling CEC commands, so that they +can easily be remapped. + +imon (RC_PROTO_IMON) +-------------------- + +This protocol is used by Antec Veris/SoundGraph iMON remotes. + +The protocol +describes both button presses and pointer movements. The protocol encodes +31 bits, and the scancode is simply the 31 bits with the top bit always 0. + +rc-mm-12 (RC_PROTO_RCMM12) +-------------------------- + +The rc-mm protocol is described here +https://www.sbprojects.net/knowledge/ir/rcmm.php. The scancode is simply +the 12 bits. + +rc-mm-24 (RC_PROTO_RCMM24) +-------------------------- + +The rc-mm protocol is described here +https://www.sbprojects.net/knowledge/ir/rcmm.php. The scancode is simply +the 24 bits. + +rc-mm-32 (RC_PROTO_RCMM32) +-------------------------- + +The rc-mm protocol is described here +https://www.sbprojects.net/knowledge/ir/rcmm.php. The scancode is simply +the 32 bits. + +xbox-dvd (RC_PROTO_XBOX_DVD) +---------------------------- + +This protocol is used by XBox DVD Remote, which was made for the original +XBox. There is no in-kernel decoder or encoder for this protocol. The usb +device decodes the protocol. There is a BPF decoder available in v4l-utils. diff --git a/Documentation/media/uapi/rc/remote_controllers.rst b/Documentation/media/uapi/rc/remote_controllers.rst index 3051f7abe11d3ca1f9422a1d3f45df0709f91d04..20e0f986df49ce2ab136bfaf07db62489dcb7b27 100644 --- a/Documentation/media/uapi/rc/remote_controllers.rst +++ b/Documentation/media/uapi/rc/remote_controllers.rst @@ -27,6 +27,7 @@ Part III - Remote Controller API rc-intro rc-sysfs-nodes + rc-protos rc-tables rc-table-change lirc-dev diff --git a/Documentation/media/uapi/v4l/biblio.rst b/Documentation/media/uapi/v4l/biblio.rst index 8f4eb8823d826b1897a44ba6b07dd24be7c4608f..ad2ff258afa89cd7e5ee3ec84027c2feac3e3069 100644 --- a/Documentation/media/uapi/v4l/biblio.rst +++ b/Documentation/media/uapi/v4l/biblio.rst @@ -395,3 +395,13 @@ colimg :title: Color Imaging: Fundamentals and Applications :author: Erik Reinhard et al. + +.. _vp8: + +VP8 +=== + + +:title: RFC 6386: "VP8 Data Format and Decoding Guide" + +:author: J. Bankoski et al. diff --git a/Documentation/media/uapi/v4l/control.rst b/Documentation/media/uapi/v4l/control.rst index 71417bba028c658a4c01bdb7105cdc6005a73ee3..ef62e088ff7ae63af8a822a4ce4f16c95fa72479 100644 --- a/Documentation/media/uapi/v4l/control.rst +++ b/Documentation/media/uapi/v4l/control.rst @@ -295,7 +295,7 @@ Control IDs Sets the alpha color component. When a capture device (or capture queue of a mem-to-mem device) produces a frame format that includes an alpha component (e.g. - :ref:`packed RGB image formats `) and the alpha value + :ref:`packed RGB image formats `) and the alpha value is not defined by the device or the mem-to-mem input data this control lets you select the alpha component value of all pixels. When an output device (or output queue of a mem-to-mem device) diff --git a/Documentation/media/uapi/v4l/dev-decoder.rst b/Documentation/media/uapi/v4l/dev-decoder.rst new file mode 100644 index 0000000000000000000000000000000000000000..606b54947e10b8df6cd2045d777e5be8fa3b3544 --- /dev/null +++ b/Documentation/media/uapi/v4l/dev-decoder.rst @@ -0,0 +1,1101 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. _decoder: + +************************************************* +Memory-to-Memory Stateful Video Decoder Interface +************************************************* + +A stateful video decoder takes complete chunks of the bytestream (e.g. Annex-B +H.264/HEVC stream, raw VP8/9 stream) and decodes them into raw video frames in +display order. The decoder is expected not to require any additional information +from the client to process these buffers. + +Performing software parsing, processing etc. of the stream in the driver in +order to support this interface is strongly discouraged. In case such +operations are needed, use of the Stateless Video Decoder Interface (in +development) is strongly advised. + +Conventions and Notations Used in This Document +=============================================== + +1. The general V4L2 API rules apply if not specified in this document + otherwise. + +2. The meaning of words "must", "may", "should", etc. is as per `RFC + 2119 `_. + +3. All steps not marked "optional" are required. + +4. :c:func:`VIDIOC_G_EXT_CTRLS` and :c:func:`VIDIOC_S_EXT_CTRLS` may be used + interchangeably with :c:func:`VIDIOC_G_CTRL` and :c:func:`VIDIOC_S_CTRL`, + unless specified otherwise. + +5. Single-planar API (see :ref:`planar-apis`) and applicable structures may be + used interchangeably with multi-planar API, unless specified otherwise, + depending on decoder capabilities and following the general V4L2 guidelines. + +6. i = [a..b]: sequence of integers from a to b, inclusive, i.e. i = + [0..2]: i = 0, 1, 2. + +7. Given an ``OUTPUT`` buffer A, then A’ represents a buffer on the ``CAPTURE`` + queue containing data that resulted from processing buffer A. + +.. _decoder-glossary: + +Glossary +======== + +CAPTURE + the destination buffer queue; for decoders, the queue of buffers containing + decoded frames; for encoders, the queue of buffers containing an encoded + bytestream; ``V4L2_BUF_TYPE_VIDEO_CAPTURE`` or + ``V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE``; data is captured from the hardware + into ``CAPTURE`` buffers. + +client + the application communicating with the decoder or encoder implementing + this interface. + +coded format + encoded/compressed video bytestream format (e.g. H.264, VP8, etc.); see + also: raw format. + +coded height + height for given coded resolution. + +coded resolution + stream resolution in pixels aligned to codec and hardware requirements; + typically visible resolution rounded up to full macroblocks; + see also: visible resolution. + +coded width + width for given coded resolution. + +decode order + the order in which frames are decoded; may differ from display order if the + coded format includes a feature of frame reordering; for decoders, + ``OUTPUT`` buffers must be queued by the client in decode order; for + encoders ``CAPTURE`` buffers must be returned by the encoder in decode order. + +destination + data resulting from the decode process; see ``CAPTURE``. + +display order + the order in which frames must be displayed; for encoders, ``OUTPUT`` + buffers must be queued by the client in display order; for decoders, + ``CAPTURE`` buffers must be returned by the decoder in display order. + +DPB + Decoded Picture Buffer; an H.264/HEVC term for a buffer that stores a decoded + raw frame available for reference in further decoding steps. + +EOS + end of stream. + +IDR + Instantaneous Decoder Refresh; a type of a keyframe in an H.264/HEVC-encoded + stream, which clears the list of earlier reference frames (DPBs). + +keyframe + an encoded frame that does not reference frames decoded earlier, i.e. + can be decoded fully on its own. + +macroblock + a processing unit in image and video compression formats based on linear + block transforms (e.g. H.264, VP8, VP9); codec-specific, but for most of + popular codecs the size is 16x16 samples (pixels). + +OUTPUT + the source buffer queue; for decoders, the queue of buffers containing + an encoded bytestream; for encoders, the queue of buffers containing raw + frames; ``V4L2_BUF_TYPE_VIDEO_OUTPUT`` or + ``V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE``; the hardware is fed with data + from ``OUTPUT`` buffers. + +PPS + Picture Parameter Set; a type of metadata entity in an H.264/HEVC bytestream. + +raw format + uncompressed format containing raw pixel data (e.g. YUV, RGB formats). + +resume point + a point in the bytestream from which decoding may start/continue, without + any previous state/data present, e.g.: a keyframe (VP8/VP9) or + SPS/PPS/IDR sequence (H.264/HEVC); a resume point is required to start decode + of a new stream, or to resume decoding after a seek. + +source + data fed to the decoder or encoder; see ``OUTPUT``. + +source height + height in pixels for given source resolution; relevant to encoders only. + +source resolution + resolution in pixels of source frames being source to the encoder and + subject to further cropping to the bounds of visible resolution; relevant to + encoders only. + +source width + width in pixels for given source resolution; relevant to encoders only. + +SPS + Sequence Parameter Set; a type of metadata entity in an H.264/HEVC bytestream. + +stream metadata + additional (non-visual) information contained inside encoded bytestream; + for example: coded resolution, visible resolution, codec profile. + +visible height + height for given visible resolution; display height. + +visible resolution + stream resolution of the visible picture, in pixels, to be used for + display purposes; must be smaller or equal to coded resolution; + display resolution. + +visible width + width for given visible resolution; display width. + +State Machine +============= + +.. kernel-render:: DOT + :alt: DOT digraph of decoder state machine + :caption: Decoder State Machine + + digraph decoder_state_machine { + node [shape = doublecircle, label="Decoding"] Decoding; + + node [shape = circle, label="Initialization"] Initialization; + node [shape = circle, label="Capture\nsetup"] CaptureSetup; + node [shape = circle, label="Dynamic\nResolution\nChange"] ResChange; + node [shape = circle, label="Stopped"] Stopped; + node [shape = circle, label="Drain"] Drain; + node [shape = circle, label="Seek"] Seek; + node [shape = circle, label="End of Stream"] EoS; + + node [shape = point]; qi + qi -> Initialization [ label = "open()" ]; + + Initialization -> CaptureSetup [ label = "CAPTURE\nformat\nestablished" ]; + + CaptureSetup -> Stopped [ label = "CAPTURE\nbuffers\nready" ]; + + Decoding -> ResChange [ label = "Stream\nresolution\nchange" ]; + Decoding -> Drain [ label = "V4L2_DEC_CMD_STOP" ]; + Decoding -> EoS [ label = "EoS mark\nin the stream" ]; + Decoding -> Seek [ label = "VIDIOC_STREAMOFF(OUTPUT)" ]; + Decoding -> Stopped [ label = "VIDIOC_STREAMOFF(CAPTURE)" ]; + Decoding -> Decoding; + + ResChange -> CaptureSetup [ label = "CAPTURE\nformat\nestablished" ]; + ResChange -> Seek [ label = "VIDIOC_STREAMOFF(OUTPUT)" ]; + + EoS -> Drain [ label = "Implicit\ndrain" ]; + + Drain -> Stopped [ label = "All CAPTURE\nbuffers dequeued\nor\nVIDIOC_STREAMOFF(CAPTURE)" ]; + Drain -> Seek [ label = "VIDIOC_STREAMOFF(OUTPUT)" ]; + + Seek -> Decoding [ label = "VIDIOC_STREAMON(OUTPUT)" ]; + Seek -> Initialization [ label = "VIDIOC_REQBUFS(OUTPUT, 0)" ]; + + Stopped -> Decoding [ label = "V4L2_DEC_CMD_START\nor\nVIDIOC_STREAMON(CAPTURE)" ]; + Stopped -> Seek [ label = "VIDIOC_STREAMOFF(OUTPUT)" ]; + } + +Querying Capabilities +===================== + +1. To enumerate the set of coded formats supported by the decoder, the + client may call :c:func:`VIDIOC_ENUM_FMT` on ``OUTPUT``. + + * The full set of supported formats will be returned, regardless of the + format set on ``CAPTURE``. + * Check the flags field of :c:type:`v4l2_fmtdesc` for more information + about the decoder's capabilities with respect to each coded format. + In particular whether or not the decoder has a full-fledged bytestream + parser and if the decoder supports dynamic resolution changes. + +2. To enumerate the set of supported raw formats, the client may call + :c:func:`VIDIOC_ENUM_FMT` on ``CAPTURE``. + + * Only the formats supported for the format currently active on ``OUTPUT`` + will be returned. + + * In order to enumerate raw formats supported by a given coded format, + the client must first set that coded format on ``OUTPUT`` and then + enumerate formats on ``CAPTURE``. + +3. The client may use :c:func:`VIDIOC_ENUM_FRAMESIZES` to detect supported + resolutions for a given format, passing desired pixel format in + :c:type:`v4l2_frmsizeenum` ``pixel_format``. + + * Values returned by :c:func:`VIDIOC_ENUM_FRAMESIZES` for a coded pixel + format will include all possible coded resolutions supported by the + decoder for given coded pixel format. + + * Values returned by :c:func:`VIDIOC_ENUM_FRAMESIZES` for a raw pixel format + will include all possible frame buffer resolutions supported by the + decoder for given raw pixel format and the coded format currently set on + ``OUTPUT``. + +4. Supported profiles and levels for the coded format currently set on + ``OUTPUT``, if applicable, may be queried using their respective controls + via :c:func:`VIDIOC_QUERYCTRL`. + +Initialization +============== + +1. Set the coded format on ``OUTPUT`` via :c:func:`VIDIOC_S_FMT` + + * **Required fields:** + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``. + + ``pixelformat`` + a coded pixel format. + + ``width``, ``height`` + coded resolution of the stream; required only if it cannot be parsed + from the stream for the given coded format; otherwise the decoder will + use this resolution as a placeholder resolution that will likely change + as soon as it can parse the actual coded resolution from the stream. + + ``sizeimage`` + desired size of ``OUTPUT`` buffers; the decoder may adjust it to + match hardware requirements. + + other fields + follow standard semantics. + + * **Return fields:** + + ``sizeimage`` + adjusted size of ``OUTPUT`` buffers. + + * The ``CAPTURE`` format will be updated with an appropriate frame buffer + resolution instantly based on the width and height returned by + :c:func:`VIDIOC_S_FMT`. + However, for coded formats that include stream resolution information, + after the decoder is done parsing the information from the stream, it will + update the ``CAPTURE`` format with new values and signal a source change + event, regardless of whether they match the values set by the client or + not. + + .. important:: + + Changing the ``OUTPUT`` format may change the currently set ``CAPTURE`` + format. How the new ``CAPTURE`` format is determined is up to the decoder + and the client must ensure it matches its needs afterwards. + +2. Allocate source (bytestream) buffers via :c:func:`VIDIOC_REQBUFS` on + ``OUTPUT``. + + * **Required fields:** + + ``count`` + requested number of buffers to allocate; greater than zero. + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``. + + ``memory`` + follows standard semantics. + + * **Return fields:** + + ``count`` + the actual number of buffers allocated. + + .. warning:: + + The actual number of allocated buffers may differ from the ``count`` + given. The client must check the updated value of ``count`` after the + call returns. + + Alternatively, :c:func:`VIDIOC_CREATE_BUFS` on the ``OUTPUT`` queue can be + used to have more control over buffer allocation. + + * **Required fields:** + + ``count`` + requested number of buffers to allocate; greater than zero. + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``. + + ``memory`` + follows standard semantics. + + ``format`` + follows standard semantics. + + * **Return fields:** + + ``count`` + adjusted to the number of allocated buffers. + + .. warning:: + + The actual number of allocated buffers may differ from the ``count`` + given. The client must check the updated value of ``count`` after the + call returns. + +3. Start streaming on the ``OUTPUT`` queue via :c:func:`VIDIOC_STREAMON`. + +4. **This step only applies to coded formats that contain resolution information + in the stream.** Continue queuing/dequeuing bytestream buffers to/from the + ``OUTPUT`` queue via :c:func:`VIDIOC_QBUF` and :c:func:`VIDIOC_DQBUF`. The + buffers will be processed and returned to the client in order, until + required metadata to configure the ``CAPTURE`` queue are found. This is + indicated by the decoder sending a ``V4L2_EVENT_SOURCE_CHANGE`` event with + ``changes`` set to ``V4L2_EVENT_SRC_CH_RESOLUTION``. + + * It is not an error if the first buffer does not contain enough data for + this to occur. Processing of the buffers will continue as long as more + data is needed. + + * If data in a buffer that triggers the event is required to decode the + first frame, it will not be returned to the client, until the + initialization sequence completes and the frame is decoded. + + * If the client has not set the coded resolution of the stream on its own, + calling :c:func:`VIDIOC_G_FMT`, :c:func:`VIDIOC_S_FMT`, + :c:func:`VIDIOC_TRY_FMT` or :c:func:`VIDIOC_REQBUFS` on the ``CAPTURE`` + queue will not return the real values for the stream until a + ``V4L2_EVENT_SOURCE_CHANGE`` event with ``changes`` set to + ``V4L2_EVENT_SRC_CH_RESOLUTION`` is signaled. + + .. important:: + + Any client query issued after the decoder queues the event will return + values applying to the just parsed stream, including queue formats, + selection rectangles and controls. + + .. note:: + + A client capable of acquiring stream parameters from the bytestream on + its own may attempt to set the width and height of the ``OUTPUT`` format + to non-zero values matching the coded size of the stream, skip this step + and continue with the `Capture Setup` sequence. However, it must not + rely on any driver queries regarding stream parameters, such as + selection rectangles and controls, since the decoder has not parsed them + from the stream yet. If the values configured by the client do not match + those parsed by the decoder, a `Dynamic Resolution Change` will be + triggered to reconfigure them. + + .. note:: + + No decoded frames are produced during this phase. + +5. Continue with the `Capture Setup` sequence. + +Capture Setup +============= + +1. Call :c:func:`VIDIOC_G_FMT` on the ``CAPTURE`` queue to get format for the + destination buffers parsed/decoded from the bytestream. + + * **Required fields:** + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``. + + * **Return fields:** + + ``width``, ``height`` + frame buffer resolution for the decoded frames. + + ``pixelformat`` + pixel format for decoded frames. + + ``num_planes`` (for _MPLANE ``type`` only) + number of planes for pixelformat. + + ``sizeimage``, ``bytesperline`` + as per standard semantics; matching frame buffer format. + + .. note:: + + The value of ``pixelformat`` may be any pixel format supported by the + decoder for the current stream. The decoder should choose a + preferred/optimal format for the default configuration. For example, a + YUV format may be preferred over an RGB format if an additional + conversion step would be required for the latter. + +2. **Optional.** Acquire the visible resolution via + :c:func:`VIDIOC_G_SELECTION`. + + * **Required fields:** + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``. + + ``target`` + set to ``V4L2_SEL_TGT_COMPOSE``. + + * **Return fields:** + + ``r.left``, ``r.top``, ``r.width``, ``r.height`` + the visible rectangle; it must fit within the frame buffer resolution + returned by :c:func:`VIDIOC_G_FMT` on ``CAPTURE``. + + * The following selection targets are supported on ``CAPTURE``: + + ``V4L2_SEL_TGT_CROP_BOUNDS`` + corresponds to the coded resolution of the stream. + + ``V4L2_SEL_TGT_CROP_DEFAULT`` + the rectangle covering the part of the ``CAPTURE`` buffer that + contains meaningful picture data (visible area); width and height + will be equal to the visible resolution of the stream. + + ``V4L2_SEL_TGT_CROP`` + the rectangle within the coded resolution to be output to + ``CAPTURE``; defaults to ``V4L2_SEL_TGT_CROP_DEFAULT``; read-only on + hardware without additional compose/scaling capabilities. + + ``V4L2_SEL_TGT_COMPOSE_BOUNDS`` + the maximum rectangle within a ``CAPTURE`` buffer, which the cropped + frame can be composed into; equal to ``V4L2_SEL_TGT_CROP`` if the + hardware does not support compose/scaling. + + ``V4L2_SEL_TGT_COMPOSE_DEFAULT`` + equal to ``V4L2_SEL_TGT_CROP``. + + ``V4L2_SEL_TGT_COMPOSE`` + the rectangle inside a ``CAPTURE`` buffer into which the cropped + frame is written; defaults to ``V4L2_SEL_TGT_COMPOSE_DEFAULT``; + read-only on hardware without additional compose/scaling capabilities. + + ``V4L2_SEL_TGT_COMPOSE_PADDED`` + the rectangle inside a ``CAPTURE`` buffer which is overwritten by the + hardware; equal to ``V4L2_SEL_TGT_COMPOSE`` if the hardware does not + write padding pixels. + + .. warning:: + + The values are guaranteed to be meaningful only after the decoder + successfully parses the stream metadata. The client must not rely on the + query before that happens. + +3. **Optional.** Enumerate ``CAPTURE`` formats via :c:func:`VIDIOC_ENUM_FMT` on + the ``CAPTURE`` queue. Once the stream information is parsed and known, the + client may use this ioctl to discover which raw formats are supported for + given stream and select one of them via :c:func:`VIDIOC_S_FMT`. + + .. important:: + + The decoder will return only formats supported for the currently + established coded format, as per the ``OUTPUT`` format and/or stream + metadata parsed in this initialization sequence, even if more formats + may be supported by the decoder in general. In other words, the set + returned will be a subset of the initial query mentioned in the + `Querying Capabilities` section. + + For example, a decoder may support YUV and RGB formats for resolutions + 1920x1088 and lower, but only YUV for higher resolutions (due to + hardware limitations). After parsing a resolution of 1920x1088 or lower, + :c:func:`VIDIOC_ENUM_FMT` may return a set of YUV and RGB pixel formats, + but after parsing resolution higher than 1920x1088, the decoder will not + return RGB, unsupported for this resolution. + + However, subsequent resolution change event triggered after + discovering a resolution change within the same stream may switch + the stream into a lower resolution and :c:func:`VIDIOC_ENUM_FMT` + would return RGB formats again in that case. + +4. **Optional.** Set the ``CAPTURE`` format via :c:func:`VIDIOC_S_FMT` on the + ``CAPTURE`` queue. The client may choose a different format than + selected/suggested by the decoder in :c:func:`VIDIOC_G_FMT`. + + * **Required fields:** + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``. + + ``pixelformat`` + a raw pixel format. + + ``width``, ``height`` + frame buffer resolution of the decoded stream; typically unchanged from + what was returned with :c:func:`VIDIOC_G_FMT`, but it may be different + if the hardware supports composition and/or scaling. + + * Setting the ``CAPTURE`` format will reset the compose selection rectangles + to their default values, based on the new resolution, as described in the + previous step. + +5. **Optional.** Set the compose rectangle via :c:func:`VIDIOC_S_SELECTION` on + the ``CAPTURE`` queue if it is desired and if the decoder has compose and/or + scaling capabilities. + + * **Required fields:** + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``. + + ``target`` + set to ``V4L2_SEL_TGT_COMPOSE``. + + ``r.left``, ``r.top``, ``r.width``, ``r.height`` + the rectangle inside a ``CAPTURE`` buffer into which the cropped + frame is written; defaults to ``V4L2_SEL_TGT_COMPOSE_DEFAULT``; + read-only on hardware without additional compose/scaling capabilities. + + * **Return fields:** + + ``r.left``, ``r.top``, ``r.width``, ``r.height`` + the visible rectangle; it must fit within the frame buffer resolution + returned by :c:func:`VIDIOC_G_FMT` on ``CAPTURE``. + + .. warning:: + + The decoder may adjust the compose rectangle to the nearest + supported one to meet codec and hardware requirements. The client needs + to check the adjusted rectangle returned by :c:func:`VIDIOC_S_SELECTION`. + +6. If all the following conditions are met, the client may resume the decoding + instantly: + + * ``sizeimage`` of the new format (determined in previous steps) is less + than or equal to the size of currently allocated buffers, + + * the number of buffers currently allocated is greater than or equal to the + minimum number of buffers acquired in previous steps. To fulfill this + requirement, the client may use :c:func:`VIDIOC_CREATE_BUFS` to add new + buffers. + + In that case, the remaining steps do not apply and the client may resume + the decoding by one of the following actions: + + * if the ``CAPTURE`` queue is streaming, call :c:func:`VIDIOC_DECODER_CMD` + with the ``V4L2_DEC_CMD_START`` command, + + * if the ``CAPTURE`` queue is not streaming, call :c:func:`VIDIOC_STREAMON` + on the ``CAPTURE`` queue. + + However, if the client intends to change the buffer set, to lower + memory usage or for any other reasons, it may be achieved by following + the steps below. + +7. **If the** ``CAPTURE`` **queue is streaming,** keep queuing and dequeuing + buffers on the ``CAPTURE`` queue until a buffer marked with the + ``V4L2_BUF_FLAG_LAST`` flag is dequeued. + +8. **If the** ``CAPTURE`` **queue is streaming,** call :c:func:`VIDIOC_STREAMOFF` + on the ``CAPTURE`` queue to stop streaming. + + .. warning:: + + The ``OUTPUT`` queue must remain streaming. Calling + :c:func:`VIDIOC_STREAMOFF` on it would abort the sequence and trigger a + seek. + +9. **If the** ``CAPTURE`` **queue has buffers allocated,** free the ``CAPTURE`` + buffers using :c:func:`VIDIOC_REQBUFS`. + + * **Required fields:** + + ``count`` + set to 0. + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``. + + ``memory`` + follows standard semantics. + +10. Allocate ``CAPTURE`` buffers via :c:func:`VIDIOC_REQBUFS` on the + ``CAPTURE`` queue. + + * **Required fields:** + + ``count`` + requested number of buffers to allocate; greater than zero. + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``. + + ``memory`` + follows standard semantics. + + * **Return fields:** + + ``count`` + actual number of buffers allocated. + + .. warning:: + + The actual number of allocated buffers may differ from the ``count`` + given. The client must check the updated value of ``count`` after the + call returns. + + .. note:: + + To allocate more than the minimum number of buffers (for pipeline + depth), the client may query the ``V4L2_CID_MIN_BUFFERS_FOR_CAPTURE`` + control to get the minimum number of buffers required, and pass the + obtained value plus the number of additional buffers needed in the + ``count`` field to :c:func:`VIDIOC_REQBUFS`. + + Alternatively, :c:func:`VIDIOC_CREATE_BUFS` on the ``CAPTURE`` queue can be + used to have more control over buffer allocation. For example, by + allocating buffers larger than the current ``CAPTURE`` format, future + resolution changes can be accommodated. + + * **Required fields:** + + ``count`` + requested number of buffers to allocate; greater than zero. + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``. + + ``memory`` + follows standard semantics. + + ``format`` + a format representing the maximum framebuffer resolution to be + accommodated by newly allocated buffers. + + * **Return fields:** + + ``count`` + adjusted to the number of allocated buffers. + + .. warning:: + + The actual number of allocated buffers may differ from the ``count`` + given. The client must check the updated value of ``count`` after the + call returns. + + .. note:: + + To allocate buffers for a format different than parsed from the stream + metadata, the client must proceed as follows, before the metadata + parsing is initiated: + + * set width and height of the ``OUTPUT`` format to desired coded resolution to + let the decoder configure the ``CAPTURE`` format appropriately, + + * query the ``CAPTURE`` format using :c:func:`VIDIOC_G_FMT` and save it + until this step. + + The format obtained in the query may be then used with + :c:func:`VIDIOC_CREATE_BUFS` in this step to allocate the buffers. + +11. Call :c:func:`VIDIOC_STREAMON` on the ``CAPTURE`` queue to start decoding + frames. + +Decoding +======== + +This state is reached after the `Capture Setup` sequence finishes successfully. +In this state, the client queues and dequeues buffers to both queues via +:c:func:`VIDIOC_QBUF` and :c:func:`VIDIOC_DQBUF`, following the standard +semantics. + +The content of the source ``OUTPUT`` buffers depends on the active coded pixel +format and may be affected by codec-specific extended controls, as stated in +the documentation of each format. + +Both queues operate independently, following the standard behavior of V4L2 +buffer queues and memory-to-memory devices. In addition, the order of decoded +frames dequeued from the ``CAPTURE`` queue may differ from the order of queuing +coded frames to the ``OUTPUT`` queue, due to properties of the selected coded +format, e.g. frame reordering. + +The client must not assume any direct relationship between ``CAPTURE`` +and ``OUTPUT`` buffers and any specific timing of buffers becoming +available to dequeue. Specifically: + +* a buffer queued to ``OUTPUT`` may result in no buffers being produced + on ``CAPTURE`` (e.g. if it does not contain encoded data, or if only + metadata syntax structures are present in it), + +* a buffer queued to ``OUTPUT`` may result in more than one buffer produced + on ``CAPTURE`` (if the encoded data contained more than one frame, or if + returning a decoded frame allowed the decoder to return a frame that + preceded it in decode, but succeeded it in the display order), + +* a buffer queued to ``OUTPUT`` may result in a buffer being produced on + ``CAPTURE`` later into decode process, and/or after processing further + ``OUTPUT`` buffers, or be returned out of order, e.g. if display + reordering is used, + +* buffers may become available on the ``CAPTURE`` queue without additional + buffers queued to ``OUTPUT`` (e.g. during drain or ``EOS``), because of the + ``OUTPUT`` buffers queued in the past whose decoding results are only + available at later time, due to specifics of the decoding process. + +.. note:: + + To allow matching decoded ``CAPTURE`` buffers with ``OUTPUT`` buffers they + originated from, the client can set the ``timestamp`` field of the + :c:type:`v4l2_buffer` struct when queuing an ``OUTPUT`` buffer. The + ``CAPTURE`` buffer(s), which resulted from decoding that ``OUTPUT`` buffer + will have their ``timestamp`` field set to the same value when dequeued. + + In addition to the straightforward case of one ``OUTPUT`` buffer producing + one ``CAPTURE`` buffer, the following cases are defined: + + * one ``OUTPUT`` buffer generates multiple ``CAPTURE`` buffers: the same + ``OUTPUT`` timestamp will be copied to multiple ``CAPTURE`` buffers. + + * multiple ``OUTPUT`` buffers generate one ``CAPTURE`` buffer: timestamp of + the ``OUTPUT`` buffer queued first will be copied. + + * the decoding order differs from the display order (i.e. the ``CAPTURE`` + buffers are out-of-order compared to the ``OUTPUT`` buffers): ``CAPTURE`` + timestamps will not retain the order of ``OUTPUT`` timestamps. + +During the decoding, the decoder may initiate one of the special sequences, as +listed below. The sequences will result in the decoder returning all the +``CAPTURE`` buffers that originated from all the ``OUTPUT`` buffers processed +before the sequence started. Last of the buffers will have the +``V4L2_BUF_FLAG_LAST`` flag set. To determine the sequence to follow, the client +must check if there is any pending event and: + +* if a ``V4L2_EVENT_SOURCE_CHANGE`` event with ``changes`` set to + ``V4L2_EVENT_SRC_CH_RESOLUTION`` is pending, the `Dynamic Resolution + Change` sequence needs to be followed, + +* if a ``V4L2_EVENT_EOS`` event is pending, the `End of Stream` sequence needs + to be followed. + +Some of the sequences can be intermixed with each other and need to be handled +as they happen. The exact operation is documented for each sequence. + +Should a decoding error occur, it will be reported to the client with the level +of details depending on the decoder capabilities. Specifically: + +* the CAPTURE buffer that contains the results of the failed decode operation + will be returned with the V4L2_BUF_FLAG_ERROR flag set, + +* if the decoder is able to precisely report the OUTPUT buffer that triggered + the error, such buffer will be returned with the V4L2_BUF_FLAG_ERROR flag + set. + +In case of a fatal failure that does not allow the decoding to continue, any +further operations on corresponding decoder file handle will return the -EIO +error code. The client may close the file handle and open a new one, or +alternatively reinitialize the instance by stopping streaming on both queues, +releasing all buffers and performing the Initialization sequence again. + +Seek +==== + +Seek is controlled by the ``OUTPUT`` queue, as it is the source of coded data. +The seek does not require any specific operation on the ``CAPTURE`` queue, but +it may be affected as per normal decoder operation. + +1. Stop the ``OUTPUT`` queue to begin the seek sequence via + :c:func:`VIDIOC_STREAMOFF`. + + * **Required fields:** + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``. + + * The decoder will drop all the pending ``OUTPUT`` buffers and they must be + treated as returned to the client (following standard semantics). + +2. Restart the ``OUTPUT`` queue via :c:func:`VIDIOC_STREAMON` + + * **Required fields:** + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``. + + * The decoder will start accepting new source bytestream buffers after the + call returns. + +3. Start queuing buffers containing coded data after the seek to the ``OUTPUT`` + queue until a suitable resume point is found. + + .. note:: + + There is no requirement to begin queuing coded data starting exactly + from a resume point (e.g. SPS or a keyframe). Any queued ``OUTPUT`` + buffers will be processed and returned to the client until a suitable + resume point is found. While looking for a resume point, the decoder + should not produce any decoded frames into ``CAPTURE`` buffers. + + Some hardware is known to mishandle seeks to a non-resume point. Such an + operation may result in an unspecified number of corrupted decoded frames + being made available on the ``CAPTURE`` queue. Drivers must ensure that + no fatal decoding errors or crashes occur, and implement any necessary + handling and workarounds for hardware issues related to seek operations. + + .. warning:: + + In case of the H.264/HEVC codec, the client must take care not to seek + over a change of SPS/PPS. Even though the target frame could be a + keyframe, the stale SPS/PPS inside decoder state would lead to undefined + results when decoding. Although the decoder must handle that case without + a crash or a fatal decode error, the client must not expect a sensible + decode output. + + If the hardware can detect such corrupted decoded frames, then + corresponding buffers will be returned to the client with the + V4L2_BUF_FLAG_ERROR set. See the `Decoding` section for further + description of decode error reporting. + +4. After a resume point is found, the decoder will start returning ``CAPTURE`` + buffers containing decoded frames. + +.. important:: + + A seek may result in the `Dynamic Resolution Change` sequence being + initiated, due to the seek target having decoding parameters different from + the part of the stream decoded before the seek. The sequence must be handled + as per normal decoder operation. + +.. warning:: + + It is not specified when the ``CAPTURE`` queue starts producing buffers + containing decoded data from the ``OUTPUT`` buffers queued after the seek, + as it operates independently from the ``OUTPUT`` queue. + + The decoder may return a number of remaining ``CAPTURE`` buffers containing + decoded frames originating from the ``OUTPUT`` buffers queued before the + seek sequence is performed. + + The ``VIDIOC_STREAMOFF`` operation discards any remaining queued + ``OUTPUT`` buffers, which means that not all of the ``OUTPUT`` buffers + queued before the seek sequence may have matching ``CAPTURE`` buffers + produced. For example, given the sequence of operations on the + ``OUTPUT`` queue: + + QBUF(A), QBUF(B), STREAMOFF(), STREAMON(), QBUF(G), QBUF(H), + + any of the following results on the ``CAPTURE`` queue is allowed: + + {A’, B’, G’, H’}, {A’, G’, H’}, {G’, H’}. + + To determine the CAPTURE buffer containing the first decoded frame after the + seek, the client may observe the timestamps to match the CAPTURE and OUTPUT + buffers or use V4L2_DEC_CMD_STOP and V4L2_DEC_CMD_START to drain the + decoder. + +.. note:: + + To achieve instantaneous seek, the client may restart streaming on the + ``CAPTURE`` queue too to discard decoded, but not yet dequeued buffers. + +Dynamic Resolution Change +========================= + +Streams that include resolution metadata in the bytestream may require switching +to a different resolution during the decoding. + +.. note:: + + Not all decoders can detect resolution changes. Those that do set the + ``V4L2_FMT_FLAG_DYN_RESOLUTION`` flag for the coded format when + :c:func:`VIDIOC_ENUM_FMT` is called. + +The sequence starts when the decoder detects a coded frame with one or more of +the following parameters different from those previously established (and +reflected by corresponding queries): + +* coded resolution (``OUTPUT`` width and height), + +* visible resolution (selection rectangles), + +* the minimum number of buffers needed for decoding. + +Whenever that happens, the decoder must proceed as follows: + +1. After encountering a resolution change in the stream, the decoder sends a + ``V4L2_EVENT_SOURCE_CHANGE`` event with ``changes`` set to + ``V4L2_EVENT_SRC_CH_RESOLUTION``. + + .. important:: + + Any client query issued after the decoder queues the event will return + values applying to the stream after the resolution change, including + queue formats, selection rectangles and controls. + +2. The decoder will then process and decode all remaining buffers from before + the resolution change point. + + * The last buffer from before the change must be marked with the + ``V4L2_BUF_FLAG_LAST`` flag, similarly to the `Drain` sequence above. + + .. warning:: + + The last buffer may be empty (with :c:type:`v4l2_buffer` ``bytesused`` + = 0) and in that case it must be ignored by the client, as it does not + contain a decoded frame. + + .. note:: + + Any attempt to dequeue more ``CAPTURE`` buffers beyond the buffer marked + with ``V4L2_BUF_FLAG_LAST`` will result in a -EPIPE error from + :c:func:`VIDIOC_DQBUF`. + +The client must continue the sequence as described below to continue the +decoding process. + +1. Dequeue the source change event. + + .. important:: + + A source change triggers an implicit decoder drain, similar to the + explicit `Drain` sequence. The decoder is stopped after it completes. + The decoding process must be resumed with either a pair of calls to + :c:func:`VIDIOC_STREAMOFF` and :c:func:`VIDIOC_STREAMON` on the + ``CAPTURE`` queue, or a call to :c:func:`VIDIOC_DECODER_CMD` with the + ``V4L2_DEC_CMD_START`` command. + +2. Continue with the `Capture Setup` sequence. + +.. note:: + + During the resolution change sequence, the ``OUTPUT`` queue must remain + streaming. Calling :c:func:`VIDIOC_STREAMOFF` on the ``OUTPUT`` queue would + abort the sequence and initiate a seek. + + In principle, the ``OUTPUT`` queue operates separately from the ``CAPTURE`` + queue and this remains true for the duration of the entire resolution change + sequence as well. + + The client should, for best performance and simplicity, keep queuing/dequeuing + buffers to/from the ``OUTPUT`` queue even while processing this sequence. + +Drain +===== + +To ensure that all queued ``OUTPUT`` buffers have been processed and related +``CAPTURE`` buffers are given to the client, the client must follow the drain +sequence described below. After the drain sequence ends, the client has +received all decoded frames for all ``OUTPUT`` buffers queued before the +sequence was started. + +1. Begin drain by issuing :c:func:`VIDIOC_DECODER_CMD`. + + * **Required fields:** + + ``cmd`` + set to ``V4L2_DEC_CMD_STOP``. + + ``flags`` + set to 0. + + ``pts`` + set to 0. + + .. warning:: + + The sequence can be only initiated if both ``OUTPUT`` and ``CAPTURE`` + queues are streaming. For compatibility reasons, the call to + :c:func:`VIDIOC_DECODER_CMD` will not fail even if any of the queues is + not streaming, but at the same time it will not initiate the `Drain` + sequence and so the steps described below would not be applicable. + +2. Any ``OUTPUT`` buffers queued by the client before the + :c:func:`VIDIOC_DECODER_CMD` was issued will be processed and decoded as + normal. The client must continue to handle both queues independently, + similarly to normal decode operation. This includes: + + * handling any operations triggered as a result of processing those buffers, + such as the `Dynamic Resolution Change` sequence, before continuing with + the drain sequence, + + * queuing and dequeuing ``CAPTURE`` buffers, until a buffer marked with the + ``V4L2_BUF_FLAG_LAST`` flag is dequeued, + + .. warning:: + + The last buffer may be empty (with :c:type:`v4l2_buffer` + ``bytesused`` = 0) and in that case it must be ignored by the client, + as it does not contain a decoded frame. + + .. note:: + + Any attempt to dequeue more ``CAPTURE`` buffers beyond the buffer + marked with ``V4L2_BUF_FLAG_LAST`` will result in a -EPIPE error from + :c:func:`VIDIOC_DQBUF`. + + * dequeuing processed ``OUTPUT`` buffers, until all the buffers queued + before the ``V4L2_DEC_CMD_STOP`` command are dequeued, + + * dequeuing the ``V4L2_EVENT_EOS`` event, if the client subscribed to it. + + .. note:: + + For backwards compatibility, the decoder will signal a ``V4L2_EVENT_EOS`` + event when the last frame has been decoded and all frames are ready to be + dequeued. It is a deprecated behavior and the client must not rely on it. + The ``V4L2_BUF_FLAG_LAST`` buffer flag should be used instead. + +3. Once all the ``OUTPUT`` buffers queued before the ``V4L2_DEC_CMD_STOP`` call + are dequeued and the last ``CAPTURE`` buffer is dequeued, the decoder is + stopped and it will accept, but not process, any newly queued ``OUTPUT`` + buffers until the client issues any of the following operations: + + * ``V4L2_DEC_CMD_START`` - the decoder will not be reset and will resume + operation normally, with all the state from before the drain, + + * a pair of :c:func:`VIDIOC_STREAMOFF` and :c:func:`VIDIOC_STREAMON` on the + ``CAPTURE`` queue - the decoder will resume the operation normally, + however any ``CAPTURE`` buffers still in the queue will be returned to the + client, + + * a pair of :c:func:`VIDIOC_STREAMOFF` and :c:func:`VIDIOC_STREAMON` on the + ``OUTPUT`` queue - any pending source buffers will be returned to the + client and the `Seek` sequence will be triggered. + +.. note:: + + Once the drain sequence is initiated, the client needs to drive it to + completion, as described by the steps above, unless it aborts the process by + issuing :c:func:`VIDIOC_STREAMOFF` on any of the ``OUTPUT`` or ``CAPTURE`` + queues. The client is not allowed to issue ``V4L2_DEC_CMD_START`` or + ``V4L2_DEC_CMD_STOP`` again while the drain sequence is in progress and they + will fail with -EBUSY error code if attempted. + + Although mandatory, the availability of decoder commands may be queried + using :c:func:`VIDIOC_TRY_DECODER_CMD`. + +End of Stream +============= + +If the decoder encounters an end of stream marking in the stream, the decoder +will initiate the `Drain` sequence, which the client must handle as described +above, skipping the initial :c:func:`VIDIOC_DECODER_CMD`. + +Commit Points +============= + +Setting formats and allocating buffers trigger changes in the behavior of the +decoder. + +1. Setting the format on the ``OUTPUT`` queue may change the set of formats + supported/advertised on the ``CAPTURE`` queue. In particular, it also means + that the ``CAPTURE`` format may be reset and the client must not rely on the + previously set format being preserved. + +2. Enumerating formats on the ``CAPTURE`` queue always returns only formats + supported for the current ``OUTPUT`` format. + +3. Setting the format on the ``CAPTURE`` queue does not change the list of + formats available on the ``OUTPUT`` queue. An attempt to set a ``CAPTURE`` + format that is not supported for the currently selected ``OUTPUT`` format + will result in the decoder adjusting the requested ``CAPTURE`` format to a + supported one. + +4. Enumerating formats on the ``OUTPUT`` queue always returns the full set of + supported coded formats, irrespectively of the current ``CAPTURE`` format. + +5. While buffers are allocated on any of the ``OUTPUT`` or ``CAPTURE`` queues, + the client must not change the format on the ``OUTPUT`` queue. Drivers will + return the -EBUSY error code for any such format change attempt. + +To summarize, setting formats and allocation must always start with the +``OUTPUT`` queue and the ``OUTPUT`` queue is the master that governs the +set of supported formats for the ``CAPTURE`` queue. diff --git a/Documentation/media/uapi/v4l/dev-mem2mem.rst b/Documentation/media/uapi/v4l/dev-mem2mem.rst index 67a980818dc8b72fbd5ca8b0dfd197495076c2b4..caa05f5f638019d5a85e0165c8458dd158749263 100644 --- a/Documentation/media/uapi/v4l/dev-mem2mem.rst +++ b/Documentation/media/uapi/v4l/dev-mem2mem.rst @@ -39,4 +39,10 @@ file handle is visible through another file handle). One of the most common memory-to-memory device is the codec. Codecs are more complicated than most and require additional setup for their codec parameters. This is done through codec controls. -See :ref:`mpeg-controls`. +See :ref:`mpeg-controls`. More details on how to use codec memory-to-memory +devices are given in the following sections. + +.. toctree:: + :maxdepth: 1 + + dev-decoder diff --git a/Documentation/media/uapi/v4l/ext-ctrls-codec.rst b/Documentation/media/uapi/v4l/ext-ctrls-codec.rst index d6ea2ffd65c5402ccdfd47b1299d56e23b4ca72b..bc5dd8e76567b688db0f1af37d050a229087b151 100644 --- a/Documentation/media/uapi/v4l/ext-ctrls-codec.rst +++ b/Documentation/media/uapi/v4l/ext-ctrls-codec.rst @@ -1747,6 +1747,14 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - * - __u32 - ``size`` - + * - __u32 + - ``start_byte_offset`` + Offset (in bytes) from the beginning of the OUTPUT buffer to the start + of the slice. If the slice starts with a start code, then this is the + offset to such start code. When operating in slice-based decoding mode + (see :c:type:`v4l2_mpeg_video_h264_decode_mode`), this field should + be set to 0. When operating in frame-based decoding mode, this field + should be 0 for the first slice. * - __u32 - ``header_bit_size`` - @@ -1930,19 +1938,13 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - - * - __u16 - ``num_slices`` - - Number of slices needed to decode the current frame + - Number of slices needed to decode the current frame/field. When + operating in slice-based decoding mode (see + :c:type:`v4l2_mpeg_video_h264_decode_mode`), this field + should always be set to one. * - __u16 - ``nal_ref_idc`` - NAL reference ID value coming from the NAL Unit header - * - __u8 - - ``ref_pic_list_p0[32]`` - - Backward reference list used by P-frames in the original bitstream order - * - __u8 - - ``ref_pic_list_b0[32]`` - - Backward reference list used by B-frames in the original bitstream order - * - __u8 - - ``ref_pic_list_b1[32]`` - - Forward reference list used by B-frames in the original bitstream order * - __s32 - ``top_field_order_cnt`` - Picture Order Count for the coded top field @@ -2021,6 +2023,83 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - - 0x00000004 - The DPB entry is a long term reference frame +``V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE (enum)`` + Specifies the decoding mode to use. Currently exposes slice-based and + frame-based decoding but new modes might be added later on. + This control is used as a modifier for V4L2_PIX_FMT_H264_SLICE + pixel format. Applications that support V4L2_PIX_FMT_H264_SLICE + are required to set this control in order to specify the decoding mode + that is expected for the buffer. + Drivers may expose a single or multiple decoding modes, depending + on what they can support. + + .. note:: + + This menu control is not yet part of the public kernel API and + it is expected to change. + +.. c:type:: v4l2_mpeg_video_h264_decode_mode + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED`` + - 0 + - Decoding is done at the slice granularity. + In this mode, ``num_slices`` field in struct + :c:type:`v4l2_ctrl_h264_decode_params` should be set to 1, + and ``start_byte_offset`` in struct + :c:type:`v4l2_ctrl_h264_slice_params` should be set to 0. + The OUTPUT buffer must contain a single slice. + * - ``V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED`` + - 1 + - Decoding is done at the frame granularity. + In this mode, ``num_slices`` field in struct + :c:type:`v4l2_ctrl_h264_decode_params` should be set to the number + of slices in the frame, and ``start_byte_offset`` in struct + :c:type:`v4l2_ctrl_h264_slice_params` should be set accordingly + for each slice. For the first slice, ``start_byte_offset`` should + be zero. + The OUTPUT buffer must contain all slices needed to decode the + frame. The OUTPUT buffer must also contain both fields. + +``V4L2_CID_MPEG_VIDEO_H264_START_CODE (enum)`` + Specifies the H264 slice start code expected for each slice. + This control is used as a modifier for V4L2_PIX_FMT_H264_SLICE + pixel format. Applications that support V4L2_PIX_FMT_H264_SLICE + are required to set this control in order to specify the start code + that is expected for the buffer. + Drivers may expose a single or multiple start codes, depending + on what they can support. + + .. note:: + + This menu control is not yet part of the public kernel API and + it is expected to change. + +.. c:type:: v4l2_mpeg_video_h264_start_code + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_MPEG_VIDEO_H264_START_CODE_NONE`` + - 0 + - Selecting this value specifies that H264 slices are passed + to the driver without any start code. + * - ``V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B`` + - 1 + - Selecting this value specifies that H264 slices are expected + to be prefixed by Annex B start codes. According to :ref:`h264` + valid start codes can be 3-bytes 0x000001 or 4-bytes 0x00000001. + .. _v4l2-mpeg-mpeg2: ``V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS (struct)`` @@ -2234,6 +2313,329 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - Quantization parameter for a P frame for FWHT. Valid range: from 1 to 31. +.. _v4l2-mpeg-vp8: + +``V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER (struct)`` + Specifies the frame parameters for the associated VP8 parsed frame data. + This includes the necessary parameters for + configuring a stateless hardware decoding pipeline for VP8. + The bitstream parameters are defined according to :ref:`vp8`. + + .. note:: + + This compound control is not yet part of the public kernel API and + it is expected to change. + +.. c:type:: v4l2_ctrl_vp8_frame_header + +.. cssclass:: longtable + +.. tabularcolumns:: |p{5.8cm}|p{4.8cm}|p{6.6cm}| + +.. flat-table:: struct v4l2_ctrl_vp8_frame_header + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - struct :c:type:`v4l2_vp8_segment_header` + - ``segment_header`` + - Structure with segment-based adjustments metadata. + * - struct :c:type:`v4l2_vp8_loopfilter_header` + - ``loopfilter_header`` + - Structure with loop filter level adjustments metadata. + * - struct :c:type:`v4l2_vp8_quantization_header` + - ``quant_header`` + - Structure with VP8 dequantization indices metadata. + * - struct :c:type:`v4l2_vp8_entropy_header` + - ``entropy_header`` + - Structure with VP8 entropy coder probabilities metadata. + * - struct :c:type:`v4l2_vp8_entropy_coder_state` + - ``coder_state`` + - Structure with VP8 entropy coder state. + * - __u16 + - ``width`` + - The width of the frame. Must be set for all frames. + * - __u16 + - ``height`` + - The height of the frame. Must be set for all frames. + * - __u8 + - ``horizontal_scale`` + - Horizontal scaling factor. + * - __u8 + - ``vertical_scaling factor`` + - Vertical scale. + * - __u8 + - ``version`` + - Bitstream version. + * - __u8 + - ``prob_skip_false`` + - Indicates the probability that the macroblock is not skipped. + * - __u8 + - ``prob_intra`` + - Indicates the probability that a macroblock is intra-predicted. + * - __u8 + - ``prob_last`` + - Indicates the probability that the last reference frame is used + for inter-prediction + * - __u8 + - ``prob_gf`` + - Indicates the probability that the golden reference frame is used + for inter-prediction + * - __u8 + - ``num_dct_parts`` + - Number of DCT coefficients partitions. Must be one of: 1, 2, 4, or 8. + * - __u32 + - ``first_part_size`` + - Size of the first partition, i.e. the control partition. + * - __u32 + - ``first_part_header_bits`` + - Size in bits of the first partition header portion. + * - __u32 + - ``dct_part_sizes[8]`` + - DCT coefficients sizes. + * - __u64 + - ``last_frame_ts`` + - Timestamp for the V4L2 capture buffer to use as last reference frame, used + with inter-coded frames. The timestamp refers to the ``timestamp`` field in + struct :c:type:`v4l2_buffer`. Use the :c:func:`v4l2_timeval_to_ns()` + function to convert the struct :c:type:`timeval` in struct + :c:type:`v4l2_buffer` to a __u64. + * - __u64 + - ``golden_frame_ts`` + - Timestamp for the V4L2 capture buffer to use as last reference frame, used + with inter-coded frames. The timestamp refers to the ``timestamp`` field in + struct :c:type:`v4l2_buffer`. Use the :c:func:`v4l2_timeval_to_ns()` + function to convert the struct :c:type:`timeval` in struct + :c:type:`v4l2_buffer` to a __u64. + * - __u64 + - ``alt_frame_ts`` + - Timestamp for the V4L2 capture buffer to use as alternate reference frame, used + with inter-coded frames. The timestamp refers to the ``timestamp`` field in + struct :c:type:`v4l2_buffer`. Use the :c:func:`v4l2_timeval_to_ns()` + function to convert the struct :c:type:`timeval` in struct + :c:type:`v4l2_buffer` to a __u64. + * - __u64 + - ``flags`` + - See :ref:`Frame Header Flags ` + +.. _vp8_frame_header_flags: + +``Frame Header Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_VP8_FRAME_HEADER_FLAG_KEY_FRAME`` + - 0x01 + - Indicates if the frame is a key frame. + * - ``V4L2_VP8_FRAME_HEADER_FLAG_EXPERIMENTAL`` + - 0x02 + - Experimental bitstream. + * - ``V4L2_VP8_FRAME_HEADER_FLAG_SHOW_FRAME`` + - 0x04 + - Show frame flag, indicates if the frame is for display. + * - ``V4L2_VP8_FRAME_HEADER_FLAG_MB_NO_SKIP_COEFF`` + - 0x08 + - Enable/disable skipping of macroblocks with no non-zero coefficients. + * - ``V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_GOLDEN`` + - 0x10 + - Sign of motion vectors when the golden frame is referenced. + * - ``V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_ALT`` + - 0x20 + - Sign of motion vectors when the alt frame is referenced. + +.. c:type:: v4l2_vp8_entropy_coder_state + +.. cssclass:: longtable + +.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| + +.. flat-table:: struct v4l2_vp8_entropy_coder_state + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u8 + - ``range`` + - + * - __u8 + - ``value`` + - + * - __u8 + - ``bit_count`` + - + * - __u8 + - ``padding`` + - Applications and drivers must set this to zero. + +.. c:type:: v4l2_vp8_segment_header + +.. cssclass:: longtable + +.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| + +.. flat-table:: struct v4l2_vp8_segment_header + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __s8 + - ``quant_update[4]`` + - Signed quantizer value update. + * - __s8 + - ``lf_update[4]`` + - Signed loop filter level value update. + * - __u8 + - ``segment_probs[3]`` + - Segment probabilities. + * - __u8 + - ``padding`` + - Applications and drivers must set this to zero. + * - __u32 + - ``flags`` + - See :ref:`Segment Header Flags ` + +.. _vp8_segment_header_flags: + +``Segment Header Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED`` + - 0x01 + - Enable/disable segment-based adjustments. + * - ``V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_MAP`` + - 0x02 + - Indicates if the macroblock segmentation map is updated in this frame. + * - ``V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_FEATURE_DATA`` + - 0x04 + - Indicates if the segment feature data is updated in this frame. + * - ``V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE`` + - 0x08 + - If is set, the segment feature data mode is delta-value. + If cleared, it's absolute-value. + +.. c:type:: v4l2_vp8_loopfilter_header + +.. cssclass:: longtable + +.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| + +.. flat-table:: struct v4l2_vp8_loopfilter_header + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __s8 + - ``ref_frm_delta[4]`` + - Reference adjustment (signed) delta value. + * - __s8 + - ``mb_mode_delta[4]`` + - Macroblock prediction mode adjustment (signed) delta value. + * - __u8 + - ``sharpness_level`` + - Sharpness level + * - __u8 + - ``level`` + - Filter level + * - __u16 + - ``padding`` + - Applications and drivers must set this to zero. + * - __u32 + - ``flags`` + - See :ref:`Loopfilter Header Flags ` + +.. _vp8_loopfilter_header_flags: + +``Loopfilter Header Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_VP8_LF_HEADER_ADJ_ENABLE`` + - 0x01 + - Enable/disable macroblock-level loop filter adjustment. + * - ``V4L2_VP8_LF_HEADER_DELTA_UPDATE`` + - 0x02 + - Indicates if the delta values used in an adjustment are updated. + * - ``V4L2_VP8_LF_FILTER_TYPE_SIMPLE`` + - 0x04 + - If set, indicates the filter type is simple. + If cleared, the filter type is normal. + +.. c:type:: v4l2_vp8_quantization_header + +.. cssclass:: longtable + +.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| + +.. flat-table:: struct v4l2_vp8_quantization_header + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u8 + - ``y_ac_qi`` + - Luma AC coefficient table index. + * - __s8 + - ``y_dc_delta`` + - Luma DC delta vaue. + * - __s8 + - ``y2_dc_delta`` + - Y2 block DC delta value. + * - __s8 + - ``y2_ac_delta`` + - Y2 block AC delta value. + * - __s8 + - ``uv_dc_delta`` + - Chroma DC delta value. + * - __s8 + - ``uv_ac_delta`` + - Chroma AC delta value. + * - __u16 + - ``padding`` + - Applications and drivers must set this to zero. + +.. c:type:: v4l2_vp8_entropy_header + +.. cssclass:: longtable + +.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| + +.. flat-table:: struct v4l2_vp8_entropy_header + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u8 + - ``coeff_probs[4][8][3][11]`` + - Coefficient update probabilities. + * - __u8 + - ``y_mode_probs[4]`` + - Luma mode update probabilities. + * - __u8 + - ``uv_mode_probs[3]`` + - Chroma mode update probabilities. + * - __u8 + - ``mv_probs[2][19]`` + - MV decoding update probabilities. + * - __u8 + - ``padding[3]`` + - Applications and drivers must set this to zero. + .. raw:: latex \normalsize diff --git a/Documentation/media/uapi/v4l/hist-v4l2.rst b/Documentation/media/uapi/v4l/hist-v4l2.rst index 7d8e9efbeb1ed0ee5fc57a3e83bc6da9367b03ea..9e097f34cb7439f2a5a9a11c19c48092af2d04b1 100644 --- a/Documentation/media/uapi/v4l/hist-v4l2.rst +++ b/Documentation/media/uapi/v4l/hist-v4l2.rst @@ -900,7 +900,7 @@ V4L2 in Linux 2.6.19 :ref:`VIDIOC_ENUM_FRAMEINTERVALS` were added. -3. A new pixel format ``V4L2_PIX_FMT_RGB444`` (:ref:`rgb-formats`) was +3. A new pixel format ``V4L2_PIX_FMT_RGB444`` (:ref:`pixfmt-rgb`) was added. diff --git a/Documentation/media/uapi/v4l/pixfmt-bayer.rst b/Documentation/media/uapi/v4l/pixfmt-bayer.rst new file mode 100644 index 0000000000000000000000000000000000000000..cfa2f4e3e1142b3c98585601b8f4bd446735d728 --- /dev/null +++ b/Documentation/media/uapi/v4l/pixfmt-bayer.rst @@ -0,0 +1,38 @@ +.. Permission is granted to copy, distribute and/or modify this +.. document under the terms of the GNU Free Documentation License, +.. Version 1.1 or any later version published by the Free Software +.. Foundation, with no Invariant Sections, no Front-Cover Texts +.. and no Back-Cover Texts. A copy of the license is included at +.. Documentation/media/uapi/fdl-appendix.rst. +.. +.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections + +.. _pixfmt-bayer: + +***************** +Raw Bayer Formats +***************** + +Description +=========== + +The raw Bayer formats are used by image sensors before much if any processing is +performed on the image. The formats contain green, red and blue components, with +alternating lines of red and green, and blue and green pixels in different +orders. See also `the Wikipedia article on Bayer filter +`__. + + +.. toctree:: + :maxdepth: 1 + + pixfmt-srggb8 + pixfmt-srggb10 + pixfmt-srggb10p + pixfmt-srggb10alaw8 + pixfmt-srggb10dpcm8 + pixfmt-srggb10-ipu3 + pixfmt-srggb12 + pixfmt-srggb12p + pixfmt-srggb14p + pixfmt-srggb16 diff --git a/Documentation/media/uapi/v4l/pixfmt-compressed.rst b/Documentation/media/uapi/v4l/pixfmt-compressed.rst index 4b701fc7653e7655937fc3e4722c5b09c9dd7338..292fdc116c777b08ed3db2bd5194b0d1d166e771 100644 --- a/Documentation/media/uapi/v4l/pixfmt-compressed.rst +++ b/Documentation/media/uapi/v4l/pixfmt-compressed.rst @@ -41,7 +41,12 @@ Compressed Formats - ``V4L2_PIX_FMT_H264`` - 'H264' - - H264 video elementary stream with start codes. + - H264 Access Unit. + The decoder expects one Access Unit per buffer. + The encoder generates one Access Unit per buffer. + If :ref:`VIDIOC_ENUM_FMT` reports ``V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM`` + then the decoder has no requirements since it can parse all the + information from the raw bytestream. * .. _V4L2-PIX-FMT-H264-NO-SC: - ``V4L2_PIX_FMT_H264_NO_SC`` @@ -52,16 +57,19 @@ Compressed Formats - ``V4L2_PIX_FMT_H264_MVC`` - 'M264' - H264 MVC video elementary stream. - * .. _V4L2-PIX-FMT-H264-SLICE-RAW: + * .. _V4L2-PIX-FMT-H264-SLICE: - - ``V4L2_PIX_FMT_H264_SLICE_RAW`` + - ``V4L2_PIX_FMT_H264_SLICE`` - 'S264' - H264 parsed slice data, without the start code and as extracted from the H264 bitstream. This format is adapted for stateless video decoders that implement an H264 pipeline (using the :ref:`mem2mem` and :ref:`media-request-api`). - Metadata associated with the frame to decode are required to - be passed through the ``V4L2_CID_MPEG_VIDEO_H264_SPS``, + This pixelformat has two modifiers that must be set at least once + through the ``V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE`` + and ``V4L2_CID_MPEG_VIDEO_H264_START_CODE`` controls. + In addition, metadata associated with the frame to decode are + required to be passed through the ``V4L2_CID_MPEG_VIDEO_H264_SPS``, ``V4L2_CID_MPEG_VIDEO_H264_PPS``, ``V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX``, ``V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS`` and @@ -86,12 +94,20 @@ Compressed Formats - ``V4L2_PIX_FMT_MPEG1`` - 'MPG1' - - MPEG1 video elementary stream. + - MPEG1 Picture. Each buffer starts with a Picture header, followed + by other headers as needed and ending with the Picture data. + If :ref:`VIDIOC_ENUM_FMT` reports ``V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM`` + then the decoder has no requirements since it can parse all the + information from the raw bytestream. * .. _V4L2-PIX-FMT-MPEG2: - ``V4L2_PIX_FMT_MPEG2`` - 'MPG2' - - MPEG2 video elementary stream. + - MPEG2 Picture. Each buffer starts with a Picture header, followed + by other headers as needed and ending with the Picture data. + If :ref:`VIDIOC_ENUM_FMT` reports ``V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM`` + then the decoder has no requirements since it can parse all the + information from the raw bytestream. * .. _V4L2-PIX-FMT-MPEG2-SLICE: - ``V4L2_PIX_FMT_MPEG2_SLICE`` @@ -132,17 +148,46 @@ Compressed Formats - ``V4L2_PIX_FMT_VP8`` - 'VP80' - - VP8 video elementary stream. + - VP8 compressed video frame. The encoder generates one + compressed frame per buffer, and the decoder requires one + compressed frame per buffer. + * .. _V4L2-PIX-FMT-VP8-FRAME: + + - ``V4L2_PIX_FMT_VP8_FRAME`` + - 'VP8F' + - VP8 parsed frame, as extracted from the container. + This format is adapted for stateless video decoders that implement a + VP8 pipeline (using the :ref:`mem2mem` and :ref:`media-request-api`). + Metadata associated with the frame to decode is required to be passed + through the ``V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER`` control. + See the :ref:`associated Codec Control IDs `. + Exactly one output and one capture buffer must be provided for use with + this pixel format. The output buffer must contain the appropriate number + of macroblocks to decode a full corresponding frame to the matching + capture buffer. + + .. note:: + + This format is not yet part of the public kernel API and it + is expected to change. + * .. _V4L2-PIX-FMT-VP9: - ``V4L2_PIX_FMT_VP9`` - 'VP90' - - VP9 video elementary stream. + - VP9 compressed video frame. The encoder generates one + compressed frame per buffer, and the decoder requires one + compressed frame per buffer. * .. _V4L2-PIX-FMT-HEVC: - ``V4L2_PIX_FMT_HEVC`` - 'HEVC' - - HEVC/H.265 video elementary stream. + - HEVC/H.265 Access Unit. + The decoder expects one Access Unit per buffer. + The encoder generates one Access Unit per buffer. + If :ref:`VIDIOC_ENUM_FMT` reports ``V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM`` + then the decoder has no requirements since it can parse all the + information from the raw bytestream. * .. _V4L2-PIX-FMT-FWHT: - ``V4L2_PIX_FMT_FWHT`` @@ -150,6 +195,8 @@ Compressed Formats - Video elementary stream using a codec based on the Fast Walsh Hadamard Transform. This codec is implemented by the vicodec ('Virtual Codec') driver. See the codec-fwht.h header for more details. + :ref:`VIDIOC_ENUM_FMT` reports ``V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM`` + since the decoder can parse all the information from the raw bytestream. * .. _V4L2-PIX-FMT-FWHT-STATELESS: - ``V4L2_PIX_FMT_FWHT_STATELESS`` diff --git a/Documentation/media/uapi/v4l/pixfmt-packed-rgb.rst b/Documentation/media/uapi/v4l/pixfmt-packed-rgb.rst deleted file mode 100644 index 738bb14c0ee28243919d72f2617556aa99e7af0d..0000000000000000000000000000000000000000 --- a/Documentation/media/uapi/v4l/pixfmt-packed-rgb.rst +++ /dev/null @@ -1,1306 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _packed-rgb: - -****************** -Packed RGB formats -****************** - -Description -=========== - -These formats are designed to match the pixel formats of typical PC -graphics frame buffers. They occupy 8, 16, 24 or 32 bits per pixel. -These are all packed-pixel formats, meaning all the data for a pixel lie -next to each other in memory. - -.. raw:: latex - - \begingroup - \tiny - \setlength{\tabcolsep}{2pt} - -.. tabularcolumns:: |p{2.8cm}|p{2.0cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| - - -.. _rgb-formats: - -.. flat-table:: Packed RGB Image Formats - :header-rows: 2 - :stub-columns: 0 - - * - Identifier - - Code - - :cspan:`7` Byte 0 in memory - - :cspan:`7` Byte 1 - - :cspan:`7` Byte 2 - - :cspan:`7` Byte 3 - * - - - - - 7 - - 6 - - 5 - - 4 - - 3 - - 2 - - 1 - - 0 - - - 7 - - 6 - - 5 - - 4 - - 3 - - 2 - - 1 - - 0 - - - 7 - - 6 - - 5 - - 4 - - 3 - - 2 - - 1 - - 0 - - - 7 - - 6 - - 5 - - 4 - - 3 - - 2 - - 1 - - 0 - * .. _V4L2-PIX-FMT-RGB332: - - - ``V4L2_PIX_FMT_RGB332`` - - 'RGB1' - - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - b\ :sub:`1` - - b\ :sub:`0` - - - * .. _V4L2-PIX-FMT-ARGB444: - - - ``V4L2_PIX_FMT_ARGB444`` - - 'AR12' - - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - * .. _V4L2-PIX-FMT-XRGB444: - - - ``V4L2_PIX_FMT_XRGB444`` - - 'XR12' - - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - - - - - - - - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - * .. _V4L2-PIX-FMT-RGBA444: - - - ``V4L2_PIX_FMT_RGBA444`` - - 'RA12' - - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` - - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - * .. _V4L2-PIX-FMT-RGBX444: - - - ``V4L2_PIX_FMT_RGBX444`` - - 'RX12' - - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - - - - - - - - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - * .. _V4L2-PIX-FMT-ABGR444: - - - ``V4L2_PIX_FMT_ABGR444`` - - 'AB12' - - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - * .. _V4L2-PIX-FMT-XBGR444: - - - ``V4L2_PIX_FMT_XBGR444`` - - 'XB12' - - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - - - - - - - - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - * .. _V4L2-PIX-FMT-BGRA444: - - - ``V4L2_PIX_FMT_BGRA444`` - - 'BA12' - - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` - - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - * .. _V4L2-PIX-FMT-BGRX444: - - - ``V4L2_PIX_FMT_BGRX444`` - - 'BX12' - - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - - - - - - - - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - * .. _V4L2-PIX-FMT-ARGB555: - - - ``V4L2_PIX_FMT_ARGB555`` - - 'AR15' - - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - a - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - g\ :sub:`4` - - g\ :sub:`3` - - - * .. _V4L2-PIX-FMT-XRGB555: - - - ``V4L2_PIX_FMT_XRGB555`` - - 'XR15' - - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - g\ :sub:`4` - - g\ :sub:`3` - - - * .. _V4L2-PIX-FMT-RGBA555: - - - ``V4L2_PIX_FMT_RGBA555`` - - 'RA15' - - - g\ :sub:`1` - - g\ :sub:`0` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - a - - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - - * .. _V4L2-PIX-FMT-RGBX555: - - - ``V4L2_PIX_FMT_RGBX555`` - - 'RX15' - - - g\ :sub:`1` - - g\ :sub:`0` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - - * .. _V4L2-PIX-FMT-ABGR555: - - - ``V4L2_PIX_FMT_ABGR555`` - - 'AB15' - - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - a - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - g\ :sub:`4` - - g\ :sub:`3` - - - * .. _V4L2-PIX-FMT-XBGR555: - - - ``V4L2_PIX_FMT_XBGR555`` - - 'XB15' - - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - g\ :sub:`4` - - g\ :sub:`3` - - - * .. _V4L2-PIX-FMT-BGRA555: - - - ``V4L2_PIX_FMT_BGRA555`` - - 'BA15' - - - g\ :sub:`1` - - g\ :sub:`0` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - a - - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - - * .. _V4L2-PIX-FMT-BGRX555: - - - ``V4L2_PIX_FMT_BGRX555`` - - 'BX15' - - - g\ :sub:`1` - - g\ :sub:`0` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - - * .. _V4L2-PIX-FMT-RGB565: - - - ``V4L2_PIX_FMT_RGB565`` - - 'RGBP' - - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - - * .. _V4L2-PIX-FMT-ARGB555X: - - - ``V4L2_PIX_FMT_ARGB555X`` - - 'AR15' | (1 << 31) - - - a - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - g\ :sub:`4` - - g\ :sub:`3` - - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - * .. _V4L2-PIX-FMT-XRGB555X: - - - ``V4L2_PIX_FMT_XRGB555X`` - - 'XR15' | (1 << 31) - - - - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - g\ :sub:`4` - - g\ :sub:`3` - - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - * .. _V4L2-PIX-FMT-RGB565X: - - - ``V4L2_PIX_FMT_RGB565X`` - - 'RGBR' - - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - * .. _V4L2-PIX-FMT-BGR24: - - - ``V4L2_PIX_FMT_BGR24`` - - 'BGR3' - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - * .. _V4L2-PIX-FMT-RGB24: - - - ``V4L2_PIX_FMT_RGB24`` - - 'RGB3' - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - * .. _V4L2-PIX-FMT-BGR666: - - - ``V4L2_PIX_FMT_BGR666`` - - 'BGRH' - - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - g\ :sub:`5` - - g\ :sub:`4` - - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - - r\ :sub:`1` - - r\ :sub:`0` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * .. _V4L2-PIX-FMT-ABGR32: - - - ``V4L2_PIX_FMT_ABGR32`` - - 'AR24' - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - a\ :sub:`7` - - a\ :sub:`6` - - a\ :sub:`5` - - a\ :sub:`4` - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` - * .. _V4L2-PIX-FMT-XBGR32: - - - ``V4L2_PIX_FMT_XBGR32`` - - 'XR24' - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - - - - - - - - - - - - - - - - * .. _V4L2-PIX-FMT-BGRA32: - - - ``V4L2_PIX_FMT_BGRA32`` - - 'RA24' - - - a\ :sub:`7` - - a\ :sub:`6` - - a\ :sub:`5` - - a\ :sub:`4` - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - * .. _V4L2-PIX-FMT-BGRX32: - - - ``V4L2_PIX_FMT_BGRX32`` - - 'RX24' - - - - - - - - - - - - - - - - - - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - * .. _V4L2-PIX-FMT-RGBA32: - - - ``V4L2_PIX_FMT_RGBA32`` - - 'AB24' - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - a\ :sub:`7` - - a\ :sub:`6` - - a\ :sub:`5` - - a\ :sub:`4` - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` - * .. _V4L2-PIX-FMT-RGBX32: - - - ``V4L2_PIX_FMT_RGBX32`` - - 'XB24' - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - - - - - - - - - - - - - - - - * .. _V4L2-PIX-FMT-ARGB32: - - - ``V4L2_PIX_FMT_ARGB32`` - - 'BA24' - - - a\ :sub:`7` - - a\ :sub:`6` - - a\ :sub:`5` - - a\ :sub:`4` - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - * .. _V4L2-PIX-FMT-XRGB32: - - - ``V4L2_PIX_FMT_XRGB32`` - - 'BX24' - - - - - - - - - - - - - - - - - - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - -.. raw:: latex - - \endgroup - -.. note:: Bit 7 is the most significant bit. - -The usage and value of the alpha bits (a) in the ARGB and ABGR formats -(collectively referred to as alpha formats) depend on the device type -and hardware operation. :ref:`Capture ` devices (including -capture queues of mem-to-mem devices) fill the alpha component in -memory. When the device outputs an alpha channel the alpha component -will have a meaningful value. Otherwise, when the device doesn't output -an alpha channel but can set the alpha bit to a user-configurable value, -the :ref:`V4L2_CID_ALPHA_COMPONENT ` control -is used to specify that alpha value, and the alpha component of all -pixels will be set to the value specified by that control. Otherwise a -corresponding format without an alpha component (XRGB or XBGR) must be -used instead of an alpha format. - -:ref:`Output ` devices (including output queues of mem-to-mem -devices and :ref:`video output overlay ` devices) read the alpha -component from memory. When the device processes the alpha channel the -alpha component must be filled with meaningful values by applications. -Otherwise a corresponding format without an alpha component (XRGB or -XBGR) must be used instead of an alpha format. - -The XRGB and XBGR formats contain undefined bits (-). Applications, -devices and drivers must ignore those bits, for both -:ref:`capture` and :ref:`output` devices. - -**Byte Order.** -Each cell is one byte. - - -.. raw:: latex - - \small - -.. tabularcolumns:: |p{3.1cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}| - -.. flat-table:: RGB byte order - :header-rows: 0 - :stub-columns: 0 - :widths: 11 3 3 3 3 3 3 3 3 3 3 3 3 - - * - start + 0: - - B\ :sub:`00` - - G\ :sub:`00` - - R\ :sub:`00` - - B\ :sub:`01` - - G\ :sub:`01` - - R\ :sub:`01` - - B\ :sub:`02` - - G\ :sub:`02` - - R\ :sub:`02` - - B\ :sub:`03` - - G\ :sub:`03` - - R\ :sub:`03` - * - start + 12: - - B\ :sub:`10` - - G\ :sub:`10` - - R\ :sub:`10` - - B\ :sub:`11` - - G\ :sub:`11` - - R\ :sub:`11` - - B\ :sub:`12` - - G\ :sub:`12` - - R\ :sub:`12` - - B\ :sub:`13` - - G\ :sub:`13` - - R\ :sub:`13` - * - start + 24: - - B\ :sub:`20` - - G\ :sub:`20` - - R\ :sub:`20` - - B\ :sub:`21` - - G\ :sub:`21` - - R\ :sub:`21` - - B\ :sub:`22` - - G\ :sub:`22` - - R\ :sub:`22` - - B\ :sub:`23` - - G\ :sub:`23` - - R\ :sub:`23` - * - start + 36: - - B\ :sub:`30` - - G\ :sub:`30` - - R\ :sub:`30` - - B\ :sub:`31` - - G\ :sub:`31` - - R\ :sub:`31` - - B\ :sub:`32` - - G\ :sub:`32` - - R\ :sub:`32` - - B\ :sub:`33` - - G\ :sub:`33` - - R\ :sub:`33` - -.. raw:: latex - - \normalsize - -Formats defined in :ref:`rgb-formats-deprecated` are deprecated and -must not be used by new drivers. They are documented here for reference. -The meaning of their alpha bits ``(a)`` are ill-defined and interpreted as in -either the corresponding ARGB or XRGB format, depending on the driver. - - -.. raw:: latex - - \begingroup - \tiny - \setlength{\tabcolsep}{2pt} - -.. tabularcolumns:: |p{2.6cm}|p{0.70cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| - -.. _rgb-formats-deprecated: - -.. flat-table:: Deprecated Packed RGB Image Formats - :header-rows: 2 - :stub-columns: 0 - - * - Identifier - - Code - - :cspan:`7` Byte 0 in memory - - - :cspan:`7` Byte 1 - - - :cspan:`7` Byte 2 - - - :cspan:`7` Byte 3 - * - - - - - 7 - - 6 - - 5 - - 4 - - 3 - - 2 - - 1 - - 0 - - - 7 - - 6 - - 5 - - 4 - - 3 - - 2 - - 1 - - 0 - - - 7 - - 6 - - 5 - - 4 - - 3 - - 2 - - 1 - - 0 - - - 7 - - 6 - - 5 - - 4 - - 3 - - 2 - - 1 - - 0 - * .. _V4L2-PIX-FMT-RGB444: - - - ``V4L2_PIX_FMT_RGB444`` - - 'R444' - - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - * .. _V4L2-PIX-FMT-RGB555: - - - ``V4L2_PIX_FMT_RGB555`` - - 'RGBO' - - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - a - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - g\ :sub:`4` - - g\ :sub:`3` - - - * .. _V4L2-PIX-FMT-RGB555X: - - - ``V4L2_PIX_FMT_RGB555X`` - - 'RGBQ' - - - a - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - g\ :sub:`4` - - g\ :sub:`3` - - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - * .. _V4L2-PIX-FMT-BGR32: - - - ``V4L2_PIX_FMT_BGR32`` - - 'BGR4' - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - a\ :sub:`7` - - a\ :sub:`6` - - a\ :sub:`5` - - a\ :sub:`4` - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` - * .. _V4L2-PIX-FMT-RGB32: - - - ``V4L2_PIX_FMT_RGB32`` - - 'RGB4' - - - a\ :sub:`7` - - a\ :sub:`6` - - a\ :sub:`5` - - a\ :sub:`4` - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - -.. raw:: latex - - \endgroup - -A test utility to determine which RGB formats a driver actually supports -is available from the LinuxTV v4l-dvb repository. See -`https://linuxtv.org/repo/ `__ for access -instructions. diff --git a/Documentation/media/uapi/v4l/pixfmt-rgb.rst b/Documentation/media/uapi/v4l/pixfmt-rgb.rst index 48ab800248352788b4950aaa923d57963414eca9..4ce305cc45da265e306f72da4fa8e5e42b01117c 100644 --- a/Documentation/media/uapi/v4l/pixfmt-rgb.rst +++ b/Documentation/media/uapi/v4l/pixfmt-rgb.rst @@ -13,18 +13,1292 @@ RGB Formats *********** +Description +=========== -.. toctree:: - :maxdepth: 1 - - pixfmt-packed-rgb - pixfmt-srggb8 - pixfmt-srggb10 - pixfmt-srggb10p - pixfmt-srggb10alaw8 - pixfmt-srggb10dpcm8 - pixfmt-srggb10-ipu3 - pixfmt-srggb12 - pixfmt-srggb12p - pixfmt-srggb14p - pixfmt-srggb16 +These formats are designed to match the pixel formats of typical PC +graphics frame buffers. They occupy 8, 16, 24 or 32 bits per pixel. +These are all packed-pixel formats, meaning all the data for a pixel lie +next to each other in memory. + +.. raw:: latex + + \begingroup + \tiny + \setlength{\tabcolsep}{2pt} + +.. tabularcolumns:: |p{2.8cm}|p{2.0cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| + + +.. flat-table:: RGB Image Formats + :header-rows: 2 + :stub-columns: 0 + + * - Identifier + - Code + - :cspan:`7` Byte 0 in memory + - :cspan:`7` Byte 1 + - :cspan:`7` Byte 2 + - :cspan:`7` Byte 3 + * - + - + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + * .. _V4L2-PIX-FMT-RGB332: + + - ``V4L2_PIX_FMT_RGB332`` + - 'RGB1' + + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`1` + - b\ :sub:`0` + - + * .. _V4L2-PIX-FMT-ARGB444: + + - ``V4L2_PIX_FMT_ARGB444`` + - 'AR12' + + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - + * .. _V4L2-PIX-FMT-XRGB444: + + - ``V4L2_PIX_FMT_XRGB444`` + - 'XR12' + + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - + - + - + - + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - + * .. _V4L2-PIX-FMT-RGBA444: + + - ``V4L2_PIX_FMT_RGBA444`` + - 'RA12' + + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - + * .. _V4L2-PIX-FMT-RGBX444: + + - ``V4L2_PIX_FMT_RGBX444`` + - 'RX12' + + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - + - + - + - + + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - + * .. _V4L2-PIX-FMT-ABGR444: + + - ``V4L2_PIX_FMT_ABGR444`` + - 'AB12' + + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - + * .. _V4L2-PIX-FMT-XBGR444: + + - ``V4L2_PIX_FMT_XBGR444`` + - 'XB12' + + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - + - + - + - + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - + * .. _V4L2-PIX-FMT-BGRA444: + + - ``V4L2_PIX_FMT_BGRA444`` + - 'BA12' + + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - + * .. _V4L2-PIX-FMT-BGRX444: + + - ``V4L2_PIX_FMT_BGRX444`` + - 'BX12' + + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - + - + - + - + + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - + * .. _V4L2-PIX-FMT-ARGB555: + + - ``V4L2_PIX_FMT_ARGB555`` + - 'AR15' + + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - a + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + - + * .. _V4L2-PIX-FMT-XRGB555: + + - ``V4L2_PIX_FMT_XRGB555`` + - 'XR15' + + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + - + * .. _V4L2-PIX-FMT-RGBA555: + + - ``V4L2_PIX_FMT_RGBA555`` + - 'RA15' + + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - a + + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - + * .. _V4L2-PIX-FMT-RGBX555: + + - ``V4L2_PIX_FMT_RGBX555`` + - 'RX15' + + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - + + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - + * .. _V4L2-PIX-FMT-ABGR555: + + - ``V4L2_PIX_FMT_ABGR555`` + - 'AB15' + + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - a + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + - + * .. _V4L2-PIX-FMT-XBGR555: + + - ``V4L2_PIX_FMT_XBGR555`` + - 'XB15' + + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + - + * .. _V4L2-PIX-FMT-BGRA555: + + - ``V4L2_PIX_FMT_BGRA555`` + - 'BA15' + + - g\ :sub:`1` + - g\ :sub:`0` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - a + + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - + * .. _V4L2-PIX-FMT-BGRX555: + + - ``V4L2_PIX_FMT_BGRX555`` + - 'BX15' + + - g\ :sub:`1` + - g\ :sub:`0` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - + + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - + * .. _V4L2-PIX-FMT-RGB565: + + - ``V4L2_PIX_FMT_RGB565`` + - 'RGBP' + + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - + * .. _V4L2-PIX-FMT-ARGB555X: + + - ``V4L2_PIX_FMT_ARGB555X`` + - 'AR15' | (1 << 31) + + - a + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - + * .. _V4L2-PIX-FMT-XRGB555X: + + - ``V4L2_PIX_FMT_XRGB555X`` + - 'XR15' | (1 << 31) + + - + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - + * .. _V4L2-PIX-FMT-RGB565X: + + - ``V4L2_PIX_FMT_RGB565X`` + - 'RGBR' + + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - + * .. _V4L2-PIX-FMT-BGR24: + + - ``V4L2_PIX_FMT_BGR24`` + - 'BGR3' + + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - + * .. _V4L2-PIX-FMT-RGB24: + + - ``V4L2_PIX_FMT_RGB24`` + - 'RGB3' + + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - + * .. _V4L2-PIX-FMT-BGR666: + + - ``V4L2_PIX_FMT_BGR666`` + - 'BGRH' + + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - g\ :sub:`5` + - g\ :sub:`4` + + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + + - r\ :sub:`1` + - r\ :sub:`0` + - + - + - + - + - + - + + - + - + - + - + - + - + - + - + * .. _V4L2-PIX-FMT-ABGR32: + + - ``V4L2_PIX_FMT_ABGR32`` + - 'AR24' + + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - a\ :sub:`7` + - a\ :sub:`6` + - a\ :sub:`5` + - a\ :sub:`4` + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + * .. _V4L2-PIX-FMT-XBGR32: + + - ``V4L2_PIX_FMT_XBGR32`` + - 'XR24' + + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - + - + - + - + - + - + - + - + * .. _V4L2-PIX-FMT-BGRA32: + + - ``V4L2_PIX_FMT_BGRA32`` + - 'RA24' + + - a\ :sub:`7` + - a\ :sub:`6` + - a\ :sub:`5` + - a\ :sub:`4` + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + * .. _V4L2-PIX-FMT-BGRX32: + + - ``V4L2_PIX_FMT_BGRX32`` + - 'RX24' + + - + - + - + - + - + - + - + - + + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + * .. _V4L2-PIX-FMT-RGBA32: + + - ``V4L2_PIX_FMT_RGBA32`` + - 'AB24' + + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - a\ :sub:`7` + - a\ :sub:`6` + - a\ :sub:`5` + - a\ :sub:`4` + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + * .. _V4L2-PIX-FMT-RGBX32: + + - ``V4L2_PIX_FMT_RGBX32`` + - 'XB24' + + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - + - + - + - + - + - + - + - + * .. _V4L2-PIX-FMT-ARGB32: + + - ``V4L2_PIX_FMT_ARGB32`` + - 'BA24' + + - a\ :sub:`7` + - a\ :sub:`6` + - a\ :sub:`5` + - a\ :sub:`4` + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + * .. _V4L2-PIX-FMT-XRGB32: + + - ``V4L2_PIX_FMT_XRGB32`` + - 'BX24' + + - + - + - + - + - + - + - + - + + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + +.. raw:: latex + + \endgroup + +.. note:: Bit 7 is the most significant bit. + +The usage and value of the alpha bits (a) in the ARGB and ABGR formats +(collectively referred to as alpha formats) depend on the device type +and hardware operation. :ref:`Capture ` devices (including +capture queues of mem-to-mem devices) fill the alpha component in +memory. When the device outputs an alpha channel the alpha component +will have a meaningful value. Otherwise, when the device doesn't output +an alpha channel but can set the alpha bit to a user-configurable value, +the :ref:`V4L2_CID_ALPHA_COMPONENT ` control +is used to specify that alpha value, and the alpha component of all +pixels will be set to the value specified by that control. Otherwise a +corresponding format without an alpha component (XRGB or XBGR) must be +used instead of an alpha format. + +:ref:`Output ` devices (including output queues of mem-to-mem +devices and :ref:`video output overlay ` devices) read the alpha +component from memory. When the device processes the alpha channel the +alpha component must be filled with meaningful values by applications. +Otherwise a corresponding format without an alpha component (XRGB or +XBGR) must be used instead of an alpha format. + +The XRGB and XBGR formats contain undefined bits (-). Applications, +devices and drivers must ignore those bits, for both +:ref:`capture` and :ref:`output` devices. + +**Byte Order.** +Each cell is one byte. + + +.. raw:: latex + + \small + +.. tabularcolumns:: |p{3.1cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}| + +.. flat-table:: RGB byte order + :header-rows: 0 + :stub-columns: 0 + :widths: 11 3 3 3 3 3 3 3 3 3 3 3 3 + + * - start + 0: + - B\ :sub:`00` + - G\ :sub:`00` + - R\ :sub:`00` + - B\ :sub:`01` + - G\ :sub:`01` + - R\ :sub:`01` + - B\ :sub:`02` + - G\ :sub:`02` + - R\ :sub:`02` + - B\ :sub:`03` + - G\ :sub:`03` + - R\ :sub:`03` + * - start + 12: + - B\ :sub:`10` + - G\ :sub:`10` + - R\ :sub:`10` + - B\ :sub:`11` + - G\ :sub:`11` + - R\ :sub:`11` + - B\ :sub:`12` + - G\ :sub:`12` + - R\ :sub:`12` + - B\ :sub:`13` + - G\ :sub:`13` + - R\ :sub:`13` + * - start + 24: + - B\ :sub:`20` + - G\ :sub:`20` + - R\ :sub:`20` + - B\ :sub:`21` + - G\ :sub:`21` + - R\ :sub:`21` + - B\ :sub:`22` + - G\ :sub:`22` + - R\ :sub:`22` + - B\ :sub:`23` + - G\ :sub:`23` + - R\ :sub:`23` + * - start + 36: + - B\ :sub:`30` + - G\ :sub:`30` + - R\ :sub:`30` + - B\ :sub:`31` + - G\ :sub:`31` + - R\ :sub:`31` + - B\ :sub:`32` + - G\ :sub:`32` + - R\ :sub:`32` + - B\ :sub:`33` + - G\ :sub:`33` + - R\ :sub:`33` + +.. raw:: latex + + \normalsize + +Formats defined in :ref:`pixfmt-rgb-deprecated` are deprecated and +must not be used by new drivers. They are documented here for reference. +The meaning of their alpha bits ``(a)`` are ill-defined and interpreted as in +either the corresponding ARGB or XRGB format, depending on the driver. + + +.. raw:: latex + + \begingroup + \tiny + \setlength{\tabcolsep}{2pt} + +.. tabularcolumns:: |p{2.6cm}|p{0.70cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| + +.. _pixfmt-rgb-deprecated: + +.. flat-table:: Deprecated Packed RGB Image Formats + :header-rows: 2 + :stub-columns: 0 + + * - Identifier + - Code + - :cspan:`7` Byte 0 in memory + + - :cspan:`7` Byte 1 + + - :cspan:`7` Byte 2 + + - :cspan:`7` Byte 3 + * - + - + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + * .. _V4L2-PIX-FMT-RGB444: + + - ``V4L2_PIX_FMT_RGB444`` + - 'R444' + + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - + * .. _V4L2-PIX-FMT-RGB555: + + - ``V4L2_PIX_FMT_RGB555`` + - 'RGBO' + + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - a + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + - + * .. _V4L2-PIX-FMT-RGB555X: + + - ``V4L2_PIX_FMT_RGB555X`` + - 'RGBQ' + + - a + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - + * .. _V4L2-PIX-FMT-BGR32: + + - ``V4L2_PIX_FMT_BGR32`` + - 'BGR4' + + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - a\ :sub:`7` + - a\ :sub:`6` + - a\ :sub:`5` + - a\ :sub:`4` + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + * .. _V4L2-PIX-FMT-RGB32: + + - ``V4L2_PIX_FMT_RGB32`` + - 'RGB4' + + - a\ :sub:`7` + - a\ :sub:`6` + - a\ :sub:`5` + - a\ :sub:`4` + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + +.. raw:: latex + + \endgroup + +A test utility to determine which RGB formats a driver actually supports +is available from the LinuxTV v4l-dvb repository. See +`https://linuxtv.org/repo/ `__ for access +instructions. diff --git a/Documentation/media/uapi/v4l/pixfmt-v4l2.rst b/Documentation/media/uapi/v4l/pixfmt-v4l2.rst index da6da2ef139a813189a9e9bdb8214a2bab1dacbb..a8321c348bf8cc0987bd7f1fbfdd3374f4f07067 100644 --- a/Documentation/media/uapi/v4l/pixfmt-v4l2.rst +++ b/Documentation/media/uapi/v4l/pixfmt-v4l2.rst @@ -39,12 +39,17 @@ Single-planar format structure to a multiple of the scale factor of any smaller planes. For example when the image format is YUV 4:2:0, ``width`` and ``height`` must be multiples of two. + + For compressed formats that contain the resolution information encoded + inside the stream, when fed to a stateful mem2mem decoder, the fields + may be zero to rely on the decoder to detect the right values. For more + details see :ref:`decoder` and format descriptions. * - __u32 - ``pixelformat`` - The pixel format or type of compression, set by the application. This is a little endian :ref:`four character code `. V4L2 defines standard - RGB formats in :ref:`rgb-formats`, YUV formats in + RGB formats in :ref:`pixfmt-rgb`, YUV formats in :ref:`yuv-formats`, and reserved codes in :ref:`reserved-formats` * - __u32 diff --git a/Documentation/media/uapi/v4l/pixfmt.rst b/Documentation/media/uapi/v4l/pixfmt.rst index 29be001796dbc0689e4523d9955567c88512e49f..a7d4cd43a298f853128d7c2151a11b73c71b39c9 100644 --- a/Documentation/media/uapi/v4l/pixfmt.rst +++ b/Documentation/media/uapi/v4l/pixfmt.rst @@ -31,6 +31,7 @@ see also :ref:`VIDIOC_G_FBUF `.) pixfmt-intro pixfmt-indexed pixfmt-rgb + pixfmt-bayer yuv-formats hsv-formats depth-formats diff --git a/Documentation/media/uapi/v4l/subdev-formats.rst b/Documentation/media/uapi/v4l/subdev-formats.rst index ab1a48a5ae80bdabb841532280b2ec0f4903e064..7b8e17c7b68b4ed7840232f18f7a7f497662caac 100644 --- a/Documentation/media/uapi/v4l/subdev-formats.rst +++ b/Documentation/media/uapi/v4l/subdev-formats.rst @@ -85,6 +85,14 @@ formats in memory (a raw Bayer image won't be magically converted to JPEG just by storing it to memory), there is no one-to-one correspondence between them. +The media bus pixel codes document parallel formats. Should the pixel data be +transported over a serial bus, the media bus pixel code that describes a +parallel format that transfers a sample on a single clock cycle is used. For +instance, both MEDIA_BUS_FMT_BGR888_1X24 and MEDIA_BUS_FMT_BGR888_3X8 are used +on parallel busses for transferring an 8 bits per sample BGR data, whereas on +serial busses the data in this format is only referred to using +MEDIA_BUS_FMT_BGR888_1X24. This is because there is effectively only a single +way to transport that format on the serial busses. Packed RGB Formats ^^^^^^^^^^^^^^^^^^ diff --git a/Documentation/media/uapi/v4l/v4l2.rst b/Documentation/media/uapi/v4l/v4l2.rst index 004ec00db6bdc71b94770f999b8543a9c26a32f4..97015b9b40b8a57c35e45f8619f57125570b25e5 100644 --- a/Documentation/media/uapi/v4l/v4l2.rst +++ b/Documentation/media/uapi/v4l/v4l2.rst @@ -60,6 +60,10 @@ Authors, in alphabetical order: - Original author of the V4L2 API and documentation. +- Figa, Tomasz + + - Documented the memory-to-memory decoder interface. + - H Schimek, Michael - Original author of the V4L2 API and documentation. @@ -68,6 +72,10 @@ Authors, in alphabetical order: - Documented the Digital Video timings API. +- Osciak, Pawel + + - Documented the memory-to-memory decoder interface. + - Osciak, Pawel - Designed and documented the multi-planar API. @@ -92,7 +100,7 @@ Authors, in alphabetical order: - Designed and documented the VIDIOC_LOG_STATUS ioctl, the extended control ioctls, major parts of the sliced VBI API, the MPEG encoder and decoder APIs and the DV Timings API. -**Copyright** |copy| 1999-2016: Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab, Pawel Osciak, Sakari Ailus & Antti Palosaari. +**Copyright** |copy| 1999-2018: Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab, Pawel Osciak, Sakari Ailus & Antti Palosaari, Tomasz Figa Except when explicitly stated as GPL, programming examples within this part can be used and distributed without restrictions. diff --git a/Documentation/media/uapi/v4l/vidioc-decoder-cmd.rst b/Documentation/media/uapi/v4l/vidioc-decoder-cmd.rst index ccf83b05afa736718797c5289e6c4a187ddebc57..57f0066f4cfffaf5ddb4fd5e567d89a386759661 100644 --- a/Documentation/media/uapi/v4l/vidioc-decoder-cmd.rst +++ b/Documentation/media/uapi/v4l/vidioc-decoder-cmd.rst @@ -56,14 +56,16 @@ The ``cmd`` field must contain the command code. Some commands use the A :ref:`write() ` or :ref:`VIDIOC_STREAMON` call sends an implicit START command to the decoder if it has not been -started yet. +started yet. Applies to both queues of mem2mem decoders. A :ref:`close() ` or :ref:`VIDIOC_STREAMOFF ` call of a streaming file descriptor sends an implicit immediate STOP -command to the decoder, and all buffered data is discarded. +command to the decoder, and all buffered data is discarded. Applies to both +queues of mem2mem decoders. -These ioctls are optional, not all drivers may support them. They were -introduced in Linux 3.3. +In principle, these ioctls are optional, not all drivers may support them. They were +introduced in Linux 3.3. They are, however, mandatory for stateful mem2mem decoders +(as further documented in :ref:`decoder`). .. tabularcolumns:: |p{1.1cm}|p{2.4cm}|p{1.2cm}|p{1.6cm}|p{10.6cm}| @@ -167,26 +169,32 @@ introduced in Linux 3.3. ``V4L2_DEC_CMD_RESUME`` for that. This command has one flag: ``V4L2_DEC_CMD_START_MUTE_AUDIO``. If set, then audio will be muted when playing back at a non-standard speed. + + For a device implementing the :ref:`decoder`, once the drain sequence + is initiated with the ``V4L2_DEC_CMD_STOP`` command, it must be driven + to completion before this command can be invoked. Any attempt to + invoke the command while the drain sequence is in progress will trigger + an ``EBUSY`` error code. The command may be also used to restart the + decoder in case of an implicit stop initiated by the decoder itself, + without the ``V4L2_DEC_CMD_STOP`` being called explicitly. See + :ref:`decoder` for more details. * - ``V4L2_DEC_CMD_STOP`` - 1 - Stop the decoder. When the decoder is already stopped, this command does nothing. This command has two flags: if ``V4L2_DEC_CMD_STOP_TO_BLACK`` is set, then the decoder will set the picture to black after it stopped decoding. Otherwise the last - image will repeat. mem2mem decoders will stop producing new frames - altogether. They will send a ``V4L2_EVENT_EOS`` event when the - last frame has been decoded and all frames are ready to be - dequeued and will set the ``V4L2_BUF_FLAG_LAST`` buffer flag on - the last buffer of the capture queue to indicate there will be no - new buffers produced to dequeue. This buffer may be empty, - indicated by the driver setting the ``bytesused`` field to 0. Once - the ``V4L2_BUF_FLAG_LAST`` flag was set, the - :ref:`VIDIOC_DQBUF ` ioctl will not block anymore, - but return an ``EPIPE`` error code. If + image will repeat. If ``V4L2_DEC_CMD_STOP_IMMEDIATELY`` is set, then the decoder stops immediately (ignoring the ``pts`` value), otherwise it will keep decoding until timestamp >= pts or until the last of the pending data from its internal buffers was decoded. + + For a device implementing the :ref:`decoder`, the command will initiate + the drain sequence as documented in :ref:`decoder`. No flags or other + arguments are accepted in this case. Any attempt to invoke the command + again before the sequence completes will trigger an ``EBUSY`` error + code. * - ``V4L2_DEC_CMD_PAUSE`` - 2 - Pause the decoder. When the decoder has not been started yet, the @@ -209,6 +217,11 @@ On success 0 is returned, on error -1 and the ``errno`` variable is set appropriately. The generic error codes are described at the :ref:`Generic Error Codes ` chapter. +EBUSY + A drain sequence of a device implementing the :ref:`decoder` is still in + progress. It is not allowed to issue another decoder command until it + completes. + EINVAL The ``cmd`` field is invalid. diff --git a/Documentation/media/uapi/v4l/vidioc-dqevent.rst b/Documentation/media/uapi/v4l/vidioc-dqevent.rst index dea9c0cc00ab92344bfe66909c2b308af9b5ac95..42659a3d170585d3b5006333a25ad6c36783a136 100644 --- a/Documentation/media/uapi/v4l/vidioc-dqevent.rst +++ b/Documentation/media/uapi/v4l/vidioc-dqevent.rst @@ -389,14 +389,19 @@ call. decoder. Applications will have to query the new resolution (if any, the signal may also have been lost). + For stateful decoders follow the guidelines in :ref:`decoder`. + Video Capture devices have to query the new timings using + :ref:`VIDIOC_QUERY_DV_TIMINGS` or + :ref:`VIDIOC_QUERYSTD `. + *Important*: even if the new video timings appear identical to the old ones, receiving this event indicates that there was an issue with the video signal and you must stop and restart streaming (:ref:`VIDIOC_STREAMOFF ` followed by :ref:`VIDIOC_STREAMON `). The reason is - that many devices are not able to recover from a temporary loss of - signal and so restarting streaming I/O is required in order for the - hardware to synchronize to the video signal. + that many Video Capture devices are not able to recover from a temporary + loss of signal and so restarting streaming I/O is required in order for + the hardware to synchronize to the video signal. Return Value diff --git a/Documentation/media/uapi/v4l/vidioc-enum-fmt.rst b/Documentation/media/uapi/v4l/vidioc-enum-fmt.rst index 822d6730e7d2c99e4ef9316a71d3bb22c1e5bad0..399ef1062bacb4abc43c741a6bc7bda5ae90e9f8 100644 --- a/Documentation/media/uapi/v4l/vidioc-enum-fmt.rst +++ b/Documentation/media/uapi/v4l/vidioc-enum-fmt.rst @@ -127,6 +127,22 @@ one until ``EINVAL`` is returned. - This format is not native to the device but emulated through software (usually libv4l2), where possible try to use a native format instead for better performance. + * - ``V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM`` + - 0x0004 + - The hardware decoder for this compressed bytestream format (aka coded + format) is capable of parsing a continuous bytestream. Applications do + not need to parse the bytestream themselves to find the boundaries + between frames/fields. This flag can only be used in combination with + the ``V4L2_FMT_FLAG_COMPRESSED`` flag, since this applies to compressed + formats only. This flag is valid for stateful decoders only. + * - ``V4L2_FMT_FLAG_DYN_RESOLUTION`` + - 0x0008 + - Dynamic resolution switching is supported by the device for this + compressed bytestream format (aka coded format). It will notify the user + via the event ``V4L2_EVENT_SOURCE_CHANGE`` when changes in the video + parameters are detected. This flag can only be used in combination + with the ``V4L2_FMT_FLAG_COMPRESSED`` flag, since this applies to + compressed formats only. It is also only applies to stateful codecs. Return Value diff --git a/Documentation/media/uapi/v4l/vidioc-queryctrl.rst b/Documentation/media/uapi/v4l/vidioc-queryctrl.rst index dc500632095db3a97bcf96306538962fad42ed9d..a3d56ffbf4cc489ff2c1c47261045ef14bd9be80 100644 --- a/Documentation/media/uapi/v4l/vidioc-queryctrl.rst +++ b/Documentation/media/uapi/v4l/vidioc-queryctrl.rst @@ -39,8 +39,8 @@ Arguments File descriptor returned by :ref:`open() `. ``argp`` - Pointer to struct :c:type:`v4l2_queryctl`, :c:type:`v4l2_query_ext_ctrl` - or :c:type`v4l2_querymenu` (depending on the ioctl). + Pointer to struct :c:type:`v4l2_queryctrl`, :c:type:`v4l2_query_ext_ctrl` + or :c:type:`v4l2_querymenu` (depending on the ioctl). Description diff --git a/Documentation/media/v4l-drivers/imx7.rst b/Documentation/media/v4l-drivers/imx7.rst index fe411f65c01cc03d2180c783736f20adc420ee41..1e442c97da477d5756f060d8b8f22ffb94c9c9ea 100644 --- a/Documentation/media/v4l-drivers/imx7.rst +++ b/Documentation/media/v4l-drivers/imx7.rst @@ -41,7 +41,7 @@ data from MIPI CSI-2 camera sensor. It has one source pad, corresponding to the virtual channel 0. This module is compliant to previous version of Samsung D-phy, and supports two D-PHY Rx Data lanes. -csi_mux +csi-mux ------- This is the video multiplexer. It has two sink pads to select from either camera @@ -56,7 +56,7 @@ can interface directly with Parallel and MIPI CSI-2 buses. It has 256 x 64 FIFO to store received image pixel data and embedded DMA controllers to transfer data from the FIFO through AHB bus. -This entity has one sink pad that receives from the csi_mux entity and a single +This entity has one sink pad that receives from the csi-mux entity and a single source pad that routes video frames directly to memory buffers. This pad is routed to a capture device node. @@ -81,14 +81,14 @@ an output of 800x600, and BGGR 10 bit bayer format: # Setup links media-ctl -l "'ov2680 1-0036':0 -> 'imx7-mipi-csis.0':0[1]" - media-ctl -l "'imx7-mipi-csis.0':1 -> 'csi_mux':1[1]" - media-ctl -l "'csi_mux':2 -> 'csi':0[1]" + media-ctl -l "'imx7-mipi-csis.0':1 -> 'csi-mux':1[1]" + media-ctl -l "'csi-mux':2 -> 'csi':0[1]" media-ctl -l "'csi':1 -> 'csi capture':0[1]" # Configure pads for pipeline media-ctl -V "'ov2680 1-0036':0 [fmt:SBGGR10_1X10/800x600 field:none]" - media-ctl -V "'csi_mux':1 [fmt:SBGGR10_1X10/800x600 field:none]" - media-ctl -V "'csi_mux':2 [fmt:SBGGR10_1X10/800x600 field:none]" + media-ctl -V "'csi-mux':1 [fmt:SBGGR10_1X10/800x600 field:none]" + media-ctl -V "'csi-mux':2 [fmt:SBGGR10_1X10/800x600 field:none]" media-ctl -V "'imx7-mipi-csis.0':0 [fmt:SBGGR10_1X10/800x600 field:none]" media-ctl -V "'csi':0 [fmt:SBGGR10_1X10/800x600 field:none]" @@ -97,64 +97,63 @@ the resolutions supported by the sensor. .. code-block:: none - root@imx7s-warp:~# media-ctl -p - Media controller API version 4.17.0 - - Media device information - ------------------------ - driver imx-media - model imx-media - serial - bus info - hw revision 0x0 - driver version 4.17.0 - - Device topology - - entity 1: csi (2 pads, 2 links) - type V4L2 subdev subtype Unknown flags 0 - device node name /dev/v4l-subdev0 - pad0: Sink - [fmt:SBGGR10_1X10/800x600 field:none] - <- "csi_mux":2 [ENABLED] - pad1: Source - [fmt:SBGGR10_1X10/800x600 field:none] - -> "csi capture":0 [ENABLED] - - - entity 4: csi capture (1 pad, 1 link) - type Node subtype V4L flags 0 - device node name /dev/video0 - pad0: Sink - <- "csi":1 [ENABLED] - - - entity 10: csi_mux (3 pads, 2 links) - type V4L2 subdev subtype Unknown flags 0 - device node name /dev/v4l-subdev1 - pad0: Sink - [fmt:unknown/0x0] - pad1: Sink - [fmt:unknown/800x600 field:none] - <- "imx7-mipi-csis.0":1 [ENABLED] - pad2: Source - [fmt:unknown/800x600 field:none] - -> "csi":0 [ENABLED] - - - entity 14: imx7-mipi-csis.0 (2 pads, 2 links) - type V4L2 subdev subtype Unknown flags 0 - device node name /dev/v4l-subdev2 - pad0: Sink - [fmt:SBGGR10_1X10/800x600 field:none] - <- "ov2680 1-0036":0 [ENABLED] - pad1: Source - [fmt:SBGGR10_1X10/800x600 field:none] - -> "csi_mux":1 [ENABLED] - - - entity 17: ov2680 1-0036 (1 pad, 1 link) - type V4L2 subdev subtype Sensor flags 0 - device node name /dev/v4l-subdev3 - pad0: Source - [fmt:SBGGR10_1X10/800x600 field:none] - -> "imx7-mipi-csis.0":0 [ENABLED] - + # media-ctl -p + Media controller API version 5.2.0 + + Media device information + ------------------------ + driver imx7-csi + model imx-media + serial + bus info + hw revision 0x0 + driver version 5.2.0 + + Device topology + - entity 1: csi (2 pads, 2 links) + type V4L2 subdev subtype Unknown flags 0 + device node name /dev/v4l-subdev0 + pad0: Sink + [fmt:SBGGR10_1X10/800x600 field:none colorspace:srgb xfer:srgb ycbcr:601 quantization:full-range] + <- "csi-mux":2 [ENABLED] + pad1: Source + [fmt:SBGGR10_1X10/800x600 field:none colorspace:srgb xfer:srgb ycbcr:601 quantization:full-range] + -> "csi capture":0 [ENABLED] + + - entity 4: csi capture (1 pad, 1 link) + type Node subtype V4L flags 0 + device node name /dev/video0 + pad0: Sink + <- "csi":1 [ENABLED] + + - entity 10: csi-mux (3 pads, 2 links) + type V4L2 subdev subtype Unknown flags 0 + device node name /dev/v4l-subdev1 + pad0: Sink + [fmt:Y8_1X8/1x1 field:none] + pad1: Sink + [fmt:SBGGR10_1X10/800x600 field:none] + <- "imx7-mipi-csis.0":1 [ENABLED] + pad2: Source + [fmt:SBGGR10_1X10/800x600 field:none] + -> "csi":0 [ENABLED] + + - entity 14: imx7-mipi-csis.0 (2 pads, 2 links) + type V4L2 subdev subtype Unknown flags 0 + device node name /dev/v4l-subdev2 + pad0: Sink + [fmt:SBGGR10_1X10/800x600 field:none] + <- "ov2680 1-0036":0 [ENABLED] + pad1: Source + [fmt:SBGGR10_1X10/800x600 field:none] + -> "csi-mux":1 [ENABLED] + + - entity 17: ov2680 1-0036 (1 pad, 1 link) + type V4L2 subdev subtype Sensor flags 0 + device node name /dev/v4l-subdev3 + pad0: Source + [fmt:SBGGR10_1X10/800x600@1/30 field:none colorspace:srgb] + -> "imx7-mipi-csis.0":0 [ENABLED] References ---------- diff --git a/Documentation/media/v4l-drivers/vimc.rst b/Documentation/media/v4l-drivers/vimc.rst index 4628b12d417fc83d4c23ecbb5f45b0fe7e532e1b..406417680db557af626e1d92a1eb377246d74386 100644 --- a/Documentation/media/v4l-drivers/vimc.rst +++ b/Documentation/media/v4l-drivers/vimc.rst @@ -15,7 +15,7 @@ recompile the driver to achieve your own topology. This is the default topology: .. _vimc_topology_graph: .. kernel-figure:: vimc.dot - :alt: vimc.dot + :alt: Diagram of the default media pipeline topology :align: center Media pipeline graph on vimc @@ -96,3 +96,14 @@ those arguments to each subdevice, not to the vimc module. For example:: Window size to calculate the mean. Note: the window size needs to be an odd number, as the main pixel stays in the center of the window, otherwise the next odd number is considered (the default value is 3). + +Source code documentation +------------------------- + +vimc-streamer +~~~~~~~~~~~~~ + +.. kernel-doc:: drivers/media/platform/vimc/vimc-streamer.h + :internal: + +.. kernel-doc:: drivers/media/platform/vimc/vimc-streamer.c diff --git a/Documentation/media/videodev2.h.rst.exceptions b/Documentation/media/videodev2.h.rst.exceptions index 55cbe324b9fc71cee89ad5a31456ea1ef47ace15..adeb6b7a15cb33aa052cd594deec4a6971054ba4 100644 --- a/Documentation/media/videodev2.h.rst.exceptions +++ b/Documentation/media/videodev2.h.rst.exceptions @@ -180,15 +180,17 @@ replace define V4L2_PIX_FMT_FLAG_PREMUL_ALPHA reserved-formats # V4L2 format flags replace define V4L2_FMT_FLAG_COMPRESSED fmtdesc-flags replace define V4L2_FMT_FLAG_EMULATED fmtdesc-flags +replace define V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM fmtdesc-flags +replace define V4L2_FMT_FLAG_DYN_RESOLUTION fmtdesc-flags -# V4L2 tymecode types +# V4L2 timecode types replace define V4L2_TC_TYPE_24FPS timecode-type replace define V4L2_TC_TYPE_25FPS timecode-type replace define V4L2_TC_TYPE_30FPS timecode-type replace define V4L2_TC_TYPE_50FPS timecode-type replace define V4L2_TC_TYPE_60FPS timecode-type -# V4L2 tymecode flags +# V4L2 timecode flags replace define V4L2_TC_FLAG_DROPFRAME timecode-flags replace define V4L2_TC_FLAG_COLORFRAME timecode-flags replace define V4L2_TC_USERBITS_field timecode-flags diff --git a/Documentation/mips/AU1xxx_IDE.README b/Documentation/mips/au1xxx_ide.rst similarity index 67% rename from Documentation/mips/AU1xxx_IDE.README rename to Documentation/mips/au1xxx_ide.rst index ff675a1b142223af49c7f2fad5dbbe82d7c7dafa..2f9c2cff67389fc9741f6e338bc9e872681a7cde 100644 --- a/Documentation/mips/AU1xxx_IDE.README +++ b/Documentation/mips/au1xxx_ide.rst @@ -1,7 +1,14 @@ -README for MIPS AU1XXX IDE driver - Released 2005-07-15 +.. include:: + +====================== +MIPS AU1XXX IDE driver +====================== + +Released 2005-07-15 + +About +===== -ABOUT ------ This file describes the 'drivers/ide/au1xxx-ide.c', related files and the services they provide. @@ -10,17 +17,17 @@ the white or black list, go to the 'ADD NEW HARD DISC TO WHITE OR BLACK LIST' section. -LICENSE -------- +License +======= -Copyright (c) 2003-2005 AMD, Personal Connectivity Solutions +:Copyright: |copy| 2003-2005 AMD, Personal Connectivity Solutions 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +THIS SOFTWARE IS PROVIDED ``AS IS`` AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR @@ -35,31 +42,35 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA. -Note: for more information, please refer "AMD Alchemy Au1200/Au1550 IDE +Note: + for more information, please refer "AMD Alchemy Au1200/Au1550 IDE Interface and Linux Device Driver" Application Note. -FILES, CONFIGS AND COMPATIBILITY --------------------------------- +Files, Configs and Compatibility +================================ Two files are introduced: a) 'arch/mips/include/asm/mach-au1x00/au1xxx_ide.h' contains : struct _auide_hwif - timing parameters for PIO mode 0/1/2/3/4 - timing parameters for MWDMA 0/1/2 + + - timing parameters for PIO mode 0/1/2/3/4 + - timing parameters for MWDMA 0/1/2 b) 'drivers/ide/mips/au1xxx-ide.c' contains the functionality of the AU1XXX IDE driver Following extra configs variables are introduced: - CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA - enable the PIO+DBDMA mode - CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - enable the MWDMA mode + CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA + - enable the PIO+DBDMA mode + CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA + - enable the MWDMA mode -SUPPORTED IDE MODES -------------------- +Supported IDE Modes +=================== The AU1XXX IDE driver supported all PIO modes - PIO mode 0/1/2/3/4 - and all MWDMA modes - MWDMA 0/1/2 -. There is no support for SWDMA and UDMA mode. @@ -69,20 +80,21 @@ To change the PIO mode use the program hdparm with option -p, e.g. -X, e.g. 'hdparm -X32 [device]' for MWDMA mode 0. -PERFORMANCE CONFIGURATIONS --------------------------- +Performance Configurations +========================== -If the used system doesn't need USB support enable the following kernel configs: +If the used system doesn't need USB support enable the following kernel +configs:: -CONFIG_IDE=y -CONFIG_BLK_DEV_IDE=y -CONFIG_IDE_GENERIC=y -CONFIG_BLK_DEV_IDEPCI=y -CONFIG_BLK_DEV_GENERIC=y -CONFIG_BLK_DEV_IDEDMA_PCI=y -CONFIG_BLK_DEV_IDE_AU1XXX=y -CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA=y -CONFIG_BLK_DEV_IDEDMA=y + CONFIG_IDE=y + CONFIG_BLK_DEV_IDE=y + CONFIG_IDE_GENERIC=y + CONFIG_BLK_DEV_IDEPCI=y + CONFIG_BLK_DEV_GENERIC=y + CONFIG_BLK_DEV_IDEDMA_PCI=y + CONFIG_BLK_DEV_IDE_AU1XXX=y + CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA=y + CONFIG_BLK_DEV_IDEDMA=y Also define 'IDE_AU1XXX_BURSTMODE' in 'drivers/ide/mips/au1xxx-ide.c' to enable the burst support on DBDMA controller. @@ -90,20 +102,22 @@ the burst support on DBDMA controller. If the used system need the USB support enable the following kernel configs for high IDE to USB throughput. -CONFIG_IDE_GENERIC=y -CONFIG_BLK_DEV_IDEPCI=y -CONFIG_BLK_DEV_GENERIC=y -CONFIG_BLK_DEV_IDEDMA_PCI=y -CONFIG_BLK_DEV_IDE_AU1XXX=y -CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA=y -CONFIG_BLK_DEV_IDEDMA=y +:: + + CONFIG_IDE_GENERIC=y + CONFIG_BLK_DEV_IDEPCI=y + CONFIG_BLK_DEV_GENERIC=y + CONFIG_BLK_DEV_IDEDMA_PCI=y + CONFIG_BLK_DEV_IDE_AU1XXX=y + CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA=y + CONFIG_BLK_DEV_IDEDMA=y Also undefine 'IDE_AU1XXX_BURSTMODE' in 'drivers/ide/mips/au1xxx-ide.c' to disable the burst support on DBDMA controller. -ACKNOWLEDGMENTS ---------------- +Acknowledgments +=============== These drivers wouldn't have been done without the base of kernel 2.4.x AU1XXX IDE driver from AMD. @@ -112,4 +126,5 @@ Additional input also from: Matthias Lenk Happy hacking! + Enrico Walther diff --git a/Documentation/mips/index.rst b/Documentation/mips/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..fd9023c8a89f5806033a2e24e65b47425a830911 --- /dev/null +++ b/Documentation/mips/index.rst @@ -0,0 +1,17 @@ +.. SPDX-License-Identifier: GPL-2.0 + +================= +MIPS architecture +================= + +.. toctree:: + :maxdepth: 2 + + au1xxx_ide + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/misc-devices/index.rst b/Documentation/misc-devices/index.rst index a57f92dfe49ab60a082efb072042d14f23a52897..f11c5daeada5485f04767fbe707eaa92dc2e2a0f 100644 --- a/Documentation/misc-devices/index.rst +++ b/Documentation/misc-devices/index.rst @@ -20,3 +20,4 @@ fit into other categories. isl29003 lis3lv02d max6875 + xilinx_sdfec diff --git a/Documentation/networking/af_xdp.rst b/Documentation/networking/af_xdp.rst index eeedc2e826aa066c89b2073d8fd26100a66fdf8d..83f7ae5fc045e22ad7e35dfdb65dd3e7e342e0b3 100644 --- a/Documentation/networking/af_xdp.rst +++ b/Documentation/networking/af_xdp.rst @@ -153,10 +153,12 @@ an example, if the UMEM is 64k and each chunk is 4k, then the UMEM has Frames passed to the kernel are used for the ingress path (RX rings). -The user application produces UMEM addrs to this ring. Note that the -kernel will mask the incoming addr. E.g. for a chunk size of 2k, the -log2(2048) LSB of the addr will be masked off, meaning that 2048, 2050 -and 3000 refers to the same chunk. +The user application produces UMEM addrs to this ring. Note that, if +running the application with aligned chunk mode, the kernel will mask +the incoming addr. E.g. for a chunk size of 2k, the log2(2048) LSB of +the addr will be masked off, meaning that 2048, 2050 and 3000 refers +to the same chunk. If the user application is run in the unaligned +chunks mode, then the incoming addr will be left untouched. UMEM Completion Ring diff --git a/Documentation/networking/caif/README b/Documentation/networking/caif/caif.rst similarity index 70% rename from Documentation/networking/caif/README rename to Documentation/networking/caif/caif.rst index 757ccfaa138565e8a418992dd5b83413bc6d3579..07afc8063d4d54ec286d4d3273256e082c351aa1 100644 --- a/Documentation/networking/caif/README +++ b/Documentation/networking/caif/caif.rst @@ -1,18 +1,31 @@ -Copyright (C) ST-Ericsson AB 2010 -Author: Sjur Brendeland/ sjur.brandeland@stericsson.com -License terms: GNU General Public License (GPL) version 2 ---------------------------------------------------------- +:orphan: -=== Start === -If you have compiled CAIF for modules do: +.. SPDX-License-Identifier: GPL-2.0 +.. include:: -$modprobe crc_ccitt -$modprobe caif -$modprobe caif_socket -$modprobe chnl_net +================ +Using Linux CAIF +================ -=== Preparing the setup with a STE modem === + +:Copyright: |copy| ST-Ericsson AB 2010 + +:Author: Sjur Brendeland/ sjur.brandeland@stericsson.com + +Start +===== + +If you have compiled CAIF for modules do:: + + $modprobe crc_ccitt + $modprobe caif + $modprobe caif_socket + $modprobe chnl_net + + +Preparing the setup with a STE modem +==================================== If you are working on integration of CAIF you should make sure that the kernel is built with module support. @@ -32,24 +45,30 @@ module parameter "ser_use_stx". Normally Frame Checksum is always used on UART, but this is also provided as a module parameter "ser_use_fcs". -$ modprobe caif_serial ser_ttyname=/dev/ttyS0 ser_use_stx=yes -$ ifconfig caif_ttyS0 up +:: + + $ modprobe caif_serial ser_ttyname=/dev/ttyS0 ser_use_stx=yes + $ ifconfig caif_ttyS0 up -PLEASE NOTE: There is a limitation in Android shell. +PLEASE NOTE: + There is a limitation in Android shell. It only accepts one argument to insmod/modprobe! -=== Trouble shooting === +Trouble shooting +================ There are debugfs parameters provided for serial communication. /sys/kernel/debug/caif_serial// * ser_state: Prints the bit-mask status where + - 0x02 means SENDING, this is a transient state. - 0x10 means FLOW_OFF_SENT, i.e. the previous frame has not been sent - and is blocking further send operation. Flow OFF has been propagated - to all CAIF Channels using this TTY. + and is blocking further send operation. Flow OFF has been propagated + to all CAIF Channels using this TTY. * tty_status: Prints the bit-mask tty status information + - 0x01 - tty->warned is on. - 0x02 - tty->low_latency is on. - 0x04 - tty->packed is on. @@ -58,13 +77,17 @@ There are debugfs parameters provided for serial communication. - 0x20 - tty->stopped is on. * last_tx_msg: Binary blob Prints the last transmitted frame. - This can be printed with + + This can be printed with:: + $od --format=x1 /sys/kernel/debug/caif_serial//last_rx_msg. - The first two tx messages sent look like this. Note: The initial - byte 02 is start of frame extension (STX) used for re-syncing - upon errors. - - Enumeration: + The first two tx messages sent look like this. Note: The initial + byte 02 is start of frame extension (STX) used for re-syncing + upon errors. + + - Enumeration:: + 0000000 02 05 00 00 03 01 d2 02 | | | | | | STX(1) | | | | @@ -73,7 +96,9 @@ There are debugfs parameters provided for serial communication. Command:Enumeration(1) Link-ID(1) Checksum(2) - - Channel Setup: + + - Channel Setup:: + 0000000 02 07 00 00 00 21 a1 00 48 df | | | | | | | | STX(1) | | | | | | @@ -86,13 +111,18 @@ There are debugfs parameters provided for serial communication. Checksum(2) * last_rx_msg: Prints the last transmitted frame. - The RX messages for LinkSetup look almost identical but they have the - bit 0x20 set in the command bit, and Channel Setup has added one byte - before Checksum containing Channel ID. - NOTE: Several CAIF Messages might be concatenated. The maximum debug + + The RX messages for LinkSetup look almost identical but they have the + bit 0x20 set in the command bit, and Channel Setup has added one byte + before Checksum containing Channel ID. + + NOTE: + Several CAIF Messages might be concatenated. The maximum debug buffer size is 128 bytes. -== Error Scenarios: +Error Scenarios +=============== + - last_tx_msg contains channel setup message and last_rx_msg is empty -> The host seems to be able to send over the UART, at least the CAIF ldisc get notified that sending is completed. @@ -103,7 +133,9 @@ There are debugfs parameters provided for serial communication. - if /sys/kernel/debug/caif_serial//tty_status is non-zero there might be problems transmitting over UART. + E.g. host and modem wiring is not correct you will typically see tty_status = 0x10 (hw_stopped) and ser_state = 0x10 (FLOW_OFF_SENT). + You will probably see the enumeration message in last_tx_message and empty last_rx_message. diff --git a/Documentation/networking/device_drivers/index.rst b/Documentation/networking/device_drivers/index.rst index 2b7fefe72351d9e858000092a3e628c0effb8817..f51f92571e395409e96cecd25ee4a3d6721a859c 100644 --- a/Documentation/networking/device_drivers/index.rst +++ b/Documentation/networking/device_drivers/index.rst @@ -23,8 +23,9 @@ Contents: intel/ice google/gve mellanox/mlx5 + pensando/ionic -.. only:: subproject +.. only:: subproject and html Indices ======= diff --git a/Documentation/networking/device_drivers/intel/iavf.rst b/Documentation/networking/device_drivers/intel/iavf.rst index 2d0c3baa17528928fcb8fa5e8a0ce10e5fef1edf..cfc08842e32c6e4c00839c13a2861c5e32bb890d 100644 --- a/Documentation/networking/device_drivers/intel/iavf.rst +++ b/Documentation/networking/device_drivers/intel/iavf.rst @@ -10,11 +10,15 @@ Copyright(c) 2013-2018 Intel Corporation. Contents ======== +- Overview - Identifying Your Adapter - Additional Configurations - Known Issues/Troubleshooting - Support +Overview +======== + This file describes the iavf Linux* Base Driver. This driver was formerly called i40evf. @@ -27,6 +31,7 @@ The guest OS loading the iavf driver must support MSI-X interrupts. Identifying Your Adapter ======================== + The driver in this kernel is compatible with devices based on the following: * Intel(R) XL710 X710 Virtual Function * Intel(R) X722 Virtual Function @@ -50,9 +55,10 @@ Link messages will not be displayed to the console if the distribution is restricting system messages. In order to see network driver link messages on your console, set dmesg to eight by entering the following:: - dmesg -n 8 + # dmesg -n 8 -NOTE: This setting is not saved across reboots. +NOTE: + This setting is not saved across reboots. ethtool ------- @@ -72,11 +78,11 @@ then requests from that VF to set VLAN tag stripping will be ignored. To enable/disable VLAN tag stripping for a VF, issue the following command from inside the VM in which you are running the VF:: - ethtool -K rxvlan on/off + # ethtool -K rxvlan on/off or alternatively:: - ethtool --offload rxvlan on/off + # ethtool --offload rxvlan on/off Adaptive Virtual Function ------------------------- @@ -91,21 +97,21 @@ additional features depending on what features are available in the PF with which the AVF is associated. The following are base mode features: - 4 Queue Pairs (QP) and associated Configuration Status Registers (CSRs) - for Tx/Rx. -- i40e descriptors and ring format. -- Descriptor write-back completion. -- 1 control queue, with i40e descriptors, CSRs and ring format. -- 5 MSI-X interrupt vectors and corresponding i40e CSRs. -- 1 Interrupt Throttle Rate (ITR) index. -- 1 Virtual Station Interface (VSI) per VF. + for Tx/Rx +- i40e descriptors and ring format +- Descriptor write-back completion +- 1 control queue, with i40e descriptors, CSRs and ring format +- 5 MSI-X interrupt vectors and corresponding i40e CSRs +- 1 Interrupt Throttle Rate (ITR) index +- 1 Virtual Station Interface (VSI) per VF - 1 Traffic Class (TC), TC0 - Receive Side Scaling (RSS) with 64 entry indirection table and key, - configured through the PF. -- 1 unicast MAC address reserved per VF. -- 16 MAC address filters for each VF. -- Stateless offloads - non-tunneled checksums. -- AVF device ID. -- HW mailbox is used for VF to PF communications (including on Windows). + configured through the PF +- 1 unicast MAC address reserved per VF +- 16 MAC address filters for each VF +- Stateless offloads - non-tunneled checksums +- AVF device ID +- HW mailbox is used for VF to PF communications (including on Windows) IEEE 802.1ad (QinQ) Support --------------------------- @@ -117,8 +123,8 @@ VLAN ID, among other uses. The following are examples of how to configure 802.1ad (QinQ):: - ip link add link eth0 eth0.24 type vlan proto 802.1ad id 24 - ip link add link eth0.24 eth0.24.371 type vlan proto 802.1Q id 371 + # ip link add link eth0 eth0.24 type vlan proto 802.1ad id 24 + # ip link add link eth0.24 eth0.24.371 type vlan proto 802.1Q id 371 Where "24" and "371" are example VLAN IDs. @@ -133,6 +139,19 @@ specific application. This can reduce latency for the specified application, and allow Tx traffic to be rate limited per application. Follow the steps below to set ADq. +Requirements: + +- The sch_mqprio, act_mirred and cls_flower modules must be loaded +- The latest version of iproute2 +- If another driver (for example, DPDK) has set cloud filters, you cannot + enable ADQ +- Depending on the underlying PF device, ADQ cannot be enabled when the + following features are enabled: + + + Data Center Bridging (DCB) + + Multiple Functions per Port (MFP) + + Sideband Filters + 1. Create traffic classes (TCs). Maximum of 8 TCs can be created per interface. The shaper bw_rlimit parameter is optional. @@ -141,9 +160,9 @@ to 1Gbit for tc0 and 3Gbit for tc1. :: - # tc qdisc add dev root mqprio num_tc 2 map 0 0 0 0 1 1 1 1 - queues 16@0 16@16 hw 1 mode channel shaper bw_rlimit min_rate 1Gbit 2Gbit - max_rate 1Gbit 3Gbit + tc qdisc add dev root mqprio num_tc 2 map 0 0 0 0 1 1 1 1 + queues 16@0 16@16 hw 1 mode channel shaper bw_rlimit min_rate 1Gbit 2Gbit + max_rate 1Gbit 3Gbit map: priority mapping for up to 16 priorities to tcs (e.g. map 0 0 0 0 1 1 1 1 sets priorities 0-3 to use tc0 and 4-7 to use tc1) @@ -162,6 +181,10 @@ Totals must be equal or less than port speed. For example: min_rate 1Gbit 3Gbit: Verify bandwidth limit using network monitoring tools such as ifstat or sar –n DEV [interval] [number of samples] +NOTE: + Setting up channels via ethtool (ethtool -L) is not supported when the + TCs are configured using mqprio. + 2. Enable HW TC offload on interface:: # ethtool -K hw-tc-offload on @@ -171,16 +194,16 @@ monitoring tools such as ifstat or sar –n DEV [interval] [number of samples] # tc qdisc add dev ingress NOTES: - - Run all tc commands from the iproute2 /tc/ directory. - - ADq is not compatible with cloud filters. + - Run all tc commands from the iproute2 /tc/ directory + - ADq is not compatible with cloud filters - Setting up channels via ethtool (ethtool -L) is not supported when the TCs - are configured using mqprio. + are configured using mqprio - You must have iproute2 latest version - - NVM version 6.01 or later is required. + - NVM version 6.01 or later is required - ADq cannot be enabled when any the following features are enabled: Data - Center Bridging (DCB), Multiple Functions per Port (MFP), or Sideband Filters. + Center Bridging (DCB), Multiple Functions per Port (MFP), or Sideband Filters - If another driver (for example, DPDK) has set cloud filters, you cannot - enable ADq. + enable ADq - Tunnel filters are not supported in ADq. If encapsulated packets do arrive in non-tunnel mode, filtering will be done on the inner headers. For example, for VXLAN traffic in non-tunnel mode, PCTYPE is identified as a VXLAN @@ -198,6 +221,16 @@ NOTES: Known Issues/Troubleshooting ============================ +Bonding fails with VFs bound to an Intel(R) Ethernet Controller 700 series device +--------------------------------------------------------------------------------- +If you bind Virtual Functions (VFs) to an Intel(R) Ethernet Controller 700 +series based device, the VF slaves may fail when they become the active slave. +If the MAC address of the VF is set by the PF (Physical Function) of the +device, when you add a slave, or change the active-backup slave, Linux bonding +tries to sync the backup slave's MAC address to the same MAC address as the +active slave. Linux bonding will fail at this point. This issue will not occur +if the VF's MAC address is not set by the PF. + Traffic Is Not Being Passed Between VM and Client ------------------------------------------------- You may not be able to pass traffic between a client system and a @@ -215,13 +248,28 @@ Do not unload a port's driver if a Virtual Function (VF) with an active Virtual Machine (VM) is bound to it. Doing so will cause the port to appear to hang. Once the VM shuts down, or otherwise releases the VF, the command will complete. +Using four traffic classes fails +-------------------------------- +Do not try to reserve more than three traffic classes in the iavf driver. Doing +so will fail to set any traffic classes and will cause the driver to write +errors to stdout. Use a maximum of three queues to avoid this issue. + +Multiple log error messages on iavf driver removal +-------------------------------------------------- +If you have several VFs and you remove the iavf driver, several instances of +the following log errors are written to the log:: + + Unable to send opcode 2 to PF, err I40E_ERR_QUEUE_EMPTY, aq_err ok + Unable to send the message to VF 2 aq_err 12 + ARQ Overflow Error detected + Virtual machine does not get link --------------------------------- If the virtual machine has more than one virtual port assigned to it, and those virtual ports are bound to different physical ports, you may not get link on all of the virtual ports. The following command may work around the issue:: - ethtool -r + # ethtool -r Where is the PF interface in the host, for example: p5p1. You may need to run the command more than once to get link on all virtual ports. @@ -251,12 +299,13 @@ traffic. If you have multiple interfaces in a server, either turn on ARP filtering by entering:: - echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter + # echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter -NOTE: This setting is not saved across reboots. The configuration change can be -made permanent by adding the following line to the file /etc/sysctl.conf:: +NOTE: + This setting is not saved across reboots. The configuration change can be + made permanent by adding the following line to the file /etc/sysctl.conf:: - net.ipv4.conf.all.arp_filter = 1 + net.ipv4.conf.all.arp_filter = 1 Another alternative is to install the interfaces in separate broadcast domains (either in different switches or in a switch partitioned to VLANs). diff --git a/Documentation/networking/device_drivers/mellanox/mlx5.rst b/Documentation/networking/device_drivers/mellanox/mlx5.rst index 214325897732f5846fb68a2de85feb4cbfca6e3d..d071c6b49e1ff9d7d83bec0c6d722d644554c703 100644 --- a/Documentation/networking/device_drivers/mellanox/mlx5.rst +++ b/Documentation/networking/device_drivers/mellanox/mlx5.rst @@ -11,7 +11,9 @@ Contents - `Enabling the driver and kconfig options`_ - `Devlink info`_ +- `Devlink parameters`_ - `Devlink health reporters`_ +- `mlx5 tracepoints`_ Enabling the driver and kconfig options ================================================ @@ -121,12 +123,44 @@ User command example:: stored: fw.version 16.26.0100 +Devlink parameters +================== + +flow_steering_mode: Device flow steering mode +--------------------------------------------- +The flow steering mode parameter controls the flow steering mode of the driver. +Two modes are supported: +1. 'dmfs' - Device managed flow steering. +2. 'smfs - Software/Driver managed flow steering. + +In DMFS mode, the HW steering entities are created and managed through the +Firmware. +In SMFS mode, the HW steering entities are created and managed though by +the driver directly into Hardware without firmware intervention. + +SMFS mode is faster and provides better rule inserstion rate compared to default DMFS mode. + +User command examples: + +- Set SMFS flow steering mode:: + + $ devlink dev param set pci/0000:06:00.0 name flow_steering_mode value "smfs" cmode runtime + +- Read device flow steering mode:: + + $ devlink dev param show pci/0000:06:00.0 name flow_steering_mode + pci/0000:06:00.0: + name flow_steering_mode type driver-specific + values: + cmode runtime value smfs + + Devlink health reporters ======================== tx reporter ----------- -The tx reporter is responsible of two error scenarios: +The tx reporter is responsible for reporting and recovering of the following two error scenarios: - TX timeout Report on kernel tx timeout detection. @@ -135,7 +169,7 @@ The tx reporter is responsible of two error scenarios: Report on error tx completion. Recover by flushing the TX queue and reset it. -TX reporter also support Diagnose callback, on which it provides +TX reporter also support on demand diagnose callback, on which it provides real time information of its send queues status. User commands examples: @@ -144,11 +178,40 @@ User commands examples: $ devlink health diagnose pci/0000:82:00.0 reporter tx +NOTE: This command has valid output only when interface is up, otherwise the command has empty output. + - Show number of tx errors indicated, number of recover flows ended successfully, is autorecover enabled and graceful period from last recover:: $ devlink health show pci/0000:82:00.0 reporter tx +rx reporter +----------- +The rx reporter is responsible for reporting and recovering of the following two error scenarios: + +- RX queues initialization (population) timeout + RX queues descriptors population on ring initialization is done in + napi context via triggering an irq, in case of a failure to get + the minimum amount of descriptors, a timeout would occur and it + could be recoverable by polling the EQ (Event Queue). +- RX completions with errors (reported by HW on interrupt context) + Report on rx completion error. + Recover (if needed) by flushing the related queue and reset it. + +RX reporter also supports on demand diagnose callback, on which it +provides real time information of its receive queues status. + +- Diagnose rx queues status, and corresponding completion queue:: + + $ devlink health diagnose pci/0000:82:00.0 reporter rx + +NOTE: This command has valid output only when interface is up, otherwise the command has empty output. + +- Show number of rx errors indicated, number of recover flows ended successfully, + is autorecover enabled and graceful period from last recover:: + + $ devlink health show pci/0000:82:00.0 reporter rx + fw reporter ----------- The fw reporter implements diagnose and dump callbacks. @@ -190,3 +253,48 @@ User commands examples: $ devlink health dump show pci/0000:82:00.1 reporter fw_fatal NOTE: This command can run only on PF. + +mlx5 tracepoints +================ + +mlx5 driver provides internal trace points for tracking and debugging using +kernel tracepoints interfaces (refer to Documentation/trace/ftrase.rst). + +For the list of support mlx5 events check /sys/kernel/debug/tracing/events/mlx5/ + +tc and eswitch offloads tracepoints: + +- mlx5e_configure_flower: trace flower filter actions and cookies offloaded to mlx5:: + + $ echo mlx5:mlx5e_configure_flower >> /sys/kernel/debug/tracing/set_event + $ cat /sys/kernel/debug/tracing/trace + ... + tc-6535 [019] ...1 2672.404466: mlx5e_configure_flower: cookie=0000000067874a55 actions= REDIRECT + +- mlx5e_delete_flower: trace flower filter actions and cookies deleted from mlx5:: + + $ echo mlx5:mlx5e_delete_flower >> /sys/kernel/debug/tracing/set_event + $ cat /sys/kernel/debug/tracing/trace + ... + tc-6569 [010] .N.1 2686.379075: mlx5e_delete_flower: cookie=0000000067874a55 actions= NULL + +- mlx5e_stats_flower: trace flower stats request:: + + $ echo mlx5:mlx5e_stats_flower >> /sys/kernel/debug/tracing/set_event + $ cat /sys/kernel/debug/tracing/trace + ... + tc-6546 [010] ...1 2679.704889: mlx5e_stats_flower: cookie=0000000060eb3d6a bytes=0 packets=0 lastused=4295560217 + +- mlx5e_tc_update_neigh_used_value: trace tunnel rule neigh update value offloaded to mlx5:: + + $ echo mlx5:mlx5e_tc_update_neigh_used_value >> /sys/kernel/debug/tracing/set_event + $ cat /sys/kernel/debug/tracing/trace + ... + kworker/u48:4-8806 [009] ...1 55117.882428: mlx5e_tc_update_neigh_used_value: netdev: ens1f0 IPv4: 1.1.1.10 IPv6: ::ffff:1.1.1.10 neigh_used=1 + +- mlx5e_rep_neigh_update: trace neigh update tasks scheduled due to neigh state change events:: + + $ echo mlx5:mlx5e_rep_neigh_update >> /sys/kernel/debug/tracing/set_event + $ cat /sys/kernel/debug/tracing/trace + ... + kworker/u48:7-2221 [009] ...1 1475.387435: mlx5e_rep_neigh_update: netdev: ens1f0 MAC: 24:8a:07:9a:17:9a IPv4: 1.1.1.10 IPv6: ::ffff:1.1.1.10 neigh_connected=1 diff --git a/Documentation/networking/device_drivers/netronome/nfp.rst b/Documentation/networking/device_drivers/netronome/nfp.rst new file mode 100644 index 0000000000000000000000000000000000000000..6c08ac8b5147073eeeb9637f85551f3749b3bfd2 --- /dev/null +++ b/Documentation/networking/device_drivers/netronome/nfp.rst @@ -0,0 +1,133 @@ +.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +============================================= +Netronome Flow Processor (NFP) Kernel Drivers +============================================= + +Copyright (c) 2019, Netronome Systems, Inc. + +Contents +======== + +- `Overview`_ +- `Acquiring Firmware`_ + +Overview +======== + +This driver supports Netronome's line of Flow Processor devices, +including the NFP4000, NFP5000, and NFP6000 models, which are also +incorporated in the company's family of Agilio SmartNICs. The SR-IOV +physical and virtual functions for these devices are supported by +the driver. + +Acquiring Firmware +================== + +The NFP4000 and NFP6000 devices require application specific firmware +to function. Application firmware can be located either on the host file system +or in the device flash (if supported by management firmware). + +Firmware files on the host filesystem contain card type (`AMDA-*` string), media +config etc. They should be placed in `/lib/firmware/netronome` directory to +load firmware from the host file system. + +Firmware for basic NIC operation is available in the upstream +`linux-firmware.git` repository. + +Firmware in NVRAM +----------------- + +Recent versions of management firmware supports loading application +firmware from flash when the host driver gets probed. The firmware loading +policy configuration may be used to configure this feature appropriately. + +Devlink or ethtool can be used to update the application firmware on the device +flash by providing the appropriate `nic_AMDA*.nffw` file to the respective +command. Users need to take care to write the correct firmware image for the +card and media configuration to flash. + +Available storage space in flash depends on the card being used. + +Dealing with multiple projects +------------------------------ + +NFP hardware is fully programmable therefore there can be different +firmware images targeting different applications. + +When using application firmware from host, we recommend placing +actual firmware files in application-named subdirectories in +`/lib/firmware/netronome` and linking the desired files, e.g.:: + + $ tree /lib/firmware/netronome/ + /lib/firmware/netronome/ + ├── bpf + │   ├── nic_AMDA0081-0001_1x40.nffw + │   └── nic_AMDA0081-0001_4x10.nffw + ├── flower + │   ├── nic_AMDA0081-0001_1x40.nffw + │   └── nic_AMDA0081-0001_4x10.nffw + ├── nic + │   ├── nic_AMDA0081-0001_1x40.nffw + │   └── nic_AMDA0081-0001_4x10.nffw + ├── nic_AMDA0081-0001_1x40.nffw -> bpf/nic_AMDA0081-0001_1x40.nffw + └── nic_AMDA0081-0001_4x10.nffw -> bpf/nic_AMDA0081-0001_4x10.nffw + + 3 directories, 8 files + +You may need to use hard instead of symbolic links on distributions +which use old `mkinitrd` command instead of `dracut` (e.g. Ubuntu). + +After changing firmware files you may need to regenerate the initramfs +image. Initramfs contains drivers and firmware files your system may +need to boot. Refer to the documentation of your distribution to find +out how to update initramfs. Good indication of stale initramfs +is system loading wrong driver or firmware on boot, but when driver is +later reloaded manually everything works correctly. + +Selecting firmware per device +----------------------------- + +Most commonly all cards on the system use the same type of firmware. +If you want to load specific firmware image for a specific card, you +can use either the PCI bus address or serial number. Driver will print +which files it's looking for when it recognizes a NFP device:: + + nfp: Looking for firmware file in order of priority: + nfp: netronome/serial-00-12-34-aa-bb-cc-10-ff.nffw: not found + nfp: netronome/pci-0000:02:00.0.nffw: not found + nfp: netronome/nic_AMDA0081-0001_1x40.nffw: found, loading... + +In this case if file (or link) called *serial-00-12-34-aa-bb-5d-10-ff.nffw* +or *pci-0000:02:00.0.nffw* is present in `/lib/firmware/netronome` this +firmware file will take precedence over `nic_AMDA*` files. + +Note that `serial-*` and `pci-*` files are **not** automatically included +in initramfs, you will have to refer to documentation of appropriate tools +to find out how to include them. + +Firmware loading policy +----------------------- + +Firmware loading policy is controlled via three HWinfo parameters +stored as key value pairs in the device flash: + +app_fw_from_flash + Defines which firmware should take precedence, 'Disk' (0), 'Flash' (1) or + the 'Preferred' (2) firmware. When 'Preferred' is selected, the management + firmware makes the decision over which firmware will be loaded by comparing + versions of the flash firmware and the host supplied firmware. + This variable is configurable using the 'fw_load_policy' + devlink parameter. + +abi_drv_reset + Defines if the driver should reset the firmware when + the driver is probed, either 'Disk' (0) if firmware was found on disk, + 'Always' (1) reset or 'Never' (2) reset. Note that the device is always + reset on driver unload if firmware was loaded when the driver was probed. + This variable is configurable using the 'reset_dev_on_drv_probe' + devlink parameter. + +abi_drv_load_ifc + Defines a list of PF devices allowed to load FW on the device. + This variable is not currently user configurable. diff --git a/Documentation/networking/device_drivers/pensando/ionic.rst b/Documentation/networking/device_drivers/pensando/ionic.rst new file mode 100644 index 0000000000000000000000000000000000000000..67b6839d516b976d5c850d51d78dc6c5fcb64e1a --- /dev/null +++ b/Documentation/networking/device_drivers/pensando/ionic.rst @@ -0,0 +1,43 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +========================================================== +Linux* Driver for the Pensando(R) Ethernet adapter family +========================================================== + +Pensando Linux Ethernet driver. +Copyright(c) 2019 Pensando Systems, Inc + +Contents +======== + +- Identifying the Adapter +- Support + +Identifying the Adapter +======================= + +To find if one or more Pensando PCI Ethernet devices are installed on the +host, check for the PCI devices:: + + $ lspci -d 1dd8: + b5:00.0 Ethernet controller: Device 1dd8:1002 + b6:00.0 Ethernet controller: Device 1dd8:1002 + +If such devices are listed as above, then the ionic.ko driver should find +and configure them for use. There should be log entries in the kernel +messages such as these:: + + $ dmesg | grep ionic + ionic Pensando Ethernet NIC Driver, ver 0.15.0-k + ionic 0000:b5:00.0 enp181s0: renamed from eth0 + ionic 0000:b6:00.0 enp182s0: renamed from eth0 + +Support +======= +For general Linux networking support, please use the netdev mailing +list, which is monitored by Pensando personnel:: + netdev@vger.kernel.org + +For more specific support needs, please use the Pensando driver support +email:: + drivers@pensando.io diff --git a/Documentation/networking/devlink-info-versions.rst b/Documentation/networking/devlink-info-versions.rst index 4316342b77468fa000a83b19c8b36a904185b612..4914f581b1fd94d324f2c63f942d940bcca0c892 100644 --- a/Documentation/networking/devlink-info-versions.rst +++ b/Documentation/networking/devlink-info-versions.rst @@ -14,11 +14,27 @@ board.rev Board design revision. +asic.id +======= + +ASIC design identifier. + +asic.rev +======== + +ASIC design revision. + board.manufacture ================= An identifier of the company or the facility which produced the part. +fw +== + +Overall firmware version, often representing the collection of +fw.mgmt, fw.app, etc. + fw.mgmt ======= diff --git a/Documentation/networking/devlink-params-nfp.txt b/Documentation/networking/devlink-params-nfp.txt new file mode 100644 index 0000000000000000000000000000000000000000..43e4d4034865b350802c0bad9705e6220d15b7dc --- /dev/null +++ b/Documentation/networking/devlink-params-nfp.txt @@ -0,0 +1,5 @@ +fw_load_policy [DEVICE, GENERIC] + Configuration mode: permanent + +reset_dev_on_drv_probe [DEVICE, GENERIC] + Configuration mode: permanent diff --git a/Documentation/networking/devlink-params.txt b/Documentation/networking/devlink-params.txt index 2d26434ddcf8a5290c4ef9735c8f8e9e64491114..ddba3e9b55b1fcceb5972e347601f31208656eed 100644 --- a/Documentation/networking/devlink-params.txt +++ b/Documentation/networking/devlink-params.txt @@ -48,4 +48,20 @@ fw_load_policy [DEVICE, GENERIC] Load firmware version preferred by the driver. * DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH (1) Load firmware currently stored in flash. + * DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DISK (2) + Load firmware currently available on host's disk. + Type: u8 + +reset_dev_on_drv_probe [DEVICE, GENERIC] + Controls the device's reset policy on driver probe. + Valid values: + * DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_UNKNOWN (0) + Unknown or invalid value. + * DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_ALWAYS (1) + Always reset device on driver probe. + * DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_NEVER (2) + Never reset device on driver probe. + * DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK (3) + Reset only if device firmware can be found in the + filesystem. Type: u8 diff --git a/Documentation/networking/devlink-trap-netdevsim.rst b/Documentation/networking/devlink-trap-netdevsim.rst new file mode 100644 index 0000000000000000000000000000000000000000..b721c9415473bfa53cf39decde25474fa26c851d --- /dev/null +++ b/Documentation/networking/devlink-trap-netdevsim.rst @@ -0,0 +1,20 @@ +.. SPDX-License-Identifier: GPL-2.0 + +====================== +Devlink Trap netdevsim +====================== + +Driver-specific Traps +===================== + +.. list-table:: List of Driver-specific Traps Registered by ``netdevsim`` + :widths: 5 5 90 + + * - Name + - Type + - Description + * - ``fid_miss`` + - ``exception`` + - When a packet enters the device it is classified to a filtering + indentifier (FID) based on the ingress port and VLAN. This trap is used + to trap packets for which a FID could not be found diff --git a/Documentation/networking/devlink-trap.rst b/Documentation/networking/devlink-trap.rst new file mode 100644 index 0000000000000000000000000000000000000000..c20c7c4836640fa3f0cfe943b4d4d89367cb8ea7 --- /dev/null +++ b/Documentation/networking/devlink-trap.rst @@ -0,0 +1,208 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============ +Devlink Trap +============ + +Background +========== + +Devices capable of offloading the kernel's datapath and perform functions such +as bridging and routing must also be able to send specific packets to the +kernel (i.e., the CPU) for processing. + +For example, a device acting as a multicast-aware bridge must be able to send +IGMP membership reports to the kernel for processing by the bridge module. +Without processing such packets, the bridge module could never populate its +MDB. + +As another example, consider a device acting as router which has received an IP +packet with a TTL of 1. Upon routing the packet the device must send it to the +kernel so that it will route it as well and generate an ICMP Time Exceeded +error datagram. Without letting the kernel route such packets itself, utilities +such as ``traceroute`` could never work. + +The fundamental ability of sending certain packets to the kernel for processing +is called "packet trapping". + +Overview +======== + +The ``devlink-trap`` mechanism allows capable device drivers to register their +supported packet traps with ``devlink`` and report trapped packets to +``devlink`` for further analysis. + +Upon receiving trapped packets, ``devlink`` will perform a per-trap packets and +bytes accounting and potentially report the packet to user space via a netlink +event along with all the provided metadata (e.g., trap reason, timestamp, input +port). This is especially useful for drop traps (see :ref:`Trap-Types`) +as it allows users to obtain further visibility into packet drops that would +otherwise be invisible. + +The following diagram provides a general overview of ``devlink-trap``:: + + Netlink event: Packet w/ metadata + Or a summary of recent drops + ^ + | + Userspace | + +---------------------------------------------------+ + Kernel | + | + +-------+--------+ + | | + | drop_monitor | + | | + +-------^--------+ + | + | + | + +----+----+ + | | Kernel's Rx path + | devlink | (non-drop traps) + | | + +----^----+ ^ + | | + +-----------+ + | + +-------+-------+ + | | + | Device driver | + | | + +-------^-------+ + Kernel | + +---------------------------------------------------+ + Hardware | + | Trapped packet + | + +--+---+ + | | + | ASIC | + | | + +------+ + +.. _Trap-Types: + +Trap Types +========== + +The ``devlink-trap`` mechanism supports the following packet trap types: + + * ``drop``: Trapped packets were dropped by the underlying device. Packets + are only processed by ``devlink`` and not injected to the kernel's Rx path. + The trap action (see :ref:`Trap-Actions`) can be changed. + * ``exception``: Trapped packets were not forwarded as intended by the + underlying device due to an exception (e.g., TTL error, missing neighbour + entry) and trapped to the control plane for resolution. Packets are + processed by ``devlink`` and injected to the kernel's Rx path. Changing the + action of such traps is not allowed, as it can easily break the control + plane. + +.. _Trap-Actions: + +Trap Actions +============ + +The ``devlink-trap`` mechanism supports the following packet trap actions: + + * ``trap``: The sole copy of the packet is sent to the CPU. + * ``drop``: The packet is dropped by the underlying device and a copy is not + sent to the CPU. + +Generic Packet Traps +==================== + +Generic packet traps are used to describe traps that trap well-defined packets +or packets that are trapped due to well-defined conditions (e.g., TTL error). +Such traps can be shared by multiple device drivers and their description must +be added to the following table: + +.. list-table:: List of Generic Packet Traps + :widths: 5 5 90 + + * - Name + - Type + - Description + * - ``source_mac_is_multicast`` + - ``drop`` + - Traps incoming packets that the device decided to drop because of a + multicast source MAC + * - ``vlan_tag_mismatch`` + - ``drop`` + - Traps incoming packets that the device decided to drop in case of VLAN + tag mismatch: The ingress bridge port is not configured with a PVID and + the packet is untagged or prio-tagged + * - ``ingress_vlan_filter`` + - ``drop`` + - Traps incoming packets that the device decided to drop in case they are + tagged with a VLAN that is not configured on the ingress bridge port + * - ``ingress_spanning_tree_filter`` + - ``drop`` + - Traps incoming packets that the device decided to drop in case the STP + state of the ingress bridge port is not "forwarding" + * - ``port_list_is_empty`` + - ``drop`` + - Traps packets that the device decided to drop in case they need to be + flooded and the flood list is empty + * - ``port_loopback_filter`` + - ``drop`` + - Traps packets that the device decided to drop in case after layer 2 + forwarding the only port from which they should be transmitted through + is the port from which they were received + * - ``blackhole_route`` + - ``drop`` + - Traps packets that the device decided to drop in case they hit a + blackhole route + * - ``ttl_value_is_too_small`` + - ``exception`` + - Traps unicast packets that should be forwarded by the device whose TTL + was decremented to 0 or less + * - ``tail_drop`` + - ``drop`` + - Traps packets that the device decided to drop because they could not be + enqueued to a transmission queue which is full + +Driver-specific Packet Traps +============================ + +Device drivers can register driver-specific packet traps, but these must be +clearly documented. Such traps can correspond to device-specific exceptions and +help debug packet drops caused by these exceptions. The following list includes +links to the description of driver-specific traps registered by various device +drivers: + + * :doc:`/devlink-trap-netdevsim` + +Generic Packet Trap Groups +========================== + +Generic packet trap groups are used to aggregate logically related packet +traps. These groups allow the user to batch operations such as setting the trap +action of all member traps. In addition, ``devlink-trap`` can report aggregated +per-group packets and bytes statistics, in case per-trap statistics are too +narrow. The description of these groups must be added to the following table: + +.. list-table:: List of Generic Packet Trap Groups + :widths: 10 90 + + * - Name + - Description + * - ``l2_drops`` + - Contains packet traps for packets that were dropped by the device during + layer 2 forwarding (i.e., bridge) + * - ``l3_drops`` + - Contains packet traps for packets that were dropped by the device or hit + an exception (e.g., TTL error) during layer 3 forwarding + * - ``buffer_drops`` + - Contains packet traps for packets that were dropped by the device due to + an enqueue decision + +Testing +======= + +See ``tools/testing/selftests/drivers/net/netdevsim/devlink_trap.sh`` for a +test covering the core infrastructure. Test cases should be added for any new +functionality. + +Device drivers should focus their tests on device-specific functionality, such +as the triggering of supported packet traps. diff --git a/Documentation/networking/dsa/sja1105.rst b/Documentation/networking/dsa/sja1105.rst index cb2858dece93a84ae8308d983005d3655b8c409d..eef20d0bcf7c15183b7db65ba847dd47f2c45b60 100644 --- a/Documentation/networking/dsa/sja1105.rst +++ b/Documentation/networking/dsa/sja1105.rst @@ -146,6 +146,96 @@ enslaves eth0 and eth1 (the DSA master of the switch ports). This is because in this mode, the switch ports beneath br0 are not capable of regular traffic, and are only used as a conduit for switchdev operations. +Offloads +======== + +Time-aware scheduling +--------------------- + +The switch supports a variation of the enhancements for scheduled traffic +specified in IEEE 802.1Q-2018 (formerly 802.1Qbv). This means it can be used to +ensure deterministic latency for priority traffic that is sent in-band with its +gate-open event in the network schedule. + +This capability can be managed through the tc-taprio offload ('flags 2'). The +difference compared to the software implementation of taprio is that the latter +would only be able to shape traffic originated from the CPU, but not +autonomously forwarded flows. + +The device has 8 traffic classes, and maps incoming frames to one of them based +on the VLAN PCP bits (if no VLAN is present, the port-based default is used). +As described in the previous sections, depending on the value of +``vlan_filtering``, the EtherType recognized by the switch as being VLAN can +either be the typical 0x8100 or a custom value used internally by the driver +for tagging. Therefore, the switch ignores the VLAN PCP if used in standalone +or bridge mode with ``vlan_filtering=0``, as it will not recognize the 0x8100 +EtherType. In these modes, injecting into a particular TX queue can only be +done by the DSA net devices, which populate the PCP field of the tagging header +on egress. Using ``vlan_filtering=1``, the behavior is the other way around: +offloaded flows can be steered to TX queues based on the VLAN PCP, but the DSA +net devices are no longer able to do that. To inject frames into a hardware TX +queue with VLAN awareness active, it is necessary to create a VLAN +sub-interface on the DSA master port, and send normal (0x8100) VLAN-tagged +towards the switch, with the VLAN PCP bits set appropriately. + +Management traffic (having DMAC 01-80-C2-xx-xx-xx or 01-19-1B-xx-xx-xx) is the +notable exception: the switch always treats it with a fixed priority and +disregards any VLAN PCP bits even if present. The traffic class for management +traffic has a value of 7 (highest priority) at the moment, which is not +configurable in the driver. + +Below is an example of configuring a 500 us cyclic schedule on egress port +``swp5``. The traffic class gate for management traffic (7) is open for 100 us, +and the gates for all other traffic classes are open for 400 us:: + + #!/bin/bash + + set -e -u -o pipefail + + NSEC_PER_SEC="1000000000" + + gatemask() { + local tc_list="$1" + local mask=0 + + for tc in ${tc_list}; do + mask=$((${mask} | (1 << ${tc}))) + done + + printf "%02x" ${mask} + } + + if ! systemctl is-active --quiet ptp4l; then + echo "Please start the ptp4l service" + exit + fi + + now=$(phc_ctl /dev/ptp1 get | gawk '/clock time is/ { print $5; }') + # Phase-align the base time to the start of the next second. + sec=$(echo "${now}" | gawk -F. '{ print $1; }') + base_time="$(((${sec} + 1) * ${NSEC_PER_SEC}))" + + tc qdisc add dev swp5 parent root handle 100 taprio \ + num_tc 8 \ + map 0 1 2 3 5 6 7 \ + queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \ + base-time ${base_time} \ + sched-entry S $(gatemask 7) 100000 \ + sched-entry S $(gatemask "0 1 2 3 4 5 6") 400000 \ + flags 2 + +It is possible to apply the tc-taprio offload on multiple egress ports. There +are hardware restrictions related to the fact that no gate event may trigger +simultaneously on two ports. The driver checks the consistency of the schedules +against this restriction and errors out when appropriate. Schedule analysis is +needed to avoid this, which is outside the scope of the document. + +At the moment, the time-aware scheduler can only be triggered based on a +standalone clock and not based on PTP time. This means the base-time argument +from tc-taprio is ignored and the schedule starts right away. It also means it +is more difficult to phase-align the scheduler with the other devices in the +network. + Device Tree bindings and board design ===================================== diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst index a46fca264beed8299c6498bfb084523976b27453..d4dca42910d095f15a2573338d02f3d55fd4ace0 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -14,7 +14,10 @@ Contents: device_drivers/index dsa/index devlink-info-versions + devlink-trap + devlink-trap-netdevsim ieee802154 + j1939 kapi z8530book msg_zerocopy @@ -31,7 +34,7 @@ Contents: tls tls-offload -.. only:: subproject +.. only:: subproject and html Indices ======= diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index df33674799b5260933fe6bcef73dcb60f44096e3..49e95f438ed7571a93bceffdc17846c35dd64fca 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -256,6 +256,12 @@ tcp_base_mss - INTEGER Path MTU discovery (MTU probing). If MTU probing is enabled, this is the initial MSS used by the connection. +tcp_mtu_probe_floor - INTEGER + If MTU probing is enabled this caps the minimum MSS used for search_low + for the connection. + + Default : 48 + tcp_min_snd_mss - INTEGER TCP SYN and SYNACK messages usually advertise an ADVMSS option, as described in RFC 1122 and RFC 6691. diff --git a/Documentation/networking/j1939.rst b/Documentation/networking/j1939.rst new file mode 100644 index 0000000000000000000000000000000000000000..ce7e7a044e080e9209e13b9b4915b209e56b4574 --- /dev/null +++ b/Documentation/networking/j1939.rst @@ -0,0 +1,422 @@ +.. SPDX-License-Identifier: (GPL-2.0 OR MIT) + +=================== +J1939 Documentation +=================== + +Overview / What Is J1939 +======================== + +SAE J1939 defines a higher layer protocol on CAN. It implements a more +sophisticated addressing scheme and extends the maximum packet size above 8 +bytes. Several derived specifications exist, which differ from the original +J1939 on the application level, like MilCAN A, NMEA2000 and especially +ISO-11783 (ISOBUS). This last one specifies the so-called ETP (Extended +Transport Protocol) which is has been included in this implementation. This +results in a maximum packet size of ((2 ^ 24) - 1) * 7 bytes == 111 MiB. + +Specifications used +------------------- + +* SAE J1939-21 : data link layer +* SAE J1939-81 : network management +* ISO 11783-6 : Virtual Terminal (Extended Transport Protocol) + +.. _j1939-motivation: + +Motivation +========== + +Given the fact there's something like SocketCAN with an API similar to BSD +sockets, we found some reasons to justify a kernel implementation for the +addressing and transport methods used by J1939. + +* **Addressing:** when a process on an ECU communicates via J1939, it should + not necessarily know its source address. Although at least one process per + ECU should know the source address. Other processes should be able to reuse + that address. This way, address parameters for different processes + cooperating for the same ECU, are not duplicated. This way of working is + closely related to the UNIX concept where programs do just one thing, and do + it well. + +* **Dynamic addressing:** Address Claiming in J1939 is time critical. + Furthermore data transport should be handled properly during the address + negotiation. Putting this functionality in the kernel eliminates it as a + requirement for _every_ user space process that communicates via J1939. This + results in a consistent J1939 bus with proper addressing. + +* **Transport:** both TP & ETP reuse some PGNs to relay big packets over them. + Different processes may thus use the same TP & ETP PGNs without actually + knowing it. The individual TP & ETP sessions _must_ be serialized + (synchronized) between different processes. The kernel solves this problem + properly and eliminates the serialization (synchronization) as a requirement + for _every_ user space process that communicates via J1939. + +J1939 defines some other features (relaying, gateway, fast packet transport, +...). In-kernel code for these would not contribute to protocol stability. +Therefore, these parts are left to user space. + +The J1939 sockets operate on CAN network devices (see SocketCAN). Any J1939 +user space library operating on CAN raw sockets will still operate properly. +Since such library does not communicate with the in-kernel implementation, care +must be taken that these two do not interfere. In practice, this means they +cannot share ECU addresses. A single ECU (or virtual ECU) address is used by +the library exclusively, or by the in-kernel system exclusively. + +J1939 concepts +============== + +PGN +--- + +The PGN (Parameter Group Number) is a number to identify a packet. The PGN +is composed as follows: +1 bit : Reserved Bit +1 bit : Data Page +8 bits : PF (PDU Format) +8 bits : PS (PDU Specific) + +In J1939-21 distinction is made between PDU1 format (where PF < 240) and PDU2 +format (where PF >= 240). Furthermore, when using PDU2 format, the PS-field +contains a so-called Group Extension, which is part of the PGN. When using PDU2 +format, the Group Extension is set in the PS-field. + +On the other hand, when using PDU1 format, the PS-field contains a so-called +Destination Address, which is _not_ part of the PGN. When communicating a PGN +from user space to kernel (or visa versa) and PDU2 format is used, the PS-field +of the PGN shall be set to zero. The Destination Address shall be set +elsewhere. + +Regarding PGN mapping to 29-bit CAN identifier, the Destination Address shall +be get/set from/to the appropriate bits of the identifier by the kernel. + + +Addressing +---------- + +Both static and dynamic addressing methods can be used. + +For static addresses, no extra checks are made by the kernel, and provided +addresses are considered right. This responsibility is for the OEM or system +integrator. + +For dynamic addressing, so-called Address Claiming, extra support is foreseen +in the kernel. In J1939 any ECU is known by it's 64-bit NAME. At the moment of +a successful address claim, the kernel keeps track of both NAME and source +address being claimed. This serves as a base for filter schemes. By default, +packets with a destination that is not locally, will be rejected. + +Mixed mode packets (from a static to a dynamic address or vice versa) are +allowed. The BSD sockets define separate API calls for getting/setting the +local & remote address and are applicable for J1939 sockets. + +Filtering +--------- + +J1939 defines white list filters per socket that a user can set in order to +receive a subset of the J1939 traffic. Filtering can be based on: + +* SA +* SOURCE_NAME +* PGN + +When multiple filters are in place for a single socket, and a packet comes in +that matches several of those filters, the packet is only received once for +that socket. + +How to Use J1939 +================ + +API Calls +--------- + +On CAN, you first need to open a socket for communicating over a CAN network. +To use J1939, #include . From there, will be +included too. To open a socket, use: + +.. code-block:: C + + s = socket(PF_CAN, SOCK_DGRAM, CAN_J1939); + +J1939 does use SOCK_DGRAM sockets. In the J1939 specification, connections are +mentioned in the context of transport protocol sessions. These still deliver +packets to the other end (using several CAN packets). SOCK_STREAM is not +supported. + +After the successful creation of the socket, you would normally use the bind(2) +and/or connect(2) system call to bind the socket to a CAN interface. After +binding and/or connecting the socket, you can read(2) and write(2) from/to the +socket or use send(2), sendto(2), sendmsg(2) and the recv*() counterpart +operations on the socket as usual. There are also J1939 specific socket options +described below. + +In order to send data, a bind(2) must have been successful. bind(2) assigns a +local address to a socket. + +Different from CAN is that the payload data is just the data that get send, +without it's header info. The header info is derived from the sockaddr supplied +to bind(2), connect(2), sendto(2) and recvfrom(2). A write(2) with size 4 will +result in a packet with 4 bytes. + +The sockaddr structure has extensions for use with J1939 as specified below: + +.. code-block:: C + + struct sockaddr_can { + sa_family_t can_family; + int can_ifindex; + union { + struct { + __u64 name; + /* pgn: + * 8 bit: PS in PDU2 case, else 0 + * 8 bit: PF + * 1 bit: DP + * 1 bit: reserved + */ + __u32 pgn; + __u8 addr; + } j1939; + } can_addr; + } + +can_family & can_ifindex serve the same purpose as for other SocketCAN sockets. + +can_addr.j1939.pgn specifies the PGN (max 0x3ffff). Individual bits are +specified above. + +can_addr.j1939.name contains the 64-bit J1939 NAME. + +can_addr.j1939.addr contains the address. + +The bind(2) system call assigns the local address, i.e. the source address when +sending packages. If a PGN during bind(2) is set, it's used as a RX filter. +I.e. only packets with a matching PGN are received. If an ADDR or NAME is set +it is used as a receive filter, too. It will match the destination NAME or ADDR +of the incoming packet. The NAME filter will work only if appropriate Address +Claiming for this name was done on the CAN bus and registered/cached by the +kernel. + +On the other hand connect(2) assigns the remote address, i.e. the destination +address. The PGN from connect(2) is used as the default PGN when sending +packets. If ADDR or NAME is set it will be used as the default destination ADDR +or NAME. Further a set ADDR or NAME during connect(2) is used as a receive +filter. It will match the source NAME or ADDR of the incoming packet. + +Both write(2) and send(2) will send a packet with local address from bind(2) and +the remote address from connect(2). Use sendto(2) to overwrite the destination +address. + +If can_addr.j1939.name is set (!= 0) the NAME is looked up by the kernel and +the corresponding ADDR is used. If can_addr.j1939.name is not set (== 0), +can_addr.j1939.addr is used. + +When creating a socket, reasonable defaults are set. Some options can be +modified with setsockopt(2) & getsockopt(2). + +RX path related options: + +- SO_J1939_FILTER - configure array of filters +- SO_J1939_PROMISC - disable filters set by bind(2) and connect(2) + +By default no broadcast packets can be send or received. To enable sending or +receiving broadcast packets use the socket option SO_BROADCAST: + +.. code-block:: C + + int value = 1; + setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value)); + +The following diagram illustrates the RX path: + +.. code:: + + +--------------------+ + | incoming packet | + +--------------------+ + | + V + +--------------------+ + | SO_J1939_PROMISC? | + +--------------------+ + | | + no | | yes + | | + .---------' `---------. + | | + +---------------------------+ | + | bind() + connect() + | | + | SOCK_BROADCAST filter | | + +---------------------------+ | + | | + |<---------------------' + V + +---------------------------+ + | SO_J1939_FILTER | + +---------------------------+ + | + V + +---------------------------+ + | socket recv() | + +---------------------------+ + +TX path related options: +SO_J1939_SEND_PRIO - change default send priority for the socket + +Message Flags during send() and Related System Calls +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +send(2), sendto(2) and sendmsg(2) take a 'flags' argument. Currently +supported flags are: + +* MSG_DONTWAIT, i.e. non-blocking operation. + +recvmsg(2) +^^^^^^^^^ + +In most cases recvmsg(2) is needed if you want to extract more information than +recvfrom(2) can provide. For example package priority and timestamp. The +Destination Address, name and packet priority (if applicable) are attached to +the msghdr in the recvmsg(2) call. They can be extracted using cmsg(3) macros, +with cmsg_level == SOL_J1939 && cmsg_type == SCM_J1939_DEST_ADDR, +SCM_J1939_DEST_NAME or SCM_J1939_PRIO. The returned data is a uint8_t for +priority and dst_addr, and uint64_t for dst_name. + +.. code-block:: C + + uint8_t priority, dst_addr; + uint64_t dst_name; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + switch (cmsg->cmsg_level) { + case SOL_CAN_J1939: + if (cmsg->cmsg_type == SCM_J1939_DEST_ADDR) + dst_addr = *CMSG_DATA(cmsg); + else if (cmsg->cmsg_type == SCM_J1939_DEST_NAME) + memcpy(&dst_name, CMSG_DATA(cmsg), cmsg->cmsg_len - CMSG_LEN(0)); + else if (cmsg->cmsg_type == SCM_J1939_PRIO) + priority = *CMSG_DATA(cmsg); + break; + } + } + +Dynamic Addressing +------------------ + +Distinction has to be made between using the claimed address and doing an +address claim. To use an already claimed address, one has to fill in the +j1939.name member and provide it to bind(2). If the name had claimed an address +earlier, all further messages being sent will use that address. And the +j1939.addr member will be ignored. + +An exception on this is PGN 0x0ee00. This is the "Address Claim/Cannot Claim +Address" message and the kernel will use the j1939.addr member for that PGN if +necessary. + +To claim an address following code example can be used: + +.. code-block:: C + + struct sockaddr_can baddr = { + .can_family = AF_CAN, + .can_addr.j1939 = { + .name = name, + .addr = J1939_IDLE_ADDR, + .pgn = J1939_NO_PGN, /* to disable bind() rx filter for PGN */ + }, + .can_ifindex = if_nametoindex("can0"), + }; + + bind(sock, (struct sockaddr *)&baddr, sizeof(baddr)); + + /* for Address Claiming broadcast must be allowed */ + int value = 1; + setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value)); + + /* configured advanced RX filter with PGN needed for Address Claiming */ + const struct j1939_filter filt[] = { + { + .pgn = J1939_PGN_ADDRESS_CLAIMED, + .pgn_mask = J1939_PGN_PDU1_MAX, + }, { + .pgn = J1939_PGN_ADDRESS_REQUEST, + .pgn_mask = J1939_PGN_PDU1_MAX, + }, { + .pgn = J1939_PGN_ADDRESS_COMMANDED, + .pgn_mask = J1939_PGN_MAX, + }, + }; + + setsockopt(sock, SOL_CAN_J1939, SO_J1939_FILTER, &filt, sizeof(filt)); + + uint64_t dat = htole64(name); + const struct sockaddr_can saddr = { + .can_family = AF_CAN, + .can_addr.j1939 = { + .pgn = J1939_PGN_ADDRESS_CLAIMED, + .addr = J1939_NO_ADDR, + }, + }; + + /* Afterwards do a sendto(2) with data set to the NAME (Little Endian). If the + * NAME provided, does not match the j1939.name provided to bind(2), EPROTO + * will be returned. + */ + sendto(sock, dat, sizeof(dat), 0, (const struct sockaddr *)&saddr, sizeof(saddr)); + +If no-one else contests the address claim within 250ms after transmission, the +kernel marks the NAME-SA assignment as valid. The valid assignment will be kept +among other valid NAME-SA assignments. From that point, any socket bound to the +NAME can send packets. + +If another ECU claims the address, the kernel will mark the NAME-SA expired. +No socket bound to the NAME can send packets (other than address claims). To +claim another address, some socket bound to NAME, must bind(2) again, but with +only j1939.addr changed to the new SA, and must then send a valid address claim +packet. This restarts the state machine in the kernel (and any other +participant on the bus) for this NAME. + +can-utils also include the jacd tool, so it can be used as code example or as +default Address Claiming daemon. + +Send Examples +------------- + +Static Addressing +^^^^^^^^^^^^^^^^^ + +This example will send a PGN (0x12300) from SA 0x20 to DA 0x30. + +Bind: + +.. code-block:: C + + struct sockaddr_can baddr = { + .can_family = AF_CAN, + .can_addr.j1939 = { + .name = J1939_NO_NAME, + .addr = 0x20, + .pgn = J1939_NO_PGN, + }, + .can_ifindex = if_nametoindex("can0"), + }; + + bind(sock, (struct sockaddr *)&baddr, sizeof(baddr)); + +Now, the socket 'sock' is bound to the SA 0x20. Since no connect(2) was called, +at this point we can use only sendto(2) or sendmsg(2). + +Send: + +.. code-block:: C + + const struct sockaddr_can saddr = { + .can_family = AF_CAN, + .can_addr.j1939 = { + .name = J1939_NO_NAME; + .pgn = 0x30, + .addr = 0x12300, + }, + }; + + sendto(sock, dat, sizeof(dat), 0, (const struct sockaddr *)&saddr, sizeof(saddr)); diff --git a/Documentation/networking/mac80211_hwsim/README b/Documentation/networking/mac80211_hwsim/mac80211_hwsim.rst similarity index 81% rename from Documentation/networking/mac80211_hwsim/README rename to Documentation/networking/mac80211_hwsim/mac80211_hwsim.rst index 3566a725d19c7dd704b929206f2a0aad81a10dfa..d2266ce5534e15583198bff712df3915e492b9db 100644 --- a/Documentation/networking/mac80211_hwsim/README +++ b/Documentation/networking/mac80211_hwsim/mac80211_hwsim.rst @@ -1,5 +1,13 @@ +:orphan: + +.. SPDX-License-Identifier: GPL-2.0 +.. include:: + +=================================================================== mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 -Copyright (c) 2008, Jouni Malinen +=================================================================== + +:Copyright: |copy| 2008, Jouni Malinen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as @@ -7,6 +15,7 @@ published by the Free Software Foundation. Introduction +============ mac80211_hwsim is a Linux kernel module that can be used to simulate arbitrary number of IEEE 802.11 radios for mac80211. It can be used to @@ -43,6 +52,7 @@ regardless of channel. Simple example +============== This example shows how to use mac80211_hwsim to simulate two radios: one to act as an access point and the other as a station that @@ -50,17 +60,19 @@ associates with the AP. hostapd and wpa_supplicant are used to take care of WPA2-PSK authentication. In addition, hostapd is also processing access point side of association. +:: + -# Build mac80211_hwsim as part of kernel configuration + # Build mac80211_hwsim as part of kernel configuration -# Load the module -modprobe mac80211_hwsim + # Load the module + modprobe mac80211_hwsim -# Run hostapd (AP) for wlan0 -hostapd hostapd.conf + # Run hostapd (AP) for wlan0 + hostapd hostapd.conf -# Run wpa_supplicant (station) for wlan1 -wpa_supplicant -Dnl80211 -iwlan1 -c wpa_supplicant.conf + # Run wpa_supplicant (station) for wlan1 + wpa_supplicant -Dnl80211 -iwlan1 -c wpa_supplicant.conf More test cases are available in hostap.git: diff --git a/Documentation/networking/sfp-phylink.rst b/Documentation/networking/sfp-phylink.rst index 91446b431b70b323cd5f0651e4d06c974214f6d0..a5e00a159d214e8d9b81f7ab767a1cc951cd15ef 100644 --- a/Documentation/networking/sfp-phylink.rst +++ b/Documentation/networking/sfp-phylink.rst @@ -8,7 +8,8 @@ Overview ======== phylink is a mechanism to support hot-pluggable networking modules -without needing to re-initialise the adapter on hot-plug events. +directly connected to a MAC without needing to re-initialise the +adapter on hot-plug events. phylink supports conventional phylib-based setups, fixed link setups and SFP (Small Formfactor Pluggable) modules at present. diff --git a/Documentation/nios2/README b/Documentation/nios2/nios2.rst similarity index 96% rename from Documentation/nios2/README rename to Documentation/nios2/nios2.rst index 054a67d55563030158c27684de2de4ae64e68517..43da3f7cee76c4dcf55ae937268aa486fe5a3f5b 100644 --- a/Documentation/nios2/README +++ b/Documentation/nios2/nios2.rst @@ -1,3 +1,4 @@ +================================= Linux on the Nios II architecture ================================= diff --git a/Documentation/openrisc/index.rst b/Documentation/openrisc/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..748b3eea1707cd132f1857ea16d89062faf40423 --- /dev/null +++ b/Documentation/openrisc/index.rst @@ -0,0 +1,18 @@ +.. SPDX-License-Identifier: GPL-2.0 + +===================== +OpenRISC Architecture +===================== + +.. toctree:: + :maxdepth: 2 + + openrisc_port + todo + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/openrisc/README b/Documentation/openrisc/openrisc_port.rst similarity index 80% rename from Documentation/openrisc/README rename to Documentation/openrisc/openrisc_port.rst index 777a893d533d14cb161987085ab471645f2b4c24..a18747a8d1916ff0ed88be1819249e968c395f7f 100644 --- a/Documentation/openrisc/README +++ b/Documentation/openrisc/openrisc_port.rst @@ -1,3 +1,4 @@ +============== OpenRISC Linux ============== @@ -6,8 +7,10 @@ target architecture, specifically, is the 32-bit OpenRISC 1000 family (or1k). For information about OpenRISC processors and ongoing development: + ======= ============================= website http://openrisc.io email openrisc@lists.librecores.org + ======= ============================= --------------------------------------------------------------------- @@ -24,13 +27,15 @@ Toolchain binaries can be obtained from openrisc.io or our github releases page. Instructions for building the different toolchains can be found on openrisc.io or Stafford's toolchain build and release scripts. + ========== ================================================= binaries https://github.com/openrisc/or1k-gcc/releases toolchains https://openrisc.io/software building https://github.com/stffrdhrn/or1k-toolchain-build + ========== ================================================= 2) Building -Build the Linux kernel as usual +Build the Linux kernel as usual:: make ARCH=openrisc defconfig make ARCH=openrisc @@ -43,6 +48,8 @@ development board with the OpenRISC SoC. During the build FPGA RTL is code downloaded from the FuseSoC IP cores repository and built using the FPGA vendor tools. Binaries are loaded onto the board with openocd. +:: + git clone https://github.com/olofk/fusesoc cd fusesoc sudo pip install -e . @@ -65,7 +72,9 @@ platform. Please follow the OpenRISC instructions on the QEMU website to get Linux running on QEMU. You can build QEMU yourself, but your Linux distribution likely provides binary packages to support OpenRISC. + ============= ====================================================== qemu openrisc https://wiki.qemu.org/Documentation/Platforms/OpenRISC + ============= ====================================================== --------------------------------------------------------------------- @@ -75,36 +84,38 @@ Terminology In the code, the following particles are used on symbols to limit the scope to more or less specific processor implementations: +========= ======================================= openrisc: the OpenRISC class of processors or1k: the OpenRISC 1000 family of processors or1200: the OpenRISC 1200 processor +========= ======================================= --------------------------------------------------------------------- History ======== -18. 11. 2003 Matjaz Breskvar (phoenix@bsemi.com) +18-11-2003 Matjaz Breskvar (phoenix@bsemi.com) initial port of linux to OpenRISC/or32 architecture. all the core stuff is implemented and seams usable. -08. 12. 2003 Matjaz Breskvar (phoenix@bsemi.com) +08-12-2003 Matjaz Breskvar (phoenix@bsemi.com) complete change of TLB miss handling. rewrite of exceptions handling. fully functional sash-3.6 in default initrd. a much improved version with changes all around. -10. 04. 2004 Matjaz Breskvar (phoenix@bsemi.com) +10-04-2004 Matjaz Breskvar (phoenix@bsemi.com) alot of bugfixes all over. ethernet support, functional http and telnet servers. running many standard linux apps. -26. 06. 2004 Matjaz Breskvar (phoenix@bsemi.com) +26-06-2004 Matjaz Breskvar (phoenix@bsemi.com) port to 2.6.x -30. 11. 2004 Matjaz Breskvar (phoenix@bsemi.com) +30-11-2004 Matjaz Breskvar (phoenix@bsemi.com) lots of bugfixes and enhancments. added opencores framebuffer driver. -09. 10. 2010 Jonas Bonn (jonas@southpole.se) +09-10-2010 Jonas Bonn (jonas@southpole.se) major rewrite to bring up to par with upstream Linux 2.6.36 diff --git a/Documentation/openrisc/TODO b/Documentation/openrisc/todo.rst similarity index 78% rename from Documentation/openrisc/TODO rename to Documentation/openrisc/todo.rst index c43d4e1d14eb9c576b1438d19e479d147a642c97..420b18b87eda00bd24e11e7981ad13c0819d17b2 100644 --- a/Documentation/openrisc/TODO +++ b/Documentation/openrisc/todo.rst @@ -1,12 +1,15 @@ +==== +TODO +==== + The OpenRISC Linux port is fully functional and has been tracking upstream since 2.6.35. There are, however, remaining items to be completed within the coming months. Here's a list of known-to-be-less-than-stellar items that are due for investigation shortly, i.e. our TODO list: --- Implement the rest of the DMA API... dma_map_sg, etc. +- Implement the rest of the DMA API... dma_map_sg, etc. --- Finish the renaming cleanup... there are references to or32 in the code +- Finish the renaming cleanup... there are references to or32 in the code which was an older name for the architecture. The name we've settled on is or1k and this change is slowly trickling through the stack. For the time being, or32 is equivalent to or1k. - diff --git a/Documentation/padata.txt b/Documentation/padata.txt index b103d0c820004953667db9e41dd93999ae4e56bc..b37ba1eaace3d905063836b1a715ecf697cd317f 100644 --- a/Documentation/padata.txt +++ b/Documentation/padata.txt @@ -16,10 +16,12 @@ overall control of how tasks are to be run:: #include - struct padata_instance *padata_alloc(struct workqueue_struct *wq, + struct padata_instance *padata_alloc(const char *name, const struct cpumask *pcpumask, const struct cpumask *cbcpumask); +'name' simply identifies the instance. + The pcpumask describes which processors will be used to execute work submitted to this instance in parallel. The cbcpumask defines which processors are allowed to be used as the serialization callback processor. @@ -128,8 +130,7 @@ in that CPU mask or about a not running instance. Each task submitted to padata_do_parallel() will, in turn, be passed to exactly one call to the above-mentioned parallel() function, on one CPU, so -true parallelism is achieved by submitting multiple tasks. Despite the -fact that the workqueue is used to make these calls, parallel() is run with +true parallelism is achieved by submitting multiple tasks. parallel() runs with software interrupts disabled and thus cannot sleep. The parallel() function gets the padata_priv structure pointer as its lone parameter; information about the actual work to be done is probably obtained by using @@ -148,7 +149,7 @@ fact with a call to:: At some point in the future, padata_do_serial() will trigger a call to the serial() function in the padata_priv structure. That call will happen on the CPU requested in the initial call to padata_do_parallel(); it, too, is -done through the workqueue, but with local software interrupts disabled. +run with local software interrupts disabled. Note that this call may be deferred for a while since the padata code takes pains to ensure that tasks are completed in the order in which they were submitted. @@ -159,5 +160,4 @@ when a padata instance is no longer needed:: void padata_free(struct padata_instance *pinst); This function will busy-wait while any remaining tasks are completed, so it -might be best not to call it while there is work outstanding. Shutting -down the workqueue, if necessary, should be done separately. +might be best not to call it while there is work outstanding. diff --git a/Documentation/parisc/debugging b/Documentation/parisc/debugging.rst similarity index 94% rename from Documentation/parisc/debugging rename to Documentation/parisc/debugging.rst index 7d75223fa18d6b9347d97992d4d4c0e519a28922..de1b60402c5b89e98e50e0090fb128acefc941a5 100644 --- a/Documentation/parisc/debugging +++ b/Documentation/parisc/debugging.rst @@ -1,8 +1,13 @@ +================= +PA-RISC Debugging +================= + okay, here are some hints for debugging the lower-level parts of linux/parisc. 1. Absolute addresses +===================== A lot of the assembly code currently runs in real mode, which means absolute addresses are used instead of virtual addresses as in the @@ -12,6 +17,7 @@ currently). 2. HPMCs +======== When real-mode code tries to access non-existent memory, you'll get an HPMC instead of a kernel oops. To debug an HPMC, try to find @@ -27,6 +33,7 @@ access it. 3. Q bit fun +============ Certain, very critical code has to clear the Q bit in the PSW. What happens when the Q bit is cleared is the CPU does not update the diff --git a/Documentation/parisc/index.rst b/Documentation/parisc/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..aa3ee04704252dc892cce6997458aa6016f415b6 --- /dev/null +++ b/Documentation/parisc/index.rst @@ -0,0 +1,18 @@ +.. SPDX-License-Identifier: GPL-2.0 + +==================== +PA-RISC Architecture +==================== + +.. toctree:: + :maxdepth: 2 + + debugging + registers + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/parisc/registers b/Documentation/parisc/registers.rst similarity index 70% rename from Documentation/parisc/registers rename to Documentation/parisc/registers.rst index 10c7d1730f5d8ccd0e7ace717627a2b1efe837b4..59c8ecf3e856aee41e82e89457a5c07742ea6891 100644 --- a/Documentation/parisc/registers +++ b/Documentation/parisc/registers.rst @@ -1,11 +1,16 @@ +================================ Register Usage for Linux/PA-RISC +================================ [ an asterisk is used for planned usage which is currently unimplemented ] - General Registers as specified by ABI +General Registers as specified by ABI +===================================== - Control Registers +Control Registers +----------------- +=============================== =============================================== CR 0 (Recovery Counter) used for ptrace CR 1-CR 7(undefined) unused CR 8 (Protection ID) per-process value* @@ -29,26 +34,35 @@ CR28 (TR 4) not used CR29 (TR 5) not used CR30 (TR 6) current / 0 CR31 (TR 7) Temporary register, used in various places +=============================== =============================================== - Space Registers (kernel mode) +Space Registers (kernel mode) +----------------------------- +=============================== =============================================== SR0 temporary space register SR4-SR7 set to 0 SR1 temporary space register SR2 kernel should not clobber this SR3 used for userspace accesses (current process) +=============================== =============================================== - Space Registers (user mode) +Space Registers (user mode) +--------------------------- +=============================== =============================================== SR0 temporary space register SR1 temporary space register SR2 holds space of linux gateway page SR3 holds user address space value while in kernel SR4-SR7 Defines short address space for user/kernel +=============================== =============================================== - Processor Status Word +Processor Status Word +--------------------- +=============================== =============================================== W (64-bit addresses) 0 E (Little-endian) 0 S (Secure Interval Timer) 0 @@ -69,15 +83,19 @@ Q (collect interruption state) 1 (0 in code directly preceding an rfi) P (Protection Identifiers) 1* D (Data address translation) 1, 0 while executing real-mode code I (external interrupt mask) used by cli()/sti() macros +=============================== =============================================== - "Invisible" Registers +"Invisible" Registers +--------------------- +=============================== =============================================== PSW default W value 0 PSW default E value 0 Shadow Registers used by interruption handler code TOC enable bit 1 +=============================== =============================================== -========================================================================= +------------------------------------------------------------------------- The PA-RISC architecture defines 7 registers as "shadow registers". Those are used in RETURN FROM INTERRUPTION AND RESTORE instruction to reduce @@ -85,7 +103,8 @@ the state save and restore time by eliminating the need for general register (GR) saves and restores in interruption handlers. Shadow registers are the GRs 1, 8, 9, 16, 17, 24, and 25. -========================================================================= +------------------------------------------------------------------------- + Register usage notes, originally from John Marvin, with some additional notes from Randolph Chung. @@ -96,10 +115,12 @@ course, you need to save them if you care about them, before calling another procedure. Some of the above registers do have special meanings that you should be aware of: - r1: The addil instruction is hardwired to place its result in r1, + r1: + The addil instruction is hardwired to place its result in r1, so if you use that instruction be aware of that. - r2: This is the return pointer. In general you don't want to + r2: + This is the return pointer. In general you don't want to use this, since you need the pointer to get back to your caller. However, it is grouped with this set of registers since the caller can't rely on the value being the same @@ -107,23 +128,27 @@ that you should be aware of: and return through that register after trashing r2, and that should not cause a problem for the calling routine. - r19-r22: these are generally regarded as temporary registers. + r19-r22: + these are generally regarded as temporary registers. Note that in 64 bit they are arg7-arg4. - r23-r26: these are arg3-arg0, i.e. you can use them if you + r23-r26: + these are arg3-arg0, i.e. you can use them if you don't care about the values that were passed in anymore. - r28,r29: are ret0 and ret1. They are what you pass return values + r28,r29: + are ret0 and ret1. They are what you pass return values in. r28 is the primary return. When returning small structures r29 may also be used to pass data back to the caller. - r30: stack pointer + r30: + stack pointer - r31: the ble instruction puts the return pointer in here. + r31: + the ble instruction puts the return pointer in here. -r3-r18,r27,r30 need to be saved and restored. r3-r18 are just + r3-r18,r27,r30 need to be saved and restored. r3-r18 are just general purpose registers. r27 is the data pointer, and is used to make references to global variables easier. r30 is the stack pointer. - diff --git a/Documentation/power/opp.rst b/Documentation/power/opp.rst index b3cf1def9deec0e6eee02e26d5e3cf1bd660b1e8..209c7613f5a4b82f2e374e8d02f19513761a9d27 100644 --- a/Documentation/power/opp.rst +++ b/Documentation/power/opp.rst @@ -46,7 +46,7 @@ We can represent these as three OPPs as the following {Hz, uV} tuples: ---------------------------------------- OPP library provides a set of helper functions to organize and query the OPP -information. The library is located in drivers/base/power/opp.c and the header +information. The library is located in drivers/opp/ directory and the header is located in include/linux/pm_opp.h. OPP library can be enabled by enabling CONFIG_PM_OPP from power management menuconfig menu. OPP library depends on CONFIG_PM as certain SoCs such as Texas Instrument's OMAP framework allows to diff --git a/Documentation/power/pm_qos_interface.rst b/Documentation/power/pm_qos_interface.rst index 69921f072ce199f03c672bd63aa0eaab17bd1217..3097694fba69805aa1eb365aaf349e334e9ecde0 100644 --- a/Documentation/power/pm_qos_interface.rst +++ b/Documentation/power/pm_qos_interface.rst @@ -7,8 +7,7 @@ performance expectations by drivers, subsystems and user space applications on one of the parameters. Two different PM QoS frameworks are available: -1. PM QoS classes for cpu_dma_latency, network_latency, network_throughput, -memory_bandwidth. +1. PM QoS classes for cpu_dma_latency 2. the per-device PM QoS framework provides the API to manage the per-device latency constraints and PM QoS flags. @@ -79,7 +78,7 @@ cleanup of a process, the interface requires the process to register its parameter requests in the following way: To register the default pm_qos target for the specific parameter, the process -must open one of /dev/[cpu_dma_latency, network_latency, network_throughput] +must open /dev/cpu_dma_latency As long as the device node is held open that process has a registered request on the parameter. diff --git a/Documentation/process/email-clients.rst b/Documentation/process/email-clients.rst index 07faa5457bcb62eed958195cd97d52cd11329e8c..5273d06c8ff68b697e0ee0a8ce118f9522c631c3 100644 --- a/Documentation/process/email-clients.rst +++ b/Documentation/process/email-clients.rst @@ -40,7 +40,7 @@ Emailed patches should be in ASCII or UTF-8 encoding only. If you configure your email client to send emails with UTF-8 encoding, you avoid some possible charset problems. -Email clients should generate and maintain References: or In-Reply-To: +Email clients should generate and maintain "References:" or "In-Reply-To:" headers so that mail threading is not broken. Copy-and-paste (or cut-and-paste) usually does not work for patches @@ -89,7 +89,7 @@ Claws Mail (GUI) Works. Some people use this successfully for patches. -To insert a patch use :menuselection:`Message-->Insert` File (:kbd:`CTRL-I`) +To insert a patch use :menuselection:`Message-->Insert File` (:kbd:`CTRL-I`) or an external editor. If the inserted patch has to be edited in the Claws composition window @@ -132,8 +132,8 @@ wrapping. At the bottom of your email, put the commonly-used patch delimiter before inserting your patch: three hyphens (``---``). -Then from the :menuselection:`Message` menu item, select insert file and -choose your patch. +Then from the :menuselection:`Message` menu item, select +:menuselection:`insert file` and choose your patch. As an added bonus you can customise the message creation toolbar menu and put the :menuselection:`insert file` icon there. @@ -149,18 +149,16 @@ patches so do not GPG sign them. Signing patches that have been inserted as inlined text will make them tricky to extract from their 7-bit encoding. If you absolutely must send patches as attachments instead of inlining -them as text, right click on the attachment and select properties, and -highlight :menuselection:`Suggest automatic display` to make the attachment +them as text, right click on the attachment and select :menuselection:`properties`, +and highlight :menuselection:`Suggest automatic display` to make the attachment inlined to make it more viewable. When saving patches that are sent as inlined text, select the email that contains the patch from the message list pane, right click and select :menuselection:`save as`. You can use the whole email unmodified as a patch -if it was properly composed. There is no option currently to save the email -when you are actually viewing it in its own window -- there has been a request -filed at kmail's bugzilla and hopefully this will be addressed. Emails are -saved as read-write for user only so you will have to chmod them to make them -group and world readable if you copy them elsewhere. +if it was properly composed. Emails are saved as read-write for user only so +you will have to chmod them to make them group and world readable if you copy +them elsewhere. Lotus Notes (GUI) ***************** diff --git a/Documentation/process/howto.rst b/Documentation/process/howto.rst index 6ab75c11d2c3bd4bf4de6509a8a73354cb36694d..b6f5a379ad6cb7422d129802635951181910e0b6 100644 --- a/Documentation/process/howto.rst +++ b/Documentation/process/howto.rst @@ -123,7 +123,7 @@ required reading: https://www.ozlabs.org/~akpm/stuff/tpp.txt "Linux kernel patch submission format" - http://linux.yyz.us/patch-format.html + https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html :ref:`Documentation/process/stable-api-nonsense.rst ` This file describes the rationale behind the conscious decision to diff --git a/Documentation/process/submitting-patches.rst b/Documentation/process/submitting-patches.rst index 9c4299293c7294402219a7d491b7fa50990f1cce..fb56297f70dc8817b5a29445768f1f4c72c35230 100644 --- a/Documentation/process/submitting-patches.rst +++ b/Documentation/process/submitting-patches.rst @@ -844,7 +844,7 @@ Andrew Morton, "The perfect patch" (tpp). Jeff Garzik, "Linux kernel patch submission format". - + Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer". diff --git a/Documentation/riscv/boot-image-header.txt b/Documentation/riscv/boot-image-header.rst similarity index 72% rename from Documentation/riscv/boot-image-header.txt rename to Documentation/riscv/boot-image-header.rst index 14b1492f689bbe71c983a1baba1756d4e79e4204..7b4d1d747585e7717b489300908ae3bf35aae82b 100644 --- a/Documentation/riscv/boot-image-header.txt +++ b/Documentation/riscv/boot-image-header.rst @@ -1,22 +1,25 @@ - Boot image header in RISC-V Linux - ============================================= +================================= +Boot image header in RISC-V Linux +================================= -Author: Atish Patra -Date : 20 May 2019 +:Author: Atish Patra +:Date: 20 May 2019 This document only describes the boot image header details for RISC-V Linux. -The complete booting guide will be available at Documentation/riscv/booting.txt. -The following 64-byte header is present in decompressed Linux kernel image. +TODO: + Write a complete booting guide. + +The following 64-byte header is present in decompressed Linux kernel image:: u32 code0; /* Executable code */ - u32 code1; /* 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 */ + u32 res1 = 0; /* Reserved */ + u64 res2 = 0; /* Reserved */ u64 magic = 0x5643534952; /* Magic number, little endian, "RISCV" */ u32 magic2 = 0x56534905; /* Magic number 2, little endian, "RSC\x05" */ u32 res4; /* Reserved for PE COFF offset */ @@ -25,16 +28,21 @@ This header format is compliant with PE/COFF header and largely inspired from ARM64 header. Thus, both ARM64 & RISC-V header can be combined into one common header in future. -Notes: +Notes +===== + - This header can also be reused to support EFI stub for RISC-V in future. EFI specification needs PE/COFF image header in the beginning of the kernel image in order to load it as an EFI application. In order to support EFI stub, code0 should be replaced with "MZ" magic string and res5(at offset 0x3c) should point to the rest of the PE/COFF header. -- version field indicate header version number. - Bits 0:15 - Minor version - Bits 16:31 - Major version +- version field indicate header version number + + ========== ============= + Bits 0:15 Minor version + Bits 16:31 Major version + ========== ============= This preserves compatibility across newer and older version of the header. The current version is defined as 0.2. @@ -45,7 +53,10 @@ Notes: The "magic2" field replaces it, matching up with the ARM64 header. - In current header, the flags field has only one field. - Bit 0: Kernel endianness. 1 if BE, 0 if LE. + + ===== ==================================== + Bit 0 Kernel endianness. 1 if BE, 0 if LE. + ===== ==================================== - Image size is mandatory for boot loader to load kernel image. Booting will fail otherwise. diff --git a/Documentation/riscv/index.rst b/Documentation/riscv/index.rst index e3ca0922a8c2086a7dc920d0e1441328615a47a0..215fd3c1f2d57f5397b469ee6c42b17be7025732 100644 --- a/Documentation/riscv/index.rst +++ b/Documentation/riscv/index.rst @@ -5,6 +5,7 @@ RISC-V architecture .. toctree:: :maxdepth: 1 + boot-image-header pmu .. only:: subproject and html diff --git a/Documentation/s390/dasd.rst b/Documentation/s390/dasd.rst deleted file mode 100644 index 9e22247285c888dba82eac243f491a72fc614c0f..0000000000000000000000000000000000000000 --- a/Documentation/s390/dasd.rst +++ /dev/null @@ -1,84 +0,0 @@ -================== -DASD device driver -================== - -S/390's disk devices (DASDs) are managed by Linux via the DASD device -driver. It is valid for all types of DASDs and represents them to -Linux as block devices, namely "dd". Currently the DASD driver uses a -single major number (254) and 4 minor numbers per volume (1 for the -physical volume and 3 for partitions). With respect to partitions see -below. Thus you may have up to 64 DASD devices in your system. - -The kernel parameter 'dasd=from-to,...' may be issued arbitrary times -in the kernel's parameter line or not at all. The 'from' and 'to' -parameters are to be given in hexadecimal notation without a leading -0x. -If you supply kernel parameters the different instances are processed -in order of appearance and a minor number is reserved for any device -covered by the supplied range up to 64 volumes. Additional DASDs are -ignored. If you do not supply the 'dasd=' kernel parameter at all, the -DASD driver registers all supported DASDs of your system to a minor -number in ascending order of the subchannel number. - -The driver currently supports ECKD-devices and there are stubs for -support of the FBA and CKD architectures. For the FBA architecture -only some smart data structures are missing to make the support -complete. -We performed our testing on 3380 and 3390 type disks of different -sizes, under VM and on the bare hardware (LPAR), using internal disks -of the multiprise as well as a RAMAC virtual array. Disks exported by -an Enterprise Storage Server (Seascape) should work fine as well. - -We currently implement one partition per volume, which is the whole -volume, skipping the first blocks up to the volume label. These are -reserved for IPL records and IBM's volume label to assure -accessibility of the DASD from other OSs. In a later stage we will -provide support of partitions, maybe VTOC oriented or using a kind of -partition table in the label record. - -Usage -===== - --Low-level format (?CKD only) -For using an ECKD-DASD as a Linux harddisk you have to low-level -format the tracks by issuing the BLKDASDFORMAT-ioctl on that -device. This will erase any data on that volume including IBM volume -labels, VTOCs etc. The ioctl may take a `struct format_data *` or -'NULL' as an argument:: - - typedef struct { - int start_unit; - int stop_unit; - int blksize; - } format_data_t; - -When a NULL argument is passed to the BLKDASDFORMAT ioctl the whole -disk is formatted to a blocksize of 1024 bytes. Otherwise start_unit -and stop_unit are the first and last track to be formatted. If -stop_unit is -1 it implies that the DASD is formatted from start_unit -up to the last track. blksize can be any power of two between 512 and -4096. We recommend no blksize lower than 1024 because the ext2fs uses -1kB blocks anyway and you gain approx. 50% of capacity increasing your -blksize from 512 byte to 1kB. - -Make a filesystem -================= - -Then you can mk??fs the filesystem of your choice on that volume or -partition. For reasons of sanity you should build your filesystem on -the partition /dev/dd?1 instead of the whole volume. You only lose 3kB -but may be sure that you can reuse your data after introduction of a -real partition table. - -Bugs -==== - -- Performance sometimes is rather low because we don't fully exploit clustering - -TODO-List -========= - -- Add IBM'S Disk layout to genhd -- Enhance driver to use more than one major number -- Enable usage as a module -- Support Cache fast write and DASD fast write (ECKD) diff --git a/Documentation/s390/debugging390.rst b/Documentation/s390/debugging390.rst deleted file mode 100644 index 73ad0b06c6660ea381f70467c3f174a4311c6b90..0000000000000000000000000000000000000000 --- a/Documentation/s390/debugging390.rst +++ /dev/null @@ -1,2613 +0,0 @@ -============================================= -Debugging on Linux for s/390 & z/Architecture -============================================= - -Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - -Copyright (C) 2000-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation - -.. Best viewed with fixed width fonts - -Overview of Document: -===================== -This document is intended to give a good overview of how to debug Linux for -s/390 and z/Architecture. It is not intended as a complete reference and not a -tutorial on the fundamentals of C & assembly. It doesn't go into -390 IO in any detail. It is intended to complement the documents in the -reference section below & any other worthwhile references you get. - -It is intended like the Enterprise Systems Architecture/390 Reference Summary -to be printed out & used as a quick cheat sheet self help style reference when -problems occur. - -.. Contents - ======== - Register Set - Address Spaces on Intel Linux - Address Spaces on Linux for s/390 & z/Architecture - The Linux for s/390 & z/Architecture Kernel Task Structure - Register Usage & Stackframes on Linux for s/390 & z/Architecture - A sample program with comments - Compiling programs for debugging on Linux for s/390 & z/Architecture - Debugging under VM - s/390 & z/Architecture IO Overview - Debugging IO on s/390 & z/Architecture under VM - GDB on s/390 & z/Architecture - Stack chaining in gdb by hand - Examining core dumps - ldd - Debugging modules - The proc file system - SysRq - References - Special Thanks - -Register Set -============ -The current architectures have the following registers. - -16 General propose registers, 32 bit on s/390 and 64 bit on z/Architecture, -r0-r15 (or gpr0-gpr15), used for arithmetic and addressing. - -16 Control registers, 32 bit on s/390 and 64 bit on z/Architecture, cr0-cr15, -kernel usage only, used for memory management, interrupt control, debugging -control etc. - -16 Access registers (ar0-ar15), 32 bit on both s/390 and z/Architecture, -normally not used by normal programs but potentially could be used as -temporary storage. These registers have a 1:1 association with general -purpose registers and are designed to be used in the so-called access -register mode to select different address spaces. -Access register 0 (and access register 1 on z/Architecture, which needs a -64 bit pointer) is currently used by the pthread library as a pointer to -the current running threads private area. - -16 64-bit floating point registers (fp0-fp15 ) IEEE & HFP floating -point format compliant on G5 upwards & a Floating point control reg (FPC) - -4 64-bit registers (fp0,fp2,fp4 & fp6) HFP only on older machines. - -Note: - Linux (currently) always uses IEEE & emulates G5 IEEE format on older - machines, ( provided the kernel is configured for this ). - - -The PSW is the most important register on the machine it -is 64 bit on s/390 & 128 bit on z/Architecture & serves the roles of -a program counter (pc), condition code register,memory space designator. -In IBM standard notation I am counting bit 0 as the MSB. -It has several advantages over a normal program counter -in that you can change address translation & program counter -in a single instruction. To change address translation, -e.g. switching address translation off requires that you -have a logical=physical mapping for the address you are -currently running at. - -+-------------------------+-------------------------------------------------+ -| Bit | | -+--------+----------------+ Value | -| s/390 | z/Architecture | | -+========+================+=================================================+ -| 0 | 0 | Reserved (must be 0) otherwise specification | -| | | exception occurs. | -+--------+----------------+-------------------------------------------------+ -| 1 | 1 | Program Event Recording 1 PER enabled, | -| | | PER is used to facilitate debugging e.g. | -| | | single stepping. | -+--------+----------------+-------------------------------------------------+ -| 2-4 | 2-4 | Reserved (must be 0). | -+--------+----------------+-------------------------------------------------+ -| 5 | 5 | Dynamic address translation 1=DAT on. | -+--------+----------------+-------------------------------------------------+ -| 6 | 6 | Input/Output interrupt Mask | -+--------+----------------+-------------------------------------------------+ -| 7 | 7 | External interrupt Mask used primarily for | -| | | interprocessor signalling and clock interrupts. | -+--------+----------------+-------------------------------------------------+ -| 8-11 | 8-11 | PSW Key used for complex memory protection | -| | | mechanism (not used under linux) | -+--------+----------------+-------------------------------------------------+ -| 12 | 12 | 1 on s/390 0 on z/Architecture | -+--------+----------------+-------------------------------------------------+ -| 13 | 13 | Machine Check Mask 1=enable machine check | -| | | interrupts | -+--------+----------------+-------------------------------------------------+ -| 14 | 14 | Wait State. Set this to 1 to stop the processor | -| | | except for interrupts and give time to other | -| | | LPARS. Used in CPU idle in the kernel to | -| | | increase overall usage of processor resources. | -+--------+----------------+-------------------------------------------------+ -| 15 | 15 | Problem state (if set to 1 certain instructions | -| | | are disabled). All linux user programs run with | -| | | this bit 1 (useful info for debugging under VM).| -+--------+----------------+-------------------------------------------------+ -| 16-17 | 16-17 | Address Space Control | -| | | | -| | | 00 Primary Space Mode: | -| | | | -| | | The register CR1 contains the primary | -| | | address-space control element (PASCE), which | -| | | points to the primary space region/segment | -| | | table origin. | -| | | | -| | | 01 Access register mode | -| | | | -| | | 10 Secondary Space Mode: | -| | | | -| | | The register CR7 contains the secondary | -| | | address-space control element (SASCE), which | -| | | points to the secondary space region or | -| | | segment table origin. | -| | | | -| | | 11 Home Space Mode: | -| | | | -| | | The register CR13 contains the home space | -| | | address-space control element (HASCE), which | -| | | points to the home space region/segment | -| | | table origin. | -| | | | -| | | See "Address Spaces on Linux for s/390 & | -| | | z/Architecture" below for more information | -| | | about address space usage in Linux. | -+--------+----------------+-------------------------------------------------+ -| 18-19 | 18-19 | Condition codes (CC) | -+--------+----------------+-------------------------------------------------+ -| 20 | 20 | Fixed point overflow mask if 1=FPU exceptions | -| | | for this event occur (normally 0) | -+--------+----------------+-------------------------------------------------+ -| 21 | 21 | Decimal overflow mask if 1=FPU exceptions for | -| | | this event occur (normally 0) | -+--------+----------------+-------------------------------------------------+ -| 22 | 22 | Exponent underflow mask if 1=FPU exceptions | -| | | for this event occur (normally 0) | -+--------+----------------+-------------------------------------------------+ -| 23 | 23 | Significance Mask if 1=FPU exceptions for this | -| | | event occur (normally 0) | -+--------+----------------+-------------------------------------------------+ -| 24-31 | 24-30 | Reserved Must be 0. | -| +----------------+-------------------------------------------------+ -| | 31 | Extended Addressing Mode | -| +----------------+-------------------------------------------------+ -| | 32 | Basic Addressing Mode | -| | | | -| | | Used to set addressing mode:: | -| | | | -| | | +---------+----------+----------+ | -| | | | PSW 31 | PSW 32 | | | -| | | +---------+----------+----------+ | -| | | | 0 | 0 | 24 bit | | -| | | +---------+----------+----------+ | -| | | | 0 | 1 | 31 bit | | -| | | +---------+----------+----------+ | -| | | | 1 | 1 | 64 bit | | -| | | +---------+----------+----------+ | -+--------+----------------+-------------------------------------------------+ -| 32 | | 1=31 bit addressing mode 0=24 bit addressing | -| | | mode (for backward compatibility), linux | -| | | always runs with this bit set to 1 | -+--------+----------------+-------------------------------------------------+ -| 33-64 | | Instruction address. | -| +----------------+-------------------------------------------------+ -| | 33-63 | Reserved must be 0 | -| +----------------+-------------------------------------------------+ -| | 64-127 | Address | -| | | | -| | | - In 24 bits mode bits 64-103=0 bits 104-127 | -| | | Address | -| | | - In 31 bits mode bits 64-96=0 bits 97-127 | -| | | Address | -| | | | -| | | Note: | -| | | unlike 31 bit mode on s/390 bit 96 must be | -| | | zero when loading the address with LPSWE | -| | | otherwise a specification exception occurs, | -| | | LPSW is fully backward compatible. | -+--------+----------------+-------------------------------------------------+ - -Prefix Page(s) --------------- -This per cpu memory area is too intimately tied to the processor not to mention. -It exists between the real addresses 0-4096 on s/390 and between 0-8192 on -z/Architecture and is exchanged with one page on s/390 or two pages on -z/Architecture in absolute storage by the set prefix instruction during Linux -startup. - -This page is mapped to a different prefix for each processor in an SMP -configuration (assuming the OS designer is sane of course). - -Bytes 0-512 (200 hex) on s/390 and 0-512, 4096-4544, 4604-5119 currently on -z/Architecture are used by the processor itself for holding such information -as exception indications and entry points for exceptions. - -Bytes after 0xc00 hex are used by linux for per processor globals on s/390 and -z/Architecture (there is a gap on z/Architecture currently between 0xc00 and -0x1000, too, which is used by Linux). - -The closest thing to this on traditional architectures is the interrupt -vector table. This is a good thing & does simplify some of the kernel coding -however it means that we now cannot catch stray NULL pointers in the -kernel without hard coded checks. - - - -Address Spaces on Intel Linux -============================= - -The traditional Intel Linux is approximately mapped as follows forgive -the ascii art:: - - 0xFFFFFFFF 4GB Himem ***************** - * * - * Kernel Space * - * * - ***************** **************** - User Space Himem * User Stack * * * - (typically 0xC0000000 3GB ) ***************** * * - * Shared Libs * * Next Process * - ***************** * to * - * * <== * Run * <== - * User Program * * * - * Data BSS * * * - * Text * * * - * Sections * * * - 0x00000000 ***************** **************** - -Now it is easy to see that on Intel it is quite easy to recognise a kernel -address as being one greater than user space himem (in this case 0xC0000000), -and addresses of less than this are the ones in the current running program on -this processor (if an smp box). - -If using the virtual machine ( VM ) as a debugger it is quite difficult to -know which user process is running as the address space you are looking at -could be from any process in the run queue. - -The limitation of Intels addressing technique is that the linux -kernel uses a very simple real address to virtual addressing technique -of Real Address=Virtual Address-User Space Himem. -This means that on Intel the kernel linux can typically only address -Himem=0xFFFFFFFF-0xC0000000=1GB & this is all the RAM these machines -can typically use. - -They can lower User Himem to 2GB or lower & thus be -able to use 2GB of RAM however this shrinks the maximum size -of User Space from 3GB to 2GB they have a no win limit of 4GB unless -they go to 64 Bit. - - -On 390 our limitations & strengths make us slightly different. -For backward compatibility we are only allowed use 31 bits (2GB) -of our 32 bit addresses, however, we use entirely separate address -spaces for the user & kernel. - -This means we can support 2GB of non Extended RAM on s/390, & more -with the Extended memory management swap device & -currently 4TB of physical memory currently on z/Architecture. - - -Address Spaces on Linux for s/390 & z/Architecture -================================================== - -Our addressing scheme is basically as follows:: - - Primary Space Home Space - Himem 0x7fffffff 2GB on s/390 ***************** **************** - currently 0x3ffffffffff (2^42)-1 * User Stack * * * - on z/Architecture. ***************** * * - * Shared Libs * * * - ***************** * * - * * * Kernel * - * User Program * * * - * Data BSS * * * - * Text * * * - * Sections * * * - 0x00000000 ***************** **************** - -This also means that we need to look at the PSW problem state bit and the -addressing mode to decide whether we are looking at user or kernel space. - -User space runs in primary address mode (or access register mode within -the vdso code). - -The kernel usually also runs in home space mode, however when accessing -user space the kernel switches to primary or secondary address mode if -the mvcos instruction is not available or if a compare-and-swap (futex) -instruction on a user space address is performed. - -When also looking at the ASCE control registers, this means: - -User space: - -- runs in primary or access register mode -- cr1 contains the user asce -- cr7 contains the user asce -- cr13 contains the kernel asce - -Kernel space: - -- runs in home space mode -- cr1 contains the user or kernel asce - - - the kernel asce is loaded when a uaccess requires primary or - secondary address mode - -- cr7 contains the user or kernel asce, (changed with set_fs()) -- cr13 contains the kernel asce - -In case of uaccess the kernel changes to: - -- primary space mode in case of a uaccess (copy_to_user) and uses - e.g. the mvcp instruction to access user space. However the kernel - will stay in home space mode if the mvcos instruction is available -- secondary space mode in case of futex atomic operations, so that the - instructions come from primary address space and data from secondary - space - -In case of KVM, the kernel runs in home space mode, but cr1 gets switched -to contain the gmap asce before the SIE instruction gets executed. When -the SIE instruction is finished, cr1 will be switched back to contain the -user asce. - - -Virtual Addresses on s/390 & z/Architecture -=========================================== - -A virtual address on s/390 is made up of 3 parts -The SX (segment index, roughly corresponding to the PGD & PMD in Linux -terminology) being bits 1-11. - -The PX (page index, corresponding to the page table entry (pte) in Linux -terminology) being bits 12-19. - -The remaining bits BX (the byte index are the offset in the page ) -i.e. bits 20 to 31. - -On z/Architecture in linux we currently make up an address from 4 parts. - -- The region index bits (RX) 0-32 we currently use bits 22-32 -- The segment index (SX) being bits 33-43 -- The page index (PX) being bits 44-51 -- The byte index (BX) being bits 52-63 - -Notes: - 1) s/390 has no PMD so the PMD is really the PGD also. - A lot of this stuff is defined in pgtable.h. - - 2) Also seeing as s/390's page indexes are only 1k in size - (bits 12-19 x 4 bytes per pte ) we use 1 ( page 4k ) - to make the best use of memory by updating 4 segment indices - entries each time we mess with a PMD & use offsets - 0,1024,2048 & 3072 in this page as for our segment indexes. - On z/Architecture our page indexes are now 2k in size - ( bits 12-19 x 8 bytes per pte ) we do a similar trick - but only mess with 2 segment indices each time we mess with - a PMD. - - 3) As z/Architecture supports up to a massive 5-level page table lookup we - can only use 3 currently on Linux ( as this is all the generic kernel - currently supports ) however this may change in future - this allows us to access ( according to my sums ) - 4TB of virtual storage per process i.e. - 4096*512(PTES)*1024(PMDS)*2048(PGD) = 4398046511104 bytes, - enough for another 2 or 3 of years I think :-). - to do this we use a region-third-table designation type in - our address space control registers. - - -The Linux for s/390 & z/Architecture Kernel Task Structure -========================================================== -Each process/thread under Linux for S390 has its own kernel task_struct -defined in linux/include/linux/sched.h -The S390 on initialisation & resuming of a process on a cpu sets -the __LC_KERNEL_STACK variable in the spare prefix area for this cpu -(which we use for per-processor globals). - -The kernel stack pointer is intimately tied with the task structure for -each processor as follows:: - - s/390 - ************************ - * 1 page kernel stack * - * ( 4K ) * - ************************ - * 1 page task_struct * - * ( 4K ) * - 8K aligned ************************ - - z/Architecture - ************************ - * 2 page kernel stack * - * ( 8K ) * - ************************ - * 2 page task_struct * - * ( 8K ) * - 16K aligned ************************ - -What this means is that we don't need to dedicate any register or global -variable to point to the current running process & can retrieve it with the -following very simple construct for s/390 & one very similar for -z/Architecture:: - - static inline struct task_struct * get_current(void) - { - struct task_struct *current; - __asm__("lhi %0,-8192\n\t" - "nr %0,15" - : "=r" (current) ); - return current; - } - -i.e. just anding the current kernel stack pointer with the mask -8192. -Thankfully because Linux doesn't have support for nested IO interrupts -& our devices have large buffers can survive interrupts being shut for -short amounts of time we don't need a separate stack for interrupts. - - - - -Register Usage & Stackframes on Linux for s/390 & z/Architecture -================================================================= -Overview: ---------- -This is the code that gcc produces at the top & the bottom of -each function. It usually is fairly consistent & similar from -function to function & if you know its layout you can probably -make some headway in finding the ultimate cause of a problem -after a crash without a source level debugger. - -Note: To follow stackframes requires a knowledge of C or Pascal & -limited knowledge of one assembly language. - -It should be noted that there are some differences between the -s/390 and z/Architecture stack layouts as the z/Architecture stack layout -didn't have to maintain compatibility with older linkage formats. - -Glossary: ---------- -alloca: - This is a built in compiler function for runtime allocation - of extra space on the callers stack which is obviously freed - up on function exit ( e.g. the caller may choose to allocate nothing - of a buffer of 4k if required for temporary purposes ), it generates - very efficient code ( a few cycles ) when compared to alternatives - like malloc. - -automatics: - These are local variables on the stack, i.e they aren't in registers & - they aren't static. - -back-chain: - This is a pointer to the stack pointer before entering a - framed functions ( see frameless function ) prologue got by - dereferencing the address of the current stack pointer, - i.e. got by accessing the 32 bit value at the stack pointers - current location. - -base-pointer: - This is a pointer to the back of the literal pool which - is an area just behind each procedure used to store constants - in each function. - -call-clobbered: - The caller probably needs to save these registers if there - is something of value in them, on the stack or elsewhere before making a - call to another procedure so that it can restore it later. - -epilogue: - The code generated by the compiler to return to the caller. - -frameless-function: - A frameless function in Linux for s390 & z/Architecture is one which doesn't - need more than the register save area (96 bytes on s/390, 160 on z/Architecture) - given to it by the caller. - - A frameless function never: - - 1) Sets up a back chain. - 2) Calls alloca. - 3) Calls other normal functions - 4) Has automatics. - -GOT-pointer: - This is a pointer to the global-offset-table in ELF - ( Executable Linkable Format, Linux'es most common executable format ), - all globals & shared library objects are found using this pointer. - -lazy-binding - ELF shared libraries are typically only loaded when routines in the shared - library are actually first called at runtime. This is lazy binding. - -procedure-linkage-table - This is a table found from the GOT which contains pointers to routines - in other shared libraries which can't be called to by easier means. - -prologue: - The code generated by the compiler to set up the stack frame. - -outgoing-args: - This is extra area allocated on the stack of the calling function if the - parameters for the callee's cannot all be put in registers, the same - area can be reused by each function the caller calls. - -routine-descriptor: - A COFF executable format based concept of a procedure reference - actually being 8 bytes or more as opposed to a simple pointer to the routine. - This is typically defined as follows: - - - Routine Descriptor offset 0=Pointer to Function - - Routine Descriptor offset 4=Pointer to Table of Contents - - The table of contents/TOC is roughly equivalent to a GOT pointer. - & it means that shared libraries etc. can be shared between several - environments each with their own TOC. - -static-chain: - This is used in nested functions a concept adopted from pascal - by gcc not used in ansi C or C++ ( although quite useful ), basically it - is a pointer used to reference local variables of enclosing functions. - You might come across this stuff once or twice in your lifetime. - - e.g. - - The function below should return 11 though gcc may get upset & toss warnings - about unused variables:: - - int FunctionA(int a) - { - int b; - FunctionC(int c) - { - b=c+1; - } - FunctionC(10); - return(b); - } - - -s/390 & z/Architecture Register usage -===================================== - -======== ========================================== =============== -r0 used by syscalls/assembly call-clobbered -r1 used by syscalls/assembly call-clobbered -r2 argument 0 / return value 0 call-clobbered -r3 argument 1 / return value 1 (if long long) call-clobbered -r4 argument 2 call-clobbered -r5 argument 3 call-clobbered -r6 argument 4 saved -r7 pointer-to arguments 5 to ... saved -r8 this & that saved -r9 this & that saved -r10 static-chain ( if nested function ) saved -r11 frame-pointer ( if function used alloca ) saved -r12 got-pointer saved -r13 base-pointer saved -r14 return-address saved -r15 stack-pointer saved - -f0 argument 0 / return value ( float/double ) call-clobbered -f2 argument 1 call-clobbered -f4 z/Architecture argument 2 saved -f6 z/Architecture argument 3 saved -======== ========================================== =============== - -The remaining floating points -f1,f3,f5 f7-f15 are call-clobbered. - -Notes: ------- -1) The only requirement is that registers which are used - by the callee are saved, e.g. the compiler is perfectly - capable of using r11 for purposes other than a frame a - frame pointer if a frame pointer is not needed. -2) In functions with variable arguments e.g. printf the calling procedure - is identical to one without variable arguments & the same number of - parameters. However, the prologue of this function is somewhat more - hairy owing to it having to move these parameters to the stack to - get va_start, va_arg & va_end to work. -3) Access registers are currently unused by gcc but are used in - the kernel. Possibilities exist to use them at the moment for - temporary storage but it isn't recommended. -4) Only 4 of the floating point registers are used for - parameter passing as older machines such as G3 only have only 4 - & it keeps the stack frame compatible with other compilers. - However with IEEE floating point emulation under linux on the - older machines you are free to use the other 12. -5) A long long or double parameter cannot be have the - first 4 bytes in a register & the second four bytes in the - outgoing args area. It must be purely in the outgoing args - area if crossing this boundary. -6) Floating point parameters are mixed with outgoing args - on the outgoing args area in the order the are passed in as parameters. -7) Floating point arguments 2 & 3 are saved in the outgoing args area for - z/Architecture - - -Stack Frame Layout ------------------- - -========= ============== ====================================================== -s/390 z/Architecture -========= ============== ====================================================== -0 0 back chain ( a 0 here signifies end of back chain ) -4 8 eos ( end of stack, not used on Linux for S390 used - in other linkage formats ) -8 16 glue used in other s/390 linkage formats for saved - routine descriptors etc. -12 24 glue used in other s/390 linkage formats for saved - routine descriptors etc. -16 32 scratch area -20 40 scratch area -24 48 saved r6 of caller function -28 56 saved r7 of caller function -32 64 saved r8 of caller function -36 72 saved r9 of caller function -40 80 saved r10 of caller function -44 88 saved r11 of caller function -48 96 saved r12 of caller function -52 104 saved r13 of caller function -56 112 saved r14 of caller function -60 120 saved r15 of caller function -64 128 saved f4 of caller function -72 132 saved f6 of caller function -80 undefined -96 160 outgoing args passed from caller to callee -96+x 160+x possible stack alignment ( 8 bytes desirable ) -96+x+y 160+x+y alloca space of caller ( if used ) -96+x+y+z 160+x+y+z automatics of caller ( if used ) -0 back-chain -========= ============== ====================================================== - -A sample program with comments. -=============================== - -Comments on the function test ------------------------------ -1) It didn't need to set up a pointer to the constant pool gpr13 as it is not - used ( :-( ). -2) This is a frameless function & no stack is bought. -3) The compiler was clever enough to recognise that it could return the - value in r2 as well as use it for the passed in parameter ( :-) ). -4) The basr ( branch relative & save ) trick works as follows the instruction - has a special case with r0,r0 with some instruction operands is understood as - the literal value 0, some risc architectures also do this ). So now - we are branching to the next address & the address new program counter is - in r13,so now we subtract the size of the function prologue we have executed - the size of the literal pool to get to the top of the literal pool:: - - - 0040037c int test(int b) - { # Function prologue below - 40037c: 90 de f0 34 stm %r13,%r14,52(%r15) # Save registers r13 & r14 - 400380: 0d d0 basr %r13,%r0 # Set up pointer to constant pool using - 400382: a7 da ff fa ahi %r13,-6 # basr trick - return(5+b); - # Huge main program - 400386: a7 2a 00 05 ahi %r2,5 # add 5 to r2 - - # Function epilogue below - 40038a: 98 de f0 34 lm %r13,%r14,52(%r15) # restore registers r13 & 14 - 40038e: 07 fe br %r14 # return - } - -Comments on the function main ------------------------------ -1) The compiler did this function optimally ( 8-) ):: - - Literal pool for main. - 400390: ff ff ff ec .long 0xffffffec - main(int argc,char *argv[]) - { # Function prologue below - 400394: 90 bf f0 2c stm %r11,%r15,44(%r15) # Save necessary registers - 400398: 18 0f lr %r0,%r15 # copy stack pointer to r0 - 40039a: a7 fa ff a0 ahi %r15,-96 # Make area for callee saving - 40039e: 0d d0 basr %r13,%r0 # Set up r13 to point to - 4003a0: a7 da ff f0 ahi %r13,-16 # literal pool - 4003a4: 50 00 f0 00 st %r0,0(%r15) # Save backchain - - return(test(5)); # Main Program Below - 4003a8: 58 e0 d0 00 l %r14,0(%r13) # load relative address of test from - # literal pool - 4003ac: a7 28 00 05 lhi %r2,5 # Set first parameter to 5 - 4003b0: 4d ee d0 00 bas %r14,0(%r14,%r13) # jump to test setting r14 as return - # address using branch & save instruction. - - # Function Epilogue below - 4003b4: 98 bf f0 8c lm %r11,%r15,140(%r15)# Restore necessary registers. - 4003b8: 07 fe br %r14 # return to do program exit - } - - -Compiler updates ----------------- - -:: - - main(int argc,char *argv[]) - { - 4004fc: 90 7f f0 1c stm %r7,%r15,28(%r15) - 400500: a7 d5 00 04 bras %r13,400508 - 400504: 00 40 04 f4 .long 0x004004f4 - # compiler now puts constant pool in code to so it saves an instruction - 400508: 18 0f lr %r0,%r15 - 40050a: a7 fa ff a0 ahi %r15,-96 - 40050e: 50 00 f0 00 st %r0,0(%r15) - return(test(5)); - 400512: 58 10 d0 00 l %r1,0(%r13) - 400516: a7 28 00 05 lhi %r2,5 - 40051a: 0d e1 basr %r14,%r1 - # compiler adds 1 extra instruction to epilogue this is done to - # avoid processor pipeline stalls owing to data dependencies on g5 & - # above as register 14 in the old code was needed directly after being loaded - # by the lm %r11,%r15,140(%r15) for the br %14. - 40051c: 58 40 f0 98 l %r4,152(%r15) - 400520: 98 7f f0 7c lm %r7,%r15,124(%r15) - 400524: 07 f4 br %r4 - } - - -Hartmut ( our compiler developer ) also has been threatening to take out the -stack backchain in optimised code as this also causes pipeline stalls, you -have been warned. - -64 bit z/Architecture code disassembly --------------------------------------- - -If you understand the stuff above you'll understand the stuff -below too so I'll avoid repeating myself & just say that -some of the instructions have g's on the end of them to indicate -they are 64 bit & the stack offsets are a bigger, -the only other difference you'll find between 32 & 64 bit is that -we now use f4 & f6 for floating point arguments on 64 bit:: - - 00000000800005b0 : - int test(int b) - { - return(5+b); - 800005b0: a7 2a 00 05 ahi %r2,5 - 800005b4: b9 14 00 22 lgfr %r2,%r2 # downcast to integer - 800005b8: 07 fe br %r14 - 800005ba: 07 07 bcr 0,%r7 - - - } - - 00000000800005bc

    : - main(int argc,char *argv[]) - { - 800005bc: eb bf f0 58 00 24 stmg %r11,%r15,88(%r15) - 800005c2: b9 04 00 1f lgr %r1,%r15 - 800005c6: a7 fb ff 60 aghi %r15,-160 - 800005ca: e3 10 f0 00 00 24 stg %r1,0(%r15) - return(test(5)); - 800005d0: a7 29 00 05 lghi %r2,5 - # brasl allows jumps > 64k & is overkill here bras would do fune - 800005d4: c0 e5 ff ff ff ee brasl %r14,800005b0 - 800005da: e3 40 f1 10 00 04 lg %r4,272(%r15) - 800005e0: eb bf f0 f8 00 04 lmg %r11,%r15,248(%r15) - 800005e6: 07 f4 br %r4 - } - - - -Compiling programs for debugging on Linux for s/390 & z/Architecture -==================================================================== --gdwarf-2 now works it should be considered the default debugging -format for s/390 & z/Architecture as it is more reliable for debugging -shared libraries, normal -g debugging works much better now -Thanks to the IBM java compiler developers bug reports. - -This is typically done adding/appending the flags -g or -gdwarf-2 to the -CFLAGS & LDFLAGS variables Makefile of the program concerned. - -If using gdb & you would like accurate displays of registers & -stack traces compile without optimisation i.e make sure -that there is no -O2 or similar on the CFLAGS line of the Makefile & -the emitted gcc commands, obviously this will produce worse code -( not advisable for shipment ) but it is an aid to the debugging process. - -This aids debugging because the compiler will copy parameters passed in -in registers onto the stack so backtracing & looking at passed in -parameters will work, however some larger programs which use inline functions -will not compile without optimisation. - -Debugging with optimisation has since much improved after fixing -some bugs, please make sure you are using gdb-5.0 or later developed -after Nov'2000. - - - -Debugging under VM -================== - -Notes ------ -Addresses & values in the VM debugger are always hex never decimal -Address ranges are of the format - or -. -For example, the address range 0x2000 to 0x3000 can be described as 2000-3000 -or 2000.1000 - -The VM Debugger is case insensitive. - -VM's strengths are usually other debuggers weaknesses you can get at any -resource no matter how sensitive e.g. memory management resources, change -address translation in the PSW. For kernel hacking you will reap dividends if -you get good at it. - -The VM Debugger displays operators but not operands, and also the debugger -displays useful information on the same line as the author of the code probably -felt that it was a good idea not to go over the 80 columns on the screen. -This isn't as unintuitive as it may seem as the s/390 instructions are easy to -decode mentally and you can make a good guess at a lot of them as all the -operands are nibble (half byte aligned). -So if you have an objdump listing by hand, it is quite easy to follow, and if -you don't have an objdump listing keep a copy of the s/390 Reference Summary -or alternatively the s/390 principles of operation next to you. -e.g. even I can guess that -0001AFF8' LR 180F CC 0 -is a ( load register ) lr r0,r15 - -Also it is very easy to tell the length of a 390 instruction from the 2 most -significant bits in the instruction (not that this info is really useful except -if you are trying to make sense of a hexdump of code). -Here is a table - -======================= ================== -Bits Instruction Length -======================= ================== -00 2 Bytes -01 4 Bytes -10 4 Bytes -11 6 Bytes -======================= ================== - -The debugger also displays other useful info on the same line such as the -addresses being operated on destination addresses of branches & condition codes. -e.g.:: - - 00019736' AHI A7DAFF0E CC 1 - 000198BA' BRC A7840004 -> 000198C2' CC 0 - 000198CE' STM 900EF068 >> 0FA95E78 CC 2 - - - -Useful VM debugger commands ---------------------------- - -I suppose I'd better mention this before I start -to list the current active traces do:: - - Q TR - -there can be a maximum of 255 of these per set -( more about trace sets later ). - -To stop traces issue a:: - - TR END. - -To delete a particular breakpoint issue:: - - TR DEL - -The PA1 key drops to CP mode so you can issue debugger commands, -Doing alt c (on my 3270 console at least ) clears the screen. - -hitting b comes back to the running operating system -from cp mode ( in our case linux ). - -It is typically useful to add shortcuts to your profile.exec file -if you have one ( this is roughly equivalent to autoexec.bat in DOS ). -file here are a few from mine:: - - /* this gives me command history on issuing f12 */ - set pf12 retrieve - /* this continues */ - set pf8 imm b - /* goes to trace set a */ - set pf1 imm tr goto a - /* goes to trace set b */ - set pf2 imm tr goto b - /* goes to trace set c */ - set pf3 imm tr goto c - - - -Instruction Tracing -------------------- -Setting a simple breakpoint:: - - TR I PSWA
    - -To debug a particular function try:: - - TR I R - TR I on its own will single step. - TR I DATA will trace for particular mnemonics - -e.g.:: - - TR I DATA 4D R 0197BC.4000 - -will trace for BAS'es ( opcode 4D ) in the range 0197BC.4000 - -if you were inclined you could add traces for all branch instructions & -suffix them with the run prefix so you would have a backtrace on screen -when a program crashes:: - - TR BR will trace branches into or out of an address. - -e.g.:: - - TR BR INTO 0 - -is often quite useful if a program is getting awkward & deciding -to branch to 0 & crashing as this will stop at the address before in jumps to 0. - -:: - - TR I R
    RUN cmd d g - -single steps a range of addresses but stays running & -displays the gprs on each step. - - - -Displaying & modifying Registers --------------------------------- -D G - will display all the gprs - -Adding a extra G to all the commands is necessary to access the full 64 bit -content in VM on z/Architecture. Obviously this isn't required for access -registers as these are still 32 bit. - -e.g. - -DGG - instead of DG - -D X - will display all the control registers -D AR - will display all the access registers -D AR4-7 - will display access registers 4 to 7 -CPU ALL D G - will display the GRPS of all CPUS in the configuration -D PSW - will display the current PSW -st PSW 2000 - will put the value 2000 into the PSW & cause crash your machine. -D PREFIX - displays the prefix offset - - -Displaying Memory ------------------ -To display memory mapped using the current PSW's mapping try:: - - D - -To make VM display a message each time it hits a particular address and -continue try: - -D I - will disassemble/display a range of instructions. - -ST addr 32 bit word - will store a 32 bit aligned address -D T - will display the EBCDIC in an address (if you are that way inclined) -D R - will display real addresses ( without DAT ) but with prefixing. - -There are other complex options to display if you need to get at say home space -but are in primary space the easiest thing to do is to temporarily -modify the PSW to the other addressing mode, display the stuff & then -restore it. - - - -Hints ------ -If you want to issue a debugger command without halting your virtual machine -with the PA1 key try prefixing the command with #CP e.g.:: - - #cp tr i pswa 2000 - -also suffixing most debugger commands with RUN will cause them not -to stop just display the mnemonic at the current instruction on the console. - -If you have several breakpoints you want to put into your program & -you get fed up of cross referencing with System.map -you can do the following trick for several symbols. - -:: - - grep do_signal System.map - -which emits the following among other things:: - - 0001f4e0 T do_signal - -now you can do:: - - TR I PSWA 0001f4e0 cmd msg * do_signal - -This sends a message to your own console each time do_signal is entered. -( As an aside I wrote a perl script once which automatically generated a REXX -script with breakpoints on every kernel procedure, this isn't a good idea -because there are thousands of these routines & VM can only set 255 breakpoints -at a time so you nearly had to spend as long pruning the file down as you would -entering the msgs by hand), however, the trick might be useful for a single -object file. In the 3270 terminal emulator x3270 there is a very useful option -in the file menu called "Save Screen In File" - this is very good for keeping a -copy of traces. - -From CMS help will give you online help on a particular command. -e.g.:: - - HELP DISPLAY - -Also CP has a file called profile.exec which automatically gets called -on startup of CMS ( like autoexec.bat ), keeping on a DOS analogy session -CP has a feature similar to doskey, it may be useful for you to -use profile.exec to define some keystrokes. - -SET PF9 IMM B - This does a single step in VM on pressing F8. - -SET PF10 ^ - This sets up the ^ key. - which can be used for ^c (ctrl-c),^z (ctrl-z) which can't be typed - directly into some 3270 consoles. - -SET PF11 ^- - This types the starting keystrokes for a sysrq see SysRq below. -SET PF12 RETRIEVE - This retrieves command history on pressing F12. - - -Sometimes in VM the display is set up to scroll automatically this -can be very annoying if there are messages you wish to look at -to stop this do - -TERM MORE 255 255 - This will nearly stop automatic screen updates, however it will - cause a denial of service if lots of messages go to the 3270 console, - so it would be foolish to use this as the default on a production machine. - - -Tracing particular processes ----------------------------- -The kernel's text segment is intentionally at an address in memory that it will -very seldom collide with text segments of user programs ( thanks Martin ), -this simplifies debugging the kernel. -However it is quite common for user processes to have addresses which collide -this can make debugging a particular process under VM painful under normal -circumstances as the process may change when doing a:: - - TR I R
    . - -Thankfully after reading VM's online help I figured out how to debug -I particular process. - -Your first problem is to find the STD ( segment table designation ) -of the program you wish to debug. -There are several ways you can do this here are a few - -Run:: - - objdump --syms | grep main - -To get the address of main in the program. Then:: - - tr i pswa
    - -Start the program, if VM drops to CP on what looks like the entry -point of the main function this is most likely the process you wish to debug. -Now do a D X13 or D XG13 on z/Architecture. - -On 31 bit the STD is bits 1-19 ( the STO segment table origin ) -& 25-31 ( the STL segment table length ) of CR13. - -now type:: - - TR I R STD 0.7fffffff - -e.g.:: - - TR I R STD 8F32E1FF 0.7fffffff - -Another very useful variation is:: - - TR STORE INTO STD
    - -for finding out when a particular variable changes. - -An alternative way of finding the STD of a currently running process -is to do the following, ( this method is more complex but -could be quite convenient if you aren't updating the kernel much & -so your kernel structures will stay constant for a reasonable period of -time ). - -:: - - grep task /proc//status - -from this you should see something like:: - - task: 0f160000 ksp: 0f161de8 pt_regs: 0f161f68 - -This now gives you a pointer to the task structure. - -Now make:: - - CC:="s390-gcc -g" kernel/sched.s - -To get the task_struct stabinfo. - -( task_struct is defined in include/linux/sched.h ). - -Now we want to look at -task->active_mm->pgd - -on my machine the active_mm in the task structure stab is -active_mm:(4,12),672,32 - -its offset is 672/8=84=0x54 - -the pgd member in the mm_struct stab is -pgd:(4,6)=*(29,5),96,32 -so its offset is 96/8=12=0xc - -so we'll:: - - hexdump -s 0xf160054 /dev/mem | more - -i.e. task_struct+active_mm offset -to look at the active_mm member:: - - f160054 0fee cc60 0019 e334 0000 0000 0000 0011 - -:: - - hexdump -s 0x0feecc6c /dev/mem | more - -i.e. active_mm+pgd offset:: - - feecc6c 0f2c 0000 0000 0001 0000 0001 0000 0010 - -we get something like -now do:: - - TR I R STD 0.7fffffff - -i.e. the 0x7f is added because the pgd only -gives the page table origin & we need to set the low bits -to the maximum possible segment table length. - -:: - - TR I R STD 0f2c007f 0.7fffffff - -on z/Architecture you'll probably need to do:: - - TR I R STD 0.ffffffffffffffff - -to set the TableType to 0x1 & the Table length to 3. - - - -Tracing Program Exceptions --------------------------- -If you get a crash which says something like -illegal operation or specification exception followed by a register dump -You can restart linux & trace these using the tr prog trace -option. - - -The most common ones you will normally be tracing for is: - -- 1=operation exception -- 2=privileged operation exception -- 4=protection exception -- 5=addressing exception -- 6=specification exception -- 10=segment translation exception -- 11=page translation exception - -The full list of these is on page 22 of the current s/390 Reference Summary. -e.g. - -tr prog 10 will trace segment translation exceptions. - -tr prog on its own will trace all program interruption codes. - -Trace Sets ----------- -On starting VM you are initially in the INITIAL trace set. -You can do a Q TR to verify this. -If you have a complex tracing situation where you wish to wait for instance -till a driver is open before you start tracing IO, but know in your -heart that you are going to have to make several runs through the code till you -have a clue whats going on. - -What you can do is:: - - TR I PSWA - -hit b to continue till breakpoint - -reach the breakpoint - -now do your:: - - TR GOTO B - TR IO 7c08-7c09 inst int run - -or whatever the IO channels you wish to trace are & hit b - -To got back to the initial trace set do:: - - TR GOTO INITIAL - -& the TR I PSWA will be the only active breakpoint again. - - -Tracing linux syscalls under VM -------------------------------- -Syscalls are implemented on Linux for S390 by the Supervisor call instruction -(SVC). There 256 possibilities of these as the instruction is made up of a 0xA -opcode and the second byte being the syscall number. They are traced using the -simple command:: - - TR SVC - -the syscalls are defined in linux/arch/s390/include/asm/unistd.h -e.g. to trace all file opens just do:: - - TR SVC 5 ( as this is the syscall number of open ) - - -SMP Specific commands ---------------------- -To find out how many cpus you have -Q CPUS displays all the CPU's available to your virtual machine -To find the cpu that the current cpu VM debugger commands are being directed at -do Q CPU to change the current cpu VM debugger commands are being directed at -do:: - - CPU - -On a SMP guest issue a command to all CPUs try prefixing the command with cpu -all. To issue a command to a particular cpu try cpu e.g.:: - - CPU 01 TR I R 2000.3000 - -If you are running on a guest with several cpus & you have a IO related problem -& cannot follow the flow of code but you know it isn't smp related. - -from the bash prompt issue:: - - shutdown -h now or halt. - -do a:: - - Q CPUS - -to find out how many cpus you have detach each one of them from cp except -cpu 0 by issuing a:: - - DETACH CPU 01-(number of cpus in configuration) - -& boot linux again. - -TR SIGP - will trace inter processor signal processor instructions. - -DEFINE CPU 01-(number in configuration) - will get your guests cpus back. - - -Help for displaying ascii textstrings -------------------------------------- -On the very latest VM Nucleus'es VM can now display ascii -( thanks Neale for the hint ) by doing:: - - D TX. - -e.g.:: - - D TX0.100 - -Alternatively -============= -Under older VM debuggers (I love EBDIC too) you can use following little -program which converts a command line of hex digits to ascii text. It can be -compiled under linux and you can copy the hex digits from your x3270 terminal -to your xterm if you are debugging from a linuxbox. - -This is quite useful when looking at a parameter passed in as a text string -under VM ( unless you are good at decoding ASCII in your head ). - -e.g. consider tracing an open syscall:: - - TR SVC 5 - -We have stopped at a breakpoint:: - - 000151B0' SVC 0A05 -> 0001909A' CC 0 - -D 20.8 to check the SVC old psw in the prefix area and see was it from userspace -(for the layout of the prefix area consult the "Fixed Storage Locations" -chapter of the s/390 Reference Summary if you have it available). - -:: - - V00000020 070C2000 800151B2 - -The problem state bit wasn't set & it's also too early in the boot sequence -for it to be a userspace SVC if it was we would have to temporarily switch the -psw to user space addressing so we could get at the first parameter of the open -in gpr2. - -Next do a:: - - D G2 - GPR 2 = 00014CB4 - -Now display what gpr2 is pointing to:: - - D 00014CB4.20 - V00014CB4 2F646576 2F636F6E 736F6C65 00001BF5 - V00014CC4 FC00014C B4001001 E0001000 B8070707 - -Now copy the text till the first 00 hex ( which is the end of the string -to an xterm & do hex2ascii on it:: - - hex2ascii 2F646576 2F636F6E 736F6C65 00 - -outputs:: - - Decoded Hex:=/ d e v / c o n s o l e 0x00 - -We were opening the console device, - -You can compile the code below yourself for practice :-), - -:: - - /* - * hex2ascii.c - * a useful little tool for converting a hexadecimal command line to ascii - * - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - * (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation. - */ - #include - - int main(int argc,char *argv[]) - { - int cnt1,cnt2,len,toggle=0; - int startcnt=1; - unsigned char c,hex; - - if(argc>1&&(strcmp(argv[1],"-a")==0)) - startcnt=2; - printf("Decoded Hex:="); - for(cnt1=startcnt;cnt1='0'&&c<='9') - c=c-'0'; - if(c>='A'&&c<='F') - c=c-'A'+10; - if(c>='a'&&c<='f') - c=c-'a'+10; - switch(toggle) - { - case 0: - hex=c<<4; - toggle=1; - break; - case 1: - hex+=c; - if(hex<32||hex>127) - { - if(startcnt==1) - printf("0x%02X ",(int)hex); - else - printf("."); - } - else - { - printf("%c",hex); - if(startcnt==1) - printf(" "); - } - toggle=0; - break; - } - } - } - printf("\n"); - } - - - - -Stack tracing under VM ----------------------- -A basic backtrace ------------------ - -Here are the tricks I use 9 out of 10 times it works pretty well, - -When your backchain reaches a dead end --------------------------------------- -This can happen when an exception happens in the kernel and the kernel is -entered twice. If you reach the NULL pointer at the end of the back chain you -should be able to sniff further back if you follow the following tricks. -1) A kernel address should be easy to recognise since it is in -primary space & the problem state bit isn't set & also -The Hi bit of the address is set. -2) Another backchain should also be easy to recognise since it is an -address pointing to another address approximately 100 bytes or 0x70 hex -behind the current stackpointer. - - -Here is some practice. - -boot the kernel & hit PA1 at some random time - -d g to display the gprs, this should display something like:: - - GPR 0 = 00000001 00156018 0014359C 00000000 - GPR 4 = 00000001 001B8888 000003E0 00000000 - GPR 8 = 00100080 00100084 00000000 000FE000 - GPR 12 = 00010400 8001B2DC 8001B36A 000FFED8 - -Note that GPR14 is a return address but as we are real men we are going to -trace the stack. -display 0x40 bytes after the stack pointer:: - - V000FFED8 000FFF38 8001B838 80014C8E 000FFF38 - V000FFEE8 00000000 00000000 000003E0 00000000 - V000FFEF8 00100080 00100084 00000000 000FE000 - V000FFF08 00010400 8001B2DC 8001B36A 000FFED8 - - -Ah now look at whats in sp+56 (sp+0x38) this is 8001B36A our saved r14 if -you look above at our stackframe & also agrees with GPR14. - -now backchain:: - - d 000FFF38.40 - -we now are taking the contents of SP to get our first backchain:: - - V000FFF38 000FFFA0 00000000 00014995 00147094 - V000FFF48 00147090 001470A0 000003E0 00000000 - V000FFF58 00100080 00100084 00000000 001BF1D0 - V000FFF68 00010400 800149BA 80014CA6 000FFF38 - -This displays a 2nd return address of 80014CA6 - -now do:: - - d 000FFFA0.40 - -for our 3rd backchain:: - - V000FFFA0 04B52002 0001107F 00000000 00000000 - V000FFFB0 00000000 00000000 FF000000 0001107F - V000FFFC0 00000000 00000000 00000000 00000000 - V000FFFD0 00010400 80010802 8001085A 000FFFA0 - - -our 3rd return address is 8001085A - -as the 04B52002 looks suspiciously like rubbish it is fair to assume that the -kernel entry routines for the sake of optimisation don't set up a backchain. - -now look at System.map to see if the addresses make any sense:: - - grep -i 0001b3 System.map - -outputs among other things:: - - 0001b304 T cpu_idle - -so 8001B36A -is cpu_idle+0x66 ( quiet the cpu is asleep, don't wake it ) - -:: - - grep -i 00014 System.map - -produces among other things:: - - 00014a78 T start_kernel - -so 0014CA6 is start_kernel+some hex number I can't add in my head. - -:: - - grep -i 00108 System.map - -this produces:: - - 00010800 T _stext - -so 8001085A is _stext+0x5a - -Congrats you've done your first backchain. - - - -s/390 & z/Architecture IO Overview -================================== - -I am not going to give a course in 390 IO architecture as this would take me -quite a while and I'm no expert. Instead I'll give a 390 IO architecture -summary for Dummies. If you have the s/390 principles of operation available -read this instead. If nothing else you may find a few useful keywords in here -and be able to use them on a web search engine to find more useful information. - -Unlike other bus architectures modern 390 systems do their IO using mostly -fibre optics and devices such as tapes and disks can be shared between several -mainframes. Also S390 can support up to 65536 devices while a high end PC based -system might be choking with around 64. - -Here is some of the common IO terminology: - -Subchannel: - This is the logical number most IO commands use to talk to an IO device. There - can be up to 0x10000 (65536) of these in a configuration, typically there are a - few hundred. Under VM for simplicity they are allocated contiguously, however - on the native hardware they are not. They typically stay consistent between - boots provided no new hardware is inserted or removed. - - Under Linux for s390 we use these as IRQ's and also when issuing an IO command - (CLEAR SUBCHANNEL, HALT SUBCHANNEL, MODIFY SUBCHANNEL, RESUME SUBCHANNEL, - START SUBCHANNEL, STORE SUBCHANNEL and TEST SUBCHANNEL). We use this as the ID - of the device we wish to talk to. The most important of these instructions are - START SUBCHANNEL (to start IO), TEST SUBCHANNEL (to check whether the IO - completed successfully) and HALT SUBCHANNEL (to kill IO). A subchannel can have - up to 8 channel paths to a device, this offers redundancy if one is not - available. - -Device Number: - This number remains static and is closely tied to the hardware. There are 65536 - of these, made up of a CHPID (Channel Path ID, the most significant 8 bits) and - another lsb 8 bits. These remain static even if more devices are inserted or - removed from the hardware. There is a 1 to 1 mapping between subchannels and - device numbers, provided devices aren't inserted or removed. - -Channel Control Words: - CCWs are linked lists of instructions initially pointed to by an operation - request block (ORB), which is initially given to Start Subchannel (SSCH) - command along with the subchannel number for the IO subsystem to process - while the CPU continues executing normal code. - CCWs come in two flavours, Format 0 (24 bit for backward compatibility) and - Format 1 (31 bit). These are typically used to issue read and write (and many - other) instructions. They consist of a length field and an absolute address - field. - - Each IO typically gets 1 or 2 interrupts, one for channel end (primary status) - when the channel is idle, and the second for device end (secondary status). - Sometimes you get both concurrently. You check how the IO went on by issuing a - TEST SUBCHANNEL at each interrupt, from which you receive an Interruption - response block (IRB). If you get channel and device end status in the IRB - without channel checks etc. your IO probably went okay. If you didn't you - probably need to examine the IRB, extended status word etc. - If an error occurs, more sophisticated control units have a facility known as - concurrent sense. This means that if an error occurs Extended sense information - will be presented in the Extended status word in the IRB. If not you have to - issue a subsequent SENSE CCW command after the test subchannel. - - -TPI (Test pending interrupt) can also be used for polled IO, but in -multitasking multiprocessor systems it isn't recommended except for -checking special cases (i.e. non looping checks for pending IO etc.). - -Store Subchannel and Modify Subchannel can be used to examine and modify -operating characteristics of a subchannel (e.g. channel paths). - -Other IO related Terms: - -Sysplex: - S390's Clustering Technology -QDIO: - S390's new high speed IO architecture to support devices such as gigabit - ethernet, this architecture is also designed to be forward compatible with - upcoming 64 bit machines. - - -General Concepts ----------------- - -Input Output Processors (IOP's) are responsible for communicating between -the mainframe CPU's & the channel & relieve the mainframe CPU's from the -burden of communicating with IO devices directly, this allows the CPU's to -concentrate on data processing. - -IOP's can use one or more links ( known as channel paths ) to talk to each -IO device. It first checks for path availability & chooses an available one, -then starts ( & sometimes terminates IO ). -There are two types of channel path: ESCON & the Parallel IO interface. - -IO devices are attached to control units, control units provide the -logic to interface the channel paths & channel path IO protocols to -the IO devices, they can be integrated with the devices or housed separately -& often talk to several similar devices ( typical examples would be raid -controllers or a control unit which connects to 1000 3270 terminals ):: - - - +---------------------------------------------------------------+ - | +-----+ +-----+ +-----+ +-----+ +----------+ +----------+ | - | | CPU | | CPU | | CPU | | CPU | | Main | | Expanded | | - | | | | | | | | | | Memory | | Storage | | - | +-----+ +-----+ +-----+ +-----+ +----------+ +----------+ | - |---------------------------------------------------------------+ - | IOP | IOP | IOP | - |--------------------------------------------------------------- - | C | C | C | C | C | C | C | C | C | C | C | C | C | C | C | C | - ---------------------------------------------------------------- - || || - || Bus & Tag Channel Path || ESCON - || ====================== || Channel - || || || || Path - +----------+ +----------+ +----------+ - | | | | | | - | CU | | CU | | CU | - | | | | | | - +----------+ +----------+ +----------+ - | | | | | - +----------+ +----------+ +----------+ +----------+ +----------+ - |I/O Device| |I/O Device| |I/O Device| |I/O Device| |I/O Device| - +----------+ +----------+ +----------+ +----------+ +----------+ - CPU = Central Processing Unit - C = Channel - IOP = IP Processor - CU = Control Unit - -The 390 IO systems come in 2 flavours the current 390 machines support both - -The Older 360 & 370 Interface,sometimes called the Parallel I/O interface, -sometimes called Bus-and Tag & sometimes Original Equipment Manufacturers -Interface (OEMI). - -This byte wide Parallel channel path/bus has parity & data on the "Bus" cable -and control lines on the "Tag" cable. These can operate in byte multiplex mode -for sharing between several slow devices or burst mode and monopolize the -channel for the whole burst. Up to 256 devices can be addressed on one of these -cables. These cables are about one inch in diameter. The maximum unextended -length supported by these cables is 125 Meters but this can be extended up to -2km with a fibre optic channel extended such as a 3044. The maximum burst speed -supported is 4.5 megabytes per second. However, some really old processors -support only transfer rates of 3.0, 2.0 & 1.0 MB/sec. -One of these paths can be daisy chained to up to 8 control units. - - -ESCON if fibre optic it is also called FICON -Was introduced by IBM in 1990. Has 2 fibre optic cables and uses either leds or -lasers for communication at a signaling rate of up to 200 megabits/sec. As -10bits are transferred for every 8 bits info this drops to 160 megabits/sec -and to 18.6 Megabytes/sec once control info and CRC are added. ESCON only -operates in burst mode. - -ESCONs typical max cable length is 3km for the led version and 20km for the -laser version known as XDF (extended distance facility). This can be further -extended by using an ESCON director which triples the above mentioned ranges. -Unlike Bus & Tag as ESCON is serial it uses a packet switching architecture, -the standard Bus & Tag control protocol is however present within the packets. -Up to 256 devices can be attached to each control unit that uses one of these -interfaces. - -Common 390 Devices include: -Network adapters typically OSA2,3172's,2116's & OSA-E gigabit ethernet adapters, -Consoles 3270 & 3215 (a teletype emulated under linux for a line mode console). -DASD's direct access storage devices ( otherwise known as hard disks ). -Tape Drives. -CTC ( Channel to Channel Adapters ), -ESCON or Parallel Cables used as a very high speed serial link -between 2 machines. - - -Debugging IO on s/390 & z/Architecture under VM -=============================================== - -Now we are ready to go on with IO tracing commands under VM - -A few self explanatory queries:: - - Q OSA - Q CTC - Q DISK ( This command is CMS specific ) - Q DASD - -Q OSA on my machine returns:: - - OSA 7C08 ON OSA 7C08 SUBCHANNEL = 0000 - OSA 7C09 ON OSA 7C09 SUBCHANNEL = 0001 - OSA 7C14 ON OSA 7C14 SUBCHANNEL = 0002 - OSA 7C15 ON OSA 7C15 SUBCHANNEL = 0003 - -If you have a guest with certain privileges you may be able to see devices -which don't belong to you. To avoid this, add the option V. -e.g.:: - - Q V OSA - -Now using the device numbers returned by this command we will -Trace the io starting up on the first device 7c08 & 7c09 -In our simplest case we can trace the -start subchannels -like TR SSCH 7C08-7C09 -or the halt subchannels -or TR HSCH 7C08-7C09 -MSCH's ,STSCH's I think you can guess the rest - -A good trick is tracing all the IO's and CCWS and spooling them into the reader -of another VM guest so he can ftp the logfile back to his own machine. I'll do -a small bit of this and give you a look at the output. - -1) Spool stdout to VM reader:: - - SP PRT TO (another vm guest ) or * for the local vm guest - -2) Fill the reader with the trace:: - - TR IO 7c08-7c09 INST INT CCW PRT RUN - -3) Start up linux:: - - i 00c -4) Finish the trace:: - - TR END - -5) close the reader:: - - C PRT - -6) list reader contents:: - - RDRLIST - -7) copy it to linux4's minidisk:: - - RECEIVE / LOG TXT A1 ( replace - -8) -filel & press F11 to look at it -You should see something like:: - - 00020942' SSCH B2334000 0048813C CC 0 SCH 0000 DEV 7C08 - CPA 000FFDF0 PARM 00E2C9C4 KEY 0 FPI C0 LPM 80 - CCW 000FFDF0 E4200100 00487FE8 0000 E4240100 ........ - IDAL 43D8AFE8 - IDAL 0FB76000 - 00020B0A' I/O DEV 7C08 -> 000197BC' SCH 0000 PARM 00E2C9C4 - 00021628' TSCH B2354000 >> 00488164 CC 0 SCH 0000 DEV 7C08 - CCWA 000FFDF8 DEV STS 0C SCH STS 00 CNT 00EC - KEY 0 FPI C0 CC 0 CTLS 4007 - 00022238' STSCH B2344000 >> 00488108 CC 0 SCH 0000 DEV 7C08 - -If you don't like messing up your readed ( because you possibly booted from it ) -you can alternatively spool it to another readers guest. - - -Other common VM device related commands ---------------------------------------------- -These commands are listed only because they have -been of use to me in the past & may be of use to -you too. For more complete info on each of the commands -use type HELP from CMS. - -detaching devices:: - - DET - ATT - -attach a device to guest * for your own guest - -READY - cause VM to issue a fake interrupt. - -The VARY command is normally only available to VM administrators:: - - VARY ON PATH TO - VARY OFF PATH FROM - -This is used to switch on or off channel paths to devices. - -Q CHPID - This displays state of devices using this channel path - -D SCHIB - This displays the subchannel information SCHIB block for the device. - this I believe is also only available to administrators. - -DEFINE CTC - defines a virtual CTC channel to channel connection - 2 need to be defined on each guest for the CTC driver to use. - -COUPLE devno userid remote devno - Joins a local virtual device to a remote virtual device - ( commonly used for the CTC driver ). - -Building a VM ramdisk under CMS which linux can use:: - - def vfb- - -blocksize is commonly 4096 for linux. - -Formatting it:: - - format (blksize - -Sharing a disk between multiple guests:: - - LINK userid devno1 devno2 mode password - - - -GDB on S390 -=========== -N.B. if compiling for debugging gdb works better without optimisation -( see Compiling programs for debugging ) - -invocation ----------- -gdb - -Online help ------------ -help: gives help on commands - -e.g.:: - - help - help display - -Note gdb's online help is very good use it. - - -Assembly --------- -info registers: - displays registers other than floating point. - -info all-registers: - displays floating points as well. - -disassemble: - disassembles - -e.g.:: - - disassemble without parameters will disassemble the current function - disassemble $pc $pc+10 - -Viewing & modifying variables ------------------------------ -print or p: - displays variable or register - -e.g. p/x $sp will display the stack pointer - -display: - prints variable or register each time program stops - -e.g.:: - - display/x $pc will display the program counter - display argc - -undisplay: - undo's display's - -info breakpoints: - shows all current breakpoints - -info stack: - shows stack back trace (if this doesn't work too well, I'll show - you the stacktrace by hand below). - -info locals: - displays local variables. - -info args: - display current procedure arguments. - -set args: - will set argc & argv each time the victim program is invoked - -e.g.:: - - set =value - set argc=100 - set $pc=0 - - - -Modifying execution -------------------- -step: - steps n lines of sourcecode - -step - steps 1 line. - -step 100 - steps 100 lines of code. - -next: - like step except this will not step into subroutines - -stepi: - steps a single machine code instruction. - -e.g.:: - - stepi 100 - -nexti: - steps a single machine code instruction but will not step into - subroutines. - -finish: - will run until exit of the current routine - -run: - (re)starts a program - -cont: - continues a program - -quit: - exits gdb. - - -breakpoints ------------- - -break - sets a breakpoint - -e.g.:: - - break main - break *$pc - break *0x400618 - -Here's a really useful one for large programs - -rbr - Set a breakpoint for all functions matching REGEXP - -e.g.:: - - rbr 390 - -will set a breakpoint with all functions with 390 in their name. - -info breakpoints - lists all breakpoints - -delete: - delete breakpoint by number or delete them all - -e.g. - -delete 1 - will delete the first breakpoint - - -delete - will delete them all - -watch: - This will set a watchpoint ( usually hardware assisted ), - -This will watch a variable till it changes - -e.g. - -watch cnt - will watch the variable cnt till it changes. - -As an aside unfortunately gdb's, architecture independent watchpoint code -is inconsistent & not very good, watchpoints usually work but not always. - -info watchpoints: - Display currently active watchpoints - -condition: ( another useful one ) - Specify breakpoint number N to break only if COND is true. - -Usage is `condition N COND`, where N is an integer and COND is an -expression to be evaluated whenever breakpoint N is reached. - - - -User defined functions/macros ------------------------------ -define: ( Note this is very very useful,simple & powerful ) - -usage define end - -examples which you should consider putting into .gdbinit in your home -directory:: - - define d - stepi - disassemble $pc $pc+10 - end - define e - nexti - disassemble $pc $pc+10 - end - - -Other hard to classify stuff ----------------------------- -signal n: - sends the victim program a signal. - -e.g. `signal 3` will send a SIGQUIT. - -info signals: - what gdb does when the victim receives certain signals. - -list: - -e.g.: - -list - lists current function source -list 1,10 - list first 10 lines of current file. - -list test.c:1,10 - - -directory: - Adds directories to be searched for source if gdb cannot find the source. - (note it is a bit sensitive about slashes) - -e.g. To add the root of the filesystem to the searchpath do:: - - directory // - - -call -This calls a function in the victim program, this is pretty powerful -e.g. -(gdb) call printf("hello world") -outputs: -$1 = 11 - -You might now be thinking that the line above didn't work, something extra had -to be done. -(gdb) call fflush(stdout) -hello world$2 = 0 -As an aside the debugger also calls malloc & free under the hood -to make space for the "hello world" string. - - - -hints ------ -1) command completion works just like bash - ( if you are a bad typist like me this really helps ) - -e.g. hit br & cursor up & down :-). - -2) if you have a debugging problem that takes a few steps to recreate -put the steps into a file called .gdbinit in your current working directory -if you have defined a few extra useful user defined commands put these in -your home directory & they will be read each time gdb is launched. - -A typical .gdbinit file might be.:: - - break main - run - break runtime_exception - cont - - -stack chaining in gdb by hand ------------------------------ -This is done using a the same trick described for VM:: - - p/x (*($sp+56))&0x7fffffff - -get the first backchain. - -For z/Architecture -Replace 56 with 112 & ignore the &0x7fffffff -in the macros below & do nasty casts to longs like the following -as gdb unfortunately deals with printed arguments as ints which -messes up everything. - -i.e. here is a 3rd backchain dereference:: - - p/x *(long *)(***(long ***)$sp+112) - - -this outputs:: - - $5 = 0x528f18 - -on my machine. - -Now you can use:: - - info symbol (*($sp+56))&0x7fffffff - -you might see something like:: - - rl_getc + 36 in section .text - -telling you what is located at address 0x528f18 -Now do:: - - p/x (*(*$sp+56))&0x7fffffff - -This outputs:: - - $6 = 0x528ed0 - -Now do:: - - info symbol (*(*$sp+56))&0x7fffffff - rl_read_key + 180 in section .text - -now do:: - - p/x (*(**$sp+56))&0x7fffffff - -& so on. - -Disassembling instructions without debug info ---------------------------------------------- -gdb typically complains if there is a lack of debugging -symbols in the disassemble command with -"No function contains specified address." To get around -this do:: - - x/xi
    - -e.g.:: - - x/20xi 0x400730 - - - -Note: - Remember gdb has history just like bash you don't need to retype the - whole line just use the up & down arrows. - - - -For more info -------------- -From your linuxbox do:: - - man gdb - -or:: - - info gdb. - -core dumps ----------- - -What a core dump ? -^^^^^^^^^^^^^^^^^^ - -A core dump is a file generated by the kernel (if allowed) which contains the -registers and all active pages of the program which has crashed. - -From this file gdb will allow you to look at the registers, stack trace and -memory of the program as if it just crashed on your system. It is usually -called core and created in the current working directory. - -This is very useful in that a customer can mail a core dump to a technical -support department and the technical support department can reconstruct what -happened. Provided they have an identical copy of this program with debugging -symbols compiled in and the source base of this build is available. - -In short it is far more useful than something like a crash log could ever hope -to be. - -Why have I never seen one ? -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Probably because you haven't used the command:: - - ulimit -c unlimited in bash - -to allow core dumps, now do:: - - ulimit -a - -to verify that the limit was accepted. - -A sample core dump - To create this I'm going to do:: - - ulimit -c unlimited - gdb - -to launch gdb (my victim app. ) now be bad & do the following from another -telnet/xterm session to the same machine:: - - ps -aux | grep gdb - kill -SIGSEGV - -or alternatively use `killall -SIGSEGV gdb` if you have the killall command. - -Now look at the core dump:: - - ./gdb core - -Displays the following:: - - GNU gdb 4.18 - Copyright 1998 Free Software Foundation, Inc. - GDB is free software, covered by the GNU General Public License, and you are - welcome to change it and/or distribute copies of it under certain conditions. - Type "show copying" to see the conditions. - There is absolutely no warranty for GDB. Type "show warranty" for details. - This GDB was configured as "s390-ibm-linux"... - Core was generated by `./gdb'. - Program terminated with signal 11, Segmentation fault. - Reading symbols from /usr/lib/libncurses.so.4...done. - Reading symbols from /lib/libm.so.6...done. - Reading symbols from /lib/libc.so.6...done. - Reading symbols from /lib/ld-linux.so.2...done. - #0 0x40126d1a in read () from /lib/libc.so.6 - Setting up the environment for debugging gdb. - Breakpoint 1 at 0x4dc6f8: file utils.c, line 471. - Breakpoint 2 at 0x4d87a4: file top.c, line 2609. - (top-gdb) info stack - #0 0x40126d1a in read () from /lib/libc.so.6 - #1 0x528f26 in rl_getc (stream=0x7ffffde8) at input.c:402 - #2 0x528ed0 in rl_read_key () at input.c:381 - #3 0x5167e6 in readline_internal_char () at readline.c:454 - #4 0x5168ee in readline_internal_charloop () at readline.c:507 - #5 0x51692c in readline_internal () at readline.c:521 - #6 0x5164fe in readline (prompt=0x7ffff810) - at readline.c:349 - #7 0x4d7a8a in command_line_input (prompt=0x564420 "(gdb) ", repeat=1, - annotation_suffix=0x4d6b44 "prompt") at top.c:2091 - #8 0x4d6cf0 in command_loop () at top.c:1345 - #9 0x4e25bc in main (argc=1, argv=0x7ffffdf4) at main.c:635 - - -LDD -=== -This is a program which lists the shared libraries which a library needs, -Note you also get the relocations of the shared library text segments which -help when using objdump --source. - -e.g.:: - - ldd ./gdb - -outputs:: - - libncurses.so.4 => /usr/lib/libncurses.so.4 (0x40018000) - libm.so.6 => /lib/libm.so.6 (0x4005e000) - libc.so.6 => /lib/libc.so.6 (0x40084000) - /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) - - -Debugging shared libraries -========================== -Most programs use shared libraries, however it can be very painful -when you single step instruction into a function like printf for the -first time & you end up in functions like _dl_runtime_resolve this is -the ld.so doing lazy binding, lazy binding is a concept in ELF where -shared library functions are not loaded into memory unless they are -actually used, great for saving memory but a pain to debug. - -To get around this either relink the program -static or exit gdb type -export LD_BIND_NOW=true this will stop lazy binding & restart the gdb'ing -the program in question. - - - -Debugging modules -================= -As modules are dynamically loaded into the kernel their address can be -anywhere to get around this use the -m option with insmod to emit a load -map which can be piped into a file if required. - -The proc file system -==================== -What is it ?. -It is a filesystem created by the kernel with files which are created on demand -by the kernel if read, or can be used to modify kernel parameters, -it is a powerful concept. - -e.g.:: - - cat /proc/sys/net/ipv4/ip_forward - -On my machine outputs:: - - 0 - -telling me ip_forwarding is not on to switch it on I can do:: - - echo 1 > /proc/sys/net/ipv4/ip_forward - -cat it again:: - - cat /proc/sys/net/ipv4/ip_forward - -On my machine now outputs:: - - 1 - -IP forwarding is on. - -There is a lot of useful info in here best found by going in and having a look -around, so I'll take you through some entries I consider important. - -All the processes running on the machine have their own entry defined by -/proc/ - -So lets have a look at the init process:: - - cd /proc/1 - cat cmdline - -emits:: - - init [2] - -:: - - cd /proc/1/fd - -This contains numerical entries of all the open files, -some of these you can cat e.g. stdout (2):: - - cat /proc/29/maps - -on my machine emits:: - - 00400000-00478000 r-xp 00000000 5f:00 4103 /bin/bash - 00478000-0047e000 rw-p 00077000 5f:00 4103 /bin/bash - 0047e000-00492000 rwxp 00000000 00:00 0 - 40000000-40015000 r-xp 00000000 5f:00 14382 /lib/ld-2.1.2.so - 40015000-40016000 rw-p 00014000 5f:00 14382 /lib/ld-2.1.2.so - 40016000-40017000 rwxp 00000000 00:00 0 - 40017000-40018000 rw-p 00000000 00:00 0 - 40018000-4001b000 r-xp 00000000 5f:00 14435 /lib/libtermcap.so.2.0.8 - 4001b000-4001c000 rw-p 00002000 5f:00 14435 /lib/libtermcap.so.2.0.8 - 4001c000-4010d000 r-xp 00000000 5f:00 14387 /lib/libc-2.1.2.so - 4010d000-40111000 rw-p 000f0000 5f:00 14387 /lib/libc-2.1.2.so - 40111000-40114000 rw-p 00000000 00:00 0 - 40114000-4011e000 r-xp 00000000 5f:00 14408 /lib/libnss_files-2.1.2.so - 4011e000-4011f000 rw-p 00009000 5f:00 14408 /lib/libnss_files-2.1.2.so - 7fffd000-80000000 rwxp ffffe000 00:00 0 - - -Showing us the shared libraries init uses where they are in memory -& memory access permissions for each virtual memory area. - -/proc/1/cwd is a softlink to the current working directory. - -/proc/1/root is the root of the filesystem for this process. - -/proc/1/mem is the current running processes memory which you -can read & write to like a file. - -strace uses this sometimes as it is a bit faster than the -rather inefficient ptrace interface for peeking at DATA. - -:: - - cat status - - Name: init - State: S (sleeping) - Pid: 1 - PPid: 0 - Uid: 0 0 0 0 - Gid: 0 0 0 0 - Groups: - VmSize: 408 kB - VmLck: 0 kB - VmRSS: 208 kB - VmData: 24 kB - VmStk: 8 kB - VmExe: 368 kB - VmLib: 0 kB - SigPnd: 0000000000000000 - SigBlk: 0000000000000000 - SigIgn: 7fffffffd7f0d8fc - SigCgt: 00000000280b2603 - CapInh: 00000000fffffeff - CapPrm: 00000000ffffffff - CapEff: 00000000fffffeff - - User PSW: 070de000 80414146 - task: 004b6000 tss: 004b62d8 ksp: 004b7ca8 pt_regs: 004b7f68 - User GPRS: - 00000400 00000000 0000000b 7ffffa90 - 00000000 00000000 00000000 0045d9f4 - 0045cafc 7ffffa90 7fffff18 0045cb08 - 00010400 804039e8 80403af8 7ffff8b0 - User ACRS: - 00000000 00000000 00000000 00000000 - 00000001 00000000 00000000 00000000 - 00000000 00000000 00000000 00000000 - 00000000 00000000 00000000 00000000 - Kernel BackChain CallChain BackChain CallChain - 004b7ca8 8002bd0c 004b7d18 8002b92c - 004b7db8 8005cd50 004b7e38 8005d12a - 004b7f08 80019114 - -Showing among other things memory usage & status of some signals & -the processes'es registers from the kernel task_structure -as well as a backchain which may be useful if a process crashes -in the kernel for some unknown reason. - -Some driver debugging techniques -================================ -debug feature -------------- -Some of our drivers now support a "debug feature" in -/proc/s390dbf see s390dbf.txt in the linux/Documentation directory -for more info. - -e.g. -to switch on the lcs "debug feature":: - - echo 5 > /proc/s390dbf/lcs/level - -& then after the error occurred:: - - cat /proc/s390dbf/lcs/sprintf >/logfile - -the logfile now contains some information which may help -tech support resolve a problem in the field. - - - -high level debugging network drivers ------------------------------------- -ifconfig is a quite useful command -it gives the current state of network drivers. - -If you suspect your network device driver is dead -one way to check is type:: - - ifconfig - -e.g. tr0 - -You should see something like:: - - ifconfig tr0 - tr0 Link encap:16/4 Mbps Token Ring (New) HWaddr 00:04:AC:20:8E:48 - inet addr:9.164.185.132 Bcast:9.164.191.255 Mask:255.255.224.0 - UP BROADCAST RUNNING MULTICAST MTU:2000 Metric:1 - RX packets:246134 errors:0 dropped:0 overruns:0 frame:0 - TX packets:5 errors:0 dropped:0 overruns:0 carrier:0 - collisions:0 txqueuelen:100 - -if the device doesn't say up -try:: - - /etc/rc.d/init.d/network start - -( this starts the network stack & hopefully calls ifconfig tr0 up ). -ifconfig looks at the output of /proc/net/dev and presents it in a more -presentable form. - -Now ping the device from a machine in the same subnet. - -if the RX packets count & TX packets counts don't increment you probably -have problems. - -next:: - - cat /proc/net/arp - -Do you see any hardware addresses in the cache if not you may have problems. -Next try:: - - ping -c 5 - -i.e. the Bcast field above in the output of -ifconfig. Do you see any replies from machines other than the local machine -if not you may have problems. also if the TX packets count in ifconfig -hasn't incremented either you have serious problems in your driver -(e.g. the txbusy field of the network device being stuck on ) -or you may have multiple network devices connected. - - -chandev -------- -There is a new device layer for channel devices, some -drivers e.g. lcs are registered with this layer. - -If the device uses the channel device layer you'll be -able to find what interrupts it uses & the current state -of the device. - -See the manpage chandev.8 &type cat /proc/chandev for more info. - - -SysRq -===== -This is now supported by linux for s/390 & z/Architecture. - -To enable it do compile the kernel with:: - - Kernel Hacking -> Magic SysRq Key Enabled - -Then:: - - echo "1" > /proc/sys/kernel/sysrq - -also type:: - - echo "8" >/proc/sys/kernel/printk - -To make printk output go to console. - -On 390 all commands are prefixed with:: - - ^- - -e.g.:: - - ^-t will show tasks. - ^-? or some unknown command will display help. - -The sysrq key reading is very picky ( I have to type the keys in an -xterm session & paste them into the x3270 console ) -& it may be wise to predefine the keys as described in the VM hints above - -This is particularly useful for syncing disks unmounting & rebooting -if the machine gets partially hung. - -Read Documentation/admin-guide/sysrq.rst for more info - -References: -=========== -- Enterprise Systems Architecture Reference Summary -- Enterprise Systems Architecture Principles of Operation -- Hartmut Penners s390 stack frame sheet. -- IBM Mainframe Channel Attachment a technology brief from a CISCO webpage -- Various bits of man & info pages of Linux. -- Linux & GDB source. -- Various info & man pages. -- CMS Help on tracing commands. -- Linux for s/390 Elf Application Binary Interface -- Linux for z/Series Elf Application Binary Interface ( Both Highly Recommended ) -- z/Architecture Principles of Operation SA22-7832-00 -- Enterprise Systems Architecture/390 Reference Summary SA22-7209-01 & the -- Enterprise Systems Architecture/390 Principles of Operation SA22-7201-05 - -Special Thanks -============== -Special thanks to Neale Ferguson who maintains a much -prettier HTML version of this page at -http://linuxvm.org/penguinvm/ -Bob Grainger Stefan Bader & others for reporting bugs diff --git a/Documentation/s390/index.rst b/Documentation/s390/index.rst index 4602312909d3daebb203d2e7f13be5e247134f1a..f7af2061e406573cfbe6296c12ec67e8052797ee 100644 --- a/Documentation/s390/index.rst +++ b/Documentation/s390/index.rst @@ -7,7 +7,6 @@ s390 Architecture cds 3270 - debugging390 driver-model monreader qeth @@ -15,7 +14,6 @@ s390 Architecture vfio-ap vfio-ccw zfcpdump - dasd common_io text_files diff --git a/Documentation/scheduler/sched-bwc.rst b/Documentation/scheduler/sched-bwc.rst index 3a9064219656cc97a2bc5881ed67e9fdb2ea15b2..9801d6b284b1ecfdd51b7e1ab5ab5f9bc6da3b40 100644 --- a/Documentation/scheduler/sched-bwc.rst +++ b/Documentation/scheduler/sched-bwc.rst @@ -9,15 +9,16 @@ CFS bandwidth control is a CONFIG_FAIR_GROUP_SCHED extension which allows the specification of the maximum CPU bandwidth available to a group or hierarchy. The bandwidth allowed for a group is specified using a quota and period. Within -each given "period" (microseconds), a group is allowed to consume only up to -"quota" microseconds of CPU time. When the CPU bandwidth consumption of a -group exceeds this limit (for that period), the tasks belonging to its -hierarchy will be throttled and are not allowed to run again until the next -period. - -A group's unused runtime is globally tracked, being refreshed with quota units -above at each period boundary. As threads consume this bandwidth it is -transferred to cpu-local "silos" on a demand basis. The amount transferred +each given "period" (microseconds), a task group is allocated up to "quota" +microseconds of CPU time. That quota is assigned to per-cpu run queues in +slices as threads in the cgroup become runnable. Once all quota has been +assigned any additional requests for quota will result in those threads being +throttled. Throttled threads will not be able to run again until the next +period when the quota is replenished. + +A group's unassigned quota is globally tracked, being refreshed back to +cfs_quota units at each period boundary. As threads consume this bandwidth it +is transferred to cpu-local "silos" on a demand basis. The amount transferred within each of these updates is tunable and described as the "slice". Management @@ -35,12 +36,12 @@ The default values are:: A value of -1 for cpu.cfs_quota_us indicates that the group does not have any bandwidth restriction in place, such a group is described as an unconstrained -bandwidth group. This represents the traditional work-conserving behavior for +bandwidth group. This represents the traditional work-conserving behavior for CFS. Writing any (valid) positive value(s) will enact the specified bandwidth limit. -The minimum quota allowed for the quota or period is 1ms. There is also an -upper bound on the period length of 1s. Additional restrictions exist when +The minimum quota allowed for the quota or period is 1ms. There is also an +upper bound on the period length of 1s. Additional restrictions exist when bandwidth limits are used in a hierarchical fashion, these are explained in more detail below. @@ -53,8 +54,8 @@ unthrottled if it is in a constrained state. System wide settings -------------------- For efficiency run-time is transferred between the global pool and CPU local -"silos" in a batch fashion. This greatly reduces global accounting pressure -on large systems. The amount transferred each time such an update is required +"silos" in a batch fashion. This greatly reduces global accounting pressure +on large systems. The amount transferred each time such an update is required is described as the "slice". This is tunable via procfs:: @@ -97,6 +98,51 @@ There are two ways in which a group may become throttled: In case b) above, even though the child may have runtime remaining it will not be allowed to until the parent's runtime is refreshed. +CFS Bandwidth Quota Caveats +--------------------------- +Once a slice is assigned to a cpu it does not expire. However all but 1ms of +the slice may be returned to the global pool if all threads on that cpu become +unrunnable. This is configured at compile time by the min_cfs_rq_runtime +variable. This is a performance tweak that helps prevent added contention on +the global lock. + +The fact that cpu-local slices do not expire results in some interesting corner +cases that should be understood. + +For cgroup cpu constrained applications that are cpu limited this is a +relatively moot point because they will naturally consume the entirety of their +quota as well as the entirety of each cpu-local slice in each period. As a +result it is expected that nr_periods roughly equal nr_throttled, and that +cpuacct.usage will increase roughly equal to cfs_quota_us in each period. + +For highly-threaded, non-cpu bound applications this non-expiration nuance +allows applications to briefly burst past their quota limits by the amount of +unused slice on each cpu that the task group is running on (typically at most +1ms per cpu or as defined by min_cfs_rq_runtime). This slight burst only +applies if quota had been assigned to a cpu and then not fully used or returned +in previous periods. This burst amount will not be transferred between cores. +As a result, this mechanism still strictly limits the task group to quota +average usage, albeit over a longer time window than a single period. This +also limits the burst ability to no more than 1ms per cpu. This provides +better more predictable user experience for highly threaded applications with +small quota limits on high core count machines. It also eliminates the +propensity to throttle these applications while simultanously using less than +quota amounts of cpu. Another way to say this, is that by allowing the unused +portion of a slice to remain valid across periods we have decreased the +possibility of wastefully expiring quota on cpu-local silos that don't need a +full slice's amount of cpu time. + +The interaction between cpu-bound and non-cpu-bound-interactive applications +should also be considered, especially when single core usage hits 100%. If you +gave each of these applications half of a cpu-core and they both got scheduled +on the same CPU it is theoretically possible that the non-cpu bound application +will use up to 1ms additional quota in some periods, thereby preventing the +cpu-bound application from fully using its quota by that same amount. In these +instances it will be up to the CFS algorithm (see sched-design-CFS.rst) to +decide which application is chosen to run, as they will both be runnable and +have remaining quota. This runtime discrepancy will be made up in the following +periods when the interactive application idles. + Examples -------- 1. Limit a group to 1 CPU worth of runtime:: diff --git a/Documentation/security/tpm/index.rst b/Documentation/security/tpm/index.rst index 3296533e54cfbcd08e2b27c4c79a3c2ce19cab96..fc40e9f23c8599b3dbf384afad78257540364c49 100644 --- a/Documentation/security/tpm/index.rst +++ b/Documentation/security/tpm/index.rst @@ -4,5 +4,7 @@ Trusted Platform Module documentation .. toctree:: + tpm_event_log tpm_vtpm_proxy xen-tpmfront + tpm_ftpm_tee diff --git a/Documentation/security/tpm/tpm_event_log.rst b/Documentation/security/tpm/tpm_event_log.rst new file mode 100644 index 0000000000000000000000000000000000000000..f00f7a1d5e92f28cc0939752a6fec5c759782f94 --- /dev/null +++ b/Documentation/security/tpm/tpm_event_log.rst @@ -0,0 +1,55 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============= +TPM Event Log +============= + +This document briefly describes what TPM log is and how it is handed +over from the preboot firmware to the operating system. + +Introduction +============ + +The preboot firmware maintains an event log that gets new entries every +time something gets hashed by it to any of the PCR registers. The events +are segregated by their type and contain the value of the hashed PCR +register. Typically, the preboot firmware will hash the components to +who execution is to be handed over or actions relevant to the boot +process. + +The main application for this is remote attestation and the reason why +it is useful is nicely put in the very first section of [1]: + +"Attestation is used to provide information about the platform’s state +to a challenger. However, PCR contents are difficult to interpret; +therefore, attestation is typically more useful when the PCR contents +are accompanied by a measurement log. While not trusted on their own, +the measurement log contains a richer set of information than do the PCR +contents. The PCR contents are used to provide the validation of the +measurement log." + +UEFI event log +============== + +UEFI provided event log has a few somewhat weird quirks. + +Before calling ExitBootServices() Linux EFI stub copies the event log to +a custom configuration table defined by the stub itself. Unfortunately, +the events generated by ExitBootServices() don't end up in the table. + +The firmware provides so called final events configuration table to sort +out this issue. Events gets mirrored to this table after the first time +EFI_TCG2_PROTOCOL.GetEventLog() gets called. + +This introduces another problem: nothing guarantees that it is not called +before the Linux EFI stub gets to run. Thus, it needs to calculate and save the +final events table size while the stub is still running to the custom +configuration table so that the TPM driver can later on skip these events when +concatenating two halves of the event log from the custom configuration table +and the final events table. + +References +========== + +- [1] https://trustedcomputinggroup.org/resource/pc-client-specific-platform-firmware-profile-specification/ +- [2] The final concatenation is done in drivers/char/tpm/eventlog/efi.c diff --git a/Documentation/security/tpm/tpm_ftpm_tee.rst b/Documentation/security/tpm/tpm_ftpm_tee.rst new file mode 100644 index 0000000000000000000000000000000000000000..8c2bae16e3d943252768a6890140dbc4e9146050 --- /dev/null +++ b/Documentation/security/tpm/tpm_ftpm_tee.rst @@ -0,0 +1,27 @@ +============================================= +Firmware TPM Driver +============================================= + +This document describes the firmware Trusted Platform Module (fTPM) +device driver. + +Introduction +============ + +This driver is a shim for firmware implemented in ARM's TrustZone +environment. The driver allows programs to interact with the TPM in the same +way they would interact with a hardware TPM. + +Design +====== + +The driver acts as a thin layer that passes commands to and from a TPM +implemented in firmware. The driver itself doesn't contain much logic and is +used more like a dumb pipe between firmware and kernel/userspace. + +The firmware itself is based on the following paper: +https://www.microsoft.com/en-us/research/wp-content/uploads/2017/06/ftpm1.pdf + +When the driver is loaded it will expose ``/dev/tpmX`` character devices to +userspace which will enable userspace to communicate with the firmware TPM +through this device. diff --git a/Documentation/sound/alsa-configuration.rst b/Documentation/sound/alsa-configuration.rst index 4a3cecc8ad383e430ef42b566b9c67abaeaf57d6..02aacd69ab96e1d975c77f13035244875428e9e7 100644 --- a/Documentation/sound/alsa-configuration.rst +++ b/Documentation/sound/alsa-configuration.rst @@ -1001,6 +1001,8 @@ position_fix 2 = POSBUF: use position buffer, 3 = VIACOMBO: VIA-specific workaround for capture, 4 = COMBO: use LPIB for playback, auto for capture stream + 5 = SKL+: apply the delay calculation available on recent Intel chips + 6 = FIFO: correct the position with the fixed FIFO size, for recent AMD chips probe_mask Bitmask to probe codecs (default = -1, meaning all slots); When the bit 8 (0x100) is set, the lower 8 bits are used diff --git a/Documentation/sound/hd-audio/models.rst b/Documentation/sound/hd-audio/models.rst index 7d7c191102a73baf4eb1e72b01119458a2d3b53f..11298f0ce44dbf9a656ce42226b9bee76efae19a 100644 --- a/Documentation/sound/hd-audio/models.rst +++ b/Documentation/sound/hd-audio/models.rst @@ -260,6 +260,9 @@ alc295-hp-x360 HP Spectre X360 fixups alc-sense-combo Headset button support for Chrome platform +huawei-mbx-stereo + Enable initialization verbs for Huawei MBX stereo speakers; + might be risky, try this at your own risk ALC66x/67x/892 ============== diff --git a/Documentation/sound/hd-audio/notes.rst b/Documentation/sound/hd-audio/notes.rst index 9f7347830ba4234bf618043e41869e7ebe231060..0f3109d9abc82f91937e136182e888844b7f48b7 100644 --- a/Documentation/sound/hd-audio/notes.rst +++ b/Documentation/sound/hd-audio/notes.rst @@ -66,6 +66,11 @@ by comparing both LPIB and position-buffer values. ``position_fix=4`` is another combination available for all controllers, and uses LPIB for the playback and the position-buffer for the capture streams. +``position_fix=5`` is specific to Intel platforms, so far, for Skylake +and onward. It applies the delay calculation for the precise position +reporting. +``position_fix=6`` is to correct the position with the fixed FIFO +size, mainly targeted for the recent AMD controllers. 0 is the default value for all other controllers, the automatic check and fallback to LPIB as described in the above. If you get a problem of repeated sounds, this option might diff --git a/Documentation/sound/index.rst b/Documentation/sound/index.rst index 47b89f014e694183a16ccf298957a8a043c8564e..4d7d42acf6dfda53c5533b0958d4d69935e318f7 100644 --- a/Documentation/sound/index.rst +++ b/Documentation/sound/index.rst @@ -12,7 +12,7 @@ Linux Sound Subsystem Documentation hd-audio/index cards/index -.. only:: subproject +.. only:: subproject and html Indices ======= diff --git a/Documentation/sphinx/automarkup.py b/Documentation/sphinx/automarkup.py index 77e89c1956d7dacbe69142665305ccf7cb0cf06c..5b6119ff69f40da43fa33e17d4a4ccf6c98c9cef 100644 --- a/Documentation/sphinx/automarkup.py +++ b/Documentation/sphinx/automarkup.py @@ -25,8 +25,9 @@ RE_function = re.compile(r'([\w_][\w\d_]+\(\))') # to the creation of incorrect and confusing cross references. So # just don't even try with these names. # -Skipfuncs = [ 'open', 'close', 'read', 'write', 'fcntl', 'mmap' - 'select', 'poll', 'fork', 'execve', 'clone', 'ioctl'] +Skipfuncs = [ 'open', 'close', 'read', 'write', 'fcntl', 'mmap', + 'select', 'poll', 'fork', 'execve', 'clone', 'ioctl', + 'socket' ] # # Find all occurrences of function() and try to replace them with diff --git a/Documentation/spi/butterfly b/Documentation/spi/butterfly.rst similarity index 71% rename from Documentation/spi/butterfly rename to Documentation/spi/butterfly.rst index 9927af7a629c9a16022fc9cb689ae4f1ee2d91ef..e614a589547cf7ed7731c294ad6528e2186eb9d5 100644 --- a/Documentation/spi/butterfly +++ b/Documentation/spi/butterfly.rst @@ -1,3 +1,4 @@ +=================================================== spi_butterfly - parport-to-butterfly adapter driver =================================================== @@ -27,25 +28,29 @@ need to reflash the firmware, and the pins are the standard Atmel "ISP" connector pins (used also on non-Butterfly AVR boards). On the parport side this is like "sp12" programming cables. + ====== ============= =================== Signal Butterfly Parport (DB-25) - ------ --------- --------------- - SCK = J403.PB1/SCK = pin 2/D0 - RESET = J403.nRST = pin 3/D1 - VCC = J403.VCC_EXT = pin 8/D6 - MOSI = J403.PB2/MOSI = pin 9/D7 - MISO = J403.PB3/MISO = pin 11/S7,nBUSY - GND = J403.GND = pin 23/GND + ====== ============= =================== + SCK J403.PB1/SCK pin 2/D0 + RESET J403.nRST pin 3/D1 + VCC J403.VCC_EXT pin 8/D6 + MOSI J403.PB2/MOSI pin 9/D7 + MISO J403.PB3/MISO pin 11/S7,nBUSY + GND J403.GND pin 23/GND + ====== ============= =================== Then to let Linux master that bus to talk to the DataFlash chip, you must (a) flash new firmware that disables SPI (set PRR.2, and disable pullups by clearing PORTB.[0-3]); (b) configure the mtd_dataflash driver; and (c) cable in the chipselect. + ====== ============ =================== Signal Butterfly Parport (DB-25) - ------ --------- --------------- - VCC = J400.VCC_EXT = pin 7/D5 - SELECT = J400.PB0/nSS = pin 17/C3,nSELECT - GND = J400.GND = pin 24/GND + ====== ============ =================== + VCC J400.VCC_EXT pin 7/D5 + SELECT J400.PB0/nSS pin 17/C3,nSELECT + GND J400.GND pin 24/GND + ====== ============ =================== Or you could flash firmware making the AVR into an SPI slave (keeping the DataFlash in reset) and tweak the spi_butterfly driver to make it bind to @@ -56,13 +61,14 @@ That would let you talk to the AVR using custom SPI-with-USI firmware, while letting either Linux or the AVR use the DataFlash. There are plenty of spare parport pins to wire this one up, such as: + ====== ============= =================== Signal Butterfly Parport (DB-25) - ------ --------- --------------- - SCK = J403.PE4/USCK = pin 5/D3 - MOSI = J403.PE5/DI = pin 6/D4 - MISO = J403.PE6/DO = pin 12/S5,nPAPEROUT - GND = J403.GND = pin 22/GND - - IRQ = J402.PF4 = pin 10/S6,ACK - GND = J402.GND(P2) = pin 25/GND + ====== ============= =================== + SCK J403.PE4/USCK pin 5/D3 + MOSI J403.PE5/DI pin 6/D4 + MISO J403.PE6/DO pin 12/S5,nPAPEROUT + GND J403.GND pin 22/GND + IRQ J402.PF4 pin 10/S6,ACK + GND J402.GND(P2) pin 25/GND + ====== ============= =================== diff --git a/Documentation/spi/index.rst b/Documentation/spi/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..06c34ea11bcf39a416bb1c1c34b27a523a3e181e --- /dev/null +++ b/Documentation/spi/index.rst @@ -0,0 +1,22 @@ +.. SPDX-License-Identifier: GPL-2.0 + +================================= +Serial Peripheral Interface (SPI) +================================= + +.. toctree:: + :maxdepth: 1 + + spi-summary + spidev + butterfly + pxa2xx + spi-lm70llp + spi-sc18is602 + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/spi/pxa2xx b/Documentation/spi/pxa2xx.rst similarity index 83% rename from Documentation/spi/pxa2xx rename to Documentation/spi/pxa2xx.rst index 551325b66b233686373f7ff4b1628a58dea55388..882d3cc72cc2b1598d603893c0e3d47a2f931785 100644 --- a/Documentation/spi/pxa2xx +++ b/Documentation/spi/pxa2xx.rst @@ -1,8 +1,10 @@ +============================== PXA2xx SPI on SSP driver HOWTO -=================================================== +============================== + This a mini howto on the pxa2xx_spi driver. The driver turns a PXA2xx synchronous serial port into a SPI master controller -(see Documentation/spi/spi-summary). The driver has the following features +(see Documentation/spi/spi-summary.rst). The driver has the following features - Support for any PXA2xx SSP - SSP PIO and SSP DMA data transfers. @@ -19,12 +21,12 @@ Declaring PXA2xx Master Controllers ----------------------------------- Typically a SPI master is defined in the arch/.../mach-*/board-*.c as a "platform device". The master configuration is passed to the driver via a table -found in include/linux/spi/pxa2xx_spi.h: +found in include/linux/spi/pxa2xx_spi.h:: -struct pxa2xx_spi_controller { + struct pxa2xx_spi_controller { u16 num_chipselect; u8 enable_dma; -}; + }; The "pxa2xx_spi_controller.num_chipselect" field is used to determine the number of slave device (chips) attached to this SPI master. @@ -36,9 +38,9 @@ See the "PXA2xx Developer Manual" section "DMA Controller". NSSP MASTER SAMPLE ------------------ -Below is a sample configuration using the PXA255 NSSP. +Below is a sample configuration using the PXA255 NSSP:: -static struct resource pxa_spi_nssp_resources[] = { + static struct resource pxa_spi_nssp_resources[] = { [0] = { .start = __PREG(SSCR0_P(2)), /* Start address of NSSP */ .end = __PREG(SSCR0_P(2)) + 0x2c, /* Range of registers */ @@ -49,14 +51,14 @@ static struct resource pxa_spi_nssp_resources[] = { .end = IRQ_NSSP, .flags = IORESOURCE_IRQ, }, -}; + }; -static struct pxa2xx_spi_controller pxa_nssp_master_info = { + static struct pxa2xx_spi_controller pxa_nssp_master_info = { .num_chipselect = 1, /* Matches the number of chips attached to NSSP */ .enable_dma = 1, /* Enables NSSP DMA */ -}; + }; -static struct platform_device pxa_spi_nssp = { + static struct platform_device pxa_spi_nssp = { .name = "pxa2xx-spi", /* MUST BE THIS VALUE, so device match driver */ .id = 2, /* Bus number, MUST MATCH SSP number 1..n */ .resource = pxa_spi_nssp_resources, @@ -64,22 +66,22 @@ static struct platform_device pxa_spi_nssp = { .dev = { .platform_data = &pxa_nssp_master_info, /* Passed to driver */ }, -}; + }; -static struct platform_device *devices[] __initdata = { + static struct platform_device *devices[] __initdata = { &pxa_spi_nssp, -}; + }; -static void __init board_init(void) -{ + static void __init board_init(void) + { (void)platform_add_device(devices, ARRAY_SIZE(devices)); -} + } Declaring Slave Devices ----------------------- Typically each SPI slave (chip) is defined in the arch/.../mach-*/board-*.c using the "spi_board_info" structure found in "linux/spi/spi.h". See -"Documentation/spi/spi-summary" for additional information. +"Documentation/spi/spi-summary.rst" for additional information. Each slave device attached to the PXA must provide slave specific configuration information via the structure "pxa2xx_spi_chip" found in @@ -87,19 +89,21 @@ information via the structure "pxa2xx_spi_chip" found in will uses the configuration whenever the driver communicates with the slave device. All fields are optional. -struct pxa2xx_spi_chip { +:: + + struct pxa2xx_spi_chip { u8 tx_threshold; u8 rx_threshold; u8 dma_burst_size; u32 timeout; u8 enable_loopback; void (*cs_control)(u32 command); -}; + }; The "pxa2xx_spi_chip.tx_threshold" and "pxa2xx_spi_chip.rx_threshold" fields are used to configure the SSP hardware fifo. These fields are critical to the performance of pxa2xx_spi driver and misconfiguration will result in rx -fifo overruns (especially in PIO mode transfers). Good default values are +fifo overruns (especially in PIO mode transfers). Good default values are:: .tx_threshold = 8, .rx_threshold = 8, @@ -141,41 +145,43 @@ The pxa2xx_spi_chip structure is passed to the pxa2xx_spi driver in the "spi_board_info.controller_data" field. Below is a sample configuration using the PXA255 NSSP. -/* Chip Select control for the CS8415A SPI slave device */ -static void cs8415a_cs_control(u32 command) -{ +:: + + /* Chip Select control for the CS8415A SPI slave device */ + static void cs8415a_cs_control(u32 command) + { if (command & PXA2XX_CS_ASSERT) GPCR(2) = GPIO_bit(2); else GPSR(2) = GPIO_bit(2); -} + } -/* Chip Select control for the CS8405A SPI slave device */ -static void cs8405a_cs_control(u32 command) -{ + /* Chip Select control for the CS8405A SPI slave device */ + static void cs8405a_cs_control(u32 command) + { if (command & PXA2XX_CS_ASSERT) GPCR(3) = GPIO_bit(3); else GPSR(3) = GPIO_bit(3); -} + } -static struct pxa2xx_spi_chip cs8415a_chip_info = { + static struct pxa2xx_spi_chip cs8415a_chip_info = { .tx_threshold = 8, /* SSP hardward FIFO threshold */ .rx_threshold = 8, /* SSP hardward FIFO threshold */ .dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */ .timeout = 235, /* See Intel documentation */ .cs_control = cs8415a_cs_control, /* Use external chip select */ -}; + }; -static struct pxa2xx_spi_chip cs8405a_chip_info = { + static struct pxa2xx_spi_chip cs8405a_chip_info = { .tx_threshold = 8, /* SSP hardward FIFO threshold */ .rx_threshold = 8, /* SSP hardward FIFO threshold */ .dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */ .timeout = 235, /* See Intel documentation */ .cs_control = cs8405a_cs_control, /* Use external chip select */ -}; + }; -static struct spi_board_info streetracer_spi_board_info[] __initdata = { + static struct spi_board_info streetracer_spi_board_info[] __initdata = { { .modalias = "cs8415a", /* Name of spi_driver for this device */ .max_speed_hz = 3686400, /* Run SSP as fast a possbile */ @@ -193,13 +199,13 @@ static struct spi_board_info streetracer_spi_board_info[] __initdata = { .controller_data = &cs8405a_chip_info, /* Master chip config */ .irq = STREETRACER_APCI_IRQ, /* Slave device interrupt */ }, -}; + }; -static void __init streetracer_init(void) -{ + static void __init streetracer_init(void) + { spi_register_board_info(streetracer_spi_board_info, ARRAY_SIZE(streetracer_spi_board_info)); -} + } DMA and PIO I/O Support @@ -210,26 +216,25 @@ by setting the "enable_dma" flag in the "pxa2xx_spi_controller" structure. The mode supports both coherent and stream based DMA mappings. The following logic is used to determine the type of I/O to be used on -a per "spi_transfer" basis: +a per "spi_transfer" basis:: -if !enable_dma then + if !enable_dma then always use PIO transfers -if spi_message.len > 8191 then + if spi_message.len > 8191 then print "rate limited" warning use PIO transfers -if spi_message.is_dma_mapped and rx_dma_buf != 0 and tx_dma_buf != 0 then + if spi_message.is_dma_mapped and rx_dma_buf != 0 and tx_dma_buf != 0 then use coherent DMA mode -if rx_buf and tx_buf are aligned on 8 byte boundary then + if rx_buf and tx_buf are aligned on 8 byte boundary then use streaming DMA mode -otherwise + otherwise use PIO transfer THANKS TO --------- David Brownell and others for mentoring the development of this driver. - diff --git a/Documentation/spi/spi-lm70llp b/Documentation/spi/spi-lm70llp.rst similarity index 88% rename from Documentation/spi/spi-lm70llp rename to Documentation/spi/spi-lm70llp.rst index 463f6d01fa155f3d61eed020c650de3e5511cc81..07631aef4343bdab4459110861a2792fe239afdf 100644 --- a/Documentation/spi/spi-lm70llp +++ b/Documentation/spi/spi-lm70llp.rst @@ -1,8 +1,11 @@ +============================================== spi_lm70llp : LM70-LLP parport-to-SPI adapter ============================================== Supported board/chip: + * National Semiconductor LM70 LLP evaluation board + Datasheet: http://www.national.com/pf/LM/LM70.html Author: @@ -29,9 +32,10 @@ available (on page 4) here: The hardware interfacing on the LM70 LLP eval board is as follows: + ======== == ========= ========== Parallel LM70 LLP - Port Direction JP2 Header - ----------- --------- ---------------- + Port . Direction JP2 Header + ======== == ========= ========== D0 2 - - D1 3 --> V+ 5 D2 4 --> V+ 5 @@ -42,7 +46,7 @@ The hardware interfacing on the LM70 LLP eval board is as follows: D7 9 --> SI/O 5 GND 25 - GND 7 Select 13 <-- SI/O 1 - ----------- --------- ---------------- + ======== == ========= ========== Note that since the LM70 uses a "3-wire" variant of SPI, the SI/SO pin is connected to both pin D7 (as Master Out) and Select (as Master In) @@ -74,6 +78,7 @@ inverting the value read at pin 13. Thanks to --------- -o David Brownell for mentoring the SPI-side driver development. -o Dr.Craig Hollabaugh for the (early) "manual" bitbanging driver version. -o Nadir Billimoria for help interpreting the circuit schematic. + +- David Brownell for mentoring the SPI-side driver development. +- Dr.Craig Hollabaugh for the (early) "manual" bitbanging driver version. +- Nadir Billimoria for help interpreting the circuit schematic. diff --git a/Documentation/spi/spi-sc18is602 b/Documentation/spi/spi-sc18is602.rst similarity index 92% rename from Documentation/spi/spi-sc18is602 rename to Documentation/spi/spi-sc18is602.rst index a45702865a38a011a5aebbf64a3cc810e2d6a106..2a31dc722321bf1699fa83ae4ece789f4d47c6e5 100644 --- a/Documentation/spi/spi-sc18is602 +++ b/Documentation/spi/spi-sc18is602.rst @@ -1,8 +1,11 @@ +=========================== Kernel driver spi-sc18is602 =========================== Supported chips: + * NXP SI18IS602/602B/603 + Datasheet: http://www.nxp.com/documents/data_sheet/SC18IS602_602B_603.pdf Author: @@ -17,7 +20,7 @@ kernel's SPI core subsystem. The driver does not probe for supported chips, since the SI18IS602/603 does not support Chip ID registers. You will have to instantiate the devices explicitly. -Please see Documentation/i2c/instantiating-devices for details. +Please see Documentation/i2c/instantiating-devices.rst for details. Usage Notes diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary.rst similarity index 93% rename from Documentation/spi/spi-summary rename to Documentation/spi/spi-summary.rst index 1a63194b74d7d7310efe1fab7e777a415d9a7a3c..f1daffe10d782086a1a7a4db0e1991a29edf930a 100644 --- a/Documentation/spi/spi-summary +++ b/Documentation/spi/spi-summary.rst @@ -1,3 +1,4 @@ +==================================== Overview of Linux kernel SPI support ==================================== @@ -139,12 +140,14 @@ a command and then reading its response. There are two types of SPI driver, here called: - Controller drivers ... controllers may be built into System-On-Chip + Controller drivers ... + controllers may be built into System-On-Chip processors, and often support both Master and Slave roles. These drivers touch hardware registers and may use DMA. Or they can be PIO bitbangers, needing just GPIO pins. - Protocol drivers ... these pass messages through the controller + Protocol drivers ... + these pass messages through the controller driver to communicate with a Slave or Master device on the other side of an SPI link. @@ -160,7 +163,7 @@ those two types of drivers. There is a minimal core of SPI programming interfaces, focussing on using the driver model to connect controller and protocol drivers using device tables provided by board specific initialization code. SPI -shows up in sysfs in several locations: +shows up in sysfs in several locations:: /sys/devices/.../CTLR ... physical node for a given SPI controller @@ -168,7 +171,7 @@ shows up in sysfs in several locations: chipselect C, accessed through CTLR. /sys/bus/spi/devices/spiB.C ... symlink to that physical - .../CTLR/spiB.C device + .../CTLR/spiB.C device /sys/devices/.../CTLR/spiB.C/modalias ... identifies the driver that should be used with this device (for hotplug/coldplug) @@ -206,7 +209,8 @@ Linux needs several kinds of information to properly configure SPI devices. That information is normally provided by board-specific code, even for chips that do support some of automated discovery/enumeration. -DECLARE CONTROLLERS +Declare Controllers +^^^^^^^^^^^^^^^^^^^ The first kind of information is a list of what SPI controllers exist. For System-on-Chip (SOC) based boards, these will usually be platform @@ -221,7 +225,7 @@ same basic controller setup code. This is because most SOCs have several SPI-capable controllers, and only the ones actually usable on a given board should normally be set up and registered. -So for example arch/.../mach-*/board-*.c files might have code like: +So for example arch/.../mach-*/board-*.c files might have code like:: #include /* for mysoc_spi_data */ @@ -238,7 +242,7 @@ So for example arch/.../mach-*/board-*.c files might have code like: ... } -And SOC-specific utility code might look something like: +And SOC-specific utility code might look something like:: #include @@ -269,8 +273,8 @@ same SOC controller is used. For example, on one board SPI might use an external clock, where another derives the SPI clock from current settings of some master clock. - -DECLARE SLAVE DEVICES +Declare Slave Devices +^^^^^^^^^^^^^^^^^^^^^ The second kind of information is a list of what SPI slave devices exist on the target board, often with some board-specific data needed for the @@ -278,7 +282,7 @@ driver to work correctly. Normally your arch/.../mach-*/board-*.c files would provide a small table listing the SPI devices on each board. (This would typically be only a -small handful.) That might look like: +small handful.) That might look like:: static struct ads7846_platform_data ads_info = { .vref_delay_usecs = 100, @@ -316,7 +320,7 @@ not possible until the infrastructure knows how to deselect it. Then your board initialization code would register that table with the SPI infrastructure, so that it's available later when the SPI master controller -driver is registered: +driver is registered:: spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); @@ -324,12 +328,13 @@ Like with other static board-specific setup, you won't unregister those. The widely used "card" style computers bundle memory, cpu, and little else onto a card that's maybe just thirty square centimeters. On such systems, -your arch/.../mach-.../board-*.c file would primarily provide information +your ``arch/.../mach-.../board-*.c`` file would primarily provide information about the devices on the mainboard into which such a card is plugged. That certainly includes SPI devices hooked up through the card connectors! -NON-STATIC CONFIGURATIONS +Non-static Configurations +^^^^^^^^^^^^^^^^^^^^^^^^^ Developer boards often play by different rules than product boards, and one example is the potential need to hotplug SPI devices and/or controllers. @@ -349,7 +354,7 @@ How do I write an "SPI Protocol Driver"? Most SPI drivers are currently kernel drivers, but there's also support for userspace drivers. Here we talk only about kernel drivers. -SPI protocol drivers somewhat resemble platform device drivers: +SPI protocol drivers somewhat resemble platform device drivers:: static struct spi_driver CHIP_driver = { .driver = { @@ -367,6 +372,8 @@ device whose board_info gave a modalias of "CHIP". Your probe() code might look like this unless you're creating a device which is managing a bus (appearing under /sys/class/spi_master). +:: + static int CHIP_probe(struct spi_device *spi) { struct CHIP *chip; @@ -479,6 +486,8 @@ The main task of this type of driver is to provide an "spi_master". Use spi_alloc_master() to allocate the master, and spi_master_get_devdata() to get the driver-private data allocated for that device. +:: + struct spi_master *master; struct CONTROLLER *c; @@ -503,7 +512,8 @@ If you need to remove your SPI controller driver, spi_unregister_master() will reverse the effect of spi_register_master(). -BUS NUMBERING +Bus Numbering +^^^^^^^^^^^^^ Bus numbering is important, since that's how Linux identifies a given SPI bus (shared SCK, MOSI, MISO). Valid bus numbers start at zero. On @@ -517,9 +527,10 @@ then be replaced by a dynamically assigned number. You'd then need to treat this as a non-static configuration (see above). -SPI MASTER METHODS +SPI Master Methods +^^^^^^^^^^^^^^^^^^ - master->setup(struct spi_device *spi) +``master->setup(struct spi_device *spi)`` This sets up the device clock rate, SPI mode, and word sizes. Drivers may change the defaults provided by board_info, and then call spi_setup(spi) to invoke this routine. It may sleep. @@ -528,37 +539,37 @@ SPI MASTER METHODS change them right away ... otherwise drivers could corrupt I/O that's in progress for other SPI devices. - ** BUG ALERT: for some reason the first version of - ** many spi_master drivers seems to get this wrong. - ** When you code setup(), ASSUME that the controller - ** is actively processing transfers for another device. + .. note:: + + BUG ALERT: for some reason the first version of + many spi_master drivers seems to get this wrong. + When you code setup(), ASSUME that the controller + is actively processing transfers for another device. - master->cleanup(struct spi_device *spi) +``master->cleanup(struct spi_device *spi)`` Your controller driver may use spi_device.controller_state to hold state it dynamically associates with that device. If you do that, be sure to provide the cleanup() method to free that state. - master->prepare_transfer_hardware(struct spi_master *master) +``master->prepare_transfer_hardware(struct spi_master *master)`` This will be called by the queue mechanism to signal to the driver that a message is coming in soon, so the subsystem requests the driver to prepare the transfer hardware by issuing this call. This may sleep. - master->unprepare_transfer_hardware(struct spi_master *master) +``master->unprepare_transfer_hardware(struct spi_master *master)`` This will be called by the queue mechanism to signal to the driver that there are no more messages pending in the queue and it may relax the hardware (e.g. by power management calls). This may sleep. - master->transfer_one_message(struct spi_master *master, - struct spi_message *mesg) +``master->transfer_one_message(struct spi_master *master, struct spi_message *mesg)`` The subsystem calls the driver to transfer a single message while queuing transfers that arrive in the meantime. When the driver is finished with this message, it must call spi_finalize_current_message() so the subsystem can issue the next message. This may sleep. - master->transfer_one(struct spi_master *master, struct spi_device *spi, - struct spi_transfer *transfer) +``master->transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *transfer)`` The subsystem calls the driver to transfer a single transfer while queuing transfers that arrive in the meantime. When the driver is finished with this transfer, it must call @@ -568,19 +579,20 @@ SPI MASTER METHODS not call your transfer_one callback. Return values: - negative errno: error - 0: transfer is finished - 1: transfer is still in progress - master->set_cs_timing(struct spi_device *spi, u8 setup_clk_cycles, - u8 hold_clk_cycles, u8 inactive_clk_cycles) + * negative errno: error + * 0: transfer is finished + * 1: transfer is still in progress + +``master->set_cs_timing(struct spi_device *spi, u8 setup_clk_cycles, u8 hold_clk_cycles, u8 inactive_clk_cycles)`` This method allows SPI client drivers to request SPI master controller for configuring device specific CS setup, hold and inactive timing requirements. - DEPRECATED METHODS +Deprecated Methods +^^^^^^^^^^^^^^^^^^ - master->transfer(struct spi_device *spi, struct spi_message *message) +``master->transfer(struct spi_device *spi, struct spi_message *message)`` This must not sleep. Its responsibility is to arrange that the transfer happens and its complete() callback is issued. The two will normally happen later, after other transfers complete, and @@ -590,7 +602,8 @@ SPI MASTER METHODS implemented. -SPI MESSAGE QUEUE +SPI Message Queue +^^^^^^^^^^^^^^^^^ If you are happy with the standard queueing mechanism provided by the SPI subsystem, just implement the queued methods specified above. Using @@ -619,13 +632,13 @@ THANKS TO Contributors to Linux-SPI discussions include (in alphabetical order, by last name): -Mark Brown -David Brownell -Russell King -Grant Likely -Dmitry Pervushin -Stephen Street -Mark Underwood -Andrew Victor -Linus Walleij -Vitaly Wool +- Mark Brown +- David Brownell +- Russell King +- Grant Likely +- Dmitry Pervushin +- Stephen Street +- Mark Underwood +- Andrew Victor +- Linus Walleij +- Vitaly Wool diff --git a/Documentation/spi/spidev b/Documentation/spi/spidev.rst similarity index 90% rename from Documentation/spi/spidev rename to Documentation/spi/spidev.rst index 3d14035b1766994b537fb273d20dffc92d9554d9..f05dbc5ccdbc66f3d9e916be44f13bb8ebf61833 100644 --- a/Documentation/spi/spidev +++ b/Documentation/spi/spidev.rst @@ -1,7 +1,13 @@ +================= +SPI userspace API +================= + SPI devices have a limited userspace API, supporting basic half-duplex read() and write() access to SPI slave devices. Using ioctl() requests, full duplex transfers and device I/O configuration are also available. +:: + #include #include #include @@ -39,14 +45,17 @@ device node with a "dev" attribute that will be understood by udev or mdev. busybox; it's less featureful, but often enough.) For a SPI device with chipselect C on bus B, you should see: - /dev/spidevB.C ... character special device, major number 153 with + /dev/spidevB.C ... + character special device, major number 153 with a dynamically chosen minor device number. This is the node that userspace programs will open, created by "udev" or "mdev". - /sys/devices/.../spiB.C ... as usual, the SPI device node will + /sys/devices/.../spiB.C ... + as usual, the SPI device node will be a child of its SPI master controller. - /sys/class/spidev/spidevB.C ... created when the "spidev" driver + /sys/class/spidev/spidevB.C ... + created when the "spidev" driver binds to that device. (Directory or symlink, based on whether or not you enabled the "deprecated sysfs files" Kconfig option.) @@ -80,7 +89,8 @@ the SPI_IOC_MESSAGE(N) request. Several ioctl() requests let your driver read or override the device's current settings for data transfer parameters: - SPI_IOC_RD_MODE, SPI_IOC_WR_MODE ... pass a pointer to a byte which will + SPI_IOC_RD_MODE, SPI_IOC_WR_MODE ... + pass a pointer to a byte which will return (RD) or assign (WR) the SPI transfer mode. Use the constants SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL (clock polarity, idle high iff this is set) or SPI_CPHA (clock phase, @@ -88,22 +98,26 @@ settings for data transfer parameters: Note that this request is limited to SPI mode flags that fit in a single byte. - SPI_IOC_RD_MODE32, SPI_IOC_WR_MODE32 ... pass a pointer to a uin32_t + SPI_IOC_RD_MODE32, SPI_IOC_WR_MODE32 ... + pass a pointer to a uin32_t which will return (RD) or assign (WR) the full SPI transfer mode, not limited to the bits that fit in one byte. - SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte + SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... + pass a pointer to a byte which will return (RD) or assign (WR) the bit justification used to transfer SPI words. Zero indicates MSB-first; other values indicate the less common LSB-first encoding. In both cases the specified value is right-justified in each word, so that unused (TX) or undefined (RX) bits are in the MSBs. - SPI_IOC_RD_BITS_PER_WORD, SPI_IOC_WR_BITS_PER_WORD ... pass a pointer to + SPI_IOC_RD_BITS_PER_WORD, SPI_IOC_WR_BITS_PER_WORD ... + pass a pointer to a byte which will return (RD) or assign (WR) the number of bits in each SPI transfer word. The value zero signifies eight bits. - SPI_IOC_RD_MAX_SPEED_HZ, SPI_IOC_WR_MAX_SPEED_HZ ... pass a pointer to a + SPI_IOC_RD_MAX_SPEED_HZ, SPI_IOC_WR_MAX_SPEED_HZ ... + pass a pointer to a u32 which will return (RD) or assign (WR) the maximum SPI transfer speed, in Hz. The controller can't necessarily assign that specific clock speed. diff --git a/Documentation/trace/coresight-cpu-debug.txt b/Documentation/trace/coresight-cpu-debug.rst similarity index 84% rename from Documentation/trace/coresight-cpu-debug.txt rename to Documentation/trace/coresight-cpu-debug.rst index 1a660a39e3c017ae18a1360e8c87a75b87b992ed..993dd294b81bad4efec0115326eee66629c541b3 100644 --- a/Documentation/trace/coresight-cpu-debug.txt +++ b/Documentation/trace/coresight-cpu-debug.rst @@ -1,8 +1,9 @@ - Coresight CPU Debug Module - ========================== +========================== +Coresight CPU Debug Module +========================== - Author: Leo Yan - Date: April 5th, 2017 + :Author: Leo Yan + :Date: April 5th, 2017 Introduction ------------ @@ -69,6 +70,7 @@ Before accessing debug registers, we should ensure the clock and power domain have been enabled properly. In ARMv8-a ARM (ARM DDI 0487A.k) chapter 'H9.1 Debug registers', the debug registers are spread into two domains: the debug domain and the CPU domain. +:: +---------------+ | | @@ -125,18 +127,21 @@ If you want to enable debugging functionality at boot time, you can add "coresight_cpu_debug.enable=1" to the kernel command line parameter. The driver also can work as module, so can enable the debugging when insmod -module: -# insmod coresight_cpu_debug.ko debug=1 +module:: + + # insmod coresight_cpu_debug.ko debug=1 When boot time or insmod module you have not enabled the debugging, the driver uses the debugfs file system to provide a knob to dynamically enable or disable debugging: -To enable it, write a '1' into /sys/kernel/debug/coresight_cpu_debug/enable: -# echo 1 > /sys/kernel/debug/coresight_cpu_debug/enable +To enable it, write a '1' into /sys/kernel/debug/coresight_cpu_debug/enable:: + + # echo 1 > /sys/kernel/debug/coresight_cpu_debug/enable + +To disable it, write a '0' into /sys/kernel/debug/coresight_cpu_debug/enable:: -To disable it, write a '0' into /sys/kernel/debug/coresight_cpu_debug/enable: -# echo 0 > /sys/kernel/debug/coresight_cpu_debug/enable + # echo 0 > /sys/kernel/debug/coresight_cpu_debug/enable As explained in chapter "Clock and power domain", if you are working on one platform which has idle states to power off debug logic and the power @@ -154,34 +159,34 @@ subsystem, more specifically by using the "/dev/cpu_dma_latency" interface (see Documentation/power/pm_qos_interface.rst for more details). As specified in the PM QoS documentation the requested parameter will stay in effect until the file descriptor is released. -For example: +For example:: -# exec 3<> /dev/cpu_dma_latency; echo 0 >&3 -... -Do some work... -... -# exec 3<>- + # exec 3<> /dev/cpu_dma_latency; echo 0 >&3 + ... + Do some work... + ... + # exec 3<>- The same can also be done from an application program. Disable specific CPU's specific idle state from cpuidle sysfs (see -Documentation/admin-guide/pm/cpuidle.rst): -# echo 1 > /sys/devices/system/cpu/cpu$cpu/cpuidle/state$state/disable +Documentation/admin-guide/pm/cpuidle.rst):: + # echo 1 > /sys/devices/system/cpu/cpu$cpu/cpuidle/state$state/disable Output format ------------- -Here is an example of the debugging output format: - -ARM external debug module: -coresight-cpu-debug 850000.debug: CPU[0]: -coresight-cpu-debug 850000.debug: EDPRSR: 00000001 (Power:On DLK:Unlock) -coresight-cpu-debug 850000.debug: EDPCSR: handle_IPI+0x174/0x1d8 -coresight-cpu-debug 850000.debug: EDCIDSR: 00000000 -coresight-cpu-debug 850000.debug: EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0) -coresight-cpu-debug 852000.debug: CPU[1]: -coresight-cpu-debug 852000.debug: EDPRSR: 00000001 (Power:On DLK:Unlock) -coresight-cpu-debug 852000.debug: EDPCSR: debug_notifier_call+0x23c/0x358 -coresight-cpu-debug 852000.debug: EDCIDSR: 00000000 -coresight-cpu-debug 852000.debug: EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0) +Here is an example of the debugging output format:: + + ARM external debug module: + coresight-cpu-debug 850000.debug: CPU[0]: + coresight-cpu-debug 850000.debug: EDPRSR: 00000001 (Power:On DLK:Unlock) + coresight-cpu-debug 850000.debug: EDPCSR: handle_IPI+0x174/0x1d8 + coresight-cpu-debug 850000.debug: EDCIDSR: 00000000 + coresight-cpu-debug 850000.debug: EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0) + coresight-cpu-debug 852000.debug: CPU[1]: + coresight-cpu-debug 852000.debug: EDPRSR: 00000001 (Power:On DLK:Unlock) + coresight-cpu-debug 852000.debug: EDPCSR: debug_notifier_call+0x23c/0x358 + coresight-cpu-debug 852000.debug: EDCIDSR: 00000000 + coresight-cpu-debug 852000.debug: EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0) diff --git a/Documentation/trace/coresight.txt b/Documentation/trace/coresight.rst similarity index 56% rename from Documentation/trace/coresight.txt rename to Documentation/trace/coresight.rst index b027d61b27a6e787c929d39455cba29b7d72baf8..72f4b7ef1bade72cdf9f37acf0d8e94fd9cf4304 100644 --- a/Documentation/trace/coresight.txt +++ b/Documentation/trace/coresight.rst @@ -1,8 +1,9 @@ - Coresight - HW Assisted Tracing on ARM - ====================================== +====================================== +Coresight - HW Assisted Tracing on ARM +====================================== - Author: Mathieu Poirier - Date: September 11th, 2014 + :Author: Mathieu Poirier + :Date: September 11th, 2014 Introduction ------------ @@ -26,7 +27,7 @@ implementation, either storing the compressed stream in a memory buffer or creating an interface to the outside world where data can be transferred to a host without fear of filling up the onboard coresight memory buffer. -At typical coresight system would look like this: +At typical coresight system would look like this:: ***************************************************************** **************************** AMBA AXI ****************************===|| @@ -95,15 +96,24 @@ Acronyms and Classification Acronyms: -PTM: Program Trace Macrocell -ETM: Embedded Trace Macrocell -STM: System trace Macrocell -ETB: Embedded Trace Buffer -ITM: Instrumentation Trace Macrocell -TPIU: Trace Port Interface Unit -TMC-ETR: Trace Memory Controller, configured as Embedded Trace Router -TMC-ETF: Trace Memory Controller, configured as Embedded Trace FIFO -CTI: Cross Trigger Interface +PTM: + Program Trace Macrocell +ETM: + Embedded Trace Macrocell +STM: + System trace Macrocell +ETB: + Embedded Trace Buffer +ITM: + Instrumentation Trace Macrocell +TPIU: + Trace Port Interface Unit +TMC-ETR: + Trace Memory Controller, configured as Embedded Trace Router +TMC-ETF: + Trace Memory Controller, configured as Embedded Trace FIFO +CTI: + Cross Trigger Interface Classification: @@ -118,7 +128,7 @@ Misc: Device Tree Bindings ----------------------- +-------------------- See Documentation/devicetree/bindings/arm/coresight.txt for details. @@ -133,79 +143,79 @@ The coresight framework provides a central point to represent, configure and manage coresight devices on a platform. Any coresight compliant device can register with the framework for as long as they use the right APIs: -struct coresight_device *coresight_register(struct coresight_desc *desc); -void coresight_unregister(struct coresight_device *csdev); +.. c:function:: struct coresight_device *coresight_register(struct coresight_desc *desc); +.. c:function:: void coresight_unregister(struct coresight_device *csdev); -The registering function is taking a "struct coresight_device *csdev" and -register the device with the core framework. The unregister function takes -a reference to a "struct coresight_device", obtained at registration time. +The registering function is taking a ``struct coresight_desc *desc`` and +register the device with the core framework. The unregister function takes +a reference to a ``struct coresight_device *csdev`` obtained at registration time. If everything goes well during the registration process the new devices will -show up under /sys/bus/coresight/devices, as showns here for a TC2 platform: +show up under /sys/bus/coresight/devices, as showns here for a TC2 platform:: -root:~# ls /sys/bus/coresight/devices/ -replicator 20030000.tpiu 2201c000.ptm 2203c000.etm 2203e000.etm -20010000.etb 20040000.funnel 2201d000.ptm 2203d000.etm -root:~# + root:~# ls /sys/bus/coresight/devices/ + replicator 20030000.tpiu 2201c000.ptm 2203c000.etm 2203e000.etm + 20010000.etb 20040000.funnel 2201d000.ptm 2203d000.etm + root:~# -The functions take a "struct coresight_device", which looks like this: +The functions take a ``struct coresight_device``, which looks like this:: -struct coresight_desc { - enum coresight_dev_type type; - struct coresight_dev_subtype subtype; - const struct coresight_ops *ops; - struct coresight_platform_data *pdata; - struct device *dev; - const struct attribute_group **groups; -}; + struct coresight_desc { + enum coresight_dev_type type; + struct coresight_dev_subtype subtype; + const struct coresight_ops *ops; + struct coresight_platform_data *pdata; + struct device *dev; + const struct attribute_group **groups; + }; The "coresight_dev_type" identifies what the device is, i.e, source link or sink while the "coresight_dev_subtype" will characterise that type further. -The "struct coresight_ops" is mandatory and will tell the framework how to +The ``struct coresight_ops`` is mandatory and will tell the framework how to perform base operations related to the components, each component having -a different set of requirement. For that "struct coresight_ops_sink", -"struct coresight_ops_link" and "struct coresight_ops_source" have been +a different set of requirement. For that ``struct coresight_ops_sink``, +``struct coresight_ops_link`` and ``struct coresight_ops_source`` have been provided. -The next field, "struct coresight_platform_data *pdata" is acquired by calling -"of_get_coresight_platform_data()", as part of the driver's _probe routine and -"struct device *dev" gets the device reference embedded in the "amba_device": +The next field ``struct coresight_platform_data *pdata`` is acquired by calling +``of_get_coresight_platform_data()``, as part of the driver's _probe routine and +``struct device *dev`` gets the device reference embedded in the ``amba_device``:: -static int etm_probe(struct amba_device *adev, const struct amba_id *id) -{ - ... - ... - drvdata->dev = &adev->dev; - ... -} + static int etm_probe(struct amba_device *adev, const struct amba_id *id) + { + ... + ... + drvdata->dev = &adev->dev; + ... + } Specific class of device (source, link, or sink) have generic operations -that can be performed on them (see "struct coresight_ops"). The -"**groups" is a list of sysfs entries pertaining to operations +that can be performed on them (see ``struct coresight_ops``). The ``**groups`` +is a list of sysfs entries pertaining to operations specific to that component only. "Implementation defined" customisations are expected to be accessed and controlled using those entries. - Device Naming scheme ------------------------- +-------------------- + The devices that appear on the "coresight" bus were named the same as their parent devices, i.e, the real devices that appears on AMBA bus or the platform bus. Thus the names were based on the Linux Open Firmware layer naming convention, which follows the base physical address of the device followed by the device -type. e.g: +type. e.g:: -root:~# ls /sys/bus/coresight/devices/ - 20010000.etf 20040000.funnel 20100000.stm 22040000.etm - 22140000.etm 230c0000.funnel 23240000.etm 20030000.tpiu - 20070000.etr 20120000.replicator 220c0000.funnel - 23040000.etm 23140000.etm 23340000.etm + root:~# ls /sys/bus/coresight/devices/ + 20010000.etf 20040000.funnel 20100000.stm 22040000.etm + 22140000.etm 230c0000.funnel 23240000.etm 20030000.tpiu + 20070000.etr 20120000.replicator 220c0000.funnel + 23040000.etm 23140000.etm 23340000.etm However, with the introduction of ACPI support, the names of the real devices are a bit cryptic and non-obvious. Thus, a new naming scheme was introduced to use more generic names based on the type of the device. The -following rules apply: +following rules apply:: 1) Devices that are bound to CPUs, are named based on the CPU logical number. @@ -220,11 +230,11 @@ following rules apply: e.g, tmc_etf0, tmc_etr0, funnel0, funnel1 -Thus, with the new scheme the devices could appear as : +Thus, with the new scheme the devices could appear as :: -root:~# ls /sys/bus/coresight/devices/ - etm0 etm1 etm2 etm3 etm4 etm5 funnel0 - funnel1 funnel2 replicator0 stm0 tmc_etf0 tmc_etr0 tpiu0 + root:~# ls /sys/bus/coresight/devices/ + etm0 etm1 etm2 etm3 etm4 etm5 funnel0 + funnel1 funnel2 replicator0 stm0 tmc_etf0 tmc_etr0 tpiu0 Some of the examples below might refer to old naming scheme and some to the newer scheme, to give a confirmation that what you see on your @@ -234,9 +244,12 @@ the system under specified locations. How to use the tracer modules ----------------------------- -There are two ways to use the Coresight framework: 1) using the perf cmd line -tools and 2) interacting directly with the Coresight devices using the sysFS -interface. Preference is given to the former as using the sysFS interface +There are two ways to use the Coresight framework: + +1. using the perf cmd line tools. +2. interacting directly with the Coresight devices using the sysFS interface. + +Preference is given to the former as using the sysFS interface requires a deep understanding of the Coresight HW. The following sections provide details on using both methods. @@ -245,107 +258,107 @@ provide details on using both methods. Before trace collection can start, a coresight sink needs to be identified. There is no limit on the amount of sinks (nor sources) that can be enabled at any given moment. As a generic operation, all device pertaining to the sink -class will have an "active" entry in sysfs: - -root:/sys/bus/coresight/devices# ls -replicator 20030000.tpiu 2201c000.ptm 2203c000.etm 2203e000.etm -20010000.etb 20040000.funnel 2201d000.ptm 2203d000.etm -root:/sys/bus/coresight/devices# ls 20010000.etb -enable_sink status trigger_cntr -root:/sys/bus/coresight/devices# echo 1 > 20010000.etb/enable_sink -root:/sys/bus/coresight/devices# cat 20010000.etb/enable_sink -1 -root:/sys/bus/coresight/devices# +class will have an "active" entry in sysfs:: + + root:/sys/bus/coresight/devices# ls + replicator 20030000.tpiu 2201c000.ptm 2203c000.etm 2203e000.etm + 20010000.etb 20040000.funnel 2201d000.ptm 2203d000.etm + root:/sys/bus/coresight/devices# ls 20010000.etb + enable_sink status trigger_cntr + root:/sys/bus/coresight/devices# echo 1 > 20010000.etb/enable_sink + root:/sys/bus/coresight/devices# cat 20010000.etb/enable_sink + 1 + root:/sys/bus/coresight/devices# At boot time the current etm3x driver will configure the first address comparator with "_stext" and "_etext", essentially tracing any instruction that falls within that range. As such "enabling" a source will immediately -trigger a trace capture: - -root:/sys/bus/coresight/devices# echo 1 > 2201c000.ptm/enable_source -root:/sys/bus/coresight/devices# cat 2201c000.ptm/enable_source -1 -root:/sys/bus/coresight/devices# cat 20010000.etb/status -Depth: 0x2000 -Status: 0x1 -RAM read ptr: 0x0 -RAM wrt ptr: 0x19d3 <----- The write pointer is moving -Trigger cnt: 0x0 -Control: 0x1 -Flush status: 0x0 -Flush ctrl: 0x2001 -root:/sys/bus/coresight/devices# - -Trace collection is stopped the same way: - -root:/sys/bus/coresight/devices# echo 0 > 2201c000.ptm/enable_source -root:/sys/bus/coresight/devices# - -The content of the ETB buffer can be harvested directly from /dev: - -root:/sys/bus/coresight/devices# dd if=/dev/20010000.etb \ -of=~/cstrace.bin - -64+0 records in -64+0 records out -32768 bytes (33 kB) copied, 0.00125258 s, 26.2 MB/s -root:/sys/bus/coresight/devices# +trigger a trace capture:: + + root:/sys/bus/coresight/devices# echo 1 > 2201c000.ptm/enable_source + root:/sys/bus/coresight/devices# cat 2201c000.ptm/enable_source + 1 + root:/sys/bus/coresight/devices# cat 20010000.etb/status + Depth: 0x2000 + Status: 0x1 + RAM read ptr: 0x0 + RAM wrt ptr: 0x19d3 <----- The write pointer is moving + Trigger cnt: 0x0 + Control: 0x1 + Flush status: 0x0 + Flush ctrl: 0x2001 + root:/sys/bus/coresight/devices# + +Trace collection is stopped the same way:: + + root:/sys/bus/coresight/devices# echo 0 > 2201c000.ptm/enable_source + root:/sys/bus/coresight/devices# + +The content of the ETB buffer can be harvested directly from /dev:: + + root:/sys/bus/coresight/devices# dd if=/dev/20010000.etb \ + of=~/cstrace.bin + 64+0 records in + 64+0 records out + 32768 bytes (33 kB) copied, 0.00125258 s, 26.2 MB/s + root:/sys/bus/coresight/devices# The file cstrace.bin can be decompressed using "ptm2human", DS-5 or Trace32. Following is a DS-5 output of an experimental loop that increments a variable up to a certain value. The example is simple and yet provides a glimpse of the wealth of possibilities that coresight provides. - -Info Tracing enabled -Instruction 106378866 0x8026B53C E52DE004 false PUSH {lr} -Instruction 0 0x8026B540 E24DD00C false SUB sp,sp,#0xc -Instruction 0 0x8026B544 E3A03000 false MOV r3,#0 -Instruction 0 0x8026B548 E58D3004 false STR r3,[sp,#4] -Instruction 0 0x8026B54C E59D3004 false LDR r3,[sp,#4] -Instruction 0 0x8026B550 E3530004 false CMP r3,#4 -Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 -Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] -Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c -Timestamp Timestamp: 17106715833 -Instruction 319 0x8026B54C E59D3004 false LDR r3,[sp,#4] -Instruction 0 0x8026B550 E3530004 false CMP r3,#4 -Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 -Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] -Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c -Instruction 9 0x8026B54C E59D3004 false LDR r3,[sp,#4] -Instruction 0 0x8026B550 E3530004 false CMP r3,#4 -Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 -Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] -Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c -Instruction 7 0x8026B54C E59D3004 false LDR r3,[sp,#4] -Instruction 0 0x8026B550 E3530004 false CMP r3,#4 -Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 -Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] -Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c -Instruction 7 0x8026B54C E59D3004 false LDR r3,[sp,#4] -Instruction 0 0x8026B550 E3530004 false CMP r3,#4 -Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 -Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] -Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c -Instruction 10 0x8026B54C E59D3004 false LDR r3,[sp,#4] -Instruction 0 0x8026B550 E3530004 false CMP r3,#4 -Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 -Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] -Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c -Instruction 6 0x8026B560 EE1D3F30 false MRC p15,#0x0,r3,c13,c0,#1 -Instruction 0 0x8026B564 E1A0100D false MOV r1,sp -Instruction 0 0x8026B568 E3C12D7F false BIC r2,r1,#0x1fc0 -Instruction 0 0x8026B56C E3C2203F false BIC r2,r2,#0x3f -Instruction 0 0x8026B570 E59D1004 false LDR r1,[sp,#4] -Instruction 0 0x8026B574 E59F0010 false LDR r0,[pc,#16] ; [0x8026B58C] = 0x80550368 -Instruction 0 0x8026B578 E592200C false LDR r2,[r2,#0xc] -Instruction 0 0x8026B57C E59221D0 false LDR r2,[r2,#0x1d0] -Instruction 0 0x8026B580 EB07A4CF true BL {pc}+0x1e9344 ; 0x804548c4 -Info Tracing enabled -Instruction 13570831 0x8026B584 E28DD00C false ADD sp,sp,#0xc -Instruction 0 0x8026B588 E8BD8000 true LDM sp!,{pc} -Timestamp Timestamp: 17107041535 +:: + + Info Tracing enabled + Instruction 106378866 0x8026B53C E52DE004 false PUSH {lr} + Instruction 0 0x8026B540 E24DD00C false SUB sp,sp,#0xc + Instruction 0 0x8026B544 E3A03000 false MOV r3,#0 + Instruction 0 0x8026B548 E58D3004 false STR r3,[sp,#4] + Instruction 0 0x8026B54C E59D3004 false LDR r3,[sp,#4] + Instruction 0 0x8026B550 E3530004 false CMP r3,#4 + Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 + Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] + Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c + Timestamp Timestamp: 17106715833 + Instruction 319 0x8026B54C E59D3004 false LDR r3,[sp,#4] + Instruction 0 0x8026B550 E3530004 false CMP r3,#4 + Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 + Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] + Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c + Instruction 9 0x8026B54C E59D3004 false LDR r3,[sp,#4] + Instruction 0 0x8026B550 E3530004 false CMP r3,#4 + Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 + Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] + Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c + Instruction 7 0x8026B54C E59D3004 false LDR r3,[sp,#4] + Instruction 0 0x8026B550 E3530004 false CMP r3,#4 + Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 + Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] + Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c + Instruction 7 0x8026B54C E59D3004 false LDR r3,[sp,#4] + Instruction 0 0x8026B550 E3530004 false CMP r3,#4 + Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 + Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] + Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c + Instruction 10 0x8026B54C E59D3004 false LDR r3,[sp,#4] + Instruction 0 0x8026B550 E3530004 false CMP r3,#4 + Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 + Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] + Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c + Instruction 6 0x8026B560 EE1D3F30 false MRC p15,#0x0,r3,c13,c0,#1 + Instruction 0 0x8026B564 E1A0100D false MOV r1,sp + Instruction 0 0x8026B568 E3C12D7F false BIC r2,r1,#0x1fc0 + Instruction 0 0x8026B56C E3C2203F false BIC r2,r2,#0x3f + Instruction 0 0x8026B570 E59D1004 false LDR r1,[sp,#4] + Instruction 0 0x8026B574 E59F0010 false LDR r0,[pc,#16] ; [0x8026B58C] = 0x80550368 + Instruction 0 0x8026B578 E592200C false LDR r2,[r2,#0xc] + Instruction 0 0x8026B57C E59221D0 false LDR r2,[r2,#0x1d0] + Instruction 0 0x8026B580 EB07A4CF true BL {pc}+0x1e9344 ; 0x804548c4 + Info Tracing enabled + Instruction 13570831 0x8026B584 E28DD00C false ADD sp,sp,#0xc + Instruction 0 0x8026B588 E8BD8000 true LDM sp!,{pc} + Timestamp Timestamp: 17107041535 2) Using perf framework: @@ -370,19 +383,18 @@ A Coresight PMU works the same way as any other PMU, i.e the name of the PMU is listed along with configuration options within forward slashes '/'. Since a Coresight system will typically have more than one sink, the name of the sink to work with needs to be specified as an event option. -On newer kernels the available sinks are listed in sysFS under: -($SYSFS)/bus/event_source/devices/cs_etm/sinks/ +On newer kernels the available sinks are listed in sysFS under +($SYSFS)/bus/event_source/devices/cs_etm/sinks/:: root@localhost:/sys/bus/event_source/devices/cs_etm/sinks# ls tmc_etf0 tmc_etr0 tpiu0 On older kernels, this may need to be found from the list of coresight devices, -available under ($SYSFS)/bus/coresight/devices/: +available under ($SYSFS)/bus/coresight/devices/:: root:~# ls /sys/bus/coresight/devices/ etm0 etm1 etm2 etm3 etm4 etm5 funnel0 funnel1 funnel2 replicator0 stm0 tmc_etf0 tmc_etr0 tpiu0 - root@linaro-nano:~# perf record -e cs_etm/@tmc_etr0/u --per-thread program As mentioned above in section "Device Naming scheme", the names of the devices could @@ -395,14 +407,14 @@ to use for the trace session. More information on the above and other example on how to use Coresight with the perf tools can be found in the "HOWTO.md" file of the openCSD gitHub -repository [3]. +repository [#third]_. 2.1) AutoFDO analysis using the perf tools: perf can be used to record and analyze trace of programs. Execution can be recorded using 'perf record' with the cs_etm event, -specifying the name of the sink to record to, e.g: +specifying the name of the sink to record to, e.g:: perf record -e cs_etm/@tmc_etr0/u --per-thread @@ -421,12 +433,14 @@ Generating coverage files for Feedback Directed Optimization: AutoFDO 'perf inject' accepts the --itrace option in which case tracing data is removed and replaced with the synthesized events. e.g. +:: perf inject --itrace --strip -i perf.data -o perf.data.new Below is an example of using ARM ETM for autoFDO. It requires autofdo (https://github.com/google/autofdo) and gcc version 5. The bubble sort example is from the AutoFDO tutorial (https://gcc.gnu.org/wiki/AutoFDO/Tutorial). +:: $ gcc-5 -O3 sort.c -o sort $ taskset -c 2 ./sort @@ -455,28 +469,30 @@ difference is that clients are driving the trace capture rather than the program flow through the code. As with any other CoreSight component, specifics about the STM tracer can be -found in sysfs with more information on each entry being found in [1]: +found in sysfs with more information on each entry being found in [#first]_:: -root@genericarmv8:~# ls /sys/bus/coresight/devices/stm0 -enable_source hwevent_select port_enable subsystem uevent -hwevent_enable mgmt port_select traceid -root@genericarmv8:~# + root@genericarmv8:~# ls /sys/bus/coresight/devices/stm0 + enable_source hwevent_select port_enable subsystem uevent + hwevent_enable mgmt port_select traceid + root@genericarmv8:~# Like any other source a sink needs to be identified and the STM enabled before -being used: +being used:: -root@genericarmv8:~# echo 1 > /sys/bus/coresight/devices/tmc_etf0/enable_sink -root@genericarmv8:~# echo 1 > /sys/bus/coresight/devices/stm0/enable_source + root@genericarmv8:~# echo 1 > /sys/bus/coresight/devices/tmc_etf0/enable_sink + root@genericarmv8:~# echo 1 > /sys/bus/coresight/devices/stm0/enable_source From there user space applications can request and use channels using the devfs -interface provided for that purpose by the generic STM API: +interface provided for that purpose by the generic STM API:: + + root@genericarmv8:~# ls -l /dev/stm0 + crw------- 1 root root 10, 61 Jan 3 18:11 /dev/stm0 + root@genericarmv8:~# + +Details on how to use the generic STM API can be found here [#second]_. -root@genericarmv8:~# ls -l /dev/stm0 -crw------- 1 root root 10, 61 Jan 3 18:11 /dev/stm0 -root@genericarmv8:~# +.. [#first] Documentation/ABI/testing/sysfs-bus-coresight-devices-stm -Details on how to use the generic STM API can be found here [2]. +.. [#second] Documentation/trace/stm.rst -[1]. Documentation/ABI/testing/sysfs-bus-coresight-devices-stm -[2]. Documentation/trace/stm.rst -[3]. https://github.com/Linaro/perf-opencsd +.. [#third] https://github.com/Linaro/perf-opencsd diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst index f60079259669132e4745eede87b4bda933f3a6a5..e3060eedb22d7c6edaada02aeec723c300f37d33 100644 --- a/Documentation/trace/ftrace.rst +++ b/Documentation/trace/ftrace.rst @@ -125,7 +125,8 @@ of ftrace. Here is a list of some of the key files: This file holds the output of the trace in a human readable format (described below). Note, tracing is temporarily - disabled while this file is being read (opened). + disabled when the file is open for reading. Once all readers + are closed, tracing is re-enabled. trace_pipe: @@ -139,8 +140,9 @@ of ftrace. Here is a list of some of the key files: will not be read again with a sequential read. The "trace" file is static, and if the tracer is not adding more data, it will display the same - information every time it is read. This file will not - disable tracing while being read. + information every time it is read. Unlike the + "trace" file, opening this file for reading will not + temporarily disable tracing. trace_options: @@ -3153,7 +3155,10 @@ different. The trace is live. Note, reading the trace_pipe file will block until more input is -added. +added. This is contrary to the trace file. If any process opened +the trace file for reading, it will actually disable tracing and +prevent new entries from being added. The trace_pipe file does +not have this limitation. trace entries ------------- diff --git a/Documentation/trace/index.rst b/Documentation/trace/index.rst index 6b4107cf4b98aa1e8fcd7f6bd96bc46ff50444f6..b7891cb1ab4dd9fa79c9b9f1ac52af2c74c8fd2c 100644 --- a/Documentation/trace/index.rst +++ b/Documentation/trace/index.rst @@ -23,3 +23,5 @@ Linux Tracing Technologies intel_th stm sys-t + coresight + coresight-cpu-debug diff --git a/Documentation/translations/it_IT/process/changes.rst b/Documentation/translations/it_IT/process/changes.rst index d0874327f30127b0b8313373a03f01a0685ae9e8..94a6499742ac0e6671adc5427e2ff51fa3e0f10e 100644 --- a/Documentation/translations/it_IT/process/changes.rst +++ b/Documentation/translations/it_IT/process/changes.rst @@ -26,16 +26,15 @@ Prima di pensare d'avere trovato un baco, aggiornate i seguenti programmi usando, il comando indicato dovrebbe dirvelo. Questa lista presume che abbiate già un kernel Linux funzionante. In aggiunta, -non tutti gli strumenti sono necessari ovunque; ovviamente, se non avete un -modem ISDN, per esempio, probabilmente non dovreste preoccuparvi di -isdn4k-utils. +non tutti gli strumenti sono necessari ovunque; ovviamente, se non avete una +PC Card, per esempio, probabilmente non dovreste preoccuparvi di pcmciautils. ====================== ================= ======================================== Programma Versione minima Comando per verificare la versione ====================== ================= ======================================== GNU C 4.6 gcc --version GNU make 3.81 make --version -binutils 2.20 ld -v +binutils 2.21 ld -v flex 2.5.35 flex --version bison 2.0 bison --version util-linux 2.10o fdformat --version @@ -49,7 +48,6 @@ btrfs-progs 0.18 btrfsck pcmciautils 004 pccardctl -V quota-tools 3.09 quota -V PPP 2.4.0 pppd --version -isdn4k-utils 3.1pre1 isdnctrl 2>&1|grep version nfs-utils 1.0.5 showmount --version procps 3.2.0 ps --version oprofile 0.9 oprofiled --version @@ -81,10 +79,7 @@ Per compilare il kernel vi servirà GNU make 3.81 o successivo. Binutils -------- -Il sistema di compilazione, dalla versione 4.13, per la produzione dei passi -intermedi, si è convertito all'uso di *thin archive* (`ar T`) piuttosto che -all'uso del *linking* incrementale (`ld -r`). Questo richiede binutils 2.20 o -successivo. +Per generare il kernel è necessario avere Binutils 2.21 o superiore. pkg-config ---------- @@ -286,11 +281,6 @@ col seguente comando:: mknod /dev/ppp c 108 0 -Isdn4k-utils ------------- - -Per via della modifica del campo per il numero di telefono, il pacchetto -isdn4k-utils dev'essere ricompilato o (preferibilmente) aggiornato. NFS-utils --------- @@ -456,10 +446,6 @@ PPP - -Isdn4k-utils ------------- - -- NFS-utils --------- diff --git a/Documentation/translations/it_IT/process/howto.rst b/Documentation/translations/it_IT/process/howto.rst index 44e6077730e837b8f4ddbbf84f986720a89c8b02..1db5a1082389752b2e20163b4f25c9d1810f3892 100644 --- a/Documentation/translations/it_IT/process/howto.rst +++ b/Documentation/translations/it_IT/process/howto.rst @@ -129,7 +129,7 @@ Di seguito una lista di file che sono presenti nei sorgente del kernel e che https://www.ozlabs.org/~akpm/stuff/tpp.txt "Linux kernel patch submission format" - http://linux.yyz.us/patch-format.html + https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html :ref:`Documentation/translations/it_IT/process/stable-api-nonsense.rst ` diff --git a/Documentation/translations/it_IT/process/submitting-patches.rst b/Documentation/translations/it_IT/process/submitting-patches.rst index 7d7ea92c5c5ad27677af982b5b168bbad257149c..cba1f8cb61ed15f1a255e1d11b1ade8e4046d6c5 100644 --- a/Documentation/translations/it_IT/process/submitting-patches.rst +++ b/Documentation/translations/it_IT/process/submitting-patches.rst @@ -868,7 +868,7 @@ Andrew Morton, "La patch perfetta" (tpp). Jeff Garzik, "Formato per la sottomissione di patch per il kernel Linux" - + Greg Kroah-Hartman, "Come scocciare un manutentore di un sottosistema" diff --git a/Documentation/translations/ja_JP/SubmittingPatches b/Documentation/translations/ja_JP/SubmittingPatches index ad979c3c06a6cc1b26bc90d95143ee23113688e8..dd0c3280ba5ac1a10e136eed0014e6b1e305d872 100644 --- a/Documentation/translations/ja_JP/SubmittingPatches +++ b/Documentation/translations/ja_JP/SubmittingPatches @@ -693,7 +693,7 @@ Andrew Morton, "The perfect patch" (tpp). Jeff Garzik, "Linux kernel patch submission format". - + Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer". diff --git a/Documentation/translations/ja_JP/howto.rst b/Documentation/translations/ja_JP/howto.rst index 2621b770a745c87f0da5a3018b8065b40316873a..73ebdab4ced73f9922531e616f0d76501760b5d9 100644 --- a/Documentation/translations/ja_JP/howto.rst +++ b/Documentation/translations/ja_JP/howto.rst @@ -139,7 +139,7 @@ linux-api@vger.kernel.org に送ることを勧めます。 "The Perfect Patch" http://www.ozlabs.org/~akpm/stuff/tpp.txt "Linux kernel patch submission format" - http://linux.yyz.us/patch-format.html + https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html :ref:`Documentation/process/stable-api-nonsense.rst ` このファイルはカーネルの中に不変の API を持たないことにした意識的 diff --git a/Documentation/translations/ko_KR/howto.rst b/Documentation/translations/ko_KR/howto.rst index bcd63731b80a48c1690d2fb2e35b43e531382eb6..b3f51b19de7ca7c8d8eddbf4431609e93abe2820 100644 --- a/Documentation/translations/ko_KR/howto.rst +++ b/Documentation/translations/ko_KR/howto.rst @@ -135,7 +135,7 @@ mtk.manpages@gmail.com의 메인테이너에게 보낼 것을 권장한다. https://www.ozlabs.org/~akpm/stuff/tpp.txt "Linux kernel patch submission format" - http://linux.yyz.us/patch-format.html + https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html :ref:`Documentation/process/stable-api-nonsense.rst ` 이 문서는 의도적으로 커널이 불변하는 API를 갖지 않도록 결정한 diff --git a/Documentation/translations/zh_CN/arm64/booting.txt b/Documentation/translations/zh_CN/arm64/booting.txt index 4e373d128d9812ddcbeca4b86d346e708bc4f49f..5b0164132c712cd5da47657a074b06f24e3a9be9 100644 --- a/Documentation/translations/zh_CN/arm64/booting.txt +++ b/Documentation/translations/zh_CN/arm64/booting.txt @@ -67,8 +67,8 @@ RAM,或可能使用对这个设备已知的 RAM 信息,还可能是引导装 必要性: 强制 设备树数据块(dtb)必须 8 字节对齐,且大小不能超过 2MB。由于设备树 -数据块将在使能缓存的情况下以 2MB 粒度被映射,故其不能被置于带任意 -特定属性被映射的 2MB 区域内。 +数据块将在使能缓存的情况下以 2MB 粒度被映射,故其不能被置于必须以特定 +属性映射的2M区域内。 注: v4.2 之前的版本同时要求设备树数据块被置于从内核映像以下 text_offset 字节处算起第一个 512MB 内。 diff --git a/Documentation/translations/zh_CN/process/howto.rst b/Documentation/translations/zh_CN/process/howto.rst index 5b671178b17b9d61d3cd7a372538a4489f282c70..a8e6ab818983a80a3a45f2775f0f9f41a14eca37 100644 --- a/Documentation/translations/zh_CN/process/howto.rst +++ b/Documentation/translations/zh_CN/process/howto.rst @@ -113,7 +113,7 @@ Linux内核代码中包含有大量的文档。这些文档对于学习如何与 "Linux kernel patch submission format" - http://linux.yyz.us/patch-format.html + https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html :ref:`Documentation/translations/zh_CN/process/stable-api-nonsense.rst ` 论证内核为什么特意不包括稳定的内核内部API,也就是说不包括像这样的特 @@ -146,14 +146,18 @@ Linux内核代码中包含有大量的文档。这些文档对于学习如何与 :ref:`Documentation/process/applying-patches.rst ` 关于补丁是什么以及如何将它打在不同内核开发分支上的好介绍 -内核还拥有大量从代码自动生成的文档。它包含内核内部API的全面介绍以及如何 -妥善处理加锁的规则。生成的文档会放在 Documentation/DocBook/目录下。在内 -核源码的主目录中使用以下不同命令将会分别生成PDF、Postscript、HTML和手册 -页等不同格式的文档:: +内核还拥有大量从代码自动生成或者从 ReStructuredText(ReST) 标记生成的文档, +比如这个文档,它包含内核内部API的全面介绍以及如何妥善处理加锁的规则。所有 +这些文档都可以通过运行以下命令从内核代码中生成为PDF或HTML文档:: make pdfdocs make htmldocs +ReST格式的文档会生成在 Documentation/output. 目录中。 +它们也可以用下列命令生成 LaTeX 和 ePub 格式文档:: + + make latexdocs + make epubdocs 如何成为内核开发者 ------------------ diff --git a/Documentation/translations/zh_CN/process/submitting-patches.rst b/Documentation/translations/zh_CN/process/submitting-patches.rst index 437c23b367bb36a1cc9801aa47b7accab6fcb888..1bb4271ab420a4892a989c15d4403f5e6fdedd3c 100644 --- a/Documentation/translations/zh_CN/process/submitting-patches.rst +++ b/Documentation/translations/zh_CN/process/submitting-patches.rst @@ -652,7 +652,7 @@ Andrew Morton, "The perfect patch" (tpp). Jeff Garzik, "Linux kernel patch submission format". - + Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer". diff --git a/Documentation/virt/kvm/api.txt b/Documentation/virt/kvm/api.txt index 2d067767b6170249975340d24f9af56c027da5bb..136f1eef3712d3b3205c43a61b4c6e78c69d3e28 100644 --- a/Documentation/virt/kvm/api.txt +++ b/Documentation/virt/kvm/api.txt @@ -586,7 +586,7 @@ Capability: basic Architectures: x86 Type: vcpu ioctl Parameters: struct kvm_msrs (in) -Returns: 0 on success, -1 on error +Returns: number of msrs successfully set (see below), -1 on error Writes model-specific registers to the vcpu. See KVM_GET_MSRS for the data structures. @@ -595,6 +595,11 @@ Application code should set the 'nmsrs' member (which indicates the size of the entries array), and the 'index' and 'data' members of each array entry. +It tries to set the MSRs in array entries[] one by one. If setting an MSR +fails, e.g., due to setting reserved bits, the MSR isn't supported/emulated +by KVM, etc..., it stops processing the MSR list and returns the number of +MSRs that have been set successfully. + 4.20 KVM_SET_CPUID @@ -753,8 +758,8 @@ in-kernel irqchip (GIC), and for in-kernel irqchip can tell the GIC to use PPIs designated for specific cpus. The irq field is interpreted like this: -  bits: | 31 ... 24 | 23 ... 16 | 15 ... 0 | - field: | irq_type | vcpu_index | irq_id | +  bits: | 31 ... 28 | 27 ... 24 | 23 ... 16 | 15 ... 0 | + field: | vcpu2_index | irq_type | vcpu_index | irq_id | The irq_type field has the following values: - irq_type[0]: out-of-kernel GIC: irq_id 0 is IRQ, irq_id 1 is FIQ @@ -766,6 +771,14 @@ The irq_type field has the following values: In both cases, level is used to assert/deassert the line. +When KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 is supported, the target vcpu is +identified as (256 * vcpu2_index + vcpu_index). Otherwise, vcpu2_index +must be zero. + +Note that on arm/arm64, the KVM_CAP_IRQCHIP capability only conditions +injection of interrupts for the in-kernel irqchip. KVM_IRQ_LINE can always +be used for a userspace interrupt controller. + struct kvm_irq_level { union { __u32 irq; /* GSI */ @@ -3079,12 +3092,14 @@ This exception is also raised directly at the corresponding VCPU if the flag KVM_S390_MEMOP_F_INJECT_EXCEPTION is set in the "flags" field. The start address of the memory region has to be specified in the "gaddr" -field, and the length of the region in the "size" field. "buf" is the buffer -supplied by the userspace application where the read data should be written -to for KVM_S390_MEMOP_LOGICAL_READ, or where the data that should be written -is stored for a KVM_S390_MEMOP_LOGICAL_WRITE. "buf" is unused and can be NULL -when KVM_S390_MEMOP_F_CHECK_ONLY is specified. "ar" designates the access -register number to be used. +field, and the length of the region in the "size" field (which must not +be 0). The maximum value for "size" can be obtained by checking the +KVM_CAP_S390_MEM_OP capability. "buf" is the buffer supplied by the +userspace application where the read data should be written to for +KVM_S390_MEMOP_LOGICAL_READ, or where the data that should be written is +stored for a KVM_S390_MEMOP_LOGICAL_WRITE. When KVM_S390_MEMOP_F_CHECK_ONLY +is specified, "buf" is unused and can be NULL. "ar" designates the access +register number to be used; the valid range is 0..15. The "reserved" field is meant for future extensions. It is not used by KVM with the currently defined set of flags. diff --git a/Documentation/virt/kvm/mmu.txt b/Documentation/virt/kvm/mmu.txt index 1b9880dfba0ae2d2993504c5cc4f1c34a7780310..dadb29e8738fea131243a6cb8567a5fd5b6895c1 100644 --- a/Documentation/virt/kvm/mmu.txt +++ b/Documentation/virt/kvm/mmu.txt @@ -294,7 +294,7 @@ Handling a page fault is performed as follows: - walk shadow page table - check for valid generation number in the spte (see "Fast invalidation of MMIO sptes" below) - - cache the information to vcpu->arch.mmio_gva, vcpu->arch.access and + - cache the information to vcpu->arch.mmio_gva, vcpu->arch.mmio_access and vcpu->arch.mmio_gfn, and call the emulator - If both P bit and R/W bit of error code are set, this could possibly be handled as a "fast page fault" (fixed without taking the MMU lock). See @@ -304,7 +304,7 @@ Handling a page fault is performed as follows: - if permissions are insufficient, reflect the fault back to the guest - determine the host page - if this is an mmio request, there is no host page; cache the info to - vcpu->arch.mmio_gva, vcpu->arch.access and vcpu->arch.mmio_gfn + vcpu->arch.mmio_gva, vcpu->arch.mmio_access and vcpu->arch.mmio_gfn - walk the shadow page table to find the spte for the translation, instantiating missing intermediate page tables as necessary - If this is an mmio request, cache the mmio info to the spte and set some diff --git a/Documentation/virtual/guest-halt-polling.txt b/Documentation/virtual/guest-halt-polling.txt new file mode 100644 index 0000000000000000000000000000000000000000..b3a2a294532da0729a101b9ebb2751f6676ddf4b --- /dev/null +++ b/Documentation/virtual/guest-halt-polling.txt @@ -0,0 +1,78 @@ +Guest halt polling +================== + +The cpuidle_haltpoll driver, with the haltpoll governor, allows +the guest vcpus to poll for a specified amount of time before +halting. +This provides the following benefits to host side polling: + + 1) The POLL flag is set while polling is performed, which allows + a remote vCPU to avoid sending an IPI (and the associated + cost of handling the IPI) when performing a wakeup. + + 2) The VM-exit cost can be avoided. + +The downside of guest side polling is that polling is performed +even with other runnable tasks in the host. + +The basic logic as follows: A global value, guest_halt_poll_ns, +is configured by the user, indicating the maximum amount of +time polling is allowed. This value is fixed. + +Each vcpu has an adjustable guest_halt_poll_ns +("per-cpu guest_halt_poll_ns"), which is adjusted by the algorithm +in response to events (explained below). + +Module Parameters +================= + +The haltpoll governor has 5 tunable module parameters: + +1) guest_halt_poll_ns: +Maximum amount of time, in nanoseconds, that polling is +performed before halting. + +Default: 200000 + +2) guest_halt_poll_shrink: +Division factor used to shrink per-cpu guest_halt_poll_ns when +wakeup event occurs after the global guest_halt_poll_ns. + +Default: 2 + +3) guest_halt_poll_grow: +Multiplication factor used to grow per-cpu guest_halt_poll_ns +when event occurs after per-cpu guest_halt_poll_ns +but before global guest_halt_poll_ns. + +Default: 2 + +4) guest_halt_poll_grow_start: +The per-cpu guest_halt_poll_ns eventually reaches zero +in case of an idle system. This value sets the initial +per-cpu guest_halt_poll_ns when growing. This can +be increased from 10000, to avoid misses during the initial +growth stage: + +10k, 20k, 40k, ... (example assumes guest_halt_poll_grow=2). + +Default: 50000 + +5) guest_halt_poll_allow_shrink: + +Bool parameter which allows shrinking. Set to N +to avoid it (per-cpu guest_halt_poll_ns will remain +high once achieves global guest_halt_poll_ns value). + +Default: Y + +The module parameters can be set from the debugfs files in: + + /sys/module/haltpoll/parameters/ + +Further Notes +============= + +- Care should be taken when setting the guest_halt_poll_ns parameter as a +large value has the potential to drive the cpu usage to 100% on a machine which +would be almost entirely idle otherwise. diff --git a/Documentation/w1/index.rst b/Documentation/w1/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..57cba81865e29b995554389b4d91d534c083b45b --- /dev/null +++ b/Documentation/w1/index.rst @@ -0,0 +1,21 @@ +. SPDX-License-Identifier: GPL-2.0 + +================ +1-Wire Subsystem +================ + +.. toctree:: + :maxdepth: 1 + + + w1-generic.rst + w1-netlink.rst + masters/index + slaves/index + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/w1/masters/ds2482 b/Documentation/w1/masters/ds2482.rst similarity index 71% rename from Documentation/w1/masters/ds2482 rename to Documentation/w1/masters/ds2482.rst index 56f8edace6ac59617559bb46240adc5254bbc24c..17ebe8f660cd05d7c6872b4cc56171b58f4b21b4 100644 --- a/Documentation/w1/masters/ds2482 +++ b/Documentation/w1/masters/ds2482.rst @@ -1,13 +1,19 @@ +==================== Kernel driver ds2482 ==================== Supported chips: + * Maxim DS2482-100, Maxim DS2482-800 + Prefix: 'ds2482' + Addresses scanned: None + Datasheets: - http://datasheets.maxim-ic.com/en/ds/DS2482-100.pdf - http://datasheets.maxim-ic.com/en/ds/DS2482-800.pdf + + - http://datasheets.maxim-ic.com/en/ds/DS2482-100.pdf + - http://datasheets.maxim-ic.com/en/ds/DS2482-800.pdf Author: Ben Gardner @@ -23,9 +29,11 @@ General Remarks --------------- Valid addresses are 0x18, 0x19, 0x1a, and 0x1b. + However, the device cannot be detected without writing to the i2c bus, so no detection is done. You should instantiate the device explicitly. -$ modprobe ds2482 -$ echo ds2482 0x18 > /sys/bus/i2c/devices/i2c-0/new_device +:: + $ modprobe ds2482 + $ echo ds2482 0x18 > /sys/bus/i2c/devices/i2c-0/new_device diff --git a/Documentation/w1/masters/ds2490 b/Documentation/w1/masters/ds2490.rst similarity index 98% rename from Documentation/w1/masters/ds2490 rename to Documentation/w1/masters/ds2490.rst index 3e091151dd80251363b99746be61c41362ee5e0a..7e5b50f9c0f56a80c1cad51b38404ea7b966d7d9 100644 --- a/Documentation/w1/masters/ds2490 +++ b/Documentation/w1/masters/ds2490.rst @@ -1,7 +1,9 @@ +==================== Kernel driver ds2490 ==================== Supported chips: + * Maxim DS2490 based Author: Evgeniy Polyakov @@ -18,6 +20,7 @@ which has 0x81 family ID integrated chip and DS2490 low-level operational chip. Notes and limitations. + - The weak pullup current is a minimum of 0.9mA and maximum of 6.0mA. - The 5V strong pullup is supported with a minimum of 5.9mA and a maximum of 30.4 mA. (From DS2490.pdf) @@ -65,4 +68,5 @@ Notes and limitations. reattaching would clear the problem. usbmon output in the guest and host did not explain the problem. My guess is a bug in either qemu or the host OS and more likely the host OS. --- 03-06-2008 David Fries + +03-06-2008 David Fries diff --git a/Documentation/w1/masters/index.rst b/Documentation/w1/masters/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..4442a98850adf3b8297058fde80dc65ff98a7600 --- /dev/null +++ b/Documentation/w1/masters/index.rst @@ -0,0 +1,14 @@ +. SPDX-License-Identifier: GPL-2.0 + +===================== +1-wire Master Drivers +===================== + +.. toctree:: + :maxdepth: 1 + + ds2482 + ds2490 + mxc-w1 + omap-hdq + w1-gpio diff --git a/Documentation/w1/masters/mxc-w1 b/Documentation/w1/masters/mxc-w1 deleted file mode 100644 index 38be1ad655324879d4adae306ac7a58922a6b26e..0000000000000000000000000000000000000000 --- a/Documentation/w1/masters/mxc-w1 +++ /dev/null @@ -1,12 +0,0 @@ -Kernel driver mxc_w1 -==================== - -Supported chips: - * Freescale MX27, MX31 and probably other i.MX SoCs - Datasheets: - http://www.freescale.com/files/32bit/doc/data_sheet/MCIMX31.pdf?fpsp=1 - http://cache.freescale.com/files/dsp/doc/archive/MCIMX27.pdf?fsrch=1&WT_TYPE= - Data%20Sheets&WT_VENDOR=FREESCALE&WT_FILE_FORMAT=pdf&WT_ASSET=Documentation - -Author: Originally based on Freescale code, prepared for mainline by - Sascha Hauer diff --git a/Documentation/w1/masters/mxc-w1.rst b/Documentation/w1/masters/mxc-w1.rst new file mode 100644 index 0000000000000000000000000000000000000000..334f9893103f17d8b813adf25c8b3b2873dfed4f --- /dev/null +++ b/Documentation/w1/masters/mxc-w1.rst @@ -0,0 +1,17 @@ +==================== +Kernel driver mxc_w1 +==================== + +Supported chips: + + * Freescale MX27, MX31 and probably other i.MX SoCs + + Datasheets: + + - http://www.freescale.com/files/32bit/doc/data_sheet/MCIMX31.pdf?fpsp=1 + - http://cache.freescale.com/files/dsp/doc/archive/MCIMX27.pdf?fsrch=1&WT_TYPE=Data%20Sheets&WT_VENDOR=FREESCALE&WT_FILE_FORMAT=pdf&WT_ASSET=Documentation + +Author: + + Originally based on Freescale code, prepared for mainline by + Sascha Hauer diff --git a/Documentation/w1/masters/omap-hdq b/Documentation/w1/masters/omap-hdq.rst similarity index 90% rename from Documentation/w1/masters/omap-hdq rename to Documentation/w1/masters/omap-hdq.rst index 234522709a5f4bf9405594e58b430a9e61384c9d..345298a59e5090d6070bc9a41466a985b28ed051 100644 --- a/Documentation/w1/masters/omap-hdq +++ b/Documentation/w1/masters/omap-hdq.rst @@ -1,9 +1,10 @@ -Kernel driver for omap HDQ/1-wire module. +======================================== +Kernel driver for omap HDQ/1-wire module ======================================== Supported chips: ================ - HDQ/1-wire controller on the TI OMAP 2430/3430 platforms. +HDQ/1-wire controller on the TI OMAP 2430/3430 platforms. A useful link about HDQ basics: =============================== @@ -40,9 +41,10 @@ driver(drivers/w1/slaves/w1_bq27000.c) sets the ID to 1. Please note to load both the modules with a different ID if required, but note that the ID used should be same for both master and slave driver loading. -e.g: -insmod omap_hdq.ko W1_ID=2 -inamod w1_bq27000.ko F_ID=2 +e.g:: + + insmod omap_hdq.ko W1_ID=2 + inamod w1_bq27000.ko F_ID=2 The driver also supports 1-wire mode. In this mode, there is no need to pass slave ID as parameter. The driver will auto-detect slaves connected diff --git a/Documentation/w1/masters/w1-gpio b/Documentation/w1/masters/w1-gpio.rst similarity index 75% rename from Documentation/w1/masters/w1-gpio rename to Documentation/w1/masters/w1-gpio.rst index 623961d9e83fd80a0a3cf4dd39de8bbef8ff605e..18fdb7366372791191eb7ba081f955670542ab55 100644 --- a/Documentation/w1/masters/w1-gpio +++ b/Documentation/w1/masters/w1-gpio.rst @@ -1,3 +1,4 @@ +===================== Kernel driver w1-gpio ===================== @@ -16,28 +17,30 @@ Documentation/devicetree/bindings/w1/w1-gpio.txt Example (mach-at91) ------------------- -#include -#include +:: + + #include + #include -static struct gpiod_lookup_table foo_w1_gpiod_table = { + static struct gpiod_lookup_table foo_w1_gpiod_table = { .dev_id = "w1-gpio", .table = { GPIO_LOOKUP_IDX("at91-gpio", AT91_PIN_PB20, NULL, 0, GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN), }, -}; + }; -static struct w1_gpio_platform_data foo_w1_gpio_pdata = { + static struct w1_gpio_platform_data foo_w1_gpio_pdata = { .ext_pullup_enable_pin = -EINVAL, -}; + }; -static struct platform_device foo_w1_device = { + static struct platform_device foo_w1_device = { .name = "w1-gpio", .id = -1, .dev.platform_data = &foo_w1_gpio_pdata, -}; + }; -... + ... at91_set_GPIO_periph(foo_w1_gpio_pdata.pin, 1); at91_set_multi_drive(foo_w1_gpio_pdata.pin, 1); gpiod_add_lookup_table(&foo_w1_gpiod_table); diff --git a/Documentation/w1/slaves/index.rst b/Documentation/w1/slaves/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..d0697b202f09f041fa9ff8fc09f9d624d66b0c22 --- /dev/null +++ b/Documentation/w1/slaves/index.rst @@ -0,0 +1,16 @@ +. SPDX-License-Identifier: GPL-2.0 + +==================== +1-wire Slave Drivers +==================== + +.. toctree:: + :maxdepth: 1 + + w1_ds2406 + w1_ds2413 + w1_ds2423 + w1_ds2438 + w1_ds28e04 + w1_ds28e17 + w1_therm diff --git a/Documentation/w1/slaves/w1_ds2406 b/Documentation/w1/slaves/w1_ds2406.rst similarity index 96% rename from Documentation/w1/slaves/w1_ds2406 rename to Documentation/w1/slaves/w1_ds2406.rst index 8137fe6f6c3d11534458457ade422d8a84fd8dac..d3e68266084fc314f12312ceda7c99ef9f37242a 100644 --- a/Documentation/w1/slaves/w1_ds2406 +++ b/Documentation/w1/slaves/w1_ds2406.rst @@ -1,7 +1,9 @@ +======================= w1_ds2406 kernel driver ======================= Supported chips: + * Maxim DS2406 (and other family 0x12) addressable switches Author: Scott Alfter @@ -9,7 +11,7 @@ Author: Scott Alfter Description ----------- -The w1_ds2406 driver allows connected devices to be switched on and off. +The w1_ds2406 driver allows connected devices to be switched on and off. These chips also provide 128 bytes of OTP EPROM, but reading/writing it is not supported. In TSOC-6 form, the DS2406 provides two switch outputs and can be provided with power on a dedicated input. In TO-92 form, it provides diff --git a/Documentation/w1/slaves/w1_ds2413 b/Documentation/w1/slaves/w1_ds2413.rst similarity index 81% rename from Documentation/w1/slaves/w1_ds2413 rename to Documentation/w1/slaves/w1_ds2413.rst index 936263a8ccb4f4f3e6891bc8ba5d0d4d182da12f..c15bb5b919b7975d1d8ad0cdd01976e32dfd074a 100644 --- a/Documentation/w1/slaves/w1_ds2413 +++ b/Documentation/w1/slaves/w1_ds2413.rst @@ -1,11 +1,16 @@ +======================= Kernel driver w1_ds2413 ======================= Supported chips: + * Maxim DS2413 1-Wire Dual Channel Addressable Switch supported family codes: + + ================ ==== W1_FAMILY_DS2413 0x3A + ================ ==== Author: Mariusz Bialonczyk @@ -20,11 +25,13 @@ Reading state The "state" file provides one-byte value which is in the same format as for the chip PIO_ACCESS_READ command (refer the datasheet for details): +======== ============================================================= Bit 0: PIOA Pin State Bit 1: PIOA Output Latch State Bit 2: PIOB Pin State Bit 3: PIOB Output Latch State Bit 4-7: Complement of Bit 3 to Bit 0 (verified by the kernel module) +======== ============================================================= This file is readonly. @@ -34,9 +41,11 @@ You can set the PIO pins using the "output" file. It is writable, you can write one-byte value to this sysfs file. Similarly the byte format is the same as for the PIO_ACCESS_WRITE command: +======== ====================================== Bit 0: PIOA Bit 1: PIOB Bit 2-7: No matter (driver will set it to "1"s) +======== ====================================== The chip has some kind of basic protection against transmission errors. diff --git a/Documentation/w1/slaves/w1_ds2423 b/Documentation/w1/slaves/w1_ds2423 deleted file mode 100644 index 3f98b505a0ee6855931a5fef560ba1a3c7699cd0..0000000000000000000000000000000000000000 --- a/Documentation/w1/slaves/w1_ds2423 +++ /dev/null @@ -1,47 +0,0 @@ -Kernel driver w1_ds2423 -======================= - -Supported chips: - * Maxim DS2423 based counter devices. - -supported family codes: - W1_THERM_DS2423 0x1D - -Author: Mika Laitio - -Description ------------ - -Support is provided through the sysfs w1_slave file. Each opening and -read sequence of w1_slave file initiates the read of counters and ram -available in DS2423 pages 12 - 15. - -Result of each page is provided as an ASCII output where each counter -value and associated ram buffer is outpputed to own line. - -Each lines will contain the values of 42 bytes read from the counter and -memory page along the crc=YES or NO for indicating whether the read operation -was successful and CRC matched. -If the operation was successful, there is also in the end of each line -a counter value expressed as an integer after c= - -Meaning of 42 bytes represented is following: - - 1 byte from ram page - - 4 bytes for the counter value - - 4 zero bytes - - 2 bytes for crc16 which was calculated from the data read since the previous crc bytes - - 31 remaining bytes from the ram page - - crc=YES/NO indicating whether read was ok and crc matched - - c= current counter value - -example from the successful read: -00 02 00 00 00 00 00 00 00 6d 38 00 ff ff 00 00 fe ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=YES c=2 -00 02 00 00 00 00 00 00 00 e0 1f 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=YES c=2 -00 29 c6 5d 18 00 00 00 00 04 37 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=YES c=408798761 -00 05 00 00 00 00 00 00 00 8d 39 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff crc=YES c=5 - -example from the read with crc errors: -00 02 00 00 00 00 00 00 00 6d 38 00 ff ff 00 00 fe ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=YES c=2 -00 02 00 00 22 00 00 00 00 e0 1f 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=NO -00 e1 61 5d 19 00 00 00 00 df 0b 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=NO -00 05 00 00 20 00 00 00 00 8d 39 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff crc=NO diff --git a/Documentation/w1/slaves/w1_ds2423.rst b/Documentation/w1/slaves/w1_ds2423.rst new file mode 100644 index 0000000000000000000000000000000000000000..755d659ad99718ed70f6280872ede145b972d866 --- /dev/null +++ b/Documentation/w1/slaves/w1_ds2423.rst @@ -0,0 +1,54 @@ +Kernel driver w1_ds2423 +======================= + +Supported chips: + + * Maxim DS2423 based counter devices. + +supported family codes: + + =============== ==== + W1_THERM_DS2423 0x1D + =============== ==== + +Author: Mika Laitio + +Description +----------- + +Support is provided through the sysfs w1_slave file. Each opening and +read sequence of w1_slave file initiates the read of counters and ram +available in DS2423 pages 12 - 15. + +Result of each page is provided as an ASCII output where each counter +value and associated ram buffer is outpputed to own line. + +Each lines will contain the values of 42 bytes read from the counter and +memory page along the crc=YES or NO for indicating whether the read operation +was successful and CRC matched. +If the operation was successful, there is also in the end of each line +a counter value expressed as an integer after c= + +Meaning of 42 bytes represented is following: + + - 1 byte from ram page + - 4 bytes for the counter value + - 4 zero bytes + - 2 bytes for crc16 which was calculated from the data read since the previous crc bytes + - 31 remaining bytes from the ram page + - crc=YES/NO indicating whether read was ok and crc matched + - c= current counter value + +example from the successful read:: + + 00 02 00 00 00 00 00 00 00 6d 38 00 ff ff 00 00 fe ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=YES c=2 + 00 02 00 00 00 00 00 00 00 e0 1f 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=YES c=2 + 00 29 c6 5d 18 00 00 00 00 04 37 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=YES c=408798761 + 00 05 00 00 00 00 00 00 00 8d 39 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff crc=YES c=5 + +example from the read with crc errors:: + + 00 02 00 00 00 00 00 00 00 6d 38 00 ff ff 00 00 fe ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=YES c=2 + 00 02 00 00 22 00 00 00 00 e0 1f 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=NO + 00 e1 61 5d 19 00 00 00 00 df 0b 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=NO + 00 05 00 00 20 00 00 00 00 8d 39 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff crc=NO diff --git a/Documentation/w1/slaves/w1_ds2438 b/Documentation/w1/slaves/w1_ds2438.rst similarity index 93% rename from Documentation/w1/slaves/w1_ds2438 rename to Documentation/w1/slaves/w1_ds2438.rst index e64f65a09387eccefb3a1f13d3fe68abb11c6966..a29309a3f8e579aa3f8c5289174db88e99c75568 100644 --- a/Documentation/w1/slaves/w1_ds2438 +++ b/Documentation/w1/slaves/w1_ds2438.rst @@ -2,10 +2,13 @@ Kernel driver w1_ds2438 ======================= Supported chips: + * Maxim DS2438 Smart Battery Monitor supported family codes: + ================ ==== W1_FAMILY_DS2438 0x26 + ================ ==== Author: Mariusz Bialonczyk @@ -56,8 +59,11 @@ Opening and reading this file initiates the CONVERT_V (voltage conversion) command of the chip. Depending on a sysfs filename a different input for the A/D will be selected: -vad: general purpose A/D input (VAD) -vdd: battery input (VDD) + +vad: + general purpose A/D input (VAD) +vdd: + battery input (VDD) After the voltage conversion the value is returned as decimal ASCII. Note: To get a volts the value has to be divided by 100. diff --git a/Documentation/w1/slaves/w1_ds28e04 b/Documentation/w1/slaves/w1_ds28e04.rst similarity index 93% rename from Documentation/w1/slaves/w1_ds28e04 rename to Documentation/w1/slaves/w1_ds28e04.rst index 7819b65cfa48ed4f8bd33ba48139754be1dd4212..b12b118890d3a8b3157c6259331f88dca211687c 100644 --- a/Documentation/w1/slaves/w1_ds28e04 +++ b/Documentation/w1/slaves/w1_ds28e04.rst @@ -1,11 +1,16 @@ +======================== Kernel driver w1_ds28e04 ======================== Supported chips: + * Maxim DS28E04-100 4096-Bit Addressable 1-Wire EEPROM with PIO supported family codes: + + ================= ==== W1_FAMILY_DS28E04 0x1C + ================= ==== Author: Markus Franke, diff --git a/Documentation/w1/slaves/w1_ds28e17 b/Documentation/w1/slaves/w1_ds28e17.rst similarity index 88% rename from Documentation/w1/slaves/w1_ds28e17 rename to Documentation/w1/slaves/w1_ds28e17.rst index 7fcfad5b4a37280c1c8f997a271592ab72125af2..e2d9f96d8f2ce404e4eaafc87484d38c36d72651 100644 --- a/Documentation/w1/slaves/w1_ds28e17 +++ b/Documentation/w1/slaves/w1_ds28e17.rst @@ -1,11 +1,16 @@ +======================== Kernel driver w1_ds28e17 ======================== Supported chips: + * Maxim DS28E17 1-Wire-to-I2C Master Bridge supported family codes: + + ================= ==== W1_FAMILY_DS28E17 0x19 + ================= ==== Author: Jan Kandziora @@ -20,11 +25,11 @@ a DS28E17 can be accessed by the kernel or userspace tools as if they were connected to a "native" I2C bus master. -An udev rule like the following -------------------------------------------------------------------------------- -SUBSYSTEM=="i2c-dev", KERNEL=="i2c-[0-9]*", ATTRS{name}=="w1-19-*", \ - SYMLINK+="i2c-$attr{name}" -------------------------------------------------------------------------------- +An udev rule like the following:: + + SUBSYSTEM=="i2c-dev", KERNEL=="i2c-[0-9]*", ATTRS{name}=="w1-19-*", \ + SYMLINK+="i2c-$attr{name}" + may be used to create stable /dev/i2c- entries based on the unique id of the DS28E17 chip. @@ -65,4 +70,3 @@ structure is created. See https://github.com/ianka/w1_ds28e17 for even more information. - diff --git a/Documentation/w1/slaves/w1_therm b/Documentation/w1/slaves/w1_therm.rst similarity index 95% rename from Documentation/w1/slaves/w1_therm rename to Documentation/w1/slaves/w1_therm.rst index d1f93af36f385f8e308e6062362eb36ba97b6312..90531c340a07aa96633b6a91f74b705ee3822ba1 100644 --- a/Documentation/w1/slaves/w1_therm +++ b/Documentation/w1/slaves/w1_therm.rst @@ -1,7 +1,9 @@ +====================== Kernel driver w1_therm -==================== +====================== Supported chips: + * Maxim ds18*20 based temperature sensors. * Maxim ds1825 based temperature sensors. @@ -13,12 +15,16 @@ Description w1_therm provides basic temperature conversion for ds18*20 devices, and the ds28ea00 device. -supported family codes: + +Supported family codes: + +==================== ==== W1_THERM_DS18S20 0x10 W1_THERM_DS1822 0x22 W1_THERM_DS18B20 0x28 W1_THERM_DS1825 0x3B W1_THERM_DS28EA00 0x42 +==================== ==== Support is provided through the sysfs w1_slave file. Each open and read sequence will initiate a temperature conversion then provide two @@ -51,6 +57,7 @@ If so, it will activate the master's strong pullup. In case the detection of parasite devices using this command fails (seems to be the case with some DS18S20) the strong pullup can be force-enabled. + If the strong pullup is enabled, the master's strong pullup will be driven when the conversion is taking place, provided the master driver does support the strong pullup (or it falls back to a pullup diff --git a/Documentation/w1/w1.generic b/Documentation/w1/w1-generic.rst similarity index 59% rename from Documentation/w1/w1.generic rename to Documentation/w1/w1-generic.rst index c51b1ab012d0212353ef7c77339b7f5f8a699066..da4e8b4e9b01185f90a4d411ae8817ba4a437467 100644 --- a/Documentation/w1/w1.generic +++ b/Documentation/w1/w1-generic.rst @@ -1,5 +1,7 @@ -The 1-wire (w1) subsystem ------------------------------------------------------------------- +========================================= +Introduction to the 1-wire (w1) subsystem +========================================= + The 1-wire bus is a simple master-slave bus that communicates via a single signal wire (plus ground, so two wires). @@ -12,14 +14,16 @@ communication with slaves. All w1 slave devices must be connected to a w1 bus master device. Example w1 master devices: - DS9490 usb device - W1-over-GPIO - DS2482 (i2c to w1 bridge) - Emulated devices, such as a RS232 converter, parallel port adapter, etc + + - DS9490 usb device + - W1-over-GPIO + - DS2482 (i2c to w1 bridge) + - Emulated devices, such as a RS232 converter, parallel port adapter, etc What does the w1 subsystem do? ------------------------------------------------------------------- +------------------------------ + When a w1 master driver registers with the w1 subsystem, the following occurs: - sysfs entries for that w1 master are created @@ -43,24 +47,28 @@ be read, since no device was selected. W1 device families ------------------------------------------------------------------- +------------------ + Slave devices are handled by a driver written for a family of w1 devices. A family driver populates a struct w1_family_ops (see w1_family.h) and registers with the w1 subsystem. Current family drivers: -w1_therm - (ds18?20 thermal sensor family driver) + +w1_therm + - (ds18?20 thermal sensor family driver) provides temperature reading function which is bound to ->rbin() method of the above w1_family_ops structure. -w1_smem - driver for simple 64bit memory cell provides ID reading method. +w1_smem + - driver for simple 64bit memory cell provides ID reading method. You can call above methods by reading appropriate sysfs files. What does a w1 master driver need to implement? ------------------------------------------------------------------- +----------------------------------------------- The driver for w1 bus master must provide at minimum two functions. @@ -75,25 +83,26 @@ See struct w1_bus_master definition in w1.h for details. w1 master sysfs interface ------------------------------------------------------------------- - - A directory for a found device. The format is family-serial -bus - (standard) symlink to the w1 bus -driver - (standard) symlink to the w1 driver -w1_master_add - (rw) manually register a slave device -w1_master_attempts - (ro) the number of times a search was attempted -w1_master_max_slave_count - - (rw) maximum number of slaves to search for at a time -w1_master_name - (ro) the name of the device (w1_bus_masterX) -w1_master_pullup - (rw) 5V strong pullup 0 enabled, 1 disabled -w1_master_remove - (rw) manually remove a slave device -w1_master_search - (rw) the number of searches left to do, - -1=continual (default) -w1_master_slave_count - - (ro) the number of slaves found -w1_master_slaves - (ro) the names of the slaves, one per line -w1_master_timeout - (ro) the delay in seconds between searches -w1_master_timeout_us - - (ro) the delay in microseconds beetwen searches +------------------------- + +========================= ===================================================== + A directory for a found device. The format is + family-serial +bus (standard) symlink to the w1 bus +driver (standard) symlink to the w1 driver +w1_master_add (rw) manually register a slave device +w1_master_attempts (ro) the number of times a search was attempted +w1_master_max_slave_count (rw) maximum number of slaves to search for at a time +w1_master_name (ro) the name of the device (w1_bus_masterX) +w1_master_pullup (rw) 5V strong pullup 0 enabled, 1 disabled +w1_master_remove (rw) manually remove a slave device +w1_master_search (rw) the number of searches left to do, + -1=continual (default) +w1_master_slave_count (ro) the number of slaves found +w1_master_slaves (ro) the names of the slaves, one per line +w1_master_timeout (ro) the delay in seconds between searches +w1_master_timeout_us (ro) the delay in microseconds beetwen searches +========================= ===================================================== If you have a w1 bus that never changes (you don't add or remove devices), you can set the module parameter search_count to a small positive number @@ -111,11 +120,14 @@ decrements w1_master_search by 1 (down to 0) and increments w1_master_attempts by 1. w1 slave sysfs interface ------------------------------------------------------------------- -bus - (standard) symlink to the w1 bus -driver - (standard) symlink to the w1 driver -name - the device name, usually the same as the directory name -w1_slave - (optional) a binary file whose meaning depends on the - family driver -rw - (optional) created for slave devices which do not have - appropriate family driver. Allows to read/write binary data. +------------------------ + +=================== ============================================================ +bus (standard) symlink to the w1 bus +driver (standard) symlink to the w1 driver +name the device name, usually the same as the directory name +w1_slave (optional) a binary file whose meaning depends on the + family driver +rw (optional) created for slave devices which do not have + appropriate family driver. Allows to read/write binary data. +=================== ============================================================ diff --git a/Documentation/w1/w1.netlink b/Documentation/w1/w1-netlink.rst similarity index 77% rename from Documentation/w1/w1.netlink rename to Documentation/w1/w1-netlink.rst index 94ad4c42082857d4ee7cf6199eb0d8067beb159a..aaa13243a5e43ddbacc9a7c42afa67e4bcb985d4 100644 --- a/Documentation/w1/w1.netlink +++ b/Documentation/w1/w1-netlink.rst @@ -1,22 +1,26 @@ -Userspace communication protocol over connector [1]. +=============================================== +Userspace communication protocol over connector +=============================================== - -Message types. +Message types ============= There are three types of messages between w1 core and userspace: + 1. Events. They are generated each time a new master or slave device - is found either due to automatic or requested search. + is found either due to automatic or requested search. 2. Userspace commands. 3. Replies to userspace commands. -Protocol. +Protocol ======== -[struct cn_msg] - connector header. +:: + + [struct cn_msg] - connector header. Its length field is equal to size of the attached data -[struct w1_netlink_msg] - w1 netlink header. + [struct w1_netlink_msg] - w1 netlink header. __u8 type - message type. W1_LIST_MASTERS list current bus masters @@ -40,7 +44,7 @@ Protocol. } mst; } id; -[struct w1_netlink_cmd] - command for given master or slave device. + [struct w1_netlink_cmd] - command for given master or slave device. __u8 cmd - command opcode. W1_CMD_READ - read command W1_CMD_WRITE - write command @@ -71,18 +75,18 @@ when it is added to w1 core. Currently replies to userspace commands are only generated for read command request. One reply is generated exactly for one w1_netlink_cmd read request. Replies are not combined when sent - i.e. typical reply -messages looks like the following: +messages looks like the following:: -[cn_msg][w1_netlink_msg][w1_netlink_cmd] -cn_msg.len = sizeof(struct w1_netlink_msg) + + [cn_msg][w1_netlink_msg][w1_netlink_cmd] + cn_msg.len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len; -w1_netlink_msg.len = sizeof(struct w1_netlink_cmd) + cmd->len; -w1_netlink_cmd.len = cmd->len; + w1_netlink_msg.len = sizeof(struct w1_netlink_cmd) + cmd->len; + w1_netlink_cmd.len = cmd->len; Replies to W1_LIST_MASTERS should send a message back to the userspace which will contain list of all registered master ids in the following -format: +format:: cn_msg (CN_W1_IDX.CN_W1_VAL as id, len is equal to sizeof(struct w1_netlink_msg) plus number of masters multiplied by 4) @@ -90,39 +94,47 @@ format: number of masters multiplied by 4 (u32 size)) id0 ... idN - Each message is at most 4k in size, so if number of master devices - exceeds this, it will be split into several messages. +Each message is at most 4k in size, so if number of master devices +exceeds this, it will be split into several messages. W1 search and alarm search commands. -request: -[cn_msg] - [w1_netlink_msg type = W1_MASTER_CMD - id is equal to the bus master id to use for searching] - [w1_netlink_cmd cmd = W1_CMD_SEARCH or W1_CMD_ALARM_SEARCH] -reply: +request:: + + [cn_msg] + [w1_netlink_msg type = W1_MASTER_CMD + id is equal to the bus master id to use for searching] + [w1_netlink_cmd cmd = W1_CMD_SEARCH or W1_CMD_ALARM_SEARCH] + +reply:: + [cn_msg, ack = 1 and increasing, 0 means the last message, - seq is equal to the request seq] + seq is equal to the request seq] [w1_netlink_msg type = W1_MASTER_CMD] [w1_netlink_cmd cmd = W1_CMD_SEARCH or W1_CMD_ALARM_SEARCH len is equal to number of IDs multiplied by 8] [64bit-id0 ... 64bit-idN] + Length in each header corresponds to the size of the data behind it, so w1_netlink_cmd->len = N * 8; where N is number of IDs in this message. - Can be zero. -w1_netlink_msg->len = sizeof(struct w1_netlink_cmd) + N * 8; -cn_msg->len = sizeof(struct w1_netlink_msg) + +Can be zero. + +:: + + w1_netlink_msg->len = sizeof(struct w1_netlink_cmd) + N * 8; + cn_msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + N*8; -W1 reset command. -[cn_msg] - [w1_netlink_msg type = W1_MASTER_CMD - id is equal to the bus master id to use for searching] - [w1_netlink_cmd cmd = W1_CMD_RESET] +W1 reset command:: + [cn_msg] + [w1_netlink_msg type = W1_MASTER_CMD + id is equal to the bus master id to use for searching] + [w1_netlink_cmd cmd = W1_CMD_RESET] -Command status replies. + +Command status replies ====================== Each command (either root, master or slave with or without w1_netlink_cmd @@ -150,7 +162,7 @@ All w1_netlink_cmd command structures are handled in every w1_netlink_msg, even if there were errors, only length mismatch interrupts message processing. -Operation steps in w1 core when new command is received. +Operation steps in w1 core when new command is received ======================================================= When new message (w1_netlink_msg) is received w1 core detects if it is @@ -167,7 +179,7 @@ When all commands (w1_netlink_cmd) are processed master device is unlocked and next w1_netlink_msg header processing started. -Connector [1] specific documentation. +Connector [1] specific documentation ==================================== Each connector message includes two u32 fields as "address". @@ -180,10 +192,11 @@ Sequence number for reply is the same as was in request, and acknowledge number is set to seq+1. -Additional documantion, source code examples. -============================================ +Additional documentation, source code examples +============================================== 1. Documentation/driver-api/connector.rst 2. http://www.ioremap.net/archive/w1 -This archive includes userspace application w1d.c which uses -read/write/search commands for all master/slave devices found on the bus. + + This archive includes userspace application w1d.c which uses + read/write/search commands for all master/slave devices found on the bus. diff --git a/MAINTAINERS b/MAINTAINERS index a50e97a63bc84095fa0083aefd7b0888c4db1e4e..b2326dece28ebeb1412b04bcc49f81705da58c99 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -517,14 +517,6 @@ W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/video/backlight/adp8860_bl.c -ADS1015 HARDWARE MONITOR DRIVER -M: Dirk Eibach -L: linux-hwmon@vger.kernel.org -S: Maintained -F: Documentation/hwmon/ads1015.rst -F: drivers/hwmon/ads1015.c -F: include/linux/platform_data/ads1015.h - ADT746X FAN DRIVER M: Colin Leroy S: Maintained @@ -649,6 +641,12 @@ M: Lino Sanfilippo S: Maintained F: drivers/net/ethernet/alacritech/* +FORCEDETH GIGABIT ETHERNET DRIVER +M: Rain River +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/ethernet/nvidia/* + ALCATEL SPEEDTOUCH USB DRIVER M: Duncan Sands L: linux-usb@vger.kernel.org @@ -666,7 +664,7 @@ ALI1563 I2C DRIVER M: Rudolf Marek L: linux-i2c@vger.kernel.org S: Maintained -F: Documentation/i2c/busses/i2c-ali1563 +F: Documentation/i2c/busses/i2c-ali1563.rst F: drivers/i2c/busses/i2c-ali1563.c ALLEGRO DVT VIDEO IP CORE DRIVER @@ -676,6 +674,13 @@ L: linux-media@vger.kernel.org S: Maintained F: drivers/staging/media/allegro-dvt/ +ALLWINNER CPUFREQ DRIVER +M: Yangtao Li +L: linux-pm@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/opp/sun50i-nvmem-cpufreq.txt +F: drivers/cpufreq/sun50i-cpufreq-nvmem.c + ALLWINNER SECURITY SYSTEM M: Corentin Labbe L: linux-crypto@vger.kernel.org @@ -903,11 +908,12 @@ F: Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml ANALOG DEVICES INC AD7606 DRIVER M: Stefan Popa +M: Beniamin Bia L: linux-iio@vger.kernel.org W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/iio/adc/ad7606.c -F: Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt +F: Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml ANALOG DEVICES INC AD7768-1 DRIVER M: Stefan Popa @@ -938,6 +944,14 @@ S: Supported F: drivers/mux/adgs1408.c F: Documentation/devicetree/bindings/mux/adi,adgs1408.txt +ANALOG DEVICES INC ADIN DRIVER +M: Alexandru Ardelean +L: netdev@vger.kernel.org +W: http://ez.analog.com/community/linux-device-drivers +S: Supported +F: drivers/net/phy/adin.c +F: Documentation/devicetree/bindings/net/adi,adin.yaml + ANALOG DEVICES INC ADIS DRIVER LIBRARY M: Alexandru Ardelean S: Supported @@ -945,6 +959,14 @@ L: linux-iio@vger.kernel.org F: include/linux/iio/imu/adis.h F: drivers/iio/imu/adis.c +ANALOG DEVICES INC ADIS16460 DRIVER +M: Dragos Bogdan +S: Supported +L: linux-iio@vger.kernel.org +W: http://ez.analog.com/community/linux-device-drivers +F: drivers/iio/imu/adis16460.c +F: Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml + ANALOG DEVICES INC ADP5061 DRIVER M: Stefan Popa L: linux-pm@vger.kernel.org @@ -1350,8 +1372,7 @@ M: Will Deacon R: Robin Murphy L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained -F: drivers/iommu/arm-smmu.c -F: drivers/iommu/arm-smmu-v3.c +F: drivers/iommu/arm-smmu* F: drivers/iommu/io-pgtable-arm.c F: drivers/iommu/io-pgtable-arm-v7s.c @@ -1421,6 +1442,14 @@ F: drivers/pinctrl/sunxi/ F: drivers/soc/sunxi/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux.git +Allwinner A10 CSI driver +M: Maxime Ripard +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +F: drivers/media/platform/sunxi/sun4i-csi/ +F: Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml +S: Maintained + ARM/Amlogic Meson SoC CLOCK FRAMEWORK M: Neil Armstrong M: Jerome Brunet @@ -1471,6 +1500,7 @@ F: arch/arm/mach-artpec F: arch/arm/boot/dts/artpec6* F: drivers/clk/axis F: drivers/crypto/axis +F: drivers/mmc/host/usdhi6rol0.c F: drivers/pinctrl/pinctrl-artpec* F: Documentation/devicetree/bindings/pinctrl/axis,artpec6-pinctrl.txt @@ -1582,8 +1612,8 @@ R: Suzuki K Poulose L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: drivers/hwtracing/coresight/* -F: Documentation/trace/coresight.txt -F: Documentation/trace/coresight-cpu-debug.txt +F: Documentation/trace/coresight.rst +F: Documentation/trace/coresight-cpu-debug.rst F: Documentation/devicetree/bindings/arm/coresight.txt F: Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt F: Documentation/ABI/testing/sysfs-bus-coresight-devices-* @@ -1626,6 +1656,21 @@ F: drivers/clocksource/timer-atlas7.c N: [^a-z]sirf X: drivers/gnss +ARM/CZ.NIC TURRIS MOX SUPPORT +M: Marek Behun +W: http://mox.turris.cz +S: Maintained +F: Documentation/ABI/testing/debugfs-moxtet +F: Documentation/ABI/testing/sysfs-bus-moxtet-devices +F: Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm +F: Documentation/devicetree/bindings/bus/moxtet.txt +F: Documentation/devicetree/bindings/firmware/cznic,turris-mox-rwtm.txt +F: Documentation/devicetree/bindings/gpio/gpio-moxtet.txt +F: include/linux/moxtet.h +F: drivers/bus/moxtet.c +F: drivers/firmware/turris-mox-rwtm.c +F: drivers/gpio/gpio-moxtet.c + ARM/EBSA110 MACHINE SUPPORT M: Russell King L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -1749,20 +1794,11 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/mach-pxa/colibri-pxa270-income.c -ARM/INTEL IOP13XX ARM ARCHITECTURE -M: Lennert Buytenhek -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Maintained - ARM/INTEL IOP32X ARM ARCHITECTURE M: Lennert Buytenhek L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained -ARM/INTEL IOP33X ARM ARCHITECTURE -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Orphan - ARM/INTEL IQ81342EX MACHINE SUPPORT M: Lennert Buytenhek L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -1921,12 +1957,6 @@ S: Maintained F: drivers/phy/mediatek/ F: Documentation/devicetree/bindings/phy/phy-mtk-* -ARM/MICREL KS8695 ARCHITECTURE -M: Greg Ungerer -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -F: arch/arm/mach-ks8695/ -S: Odd Fixes - ARM/Microchip (AT91) SoC support M: Nicolas Ferre M: Alexandre Belloni @@ -1968,6 +1998,7 @@ F: Documentation/devicetree/bindings/i2c/i2c-stu300.txt F: arch/arm/mach-nomadik/ F: arch/arm/mach-u300/ F: arch/arm/mach-ux500/ +F: drivers/soc/ux500/ F: arch/arm/boot/dts/ste-* F: drivers/clk/clk-nomadik.c F: drivers/clk/clk-u300.c @@ -2011,22 +2042,6 @@ F: drivers/*/*npcm* F: Documentation/devicetree/bindings/*/*npcm* F: Documentation/devicetree/bindings/*/*/*npcm* -ARM/NUVOTON W90X900 ARM ARCHITECTURE -M: Wan ZongShun -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -W: http://www.mcuos.com -S: Maintained -F: arch/arm/mach-w90x900/ -F: drivers/input/keyboard/w90p910_keypad.c -F: drivers/input/touchscreen/w90p910_ts.c -F: drivers/watchdog/nuc900_wdt.c -F: drivers/net/ethernet/nuvoton/w90p910_ether.c -F: drivers/mtd/nand/raw/nuc900_nand.c -F: drivers/rtc/rtc-nuc900.c -F: drivers/spi/spi-nuc900.c -F: drivers/usb/host/ehci-w90x900.c -F: drivers/video/fbdev/nuc900fb.c - ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT L: openmoko-kernel@lists.openmoko.org (subscribers-only) W: http://wiki.openmoko.org/wiki/Neo_FreeRunner @@ -2219,8 +2234,9 @@ F: drivers/*/*s3c24* F: drivers/*/*/*s3c24* F: drivers/*/*s3c64xx* F: drivers/*/*s5pv210* -F: drivers/memory/samsung/* -F: drivers/soc/samsung/* +F: drivers/memory/samsung/ +F: drivers/soc/samsung/ +F: include/linux/soc/samsung/ F: Documentation/arm/samsung/ F: Documentation/devicetree/bindings/arm/samsung/ F: Documentation/devicetree/bindings/sram/samsung-sram.txt @@ -2915,6 +2931,7 @@ BATMAN ADVANCED M: Marek Lindner M: Simon Wunderlich M: Antonio Quartulli +M: Sven Eckelmann L: b.a.t.m.a.n@lists.open-mesh.org (moderated for non-subscribers) W: https://www.open-mesh.org/ B: https://www.open-mesh.org/projects/batman-adv/issues @@ -3635,9 +3652,12 @@ S: Maintained F: Documentation/devicetree/bindings/net/can/ F: drivers/net/can/ F: include/linux/can/dev.h +F: include/linux/can/led.h +F: include/linux/can/rx-offload.h F: include/linux/can/platform/ F: include/uapi/linux/can/error.h F: include/uapi/linux/can/netlink.h +F: include/uapi/linux/can/vxcan.h CAN NETWORK LAYER M: Oliver Hartkopp @@ -3650,11 +3670,23 @@ S: Maintained F: Documentation/networking/can.rst F: net/can/ F: include/linux/can/core.h +F: include/linux/can/skb.h +F: include/net/netns/can.h F: include/uapi/linux/can.h F: include/uapi/linux/can/bcm.h F: include/uapi/linux/can/raw.h F: include/uapi/linux/can/gw.h +CAN-J1939 NETWORK LAYER +M: Robin van der Gracht +M: Oleksij Rempel +R: Pengutronix Kernel Team +L: linux-can@vger.kernel.org +S: Maintained +F: Documentation/networking/j1939.txt +F: net/can/j1939/ +F: include/uapi/linux/can/j1939.h + CAPABILITIES M: Serge Hallyn L: linux-security-module@vger.kernel.org @@ -3804,14 +3836,9 @@ F: scripts/sign-file.c F: scripts/extract-cert.c CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM: -L: linux-usb@vger.kernel.org -S: Orphan -F: Documentation/usb/wusb-design-overview.rst -F: Documentation/usb/wusb-cbaf -F: drivers/usb/host/hwa-hc.c -F: drivers/usb/host/whci/ -F: drivers/usb/wusbcore/ -F: include/linux/usb/wusb* +L: devel@driverdev.osuosl.org +S: Obsolete +F: drivers/staging/wusbcore/ CFAG12864B LCD DRIVER M: Miguel Ojeda Sandonis @@ -4103,7 +4130,7 @@ L: samba-technical@lists.samba.org (moderated for non-subscribers) W: http://linux-cifs.samba.org/ T: git git://git.samba.org/sfrench/cifs-2.6.git S: Supported -F: Documentation/filesystems/cifs/ +F: Documentation/admin-guide/cifs/ F: fs/cifs/ COMPACTPCI HOTPLUG CORE @@ -4290,6 +4317,14 @@ S: Supported F: drivers/cpuidle/cpuidle-exynos.c F: arch/arm/mach-exynos/pm.c +CPUIDLE DRIVER - ARM PSCI +M: Lorenzo Pieralisi +M: Sudeep Holla +L: linux-pm@vger.kernel.org +L: linux-arm-kernel@lists.infradead.org +S: Supported +F: drivers/cpuidle/cpuidle-psci.c + CPU IDLE TIME MANAGEMENT FRAMEWORK M: "Rafael J. Wysocki" M: Daniel Lezcano @@ -4951,7 +4986,9 @@ M: Jonathan Corbet L: linux-doc@vger.kernel.org S: Maintained F: Documentation/ +F: scripts/documentation-file-ref-check F: scripts/kernel-doc +F: scripts/sphinx-pre-install X: Documentation/ABI/ X: Documentation/firmware-guide/acpi/ X: Documentation/devicetree/ @@ -4967,6 +5004,14 @@ L: linux-doc@vger.kernel.org S: Maintained F: Documentation/translations/it_IT +DOCUMENTATION SCRIPTS +M: Mauro Carvalho Chehab +L: linux-doc@vger.kernel.org +S: Maintained +F: scripts/documentation-file-ref-check +F: scripts/sphinx-pre-install +F: Documentation/sphinx/parse-headers.pl + DONGWOON DW9714 LENS VOICE COIL DRIVER M: Sakari Ailus L: linux-media@vger.kernel.org @@ -5558,12 +5603,6 @@ T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/radio/dsbr100.c -DSCC4 DRIVER -M: Francois Romieu -L: netdev@vger.kernel.org -S: Maintained -F: drivers/net/wan/dscc4.c - DT3155 MEDIA DRIVER M: Hans Verkuil L: linux-media@vger.kernel.org @@ -5761,6 +5800,11 @@ S: Supported F: drivers/edac/aspeed_edac.c F: Documentation/devicetree/bindings/edac/aspeed-sdram-edac.txt +EDAC-BLUEFIELD +M: Shravan Kumar Ramani +S: Supported +F: drivers/edac/bluefield_edac.c + EDAC-CALXEDA M: Robert Richter L: linux-edac@vger.kernel.org @@ -5785,10 +5829,11 @@ F: drivers/edac/thunderx_edac* EDAC-CORE M: Borislav Petkov M: Mauro Carvalho Chehab +M: Tony Luck R: James Morse +R: Robert Richter L: linux-edac@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git for-next -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac.git linux_next +T: git git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras.git edac-for-next S: Supported F: Documentation/admin-guide/ras.rst F: Documentation/driver-api/edac.rst @@ -6038,6 +6083,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kristoffer/linux-hpc.git F: drivers/video/fbdev/s1d13xxxfb.c F: include/video/s1d13xxxfb.h +EROFS FILE SYSTEM +M: Gao Xiang +M: Chao Yu +L: linux-erofs@lists.ozlabs.org +S: Maintained +F: fs/erofs/ + ERRSEQ ERROR TRACKING INFRASTRUCTURE M: Jeff Layton S: Maintained @@ -6082,6 +6134,11 @@ F: include/trace/events/mdio.h F: include/uapi/linux/mdio.h F: include/uapi/linux/mii.h +EXFAT FILE SYSTEM +M: Valdis Kletnieks +S: Maintained +F: drivers/staging/exfat/ + EXT2 FILE SYSTEM M: Jan Kara L: linux-ext4@vger.kernel.org @@ -6268,12 +6325,14 @@ S: Maintained F: drivers/hwmon/f75375s.c F: include/linux/f75375s.h -FIREWIRE AUDIO DRIVERS +FIREWIRE AUDIO DRIVERS and IEC 61883-1/6 PACKET STREAMING ENGINE M: Clemens Ladisch +M: Takashi Sakamoto L: alsa-devel@alsa-project.org (moderated for non-subscribers) T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git S: Maintained F: sound/firewire/ +F: include/uapi/sound/firewire.h FIREWIRE MEDIA DRIVERS (firedtv) M: Stefan Richter @@ -6321,7 +6380,7 @@ FLEXTIMER FTM-QUADDEC DRIVER M: Patrick Havelange L: linux-iio@vger.kernel.org S: Maintained -F: Documentation/ABI/testing/sysfs-bus-counter-ftm-quadddec +F: Documentation/ABI/testing/sysfs-bus-counter-ftm-quaddec F: Documentation/devicetree/bindings/counter/ftm-quaddec.txt F: drivers/counter/ftm-quaddec.c @@ -6331,15 +6390,6 @@ S: Odd Fixes L: linux-block@vger.kernel.org F: drivers/block/floppy.c -FMC SUBSYSTEM -M: Alessandro Rubini -W: http://www.ohwr.org/projects/fmc-bus -S: Supported -F: drivers/fmc/ -F: include/linux/fmc*.h -F: include/linux/ipmi-fru.h -K: fmc_d.*register - FPGA MANAGER FRAMEWORK M: Moritz Fischer L: linux-fpga@vger.kernel.org @@ -6439,6 +6489,7 @@ M: Frank Li L: linux-arm-kernel@lists.infradead.org S: Maintained F: drivers/perf/fsl_imx8_ddr_perf.c +F: Documentation/admin-guide/perf/imx-ddr.rst F: Documentation/devicetree/bindings/perf/fsl-imx-ddr.txt FREESCALE IMX I2C DRIVER @@ -6611,6 +6662,7 @@ T: git git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git S: Supported F: fs/crypto/ F: include/linux/fscrypt*.h +F: include/uapi/linux/fscrypt.h F: Documentation/filesystems/fscrypt.rst FSI SUBSYSTEM @@ -6642,6 +6694,18 @@ S: Maintained F: fs/notify/ F: include/linux/fsnotify*.h +FSVERITY: READ-ONLY FILE-BASED AUTHENTICITY PROTECTION +M: Eric Biggers +M: Theodore Y. Ts'o +L: linux-fscrypt@vger.kernel.org +Q: https://patchwork.kernel.org/project/linux-fscrypt/list/ +T: git git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git fsverity +S: Supported +F: fs/verity/ +F: include/linux/fsverity.h +F: include/uapi/linux/fsverity.h +F: Documentation/filesystems/fsverity.rst + FUJITSU LAPTOP EXTRAS M: Jonathan Woithe L: platform-driver-x86@vger.kernel.org @@ -6732,6 +6796,13 @@ W: https://linuxtv.org S: Maintained F: drivers/media/radio/radio-gemtek* +GENERIC ARCHITECTURE TOPOLOGY +M: Sudeep Holla +L: linux-kernel@vger.kernel.org +S: Maintained +F: drivers/base/arch_topology.c +F: include/linux/arch_topology.h + GENERIC GPIO I2C DRIVER M: Wolfram Sang S: Supported @@ -6744,7 +6815,7 @@ L: linux-i2c@vger.kernel.org S: Supported F: drivers/i2c/muxes/i2c-mux-gpio.c F: include/linux/platform_data/i2c-mux-gpio.h -F: Documentation/i2c/muxes/i2c-mux-gpio +F: Documentation/i2c/muxes/i2c-mux-gpio.rst GENERIC HDLC (WAN) DRIVERS M: Krzysztof Halasa @@ -6988,6 +7059,9 @@ M: Alex Elder M: Greg Kroah-Hartman S: Maintained F: drivers/staging/greybus/ +F: drivers/greybus/ +F: include/linux/greybus.h +F: include/linux/greybus/ L: greybus-dev@lists.linaro.org (moderated for non-subscribers) GREYBUS UART PROTOCOLS DRIVERS @@ -7313,6 +7387,17 @@ S: Supported F: drivers/scsi/hisi_sas/ F: Documentation/devicetree/bindings/scsi/hisilicon-sas.txt +HISILICON QM AND ZIP Controller DRIVER +M: Zhou Wang +L: linux-crypto@vger.kernel.org +S: Maintained +F: drivers/crypto/hisilicon/qm.c +F: drivers/crypto/hisilicon/qm.h +F: drivers/crypto/hisilicon/sgl.c +F: drivers/crypto/hisilicon/sgl.h +F: drivers/crypto/hisilicon/zip/ +F: Documentation/ABI/testing/debugfs-hisi-zip + HMM - Heterogeneous Memory Management M: Jérôme Glisse L: linux-mm@kvack.org @@ -7456,6 +7541,7 @@ F: drivers/hid/hid-hyperv.c F: drivers/hv/ F: drivers/input/serio/hyperv-keyboard.c F: drivers/pci/controller/pci-hyperv.c +F: drivers/pci/controller/pci-hyperv-intf.c F: drivers/net/hyperv/ F: drivers/scsi/storvsc_drv.c F: drivers/uio/uio_hv_generic.c @@ -7493,14 +7579,14 @@ I2C CONTROLLER DRIVER FOR NVIDIA GPU M: Ajay Gupta L: linux-i2c@vger.kernel.org S: Maintained -F: Documentation/i2c/busses/i2c-nvidia-gpu +F: Documentation/i2c/busses/i2c-nvidia-gpu.rst F: drivers/i2c/busses/i2c-nvidia-gpu.c I2C MUXES M: Peter Rosin L: linux-i2c@vger.kernel.org S: Maintained -F: Documentation/i2c/i2c-topology +F: Documentation/i2c/i2c-topology.rst F: Documentation/i2c/muxes/ F: Documentation/devicetree/bindings/i2c/i2c-mux* F: Documentation/devicetree/bindings/i2c/i2c-arb* @@ -7520,8 +7606,8 @@ I2C OVER PARALLEL PORT M: Jean Delvare L: linux-i2c@vger.kernel.org S: Maintained -F: Documentation/i2c/busses/i2c-parport -F: Documentation/i2c/busses/i2c-parport-light +F: Documentation/i2c/busses/i2c-parport.rst +F: Documentation/i2c/busses/i2c-parport-light.rst F: drivers/i2c/busses/i2c-parport.c F: drivers/i2c/busses/i2c-parport-light.c @@ -7555,7 +7641,7 @@ I2C-TAOS-EVM DRIVER M: Jean Delvare L: linux-i2c@vger.kernel.org S: Maintained -F: Documentation/i2c/busses/i2c-taos-evm +F: Documentation/i2c/busses/i2c-taos-evm.rst F: drivers/i2c/busses/i2c-taos-evm.c I2C-TINY-USB DRIVER @@ -7569,19 +7655,19 @@ I2C/SMBUS CONTROLLER DRIVERS FOR PC M: Jean Delvare L: linux-i2c@vger.kernel.org S: Maintained -F: Documentation/i2c/busses/i2c-ali1535 -F: Documentation/i2c/busses/i2c-ali1563 -F: Documentation/i2c/busses/i2c-ali15x3 -F: Documentation/i2c/busses/i2c-amd756 -F: Documentation/i2c/busses/i2c-amd8111 -F: Documentation/i2c/busses/i2c-i801 -F: Documentation/i2c/busses/i2c-nforce2 -F: Documentation/i2c/busses/i2c-piix4 -F: Documentation/i2c/busses/i2c-sis5595 -F: Documentation/i2c/busses/i2c-sis630 -F: Documentation/i2c/busses/i2c-sis96x -F: Documentation/i2c/busses/i2c-via -F: Documentation/i2c/busses/i2c-viapro +F: Documentation/i2c/busses/i2c-ali1535.rst +F: Documentation/i2c/busses/i2c-ali1563.rst +F: Documentation/i2c/busses/i2c-ali15x3.rst +F: Documentation/i2c/busses/i2c-amd756.rst +F: Documentation/i2c/busses/i2c-amd8111.rst +F: Documentation/i2c/busses/i2c-i801.rst +F: Documentation/i2c/busses/i2c-nforce2.rst +F: Documentation/i2c/busses/i2c-piix4.rst +F: Documentation/i2c/busses/i2c-sis5595.rst +F: Documentation/i2c/busses/i2c-sis630.rst +F: Documentation/i2c/busses/i2c-sis96x.rst +F: Documentation/i2c/busses/i2c-via.rst +F: Documentation/i2c/busses/i2c-viapro.rst F: drivers/i2c/busses/i2c-ali1535.c F: drivers/i2c/busses/i2c-ali1563.c F: drivers/i2c/busses/i2c-ali15x3.c @@ -7610,7 +7696,7 @@ M: Seth Heasley M: Neil Horman L: linux-i2c@vger.kernel.org F: drivers/i2c/busses/i2c-ismt.c -F: Documentation/i2c/busses/i2c-ismt +F: Documentation/i2c/busses/i2c-ismt.rst I2C/SMBUS STUB DRIVER M: Jean Delvare @@ -7666,7 +7752,7 @@ F: drivers/crypto/nx/nx-aes* F: drivers/crypto/nx/nx-sha* F: drivers/crypto/nx/nx.* F: drivers/crypto/nx/nx_csbcpb.h -F: drivers/crypto/nx/nx_debugfs.h +F: drivers/crypto/nx/nx_debugfs.c IBM Power Linux RAID adapter M: Brian King @@ -8323,6 +8409,17 @@ F: drivers/platform/x86/intel_speed_select_if/ F: tools/power/x86/intel-speed-select/ F: include/uapi/linux/isst_if.h +INTEL STRATIX10 FIRMWARE DRIVERS +M: Richard Gong +L: linux-kernel@vger.kernel.org +S: Maintained +F: drivers/firmware/stratix10-rsu.c +F: drivers/firmware/stratix10-svc.c +F: include/linux/firmware/intel/stratix10-smc.h +F: include/linux/firmware/intel/stratix10-svc-client.h +F: Documentation/ABI/testing/sysfs-devices-platform-stratix10-rsu +F: Documentation/devicetree/bindings/firmware/intel,stratix10-svc.txt + INTEL TELEMETRY DRIVER M: Rajneesh Bhardwaj M: "David E. Box" @@ -8360,7 +8457,7 @@ M: linux-wimax@intel.com L: wimax@linuxwimax.org (subscribers-only) S: Supported W: http://linuxwimax.org -F: Documentation/wimax/README.i2400m +F: Documentation/admin-guide/wimax/i2400m.rst F: drivers/net/wimax/i2400m/ F: include/uapi/linux/wimax/i2400m.h @@ -8374,6 +8471,7 @@ M: Alexander Shishkin S: Supported F: Documentation/trace/intel_th.rst F: drivers/hwtracing/intel_th/ +F: include/linux/intel_th.h INTEL(R) TRUSTED EXECUTION TECHNOLOGY (TXT) M: Ning Sun @@ -8385,12 +8483,6 @@ F: Documentation/x86/intel_txt.rst F: include/linux/tboot.h F: arch/x86/kernel/tboot.c -INTEL-MID GPIO DRIVER -M: David Cohen -L: linux-gpio@vger.kernel.org -S: Maintained -F: drivers/gpio/gpio-intel-mid.c - INTERCONNECT API M: Georgi Djakov L: linux-pm@vger.kernel.org @@ -8415,12 +8507,6 @@ L: linux-mips@vger.kernel.org S: Maintained F: drivers/net/ethernet/sgi/ioc3-eth.c -IOC3 SERIAL DRIVER -M: Pat Gefre -L: linux-serial@vger.kernel.org -S: Maintained -F: drivers/tty/serial/ioc3_serial.c - IOMAP FILESYSTEM LIBRARY M: Christoph Hellwig M: Darrick J. Wong @@ -8657,7 +8743,7 @@ L: jfs-discussion@lists.sourceforge.net W: http://jfs.sourceforge.net/ T: git git://github.com/kleikamp/linux-shaggy.git S: Maintained -F: Documentation/filesystems/jfs.txt +F: Documentation/admin-guide/jfs.rst F: fs/jfs/ JME NETWORK DRIVER @@ -8933,7 +9019,7 @@ F: security/keys/encrypted-keys/ KEYS-TRUSTED M: James Bottomley -M: Jarkko Sakkinen +M: Jarkko Sakkinen M: Mimi Zohar L: linux-integrity@vger.kernel.org L: keyrings@vger.kernel.org @@ -9000,7 +9086,7 @@ F: kernel/kprobes.c KS0108 LCD CONTROLLER DRIVER M: Miguel Ojeda Sandonis S: Maintained -F: Documentation/auxdisplay/ks0108 +F: Documentation/admin-guide/auxdisplay/ks0108.rst F: drivers/auxdisplay/ks0108.c F: include/linux/ks0108.h @@ -9347,7 +9433,7 @@ F: drivers/misc/lkdtm/* LINUX KERNEL MEMORY CONSISTENCY MODEL (LKMM) M: Alan Stern -M: Andrea Parri +M: Andrea Parri M: Will Deacon M: Peter Zijlstra M: Boqun Feng @@ -9355,7 +9441,7 @@ M: Nicholas Piggin M: David Howells M: Jade Alglave M: Luc Maranget -M: "Paul E. McKenney" +M: "Paul E. McKenney" R: Akira Yokosawa R: Daniel Lustig L: linux-kernel@vger.kernel.org @@ -9589,7 +9675,7 @@ F: Documentation/networking/mac80211-injection.txt F: include/net/mac80211.h F: net/mac80211/ F: drivers/net/wireless/mac80211_hwsim.[ch] -F: Documentation/networking/mac80211_hwsim/README +F: Documentation/networking/mac80211_hwsim/mac80211_hwsim.rst MAILBOX API M: Jassi Brar @@ -10038,8 +10124,8 @@ L: linux-media@vger.kernel.org L: linux-renesas-soc@vger.kernel.org T: git git://linuxtv.org/media_tree.git S: Supported -F: Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt -F: Documentation/devicetree/bindings/media/rcar_vin.txt +F: Documentation/devicetree/bindings/media/renesas,csi2.txt +F: Documentation/devicetree/bindings/media/renesas,vin.txt F: drivers/media/platform/rcar-vin/ MEDIA DRIVERS FOR RENESAS - VSP1 @@ -10366,7 +10452,7 @@ L: linux-i2c@vger.kernel.org S: Supported F: drivers/i2c/busses/i2c-mlxcpld.c F: drivers/i2c/muxes/i2c-mux-mlxcpld.c -F: Documentation/i2c/busses/i2c-mlxcpld +F: Documentation/i2c/busses/i2c-mlxcpld.rst MELLANOX MLXCPLD LED DRIVER M: Vadim Pasternak @@ -10384,7 +10470,7 @@ F: drivers/platform/x86/mlx-platform.c MEMBARRIER SUPPORT M: Mathieu Desnoyers -M: "Paul E. McKenney" +M: "Paul E. McKenney" L: linux-kernel@vger.kernel.org S: Supported F: kernel/sched/membarrier.c @@ -10636,12 +10722,6 @@ M: Nicolas Ferre S: Supported F: drivers/power/reset/at91-sama5d2_shdwc.c -MICROCHIP SAMA5D2-COMPATIBLE PIOBU GPIO -M: Andrei Stefanescu -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -L: linux-gpio@vger.kernel.org -F: drivers/gpio/gpio-sama5d2-piobu.c - MICROCHIP SPI DRIVER M: Nicolas Ferre S: Supported @@ -10654,13 +10734,6 @@ S: Supported F: drivers/misc/atmel-ssc.c F: include/linux/atmel-ssc.h -MICROCHIP TIMER COUNTER (TC) AND CLOCKSOURCE DRIVERS -M: Nicolas Ferre -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Supported -F: drivers/misc/atmel_tclib.c -F: drivers/clocksource/tcb_clksrc.c - MICROCHIP USBA UDC DRIVER M: Cristian Birsan L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -11166,6 +11239,7 @@ S: Maintained W: https://fedorahosted.org/dropwatch/ F: net/core/drop_monitor.c F: include/uapi/linux/net_dropmon.h +F: include/net/drop_monitor.h NETWORKING DRIVERS M: "David S. Miller" @@ -11345,7 +11419,6 @@ F: include/net/nfc/ F: include/uapi/linux/nfc.h F: drivers/nfc/ F: include/linux/platform_data/nfcmrvl.h -F: include/linux/platform_data/nxp-nci.h F: Documentation/devicetree/bindings/net/nfc/ NFS, SUNRPC, AND LOCKD CLIENTS @@ -11868,6 +11941,21 @@ T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/i2c/ov5647.c +OMNIVISION OV5670 SENSOR DRIVER +M: Chiranjeevi Rapolu +M: Hyungwoo Yang +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/i2c/ov5670.c + +OMNIVISION OV5675 SENSOR DRIVER +M: Shawn Tu +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/i2c/ov5675.c + OMNIVISION OV5695 SENSOR DRIVER M: Shunqian Zheng L: linux-media@vger.kernel.org @@ -11989,7 +12077,7 @@ M: Andrew Lunn L: linux-i2c@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/i2c/i2c-ocores.txt -F: Documentation/i2c/busses/i2c-ocores +F: Documentation/i2c/busses/i2c-ocores.rst F: drivers/i2c/busses/i2c-ocores.c F: include/linux/platform_data/i2c-ocores.h @@ -12112,7 +12200,7 @@ L: netdev@vger.kernel.org S: Supported F: lib/packing.c F: include/linux/packing.h -F: Documentation/packing.txt +F: Documentation/core-api/packing.rst PADATA PARALLEL EXECUTION MECHANISM M: Steffen Klassert @@ -12593,6 +12681,14 @@ L: platform-driver-x86@vger.kernel.org S: Maintained F: drivers/platform/x86/peaq-wmi.c +PENSANDO ETHERNET DRIVERS +M: Shannon Nelson +M: Pensando Drivers +L: netdev@vger.kernel.org +S: Supported +F: Documentation/networking/device_drivers/pensando/ionic.rst +F: drivers/net/ethernet/pensando/ + PER-CPU MEMORY ALLOCATOR M: Dennis Zhou M: Tejun Heo @@ -12613,6 +12709,7 @@ PERFORMANCE EVENTS SUBSYSTEM M: Peter Zijlstra M: Ingo Molnar M: Arnaldo Carvalho de Melo +R: Mark Rutland R: Alexander Shishkin R: Jiri Olsa R: Namhyung Kim @@ -12702,6 +12799,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-gpio@vger.kernel.org S: Supported F: drivers/pinctrl/pinctrl-at91* +F: drivers/gpio/gpio-sama5d2-piobu.c PIN CONTROLLER - FREESCALE M: Dong Aisheng @@ -12798,6 +12896,12 @@ F: drivers/i2c/busses/i2c-puv3.c F: drivers/video/fbdev/fb-puv3.c F: drivers/rtc/rtc-puv3.c +PLANTOWER PMS7003 AIR POLLUTION SENSOR DRIVER +M: Tomasz Duszynski +S: Maintained +F: drivers/iio/chemical/pms7003.c +F: Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml + PMBUS HARDWARE MONITORING DRIVERS M: Guenter Roeck L: linux-hwmon@vger.kernel.org @@ -13240,7 +13344,7 @@ M: Manish Chopra M: GR-Linux-NIC-Dev@marvell.com L: netdev@vger.kernel.org S: Supported -F: drivers/net/ethernet/qlogic/qlge/ +F: drivers/staging/qlge/ QM1D1B0004 MEDIA DRIVER M: Akihiro Tsukada @@ -13308,8 +13412,8 @@ QUALCOMM CPUFREQ DRIVER MSM8996/APQ8096 M: Ilia Lin L: linux-pm@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/opp/kryo-cpufreq.txt -F: drivers/cpufreq/qcom-cpufreq-kryo.c +F: Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt +F: drivers/cpufreq/qcom-cpufreq-nvmem.c QUALCOMM EMAC GIGABIT ETHERNET DRIVER M: Timur Tabi @@ -13499,7 +13603,7 @@ S: Orphan F: drivers/net/wireless/ray* RCUTORTURE TEST FRAMEWORK -M: "Paul E. McKenney" +M: "Paul E. McKenney" M: Josh Triplett R: Steven Rostedt R: Mathieu Desnoyers @@ -13546,7 +13650,7 @@ F: arch/x86/include/asm/resctrl_sched.h F: Documentation/x86/resctrl* READ-COPY UPDATE (RCU) -M: "Paul E. McKenney" +M: "Paul E. McKenney" M: Josh Triplett R: Steven Rostedt R: Mathieu Desnoyers @@ -13704,7 +13808,7 @@ F: include/linux/reset-controller.h RESTARTABLE SEQUENCES SUPPORT M: Mathieu Desnoyers M: Peter Zijlstra -M: "Paul E. McKenney" +M: "Paul E. McKenney" M: Boqun Feng L: linux-kernel@vger.kernel.org S: Supported @@ -13767,7 +13871,8 @@ F: include/linux/hid-roccat* F: Documentation/ABI/*/sysfs-driver-hid-roccat* ROCKCHIP RASTER 2D GRAPHIC ACCELERATION UNIT DRIVER -M: Jacob chen +M: Jacob Chen +M: Ezequiel Garcia L: linux-media@vger.kernel.org S: Maintained F: drivers/media/platform/rockchip/rga/ @@ -13777,7 +13882,7 @@ HANTRO VPU CODEC DRIVER M: Ezequiel Garcia L: linux-media@vger.kernel.org S: Maintained -F: drivers/staging/media/platform/hantro/ +F: drivers/staging/media/hantro/ F: Documentation/devicetree/bindings/media/rockchip-vpu.txt ROCKER DRIVER @@ -14135,6 +14240,8 @@ M: Kamil Konieczny L: linux-crypto@vger.kernel.org L: linux-samsung-soc@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/crypto/samsung-slimsss.txt +F: Documentation/devicetree/bindings/crypto/samsung-sss.txt F: drivers/crypto/s5p-sss.c SAMSUNG S5P/EXYNOS4 SOC SERIES CAMERA SUBSYSTEM DRIVERS @@ -14155,6 +14262,8 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/snawrocki/clk.git F: drivers/clk/samsung/ F: include/dt-bindings/clock/exynos*.h F: Documentation/devicetree/bindings/clock/exynos*.txt +F: Documentation/devicetree/bindings/clock/samsung,s3c* +F: Documentation/devicetree/bindings/clock/samsung,s5p* SAMSUNG SPI DRIVERS M: Kukjin Kim @@ -14205,6 +14314,12 @@ F: drivers/watchdog/sc1200wdt.c SCHEDULER M: Ingo Molnar M: Peter Zijlstra +M: Juri Lelli (SCHED_DEADLINE) +M: Vincent Guittot (SCHED_NORMAL) +R: Dietmar Eggemann (SCHED_NORMAL) +R: Steven Rostedt (SCHED_FIFO/SCHED_RR) +R: Ben Segall (CONFIG_CFS_BANDWIDTH) +R: Mel Gorman (CONFIG_NUMA_BALANCING) L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git sched/core S: Maintained @@ -14299,7 +14414,7 @@ F: net/sctp/ SCx200 CPU SUPPORT M: Jim Cromie S: Odd Fixes -F: Documentation/i2c/busses/scx200_acb +F: Documentation/i2c/busses/scx200_acb.rst F: arch/x86/platform/scx200/ F: drivers/watchdog/scx200_wdt.c F: drivers/i2c/busses/scx200* @@ -14740,7 +14855,7 @@ F: mm/sl?b* SLEEPABLE READ-COPY UPDATE (SRCU) M: Lai Jiangshan -M: "Paul E. McKenney" +M: "Paul E. McKenney" M: Josh Triplett R: Steven Rostedt R: Mathieu Desnoyers @@ -15224,13 +15339,6 @@ M: H Hartley Sweeten S: Odd Fixes F: drivers/staging/comedi/ -STAGING - EROFS FILE SYSTEM -M: Gao Xiang -M: Chao Yu -L: linux-erofs@lists.ozlabs.org -S: Maintained -F: drivers/staging/erofs/ - STAGING - FIELDBUS SUBSYSTEM M: Sven Van Asbroeck S: Maintained @@ -15518,7 +15626,7 @@ F: Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt SYNOPSYS DESIGNWARE AXI DMAC DRIVER M: Eugeniy Paltsev S: Maintained -F: drivers/dma/dwi-axi-dmac/ +F: drivers/dma/dw-axi-dmac/ F: Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.txt SYNOPSYS DESIGNWARE DMAC DRIVER @@ -15575,6 +15683,7 @@ F: drivers/clk/clk-sc[mp]i.c F: drivers/cpufreq/sc[mp]i-cpufreq.c F: drivers/firmware/arm_scpi.c F: drivers/firmware/arm_scmi/ +F: drivers/reset/reset-scmi.c F: include/linux/sc[mp]i_protocol.h SYSTEM RESET/SHUTDOWN DRIVERS @@ -15883,6 +15992,7 @@ F: drivers/firmware/ti_sci* F: include/linux/soc/ti/ti_sci_protocol.h F: Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt F: drivers/soc/ti/ti_sci_pm_domains.c +F: include/dt-bindings/soc/ti,sci_pm_domain.h F: Documentation/devicetree/bindings/reset/ti,sci-reset.txt F: Documentation/devicetree/bindings/clock/ti,sci-clk.txt F: drivers/clk/keystone/sci-clk.c @@ -15936,7 +16046,7 @@ M: Viresh Kumar M: Javi Merino L: linux-pm@vger.kernel.org S: Supported -F: Documentation/thermal/cpu-cooling-api.rst +F: Documentation/driver-api/thermal/cpu-cooling-api.rst F: drivers/thermal/cpu_cooling.c F: include/linux/cpu_cooling.h @@ -16237,7 +16347,7 @@ F: drivers/platform/x86/topstar-laptop.c TORTURE-TEST MODULES M: Davidlohr Bueso -M: "Paul E. McKenney" +M: "Paul E. McKenney" M: Josh Triplett L: linux-kernel@vger.kernel.org S: Supported @@ -16459,7 +16569,7 @@ F: drivers/hid/hid-udraw-ps3.c UFS FILESYSTEM M: Evgeniy Dushistov S: Maintained -F: Documentation/filesystems/ufs.txt +F: Documentation/admin-guide/ufs.rst F: fs/ufs/ UHID USERSPACE HID IO DRIVER: @@ -16477,11 +16587,9 @@ F: drivers/usb/common/ulpi.c F: include/linux/ulpi/ ULTRA-WIDEBAND (UWB) SUBSYSTEM: -L: linux-usb@vger.kernel.org -S: Orphan -F: drivers/uwb/ -F: include/linux/uwb.h -F: include/linux/uwb/ +L: devel@driverdev.osuosl.org +S: Obsolete +F: drivers/staging/uwb/ UNICODE SUBSYSTEM: M: Gabriel Krisman Bertazi @@ -17214,6 +17322,7 @@ M: "VMware, Inc." L: virtualization@lists.linux-foundation.org S: Supported F: arch/x86/kernel/cpu/vmware.c +F: arch/x86/include/asm/vmware.h VMWARE PVRDMA DRIVER M: Adit Ranadive @@ -17263,6 +17372,7 @@ F: Documentation/power/regulator/ F: drivers/regulator/ F: include/dt-bindings/regulator/ F: include/linux/regulator/ +K: regulator_get_optional VRF M: David Ahern @@ -17377,7 +17487,7 @@ M: linux-wimax@intel.com L: wimax@linuxwimax.org (subscribers-only) S: Supported W: http://linuxwimax.org -F: Documentation/wimax/README.wimax +F: Documentation/admin-guide/wimax/wimax.rst F: include/linux/wimax/debug.h F: include/net/wimax.h F: include/uapi/linux/wimax.h @@ -17531,7 +17641,7 @@ M: Darren Hart M: Andy Shevchenko L: platform-driver-x86@vger.kernel.org T: git git://git.infradead.org/linux-platform-drivers-x86.git -S: Maintained +S: Odd Fixes F: drivers/platform/x86/ F: drivers/platform/olpc/ @@ -17646,7 +17756,7 @@ F: Documentation/ABI/testing/sysfs-hypervisor-xen XEN NETWORK BACKEND DRIVER M: Wei Liu -M: Paul Durrant +M: Paul Durrant L: xen-devel@lists.xenproject.org (moderated for non-subscribers) L: netdev@vger.kernel.org S: Supported @@ -17719,6 +17829,17 @@ F: Documentation/devicetree/bindings/media/xilinx/ F: drivers/media/platform/xilinx/ F: include/uapi/linux/xilinx-v4l2-controls.h +XILINX SD-FEC IP CORES +M: Derek Kiernan +M: Dragan Cvetic +S: Maintained +F: Documentation/devicetree/bindings/misc/xlnx,sd-fec.txt +F: Documentation/misc-devices/xilinx_sdfec.rst +F: drivers/misc/xilinx_sdfec.c +F: drivers/misc/Kconfig +F: drivers/misc/Makefile +F: include/uapi/misc/xilinx_sdfec.h + XILLYBUS DRIVER M: Eli Billauer L: linux-kernel@vger.kernel.org @@ -17828,14 +17949,6 @@ S: Maintained F: mm/zpool.c F: include/linux/zpool.h -ZR36067 VIDEO FOR LINUX DRIVER -L: mjpeg-users@lists.sourceforge.net -L: linux-media@vger.kernel.org -W: http://mjpeg.sourceforge.net/driver-zoran/ -T: hg https://linuxtv.org/hg/v4l-dvb -S: Odd Fixes -F: drivers/staging/media/zoran/ - ZRAM COMPRESSED RAM BLOCK DEVICE DRVIER M: Minchan Kim M: Nitin Gupta diff --git a/Makefile b/Makefile index 4f2d1676df5676f0f40f0f1baed5839b9250dd31..2b99e2fa40e6448168e1246ebf610e06434aa83d 100644 --- a/Makefile +++ b/Makefile @@ -917,6 +917,10 @@ ifeq ($(CONFIG_STRIP_ASM_SYMS),y) LDFLAGS_vmlinux += $(call ld-option, -X,) endif +ifeq ($(CONFIG_RELR),y) +LDFLAGS_vmlinux += --pack-dyn-relocs=relr +endif + # insure the checker run with the right endianness CHECKFLAGS += $(if $(CONFIG_CPU_BIG_ENDIAN),-mbig-endian,-mlittle-endian) diff --git a/arch/Kconfig b/arch/Kconfig index a7b57dd42c26698b319430ac65cd81610ba08b71..6baedab10dcaa14130b15907313200a6f04b38b4 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -18,6 +18,9 @@ config KEXEC_CORE select CRASH_CORE bool +config KEXEC_ELF + bool + config HAVE_IMA_KEXEC bool @@ -103,7 +106,7 @@ config STATIC_KEYS_SELFTEST config OPTPROBES def_bool y depends on KPROBES && HAVE_OPTPROBES - select TASKS_RCU if PREEMPT + select TASKS_RCU if PREEMPTION config KPROBES_ON_FTRACE def_bool y @@ -925,6 +928,20 @@ config LOCK_EVENT_COUNTS the chance of application behavior change because of timing differences. The counts are reported via debugfs. +# Select if the architecture has support for applying RELR relocations. +config ARCH_HAS_RELR + bool + +config RELR + bool "Use RELR relocation packing" + depends on ARCH_HAS_RELR && TOOLS_SUPPORT_RELR + default y + help + Store the kernel's dynamic relocations in the RELR relocation packing + format. Requires a compatible linker (LLD supports this feature), as + well as compatible NM and OBJCOPY utilities (llvm-nm and llvm-objcopy + are compatible). + source "kernel/gcov/Kconfig" source "scripts/gcc-plugins/Kconfig" diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 24360211534abe47a053dbc575c6e46c49e3c734..2ae7f8adcac44ddca43312d17c1efd2ffad84740 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -267,8 +267,6 @@ config PHYS_OFFSET default 0x00000000 if ARCH_EBSA110 || \ ARCH_FOOTBRIDGE || \ ARCH_INTEGRATOR || \ - ARCH_IOP13XX || \ - ARCH_KS8695 || \ ARCH_REALVIEW default 0x10000000 if ARCH_OMAP1 || ARCH_RPC default 0x20000000 if ARCH_S5PV210 @@ -381,19 +379,6 @@ config ARCH_FOOTBRIDGE Support for systems based on the DC21285 companion chip ("FootBridge"), such as the Simtec CATS and the Rebel NetWinder. -config ARCH_IOP13XX - bool "IOP13xx-based" - depends on MMU - select CPU_XSC3 - select NEED_MACH_MEMORY_H - select NEED_RET_TO_USER - select FORCE_PCI - select PLAT_IOP - select VMSPLIT_1G - select SPARSE_IRQ - help - Support for Intel's IOP13XX (XScale) family of processors. - config ARCH_IOP32X bool "IOP32x-based" depends on MMU @@ -407,18 +392,6 @@ config ARCH_IOP32X Support for Intel's 80219 and IOP32X (XScale) family of processors. -config ARCH_IOP33X - bool "IOP33x-based" - depends on MMU - select CPU_XSCALE - select GPIO_IOP - select GPIOLIB - select NEED_RET_TO_USER - select FORCE_PCI - select PLAT_IOP - help - Support for Intel's IOP33X (XScale) family of processors. - config ARCH_IXP4XX bool "IXP4xx-based" depends on MMU @@ -455,48 +428,6 @@ config ARCH_DOVE help Support for the Marvell Dove SoC 88AP510 -config ARCH_KS8695 - bool "Micrel/Kendin KS8695" - select CLKSRC_MMIO - select CPU_ARM922T - select GENERIC_CLOCKEVENTS - select GPIOLIB - select NEED_MACH_MEMORY_H - help - Support for Micrel/Kendin KS8695 "Centaur" (ARM922T) based - System-on-Chip devices. - -config ARCH_W90X900 - bool "Nuvoton W90X900 CPU" - select CLKDEV_LOOKUP - select CLKSRC_MMIO - select CPU_ARM926T - select GENERIC_CLOCKEVENTS - select GPIOLIB - help - Support for Nuvoton (Winbond logic dept.) ARM9 processor, - At present, the w90x900 has been renamed nuc900, regarding - the ARM series product line, you can login the following - link address to know more. - - - -config ARCH_LPC32XX - bool "NXP LPC32XX" - select ARM_AMBA - select CLKDEV_LOOKUP - select CLKSRC_LPC32XX - select COMMON_CLK - select CPU_ARM926T - select GENERIC_CLOCKEVENTS - select GENERIC_IRQ_MULTI_HANDLER - select GPIOLIB - select SPARSE_IRQ - select USE_OF - help - Support for the NXP LPC32XX family of processors - config ARCH_PXA bool "PXA2xx/PXA3xx-based" depends on MMU @@ -582,27 +513,6 @@ config ARCH_S3C24XX (), the IPAQ 1940 or the Samsung SMDK2410 development board (and derivatives). -config ARCH_DAVINCI - bool "TI DaVinci" - select ARCH_HAS_HOLES_MEMORYMODEL - select COMMON_CLK - select CPU_ARM926T - select GENERIC_ALLOCATOR - select GENERIC_CLOCKEVENTS - select GENERIC_IRQ_CHIP - select GENERIC_IRQ_MULTI_HANDLER - select GPIOLIB - select HAVE_IDE - select PM_GENERIC_DOMAINS if PM - select PM_GENERIC_DOMAINS_OF if PM && OF - select REGMAP_MMIO - select RESET_CONTROLLER - select SPARSE_IRQ - select USE_OF - select ZONE_DMA - help - Support for TI's DaVinci platform. - config ARCH_OMAP1 bool "TI OMAP1" depends on MMU @@ -738,17 +648,13 @@ source "arch/arm/mach-imx/Kconfig" source "arch/arm/mach-integrator/Kconfig" -source "arch/arm/mach-iop13xx/Kconfig" - source "arch/arm/mach-iop32x/Kconfig" -source "arch/arm/mach-iop33x/Kconfig" - source "arch/arm/mach-ixp4xx/Kconfig" source "arch/arm/mach-keystone/Kconfig" -source "arch/arm/mach-ks8695/Kconfig" +source "arch/arm/mach-lpc32xx/Kconfig" source "arch/arm/mach-mediatek/Kconfig" @@ -834,8 +740,6 @@ source "arch/arm/plat-versatile/Kconfig" source "arch/arm/mach-vt8500/Kconfig" -source "arch/arm/mach-w90x900/Kconfig" - source "arch/arm/mach-zx/Kconfig" source "arch/arm/mach-zynq/Kconfig" diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 85710e078afb4878738c75b8d3d7fd0814e119aa..fe7e9b583e635424ef5d2781d14faaccfab75989 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -509,13 +509,6 @@ choice Say Y here if you want the debug print routines to direct their output to UART1 serial port on KEYSTONE2 devices. - config DEBUG_KS8695_UART - bool "KS8695 Debug UART" - depends on ARCH_KS8695 - help - Say Y here if you want kernel low-level debugging support - on KS8695. - config DEBUG_LPC18XX_UART0 bool "Kernel low-level debugging via LPC18xx/43xx UART0" depends on ARCH_LPC18XX @@ -924,6 +917,20 @@ choice Say Y here if you want kernel low-level debugging support via SCIF2 on Renesas RZ/A1H (R7S72100). + config DEBUG_R7S9210_SCIF2 + bool "Kernel low-level debugging messages via SCIF2 on R7S9210" + depends on ARCH_R7S9210 + help + Say Y here if you want kernel low-level debugging support + via SCIF2 on Renesas RZ/A2M (R7S9210). + + config DEBUG_R7S9210_SCIF4 + bool "Kernel low-level debugging messages via SCIF4 on R7S9210" + depends on ARCH_R7S9210 + help + Say Y here if you want kernel low-level debugging support + via SCIF4 on Renesas RZ/A2M (R7S9210). + config DEBUG_RCAR_GEN1_SCIF0 bool "Kernel low-level debugging messages via SCIF0 on R8A7778" depends on ARCH_R8A7778 @@ -1533,10 +1540,11 @@ config DEBUG_LL_INCLUDE DEBUG_IMX6SX_UART || \ DEBUG_IMX6UL_UART || \ DEBUG_IMX7D_UART - default "debug/ks8695.S" if DEBUG_KS8695_UART default "debug/msm.S" if DEBUG_QCOM_UARTDM default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART default "debug/renesas-scif.S" if DEBUG_R7S72100_SCIF2 + default "debug/renesas-scif.S" if DEBUG_R7S9210_SCIF2 + default "debug/renesas-scif.S" if DEBUG_R7S9210_SCIF4 default "debug/renesas-scif.S" if DEBUG_RCAR_GEN1_SCIF0 default "debug/renesas-scif.S" if DEBUG_RCAR_GEN1_SCIF2 default "debug/renesas-scif.S" if DEBUG_RCAR_GEN2_SCIF0 @@ -1568,9 +1576,7 @@ config DEBUG_UART_PL01X # Compatibility options for 8250 config DEBUG_UART_8250 - def_bool ARCH_EBSA110 || \ - ARCH_IOP13XX || ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || \ - ARCH_RPC + def_bool ARCH_EBSA110 || ARCH_IOP32X || ARCH_IXP4XX || ARCH_RPC config DEBUG_UART_PHYS hex "Physical base address of debug UART" @@ -1666,7 +1672,8 @@ config DEBUG_UART_PHYS default 0xe6e60000 if DEBUG_RCAR_GEN2_SCIF0 default 0xe6e68000 if DEBUG_RCAR_GEN2_SCIF1 default 0xe6ee0000 if DEBUG_RCAR_GEN2_SCIF4 - default 0xe8008000 if DEBUG_R7S72100_SCIF2 + default 0xe8008000 if DEBUG_R7S72100_SCIF2 || DEBUG_R7S9210_SCIF2 + default 0xe8009000 if DEBUG_R7S9210_SCIF4 default 0xf0000000 if DEBUG_DIGICOLOR_UA0 default 0xf0000be0 if ARCH_EBSA110 default 0xf1012000 if DEBUG_MVEBU_UART0_ALTERNATE @@ -1683,7 +1690,6 @@ config DEBUG_UART_PHYS default 0xffc02000 if DEBUG_SOCFPGA_UART0 default 0xffc02100 if DEBUG_SOCFPGA_ARRIA10_UART1 default 0xffc03000 if DEBUG_SOCFPGA_CYCLONE5_UART1 - default 0xffd82340 if ARCH_IOP13XX default 0xffe40000 if DEBUG_RCAR_GEN1_SCIF0 default 0xffe42000 if DEBUG_RCAR_GEN1_SCIF2 default 0xfff36000 if DEBUG_HIGHBANK_UART @@ -1693,12 +1699,12 @@ config DEBUG_UART_PHYS default 0xfffe8600 if DEBUG_BCM63XX_UART default 0xffffee00 if DEBUG_AT91_SAM9263_DBGU default 0xfffff200 if DEBUG_AT91_RM9200_DBGU - default 0xfffff700 if ARCH_IOP33X depends on ARCH_EP93XX || \ DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ DEBUG_LL_UART_EFM32 || \ DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ DEBUG_QCOM_UARTDM || DEBUG_R7S72100_SCIF2 || \ + DEBUG_R7S9210_SCIF2 || DEBUG_R7S9210_SCIF4 || \ DEBUG_RCAR_GEN1_SCIF0 || DEBUG_RCAR_GEN1_SCIF2 || \ DEBUG_RCAR_GEN2_SCIF0 || DEBUG_RCAR_GEN2_SCIF1 || \ DEBUG_RCAR_GEN2_SCIF2 || DEBUG_RCAR_GEN2_SCIF4 || \ @@ -1772,10 +1778,7 @@ config DEBUG_UART_VIRT default 0xfc705000 if DEBUG_ZTE_ZX default 0xfcfe8600 if DEBUG_BCM63XX_UART default 0xfd000000 if DEBUG_SPEAR3XX || DEBUG_SPEAR13XX - default 0xfd012000 if DEBUG_MVEBU_UART0_ALTERNATE && ARCH_MV78XX0 default 0xfd883000 if DEBUG_ALPINE_UART0 - default 0xfde12000 if DEBUG_MVEBU_UART0_ALTERNATE && ARCH_DOVE - default 0xfe012000 if DEBUG_MVEBU_UART0_ALTERNATE && ARCH_ORION5X default 0xfe017000 if DEBUG_MMP_UART2 default 0xfe018000 if DEBUG_MMP_UART3 default 0xfe100000 if DEBUG_IMX23_UART || DEBUG_IMX28_UART @@ -1790,7 +1793,7 @@ config DEBUG_UART_VIRT default 0xfec02000 if DEBUG_SOCFPGA_UART0 default 0xfec02100 if DEBUG_SOCFPGA_ARRIA10_UART1 default 0xfec03000 if DEBUG_SOCFPGA_CYCLONE5_UART1 - default 0xfec12000 if (DEBUG_MVEBU_UART0 || DEBUG_MVEBU_UART0_ALTERNATE) && ARCH_MVEBU + default 0xfec12000 if DEBUG_MVEBU_UART0 || DEBUG_MVEBU_UART0_ALTERNATE default 0xfec12100 if DEBUG_MVEBU_UART1_ALTERNATE default 0xfec10000 if DEBUG_SIRFATLAS7_UART0 default 0xfec20000 if DEBUG_DAVINCI_DMx_UART0 @@ -1805,14 +1808,12 @@ config DEBUG_UART_VIRT default 0xfedc0000 if DEBUG_EP93XX default 0xfee003f8 if DEBUG_FOOTBRIDGE_COM1 default 0xfee20000 if DEBUG_NSPIRE_CLASSIC_UART || DEBUG_NSPIRE_CX_UART - default 0xfee82340 if ARCH_IOP13XX default 0xfef00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN default 0xfef00003 if ARCH_IXP4XX && CPU_BIG_ENDIAN default 0xfef36000 if DEBUG_HIGHBANK_UART default 0xfefb0000 if DEBUG_OMAP1UART1 || DEBUG_OMAP7XXUART1 default 0xfefb0800 if DEBUG_OMAP1UART2 || DEBUG_OMAP7XXUART2 default 0xfefb9800 if DEBUG_OMAP1UART3 || DEBUG_OMAP7XXUART3 - default 0xfefff700 if ARCH_IOP33X default 0xff003000 if DEBUG_U300_UART default 0xffd01000 if DEBUG_HIP01_UART default DEBUG_UART_PHYS if !MMU diff --git a/arch/arm/Makefile b/arch/arm/Makefile index c3624ca6c0bca7c036c6f7e386a9a6fc1ae72b3c..f9002e44f18fb84deae814e87bbc9b32b8aef9ca 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -155,6 +155,7 @@ textofs-$(CONFIG_ARCH_AXXIA) := 0x00308000 machine-$(CONFIG_ARCH_ACTIONS) += actions machine-$(CONFIG_ARCH_ALPINE) += alpine machine-$(CONFIG_ARCH_ARTPEC) += artpec +machine-$(CONFIG_ARCH_ASPEED) += aspeed machine-$(CONFIG_ARCH_AT91) += at91 machine-$(CONFIG_ARCH_AXXIA) += axxia machine-$(CONFIG_ARCH_BCM) += bcm @@ -173,12 +174,9 @@ machine-$(CONFIG_ARCH_GEMINI) += gemini machine-$(CONFIG_ARCH_HIGHBANK) += highbank machine-$(CONFIG_ARCH_HISI) += hisi machine-$(CONFIG_ARCH_INTEGRATOR) += integrator -machine-$(CONFIG_ARCH_IOP13XX) += iop13xx machine-$(CONFIG_ARCH_IOP32X) += iop32x -machine-$(CONFIG_ARCH_IOP33X) += iop33x machine-$(CONFIG_ARCH_IXP4XX) += ixp4xx machine-$(CONFIG_ARCH_KEYSTONE) += keystone -machine-$(CONFIG_ARCH_KS8695) += ks8695 machine-$(CONFIG_ARCH_LPC18XX) += lpc18xx machine-$(CONFIG_ARCH_LPC32XX) += lpc32xx machine-$(CONFIG_ARCH_MESON) += meson @@ -222,7 +220,6 @@ machine-$(CONFIG_ARCH_U8500) += ux500 machine-$(CONFIG_ARCH_VERSATILE) += versatile machine-$(CONFIG_ARCH_VEXPRESS) += vexpress machine-$(CONFIG_ARCH_VT8500) += vt8500 -machine-$(CONFIG_ARCH_W90X900) += w90x900 machine-$(CONFIG_ARCH_ZX) += zx machine-$(CONFIG_ARCH_ZYNQ) += zynq machine-$(CONFIG_PLAT_SPEAR) += spear @@ -233,7 +230,6 @@ plat-$(CONFIG_ARCH_EXYNOS) += samsung plat-$(CONFIG_ARCH_OMAP) += omap plat-$(CONFIG_ARCH_S3C64XX) += samsung plat-$(CONFIG_ARCH_S5PV210) += samsung -plat-$(CONFIG_PLAT_IOP) += iop plat-$(CONFIG_PLAT_ORION) += orion plat-$(CONFIG_PLAT_PXA) += pxa plat-$(CONFIG_PLAT_S3C24XX) += samsung diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 9159fa2cea90c22b8163d12e978b7fd5063dbad0..a24a6a132b07967aa72d74e500c1aa50618d069a 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -569,17 +569,22 @@ dtb-$(CONFIG_SOC_IMX6UL) += \ imx6ul-geam.dtb \ imx6ul-isiot-emmc.dtb \ imx6ul-isiot-nand.dtb \ + imx6ul-kontron-n6310-s.dtb \ + imx6ul-kontron-n6310-s-43.dtb \ imx6ul-liteboard.dtb \ imx6ul-opos6uldev.dtb \ imx6ul-pico-hobbit.dtb \ imx6ul-pico-pi.dtb \ - imx6ul-phytec-phyboard-segin-full.dtb \ + imx6ul-phytec-segin-ff-rdk-nand.dtb \ imx6ul-tx6ul-0010.dtb \ imx6ul-tx6ul-0011.dtb \ imx6ul-tx6ul-mainboard.dtb \ imx6ull-14x14-evk.dtb \ imx6ull-colibri-eval-v3.dtb \ imx6ull-colibri-wifi-eval-v3.dtb \ + imx6ull-phytec-segin-ff-rdk-nand.dtb \ + imx6ull-phytec-segin-ff-rdk-emmc.dtb \ + imx6ull-phytec-segin-lc-rdk-nand.dtb \ imx6ulz-14x14-evk.dtb dtb-$(CONFIG_SOC_IMX7D) += \ imx7d-cl-som-imx7.dtb \ @@ -594,6 +599,7 @@ dtb-$(CONFIG_SOC_IMX7D) += \ imx7d-sdb.dtb \ imx7d-sdb-reva.dtb \ imx7d-sdb-sht11.dtb \ + imx7d-zii-rmu2.dtb \ imx7d-zii-rpu2.dtb \ imx7s-colibri-eval-v3.dtb \ imx7s-mba7.dtb \ @@ -905,9 +911,9 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk3188-radxarock.dtb \ rk3228-evb.dtb \ rk3229-evb.dtb \ + rk3229-xms6.dtb \ rk3288-evb-act8846.dtb \ rk3288-evb-rk808.dtb \ - rk3288-fennec.dtb \ rk3288-firefly-beta.dtb \ rk3288-firefly.dtb \ rk3288-firefly-reload.dtb \ @@ -919,6 +925,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk3288-tinker.dtb \ rk3288-tinker-s.dtb \ rk3288-veyron-brain.dtb \ + rk3288-veyron-fievel.dtb \ rk3288-veyron-jaq.dtb \ rk3288-veyron-jerry.dtb \ rk3288-veyron-mickey.dtb \ @@ -926,6 +933,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk3288-veyron-minnie.dtb \ rk3288-veyron-pinky.dtb \ rk3288-veyron-speedy.dtb \ + rk3288-veyron-tiger.dtb \ rk3288-vyasa.dtb dtb-$(CONFIG_ARCH_S3C24XX) += \ s3c2416-smdk2416.dtb @@ -1114,6 +1122,7 @@ dtb-$(CONFIG_MACH_SUN8I) += \ sun8i-r16-nintendo-super-nes-classic.dtb \ sun8i-r16-parrot.dtb \ sun8i-r40-bananapi-m2-ultra.dtb \ + sun8i-s3-lichee-zero-plus.dtb \ sun8i-t3-cqa3t-bv3.dtb \ sun8i-v3s-licheepi-zero.dtb \ sun8i-v3s-licheepi-zero-dock.dtb \ @@ -1262,6 +1271,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ mt7623a-rfb-nand.dtb \ mt7623n-rfb-emmc.dtb \ mt7623n-bananapi-bpi-r2.dtb \ + mt7629-rfb.dtb \ mt8127-moose.dtb \ mt8135-evbp1.dtb dtb-$(CONFIG_ARCH_MILBEAUT) += milbeaut-m10v-evb.dtb @@ -1271,13 +1281,18 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ aspeed-bmc-arm-centriq2400-rep.dtb \ aspeed-bmc-arm-stardragon4800-rep2.dtb \ aspeed-bmc-facebook-cmm.dtb \ + aspeed-bmc-facebook-minipack.dtb \ aspeed-bmc-facebook-tiogapass.dtb \ + aspeed-bmc-facebook-wedge40.dtb \ + aspeed-bmc-facebook-wedge100.dtb \ aspeed-bmc-facebook-yamp.dtb \ aspeed-bmc-intel-s2600wf.dtb \ aspeed-bmc-inspur-fp5280g2.dtb \ aspeed-bmc-lenovo-hr630.dtb \ + aspeed-bmc-lenovo-hr855xg2.dtb \ aspeed-bmc-microsoft-olympus.dtb \ aspeed-bmc-opp-lanyang.dtb \ + aspeed-bmc-opp-mihawk.dtb \ aspeed-bmc-opp-palmetto.dtb \ aspeed-bmc-opp-romulus.dtb \ aspeed-bmc-opp-swift.dtb \ diff --git a/arch/arm/boot/dts/am335x-boneblue.dts b/arch/arm/boot/dts/am335x-boneblue.dts index 0257576d5d16f778b4deeb6bf848f50f9f6f5232..2f6652ef9a1579554a257b6d051165efa1493694 100644 --- a/arch/arm/boot/dts/am335x-boneblue.dts +++ b/arch/arm/boot/dts/am335x-boneblue.dts @@ -5,23 +5,13 @@ /dts-v1/; #include "am33xx.dtsi" +#include "am335x-osd335x-common.dtsi" #include / { model = "TI AM335x BeagleBone Blue"; compatible = "ti,am335x-bone-blue", "ti,am33xx"; - cpus { - cpu@0 { - cpu0-supply = <&dcdc2_reg>; - }; - }; - - memory@80000000 { - device_type = "memory"; - reg = <0x80000000 0x20000000>; /* 512 MB */ - }; - chosen { stdout-path = &uart0; }; @@ -142,13 +132,6 @@ >; }; - i2c0_pins: pinmux_i2c0_pins { - pinctrl-single,pins = < - AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLUP, MUX_MODE0) /* (C17) I2C0_SDA.I2C0_SDA */ - AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT_PULLUP, MUX_MODE0) /* (C16) I2C0_SCL.I2C0_SCL */ - >; - }; - i2c2_pins: pinmux_i2c2_pins { pinctrl-single,pins = < AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT_PULLUP, MUX_MODE3) /* (D18) uart1_ctsn.I2C2_SDA */ @@ -328,16 +311,6 @@ }; &i2c0 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c0_pins>; - - status = "okay"; - clock-frequency = <400000>; - - tps: tps@24 { - reg = <0x24>; - }; - baseboard_eeprom: baseboard_eeprom@50 { compatible = "atmel,24c256"; reg = <0x50>; @@ -381,66 +354,13 @@ /include/ "tps65217.dtsi" &tps { - interrupts = <7>; /* NMI */ - interrupt-parent = <&intc>; + /delete-property/ ti,pmic-shutdown-controller; charger { interrupts = <0>, <1>; interrupt-names = "USB", "AC"; status = "okay"; }; - - pwrbutton { - interrupts = <2>; - status = "okay"; - }; - - regulators { - dcdc1_reg: regulator@0 { - regulator-name = "vdds_dpr"; - regulator-always-on; - }; - - dcdc2_reg: regulator@1 { - /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */ - regulator-name = "vdd_mpu"; - regulator-min-microvolt = <925000>; - regulator-max-microvolt = <1351500>; - regulator-boot-on; - regulator-always-on; - }; - - dcdc3_reg: regulator@2 { - /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */ - regulator-name = "vdd_core"; - regulator-min-microvolt = <925000>; - regulator-max-microvolt = <1150000>; - regulator-boot-on; - regulator-always-on; - }; - - ldo1_reg: regulator@3 { - regulator-name = "vio,vrtc,vdds"; - regulator-always-on; - }; - - ldo2_reg: regulator@4 { - regulator-name = "vdd_3v3aux"; - regulator-always-on; - }; - - ldo3_reg: regulator@5 { - regulator-name = "vdd_1v8"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-always-on; - }; - - ldo4_reg: regulator@6 { - regulator-name = "vdd_3v3a"; - regulator-always-on; - }; - }; }; &mmc1 { @@ -502,14 +422,6 @@ }; }; -&aes { - status = "okay"; -}; - -&sham { - status = "okay"; -}; - &rtc { system-power-controller; clocks = <&clk_32768_ck>, <&clk_24mhz_clkctrl AM3_CLK_24MHZ_CLKDIV32K_CLKCTRL 0>; diff --git a/arch/arm/boot/dts/am335x-cm-t335.dts b/arch/arm/boot/dts/am335x-cm-t335.dts index ceecbfd29d2c5f4b2da7d89cd968d68b1cd7b2ee..1fe3b566ba3df719f20a752be95335a3beeccdd7 100644 --- a/arch/arm/boot/dts/am335x-cm-t335.dts +++ b/arch/arm/boot/dts/am335x-cm-t335.dts @@ -44,7 +44,6 @@ regulator-name = "vwlan_fixed"; gpio = <&gpio0 20 GPIO_ACTIVE_HIGH>; /* gpio0_20 */ enable-active-high; - regulator-boot-off; }; backlight { diff --git a/arch/arm/boot/dts/aspeed-ast2500-evb.dts b/arch/arm/boot/dts/aspeed-ast2500-evb.dts index 556ed469830cdb015dd7d3b3f7f3ad9d2883608b..c9d88c90135e6d32a8778c5cbef6ac2e8e77c0c4 100644 --- a/arch/arm/boot/dts/aspeed-ast2500-evb.dts +++ b/arch/arm/boot/dts/aspeed-ast2500-evb.dts @@ -94,6 +94,17 @@ }; }; +&sdmmc { + status = "okay"; +}; + +&sdhci0 { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sd1_default>; +}; + /* * Enable port A as device (via the virtual hub) and port B as * host by default on the eval board. This can be easily changed diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-minipack.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-minipack.dts new file mode 100644 index 0000000000000000000000000000000000000000..c05478296446e4136efdc28a6796970eb46a3077 --- /dev/null +++ b/arch/arm/boot/dts/aspeed-bmc-facebook-minipack.dts @@ -0,0 +1,429 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2018 Facebook Inc. +/dts-v1/; + +#include "aspeed-g5.dtsi" + +/ { + model = "Facebook Minipack 100 BMC"; + compatible = "facebook,minipack-bmc", "aspeed,ast2500"; + + aliases { + /* + * Override the default serial aliases to avoid breaking + * the legacy applications. + */ + serial0 = &uart5; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + + /* + * i2c switch 2-0070, pca9548, 8 child channels assigned + * with bus number 16-23. + */ + i2c16 = &imux16; + i2c17 = &imux17; + i2c18 = &imux18; + i2c19 = &imux19; + i2c20 = &imux20; + i2c21 = &imux21; + i2c22 = &imux22; + i2c23 = &imux23; + + /* + * i2c switch 8-0070, pca9548, 8 child channels assigned + * with bus number 24-31. + */ + i2c24 = &imux24; + i2c25 = &imux25; + i2c26 = &imux26; + i2c27 = &imux27; + i2c28 = &imux28; + i2c29 = &imux29; + i2c30 = &imux30; + i2c31 = &imux31; + + /* + * i2c switch 9-0070, pca9548, 8 child channels assigned + * with bus number 32-39. + */ + i2c32 = &imux32; + i2c33 = &imux33; + i2c34 = &imux34; + i2c35 = &imux35; + i2c36 = &imux36; + i2c37 = &imux37; + i2c38 = &imux38; + i2c39 = &imux39; + + /* + * i2c switch 11-0070, pca9548, 8 child channels assigned + * with bus number 40-47. + */ + i2c40 = &imux40; + i2c41 = &imux41; + i2c42 = &imux42; + i2c43 = &imux43; + i2c44 = &imux44; + i2c45 = &imux45; + i2c46 = &imux46; + i2c47 = &imux47; + }; + + chosen { + stdout-path = &uart1; + bootargs = "debug console=ttyS1,9600n8 root=/dev/ram rw"; + }; + + memory@80000000 { + reg = <0x80000000 0x20000000>; + }; +}; + +&wdt1 { + status = "okay"; + aspeed,reset-type = "system"; +}; + +&wdt2 { + status = "okay"; + aspeed,reset-type = "system"; +}; + +&fmc { + status = "okay"; + flash@0 { + status = "okay"; + m25p,fast-read; + label = "bmc"; +#include "facebook-bmc-flash-layout.dtsi" + }; +}; + +&uart1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd1_default + &pinctrl_rxd1_default + &pinctrl_ncts1_default + &pinctrl_ndsr1_default + &pinctrl_ndtr1_default + &pinctrl_nrts1_default>; +}; + +&uart2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd2_default + &pinctrl_rxd2_default>; +}; + +&uart3 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd3_default + &pinctrl_rxd3_default>; +}; + +&uart4 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd4_default + &pinctrl_rxd4_default>; +}; + +&uart5 { + status = "okay"; +}; + +&mac1 { + status = "okay"; + no-hw-checksum; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>; +}; + +&i2c0 { + status = "okay"; + bus-frequency = <400000>; + multi-master; +}; + +&i2c1 { + status = "okay"; +}; + +&i2c2 { + status = "okay"; + + i2c-switch@70 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + + imux16: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux17: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux18: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux19: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux20: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux21: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux22: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux23: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; +}; + +&i2c3 { + status = "okay"; +}; + +&i2c4 { + status = "okay"; + multi-master; +}; + +&i2c5 { + status = "okay"; +}; + +&i2c6 { + status = "okay"; +}; + +&i2c7 { + status = "okay"; +}; + +&i2c8 { + status = "okay"; + + i2c-switch@70 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + + imux24: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux25: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux26: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux27: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux28: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux29: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux30: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux31: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; +}; + +&i2c9 { + status = "okay"; + + i2c-switch@70 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + + imux32: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux33: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux34: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux35: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux36: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux37: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux38: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux39: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; +}; + +&i2c10 { + status = "okay"; +}; + +&i2c11 { + status = "okay"; + + i2c-switch@70 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + + imux40: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux41: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux42: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux43: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux44: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux45: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux46: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux47: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; +}; + +&i2c12 { + status = "okay"; +}; + +&i2c13 { + status = "okay"; +}; + +&vhub { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts index c4521eda787cd5d1a3914fd11c9e9a80dd66e89c..682f729ea25e11df55d0d51d612562691d4eb6ea 100644 --- a/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts +++ b/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts @@ -12,6 +12,27 @@ aliases { serial0 = &uart1; serial4 = &uart5; + + /* + * Hardcode the bus number of i2c switches' channels to + * avoid breaking the legacy applications. + */ + i2c16 = &imux16; + i2c17 = &imux17; + i2c18 = &imux18; + i2c19 = &imux19; + i2c20 = &imux20; + i2c21 = &imux21; + i2c22 = &imux22; + i2c23 = &imux23; + i2c24 = &imux24; + i2c25 = &imux25; + i2c26 = &imux26; + i2c27 = &imux27; + i2c28 = &imux28; + i2c29 = &imux29; + i2c30 = &imux30; + i2c31 = &imux31; }; chosen { stdout-path = &uart5; @@ -25,13 +46,9 @@ iio-hwmon { compatible = "iio-hwmon"; io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, - <&adc 4>, <&adc 5>, <&adc 6>; + <&adc 4>, <&adc 5>, <&adc 6>, <&adc 7>; }; - iio-hwmon-battery { - compatible = "iio-hwmon"; - io-channels = <&adc 7>; - }; }; &fmc { @@ -124,6 +141,215 @@ &i2c1 { status = "okay"; //X24 Riser + i2c-switch@71 { + compatible = "nxp,pca9544"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + imux16: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + ina230@45 { + compatible = "ti,ina230"; + reg = <0x45>; + }; + + tmp75@48 { + compatible = "ti,tmp75"; + reg = <0x48>; + }; + + tmp421@49 { + compatible = "ti,tmp75"; + reg = <0x49>; + }; + + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + pagesize = <32>; + }; + + i2c-switch@73 { + compatible = "nxp,pca9546"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x73>; + + imux20: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux21: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux22: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux23: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + }; + + }; + + imux17: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + ina230@45 { + compatible = "ti,ina230"; + reg = <0x45>; + }; + + tmp421@48 { + compatible = "ti,tmp75"; + reg = <0x48>; + }; + + tmp421@49 { + compatible = "ti,tmp75"; + reg = <0x49>; + }; + + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + pagesize = <32>; + }; + + i2c-switch@73 { + compatible = "nxp,pca9546"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x73>; + + imux24: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux25: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux26: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux27: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + }; + + }; + + imux18: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + ina230@45 { + compatible = "ti,ina230"; + reg = <0x45>; + }; + + tmp421@48 { + compatible = "ti,tmp75"; + reg = <0x48>; + }; + + tmp421@49 { + compatible = "ti,tmp75"; + reg = <0x49>; + }; + + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + pagesize = <32>; + }; + + i2c-switch@73 { + compatible = "nxp,pca9546"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x73>; + + imux28: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux29: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux30: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux31: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + }; + + }; + + imux19: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + i2c-switch@40 { + compatible = "ti,ina230"; + reg = <0x40>; + }; + + i2c-switch@41 { + compatible = "ti,ina230"; + reg = <0x41>; + }; + + i2c-switch@45 { + compatible = "ti,ina230"; + reg = <0x45>; + }; + + }; + + }; }; &i2c2 { @@ -144,6 +370,42 @@ &i2c5 { status = "okay"; // CPU Voltage regulators + regulator@48 { + compatible = "infineon,pxe1610"; + reg = <0x48>; + }; + regulator@4a { + compatible = "infineon,pxe1610"; + reg = <0x4a>; + }; + regulator@50 { + compatible = "infineon,pxe1610"; + reg = <0x50>; + }; + regulator@52 { + compatible = "infineon,pxe1610"; + reg = <0x52>; + }; + regulator@58 { + compatible = "infineon,pxe1610"; + reg = <0x58>; + }; + regulator@5a { + compatible = "infineon,pxe1610"; + reg = <0x5a>; + }; + regulator@68 { + compatible = "infineon,pxe1610"; + reg = <0x68>; + }; + regulator@70 { + compatible = "infineon,pxe1610"; + reg = <0x70>; + }; + regulator@72 { + compatible = "infineon,pxe1610"; + reg = <0x72>; + }; }; &i2c6 { diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-wedge100.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-wedge100.dts new file mode 100644 index 0000000000000000000000000000000000000000..b1e10f0c85c964ff37a283803693561be63399f5 --- /dev/null +++ b/arch/arm/boot/dts/aspeed-bmc-facebook-wedge100.dts @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2018 Facebook Inc. +/dts-v1/; + +#include "aspeed-g4.dtsi" + +/ { + model = "Facebook Wedge 100 BMC"; + compatible = "facebook,wedge100-bmc", "aspeed,ast2400"; + + aliases { + /* + * Override the default uart aliases to avoid breaking + * the legacy applications. + */ + serial0 = &uart5; + serial1 = &uart1; + serial2 = &uart3; + serial3 = &uart4; + }; + + chosen { + stdout-path = &uart3; + bootargs = "console=ttyS2,9600n8 root=/dev/ram rw"; + }; + + memory@40000000 { + reg = <0x40000000 0x20000000>; + }; +}; + +&wdt1 { + status = "okay"; + aspeed,reset-type = "system"; +}; + +&wdt2 { + status = "okay"; + aspeed,reset-type = "system"; +}; + +&fmc { + status = "okay"; + flash@0 { + status = "okay"; + m25p,fast-read; + label = "fmc0"; +#include "facebook-bmc-flash-layout.dtsi" + }; +}; + +&uart1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd1_default + &pinctrl_rxd1_default>; +}; + +&uart3 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd3_default + &pinctrl_rxd3_default>; +}; + +&uart4 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd4_default + &pinctrl_rxd4_default>; +}; + +&uart5 { + status = "okay"; +}; + +&mac1 { + status = "okay"; + no-hw-checksum; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>; +}; + +&i2c0 { + status = "okay"; +}; + +&i2c1 { + status = "okay"; +}; + +&i2c2 { + status = "okay"; +}; + +&i2c3 { + status = "okay"; +}; + +&i2c4 { + status = "okay"; +}; + +&i2c5 { + status = "okay"; +}; + +&i2c6 { + status = "okay"; +}; + +&i2c7 { + status = "okay"; + + i2c-switch@70 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + }; +}; + +&i2c8 { + status = "okay"; +}; + +&i2c9 { + status = "okay"; +}; + +&i2c10 { + status = "okay"; +}; + +&i2c11 { + status = "okay"; +}; + +&i2c12 { + status = "okay"; +}; + +&i2c13 { + status = "okay"; +}; + +&vhub { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-wedge40.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-wedge40.dts new file mode 100644 index 0000000000000000000000000000000000000000..aaa77a597d1a1ca341e8ddec6872b40e1ad1a2ce --- /dev/null +++ b/arch/arm/boot/dts/aspeed-bmc-facebook-wedge40.dts @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2018 Facebook Inc. +/dts-v1/; + +#include "aspeed-g4.dtsi" + +/ { + model = "Facebook Wedge 40 BMC"; + compatible = "facebook,wedge40-bmc", "aspeed,ast2400"; + + aliases { + /* + * Override the default uart aliases to avoid breaking + * the legacy applications. + */ + serial0 = &uart5; + serial1 = &uart1; + serial2 = &uart3; + serial3 = &uart4; + }; + + chosen { + stdout-path = &uart3; + bootargs = "console=ttyS2,9600n8 root=/dev/ram rw"; + }; + + memory@40000000 { + reg = <0x40000000 0x20000000>; + }; +}; + +&wdt1 { + status = "okay"; + aspeed,reset-type = "system"; +}; + +&wdt2 { + status = "disabled"; +}; + +&fmc { + status = "okay"; + flash@0 { + status = "okay"; + m25p,fast-read; + label = "fmc0"; +#include "facebook-bmc-flash-layout.dtsi" + }; +}; + +&uart1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd1_default + &pinctrl_rxd1_default>; +}; + +&uart3 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd3_default + &pinctrl_rxd3_default>; +}; + +&uart4 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd4_default + &pinctrl_rxd4_default>; +}; + +&uart5 { + status = "okay"; +}; + +&mac1 { + status = "okay"; + no-hw-checksum; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>; +}; + +&i2c0 { + status = "okay"; +}; + +&i2c1 { + status = "okay"; +}; + +&i2c2 { + status = "okay"; +}; + +&i2c3 { + status = "okay"; +}; + +&i2c4 { + status = "okay"; +}; + +&i2c5 { + status = "okay"; +}; + +&i2c6 { + status = "okay"; +}; + +&i2c7 { + status = "okay"; +}; + +&i2c8 { + status = "okay"; +}; + +&i2c9 { + status = "okay"; +}; + +&i2c10 { + status = "okay"; +}; + +&i2c11 { + status = "okay"; +}; + +&i2c12 { + status = "okay"; +}; + +&i2c13 { + status = "okay"; +}; + +&vhub { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts b/arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts index 628195b66d465ac4bda65ec7f71085668ef254fb..e9d714a46a60ba7b41e7f40d318c0ee74f27fd69 100644 --- a/arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts +++ b/arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts @@ -725,9 +725,9 @@ reg = <0x58>; }; - power-supply@5a { + power-supply@59 { compatible = "pmbus"; - reg = <0x5a>; + reg = <0x59>; }; }; diff --git a/arch/arm/boot/dts/aspeed-bmc-lenovo-hr855xg2.dts b/arch/arm/boot/dts/aspeed-bmc-lenovo-hr855xg2.dts new file mode 100644 index 0000000000000000000000000000000000000000..118eb8bbbf1b2a6e9ea0811073243a03014193f9 --- /dev/null +++ b/arch/arm/boot/dts/aspeed-bmc-lenovo-hr855xg2.dts @@ -0,0 +1,663 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Device Tree file for Lenovo Hr855xg2 platform + * + * Copyright (C) 2019-present Lenovo + */ + +/dts-v1/; + +#include "aspeed-g5.dtsi" +#include + +/ { + model = "HR855XG2 BMC"; + compatible = "lenovo,hr855xg2-bmc", "aspeed,ast2500"; + + aliases { + i2c14 = &i2c_riser1; + i2c15 = &i2c_riser2; + i2c16 = &i2c_riser3; + i2c17 = &i2c_M2; + i2c18 = &channel_0; + i2c19 = &channel_1; + i2c20 = &channel_2; + i2c21 = &channel_3; + }; + + chosen { + stdout-path = &uart5; + bootargs = "console=tty0 console=ttyS4,115200 earlyprintk"; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x20000000>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + flash_memory: region@98000000 { + no-map; + reg = <0x98000000 0x00100000>; /* 1M */ + }; + + gfx_memory: framebuffer { + size = <0x01000000>; + alignment = <0x01000000>; + compatible = "shared-dma-pool"; + reusable; + }; + }; + + leds { + compatible = "gpio-leds"; + + heartbeat { + gpios = <&gpio ASPEED_GPIO(C, 7) GPIO_ACTIVE_LOW>; + }; + + fault { + gpios = <&gpio ASPEED_GPIO(G, 3) GPIO_ACTIVE_LOW>; + }; + }; + + 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>,<&adc 13>,<&adc 14>; + }; + + iio-hwmon-battery { + compatible = "iio-hwmon"; + io-channels = <&adc 15>; + }; + +}; + +&fmc { + status = "okay"; + flash@0 { + status = "okay"; + m25p,fast-read; + label = "bmc"; + spi-max-frequency = <50000000>; +#include "openbmc-flash-layout.dtsi" + }; +}; + +&lpc_ctrl { + status = "okay"; + memory-region = <&flash_memory>; + flash = <&spi1>; +}; + +&lpc_snoop { + status = "okay"; + snoop-ports = <0x80>; +}; + +&uart1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd1_default + &pinctrl_rxd1_default>; +}; + +&uart2 { + /* Rear RS-232 connector */ + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd2_default + &pinctrl_rxd2_default + &pinctrl_nrts2_default + &pinctrl_ndtr2_default + &pinctrl_ndsr2_default + &pinctrl_ncts2_default + &pinctrl_ndcd2_default + &pinctrl_nri2_default>; +}; + +&uart3 { + status = "okay"; +}; + +&uart5 { + status = "okay"; +}; + +&ibt { + status = "okay"; +}; + +&mac0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rmii1_default>; + use-ncsi; +}; + +&mac1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>; +}; + +&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 + &pinctrl_adc13_default + &pinctrl_adc14_default + &pinctrl_adc15_default>; +}; + +&i2c0 { + status = "okay"; + + i2c-switch@70 { + compatible = "nxp,pca9545"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + + i2c_riser1: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c_riser2: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + i2c_riser3: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c_M2: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; +}; + +&i2c1 { + status = "okay"; + bus-frequency = <90000>; + HotSwap@10 { + compatible = "adm1272"; + reg = <0x10>; + }; + + VR@45 { + compatible = "pmbus"; + reg = <0x45>; + }; +}; + +&i2c2 { + status = "okay"; +}; + +&i2c3 { + status = "okay"; + i2c-switch@70 { + compatible = "nxp,pca9546"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + + channel_0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + channel_1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + channel_2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + channel_3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; +}; + +&i2c4 { + status = "okay"; +}; + +&i2c5 { + status = "okay"; +}; + +&i2c6 { + status = "okay"; + /* temp1 */ + tmp75@49 { + compatible = "national,lm75"; + reg = <0x49>; + }; + + /* temp2 */ + tmp75@4d { + compatible = "national,lm75"; + reg = <0x4d>; + }; + + eeprom@54 { + compatible = "atmel,24c256"; + reg = <0x54>; + pagesize = <16>; + }; +}; + +&i2c7 { + status = "okay"; +}; + +&i2c8 { + status = "okay"; +}; + +&i2c9 { + status = "okay"; +}; + +&i2c10 { + status = "okay"; +}; + +&i2c11 { + status = "okay"; +}; + +&i2c13 { + status = "okay"; +}; + +&ehci1 { + status = "okay"; +}; + +&uhci { + status = "okay"; +}; + +&gfx { + status = "okay"; + memory-region = <&gfx_memory>; +}; + +&pwm_tacho { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0_default + &pinctrl_pwm1_default + &pinctrl_pwm2_default + &pinctrl_pwm3_default + &pinctrl_pwm4_default + &pinctrl_pwm5_default + &pinctrl_pwm6_default + &pinctrl_pwm7_default>; + + fan@0 { + reg = <0x00>; + aspeed,fan-tach-ch = /bits/ 8 <0x00>; + }; + + fan@1 { + reg = <0x00>; + aspeed,fan-tach-ch = /bits/ 8 <0x01>; + }; + + fan@2 { + reg = <0x01>; + aspeed,fan-tach-ch = /bits/ 8 <0x02>; + }; + + fan@3 { + reg = <0x01>; + aspeed,fan-tach-ch = /bits/ 8 <0x03>; + }; + + fan@4 { + reg = <0x02>; + aspeed,fan-tach-ch = /bits/ 8 <0x04>; + }; + + fan@5 { + reg = <0x02>; + aspeed,fan-tach-ch = /bits/ 8 <0x05>; + }; + + fan@6 { + reg = <0x03>; + aspeed,fan-tach-ch = /bits/ 8 <0x06>; + }; + + fan@7 { + reg = <0x03>; + aspeed,fan-tach-ch = /bits/ 8 <0x07>; + }; + + fan@8 { + reg = <0x04>; + aspeed,fan-tach-ch = /bits/ 8 <0x08>; + }; + + fan@9 { + reg = <0x04>; + aspeed,fan-tach-ch = /bits/ 8 <0x09>; + }; + + fan@10 { + reg = <0x05>; + aspeed,fan-tach-ch = /bits/ 8 <0x0a>; + }; + + fan@11 { + reg = <0x05>; + aspeed,fan-tach-ch = /bits/ 8 <0x0b>; + }; + + fan@12 { + reg = <0x06>; + aspeed,fan-tach-ch = /bits/ 8 <0x0c>; + }; + + fan@13 { + reg = <0x06>; + aspeed,fan-tach-ch = /bits/ 8 <0x0d>; + }; + + fan@14 { + reg = <0x07>; + aspeed,fan-tach-ch = /bits/ 8 <0x0e>; + }; + + fan@15 { + reg = <0x07>; + aspeed,fan-tach-ch = /bits/ 8 <0x0f>; + }; + + fan@16 { + reg = <0x07>; + aspeed,fan-tach-ch = /bits/ 8 <0x0f>; + }; +}; + +&gpio { + + pin_gpio_a1 { + gpio-hog; + gpios = ; + output-high; + line-name = "BMC_EMMC_RST_N"; + }; + + pin_gpio_a3 { + gpio-hog; + gpios = ; + output-high; + line-name = "PCH_PWROK_BMC_FPGA"; + }; + + pin_gpio_b5 { + gpio-hog; + gpios = ; + output-high; + line-name = "IRQ_BMC_PCH_SMI_LPC_N"; + }; + + pin_gpio_b7 { + gpio-hog; + gpios = ; + output-low; + line-name = "CPU_SM_WP"; + }; + + pin_gpio_e0 { + gpio-hog; + gpios = ; + input; + line-name = "PDB_PSU_SEL"; + }; + + pin_gpio_e2 { + gpio-hog; + gpios = ; + output-high; + line-name = "LOCATOR_LED_N"; + }; + + pin_gpio_e5 { + gpio-hog; + gpios = ; + output-high; + line-name = "FM_BMC_DBP_PRESENT_R1_N"; + }; + + pin_gpio_e6 { + gpio-hog; + gpios = ; + output-high; + line-name = "BMC_ME_SECURITY_OVERRIDE_N"; + }; + + pin_gpio_f0 { + gpio-hog; + gpios = ; + output-high; + line-name = "IRQ_BMC_PCH_NMI_R"; + }; + + pin_gpio_f1 { + gpio-hog; + gpios = ; + input; + line-name = "CPU2_PROCDIS_BMC_N"; + }; + + pin_gpio_f2 { + gpio-hog; + gpios = ; + output-high; + line-name = "RM_THROTTLE_EN_N"; + }; + + pin_gpio_f3 { + gpio-hog; + gpios = ; + output-low; + line-name = "FM_PMBUS_ALERT_B_EN"; + }; + + pin_gpio_f4 { + gpio-hog; + gpios = ; + output-high; + line-name = "BMC_FORCE_NM_THROTTLE_N"; + }; + + pin_gpio_f6 { + gpio-hog; + gpios = ; + output-high; + line-name = "FM_BMC_CPU_PWR_DEBUG_N"; + }; + + pin_gpio_g7 { + gpio-hog; + gpios = ; + output-high; + line-name = "BMC_PCIE_I2C_MUX_RST_N"; + }; + + pin_gpio_h6 { + gpio-hog; + gpios = ; + output-high; + line-name = "FM_BMC_DBP_PRESENT_R2_N"; + }; + + pin_gpio_i3 { + gpio-hog; + gpios = ; + output-high; + line-name = "SPI_BMC_BIOS_WP_N"; + }; + + pin_gpio_j1 { + gpio-hog; + gpios = ; + output-high; + line-name = "BMC_USB_SEL"; + }; + + pin_gpio_j2 { + gpio-hog; + gpios = ; + output-high; + line-name = "PDB_SMB_RST_N"; + }; + + pin_gpio_j3 { + gpio-hog; + gpios = ; + output-high; + line-name = "SPI_BMC_BIOS_HOLD_N"; + }; + + pin_gpio_l0 { + gpio-hog; + gpios = ; + output-high; + line-name = "PDB_FAN_TACH_SEL"; + }; + + pin_gpio_l1 { + gpio-hog; + gpios = ; + output-high; + line-name = "SYS_RESET_BMC_FPGA_N"; + }; + + pin_gpio_l4 { + gpio-hog; + gpios = ; + output-high; + line-name = "FM_EFUSE_FAN_G1_EN"; + }; + + pin_gpio_l5 { + gpio-hog; + gpios = ; + output-high; + line-name = "FM_EFUSE_FAN_G2_EN"; + }; + + pin_gpio_r6 { + gpio-hog; + gpios = ; + input; + line-name = "CPU3_PROCDIS_BMC_N"; + }; + + pin_gpio_r7 { + gpio-hog; + gpios = ; + input; + line-name = "CPU4_PROCDIS_BMC_N"; + }; + + pin_gpio_s1 { + gpio-hog; + gpios = ; + output-low; + line-name = "DBP_SYSPWROK_BMC"; + }; + + pin_gpio_s2 { + gpio-hog; + gpios = ; + output-high; + line-name = "PCH_RST_RSMRST_N"; + }; + + pin_gpio_s6 { + gpio-hog; + gpios = ; + output-high; + line-name = "BMC_HW_STRAP_5"; + }; + + pin_gpio_z3 { + gpio-hog; + gpios = ; + output-high; + line-name = "FM_BMC_PCH_SCI_LPC_N"; + }; + + pin_gpio_aa0 { + gpio-hog; + gpios = ; + output-low; + line-name = "FW_PSU_ALERT_EN_N"; + }; + + pin_gpio_aa4 { + gpio-hog; + gpios = ; + output-high; + line-name = "DBP_CPU_PREQ_N"; + }; + + pin_gpio_ab3 { + gpio-hog; + gpios = ; + output-low; + line-name = "BMC_WDTRST"; + }; + + pin_gpio_ac6 { + gpio-hog; + gpios = ; + output-high; + line-name = "ESPI_BMC_ALERT_N"; + }; + +}; diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts b/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts new file mode 100644 index 0000000000000000000000000000000000000000..e55cc454b17f511e492bc49767a8ca3de5d43441 --- /dev/null +++ b/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts @@ -0,0 +1,918 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; +#include "aspeed-g5.dtsi" +#include +#include + +/ { + model = "Mihawk BMC"; + compatible = "ibm,mihawk-bmc", "aspeed,ast2500"; + + + chosen { + stdout-path = &uart5; + bootargs = "console=ttyS4,115200 earlyprintk"; + }; + + memory@80000000 { + reg = <0x80000000 0x20000000>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + flash_memory: region@98000000 { + no-map; + reg = <0x98000000 0x04000000>; /* 64M */ + }; + + gfx_memory: framebuffer { + size = <0x01000000>; + alignment = <0x01000000>; + compatible = "shared-dma-pool"; + reusable; + }; + + video_engine_memory: jpegbuffer { + size = <0x02000000>; + alignment = <0x01000000>; + compatible = "shared-dma-pool"; + reusable; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + air-water { + label = "air-water"; + gpios = <&gpio ASPEED_GPIO(F, 6) GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + checkstop { + label = "checkstop"; + gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + ps0-presence { + label = "ps0-presence"; + gpios = <&gpio ASPEED_GPIO(Z, 2) GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + ps1-presence { + label = "ps1-presence"; + gpios = <&gpio ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>; + linux,code = ; + }; + id-button { + label = "id-button"; + gpios = <&gpio ASPEED_GPIO(F, 1) GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + poll-interval = <1000>; + + fan0-presence { + label = "fan0-presence"; + gpios = <&pca9552 9 GPIO_ACTIVE_LOW>; + linux,code = <9>; + }; + + fan1-presence { + label = "fan1-presence"; + gpios = <&pca9552 10 GPIO_ACTIVE_LOW>; + linux,code = <10>; + }; + + fan2-presence { + label = "fan2-presence"; + gpios = <&pca9552 11 GPIO_ACTIVE_LOW>; + linux,code = <11>; + }; + + fan3-presence { + label = "fan3-presence"; + gpios = <&pca9552 12 GPIO_ACTIVE_LOW>; + linux,code = <12>; + }; + + fan4-presence { + label = "fan4-presence"; + gpios = <&pca9552 13 GPIO_ACTIVE_LOW>; + linux,code = <13>; + }; + + fan5-presence { + label = "fan5-presence"; + gpios = <&pca9552 14 GPIO_ACTIVE_LOW>; + linux,code = <14>; + }; + }; + + leds { + compatible = "gpio-leds"; + + fault { + retain-state-shutdown; + default-state = "keep"; + gpios = <&gpio ASPEED_GPIO(AA, 0) GPIO_ACTIVE_LOW>; + }; + + power { + retain-state-shutdown; + default-state = "keep"; + gpios = <&gpio ASPEED_GPIO(AA, 1) GPIO_ACTIVE_LOW>; + }; + + rear-id { + retain-state-shutdown; + default-state = "keep"; + gpios = <&gpio ASPEED_GPIO(AA, 2) GPIO_ACTIVE_LOW>; + }; + + rear-g { + retain-state-shutdown; + default-state = "keep"; + gpios = <&gpio ASPEED_GPIO(AA, 4) GPIO_ACTIVE_LOW>; + }; + + rear-ok { + retain-state-shutdown; + default-state = "keep"; + gpios = <&gpio ASPEED_GPIO(Y, 0) GPIO_ACTIVE_LOW>; + }; + + fan0 { + retain-state-shutdown; + default-state = "keep"; + gpios = <&pca9552 0 GPIO_ACTIVE_LOW>; + }; + + fan1 { + retain-state-shutdown; + default-state = "keep"; + gpios = <&pca9552 1 GPIO_ACTIVE_LOW>; + }; + + fan2 { + retain-state-shutdown; + default-state = "keep"; + gpios = <&pca9552 2 GPIO_ACTIVE_LOW>; + }; + + fan3 { + retain-state-shutdown; + default-state = "keep"; + gpios = <&pca9552 3 GPIO_ACTIVE_LOW>; + }; + + fan4 { + retain-state-shutdown; + default-state = "keep"; + gpios = <&pca9552 4 GPIO_ACTIVE_LOW>; + }; + + fan5 { + retain-state-shutdown; + default-state = "keep"; + gpios = <&pca9552 5 GPIO_ACTIVE_LOW>; + }; + }; + + fsi: gpio-fsi { + compatible = "fsi-master-gpio", "fsi-master"; + #address-cells = <2>; + #size-cells = <0>; + no-gpio-delays; + + clock-gpios = <&gpio ASPEED_GPIO(E, 6) GPIO_ACTIVE_HIGH>; + data-gpios = <&gpio ASPEED_GPIO(E, 7) GPIO_ACTIVE_HIGH>; + mux-gpios = <&gpio ASPEED_GPIO(E, 5) GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>; + trans-gpios = <&gpio ASPEED_GPIO(R, 2) GPIO_ACTIVE_HIGH>; + }; + iio-hwmon-12v { + compatible = "iio-hwmon"; + io-channels = <&adc 0>; + }; + + iio-hwmon-5v { + compatible = "iio-hwmon"; + io-channels = <&adc 1>; + }; + + iio-hwmon-3v { + compatible = "iio-hwmon"; + io-channels = <&adc 2>; + }; + + iio-hwmon-vdd0 { + compatible = "iio-hwmon"; + io-channels = <&adc 3>; + }; + + iio-hwmon-vdd1 { + compatible = "iio-hwmon"; + io-channels = <&adc 4>; + }; + + iio-hwmon-vcs0 { + compatible = "iio-hwmon"; + io-channels = <&adc 5>; + }; + + iio-hwmon-vcs1 { + compatible = "iio-hwmon"; + io-channels = <&adc 6>; + }; + + iio-hwmon-vdn0 { + compatible = "iio-hwmon"; + io-channels = <&adc 7>; + }; + + iio-hwmon-vdn1 { + compatible = "iio-hwmon"; + io-channels = <&adc 8>; + }; + + iio-hwmon-vio0 { + compatible = "iio-hwmon"; + io-channels = <&adc 9>; + }; + + iio-hwmon-vio1 { + compatible = "iio-hwmon"; + io-channels = <&adc 10>; + }; + + iio-hwmon-vddra { + compatible = "iio-hwmon"; + io-channels = <&adc 11>; + }; + + iio-hwmon-battery { + compatible = "iio-hwmon"; + io-channels = <&adc 12>; + }; + + iio-hwmon-vddrb { + compatible = "iio-hwmon"; + io-channels = <&adc 13>; + }; + + iio-hwmon-vddrc { + compatible = "iio-hwmon"; + io-channels = <&adc 14>; + }; + + iio-hwmon-vddrd { + compatible = "iio-hwmon"; + io-channels = <&adc 15>; + }; +}; + +&pwm_tacho { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default + &pinctrl_pwm2_default &pinctrl_pwm3_default + &pinctrl_pwm4_default &pinctrl_pwm5_default>; + + fan@0 { + reg = <0x00>; + aspeed,fan-tach-ch = /bits/ 8 <0x00>; + }; + + fan@1 { + reg = <0x01>; + aspeed,fan-tach-ch = /bits/ 8 <0x01>; + }; + + fan@2 { + reg = <0x02>; + aspeed,fan-tach-ch = /bits/ 8 <0x02>; + }; + + fan@3 { + reg = <0x03>; + aspeed,fan-tach-ch = /bits/ 8 <0x03>; + }; + + fan@4 { + reg = <0x04>; + aspeed,fan-tach-ch = /bits/ 8 <0x04>; + }; + + fan@5 { + reg = <0x05>; + aspeed,fan-tach-ch = /bits/ 8 <0x05>; + }; + + fan@6 { + reg = <0x00>; + aspeed,fan-tach-ch = /bits/ 8 <0x06>; + }; + + fan@7 { + reg = <0x01>; + aspeed,fan-tach-ch = /bits/ 8 <0x07>; + }; + + fan@8 { + reg = <0x02>; + aspeed,fan-tach-ch = /bits/ 8 <0x08>; + }; + + fan@9 { + reg = <0x03>; + aspeed,fan-tach-ch = /bits/ 8 <0x09>; + }; + + fan@10 { + reg = <0x04>; + aspeed,fan-tach-ch = /bits/ 8 <0x0a>; + }; + + fan@11 { + reg = <0x05>; + aspeed,fan-tach-ch = /bits/ 8 <0x0b>; + }; +}; + +&fmc { + status = "okay"; + flash@0 { + status = "okay"; + label = "bmc"; + m25p,fast-read; + spi-max-frequency = <50000000>; + partitions { + #address-cells = < 1 >; + #size-cells = < 1 >; + compatible = "fixed-partitions"; + u-boot@0 { + reg = < 0 0x60000 >; + label = "u-boot"; + }; + u-boot-env@60000 { + reg = < 0x60000 0x20000 >; + label = "u-boot-env"; + }; + obmc-ubi@80000 { + reg = < 0x80000 0x1F80000 >; + label = "obmc-ubi"; + }; + }; + }; + flash@1 { + status = "okay"; + label = "alt-bmc"; + m25p,fast-read; + spi-max-frequency = <50000000>; + partitions { + #address-cells = < 1 >; + #size-cells = < 1 >; + compatible = "fixed-partitions"; + u-boot@0 { + reg = < 0 0x60000 >; + label = "alt-u-boot"; + }; + u-boot-env@60000 { + reg = < 0x60000 0x20000 >; + label = "alt-u-boot-env"; + }; + obmc-ubi@80000 { + reg = < 0x80000 0x1F80000 >; + label = "alt-obmc-ubi"; + }; + }; + }; +}; + +&spi1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi1_default>; + + flash@0 { + status = "okay"; + label = "pnor"; + m25p,fast-read; + spi-max-frequency = <100000000>; + }; +}; + +&lpc_ctrl { + status = "okay"; + memory-region = <&flash_memory>; + flash = <&spi1>; +}; + +&uart1 { + /* Rear RS-232 connector */ + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd1_default + &pinctrl_rxd1_default + &pinctrl_nrts1_default + &pinctrl_ndtr1_default + &pinctrl_ndsr1_default + &pinctrl_ncts1_default + &pinctrl_ndcd1_default + &pinctrl_nri1_default>; +}; + +&uart2 { + /* APSS */ + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd2_default &pinctrl_rxd2_default>; +}; + +&uart5 { + status = "okay"; +}; + +&mac0 { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rmii1_default>; + use-ncsi; +}; + +&mac1 { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>; +}; + +&i2c0 { + status = "disabled"; +}; + +&i2c1 { + status = "disabled"; +}; + +&i2c2 { + status = "okay"; + + /* SAMTEC P0 */ + /* SAMTEC P1 */ + +}; + +&i2c3 { + status = "okay"; + + /* APSS */ + /* CPLD */ + + /* PCA9516 (repeater) -> + * CLK Buffer 9FGS9092 + * CLK Buffer 9DBL0651BKILFT + * CLK Buffer 9DBL0651BKILFT + * Power Supply 0 + * Power Supply 1 + * PCA 9552 LED + */ + + power-supply@58 { + compatible = "ibm,cffps1"; + reg = <0x58>; + }; + + power-supply@5b { + compatible = "ibm,cffps1"; + reg = <0x5b>; + }; + + pca9552: pca9552@60 { + compatible = "nxp,pca9552"; + reg = <0x60>; + #address-cells = <1>; + #size-cells = <0>; + gpio-controller; + #gpio-cells = <2>; + + gpio@0 { + reg = <0>; + type = ; + }; + gpio@1 { + reg = <1>; + type = ; + }; + gpio@2 { + reg = <2>; + type = ; + }; + gpio@3 { + reg = <3>; + type = ; + }; + gpio@4 { + reg = <4>; + type = ; + }; + gpio@5 { + reg = <5>; + type = ; + }; + gpio@6 { + reg = <6>; + type = ; + }; + gpio@7 { + reg = <7>; + type = ; + }; + gpio@8 { + reg = <8>; + type = ; + }; + gpio@9 { + reg = <9>; + type = ; + }; + gpio@10 { + reg = <10>; + type = ; + }; + gpio@11 { + reg = <11>; + type = ; + }; + gpio@12 { + reg = <12>; + type = ; + }; + gpio@13 { + reg = <13>; + type = ; + }; + gpio@14 { + reg = <14>; + type = ; + }; + gpio@15 { + reg = <15>; + type = ; + }; + + }; + +}; + +&i2c4 { + status = "okay"; + + /* CP0 VDD & VCS : IR35221 */ + /* CP0 VDN : IR35221 */ + /* CP0 VIO : IR38064 */ + /* CP0 VDDR : PXM1330 */ + + ir35221@70 { + compatible = "infineon,ir35221"; + reg = <0x70>; + }; + + ir35221@72 { + compatible = "infineon,ir35221"; + reg = <0x72>; + }; + +}; + +&i2c5 { + status = "okay"; + + /* CP0 VDD & VCS : IR35221 */ + /* CP0 VDN : IR35221 */ + /* CP0 VIO : IR38064 */ + /* CP0 VDDR : PXM1330 */ + + ir35221@70 { + compatible = "infineon,ir35221"; + reg = <0x70>; + }; + + ir35221@72 { + compatible = "infineon,ir35221"; + reg = <0x72>; + }; + +}; + +&i2c6 { + status = "okay"; + + /* pca9548 -> NVMe1 to 8 */ + + pca9548@70 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + }; + +}; + +&i2c7 { + status = "okay"; + + /* pca9548 -> NVMe9 to 16 */ + + pca9548@70 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + }; + +}; + +&i2c8 { + status = "okay"; + + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; +}; + +&i2c9 { + status = "okay"; + + /* pca9545 Riser -> + * PCIe x8 Slot3 + * PCIe x16 slot4 + * PCIe x8 slot5 + * I2C BMC RISER PCA9554 + * BMC SCL/SDA PCA9554 + * PCA9554 + */ + + /* pca9545 -> + * PCIe x16 Slot1 + * PCIe x8 slot2 + * PEX8748 + */ + + pca9545riser@70 { + compatible = "nxp,pca9545"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + + i2c-mux-idle-disconnect; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pca9545@71 { + compatible = "nxp,pca9545"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + i2c-mux-idle-disconnect; + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + +&i2c10 { + status = "okay"; + + /* pca9545 Riser -> + * PCIe x8 Slot8 + * PCIe x16 slot9 + * PCIe x8 slot10 + * I2C BMC RISER PCA9554 + * BMC SCL/SDA PCA9554 + * PCA9554 + */ + + /* pca9545 -> + * PCIe x16 Slot1 + * PCIe x8 slot2 + * PEX8748 + */ + + pca9545riser@70 { + compatible = "nxp,pca9545"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + + i2c-mux-idle-disconnect; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pca9545@71 { + compatible = "nxp,pca9545"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + i2c-mux-idle-disconnect; + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + +&i2c11 { + status = "okay"; + + /* TPM */ + /* RTC RX8900CE */ + /* FPGA for power sequence */ + /* TMP275A */ + /* TMP275A */ + /* EMC1462 */ + + tpm@57 { + compatible = "infineon,slb9645tt"; + reg = <0x57>; + }; + + rtc@32 { + compatible = "epson,rx8900"; + reg = <0x32>; + }; + + tmp275@48 { + compatible = "ti,tmp275"; + reg = <0x48>; + }; + + tmp275@49 { + compatible = "ti,tmp275"; + reg = <0x49>; + }; + + /* chip emc1462 use emc1403 driver */ + emc1403@4c { + compatible = "smsc,emc1403"; + reg = <0x4c>; + }; + +}; + +&i2c12 { + status = "okay"; + + /* pca9545 -> + * SAS BP1 + * SAS BP2 + * NVMe BP + * M.2 riser + */ + + pca9545@70 { + compatible = "nxp,pca9545"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + + interrupt-controller; + #interrupt-cells = <2>; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + }; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + }; + + i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + }; + + i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + tmp275@48 { + compatible = "ti,tmp275"; + reg = <0x48>; + }; + }; + + }; + +}; + +&i2c13 { + status = "okay"; + + /* pca9548 -> + * NVMe BP + * NVMe HDD17 to 24 + */ + + pca9548@70 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + }; +}; + +&vuart { + status = "okay"; +}; + +&gfx { + status = "okay"; + memory-region = <&gfx_memory>; +}; + +&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 + &pinctrl_adc13_default + &pinctrl_adc14_default + &pinctrl_adc15_default>; +}; + +&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 { + aspeed,alt-boot; +}; + +&ibt { + status = "okay"; +}; + +&vhub { + status = "okay"; +}; + +&video { + status = "okay"; + memory-region = <&video_engine_memory>; +}; + +#include "ibm-power9-dual.dtsi" + diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-swift.dts b/arch/arm/boot/dts/aspeed-bmc-opp-swift.dts index caac895c60b42dbedd5e6143e1af2824b77cf6b0..f67fef1ac5e12f49dc3a9d4196b9182dff7136e9 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-swift.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-swift.dts @@ -207,8 +207,8 @@ #size-cells = <0>; no-gpio-delays; - clock-gpios = <&gpio ASPEED_GPIO(AA, 0) GPIO_ACTIVE_HIGH>; - data-gpios = <&gpio ASPEED_GPIO(E, 0) GPIO_ACTIVE_HIGH>; + clock-gpios = <&gpio ASPEED_GPIO(P, 1) GPIO_ACTIVE_HIGH>; + data-gpios = <&gpio ASPEED_GPIO(P, 2) GPIO_ACTIVE_HIGH>; mux-gpios = <&gpio ASPEED_GPIO(P, 4) GPIO_ACTIVE_HIGH>; enable-gpios = <&gpio ASPEED_GPIO(P, 0) GPIO_ACTIVE_HIGH>; trans-gpios = <&gpio ASPEED_GPIO(P, 3) GPIO_ACTIVE_HIGH>; @@ -494,7 +494,7 @@ }; power-supply@68 { - compatible = "ibm,cffps1"; + compatible = "ibm,cffps2"; reg = <0x68>; }; @@ -504,7 +504,7 @@ }; power-supply@69 { - compatible = "ibm,cffps1"; + compatible = "ibm,cffps2"; reg = <0x69>; }; @@ -963,4 +963,15 @@ status = "okay"; }; +&sdmmc { + status = "okay"; +}; + +&sdhci1 { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sd2_default>; +}; + #include "ibm-power9-dual.dtsi" diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts b/arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts index 0b9e29c3212ebfd763965d414725d417a410827c..a27c88d23056c45da25641beb612ef0829b3dff3 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts @@ -81,6 +81,12 @@ label = "bmc"; #include "openbmc-flash-layout.dtsi" }; + + flash@1 { + status = "okay"; + m25p,fast-read; + label = "alt"; + }; }; &spi { @@ -222,3 +228,7 @@ &vuart { status = "okay"; }; + +&wdt2 { + aspeed,alt-boot; +}; diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi index dd4b0b15afcfdc114305931bed0a9757595acf68..dffb595d30e4042bf6349cab117f5cfc832203d0 100644 --- a/arch/arm/boot/dts/aspeed-g4.dtsi +++ b/arch/arm/boot/dts/aspeed-g4.dtsi @@ -67,6 +67,26 @@ compatible = "jedec,spi-nor"; status = "disabled"; }; + flash@1 { + reg = < 1 >; + compatible = "jedec,spi-nor"; + status = "disabled"; + }; + flash@2 { + reg = < 2 >; + compatible = "jedec,spi-nor"; + status = "disabled"; + }; + flash@3 { + reg = < 3 >; + compatible = "jedec,spi-nor"; + status = "disabled"; + }; + flash@4 { + reg = < 4 >; + compatible = "jedec,spi-nor"; + status = "disabled"; + }; }; spi: spi@1e630000 { @@ -192,6 +212,34 @@ reg = <0x1e720000 0x8000>; // 32K }; + sdmmc: sd-controller@1e740000 { + compatible = "aspeed,ast2400-sd-controller"; + reg = <0x1e740000 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1e740000 0x10000>; + clocks = <&syscon ASPEED_CLK_GATE_SDCLK>; + status = "disabled"; + + sdhci0: sdhci@100 { + compatible = "aspeed,ast2400-sdhci"; + reg = <0x100 0x100>; + interrupts = <26>; + sdhci,auto-cmd12; + clocks = <&syscon ASPEED_CLK_SDIO>; + status = "disabled"; + }; + + sdhci1: sdhci@200 { + compatible = "aspeed,ast2400-sdhci"; + reg = <0x200 0x100>; + interrupts = <26>; + sdhci,auto-cmd12; + clocks = <&syscon ASPEED_CLK_SDIO>; + status = "disabled"; + }; + }; + gpio: gpio@1e780000 { #gpio-cells = <2>; gpio-controller; diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi index 5b1ca265c2ce487c57aa6171ade5ff413f1ef8b4..e8feb8b66a2f71587270c9cb1a911679029c834b 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi @@ -267,13 +267,41 @@ reg = <0x1e720000 0x9000>; // 36K }; + sdmmc: sd-controller@1e740000 { + compatible = "aspeed,ast2500-sd-controller"; + reg = <0x1e740000 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1e740000 0x10000>; + clocks = <&syscon ASPEED_CLK_GATE_SDCLK>; + status = "disabled"; + + sdhci0: sdhci@100 { + compatible = "aspeed,ast2500-sdhci"; + reg = <0x100 0x100>; + interrupts = <26>; + sdhci,auto-cmd12; + clocks = <&syscon ASPEED_CLK_SDIO>; + status = "disabled"; + }; + + sdhci1: sdhci@200 { + compatible = "aspeed,ast2500-sdhci"; + reg = <0x200 0x100>; + interrupts = <26>; + sdhci,auto-cmd12; + clocks = <&syscon ASPEED_CLK_SDIO>; + status = "disabled"; + }; + }; + gpio: gpio@1e780000 { #gpio-cells = <2>; gpio-controller; compatible = "aspeed,ast2500-gpio"; reg = <0x1e780000 0x1000>; interrupts = <20>; - gpio-ranges = <&pinctrl 0 0 220>; + gpio-ranges = <&pinctrl 0 0 232>; clocks = <&syscon ASPEED_CLK_APB>; interrupt-controller; #interrupt-cells = <2>; @@ -1346,6 +1374,11 @@ groups = "SDA2"; }; + pinctrl_sgpm_default: sgpm_default { + function = "SGPM"; + groups = "SGPM"; + }; + pinctrl_sgps1_default: sgps1_default { function = "SGPS1"; groups = "SGPS1"; diff --git a/arch/arm/boot/dts/at91-ariag25.dts b/arch/arm/boot/dts/at91-ariag25.dts index 0d695c762e54219a314b8e44702b2d23d2556c00..dbfefef2869de13eb62c95ba738daa94c537e753 100644 --- a/arch/arm/boot/dts/at91-ariag25.dts +++ b/arch/arm/boot/dts/at91-ariag25.dts @@ -14,11 +14,6 @@ "atmel,at91sam9x5", "atmel,at91sam9"; aliases { - serial0 = &dbgu; - serial1 = &usart0; - serial2 = &usart1; - serial3 = &usart2; - serial4 = &usart3; serial5 = &uart0; serial6 = &uart1; }; @@ -42,132 +37,6 @@ }; }; - ahb { - apb { - mmc0: mmc@f0008000 { - /* N.B. Aria has no SD card detect (CD), assumed present */ - - pinctrl-0 = < - &pinctrl_mmc0_slot0_clk_cmd_dat0 - &pinctrl_mmc0_slot0_dat1_3>; - status = "okay"; - slot@0 { - reg = <0>; - bus-width = <4>; - }; - }; - - tcb0: timer@f8008000 { - timer@0 { - compatible = "atmel,tcb-timer"; - reg = <0>; - }; - - timer@1 { - compatible = "atmel,tcb-timer"; - reg = <1>; - }; - }; - - i2c0: i2c@f8010000 { - status = "okay"; - }; - - i2c1: i2c@f8014000 { - status = "okay"; - }; - - /* TWD2+TCLK2 hidden behind ethernet, so no i2c2 */ - - usart0: serial@f801c000 { - pinctrl-0 = <&pinctrl_usart0 - &pinctrl_usart0_rts - &pinctrl_usart0_cts>; - status = "okay"; - }; - - usart1: serial@f8020000 { - pinctrl-0 = <&pinctrl_usart1 - /* &pinctrl_usart1_rts */ - /* &pinctrl_usart1_cts */ - >; - status = "okay"; - }; - - usart2: serial@f8024000 { - /* cannot activate RTS2+CTS2, clash with - * ethernet on PB0 and PB1 */ - pinctrl-0 = <&pinctrl_usart2>; - status = "okay"; - }; - - usart3: serial@f8028000 { - compatible = "atmel,at91sam9260-usart"; - reg = <0xf8028000 0x200>; - interrupts = <8 4 5>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usart3 - /* &pinctrl_usart3_rts */ - /* &pinctrl_usart3_cts */ - >; - status = "okay"; - }; - - macb0: ethernet@f802c000 { - phy-mode = "rmii"; - /* - * following can be overwritten by bootloader: - * for example u-boot 'ftd set' command - */ - local-mac-address = [00 00 00 00 00 00]; - status = "okay"; - }; - - /* - * UART0/1 pins are marked as GPIO on - * Aria documentation. - * Change to "okay" if you need additional serial ports - */ - uart0: serial@f8040000 { - status = "disabled"; - }; - - uart1: serial@f8044000 { - status = "disabled"; - }; - - adc0: adc@f804c000 { - status = "okay"; - atmel,adc-channels-used = <0xf>; - }; - - dbgu: serial@fffff200 { - status = "okay"; - }; - - pinctrl@fffff400 { - w1_0 { - pinctrl_w1_0: w1_0-0 { - atmel,pins = <0 21 0x0 0x1>; /* PA21 PIO, pull-up */ - }; - }; - }; - - rtc@fffffeb0 { - status = "okay"; - }; - }; - - usb0: ohci@600000 { - status = "okay"; - num-ports = <3>; - }; - - usb1: ehci@700000 { - status = "okay"; - }; - }; - leds { compatible = "gpio-leds"; @@ -187,3 +56,127 @@ pinctrl-0 = <&pinctrl_w1_0>; }; }; + +&adc0 { + status = "okay"; + atmel,adc-channels-used = <0xf>; +}; + +&dbgu { + status = "okay"; +}; + +&i2c0 { + status = "okay"; +}; + +&i2c1 { + status = "okay"; +}; + +/* TWD2+TCLK2 hidden behind ethernet, so no i2c2 */ + +&macb0 { + phy-mode = "rmii"; + /* + * following can be overwritten by bootloader: + * for example u-boot 'ftd set' command + */ + local-mac-address = [00 00 00 00 00 00]; + status = "okay"; +}; + + +&mmc0 { + /* N.B. Aria has no SD card detect (CD), assumed present */ + + pinctrl-0 = < + &pinctrl_mmc0_slot0_clk_cmd_dat0 + &pinctrl_mmc0_slot0_dat1_3>; + status = "okay"; + + slot@0 { + reg = <0>; + bus-width = <4>; + }; +}; + +&pinctrl { + w1_0 { + pinctrl_w1_0: w1_0-0 { + atmel,pins = <0 21 0x0 0x1>; /* PA21 PIO, pull-up */ + }; + }; +}; + +&rtc { + status = "okay"; +}; + +&tcb0 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; +}; + +/* + * UART0/1 pins are marked as GPIO on + * Aria documentation. + * Change to "okay" if you need additional serial ports + */ +&uart0 { + status = "disabled"; +}; + +&uart1 { + status = "disabled"; +}; + +&usart0 { + pinctrl-0 = <&pinctrl_usart0 + &pinctrl_usart0_rts + &pinctrl_usart0_cts>; + status = "okay"; +}; + +&usart1 { + pinctrl-0 = <&pinctrl_usart1 + /* &pinctrl_usart1_rts */ + /* &pinctrl_usart1_cts */ + >; + status = "okay"; +}; + +&usart2 { + /* cannot activate RTS2+CTS2, clash with + * ethernet on PB0 and PB1 */ + pinctrl-0 = <&pinctrl_usart2>; + status = "okay"; +}; + +&usart3 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xf8028000 0x200>; + interrupts = <8 4 5>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usart3 + /* &pinctrl_usart3_rts */ + /* &pinctrl_usart3_cts */ + >; + status = "okay"; +}; + +&usb0 { + status = "okay"; + num-ports = <3>; +}; + +&usb1 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/at91-ariettag25.dts b/arch/arm/boot/dts/at91-ariettag25.dts index 7a34c4dc05d24fde72cca6f394f5f040e1c30576..0267e72c074a89819b48ae081771fbe753d8b396 100644 --- a/arch/arm/boot/dts/at91-ariettag25.dts +++ b/arch/arm/boot/dts/at91-ariettag25.dts @@ -6,14 +6,11 @@ */ /dts-v1/; #include "at91sam9g25.dtsi" + / { model = "Acme Systems Arietta G25"; compatible = "acme,ariettag25", "atmel,at91sam9x5", "atmel,at91sam9"; - aliases { - serial0 = &dbgu; - }; - chosen { stdout-path = "serial0:115200n8"; }; @@ -32,57 +29,9 @@ }; }; - ahb { - apb { - mmc0: mmc@f0008000 { - pinctrl-0 = < - &pinctrl_mmc0_slot0_clk_cmd_dat0 - &pinctrl_mmc0_slot0_dat1_3>; - status = "okay"; - - slot@0 { - reg = <0>; - bus-width = <4>; - }; - }; - - tcb0: timer@f8008000 { - timer@0 { - compatible = "atmel,tcb-timer"; - reg = <0>; - }; - - timer@1 { - compatible = "atmel,tcb-timer"; - reg = <1>; - }; - }; - - usb2: gadget@f803c000 { - status = "okay"; - }; - - dbgu: serial@fffff200 { - status = "okay"; - }; - - rtc@fffffeb0 { - status = "okay"; - }; - }; - - usb0: ohci@600000 { - status = "okay"; - num-ports = <3>; - }; - - usb1: ehci@700000 { - status = "okay"; - }; - }; - leds { compatible = "gpio-leds"; + arietta_led { label = "arietta_led"; gpios = <&pioB 8 GPIO_ACTIVE_HIGH>; /* PB8 */ @@ -90,3 +39,48 @@ }; }; }; + +&dbgu { + status = "okay"; +}; + +&mmc0 { + pinctrl-0 = < + &pinctrl_mmc0_slot0_clk_cmd_dat0 + &pinctrl_mmc0_slot0_dat1_3>; + status = "okay"; + + slot@0 { + reg = <0>; + bus-width = <4>; + }; +}; + +&rtc { + status = "okay"; +}; + +&tcb0 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; +}; + +&usb0 { + num-ports = <3>; + status = "okay"; +}; + +&usb1 { + status = "okay"; +}; + +&usb2 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/at91-cosino.dtsi b/arch/arm/boot/dts/at91-cosino.dtsi index 47721c9a2e42e1d4f0ab4be43f125113a3094636..feebd54f670efc9344116d52eaa8f15b322bc06c 100644 --- a/arch/arm/boot/dts/at91-cosino.dtsi +++ b/arch/arm/boot/dts/at91-cosino.dtsi @@ -33,122 +33,119 @@ clock-frequency = <12000000>; }; }; +}; - ahb { - apb { - tcb0: timer@f8008000 { - timer@0 { - compatible = "atmel,tcb-timer"; - reg = <0>; - }; +&adc0 { + atmel,adc-ts-wires = <4>; + atmel,adc-ts-pressure-threshold = <10000>; + status = "okay"; +}; + +&dbgu { + status = "okay"; +}; - timer@1 { - compatible = "atmel,tcb-timer"; - reg = <1>; +&ebi { + pinctrl-0 = <&pinctrl_ebi_addr_nand + &pinctrl_ebi_data_0_7>; + pinctrl-names = "default"; + status = "okay"; + + nand-controller { + pinctrl-0 = <&pinctrl_nand_oe_we + &pinctrl_nand_cs + &pinctrl_nand_rb>; + pinctrl-names = "default"; + status = "okay"; + + nand@3 { + reg = <0x3 0x0 0x800000>; + rb-gpios = <&pioD 5 GPIO_ACTIVE_HIGH>; + cs-gpios = <&pioD 4 GPIO_ACTIVE_HIGH>; + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + nand-ecc-strength = <4>; + nand-ecc-step-size = <512>; + nand-on-flash-bbt; + label = "atmel_nand"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x40000>; }; - }; - mmc0: mmc@f0008000 { - pinctrl-0 = < - &pinctrl_board_mmc0 - &pinctrl_mmc0_slot0_clk_cmd_dat0 - &pinctrl_mmc0_slot0_dat1_3>; - status = "okay"; - slot@0 { - reg = <0>; - bus-width = <4>; - cd-gpios = <&pioD 15 GPIO_ACTIVE_HIGH>; + uboot@40000 { + label = "u-boot"; + reg = <0x40000 0x80000>; }; - }; - dbgu: serial@fffff200 { - status = "okay"; - }; + ubootenv@c0000 { + label = "U-Boot Env"; + reg = <0xc0000 0x140000>; + }; - usart0: serial@f801c000 { - status = "okay"; - }; + kernel@200000 { + label = "kernel"; + reg = <0x200000 0x600000>; + }; - i2c0: i2c@f8010000 { - status = "okay"; + rootfs@800000 { + label = "rootfs"; + reg = <0x800000 0x0f800000>; + }; }; + }; + }; +}; - adc0: adc@f804c000 { - atmel,adc-ts-wires = <4>; - atmel,adc-ts-pressure-threshold = <10000>; - status = "okay"; - }; +&i2c0 { + status = "okay"; +}; - pinctrl@fffff400 { - mmc0 { - pinctrl_board_mmc0: mmc0-board { - atmel,pins = - ; /* PD15 gpio CD pin pull up and deglitch */ - }; - }; - }; +&mmc0 { + pinctrl-0 = < + &pinctrl_board_mmc0 + &pinctrl_mmc0_slot0_clk_cmd_dat0 + &pinctrl_mmc0_slot0_dat1_3>; + status = "okay"; + + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioD 15 GPIO_ACTIVE_HIGH>; + }; +}; - watchdog@fffffe40 { - status = "okay"; - }; +&pinctrl { + mmc0 { + pinctrl_board_mmc0: mmc0-board { + atmel,pins = + ; /* PD15 gpio CD pin pull up and deglitch */ }; + }; +}; - ebi: ebi@10000000 { - pinctrl-0 = <&pinctrl_ebi_addr_nand - &pinctrl_ebi_data_0_7>; - pinctrl-names = "default"; - status = "okay"; - - nand_controller: nand-controller { - status = "okay"; - pinctrl-0 = <&pinctrl_nand_oe_we - &pinctrl_nand_cs - &pinctrl_nand_rb>; - pinctrl-names = "default"; - - nand@3 { - reg = <0x3 0x0 0x800000>; - rb-gpios = <&pioD 5 GPIO_ACTIVE_HIGH>; - cs-gpios = <&pioD 4 GPIO_ACTIVE_HIGH>; - nand-bus-width = <8>; - nand-ecc-mode = "hw"; - nand-ecc-strength = <4>; - nand-ecc-step-size = <512>; - nand-on-flash-bbt; - label = "atmel_nand"; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - at91bootstrap@0 { - label = "at91bootstrap"; - reg = <0x0 0x40000>; - }; - - uboot@40000 { - label = "u-boot"; - reg = <0x40000 0x80000>; - }; - - ubootenv@c0000 { - label = "U-Boot Env"; - reg = <0xc0000 0x140000>; - }; - - kernel@200000 { - label = "kernel"; - reg = <0x200000 0x600000>; - }; - - rootfs@800000 { - label = "rootfs"; - reg = <0x800000 0x0f800000>; - }; - }; - }; - }; - }; +&tcb0 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; }; }; + +&usart0 { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/at91-cosino_mega2560.dts b/arch/arm/boot/dts/at91-cosino_mega2560.dts index 8fde06adf7cb3139b67ddfc00cfc8bd82ddaf517..73e88d1ba4edcbb199fd6a7fa69a11c45b7b70f3 100644 --- a/arch/arm/boot/dts/at91-cosino_mega2560.dts +++ b/arch/arm/boot/dts/at91-cosino_mega2560.dts @@ -17,61 +17,58 @@ / { model = "HCE Cosino Mega 2560"; compatible = "hce,cosino_mega2560", "atmel,at91sam9x5", "atmel,at91sam9"; +}; + +&adc0 { + atmel,adc-ts-wires = <4>; + atmel,adc-ts-pressure-threshold = <10000>; + status = "okay"; +}; - ahb { - apb { - macb0: ethernet@f802c000 { - phy-mode = "rmii"; - status = "okay"; - }; +&macb0 { + phy-mode = "rmii"; + status = "okay"; +}; - adc0: adc@f804c000 { - atmel,adc-ts-wires = <4>; - atmel,adc-ts-pressure-threshold = <10000>; - status = "okay"; - }; +&mmc1 { + pinctrl-0 = < + &pinctrl_mmc1_slot0_clk_cmd_dat0 + &pinctrl_mmc1_slot0_dat1_3>; + status = "okay"; - rtc@fffffeb0 { - status = "okay"; - }; + slot@0 { + reg = <0>; + bus-width = <4>; + non-removable; + }; +}; - usart1: serial@f8020000 { - status = "okay"; - }; +&rtc { + status = "okay"; +}; - usart2: serial@f8024000 { - status = "okay"; - }; +&usart1 { + status = "okay"; +}; - usb2: gadget@f803c000 { - atmel,vbus-gpio = <&pioB 16 GPIO_ACTIVE_HIGH>; - status = "okay"; - }; +&usart2 { + status = "okay"; +}; - mmc1: mmc@f000c000 { - pinctrl-0 = < - &pinctrl_mmc1_slot0_clk_cmd_dat0 - &pinctrl_mmc1_slot0_dat1_3>; - status = "okay"; - slot@0 { - reg = <0>; - bus-width = <4>; - non-removable; - }; - }; - }; +&usb0 { + num-ports = <3>; + atmel,vbus-gpio = <0 /* &pioD 18 GPIO_ACTIVE_LOW */ + &pioD 19 GPIO_ACTIVE_LOW + &pioD 20 GPIO_ACTIVE_LOW + >; + status = "okay"; +}; - usb0: ohci@600000 { - status = "okay"; - num-ports = <3>; - atmel,vbus-gpio = <0 /* &pioD 18 GPIO_ACTIVE_LOW */ - &pioD 19 GPIO_ACTIVE_LOW - &pioD 20 GPIO_ACTIVE_LOW - >; - }; +&usb1 { + status = "okay"; +}; - usb1: ehci@700000 { - status = "okay"; - }; - }; +&usb2 { + atmel,vbus-gpio = <&pioB 16 GPIO_ACTIVE_HIGH>; + status = "okay"; }; diff --git a/arch/arm/boot/dts/at91-kizboxmini.dts b/arch/arm/boot/dts/at91-kizboxmini.dts index 0620dcdf4dfbb67835332ba8d59e27e4124c1aaa..cb22f5fb055f196191dd8ea291d85fd7631e8fa0 100644 --- a/arch/arm/boot/dts/at91-kizboxmini.dts +++ b/arch/arm/boot/dts/at91-kizboxmini.dts @@ -32,96 +32,6 @@ }; ahb { - apb { - tcb0: timer@f8008000 { - timer@0 { - compatible = "atmel,tcb-timer"; - reg = <0>; - }; - - timer@1 { - compatible = "atmel,tcb-timer"; - reg = <1>; - }; - }; - - usart0: serial@f801c000 { - status = "okay"; - }; - - macb0: ethernet@f802c000 { - phy-mode = "rmii"; - status = "okay"; - }; - - pwm0: pwm@f8034000 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_pwm0_pwm0_1 - &pinctrl_pwm0_pwm1_1>; - status = "okay"; - }; - - dbgu: serial@fffff200 { - status = "okay"; - }; - - watchdog@fffffe40 { - status = "okay"; - }; - }; - - usb0: ohci@600000 { - num-ports = <1>; - status = "okay"; - }; - - usb1: ehci@700000 { - status = "okay"; - }; - - ebi: ebi@10000000 { - pinctrl-0 = <&pinctrl_ebi_addr_nand - &pinctrl_ebi_data_0_7>; - pinctrl-names = "default"; - status = "okay"; - - nand_controller: nand-controller { - status = "okay"; - pinctrl-0 = <&pinctrl_nand_oe_we - &pinctrl_nand_cs - &pinctrl_nand_rb>; - pinctrl-names = "default"; - - nand@3 { - reg = <0x3 0x0 0x800000>; - rb-gpios = <&pioD 5 GPIO_ACTIVE_HIGH>; - cs-gpios = <&pioD 4 GPIO_ACTIVE_HIGH>; - nand-bus-width = <8>; - nand-ecc-mode = "hw"; - nand-ecc-strength = <4>; - nand-ecc-step-size = <512>; - nand-on-flash-bbt; - label = "atmel_nand"; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - bootstrap@0 { - label = "bootstrap"; - reg = <0x0 0x20000>; - }; - - ubi@20000 { - label = "ubi"; - reg = <0x20000 0x7fe0000>; - }; - }; - }; - }; - }; - nand0: nand@40000000 { nand-bus-width = <8>; nand-ecc-mode = "hw"; @@ -130,7 +40,6 @@ atmel,pmecc-sector-size = <512>; nand-on-flash-bbt; status = "okay"; - }; }; @@ -172,3 +81,91 @@ }; }; }; + +&dbgu { + status = "okay"; +}; + +&ebi { + pinctrl-0 = <&pinctrl_ebi_addr_nand + &pinctrl_ebi_data_0_7>; + pinctrl-names = "default"; + status = "okay"; + + nand-controller { + pinctrl-0 = <&pinctrl_nand_oe_we + &pinctrl_nand_cs + &pinctrl_nand_rb>; + pinctrl-names = "default"; + status = "okay"; + + nand@3 { + reg = <0x3 0x0 0x800000>; + rb-gpios = <&pioD 5 GPIO_ACTIVE_HIGH>; + cs-gpios = <&pioD 4 GPIO_ACTIVE_HIGH>; + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + nand-ecc-strength = <4>; + nand-ecc-step-size = <512>; + nand-on-flash-bbt; + label = "atmel_nand"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + bootstrap@0 { + label = "bootstrap"; + reg = <0x0 0x20000>; + }; + + ubi@20000 { + label = "ubi"; + reg = <0x20000 0x7fe0000>; + }; + }; + }; + }; +}; + +&macb0 { + phy-mode = "rmii"; + status = "okay"; +}; + +&pwm0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0_pwm0_1 + &pinctrl_pwm0_pwm1_1>; + status = "okay"; +}; + +&tcb0 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; +}; + +&usart0 { + status = "okay"; +}; + +&usb0 { + num-ports = <1>; + status = "okay"; +}; + +&usb1 { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/at91sam9261ek.dts b/arch/arm/boot/dts/at91sam9261ek.dts index 7debdeabcf2f7f7f71396bf7714260bff1aba4fb..c4ef74fea97c222b3b60412a3fbbeb240d1d4a05 100644 --- a/arch/arm/boot/dts/at91sam9261ek.dts +++ b/arch/arm/boot/dts/at91sam9261ek.dts @@ -40,7 +40,7 @@ atmel,power-control-gpio = <&pioA 12 GPIO_ACTIVE_LOW>; status = "okay"; - display0: display { + display0: panel { bits-per-pixel = <16>; atmel,lcdcon-backlight; atmel,dmacon = <0x1>; diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts index 45e0c6e88cab706cf873b8dffae0ad0ebbecc695..62d218542a480336ffde7a6150a3b05309124e8f 100644 --- a/arch/arm/boot/dts/at91sam9263ek.dts +++ b/arch/arm/boot/dts/at91sam9263ek.dts @@ -110,7 +110,7 @@ display = <&display0>; status = "okay"; - display0: display { + display0: panel { bits-per-pixel = <16>; atmel,lcdcon-backlight; atmel,dmacon = <0x1>; diff --git a/arch/arm/boot/dts/at91sam9g15.dtsi b/arch/arm/boot/dts/at91sam9g15.dtsi index d77c69ad7f027881186a75cd903514e6197b7246..dde88276fe52321ae95b701718e7577c3f94cc9b 100644 --- a/arch/arm/boot/dts/at91sam9g15.dtsi +++ b/arch/arm/boot/dts/at91sam9g15.dtsi @@ -11,22 +11,18 @@ / { model = "Atmel AT91SAM9G15 SoC"; compatible = "atmel,at91sam9g15", "atmel,at91sam9x5"; +}; - ahb { - apb { - pinctrl@fffff400 { - atmel,mux-mask = < - /* A B C */ - 0xffffffff 0xffe0399f 0x00000000 /* pioA */ - 0x00040000 0x00047e3f 0x00000000 /* pioB */ - 0xfdffffff 0x00000000 0xb83fffff /* pioC */ - 0x003fffff 0x003f8000 0x00000000 /* pioD */ - >; - }; +&pinctrl { + atmel,mux-mask = < + /* A B C */ + 0xffffffff 0xffe0399f 0x00000000 /* pioA */ + 0x00040000 0x00047e3f 0x00000000 /* pioB */ + 0xfdffffff 0x00000000 0xb83fffff /* pioC */ + 0x003fffff 0x003f8000 0x00000000 /* pioD */ + >; +}; - pmc: pmc@fffffc00 { - compatible = "atmel,at91sam9g15-pmc", "atmel,at91sam9x5-pmc", "syscon"; - }; - }; - }; +&pmc { + compatible = "atmel,at91sam9g15-pmc", "atmel,at91sam9x5-pmc", "syscon"; }; diff --git a/arch/arm/boot/dts/at91sam9g15ek.dts b/arch/arm/boot/dts/at91sam9g15ek.dts index 97100d29840078517e0e157f81f8625efefbac7c..889a5097eb2d453c8d003dbfae1c7aabeaadad8a 100644 --- a/arch/arm/boot/dts/at91sam9g15ek.dts +++ b/arch/arm/boot/dts/at91sam9g15ek.dts @@ -14,14 +14,6 @@ model = "Atmel AT91SAM9G15-EK"; compatible = "atmel,at91sam9g15ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9"; - ahb { - apb { - hlcdc: hlcdc@f8038000 { - status = "okay"; - }; - }; - }; - backlight: backlight { status = "okay"; }; @@ -38,3 +30,7 @@ status = "okay"; }; }; + +&hlcdc { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts index a02c6c79ce524b79de719755eb33c391808ddea6..61b0bdb615dc60a45dedb385f537131647b0cd9e 100644 --- a/arch/arm/boot/dts/at91sam9g25ek.dts +++ b/arch/arm/boot/dts/at91sam9g25ek.dts @@ -12,57 +12,54 @@ / { model = "Atmel AT91SAM9G25-EK"; compatible = "atmel,at91sam9g25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9"; +}; - ahb { - apb { - spi0: spi@f0000000 { - status = "disabled"; - }; - - mmc1: mmc@f000c000 { - status = "disabled"; - }; - - i2c0: i2c@f8010000 { - ov2640: camera@30 { - compatible = "ovti,ov2640"; - reg = <0x30>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_pck0_as_isi_mck &pinctrl_sensor_power &pinctrl_sensor_reset>; - resetb-gpios = <&pioA 7 GPIO_ACTIVE_LOW>; - pwdn-gpios = <&pioA 13 GPIO_ACTIVE_HIGH>; - clocks = <&pmc PMC_TYPE_SYSTEM 8>; - clock-names = "xvclk"; - assigned-clocks = <&pmc PMC_TYPE_SYSTEM 8>; - assigned-clock-rates = <25000000>; - status = "okay"; +&i2c0 { + camera@30 { + compatible = "ovti,ov2640"; + reg = <0x30>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pck0_as_isi_mck &pinctrl_sensor_power &pinctrl_sensor_reset>; + resetb-gpios = <&pioA 7 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&pioA 13 GPIO_ACTIVE_HIGH>; + clocks = <&pmc PMC_TYPE_SYSTEM 8>; + clock-names = "xvclk"; + assigned-clocks = <&pmc PMC_TYPE_SYSTEM 8>; + assigned-clock-rates = <25000000>; + status = "okay"; - port { - ov2640_0: endpoint { - remote-endpoint = <&isi_0>; - bus-width = <8>; - }; - }; - }; + port { + ov2640_0: endpoint { + remote-endpoint = <&isi_0>; + bus-width = <8>; }; + }; + }; +}; - macb0: ethernet@f802c000 { - phy-mode = "rmii"; - status = "okay"; - }; +&isi { + status = "okay"; - isi: isi@f8048000 { - status = "okay"; - port { - isi_0: endpoint@0 { - reg = <0>; - remote-endpoint = <&ov2640_0>; - bus-width = <8>; - vsync-active = <1>; - hsync-active = <1>; - }; - }; - }; + port { + isi_0: endpoint@0 { + reg = <0>; + remote-endpoint = <&ov2640_0>; + bus-width = <8>; + vsync-active = <1>; + hsync-active = <1>; }; }; }; + +&macb0 { + phy-mode = "rmii"; + status = "okay"; +}; + +&mmc1 { + status = "disabled"; +}; + +&spi0 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/at91sam9g35ek.dts b/arch/arm/boot/dts/at91sam9g35ek.dts index 449ec712ab521902aa15237d974b74b451bcd749..f966b56de63c27dc604fd921f2c3c115bed5b0f3 100644 --- a/arch/arm/boot/dts/at91sam9g35ek.dts +++ b/arch/arm/boot/dts/at91sam9g35ek.dts @@ -14,19 +14,6 @@ model = "Atmel AT91SAM9G35-EK"; compatible = "atmel,at91sam9g35ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9"; - ahb { - apb { - macb0: ethernet@f802c000 { - phy-mode = "rmii"; - status = "okay"; - }; - - hlcdc: hlcdc@f8038000 { - status = "okay"; - }; - }; - }; - backlight: backlight { status = "okay"; }; @@ -43,3 +30,12 @@ status = "okay"; }; }; + +&hlcdc { + status = "okay"; +}; + +&macb0 { + phy-mode = "rmii"; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts index 06d74ff1a7d078c5f2d36daa273fd8cf428dac4e..84bed6f55fcdd4f9874c3db5e1cadefa18cae176 100644 --- a/arch/arm/boot/dts/at91sam9m10g45ek.dts +++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts @@ -235,7 +235,7 @@ display = <&display0>; status = "okay"; - display0: display { + display0: panel { bits-per-pixel = <32>; atmel,lcdcon-backlight; atmel,dmacon = <0x1>; diff --git a/arch/arm/boot/dts/at91sam9rlek.dts b/arch/arm/boot/dts/at91sam9rlek.dts index 3a3869444fdcdc872bbfe14d478a4ffa5ff2a3f6..0de75d3c4f18c61a502d021078e20c7835d24d90 100644 --- a/arch/arm/boot/dts/at91sam9rlek.dts +++ b/arch/arm/boot/dts/at91sam9rlek.dts @@ -36,7 +36,7 @@ display = <&display0>; status = "okay"; - display0: display { + display0: panel { bits-per-pixel = <16>; atmel,lcdcon-backlight; atmel,dmacon = <0x1>; diff --git a/arch/arm/boot/dts/at91sam9x25ek.dts b/arch/arm/boot/dts/at91sam9x25ek.dts index 4e1c3df89a6c6969cbfa86d5e811648900182e34..ad7c6b36f0bacd21d875ea37d82b0a272e73a939 100644 --- a/arch/arm/boot/dts/at91sam9x25ek.dts +++ b/arch/arm/boot/dts/at91sam9x25ek.dts @@ -12,28 +12,24 @@ / { model = "Atmel AT91SAM9X25-EK"; compatible = "atmel,at91sam9x25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9"; +}; - ahb { - apb { - can1: can@f8004000 { - status = "okay"; - }; +&can1 { + status = "okay"; +}; - macb0: ethernet@f802c000 { - phy-mode = "rmii"; - status = "okay"; - }; +&macb0 { + phy-mode = "rmii"; + status = "okay"; +}; - macb1: ethernet@f8030000 { - phy-mode = "rmii"; - status = "okay"; - }; +&macb1 { + phy-mode = "rmii"; + status = "okay"; +}; - pwm0: pwm@f8034000 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_pwm0_pwm0_1>; - status = "okay"; - }; - }; - }; +&pwm0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0_pwm0_1>; + status = "okay"; }; diff --git a/arch/arm/boot/dts/at91sam9x35ek.dts b/arch/arm/boot/dts/at91sam9x35ek.dts index 7646c680fa97a8ad676fd077cc6d0337bf38c4f4..66675c787b97d0cf8fd6b99a5c69a5cd9c4b9b84 100644 --- a/arch/arm/boot/dts/at91sam9x35ek.dts +++ b/arch/arm/boot/dts/at91sam9x35ek.dts @@ -13,32 +13,29 @@ / { model = "Atmel AT91SAM9X35-EK"; compatible = "atmel,at91sam9x35ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9"; +}; - ahb { - apb { - macb0: ethernet@f802c000 { - phy-mode = "rmii"; - status = "okay"; - }; - hlcdc: hlcdc@f8038000 { - status = "okay"; - }; - }; - }; +&backlight { + status = "okay"; +}; - backlight: backlight { - status = "okay"; - }; +&bl_reg { + status = "okay"; +}; - bl_reg: backlight_regulator { - status = "okay"; - }; +&hlcdc { + status = "okay"; +}; - panel: panel { - status = "okay"; - }; +&macb0 { + phy-mode = "rmii"; + status = "okay"; +}; + +&panel { + status = "okay"; +}; - panel_reg: panel_regulator { - status = "okay"; - }; +&panel_reg { + status = "okay"; }; diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index ef47c005ef034c2194ec9266212ef30322aa9e8d..7c2eb93f8cac652b94b943e9bbd2dba0709a6191 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -941,7 +941,7 @@ status = "disabled"; }; - rtc@fffffeb0 { + rtc: rtc@fffffeb0 { compatible = "atmel,at91sam9x5-rtc"; reg = <0xfffffeb0 0x40>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; diff --git a/arch/arm/boot/dts/at91sam9x5_lcd.dtsi b/arch/arm/boot/dts/at91sam9x5_lcd.dtsi index 584f840cc6a5dd26999e9e29be69fc882360e451..f81c9d1691e036276f1d55600ec54591ed41114c 100644 --- a/arch/arm/boot/dts/at91sam9x5_lcd.dtsi +++ b/arch/arm/boot/dts/at91sam9x5_lcd.dtsi @@ -39,109 +39,109 @@ #pwm-cells = <3>; }; }; + }; + }; +}; - pinctrl@fffff400 { - lcd { - pinctrl_lcd_base: lcd-base-0 { - atmel,pins = - ; /* LCDPCK */ - }; +&pinctrl { + lcd { + pinctrl_lcd_base: lcd-base-0 { + atmel,pins = + ; /* LCDPCK */ + }; - pinctrl_lcd_pwm: lcd-pwm-0 { - atmel,pins = ; /* LCDPWM */ - }; + pinctrl_lcd_pwm: lcd-pwm-0 { + atmel,pins = ; /* LCDPWM */ + }; - pinctrl_lcd_rgb444: lcd-rgb-0 { - atmel,pins = - ; /* LCDD11 pin */ - }; + pinctrl_lcd_rgb444: lcd-rgb-0 { + atmel,pins = + ; /* LCDD11 pin */ + }; - pinctrl_lcd_rgb565: lcd-rgb-1 { - atmel,pins = - ; /* LCDD15 pin */ - }; + pinctrl_lcd_rgb565: lcd-rgb-1 { + atmel,pins = + ; /* LCDD15 pin */ + }; - pinctrl_lcd_rgb666: lcd-rgb-2 { - atmel,pins = - ; /* LCDD17 pin */ - }; + pinctrl_lcd_rgb666: lcd-rgb-2 { + atmel,pins = + ; /* LCDD17 pin */ + }; - pinctrl_lcd_rgb888: lcd-rgb-3 { - atmel,pins = - ; /* LCDD23 pin */ - }; - }; - }; + pinctrl_lcd_rgb888: lcd-rgb-3 { + atmel,pins = + ; /* LCDD23 pin */ }; }; }; diff --git a/arch/arm/boot/dts/at91sam9x5dm.dtsi b/arch/arm/boot/dts/at91sam9x5dm.dtsi index b04ebf1a31313bbe26ceb1b303f7b42179b1306f..7f00c1f57b901967ebcc6cbfb6508d73433c8039 100644 --- a/arch/arm/boot/dts/at91sam9x5dm.dtsi +++ b/arch/arm/boot/dts/at91sam9x5dm.dtsi @@ -9,51 +9,6 @@ */ / { - ahb { - apb { - i2c0: i2c@f8010000 { - qt1070: keyboard@1b { - compatible = "qt1070"; - reg = <0x1b>; - interrupt-parent = <&pioA>; - interrupts = <7 0x0>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_qt1070_irq>; - wakeup-source; - }; - }; - - hlcdc: hlcdc@f8038000 { - hlcdc-display-controller { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>; - - port@0 { - hlcdc_panel_output: endpoint@0 { - reg = <0>; - remote-endpoint = <&panel_input>; - }; - }; - }; - }; - - adc0: adc@f804c000 { - atmel,adc-ts-wires = <4>; - atmel,adc-ts-pressure-threshold = <10000>; - status = "okay"; - }; - - pinctrl@fffff400 { - board { - pinctrl_qt1070_irq: qt1070_irq { - atmel,pins = - ; - }; - }; - }; - }; - }; - backlight: backlight { compatible = "pwm-backlight"; pwms = <&hlcdc_pwm 0 50000 0>; @@ -98,3 +53,44 @@ status = "disabled"; }; }; + +&adc0 { + atmel,adc-ts-wires = <4>; + atmel,adc-ts-pressure-threshold = <10000>; + status = "okay"; +}; + +&i2c0 { + keyboard@1b { + compatible = "qt1070"; + reg = <0x1b>; + interrupt-parent = <&pioA>; + interrupts = <7 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qt1070_irq>; + wakeup-source; + }; +}; + +&hlcdc { + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>; + + port@0 { + hlcdc_panel_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; + }; + }; +}; + +&pinctrl { + board { + pinctrl_qt1070_irq: qt1070_irq { + atmel,pins = + ; + }; + }; +}; diff --git a/arch/arm/boot/dts/at91sam9x5ek.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi index 2ad0a43656e42077fa8b236ed9ba1b08f7ae7b01..c934928742b09293c63a12115661e3ed2eec300e 100644 --- a/arch/arm/boot/dts/at91sam9x5ek.dtsi +++ b/arch/arm/boot/dts/at91sam9x5ek.dtsi @@ -16,139 +16,6 @@ stdout-path = "serial0:115200n8"; }; - ahb { - apb { - mmc0: mmc@f0008000 { - pinctrl-0 = < - &pinctrl_board_mmc0 - &pinctrl_mmc0_slot0_clk_cmd_dat0 - &pinctrl_mmc0_slot0_dat1_3>; - status = "okay"; - slot@0 { - reg = <0>; - bus-width = <4>; - cd-gpios = <&pioD 15 GPIO_ACTIVE_HIGH>; - }; - }; - - mmc1: mmc@f000c000 { - pinctrl-0 = < - &pinctrl_board_mmc1 - &pinctrl_mmc1_slot0_clk_cmd_dat0 - &pinctrl_mmc1_slot0_dat1_3>; - status = "okay"; - slot@0 { - reg = <0>; - bus-width = <4>; - cd-gpios = <&pioD 14 GPIO_ACTIVE_HIGH>; - }; - }; - - dbgu: serial@fffff200 { - status = "okay"; - }; - - usart0: serial@f801c000 { - atmel,use-dma-rx; - atmel,use-dma-tx; - status = "okay"; - }; - - usb2: gadget@f803c000 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_board_usb2>; - atmel,vbus-gpio = <&pioB 16 GPIO_ACTIVE_HIGH>; - status = "okay"; - }; - - i2c0: i2c@f8010000 { - status = "okay"; - - wm8731: wm8731@1a { - compatible = "wm8731"; - reg = <0x1a>; - }; - }; - - adc0: adc@f804c000 { - atmel,adc-ts-wires = <4>; - atmel,adc-ts-pressure-threshold = <10000>; - status = "okay"; - }; - - pinctrl@fffff400 { - camera_sensor { - pinctrl_pck0_as_isi_mck: pck0_as_isi_mck-0 { - atmel,pins = - ; /* ISI_MCK */ - }; - - pinctrl_sensor_power: sensor_power-0 { - atmel,pins = - ; - }; - - pinctrl_sensor_reset: sensor_reset-0 { - atmel,pins = - ; - }; - }; - - mmc0 { - pinctrl_board_mmc0: mmc0-board { - atmel,pins = - ; /* PD15 gpio CD pin pull up and deglitch */ - }; - }; - - mmc1 { - pinctrl_board_mmc1: mmc1-board { - atmel,pins = - ; /* PD14 gpio CD pin pull up and deglitch */ - }; - }; - - usb2 { - pinctrl_board_usb2: usb2-board { - atmel,pins = - ; /* PB16 gpio vbus sense, deglitch */ - }; - }; - }; - - spi0: spi@f0000000 { - status = "disabled"; /* conflicts with mmc1 */ - cs-gpios = <&pioA 14 0>, <0>, <0>, <0>; - m25p80@0 { - compatible = "atmel,at25df321a"; - spi-max-frequency = <50000000>; - reg = <0>; - }; - }; - - watchdog@fffffe40 { - status = "okay"; - }; - - ssc0: ssc@f0010000 { - status = "okay"; - }; - }; - - usb0: ohci@600000 { - status = "okay"; - num-ports = <3>; - atmel,vbus-gpio = <0 /* &pioD 18 GPIO_ACTIVE_LOW *//* Activate to have access to port A */ - &pioD 19 GPIO_ACTIVE_LOW - &pioD 20 GPIO_ACTIVE_LOW - >; - }; - - usb1: ehci@700000 { - status = "okay"; - }; - }; - sound { compatible = "atmel,sam9x5-wm8731-audio"; @@ -164,3 +31,135 @@ atmel,audio-codec = <&wm8731>; }; }; + +&adc0 { + atmel,adc-ts-wires = <4>; + atmel,adc-ts-pressure-threshold = <10000>; + status = "okay"; +}; + +&dbgu { + status = "okay"; +}; + +&i2c0 { + status = "okay"; + + wm8731: wm8731@1a { + compatible = "wm8731"; + reg = <0x1a>; + }; +}; + +&mmc0 { + pinctrl-0 = < + &pinctrl_board_mmc0 + &pinctrl_mmc0_slot0_clk_cmd_dat0 + &pinctrl_mmc0_slot0_dat1_3>; + status = "okay"; + + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioD 15 GPIO_ACTIVE_HIGH>; + }; +}; + +&mmc1 { + pinctrl-0 = < + &pinctrl_board_mmc1 + &pinctrl_mmc1_slot0_clk_cmd_dat0 + &pinctrl_mmc1_slot0_dat1_3>; + status = "okay"; + + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioD 14 GPIO_ACTIVE_HIGH>; + }; +}; + +&pinctrl { + camera_sensor { + pinctrl_pck0_as_isi_mck: pck0_as_isi_mck-0 { + atmel,pins = + ; /* ISI_MCK */ + }; + + pinctrl_sensor_power: sensor_power-0 { + atmel,pins = + ; + }; + + pinctrl_sensor_reset: sensor_reset-0 { + atmel,pins = + ; + }; + }; + + mmc0 { + pinctrl_board_mmc0: mmc0-board { + atmel,pins = + ; /* PD15 gpio CD pin pull up and deglitch */ + }; + }; + + mmc1 { + pinctrl_board_mmc1: mmc1-board { + atmel,pins = + ; /* PD14 gpio CD pin pull up and deglitch */ + }; + }; + + usb2 { + pinctrl_board_usb2: usb2-board { + atmel,pins = + ; /* PB16 gpio vbus sense, deglitch */ + }; + }; +}; + +&spi0 { + cs-gpios = <&pioA 14 0>, <0>, <0>, <0>; + status = "disabled"; /* conflicts with mmc1 */ + + m25p80@0 { + compatible = "atmel,at25df321a"; + spi-max-frequency = <50000000>; + reg = <0>; + }; +}; + +&ssc0 { + status = "okay"; +}; + +&usart0 { + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "okay"; +}; + +&usb0 { + num-ports = <3>; + atmel,vbus-gpio = <0 /* &pioD 18 GPIO_ACTIVE_LOW *//* Activate to have access to port A */ + &pioD 19 GPIO_ACTIVE_LOW + &pioD 20 GPIO_ACTIVE_LOW + >; + status = "okay"; +}; + +&usb1 { + status = "okay"; +}; + +&usb2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_board_usb2>; + atmel,vbus-gpio = <&pioB 16 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts index db8a6017f220a2b737b5e0af002e9b1077572f03..6c8ce39833bf68345b93d2efeee54c4238115341 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts @@ -8,6 +8,11 @@ compatible = "raspberrypi,model-a-plus", "brcm,bcm2835"; model = "Raspberry Pi Model A+"; + memory@0 { + device_type = "memory"; + reg = <0 0x10000000>; + }; + leds { act { gpios = <&gpio 47 GPIO_ACTIVE_HIGH>; @@ -99,6 +104,8 @@ &hdmi { hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>; + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; }; &pwm { @@ -107,6 +114,13 @@ status = "okay"; }; +&sdhost { + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_gpio48>; + bus-width = <4>; + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_gpio14>; diff --git a/arch/arm/boot/dts/bcm2835-rpi-a.dts b/arch/arm/boot/dts/bcm2835-rpi-a.dts index 067d1f07a2d36c1653e47b2b3d64d77a0c81b813..17fdd48346ffbb7f23ecd6a963b9b0e0c02d6ae4 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-a.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts @@ -8,6 +8,11 @@ compatible = "raspberrypi,model-a", "brcm,bcm2835"; model = "Raspberry Pi Model A"; + memory@0 { + device_type = "memory"; + reg = <0 0x10000000>; + }; + leds { act { gpios = <&gpio 16 GPIO_ACTIVE_LOW>; @@ -94,6 +99,8 @@ &hdmi { hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>; + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; }; &pwm { @@ -102,6 +109,13 @@ status = "okay"; }; +&sdhost { + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_gpio48>; + bus-width = <4>; + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_gpio14>; diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts index 1e40d672b05522c628e77eaf31b011f7d4341192..b0355c229cdc21d56219da18e760805479b2b77d 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts @@ -9,6 +9,11 @@ compatible = "raspberrypi,model-b-plus", "brcm,bcm2835"; model = "Raspberry Pi Model B+"; + memory@0 { + device_type = "memory"; + reg = <0 0x20000000>; + }; + leds { act { gpios = <&gpio 47 GPIO_ACTIVE_HIGH>; @@ -101,6 +106,8 @@ &hdmi { hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>; + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; }; &pwm { @@ -109,6 +116,13 @@ status = "okay"; }; +&sdhost { + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_gpio48>; + bus-width = <4>; + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_gpio14>; diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts index 28e7513ce61713a084bc5f91f96cc2426d3f50a8..33b3b5c0252190599c8d42b1f0728e1668647143 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts @@ -9,6 +9,11 @@ compatible = "raspberrypi,model-b-rev2", "brcm,bcm2835"; model = "Raspberry Pi Model B rev2"; + memory@0 { + device_type = "memory"; + reg = <0 0x10000000>; + }; + leds { act { gpios = <&gpio 16 GPIO_ACTIVE_LOW>; @@ -94,6 +99,8 @@ &hdmi { hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>; + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; }; &pwm { @@ -102,6 +109,13 @@ status = "okay"; }; +&sdhost { + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_gpio48>; + bus-width = <4>; + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_gpio14>; diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts index 31ff602e2cd3644a5524443dbc817023852c01a9..2b69957e0113ee133056f5a5c8eae0febf0582eb 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-b.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts @@ -9,6 +9,11 @@ compatible = "raspberrypi,model-b", "brcm,bcm2835"; model = "Raspberry Pi Model B"; + memory@0 { + device_type = "memory"; + reg = <0 0x10000000>; + }; + leds { act { gpios = <&gpio 16 GPIO_ACTIVE_LOW>; @@ -89,6 +94,8 @@ &hdmi { hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>; + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; }; &pwm { @@ -97,6 +104,13 @@ status = "okay"; }; +&sdhost { + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_gpio48>; + bus-width = <4>; + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_gpio14>; diff --git a/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts b/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts index 4764a25585ab69f9a79868f7746380f4b09d000f..a75c882e65751fae008e4d8d8807b927ea5b88c6 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts @@ -79,6 +79,15 @@ &hdmi { hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>; + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; +}; + +&sdhost { + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_gpio48>; + bus-width = <4>; + status = "okay"; }; &uart0 { diff --git a/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi b/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi index ef22c2da783afe706548637ca0ca39c816c04e23..58059c2ce1294a8a6d0fb426b833498e6cfb6950 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi +++ b/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi @@ -10,6 +10,11 @@ }; }; + memory@0 { + device_type = "memory"; + reg = <0 0x20000000>; + }; + reg_3v3: fixed-regulator { compatible = "regulator-fixed"; regulator-name = "3V3"; diff --git a/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts b/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts index ba0167df6c5fe5a9a11bce1f87ee12f19a3f48df..09a088f98566178bbb4d5df30f44d03ca7280357 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts @@ -12,6 +12,11 @@ compatible = "raspberrypi,model-zero-w", "brcm,bcm2835"; model = "Raspberry Pi Zero W"; + memory@0 { + device_type = "memory"; + reg = <0 0x20000000>; + }; + chosen { /* 8250 auxiliary UART instead of pl011 */ stdout-path = "serial1:115200n8"; @@ -100,6 +105,8 @@ &hdmi { hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>; + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; }; &sdhci { @@ -116,6 +123,13 @@ }; }; +&sdhost { + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_gpio48>; + bus-width = <4>; + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_gpio32 &uart0_ctsrts_gpio30>; diff --git a/arch/arm/boot/dts/bcm2835-rpi-zero.dts b/arch/arm/boot/dts/bcm2835-rpi-zero.dts index 3b35a8a4a55f92afa680afcf2cd5ad9da636770b..6dd93c6f49666557b3ee0a958be961bfd8446370 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-zero.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-zero.dts @@ -12,6 +12,11 @@ compatible = "raspberrypi,model-zero", "brcm,bcm2835"; model = "Raspberry Pi Zero"; + memory@0 { + device_type = "memory"; + reg = <0 0x20000000>; + }; + leds { act { gpios = <&gpio 47 GPIO_ACTIVE_HIGH>; @@ -96,6 +101,15 @@ &hdmi { hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>; + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; +}; + +&sdhost { + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_gpio48>; + bus-width = <4>; + status = "okay"; }; &uart0 { diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi index 715d50c64529ad7217e9906a69f873f23e68a337..6c6a7f620d8b746b14a7706396b3c3f5fad165ec 100644 --- a/arch/arm/boot/dts/bcm2835-rpi.dtsi +++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi @@ -1,11 +1,6 @@ #include / { - memory@0 { - device_type = "memory"; - reg = <0 0x10000000>; - }; - leds { compatible = "gpio-leds"; @@ -68,28 +63,10 @@ status = "okay"; }; -&sdhci { - pinctrl-names = "default"; - pinctrl-0 = <&emmc_gpio48>; - bus-width = <4>; -}; - -&sdhost { - pinctrl-names = "default"; - pinctrl-0 = <&sdhost_gpio48>; - status = "okay"; - bus-width = <4>; -}; - &usb { power-domains = <&power RPI_POWER_DOMAIN_USB>; }; -&hdmi { - power-domains = <&power RPI_POWER_DOMAIN_HDMI>; - status = "okay"; -}; - &vec { power-domains = <&power RPI_POWER_DOMAIN_VEC>; status = "okay"; diff --git a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts index 7b4e651bafddab48bcb22ff3cc7d8184d6c9996c..0455a680394a22e1b61a50de5a9345a2902629d8 100644 --- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts +++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts @@ -10,6 +10,7 @@ model = "Raspberry Pi 2 Model B"; memory@0 { + device_type = "memory"; reg = <0 0x40000000>; }; @@ -105,6 +106,8 @@ &hdmi { hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>; + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; }; &pwm { @@ -113,6 +116,13 @@ status = "okay"; }; +&sdhost { + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_gpio48>; + bus-width = <4>; + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_gpio14>; diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts b/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts index 7f4437a8eedbe338e00332a3e7e82e1587aad874..66ab35eccba7bbc0f753ac99ce0763a8b1f5af9c 100644 --- a/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts +++ b/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts @@ -14,6 +14,7 @@ }; memory@0 { + device_type = "memory"; reg = <0 0x20000000>; }; @@ -117,6 +118,8 @@ &hdmi { hpd-gpios = <&gpio 28 GPIO_ACTIVE_LOW>; + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; }; &pwm { diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts b/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts index c6fa34c24100d43f053f5b64a4e5b4a8e801da7f..74ed6d04780703d8c3197c39716baecad5cafcb5 100644 --- a/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts +++ b/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts @@ -15,6 +15,7 @@ }; memory@0 { + device_type = "memory"; reg = <0 0x40000000>; }; @@ -124,6 +125,8 @@ &hdmi { hpd-gpios = <&gpio 28 GPIO_ACTIVE_LOW>; + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; }; &pwm { diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts index ce71f578c51a7b5a210aad098ad283292cba5317..054ecaa355c9ab4589e784a186e9efeef5f08375 100644 --- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts +++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts @@ -15,6 +15,7 @@ }; memory@0 { + device_type = "memory"; reg = <0 0x40000000>; }; @@ -125,6 +126,8 @@ &hdmi { hpd-gpios = <&expgpio 4 GPIO_ACTIVE_LOW>; + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; }; /* uart0 communicates with the BT module */ diff --git a/arch/arm/boot/dts/bcm2837-rpi-cm3-io3.dts b/arch/arm/boot/dts/bcm2837-rpi-cm3-io3.dts index 6c8233a36d86b66492a8425b94b360b5ea1db193..588d9411ceb61a9af583d3677d4916acf415b82d 100644 --- a/arch/arm/boot/dts/bcm2837-rpi-cm3-io3.dts +++ b/arch/arm/boot/dts/bcm2837-rpi-cm3-io3.dts @@ -78,6 +78,15 @@ &hdmi { hpd-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>; + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; +}; + +&sdhost { + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_gpio48>; + bus-width = <4>; + status = "okay"; }; &uart0 { diff --git a/arch/arm/boot/dts/bcm2837-rpi-cm3.dtsi b/arch/arm/boot/dts/bcm2837-rpi-cm3.dtsi index 81399b2c5af9e1f46e4d7e61fb2567bb84146aab..7c3cb7ece6cbf87c2f2e668fb7287968f95a44ee 100644 --- a/arch/arm/boot/dts/bcm2837-rpi-cm3.dtsi +++ b/arch/arm/boot/dts/bcm2837-rpi-cm3.dtsi @@ -5,6 +5,7 @@ / { memory@0 { + device_type = "memory"; reg = <0 0x40000000>; }; diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi index 4b21ddb26aa563d935bb96757ecc5a3c426a11ba..2d191fcbc2cc16b64c226c3b11992bda2e83f757 100644 --- a/arch/arm/boot/dts/bcm283x.dtsi +++ b/arch/arm/boot/dts/bcm283x.dtsi @@ -397,7 +397,7 @@ uart0: serial@7e201000 { compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell"; - reg = <0x7e201000 0x1000>; + reg = <0x7e201000 0x200>; interrupts = <2 25>; clocks = <&clocks BCM2835_CLOCK_UART>, <&clocks BCM2835_CLOCK_VPU>; @@ -428,7 +428,7 @@ spi: spi@7e204000 { compatible = "brcm,bcm2835-spi"; - reg = <0x7e204000 0x1000>; + reg = <0x7e204000 0x200>; interrupts = <2 22>; clocks = <&clocks BCM2835_CLOCK_VPU>; dmas = <&dma 6>, <&dma 7>; @@ -440,7 +440,7 @@ i2c0: i2c@7e205000 { compatible = "brcm,bcm2835-i2c"; - reg = <0x7e205000 0x1000>; + reg = <0x7e205000 0x200>; interrupts = <2 21>; clocks = <&clocks BCM2835_CLOCK_VPU>; #address-cells = <1>; diff --git a/arch/arm/boot/dts/da850-evm.dts b/arch/arm/boot/dts/da850-evm.dts index 5b2b1ed04d510cf52a952cdfc2c43d580d4f0d83..f2e7609e5346afc6145379b9adcb2d4080f35157 100644 --- a/arch/arm/boot/dts/da850-evm.dts +++ b/arch/arm/boot/dts/da850-evm.dts @@ -281,7 +281,7 @@ flash: m25p80@0 { #address-cells = <1>; #size-cells = <1>; - compatible = "m25p64"; + compatible = "jedec,spi-nor"; spi-max-frequency = <30000000>; m25p,fast-read; reg = <0>; diff --git a/arch/arm/boot/dts/ep7211-edb7211.dts b/arch/arm/boot/dts/ep7211-edb7211.dts index a0c270f63fee128a17a1898474eb9c3f580797c7..da076479c8e2cb487a22fbf28715ac5af82a350d 100644 --- a/arch/arm/boot/dts/ep7211-edb7211.dts +++ b/arch/arm/boot/dts/ep7211-edb7211.dts @@ -25,11 +25,11 @@ display: display { model = "320x240x4"; - native-mode = <&timing0>; bits-per-pixel = <4>; ac-prescale = <17>; display-timings { + native-mode = <&timing0>; timing0: 320x240 { hactive = <320>; hback-porch = <0>; diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi index 5659c4a107296d3012a33a436097a7b1f7337788..78481849037612ea9bbbbe6eddc8357a4d36061b 100644 --- a/arch/arm/boot/dts/exynos3250.dtsi +++ b/arch/arm/boot/dts/exynos3250.dtsi @@ -450,8 +450,7 @@ }; adc: adc@126c0000 { - compatible = "samsung,exynos3250-adc", - "samsung,exynos-adc-v2"; + compatible = "samsung,exynos3250-adc"; reg = <0x126C0000 0x100>; interrupts = ; clock-names = "adc", "sclk"; diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index 1264cc431ff6f0654d1affc20ab81c945e44e7df..433f109d97cae7d56be37861c4cc47d84bf2eb1d 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi @@ -380,23 +380,8 @@ clocks = <&clock CLK_USB_HOST>; clock-names = "usbhost"; status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - phys = <&exynos_usbphy 1>; - status = "disabled"; - }; - port@1 { - reg = <1>; - phys = <&exynos_usbphy 2>; - status = "disabled"; - }; - port@2 { - reg = <2>; - phys = <&exynos_usbphy 3>; - status = "disabled"; - }; + phys = <&exynos_usbphy 1>, <&exynos_usbphy 2>, <&exynos_usbphy 3>; + phy-names = "host", "hsic0", "hsic1"; }; ohci: ohci@12590000 { @@ -406,13 +391,8 @@ clocks = <&clock CLK_USB_HOST>; clock-names = "usbhost"; status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - phys = <&exynos_usbphy 1>; - status = "disabled"; - }; + phys = <&exynos_usbphy 1>; + phy-names = "host"; }; gpu: gpu@13000000 { diff --git a/arch/arm/boot/dts/exynos4210-universal_c210.dts b/arch/arm/boot/dts/exynos4210-universal_c210.dts index 82a8b5449978a166d4fd1e2d120e54deee98d852..09d3d54d09ff8bf32988d49f2f223d262c799b46 100644 --- a/arch/arm/boot/dts/exynos4210-universal_c210.dts +++ b/arch/arm/boot/dts/exynos4210-universal_c210.dts @@ -204,9 +204,8 @@ &ehci { status = "okay"; - port@0 { - status = "okay"; - }; + phys = <&exynos_usbphy 1>; + phy-names = "host"; }; &exynos_usbphy { @@ -520,9 +519,6 @@ &ohci { status = "okay"; - port@0 { - status = "okay"; - }; }; &pinctrl_1 { diff --git a/arch/arm/boot/dts/exynos4412-itop-elite.dts b/arch/arm/boot/dts/exynos4412-itop-elite.dts index 0dedeba89b5f46d9c3637e90413441adc2139ae1..f6d0a5f5d339edf76da9373fdd7ceb81fb54317e 100644 --- a/arch/arm/boot/dts/exynos4412-itop-elite.dts +++ b/arch/arm/boot/dts/exynos4412-itop-elite.dts @@ -146,13 +146,8 @@ /* In order to reset USB ethernet */ samsung,vbus-gpio = <&gpc0 1 GPIO_ACTIVE_HIGH>; - port@0 { - status = "okay"; - }; - - port@2 { - status = "okay"; - }; + phys = <&exynos_usbphy 1>, <&exynos_usbphy 3>; + phy-names = "host", "hsic1"; }; &exynos_usbphy { diff --git a/arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi b/arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi index 462a5409b1de3e3cf47191ecb6835c8d8b62a6cf..dfceb155b3a7636c503cb69aa3845b3ab9368144 100644 --- a/arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi +++ b/arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi @@ -377,7 +377,7 @@ buck1_reg: BUCK1 { regulator-name = "vdd_mif"; regulator-min-microvolt = <850000>; - regulator-max-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; regulator-always-on; regulator-boot-on; op_mode = <1>; /* Normal Mode */ @@ -386,7 +386,7 @@ buck2_reg: BUCK2 { regulator-name = "vdd_arm"; regulator-min-microvolt = <850000>; - regulator-max-microvolt = <1456250>; + regulator-max-microvolt = <1456250>; regulator-always-on; regulator-boot-on; op_mode = <1>; /* Normal Mode */ @@ -395,7 +395,7 @@ buck3_reg: BUCK3 { regulator-name = "vdd_int"; regulator-min-microvolt = <875000>; - regulator-max-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; regulator-always-on; regulator-boot-on; op_mode = <1>; /* Normal Mode */ @@ -404,7 +404,7 @@ buck4_reg: BUCK4 { regulator-name = "vdd_g3d"; regulator-min-microvolt = <750000>; - regulator-max-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; regulator-always-on; regulator-boot-on; op_mode = <1>; /* Normal Mode */ @@ -413,7 +413,7 @@ buck5_reg: BUCK5 { regulator-name = "vdd_m12"; regulator-min-microvolt = <750000>; - regulator-max-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; regulator-always-on; regulator-boot-on; op_mode = <1>; /* Normal Mode */ @@ -422,7 +422,7 @@ buck6_reg: BUCK6 { regulator-name = "vdd12_5m"; regulator-min-microvolt = <750000>; - regulator-max-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; regulator-always-on; regulator-boot-on; op_mode = <1>; /* Normal Mode */ @@ -431,7 +431,7 @@ buck7_reg: BUCK7 { regulator-name = "pvdd_buck7"; regulator-min-microvolt = <750000>; - regulator-max-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; regulator-boot-on; regulator-always-on; op_mode = <1>; /* Normal Mode */ @@ -440,7 +440,7 @@ buck8_reg: BUCK8 { regulator-name = "pvdd_buck8"; regulator-min-microvolt = <750000>; - regulator-max-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; regulator-boot-on; regulator-always-on; op_mode = <1>; /* Normal Mode */ @@ -449,7 +449,7 @@ buck9_reg: BUCK9 { regulator-name = "vddf28_emmc"; regulator-min-microvolt = <750000>; - regulator-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; op_mode = <1>; /* Normal Mode */ }; }; diff --git a/arch/arm/boot/dts/exynos4412-odroidu3.dts b/arch/arm/boot/dts/exynos4412-odroidu3.dts index 96d99887bceb555d6787e833bd443585e048be43..8ff243ba454260f240d65f51d740fbcab17bd4f4 100644 --- a/arch/arm/boot/dts/exynos4412-odroidu3.dts +++ b/arch/arm/boot/dts/exynos4412-odroidu3.dts @@ -105,12 +105,8 @@ }; &ehci { - port@1 { - status = "okay"; - }; - port@2 { - status = "okay"; - }; + phys = <&exynos_usbphy 2>, <&exynos_usbphy 3>; + phy-names = "hsic0", "hsic1"; }; &sound { diff --git a/arch/arm/boot/dts/exynos4412-odroidx.dts b/arch/arm/boot/dts/exynos4412-odroidx.dts index a2251581f6b60223bedb1d2b0dd594c34c73dab6..3ea2a0101e8086f2b8078a4593ee19d2c2540aa1 100644 --- a/arch/arm/boot/dts/exynos4412-odroidx.dts +++ b/arch/arm/boot/dts/exynos4412-odroidx.dts @@ -72,9 +72,8 @@ }; &ehci { - port@1 { - status = "okay"; - }; + phys = <&exynos_usbphy 2>; + phy-names = "hsic0"; }; &mshc_0 { diff --git a/arch/arm/boot/dts/exynos4412-origen.dts b/arch/arm/boot/dts/exynos4412-origen.dts index 698de4345d16e672b28fb5386d1c0fec9b4763fa..ecd14b283a6b409d5fdf5488f2af3db0bc543a0b 100644 --- a/arch/arm/boot/dts/exynos4412-origen.dts +++ b/arch/arm/boot/dts/exynos4412-origen.dts @@ -88,13 +88,8 @@ &ehci { samsung,vbus-gpio = <&gpx3 5 1>; status = "okay"; - - port@1 { - status = "okay"; - }; - port@2 { - status = "okay"; - }; + phys = <&exynos_usbphy 2>, <&exynos_usbphy 3>; + phy-names = "hsic0", "hsic1"; }; &fimd { diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts index dc6fa6fe83f1e4596bb90d2d1d05d906102b1be5..6fcb78a354fe829eb0464843ae7cfc50d8ccff73 100644 --- a/arch/arm/boot/dts/exynos5250-arndale.dts +++ b/arch/arm/boot/dts/exynos5250-arndale.dts @@ -461,8 +461,8 @@ buck4_reg: BUCK4 { regulator-name = "vdd_g3d"; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1300000>; regulator-always-on; regulator-boot-on; op_mode = <1>; @@ -543,6 +543,11 @@ status = "okay"; }; +&mali { + mali-supply = <&buck4_reg>; + status = "okay"; +}; + &mixer { status = "okay"; }; diff --git a/arch/arm/boot/dts/exynos5250-snow-common.dtsi b/arch/arm/boot/dts/exynos5250-snow-common.dtsi index fd9226d3b207e0175d1f431cbd47fe974f7f604e..c952a615148e55b24285f19a8ff7abdf4087a950 100644 --- a/arch/arm/boot/dts/exynos5250-snow-common.dtsi +++ b/arch/arm/boot/dts/exynos5250-snow-common.dtsi @@ -529,6 +529,11 @@ status = "okay"; }; +&mali { + mali-supply = <&buck4_reg>; + status = "okay"; +}; + &mixer { status = "okay"; }; diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index d5e0392b409ecada566fbd2f43c74b0aa57c8608..fc966c10cf498bb0a0b791329b089019bd0b15fc 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -328,6 +328,53 @@ iommus = <&sysmmu_rotator>; }; + mali: gpu@11800000 { + compatible = "samsung,exynos5250-mali", "arm,mali-t604"; + reg = <0x11800000 0x5000>; + interrupts = , + , + ; + interrupt-names = "job", "mmu", "gpu"; + clocks = <&clock CLK_G3D>; + clock-names = "core"; + operating-points-v2 = <&gpu_opp_table>; + power-domains = <&pd_g3d>; + status = "disabled"; + + gpu_opp_table: gpu-opp-table { + compatible = "operating-points-v2"; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + opp-microvolt = <925000>; + }; + opp-160000000 { + opp-hz = /bits/ 64 <160000000>; + opp-microvolt = <925000>; + }; + opp-266000000 { + opp-hz = /bits/ 64 <266000000>; + opp-microvolt = <1025000>; + }; + opp-350000000 { + opp-hz = /bits/ 64 <350000000>; + opp-microvolt = <1075000>; + }; + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <1125000>; + }; + opp-450000000 { + opp-hz = /bits/ 64 <450000000>; + opp-microvolt = <1150000>; + }; + opp-533000000 { + opp-hz = /bits/ 64 <533000000>; + opp-microvolt = <1250000>; + }; + }; + }; + tmu: tmu@10060000 { compatible = "samsung,exynos5250-tmu"; reg = <0x10060000 0x100>; @@ -346,6 +393,7 @@ clock-names = "sata", "sclk_sata"; phys = <&sata_phy>; phy-names = "sata-phy"; + ports-implemented = <0x1>; status = "disabled"; }; @@ -617,12 +665,8 @@ clocks = <&clock CLK_USB2>; clock-names = "usbhost"; - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - phys = <&usb2_phy_gen 1>; - }; + phys = <&usb2_phy_gen 1>; + phy-names = "host"; }; ohci: usb@12120000 { @@ -632,12 +676,8 @@ clocks = <&clock CLK_USB2>; clock-names = "usbhost"; - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - phys = <&usb2_phy_gen 1>; - }; + phys = <&usb2_phy_gen 1>; + phy-names = "host"; }; usb2_phy_gen: phy@12130000 { diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts index f78db6809cca4b3659e1eb8fe490b581afabf4c5..9eb48cabcca450878f829e15562effaa476bf777 100644 --- a/arch/arm/boot/dts/exynos5420-peach-pit.dts +++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts @@ -440,6 +440,7 @@ regulator-name = "vdd_ldo10"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; + regulator-always-on; regulator-state-mem { regulator-off-in-suspend; }; diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index 55d4dbf6f83a9a34826c675048265010083d038d..7d51e0f4ab79ad9544c8141aee439ecc540c3328 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi @@ -294,11 +294,11 @@ label = "MFC"; }; - msc_pd: power-domain@10044120 { + g3d_pd: power-domain@10044080 { compatible = "samsung,exynos4210-pd"; - reg = <0x10044120 0x20>; + reg = <0x10044080 0x20>; #power-domain-cells = <0>; - label = "MSC"; + label = "G3D"; }; disp_pd: power-domain@100440c0 { @@ -315,6 +315,13 @@ label = "MAU"; }; + msc_pd: power-domain@10044120 { + compatible = "samsung,exynos4210-pd"; + reg = <0x10044120 0x20>; + #power-domain-cells = <0>; + label = "MSC"; + }; + pinctrl_0: pinctrl@13400000 { compatible = "samsung,exynos5420-pinctrl"; reg = <0x13400000 0x1000>; diff --git a/arch/arm/boot/dts/exynos54xx.dtsi b/arch/arm/boot/dts/exynos54xx.dtsi index 0b27bebf9528c20bcdb85f7d5c354e8937f44264..9c3b63b7cac6c54f2f6ec49f71230b62d163b526 100644 --- a/arch/arm/boot/dts/exynos54xx.dtsi +++ b/arch/arm/boot/dts/exynos54xx.dtsi @@ -189,26 +189,16 @@ compatible = "samsung,exynos4210-ehci"; reg = <0x12110000 0x100>; interrupts = ; - - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - phys = <&usb2_phy 1>; - }; + phys = <&usb2_phy 1>; + phy-names = "host"; }; usbhost1: usb@12120000 { compatible = "samsung,exynos4210-ohci"; reg = <0x12120000 0x100>; interrupts = ; - - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - phys = <&usb2_phy 1>; - }; + phys = <&usb2_phy 1>; + phy-names = "host"; }; usb2_phy: phy@12130000 { diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts index e0f470fe54c81da83728a1e9b7611dd2d0d3ad28..4398f2d1fe88171a989f2b928b78570f7169de12 100644 --- a/arch/arm/boot/dts/exynos5800-peach-pi.dts +++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts @@ -440,6 +440,7 @@ regulator-name = "vdd_ldo10"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; + regulator-always-on; regulator-state-mem { regulator-off-in-suspend; }; diff --git a/arch/arm/boot/dts/exynos5800.dtsi b/arch/arm/boot/dts/exynos5800.dtsi index 57d3b319fd6538457e81b38764d7f99f19eff77c..de639eecc5c913c5e8628eea4f9f50460120e23e 100644 --- a/arch/arm/boot/dts/exynos5800.dtsi +++ b/arch/arm/boot/dts/exynos5800.dtsi @@ -131,3 +131,12 @@ &mfc { compatible = "samsung,mfc-v8"; }; + +&soc { + cam_pd: power-domain@10045100 { + compatible = "samsung,exynos4210-pd"; + reg = <0x10045100 0x20>; + #power-domain-cells = <0>; + label = "CAM"; + }; +}; diff --git a/arch/arm/boot/dts/gemini-nas4220b.dts b/arch/arm/boot/dts/gemini-nas4220b.dts index f4535d635f3bcc32d7ebebd7a7328f778e145f67..521714f38eedaeaa07618c3187e0bd9740e19c41 100644 --- a/arch/arm/boot/dts/gemini-nas4220b.dts +++ b/arch/arm/boot/dts/gemini-nas4220b.dts @@ -20,7 +20,7 @@ }; chosen { - bootargs = "console=ttyS0,19200n8"; + bootargs = "console=ttyS0,19200n8 root=/dev/mtdblock3 rw rootfstype=squashfs,jffs2 rootwait"; stdout-path = &uart0; }; @@ -81,37 +81,10 @@ /* 16MB of flash */ reg = <0x30000000 0x01000000>; - partition@0 { - label = "RedBoot"; - reg = <0x00000000 0x00020000>; - read-only; - }; - partition@20000 { - label = "Kernel"; - reg = <0x00020000 0x00300000>; - }; - partition@320000 { - label = "Ramdisk"; - reg = <0x00320000 0x00600000>; - }; - partition@920000 { - label = "Application"; - reg = <0x00920000 0x00600000>; - }; - partition@f20000 { - label = "VCTL"; - reg = <0x00f20000 0x00020000>; - read-only; - }; - partition@f40000 { - label = "CurConf"; - reg = <0x00f40000 0x000a0000>; - read-only; - }; - partition@fe0000 { - label = "FIS directory"; - reg = <0x00fe0000 0x00020000>; - read-only; + partitions { + compatible = "redboot-fis"; + /* Eraseblock at 0xfe0000 */ + fis-index-block = <0x1fc>; }; }; diff --git a/arch/arm/boot/dts/gemini-sl93512r.dts b/arch/arm/boot/dts/gemini-sl93512r.dts index 2bb9534407933b0ba18eefe552c4605362350471..a98af0351906989dcdbd79673f66f78abfc6b671 100644 --- a/arch/arm/boot/dts/gemini-sl93512r.dts +++ b/arch/arm/boot/dts/gemini-sl93512r.dts @@ -24,7 +24,7 @@ }; chosen { - bootargs = "console=ttyS0,19200n8 root=/dev/sda1 rw rootwait"; + bootargs = "console=ttyS0,19200n8 root=/dev/mtdblock3 rw rootfstype=squashfs,jffs2 rootwait"; stdout-path = &uart0; }; @@ -36,8 +36,8 @@ wakeup-source; linux,code = ; label = "WPS"; - /* Conflict with NAND flash */ - gpios = <&gpio0 17 GPIO_ACTIVE_LOW>; + /* Conflicts with TVC and extended flash */ + gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; }; button-setup { @@ -143,54 +143,30 @@ /* 16MB of flash */ reg = <0x30000000 0x01000000>; - partition@0 { - label = "BOOT"; - reg = <0x00000000 0x00020000>; - read-only; - }; - partition@120000 { - label = "Kern"; - reg = <0x00020000 0x00300000>; - }; - partition@320000 { - label = "Ramdisk"; - reg = <0x00320000 0x00600000>; - }; - partition@920000 { - label = "Application"; - reg = <0x00920000 0x00600000>; - }; - partition@f20000 { - label = "VCTL"; - reg = <0x00f20000 0x00020000>; - read-only; - }; - partition@f40000 { - label = "CurConf"; - reg = <0x00f40000 0x000a0000>; - read-only; - }; - partition@fe0000 { - label = "FIS directory"; - reg = <0x00fe0000 0x00020000>; - read-only; + partitions { + compatible = "redboot-fis"; + /* Eraseblock at 0xfe0000 */ + fis-index-block = <0x1fc>; }; }; syscon: syscon@40000000 { pinctrl { /* - * gpio0egrp cover line 16 used by HD LED - * gpio0fgrp cover line 17, 18 used by wireless LED and reset button - * gpio0hgrp cover line 21, 22 used by MDIO for Marvell PHY - * gpio0kgrp cover line 31 used by USB LED + * gpio0agrp cover line 0, used by WPS button + * gpio0fgrp cover line 16 used by HD LED + * gpio0ggrp cover line 17, 18 used by wireless LAN LED and + * reset button OR USB ID select on 17 and USB VBUS select + * on 18. (Confusing.) + * gpio0igrp cover line 21, 22 used by MDIO for Marvell PHY */ gpio0_default_pins: pinctrl-gpio0 { mux { function = "gpio0"; - groups = "gpio0egrp", + groups = "gpio0agrp", "gpio0fgrp", - "gpio0hgrp"; + "gpio0ggrp", + "gpio0igrp"; }; }; /* diff --git a/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts b/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts index dbecd6d2cfc4a3312801ffb49a8f27c869ec013d..7d4301b22b902e85ef4ff0ec1c3b41922a8108ec 100644 --- a/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts +++ b/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts @@ -14,8 +14,8 @@ bits-per-pixel = <16>; fsl,pcr = <0xcad08b80>; bus-width = <18>; - native-mode = <&qvga_timings>; display-timings { + native-mode = <&qvga_timings>; qvga_timings: 320x240 { clock-frequency = <6500000>; hactive = <320>; diff --git a/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-dvi-svga.dts b/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-dvi-svga.dts index ad2f7e8798313e83ef63ac30276ed5cb7f038e60..80a7f96de4c6ac70be65308808f119e0de185c0a 100644 --- a/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-dvi-svga.dts +++ b/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-dvi-svga.dts @@ -14,8 +14,8 @@ bits-per-pixel = <16>; fsl,pcr = <0xfa208b80>; bus-width = <18>; - native-mode = <&dvi_svga_timings>; display-timings { + native-mode = <&dvi_svga_timings>; dvi_svga_timings: 800x600 { clock-frequency = <40000000>; hactive = <800>; diff --git a/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-dvi-vga.dts b/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-dvi-vga.dts index d60d8f464ca955e56e412a8de40ef847bdbf8751..24027a1fb46d11e12c65b8c5307a3e3563943d8e 100644 --- a/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-dvi-vga.dts +++ b/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-dvi-vga.dts @@ -14,8 +14,8 @@ bits-per-pixel = <16>; fsl,pcr = <0xfa208b80>; bus-width = <18>; - native-mode = <&dvi_vga_timings>; display-timings { + native-mode = <&dvi_vga_timings>; dvi_vga_timings: 640x480 { clock-frequency = <31250000>; hactive = <640>; diff --git a/arch/arm/boot/dts/imx25-pdk.dts b/arch/arm/boot/dts/imx25-pdk.dts index f8544a9e46330fd756395eaff80f7290dca4af44..05cccd12624cb6c932ef5ec613396bb73de1b67a 100644 --- a/arch/arm/boot/dts/imx25-pdk.dts +++ b/arch/arm/boot/dts/imx25-pdk.dts @@ -76,8 +76,8 @@ bits-per-pixel = <16>; fsl,pcr = <0xfa208b80>; bus-width = <18>; - native-mode = <&wvga_timings>; display-timings { + native-mode = <&wvga_timings>; wvga_timings: 640x480 { hactive = <640>; vactive = <480>; diff --git a/arch/arm/boot/dts/imx27-apf27dev.dts b/arch/arm/boot/dts/imx27-apf27dev.dts index 087c6e237af0e5fe115979af986d7e9b0c066465..6f1e8ce9e76e973ba26f0c36267d1717a2b585b7 100644 --- a/arch/arm/boot/dts/imx27-apf27dev.dts +++ b/arch/arm/boot/dts/imx27-apf27dev.dts @@ -12,10 +12,10 @@ display: display { model = "Chimei-LW700AT9003"; - native-mode = <&timing0>; bits-per-pixel = <16>; /* non-standard but required */ fsl,pcr = <0xfae80083>; /* non-standard but required */ display-timings { + native-mode = <&timing0>; timing0: 800x480 { clock-frequency = <33000033>; hactive = <800>; diff --git a/arch/arm/boot/dts/imx27-eukrea-mbimxsd27-baseboard.dts b/arch/arm/boot/dts/imx27-eukrea-mbimxsd27-baseboard.dts index 84fc8df4be7c59d296ea49cd0857c73dbbc7dd63..9c3ec82ec7e5a1e3dd616bc384974acca51c8856 100644 --- a/arch/arm/boot/dts/imx27-eukrea-mbimxsd27-baseboard.dts +++ b/arch/arm/boot/dts/imx27-eukrea-mbimxsd27-baseboard.dts @@ -11,11 +11,11 @@ display0: CMO-QVGA { model = "CMO-QVGA"; - native-mode = <&timing0>; bits-per-pixel = <16>; fsl,pcr = <0xfad08b80>; display-timings { + native-mode = <&timing0>; timing0: 320x240 { clock-frequency = <6500000>; hactive = <320>; diff --git a/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts b/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts index 5e5e282ed30e8845a0abd4eaa9bfa9822b7e69c7..0cd75dadf292c2702077b29b2ac45e29b1d6b4e9 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts @@ -15,10 +15,10 @@ display: display { model = "Primeview-PD050VL1"; - native-mode = <&timing0>; bits-per-pixel = <16>; /* non-standard but required */ fsl,pcr = <0xf0c88080>; /* non-standard but required */ display-timings { + native-mode = <&timing0>; timing0: 640x480 { hactive = <640>; vactive = <480>; diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts index 5606f417e9e807d72f303ba55556e2b4ddc31f33..bf883e45576a64dfe7ac5755534dce246443b436 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts @@ -14,11 +14,11 @@ display0: LQ035Q7 { model = "Sharp-LQ035Q7"; - native-mode = <&timing0>; bits-per-pixel = <16>; fsl,pcr = <0xf00080c0>; display-timings { + native-mode = <&timing0>; timing0: 240x320 { clock-frequency = <5500000>; hactive = <240>; diff --git a/arch/arm/boot/dts/imx53-m53menlo.dts b/arch/arm/boot/dts/imx53-m53menlo.dts index 10acc5331ba6a2ee7828d5870396c3748b68fbb6..719ed5ca454affaba60ceb19fc662bf236515d76 100644 --- a/arch/arm/boot/dts/imx53-m53menlo.dts +++ b/arch/arm/boot/dts/imx53-m53menlo.dts @@ -54,7 +54,8 @@ }; panel { - compatible = "edt,etm070080dh6"; + compatible = "edt,etm0700g0dh6"; + pinctrl-0 = <&pinctrl_display_gpio>; enable-gpios = <&gpio6 0 GPIO_ACTIVE_HIGH>; port { diff --git a/arch/arm/boot/dts/imx6qdl-colibri.dtsi b/arch/arm/boot/dts/imx6qdl-colibri.dtsi index 1beac22266edc1fb56c0c1ae92c88dbd486e0049..019dda6b88ad73312590fbc782fb1adab1625865 100644 --- a/arch/arm/boot/dts/imx6qdl-colibri.dtsi +++ b/arch/arm/boot/dts/imx6qdl-colibri.dtsi @@ -140,7 +140,18 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet>; phy-mode = "rmii"; + phy-handle = <ðphy>; status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy: ethernet-phy@0 { + reg = <0>; + micrel,led-mode = <0>; + }; + }; }; &hdmi { diff --git a/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi b/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi index 7a85116ef1d2551ca89ad2185d113fdd1f128258..2418cf8f2317ba0cd626ec6596761bd0dc22dcea 100644 --- a/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi +++ b/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi @@ -556,8 +556,6 @@ non-removable; vmmc-supply = <®_3p3v>; vqmmc-supply = <®_wlan_vmmc>; - vqmmc-1-8-v; - ocr-limit = <0x180>; /* 1.65v - 2.1v */ cap-power-off-card; keep-power-in-suspend; status = "okay"; diff --git a/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi index 82802f8ce7a07858d35823bd41c8b3a659c58b0a..d434868e870a98f26a9361df2d6c23a33b069000 100644 --- a/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi +++ b/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi @@ -128,7 +128,7 @@ }; rtc@51 { - compatible = "nxp,rtc8564"; + compatible = "epson,rtc8564"; reg = <0x51>; }; diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi index 50d9a989e06a9072595f2e64d19c6e19171b9862..2cfb4112a4678c5d9123d3a8d8a1e515e8ae2cfb 100644 --- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi +++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi @@ -33,6 +33,30 @@ spdif-out; }; + reg_1p5v: regulator-1p5v { + compatible = "regulator-fixed"; + regulator-name = "1P5V"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + }; + + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "1P8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + reg_2p8v: regulator-2p8v { + compatible = "regulator-fixed"; + regulator-name = "2P8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + }; + reg_2p5v: regulator-2p5v { compatible = "regulator-fixed"; regulator-name = "2P5V"; @@ -94,6 +118,29 @@ VDDIO-supply = <®_3p3v>; lrclk-strength = <3>; }; + + camera@3c { + compatible = "ovti,ov5645"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ov5645>; + reg = <0x3c>; + clocks = <&clks IMX6QDL_CLK_CKO2>; + clock-names = "xclk"; + clock-frequency = <24000000>; + vdddo-supply = <®_1p8v>; + vdda-supply = <®_2p8v>; + vddd-supply = <®_1p5v>; + enable-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio4 14 GPIO_ACTIVE_LOW>; + + port { + ov5645_to_mipi_csi2: endpoint { + remote-endpoint = <&mipi_csi2_in>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; }; &iomuxc { @@ -128,7 +175,6 @@ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 - MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 >; }; @@ -152,6 +198,14 @@ >; }; + pinctrl_ov5645: ov5645grp { + fsl,pins = < + MX6QDL_PAD_GPIO_3__CCM_CLKO2 0x000b0 + MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x1b0b0 + MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x1b0b0 + >; + }; + pinctrl_spdif: spdifgrp { fsl,pins = < MX6QDL_PAD_ENET_RXD0__SPDIF_OUT 0x1b0b0 @@ -226,12 +280,23 @@ pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii-id"; phy-reset-gpios = <&gpio3 29 GPIO_ACTIVE_LOW>; - interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>, - <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; - fsl,err006687-workaround-present; status = "okay"; }; +&mipi_csi { + status = "okay"; + + port@0 { + reg = <0>; + + mipi_csi2_in: endpoint { + remote-endpoint = <&ov5645_to_mipi_csi2>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; +}; + &spdif { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spdif>; diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 4b801935cad11498b66dcef965a4615fbf7693ed..e6b4b8525f989399dd05273fbcb8503e7829cd56 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -171,8 +171,6 @@ gpmi: gpmi-nand@112000 { compatible = "fsl,imx6q-gpmi-nand"; - #address-cells = <1>; - #size-cells = <1>; reg = <0x00112000 0x2000>, <0x00114000 0x2000>; reg-names = "gpmi-nand", "bch"; interrupts = <0 15 IRQ_TYPE_LEVEL_HIGH>; @@ -695,7 +693,7 @@ }; anatop: anatop@20c8000 { - compatible = "fsl,imx6q-anatop", "syscon", "simple-bus"; + compatible = "fsl,imx6q-anatop", "syscon", "simple-mfd"; reg = <0x020c8000 0x1000>; interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>, <0 54 IRQ_TYPE_LEVEL_HIGH>, diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index b36fc012ff066d4032832dcd9105a088d5b1edf4..3a96b5538a2a1485c148340eee6e6658f37ed004 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -77,15 +77,6 @@ }; }; - intc: interrupt-controller@a01000 { - compatible = "arm,cortex-a9-gic"; - #interrupt-cells = <3>; - interrupt-controller; - reg = <0x00a01000 0x1000>, - <0x00a00100 0x100>; - interrupt-parent = <&intc>; - }; - clocks { ckil { compatible = "fixed-clock"; @@ -133,6 +124,15 @@ clocks = <&clks IMX6SL_CLK_OCRAM>; }; + intc: interrupt-controller@a01000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x00a01000 0x1000>, + <0x00a00100 0x100>; + interrupt-parent = <&intc>; + }; + L2: l2-cache@a02000 { compatible = "arm,pl310-cache"; reg = <0x00a02000 0x1000>; diff --git a/arch/arm/boot/dts/imx6sll.dtsi b/arch/arm/boot/dts/imx6sll.dtsi index b0a77ff70b67a3f54357ee84730b9e2154a6d004..13c7ba7fa6bc9e5ce8df6bb1d186ff8e6d845525 100644 --- a/arch/arm/boot/dts/imx6sll.dtsi +++ b/arch/arm/boot/dts/imx6sll.dtsi @@ -75,15 +75,6 @@ }; }; - intc: interrupt-controller@a01000 { - compatible = "arm,cortex-a9-gic"; - #interrupt-cells = <3>; - interrupt-controller; - reg = <0x00a01000 0x1000>, - <0x00a00100 0x100>; - interrupt-parent = <&intc>; - }; - ckil: clock-ckil { compatible = "fixed-clock"; #clock-cells = <0>; @@ -134,6 +125,15 @@ reg = <0x00900000 0x20000>; }; + intc: interrupt-controller@a01000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x00a01000 0x1000>, + <0x00a00100 0x100>; + interrupt-parent = <&intc>; + }; + L2: l2-cache@a02000 { compatible = "arm,pl310-cache"; reg = <0x00a02000 0x1000>; @@ -234,7 +234,7 @@ compatible = "fsl,imx6sl-uart", "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x02018000 0x4000>; - interrupts =; + interrupts = ; dmas = <&sdma 31 4 0>, <&sdma 32 4 0>; dma-names = "rx", "tx"; clocks = <&clks IMX6SLL_CLK_UART4_IPG>, @@ -621,7 +621,7 @@ }; sdma: dma-controller@20ec000 { - compatible = "fsl,imx6sll-sdma", "fsl,imx35-sdma"; + compatible = "fsl,imx6sll-sdma", "fsl,imx6ul-sdma"; reg = <0x020ec000 0x4000>; interrupts = ; clocks = <&clks IMX6SLL_CLK_IPG>, @@ -801,7 +801,7 @@ compatible = "fsl,imx6sll-uart", "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021f4000 0x4000>; - interrupts =; + interrupts = ; dmas = <&sdma 33 4 0>, <&sdma 34 4 0>; dma-names = "rx", "tx"; clocks = <&clks IMX6SLL_CLK_UART5_IPG>, diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi index bb25add90f19a5f6d886cee7378fbc6b9f52853d..531a52c1e987e58a5aea405e2504e6dbaa4368e9 100644 --- a/arch/arm/boot/dts/imx6sx.dtsi +++ b/arch/arm/boot/dts/imx6sx.dtsi @@ -90,15 +90,6 @@ }; }; - intc: interrupt-controller@a01000 { - compatible = "arm,cortex-a9-gic"; - #interrupt-cells = <3>; - interrupt-controller; - reg = <0x00a01000 0x1000>, - <0x00a00100 0x100>; - interrupt-parent = <&intc>; - }; - ckil: clock-ckil { compatible = "fixed-clock"; #clock-cells = <0>; @@ -181,6 +172,15 @@ clocks = <&clks IMX6SX_CLK_OCRAM>; }; + intc: interrupt-controller@a01000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x00a01000 0x1000>, + <0x00a00100 0x100>; + interrupt-parent = <&intc>; + }; + L2: l2-cache@a02000 { compatible = "arm,pl310-cache"; reg = <0x00a02000 0x1000>; @@ -926,8 +926,8 @@ <&clks IMX6SX_CLK_ENET_PTP>; clock-names = "ipg", "ahb", "ptp", "enet_clk_ref", "enet_out"; - fsl,num-tx-queues=<3>; - fsl,num-rx-queues=<3>; + fsl,num-tx-queues = <3>; + fsl,num-rx-queues = <3>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/imx6ul-kontron-n6310-s-43.dts b/arch/arm/boot/dts/imx6ul-kontron-n6310-s-43.dts new file mode 100644 index 0000000000000000000000000000000000000000..5bad29683cc36040355ffbf815e70bb2bd1a0e25 --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-kontron-n6310-s-43.dts @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 exceet electronics GmbH + * Copyright (C) 2018 Kontron Electronics GmbH + * Copyright (c) 2019 Krzysztof Kozlowski + */ + +#include "imx6ul-kontron-n6310-s.dts" + +/ { + model = "Kontron N6310 S 43"; + compatible = "kontron,imx6ul-n6310-s-43", "kontron,imx6ul-n6310-s", + "kontron,imx6ul-n6310-som", "fsl,imx6ul"; + + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm7 0 5000000>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + status = "okay"; + }; +}; + +&i2c4 { + touchscreen@5d { + compatible = "goodix,gt928"; + reg = <0x5d>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cap_touch>; + interrupt-parent = <&gpio5>; + interrupts = <6 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio5 8 GPIO_ACTIVE_HIGH>; + irq-gpios = <&gpio5 6 GPIO_ACTIVE_HIGH>; + }; +}; + +&lcdif { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcdif_dat &pinctrl_lcdif_ctrl>; + /* Leave status disabled because of missing display panel node */ +}; + +&pwm7 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm7>; + status = "okay"; +}; + +&iomuxc { + pinctrl_cap_touch: captouchgrp { + fsl,pins = < + MX6UL_PAD_SNVS_TAMPER6__GPIO5_IO06 0x1b0b0 /* Touch Interrupt */ + MX6UL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x1b0b0 /* Touch Reset */ + MX6UL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x1b0b0 /* Touch Wake */ + >; + }; + + pinctrl_lcdif_ctrl: lcdifctrlgrp { + fsl,pins = < + MX6UL_PAD_LCD_CLK__LCDIF_CLK 0x79 + MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE 0x79 + MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC 0x79 + MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC 0x79 + MX6UL_PAD_LCD_RESET__LCDIF_RESET 0x79 + >; + }; + + pinctrl_lcdif_dat: lcdifdatgrp { + fsl,pins = < + MX6UL_PAD_LCD_DATA00__LCDIF_DATA00 0x79 + MX6UL_PAD_LCD_DATA01__LCDIF_DATA01 0x79 + MX6UL_PAD_LCD_DATA02__LCDIF_DATA02 0x79 + MX6UL_PAD_LCD_DATA03__LCDIF_DATA03 0x79 + MX6UL_PAD_LCD_DATA04__LCDIF_DATA04 0x79 + MX6UL_PAD_LCD_DATA05__LCDIF_DATA05 0x79 + MX6UL_PAD_LCD_DATA06__LCDIF_DATA06 0x79 + MX6UL_PAD_LCD_DATA07__LCDIF_DATA07 0x79 + MX6UL_PAD_LCD_DATA08__LCDIF_DATA08 0x79 + MX6UL_PAD_LCD_DATA09__LCDIF_DATA09 0x79 + MX6UL_PAD_LCD_DATA10__LCDIF_DATA10 0x79 + MX6UL_PAD_LCD_DATA11__LCDIF_DATA11 0x79 + MX6UL_PAD_LCD_DATA12__LCDIF_DATA12 0x79 + MX6UL_PAD_LCD_DATA13__LCDIF_DATA13 0x79 + MX6UL_PAD_LCD_DATA14__LCDIF_DATA14 0x79 + MX6UL_PAD_LCD_DATA15__LCDIF_DATA15 0x79 + MX6UL_PAD_LCD_DATA16__LCDIF_DATA16 0x79 + MX6UL_PAD_LCD_DATA17__LCDIF_DATA17 0x79 + MX6UL_PAD_LCD_DATA18__LCDIF_DATA18 0x79 + MX6UL_PAD_LCD_DATA19__LCDIF_DATA19 0x79 + MX6UL_PAD_LCD_DATA20__LCDIF_DATA20 0x79 + MX6UL_PAD_LCD_DATA21__LCDIF_DATA21 0x79 + MX6UL_PAD_LCD_DATA22__LCDIF_DATA22 0x79 + MX6UL_PAD_LCD_DATA23__LCDIF_DATA23 0x79 + >; + }; + + pinctrl_pwm7: pwm7grp { + fsl,pins = < + MX6UL_PAD_CSI_VSYNC__PWM7_OUT 0x110b0 + >; + }; +}; diff --git a/arch/arm/boot/dts/imx6ul-kontron-n6310-s.dts b/arch/arm/boot/dts/imx6ul-kontron-n6310-s.dts new file mode 100644 index 0000000000000000000000000000000000000000..0205fd56d9754b2c0899ebf8ba46457bdfe99f22 --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-kontron-n6310-s.dts @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 exceet electronics GmbH + * Copyright (C) 2018 Kontron Electronics GmbH + * Copyright (c) 2019 Krzysztof Kozlowski + */ + +/dts-v1/; + +#include "imx6ul-kontron-n6310-som.dtsi" + +/ { + model = "Kontron N6310 S"; + compatible = "kontron,imx6ul-n6310-s", "kontron,imx6ul-n6310-som", + "fsl,imx6ul"; + + gpio-leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_leds>; + + led1 { + label = "debug-led1"; + gpios = <&gpio1 30 GPIO_ACTIVE_LOW>; + default-state = "off"; + linux,default-trigger = "heartbeat"; + }; + + led2 { + label = "debug-led2"; + gpios = <&gpio5 3 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led3 { + label = "debug-led3"; + gpios = <&gpio5 2 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + }; + + pwm-beeper { + compatible = "pwm-beeper"; + pwms = <&pwm8 0 5000>; + }; + + reg_3v3: regulator-3v3 { + compatible = "regulator-fixed"; + regulator-name = "3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + reg_usb_otg1_vbus: regulator-usb-otg1-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_otg1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 4 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_vref_adc: regulator-vref-adc { + compatible = "regulator-fixed"; + regulator-name = "vref-adc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; +}; + +&adc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_adc1>; + num-channels = <3>; + vref-supply = <®_vref_adc>; + status = "okay"; +}; + +&can2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan2>; + status = "okay"; +}; + +&ecspi1 { + cs-gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi1>; + status = "okay"; + + eeprom@0 { + compatible = "anvo,anv32e61w", "atmel,at25"; + reg = <0>; + spi-max-frequency = <20000000>; + spi-cpha; + spi-cpol; + pagesize = <1>; + size = <8192>; + address-width = <16>; + }; +}; + +&fec1 { + pinctrl-0 = <&pinctrl_enet1>; + /delete-node/ mdio; +}; + +&fec2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet2 &pinctrl_enet2_mdio>; + phy-mode = "rmii"; + phy-handle = <ðphy2>; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy1: ethernet-phy@1 { + reg = <1>; + micrel,led-mode = <0>; + clocks = <&clks IMX6UL_CLK_ENET_REF>; + clock-names = "rmii-ref"; + }; + + ethphy2: ethernet-phy@2 { + reg = <2>; + micrel,led-mode = <0>; + clocks = <&clks IMX6UL_CLK_ENET2_REF>; + clock-names = "rmii-ref"; + }; + }; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; +}; + +&i2c4 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c4>; + status = "okay"; + + rtc@32 { + compatible = "epson,rx8900"; + reg = <0x32>; + }; +}; + +&pwm8 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm8>; + status = "okay"; +}; + +&snvs_poweroff { + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + linux,rs485-enabled-at-boot-time; + rs485-rx-during-tx; + rs485-rts-active-low; + uart-has-rtscts; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + fsl,uart-has-rtscts; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; + status = "okay"; +}; + +&usbotg1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg1>; + dr_mode = "otg"; + srp-disable; + hnp-disable; + adp-disable; + vbus-supply = <®_usb_otg1_vbus>; + status = "okay"; +}; + +&usbotg2 { + dr_mode = "host"; + disable-over-current; + status = "okay"; +}; + +&usdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc1>; + cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>; + keep-power-in-suspend; + wakeup-source; + vmmc-supply = <®_3v3>; + voltage-ranges = <3300 3300>; + no-1-8-v; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>; + non-removable; + keep-power-in-suspend; + wakeup-source; + vmmc-supply = <®_3v3>; + voltage-ranges = <3300 3300>; + no-1-8-v; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; + status = "okay"; +}; + +&iomuxc { + pinctrl-0 = <&pinctrl_reset_out &pinctrl_gpio>; + + pinctrl_adc1: adc1grp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO02__GPIO1_IO02 0xb0 + MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0xb0 + MX6UL_PAD_GPIO1_IO08__GPIO1_IO08 0xb0 + >; + }; + + /* FRAM */ + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6UL_PAD_CSI_DATA07__ECSPI1_MISO 0x100b1 + MX6UL_PAD_CSI_DATA06__ECSPI1_MOSI 0x100b1 + MX6UL_PAD_CSI_DATA04__ECSPI1_SCLK 0x100b1 + MX6UL_PAD_CSI_DATA05__GPIO4_IO26 0x100b1 /* ECSPI1-CS1 */ + >; + }; + + pinctrl_enet2: enet2grp { + fsl,pins = < + MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0 + MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0 + MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0 + MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0 + MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0 + MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0 + MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0 + MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b009 + >; + }; + + pinctrl_enet2_mdio: enet2mdiogrp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0 + MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0 + >; + }; + + pinctrl_flexcan2: flexcan2grp{ + fsl,pins = < + MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX 0x1b020 + MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX 0x1b020 + >; + }; + + pinctrl_gpio: gpiogrp { + fsl,pins = < + MX6UL_PAD_SNVS_TAMPER5__GPIO5_IO05 0x1b0b0 /* DOUT1 */ + MX6UL_PAD_SNVS_TAMPER4__GPIO5_IO04 0x1b0b0 /* DIN1 */ + MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x1b0b0 /* DOUT2 */ + MX6UL_PAD_SNVS_TAMPER0__GPIO5_IO00 0x1b0b0 /* DIN2 */ + >; + }; + + pinctrl_gpio_leds: gpioledsgrp { + fsl,pins = < + MX6UL_PAD_UART5_TX_DATA__GPIO1_IO30 0x1b0b0 /* LED H14 */ + MX6UL_PAD_SNVS_TAMPER3__GPIO5_IO03 0x1b0b0 /* LED H15 */ + MX6UL_PAD_SNVS_TAMPER2__GPIO5_IO02 0x1b0b0 /* LED H16 */ + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6UL_PAD_CSI_PIXCLK__I2C1_SCL 0x4001b8b0 + MX6UL_PAD_CSI_MCLK__I2C1_SDA 0x4001b8b0 + >; + }; + + pinctrl_i2c4: i2c4grp { + fsl,pins = < + MX6UL_PAD_UART2_TX_DATA__I2C4_SCL 0x4001f8b0 + MX6UL_PAD_UART2_RX_DATA__I2C4_SDA 0x4001f8b0 + >; + }; + + pinctrl_pwm8: pwm8grp { + fsl,pins = < + MX6UL_PAD_CSI_HSYNC__PWM8_OUT 0x110b0 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1 + MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6UL_PAD_NAND_DATA04__UART2_DCE_TX 0x1b0b1 + MX6UL_PAD_NAND_DATA05__UART2_DCE_RX 0x1b0b1 + MX6UL_PAD_NAND_DATA06__UART2_DCE_CTS 0x1b0b1 + /* + * mux unused RTS to make sure it doesn't cause + * any interrupts when it is undefined + */ + MX6UL_PAD_NAND_DATA07__UART2_DCE_RTS 0x1b0b1 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX 0x1b0b1 + MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX 0x1b0b1 + MX6UL_PAD_UART3_CTS_B__UART3_DCE_CTS 0x1b0b1 + MX6UL_PAD_UART3_RTS_B__UART3_DCE_RTS 0x1b0b1 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6UL_PAD_UART4_TX_DATA__UART4_DCE_TX 0x1b0b1 + MX6UL_PAD_UART4_RX_DATA__UART4_DCE_RX 0x1b0b1 + >; + }; + + pinctrl_usbotg1: usbotg1 { + fsl,pins = < + MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0x1b0b0 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x17059 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x10059 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x17059 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x17059 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x17059 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x17059 + MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x100b1 /* SD1_CD */ + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x10059 + MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x17059 + MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059 + MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059 + MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059 + MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + fsl,pins = < + MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x100b9 + MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x170b9 + MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x170b9 + MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x170b9 + MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x170b9 + MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x170b9 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + fsl,pins = < + MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x100f9 + MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x170f9 + MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x170f9 + MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x170f9 + MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x170f9 + MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x170f9 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO09__WDOG1_WDOG_ANY 0x30b0 + >; + }; +}; diff --git a/arch/arm/boot/dts/imx6ul-kontron-n6310-som.dtsi b/arch/arm/boot/dts/imx6ul-kontron-n6310-som.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a896b2348dd2fd457ddd489b4424d17cdb5c1963 --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-kontron-n6310-som.dtsi @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 exceet electronics GmbH + * Copyright (C) 2018 Kontron Electronics GmbH + * Copyright (c) 2019 Krzysztof Kozlowski + */ + +#include "imx6ul.dtsi" +#include + +/ { + model = "Kontron N6310 SOM"; + compatible = "kontron,imx6ul-n6310-som", "fsl,imx6ul"; + + memory@80000000 { + reg = <0x80000000 0x10000000>; + device_type = "memory"; + }; +}; + +&ecspi2 { + cs-gpios = <&gpio4 22 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi2>; + status = "okay"; + + spi-flash@0 { + compatible = "mxicy,mx25v8035f", "jedec,spi-nor"; + spi-max-frequency = <50000000>; + reg = <0>; + }; +}; + +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet1 &pinctrl_enet1_mdio>; + phy-mode = "rmii"; + phy-handle = <ðphy1>; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy1: ethernet-phy@1 { + reg = <1>; + micrel,led-mode = <0>; + clocks = <&clks IMX6UL_CLK_ENET_REF>; + clock-names = "rmii-ref"; + }; + }; +}; + +&fec2 { + phy-mode = "rmii"; + status = "disabled"; +}; + +&qspi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi>; + status = "okay"; + + spi-flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spi-nand"; + spi-max-frequency = <108000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + reg = <0>; + + partition@0 { + label = "ubi1"; + reg = <0x00000000 0x08000000>; + }; + + partition@8000000 { + label = "ubi2"; + reg = <0x08000000 0x08000000>; + }; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reset_out>; + + pinctrl_ecspi2: ecspi2grp { + fsl,pins = < + MX6UL_PAD_CSI_DATA03__ECSPI2_MISO 0x100b1 + MX6UL_PAD_CSI_DATA02__ECSPI2_MOSI 0x100b1 + MX6UL_PAD_CSI_DATA00__ECSPI2_SCLK 0x100b1 + MX6UL_PAD_CSI_DATA01__GPIO4_IO22 0x100b1 + >; + }; + + pinctrl_enet1: enet1grp { + fsl,pins = < + MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0 + MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0 + MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0 + MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0 + MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b0b0 + MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0 + MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0 + MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b009 + >; + }; + + pinctrl_enet1_mdio: enet1mdiogrp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO07__ENET1_MDC 0x1b0b0 + MX6UL_PAD_GPIO1_IO06__ENET1_MDIO 0x1b0b0 + >; + }; + + pinctrl_qspi: qspigrp { + fsl,pins = < + MX6UL_PAD_NAND_WP_B__QSPI_A_SCLK 0x70a1 + MX6UL_PAD_NAND_READY_B__QSPI_A_DATA00 0x70a1 + MX6UL_PAD_NAND_CE0_B__QSPI_A_DATA01 0x70a1 + MX6UL_PAD_NAND_CE1_B__QSPI_A_DATA02 0x70a1 + MX6UL_PAD_NAND_CLE__QSPI_A_DATA03 0x70a1 + MX6UL_PAD_NAND_DQS__QSPI_A_SS0_B 0x70a1 + >; + }; + + pinctrl_reset_out: rstoutgrp { + fsl,pins = < + MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x1b0b0 + >; + }; +}; diff --git a/arch/arm/boot/dts/imx6ul-opos6uldev.dts b/arch/arm/boot/dts/imx6ul-opos6uldev.dts index 0e59ee57fd553304fc7cbae6feeb45a1ef754283..8ecdb9ad2b2e149d5fc52431a38b2d91fc5de29a 100644 --- a/arch/arm/boot/dts/imx6ul-opos6uldev.dts +++ b/arch/arm/boot/dts/imx6ul-opos6uldev.dts @@ -56,7 +56,7 @@ stdout-path = &uart1; }; - backlight { + backlight: backlight { compatible = "pwm-backlight"; pwms = <&pwm3 0 191000>; brightness-levels = <0 4 8 16 32 64 128 255>; @@ -97,6 +97,18 @@ gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>; }; + panel: panel { + compatible = "armadeus,st0700-adapt"; + power-supply = <®_3v3>; + backlight = <&backlight>; + + port { + panel_in: endpoint { + remote-endpoint = <&lcdif_out>; + }; + }; + }; + reg_5v: regulator-5v { compatible = "regulator-fixed"; regulator-name = "5V"; @@ -182,28 +194,11 @@ &lcdif { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lcdif>; - display = <&display0>; - lcd-supply = <®_3v3>; status = "okay"; - display0: display0 { - bits-per-pixel = <32>; - bus-width = <18>; - - display-timings { - timing0: timing0 { - clock-frequency = <33000033>; - hactive = <800>; - vactive = <480>; - hback-porch = <96>; - hfront-porch = <96>; - vback-porch = <20>; - vfront-porch = <21>; - hsync-len = <64>; - vsync-len = <4>; - de-active = <1>; - pixelclk-active = <0>; - }; + port { + lcdif_out: endpoint { + remote-endpoint = <&panel_in>; }; }; }; diff --git a/arch/arm/boot/dts/imx6ul-phytec-pcl063.dtsi b/arch/arm/boot/dts/imx6ul-phytec-phycore-som.dtsi similarity index 71% rename from arch/arm/boot/dts/imx6ul-phytec-pcl063.dtsi rename to arch/arm/boot/dts/imx6ul-phytec-phycore-som.dtsi index fc2997449b49b60f09021b97bde3cb1af74e0f3c..41f3b7f62bbf7a7d26ec88abf3ee03acb619141d 100644 --- a/arch/arm/boot/dts/imx6ul-phytec-pcl063.dtsi +++ b/arch/arm/boot/dts/imx6ul-phytec-phycore-som.dtsi @@ -7,10 +7,9 @@ #include #include #include -#include "imx6ul.dtsi" / { - model = "Phytec phyCORE i.MX6 UltraLite"; + model = "PHYTEC phyCORE-i.MX6 UltraLite"; compatible = "phytec,imx6ul-pcl063", "fsl,imx6ul"; chosen { @@ -31,8 +30,7 @@ pinctrl-0 = <&pinctrl_gpioleds_som>; compatible = "gpio-leds"; - led_green { - label = "phycore:green"; + phycore-green { gpios = <&gpio5 4 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; }; @@ -43,20 +41,21 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet1>; phy-mode = "rmii"; - phy-handle = <ðphy0>; - status = "okay"; + phy-handle = <ðphy1>; + status = "disabled"; mdio: mdio { #address-cells = <1>; #size-cells = <0>; - ethphy0: ethernet-phy@1 { + ethphy1: ethernet-phy@1 { reg = <1>; interrupt-parent = <&gpio1>; interrupts = <2 IRQ_TYPE_LEVEL_LOW>; micrel,led-mode = <1>; clocks = <&clks IMX6UL_CLK_ENET_REF>; clock-names = "rmii-ref"; + status = "disabled"; }; }; }; @@ -65,12 +64,12 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_gpmi_nand>; nand-on-flash-bbt; - status = "okay"; + status = "disabled"; }; &i2c1 { pinctrl-names = "default"; - pinctrl-0 =<&pinctrl_i2c1>; + pinctrl-0 = <&pinctrl_i2c1>; clock-frequency = <100000>; status = "okay"; @@ -90,19 +89,28 @@ status = "okay"; }; +&usdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2>; + bus-width = <8>; + no-1-8-v; + non-removable; + status = "disabled"; +}; + &iomuxc { pinctrl_enet1: enet1grp { fsl,pins = < - MX6UL_PAD_GPIO1_IO07__ENET1_MDC 0x1b0b0 - MX6UL_PAD_GPIO1_IO06__ENET1_MDIO 0x1b0b0 + MX6UL_PAD_GPIO1_IO07__ENET1_MDC 0x10010 + MX6UL_PAD_GPIO1_IO06__ENET1_MDIO 0x10010 MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0 MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0 MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0 MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0 - MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b0b0 - MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0 - MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0 - MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b031 + MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b010 + MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b010 + MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b010 + MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b010 MX6UL_PAD_GPIO1_IO02__GPIO1_IO02 0x17059 >; }; @@ -145,4 +153,19 @@ >; }; + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x170f9 + MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x100f9 + MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x170f9 + MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x170f9 + MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x170f9 + MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x170f9 + MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x170f9 + MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x170f9 + MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x170f9 + MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x170f9 + >; + }; + }; diff --git a/arch/arm/boot/dts/imx6ul-phytec-phyboard-segin-full.dts b/arch/arm/boot/dts/imx6ul-phytec-segin-ff-rdk-nand.dts similarity index 51% rename from arch/arm/boot/dts/imx6ul-phytec-phyboard-segin-full.dts rename to arch/arm/boot/dts/imx6ul-phytec-segin-ff-rdk-nand.dts index b6a1407a9d4409e0aa5d550899ebed10d8e08000..699dfcbf9a60837bf008c3fa8b895dd426f3c7ec 100644 --- a/arch/arm/boot/dts/imx6ul-phytec-phyboard-segin-full.dts +++ b/arch/arm/boot/dts/imx6ul-phytec-segin-ff-rdk-nand.dts @@ -5,13 +5,15 @@ */ /dts-v1/; -#include "imx6ul-phytec-pcl063.dtsi" -#include "imx6ul-phytec-phyboard-segin.dtsi" -#include "imx6ul-phytec-peb-eval-01.dtsi" +#include "imx6ul.dtsi" +#include "imx6ul-phytec-phycore-som.dtsi" +#include "imx6ul-phytec-segin.dtsi" +#include "imx6ul-phytec-segin-peb-eval-01.dtsi" / { - model = "Phytec phyBOARD-Segin i.MX6 UltraLite Full Featured"; - compatible = "phytec,imx6ul-pbacd10", "phytec,imx6ul-pcl063", "fsl,imx6ul"; + model = "PHYTEC phyBOARD-Segin i.MX6 UltraLite Full Featured with NAND"; + compatible = "phytec,imx6ul-pbacd10-nand", "phytec,imx6ul-pbacd10", + "phytec,imx6ul-pcl063", "fsl,imx6ul"; }; &adc1 { @@ -27,9 +29,18 @@ }; &ecspi3 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi3>; - cs-gpios = <&gpio1 20 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +ðphy1 { + status = "okay"; +}; + +ðphy2 { + status = "okay"; +}; + +&fec1 { status = "okay"; }; @@ -37,6 +48,10 @@ status = "okay"; }; +&gpmi { + status = "okay"; +}; + &i2c_rtc { status = "okay"; }; @@ -76,14 +91,3 @@ &usdhc1 { status = "okay"; }; - -&iomuxc { - pinctrl_ecspi3: ecspi3grp { - fsl,pins = < - MX6UL_PAD_UART2_RTS_B__ECSPI3_MISO 0x10b0 - MX6UL_PAD_UART2_CTS_B__ECSPI3_MOSI 0x10b0 - MX6UL_PAD_UART2_RX_DATA__ECSPI3_SCLK 0x10b0 - MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20 0x10b0 - >; - }; -}; diff --git a/arch/arm/boot/dts/imx6ul-phytec-peb-eval-01.dtsi b/arch/arm/boot/dts/imx6ul-phytec-segin-peb-eval-01.dtsi similarity index 84% rename from arch/arm/boot/dts/imx6ul-phytec-peb-eval-01.dtsi rename to arch/arm/boot/dts/imx6ul-phytec-segin-peb-eval-01.dtsi index e2f38f39a6ad47b0cd80d3a9fdaf26fe0e1b5dc2..2f3fd32a116795ada43a78d967704fa988f7ba3a 100644 --- a/arch/arm/boot/dts/imx6ul-phytec-peb-eval-01.dtsi +++ b/arch/arm/boot/dts/imx6ul-phytec-segin-peb-eval-01.dtsi @@ -21,20 +21,22 @@ }; }; - user_leds: leds { + user_leds: user-leds { compatible = "gpio-leds"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_user_leds>; status = "disabled"; - led_yellow { - gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-on"; + user-led1 { + gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "gpio"; + default-state = "on"; }; - led_red { - gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "default-on"; + user-led2 { + gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "gpio"; + default-state = "on"; }; }; }; diff --git a/arch/arm/boot/dts/imx6ul-phytec-phyboard-segin.dtsi b/arch/arm/boot/dts/imx6ul-phytec-segin.dtsi similarity index 91% rename from arch/arm/boot/dts/imx6ul-phytec-phyboard-segin.dtsi rename to arch/arm/boot/dts/imx6ul-phytec-segin.dtsi index 7bf439a77d2cad8df3e760cbde92900814f5d492..8d5f8dc6ad58cd9e303851261539d03ab740208a 100644 --- a/arch/arm/boot/dts/imx6ul-phytec-phyboard-segin.dtsi +++ b/arch/arm/boot/dts/imx6ul-phytec-segin.dtsi @@ -5,7 +5,7 @@ */ / { - model = "Phytec phyBOARD-Segin i.MX6 UltraLite"; + model = "PHYTEC phyBOARD-Segin i.MX6 UltraLite"; compatible = "phytec,imx6ul-pbacd-10", "phytec,imx6ul-pcl063", "fsl,imx6ul"; aliases { @@ -103,11 +103,18 @@ assigned-clock-rates = <786432000>; }; +&ecspi3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi3>; + cs-gpios = <&gpio1 20 GPIO_ACTIVE_HIGH>; + status = "disabled"; +}; + &fec2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet2>; phy-mode = "rmii"; - phy-handle = <ðphy1>; + phy-handle = <ðphy2>; status = "disabled"; }; @@ -160,11 +167,12 @@ }; &mdio { - ethphy1: ethernet-phy@2 { + ethphy2: ethernet-phy@2 { reg = <2>; micrel,led-mode = <1>; clocks = <&clks IMX6UL_CLK_ENET2_REF>; clock-names = "rmii-ref"; + status = "disabled"; }; }; @@ -224,16 +232,25 @@ >; }; + pinctrl_ecspi3: ecspi3grp { + fsl,pins = < + MX6UL_PAD_UART2_RTS_B__ECSPI3_MISO 0x10b0 + MX6UL_PAD_UART2_CTS_B__ECSPI3_MOSI 0x10b0 + MX6UL_PAD_UART2_RX_DATA__ECSPI3_SCLK 0x10b0 + MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20 0x10b0 + >; + }; + pinctrl_enet2: enet2grp { fsl,pins = < MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0 MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0 MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0 MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0 - MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0 - MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0 - MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0 - MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b031 + MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b010 + MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b010 + MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b010 + MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b010 >; }; diff --git a/arch/arm/boot/dts/imx6ul.dtsi b/arch/arm/boot/dts/imx6ul.dtsi index 81d4b4925127fe025e6dac4dfc5aeeae8ab904ec..f008036e9294825898426f80ec6ec039dbcf3011 100644 --- a/arch/arm/boot/dts/imx6ul.dtsi +++ b/arch/arm/boot/dts/imx6ul.dtsi @@ -93,18 +93,6 @@ }; }; - intc: interrupt-controller@a01000 { - compatible = "arm,gic-400", "arm,cortex-a7-gic"; - interrupts = ; - #interrupt-cells = <3>; - interrupt-controller; - interrupt-parent = <&intc>; - reg = <0x00a01000 0x1000>, - <0x00a02000 0x2000>, - <0x00a04000 0x2000>, - <0x00a06000 0x2000>; - }; - timer { compatible = "arm,armv7-timer"; interrupts = , @@ -171,6 +159,18 @@ reg = <0x00900000 0x20000>; }; + intc: interrupt-controller@a01000 { + compatible = "arm,gic-400", "arm,cortex-a7-gic"; + interrupts = ; + #interrupt-cells = <3>; + interrupt-controller; + interrupt-parent = <&intc>; + reg = <0x00a01000 0x1000>, + <0x00a02000 0x2000>, + <0x00a04000 0x2000>, + <0x00a06000 0x2000>; + }; + dma_apbh: dma-apbh@1804000 { compatible = "fsl,imx6q-dma-apbh", "fsl,imx28-dma-apbh"; reg = <0x01804000 0x2000>; @@ -227,6 +227,8 @@ clocks = <&clks IMX6UL_CLK_ECSPI1>, <&clks IMX6UL_CLK_ECSPI1>; clock-names = "ipg", "per"; + dmas = <&sdma 3 7 1>, <&sdma 4 7 2>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -239,6 +241,8 @@ clocks = <&clks IMX6UL_CLK_ECSPI2>, <&clks IMX6UL_CLK_ECSPI2>; clock-names = "ipg", "per"; + dmas = <&sdma 5 7 1>, <&sdma 6 7 2>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -251,6 +255,8 @@ clocks = <&clks IMX6UL_CLK_ECSPI3>, <&clks IMX6UL_CLK_ECSPI3>; clock-names = "ipg", "per"; + dmas = <&sdma 7 7 1>, <&sdma 8 7 2>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -263,6 +269,8 @@ clocks = <&clks IMX6UL_CLK_ECSPI4>, <&clks IMX6UL_CLK_ECSPI4>; clock-names = "ipg", "per"; + dmas = <&sdma 9 7 1>, <&sdma 10 7 2>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -510,8 +518,8 @@ <&clks IMX6UL_CLK_ENET2_REF_125M>; clock-names = "ipg", "ahb", "ptp", "enet_clk_ref", "enet_out"; - fsl,num-tx-queues=<1>; - fsl,num-rx-queues=<1>; + fsl,num-tx-queues = <1>; + fsl,num-rx-queues = <1>; status = "disabled"; }; @@ -845,8 +853,8 @@ <&clks IMX6UL_CLK_ENET_REF>; clock-names = "ipg", "ahb", "ptp", "enet_clk_ref", "enet_out"; - fsl,num-tx-queues=<1>; - fsl,num-rx-queues=<1>; + fsl,num-tx-queues = <1>; + fsl,num-rx-queues = <1>; status = "disabled"; }; @@ -858,7 +866,7 @@ <&clks IMX6UL_CLK_USDHC1>, <&clks IMX6UL_CLK_USDHC1>; clock-names = "ipg", "ahb", "per"; - fsl,tuning-step= <2>; + fsl,tuning-step = <2>; fsl,tuning-start-tap = <20>; bus-width = <4>; status = "disabled"; @@ -873,7 +881,7 @@ <&clks IMX6UL_CLK_USDHC2>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; - fsl,tuning-step= <2>; + fsl,tuning-step = <2>; fsl,tuning-start-tap = <20>; status = "disabled"; }; @@ -957,6 +965,15 @@ }; }; + csi: csi@21c4000 { + compatible = "fsl,imx6ul-csi", "fsl,imx7-csi"; + reg = <0x021c4000 0x4000>; + interrupts = ; + clocks = <&clks IMX6UL_CLK_CSI>; + clock-names = "mclk"; + status = "disabled"; + }; + lcdif: lcdif@21c8000 { compatible = "fsl,imx6ul-lcdif", "fsl,imx28-lcdif"; reg = <0x021c8000 0x4000>; diff --git a/arch/arm/boot/dts/imx6ull-phytec-phycore-som.dtsi b/arch/arm/boot/dts/imx6ull-phytec-phycore-som.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..56cd16e5a77feb68a5c43ec131f1d6583de2c336 --- /dev/null +++ b/arch/arm/boot/dts/imx6ull-phytec-phycore-som.dtsi @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2019 PHYTEC Messtechnik GmbH + * Author: Stefan Riedmueller + */ + +#include "imx6ul-phytec-phycore-som.dtsi" + +/ { + model = "PHYTEC phyCORE-i.MX6 ULL"; + compatible = "phytec,imx6ull-pcl063", "fsl,imx6ull"; +}; + +&iomuxc { + /delete-node/ gpioledssomgrp; +}; + +&iomuxc_snvs { + pinctrl_gpioleds_som: gpioledssomgrp { + fsl,pins = < + MX6ULL_PAD_SNVS_TAMPER4__GPIO5_IO04 0x0b0b0 + >; + }; +}; diff --git a/arch/arm/boot/dts/imx6ull-phytec-segin-ff-rdk-emmc.dts b/arch/arm/boot/dts/imx6ull-phytec-segin-ff-rdk-emmc.dts new file mode 100644 index 0000000000000000000000000000000000000000..9648d4ecaf58ed124bf87d7992d36099879c07cc --- /dev/null +++ b/arch/arm/boot/dts/imx6ull-phytec-segin-ff-rdk-emmc.dts @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2019 PHYTEC Messtechnik GmbH + * Author: Stefan Riedmueller + */ + +/dts-v1/; +#include "imx6ull.dtsi" +#include "imx6ull-phytec-phycore-som.dtsi" +#include "imx6ull-phytec-segin.dtsi" +#include "imx6ull-phytec-segin-peb-eval-01.dtsi" + +/ { + model = "PHYTEC phyBOARD-Segin i.MX6 ULL Full Featured with eMMC"; + compatible = "phytec,imx6ull-pbacd10-emmc", "phytec,imx6ull-pbacd10", + "phytec,imx6ull-pcl063","fsl,imx6ull"; +}; + +&adc1 { + status = "okay"; +}; + +&can1 { + status = "okay"; +}; + +&tlv320 { + status = "okay"; +}; + +&ecspi3 { + status = "okay"; +}; + +ðphy1 { + status = "okay"; +}; + +ðphy2 { + status = "okay"; +}; + +&fec1 { + status = "okay"; +}; + +&fec2 { + status = "okay"; +}; + +&i2c_rtc { + status = "okay"; +}; + +®_can1_en { + status = "okay"; +}; + +®_sound_1v8 { + status = "okay"; +}; + +®_sound_3v3 { + status = "okay"; +}; + +&sai2 { + status = "okay"; +}; + +&sound { + status = "okay"; +}; + +&uart5 { + status = "okay"; +}; + +&usbotg1 { + status = "okay"; +}; + +&usbotg2 { + status = "okay"; +}; + +&usdhc1 { + status = "okay"; +}; + +&usdhc2 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6ull-phytec-segin-ff-rdk-nand.dts b/arch/arm/boot/dts/imx6ull-phytec-segin-ff-rdk-nand.dts new file mode 100644 index 0000000000000000000000000000000000000000..656baf846453a4cbcce04afd32853d1e117e4a26 --- /dev/null +++ b/arch/arm/boot/dts/imx6ull-phytec-segin-ff-rdk-nand.dts @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2019 PHYTEC Messtechnik GmbH + * Author: Stefan Riedmueller + */ + +/dts-v1/; +#include "imx6ull.dtsi" +#include "imx6ull-phytec-phycore-som.dtsi" +#include "imx6ull-phytec-segin.dtsi" +#include "imx6ull-phytec-segin-peb-eval-01.dtsi" + +/ { + model = "PHYTEC phyBOARD-Segin i.MX6 ULL Full Featured with NAND"; + compatible = "phytec,imx6ull-pbacd10-nand", "phytec,imx6ull-pbacd10", + "phytec,imx6ull-pcl063", "fsl,imx6ull"; +}; + +&adc1 { + status = "okay"; +}; + +&can1 { + status = "okay"; +}; + +&tlv320 { + status = "okay"; +}; + +&ecspi3 { + status = "okay"; +}; + +ðphy1 { + status = "okay"; +}; + +ðphy2 { + status = "okay"; +}; + +&fec1 { + status = "okay"; +}; + +&fec2 { + status = "okay"; +}; + +&gpmi { + status = "okay"; +}; + +&i2c_rtc { + status = "okay"; +}; + +®_can1_en { + status = "okay"; +}; + +®_sound_1v8 { + status = "okay"; +}; + +®_sound_3v3 { + status = "okay"; +}; + +&sai2 { + status = "okay"; +}; + +&sound { + status = "okay"; +}; + +&uart5 { + status = "okay"; +}; + +&usbotg1 { + status = "okay"; +}; + +&usbotg2 { + status = "okay"; +}; + +&usdhc1 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6ull-phytec-segin-lc-rdk-nand.dts b/arch/arm/boot/dts/imx6ull-phytec-segin-lc-rdk-nand.dts new file mode 100644 index 0000000000000000000000000000000000000000..e168494e0a6d3e1ba0830c807c4d367b6000f287 --- /dev/null +++ b/arch/arm/boot/dts/imx6ull-phytec-segin-lc-rdk-nand.dts @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2019 PHYTEC Messtechnik GmbH + * Author: Stefan Riedmueller + */ + +/dts-v1/; +#include "imx6ull.dtsi" +#include "imx6ull-phytec-phycore-som.dtsi" +#include "imx6ull-phytec-segin.dtsi" +#include "imx6ull-phytec-segin-peb-eval-01.dtsi" + +/ { + model = "PHYTEC phyBOARD-Segin i.MX6 ULL Low Cost with NAND"; + compatible = "phytec,imx6ull-pbacd10-nand", "phytec,imx6ull-pbacd10", + "phytec,imx6ull-pcl063", "fsl,imx6ull"; +}; + +&adc1 { + status = "okay"; +}; + +ðphy1 { + status = "okay"; +}; + +&fec1 { + status = "okay"; +}; + +&gpmi { + status = "okay"; +}; + +&i2c_rtc { + status = "okay"; +}; + +&usbotg1 { + status = "okay"; +}; + +&usdhc1 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6ull-phytec-segin-peb-eval-01.dtsi b/arch/arm/boot/dts/imx6ull-phytec-segin-peb-eval-01.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ff08d95a1aa2b33760a19e2e67fbd8d7a1b3a8e3 --- /dev/null +++ b/arch/arm/boot/dts/imx6ull-phytec-segin-peb-eval-01.dtsi @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2019 PHYTEC Messtechnik GmbH + * Author: Stefan Riedmueller + */ + +#include "imx6ul-phytec-segin-peb-eval-01.dtsi" + +&iomuxc { + /delete-node/ gpio_keysgrp; +}; + +&iomuxc_snvs { + pinctrl_gpio_keys: gpio_keysgrp { + fsl,pins = < + MX6ULL_PAD_SNVS_TAMPER0__GPIO5_IO00 0x79 + >; + }; +}; diff --git a/arch/arm/boot/dts/imx6ull-phytec-segin.dtsi b/arch/arm/boot/dts/imx6ull-phytec-segin.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c1595fc785f7e402f4fb45c3ca4c5150baf15492 --- /dev/null +++ b/arch/arm/boot/dts/imx6ull-phytec-segin.dtsi @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2019 PHYTEC Messtechnik GmbH + * Author: Stefan Riedmueller + */ + +#include "imx6ul-phytec-segin.dtsi" + +/ { + model = "PHYTEC phyBOARD-Segin i.MX6 ULL"; + compatible = "phytec,imx6ull-pbacd-10", "phytec,imx6ull-pcl063","fsl,imx6ull"; +}; + +&iomuxc { + /delete-node/ flexcan1engrp; + /delete-node/ rtcintgrp; + /delete-node/ stmpegrp; +}; + +&iomuxc_snvs { + princtrl_flexcan1_en: flexcan1engrp { + fsl,pins = < + MX6ULL_PAD_SNVS_TAMPER2__GPIO5_IO02 0x17059 + >; + }; + + pinctrl_rtc_int: rtcintgrp { + fsl,pins = < + MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x17059 + >; + }; + + pinctrl_stmpe: stmpegrp { + fsl,pins = < + MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03 0x17059 + >; + }; +}; diff --git a/arch/arm/boot/dts/imx7-colibri.dtsi b/arch/arm/boot/dts/imx7-colibri.dtsi index 895fbde4d4333a3d5f37397feac66163911e4833..917eb0b58b132045b775d209ed52753c698d9034 100644 --- a/arch/arm/boot/dts/imx7-colibri.dtsi +++ b/arch/arm/boot/dts/imx7-colibri.dtsi @@ -54,6 +54,7 @@ regulator-name = "+V3.3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; + regulator-always-on; }; reg_module_3v3_avdd: regulator-module-3v3-avdd { @@ -61,6 +62,7 @@ regulator-name = "+V3.3_AVDD_AUDIO"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; + regulator-always-on; }; sound { @@ -99,8 +101,9 @@ }; &fec1 { - pinctrl-names = "default"; + pinctrl-names = "default", "sleep"; pinctrl-0 = <&pinctrl_enet1>; + pinctrl-1 = <&pinctrl_enet1_sleep>; clocks = <&clks IMX7D_ENET_AXI_ROOT_CLK>, <&clks IMX7D_ENET_AXI_ROOT_CLK>, <&clks IMX7D_ENET1_TIME_ROOT_CLK>, @@ -115,6 +118,18 @@ fsl,magic-packet; }; +&flexcan1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan1>; + status = "disabled"; +}; + +&flexcan2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan2>; + status = "disabled"; +}; + &gpmi { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_gpmi_nand>; @@ -125,8 +140,12 @@ &i2c1 { clock-frequency = <100000>; - pinctrl-names = "default"; + pinctrl-names = "default", "gpio"; pinctrl-0 = <&pinctrl_i2c1 &pinctrl_i2c1_int>; + pinctrl-1 = <&pinctrl_i2c1_recovery &pinctrl_i2c1_int>; + scl-gpios = <&gpio1 4 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio1 5 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "okay"; codec: sgtl5000@a { @@ -227,8 +246,11 @@ &i2c4 { clock-frequency = <100000>; - pinctrl-names = "default"; + pinctrl-names = "default", "gpio"; pinctrl-0 = <&pinctrl_i2c4>; + pinctrl-1 = <&pinctrl_i2c4_recovery>; + scl-gpios = <&gpio7 8 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio7 9 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; }; &lcdif { @@ -267,10 +289,6 @@ status = "okay"; }; -&snvs_pwrkey { - status = "disabled"; -}; - &uart1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart1 &pinctrl_uart1_ctrl1 &pinctrl_uart1_ctrl2>; @@ -323,16 +341,16 @@ vmmc-supply = <®_module_3v3>; vqmmc-supply = <®_DCDC3>; non-removable; + sdhci-caps-mask = <0x80000000 0x0>; }; &iomuxc { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_gpio1 &pinctrl_gpio2 &pinctrl_gpio3 &pinctrl_gpio4>; + pinctrl-0 = <&pinctrl_gpio1 &pinctrl_gpio2 &pinctrl_gpio3 &pinctrl_gpio4 + &pinctrl_gpio7>; pinctrl_gpio1: gpio1-grp { fsl,pins = < - MX7D_PAD_ENET1_RGMII_RD3__GPIO7_IO3 0x74 /* SODIMM 55 */ - MX7D_PAD_ENET1_RGMII_RD2__GPIO7_IO2 0x74 /* SODIMM 63 */ MX7D_PAD_SAI1_RX_SYNC__GPIO6_IO16 0x14 /* SODIMM 77 */ MX7D_PAD_EPDC_DATA09__GPIO2_IO9 0x14 /* SODIMM 89 */ MX7D_PAD_EPDC_DATA08__GPIO2_IO8 0x74 /* SODIMM 91 */ @@ -413,6 +431,13 @@ >; }; + pinctrl_gpio7: gpio7-grp { /* Alternatively CAN1 */ + fsl,pins = < + MX7D_PAD_ENET1_RGMII_RD3__GPIO7_IO3 0x14 /* SODIMM 55 */ + MX7D_PAD_ENET1_RGMII_RD2__GPIO7_IO2 0x14 /* SODIMM 63 */ + >; + }; + pinctrl_i2c1_int: i2c1-int-grp { /* PMIC / TOUCH */ fsl,pins = < MX7D_PAD_GPIO1_IO13__GPIO1_IO13 0x79 @@ -442,6 +467,22 @@ >; }; + pinctrl_enet1_sleep: enet1sleepgrp { + fsl,pins = < + MX7D_PAD_ENET1_RGMII_RX_CTL__GPIO7_IO4 0x0 + MX7D_PAD_ENET1_RGMII_RD0__GPIO7_IO0 0x0 + MX7D_PAD_ENET1_RGMII_RD1__GPIO7_IO1 0x0 + MX7D_PAD_ENET1_RGMII_RXC__GPIO7_IO5 0x0 + + MX7D_PAD_ENET1_RGMII_TX_CTL__GPIO7_IO10 0x0 + MX7D_PAD_ENET1_RGMII_TD0__GPIO7_IO6 0x0 + MX7D_PAD_ENET1_RGMII_TD1__GPIO7_IO7 0x0 + MX7D_PAD_GPIO1_IO12__GPIO1_IO12 0x0 + MX7D_PAD_SD2_CD_B__GPIO5_IO9 0x0 + MX7D_PAD_SD2_WP__GPIO5_IO10 0x0 + >; + }; + pinctrl_ecspi3_cs: ecspi3-cs-grp { fsl,pins = < MX7D_PAD_I2C2_SDA__GPIO4_IO11 0x14 @@ -456,10 +497,17 @@ >; }; + pinctrl_flexcan1: flexcan1-grp { + fsl,pins = < + MX7D_PAD_ENET1_RGMII_RD3__FLEXCAN1_TX 0x79 /* SODIMM 55 */ + MX7D_PAD_ENET1_RGMII_RD2__FLEXCAN1_RX 0x79 /* SODIMM 63 */ + >; + }; + pinctrl_flexcan2: flexcan2-grp { fsl,pins = < - MX7D_PAD_GPIO1_IO14__FLEXCAN2_RX 0x59 - MX7D_PAD_GPIO1_IO15__FLEXCAN2_TX 0x59 + MX7D_PAD_GPIO1_IO14__FLEXCAN2_RX 0x79 /* SODIMM 188 */ + MX7D_PAD_GPIO1_IO15__FLEXCAN2_TX 0x79 /* SODIMM 178 */ >; }; @@ -495,6 +543,13 @@ >; }; + pinctrl_i2c4_recovery: i2c4-recoverygrp { + fsl,pins = < + MX7D_PAD_ENET1_RGMII_TD2__GPIO7_IO8 0x4000007f + MX7D_PAD_ENET1_RGMII_TD3__GPIO7_IO9 0x4000007f + >; + }; + pinctrl_lcdif_dat: lcdif-dat-grp { fsl,pins = < MX7D_PAD_LCD_DATA00__LCD_DATA0 0x79 @@ -695,6 +750,13 @@ >; }; + pinctrl_i2c1_recovery: i2c1-recoverygrp { + fsl,pins = < + MX7D_PAD_LPSR_GPIO1_IO04__GPIO1_IO4 0x4000007f + MX7D_PAD_LPSR_GPIO1_IO05__GPIO1_IO5 0x4000007f + >; + }; + pinctrl_cd_usdhc1: usdhc1-cd-grp { fsl,pins = < MX7D_PAD_LPSR_GPIO1_IO00__GPIO1_IO0 0x59 /* CD */ diff --git a/arch/arm/boot/dts/imx7d-cl-som-imx7.dts b/arch/arm/boot/dts/imx7d-cl-som-imx7.dts index e61567437d73c48c3f5f15e4d4771e35a4010085..7646284e13a75bdd42986c5b1b024980f0d54e66 100644 --- a/arch/arm/boot/dts/imx7d-cl-som-imx7.dts +++ b/arch/arm/boot/dts/imx7d-cl-som-imx7.dts @@ -44,7 +44,7 @@ <&clks IMX7D_ENET1_TIME_ROOT_CLK>; assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>; assigned-clock-rates = <0>, <100000000>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; phy-handle = <ðphy0>; fsl,magic-packet; status = "okay"; @@ -54,10 +54,12 @@ #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>; }; }; @@ -70,7 +72,7 @@ <&clks IMX7D_ENET2_TIME_ROOT_CLK>; assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>; assigned-clock-rates = <0>, <100000000>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; phy-handle = <ðphy1>; fsl,magic-packet; status = "okay"; diff --git a/arch/arm/boot/dts/imx7d-zii-rmu2.dts b/arch/arm/boot/dts/imx7d-zii-rmu2.dts new file mode 100644 index 0000000000000000000000000000000000000000..2b8d6cc45a5384bf0c94eddb1952aa46a4fbc43d --- /dev/null +++ b/arch/arm/boot/dts/imx7d-zii-rmu2.dts @@ -0,0 +1,357 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Device tree file for ZII's RMU2 board + * + * RMU - Remote Modem Unit + * + * Copyright (C) 2019 Zodiac Inflight Innovations + */ + +/dts-v1/; +#include +#include "imx7d.dtsi" + +/ { + model = "ZII RMU2 Board"; + compatible = "zii,imx7d-rmu2", "fsl,imx7d"; + + chosen { + stdout-path = &uart2; + }; + + gpio-leds { + compatible = "gpio-leds"; + pinctrl-0 = <&pinctrl_leds_debug>; + pinctrl-names = "default"; + + debug { + label = "zii:green:debug1"; + gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + }; +}; + +&cpu0 { + arm-supply = <&sw1a_reg>; +}; + +&ecspi1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi1>; + cs-gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>; + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + spi-max-frequency = <20000000>; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + }; +}; + +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet1>; + assigned-clocks = <&clks IMX7D_ENET1_TIME_ROOT_SRC>, + <&clks IMX7D_ENET1_TIME_ROOT_CLK>; + assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>; + assigned-clock-rates = <0>, <100000000>; + phy-mode = "rgmii"; + phy-handle = <&fec1_phy>; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + fec1_phy: ethernet-phy@0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet1_phy_reset>, + <&pinctrl_enet1_phy_interrupt>; + reg = <0>; + interrupt-parent = <&gpio1>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio5 11 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pmic@8 { + compatible = "fsl,pfuze3000"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1a { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw1c_reg: sw1b { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1475000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1850000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1650000>; + regulator-boot-on; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen2_reg: vldo2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + regulator-always-on; + }; + + vgen3_reg: vccsd { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen4_reg: v33 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vldo4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; + + eeprom@50 { + compatible = "atmel,24c04"; + reg = <0x50>; + }; + + eeprom@52 { + compatible = "atmel,24c04"; + reg = <0x52>; + }; +}; + +&snvs_rtc { + status = "disabled"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + assigned-clocks = <&clks IMX7D_UART2_ROOT_SRC>; + assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; + assigned-clocks = <&clks IMX7D_UART4_ROOT_SRC>; + assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>; + status = "okay"; + + rave-sp { + compatible = "zii,rave-sp-rdu2"; + current-speed = <1000000>; + #address-cells = <1>; + #size-cells = <1>; + + watchdog { + compatible = "zii,rave-sp-watchdog"; + }; + + eeprom@a3 { + compatible = "zii,rave-sp-eeprom"; + reg = <0xa3 0x4000>; + #address-cells = <1>; + #size-cells = <1>; + zii,eeprom-name = "main-eeprom"; + }; + }; +}; + +&usbotg2 { + dr_mode = "host"; + disable-over-current; + status = "okay"; +}; + +&usdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc1>; + bus-width = <4>; + no-1-8-v; + no-sdio; + keep-power-in-suspend; + status = "okay"; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3>; + bus-width = <8>; + no-1-8-v; + non-removable; + no-sdio; + no-sd; + keep-power-in-suspend; + status = "okay"; +}; + +&wdog1 { + status = "disabled"; +}; + +&iomuxc { + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX7D_PAD_ECSPI1_SCLK__ECSPI1_SCLK 0x2 + MX7D_PAD_ECSPI1_MOSI__ECSPI1_MOSI 0x2 + MX7D_PAD_ECSPI1_MISO__ECSPI1_MISO 0x2 + MX7D_PAD_ECSPI1_SS0__GPIO4_IO19 0x59 + >; + }; + + pinctrl_enet1: enet1grp { + fsl,pins = < + MX7D_PAD_SD2_CD_B__ENET1_MDIO 0x3 + MX7D_PAD_SD2_WP__ENET1_MDC 0x3 + MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC 0x1 + MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0 0x1 + MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1 0x1 + MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2 0x1 + MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3 0x1 + MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL 0x1 + MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC 0x1 + MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0 0x1 + MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1 0x1 + MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2 0x1 + MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3 0x1 + MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL 0x1 + >; + }; + + pinctrl_enet1_phy_reset: enet1phyresetgrp { + fsl,pins = < + MX7D_PAD_SD2_RESET_B__GPIO5_IO11 0x14 + + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX7D_PAD_I2C1_SDA__I2C1_SDA 0x4000007f + MX7D_PAD_I2C1_SCL__I2C1_SCL 0x4000007f + >; + }; + + pinctrl_leds_debug: ledsgrp { + fsl,pins = < + MX7D_PAD_EPDC_DATA08__GPIO2_IO8 0x59 + >; + }; + + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX7D_PAD_UART2_RX_DATA__UART2_DCE_RX 0x79 + MX7D_PAD_UART2_TX_DATA__UART2_DCE_TX 0x79 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX7D_PAD_SD2_DATA0__UART4_DCE_RX 0x79 + MX7D_PAD_SD2_DATA1__UART4_DCE_TX 0x79 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX7D_PAD_SD1_CMD__SD1_CMD 0x59 + MX7D_PAD_SD1_CLK__SD1_CLK 0x19 + MX7D_PAD_SD1_DATA0__SD1_DATA0 0x59 + MX7D_PAD_SD1_DATA1__SD1_DATA1 0x59 + MX7D_PAD_SD1_DATA2__SD1_DATA2 0x59 + MX7D_PAD_SD1_DATA3__SD1_DATA3 0x59 + >; + }; + + 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_RESET_B__SD3_RESET_B 0x59 + >; + }; +}; + +&iomuxc_lpsr { + pinctrl_enet1_phy_interrupt: enet1phyinterruptgrp { + fsl,phy = < + MX7D_PAD_LPSR_GPIO1_IO02__GPIO1_IO2 0x08 + >; + }; +}; diff --git a/arch/arm/boot/dts/imx7d-zii-rpu2.dts b/arch/arm/boot/dts/imx7d-zii-rpu2.dts index 4a78ddc7513dcac4d772eeb960b0bb5e31c2065a..39812c92bf0dcb5bb774122789e2739a7b2cf0f5 100644 --- a/arch/arm/boot/dts/imx7d-zii-rpu2.dts +++ b/arch/arm/boot/dts/imx7d-zii-rpu2.dts @@ -669,10 +669,6 @@ status = "disabled"; }; -&snvs_pwrkey { - status = "disabled"; -}; - &iomuxc { pinctrl_ecspi1: ecspi1grp { fsl,pins = < diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi index 42528d2812a2eb758b031769e0fd032ba04f5c89..9c8dd32cc035f8b9ad419c773f0d48b9a5fb4854 100644 --- a/arch/arm/boot/dts/imx7d.dtsi +++ b/arch/arm/boot/dts/imx7d.dtsi @@ -147,8 +147,8 @@ <&clks IMX7D_ENET_PHY_REF_ROOT_CLK>; clock-names = "ipg", "ahb", "ptp", "enet_clk_ref", "enet_out"; - fsl,num-tx-queues=<3>; - fsl,num-rx-queues=<3>; + fsl,num-tx-queues = <3>; + fsl,num-rx-queues = <3>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi index c1a4fff5ceda9791603a4ce23e142fd539b443da..710f850e785c6cbb465faa1697e15a52de378171 100644 --- a/arch/arm/boot/dts/imx7s.dtsi +++ b/arch/arm/boot/dts/imx7s.dtsi @@ -151,7 +151,7 @@ compatible = "fsl,imx7d-tempmon"; interrupt-parent = <&gpc>; interrupts = ; - fsl,tempmon =<&anatop>; + fsl,tempmon = <&anatop>; nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>; nvmem-cell-names = "calib", "temp_grade"; @@ -1184,8 +1184,8 @@ <&clks IMX7D_ENET_PHY_REF_ROOT_CLK>; clock-names = "ipg", "ahb", "ptp", "enet_clk_ref", "enet_out"; - fsl,num-tx-queues=<3>; - fsl,num-rx-queues=<3>; + fsl,num-tx-queues = <3>; + fsl,num-rx-queues = <3>; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/imx7ulp.dtsi b/arch/arm/boot/dts/imx7ulp.dtsi index 56907bb4b3291dc65849c8833bb02784773bbadc..6859a3a83750ce4c811942e21a710022123e2768 100644 --- a/arch/arm/boot/dts/imx7ulp.dtsi +++ b/arch/arm/boot/dts/imx7ulp.dtsi @@ -101,6 +101,34 @@ reg = <0x40000000 0x800000>; ranges; + edma1: dma-controller@40080000 { + #dma-cells = <2>; + compatible = "fsl,imx7ulp-edma"; + reg = <0x40080000 0x2000>, + <0x40210000 0x1000>; + dma-channels = <32>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + clock-names = "dma", "dmamux0"; + clocks = <&pcc2 IMX7ULP_CLK_DMA1>, + <&pcc2 IMX7ULP_CLK_DMA_MUX1>; + }; + crypto: crypto@40240000 { compatible = "fsl,sec-v4.0"; #address-cells = <1>; @@ -201,12 +229,12 @@ clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>, <&scg1 IMX7ULP_CLK_NIC1_DIV>, <&pcc2 IMX7ULP_CLK_USDHC0>; - clock-names ="ipg", "ahb", "per"; + clock-names = "ipg", "ahb", "per"; assigned-clocks = <&pcc2 IMX7ULP_CLK_USDHC0>; assigned-clock-parents = <&scg1 IMX7ULP_CLK_NIC1_DIV>; bus-width = <4>; fsl,tuning-start-tap = <20>; - fsl,tuning-step= <2>; + fsl,tuning-step = <2>; status = "disabled"; }; @@ -217,12 +245,12 @@ clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>, <&scg1 IMX7ULP_CLK_NIC1_DIV>, <&pcc2 IMX7ULP_CLK_USDHC1>; - clock-names ="ipg", "ahb", "per"; + clock-names = "ipg", "ahb", "per"; assigned-clocks = <&pcc2 IMX7ULP_CLK_USDHC1>; assigned-clock-parents = <&scg1 IMX7ULP_CLK_NIC1_DIV>; bus-width = <4>; fsl,tuning-start-tap = <20>; - fsl,tuning-step= <2>; + fsl,tuning-step = <2>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/kirkwood-ts219.dtsi b/arch/arm/boot/dts/kirkwood-ts219.dtsi index a88eb22070a1b714ca74a5384e3302b2806166b7..994cabcf4b51016df9d9430e6f001941d11d9620 100644 --- a/arch/arm/boot/dts/kirkwood-ts219.dtsi +++ b/arch/arm/boot/dts/kirkwood-ts219.dtsi @@ -104,3 +104,11 @@ &pcie0 { status = "okay"; }; + +&rtc { + /* + * There is a s35390a available on the i2c bus, the internal rtc isn't + * working (probably no crystal assembled). + */ + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/meson8b-ec100.dts b/arch/arm/boot/dts/meson8b-ec100.dts index 96d239d8334ee29478bb4cfa1ec5078dbcde2459..bed1dfef198578e1f56d13abfda4fcd4703a78e5 100644 --- a/arch/arm/boot/dts/meson8b-ec100.dts +++ b/arch/arm/boot/dts/meson8b-ec100.dts @@ -219,6 +219,27 @@ */ vin-supply = <&vcc_3v3>; }; + + vddee: regulator-vddee { + /* + * Silergy SY8089AAC-GP 2A continuous, 3A peak, 1MHz + * Synchronous Step Down Regulator. Also called VDDAO + * in a part of the schematics. + */ + compatible = "pwm-regulator"; + + regulator-name = "VDDEE"; + regulator-min-microvolt = <860000>; + regulator-max-microvolt = <1140000>; + + vin-supply = <&vcc_5v>; + + pwms = <&pwm_cd 1 1148 0>; + pwm-dutycycle-range = <100 0>; + + regulator-boot-on; + regulator-always-on; + }; }; &cpu0 { @@ -269,6 +290,10 @@ }; }; +&mali { + mali-supply = <&vddee>; +}; + &saradc { status = "okay"; vref-supply = <&vcc_1v8>; @@ -350,10 +375,10 @@ &pwm_cd { status = "okay"; - pinctrl-0 = <&pwm_c1_pins>; + pinctrl-0 = <&pwm_c1_pins>, <&pwm_d_pins>; pinctrl-names = "default"; - clocks = <&clkc CLKID_XTAL>; - clock-names = "clkin0"; + clocks = <&clkc CLKID_XTAL>, <&clkc CLKID_XTAL>; + clock-names = "clkin0", "clkin1"; }; &rtc { diff --git a/arch/arm/boot/dts/meson8b-mxq.dts b/arch/arm/boot/dts/meson8b-mxq.dts index bb27b34eb34613ca124153abfb93998bc833b19f..6e39ad52e42d32b0f95f15527b058337bb848c6f 100644 --- a/arch/arm/boot/dts/meson8b-mxq.dts +++ b/arch/arm/boot/dts/meson8b-mxq.dts @@ -76,6 +76,22 @@ regulator-boot-on; regulator-always-on; }; + + vddee: regulator-vddee { + compatible = "pwm-regulator"; + + regulator-name = "VDDEE"; + regulator-min-microvolt = <860000>; + regulator-max-microvolt = <1140000>; + + vin-supply = <&vcc_5v>; + + pwms = <&pwm_cd 1 1148 0>; + pwm-dutycycle-range = <100 0>; + + regulator-boot-on; + regulator-always-on; + }; }; &cpu0 { @@ -112,6 +128,10 @@ }; }; +&mali { + mali-supply = <&vddee>; +}; + &saradc { status = "okay"; vref-supply = <&vcc_1v8>; @@ -143,10 +163,10 @@ &pwm_cd { status = "okay"; - pinctrl-0 = <&pwm_c1_pins>; + pinctrl-0 = <&pwm_c1_pins>, <&pwm_d_pins>; pinctrl-names = "default"; - clocks = <&clkc CLKID_XTAL>; - clock-names = "clkin0"; + clocks = <&clkc CLKID_XTAL>, <&clkc CLKID_XTAL>; + clock-names = "clkin0", "clkin1"; }; &uart_AO { diff --git a/arch/arm/boot/dts/meson8b-odroidc1.dts b/arch/arm/boot/dts/meson8b-odroidc1.dts index 86c4614e0a387520591ce50f0d695e5023bf4db7..a24eccc354b95851f1b48663776a26e5e74a9712 100644 --- a/arch/arm/boot/dts/meson8b-odroidc1.dts +++ b/arch/arm/boot/dts/meson8b-odroidc1.dts @@ -154,6 +154,23 @@ vin-supply = <&p5v0>; }; + vddee: regulator-vddee { + /* Monolithic Power Systems MP2161 */ + compatible = "pwm-regulator"; + + regulator-name = "VDDEE"; + regulator-min-microvolt = <860000>; + regulator-max-microvolt = <1140000>; + + vin-supply = <&p5v0>; + + pwms = <&pwm_cd 1 12218 0>; + pwm-dutycycle-range = <91 0>; + + regulator-boot-on; + regulator-always-on; + }; + vdd_rtc: regulator-vdd-rtc { /* * Torex Semiconductor XC6215 configured for a fixed output of @@ -173,6 +190,12 @@ cpu-supply = <&vcck>; }; +&efuse { + ethernet_mac_address: mac@1b4 { + reg = <0x1b4 0x6>; + }; +}; + ðmac { status = "okay"; @@ -183,6 +206,9 @@ phy-handle = <ð_phy>; amlogic,tx-delay-ns = <4>; + nvmem-cells = <ðernet_mac_address>; + nvmem-cell-names = "mac-address"; + mdio { compatible = "snps,dwmac-mdio"; #address-cells = <1>; @@ -276,6 +302,10 @@ pinctrl-names = "default"; }; +&mali { + mali-supply = <&vddee>; +}; + &saradc { status = "okay"; vref-supply = <&vcc_1v8>; @@ -308,10 +338,10 @@ &pwm_cd { status = "okay"; - pinctrl-0 = <&pwm_c1_pins>; + pinctrl-0 = <&pwm_c1_pins>, <&pwm_d_pins>; pinctrl-names = "default"; - clocks = <&clkc CLKID_XTAL>; - clock-names = "clkin0"; + clocks = <&clkc CLKID_XTAL>, <&clkc CLKID_XTAL>; + clock-names = "clkin0", "clkin1"; }; &rtc { diff --git a/arch/arm/boot/dts/meson8b.dtsi b/arch/arm/boot/dts/meson8b.dtsi index fba2c70c2fda321155ffa498f4d6691af70720eb..099bf8e711c94ecf3c1d974fa878c6ea9f0af211 100644 --- a/arch/arm/boot/dts/meson8b.dtsi +++ b/arch/arm/boot/dts/meson8b.dtsi @@ -361,6 +361,14 @@ }; }; + pwm_d_pins: pwm-d { + mux { + groups = "pwm_d"; + function = "pwm_d"; + bias-disable; + }; + }; + uart_b0_pins: uart-b0 { mux { groups = "uart_tx_b0", @@ -410,6 +418,8 @@ <&clkc CLKID_MPLL2>, <&clkc CLKID_MPLL2>; clock-names = "stmmaceth", "clkin0", "clkin1"; + rx-fifo-depth = <4096>; + tx-fifo-depth = <2048>; resets = <&reset RESET_ETHERNET>; reset-names = "stmmaceth"; diff --git a/arch/arm/boot/dts/mt7629-rfb.dts b/arch/arm/boot/dts/mt7629-rfb.dts new file mode 100644 index 0000000000000000000000000000000000000000..3621b7d2b22ac28eb905e5aa58e9ac0918c42eb5 --- /dev/null +++ b/arch/arm/boot/dts/mt7629-rfb.dts @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 MediaTek Inc. + * Author: Ryder Lee + */ + +/dts-v1/; +#include +#include "mt7629.dtsi" + +/ { + model = "MediaTek MT7629 reference board"; + compatible = "mediatek,mt7629-rfb", "mediatek,mt7629"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + gpio-keys { + compatible = "gpio-keys"; + + reset { + label = "factory"; + linux,code = ; + gpios = <&pio 60 GPIO_ACTIVE_LOW>; + }; + + wps { + label = "wps"; + linux,code = ; + gpios = <&pio 58 GPIO_ACTIVE_LOW>; + }; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0x40000000 0x10000000>; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_5v: regulator-5v { + compatible = "regulator-fixed"; + regulator-name = "fixed-5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + regulator-always-on; + }; +}; + +ð { + pinctrl-names = "default"; + pinctrl-0 = <ð_pins>; + pinctrl-1 = <&ephy_leds_pins>; + status = "okay"; + + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + phy-handle = <&phy0>; + }; + + mdio: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@0 { + reg = <0>; + phy-mode = "gmii"; + }; + }; +}; + +&i2c { + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins>; + status = "okay"; +}; + +&qspi { + pinctrl-names = "default"; + pinctrl-0 = <&qspi_pins>; + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0x00000 0x60000>; + read-only; + }; + + partition@60000 { + label = "u-boot-env"; + reg = <0x60000 0x10000>; + read-only; + }; + + factory: partition@70000 { + label = "factory"; + reg = <0x70000 0x40000>; + read-only; + }; + + partition@b0000 { + label = "kernel"; + reg = <0xb0000 0xb50000>; + }; + }; + }; +}; + +&pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pcie_pins>; +}; + +&pciephy1 { + status = "okay"; +}; + +&pio { + eth_pins: eth-pins { + mux { + function = "eth"; + groups = "mdc_mdio"; + }; + }; + + ephy_leds_pins: ephy-leds-pins { + mux { + function = "led"; + groups = "gphy_leds_0", "ephy_leds"; + }; + }; + + i2c_pins: i2c-pins { + mux { + function = "i2c"; + groups = "i2c_0"; + }; + + conf { + pins = "I2C_SDA", "I2C_SCL"; + drive-strength = <4>; + bias-disable; + }; + }; + + pcie_pins: pcie-pins { + mux { + function = "pcie"; + groups = "pcie_clkreq", + "pcie_pereset", + "pcie_wake"; + }; + }; + + pwm_pins: pwm-pins { + mux { + function = "pwm"; + groups = "pwm_0"; + }; + }; + + /* SPI-NOR is shared pin with serial NAND */ + qspi_pins: qspi-pins { + mux { + function = "flash"; + groups = "spi_nor"; + }; + }; + + /* Serial NAND is shared pin with SPI-NOR */ + serial_nand_pins: serial-nand-pins { + mux { + function = "flash"; + groups = "snfi"; + }; + }; + + spi_pins: spi-pins { + mux { + function = "spi"; + groups = "spi_0"; + }; + }; + + uart0_pins: uart0-pins { + mux { + function = "uart"; + groups = "uart0_txd_rxd" ; + }; + }; + + uart1_pins: uart1-pins { + mux { + function = "uart"; + groups = "uart1_0_tx_rx" ; + }; + }; + + uart2_pins: uart2-pins { + mux { + function = "uart"; + groups = "uart2_0_txd_rxd" ; + }; + }; + + watchdog_pins: watchdog-pins { + mux { + function = "watchdog"; + groups = "watchdog"; + }; + }; +}; + +&spi { + pinctrl-names = "default"; + pinctrl-0 = <&spi_pins>; + status = "okay"; +}; + +&ssusb { + vusb33-supply = <®_3p3v>; + vbus-supply = <®_5v>; + status = "okay"; +}; + +&u3phy0 { + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + status = "okay"; +}; + +&watchdog { + pinctrl-names = "default"; + pinctrl-0 = <&watchdog_pins>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/mt7629.dtsi b/arch/arm/boot/dts/mt7629.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9608bc2ccb3f9367f0bf5172564f0dd761555c26 --- /dev/null +++ b/arch/arm/boot/dts/mt7629.dtsi @@ -0,0 +1,481 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 MediaTek Inc. + * + * Author: Ryder Lee + */ + +#include +#include +#include +#include +#include +#include +#include + +/ { + compatible = "mediatek,mt7629"; + interrupt-parent = <&sysirq>; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + enable-method = "mediatek,mt6589-smp"; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x0>; + clock-frequency = <1250000000>; + cci-control-port = <&cci_control2>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x1>; + clock-frequency = <1250000000>; + cci-control-port = <&cci_control2>; + }; + }; + + pmu { + compatible = "arm,cortex-a7-pmu"; + interrupts = , + ; + interrupt-affinity = <&cpu0>, <&cpu1>; + }; + + clk20m: oscillator-0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <20000000>; + clock-output-names = "clk20m"; + }; + + clk40m: oscillator-1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <40000000>; + clock-output-names = "clkxtal"; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + clock-frequency = <20000000>; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + infracfg: syscon@10000000 { + compatible = "mediatek,mt7629-infracfg", "syscon"; + reg = <0x10000000 0x1000>; + #clock-cells = <1>; + }; + + pericfg: syscon@10002000 { + compatible = "mediatek,mt7629-pericfg", "syscon"; + reg = <0x10002000 0x1000>; + #clock-cells = <1>; + }; + + scpsys: scpsys@10006000 { + compatible = "mediatek,mt7629-scpsys", + "mediatek,mt7622-scpsys"; + #power-domain-cells = <1>; + reg = <0x10006000 0x1000>; + clocks = <&topckgen CLK_TOP_HIF_SEL>; + clock-names = "hif_sel"; + assigned-clocks = <&topckgen CLK_TOP_HIF_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL1_D2>; + infracfg = <&infracfg>; + }; + + timer: timer@10009000 { + compatible = "mediatek,mt7629-timer", + "mediatek,mt6765-timer"; + reg = <0x10009000 0x60>; + interrupts = , + ; + clocks = <&clk20m>; + clock-names = "clk20m"; + }; + + sysirq: interrupt-controller@10200a80 { + compatible = "mediatek,mt7629-sysirq", + "mediatek,mt6577-sysirq"; + reg = <0x10200a80 0x20>; + interrupt-controller; + #interrupt-cells = <3>; + interrupt-parent = <&gic>; + }; + + apmixedsys: syscon@10209000 { + compatible = "mediatek,mt7629-apmixedsys", "syscon"; + reg = <0x10209000 0x1000>; + #clock-cells = <1>; + }; + + rng: rng@1020f000 { + compatible = "mediatek,mt7629-rng", + "mediatek,mt7623-rng"; + reg = <0x1020f000 0x100>; + clocks = <&infracfg CLK_INFRA_TRNG_PD>; + clock-names = "rng"; + }; + + topckgen: syscon@10210000 { + compatible = "mediatek,mt7629-topckgen", "syscon"; + reg = <0x10210000 0x1000>; + #clock-cells = <1>; + }; + + watchdog: watchdog@10212000 { + compatible = "mediatek,mt7629-wdt", + "mediatek,mt6589-wdt"; + reg = <0x10212000 0x100>; + }; + + pio: pinctrl@10217000 { + compatible = "mediatek,mt7629-pinctrl"; + reg = <0x10217000 0x8000>, + <0x10005000 0x1000>; + reg-names = "base", "eint"; + gpio-controller; + gpio-ranges = <&pio 0 0 79>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + interrupt-controller; + interrupts = ; + interrupt-parent = <&gic>; + }; + + gic: interrupt-controller@10300000 { + compatible = "arm,gic-400"; + interrupt-controller; + #interrupt-cells = <3>; + interrupt-parent = <&gic>; + reg = <0x10310000 0x1000>, + <0x10320000 0x1000>, + <0x10340000 0x2000>, + <0x10360000 0x2000>; + }; + + cci: cci@10390000 { + compatible = "arm,cci-400"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x10390000 0x1000>; + ranges = <0 0x10390000 0x10000>; + + cci_control0: slave-if@1000 { + compatible = "arm,cci-400-ctrl-if"; + interface-type = "ace-lite"; + reg = <0x1000 0x1000>; + }; + + cci_control1: slave-if@4000 { + compatible = "arm,cci-400-ctrl-if"; + interface-type = "ace"; + reg = <0x4000 0x1000>; + }; + + cci_control2: slave-if@5000 { + compatible = "arm,cci-400-ctrl-if"; + interface-type = "ace"; + reg = <0x5000 0x1000>; + }; + + pmu@9000 { + compatible = "arm,cci-400-pmu,r1"; + reg = <0x9000 0x5000>; + interrupts = , + , + , + , + ; + }; + }; + + uart0: serial@11002000 { + compatible = "mediatek,mt7629-uart", + "mediatek,mt6577-uart"; + reg = <0x11002000 0x400>; + interrupts = ; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&pericfg CLK_PERI_UART0_PD>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + uart1: serial@11003000 { + compatible = "mediatek,mt7629-uart", + "mediatek,mt6577-uart"; + reg = <0x11003000 0x400>; + interrupts = ; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&pericfg CLK_PERI_UART1_PD>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + uart2: serial@11004000 { + compatible = "mediatek,mt7629-uart", + "mediatek,mt6577-uart"; + reg = <0x11004000 0x400>; + interrupts = ; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&pericfg CLK_PERI_UART2_PD>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + i2c: i2c@11007000 { + compatible = "mediatek,mt7629-i2c", + "mediatek,mt2712-i2c"; + reg = <0x11007000 0x90>, + <0x11000100 0x80>; + interrupts = ; + clock-div = <4>; + clocks = <&pericfg CLK_PERI_I2C0_PD>, + <&pericfg CLK_PERI_AP_DMA_PD>; + clock-names = "main", "dma"; + assigned-clocks = <&topckgen CLK_TOP_AXI_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_SYSPLL1_D2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi: spi@1100a000 { + compatible = "mediatek,mt7629-spi", + "mediatek,mt7622-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x1100a000 0x100>; + interrupts = ; + clocks = <&topckgen CLK_TOP_SYSPLL3_D2>, + <&topckgen CLK_TOP_SPI0_SEL>, + <&pericfg CLK_PERI_SPI0_PD>; + clock-names = "parent-clk", "sel-clk", "spi-clk"; + status = "disabled"; + }; + + qspi: spi@11014000 { + compatible = "mediatek,mt7629-nor", + "mediatek,mt8173-nor"; + reg = <0x11014000 0xe0>; + clocks = <&pericfg CLK_PERI_FLASH_PD>, + <&topckgen CLK_TOP_FLASH_SEL>; + clock-names = "spi", "sf"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + ssusbsys: syscon@1a000000 { + compatible = "mediatek,mt7629-ssusbsys", "syscon"; + reg = <0x1a000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + ssusb: usb@1a0c0000 { + compatible = "mediatek,mt7629-xhci", + "mediatek,mtk-xhci"; + reg = <0x1a0c0000 0x01000>, + <0x1a0c3e00 0x0100>; + reg-names = "mac", "ippc"; + interrupts = ; + clocks = <&ssusbsys CLK_SSUSB_SYS_EN>, + <&ssusbsys CLK_SSUSB_REF_EN>, + <&ssusbsys CLK_SSUSB_MCU_EN>, + <&ssusbsys CLK_SSUSB_DMA_EN>; + clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck"; + assigned-clocks = <&topckgen CLK_TOP_AXI_SEL>, + <&topckgen CLK_TOP_SATA_SEL>, + <&topckgen CLK_TOP_HIF_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_SYSPLL1_D2>, + <&topckgen CLK_TOP_UNIVPLL2_D4>, + <&topckgen CLK_TOP_UNIVPLL1_D2>; + power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF1>; + phys = <&u2port0 PHY_TYPE_USB2>, + <&u3port0 PHY_TYPE_USB3>; + status = "disabled"; + }; + + u3phy0: usb-phy@1a0c4000 { + compatible = "mediatek,generic-tphy-v2"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1a0c4000 0xe00>; + status = "disabled"; + + u2port0: usb-phy@0 { + reg = <0 0x700>; + clocks = <&ssusbsys CLK_SSUSB_U2_PHY_EN>; + clock-names = "ref"; + #phy-cells = <1>; + status = "okay"; + }; + + u3port0: usb-phy@700 { + reg = <0x700 0x700>; + clocks = <&clk20m>; + clock-names = "ref"; + #phy-cells = <1>; + status = "okay"; + }; + }; + + pciesys: syscon@1a100800 { + compatible = "mediatek,mt7629-pciesys", "syscon"; + reg = <0x1a100800 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + pcie: pcie@1a140000 { + compatible = "mediatek,mt7629-pcie"; + device_type = "pci"; + reg = <0x1a140000 0x1000>, + <0x1a145000 0x1000>; + reg-names = "subsys","port1"; + #address-cells = <3>; + #size-cells = <2>; + interrupts = , + ; + clocks = <&pciesys CLK_PCIE_P1_MAC_EN>, + <&pciesys CLK_PCIE_P0_AHB_EN>, + <&pciesys CLK_PCIE_P1_AUX_EN>, + <&pciesys CLK_PCIE_P1_AXI_EN>, + <&pciesys CLK_PCIE_P1_OBFF_EN>, + <&pciesys CLK_PCIE_P1_PIPE_EN>; + clock-names = "sys_ck1", "ahb_ck1", + "aux_ck1", "axi_ck1", + "obff_ck1", "pipe_ck1"; + assigned-clocks = <&topckgen CLK_TOP_SATA_SEL>, + <&topckgen CLK_TOP_AXI_SEL>, + <&topckgen CLK_TOP_HIF_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL2_D4>, + <&topckgen CLK_TOP_SYSPLL1_D2>, + <&topckgen CLK_TOP_UNIVPLL1_D2>; + phys = <&pcieport1 PHY_TYPE_PCIE>; + phy-names = "pcie-phy1"; + power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF0>; + bus-range = <0x00 0xff>; + ranges = <0x82000000 0 0x20000000 0x20000000 0 0x10000000>; + + pcie1: pcie@1,0 { + device_type = "pci"; + reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges; + num-lanes = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc1 0>, + <0 0 0 2 &pcie_intc1 1>, + <0 0 0 3 &pcie_intc1 2>, + <0 0 0 4 &pcie_intc1 3>; + + pcie_intc1: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + }; + + pciephy1: pcie-phy@1a14a000 { + compatible = "mediatek,generic-tphy-v2"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1a14a000 0x1000>; + status = "disabled"; + + pcieport1: port1phy@0 { + reg = <0 0x1000>; + clocks = <&clk20m>; + clock-names = "ref"; + #phy-cells = <1>; + status = "okay"; + }; + }; + + ethsys: syscon@1b000000 { + compatible = "mediatek,mt7629-ethsys", "syscon"; + reg = <0x1b000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + eth: ethernet@1b100000 { + compatible = "mediatek,mt7629-eth","syscon"; + reg = <0x1b100000 0x20000>; + interrupts = , + , + ; + clocks = <&topckgen CLK_TOP_ETH_SEL>, + <&topckgen CLK_TOP_F10M_REF_SEL>, + <ðsys CLK_ETH_ESW_EN>, + <ðsys CLK_ETH_GP0_EN>, + <ðsys CLK_ETH_GP1_EN>, + <ðsys CLK_ETH_GP2_EN>, + <ðsys CLK_ETH_FE_EN>, + <&sgmiisys0 CLK_SGMII_TX_EN>, + <&sgmiisys0 CLK_SGMII_RX_EN>, + <&sgmiisys0 CLK_SGMII_CDR_REF>, + <&sgmiisys0 CLK_SGMII_CDR_FB>, + <&sgmiisys1 CLK_SGMII_TX_EN>, + <&sgmiisys1 CLK_SGMII_RX_EN>, + <&sgmiisys1 CLK_SGMII_CDR_REF>, + <&sgmiisys1 CLK_SGMII_CDR_FB>, + <&apmixedsys CLK_APMIXED_SGMIPLL>, + <&apmixedsys CLK_APMIXED_ETH2PLL>; + clock-names = "ethif", "sgmiitop", "esw", "gp0", "gp1", + "gp2", "fe", "sgmii_tx250m", "sgmii_rx250m", + "sgmii_cdr_ref", "sgmii_cdr_fb", + "sgmii2_tx250m", "sgmii2_rx250m", + "sgmii2_cdr_ref", "sgmii2_cdr_fb", + "sgmii_ck", "eth2pll"; + assigned-clocks = <&topckgen CLK_TOP_ETH_SEL>, + <&topckgen CLK_TOP_F10M_REF_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL1_D2>, + <&topckgen CLK_TOP_SGMIIPLL_D2>; + power-domains = <&scpsys MT7622_POWER_DOMAIN_ETHSYS>; + mediatek,ethsys = <ðsys>; + mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>; + mediatek,infracfg = <&infracfg>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + sgmiisys0: syscon@1b128000 { + compatible = "mediatek,mt7629-sgmiisys", "syscon"; + reg = <0x1b128000 0x3000>; + #clock-cells = <1>; + mediatek,physpeed = "2500"; + }; + + sgmiisys1: syscon@1b130000 { + compatible = "mediatek,mt7629-sgmiisys", "syscon"; + reg = <0x1b130000 0x3000>; + #clock-cells = <1>; + mediatek,physpeed = "2500"; + }; + }; +}; diff --git a/arch/arm/boot/dts/nspire-classic.dtsi b/arch/arm/boot/dts/nspire-classic.dtsi index c53f42777851e8556dc8c04f7c330f0c9352e699..41744cc2bc72860e81903c0b1943f1c854f5898e 100644 --- a/arch/arm/boot/dts/nspire-classic.dtsi +++ b/arch/arm/boot/dts/nspire-classic.dtsi @@ -8,7 +8,11 @@ /include/ "nspire.dtsi" &lcd { - lcd-type = "classic"; + port { + clcd_pads: endpoint { + remote-endpoint = <&panel_in>; + }; + }; }; &fast_timer { @@ -69,6 +73,15 @@ #interrupt-cells = <1>; }; }; + + panel { + compatible = "ti,nspire-classic-lcd-panel"; + port { + panel_in: endpoint { + remote-endpoint = <&clcd_pads>; + }; + }; + }; chosen { bootargs = "debug earlyprintk console=tty0 console=ttyS0,115200n8 root=/dev/ram0"; }; diff --git a/arch/arm/boot/dts/nspire-cx.dts b/arch/arm/boot/dts/nspire-cx.dts index da95c3736651f022c25bacbadcc26291ac724396..0c16b04e2744dd54e126f77377210e44f4ee9822 100644 --- a/arch/arm/boot/dts/nspire-cx.dts +++ b/arch/arm/boot/dts/nspire-cx.dts @@ -9,7 +9,11 @@ /include/ "nspire.dtsi" &lcd { - lcd-type = "cx"; + port { + clcd_pads: endpoint { + remote-endpoint = <&panel_in>; + }; + }; }; &fast_timer { @@ -106,6 +110,15 @@ }; }; }; + + panel { + compatible = "ti,nspire-cx-lcd-panel"; + port { + panel_in: endpoint { + remote-endpoint = <&clcd_pads>; + }; + }; + }; chosen { bootargs = "debug earlyprintk console=tty0 console=ttyAMA0,115200n8 root=/dev/ram0"; }; diff --git a/arch/arm/boot/dts/nspire.dtsi b/arch/arm/boot/dts/nspire.dtsi index c35fd66677166f9e93dd3a47b2f6bed9afdad46d..d9a0fd7524dc68668e9a956ffa638ff2ad3956b6 100644 --- a/arch/arm/boot/dts/nspire.dtsi +++ b/arch/arm/boot/dts/nspire.dtsi @@ -95,8 +95,14 @@ reg = <0xC0000000 0x1000>; interrupts = <21>; - clocks = <&apb_pclk>; - clock-names = "apb_pclk"; + /* + * We assume the same clock is fed to APB and CLCDCLK. + * There is some code to scale the clock down by a factor + * 48 for the display so likely the frequency to the + * display is 1MHz and the CLCDCLK is 48 MHz. + */ + clocks = <&apb_pclk>, <&apb_pclk>; + clock-names = "clcdclk", "apb_pclk"; }; adc: adc@C4000000 { diff --git a/arch/arm/boot/dts/omap3-gta04.dtsi b/arch/arm/boot/dts/omap3-gta04.dtsi index b295f6fad2a55854b86cccf216f8cd081a14ef9d..d01fc8744fd79246fe068f2886b04dca2c75833a 100644 --- a/arch/arm/boot/dts/omap3-gta04.dtsi +++ b/arch/arm/boot/dts/omap3-gta04.dtsi @@ -24,6 +24,10 @@ reg = <0x80000000 0x20000000>; /* 512 MB */ }; + chosen { + stdout-path = &uart3; + }; + aliases { display0 = &lcd; display1 = &tv0; diff --git a/arch/arm/boot/dts/omap3-n950-n9.dtsi b/arch/arm/boot/dts/omap3-n950-n9.dtsi index 5441e9ffdbb4bc3e2122ab2231216ed813199773..6681d4519e97f06d3b26acffe01736a816500aff 100644 --- a/arch/arm/boot/dts/omap3-n950-n9.dtsi +++ b/arch/arm/boot/dts/omap3-n950-n9.dtsi @@ -41,7 +41,6 @@ regulator-name = "VWLAN"; gpio = <&gpio2 3 GPIO_ACTIVE_HIGH>; /* gpio 35 */ enable-active-high; - regulator-boot-off; }; leds { diff --git a/arch/arm/boot/dts/r8a77470.dtsi b/arch/arm/boot/dts/r8a77470.dtsi index 56cb10b42ed940dd42b9413cb58dc2c493e4941e..51806c7f486a3681c17f3cea5fd13f93982891a3 100644 --- a/arch/arm/boot/dts/r8a77470.dtsi +++ b/arch/arm/boot/dts/r8a77470.dtsi @@ -63,6 +63,13 @@ clock-frequency = <0>; }; + pmu { + compatible = "arm,cortex-a7-pmu"; + interrupts-extended = <&gic GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>, + <&gic GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>; + interrupt-affinity = <&cpu0>, <&cpu1>; + }; + /* External SCIF clock */ scif_clk: scif { compatible = "fixed-clock"; diff --git a/arch/arm/boot/dts/r8a7779.dtsi b/arch/arm/boot/dts/r8a7779.dtsi index 3ff259207527555582da8e7c9393d5a981d456ee..ebf5b7cfe21599c6adb871f10a740f72cd655a24 100644 --- a/arch/arm/boot/dts/r8a7779.dtsi +++ b/arch/arm/boot/dts/r8a7779.dtsi @@ -296,7 +296,7 @@ <&cpg_clocks R8A7779_CLK_S>, <&scif_clk>; clock-names = "fck", "brg_int", "scif_clk"; - power-domains = <&cpg_clocks>; + power-domains = <&sysc R8A7779_PD_ALWAYS_ON>; status = "disabled"; }; @@ -309,7 +309,7 @@ <&cpg_clocks R8A7779_CLK_S>, <&scif_clk>; clock-names = "fck", "brg_int", "scif_clk"; - power-domains = <&cpg_clocks>; + power-domains = <&sysc R8A7779_PD_ALWAYS_ON>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi index 0290ea4edd321a642fa152b7af6cf7209f913e9b..c776321b2cc4e52a196975749ee4aa686631a6e9 100644 --- a/arch/arm/boot/dts/rk3036.dtsi +++ b/arch/arm/boot/dts/rk3036.dtsi @@ -484,7 +484,7 @@ compatible = "rockchip,rockchip-spi"; reg = <0x20074000 0x1000>; interrupts = ; - clocks =<&cru PCLK_SPI>, <&cru SCLK_SPI>; + clocks = <&cru PCLK_SPI>, <&cru SCLK_SPI>; clock-names = "apb-pclk","spi_pclk"; dmas = <&pdma 8>, <&pdma 9>; dma-names = "tx", "rx"; diff --git a/arch/arm/boot/dts/rk3229-xms6.dts b/arch/arm/boot/dts/rk3229-xms6.dts new file mode 100644 index 0000000000000000000000000000000000000000..679fc2b00e5ac37064283121e2438b3dca0afcdb --- /dev/null +++ b/arch/arm/boot/dts/rk3229-xms6.dts @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include +#include "rk3229.dtsi" + +/ { + model = "Mecer Xtreme Mini S6"; + compatible = "mecer,xms6", "rockchip,rk3229"; + + memory@60000000 { + device_type = "memory"; + reg = <0x60000000 0x40000000>; + }; + + dc_12v: dc-12v-regulator { + compatible = "regulator-fixed"; + regulator-name = "dc_12v"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + }; + + ext_gmac: ext_gmac { + compatible = "fixed-clock"; + clock-frequency = <125000000>; + clock-output-names = "ext_gmac"; + #clock-cells = <0>; + }; + + power-led { + compatible = "gpio-leds"; + + blue { + gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + }; + + vcc_host: vcc-host-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&host_vbus_drv>; + regulator-name = "vcc_host"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vcc_sys>; + }; + + vcc_phy: vcc-phy-regulator { + compatible = "regulator-fixed"; + enable-active-high; + regulator-name = "vcc_phy"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vccio_1v8>; + }; + + vcc_sys: vcc-sys-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&dc_12v>; + }; + + vccio_1v8: vccio-1v8-regulator { + compatible = "regulator-fixed"; + regulator-name = "vccio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + vin-supply = <&vcc_sys>; + }; + + vccio_3v3: vccio-3v3-regulator { + compatible = "regulator-fixed"; + regulator-name = "vccio_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + vin-supply = <&vcc_sys>; + }; + + vdd_arm: vdd-arm-regulator { + compatible = "pwm-regulator"; + pwms = <&pwm1 0 25000 1>; + pwm-supply = <&vcc_sys>; + regulator-name = "vdd_arm"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1400000>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_log: vdd-log-regulator { + compatible = "pwm-regulator"; + pwms = <&pwm2 0 25000 1>; + pwm-supply = <&vcc_sys>; + regulator-name = "vdd_log"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + regulator-boot-on; + }; +}; + +&cpu0 { + cpu-supply = <&vdd_arm>; +}; + +&cpu1 { + cpu-supply = <&vdd_arm>; +}; + +&cpu2 { + cpu-supply = <&vdd_arm>; +}; + +&cpu3 { + cpu-supply = <&vdd_arm>; +}; + +&emmc { + cap-mmc-highspeed; + disable-wp; + non-removable; + status = "okay"; +}; + +&gmac { + assigned-clocks = <&cru SCLK_MAC_SRC>; + assigned-clock-rates = <50000000>; + clock_in_out = "output"; + phy-handle = <&phy>; + phy-mode = "rmii"; + phy-supply = <&vcc_phy>; + status = "okay"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + phy: phy@0 { + compatible = "ethernet-phy-id1234.d400", + "ethernet-phy-ieee802.3-c22"; + reg = <0>; + clocks = <&cru SCLK_MAC_PHY>; + phy-is-integrated; + resets = <&cru SRST_MACPHY>; + }; + }; +}; + +&gpu { + mali-supply = <&vdd_log>; + status = "okay"; +}; + +&hdmi { + status = "okay"; +}; + +&hdmi_phy { + status = "okay"; +}; + +&iep_mmu { + status = "okay"; +}; + +&io_domains { + status = "okay"; + + vccio1-supply = <&vccio_3v3>; + vccio2-supply = <&vccio_1v8>; + vccio4-supply = <&vccio_3v3>; +}; + +&pinctrl { + usb { + host_vbus_drv: host-vbus-drv { + rockchip,pins = <3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pwm1 { + status = "okay"; +}; + +&pwm2 { + status = "okay"; +}; + +&sdmmc { + cap-mmc-highspeed; + disable-wp; + status = "okay"; +}; + +&tsadc { + rockchip,hw-tshut-mode = <0>; + status = "okay"; +}; + +&u2phy0 { + status = "okay"; + + u2phy0_host: host-port { + phy-supply = <&vcc_host>; + status = "okay"; + }; + + u2phy0_otg: otg-port { + phy-supply = <&vcc_host>; + status = "okay"; + }; +}; + +&u2phy1 { + status = "okay"; + + u2phy1_host: host-port { + phy-supply = <&vcc_host>; + status = "okay"; + }; + + u2phy1_otg: otg-port { + phy-supply = <&vcc_host>; + status = "okay"; + }; +}; + +&uart2 { + pinctrl-0 = <&uart21_xfer>; + status = "okay"; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_ohci { + status = "okay"; +}; + +&usb_host1_ehci { + status = "okay"; +}; + +&usb_host1_ohci { + status = "okay"; +}; + +&usb_host2_ehci { + status = "okay"; +}; + +&usb_host2_ohci { + status = "okay"; +}; + +&usb_otg { + status = "okay"; +}; + +&vop { + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/rk3288-evb.dtsi b/arch/arm/boot/dts/rk3288-evb.dtsi index 820440715302d455ec6f176a905021bc15acf9ab..2afd686b2033ee00c2392777548e3fa96f217f76 100644 --- a/arch/arm/boot/dts/rk3288-evb.dtsi +++ b/arch/arm/boot/dts/rk3288-evb.dtsi @@ -97,7 +97,7 @@ }; panel: panel { - compatible ="lg,lp079qx1-sp0v", "simple-panel"; + compatible = "lg,lp079qx1-sp0v", "simple-panel"; backlight = <&backlight>; enable-gpios = <&gpio7 RK_PA4 GPIO_ACTIVE_HIGH>; pinctrl-0 = <&lcd_cs>; diff --git a/arch/arm/boot/dts/rk3288-fennec.dts b/arch/arm/boot/dts/rk3288-fennec.dts deleted file mode 100644 index 4847cf902a154a0ab5fe7a20970e00e0beb2cb09..0000000000000000000000000000000000000000 --- a/arch/arm/boot/dts/rk3288-fennec.dts +++ /dev/null @@ -1,347 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) - -/dts-v1/; - -#include "rk3288.dtsi" - -/ { - model = "Rockchip RK3288 Fennec Board"; - compatible = "rockchip,rk3288-fennec", "rockchip,rk3288"; - - memory@0 { - reg = <0x0 0x0 0x0 0x80000000>; - device_type = "memory"; - }; - - ext_gmac: external-gmac-clock { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <125000000>; - clock-output-names = "ext_gmac"; - }; - - vcc_sys: vsys-regulator { - compatible = "regulator-fixed"; - regulator-name = "vcc_sys"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - regulator-always-on; - regulator-boot-on; - }; -}; - -&cpu0 { - cpu0-supply = <&vdd_cpu>; -}; - -&emmc { - bus-width = <8>; - cap-mmc-highspeed; - non-removable; - pinctrl-names = "default"; - pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_pwr &emmc_bus8>; - status = "okay"; -}; - -&gmac { - assigned-clocks = <&cru SCLK_MAC>; - assigned-clock-parents = <&ext_gmac>; - clock_in_out = "input"; - pinctrl-names = "default"; - pinctrl-0 = <&rgmii_pins>, <&phy_rst>, <&phy_pmeb>, <&phy_int>; - phy-supply = <&vcc_lan>; - phy-mode = "rgmii"; - snps,reset-active-low; - snps,reset-delays-us = <0 10000 1000000>; - snps,reset-gpio = <&gpio4 RK_PB0 GPIO_ACTIVE_LOW>; - tx_delay = <0x30>; - rx_delay = <0x10>; - status = "okay"; -}; - -&gpu { - mali-supply = <&vdd_gpu>; - status = "okay"; -}; - -&hdmi { - status = "okay"; -}; - -&i2c0 { - status = "okay"; - clock-frequency = <400000>; - - rk808: pmic@1b { - compatible = "rockchip,rk808"; - reg = <0x1b>; - interrupt-parent = <&gpio0>; - interrupts = ; - #clock-cells = <1>; - clock-output-names = "xin32k", "rk808-clkout2"; - pinctrl-names = "default"; - pinctrl-0 = <&pmic_int &global_pwroff>; - rockchip,system-power-controller; - wakeup-source; - - vcc1-supply = <&vcc_sys>; - vcc2-supply = <&vcc_sys>; - vcc3-supply = <&vcc_sys>; - vcc4-supply = <&vcc_sys>; - vcc6-supply = <&vcc_sys>; - vcc7-supply = <&vcc_sys>; - vcc8-supply = <&vcc_io>; - vcc9-supply = <&vcc_io>; - vcc10-supply = <&vcc_io>; - vcc11-supply = <&vcc_io>; - vcc12-supply = <&vcc_io>; - vddio-supply = <&vcc_io>; - - regulators { - vdd_cpu: DCDC_REG1 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <750000>; - regulator-max-microvolt = <1350000>; - regulator-name = "vdd_arm"; - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vdd_gpu: DCDC_REG2 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <850000>; - regulator-max-microvolt = <1250000>; - regulator-name = "vdd_gpu"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1000000>; - }; - }; - - vcc_ddr: DCDC_REG3 { - regulator-always-on; - regulator-boot-on; - regulator-name = "vcc_ddr"; - regulator-state-mem { - regulator-on-in-suspend; - }; - }; - - vcc_io: DCDC_REG4 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-name = "vcc_io"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <3300000>; - }; - }; - - vccio_pmu: LDO_REG1 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-name = "vccio_pmu"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <3300000>; - }; - }; - - vcca_33: LDO_REG2 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-name = "vcca_33"; - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vdd_10: LDO_REG3 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; - regulator-name = "vdd_10"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1000000>; - }; - }; - - vcc_wl: LDO_REG4 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-name = "vcc_wl"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - vccio_sd: LDO_REG5 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; - regulator-name = "vccio_sd"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <3300000>; - }; - }; - - vdd10_lcd: LDO_REG6 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; - regulator-name = "vdd10_lcd"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1000000>; - }; - }; - - vcc_18: LDO_REG7 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-name = "vcc_18"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - vcc18_lcd: LDO_REG8 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-name = "vcc18_lcd"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - vcc_sd: SWITCH_REG1 { - regulator-always-on; - regulator-boot-on; - regulator-name = "vcc_sd"; - regulator-state-mem { - regulator-on-in-suspend; - }; - }; - - vcc_lan: SWITCH_REG2 { - regulator-always-on; - regulator-boot-on; - regulator-name = "vcc_lan"; - regulator-state-mem { - regulator-on-in-suspend; - }; - }; - }; - }; -}; - -&pinctrl { - pcfg_output_high: pcfg-output-high { - output-high; - }; - - pcfg_output_low: pcfg-output-low { - output-low; - }; - - pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma { - drive-strength = <8>; - }; - - pcfg_pull_up_drv_8ma: pcfg-pull-up-drv-8ma { - bias-pull-up; - drive-strength = <8>; - }; - - gmac { - phy_int: phy-int { - rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>; - }; - - phy_pmeb: phy-pmeb { - rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; - }; - - phy_rst: phy-rst { - rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_output_high>; - }; - }; - - pmic { - pmic_int: pmic-int { - rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>; - }; - }; - - usbphy { - host_drv: host-drv { - rockchip,pins = <0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; -}; - -&uart2 { - status = "okay"; -}; - -&usbphy { - pinctrl-names = "default"; - pinctrl-0 = <&host_drv>; - vbus_drv-gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>; - status = "okay"; -}; - -&usb_host0_ehci { - status = "okay"; -}; - -&usb_host1 { - status = "okay"; -}; - -&usb_otg { - status = "okay"; -}; - -&usb_hsic { - status = "okay"; -}; - -&vopb { - status = "okay"; -}; - -&vopb_mmu { - status = "okay"; -}; - -&vopl { - status = "okay"; -}; - -&vopl_mmu { - status = "okay"; -}; diff --git a/arch/arm/boot/dts/rk3288-tinker.dtsi b/arch/arm/boot/dts/rk3288-tinker.dtsi index 293576869546efa305ae662a9f3db1777cde4819..81e4e953d4a40b97c5c1d4a4ea573ed454b5df83 100644 --- a/arch/arm/boot/dts/rk3288-tinker.dtsi +++ b/arch/arm/boot/dts/rk3288-tinker.dtsi @@ -47,13 +47,13 @@ compatible = "gpio-leds"; act-led { - gpios=<&gpio1 RK_PD0 GPIO_ACTIVE_HIGH>; - linux,default-trigger="mmc0"; + gpios = <&gpio1 RK_PD0 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc0"; }; heartbeat-led { - gpios=<&gpio1 RK_PD1 GPIO_ACTIVE_HIGH>; - linux,default-trigger="heartbeat"; + gpios = <&gpio1 RK_PD1 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; }; pwr-led { @@ -443,7 +443,7 @@ &saradc { vref-supply = <&vcc18_ldo1>; - status ="okay"; + status = "okay"; }; &sdmmc { @@ -516,7 +516,7 @@ }; &usb_otg { - status= "okay"; + status = "okay"; }; &vopb { diff --git a/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi b/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi index 1cadb522fd0de0c1f104aa13db0f74e3a614d261..ffb60f880b3965153d02226c2e3f8da5d9a40c79 100644 --- a/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi +++ b/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi @@ -10,6 +10,7 @@ #include #include "rk3288-veyron.dtsi" #include "rk3288-veyron-analog-audio.dtsi" +#include "rk3288-veyron-edp.dtsi" #include "rk3288-veyron-sdmmc.dtsi" / { @@ -18,50 +19,6 @@ i2c20 = &i2c_tunnel; }; - backlight: backlight { - compatible = "pwm-backlight"; - brightness-levels = < - 0 1 2 3 4 5 6 7 - 8 9 10 11 12 13 14 15 - 16 17 18 19 20 21 22 23 - 24 25 26 27 28 29 30 31 - 32 33 34 35 36 37 38 39 - 40 41 42 43 44 45 46 47 - 48 49 50 51 52 53 54 55 - 56 57 58 59 60 61 62 63 - 64 65 66 67 68 69 70 71 - 72 73 74 75 76 77 78 79 - 80 81 82 83 84 85 86 87 - 88 89 90 91 92 93 94 95 - 96 97 98 99 100 101 102 103 - 104 105 106 107 108 109 110 111 - 112 113 114 115 116 117 118 119 - 120 121 122 123 124 125 126 127 - 128 129 130 131 132 133 134 135 - 136 137 138 139 140 141 142 143 - 144 145 146 147 148 149 150 151 - 152 153 154 155 156 157 158 159 - 160 161 162 163 164 165 166 167 - 168 169 170 171 172 173 174 175 - 176 177 178 179 180 181 182 183 - 184 185 186 187 188 189 190 191 - 192 193 194 195 196 197 198 199 - 200 201 202 203 204 205 206 207 - 208 209 210 211 212 213 214 215 - 216 217 218 219 220 221 222 223 - 224 225 226 227 228 229 230 231 - 232 233 234 235 236 237 238 239 - 240 241 242 243 244 245 246 247 - 248 249 250 251 252 253 254 255>; - default-brightness-level = <128>; - enable-gpios = <&gpio7 RK_PA2 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&bl_en>; - pwms = <&pwm0 0 1000000 0>; - post-pwm-on-delay-ms = <10>; - pwm-off-delay-ms = <10>; - }; - gpio-charger { compatible = "gpio-charger"; charger-type = "mains"; @@ -85,21 +42,6 @@ }; }; - panel: panel { - compatible ="innolux,n116bge", "simple-panel"; - status = "okay"; - power-supply = <&vcc33_lcd>; - backlight = <&backlight>; - - ports { - panel_in: port { - panel_in_edp: endpoint { - remote-endpoint = <&edp_out_panel>; - }; - }; - }; - }; - /* A non-regulated voltage from power supply or battery */ vccsys: vccsys { compatible = "regulator-fixed"; @@ -141,33 +83,6 @@ }; }; -&edp { - status = "okay"; - - pinctrl-names = "default"; - pinctrl-0 = <&edp_hpd>; - - ports { - edp_out: port@1 { - reg = <1>; - #address-cells = <1>; - #size-cells = <0>; - edp_out_panel: endpoint@0 { - reg = <0>; - remote-endpoint = <&panel_in_edp>; - }; - }; - }; -}; - -&edp_phy { - status = "okay"; -}; - -&pwm0 { - status = "okay"; -}; - &rk808 { vcc11-supply = <&vcc_5v>; @@ -220,14 +135,6 @@ }; }; -&vopl { - status = "okay"; -}; - -&vopl_mmu { - status = "okay"; -}; - &pinctrl { pinctrl-0 = < /* Common for sleep and wake, but no owners */ @@ -250,12 +157,6 @@ &bt_dev_wake_sleep >; - backlight { - bl_en: bl-en { - rockchip,pins = <7 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - buttons { ap_lid_int_l: ap-lid-int-l { rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>; diff --git a/arch/arm/boot/dts/rk3288-veyron-edp.dtsi b/arch/arm/boot/dts/rk3288-veyron-edp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b12e061c5f7f60055ab17725bd26e7ce0df6cc88 --- /dev/null +++ b/arch/arm/boot/dts/rk3288-veyron-edp.dtsi @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google Veyron (and derivatives) fragment for the edp displays + * + * Copyright 2019 Google LLC + */ + +/ { + backlight_regulator: backlight-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&bl_pwr_en>; + regulator-name = "backlight_regulator"; + vin-supply = <&vcc33_sys>; + startup-delay-us = <15000>; + }; + + panel_regulator: panel-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio7 RK_PB6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&lcd_enable_h>; + regulator-name = "panel_regulator"; + vin-supply = <&vcc33_sys>; + }; + + vcc18_lcd: vcc18-lcd { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&avdd_1v8_disp_en>; + regulator-name = "vcc18_lcd"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vcc18_wl>; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + brightness-levels = < + 0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 19 20 21 22 23 + 24 25 26 27 28 29 30 31 + 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 + 48 49 50 51 52 53 54 55 + 56 57 58 59 60 61 62 63 + 64 65 66 67 68 69 70 71 + 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 + 88 89 90 91 92 93 94 95 + 96 97 98 99 100 101 102 103 + 104 105 106 107 108 109 110 111 + 112 113 114 115 116 117 118 119 + 120 121 122 123 124 125 126 127 + 128 129 130 131 132 133 134 135 + 136 137 138 139 140 141 142 143 + 144 145 146 147 148 149 150 151 + 152 153 154 155 156 157 158 159 + 160 161 162 163 164 165 166 167 + 168 169 170 171 172 173 174 175 + 176 177 178 179 180 181 182 183 + 184 185 186 187 188 189 190 191 + 192 193 194 195 196 197 198 199 + 200 201 202 203 204 205 206 207 + 208 209 210 211 212 213 214 215 + 216 217 218 219 220 221 222 223 + 224 225 226 227 228 229 230 231 + 232 233 234 235 236 237 238 239 + 240 241 242 243 244 245 246 247 + 248 249 250 251 252 253 254 255>; + default-brightness-level = <128>; + enable-gpios = <&gpio7 RK_PA2 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&bl_en>; + pwms = <&pwm0 0 1000000 0>; + post-pwm-on-delay-ms = <10>; + pwm-off-delay-ms = <10>; + power-supply = <&backlight_regulator>; + }; + + panel: panel { + compatible = "innolux,n116bge", "simple-panel"; + status = "okay"; + power-supply = <&panel_regulator>; + backlight = <&backlight>; + + panel-timing { + clock-frequency = <74250000>; + hactive = <1366>; + hfront-porch = <136>; + hback-porch = <60>; + hsync-len = <30>; + hsync-active = <0>; + vactive = <768>; + vfront-porch = <8>; + vback-porch = <12>; + vsync-len = <12>; + vsync-active = <0>; + }; + + ports { + panel_in: port { + panel_in_edp: endpoint { + remote-endpoint = <&edp_out_panel>; + }; + }; + }; + }; +}; + +&edp { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&edp_hpd>; + + ports { + edp_out: port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + edp_out_panel: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_in_edp>; + }; + }; + }; +}; + +&edp_phy { + status = "okay"; +}; + +&pwm0 { + status = "okay"; +}; + +&vopl { + status = "okay"; +}; + +&vopl_mmu { + status = "okay"; +}; + +&pinctrl { + backlight { + bl_pwr_en: bl_pwr_en { + rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + bl_en: bl-en { + rockchip,pins = <7 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + lcd { + lcd_enable_h: lcd-en { + rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + avdd_1v8_disp_en: avdd-1v8-disp-en { + rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; diff --git a/arch/arm/boot/dts/rk3288-veyron-fievel.dts b/arch/arm/boot/dts/rk3288-veyron-fievel.dts new file mode 100644 index 0000000000000000000000000000000000000000..9a0f55085839d9b9b495949784c61ea9aceb9d30 --- /dev/null +++ b/arch/arm/boot/dts/rk3288-veyron-fievel.dts @@ -0,0 +1,522 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google Veyron Fievel Rev 0+ board device tree source + * + * Copyright 2016 Google, Inc + */ + +/dts-v1/; +#include "rk3288-veyron.dtsi" +#include "rk3288-veyron-analog-audio.dtsi" + +/ { + model = "Google Fievel"; + compatible = "google,veyron-fievel-rev8", "google,veyron-fievel-rev7", + "google,veyron-fievel-rev6", "google,veyron-fievel-rev5", + "google,veyron-fievel-rev4", "google,veyron-fievel-rev3", + "google,veyron-fievel-rev2", "google,veyron-fievel-rev1", + "google,veyron-fievel-rev0", "google,veyron-fievel", + "google,veyron", "rockchip,rk3288"; + + /delete-node/ bt-activity; + + vccsys: vccsys { + compatible = "regulator-fixed"; + regulator-name = "vccsys"; + regulator-boot-on; + regulator-always-on; + }; + + /* + * vcc33_pmuio and vcc33_io is sourced directly from vcc33_sys, + * enabled by vcc_18 + */ + vcc33_io: vcc33-io { + compatible = "regulator-fixed"; + regulator-always-on; + regulator-boot-on; + regulator-name = "vcc33_io"; + }; + + vcc5_host1: vcc5-host1-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio5 RK_PC2 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&hub_usb1_pwr_en>; + regulator-name = "vcc5_host1"; + regulator-always-on; + regulator-boot-on; + }; + + vcc5_host2: vcc5-host2-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio5 RK_PB6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&hub_usb2_pwr_en>; + regulator-name = "vcc5_host2"; + regulator-always-on; + regulator-boot-on; + }; + + vcc5v_otg: vcc5v-otg-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_otg_pwr_en>; + regulator-name = "vcc5_otg"; + regulator-always-on; + regulator-boot-on; + }; + + ext_gmac: external-gmac-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <125000000>; + clock-output-names = "ext_gmac"; + }; +}; + +&gmac { + status = "okay"; + + assigned-clocks = <&cru SCLK_MAC>; + assigned-clock-parents = <&ext_gmac>; + clock_in_out = "input"; + phy-handle = <ðphy>; + phy-mode = "rgmii"; + phy-supply = <&vcc33_lan>; + pinctrl-names = "default"; + pinctrl-0 = <&rgmii_pins>, <&phy_rst>, <&phy_pmeb>, <&phy_int>; + rx_delay = <0x10>; + tx_delay = <0x30>; + + /* + * Reset for the RTL8211 PHY which requires a 10-ms reset pulse (low) + * with a 30ms settling time. + */ + snps,reset-gpio = <&gpio4 RK_PB0 0>; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 30000>; + wakeup-source; + + mdio0 { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + ethphy: ethernet-phy@1 { + reg = <1>; + }; + }; +}; + +&rk808 { + dvs-gpios = <&gpio7 RK_PB4 GPIO_ACTIVE_HIGH>, + <&gpio7 RK_PB7 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int_l &dvs_1 &dvs_2>; + + vcc6-supply = <&vcc33_sys>; + vcc10-supply = <&vcc33_sys>; + vcc11-supply = <&vcc_5v>; + vcc12-supply = <&vcc33_sys>; + + regulators { + /delete-node/ LDO_REG1; + + /* + * According to the schematic, vcc18_lcdt is for + * HDMI_AVDD_1V8 + */ + vcc18_lcdt: LDO_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vdd18_lcdt"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + /* + * This is not a pwren anymore, but the real power supply, + * vdd10_lcd for HDMI_AVDD_1V0 + */ + vdd10_lcd: LDO_REG7 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-name = "vdd10_lcd"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + /* for usb camera */ + vcc33_ccd: LDO_REG8 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc33_ccd"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc33_lan: SWITCH_REG2 { + regulator-name = "vcc33_lan"; + }; + }; +}; + +&sdio0 { + #address-cells = <1>; + #size-cells = <0>; + + btmrvl: btmrvl@2 { + compatible = "marvell,sd8897-bt"; + reg = <2>; + interrupt-parent = <&gpio4>; + interrupts = ; + marvell,wakeup-pin = /bits/ 16 <13>; + pinctrl-names = "default"; + pinctrl-0 = <&bt_host_wake_l>; + }; +}; + +&vcc50_hdmi { + enable-active-high; + gpio = <&gpio5 RK_PC3 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc50_hdmi_en>; +}; + +&vcc_5v { + enable-active-high; + gpio = <&gpio7 RK_PC5 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&drv_5v>; +}; + +&gpio0 { + gpio-line-names = "PMIC_SLEEP_AP", + "DDRIO_PWROFF", + "DDRIO_RETEN", + "TS3A227E_INT_L", + "PMIC_INT_L", + "PWR_KEY_L", + "HUB_USB1_nFALUT", + "PHY_PMEB", + + "PHY_INT", + "REC_MODE_L", + "OTP_OUT", + "", + "USB_OTG_POWER_EN", + "AP_WARM_RESET_H", + "USB_OTG_nFALUT", + "I2C0_SDA_PMIC", + + "I2C0_SCL_PMIC", + "DEVMODE_L", + "USB_INT"; +}; + +&gpio2 { + gpio-line-names = "CONFIG0", + "CONFIG1", + "CONFIG2", + "", + "", + "", + "", + "CONFIG3", + + "", + "EMMC_RST_L", + "", + "", + "BL_PWR_EN", + "", + "TOUCH_INT", + "TOUCH_RST", + + "I2C3_SCL_TP", + "I2C3_SDA_TP"; +}; + +&gpio3 { + gpio-line-names = "FLASH0_D0", + "FLASH0_D1", + "FLASH0_D2", + "FLASH0_D3", + "FLASH0_D4", + "FLASH0_D5", + "FLASH0_D6", + "FLASH0_D7", + + "VCC5V_GOOD_H", + "", + "", + "", + "", + "", + "", + "", + + "FLASH0_CS2/EMMC_CMD", + "", + "FLASH0_DQS/EMMC_CLKO", + "", + "", + "", + "", + "", + + "PHY_TXD2", + "PHY_TXD3", + "MAC_RXD2", + "MAC_RXD3", + "PHY_TXD0", + "PHY_TXD1", + "MAC_RXD0", + "MAC_RXD1"; +}; + +&gpio4 { + gpio-line-names = "MAC_MDC", + "MAC_RXDV", + "MAC_RXER", + "MAC_CLK", + "PHY_TXEN", + "MAC_MDIO", + "MAC_RXCLK", + "", + + "PHY_RST", + "PHY_TXCLK", + "", + "", + "", + "", + "", + "", + + "UART0_RXD", + "UART0_TXD", + "UART0_CTS_L", + "UART0_RTS_L", + "SDIO0_D0", + "SDIO0_D1", + "SDIO0_D2", + "SDIO0_D3", + + "SDIO0_CMD", + "SDIO0_CLK", + "BT_DEV_WAKE", + "", + "WIFI_ENABLE_H", + "BT_ENABLE_L", + "WIFI_HOST_WAKE", + "BT_HOST_WAKE"; +}; + +&gpio5 { + gpio-line-names = "", + "", + "", + "", + "", + "", + "", + "", + + "", + "", + "", + "", + "USB_OTG_CTL1", + "HUB_USB2_CTL1", + "HUB_USB2_PWR_EN", + "HUB_USB_ILIM_SEL", + + "USB_OTG_STATUS_L", + "HUB_USB1_CTL1", + "HUB_USB1_PWR_EN", + "VCC50_HDMI_EN"; +}; + +&gpio6 { + gpio-line-names = "I2S0_SCLK", + "I2S0_LRCK_RX", + "I2S0_LRCK_TX", + "I2S0_SDI", + "I2S0_SDO0", + "HP_DET_H", + "", + "INT_CODEC", + + "I2S0_CLK", + "I2C2_SDA", + "I2C2_SCL", + "MICDET", + "", + "", + "", + "", + + "HUB_USB2_nFALUT", + "USB_OTG_ILIM_SEL"; +}; + +&gpio7 { + gpio-line-names = "LCD_BL_PWM", + "PWM_LOG", + "BL_EN", + "PWR_LED1", + "TPM_INT_H", + "SPK_ON", + "FW_WP_AP", + "", + + "CPU_NMI", + "DVSOK", + "", + "EDP_HPD", + "DVS1", + "", + "LCD_EN", + "DVS2", + + "HDMI_CEC", + "I2C4_SDA", + "I2C4_SCL", + "I2C5_SDA_HDMI", + "I2C5_SCL_HDMI", + "5V_DRV", + "UART2_RXD", + "UART2_TXD"; +}; + +&gpio8 { + gpio-line-names = "RAM_ID0", + "RAM_ID1", + "RAM_ID2", + "RAM_ID3", + "I2C1_SDA_TPM", + "I2C1_SCL_TPM", + "SPI2_CLK", + "SPI2_CS0", + + "SPI2_RXD", + "SPI2_TXD"; +}; + +&pinctrl { + pinctrl-names = "default", "sleep"; + pinctrl-0 = < + /* Common for sleep and wake, but no owners */ + &ddr0_retention + &ddrio_pwroff + &global_pwroff + + /* For usb bc1.2 */ + &usb_otg_ilim_sel + &usb_usb_ilim_sel + + /* Wake only */ + &bt_dev_wake_awake + &pwr_led1_on + >; + + pinctrl-1 = < + /* Common for sleep and wake, but no owners */ + &ddr0_retention + &ddrio_pwroff + &global_pwroff + + /* For usb bc1.2 */ + &usb_otg_ilim_sel + &usb_usb_ilim_sel + + /* Sleep only */ + &bt_dev_wake_sleep + &pwr_led1_blink + >; + + buck-5v { + drv_5v: drv-5v { + rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + gmac { + phy_rst: phy-rst { + rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_output_high>; + }; + + phy_pmeb: phy-pmeb { + rockchip,pins = <0 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + phy_int: phy-int { + rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + hdmi { + vcc50_hdmi_en: vcc50-hdmi-en { + rockchip,pins = <5 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + leds { + pwr_led1_on: pwr-led1-on { + rockchip,pins = <7 RK_PA3 RK_FUNC_GPIO &pcfg_output_low>; + }; + + pwr_led1_blink: pwr-led1-blink { + rockchip,pins = <7 RK_PA3 RK_FUNC_GPIO &pcfg_output_high>; + }; + }; + + pmic { + dvs_1: dvs-1 { + rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>; + }; + + dvs_2: dvs-2 { + rockchip,pins = <7 RK_PB7 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + usb-bc12 { + usb_otg_ilim_sel: usb-otg-ilim-sel { + rockchip,pins = <6 RK_PC1 RK_FUNC_GPIO &pcfg_output_low>; + }; + + usb_usb_ilim_sel: usb-usb-ilim-sel { + rockchip,pins = <5 RK_PB7 RK_FUNC_GPIO &pcfg_output_low>; + }; + }; + + usb-host { + hub_usb1_pwr_en: hub_usb1_pwr_en { + rockchip,pins = <5 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + hub_usb2_pwr_en: hub_usb2_pwr_en { + rockchip,pins = <5 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + usb_otg_pwr_en: usb_otg_pwr_en { + rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; diff --git a/arch/arm/boot/dts/rk3288-veyron-jaq.dts b/arch/arm/boot/dts/rk3288-veyron-jaq.dts index fcd119168cb65ac0aaebac80b98208d09a401deb..80386203e85bcb30bbbce02432c7f7990147be7c 100644 --- a/arch/arm/boot/dts/rk3288-veyron-jaq.dts +++ b/arch/arm/boot/dts/rk3288-veyron-jaq.dts @@ -16,40 +16,6 @@ "google,veyron-jaq-rev3", "google,veyron-jaq-rev2", "google,veyron-jaq-rev1", "google,veyron-jaq", "google,veyron", "rockchip,rk3288"; - - panel_regulator: panel-regulator { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio7 RK_PB6 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&lcd_enable_h>; - regulator-name = "panel_regulator"; - startup-delay-us = <100000>; - vin-supply = <&vcc33_sys>; - }; - - vcc18_lcd: vcc18-lcd { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&avdd_1v8_disp_en>; - regulator-name = "vcc18_lcd"; - regulator-always-on; - regulator-boot-on; - vin-supply = <&vcc18_wl>; - }; - - backlight_regulator: backlight-regulator { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&bl_pwr_en>; - regulator-name = "backlight_regulator"; - vin-supply = <&vcc33_sys>; - startup-delay-us = <15000>; - }; }; &backlight { @@ -87,11 +53,6 @@ 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255>; - power-supply = <&backlight_regulator>; -}; - -&panel { - power-supply = <&panel_regulator>; }; &rk808 { @@ -343,12 +304,6 @@ }; &pinctrl { - backlight { - bl_pwr_en: bl_pwr_en { - rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - buck-5v { drv_5v: drv-5v { rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; @@ -361,16 +316,6 @@ }; }; - lcd { - lcd_enable_h: lcd-en { - rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; - }; - - avdd_1v8_disp_en: avdd-1v8-disp-en { - rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - pmic { dvs_1: dvs-1 { rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>; diff --git a/arch/arm/boot/dts/rk3288-veyron-jerry.dts b/arch/arm/boot/dts/rk3288-veyron-jerry.dts index 164561f04c1d5172e9965a43fdaa1c04217e8dc9..a6ee44f0fe13b18f789a37abf03d7016e295845c 100644 --- a/arch/arm/boot/dts/rk3288-veyron-jerry.dts +++ b/arch/arm/boot/dts/rk3288-veyron-jerry.dts @@ -18,48 +18,6 @@ "google,veyron-jerry-rev5", "google,veyron-jerry-rev4", "google,veyron-jerry-rev3", "google,veyron-jerry", "google,veyron", "rockchip,rk3288"; - - panel_regulator: panel-regulator { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio7 RK_PB6 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&lcd_enable_h>; - regulator-name = "panel_regulator"; - startup-delay-us = <100000>; - vin-supply = <&vcc33_sys>; - }; - - vcc18_lcd: vcc18-lcd { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&avdd_1v8_disp_en>; - regulator-name = "vcc18_lcd"; - regulator-always-on; - regulator-boot-on; - vin-supply = <&vcc18_wl>; - }; - - backlight_regulator: backlight-regulator { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&bl_pwr_en>; - regulator-name = "backlight_regulator"; - vin-supply = <&vcc33_sys>; - startup-delay-us = <15000>; - }; -}; - -&backlight { - power-supply = <&backlight_regulator>; -}; - -&panel { - power-supply= <&panel_regulator>; }; &rk808 { @@ -82,6 +40,155 @@ }; }; +&sdio0 { + #address-cells = <1>; + #size-cells = <0>; + + mwifiex: wifi@1 { + compatible = "marvell,sd8897"; + reg = <1>; + + marvell,caldata-txpwrlimit-2g = /bits/ 8 < +0x01 0x00 0x06 0x00 0x08 0x02 0x89 0x01 +0x24 0x00 0x67 0x09 0x14 0x01 0x00 0x0f 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0c +0x05 0x0c 0x06 0x0c 0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0c 0x0b 0x0c 0x0c 0x0c +0x0d 0x09 0x0e 0x09 0x0f 0x09 0x89 0x01 0x24 0x00 0x67 0x09 0x14 0x02 0x00 0x0f +0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0c 0x05 0x0c 0x06 0x0c 0x07 0x09 0x08 0x09 +0x09 0x09 0x0a 0x0c 0x0b 0x0c 0x0c 0x0c 0x0d 0x09 0x0e 0x09 0x0f 0x09 0x89 0x01 +0x24 0x00 0x67 0x09 0x14 0x03 0x00 0x0f 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0c +0x05 0x0c 0x06 0x0c 0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0c 0x0b 0x0c 0x0c 0x0c +0x0d 0x09 0x0e 0x09 0x0f 0x09 0x89 0x01 0x24 0x00 0x67 0x09 0x14 0x04 0x00 0x0f +0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0c 0x05 0x0c 0x06 0x0c 0x07 0x09 0x08 0x09 +0x09 0x09 0x0a 0x0c 0x0b 0x0c 0x0c 0x0c 0x0d 0x09 0x0e 0x09 0x0f 0x09 0x89 0x01 +0x24 0x00 0x67 0x09 0x14 0x05 0x00 0x0f 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0c +0x05 0x0c 0x06 0x0c 0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0c 0x0b 0x0c 0x0c 0x0c +0x0d 0x09 0x0e 0x09 0x0f 0x09 0x89 0x01 0x24 0x00 0x67 0x09 0x14 0x06 0x00 0x0f +0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0c 0x05 0x0c 0x06 0x0c 0x07 0x09 0x08 0x09 +0x09 0x09 0x0a 0x0c 0x0b 0x0c 0x0c 0x0c 0x0d 0x09 0x0e 0x09 0x0f 0x09 0x89 0x01 +0x24 0x00 0x67 0x09 0x14 0x07 0x00 0x0f 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0c +0x05 0x0c 0x06 0x0c 0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0c 0x0b 0x0c 0x0c 0x0c +0x0d 0x09 0x0e 0x09 0x0f 0x09 0x89 0x01 0x24 0x00 0x67 0x09 0x14 0x08 0x00 0x0f +0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0c 0x05 0x0c 0x06 0x0c 0x07 0x09 0x08 0x09 +0x09 0x09 0x0a 0x0c 0x0b 0x0c 0x0c 0x0c 0x0d 0x09 0x0e 0x09 0x0f 0x09 0x89 0x01 +0x24 0x00 0x67 0x09 0x14 0x09 0x00 0x0f 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0c +0x05 0x0c 0x06 0x0c 0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0c 0x0b 0x0c 0x0c 0x0c +0x0d 0x09 0x0e 0x09 0x0f 0x09 0x89 0x01 0x24 0x00 0x67 0x09 0x14 0x0a 0x00 0x0f +0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0c 0x05 0x0c 0x06 0x0c 0x07 0x09 0x08 0x09 +0x09 0x09 0x0a 0x0c 0x0b 0x0c 0x0c 0x0c 0x0d 0x09 0x0e 0x09 0x0f 0x09 0x89 0x01 +0x24 0x00 0x67 0x09 0x14 0x0b 0x00 0x0f 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0c +0x05 0x0c 0x06 0x0c 0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0c 0x0b 0x0c 0x0c 0x0c +0x0d 0x09 0x0e 0x09 0x0f 0x09 0x89 0x01 0x24 0x00 0x67 0x09 0x14 0x0c 0x00 0x0f +0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0c 0x05 0x0c 0x06 0x0c 0x07 0x09 0x08 0x09 +0x09 0x09 0x0a 0x0c 0x0b 0x0c 0x0c 0x0c 0x0d 0x09 0x0e 0x09 0x0f 0x09 0x89 0x01 +0x24 0x00 0x67 0x09 0x14 0x0d 0x00 0x0f 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0c +0x05 0x0c 0x06 0x0c 0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0c 0x0b 0x0c 0x0c 0x0c +0x0d 0x09 0x0e 0x09 0x0f 0x09>; + + marvell,caldata-txpwrlimit-5g-sub0 = /bits/ 8 < +0x01 0x00 0x06 0x00 0xf0 0x01 0x89 0x01 +0x3a 0x00 0x88 0x13 0x14 0x24 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0a 0x05 0x0a +0x06 0x0a 0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x09 +0x0e 0x09 0x0f 0x09 0x10 0x05 0x11 0x05 0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 +0x16 0x05 0x17 0x05 0x18 0x05 0x19 0x05 0x1a 0x05 0x1b 0x05 0x89 0x01 0x3a 0x00 +0x88 0x13 0x14 0x28 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0a 0x05 0x0a 0x06 0x0a +0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x09 0x0e 0x09 +0x0f 0x09 0x10 0x05 0x11 0x05 0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 0x16 0x05 +0x17 0x05 0x18 0x05 0x19 0x05 0x1a 0x05 0x1b 0x05 0x89 0x01 0x3a 0x00 0x88 0x13 +0x14 0x2c 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0a 0x05 0x0a 0x06 0x0a 0x07 0x09 +0x08 0x09 0x09 0x09 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x09 0x0e 0x09 0x0f 0x09 +0x10 0x05 0x11 0x05 0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 0x16 0x05 0x17 0x05 +0x18 0x05 0x19 0x05 0x1a 0x05 0x1b 0x05 0x89 0x01 0x3a 0x00 0x88 0x13 0x14 0x30 +0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0a 0x05 0x0a 0x06 0x0a 0x07 0x09 0x08 0x09 +0x09 0x09 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x09 0x0e 0x09 0x0f 0x09 0x10 0x05 +0x11 0x05 0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 0x16 0x05 0x17 0x05 0x18 0x05 +0x19 0x05 0x1a 0x05 0x1b 0x05 0x89 0x01 0x3a 0x00 0x88 0x13 0x14 0x34 0x01 0x0c +0x02 0x0c 0x03 0x0c 0x04 0x0a 0x05 0x0a 0x06 0x0a 0x07 0x09 0x08 0x09 0x09 0x09 +0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x09 0x0e 0x09 0x0f 0x09 0x10 0x05 0x11 0x05 +0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 0x16 0x05 0x17 0x05 0x18 0x05 0x19 0x05 +0x1a 0x05 0x1b 0x05 0x89 0x01 0x3a 0x00 0x88 0x13 0x14 0x38 0x01 0x0c 0x02 0x0c +0x03 0x0c 0x04 0x0a 0x05 0x0a 0x06 0x0a 0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0a +0x0b 0x0a 0x0c 0x0a 0x0d 0x09 0x0e 0x09 0x0f 0x09 0x10 0x05 0x11 0x05 0x12 0x05 +0x13 0x05 0x14 0x05 0x15 0x05 0x16 0x05 0x17 0x05 0x18 0x05 0x19 0x05 0x1a 0x05 +0x1b 0x05 0x89 0x01 0x3a 0x00 0x88 0x13 0x14 0x3c 0x01 0x0c 0x02 0x0c 0x03 0x0c +0x04 0x0a 0x05 0x0a 0x06 0x0a 0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0a 0x0b 0x0a +0x0c 0x0a 0x0d 0x09 0x0e 0x09 0x0f 0x09 0x10 0x05 0x11 0x05 0x12 0x05 0x13 0x05 +0x14 0x05 0x15 0x05 0x16 0x05 0x17 0x05 0x18 0x05 0x19 0x05 0x1a 0x05 0x1b 0x05 +0x89 0x01 0x3a 0x00 0x88 0x13 0x14 0x40 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0a +0x05 0x0a 0x06 0x0a 0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a +0x0d 0x09 0x0e 0x09 0x0f 0x09 0x10 0x05 0x11 0x05 0x12 0x05 0x13 0x05 0x14 0x05 +0x15 0x05 0x16 0x05 0x17 0x05 0x18 0x05 0x19 0x05 0x1a 0x05 0x1b 0x05>; + + marvell,caldata-txpwrlimit-5g-sub1 = /bits/ 8 < +0x01 0x00 0x06 0x00 0xaa 0x02 0x89 0x01 +0x3a 0x00 0x88 0x13 0x14 0x64 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0a 0x05 0x0a +0x06 0x0a 0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x09 +0x0e 0x09 0x0f 0x09 0x10 0x05 0x11 0x05 0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 +0x16 0x05 0x17 0x05 0x18 0x05 0x19 0x05 0x1a 0x05 0x1b 0x05 0x89 0x01 0x3a 0x00 +0x88 0x13 0x14 0x68 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0a 0x05 0x0a 0x06 0x0a +0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x09 0x0e 0x09 +0x0f 0x09 0x10 0x05 0x11 0x05 0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 0x16 0x05 +0x17 0x05 0x18 0x05 0x19 0x05 0x1a 0x05 0x1b 0x05 0x89 0x01 0x3a 0x00 0x88 0x13 +0x14 0x6c 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0a 0x05 0x0a 0x06 0x0a 0x07 0x09 +0x08 0x09 0x09 0x09 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x09 0x0e 0x09 0x0f 0x09 +0x10 0x05 0x11 0x05 0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 0x16 0x05 0x17 0x05 +0x18 0x05 0x19 0x05 0x1a 0x05 0x1b 0x05 0x89 0x01 0x3a 0x00 0x88 0x13 0x14 0x70 +0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0a 0x05 0x0a 0x06 0x0a 0x07 0x09 0x08 0x09 +0x09 0x09 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x09 0x0e 0x09 0x0f 0x09 0x10 0x05 +0x11 0x05 0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 0x16 0x05 0x17 0x05 0x18 0x05 +0x19 0x05 0x1a 0x05 0x1b 0x05 0x89 0x01 0x3a 0x00 0x88 0x13 0x14 0x74 0x01 0x0c +0x02 0x0c 0x03 0x0c 0x04 0x0a 0x05 0x0a 0x06 0x0a 0x07 0x09 0x08 0x09 0x09 0x09 +0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x09 0x0e 0x09 0x0f 0x09 0x10 0x05 0x11 0x05 +0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 0x16 0x05 0x17 0x05 0x18 0x05 0x19 0x05 +0x1a 0x05 0x1b 0x05 0x89 0x01 0x3a 0x00 0x88 0x13 0x14 0x78 0x01 0x0c 0x02 0x0c +0x03 0x0c 0x04 0x0a 0x05 0x0a 0x06 0x0a 0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0a +0x0b 0x0a 0x0c 0x0a 0x0d 0x09 0x0e 0x09 0x0f 0x09 0x10 0x05 0x11 0x05 0x12 0x05 +0x13 0x05 0x14 0x05 0x15 0x05 0x16 0x05 0x17 0x05 0x18 0x05 0x19 0x05 0x1a 0x05 +0x1b 0x05 0x89 0x01 0x3a 0x00 0x88 0x13 0x14 0x7c 0x01 0x0c 0x02 0x0c 0x03 0x0c +0x04 0x0a 0x05 0x0a 0x06 0x0a 0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0a 0x0b 0x0a +0x0c 0x0a 0x0d 0x09 0x0e 0x09 0x0f 0x09 0x10 0x05 0x11 0x05 0x12 0x05 0x13 0x05 +0x14 0x05 0x15 0x05 0x16 0x05 0x17 0x05 0x18 0x05 0x19 0x05 0x1a 0x05 0x1b 0x05 +0x89 0x01 0x3a 0x00 0x88 0x13 0x14 0x80 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0a +0x05 0x0a 0x06 0x0a 0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a +0x0d 0x09 0x0e 0x09 0x0f 0x09 0x10 0x05 0x11 0x05 0x12 0x05 0x13 0x05 0x14 0x05 +0x15 0x05 0x16 0x05 0x17 0x05 0x18 0x05 0x19 0x05 0x1a 0x05 0x1b 0x05 0x89 0x01 +0x3a 0x00 0x88 0x13 0x14 0x84 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0a 0x05 0x0a +0x06 0x0a 0x07 0x09 0x08 0x09 0x09 0x09 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x09 +0x0e 0x09 0x0f 0x09 0x10 0x05 0x11 0x05 0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 +0x16 0x05 0x17 0x05 0x18 0x05 0x19 0x05 0x1a 0x05 0x1b 0x05 0x89 0x01 0x3a 0x00 +0x88 0x13 0x14 0x88 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0a 0x05 0x0a 0x06 0x0a +0x07 0x08 0x08 0x08 0x09 0x08 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x08 0x0e 0x08 +0x0f 0x08 0x10 0x04 0x11 0x04 0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 0x16 0x04 +0x17 0x04 0x18 0x05 0x19 0x05 0x1a 0x05 0x1b 0x05 0x89 0x01 0x3a 0x00 0x88 0x13 +0x14 0x8c 0x01 0x0c 0x02 0x0c 0x03 0x0c 0x04 0x0a 0x05 0x0a 0x06 0x0a 0x07 0x08 +0x08 0x08 0x09 0x08 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x08 0x0e 0x08 0x0f 0x08 +0x10 0x04 0x11 0x04 0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 0x16 0x04 0x17 0x04 +0x18 0x05 0x19 0x05 0x1a 0x05 0x1b 0x05>; + + marvell,caldata-txpwrlimit-5g-sub2 = /bits/ 8 < +0x01 0x00 0x06 0x00 0x36 0x01 0x89 0x01 +0x3a 0x00 0x88 0x13 0x14 0x95 0x01 0x0b 0x02 0x0b 0x03 0x0b 0x04 0x0a 0x05 0x0a +0x06 0x0a 0x07 0x08 0x08 0x08 0x09 0x08 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x08 +0x0e 0x08 0x0f 0x08 0x10 0x04 0x11 0x04 0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 +0x16 0x04 0x17 0x04 0x18 0x05 0x19 0x05 0x1a 0x05 0x1b 0x05 0x89 0x01 0x3a 0x00 +0x88 0x13 0x14 0x99 0x01 0x0b 0x02 0x0b 0x03 0x0b 0x04 0x0a 0x05 0x0a 0x06 0x0a +0x07 0x08 0x08 0x08 0x09 0x08 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x08 0x0e 0x08 +0x0f 0x08 0x10 0x04 0x11 0x04 0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 0x16 0x04 +0x17 0x04 0x18 0x05 0x19 0x05 0x1a 0x05 0x1b 0x05 0x89 0x01 0x3a 0x00 0x88 0x13 +0x14 0x9d 0x01 0x0b 0x02 0x0b 0x03 0x0b 0x04 0x0a 0x05 0x0a 0x06 0x0a 0x07 0x08 +0x08 0x08 0x09 0x08 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x08 0x0e 0x08 0x0f 0x08 +0x10 0x04 0x11 0x04 0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 0x16 0x04 0x17 0x04 +0x18 0x05 0x19 0x05 0x1a 0x05 0x1b 0x05 0x89 0x01 0x3a 0x00 0x88 0x13 0x14 0xa1 +0x01 0x0b 0x02 0x0b 0x03 0x0b 0x04 0x0a 0x05 0x0a 0x06 0x0a 0x07 0x08 0x08 0x08 +0x09 0x08 0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x08 0x0e 0x08 0x0f 0x08 0x10 0x04 +0x11 0x04 0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 0x16 0x04 0x17 0x04 0x18 0x05 +0x19 0x05 0x1a 0x05 0x1b 0x05 0x89 0x01 0x3a 0x00 0x88 0x13 0x14 0xa5 0x01 0x0b +0x02 0x0b 0x03 0x0b 0x04 0x0a 0x05 0x0a 0x06 0x0a 0x07 0x08 0x08 0x08 0x09 0x08 +0x0a 0x0a 0x0b 0x0a 0x0c 0x0a 0x0d 0x08 0x0e 0x08 0x0f 0x08 0x10 0x04 0x11 0x04 +0x12 0x05 0x13 0x05 0x14 0x05 0x15 0x05 0x16 0x04 0x17 0x04 0x18 0x05 0x19 0x05 +0x1a 0x05 0x1b 0x05>; + }; +}; + &sdmmc { disable-wp; pinctrl-names = "default"; @@ -311,12 +418,6 @@ }; &pinctrl { - backlight { - bl_pwr_en: bl_pwr_en { - rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - buck-5v { drv_5v: drv-5v { rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; @@ -329,16 +430,6 @@ }; }; - lcd { - lcd_enable_h: lcd-en { - rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; - }; - - avdd_1v8_disp_en: avdd-1v8-disp-en { - rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - pmic { dvs_1: dvs-1 { rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>; diff --git a/arch/arm/boot/dts/rk3288-veyron-minnie.dts b/arch/arm/boot/dts/rk3288-veyron-minnie.dts index 9008e703c07e71b20a0c8b39b53787ba9873fcee..55955b082501dac1101c8cd9d506fe2060d501e3 100644 --- a/arch/arm/boot/dts/rk3288-veyron-minnie.dts +++ b/arch/arm/boot/dts/rk3288-veyron-minnie.dts @@ -15,40 +15,6 @@ "google,veyron-minnie-rev0", "google,veyron-minnie", "google,veyron", "rockchip,rk3288"; - backlight_regulator: backlight-regulator { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&bl_pwr_en>; - regulator-name = "backlight_regulator"; - vin-supply = <&vcc33_sys>; - startup-delay-us = <15000>; - }; - - panel_regulator: panel-regulator { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio7 RK_PB6 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&lcd_enable_h>; - regulator-name = "panel_regulator"; - startup-delay-us = <100000>; - vin-supply = <&vcc33_sys>; - }; - - vcc18_lcd: vcc18-lcd { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&avdd_1v8_disp_en>; - regulator-name = "vcc18_lcd"; - regulator-always-on; - regulator-boot-on; - vin-supply = <&vcc18_wl>; - }; - volume_buttons: volume-buttons { compatible = "gpio-keys"; pinctrl-names = "default"; @@ -105,7 +71,6 @@ 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255>; - power-supply = <&backlight_regulator>; }; &i2c_tunnel { @@ -137,7 +102,20 @@ &panel { compatible = "auo,b101ean01", "simple-panel"; - power-supply= <&panel_regulator>; + + /delete-node/ panel-timing; + + panel-timing { + clock-frequency = <66666667>; + hactive = <1280>; + hfront-porch = <18>; + hback-porch = <21>; + hsync-len = <32>; + vactive = <800>; + vfront-porch = <4>; + vback-porch = <8>; + vsync-len = <18>; + }; }; &rk808 { @@ -397,12 +375,6 @@ }; &pinctrl { - backlight { - bl_pwr_en: bl_pwr_en { - rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - buck-5v { drv_5v: drv-5v { rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; @@ -425,16 +397,6 @@ }; }; - lcd { - lcd_enable_h: lcd-en { - rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; - }; - - avdd_1v8_disp_en: avdd-1v8-disp-en { - rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - pmic { dvs_1: dvs-1 { rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>; diff --git a/arch/arm/boot/dts/rk3288-veyron-pinky.dts b/arch/arm/boot/dts/rk3288-veyron-pinky.dts index 9b6f4d9b03b64d4c5ea01e68fc9343bfe19ae94b..f420499f300ac29c156327d60952a81c5b4e4836 100644 --- a/arch/arm/boot/dts/rk3288-veyron-pinky.dts +++ b/arch/arm/boot/dts/rk3288-veyron-pinky.dts @@ -14,7 +14,14 @@ compatible = "google,veyron-pinky-rev2", "google,veyron-pinky", "google,veyron", "rockchip,rk3288"; + /delete-node/backlight-regulator; + /delete-node/panel-regulator; /delete-node/emmc-pwrseq; + /delete-node/vcc18-lcd; +}; + +&backlight { + /delete-property/power-supply; }; &emmc { @@ -52,7 +59,17 @@ i2c-scl-rising-time-ns = <300>; }; +&panel { + power-supply = <&vcc33_lcd>; +}; + &pinctrl { + /delete-node/ lcd; + + backlight { + /delete-node/ bl_pwr_en; + }; + buttons { pwr_key_h: pwr-key-h { rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>; diff --git a/arch/arm/boot/dts/rk3288-veyron-speedy.dts b/arch/arm/boot/dts/rk3288-veyron-speedy.dts index 9b140db0445632d5a8793b02bdbaaeb9940a7e85..2f2989bc3f9c37b8eea24e10155998ba1fafe1b5 100644 --- a/arch/arm/boot/dts/rk3288-veyron-speedy.dts +++ b/arch/arm/boot/dts/rk3288-veyron-speedy.dts @@ -16,44 +16,6 @@ "google,veyron-speedy-rev5", "google,veyron-speedy-rev4", "google,veyron-speedy-rev3", "google,veyron-speedy-rev2", "google,veyron-speedy", "google,veyron", "rockchip,rk3288"; - - panel_regulator: panel-regulator { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio7 RK_PB6 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&lcd_enable_h>; - regulator-name = "panel_regulator"; - startup-delay-us = <100000>; - vin-supply = <&vcc33_sys>; - }; - - vcc18_lcd: vcc18-lcd { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&avdd_1v8_disp_en>; - regulator-name = "vcc18_lcd"; - regulator-always-on; - regulator-boot-on; - vin-supply = <&vcc18_wl>; - }; - - backlight_regulator: backlight-regulator { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&bl_pwr_en>; - regulator-name = "backlight_regulator"; - vin-supply = <&vcc33_sys>; - startup-delay-us = <15000>; - }; -}; - -&backlight { - power-supply = <&backlight_regulator>; }; &cpu_alert0 { @@ -83,10 +45,6 @@ temperature = <90000>; }; -&panel { - power-supply= <&panel_regulator>; -}; - &rk808 { pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; @@ -321,12 +279,6 @@ }; &pinctrl { - backlight { - bl_pwr_en: bl_pwr_en { - rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - buck-5v { drv_5v: drv-5v { rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; @@ -339,16 +291,6 @@ }; }; - lcd { - lcd_enable_h: lcd-en { - rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; - }; - - avdd_1v8_disp_en: avdd-1v8-disp-en { - rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - pmic { dvs_1: dvs-1 { rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>; diff --git a/arch/arm/boot/dts/rk3288-veyron-tiger.dts b/arch/arm/boot/dts/rk3288-veyron-tiger.dts new file mode 100644 index 0000000000000000000000000000000000000000..27557203ae330acd3609f8c421ece9b5abc24b28 --- /dev/null +++ b/arch/arm/boot/dts/rk3288-veyron-tiger.dts @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google Veyron Tiger Rev 0+ board device tree source + * + * Copyright 2016 Google, Inc + */ + +/dts-v1/; +#include "rk3288-veyron-fievel.dts" +#include "rk3288-veyron-edp.dtsi" + +/ { + model = "Google Tiger"; + compatible = "google,veyron-tiger-rev8", "google,veyron-tiger-rev7", + "google,veyron-tiger-rev6", "google,veyron-tiger-rev5", + "google,veyron-tiger-rev4", "google,veyron-tiger-rev3", + "google,veyron-tiger-rev2", "google,veyron-tiger-rev1", + "google,veyron-tiger-rev0", "google,veyron-tiger", + "google,veyron", "rockchip,rk3288"; + + /delete-node/ vcc18-lcd; +}; + +&backlight { + /* Tiger panel PWM must be >= 1%, so start non-zero brightness at 3 */ + brightness-levels = < + 0 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 19 20 21 22 23 + 24 25 26 27 28 29 30 31 + 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 + 48 49 50 51 52 53 54 55 + 56 57 58 59 60 61 62 63 + 64 65 66 67 68 69 70 71 + 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 + 88 89 90 91 92 93 94 95 + 96 97 98 99 100 101 102 103 + 104 105 106 107 108 109 110 111 + 112 113 114 115 116 117 118 119 + 120 121 122 123 124 125 126 127 + 128 129 130 131 132 133 134 135 + 136 137 138 139 140 141 142 143 + 144 145 146 147 148 149 150 151 + 152 153 154 155 156 157 158 159 + 160 161 162 163 164 165 166 167 + 168 169 170 171 172 173 174 175 + 176 177 178 179 180 181 182 183 + 184 185 186 187 188 189 190 191 + 192 193 194 195 196 197 198 199 + 200 201 202 203 204 205 206 207 + 208 209 210 211 212 213 214 215 + 216 217 218 219 220 221 222 223 + 224 225 226 227 228 229 230 231 + 232 233 234 235 236 237 238 239 + 240 241 242 243 244 245 246 247 + 248 249 250 251 252 253 254 255>; +}; + +&backlight_regulator { + vin-supply = <&vccsys>; +}; + +&i2c3 { + status = "okay"; + + clock-frequency = <400000>; + i2c-scl-falling-time-ns = <50>; + i2c-scl-rising-time-ns = <300>; + + touchscreen@10 { + compatible = "elan,ekth3500"; + reg = <0x10>; + interrupt-parent = <&gpio2>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&touch_int &touch_rst>; + reset-gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_LOW>; + vcc33-supply = <&vcc33_io>; + vccio-supply = <&vcc33_io>; + wakeup-source; + }; +}; + +&panel { + compatible = "auo,b101ean01", "simple-panel"; + + /delete-node/ panel-timing; + + panel-timing { + clock-frequency = <66666667>; + hactive = <1280>; + hfront-porch = <18>; + hback-porch = <21>; + hsync-len = <32>; + vactive = <800>; + vfront-porch = <4>; + vback-porch = <8>; + vsync-len = <18>; + }; +}; + +&pinctrl { + lcd { + /delete-node/ avdd-1v8-disp-en; + }; + + touchscreen { + touch_int: touch-int { + rockchip,pins = <2 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + touch_rst: touch-rst { + rockchip,pins = <2 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; diff --git a/arch/arm/boot/dts/rk3288-veyron.dtsi b/arch/arm/boot/dts/rk3288-veyron.dtsi index 8fc8eac699bf513f324e3762d05657911b6c0b1a..7525e3dd1fc10d5d02ad55ee0e3542c6afe4398f 100644 --- a/arch/arm/boot/dts/rk3288-veyron.dtsi +++ b/arch/arm/boot/dts/rk3288-veyron.dtsi @@ -586,6 +586,10 @@ rockchip,pins = <4 RK_PD7 RK_FUNC_GPIO &pcfg_pull_down>; }; + bt_host_wake_l: bt-host-wake-l { + rockchip,pins = <4 RK_PD7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + /* * We run sdio0 at max speed; bump up drive strength. * We also have external pulls, so disable the internal ones. diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index ec1966480f2f0376522bda05d1e7347821238a46..4f3993cc022796c4a3946af0e1aabd984f3937d7 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -85,6 +85,7 @@ clocks = <&l4_main_clk>; clock-names = "apb_pclk"; resets = <&rst DMA_RESET>; + reset-names = "dma"; }; }; @@ -747,7 +748,7 @@ nand0: nand@ff900000 { #address-cells = <0x1>; - #size-cells = <0x1>; + #size-cells = <0x0>; compatible = "altr,socfpga-denali-nand"; reg = <0xff900000 0x100000>, <0xffb80000 0x10000>; diff --git a/arch/arm/boot/dts/socfpga_arria10.dtsi b/arch/arm/boot/dts/socfpga_arria10.dtsi index a0a6d85072653ad74a789f2532739cfe3d3ae23e..2a86e72d97918a36f445e6319513aa3e2364c74b 100644 --- a/arch/arm/boot/dts/socfpga_arria10.dtsi +++ b/arch/arm/boot/dts/socfpga_arria10.dtsi @@ -68,6 +68,8 @@ #dma-requests = <32>; clocks = <&l4_main_clk>; clock-names = "apb_pclk"; + resets = <&rst DMA_RESET>, <&rst DMA_OCP_RESET>; + reset-names = "dma", "dma-ocp"; }; }; @@ -660,7 +662,7 @@ nand: nand@ffb90000 { #address-cells = <1>; - #size-cells = <1>; + #size-cells = <0>; compatible = "altr,socfpga-denali-nand"; reg = <0xffb90000 0x72000>, <0xffb80000 0x10000>; @@ -753,7 +755,8 @@ cdns,fifo-width = <4>; cdns,trigger-address = <0x00000000>; clocks = <&qspi_clk>; - resets = <&rst QSPI_RESET>; + resets = <&rst QSPI_RESET>, <&rst QSPI_OCP_RESET>; + reset-names = "qspi", "qspi-ocp"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts index e36e0a0f8aa624801812f3836fb9b4246acede5d..9bd9e04c73613b45897a586bbde476aad6e248e3 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts @@ -9,12 +9,18 @@ &nand { status = "okay"; - partition@nand-boot { - label = "Boot and fpga data"; - reg = <0x0 0x1C00000>; - }; - partition@nand-rootfs { - label = "Root Filesystem - JFFS2"; - reg = <0x1C00000 0x6400000>; + nand@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "Boot and fpga data"; + reg = <0x0 0x1C00000>; + }; + partition@1c00000 { + label = "Root Filesystem - JFFS2"; + reg = <0x1C00000 0x6400000>; + }; }; }; diff --git a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts index 355b3dbf438d09be7d781d28ebc1e9ed81de06a3..a060718758b6755a154c1842f95301d1a8c93806 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts @@ -36,21 +36,33 @@ hps_temp0 { label = "BTN_0"; /* TEMP_OS */ - gpios = <&portc 18 GPIO_ACTIVE_LOW>; /* HPS_GPIO60 */ + gpios = <&portc 18 GPIO_ACTIVE_LOW>; /* HPS_GPI5 */ linux,code = ; }; hps_hkey0 { - label = "BTN_1"; /* DIS_PWR */ - gpios = <&portc 19 GPIO_ACTIVE_LOW>; /* HPS_GPIO61 */ + label = "GP_SWITCH"; /* GP_SWITCH */ + gpios = <&portc 19 GPIO_ACTIVE_LOW>; /* HPS_GPI6 */ linux,code = ; }; hps_hkey1 { - label = "hps_hkey1"; /* POWER_DOWN */ - gpios = <&portc 20 GPIO_ACTIVE_LOW>; /* HPS_GPIO62 */ + label = "RESET_SWITCH"; /* RESET_SWITCH */ + gpios = <&portc 20 GPIO_ACTIVE_LOW>; /* HPS_GPI7 */ + linux,code = ; + }; + + hps_hkey2 { + label = "POWER_DOWN"; /* POWER_DOWN */ + gpios = <&portc 4 GPIO_ACTIVE_LOW>; /* HPS_GPIO62 */ linux,code = ; }; + + hps_hkey3 { + label = "SENSE"; /* SENSE */ + gpios = <&porta 9 GPIO_ACTIVE_LOW>; /* HPS_GPIO9 */ + linux,code = ; + }; }; regulator-usb-nrst { @@ -84,10 +96,14 @@ rxd1-skew-ps = <0>; rxd2-skew-ps = <0>; rxd3-skew-ps = <0>; + txd0-skew-ps = <0>; + txd1-skew-ps = <0>; + txd2-skew-ps = <0>; + txd3-skew-ps = <0>; txen-skew-ps = <0>; - txc-skew-ps = <2600>; + txc-skew-ps = <1860>; rxdv-skew-ps = <0>; - rxc-skew-ps = <2000>; + rxc-skew-ps = <1860>; }; }; }; diff --git a/arch/arm/boot/dts/ste-ab8500.dtsi b/arch/arm/boot/dts/ste-ab8500.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..55fff4d442779912fe830e491468fcb0fb0aab1d --- /dev/null +++ b/arch/arm/boot/dts/ste-ab8500.dtsi @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2012 Linaro Ltd + */ + +#include + +/ { + soc { + prcmu@80157000 { + ab8500 { + compatible = "stericsson,ab8500"; + interrupt-parent = <&intc>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <2>; + + ab8500_clock: clock-controller { + compatible = "stericsson,ab8500-clk"; + #clock-cells = <1>; + }; + + ab8500_gpio: ab8500-gpio { + compatible = "stericsson,ab8500-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + ab8500-rtc { + compatible = "stericsson,ab8500-rtc"; + interrupts = <17 IRQ_TYPE_LEVEL_HIGH + 18 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "60S", "ALARM"; + }; + + ab8500-gpadc { + compatible = "stericsson,ab8500-gpadc"; + interrupts = <32 IRQ_TYPE_LEVEL_HIGH + 39 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "HW_CONV_END", "SW_CONV_END"; + vddadc-supply = <&ab8500_ldo_tvout_reg>; + }; + + ab8500_battery: ab8500_battery { + stericsson,battery-type = "LIPO"; + thermistor-on-batctrl; + }; + + ab8500_fg { + compatible = "stericsson,ab8500-fg"; + battery = <&ab8500_battery>; + }; + + ab8500_btemp { + compatible = "stericsson,ab8500-btemp"; + battery = <&ab8500_battery>; + }; + + ab8500_charger { + compatible = "stericsson,ab8500-charger"; + battery = <&ab8500_battery>; + vddadc-supply = <&ab8500_ldo_tvout_reg>; + }; + + ab8500_chargalg { + compatible = "stericsson,ab8500-chargalg"; + battery = <&ab8500_battery>; + }; + + ab8500_usb { + compatible = "stericsson,ab8500-usb"; + interrupts = < 90 IRQ_TYPE_LEVEL_HIGH + 96 IRQ_TYPE_LEVEL_HIGH + 14 IRQ_TYPE_LEVEL_HIGH + 15 IRQ_TYPE_LEVEL_HIGH + 79 IRQ_TYPE_LEVEL_HIGH + 74 IRQ_TYPE_LEVEL_HIGH + 75 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "ID_WAKEUP_R", + "ID_WAKEUP_F", + "VBUS_DET_F", + "VBUS_DET_R", + "USB_LINK_STATUS", + "USB_ADP_PROBE_PLUG", + "USB_ADP_PROBE_UNPLUG"; + vddulpivio18-supply = <&ab8500_ldo_intcore_reg>; + v-ape-supply = <&db8500_vape_reg>; + musb_1v8-supply = <&db8500_vsmps2_reg>; + clocks = <&prcmu_clk PRCMU_SYSCLK>; + clock-names = "sysclk"; + }; + + ab8500-ponkey { + compatible = "stericsson,ab8500-poweron-key"; + interrupts = <6 IRQ_TYPE_LEVEL_HIGH + 7 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "ONKEY_DBF", "ONKEY_DBR"; + }; + + ab8500-sysctrl { + compatible = "stericsson,ab8500-sysctrl"; + }; + + ab8500-pwm { + compatible = "stericsson,ab8500-pwm"; + clocks = <&ab8500_clock AB8500_SYSCLK_INT>; + clock-names = "intclk"; + }; + + ab8500-debugfs { + compatible = "stericsson,ab8500-debug"; + }; + + codec: ab8500-codec { + compatible = "stericsson,ab8500-codec"; + + V-AUD-supply = <&ab8500_ldo_audio_reg>; + V-AMIC1-supply = <&ab8500_ldo_anamic1_reg>; + V-AMIC2-supply = <&ab8500_ldo_anamic2_reg>; + V-DMIC-supply = <&ab8500_ldo_dmic_reg>; + + clocks = <&ab8500_clock AB8500_SYSCLK_AUDIO>; + clock-names = "audioclk"; + + stericsson,earpeice-cmv = <950>; /* Units in mV. */ + }; + + ext_regulators: ab8500-ext-regulators { + compatible = "stericsson,ab8500-ext-regulator"; + + ab8500_ext1_reg: ab8500_ext1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ab8500_ext2_reg: ab8500_ext2 { + regulator-min-microvolt = <1360000>; + regulator-max-microvolt = <1360000>; + regulator-boot-on; + regulator-always-on; + }; + + ab8500_ext3_reg: ab8500_ext3 { + regulator-min-microvolt = <3400000>; + regulator-max-microvolt = <3400000>; + regulator-boot-on; + }; + }; + + ab8500-regulators { + compatible = "stericsson,ab8500-regulator"; + vin-supply = <&ab8500_ext3_reg>; + + // supplies to the display/camera + ab8500_ldo_aux1_reg: ab8500_ldo_aux1 { + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2900000>; + regulator-boot-on; + /* BUG: If turned off MMC will be affected. */ + regulator-always-on; + }; + + // supplies to the on-board eMMC + ab8500_ldo_aux2_reg: ab8500_ldo_aux2 { + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <3300000>; + }; + + // supply for VAUX3; SDcard slots + ab8500_ldo_aux3_reg: ab8500_ldo_aux3 { + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <3300000>; + }; + + // supply for v-intcore12; VINTCORE12 LDO + ab8500_ldo_intcore_reg: ab8500_ldo_intcore { + }; + + // supply for tvout; gpadc; TVOUT LDO + ab8500_ldo_tvout_reg: ab8500_ldo_tvout { + }; + + // supply for ab8500-vaudio; VAUDIO LDO + ab8500_ldo_audio_reg: ab8500_ldo_audio { + }; + + // supply for v-anamic1 VAMIC1 LDO + ab8500_ldo_anamic1_reg: ab8500_ldo_anamic1 { + }; + + // supply for v-amic2; VAMIC2 LDO; reuse constants for AMIC1 + ab8500_ldo_anamic2_reg: ab8500_ldo_anamic2 { + }; + + // supply for v-dmic; VDMIC LDO + ab8500_ldo_dmic_reg: ab8500_ldo_dmic { + }; + + // supply for U8500 CSI/DSI; VANA LDO + ab8500_ldo_ana_reg: ab8500_ldo_ana { + }; + }; + }; + }; + + sound { + stericsson,audio-codec = <&codec>; + clocks = <&prcmu_clk PRCMU_SYSCLK>, <&ab8500_clock AB8500_SYSCLK_ULP>, <&ab8500_clock AB8500_SYSCLK_INT>; + clock-names = "sysclk", "ulpclk", "intclk"; + }; + + mcde@a0350000 { + vana-supply = <&ab8500_ldo_ana_reg>; + + dsi@a0351000 { + vana-supply = <&ab8500_ldo_ana_reg>; + }; + dsi@a0352000 { + vana-supply = <&ab8500_ldo_ana_reg>; + }; + dsi@a0353000 { + vana-supply = <&ab8500_ldo_ana_reg>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi index b1a31134f860d1665920f3c1c11b337063d4e979..a53657b8328817c6970100215338267ea94b463c 100644 --- a/arch/arm/boot/dts/ste-dbx5x0.dtsi +++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi @@ -8,7 +8,6 @@ #include #include #include -#include / { #address-cells = <1>; @@ -44,6 +43,7 @@ clocks = <&prcmu_clk PRCMU_ARMSS>; clock-names = "cpu"; clock-latency = <20000>; + #cooling-cells = <2>; }; CPU1: cpu@301 { device_type = "cpu"; @@ -52,6 +52,39 @@ }; }; + thermal-zones { + /* + * Thermal zone for the SoC, using the thermal sensor in the + * PRCMU for temperature and the cpufreq driver for passive + * cooling. + */ + cpu_thermal: cpu-thermal { + polling-delay-passive = <0>; + polling-delay = <1000>; + + thermal-sensors = <&thermal>; + + trips { + cpu_alert: cpu-alert { + temperature = <70000>; + hysteresis = <2000>; + type = "passive"; + }; + cpu-crit { + temperature = <85000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + trip = <&cpu_alert>; + cooling-device = <&CPU0 0 2>; + contribution = <100>; + }; + }; + }; + soc { #address-cells = <1>; #size-cells = <1>; @@ -92,7 +125,7 @@ }; funnel@801a6000 { - compatible = "arm,coresight-funnel", "arm,primecell"; + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; reg = <0x801a6000 0x1000>; clocks = <&prcmu_clk PRCMU_APETRACECLK>, <&prcmu_clk PRCMU_APEATCLK>; @@ -127,7 +160,7 @@ }; replicator { - compatible = "arm,coresight-replicator"; + compatible = "arm,coresight-static-replicator"; clocks = <&prcmu_clk PRCMU_APEATCLK>; clock-names = "atclk"; @@ -502,13 +535,14 @@ reg = <0x80157450 0xC>; }; - thermal@801573c0 { + thermal: thermal@801573c0 { compatible = "stericsson,db8500-thermal"; reg = <0x801573c0 0x40>; + interrupt-parent = <&prcmu>; interrupts = <21 IRQ_TYPE_LEVEL_HIGH>, <22 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "IRQ_HOTMON_LOW", "IRQ_HOTMON_HIGH"; - status = "disabled"; + #thermal-sensor-cells = <0>; }; db8500-prcmu-regulators { @@ -597,206 +631,6 @@ db8500_esram34_ret_reg: db8500_esram34_ret { }; }; - - ab8500 { - compatible = "stericsson,ab8500"; - interrupt-parent = <&intc>; - interrupts = ; - interrupt-controller; - #interrupt-cells = <2>; - - ab8500_clock: clock-controller { - compatible = "stericsson,ab8500-clk"; - #clock-cells = <1>; - }; - - ab8500_gpio: ab8500-gpio { - compatible = "stericsson,ab8500-gpio"; - gpio-controller; - #gpio-cells = <2>; - }; - - ab8500-rtc { - compatible = "stericsson,ab8500-rtc"; - interrupts = <17 IRQ_TYPE_LEVEL_HIGH - 18 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "60S", "ALARM"; - }; - - ab8500-gpadc { - compatible = "stericsson,ab8500-gpadc"; - interrupts = <32 IRQ_TYPE_LEVEL_HIGH - 39 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "HW_CONV_END", "SW_CONV_END"; - vddadc-supply = <&ab8500_ldo_tvout_reg>; - }; - - ab8500_battery: ab8500_battery { - stericsson,battery-type = "LIPO"; - thermistor-on-batctrl; - }; - - ab8500_fg { - compatible = "stericsson,ab8500-fg"; - battery = <&ab8500_battery>; - }; - - ab8500_btemp { - compatible = "stericsson,ab8500-btemp"; - battery = <&ab8500_battery>; - }; - - ab8500_charger { - compatible = "stericsson,ab8500-charger"; - battery = <&ab8500_battery>; - vddadc-supply = <&ab8500_ldo_tvout_reg>; - }; - - ab8500_chargalg { - compatible = "stericsson,ab8500-chargalg"; - battery = <&ab8500_battery>; - }; - - ab8500_usb { - compatible = "stericsson,ab8500-usb"; - interrupts = < 90 IRQ_TYPE_LEVEL_HIGH - 96 IRQ_TYPE_LEVEL_HIGH - 14 IRQ_TYPE_LEVEL_HIGH - 15 IRQ_TYPE_LEVEL_HIGH - 79 IRQ_TYPE_LEVEL_HIGH - 74 IRQ_TYPE_LEVEL_HIGH - 75 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "ID_WAKEUP_R", - "ID_WAKEUP_F", - "VBUS_DET_F", - "VBUS_DET_R", - "USB_LINK_STATUS", - "USB_ADP_PROBE_PLUG", - "USB_ADP_PROBE_UNPLUG"; - vddulpivio18-supply = <&ab8500_ldo_intcore_reg>; - v-ape-supply = <&db8500_vape_reg>; - musb_1v8-supply = <&db8500_vsmps2_reg>; - clocks = <&prcmu_clk PRCMU_SYSCLK>; - clock-names = "sysclk"; - }; - - ab8500-ponkey { - compatible = "stericsson,ab8500-poweron-key"; - interrupts = <6 IRQ_TYPE_LEVEL_HIGH - 7 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "ONKEY_DBF", "ONKEY_DBR"; - }; - - ab8500-sysctrl { - compatible = "stericsson,ab8500-sysctrl"; - }; - - ab8500-pwm { - compatible = "stericsson,ab8500-pwm"; - clocks = <&ab8500_clock AB8500_SYSCLK_INT>; - clock-names = "intclk"; - }; - - ab8500-debugfs { - compatible = "stericsson,ab8500-debug"; - }; - - codec: ab8500-codec { - compatible = "stericsson,ab8500-codec"; - - V-AUD-supply = <&ab8500_ldo_audio_reg>; - V-AMIC1-supply = <&ab8500_ldo_anamic1_reg>; - V-AMIC2-supply = <&ab8500_ldo_anamic2_reg>; - V-DMIC-supply = <&ab8500_ldo_dmic_reg>; - - clocks = <&ab8500_clock AB8500_SYSCLK_AUDIO>; - clock-names = "audioclk"; - - stericsson,earpeice-cmv = <950>; /* Units in mV. */ - }; - - ext_regulators: ab8500-ext-regulators { - compatible = "stericsson,ab8500-ext-regulator"; - - ab8500_ext1_reg: ab8500_ext1 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-boot-on; - regulator-always-on; - }; - - ab8500_ext2_reg: ab8500_ext2 { - regulator-min-microvolt = <1360000>; - regulator-max-microvolt = <1360000>; - regulator-boot-on; - regulator-always-on; - }; - - ab8500_ext3_reg: ab8500_ext3 { - regulator-min-microvolt = <3400000>; - regulator-max-microvolt = <3400000>; - regulator-boot-on; - }; - }; - - ab8500-regulators { - compatible = "stericsson,ab8500-regulator"; - vin-supply = <&ab8500_ext3_reg>; - - // supplies to the display/camera - ab8500_ldo_aux1_reg: ab8500_ldo_aux1 { - regulator-min-microvolt = <2500000>; - regulator-max-microvolt = <2900000>; - regulator-boot-on; - /* BUG: If turned off MMC will be affected. */ - regulator-always-on; - }; - - // supplies to the on-board eMMC - ab8500_ldo_aux2_reg: ab8500_ldo_aux2 { - regulator-min-microvolt = <1100000>; - regulator-max-microvolt = <3300000>; - }; - - // supply for VAUX3; SDcard slots - ab8500_ldo_aux3_reg: ab8500_ldo_aux3 { - regulator-min-microvolt = <1100000>; - regulator-max-microvolt = <3300000>; - }; - - // supply for v-intcore12; VINTCORE12 LDO - ab8500_ldo_intcore_reg: ab8500_ldo_intcore { - }; - - // supply for tvout; gpadc; TVOUT LDO - ab8500_ldo_tvout_reg: ab8500_ldo_tvout { - }; - - // supply for ab8500-usb; USB LDO - ab8500_ldo_usb_reg: ab8500_ldo_usb { - }; - - // supply for ab8500-vaudio; VAUDIO LDO - ab8500_ldo_audio_reg: ab8500_ldo_audio { - }; - - // supply for v-anamic1 VAMIC1 LDO - ab8500_ldo_anamic1_reg: ab8500_ldo_anamic1 { - }; - - // supply for v-amic2; VAMIC2 LDO; reuse constants for AMIC1 - ab8500_ldo_anamic2_reg: ab8500_ldo_anamic2 { - }; - - // supply for v-dmic; VDMIC LDO - ab8500_ldo_dmic_reg: ab8500_ldo_dmic { - }; - - // supply for U8500 CSI/DSI; VANA LDO - ab8500_ldo_ana_reg: ab8500_ldo_ana { - }; - }; - }; }; i2c@80004000 { @@ -1110,9 +944,6 @@ sound { compatible = "stericsson,snd-soc-mop500"; stericsson,cpu-dai = <&msp1 &msp3>; - stericsson,audio-codec = <&codec>; - clocks = <&prcmu_clk PRCMU_SYSCLK>, <&ab8500_clock AB8500_SYSCLK_ULP>, <&ab8500_clock AB8500_SYSCLK_INT>; - clock-names = "sysclk", "ulpclk", "intclk"; }; msp0: msp@80123000 { @@ -1219,7 +1050,6 @@ reg = <0xa0350000 0x1000>; interrupts = ; epod-supply = <&db8500_b2r2_mcde_reg>; - vana-supply = <&ab8500_ldo_ana_reg>; clocks = <&prcmu_clk PRCMU_MCDECLK>, /* Main MCDE clock */ <&prcmu_clk PRCMU_LCDCLK>, /* LCD clock */ <&prcmu_clk PRCMU_PLLDSI>; /* HDMI clock */ @@ -1232,7 +1062,6 @@ dsi0: dsi@a0351000 { compatible = "ste,mcde-dsi"; reg = <0xa0351000 0x1000>; - vana-supply = <&ab8500_ldo_ana_reg>; clocks = <&prcmu_clk PRCMU_DSI0CLK>, <&prcmu_clk PRCMU_DSI0ESCCLK>; clock-names = "hs", "lp"; #address-cells = <1>; @@ -1241,7 +1070,6 @@ dsi1: dsi@a0352000 { compatible = "ste,mcde-dsi"; reg = <0xa0352000 0x1000>; - vana-supply = <&ab8500_ldo_ana_reg>; clocks = <&prcmu_clk PRCMU_DSI1CLK>, <&prcmu_clk PRCMU_DSI1ESCCLK>; clock-names = "hs", "lp"; #address-cells = <1>; @@ -1250,7 +1078,6 @@ dsi2: dsi@a0353000 { compatible = "ste,mcde-dsi"; reg = <0xa0353000 0x1000>; - vana-supply = <&ab8500_ldo_ana_reg>; /* This DSI port only has the Low Power / Energy Save clock */ clocks = <&prcmu_clk PRCMU_DSI2ESCCLK>; clock-names = "lp"; diff --git a/arch/arm/boot/dts/ste-href-ab8500.dtsi b/arch/arm/boot/dts/ste-href-ab8500.dtsi index 8e3e947d181f7f19ee9b3238892ab96f95bb5271..4946743de7b9b8be09faffb09e6d70a4186594a3 100644 --- a/arch/arm/boot/dts/ste-href-ab8500.dtsi +++ b/arch/arm/boot/dts/ste-href-ab8500.dtsi @@ -3,6 +3,8 @@ * Copyright 2014 Linaro Ltd. */ +#include "ste-ab8500.dtsi" + / { soc { prcmu@80157000 { diff --git a/arch/arm/boot/dts/ste-href-family-pinctrl.dtsi b/arch/arm/boot/dts/ste-href-family-pinctrl.dtsi index 86621196abdae1ba3b6bfd1a8d023957178f1e1d..2c382d274ff64c54b74c21219f9cb21bcac5b693 100644 --- a/arch/arm/boot/dts/ste-href-family-pinctrl.dtsi +++ b/arch/arm/boot/dts/ste-href-family-pinctrl.dtsi @@ -607,7 +607,6 @@ groups = "lcdvsi0_a_1", /* VSI0 for LCD */ "lcd_d0_d7_a_1", /* Data lines */ - "lcd_d8_d11_a_1", /* TV-out */ "lcdvsi1_a_1"; /* VSI1 for HDMI */ }; default_mux2 { diff --git a/arch/arm/boot/dts/ste-href-stuib.dtsi b/arch/arm/boot/dts/ste-href-stuib.dtsi index b17998f4f7cad6762559943792303845075e6392..e32d0c36feb8f9ce1341a2efe84d6d43d4d9d978 100644 --- a/arch/arm/boot/dts/ste-href-stuib.dtsi +++ b/arch/arm/boot/dts/ste-href-stuib.dtsi @@ -38,6 +38,8 @@ interrupt-controller; vcc-supply = <&db8500_vsmps2_reg>; vio-supply = <&db8500_vsmps2_reg>; + pinctrl-names = "default"; + pinctrl-0 = <&stmpe_stuib_mode>; wakeup-source; st,autosleep-timeout = <1024>; @@ -126,6 +128,15 @@ }; pinctrl { + /* Pull up this GPIO pin */ + stmpe { + stmpe_stuib_mode: stmpe_stuib { + stuib_cfg { + ste,pins = "GPIO218_AH11"; + ste,config = <&gpio_in_pu>; + }; + }; + }; prox { prox_stuib_mode: prox_stuib { stuib_cfg { diff --git a/arch/arm/boot/dts/ste-href.dtsi b/arch/arm/boot/dts/ste-href.dtsi index 6422c53f2046bade0b1a87c97044a1f7e77be779..4f6acbd8c040c972b399d9d26a8ae52b3c65a469 100644 --- a/arch/arm/boot/dts/ste-href.dtsi +++ b/arch/arm/boot/dts/ste-href.dtsi @@ -234,10 +234,6 @@ regulator-name = "V-TVOUT"; }; - ab8500_ldo_usb_reg: ab8500_ldo_usb { - regulator-name = "dummy"; - }; - ab8500_ldo_audio_reg: ab8500_ldo_audio { regulator-name = "V-AUD"; }; diff --git a/arch/arm/boot/dts/ste-hrefprev60-stuib.dts b/arch/arm/boot/dts/ste-hrefprev60-stuib.dts index aed940bd65a8067122e0adc0f406e65beb3b404e..b78be5f4c212efff8ab82ab2f3535225513b5d50 100644 --- a/arch/arm/boot/dts/ste-hrefprev60-stuib.dts +++ b/arch/arm/boot/dts/ste-hrefprev60-stuib.dts @@ -4,6 +4,8 @@ */ /dts-v1/; +#include +#include #include "ste-hrefprev60.dtsi" #include "ste-href-stuib.dtsi" @@ -23,12 +25,16 @@ i2c@80110000 { /* Only one of these will be used */ bu21013_tp@5c { - touch-gpio = <&gpio2 12 0x4>; - reset-gpio = <&tc3589x_gpio 13 0x4>; + interrupt-parent = <&gpio2>; + interrupts = <12 IRQ_TYPE_LEVEL_LOW>; + touch-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>; + reset-gpios = <&tc3589x_gpio 13 GPIO_LINE_OPEN_DRAIN>; }; bu21013_tp@5d { - touch-gpio = <&gpio2 12 0x4>; - reset-gpio = <&tc3589x_gpio 13 0x4>; + interrupt-parent = <&gpio2>; + interrupts = <12 IRQ_TYPE_LEVEL_LOW>; + touch-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>; + reset-gpios = <&tc3589x_gpio 13 GPIO_LINE_OPEN_DRAIN>; }; }; }; diff --git a/arch/arm/boot/dts/ste-hrefv60plus-stuib.dts b/arch/arm/boot/dts/ste-hrefv60plus-stuib.dts index 0f3c3b86bb20a5d88931000565ff83404b09ff42..9be513aad549f4078a818e171399e16580fed146 100644 --- a/arch/arm/boot/dts/ste-hrefv60plus-stuib.dts +++ b/arch/arm/boot/dts/ste-hrefv60plus-stuib.dts @@ -6,6 +6,8 @@ */ /dts-v1/; +#include +#include #include "ste-hrefv60plus.dtsi" #include "ste-href-stuib.dtsi" @@ -25,12 +27,16 @@ i2c@80110000 { /* Only one of these will be used */ bu21013_tp@5c { - touch-gpio = <&gpio2 20 0x4>; - reset-gpio = <&gpio4 17 0x4>; + interrupt-parent = <&gpio2>; + interrupts = <20 IRQ_TYPE_LEVEL_LOW>; + touch-gpios = <&gpio2 20 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio4 17 GPIO_LINE_OPEN_DRAIN>; }; bu21013_tp@5d { - touch-gpio = <&gpio2 20 0x4>; - reset-gpio = <&gpio4 17 0x4>; + interrupt-parent = <&gpio2>; + interrupts = <20 IRQ_TYPE_LEVEL_LOW>; + touch-gpios = <&gpio2 20 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio4 17 GPIO_LINE_OPEN_DRAIN>; }; }; }; diff --git a/arch/arm/boot/dts/ste-nomadik-nhk15.dts b/arch/arm/boot/dts/ste-nomadik-nhk15.dts index 04066f9cb8a31c643cba82ea337dd22cb7a85626..41ed21a4fdc1b2e596b24fe6b282088a9d5f6c00 100644 --- a/arch/arm/boot/dts/ste-nomadik-nhk15.dts +++ b/arch/arm/boot/dts/ste-nomadik-nhk15.dts @@ -212,13 +212,7 @@ */ gpio-sck = <&gpio0 5 GPIO_ACTIVE_HIGH>; gpio-mosi = <&gpio0 4 GPIO_ACTIVE_HIGH>; - /* - * It's not actually active high, but the frameworks assume - * the polarity of the passed-in GPIO is "normal" (active - * high) then actively drives the line low to select the - * chip. - */ - cs-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>; + cs-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; num-chipselects = <1>; /* diff --git a/arch/arm/boot/dts/ste-snowball.dts b/arch/arm/boot/dts/ste-snowball.dts index 3428290644baa91e17a03510f235f814720f654d..efbc4467b8b78fdb783e485727f82cb33d1de109 100644 --- a/arch/arm/boot/dts/ste-snowball.dts +++ b/arch/arm/boot/dts/ste-snowball.dts @@ -376,40 +376,11 @@ pinctrl-0 = <&ssp0_snowball_mode>; }; - cpufreq-cooling { - status = "okay"; - }; - prcmu@80157000 { cpufreq { status = "okay"; }; - thermal@801573c0 { - num-trips = <4>; - - trip0-temp = <70000>; - trip0-type = "active"; - trip0-cdev-num = <1>; - trip0-cdev-name0 = "thermal-cpufreq-0"; - - trip1-temp = <75000>; - trip1-type = "active"; - trip1-cdev-num = <1>; - trip1-cdev-name0 = "thermal-cpufreq-0"; - - trip2-temp = <80000>; - trip2-type = "active"; - trip2-cdev-num = <1>; - trip2-cdev-name0 = "thermal-cpufreq-0"; - - trip3-temp = <85000>; - trip3-type = "critical"; - trip3-cdev-num = <0>; - - status = "okay"; - }; - ab8500 { ab8500-gpio { /* @@ -474,10 +445,6 @@ regulator-name = "V-TVOUT"; }; - ab8500_ldo_usb_reg: ab8500_ldo_usb { - regulator-name = "dummy"; - }; - ab8500_ldo_audio_reg: ab8500_ldo_audio { regulator-name = "V-AUD"; }; diff --git a/arch/arm/boot/dts/stm32429i-eval.dts b/arch/arm/boot/dts/stm32429i-eval.dts index 73ea84df7bf4c8fc87424d4776d9bf3d19219286..ba08624c6237dfbc0f065a28479488defbb425db 100644 --- a/arch/arm/boot/dts/stm32429i-eval.dts +++ b/arch/arm/boot/dts/stm32429i-eval.dts @@ -81,18 +81,18 @@ dma-ranges = <0xc0000000 0x0 0x10000000>; }; - regulators { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; + vdda: regulator-vdda { + compatible = "regulator-fixed"; + regulator-name = "vdda"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; - reg_vref: regulator@0 { - compatible = "regulator-fixed"; - reg = <0>; - regulator-name = "vref"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - }; + vref: regulator-vref { + compatible = "regulator-fixed"; + regulator-name = "vref"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; }; leds { @@ -157,7 +157,8 @@ &adc { pinctrl-names = "default"; pinctrl-0 = <&adc3_in8_pin>; - vref-supply = <®_vref>; + vdda-supply = <&vdda>; + vref-supply = <&vref>; status = "okay"; adc3: adc@200 { st,adc-channels = <8>; diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi index 4a4954492ed139e62115fa0c4993e75e9cdc95d9..5c8a826b3195868ffbd204bcdc419279dacc0313 100644 --- a/arch/arm/boot/dts/stm32f429.dtsi +++ b/arch/arm/boot/dts/stm32f429.dtsi @@ -112,6 +112,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -141,6 +142,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -170,6 +172,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -198,6 +201,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -267,6 +271,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -288,6 +293,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; }; @@ -303,6 +309,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; }; @@ -448,6 +455,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -469,6 +477,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -602,6 +611,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -623,6 +633,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; }; @@ -638,6 +649,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/stm32f746.dtsi b/arch/arm/boot/dts/stm32f746.dtsi index a25b7000a3a14c7e0804e9a4f639315e512ed25b..d26f93f8b9c2a869dea44f305d39258c1eafd93d 100644 --- a/arch/arm/boot/dts/stm32f746.dtsi +++ b/arch/arm/boot/dts/stm32f746.dtsi @@ -94,6 +94,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -123,6 +124,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -152,6 +154,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -180,6 +183,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -249,6 +253,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -270,6 +275,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; }; @@ -285,6 +291,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; }; @@ -419,6 +426,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -440,6 +448,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -512,6 +521,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -533,6 +543,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; }; @@ -548,6 +559,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/stm32h743i-eval.dts b/arch/arm/boot/dts/stm32h743i-eval.dts index ab78ad53237557066680ab48d2e384680f8646a0..e4d3c58f3d97b735e929354c0fa036feeea50667 100644 --- a/arch/arm/boot/dts/stm32h743i-eval.dts +++ b/arch/arm/boot/dts/stm32h743i-eval.dts @@ -87,6 +87,7 @@ }; &adc_12 { + vdda-supply = <&vdda>; vref-supply = <&vdda>; status = "okay"; adc1: adc@0 { diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi index df64701335741c5ed62721a24cd380c8b48f4219..e4a0d51ec3a8cde7003099dcc29f008f82704e74 100644 --- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi +++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi @@ -24,8 +24,6 @@ reg = <0x0 0x400>; clocks = <&rcc GPIOA>; st,bank-name = "GPIOA"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 0 16>; status = "disabled"; }; @@ -37,8 +35,6 @@ reg = <0x1000 0x400>; clocks = <&rcc GPIOB>; st,bank-name = "GPIOB"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 16 16>; status = "disabled"; }; @@ -50,8 +46,6 @@ reg = <0x2000 0x400>; clocks = <&rcc GPIOC>; st,bank-name = "GPIOC"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 32 16>; status = "disabled"; }; @@ -63,8 +57,6 @@ reg = <0x3000 0x400>; clocks = <&rcc GPIOD>; st,bank-name = "GPIOD"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 48 16>; status = "disabled"; }; @@ -76,8 +68,6 @@ reg = <0x4000 0x400>; clocks = <&rcc GPIOE>; st,bank-name = "GPIOE"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 64 16>; status = "disabled"; }; @@ -89,8 +79,6 @@ reg = <0x5000 0x400>; clocks = <&rcc GPIOF>; st,bank-name = "GPIOF"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 80 16>; status = "disabled"; }; @@ -102,8 +90,6 @@ reg = <0x6000 0x400>; clocks = <&rcc GPIOG>; st,bank-name = "GPIOG"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 96 16>; status = "disabled"; }; @@ -115,8 +101,6 @@ reg = <0x7000 0x400>; clocks = <&rcc GPIOH>; st,bank-name = "GPIOH"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 112 16>; status = "disabled"; }; @@ -128,8 +112,6 @@ reg = <0x8000 0x400>; clocks = <&rcc GPIOI>; st,bank-name = "GPIOI"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 128 16>; status = "disabled"; }; @@ -141,8 +123,6 @@ reg = <0x9000 0x400>; clocks = <&rcc GPIOJ>; st,bank-name = "GPIOJ"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 144 16>; status = "disabled"; }; @@ -154,8 +134,6 @@ reg = <0xa000 0x400>; clocks = <&rcc GPIOK>; st,bank-name = "GPIOK"; - ngpios = <8>; - gpio-ranges = <&pinctrl 0 160 8>; status = "disabled"; }; @@ -276,6 +254,50 @@ }; }; + fmc_pins_a: fmc-0 { + pins1 { + pinmux = , /* FMC_NOE */ + , /* FMC_NWE */ + , /* FMC_A16_FMC_CLE */ + , /* FMC_A17_FMC_ALE */ + , /* FMC_D0 */ + , /* FMC_D1 */ + , /* FMC_D2 */ + , /* FMC_D3 */ + , /* FMC_D4 */ + , /* FMC_D5 */ + , /* FMC_D6 */ + , /* FMC_D7 */ + ; /* FMC_NE2_FMC_NCE */ + bias-disable; + drive-push-pull; + slew-rate = <1>; + }; + pins2 { + pinmux = ; /* FMC_NWAIT */ + bias-pull-up; + }; + }; + + fmc_sleep_pins_a: fmc-sleep-0 { + pins { + pinmux = , /* FMC_NOE */ + , /* FMC_NWE */ + , /* FMC_A16_FMC_CLE */ + , /* FMC_A17_FMC_ALE */ + , /* FMC_D0 */ + , /* FMC_D1 */ + , /* FMC_D2 */ + , /* FMC_D3 */ + , /* FMC_D4 */ + , /* FMC_D5 */ + , /* FMC_D6 */ + , /* FMC_D7 */ + , /* FMC_NWAIT */ + ; /* FMC_NE2_FMC_NCE */ + }; + }; + i2c1_pins_a: i2c1-0 { pins { pinmux = , /* I2C1_SCL */ @@ -530,7 +552,7 @@ }; }; - m_can1_sleep_pins_a: m_can1-sleep@0 { + m_can1_sleep_pins_a: m_can1-sleep-0 { pins { pinmux = , /* CAN1_TX */ ; /* CAN1_RX */ @@ -849,8 +871,6 @@ clocks = <&rcc GPIOZ>; st,bank-name = "GPIOZ"; st,bank-ioport = <11>; - ngpios = <8>; - gpio-ranges = <&pinctrl_z 0 400 8>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts b/arch/arm/boot/dts/stm32mp157a-dk1.dts index f3f0e37aad4dd19914e400a9bda399668c96a65d..0615d1c8a6fcf5c0cf2ad885275d2fc3e90d4945 100644 --- a/arch/arm/boot/dts/stm32mp157a-dk1.dts +++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts @@ -33,6 +33,42 @@ #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; + }; + gpu_reserved: gpu@d4000000 { reg = <0xd4000000 0x4000000>; no-map; @@ -48,6 +84,17 @@ default-state = "off"; }; }; + + sound { + compatible = "audio-graph-card"; + label = "STM32MP1-DK"; + routing = + "Playback" , "MCLK", + "Capture" , "MCLK", + "MICL" , "Mic Bias"; + dais = <&sai2a_port &sai2b_port>; + status = "okay"; + }; }; &cec { @@ -116,6 +163,39 @@ }; }; }; + + cs42l51: cs42l51@4a { + compatible = "cirrus,cs42l51"; + reg = <0x4a>; + #sound-dai-cells = <0>; + VL-supply = <&v3v3>; + VD-supply = <&v1v8_audio>; + VA-supply = <&v1v8_audio>; + VAHP-supply = <&v1v8_audio>; + reset-gpios = <&gpiog 9 GPIO_ACTIVE_LOW>; + clocks = <&sai2a>; + clock-names = "MCLK"; + status = "okay"; + + cs42l51_port: port { + #address-cells = <1>; + #size-cells = <0>; + + cs42l51_tx_endpoint: endpoint@0 { + reg = <0>; + remote-endpoint = <&sai2a_endpoint>; + frame-master; + bitclock-master; + }; + + cs42l51_rx_endpoint: endpoint@1 { + reg = <1>; + remote-endpoint = <&sai2b_endpoint>; + frame-master; + bitclock-master; + }; + }; + }; }; &i2c4 { @@ -289,6 +369,16 @@ }; }; +&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"; }; @@ -297,6 +387,51 @@ status = "okay"; }; +&sai2 { + clocks = <&rcc SAI2>, <&rcc PLL3_Q>, <&rcc PLL3_R>; + clock-names = "pclk", "x8k", "x11k"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sai2a_pins_a>, <&sai2b_pins_b>; + pinctrl-1 = <&sai2a_sleep_pins_a>, <&sai2b_sleep_pins_b>; + status = "okay"; + + sai2a: audio-controller@4400b004 { + #clock-cells = <0>; + dma-names = "tx"; + clocks = <&rcc SAI2_K>; + clock-names = "sai_ck"; + status = "okay"; + + sai2a_port: port { + sai2a_endpoint: endpoint { + remote-endpoint = <&cs42l51_tx_endpoint>; + format = "i2s"; + mclk-fs = <256>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; + }; + }; + + sai2b: audio-controller@4400b024 { + dma-names = "rx"; + st,sync = <&sai2a 2>; + clocks = <&rcc SAI2_K>, <&sai2a>; + clock-names = "sai_ck", "MCLK"; + status = "okay"; + + sai2b_port: port { + sai2b_endpoint: endpoint { + remote-endpoint = <&cs42l51_rx_endpoint>; + format = "i2s"; + mclk-fs = <256>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; + }; + }; +}; + &sdmmc1 { pinctrl-names = "default", "opendrain", "sleep"; pinctrl-0 = <&sdmmc1_b4_pins_a>; diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts index 4fe7f71a74d36daa836e9983a1c141a3b0d2f03c..1d426ea8bdafafbcb4db64e9564c6f5d4a9b669c 100644 --- a/arch/arm/boot/dts/stm32mp157c-ed1.dts +++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts @@ -28,6 +28,42 @@ #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; + }; + gpu_reserved: gpu@e8000000 { reg = <0xe8000000 0x8000000>; no-map; @@ -233,6 +269,16 @@ 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"; }; diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts b/arch/arm/boot/dts/stm32mp157c-ev1.dts index feb8f7727270b670c68e5229113dda63984b6f53..89d29b50c3f46df13ba252fa914aee8de50a0dfc 100644 --- a/arch/arm/boot/dts/stm32mp157c-ev1.dts +++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts @@ -101,6 +101,7 @@ &dsi { #address-cells = <1>; #size-cells = <0>; + phy-dsi-supply = <®18>; status = "okay"; ports { @@ -157,6 +158,22 @@ }; }; +&fmc { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&fmc_pins_a>; + pinctrl-1 = <&fmc_sleep_pins_a>; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; + nand-on-flash-bbt; + #address-cells = <1>; + #size-cells = <1>; + }; +}; + &i2c2 { pinctrl-names = "default"; pinctrl-0 = <&i2c2_pins_a>; diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi index 0c4e6ebc35291e8e243c816d0a7631ae1ee8ab9f..9b11654a0a3977e62efb6f427ee1d49eb1af5bd2 100644 --- a/arch/arm/boot/dts/stm32mp157c.dtsi +++ b/arch/arm/boot/dts/stm32mp157c.dtsi @@ -109,6 +109,12 @@ }; }; + booster: regulator-booster { + compatible = "st,stm32mp1-booster"; + st,syscfg = <&syscfg>; + status = "disabled"; + }; + soc { compatible = "simple-bus"; #address-cells = <1>; @@ -133,6 +139,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -161,6 +168,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -187,6 +195,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -215,6 +224,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -272,6 +282,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -293,6 +304,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -314,6 +326,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -567,6 +580,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -597,6 +611,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -670,6 +685,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -694,6 +710,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; timer@15 { @@ -717,6 +734,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -983,6 +1001,7 @@ clocks = <&rcc ADC12>, <&rcc ADC12_K>; clock-names = "bus", "adc"; interrupt-controller; + st,syscfg = <&syscfg>; #interrupt-cells = <1>; #address-cells = <1>; #size-cells = <0>; @@ -1239,11 +1258,33 @@ dma-requests = <48>; }; + fmc: nand-controller@58002000 { + compatible = "st,stm32mp15-fmc2"; + reg = <0x58002000 0x1000>, + <0x80000000 0x1000>, + <0x88010000 0x1000>, + <0x88020000 0x1000>, + <0x81000000 0x1000>, + <0x89010000 0x1000>, + <0x89020000 0x1000>; + interrupts = ; + dmas = <&mdma1 20 0x10 0x12000a02 0x0 0x0>, + <&mdma1 20 0x10 0x12000a08 0x0 0x0>, + <&mdma1 21 0x10 0x12000a0a 0x0 0x0>; + dma-names = "tx", "rx", "ecc"; + clocks = <&rcc FMC_K>; + resets = <&rcc FMC_R>; + status = "disabled"; + }; + qspi: spi@58003000 { compatible = "st,stm32f469-qspi"; reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; reg-names = "qspi", "qspi_mm"; interrupts = ; + dmas = <&mdma1 22 0x10 0x100002 0x0 0x0>, + <&mdma1 22 0x10 0x100008 0x0 0x0>; + dma-names = "tx", "rx"; clocks = <&rcc QSPI_K>; resets = <&rcc QSPI_R>; status = "disabled"; @@ -1448,4 +1489,24 @@ status = "disabled"; }; }; + + mlahb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + dma-ranges = <0x00000000 0x38000000 0x10000>, + <0x10000000 0x10000000 0x60000>, + <0x30000000 0x30000000 0x60000>; + + m4_rproc: m4@10000000 { + compatible = "st,stm32mp1-m4"; + reg = <0x10000000 0x40000>, + <0x30000000 0x40000>, + <0x38000000 0x10000>; + resets = <&rcc MCU_R>; + st,syscfg-holdboot = <&rcc 0x10C 0x1>; + st,syscfg-tz = <&rcc 0x000 0x1>; + status = "disabled"; + }; + }; }; diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts index 6c254ec4c85b71faaff83da262ab59d4d3794211..8692b11a83c3ffc758da7a8dbd8a251c7a15b4cd 100644 --- a/arch/arm/boot/dts/sun4i-a10-a1000.dts +++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts @@ -125,7 +125,7 @@ }; &emac { - phy = <&phy1>; + phy-handle = <&phy1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts b/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts index 38a2c413495248024fc8f4e96348dd1e64260d14..816d534ac093985bcb8faf4544115dd0f7015871 100644 --- a/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts +++ b/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts @@ -68,7 +68,7 @@ }; &emac { - phy = <&phy1>; + phy-handle = <&phy1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts index 7306c65df88aa1acff7bb9446e38d776b67c21ea..6ca02e824accb0c14ca11c0410852d13c2c3f4e2 100644 --- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts +++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts @@ -114,7 +114,7 @@ }; &emac { - phy = <&phy1>; + phy-handle = <&phy1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun4i-a10-hackberry.dts b/arch/arm/boot/dts/sun4i-a10-hackberry.dts index cc988ccd5ca753157887f70a141b55679bbb24f8..47dea0922501baef6e169305c038c04d3c382122 100644 --- a/arch/arm/boot/dts/sun4i-a10-hackberry.dts +++ b/arch/arm/boot/dts/sun4i-a10-hackberry.dts @@ -80,7 +80,7 @@ }; &emac { - phy = <&phy0>; + phy-handle = <&phy0>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun4i-a10-itead-iteaduino-plus.dts b/arch/arm/boot/dts/sun4i-a10-itead-iteaduino-plus.dts index 80ecd78247ac4466a1ad4135c85fa70275c3a98e..d4e319d16aae74ca793b2aa665228c5174d2f435 100644 --- a/arch/arm/boot/dts/sun4i-a10-itead-iteaduino-plus.dts +++ b/arch/arm/boot/dts/sun4i-a10-itead-iteaduino-plus.dts @@ -58,7 +58,7 @@ &emac { pinctrl-names = "default"; pinctrl-0 = <&emac_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts b/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts index 247fa27ef7178aa9390ca70c4df27524be91e60b..8a7b4c53d278c5e6942fddf0e5ce9190034b4808 100644 --- a/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts +++ b/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts @@ -94,7 +94,7 @@ }; &emac { - phy = <&phy1>; + phy-handle = <&phy1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun4i-a10-marsboard.dts b/arch/arm/boot/dts/sun4i-a10-marsboard.dts index 58ad2ad9041f19d683b280efd6dd722b7a634603..a843e57530ed9d84b1f60b0a6da2a54c69b8d52b 100644 --- a/arch/arm/boot/dts/sun4i-a10-marsboard.dts +++ b/arch/arm/boot/dts/sun4i-a10-marsboard.dts @@ -105,7 +105,7 @@ }; &emac { - phy = <&phy1>; + phy-handle = <&phy1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts index a8e537fd4bd612637229c8221d5edb8926543fe6..845f76824d57459fdbb1e57d39ab61852c358f56 100644 --- a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts +++ b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts @@ -112,7 +112,7 @@ }; &emac { - phy = <&phy1>; + phy-handle = <&phy1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun4i-a10-pcduino.dts b/arch/arm/boot/dts/sun4i-a10-pcduino.dts index 0f1e781069e9d14491fd8236fa4b8959d2da6e2c..83287b6c975e72295dab30903e99734960257115 100644 --- a/arch/arm/boot/dts/sun4i-a10-pcduino.dts +++ b/arch/arm/boot/dts/sun4i-a10-pcduino.dts @@ -110,7 +110,7 @@ }; &emac { - phy = <&phy1>; + phy-handle = <&phy1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi index e88daa4ef1aff9a67aac12cbb6959c53137bf6c4..ce823c44e98affebfe799183e92f56f43aea1fab 100644 --- a/arch/arm/boot/dts/sun4i-a10.dtsi +++ b/arch/arm/boot/dts/sun4i-a10.dtsi @@ -803,13 +803,20 @@ timer@1c20c00 { compatible = "allwinner,sun4i-a10-timer"; reg = <0x01c20c00 0x90>; - interrupts = <22>; + interrupts = <22>, + <23>, + <24>, + <25>, + <67>, + <68>; clocks = <&osc24M>; }; wdt: watchdog@1c20c90 { compatible = "allwinner,sun4i-a10-wdt"; reg = <0x01c20c90 0x10>; + interrupts = <24>; + clocks = <&osc24M>; }; rtc: rtc@1c20d00 { diff --git a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts index 5340b4164df26e622e12bf412f09aacc4c1003f1..7033a123c9a3afaa9fe752b777794917098a97b9 100644 --- a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts +++ b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts @@ -98,7 +98,7 @@ &emac { pinctrl-names = "default"; pinctrl-0 = <&emac_pa_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts b/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts index b5ee8fb13a924dfc8cf4f0de32ef62a983583c20..1f74ba1634cc69c2731022b69feffb81d6ea1cb9 100644 --- a/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts +++ b/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts @@ -91,7 +91,7 @@ &emac { pinctrl-names = "default"; pinctrl-0 = <&emac_pd_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun5i-a13-q8-tablet.dts b/arch/arm/boot/dts/sun5i-a13-q8-tablet.dts index fde559a8b61e0f876037c5155d4d67cf159e4374..f9fc1c8b60b81f34e532f4cbfaeb295a5e0940ab 100644 --- a/arch/arm/boot/dts/sun5i-a13-q8-tablet.dts +++ b/arch/arm/boot/dts/sun5i-a13-q8-tablet.dts @@ -49,7 +49,7 @@ compatible = "allwinner,q8-a13", "allwinner,sun5i-a13"; panel: panel { - compatible = "bananapi,s070wv20-ct16", "simple-panel"; + compatible = "bananapi,s070wv20-ct16"; power-supply = <®_vcc3v3>; enable-gpios = <&axp_gpio 0 GPIO_ACTIVE_HIGH>; /* AXP GPIO0 */ backlight = <&backlight>; diff --git a/arch/arm/boot/dts/sun5i.dtsi b/arch/arm/boot/dts/sun5i.dtsi index 2fb438c4fe9d1bd90fe366f65aed183d82280352..cfb1efc8828c34de86917efff63a762b32b25985 100644 --- a/arch/arm/boot/dts/sun5i.dtsi +++ b/arch/arm/boot/dts/sun5i.dtsi @@ -588,13 +588,20 @@ timer@1c20c00 { compatible = "allwinner,sun4i-a10-timer"; reg = <0x01c20c00 0x90>; - interrupts = <22>; + interrupts = <22>, + <23>, + <24>, + <25>, + <67>, + <68>; clocks = <&ccu CLK_HOSC>; }; wdt: watchdog@1c20c90 { compatible = "allwinner,sun4i-a10-wdt"; reg = <0x01c20c90 0x10>; + interrupts = <24>; + clocks = <&osc24M>; }; ir0: ir@1c21800 { diff --git a/arch/arm/boot/dts/sun6i-a31-colombus.dts b/arch/arm/boot/dts/sun6i-a31-colombus.dts index c3d56dc93513f58bcfa2fbaa31da6fc5616084ae..93a15eaaa8cbd81873dc955c923aa7021f4276bc 100644 --- a/arch/arm/boot/dts/sun6i-a31-colombus.dts +++ b/arch/arm/boot/dts/sun6i-a31-colombus.dts @@ -76,13 +76,9 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "rgmii"; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &i2c0 { @@ -104,6 +100,12 @@ }; }; +&mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v0>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts index 09832b4e8fc8544574256e0bb96d3351f5ac4c2c..049e6ab3cf56c6fa9c2a4bc2fe576a38ee663d2d 100644 --- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts +++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts @@ -153,16 +153,9 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "rgmii"; - snps,reset-gpio = <&pio 0 21 GPIO_ACTIVE_HIGH>; - snps,reset-active-low; - snps,reset-delays-us = <0 10000 30000>; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &hdmi { @@ -199,6 +192,15 @@ status = "okay"; }; +&mdio { + phy1: ethernet-phy@1 { + reg = <1>; + reset-gpios = <&pio 0 21 GPIO_ACTIVE_LOW>; + reset-assert-us = <10000>; + reset-deassert-us = <30000>; + }; +}; + &mmc0 { vmmc-supply = <®_dcdc1>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun6i-a31-i7.dts b/arch/arm/boot/dts/sun6i-a31-i7.dts index 091eb2ac53b307c4845366ef9baaa6c8f43c9600..6cc8ccf53d886e9f9c90bee9f4f0a7d5f61a6178 100644 --- a/arch/arm/boot/dts/sun6i-a31-i7.dts +++ b/arch/arm/boot/dts/sun6i-a31-i7.dts @@ -117,13 +117,9 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_mii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "mii"; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &hdmi { @@ -142,6 +138,12 @@ status = "okay"; }; +&mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun6i-a31-m9.dts b/arch/arm/boot/dts/sun6i-a31-m9.dts index 6eafb6361a26ca9901c7f27ae92055583625fe33..a645c8f4257c039b7410d9d52d998faea9ade243 100644 --- a/arch/arm/boot/dts/sun6i-a31-m9.dts +++ b/arch/arm/boot/dts/sun6i-a31-m9.dts @@ -84,14 +84,10 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_mii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "mii"; phy-supply = <®_dldo1>; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &ir { @@ -100,6 +96,12 @@ status = "okay"; }; +&mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_dcdc1>; bus-width = <4>; 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 ca036f97923a28f5ccdfa705595ce335d4f63992..648f247462344de4851f1a13ff2bbf58905116a2 100644 --- a/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts +++ b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts @@ -84,14 +84,10 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_mii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "mii"; phy-supply = <®_dldo1>; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &ir { @@ -100,6 +96,12 @@ status = "okay"; }; +&mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_dcdc1>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi index dcddc3392460ff5874523b6cb19c2be4dac657d0..bbeb743633c68ef6f19a1b1c5375eb5e821df88b 100644 --- a/arch/arm/boot/dts/sun6i-a31.dtsi +++ b/arch/arm/boot/dts/sun6i-a31.dtsi @@ -736,13 +736,16 @@ , , , - ; + , + ; clocks = <&osc24M>; }; wdt1: watchdog@1c20ca0 { compatible = "allwinner,sun6i-a31-wdt"; reg = <0x01c20ca0 0x20>; + interrupts = ; + clocks = <&osc24M>; }; spdif: spdif@1c21000 { @@ -939,8 +942,12 @@ snps,fixed-burst; snps,force_sf_dma_mode; status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; + + mdio: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; }; crypto: crypto-engine@1c15000 { @@ -1364,7 +1371,7 @@ }; ir: ir@1f02000 { - compatible = "allwinner,sun5i-a13-ir"; + compatible = "allwinner,sun6i-a31-ir"; clocks = <&apb0_gates 1>, <&ir_clk>; clock-names = "apb", "ir"; resets = <&apb0_rst 1>; diff --git a/arch/arm/boot/dts/sun6i-a31s-cs908.dts b/arch/arm/boot/dts/sun6i-a31s-cs908.dts index 72a02c045a380f47e7cfe16c78e737fbb7ebba71..1d15e15011c6876c5c66ec5bf2d4af715e58f5e6 100644 --- a/arch/arm/boot/dts/sun6i-a31s-cs908.dts +++ b/arch/arm/boot/dts/sun6i-a31s-cs908.dts @@ -67,12 +67,9 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_mii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "mii"; status = "okay"; - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &ir { @@ -81,6 +78,12 @@ status = "okay"; }; +&mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &ohci1 { status = "okay"; }; diff --git a/arch/arm/boot/dts/sun6i-a31s-sina31s.dts b/arch/arm/boot/dts/sun6i-a31s-sina31s.dts index 4865c3271ab0485fb4081e3fb860366dd0d7b826..0af48e143b664c299e303418e0f01495e5e70ee4 100644 --- a/arch/arm/boot/dts/sun6i-a31s-sina31s.dts +++ b/arch/arm/boot/dts/sun6i-a31s-sina31s.dts @@ -115,14 +115,10 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_mii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "mii"; phy-supply = <®_dldo1>; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &hdmi { @@ -160,6 +156,12 @@ }; }; +&mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_dcdc1>; bus-width = <4>; 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 8e724c52feffeccaab0a5c25afcc6638d91de67a..708caee52425f5293e69431c7d98c0dcc95d56ef 100644 --- a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts +++ b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts @@ -92,17 +92,10 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "rgmii"; phy-supply = <®_dldo1>; - snps,reset-gpio = <&pio 0 21 GPIO_ACTIVE_HIGH>; /* PA21 */ - snps,reset-active-low; - snps,reset-delays-us = <0 10000 30000>; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &ir { @@ -111,6 +104,15 @@ status = "okay"; }; +&mdio { + phy1: ethernet-phy@1 { + reg = <1>; + reset-gpios = <&pio 0 21 GPIO_ACTIVE_LOW>; /* PA21 */ + reset-assert-us = <10000>; + reset-deassert-us = <30000>; + }; +}; + &mmc0 { vmmc-supply = <®_dcdc1>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-bananapi-m1-plus.dts b/arch/arm/boot/dts/sun7i-a20-bananapi-m1-plus.dts index e2bfe0058830fd12c14cf0b033871ba35f390d21..32d5d45a35c036934d56651bbe39f16fb9c39cdf 100644 --- a/arch/arm/boot/dts/sun7i-a20-bananapi-m1-plus.dts +++ b/arch/arm/boot/dts/sun7i-a20-bananapi-m1-plus.dts @@ -129,14 +129,10 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "rgmii"; phy-supply = <®_gmac_3v3>; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &hdmi { @@ -171,6 +167,12 @@ status = "okay"; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-bananapi.dts b/arch/arm/boot/dts/sun7i-a20-bananapi.dts index 4df921632f7a17dd4781222d0d9a2d2505100522..bb3987e101c291669a609499d481b5bb3d20c0bd 100644 --- a/arch/arm/boot/dts/sun7i-a20-bananapi.dts +++ b/arch/arm/boot/dts/sun7i-a20-bananapi.dts @@ -131,14 +131,10 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "rgmii"; phy-supply = <®_gmac_3v3>; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &hdmi { @@ -171,6 +167,12 @@ status = "okay"; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-bananapro.dts b/arch/arm/boot/dts/sun7i-a20-bananapro.dts index 0176e9de018033201cbf04b735d48a5530e9b22e..01ccff756996d83ac7d843f6fe61d7dcab5bad37 100644 --- a/arch/arm/boot/dts/sun7i-a20-bananapro.dts +++ b/arch/arm/boot/dts/sun7i-a20-bananapro.dts @@ -109,14 +109,10 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "rgmii"; phy-supply = <®_gmac_3v3>; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &i2c0 { @@ -143,6 +139,12 @@ status = "okay"; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts index 08e5a5abf8cce46c1627ac5ef93e9b365f448bb8..b8203e4ef21c975daa9fbd1ba19f5366d15952b2 100644 --- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts @@ -115,13 +115,9 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_mii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "mii"; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &hdmi { @@ -161,6 +157,12 @@ status = "okay"; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &ohci0 { status = "okay"; }; diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts index 99f531b8d2a78a2676bd34812e4a1127d214394e..8c8dee6ea461a801e1bcc5db09ba7178f94b4ba2 100644 --- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts +++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts @@ -150,13 +150,9 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "rgmii"; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &hdmi { @@ -194,6 +190,12 @@ status = "okay"; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-hummingbird.dts b/arch/arm/boot/dts/sun7i-a20-hummingbird.dts index fd0153f65685618edacc77875d49fb558e3f9f4e..3def2a33059810a3b3e18c4d491aad6c54998ebd 100644 --- a/arch/arm/boot/dts/sun7i-a20-hummingbird.dts +++ b/arch/arm/boot/dts/sun7i-a20-hummingbird.dts @@ -100,19 +100,10 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "rgmii"; phy-supply = <®_gmac_vdd>; - /* phy reset config */ - snps,reset-gpio = <&pio 0 17 GPIO_ACTIVE_HIGH>; /* PA17 */ - snps,reset-active-low; - /* wait 1s after reset, otherwise fail to read phy id */ - snps,reset-delays-us = <0 10000 1000000>; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &i2c0 { @@ -146,6 +137,16 @@ status = "okay"; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + reset-gpios = <&pio 0 17 GPIO_ACTIVE_LOW>; /* PA17 */ + reset-assert-us = <10000>; + /* wait 1s after reset, otherwise fail to read phy id */ + reset-deassert-us = <1000000>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v0>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts b/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts index 5f1c4f573d3eac3cbb3c900014119b97a629a78f..358ed5f1b1c1c1482fbaf75dcbab173cf37f1333 100644 --- a/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts +++ b/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts @@ -115,14 +115,10 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_mii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "mii"; phy-supply = <®_gmac_3v3>; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &i2c0 { @@ -145,6 +141,12 @@ status = "okay"; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-icnova-swac.dts b/arch/arm/boot/dts/sun7i-a20-icnova-swac.dts index 7449aac3f43b70d46862c9d6ee055c62da0ffc6a..413505f45a81e2e5af8b211f538c2ab98580c749 100644 --- a/arch/arm/boot/dts/sun7i-a20-icnova-swac.dts +++ b/arch/arm/boot/dts/sun7i-a20-icnova-swac.dts @@ -76,13 +76,9 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_mii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "mii"; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &i2c0 { @@ -99,6 +95,12 @@ status = "okay"; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-itead-ibox.dts b/arch/arm/boot/dts/sun7i-a20-itead-ibox.dts index b90a7607d0699514738ae04bb43f72c1e92b60cd..946c272783210f45aaf40b16efaff25f5b4c9af8 100644 --- a/arch/arm/boot/dts/sun7i-a20-itead-ibox.dts +++ b/arch/arm/boot/dts/sun7i-a20-itead-ibox.dts @@ -97,10 +97,12 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_mii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "mii"; status = "okay"; +}; +&gmac_mdio { phy1: ethernet-phy@1 { reg = <1>; }; diff --git a/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts index 3e170cfac86aeab3cc805c7468d8748244aa723d..17fa8901fc002e6f045c826ab47106f330b12e2b 100644 --- a/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts +++ b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts @@ -123,8 +123,6 @@ phy-mode = "rgmii"; phy-supply = <®_gmac_3v3>; status = "okay"; - /delete-property/#address-cells; - /delete-property/#size-cells; fixed-link { speed = <1000>; diff --git a/arch/arm/boot/dts/sun7i-a20-m3.dts b/arch/arm/boot/dts/sun7i-a20-m3.dts index b8a1aaaf3976527d6bea57966a60f5b3868132a6..6bff9e731fc34455313002684d78b8c255fac5a0 100644 --- a/arch/arm/boot/dts/sun7i-a20-m3.dts +++ b/arch/arm/boot/dts/sun7i-a20-m3.dts @@ -82,13 +82,9 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_mii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "mii"; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &i2c0 { @@ -111,6 +107,12 @@ status = "okay"; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts b/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts index f0e6a96e5785bcd1f1721a97ba15bf9667be4f97..6f9c54b8e49a5a5cd5b6d0fae1eeb84a82286998 100644 --- a/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts +++ b/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts @@ -111,13 +111,9 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "rgmii"; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &hdmi { @@ -202,6 +198,12 @@ }; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-olimex-som204-evb.dts b/arch/arm/boot/dts/sun7i-a20-olimex-som204-evb.dts index c34a83f666c72e2a61a24de9ac772e8e8ca48d47..230d62a6b8f10a6b34782e4b2e6b3581cca2880a 100644 --- a/arch/arm/boot/dts/sun7i-a20-olimex-som204-evb.dts +++ b/arch/arm/boot/dts/sun7i-a20-olimex-som204-evb.dts @@ -105,18 +105,10 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy3>; + phy-handle = <&phy3>; phy-mode = "rgmii"; phy-supply = <®_vcc3v3>; - - snps,reset-gpio = <&pio 0 17 GPIO_ACTIVE_HIGH>; - snps,reset-active-low; - snps,reset-delays-us = <0 10000 1000000>; status = "okay"; - - phy3: ethernet-phy@3 { - reg = <3>; - }; }; &hdmi { @@ -161,6 +153,16 @@ status = "okay"; }; +&gmac_mdio { + phy3: ethernet-phy@3 { + reg = <3>; + reset-gpios = <&pio 0 17 GPIO_ACTIVE_LOW>; /* PA17 */ + reset-assert-us = <10000>; + /* wait 1s after reset, otherwise fail to read phy id */ + reset-deassert-us = <1000000>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts index e40dd47df8ce350f67016e1d18575879fe1b5840..2adbac8601193bac874ebcd3c83310f2727261eb 100644 --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts @@ -106,13 +106,9 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_mii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "mii"; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &hdmi { @@ -149,6 +145,12 @@ }; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts index 56f451c07f9376b397497f45fa2a0a04309cc82a..9ba62774e89a152365eb71e058e1f4a38910dd42 100644 --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts @@ -111,13 +111,9 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "rgmii"; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &hdmi { @@ -154,6 +150,12 @@ vref-supply = <®_vcc3v0>; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts index 0dcba070444af0e577afc0165e800d15c15a02ea..359bd0d5b3b1e59f76fc7a649f1d3aae616f052b 100644 --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts @@ -118,13 +118,9 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_mii_pins>, <&gmac_txerr>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "mii"; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &hdmi { @@ -215,6 +211,12 @@ }; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts b/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts index 9628041bb3a3275a3af62d3f9c620e6d65311b50..2e328d2cefc1909e38ea7abd8e2d56926d604376 100644 --- a/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts +++ b/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts @@ -120,14 +120,10 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "rgmii"; phy-supply = <®_gmac_3v3>; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &hdmi { @@ -158,6 +154,12 @@ status = "okay"; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-orangepi.dts b/arch/arm/boot/dts/sun7i-a20-orangepi.dts index 7b3532665c2886a1516fadf84af0b5101c7b14a7..d75b2e2bab282208501c5416cca89b98533a2443 100644 --- a/arch/arm/boot/dts/sun7i-a20-orangepi.dts +++ b/arch/arm/boot/dts/sun7i-a20-orangepi.dts @@ -96,14 +96,10 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "rgmii"; phy-supply = <®_gmac_3v3>; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &i2c0 { @@ -124,6 +120,12 @@ status = "okay"; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts b/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts index 173b676436e906f348aa005ec8295adb2035243f..fce2f7fcd084a57fa0ff503670e421a83e9c875e 100644 --- a/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts +++ b/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts @@ -114,13 +114,9 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "rgmii"; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &hdmi { @@ -149,6 +145,12 @@ status = "okay"; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts index 14a88aa16a97a26fd461b1aef590864d6ce45709..cc8271d777b8e03628b77100c944a7f39c71bfec 100644 --- a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts +++ b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts @@ -122,13 +122,9 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_mii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "mii"; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &i2c0 { @@ -149,6 +145,12 @@ status = "okay"; }; +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts b/arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts index f8475a39777bf131f286f6245847aa35c891b63c..3bfae98f3cc3a18e6d312ced1337acb9340e397f 100644 --- a/arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts +++ b/arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts @@ -81,13 +81,9 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "rgmii"; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &i2c0 { @@ -110,6 +106,12 @@ #include "axp209.dtsi" +&gmac_mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index 9ad8e445b24017be087f35ed4854313554105a0f..49380de754a933b22a56b37a69c033f9a019e6b7 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -376,6 +376,17 @@ num-cs = <1>; }; + csi0: csi@1c09000 { + compatible = "allwinner,sun7i-a20-csi0"; + reg = <0x01c09000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_AHB_CSI0>, <&ccu CLK_CSI0>, + <&ccu CLK_CSI_SCLK>, <&ccu CLK_DRAM_CSI0>; + clock-names = "bus", "mod", "isp", "ram"; + resets = <&ccu RST_CSI0>; + status = "disabled"; + }; + emac: ethernet@1c0b000 { compatible = "allwinner,sun4i-a10-emac"; reg = <0x01c0b000 0x1000>; @@ -774,6 +785,20 @@ function = "clk_out_b"; }; + /omit-if-no-ref/ + csi0_8bits_pins: csi-8bits-pins { + pins = "PE0", "PE2", "PE3", "PE4", "PE5", + "PE6", "PE7", "PE8", "PE9", "PE10", + "PE11"; + function = "csi0"; + }; + + /omit-if-no-ref/ + csi0_clk_pin: csi-clk-pin { + pins = "PE1"; + function = "csi0"; + }; + /omit-if-no-ref/ emac_pa_pins: emac-pa-pins { pins = "PA0", "PA1", "PA2", @@ -1115,6 +1140,8 @@ wdt: watchdog@1c20c90 { compatible = "allwinner,sun4i-a10-wdt"; reg = <0x01c20c90 0x10>; + interrupts = ; + clocks = <&osc24M>; }; rtc: rtc@1c20d00 { @@ -1437,8 +1464,12 @@ snps,fixed-burst; snps,force_sf_dma_mode; status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; + + gmac_mdio: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; }; hstimer@1c60000 { diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi index af2fa694a467b0f4459aa5f17f6a0069d284c5ff..52eed0ae3607666a86ec6865902d115168c0aa94 100644 --- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi +++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi @@ -441,7 +441,7 @@ }; timer@1c20c00 { - compatible = "allwinner,sun4i-a10-timer"; + compatible = "allwinner,sun8i-a23-timer"; reg = <0x01c20c00 0xa0>; interrupts = , ; @@ -452,6 +452,7 @@ compatible = "allwinner,sun6i-a31-wdt"; reg = <0x01c20ca0 0x20>; interrupts = ; + clocks = <&osc24M>; }; pwm: pwm@1c21400 { diff --git a/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts b/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts index 5659c63d7d777f21029625e22769d0288743d0ec..51097c77a152c4a8fb0b0c8801f2870130b6f36c 100644 --- a/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts +++ b/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts @@ -63,7 +63,7 @@ }; &panel { - compatible = "bananapi,s070wv20-ct16", "simple-panel"; + compatible = "bananapi,s070wv20-ct16"; }; &tcon0_out { diff --git a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts index ea299d3d84d0c5a63ea1a61b0856d85e21ac7aed..fb928503ad45da35e12b24189e3ece6ae66d1cca 100644 --- a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts +++ b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts @@ -60,6 +60,17 @@ stdout-path = "serial0:115200n8"; }; + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; + leds { compatible = "gpio-leds"; @@ -153,6 +164,10 @@ cpu-supply = <®_dcdc3>; }; +&de { + status = "okay"; +}; + &ehci0 { /* GL830 USB-to-SATA bridge here */ status = "okay"; @@ -172,6 +187,16 @@ status = "okay"; }; +&hdmi { + status = "okay"; +}; + +&hdmi_out { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + &mdio { rgmii_phy: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c22"; diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi index ada6d08bc5404484780bafe9a0dc6ef2c3579f4a..523be6611c50dcdea77bcba5a1266f34972bea58 100644 --- a/arch/arm/boot/dts/sun8i-a83t.dtsi +++ b/arch/arm/boot/dts/sun8i-a83t.dtsi @@ -314,10 +314,10 @@ display_clocks: clock@1000000 { compatible = "allwinner,sun8i-a83t-de2-clk"; reg = <0x01000000 0x100000>; - clocks = <&ccu CLK_PLL_DE>, - <&ccu CLK_BUS_DE>; - clock-names = "mod", - "bus"; + clocks = <&ccu CLK_BUS_DE>, + <&ccu CLK_PLL_DE>; + clock-names = "bus", + "mod"; resets = <&ccu RST_BUS_DE>; #clock-cells = <1>; #reset-cells = <1>; @@ -806,7 +806,7 @@ }; timer@1c20c00 { - compatible = "allwinner,sun4i-a10-timer"; + compatible = "allwinner,sun8i-a23-timer"; reg = <0x01c20c00 0xa0>; interrupts = , ; @@ -1037,7 +1037,7 @@ resets = <&ccu RST_BUS_HDMI1>; reset-names = "ctrl"; phys = <&hdmi_phy>; - phy-names = "hdmi-phy"; + phy-names = "phy"; pinctrl-names = "default"; pinctrl-0 = <&hdmi_pins>; status = "disabled"; @@ -1096,7 +1096,7 @@ r_cir: ir@1f02000 { compatible = "allwinner,sun8i-a83t-ir", - "allwinner,sun5i-a13-ir"; + "allwinner,sun6i-a31-ir"; clocks = <&r_ccu CLK_APB0_IR>, <&r_ccu CLK_IR>; clock-names = "apb", "ir"; resets = <&r_ccu RST_APB0_IR>; diff --git a/arch/arm/boot/dts/sun8i-r40.dtsi b/arch/arm/boot/dts/sun8i-r40.dtsi index 6007d0cc252d3a05aeff9ab9b340781c6d99d794..bde068111b859084f482439ecf959156a8a30415 100644 --- a/arch/arm/boot/dts/sun8i-r40.dtsi +++ b/arch/arm/boot/dts/sun8i-r40.dtsi @@ -119,10 +119,10 @@ compatible = "allwinner,sun8i-r40-de2-clk", "allwinner,sun8i-h3-de2-clk"; reg = <0x01000000 0x100000>; - clocks = <&ccu CLK_DE>, - <&ccu CLK_BUS_DE>; - clock-names = "mod", - "bus"; + clocks = <&ccu CLK_BUS_DE>, + <&ccu CLK_DE>; + clock-names = "bus", + "mod"; resets = <&ccu RST_BUS_DE>; #clock-cells = <1>; #reset-cells = <1>; @@ -404,6 +404,8 @@ wdt: watchdog@1c20c90 { compatible = "allwinner,sun4i-a10-wdt"; reg = <0x01c20c90 0x10>; + interrupts = ; + clocks = <&osc24M>; }; uart0: serial@1c28000 { @@ -808,7 +810,7 @@ resets = <&ccu RST_BUS_HDMI1>; reset-names = "ctrl"; phys = <&hdmi_phy>; - phy-names = "hdmi-phy"; + phy-names = "phy"; status = "disabled"; ports { diff --git a/arch/arm/boot/dts/sun8i-s3-lichee-zero-plus.dts b/arch/arm/boot/dts/sun8i-s3-lichee-zero-plus.dts new file mode 100644 index 0000000000000000000000000000000000000000..d18192d51d1b66714ff29820305fc1162148d0c3 --- /dev/null +++ b/arch/arm/boot/dts/sun8i-s3-lichee-zero-plus.dts @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2019 Icenowy Zheng + */ + +/dts-v1/; +#include "sun8i-v3.dtsi" + +#include + +/ { + model = "Sipeed Lichee Zero Plus"; + compatible = "sipeed,lichee-zero-plus", "sochip,s3", + "allwinner,sun8i-v3"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + reg_vcc3v3: vcc3v3 { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; +}; + +&mmc0 { + broken-cd; + bus-width = <4>; + vmmc-supply = <®_vcc3v3>; + status = "okay"; +}; + +&uart0 { + pinctrl-0 = <&uart0_pb_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&usb_otg { + dr_mode = "peripheral"; + status = "okay"; +}; + +&usbphy { + usb0_id_det-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/sun8i-v3.dtsi b/arch/arm/boot/dts/sun8i-v3.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6ae8645ade50c29e161fc8a42a026a277e96e502 --- /dev/null +++ b/arch/arm/boot/dts/sun8i-v3.dtsi @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2019 Icenowy Zheng + */ + +#include "sun8i-v3s.dtsi" + +&ccu { + compatible = "allwinner,sun8i-v3-ccu"; +}; + +&pio { + compatible = "allwinner,sun8i-v3-pinctrl"; +}; diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s.dtsi index d7aef128acb37d53035b5857fba3f3d845fe10dc..23ba56df38f7341ac9caa3d0af0daa6f191108ee 100644 --- a/arch/arm/boot/dts/sun8i-v3s.dtsi +++ b/arch/arm/boot/dts/sun8i-v3s.dtsi @@ -106,10 +106,10 @@ display_clocks: clock@1000000 { compatible = "allwinner,sun8i-v3s-de2-clk"; reg = <0x01000000 0x100000>; - clocks = <&ccu CLK_DE>, - <&ccu CLK_BUS_DE>; - clock-names = "mod", - "bus"; + clocks = <&ccu CLK_BUS_DE>, + <&ccu CLK_DE>; + clock-names = "bus", + "mod"; resets = <&ccu RST_BUS_DE>; #clock-cells = <1>; #reset-cells = <1>; @@ -327,10 +327,11 @@ }; timer@1c20c00 { - compatible = "allwinner,sun4i-a10-timer"; + compatible = "allwinner,sun8i-v3s-timer"; reg = <0x01c20c00 0xa0>; interrupts = , - ; + , + ; clocks = <&osc24M>; }; @@ -338,6 +339,7 @@ compatible = "allwinner,sun6i-a31-wdt"; reg = <0x01c20ca0 0x20>; interrupts = ; + clocks = <&osc24M>; }; lradc: lradc@1c22800 { diff --git a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts index 18156ffa3ce954deb440413f32af1a459df67649..d3b337b043a15bd15059e66e5b91beed71b00b83 100644 --- a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts +++ b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts @@ -128,14 +128,10 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "rgmii"; phy-supply = <®_cldo1>; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &i2c3 { @@ -144,6 +140,12 @@ status = "okay"; }; +&mdio { + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + &mmc0 { pinctrl-names = "default"; pinctrl-0 = <&mmc0_pins>; diff --git a/arch/arm/boot/dts/sun9i-a80-optimus.dts b/arch/arm/boot/dts/sun9i-a80-optimus.dts index 2ed28d9e2787a6494323adbb2b6b59efc96d65ff..bbc6335e563141ee41ae97b6546c053ad77470cc 100644 --- a/arch/arm/boot/dts/sun9i-a80-optimus.dts +++ b/arch/arm/boot/dts/sun9i-a80-optimus.dts @@ -123,11 +123,13 @@ &gmac { pinctrl-names = "default"; pinctrl-0 = <&gmac_rgmii_pins>; - phy = <&phy1>; + phy-handle = <&phy1>; phy-mode = "rgmii"; phy-supply = <®_cldo1>; status = "okay"; +}; +&mdio { phy1: ethernet-phy@1 { reg = <1>; }; diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi index 0c1eec9000e3369a8edb207e4bb228f26b1a8ff1..c34d505c7efeaecb95cab277cb24e601441321ff 100644 --- a/arch/arm/boot/dts/sun9i-a80.dtsi +++ b/arch/arm/boot/dts/sun9i-a80.dtsi @@ -331,8 +331,12 @@ snps,fixed-burst; snps,force_sf_dma_mode; status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; + + mdio: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; }; ehci0: usb@a00000 { @@ -1167,7 +1171,7 @@ }; r_ir: ir@8002000 { - compatible = "allwinner,sun5i-a13-ir"; + compatible = "allwinner,sun6i-a31-ir"; interrupts = ; pinctrl-names = "default"; pinctrl-0 = <&r_ir_pins>; diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi index 84977d4eb97a918c8d76dbe905eb16634e09b5eb..eba190b3f9defdefa5a72558b73aa3a3b9090546 100644 --- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi +++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi @@ -114,10 +114,10 @@ display_clocks: clock@1000000 { /* compatible is in per SoC .dtsi file */ reg = <0x01000000 0x100000>; - clocks = <&ccu CLK_DE>, - <&ccu CLK_BUS_DE>; - clock-names = "mod", - "bus"; + clocks = <&ccu CLK_BUS_DE>, + <&ccu CLK_DE>; + clock-names = "bus", + "mod"; resets = <&ccu RST_BUS_DE>; #clock-cells = <1>; #reset-cells = <1>; @@ -484,7 +484,7 @@ }; timer@1c20c00 { - compatible = "allwinner,sun4i-a10-timer"; + compatible = "allwinner,sun8i-a23-timer"; reg = <0x01c20c00 0xa0>; interrupts = , ; @@ -574,6 +574,7 @@ compatible = "allwinner,sun6i-a31-wdt"; reg = <0x01c20ca0 0x20>; interrupts = ; + clocks = <&osc24M>; }; spdif: spdif@1c21000 { @@ -765,7 +766,7 @@ resets = <&ccu RST_BUS_HDMI1>; reset-names = "ctrl"; phys = <&hdmi_phy>; - phy-names = "hdmi-phy"; + phy-names = "phy"; status = "disabled"; ports { @@ -822,7 +823,7 @@ }; ir: ir@1f02000 { - compatible = "allwinner,sun5i-a13-ir"; + compatible = "allwinner,sun6i-a31-ir"; clocks = <&r_ccu CLK_APB0_IR>, <&r_ccu CLK_IR>; clock-names = "apb", "ir"; resets = <&r_ccu RST_APB0_IR>; diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi index d6a1fc269241e5c3e0c925f01a0298fa71a2e87e..dfae90adbb7caa393c0dc9f319c0c09ce6cf40e3 100644 --- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi +++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * ARM Ltd. Versatile Express * diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi index 8e57e15307e20a623abb1855b3df206af325db84..2e29d77904977f9af454809f979c7ddc85568b27 100644 --- a/arch/arm/boot/dts/vexpress-v2m.dtsi +++ b/arch/arm/boot/dts/vexpress-v2m.dtsi @@ -451,4 +451,4 @@ }; }; }; -}; \ No newline at end of file +}; diff --git a/arch/arm/boot/dts/vf610-zii-cfu1.dts b/arch/arm/boot/dts/vf610-zii-cfu1.dts index 9466913693ac71e91df8c2a914acdd1703beb348..28732249cfc0c93f4796131679d0b956c44b99af 100644 --- a/arch/arm/boot/dts/vf610-zii-cfu1.dts +++ b/arch/arm/boot/dts/vf610-zii-cfu1.dts @@ -207,7 +207,7 @@ }; &i2c0 { - clock-frequency = <400000>; + clock-frequency = <100000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c0>; status = "okay"; @@ -236,6 +236,18 @@ }; }; +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + watchdog@38 { + compatible = "zii,rave-wdt"; + reg = <0x38>; + }; +}; + &snvsrtc { status = "disabled"; }; @@ -304,6 +316,13 @@ >; }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + VF610_PAD_PTB16__I2C1_SCL 0x37ff + VF610_PAD_PTB17__I2C1_SDA 0x37ff + >; + }; + pinctrl_leds_debug: pinctrl-leds-debug { fsl,pins = < VF610_PAD_PTD3__GPIO_82 0x31c2 diff --git a/arch/arm/boot/dts/vf610-zii-scu4-aib.dts b/arch/arm/boot/dts/vf610-zii-scu4-aib.dts index d7019e89f5887407d822a3c98fadb31ce44c93c0..dc8a5f37a1ef2a6029bfcbd1d77e46d4b1936a7c 100644 --- a/arch/arm/boot/dts/vf610-zii-scu4-aib.dts +++ b/arch/arm/boot/dts/vf610-zii-scu4-aib.dts @@ -565,6 +565,8 @@ #gpio-cells = <2>; reg = <0x20>; gpio-controller; + interrupt-parent = <&gpio1>; + interrupts = <31 IRQ_TYPE_EDGE_FALLING>; }; lm75@4e { @@ -777,7 +779,8 @@ VF610_PAD_PTB15__I2C0_SDA 0x37ff >; }; - pinctrl_i2c1: i2c1grp { + + pinctrl_i2c1: i2c1grp { fsl,pins = < VF610_PAD_PTB16__I2C1_SCL 0x37ff VF610_PAD_PTB17__I2C1_SDA 0x37ff @@ -791,13 +794,6 @@ >; }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - VF610_PAD_PTA30__I2C3_SCL 0x37ff - VF610_PAD_PTA31__I2C3_SDA 0x37ff - >; - }; - pinctrl_leds_debug: pinctrl-leds-debug { fsl,pins = < VF610_PAD_PTB26__GPIO_96 0x31c2 diff --git a/arch/arm/boot/dts/vf610-zii-spb4.dts b/arch/arm/boot/dts/vf610-zii-spb4.dts index 9dde83ccb9d15f5c9f04787c76f65c369a2c4e7c..77e1484211e43a950a97d5313be47f48b874401a 100644 --- a/arch/arm/boot/dts/vf610-zii-spb4.dts +++ b/arch/arm/boot/dts/vf610-zii-spb4.dts @@ -316,13 +316,6 @@ >; }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - VF610_PAD_PTB16__I2C1_SCL 0x37ff - VF610_PAD_PTB17__I2C1_SDA 0x37ff - >; - }; - pinctrl_leds_debug: pinctrl-leds-debug { fsl,pins = < VF610_PAD_PTD3__GPIO_82 0x31c2 diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c index 60130bd7b182057e7acf4a106b9daadac59bc8d4..6edb961bd6c1d246872d227585a84c6af02df389 100644 --- a/arch/arm/common/scoop.c +++ b/arch/arm/common/scoop.c @@ -8,7 +8,7 @@ */ #include -#include +#include #include #include #include diff --git a/arch/arm/configs/acs5k_defconfig b/arch/arm/configs/acs5k_defconfig deleted file mode 100644 index bcb8bda09158cc398439118e04027359de9cb982..0000000000000000000000000000000000000000 --- a/arch/arm/configs/acs5k_defconfig +++ /dev/null @@ -1,77 +0,0 @@ -# CONFIG_SWAP is not set -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set -CONFIG_ARCH_KS8695=y -CONFIG_MACH_KS8695=y -CONFIG_MACH_DSM320=y -CONFIG_MACH_ACS5K=y -# CONFIG_ARM_THUMB is not set -CONFIG_PCI=y -CONFIG_PCI_DEBUG=y -CONFIG_PCCARD=y -CONFIG_YENTA=y -CONFIG_AEABI=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20410000,3145728 root=/dev/ram0 rw" -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IPV6 is not set -CONFIG_MTD=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_ADV_OPTIONS=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_ARM_KS8695_ETHER=y -CONFIG_PRISM54=m -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_KS8695=y -CONFIG_SERIAL_KS8695_CONSOLE=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_GPIO=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_PCA953X=y -CONFIG_WATCHDOG=y -CONFIG_KS8695_WATCHDOG=y -# CONFIG_VGA_CONSOLE is not set -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_PCF8563=y -CONFIG_EXT2_FS=y -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y -CONFIG_JFFS2_SUMMARY=y -CONFIG_JFFS2_COMPRESSION_OPTIONS=y -CONFIG_JFFS2_RUBIN=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_ROOT_NFS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_MUTEXES=y -# CONFIG_FTRACE is not set -CONFIG_DEBUG_USER=y -CONFIG_DEBUG_LL=y diff --git a/arch/arm/configs/acs5k_tiny_defconfig b/arch/arm/configs/acs5k_tiny_defconfig deleted file mode 100644 index e802cdebfd0be35ac251d5550896c17c5deba0bf..0000000000000000000000000000000000000000 --- a/arch/arm/configs/acs5k_tiny_defconfig +++ /dev/null @@ -1,69 +0,0 @@ -# CONFIG_SWAP is not set -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set -CONFIG_ARCH_KS8695=y -CONFIG_MACH_ACS5K=y -# CONFIG_ARM_THUMB is not set -CONFIG_AEABI=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="console=ttyAM0,115200 init=/bin/sh" -CONFIG_FPE_NWFPE=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_IPV6 is not set -CONFIG_MTD=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_ADV_OPTIONS=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP=y -# CONFIG_BLK_DEV is not set -CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_ARM_KS8695_ETHER=y -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_KS8695=y -CONFIG_SERIAL_KS8695_CONSOLE=y -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_GPIO=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_PCA953X=y -# CONFIG_HWMON is not set -CONFIG_WATCHDOG=y -CONFIG_KS8695_WATCHDOG=y -# CONFIG_VGA_CONSOLE is not set -# CONFIG_USB_SUPPORT is not set -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_PCF8563=y -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y -CONFIG_JFFS2_SUMMARY=y -CONFIG_JFFS2_COMPRESSION_OPTIONS=y -CONFIG_JFFS2_RUBIN=y -CONFIG_SQUASHFS=y -# CONFIG_NETWORK_FILESYSTEMS is not set -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_MUTEXES=y -# CONFIG_FTRACE is not set -CONFIG_DEBUG_USER=y diff --git a/arch/arm/configs/aspeed_g4_defconfig b/arch/arm/configs/aspeed_g4_defconfig index 019828d7b25178d6e289303da103c176b2ad777a..1857df992484269f86683abc0a55e81d7ad42200 100644 --- a/arch/arm/configs/aspeed_g4_defconfig +++ b/arch/arm/configs/aspeed_g4_defconfig @@ -20,20 +20,11 @@ CONFIG_PERF_EVENTS=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB=y CONFIG_SLAB_FREELIST_RANDOM=y -CONFIG_JUMP_LABEL=y -CONFIG_STRICT_KERNEL_RWX=y -CONFIG_GCC_PLUGINS=y -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_BLK_DEBUG_FS is not set -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_MQ_IOSCHED_DEADLINE is not set -# CONFIG_MQ_IOSCHED_KYBER is not set # CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_ASPEED=y CONFIG_MACH_ASPEED_G4=y CONFIG_VMSPLIT_2G=y CONFIG_AEABI=y -# CONFIG_COMPACTION is not set CONFIG_UACCESS_WITH_MEMCPY=y CONFIG_SECCOMP=y # CONFIG_ATAGS is not set @@ -42,7 +33,15 @@ CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_ARM_APPENDED_DTB=y CONFIG_ARM_ATAG_DTB_COMPAT=y CONFIG_KEXEC=y +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_JUMP_LABEL=y +CONFIG_STRICT_KERNEL_RWX=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEBUG_FS is not set +# CONFIG_MQ_IOSCHED_DEADLINE is not set +# CONFIG_MQ_IOSCHED_KYBER is not set # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_COMPACTION is not set CONFIG_NET=y CONFIG_PACKET=y CONFIG_PACKET_DIAG=y @@ -51,18 +50,11 @@ CONFIG_UNIX_DIAG=y CONFIG_INET=y CONFIG_IP_MULTICAST=y CONFIG_SYN_COOKIES=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set # CONFIG_INET_DIAG is not set -# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET6_XFRM_MODE_TUNNEL is not set -# CONFIG_INET6_XFRM_MODE_BEET is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_ADVANCED is not set CONFIG_VLAN_8021Q=y CONFIG_NET_NCSI=y -CONFIG_BPF_STREAM_PARSER=y # CONFIG_WIRELESS is not set CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y @@ -140,7 +132,6 @@ CONFIG_ASPEED_BT_IPMI_BMC=y CONFIG_HW_RANDOM_TIMERIOMEM=y # CONFIG_I2C_COMPAT is not set CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MUX=y CONFIG_I2C_MUX_PCA9541=y CONFIG_I2C_MUX_PCA954x=y CONFIG_I2C_ASPEED=y @@ -204,6 +195,7 @@ CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_EDAC=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=y CONFIG_RTC_DRV_PCF8523=y @@ -218,13 +210,13 @@ CONFIG_IIO=y CONFIG_ASPEED_ADC=y CONFIG_MAX1363=y CONFIG_BMP280=y +CONFIG_RAS=y CONFIG_FSI=y CONFIG_FSI_MASTER_GPIO=y CONFIG_FSI_MASTER_HUB=y CONFIG_FSI_MASTER_AST_CF=y CONFIG_FSI_SCOM=y CONFIG_FSI_SBEFIFO=y -CONFIG_FIRMWARE_MEMMAP=y CONFIG_FANOTIFY=y CONFIG_OVERLAY_FS=y CONFIG_TMPFS=y @@ -237,6 +229,17 @@ CONFIG_SQUASHFS=y CONFIG_SQUASHFS_XZ=y CONFIG_SQUASHFS_ZSTD=y # CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_HARDENED_USERCOPY=y +CONFIG_FORTIFY_SOURCE=y +# CONFIG_CRYPTO_ECHAINIV is not set +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_USER_API_HASH=y +# CONFIG_CRYPTO_HW is not set +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_SPARC is not set CONFIG_PRINTK_TIME=y CONFIG_DYNAMIC_DEBUG=y CONFIG_DEBUG_INFO=y @@ -255,14 +258,3 @@ CONFIG_FUNCTION_TRACER=y # CONFIG_RUNTIME_TESTING_MENU is not set CONFIG_DEBUG_WX=y CONFIG_DEBUG_USER=y -CONFIG_HARDENED_USERCOPY=y -CONFIG_FORTIFY_SOURCE=y -# CONFIG_CRYPTO_ECHAINIV is not set -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_SHA256=y -CONFIG_CRYPTO_USER_API_HASH=y -# CONFIG_CRYPTO_HW is not set -# CONFIG_XZ_DEC_X86 is not set -# CONFIG_XZ_DEC_POWERPC is not set -# CONFIG_XZ_DEC_IA64 is not set -# CONFIG_XZ_DEC_SPARC is not set diff --git a/arch/arm/configs/aspeed_g5_defconfig b/arch/arm/configs/aspeed_g5_defconfig index 28fe392c7dfa52318162c21fc000fcb37b2620ad..597536cc9573de066a8d3237d4b0513d8b9ae142 100644 --- a/arch/arm/configs/aspeed_g5_defconfig +++ b/arch/arm/configs/aspeed_g5_defconfig @@ -20,29 +20,33 @@ CONFIG_PERF_EVENTS=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB=y CONFIG_SLAB_FREELIST_RANDOM=y -CONFIG_JUMP_LABEL=y -CONFIG_STRICT_KERNEL_RWX=y -CONFIG_GCC_PLUGINS=y -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_BLK_DEBUG_FS is not set -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_MQ_IOSCHED_DEADLINE is not set -# CONFIG_MQ_IOSCHED_KYBER is not set CONFIG_ARCH_MULTI_V6=y -# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_ASPEED=y CONFIG_MACH_ASPEED_G5=y +CONFIG_MACH_ASPEED_G6=y # CONFIG_CACHE_L2X0 is not set +CONFIG_SMP=y +# CONFIG_ARM_CPU_TOPOLOGY is not set CONFIG_VMSPLIT_2G=y -# CONFIG_COMPACTION is not set +CONFIG_NR_CPUS=2 +CONFIG_HIGHMEM=y CONFIG_UACCESS_WITH_MEMCPY=y CONFIG_SECCOMP=y # CONFIG_ATAGS is not set CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_KEXEC=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_JUMP_LABEL=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEBUG_FS is not set +# CONFIG_MQ_IOSCHED_DEADLINE is not set +# CONFIG_MQ_IOSCHED_KYBER is not set # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -# CONFIG_SUSPEND is not set +# CONFIG_COMPACTION is not set CONFIG_NET=y CONFIG_PACKET=y CONFIG_PACKET_DIAG=y @@ -50,19 +54,20 @@ CONFIG_UNIX=y CONFIG_UNIX_DIAG=y CONFIG_INET=y CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y CONFIG_SYN_COOKIES=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set # CONFIG_INET_DIAG is not set -# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET6_XFRM_MODE_TUNNEL is not set -# CONFIG_INET6_XFRM_MODE_BEET is not set +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_NETFILTER=y # CONFIG_NETFILTER_ADVANCED is not set CONFIG_VLAN_8021Q=y CONFIG_NET_NCSI=y -CONFIG_BPF_STREAM_PARSER=y # CONFIG_WIRELESS is not set CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y @@ -145,6 +150,7 @@ CONFIG_I2C_MUX_PCA9541=y CONFIG_I2C_MUX_PCA954x=y CONFIG_I2C_ASPEED=y CONFIG_I2C_FSI=y +CONFIG_SPI=y CONFIG_GPIOLIB=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_ASPEED=y @@ -195,6 +201,10 @@ CONFIG_USB_CONFIGFS_F_LB_SS=y CONFIG_USB_CONFIGFS_F_FS=y CONFIG_USB_CONFIGFS_F_HID=y CONFIG_USB_CONFIGFS_F_PRINTER=y +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ASPEED=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_CLASS_FLASH=y @@ -228,7 +238,6 @@ CONFIG_FSI_MASTER_HUB=y CONFIG_FSI_MASTER_AST_CF=y CONFIG_FSI_SCOM=y CONFIG_FSI_SBEFIFO=y -CONFIG_FIRMWARE_MEMMAP=y CONFIG_FANOTIFY=y CONFIG_OVERLAY_FS=y CONFIG_TMPFS=y @@ -241,6 +250,16 @@ CONFIG_SQUASHFS=y CONFIG_SQUASHFS_XZ=y CONFIG_SQUASHFS_ZSTD=y # CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_HARDENED_USERCOPY=y +CONFIG_FORTIFY_SOURCE=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_USER_API_HASH=y +# CONFIG_CRYPTO_HW is not set +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_SPARC is not set CONFIG_PRINTK_TIME=y CONFIG_DYNAMIC_DEBUG=y CONFIG_DEBUG_INFO=y @@ -259,14 +278,3 @@ CONFIG_FUNCTION_TRACER=y # CONFIG_RUNTIME_TESTING_MENU is not set CONFIG_DEBUG_WX=y CONFIG_DEBUG_USER=y -CONFIG_HARDENED_USERCOPY=y -CONFIG_FORTIFY_SOURCE=y -# CONFIG_CRYPTO_ECHAINIV is not set -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_SHA256=y -CONFIG_CRYPTO_USER_API_HASH=y -# CONFIG_CRYPTO_HW is not set -# CONFIG_XZ_DEC_X86 is not set -# CONFIG_XZ_DEC_POWERPC is not set -# CONFIG_XZ_DEC_IA64 is not set -# CONFIG_XZ_DEC_SPARC is not set diff --git a/arch/arm/configs/bcm2835_defconfig b/arch/arm/configs/bcm2835_defconfig index dcf7610cfe553bf86a36a60e021d4dbf097b05f6..519ff58e67b3057b4b506f8e0a5b9c964a527eb8 100644 --- a/arch/arm/configs/bcm2835_defconfig +++ b/arch/arm/configs/bcm2835_defconfig @@ -37,6 +37,14 @@ CONFIG_CMA=y CONFIG_SECCOMP=y CONFIG_KEXEC=y CONFIG_CRASH_DUMP=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPUFREQ_DT=y +CONFIG_ARM_RASPBERRYPI_CPUFREQ=y CONFIG_VFP=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set # CONFIG_SUSPEND is not set @@ -132,6 +140,7 @@ CONFIG_DMA_BCM2835=y CONFIG_STAGING=y CONFIG_SND_BCM2835=m CONFIG_VIDEO_BCM2835=m +CONFIG_CLK_RASPBERRYPI=y CONFIG_MAILBOX=y CONFIG_BCM2835_MBOX=y # CONFIG_IOMMU_SUPPORT is not set diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig index 9a32a8c0f8735a93d36760ee2b8fbd834eb832db..b34970ce6b314b669ebfb7910d0cd224988ed0ef 100644 --- a/arch/arm/configs/davinci_all_defconfig +++ b/arch/arm/configs/davinci_all_defconfig @@ -17,6 +17,9 @@ CONFIG_MODVERSIONS=y CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_DEADLINE is not set # CONFIG_IOSCHED_CFQ is not set +CONFIG_ARCH_MULTIPLATFORM=y +CONFIG_ARCH_MULTI_V7=n +CONFIG_ARCH_MULTI_V5=y CONFIG_ARCH_DAVINCI=y CONFIG_ARCH_DAVINCI_DM644x=y CONFIG_ARCH_DAVINCI_DM355=y @@ -129,9 +132,11 @@ CONFIG_SPI=y CONFIG_SPI_DAVINCI=m CONFIG_PINCTRL_DA850_PUPD=m CONFIG_PINCTRL_SINGLE=y +CONFIG_GPIOLIB=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_PCA953X=y CONFIG_GPIO_PCA953X_IRQ=y +CONFIG_RESET_CONTROLLER=y CONFIG_POWER_RESET=y CONFIG_POWER_RESET_GPIO=y CONFIG_SYSCON_REBOOT_MODE=m diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig index 2e6a863d25aa0c904b45560200f44af963f877cf..08db1c83eb2daa0a974809db8dad8472d16dec22 100644 --- a/arch/arm/configs/exynos_defconfig +++ b/arch/arm/configs/exynos_defconfig @@ -92,9 +92,12 @@ CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_CRYPTOLOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y +CONFIG_ATA=y +# CONFIG_SATA_PMP is not set +CONFIG_SATA_AHCI_PLATFORM=y +# CONFIG_ATA_SFF is not set CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=m diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index a53b29251ed4404dbafac203037acdb00540e56b..9bfffbe22d53cd9732b98415477aa61bd97c430e 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -60,6 +60,7 @@ CONFIG_ARM_IMX6Q_CPUFREQ=y CONFIG_ARM_IMX_CPUFREQ_DT=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y +CONFIG_ARM_PSCI_CPUIDLE=y CONFIG_VFP=y CONFIG_NEON=y CONFIG_PM_DEBUG=y @@ -272,6 +273,7 @@ CONFIG_VIDEO_IMX_PXP=y CONFIG_VIDEO_ADV7180=m CONFIG_VIDEO_OV2680=m CONFIG_VIDEO_OV5640=m +CONFIG_VIDEO_OV5645=m CONFIG_IMX_IPUV3_CORE=y CONFIG_DRM=y CONFIG_DRM_PANEL_LVDS=y diff --git a/arch/arm/configs/iop13xx_defconfig b/arch/arm/configs/iop13xx_defconfig deleted file mode 100644 index 30cdb287e1b404590e8c7ecdfa590866fc29b023..0000000000000000000000000000000000000000 --- a/arch/arm/configs/iop13xx_defconfig +++ /dev/null @@ -1,118 +0,0 @@ -# CONFIG_LOCALVERSION_AUTO is not set -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODVERSIONS=y -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_IOSCHED_CFQ is not set -CONFIG_ARCH_IOP13XX=y -CONFIG_MACH_IQ81340SC=y -CONFIG_MACH_IQ81340MC=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="ip=bootp root=nfs console=ttyS0,115200 nfsroot=,tcp,v3,wsize=8192,rsize=8192" -CONFIG_FPE_NWFPE=y -CONFIG_BINFMT_AOUT=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_NET_KEY=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IPV6=y -# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET6_XFRM_MODE_TUNNEL is not set -# CONFIG_INET6_XFRM_MODE_BEET is not set -# CONFIG_IPV6_SIT is not set -CONFIG_MTD=y -CONFIG_MTD_REDBOOT_PARTS=y -CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y -CONFIG_MTD_REDBOOT_PARTS_READONLY=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_ADV_OPTIONS=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_PHYSMAP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=2 -CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_SCSI=y -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_ISCSI_ATTRS=y -CONFIG_MD=y -CONFIG_BLK_DEV_MD=y -CONFIG_MD_RAID0=y -CONFIG_MD_RAID1=y -CONFIG_MD_RAID10=y -CONFIG_MD_RAID456=y -CONFIG_BLK_DEV_DM=y -CONFIG_NETDEVICES=y -CONFIG_E1000=y -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=2 -CONFIG_HW_RANDOM=y -CONFIG_I2C=y -CONFIG_I2C_IOP3XX=y -# CONFIG_VGA_CONSOLE is not set -CONFIG_DMADEVICES=y -CONFIG_INTEL_IOP_ADMA=y -CONFIG_EXT2_FS=y -CONFIG_EXT3_FS=y -CONFIG_TMPFS=y -CONFIG_ECRYPT_FS=y -CONFIG_JFFS2_FS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_ROOT_NFS=y -CONFIG_NFSD=y -CONFIG_NFSD_V3=y -CONFIG_SMB_FS=m -CONFIG_CIFS=m -CONFIG_PARTITION_ADVANCED=y -CONFIG_NLS=y -CONFIG_DEBUG_USER=y -CONFIG_KEYS=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_LRW=y -CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_MD4=y -CONFIG_CRYPTO_MICHAEL_MIC=y -CONFIG_CRYPTO_SHA1=y -CONFIG_CRYPTO_SHA256=y -CONFIG_CRYPTO_SHA512=y -CONFIG_CRYPTO_TGR192=y -CONFIG_CRYPTO_WP512=y -CONFIG_CRYPTO_AES=y -CONFIG_CRYPTO_ANUBIS=y -CONFIG_CRYPTO_ARC4=y -CONFIG_CRYPTO_BLOWFISH=y -CONFIG_CRYPTO_CAST5=y -CONFIG_CRYPTO_CAST6=y -CONFIG_CRYPTO_DES=y -CONFIG_CRYPTO_KHAZAD=y -CONFIG_CRYPTO_SERPENT=y -CONFIG_CRYPTO_TEA=y -CONFIG_CRYPTO_TWOFISH=y -CONFIG_CRYPTO_DEFLATE=y -CONFIG_CRC_CCITT=y -CONFIG_LIBCRC32C=y diff --git a/arch/arm/configs/iop33x_defconfig b/arch/arm/configs/iop33x_defconfig deleted file mode 100644 index 089eca43214adba35a5cfc97f692894df378a045..0000000000000000000000000000000000000000 --- a/arch/arm/configs/iop33x_defconfig +++ /dev/null @@ -1,85 +0,0 @@ -CONFIG_SYSVIPC=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_KALLSYMS_ALL=y -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_ARCH_IOP33X=y -CONFIG_ARCH_IQ80331=y -CONFIG_MACH_IQ80332=y -# CONFIG_ARM_THUMB is not set -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp cachepolicy=writealloc iop3xx_init_atu=y" -CONFIG_FPE_NWFPE=y -CONFIG_BINFMT_AOUT=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IPV6=y -# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET6_XFRM_MODE_TUNNEL is not set -# CONFIG_INET6_XFRM_MODE_BEET is not set -# CONFIG_IPV6_SIT is not set -CONFIG_MTD=y -CONFIG_MTD_REDBOOT_PARTS=y -CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y -CONFIG_MTD_REDBOOT_PARTS_READONLY=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_ADV_OPTIONS=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_PHYSMAP=y -CONFIG_BLK_DEV_NBD=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_SCSI=y -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_SG=y -CONFIG_MD=y -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=y -CONFIG_MD_RAID0=y -CONFIG_MD_RAID1=y -CONFIG_MD_RAID456=y -CONFIG_BLK_DEV_DM=y -CONFIG_NETDEVICES=y -CONFIG_E1000=y -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_HW_RANDOM=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_IOP3XX=y -# CONFIG_VGA_CONSOLE is not set -CONFIG_DMADEVICES=y -CONFIG_INTEL_IOP_ADMA=y -CONFIG_NET_DMA=y -CONFIG_EXT2_FS=y -CONFIG_EXT3_FS=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_ROOT_NFS=y -CONFIG_NFSD=y -CONFIG_NFSD_V3=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_USER=y -CONFIG_DEBUG_LL=y -CONFIG_DEBUG_LL_UART_8250=y -# CONFIG_CRYPTO_ANSI_CPRNG is not set -# CONFIG_CRC32 is not set diff --git a/arch/arm/configs/ks8695_defconfig b/arch/arm/configs/ks8695_defconfig deleted file mode 100644 index df62d4dfbbb721b79977fb2385130e68b4d52838..0000000000000000000000000000000000000000 --- a/arch/arm/configs/ks8695_defconfig +++ /dev/null @@ -1,67 +0,0 @@ -# CONFIG_SWAP is not set -CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set -CONFIG_ARCH_KS8695=y -CONFIG_MACH_KS8695=y -CONFIG_MACH_DSM320=y -# CONFIG_ARM_THUMB is not set -CONFIG_PCI=y -CONFIG_PCI_DEBUG=y -CONFIG_PCCARD=y -CONFIG_YENTA=y -CONFIG_AEABI=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20410000,3145728 root=/dev/ram0 rw" -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IPV6 is not set -CONFIG_MTD=y -CONFIG_MTD_REDBOOT_PARTS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_PHYSMAP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -CONFIG_PRISM54=m -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_KS8695=y -CONFIG_SERIAL_KS8695_CONSOLE=y -# CONFIG_HWMON is not set -# CONFIG_VGA_CONSOLE is not set -CONFIG_EXT2_FS=y -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y -CONFIG_JFFS2_SUMMARY=y -CONFIG_JFFS2_COMPRESSION_OPTIONS=y -CONFIG_JFFS2_RUBIN=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_ROOT_NFS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_MUTEXES=y -# CONFIG_FTRACE is not set -CONFIG_DEBUG_USER=y -CONFIG_DEBUG_LL=y diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_defconfig index 0cdc6c7974b340fe704e4d2edb38c1ffba7ee697..09deb57db942d0075d5eba7da27b828bd46ebb78 100644 --- a/arch/arm/configs/lpc32xx_defconfig +++ b/arch/arm/configs/lpc32xx_defconfig @@ -12,6 +12,7 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL_SYSCALL=y CONFIG_EMBEDDED=y CONFIG_SLAB=y +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_LPC32XX=y CONFIG_AEABI=y CONFIG_ZBOOT_ROM_TEXT=0x0 @@ -93,6 +94,7 @@ CONFIG_SERIAL_HS_LPC32XX_CONSOLE=y # CONFIG_HW_RANDOM is not set CONFIG_I2C_CHARDEV=y CONFIG_I2C_PNX=y +CONFIG_GPIO_LPC32XX=y CONFIG_SPI=y CONFIG_SPI_PL022=y CONFIG_GPIO_SYSFS=y diff --git a/arch/arm/configs/multi_v5_defconfig b/arch/arm/configs/multi_v5_defconfig index 201237002c65f2d69a260d3498aacaa79cceecb7..bd018873e47a886671aa5e39649b9236d184509c 100644 --- a/arch/arm/configs/multi_v5_defconfig +++ b/arch/arm/configs/multi_v5_defconfig @@ -14,6 +14,18 @@ CONFIG_ARCH_ASPEED=y CONFIG_MACH_ASPEED_G4=y CONFIG_ARCH_AT91=y CONFIG_SOC_AT91SAM9=y +CONFIG_ARCH_DAVINCI=y +CONFIG_ARCH_DAVINCI_DM644x=y +CONFIG_ARCH_DAVINCI_DM355=y +CONFIG_ARCH_DAVINCI_DM646x=y +CONFIG_ARCH_DAVINCI_DA830=y +CONFIG_ARCH_DAVINCI_DA850=y +CONFIG_ARCH_DAVINCI_DM365=y +CONFIG_MACH_SFFSDR=y +CONFIG_MACH_NEUROS_OSD2=y +CONFIG_MACH_DM355_LEOPARD=y +CONFIG_MACH_MITYOMAPL138=y +CONFIG_MACH_OMAPL138_HAWKBOARD=y CONFIG_ARCH_MXC=y CONFIG_MACH_MX21ADS=y CONFIG_MACH_MX27ADS=y diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 6a40bc2ef2718bf788a908e989ebd61ec14e3edc..13ba532869017d3c969b005bfcf5948a1fbc4baf 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -9,6 +9,8 @@ CONFIG_ARCH_VIRT=y CONFIG_ARCH_ALPINE=y CONFIG_ARCH_ARTPEC=y CONFIG_MACH_ARTPEC6=y +CONFIG_ARCH_ASPEED=y +CONFIG_MACH_ASPEED_G6=y CONFIG_ARCH_AT91=y CONFIG_SOC_SAMA5D2=y CONFIG_SOC_SAMA5D3=y @@ -102,6 +104,7 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y CONFIG_CPUFREQ_DT=y CONFIG_ARM_IMX6Q_CPUFREQ=y +CONFIG_ARM_RASPBERRYPI_CPUFREQ=y CONFIG_QORIQ_CPUFREQ=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y @@ -197,7 +200,9 @@ CONFIG_MTD_NAND_GPMI_NAND=y CONFIG_MTD_NAND_BRCMNAND=y CONFIG_MTD_NAND_VF610_NFC=y CONFIG_MTD_NAND_DAVINCI=y +CONFIG_MTD_NAND_STM32_FMC2=y CONFIG_MTD_SPI_NOR=y +CONFIG_SPI_ASPEED_SMC=m CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y @@ -304,7 +309,11 @@ CONFIG_INPUT_STPMIC1_ONKEY=y CONFIG_SERIO_AMBAKMI=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=5 +CONFIG_SERIAL_8250_RUNTIME_UARTS=5 CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_ASPEED_VUART=m CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_8250_BCM2835AUX=y CONFIG_SERIAL_8250_DW=y @@ -349,6 +358,8 @@ CONFIG_SERIAL_STM32=y CONFIG_SERIAL_STM32_CONSOLE=y CONFIG_SERIAL_DEV_BUS=y CONFIG_VIRTIO_CONSOLE=y +CONFIG_ASPEED_KCS_IPMI_BMC=m +CONFIG_ASPEED_BT_IPMI_BMC=m CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_ST=y CONFIG_TCG_TPM=m @@ -358,6 +369,7 @@ CONFIG_I2C_ARB_GPIO_CHALLENGE=m CONFIG_I2C_MUX_PCA954x=y CONFIG_I2C_MUX_PINCTRL=y CONFIG_I2C_DEMUX_PINCTRL=y +CONFIG_I2C_ASPEED=m CONFIG_I2C_AT91=m CONFIG_I2C_BCM2835=y CONFIG_I2C_CADENCE=y @@ -403,6 +415,7 @@ CONFIG_SPI_SH_MSIOF=m CONFIG_SPI_SH_HSPI=y CONFIG_SPI_SIRF=y CONFIG_SPI_STM32=m +CONFIG_SPI_STM32_QSPI=m CONFIG_SPI_SUN4I=y CONFIG_SPI_SUN6I=y CONFIG_SPI_TEGRA114=y @@ -461,6 +474,7 @@ CONFIG_CHARGER_MAX77693=m CONFIG_CHARGER_MAX8997=m CONFIG_CHARGER_MAX8998=m CONFIG_CHARGER_TPS65090=y +CONFIG_SENSORS_ASPEED=m CONFIG_SENSORS_IIO_HWMON=y CONFIG_SENSORS_LM90=y CONFIG_SENSORS_LM95245=y @@ -559,7 +573,7 @@ CONFIG_REGULATOR_MAX8997=m CONFIG_REGULATOR_MAX8998=m CONFIG_REGULATOR_MAX77686=y CONFIG_REGULATOR_MAX77693=m -CONFIG_REGULATOR_MAX77802=m +CONFIG_REGULATOR_MAX77802=y CONFIG_REGULATOR_PALMAS=y CONFIG_REGULATOR_PBIAS=y CONFIG_REGULATOR_PWM=y @@ -569,6 +583,7 @@ CONFIG_REGULATOR_RK808=y CONFIG_REGULATOR_RN5T618=y CONFIG_REGULATOR_S2MPS11=y CONFIG_REGULATOR_S5M8767=y +CONFIG_REGULATOR_STM32_BOOSTER=m CONFIG_REGULATOR_STM32_VREFBUF=m CONFIG_REGULATOR_STPMIC1=y CONFIG_REGULATOR_TI_ABB=y @@ -590,6 +605,7 @@ CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=m CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_ASPEED=m CONFIG_VIDEO_STM32_DCMI=m CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS=m CONFIG_VIDEO_S5P_FIMC=m @@ -634,6 +650,7 @@ CONFIG_DRM_ATMEL_HLCDC=m CONFIG_DRM_RCAR_DU=m CONFIG_DRM_RCAR_LVDS=y CONFIG_DRM_SUN4I=m +CONFIG_DRM_MSM=m CONFIG_DRM_FSL_DCU=m CONFIG_DRM_TEGRA=y CONFIG_DRM_STM=m @@ -659,6 +676,7 @@ CONFIG_DRM_MXSFB=m CONFIG_DRM_PL111=m CONFIG_DRM_LIMA=m CONFIG_DRM_PANFROST=m +CONFIG_DRM_ASPEED_GFX=m CONFIG_FB_EFI=y CONFIG_FB_WM8505=y CONFIG_FB_SH_MOBILE_LCDC=y @@ -758,6 +776,7 @@ CONFIG_USB_MXS_PHY=y CONFIG_USB_GADGET=y CONFIG_USB_FSL_USB2=y CONFIG_USB_RENESAS_USBHS_UDC=m +CONFIG_USB_ASPEED_VHUB=m CONFIG_USB_CONFIGFS=m CONFIG_USB_CONFIGFS_SERIAL=y CONFIG_USB_CONFIGFS_ACM=y @@ -866,6 +885,7 @@ CONFIG_RTC_DRV_TEGRA=y CONFIG_RTC_DRV_ST_LPC=y CONFIG_RTC_DRV_STM32=y CONFIG_RTC_DRV_CPCAP=m +CONFIG_RTC_DRV_ASPEED=m CONFIG_DMADEVICES=y CONFIG_AT_HDMAC=y CONFIG_AT_XDMAC=y @@ -902,6 +922,7 @@ CONFIG_STAGING_BOARD=y CONFIG_COMMON_CLK_MAX77686=y CONFIG_COMMON_CLK_RK808=m CONFIG_COMMON_CLK_S2MPS11=m +CONFIG_CLK_RASPBERRYPI=y CONFIG_COMMON_CLK_QCOM=y CONFIG_QCOM_CLK_RPM=y CONFIG_APQ_MMCC_8084=y @@ -915,6 +936,9 @@ CONFIG_TEGRA_IOMMU_SMMU=y CONFIG_REMOTEPROC=m CONFIG_ST_REMOTEPROC=m CONFIG_RPMSG_VIRTIO=m +CONFIG_ASPEED_LPC_CTRL=m +CONFIG_ASPEED_LPC_SNOOP=m +CONFIG_ASPEED_P2A_CTRL=m CONFIG_RASPBERRYPI_POWER=y CONFIG_QCOM_GSBI=y CONFIG_QCOM_PM=y @@ -947,6 +971,7 @@ CONFIG_ARM_TEGRA_DEVFREQ=m CONFIG_TI_AEMIF=y CONFIG_IIO=y CONFIG_IIO_SW_TRIGGER=y +CONFIG_ASPEED_ADC=m CONFIG_AT91_ADC=m CONFIG_AT91_SAMA5D2_ADC=m CONFIG_BERLIN2_ADC=m diff --git a/arch/arm/configs/nuc910_defconfig b/arch/arm/configs/nuc910_defconfig deleted file mode 100644 index 63dba62c3326084349d78e86bf58dd9476e67caf..0000000000000000000000000000000000000000 --- a/arch/arm/configs/nuc910_defconfig +++ /dev/null @@ -1,51 +0,0 @@ -# CONFIG_LOCALVERSION_AUTO is not set -CONFIG_SYSVIPC=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_RELAY=y -CONFIG_USER_NS=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_KALLSYMS_EXTRA_PASS=y -CONFIG_SLAB=y -CONFIG_ARCH_W90X900=y -CONFIG_PREEMPT=y -CONFIG_AEABI=y -CONFIG_CMDLINE="root=/dev/ram0 console=ttyS0,115200n8 rdinit=/sbin/init mem=64M" -CONFIG_KEXEC=y -CONFIG_FPE_NWFPE=y -CONFIG_MTD=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=16384 -CONFIG_SCSI=y -# CONFIG_SCSI_PROC_FS is not set -CONFIG_BLK_DEV_SD=y -# CONFIG_SCSI_LOWLEVEL is not set -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=1 -# CONFIG_LEGACY_PTYS is not set -# CONFIG_HW_RANDOM is not set -# CONFIG_HWMON is not set -# CONFIG_VGA_CONSOLE is not set -CONFIG_USB=y -CONFIG_USB_MON=y -CONFIG_USB_STORAGE=y -# CONFIG_DNOTIFY is not set -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_ROMFS_FS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ISO8859_1=y -# CONFIG_ENABLE_MUST_CHECK is not set -CONFIG_DEBUG_FS=y -# CONFIG_CRC32 is not set diff --git a/arch/arm/configs/nuc950_defconfig b/arch/arm/configs/nuc950_defconfig deleted file mode 100644 index cb5a8788ebe8832806b0b96608957935aeab79dc..0000000000000000000000000000000000000000 --- a/arch/arm/configs/nuc950_defconfig +++ /dev/null @@ -1,67 +0,0 @@ -# CONFIG_LOCALVERSION_AUTO is not set -CONFIG_SYSVIPC=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_RELAY=y -CONFIG_USER_NS=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_KALLSYMS_EXTRA_PASS=y -CONFIG_SLAB=y -CONFIG_ARCH_W90X900=y -# CONFIG_MACH_W90P910EVB is not set -CONFIG_MACH_W90P950EVB=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_PREEMPT=y -CONFIG_AEABI=y -CONFIG_CMDLINE="root=/dev/ram0 console=ttyS0,115200n8 rdinit=/sbin/init mem=64M" -CONFIG_KEXEC=y -CONFIG_FPE_NWFPE=y -CONFIG_BINFMT_AOUT=y -CONFIG_BINFMT_MISC=y -CONFIG_MTD=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=16384 -CONFIG_SCSI=y -# CONFIG_SCSI_PROC_FS is not set -CONFIG_BLK_DEV_SD=y -# CONFIG_SCSI_LOWLEVEL is not set -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=1 -# CONFIG_LEGACY_PTYS is not set -# CONFIG_HW_RANDOM is not set -# CONFIG_HWMON is not set -CONFIG_FB=y -CONFIG_FB_NUC900=y -CONFIG_GPM1040A0_320X240=y -CONFIG_FB_NUC900_DEBUG=y -# CONFIG_VGA_CONSOLE is not set -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y -CONFIG_FONTS=y -CONFIG_FONT_8x16=y -CONFIG_LOGO=y -# CONFIG_LOGO_LINUX_MONO is not set -# CONFIG_LOGO_LINUX_VGA16 is not set -CONFIG_USB=y -CONFIG_USB_MON=y -CONFIG_USB_STORAGE=y -# CONFIG_DNOTIFY is not set -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_ROMFS_FS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ISO8859_1=y -# CONFIG_ENABLE_MUST_CHECK is not set -CONFIG_DEBUG_FS=y diff --git a/arch/arm/configs/nuc960_defconfig b/arch/arm/configs/nuc960_defconfig deleted file mode 100644 index f7af84e23a053524d461163d3e4a227b790ed4f6..0000000000000000000000000000000000000000 --- a/arch/arm/configs/nuc960_defconfig +++ /dev/null @@ -1,57 +0,0 @@ -# CONFIG_LOCALVERSION_AUTO is not set -CONFIG_SYSVIPC=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_RELAY=y -CONFIG_USER_NS=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_KALLSYMS_EXTRA_PASS=y -CONFIG_SLAB=y -CONFIG_ARCH_W90X900=y -# CONFIG_MACH_W90P910EVB is not set -CONFIG_MACH_W90N960EVB=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_PREEMPT=y -CONFIG_AEABI=y -CONFIG_CMDLINE="root=/dev/ram0 console=ttyS0,115200n8 rdinit=/sbin/init mem=64M" -CONFIG_KEXEC=y -CONFIG_FPE_NWFPE=y -CONFIG_BINFMT_AOUT=y -CONFIG_BINFMT_MISC=y -CONFIG_MTD=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=16384 -CONFIG_SCSI=y -# CONFIG_SCSI_PROC_FS is not set -CONFIG_BLK_DEV_SD=y -# CONFIG_SCSI_LOWLEVEL is not set -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=1 -# CONFIG_LEGACY_PTYS is not set -# CONFIG_HW_RANDOM is not set -# CONFIG_HWMON is not set -# CONFIG_VGA_CONSOLE is not set -CONFIG_USB=y -CONFIG_USB_MON=y -CONFIG_USB_STORAGE=y -# CONFIG_DNOTIFY is not set -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_ROMFS_FS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ISO8859_1=y -# CONFIG_ENABLE_MUST_CHECK is not set -CONFIG_DEBUG_FS=y -# CONFIG_CRC32 is not set diff --git a/arch/arm/configs/qcom_defconfig b/arch/arm/configs/qcom_defconfig index 34433bf5885d049869d75ad731f34ec071fc52c1..02f1e7b7c8f6bf71c15d4d013c78246776b05e05 100644 --- a/arch/arm/configs/qcom_defconfig +++ b/arch/arm/configs/qcom_defconfig @@ -147,6 +147,7 @@ CONFIG_REGULATOR_QCOM_SMD_RPM=y CONFIG_REGULATOR_QCOM_SPMI=y CONFIG_MEDIA_SUPPORT=y CONFIG_DRM=y +CONFIG_DRM_MSM=m CONFIG_DRM_PANEL_SIMPLE=y CONFIG_FB=y CONFIG_FRAMEBUFFER_CONSOLE=y diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig index a95322b59799f9162f366c141566e1893971561f..b24df84a1d7adceaa63880578af491e58a2b7cc5 100644 --- a/arch/arm/crypto/Kconfig +++ b/arch/arm/crypto/Kconfig @@ -82,8 +82,8 @@ config CRYPTO_AES_ARM_BS tristate "Bit sliced AES using NEON instructions" depends on KERNEL_MODE_NEON select CRYPTO_BLKCIPHER + select CRYPTO_LIB_AES select CRYPTO_SIMD - select CRYPTO_AES help Use a faster and more secure NEON based implementation of AES in CBC, CTR and XTS modes diff --git a/arch/arm/crypto/aes-ce-core.S b/arch/arm/crypto/aes-ce-core.S index caac519d62490d18104826d83e3f6a055bba3265..b978cdf133af60f6f49675dda9b565dc04e47e32 100644 --- a/arch/arm/crypto/aes-ce-core.S +++ b/arch/arm/crypto/aes-ce-core.S @@ -44,63 +44,73 @@ veor q0, q0, \key3 .endm - .macro enc_dround_3x, key1, key2 + .macro enc_dround_4x, key1, key2 enc_round q0, \key1 enc_round q1, \key1 enc_round q2, \key1 + enc_round q3, \key1 enc_round q0, \key2 enc_round q1, \key2 enc_round q2, \key2 + enc_round q3, \key2 .endm - .macro dec_dround_3x, key1, key2 + .macro dec_dround_4x, key1, key2 dec_round q0, \key1 dec_round q1, \key1 dec_round q2, \key1 + dec_round q3, \key1 dec_round q0, \key2 dec_round q1, \key2 dec_round q2, \key2 + dec_round q3, \key2 .endm - .macro enc_fround_3x, key1, key2, key3 + .macro enc_fround_4x, key1, key2, key3 enc_round q0, \key1 enc_round q1, \key1 enc_round q2, \key1 + enc_round q3, \key1 aese.8 q0, \key2 aese.8 q1, \key2 aese.8 q2, \key2 + aese.8 q3, \key2 veor q0, q0, \key3 veor q1, q1, \key3 veor q2, q2, \key3 + veor q3, q3, \key3 .endm - .macro dec_fround_3x, key1, key2, key3 + .macro dec_fround_4x, key1, key2, key3 dec_round q0, \key1 dec_round q1, \key1 dec_round q2, \key1 + dec_round q3, \key1 aesd.8 q0, \key2 aesd.8 q1, \key2 aesd.8 q2, \key2 + aesd.8 q3, \key2 veor q0, q0, \key3 veor q1, q1, \key3 veor q2, q2, \key3 + veor q3, q3, \key3 .endm .macro do_block, dround, fround cmp r3, #12 @ which key size? - vld1.8 {q10-q11}, [ip]! + vld1.32 {q10-q11}, [ip]! \dround q8, q9 - vld1.8 {q12-q13}, [ip]! + vld1.32 {q12-q13}, [ip]! \dround q10, q11 - vld1.8 {q10-q11}, [ip]! + vld1.32 {q10-q11}, [ip]! \dround q12, q13 - vld1.8 {q12-q13}, [ip]! + vld1.32 {q12-q13}, [ip]! \dround q10, q11 blo 0f @ AES-128: 10 rounds - vld1.8 {q10-q11}, [ip]! + vld1.32 {q10-q11}, [ip]! \dround q12, q13 beq 1f @ AES-192: 12 rounds - vld1.8 {q12-q13}, [ip] + vld1.32 {q12-q13}, [ip] \dround q10, q11 0: \fround q12, q13, q14 bx lr @@ -114,8 +124,9 @@ * transforms. These should preserve all registers except q0 - q2 and ip * Arguments: * q0 : first in/output block - * q1 : second in/output block (_3x version only) - * q2 : third in/output block (_3x version only) + * q1 : second in/output block (_4x version only) + * q2 : third in/output block (_4x version only) + * q3 : fourth in/output block (_4x version only) * q8 : first round key * q9 : secound round key * q14 : final round key @@ -136,44 +147,44 @@ aes_decrypt: ENDPROC(aes_decrypt) .align 6 -aes_encrypt_3x: +aes_encrypt_4x: add ip, r2, #32 @ 3rd round key - do_block enc_dround_3x, enc_fround_3x -ENDPROC(aes_encrypt_3x) + do_block enc_dround_4x, enc_fround_4x +ENDPROC(aes_encrypt_4x) .align 6 -aes_decrypt_3x: +aes_decrypt_4x: add ip, r2, #32 @ 3rd round key - do_block dec_dround_3x, dec_fround_3x -ENDPROC(aes_decrypt_3x) + do_block dec_dround_4x, dec_fround_4x +ENDPROC(aes_decrypt_4x) .macro prepare_key, rk, rounds add ip, \rk, \rounds, lsl #4 - vld1.8 {q8-q9}, [\rk] @ load first 2 round keys - vld1.8 {q14}, [ip] @ load last round key + vld1.32 {q8-q9}, [\rk] @ load first 2 round keys + vld1.32 {q14}, [ip] @ load last round key .endm /* - * aes_ecb_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, + * aes_ecb_encrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, * int blocks) - * aes_ecb_decrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, + * aes_ecb_decrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, * int blocks) */ ENTRY(ce_aes_ecb_encrypt) push {r4, lr} ldr r4, [sp, #8] prepare_key r2, r3 -.Lecbencloop3x: - subs r4, r4, #3 +.Lecbencloop4x: + subs r4, r4, #4 bmi .Lecbenc1x vld1.8 {q0-q1}, [r1]! - vld1.8 {q2}, [r1]! - bl aes_encrypt_3x + vld1.8 {q2-q3}, [r1]! + bl aes_encrypt_4x vst1.8 {q0-q1}, [r0]! - vst1.8 {q2}, [r0]! - b .Lecbencloop3x + vst1.8 {q2-q3}, [r0]! + b .Lecbencloop4x .Lecbenc1x: - adds r4, r4, #3 + adds r4, r4, #4 beq .Lecbencout .Lecbencloop: vld1.8 {q0}, [r1]! @@ -189,17 +200,17 @@ ENTRY(ce_aes_ecb_decrypt) push {r4, lr} ldr r4, [sp, #8] prepare_key r2, r3 -.Lecbdecloop3x: - subs r4, r4, #3 +.Lecbdecloop4x: + subs r4, r4, #4 bmi .Lecbdec1x vld1.8 {q0-q1}, [r1]! - vld1.8 {q2}, [r1]! - bl aes_decrypt_3x + vld1.8 {q2-q3}, [r1]! + bl aes_decrypt_4x vst1.8 {q0-q1}, [r0]! - vst1.8 {q2}, [r0]! - b .Lecbdecloop3x + vst1.8 {q2-q3}, [r0]! + b .Lecbdecloop4x .Lecbdec1x: - adds r4, r4, #3 + adds r4, r4, #4 beq .Lecbdecout .Lecbdecloop: vld1.8 {q0}, [r1]! @@ -212,9 +223,9 @@ ENTRY(ce_aes_ecb_decrypt) ENDPROC(ce_aes_ecb_decrypt) /* - * aes_cbc_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, + * aes_cbc_encrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, * int blocks, u8 iv[]) - * aes_cbc_decrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, + * aes_cbc_decrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, * int blocks, u8 iv[]) */ ENTRY(ce_aes_cbc_encrypt) @@ -236,88 +247,181 @@ ENDPROC(ce_aes_cbc_encrypt) ENTRY(ce_aes_cbc_decrypt) push {r4-r6, lr} ldrd r4, r5, [sp, #16] - vld1.8 {q6}, [r5] @ keep iv in q6 + vld1.8 {q15}, [r5] @ keep iv in q15 prepare_key r2, r3 -.Lcbcdecloop3x: - subs r4, r4, #3 +.Lcbcdecloop4x: + subs r4, r4, #4 bmi .Lcbcdec1x vld1.8 {q0-q1}, [r1]! - vld1.8 {q2}, [r1]! - vmov q3, q0 - vmov q4, q1 - vmov q5, q2 - bl aes_decrypt_3x - veor q0, q0, q6 - veor q1, q1, q3 - veor q2, q2, q4 - vmov q6, q5 + vld1.8 {q2-q3}, [r1]! + vmov q4, q0 + vmov q5, q1 + vmov q6, q2 + vmov q7, q3 + bl aes_decrypt_4x + veor q0, q0, q15 + veor q1, q1, q4 + veor q2, q2, q5 + veor q3, q3, q6 + vmov q15, q7 vst1.8 {q0-q1}, [r0]! - vst1.8 {q2}, [r0]! - b .Lcbcdecloop3x + vst1.8 {q2-q3}, [r0]! + b .Lcbcdecloop4x .Lcbcdec1x: - adds r4, r4, #3 + adds r4, r4, #4 beq .Lcbcdecout - vmov q15, q14 @ preserve last round key + vmov q6, q14 @ preserve last round key .Lcbcdecloop: vld1.8 {q0}, [r1]! @ get next ct block veor q14, q15, q6 @ combine prev ct with last key - vmov q6, q0 + vmov q15, q0 bl aes_decrypt vst1.8 {q0}, [r0]! subs r4, r4, #1 bne .Lcbcdecloop .Lcbcdecout: - vst1.8 {q6}, [r5] @ keep iv in q6 + vst1.8 {q15}, [r5] @ keep iv in q15 pop {r4-r6, pc} ENDPROC(ce_aes_cbc_decrypt) + /* - * aes_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, + * ce_aes_cbc_cts_encrypt(u8 out[], u8 const in[], u32 const rk[], + * int rounds, int bytes, u8 const iv[]) + * ce_aes_cbc_cts_decrypt(u8 out[], u8 const in[], u32 const rk[], + * int rounds, int bytes, u8 const iv[]) + */ + +ENTRY(ce_aes_cbc_cts_encrypt) + push {r4-r6, lr} + ldrd r4, r5, [sp, #16] + + movw ip, :lower16:.Lcts_permute_table + movt ip, :upper16:.Lcts_permute_table + sub r4, r4, #16 + add lr, ip, #32 + add ip, ip, r4 + sub lr, lr, r4 + vld1.8 {q5}, [ip] + vld1.8 {q6}, [lr] + + add ip, r1, r4 + vld1.8 {q0}, [r1] @ overlapping loads + vld1.8 {q3}, [ip] + + vld1.8 {q1}, [r5] @ get iv + prepare_key r2, r3 + + veor q0, q0, q1 @ xor with iv + bl aes_encrypt + + vtbl.8 d4, {d0-d1}, d10 + vtbl.8 d5, {d0-d1}, d11 + vtbl.8 d2, {d6-d7}, d12 + vtbl.8 d3, {d6-d7}, d13 + + veor q0, q0, q1 + bl aes_encrypt + + add r4, r0, r4 + vst1.8 {q2}, [r4] @ overlapping stores + vst1.8 {q0}, [r0] + + pop {r4-r6, pc} +ENDPROC(ce_aes_cbc_cts_encrypt) + +ENTRY(ce_aes_cbc_cts_decrypt) + push {r4-r6, lr} + ldrd r4, r5, [sp, #16] + + movw ip, :lower16:.Lcts_permute_table + movt ip, :upper16:.Lcts_permute_table + sub r4, r4, #16 + add lr, ip, #32 + add ip, ip, r4 + sub lr, lr, r4 + vld1.8 {q5}, [ip] + vld1.8 {q6}, [lr] + + add ip, r1, r4 + vld1.8 {q0}, [r1] @ overlapping loads + vld1.8 {q1}, [ip] + + vld1.8 {q3}, [r5] @ get iv + prepare_key r2, r3 + + bl aes_decrypt + + vtbl.8 d4, {d0-d1}, d10 + vtbl.8 d5, {d0-d1}, d11 + vtbx.8 d0, {d2-d3}, d12 + vtbx.8 d1, {d2-d3}, d13 + + veor q1, q1, q2 + bl aes_decrypt + veor q0, q0, q3 @ xor with iv + + add r4, r0, r4 + vst1.8 {q1}, [r4] @ overlapping stores + vst1.8 {q0}, [r0] + + pop {r4-r6, pc} +ENDPROC(ce_aes_cbc_cts_decrypt) + + + /* + * aes_ctr_encrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, * int blocks, u8 ctr[]) */ ENTRY(ce_aes_ctr_encrypt) push {r4-r6, lr} ldrd r4, r5, [sp, #16] - vld1.8 {q6}, [r5] @ load ctr + vld1.8 {q7}, [r5] @ load ctr prepare_key r2, r3 - vmov r6, s27 @ keep swabbed ctr in r6 + vmov r6, s31 @ keep swabbed ctr in r6 rev r6, r6 cmn r6, r4 @ 32 bit overflow? bcs .Lctrloop -.Lctrloop3x: - subs r4, r4, #3 +.Lctrloop4x: + subs r4, r4, #4 bmi .Lctr1x add r6, r6, #1 - vmov q0, q6 - vmov q1, q6 + vmov q0, q7 + vmov q1, q7 rev ip, r6 add r6, r6, #1 - vmov q2, q6 + vmov q2, q7 vmov s7, ip rev ip, r6 add r6, r6, #1 + vmov q3, q7 vmov s11, ip - vld1.8 {q3-q4}, [r1]! - vld1.8 {q5}, [r1]! - bl aes_encrypt_3x - veor q0, q0, q3 - veor q1, q1, q4 - veor q2, q2, q5 + rev ip, r6 + add r6, r6, #1 + vmov s15, ip + vld1.8 {q4-q5}, [r1]! + vld1.8 {q6}, [r1]! + vld1.8 {q15}, [r1]! + bl aes_encrypt_4x + veor q0, q0, q4 + veor q1, q1, q5 + veor q2, q2, q6 + veor q3, q3, q15 rev ip, r6 vst1.8 {q0-q1}, [r0]! - vst1.8 {q2}, [r0]! - vmov s27, ip - b .Lctrloop3x + vst1.8 {q2-q3}, [r0]! + vmov s31, ip + b .Lctrloop4x .Lctr1x: - adds r4, r4, #3 + adds r4, r4, #4 beq .Lctrout .Lctrloop: - vmov q0, q6 + vmov q0, q7 bl aes_encrypt adds r6, r6, #1 @ increment BE ctr rev ip, r6 - vmov s27, ip + vmov s31, ip bcs .Lctrcarry .Lctrcarrydone: @@ -329,7 +433,7 @@ ENTRY(ce_aes_ctr_encrypt) bne .Lctrloop .Lctrout: - vst1.8 {q6}, [r5] @ return next CTR value + vst1.8 {q7}, [r5] @ return next CTR value pop {r4-r6, pc} .Lctrtailblock: @@ -337,7 +441,7 @@ ENTRY(ce_aes_ctr_encrypt) b .Lctrout .Lctrcarry: - .irp sreg, s26, s25, s24 + .irp sreg, s30, s29, s28 vmov ip, \sreg @ load next word of ctr rev ip, ip @ ... to handle the carry adds ip, ip, #1 @@ -349,10 +453,10 @@ ENTRY(ce_aes_ctr_encrypt) ENDPROC(ce_aes_ctr_encrypt) /* - * aes_xts_encrypt(u8 out[], u8 const in[], u8 const rk1[], int rounds, - * int blocks, u8 iv[], u8 const rk2[], int first) - * aes_xts_decrypt(u8 out[], u8 const in[], u8 const rk1[], int rounds, - * int blocks, u8 iv[], u8 const rk2[], int first) + * aes_xts_encrypt(u8 out[], u8 const in[], u32 const rk1[], int rounds, + * int bytes, u8 iv[], u32 const rk2[], int first) + * aes_xts_decrypt(u8 out[], u8 const in[], u32 const rk1[], int rounds, + * int bytes, u8 iv[], u32 const rk2[], int first) */ .macro next_tweak, out, in, const, tmp @@ -363,13 +467,10 @@ ENDPROC(ce_aes_ctr_encrypt) veor \out, \out, \tmp .endm - .align 3 -.Lxts_mul_x: - .quad 1, 0x87 - ce_aes_xts_init: - vldr d14, .Lxts_mul_x - vldr d15, .Lxts_mul_x + 8 + vmov.i32 d30, #0x87 @ compose tweak mask vector + vmovl.u32 q15, d30 + vshr.u64 d30, d31, #7 ldrd r4, r5, [sp, #16] @ load args ldr r6, [sp, #28] @@ -390,49 +491,86 @@ ENTRY(ce_aes_xts_encrypt) bl ce_aes_xts_init @ run shared prologue prepare_key r2, r3 - vmov q3, q0 + vmov q4, q0 teq r6, #0 @ start of a block? - bne .Lxtsenc3x + bne .Lxtsenc4x -.Lxtsencloop3x: - next_tweak q3, q3, q7, q6 -.Lxtsenc3x: - subs r4, r4, #3 +.Lxtsencloop4x: + next_tweak q4, q4, q15, q10 +.Lxtsenc4x: + subs r4, r4, #64 bmi .Lxtsenc1x - vld1.8 {q0-q1}, [r1]! @ get 3 pt blocks - vld1.8 {q2}, [r1]! - next_tweak q4, q3, q7, q6 - veor q0, q0, q3 - next_tweak q5, q4, q7, q6 - veor q1, q1, q4 - veor q2, q2, q5 - bl aes_encrypt_3x - veor q0, q0, q3 - veor q1, q1, q4 - veor q2, q2, q5 - vst1.8 {q0-q1}, [r0]! @ write 3 ct blocks - vst1.8 {q2}, [r0]! - vmov q3, q5 + vld1.8 {q0-q1}, [r1]! @ get 4 pt blocks + vld1.8 {q2-q3}, [r1]! + next_tweak q5, q4, q15, q10 + veor q0, q0, q4 + next_tweak q6, q5, q15, q10 + veor q1, q1, q5 + next_tweak q7, q6, q15, q10 + veor q2, q2, q6 + veor q3, q3, q7 + bl aes_encrypt_4x + veor q0, q0, q4 + veor q1, q1, q5 + veor q2, q2, q6 + veor q3, q3, q7 + vst1.8 {q0-q1}, [r0]! @ write 4 ct blocks + vst1.8 {q2-q3}, [r0]! + vmov q4, q7 teq r4, #0 - beq .Lxtsencout - b .Lxtsencloop3x + beq .Lxtsencret + b .Lxtsencloop4x .Lxtsenc1x: - adds r4, r4, #3 + adds r4, r4, #64 beq .Lxtsencout + subs r4, r4, #16 + bmi .LxtsencctsNx .Lxtsencloop: vld1.8 {q0}, [r1]! - veor q0, q0, q3 +.Lxtsencctsout: + veor q0, q0, q4 bl aes_encrypt - veor q0, q0, q3 - vst1.8 {q0}, [r0]! - subs r4, r4, #1 + veor q0, q0, q4 + teq r4, #0 beq .Lxtsencout - next_tweak q3, q3, q7, q6 + subs r4, r4, #16 + next_tweak q4, q4, q15, q6 + bmi .Lxtsenccts + vst1.8 {q0}, [r0]! b .Lxtsencloop .Lxtsencout: - vst1.8 {q3}, [r5] + vst1.8 {q0}, [r0] +.Lxtsencret: + vst1.8 {q4}, [r5] pop {r4-r6, pc} + +.LxtsencctsNx: + vmov q0, q3 + sub r0, r0, #16 +.Lxtsenccts: + movw ip, :lower16:.Lcts_permute_table + movt ip, :upper16:.Lcts_permute_table + + add r1, r1, r4 @ rewind input pointer + add r4, r4, #16 @ # bytes in final block + add lr, ip, #32 + add ip, ip, r4 + sub lr, lr, r4 + add r4, r0, r4 @ output address of final block + + vld1.8 {q1}, [r1] @ load final partial block + vld1.8 {q2}, [ip] + vld1.8 {q3}, [lr] + + vtbl.8 d4, {d0-d1}, d4 + vtbl.8 d5, {d0-d1}, d5 + vtbx.8 d0, {d2-d3}, d6 + vtbx.8 d1, {d2-d3}, d7 + + vst1.8 {q2}, [r4] @ overlapping stores + mov r4, #0 + b .Lxtsencctsout ENDPROC(ce_aes_xts_encrypt) @@ -441,50 +579,90 @@ ENTRY(ce_aes_xts_decrypt) bl ce_aes_xts_init @ run shared prologue prepare_key r2, r3 - vmov q3, q0 + vmov q4, q0 + + /* subtract 16 bytes if we are doing CTS */ + tst r4, #0xf + subne r4, r4, #0x10 teq r6, #0 @ start of a block? - bne .Lxtsdec3x + bne .Lxtsdec4x -.Lxtsdecloop3x: - next_tweak q3, q3, q7, q6 -.Lxtsdec3x: - subs r4, r4, #3 +.Lxtsdecloop4x: + next_tweak q4, q4, q15, q10 +.Lxtsdec4x: + subs r4, r4, #64 bmi .Lxtsdec1x - vld1.8 {q0-q1}, [r1]! @ get 3 ct blocks - vld1.8 {q2}, [r1]! - next_tweak q4, q3, q7, q6 - veor q0, q0, q3 - next_tweak q5, q4, q7, q6 - veor q1, q1, q4 - veor q2, q2, q5 - bl aes_decrypt_3x - veor q0, q0, q3 - veor q1, q1, q4 - veor q2, q2, q5 - vst1.8 {q0-q1}, [r0]! @ write 3 pt blocks - vst1.8 {q2}, [r0]! - vmov q3, q5 + vld1.8 {q0-q1}, [r1]! @ get 4 ct blocks + vld1.8 {q2-q3}, [r1]! + next_tweak q5, q4, q15, q10 + veor q0, q0, q4 + next_tweak q6, q5, q15, q10 + veor q1, q1, q5 + next_tweak q7, q6, q15, q10 + veor q2, q2, q6 + veor q3, q3, q7 + bl aes_decrypt_4x + veor q0, q0, q4 + veor q1, q1, q5 + veor q2, q2, q6 + veor q3, q3, q7 + vst1.8 {q0-q1}, [r0]! @ write 4 pt blocks + vst1.8 {q2-q3}, [r0]! + vmov q4, q7 teq r4, #0 beq .Lxtsdecout - b .Lxtsdecloop3x + b .Lxtsdecloop4x .Lxtsdec1x: - adds r4, r4, #3 + adds r4, r4, #64 beq .Lxtsdecout + subs r4, r4, #16 .Lxtsdecloop: vld1.8 {q0}, [r1]! - veor q0, q0, q3 - add ip, r2, #32 @ 3rd round key + bmi .Lxtsdeccts +.Lxtsdecctsout: + veor q0, q0, q4 bl aes_decrypt - veor q0, q0, q3 + veor q0, q0, q4 vst1.8 {q0}, [r0]! - subs r4, r4, #1 + teq r4, #0 beq .Lxtsdecout - next_tweak q3, q3, q7, q6 + subs r4, r4, #16 + next_tweak q4, q4, q15, q6 b .Lxtsdecloop .Lxtsdecout: - vst1.8 {q3}, [r5] + vst1.8 {q4}, [r5] pop {r4-r6, pc} + +.Lxtsdeccts: + movw ip, :lower16:.Lcts_permute_table + movt ip, :upper16:.Lcts_permute_table + + add r1, r1, r4 @ rewind input pointer + add r4, r4, #16 @ # bytes in final block + add lr, ip, #32 + add ip, ip, r4 + sub lr, lr, r4 + add r4, r0, r4 @ output address of final block + + next_tweak q5, q4, q15, q6 + + vld1.8 {q1}, [r1] @ load final partial block + vld1.8 {q2}, [ip] + vld1.8 {q3}, [lr] + + veor q0, q0, q5 + bl aes_decrypt + veor q0, q0, q5 + + vtbl.8 d4, {d0-d1}, d4 + vtbl.8 d5, {d0-d1}, d5 + vtbx.8 d0, {d2-d3}, d6 + vtbx.8 d1, {d2-d3}, d7 + + vst1.8 {q2}, [r4] @ overlapping stores + mov r4, #0 + b .Lxtsdecctsout ENDPROC(ce_aes_xts_decrypt) /* @@ -505,8 +683,18 @@ ENDPROC(ce_aes_sub) * operation on round key *src */ ENTRY(ce_aes_invert) - vld1.8 {q0}, [r1] + vld1.32 {q0}, [r1] aesimc.8 q0, q0 - vst1.8 {q0}, [r0] + vst1.32 {q0}, [r0] bx lr ENDPROC(ce_aes_invert) + + .section ".rodata", "a" + .align 6 +.Lcts_permute_table: + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 + .byte 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff diff --git a/arch/arm/crypto/aes-ce-glue.c b/arch/arm/crypto/aes-ce-glue.c index 620aacf0d1282aa316045681073547a5e57b06da..cdb1a07e7ad0a03a00b7c1d99158874e9095c5ff 100644 --- a/arch/arm/crypto/aes-ce-glue.c +++ b/arch/arm/crypto/aes-ce-glue.c @@ -7,9 +7,13 @@ #include #include +#include +#include #include +#include #include #include +#include #include #include #include @@ -22,25 +26,29 @@ MODULE_LICENSE("GPL v2"); asmlinkage u32 ce_aes_sub(u32 input); asmlinkage void ce_aes_invert(void *dst, void *src); -asmlinkage void ce_aes_ecb_encrypt(u8 out[], u8 const in[], u8 const rk[], +asmlinkage void ce_aes_ecb_encrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, int blocks); -asmlinkage void ce_aes_ecb_decrypt(u8 out[], u8 const in[], u8 const rk[], +asmlinkage void ce_aes_ecb_decrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, int blocks); -asmlinkage void ce_aes_cbc_encrypt(u8 out[], u8 const in[], u8 const rk[], +asmlinkage void ce_aes_cbc_encrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, int blocks, u8 iv[]); -asmlinkage void ce_aes_cbc_decrypt(u8 out[], u8 const in[], u8 const rk[], +asmlinkage void ce_aes_cbc_decrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, int blocks, u8 iv[]); +asmlinkage void ce_aes_cbc_cts_encrypt(u8 out[], u8 const in[], u32 const rk[], + int rounds, int bytes, u8 const iv[]); +asmlinkage void ce_aes_cbc_cts_decrypt(u8 out[], u8 const in[], u32 const rk[], + int rounds, int bytes, u8 const iv[]); -asmlinkage void ce_aes_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[], +asmlinkage void ce_aes_ctr_encrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, int blocks, u8 ctr[]); -asmlinkage void ce_aes_xts_encrypt(u8 out[], u8 const in[], u8 const rk1[], - int rounds, int blocks, u8 iv[], - u8 const rk2[], int first); -asmlinkage void ce_aes_xts_decrypt(u8 out[], u8 const in[], u8 const rk1[], - int rounds, int blocks, u8 iv[], - u8 const rk2[], int first); +asmlinkage void ce_aes_xts_encrypt(u8 out[], u8 const in[], u32 const rk1[], + int rounds, int bytes, u8 iv[], + u32 const rk2[], int first); +asmlinkage void ce_aes_xts_decrypt(u8 out[], u8 const in[], u32 const rk1[], + int rounds, int bytes, u8 iv[], + u32 const rk2[], int first); struct aes_block { u8 b[AES_BLOCK_SIZE]; @@ -77,21 +85,17 @@ static int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key, key_len != AES_KEYSIZE_256) return -EINVAL; - memcpy(ctx->key_enc, in_key, key_len); ctx->key_length = key_len; + for (i = 0; i < kwords; i++) + ctx->key_enc[i] = get_unaligned_le32(in_key + i * sizeof(u32)); kernel_neon_begin(); for (i = 0; i < sizeof(rcon); i++) { u32 *rki = ctx->key_enc + (i * kwords); u32 *rko = rki + kwords; -#ifndef CONFIG_CPU_BIG_ENDIAN rko[0] = ror32(ce_aes_sub(rki[kwords - 1]), 8); rko[0] = rko[0] ^ rki[0] ^ rcon[i]; -#else - rko[0] = rol32(ce_aes_sub(rki[kwords - 1]), 8); - rko[0] = rko[0] ^ rki[0] ^ (rcon[i] << 24); -#endif rko[1] = rko[0] ^ rki[1]; rko[2] = rko[1] ^ rki[2]; rko[3] = rko[2] ^ rki[3]; @@ -178,15 +182,15 @@ static int ecb_encrypt(struct skcipher_request *req) unsigned int blocks; int err; - err = skcipher_walk_virt(&walk, req, true); + err = skcipher_walk_virt(&walk, req, false); - kernel_neon_begin(); while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { + kernel_neon_begin(); ce_aes_ecb_encrypt(walk.dst.virt.addr, walk.src.virt.addr, - (u8 *)ctx->key_enc, num_rounds(ctx), blocks); + ctx->key_enc, num_rounds(ctx), blocks); + kernel_neon_end(); err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); } - kernel_neon_end(); return err; } @@ -198,58 +202,192 @@ static int ecb_decrypt(struct skcipher_request *req) unsigned int blocks; int err; - err = skcipher_walk_virt(&walk, req, true); + err = skcipher_walk_virt(&walk, req, false); - kernel_neon_begin(); while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { + kernel_neon_begin(); ce_aes_ecb_decrypt(walk.dst.virt.addr, walk.src.virt.addr, - (u8 *)ctx->key_dec, num_rounds(ctx), blocks); + ctx->key_dec, num_rounds(ctx), blocks); + kernel_neon_end(); err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); } - kernel_neon_end(); return err; } -static int cbc_encrypt(struct skcipher_request *req) +static int cbc_encrypt_walk(struct skcipher_request *req, + struct skcipher_walk *walk) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; unsigned int blocks; + int err = 0; + + while ((blocks = (walk->nbytes / AES_BLOCK_SIZE))) { + kernel_neon_begin(); + ce_aes_cbc_encrypt(walk->dst.virt.addr, walk->src.virt.addr, + ctx->key_enc, num_rounds(ctx), blocks, + walk->iv); + kernel_neon_end(); + err = skcipher_walk_done(walk, walk->nbytes % AES_BLOCK_SIZE); + } + return err; +} + +static int cbc_encrypt(struct skcipher_request *req) +{ + struct skcipher_walk walk; int err; - err = skcipher_walk_virt(&walk, req, true); + err = skcipher_walk_virt(&walk, req, false); + if (err) + return err; + return cbc_encrypt_walk(req, &walk); +} - kernel_neon_begin(); - while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { - ce_aes_cbc_encrypt(walk.dst.virt.addr, walk.src.virt.addr, - (u8 *)ctx->key_enc, num_rounds(ctx), blocks, - walk.iv); - err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); +static int cbc_decrypt_walk(struct skcipher_request *req, + struct skcipher_walk *walk) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); + unsigned int blocks; + int err = 0; + + while ((blocks = (walk->nbytes / AES_BLOCK_SIZE))) { + kernel_neon_begin(); + ce_aes_cbc_decrypt(walk->dst.virt.addr, walk->src.virt.addr, + ctx->key_dec, num_rounds(ctx), blocks, + walk->iv); + kernel_neon_end(); + err = skcipher_walk_done(walk, walk->nbytes % AES_BLOCK_SIZE); } - kernel_neon_end(); return err; } static int cbc_decrypt(struct skcipher_request *req) +{ + struct skcipher_walk walk; + int err; + + err = skcipher_walk_virt(&walk, req, false); + if (err) + return err; + return cbc_decrypt_walk(req, &walk); +} + +static int cts_cbc_encrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); + int cbc_blocks = DIV_ROUND_UP(req->cryptlen, AES_BLOCK_SIZE) - 2; + struct scatterlist *src = req->src, *dst = req->dst; + struct scatterlist sg_src[2], sg_dst[2]; + struct skcipher_request subreq; struct skcipher_walk walk; - unsigned int blocks; int err; - err = skcipher_walk_virt(&walk, req, true); + skcipher_request_set_tfm(&subreq, tfm); + skcipher_request_set_callback(&subreq, skcipher_request_flags(req), + NULL, NULL); + + if (req->cryptlen <= AES_BLOCK_SIZE) { + if (req->cryptlen < AES_BLOCK_SIZE) + return -EINVAL; + cbc_blocks = 1; + } + + if (cbc_blocks > 0) { + skcipher_request_set_crypt(&subreq, req->src, req->dst, + cbc_blocks * AES_BLOCK_SIZE, + req->iv); + + err = skcipher_walk_virt(&walk, &subreq, false) ?: + cbc_encrypt_walk(&subreq, &walk); + if (err) + return err; + + if (req->cryptlen == AES_BLOCK_SIZE) + return 0; + + dst = src = scatterwalk_ffwd(sg_src, req->src, subreq.cryptlen); + if (req->dst != req->src) + dst = scatterwalk_ffwd(sg_dst, req->dst, + subreq.cryptlen); + } + + /* handle ciphertext stealing */ + skcipher_request_set_crypt(&subreq, src, dst, + req->cryptlen - cbc_blocks * AES_BLOCK_SIZE, + req->iv); + + err = skcipher_walk_virt(&walk, &subreq, false); + if (err) + return err; kernel_neon_begin(); - while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { - ce_aes_cbc_decrypt(walk.dst.virt.addr, walk.src.virt.addr, - (u8 *)ctx->key_dec, num_rounds(ctx), blocks, - walk.iv); - err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); + ce_aes_cbc_cts_encrypt(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key_enc, num_rounds(ctx), walk.nbytes, + walk.iv); + kernel_neon_end(); + + return skcipher_walk_done(&walk, 0); +} + +static int cts_cbc_decrypt(struct skcipher_request *req) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); + int cbc_blocks = DIV_ROUND_UP(req->cryptlen, AES_BLOCK_SIZE) - 2; + struct scatterlist *src = req->src, *dst = req->dst; + struct scatterlist sg_src[2], sg_dst[2]; + struct skcipher_request subreq; + struct skcipher_walk walk; + int err; + + skcipher_request_set_tfm(&subreq, tfm); + skcipher_request_set_callback(&subreq, skcipher_request_flags(req), + NULL, NULL); + + if (req->cryptlen <= AES_BLOCK_SIZE) { + if (req->cryptlen < AES_BLOCK_SIZE) + return -EINVAL; + cbc_blocks = 1; } + + if (cbc_blocks > 0) { + skcipher_request_set_crypt(&subreq, req->src, req->dst, + cbc_blocks * AES_BLOCK_SIZE, + req->iv); + + err = skcipher_walk_virt(&walk, &subreq, false) ?: + cbc_decrypt_walk(&subreq, &walk); + if (err) + return err; + + if (req->cryptlen == AES_BLOCK_SIZE) + return 0; + + dst = src = scatterwalk_ffwd(sg_src, req->src, subreq.cryptlen); + if (req->dst != req->src) + dst = scatterwalk_ffwd(sg_dst, req->dst, + subreq.cryptlen); + } + + /* handle ciphertext stealing */ + skcipher_request_set_crypt(&subreq, src, dst, + req->cryptlen - cbc_blocks * AES_BLOCK_SIZE, + req->iv); + + err = skcipher_walk_virt(&walk, &subreq, false); + if (err) + return err; + + kernel_neon_begin(); + ce_aes_cbc_cts_decrypt(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key_dec, num_rounds(ctx), walk.nbytes, + walk.iv); kernel_neon_end(); - return err; + + return skcipher_walk_done(&walk, 0); } static int ctr_encrypt(struct skcipher_request *req) @@ -259,13 +397,14 @@ static int ctr_encrypt(struct skcipher_request *req) struct skcipher_walk walk; int err, blocks; - err = skcipher_walk_virt(&walk, req, true); + err = skcipher_walk_virt(&walk, req, false); - kernel_neon_begin(); while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { + kernel_neon_begin(); ce_aes_ctr_encrypt(walk.dst.virt.addr, walk.src.virt.addr, - (u8 *)ctx->key_enc, num_rounds(ctx), blocks, + ctx->key_enc, num_rounds(ctx), blocks, walk.iv); + kernel_neon_end(); err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); } if (walk.nbytes) { @@ -279,36 +418,109 @@ static int ctr_encrypt(struct skcipher_request *req) */ blocks = -1; - ce_aes_ctr_encrypt(tail, NULL, (u8 *)ctx->key_enc, - num_rounds(ctx), blocks, walk.iv); + kernel_neon_begin(); + ce_aes_ctr_encrypt(tail, NULL, ctx->key_enc, num_rounds(ctx), + blocks, walk.iv); + kernel_neon_end(); crypto_xor_cpy(tdst, tsrc, tail, nbytes); err = skcipher_walk_done(&walk, 0); } - kernel_neon_end(); - return err; } +static void ctr_encrypt_one(struct crypto_skcipher *tfm, const u8 *src, u8 *dst) +{ + struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); + unsigned long flags; + + /* + * Temporarily disable interrupts to avoid races where + * cachelines are evicted when the CPU is interrupted + * to do something else. + */ + local_irq_save(flags); + aes_encrypt(ctx, dst, src); + local_irq_restore(flags); +} + +static int ctr_encrypt_sync(struct skcipher_request *req) +{ + if (!crypto_simd_usable()) + return crypto_ctr_encrypt_walk(req, ctr_encrypt_one); + + return ctr_encrypt(req); +} + static int xts_encrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct crypto_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm); int err, first, rounds = num_rounds(&ctx->key1); + int tail = req->cryptlen % AES_BLOCK_SIZE; + struct scatterlist sg_src[2], sg_dst[2]; + struct skcipher_request subreq; + struct scatterlist *src, *dst; struct skcipher_walk walk; - unsigned int blocks; - err = skcipher_walk_virt(&walk, req, true); + if (req->cryptlen < AES_BLOCK_SIZE) + return -EINVAL; - kernel_neon_begin(); - for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) { + err = skcipher_walk_virt(&walk, req, false); + + if (unlikely(tail > 0 && walk.nbytes < walk.total)) { + int xts_blocks = DIV_ROUND_UP(req->cryptlen, + AES_BLOCK_SIZE) - 2; + + skcipher_walk_abort(&walk); + + skcipher_request_set_tfm(&subreq, tfm); + skcipher_request_set_callback(&subreq, + skcipher_request_flags(req), + NULL, NULL); + skcipher_request_set_crypt(&subreq, req->src, req->dst, + xts_blocks * AES_BLOCK_SIZE, + req->iv); + req = &subreq; + err = skcipher_walk_virt(&walk, req, false); + } else { + tail = 0; + } + + for (first = 1; walk.nbytes >= AES_BLOCK_SIZE; first = 0) { + int nbytes = walk.nbytes; + + if (walk.nbytes < walk.total) + nbytes &= ~(AES_BLOCK_SIZE - 1); + + kernel_neon_begin(); ce_aes_xts_encrypt(walk.dst.virt.addr, walk.src.virt.addr, - (u8 *)ctx->key1.key_enc, rounds, blocks, - walk.iv, (u8 *)ctx->key2.key_enc, first); - err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); + ctx->key1.key_enc, rounds, nbytes, walk.iv, + ctx->key2.key_enc, first); + kernel_neon_end(); + err = skcipher_walk_done(&walk, walk.nbytes - nbytes); } + + if (err || likely(!tail)) + return err; + + dst = src = scatterwalk_ffwd(sg_src, req->src, req->cryptlen); + if (req->dst != req->src) + dst = scatterwalk_ffwd(sg_dst, req->dst, req->cryptlen); + + skcipher_request_set_crypt(req, src, dst, AES_BLOCK_SIZE + tail, + req->iv); + + err = skcipher_walk_virt(&walk, req, false); + if (err) + return err; + + kernel_neon_begin(); + ce_aes_xts_encrypt(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key1.key_enc, rounds, walk.nbytes, walk.iv, + ctx->key2.key_enc, first); kernel_neon_end(); - return err; + return skcipher_walk_done(&walk, 0); } static int xts_decrypt(struct skcipher_request *req) @@ -316,87 +528,165 @@ static int xts_decrypt(struct skcipher_request *req) struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct crypto_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm); int err, first, rounds = num_rounds(&ctx->key1); + int tail = req->cryptlen % AES_BLOCK_SIZE; + struct scatterlist sg_src[2], sg_dst[2]; + struct skcipher_request subreq; + struct scatterlist *src, *dst; struct skcipher_walk walk; - unsigned int blocks; - err = skcipher_walk_virt(&walk, req, true); + if (req->cryptlen < AES_BLOCK_SIZE) + return -EINVAL; + + err = skcipher_walk_virt(&walk, req, false); + + if (unlikely(tail > 0 && walk.nbytes < walk.total)) { + int xts_blocks = DIV_ROUND_UP(req->cryptlen, + AES_BLOCK_SIZE) - 2; + + skcipher_walk_abort(&walk); + + skcipher_request_set_tfm(&subreq, tfm); + skcipher_request_set_callback(&subreq, + skcipher_request_flags(req), + NULL, NULL); + skcipher_request_set_crypt(&subreq, req->src, req->dst, + xts_blocks * AES_BLOCK_SIZE, + req->iv); + req = &subreq; + err = skcipher_walk_virt(&walk, req, false); + } else { + tail = 0; + } + + for (first = 1; walk.nbytes >= AES_BLOCK_SIZE; first = 0) { + int nbytes = walk.nbytes; - kernel_neon_begin(); - for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) { + if (walk.nbytes < walk.total) + nbytes &= ~(AES_BLOCK_SIZE - 1); + + kernel_neon_begin(); ce_aes_xts_decrypt(walk.dst.virt.addr, walk.src.virt.addr, - (u8 *)ctx->key1.key_dec, rounds, blocks, - walk.iv, (u8 *)ctx->key2.key_enc, first); - err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); + ctx->key1.key_dec, rounds, nbytes, walk.iv, + ctx->key2.key_enc, first); + kernel_neon_end(); + err = skcipher_walk_done(&walk, walk.nbytes - nbytes); } + + if (err || likely(!tail)) + return err; + + dst = src = scatterwalk_ffwd(sg_src, req->src, req->cryptlen); + if (req->dst != req->src) + dst = scatterwalk_ffwd(sg_dst, req->dst, req->cryptlen); + + skcipher_request_set_crypt(req, src, dst, AES_BLOCK_SIZE + tail, + req->iv); + + err = skcipher_walk_virt(&walk, req, false); + if (err) + return err; + + kernel_neon_begin(); + ce_aes_xts_decrypt(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key1.key_dec, rounds, walk.nbytes, walk.iv, + ctx->key2.key_enc, first); kernel_neon_end(); - return err; + return skcipher_walk_done(&walk, 0); } static struct skcipher_alg aes_algs[] = { { - .base = { - .cra_name = "__ecb(aes)", - .cra_driver_name = "__ecb-aes-ce", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_INTERNAL, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypto_aes_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = ce_aes_setkey, - .encrypt = ecb_encrypt, - .decrypt = ecb_decrypt, + .base.cra_name = "__ecb(aes)", + .base.cra_driver_name = "__ecb-aes-ce", + .base.cra_priority = 300, + .base.cra_flags = CRYPTO_ALG_INTERNAL, + .base.cra_blocksize = AES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct crypto_aes_ctx), + .base.cra_module = THIS_MODULE, + + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = ce_aes_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, }, { - .base = { - .cra_name = "__cbc(aes)", - .cra_driver_name = "__cbc-aes-ce", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_INTERNAL, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypto_aes_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - .setkey = ce_aes_setkey, - .encrypt = cbc_encrypt, - .decrypt = cbc_decrypt, + .base.cra_name = "__cbc(aes)", + .base.cra_driver_name = "__cbc-aes-ce", + .base.cra_priority = 300, + .base.cra_flags = CRYPTO_ALG_INTERNAL, + .base.cra_blocksize = AES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct crypto_aes_ctx), + .base.cra_module = THIS_MODULE, + + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ce_aes_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, }, { - .base = { - .cra_name = "__ctr(aes)", - .cra_driver_name = "__ctr-aes-ce", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_INTERNAL, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct crypto_aes_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - .chunksize = AES_BLOCK_SIZE, - .setkey = ce_aes_setkey, - .encrypt = ctr_encrypt, - .decrypt = ctr_encrypt, + .base.cra_name = "__cts(cbc(aes))", + .base.cra_driver_name = "__cts-cbc-aes-ce", + .base.cra_priority = 300, + .base.cra_flags = CRYPTO_ALG_INTERNAL, + .base.cra_blocksize = AES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct crypto_aes_ctx), + .base.cra_module = THIS_MODULE, + + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .walksize = 2 * AES_BLOCK_SIZE, + .setkey = ce_aes_setkey, + .encrypt = cts_cbc_encrypt, + .decrypt = cts_cbc_decrypt, }, { - .base = { - .cra_name = "__xts(aes)", - .cra_driver_name = "__xts-aes-ce", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_INTERNAL, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypto_aes_xts_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = 2 * AES_MIN_KEY_SIZE, - .max_keysize = 2 * AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - .setkey = xts_set_key, - .encrypt = xts_encrypt, - .decrypt = xts_decrypt, + .base.cra_name = "__ctr(aes)", + .base.cra_driver_name = "__ctr-aes-ce", + .base.cra_priority = 300, + .base.cra_flags = CRYPTO_ALG_INTERNAL, + .base.cra_blocksize = 1, + .base.cra_ctxsize = sizeof(struct crypto_aes_ctx), + .base.cra_module = THIS_MODULE, + + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .chunksize = AES_BLOCK_SIZE, + .setkey = ce_aes_setkey, + .encrypt = ctr_encrypt, + .decrypt = ctr_encrypt, +}, { + .base.cra_name = "ctr(aes)", + .base.cra_driver_name = "ctr-aes-ce-sync", + .base.cra_priority = 300 - 1, + .base.cra_blocksize = 1, + .base.cra_ctxsize = sizeof(struct crypto_aes_ctx), + .base.cra_module = THIS_MODULE, + + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .chunksize = AES_BLOCK_SIZE, + .setkey = ce_aes_setkey, + .encrypt = ctr_encrypt_sync, + .decrypt = ctr_encrypt_sync, +}, { + .base.cra_name = "__xts(aes)", + .base.cra_driver_name = "__xts-aes-ce", + .base.cra_priority = 300, + .base.cra_flags = CRYPTO_ALG_INTERNAL, + .base.cra_blocksize = AES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct crypto_aes_xts_ctx), + .base.cra_module = THIS_MODULE, + + .min_keysize = 2 * AES_MIN_KEY_SIZE, + .max_keysize = 2 * AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .walksize = 2 * AES_BLOCK_SIZE, + .setkey = xts_set_key, + .encrypt = xts_encrypt, + .decrypt = xts_decrypt, } }; static struct simd_skcipher_alg *aes_simd_algs[ARRAY_SIZE(aes_algs)]; @@ -425,6 +715,9 @@ static int __init aes_init(void) return err; for (i = 0; i < ARRAY_SIZE(aes_algs); i++) { + if (!(aes_algs[i].base.cra_flags & CRYPTO_ALG_INTERNAL)) + continue; + algname = aes_algs[i].base.cra_name + 2; drvname = aes_algs[i].base.cra_driver_name + 2; basename = aes_algs[i].base.cra_driver_name; diff --git a/arch/arm/crypto/aes-cipher-core.S b/arch/arm/crypto/aes-cipher-core.S index 4460ed05d6ff3c8bf12e2cd17de25b54252a8e03..472e56d09eeae6d4f4fd4211960c49750bd4c649 100644 --- a/arch/arm/crypto/aes-cipher-core.S +++ b/arch/arm/crypto/aes-cipher-core.S @@ -219,43 +219,5 @@ ENDPROC(__aes_arm_encrypt) .align 5 ENTRY(__aes_arm_decrypt) - do_crypt iround, crypto_it_tab, __aes_arm_inverse_sbox, 0 + do_crypt iround, crypto_it_tab, crypto_aes_inv_sbox, 0 ENDPROC(__aes_arm_decrypt) - - .section ".rodata", "a" - .align L1_CACHE_SHIFT - .type __aes_arm_inverse_sbox, %object -__aes_arm_inverse_sbox: - .byte 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38 - .byte 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb - .byte 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87 - .byte 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb - .byte 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d - .byte 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e - .byte 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2 - .byte 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 - .byte 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16 - .byte 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 - .byte 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda - .byte 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 - .byte 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a - .byte 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 - .byte 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02 - .byte 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b - .byte 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea - .byte 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 - .byte 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85 - .byte 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e - .byte 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89 - .byte 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b - .byte 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20 - .byte 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 - .byte 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31 - .byte 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f - .byte 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d - .byte 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef - .byte 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0 - .byte 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 - .byte 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26 - .byte 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d - .size __aes_arm_inverse_sbox, . - __aes_arm_inverse_sbox diff --git a/arch/arm/crypto/aes-cipher-glue.c b/arch/arm/crypto/aes-cipher-glue.c index 128d0a1ac068f43c0ede5c70abaeeab5f2a9f756..8cd00f56800e7f97574a7f7756c896f546c7284c 100644 --- a/arch/arm/crypto/aes-cipher-glue.c +++ b/arch/arm/crypto/aes-cipher-glue.c @@ -11,12 +11,9 @@ #include asmlinkage void __aes_arm_encrypt(u32 *rk, int rounds, const u8 *in, u8 *out); -EXPORT_SYMBOL(__aes_arm_encrypt); - asmlinkage void __aes_arm_decrypt(u32 *rk, int rounds, const u8 *in, u8 *out); -EXPORT_SYMBOL(__aes_arm_decrypt); -static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +static void aes_arm_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); int rounds = 6 + ctx->key_length / 4; @@ -24,7 +21,7 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) __aes_arm_encrypt(ctx->key_enc, rounds, in, out); } -static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +static void aes_arm_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); int rounds = 6 + ctx->key_length / 4; @@ -44,8 +41,8 @@ static struct crypto_alg aes_alg = { .cra_cipher.cia_min_keysize = AES_MIN_KEY_SIZE, .cra_cipher.cia_max_keysize = AES_MAX_KEY_SIZE, .cra_cipher.cia_setkey = crypto_aes_set_key, - .cra_cipher.cia_encrypt = aes_encrypt, - .cra_cipher.cia_decrypt = aes_decrypt, + .cra_cipher.cia_encrypt = aes_arm_encrypt, + .cra_cipher.cia_decrypt = aes_arm_decrypt, #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS .cra_alignmask = 3, diff --git a/arch/arm/crypto/aes-neonbs-core.S b/arch/arm/crypto/aes-neonbs-core.S index d3eab76b6e1b37d43f19f1cd286323c1e2c461a6..cfaed4e67535f5ef7453c76336b474cd1923868c 100644 --- a/arch/arm/crypto/aes-neonbs-core.S +++ b/arch/arm/crypto/aes-neonbs-core.S @@ -887,19 +887,17 @@ ENDPROC(aesbs_ctr_encrypt) veor \out, \out, \tmp .endm - .align 4 -.Lxts_mul_x: - .quad 1, 0x87 - /* * aesbs_xts_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, - * int blocks, u8 iv[]) + * int blocks, u8 iv[], int reorder_last_tweak) * aesbs_xts_decrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, - * int blocks, u8 iv[]) + * int blocks, u8 iv[], int reorder_last_tweak) */ __xts_prepare8: vld1.8 {q14}, [r7] // load iv - __ldr q15, .Lxts_mul_x // load tweak mask + vmov.i32 d30, #0x87 // compose tweak mask vector + vmovl.u32 q15, d30 + vshr.u64 d30, d31, #7 vmov q12, q14 __adr ip, 0f @@ -946,17 +944,25 @@ __xts_prepare8: vld1.8 {q7}, [r1]! next_tweak q14, q12, q15, q13 - veor q7, q7, q12 +THUMB( itt le ) + W(cmple) r8, #0 + ble 1f +0: veor q7, q7, q12 vst1.8 {q12}, [r4, :128] -0: vst1.8 {q14}, [r7] // store next iv + vst1.8 {q14}, [r7] // store next iv bx lr + +1: vswp q12, q14 + b 0b ENDPROC(__xts_prepare8) .macro __xts_crypt, do8, o0, o1, o2, o3, o4, o5, o6, o7 push {r4-r8, lr} mov r5, sp // preserve sp ldrd r6, r7, [sp, #24] // get blocks and iv args + ldr r8, [sp, #32] // reorder final tweak? + rsb r8, r8, #1 sub ip, sp, #128 // make room for 8x tweak bic ip, ip, #0xf // align sp to 16 bytes mov sp, ip diff --git a/arch/arm/crypto/aes-neonbs-glue.c b/arch/arm/crypto/aes-neonbs-glue.c index bd0bee9c8f7b718813c8b60904e8e10ed2fc9e9e..e85839a8aaeb8b35d6f4f5e0ac804da1f7543c9d 100644 --- a/arch/arm/crypto/aes-neonbs-glue.c +++ b/arch/arm/crypto/aes-neonbs-glue.c @@ -6,10 +6,13 @@ */ #include +#include #include #include +#include #include #include +#include #include #include @@ -35,9 +38,9 @@ asmlinkage void aesbs_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, int blocks, u8 ctr[], u8 final[]); asmlinkage void aesbs_xts_encrypt(u8 out[], u8 const in[], u8 const rk[], - int rounds, int blocks, u8 iv[]); + int rounds, int blocks, u8 iv[], int); asmlinkage void aesbs_xts_decrypt(u8 out[], u8 const in[], u8 const rk[], - int rounds, int blocks, u8 iv[]); + int rounds, int blocks, u8 iv[], int); struct aesbs_ctx { int rounds; @@ -51,9 +54,15 @@ struct aesbs_cbc_ctx { struct aesbs_xts_ctx { struct aesbs_ctx key; + struct crypto_cipher *cts_tfm; struct crypto_cipher *tweak_tfm; }; +struct aesbs_ctr_ctx { + struct aesbs_ctx key; /* must be first member */ + struct crypto_aes_ctx fallback; +}; + static int aesbs_setkey(struct crypto_skcipher *tfm, const u8 *in_key, unsigned int key_len) { @@ -61,7 +70,7 @@ static int aesbs_setkey(struct crypto_skcipher *tfm, const u8 *in_key, struct crypto_aes_ctx rk; int err; - err = crypto_aes_expand_key(&rk, in_key, key_len); + err = aes_expandkey(&rk, in_key, key_len); if (err) return err; @@ -83,9 +92,8 @@ static int __ecb_crypt(struct skcipher_request *req, struct skcipher_walk walk; int err; - err = skcipher_walk_virt(&walk, req, true); + err = skcipher_walk_virt(&walk, req, false); - kernel_neon_begin(); while (walk.nbytes >= AES_BLOCK_SIZE) { unsigned int blocks = walk.nbytes / AES_BLOCK_SIZE; @@ -93,12 +101,13 @@ static int __ecb_crypt(struct skcipher_request *req, blocks = round_down(blocks, walk.stride / AES_BLOCK_SIZE); + kernel_neon_begin(); fn(walk.dst.virt.addr, walk.src.virt.addr, ctx->rk, ctx->rounds, blocks); + kernel_neon_end(); err = skcipher_walk_done(&walk, walk.nbytes - blocks * AES_BLOCK_SIZE); } - kernel_neon_end(); return err; } @@ -120,7 +129,7 @@ static int aesbs_cbc_setkey(struct crypto_skcipher *tfm, const u8 *in_key, struct crypto_aes_ctx rk; int err; - err = crypto_aes_expand_key(&rk, in_key, key_len); + err = aes_expandkey(&rk, in_key, key_len); if (err) return err; @@ -152,9 +161,8 @@ static int cbc_decrypt(struct skcipher_request *req) struct skcipher_walk walk; int err; - err = skcipher_walk_virt(&walk, req, true); + err = skcipher_walk_virt(&walk, req, false); - kernel_neon_begin(); while (walk.nbytes >= AES_BLOCK_SIZE) { unsigned int blocks = walk.nbytes / AES_BLOCK_SIZE; @@ -162,13 +170,14 @@ static int cbc_decrypt(struct skcipher_request *req) blocks = round_down(blocks, walk.stride / AES_BLOCK_SIZE); + kernel_neon_begin(); aesbs_cbc_decrypt(walk.dst.virt.addr, walk.src.virt.addr, ctx->key.rk, ctx->key.rounds, blocks, walk.iv); + kernel_neon_end(); err = skcipher_walk_done(&walk, walk.nbytes - blocks * AES_BLOCK_SIZE); } - kernel_neon_end(); return err; } @@ -189,6 +198,25 @@ static void cbc_exit(struct crypto_tfm *tfm) crypto_free_cipher(ctx->enc_tfm); } +static int aesbs_ctr_setkey_sync(struct crypto_skcipher *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct aesbs_ctr_ctx *ctx = crypto_skcipher_ctx(tfm); + int err; + + err = aes_expandkey(&ctx->fallback, in_key, key_len); + if (err) + return err; + + ctx->key.rounds = 6 + key_len / 4; + + kernel_neon_begin(); + aesbs_convert_key(ctx->key.rk, ctx->fallback.key_enc, ctx->key.rounds); + kernel_neon_end(); + + return 0; +} + static int ctr_encrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); @@ -197,9 +225,8 @@ static int ctr_encrypt(struct skcipher_request *req) u8 buf[AES_BLOCK_SIZE]; int err; - err = skcipher_walk_virt(&walk, req, true); + err = skcipher_walk_virt(&walk, req, false); - kernel_neon_begin(); while (walk.nbytes > 0) { unsigned int blocks = walk.nbytes / AES_BLOCK_SIZE; u8 *final = (walk.total % AES_BLOCK_SIZE) ? buf : NULL; @@ -210,8 +237,10 @@ static int ctr_encrypt(struct skcipher_request *req) final = NULL; } + kernel_neon_begin(); aesbs_ctr_encrypt(walk.dst.virt.addr, walk.src.virt.addr, ctx->rk, ctx->rounds, blocks, walk.iv, final); + kernel_neon_end(); if (final) { u8 *dst = walk.dst.virt.addr + blocks * AES_BLOCK_SIZE; @@ -226,11 +255,33 @@ static int ctr_encrypt(struct skcipher_request *req) err = skcipher_walk_done(&walk, walk.nbytes - blocks * AES_BLOCK_SIZE); } - kernel_neon_end(); return err; } +static void ctr_encrypt_one(struct crypto_skcipher *tfm, const u8 *src, u8 *dst) +{ + struct aesbs_ctr_ctx *ctx = crypto_skcipher_ctx(tfm); + unsigned long flags; + + /* + * Temporarily disable interrupts to avoid races where + * cachelines are evicted when the CPU is interrupted + * to do something else. + */ + local_irq_save(flags); + aes_encrypt(&ctx->fallback, dst, src); + local_irq_restore(flags); +} + +static int ctr_encrypt_sync(struct skcipher_request *req) +{ + if (!crypto_simd_usable()) + return crypto_ctr_encrypt_walk(req, ctr_encrypt_one); + + return ctr_encrypt(req); +} + static int aesbs_xts_setkey(struct crypto_skcipher *tfm, const u8 *in_key, unsigned int key_len) { @@ -242,6 +293,9 @@ static int aesbs_xts_setkey(struct crypto_skcipher *tfm, const u8 *in_key, return err; key_len /= 2; + err = crypto_cipher_setkey(ctx->cts_tfm, in_key, key_len); + if (err) + return err; err = crypto_cipher_setkey(ctx->tweak_tfm, in_key + key_len, key_len); if (err) return err; @@ -253,7 +307,13 @@ static int xts_init(struct crypto_tfm *tfm) { struct aesbs_xts_ctx *ctx = crypto_tfm_ctx(tfm); + ctx->cts_tfm = crypto_alloc_cipher("aes", 0, 0); + if (IS_ERR(ctx->cts_tfm)) + return PTR_ERR(ctx->cts_tfm); + ctx->tweak_tfm = crypto_alloc_cipher("aes", 0, 0); + if (IS_ERR(ctx->tweak_tfm)) + crypto_free_cipher(ctx->cts_tfm); return PTR_ERR_OR_ZERO(ctx->tweak_tfm); } @@ -263,49 +323,89 @@ static void xts_exit(struct crypto_tfm *tfm) struct aesbs_xts_ctx *ctx = crypto_tfm_ctx(tfm); crypto_free_cipher(ctx->tweak_tfm); + crypto_free_cipher(ctx->cts_tfm); } -static int __xts_crypt(struct skcipher_request *req, +static int __xts_crypt(struct skcipher_request *req, bool encrypt, void (*fn)(u8 out[], u8 const in[], u8 const rk[], - int rounds, int blocks, u8 iv[])) + int rounds, int blocks, u8 iv[], int)) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct aesbs_xts_ctx *ctx = crypto_skcipher_ctx(tfm); + int tail = req->cryptlen % AES_BLOCK_SIZE; + struct skcipher_request subreq; + u8 buf[2 * AES_BLOCK_SIZE]; struct skcipher_walk walk; int err; + if (req->cryptlen < AES_BLOCK_SIZE) + return -EINVAL; + + if (unlikely(tail)) { + skcipher_request_set_tfm(&subreq, tfm); + skcipher_request_set_callback(&subreq, + skcipher_request_flags(req), + NULL, NULL); + skcipher_request_set_crypt(&subreq, req->src, req->dst, + req->cryptlen - tail, req->iv); + req = &subreq; + } + err = skcipher_walk_virt(&walk, req, true); if (err) return err; crypto_cipher_encrypt_one(ctx->tweak_tfm, walk.iv, walk.iv); - kernel_neon_begin(); while (walk.nbytes >= AES_BLOCK_SIZE) { unsigned int blocks = walk.nbytes / AES_BLOCK_SIZE; + int reorder_last_tweak = !encrypt && tail > 0; - if (walk.nbytes < walk.total) + if (walk.nbytes < walk.total) { blocks = round_down(blocks, walk.stride / AES_BLOCK_SIZE); + reorder_last_tweak = 0; + } + kernel_neon_begin(); fn(walk.dst.virt.addr, walk.src.virt.addr, ctx->key.rk, - ctx->key.rounds, blocks, walk.iv); + ctx->key.rounds, blocks, walk.iv, reorder_last_tweak); + kernel_neon_end(); err = skcipher_walk_done(&walk, walk.nbytes - blocks * AES_BLOCK_SIZE); } - kernel_neon_end(); - return err; + if (err || likely(!tail)) + return err; + + /* handle ciphertext stealing */ + scatterwalk_map_and_copy(buf, req->dst, req->cryptlen - AES_BLOCK_SIZE, + AES_BLOCK_SIZE, 0); + memcpy(buf + AES_BLOCK_SIZE, buf, tail); + scatterwalk_map_and_copy(buf, req->src, req->cryptlen, tail, 0); + + crypto_xor(buf, req->iv, AES_BLOCK_SIZE); + + if (encrypt) + crypto_cipher_encrypt_one(ctx->cts_tfm, buf, buf); + else + crypto_cipher_decrypt_one(ctx->cts_tfm, buf, buf); + + crypto_xor(buf, req->iv, AES_BLOCK_SIZE); + + scatterwalk_map_and_copy(buf, req->dst, req->cryptlen - AES_BLOCK_SIZE, + AES_BLOCK_SIZE + tail, 1); + return 0; } static int xts_encrypt(struct skcipher_request *req) { - return __xts_crypt(req, aesbs_xts_encrypt); + return __xts_crypt(req, true, aesbs_xts_encrypt); } static int xts_decrypt(struct skcipher_request *req) { - return __xts_crypt(req, aesbs_xts_decrypt); + return __xts_crypt(req, false, aesbs_xts_decrypt); } static struct skcipher_alg aes_algs[] = { { @@ -358,6 +458,22 @@ static struct skcipher_alg aes_algs[] = { { .setkey = aesbs_setkey, .encrypt = ctr_encrypt, .decrypt = ctr_encrypt, +}, { + .base.cra_name = "ctr(aes)", + .base.cra_driver_name = "ctr-aes-neonbs-sync", + .base.cra_priority = 250 - 1, + .base.cra_blocksize = 1, + .base.cra_ctxsize = sizeof(struct aesbs_ctr_ctx), + .base.cra_module = THIS_MODULE, + + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .chunksize = AES_BLOCK_SIZE, + .walksize = 8 * AES_BLOCK_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = aesbs_ctr_setkey_sync, + .encrypt = ctr_encrypt_sync, + .decrypt = ctr_encrypt_sync, }, { .base.cra_name = "__xts(aes)", .base.cra_driver_name = "__xts-aes-neonbs", diff --git a/arch/arm/crypto/ghash-ce-glue.c b/arch/arm/crypto/ghash-ce-glue.c index 52d472a050e6aea9b8e887bfe96c9e8faa726f2a..c691077679a63140941afc8d3f308db28503936a 100644 --- a/arch/arm/crypto/ghash-ce-glue.c +++ b/arch/arm/crypto/ghash-ce-glue.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -17,7 +18,7 @@ #include #include -MODULE_DESCRIPTION("GHASH secure hash using ARMv8 Crypto Extensions"); +MODULE_DESCRIPTION("GHASH hash function using ARMv8 Crypto Extensions"); MODULE_AUTHOR("Ard Biesheuvel "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS_CRYPTO("ghash"); @@ -30,6 +31,8 @@ struct ghash_key { u64 h2[2]; u64 h3[2]; u64 h4[2]; + + be128 k; }; struct ghash_desc_ctx { @@ -62,6 +65,36 @@ static int ghash_init(struct shash_desc *desc) return 0; } +static void ghash_do_update(int blocks, u64 dg[], const char *src, + struct ghash_key *key, const char *head) +{ + if (likely(crypto_simd_usable())) { + kernel_neon_begin(); + pmull_ghash_update(blocks, dg, src, key, head); + kernel_neon_end(); + } else { + be128 dst = { cpu_to_be64(dg[1]), cpu_to_be64(dg[0]) }; + + do { + const u8 *in = src; + + if (head) { + in = head; + blocks++; + head = NULL; + } else { + src += GHASH_BLOCK_SIZE; + } + + crypto_xor((u8 *)&dst, in, GHASH_BLOCK_SIZE); + gf128mul_lle(&dst, &key->k); + } while (--blocks); + + dg[0] = be64_to_cpu(dst.b); + dg[1] = be64_to_cpu(dst.a); + } +} + static int ghash_update(struct shash_desc *desc, const u8 *src, unsigned int len) { @@ -85,10 +118,8 @@ static int ghash_update(struct shash_desc *desc, const u8 *src, blocks = len / GHASH_BLOCK_SIZE; len %= GHASH_BLOCK_SIZE; - kernel_neon_begin(); - pmull_ghash_update(blocks, ctx->digest, src, key, - partial ? ctx->buf : NULL); - kernel_neon_end(); + ghash_do_update(blocks, ctx->digest, src, key, + partial ? ctx->buf : NULL); src += blocks * GHASH_BLOCK_SIZE; partial = 0; } @@ -106,9 +137,7 @@ static int ghash_final(struct shash_desc *desc, u8 *dst) struct ghash_key *key = crypto_shash_ctx(desc->tfm); memset(ctx->buf + partial, 0, GHASH_BLOCK_SIZE - partial); - kernel_neon_begin(); - pmull_ghash_update(1, ctx->digest, ctx->buf, key, NULL); - kernel_neon_end(); + ghash_do_update(1, ctx->digest, ctx->buf, key, NULL); } put_unaligned_be64(ctx->digest[1], dst); put_unaligned_be64(ctx->digest[0], dst + 8); @@ -132,24 +161,25 @@ static int ghash_setkey(struct crypto_shash *tfm, const u8 *inkey, unsigned int keylen) { struct ghash_key *key = crypto_shash_ctx(tfm); - be128 h, k; + be128 h; if (keylen != GHASH_BLOCK_SIZE) { crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } - memcpy(&k, inkey, GHASH_BLOCK_SIZE); - ghash_reflect(key->h, &k); + /* needed for the fallback */ + memcpy(&key->k, inkey, GHASH_BLOCK_SIZE); + ghash_reflect(key->h, &key->k); - h = k; - gf128mul_lle(&h, &k); + h = key->k; + gf128mul_lle(&h, &key->k); ghash_reflect(key->h2, &h); - gf128mul_lle(&h, &k); + gf128mul_lle(&h, &key->k); ghash_reflect(key->h3, &h); - gf128mul_lle(&h, &k); + gf128mul_lle(&h, &key->k); ghash_reflect(key->h4, &h); return 0; @@ -162,15 +192,13 @@ static struct shash_alg ghash_alg = { .final = ghash_final, .setkey = ghash_setkey, .descsize = sizeof(struct ghash_desc_ctx), - .base = { - .cra_name = "__ghash", - .cra_driver_name = "__driver-ghash-ce", - .cra_priority = 0, - .cra_flags = CRYPTO_ALG_INTERNAL, - .cra_blocksize = GHASH_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct ghash_key), - .cra_module = THIS_MODULE, - }, + + .base.cra_name = "ghash", + .base.cra_driver_name = "ghash-ce-sync", + .base.cra_priority = 300 - 1, + .base.cra_blocksize = GHASH_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct ghash_key), + .base.cra_module = THIS_MODULE, }; static int ghash_async_init(struct ahash_request *req) @@ -285,9 +313,7 @@ static int ghash_async_init_tfm(struct crypto_tfm *tfm) struct cryptd_ahash *cryptd_tfm; struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm); - cryptd_tfm = cryptd_alloc_ahash("__driver-ghash-ce", - CRYPTO_ALG_INTERNAL, - CRYPTO_ALG_INTERNAL); + cryptd_tfm = cryptd_alloc_ahash("ghash-ce-sync", 0, 0); if (IS_ERR(cryptd_tfm)) return PTR_ERR(cryptd_tfm); ctx->cryptd_tfm = cryptd_tfm; diff --git a/arch/arm/crypto/sha256_glue.c b/arch/arm/crypto/sha256_glue.c index 70efa9656bffc768a9cf471fb1314a26eb939493..215497f011f2393461d3e297d78c7fd2ef2ad70f 100644 --- a/arch/arm/crypto/sha256_glue.c +++ b/arch/arm/crypto/sha256_glue.c @@ -39,7 +39,7 @@ int crypto_sha256_arm_update(struct shash_desc *desc, const u8 *data, } EXPORT_SYMBOL(crypto_sha256_arm_update); -static int sha256_final(struct shash_desc *desc, u8 *out) +static int crypto_sha256_arm_final(struct shash_desc *desc, u8 *out) { sha256_base_do_finalize(desc, (sha256_block_fn *)sha256_block_data_order); @@ -51,7 +51,7 @@ int crypto_sha256_arm_finup(struct shash_desc *desc, const u8 *data, { sha256_base_do_update(desc, data, len, (sha256_block_fn *)sha256_block_data_order); - return sha256_final(desc, out); + return crypto_sha256_arm_final(desc, out); } EXPORT_SYMBOL(crypto_sha256_arm_finup); @@ -59,7 +59,7 @@ static struct shash_alg algs[] = { { .digestsize = SHA256_DIGEST_SIZE, .init = sha256_base_init, .update = crypto_sha256_arm_update, - .final = sha256_final, + .final = crypto_sha256_arm_final, .finup = crypto_sha256_arm_finup, .descsize = sizeof(struct sha256_state), .base = { @@ -73,7 +73,7 @@ static struct shash_alg algs[] = { { .digestsize = SHA224_DIGEST_SIZE, .init = sha224_base_init, .update = crypto_sha256_arm_update, - .final = sha256_final, + .final = crypto_sha256_arm_final, .finup = crypto_sha256_arm_finup, .descsize = sizeof(struct sha256_state), .base = { diff --git a/arch/arm/crypto/sha256_neon_glue.c b/arch/arm/crypto/sha256_neon_glue.c index a7ce38a36006d5da918e2cb82795d11e15872bf4..38645e415196e6559eacf4426ccf8e261e9402e7 100644 --- a/arch/arm/crypto/sha256_neon_glue.c +++ b/arch/arm/crypto/sha256_neon_glue.c @@ -25,8 +25,8 @@ asmlinkage void sha256_block_data_order_neon(u32 *digest, const void *data, unsigned int num_blks); -static int sha256_update(struct shash_desc *desc, const u8 *data, - unsigned int len) +static int crypto_sha256_neon_update(struct shash_desc *desc, const u8 *data, + unsigned int len) { struct sha256_state *sctx = shash_desc_ctx(desc); @@ -42,8 +42,8 @@ static int sha256_update(struct shash_desc *desc, const u8 *data, return 0; } -static int sha256_finup(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *out) +static int crypto_sha256_neon_finup(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) { if (!crypto_simd_usable()) return crypto_sha256_arm_finup(desc, data, len, out); @@ -59,17 +59,17 @@ static int sha256_finup(struct shash_desc *desc, const u8 *data, return sha256_base_finish(desc, out); } -static int sha256_final(struct shash_desc *desc, u8 *out) +static int crypto_sha256_neon_final(struct shash_desc *desc, u8 *out) { - return sha256_finup(desc, NULL, 0, out); + return crypto_sha256_neon_finup(desc, NULL, 0, out); } struct shash_alg sha256_neon_algs[] = { { .digestsize = SHA256_DIGEST_SIZE, .init = sha256_base_init, - .update = sha256_update, - .final = sha256_final, - .finup = sha256_finup, + .update = crypto_sha256_neon_update, + .final = crypto_sha256_neon_final, + .finup = crypto_sha256_neon_finup, .descsize = sizeof(struct sha256_state), .base = { .cra_name = "sha256", @@ -81,9 +81,9 @@ struct shash_alg sha256_neon_algs[] = { { }, { .digestsize = SHA224_DIGEST_SIZE, .init = sha224_base_init, - .update = sha256_update, - .final = sha256_final, - .finup = sha256_finup, + .update = crypto_sha256_neon_update, + .final = crypto_sha256_neon_final, + .finup = crypto_sha256_neon_finup, .descsize = sizeof(struct sha256_state), .base = { .cra_name = "sha224", diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild index 6b2dc15b6dff96f12686e67aa2cd44aab14c0e05..68ca86f85eb7351e984983bbb3ecbf240e3c79ac 100644 --- a/arch/arm/include/asm/Kbuild +++ b/arch/arm/include/asm/Kbuild @@ -17,7 +17,6 @@ generic-y += parport.h generic-y += preempt.h generic-y += seccomp.h generic-y += serial.h -generic-y += simd.h generic-y += trace_clock.h generated-y += mach-types.h diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h index 2a786f54d8b8b26af5b17f00c3373e09da3e30f8..8a0fae94d45ef3a2753c2515dcb3a1b569ffe446 100644 --- a/arch/arm/include/asm/topology.h +++ b/arch/arm/include/asm/topology.h @@ -5,26 +5,6 @@ #ifdef CONFIG_ARM_CPU_TOPOLOGY #include - -struct cputopo_arm { - int thread_id; - int core_id; - int socket_id; - cpumask_t thread_sibling; - cpumask_t core_sibling; -}; - -extern struct cputopo_arm cpu_topology[NR_CPUS]; - -#define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id) -#define topology_core_id(cpu) (cpu_topology[cpu].core_id) -#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling) -#define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_sibling) - -void init_cpu_topology(void); -void store_cpu_topology(unsigned int cpuid); -const struct cpumask *cpu_coregroup_mask(int cpu); - #include /* Replace task scheduler's default frequency-invariant accounting */ diff --git a/arch/arm/include/debug/ks8695.S b/arch/arm/include/debug/ks8695.S deleted file mode 100644 index eb4d371b5eea65e9b958ac0c7738ca3945890f79..0000000000000000000000000000000000000000 --- a/arch/arm/include/debug/ks8695.S +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/include/debug/ks8695.S - * - * Copyright (C) 2006 Ben Dooks - * Copyright (C) 2006 Simtec Electronics - * - * KS8695 - Debug macros - */ - -#define KS8695_UART_PA 0x03ffe000 -#define KS8695_UART_VA 0xf00fe000 -#define KS8695_URTH (0x04) -#define KS8695_URLS (0x14) -#define URLS_URTE (1 << 6) -#define URLS_URTHRE (1 << 5) - - .macro addruart, rp, rv, tmp - ldr \rp, =KS8695_UART_PA @ physical base address - ldr \rv, =KS8695_UART_VA @ virtual base address - .endm - - .macro senduart, rd, rx - str \rd, [\rx, #KS8695_URTH] @ Write to Transmit Holding Register - .endm - - .macro busyuart, rd, rx -1001: ldr \rd, [\rx, #KS8695_URLS] @ Read Line Status Register - tst \rd, #URLS_URTE @ Holding & Shift registers empty? - beq 1001b - .endm - - .macro waituart, rd, rx -1001: ldr \rd, [\rx, #KS8695_URLS] @ Read Line Status Register - tst \rd, #URLS_URTHRE @ Holding Register empty? - beq 1001b - .endm diff --git a/arch/arm/include/debug/renesas-scif.S b/arch/arm/include/debug/renesas-scif.S index 1c5f795587fc5681bc126dad8a44c7a26ad32f00..25f06663a9a4e2c1b2f569b8bb10b5c503a78e83 100644 --- a/arch/arm/include/debug/renesas-scif.S +++ b/arch/arm/include/debug/renesas-scif.S @@ -11,7 +11,11 @@ #define SCIF_PHYS CONFIG_DEBUG_UART_PHYS #define SCIF_VIRT ((SCIF_PHYS & 0x00ffffff) | 0xfd000000) -#if CONFIG_DEBUG_UART_PHYS < 0xe6e00000 +#if defined(CONFIG_DEBUG_R7S9210_SCIF2) || defined(CONFIG_DEBUG_R7S9210_SCIF4) +/* RZ/A2 SCIFA */ +#define FTDR 0x06 +#define FSR 0x08 +#elif CONFIG_DEBUG_UART_PHYS < 0xe6e00000 /* SCIFA */ #define FTDR 0x20 #define FSR 0x14 diff --git a/arch/arm/include/debug/ux500.S b/arch/arm/include/debug/ux500.S index c626f89b3e4a5f84983a4cbcb0857be3aa30df8e..c516900947bb4e39dc7d28c88e1a93d2d2f37ec1 100644 --- a/arch/arm/include/debug/ux500.S +++ b/arch/arm/include/debug/ux500.S @@ -20,21 +20,16 @@ #define U8500_UART0_PHYS_BASE (0x80120000) #define U8500_UART1_PHYS_BASE (0x80121000) #define U8500_UART2_PHYS_BASE (0x80007000) -#define U8500_UART0_VIRT_BASE (0xf8120000) -#define U8500_UART1_VIRT_BASE (0xf8121000) -#define U8500_UART2_VIRT_BASE (0xf8007000) #define __UX500_PHYS_UART(n) U8500_UART##n##_PHYS_BASE -#define __UX500_VIRT_UART(n) U8500_UART##n##_VIRT_BASE #endif -#if !defined(__UX500_PHYS_UART) || !defined(__UX500_VIRT_UART) +#if !defined(__UX500_PHYS_UART) #error Unknown SOC #endif #define UX500_PHYS_UART(n) __UX500_PHYS_UART(n) -#define UX500_VIRT_UART(n) __UX500_VIRT_UART(n) #define UART_PHYS_BASE UX500_PHYS_UART(CONFIG_UX500_DEBUG_UART) -#define UART_VIRT_BASE UX500_VIRT_UART(CONFIG_UX500_DEBUG_UART) +#define UART_VIRT_BASE (0xfff07000) .macro addruart, rp, rv, tmp ldr \rp, =UART_PHYS_BASE @ no, physical address diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h index a4217c1a5d01178c53346ea3f48ed3415aa956fd..2769360f195cafe1ead78ea917495778a7a52c21 100644 --- a/arch/arm/include/uapi/asm/kvm.h +++ b/arch/arm/include/uapi/asm/kvm.h @@ -266,8 +266,10 @@ struct kvm_vcpu_events { #define KVM_DEV_ARM_ITS_CTRL_RESET 4 /* KVM_IRQ_LINE irq field index values */ +#define KVM_ARM_IRQ_VCPU2_SHIFT 28 +#define KVM_ARM_IRQ_VCPU2_MASK 0xf #define KVM_ARM_IRQ_TYPE_SHIFT 24 -#define KVM_ARM_IRQ_TYPE_MASK 0xff +#define KVM_ARM_IRQ_TYPE_MASK 0xf #define KVM_ARM_IRQ_VCPU_SHIFT 16 #define KVM_ARM_IRQ_VCPU_MASK 0xff #define KVM_ARM_IRQ_NUM_SHIFT 0 diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index aab8ba40ce38d6884f103d05e4a24eedfd923cb7..4b0bab2607e47b67a986eb0973d1493f5ad8e44b 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -264,15 +264,13 @@ int __cpu_disable(void) return 0; } -static DECLARE_COMPLETION(cpu_died); - /* * called on the thread which is asking for a CPU to be shutdown - * waits until shutdown has completed, or it is timed out. */ void __cpu_die(unsigned int cpu) { - if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) { + if (!cpu_wait_death(cpu, 5)) { pr_err("CPU%u: cpu didn't die\n", cpu); return; } @@ -319,7 +317,7 @@ void arch_cpu_idle_dead(void) * this returns, power and/or clocks can be removed at any point * from this CPU and its cache by platform_cpu_kill(). */ - complete(&cpu_died); + (void)cpu_report_death(); /* * Ensure that the cache lines associated with that completion are diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index d17cb1e6d67924b059a8aa855591aa9fad7305bd..5b9faba03afba6a31ca962d034b5838c302d26ae 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c @@ -177,17 +177,6 @@ static inline void parse_dt_topology(void) {} static inline void update_cpu_capacity(unsigned int cpuid) {} #endif - /* - * cpu topology table - */ -struct cputopo_arm cpu_topology[NR_CPUS]; -EXPORT_SYMBOL_GPL(cpu_topology); - -const struct cpumask *cpu_coregroup_mask(int cpu) -{ - return &cpu_topology[cpu].core_sibling; -} - /* * The current assumption is that we can power gate each core independently. * This will be superseded by DT binding once available. @@ -197,32 +186,6 @@ const struct cpumask *cpu_corepower_mask(int cpu) return &cpu_topology[cpu].thread_sibling; } -static void update_siblings_masks(unsigned int cpuid) -{ - struct cputopo_arm *cpu_topo, *cpuid_topo = &cpu_topology[cpuid]; - int cpu; - - /* update core and thread sibling masks */ - for_each_possible_cpu(cpu) { - cpu_topo = &cpu_topology[cpu]; - - if (cpuid_topo->socket_id != cpu_topo->socket_id) - continue; - - cpumask_set_cpu(cpuid, &cpu_topo->core_sibling); - if (cpu != cpuid) - cpumask_set_cpu(cpu, &cpuid_topo->core_sibling); - - if (cpuid_topo->core_id != cpu_topo->core_id) - continue; - - cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling); - if (cpu != cpuid) - cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling); - } - smp_wmb(); -} - /* * store_cpu_topology is called at boot when only one cpu is running * and with the mutex cpu_hotplug.lock locked, when several cpus have booted, @@ -230,7 +193,7 @@ static void update_siblings_masks(unsigned int cpuid) */ void store_cpu_topology(unsigned int cpuid) { - struct cputopo_arm *cpuid_topo = &cpu_topology[cpuid]; + struct cpu_topology *cpuid_topo = &cpu_topology[cpuid]; unsigned int mpidr; /* If the cpu topology has been already set, just return */ @@ -250,12 +213,12 @@ void store_cpu_topology(unsigned int cpuid) /* core performance interdependency */ cpuid_topo->thread_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 1); - cpuid_topo->socket_id = MPIDR_AFFINITY_LEVEL(mpidr, 2); + cpuid_topo->package_id = MPIDR_AFFINITY_LEVEL(mpidr, 2); } else { /* largely independent cores */ cpuid_topo->thread_id = -1; cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); - cpuid_topo->socket_id = MPIDR_AFFINITY_LEVEL(mpidr, 1); + cpuid_topo->package_id = MPIDR_AFFINITY_LEVEL(mpidr, 1); } } else { /* @@ -265,7 +228,7 @@ void store_cpu_topology(unsigned int cpuid) */ cpuid_topo->thread_id = -1; cpuid_topo->core_id = 0; - cpuid_topo->socket_id = -1; + cpuid_topo->package_id = -1; } update_siblings_masks(cpuid); @@ -275,7 +238,7 @@ void store_cpu_topology(unsigned int cpuid) pr_info("CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n", cpuid, cpu_topology[cpuid].thread_id, cpu_topology[cpuid].core_id, - cpu_topology[cpuid].socket_id, mpidr); + cpu_topology[cpuid].package_id, mpidr); } static inline int cpu_corepower_flags(void) @@ -298,18 +261,7 @@ static struct sched_domain_topology_level arm_topology[] = { */ void __init init_cpu_topology(void) { - unsigned int cpu; - - /* init core mask and capacity */ - for_each_possible_cpu(cpu) { - struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]); - - cpu_topo->thread_id = -1; - cpu_topo->core_id = -1; - cpu_topo->socket_id = -1; - cpumask_clear(&cpu_topo->core_sibling); - cpumask_clear(&cpu_topo->thread_sibling); - } + reset_cpu_topology(); smp_wmb(); parse_dt_topology(); diff --git a/arch/arm/mach-aspeed/Kconfig b/arch/arm/mach-aspeed/Kconfig index a15c3a2913861b116b916beb8a0f519d8ce25201..56007b0b6120d626cc2c2deb0e63067dd521439b 100644 --- a/arch/arm/mach-aspeed/Kconfig +++ b/arch/arm/mach-aspeed/Kconfig @@ -1,11 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only menuconfig ARCH_ASPEED bool "Aspeed BMC architectures" - depends on ARCH_MULTI_V5 || ARCH_MULTI_V6 + depends on ARCH_MULTI_V5 || ARCH_MULTI_V6 || ARCH_MULTI_V7 select SRAM select WATCHDOG select ASPEED_WATCHDOG - select FTTMR010_TIMER select MFD_SYSCON select PINCTRL help @@ -18,6 +17,7 @@ config MACH_ASPEED_G4 depends on ARCH_MULTI_V5 select CPU_ARM926T select PINCTRL_ASPEED_G4 + select FTTMR010_TIMER help Say yes if you intend to run on an Aspeed ast2400 or similar fourth generation BMCs, such as those used by OpenPower Power8 @@ -28,8 +28,21 @@ config MACH_ASPEED_G5 depends on ARCH_MULTI_V6 select CPU_V6 select PINCTRL_ASPEED_G5 + select FTTMR010_TIMER help Say yes if you intend to run on an Aspeed ast2500 or similar fifth generation Aspeed BMCs. +config MACH_ASPEED_G6 + bool "Aspeed SoC 6th Generation" + depends on ARCH_MULTI_V7 + select CPU_V7 + select PINCTRL_ASPEED_G6 + select ARM_GIC + select HAVE_ARM_ARCH_TIMER + select HAVE_SMP + help + Say yes if you intend to run on an Aspeed ast2600 or similar + sixth generation Aspeed BMCs. + endif diff --git a/arch/arm/mach-aspeed/Makefile b/arch/arm/mach-aspeed/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1951b3317a763d69e87eb24d37184301227b78b7 --- /dev/null +++ b/arch/arm/mach-aspeed/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) ASPEED Technology Inc. +# Copyright IBM Corp. + +obj-$(CONFIG_SMP) += platsmp.o diff --git a/arch/arm/mach-aspeed/platsmp.c b/arch/arm/mach-aspeed/platsmp.c new file mode 100644 index 0000000000000000000000000000000000000000..2324becf7991959d0ba6f737c9132669fba2ba9d --- /dev/null +++ b/arch/arm/mach-aspeed/platsmp.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (C) ASPEED Technology Inc. +// Copyright IBM Corp. + +#include +#include +#include +#include + +#define BOOT_ADDR 0x00 +#define BOOT_SIG 0x04 + +static struct device_node *secboot_node; + +static int aspeed_g6_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + void __iomem *base; + + base = of_iomap(secboot_node, 0); + if (!base) { + pr_err("could not map the secondary boot base!"); + return -ENODEV; + } + + writel_relaxed(0, base + BOOT_ADDR); + writel_relaxed(__pa_symbol(secondary_startup_arm), base + BOOT_ADDR); + writel_relaxed((0xABBAAB00 | (cpu & 0xff)), base + BOOT_SIG); + + dsb_sev(); + + iounmap(base); + + return 0; +} + +static void __init aspeed_g6_smp_prepare_cpus(unsigned int max_cpus) +{ + void __iomem *base; + + secboot_node = of_find_compatible_node(NULL, NULL, "aspeed,ast2600-smpmem"); + if (!secboot_node) { + pr_err("secboot device node found!!\n"); + return; + } + + base = of_iomap(secboot_node, 0); + if (!base) { + pr_err("could not map the secondary boot base!"); + return; + } + __raw_writel(0xBADABABA, base + BOOT_SIG); + + iounmap(base); +} + +static const struct smp_operations aspeed_smp_ops __initconst = { + .smp_prepare_cpus = aspeed_g6_smp_prepare_cpus, + .smp_boot_secondary = aspeed_g6_boot_secondary, +}; + +CPU_METHOD_OF_DECLARE(aspeed_smp, "aspeed,ast2600-smp", &aspeed_smp_ops); diff --git a/arch/arm/mach-at91/.gitignore b/arch/arm/mach-at91/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..2ecd6f51c8a95f72276cbb7b03b83b4c98dc0d48 --- /dev/null +++ b/arch/arm/mach-at91/.gitignore @@ -0,0 +1 @@ +pm_data-offsets.h diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index 31b61f0e1c077e707a96590ee7b9f40c4b5a230e..de64301dcff25143ad94fb0222d9eb427f71687e 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -19,9 +19,10 @@ ifeq ($(CONFIG_PM_DEBUG),y) CFLAGS_pm.o += -DDEBUG endif -include/generated/at91_pm_data-offsets.h: arch/arm/mach-at91/pm_data-offsets.s FORCE +$(obj)/pm_data-offsets.h: $(obj)/pm_data-offsets.s FORCE $(call filechk,offsets,__PM_DATA_OFFSETS_H__) -arch/arm/mach-at91/pm_suspend.o: include/generated/at91_pm_data-offsets.h +$(obj)/pm_suspend.o: $(obj)/pm_data-offsets.h targets += pm_data-offsets.s +clean-files += pm_data-offsets.h diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index c751f047b11660bc6b2919df649fe969a988743e..ed57c879d4e17b77a3c04aa87be937c8a817d115 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -10,7 +10,7 @@ #include #include #include "pm.h" -#include "generated/at91_pm_data-offsets.h" +#include "pm_data-offsets.h" #define SRAMC_SELF_FRESH_ACTIVE 0x01 #define SRAMC_SELF_FRESH_EXIT 0x00 diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index 5a59cebc7d0af9e22854a4da34472a1983ba0c81..dd427bd2768c3cf6f49152a1443cf154a51ad439 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig @@ -1,11 +1,22 @@ # SPDX-License-Identifier: GPL-2.0 + +menuconfig ARCH_DAVINCI + bool "TI DaVinci" + depends on ARCH_MULTI_V5 + select DAVINCI_TIMER + select ZONE_DMA + select ARCH_HAS_HOLES_MEMORYMODEL + select PM_GENERIC_DOMAINS if PM + select PM_GENERIC_DOMAINS_OF if PM && OF + select REGMAP_MMIO + select HAVE_IDE + select PINCTRL_SINGLE + if ARCH_DAVINCI config ARCH_DAVINCI_DMx bool -menu "TI DaVinci Implementations" - comment "DaVinci Core Type" config ARCH_DAVINCI_DM644x @@ -225,6 +236,4 @@ config DAVINCI_MUX_WARNINGS to change the pin multiplexing setup. When there are no warnings printed, it's safe to deselect DAVINCI_MUX for your product. -endmenu - endif diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile index f76a8482784f913bc492b5d3c9110104c7f40192..a03d8443ef08ef7e460619b98d8f3afbe40227a4 100644 --- a/arch/arm/mach-davinci/Makefile +++ b/arch/arm/mach-davinci/Makefile @@ -4,6 +4,8 @@ # # +ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include + # Common objects obj-y := time.o serial.o usb.o \ common.o sram.o diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 0628e7d7dcf3f05ce6c6c83ae7b939e9676cba65..5b3549f1236c56ee787b10ec43ef2aac93a4e583 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -802,37 +803,79 @@ static const short da850_evm_mmcsd0_pins[] __initconst = { -1 }; -static void da850_panel_power_ctrl(int val) -{ - /* lcd backlight */ - gpio_set_value(DA850_LCD_BL_PIN, val); +static struct property_entry da850_lcd_backlight_props[] = { + PROPERTY_ENTRY_BOOL("default-on"), + { } +}; - /* lcd power */ - gpio_set_value(DA850_LCD_PWR_PIN, val); -} +static struct gpiod_lookup_table da850_lcd_backlight_gpio_table = { + .dev_id = "gpio-backlight", + .table = { + GPIO_LOOKUP("davinci_gpio", DA850_LCD_BL_PIN, NULL, 0), + { } + }, +}; + +static const struct platform_device_info da850_lcd_backlight_info = { + .name = "gpio-backlight", + .id = PLATFORM_DEVID_NONE, + .properties = da850_lcd_backlight_props, +}; + +static struct regulator_consumer_supply da850_lcd_supplies[] = { + REGULATOR_SUPPLY("lcd", NULL), +}; + +static struct regulator_init_data da850_lcd_supply_data = { + .consumer_supplies = da850_lcd_supplies, + .num_consumer_supplies = ARRAY_SIZE(da850_lcd_supplies), + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, +}; + +static struct fixed_voltage_config da850_lcd_supply = { + .supply_name = "lcd", + .microvolts = 33000000, + .init_data = &da850_lcd_supply_data, +}; + +static struct platform_device da850_lcd_supply_device = { + .name = "reg-fixed-voltage", + .id = 1, /* Dummy fixed regulator is 0 */ + .dev = { + .platform_data = &da850_lcd_supply, + }, +}; + +static struct gpiod_lookup_table da850_lcd_supply_gpio_table = { + .dev_id = "reg-fixed-voltage.1", + .table = { + GPIO_LOOKUP("davinci_gpio", DA850_LCD_PWR_PIN, NULL, 0), + { } + }, +}; + +static struct gpiod_lookup_table *da850_lcd_gpio_lookups[] = { + &da850_lcd_backlight_gpio_table, + &da850_lcd_supply_gpio_table, +}; static int da850_lcd_hw_init(void) { + struct platform_device *backlight; int status; - status = gpio_request(DA850_LCD_BL_PIN, "lcd bl"); - if (status < 0) - return status; - - status = gpio_request(DA850_LCD_PWR_PIN, "lcd pwr"); - if (status < 0) { - gpio_free(DA850_LCD_BL_PIN); - return status; - } + gpiod_add_lookup_tables(da850_lcd_gpio_lookups, + ARRAY_SIZE(da850_lcd_gpio_lookups)); - gpio_direction_output(DA850_LCD_BL_PIN, 0); - gpio_direction_output(DA850_LCD_PWR_PIN, 0); + backlight = platform_device_register_full(&da850_lcd_backlight_info); + if (IS_ERR(backlight)) + return PTR_ERR(backlight); - /* Switch off panel power and backlight */ - da850_panel_power_ctrl(0); - - /* Switch on panel power and backlight */ - da850_panel_power_ctrl(1); + status = platform_device_register(&da850_lcd_supply_device); + if (status) + return status; return 0; } @@ -1443,7 +1486,6 @@ static __init void da850_evm_init(void) if (ret) pr_warn("%s: LCD initialization failed: %d\n", __func__, ret); - sharp_lk043t1dg01_pdata.panel_power_ctrl = da850_panel_power_ctrl, ret = da8xx_register_lcdc(&sharp_lk043t1dg01_pdata); if (ret) pr_warn("%s: LCDC registration failed: %d\n", __func__, ret); diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c index e6b8ffd934a114c9a0654749c61592671e301d68..018ab4b549f1d5374c592ad4820d8f6b86db9cc5 100644 --- a/arch/arm/mach-davinci/da830.c +++ b/arch/arm/mach-davinci/da830.c @@ -21,7 +21,8 @@ #include #include #include -#include + +#include #include "irqs.h" #include "mux.h" @@ -676,32 +677,17 @@ int __init da830_register_gpio(void) return da8xx_register_gpio(&da830_gpio_platform_data); } -static struct davinci_timer_instance da830_timer_instance[2] = { - { - .base = DA8XX_TIMER64P0_BASE, - .bottom_irq = DAVINCI_INTC_IRQ(IRQ_DA8XX_TINT12_0), - .top_irq = DAVINCI_INTC_IRQ(IRQ_DA8XX_TINT34_0), - .cmp_off = DA830_CMP12_0, - .cmp_irq = DAVINCI_INTC_IRQ(IRQ_DA830_T12CMPINT0_0), - }, - { - .base = DA8XX_TIMER64P1_BASE, - .bottom_irq = DAVINCI_INTC_IRQ(IRQ_DA8XX_TINT12_1), - .top_irq = DAVINCI_INTC_IRQ(IRQ_DA8XX_TINT34_1), - .cmp_off = DA830_CMP12_0, - .cmp_irq = DAVINCI_INTC_IRQ(IRQ_DA830_T12CMPINT0_1), - }, -}; - /* - * T0_BOT: Timer 0, bottom : Used for clock_event & clocksource - * T0_TOP: Timer 0, top : Used by DSP - * T1_BOT, T1_TOP: Timer 1, bottom & top: Used for watchdog timer + * Bottom half of timer0 is used both for clock even and clocksource. + * Top half is used by DSP. */ -static struct davinci_timer_info da830_timer_info = { - .timers = da830_timer_instance, - .clockevent_id = T0_BOT, - .clocksource_id = T0_BOT, +static const struct davinci_timer_cfg da830_timer_cfg = { + .reg = DEFINE_RES_IO(DA8XX_TIMER64P0_BASE, SZ_4K), + .irq = { + DEFINE_RES_IRQ(DAVINCI_INTC_IRQ(IRQ_DA830_T12CMPINT0_0)), + DEFINE_RES_IRQ(DAVINCI_INTC_IRQ(IRQ_DA8XX_TINT12_0)), + }, + .cmp_off = DA830_CMP12_0, }; static const struct davinci_soc_info davinci_soc_info_da830 = { @@ -713,7 +699,6 @@ static const struct davinci_soc_info davinci_soc_info_da830 = { .pinmux_base = DA8XX_SYSCFG0_BASE + 0x120, .pinmux_pins = da830_pins, .pinmux_pins_num = ARRAY_SIZE(da830_pins), - .timer_info = &da830_timer_info, .emac_pdata = &da8xx_emac_pdata, }; @@ -743,6 +728,7 @@ void __init da830_init_time(void) { void __iomem *pll; struct clk *clk; + int rv; clk_register_fixed_rate(NULL, "ref_clk", NULL, 0, DA830_REF_FREQ); @@ -751,8 +737,13 @@ void __init da830_init_time(void) da830_pll_init(NULL, pll, NULL); clk = clk_get(NULL, "timer0"); + if (WARN_ON(IS_ERR(clk))) { + pr_err("Unable to get the timer clock\n"); + return; + } - davinci_timer_init(clk); + rv = davinci_timer_register(clk, &da830_timer_cfg); + WARN(rv, "Unable to register the timer: %d\n", rv); } static struct resource da830_psc0_resources[] = { diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 77bc64d6e39be1eb5b2751d88315cf3caf341269..73b7cc53f966843b68efe701e164195b4a582422 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -35,7 +35,8 @@ #include #include #include -#include + +#include #include "irqs.h" #include "mux.h" @@ -333,38 +334,16 @@ static struct davinci_id da850_ids[] = { }, }; -static struct davinci_timer_instance da850_timer_instance[4] = { - { - .base = DA8XX_TIMER64P0_BASE, - .bottom_irq = DAVINCI_INTC_IRQ(IRQ_DA8XX_TINT12_0), - .top_irq = DAVINCI_INTC_IRQ(IRQ_DA8XX_TINT34_0), - }, - { - .base = DA8XX_TIMER64P1_BASE, - .bottom_irq = DAVINCI_INTC_IRQ(IRQ_DA8XX_TINT12_1), - .top_irq = DAVINCI_INTC_IRQ(IRQ_DA8XX_TINT34_1), - }, - { - .base = DA850_TIMER64P2_BASE, - .bottom_irq = DAVINCI_INTC_IRQ(IRQ_DA850_TINT12_2), - .top_irq = DAVINCI_INTC_IRQ(IRQ_DA850_TINT34_2), - }, - { - .base = DA850_TIMER64P3_BASE, - .bottom_irq = DAVINCI_INTC_IRQ(IRQ_DA850_TINT12_3), - .top_irq = DAVINCI_INTC_IRQ(IRQ_DA850_TINT34_3), - }, -}; - /* - * T0_BOT: Timer 0, bottom : Used for clock_event - * T0_TOP: Timer 0, top : Used for clocksource - * T1_BOT, T1_TOP: Timer 1, bottom & top: Used for watchdog timer + * Bottom half of timer 0 is used for clock_event, top half for + * clocksource. */ -static struct davinci_timer_info da850_timer_info = { - .timers = da850_timer_instance, - .clockevent_id = T0_BOT, - .clocksource_id = T0_TOP, +static const struct davinci_timer_cfg da850_timer_cfg = { + .reg = DEFINE_RES_IO(DA8XX_TIMER64P0_BASE, SZ_4K), + .irq = { + DEFINE_RES_IRQ(DAVINCI_INTC_IRQ(IRQ_DA8XX_TINT12_0)), + DEFINE_RES_IRQ(DAVINCI_INTC_IRQ(IRQ_DA8XX_TINT34_0)), + }, }; #ifdef CONFIG_CPU_FREQ @@ -635,7 +614,6 @@ static const struct davinci_soc_info davinci_soc_info_da850 = { .pinmux_base = DA8XX_SYSCFG0_BASE + 0x120, .pinmux_pins = da850_pins, .pinmux_pins_num = ARRAY_SIZE(da850_pins), - .timer_info = &da850_timer_info, .emac_pdata = &da8xx_emac_pdata, .sram_dma = DA8XX_SHARED_RAM_BASE, .sram_len = SZ_128K, @@ -672,6 +650,7 @@ void __init da850_init_time(void) void __iomem *pll0; struct regmap *cfgchip; struct clk *clk; + int rv; clk_register_fixed_rate(NULL, "ref_clk", NULL, 0, DA850_REF_FREQ); @@ -681,8 +660,13 @@ void __init da850_init_time(void) da850_pll0_init(NULL, pll0, cfgchip); clk = clk_get(NULL, "timer0"); + if (WARN_ON(IS_ERR(clk))) { + pr_err("Unable to get the timer clock\n"); + return; + } - davinci_timer_init(clk); + rv = davinci_timer_register(clk, &da850_timer_cfg); + WARN(rv, "Unable to register the timer: %d\n", rv); } static struct resource da850_pll1_resources[] = { diff --git a/arch/arm/mach-davinci/davinci.h b/arch/arm/mach-davinci/davinci.h index 56c1835c42e59bfb387ad206ecf55d9b1c660f93..208d7a4d35973f7c81230d2e3629d0cd917da192 100644 --- a/arch/arm/mach-davinci/davinci.h +++ b/arch/arm/mach-davinci/davinci.h @@ -60,6 +60,9 @@ void davinci_map_sysmod(void); #define DAVINCI_GPIO_BASE 0x01C67000 int davinci_gpio_register(struct resource *res, int size, void *pdata); +#define DAVINCI_TIMER0_BASE (IO_PHYS + 0x21400) +#define DAVINCI_WDOG_BASE (IO_PHYS + 0x21C00) + /* DM355 base addresses */ #define DM355_ASYNC_EMIF_CONTROL_BASE 0x01e10000 #define DM355_ASYNC_EMIF_DATA_CE0_BASE 0x02000000 diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index c6073326be2e16cff3488c4c7cd064e679773f3b..5de72d2fa8f097d6dc7d1cad89bb3205f0f5e9a5 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -30,7 +30,8 @@ #include #include #include -#include + +#include #include "asp.h" #include "davinci.h" @@ -620,15 +621,15 @@ static struct davinci_id dm355_ids[] = { }; /* - * T0_BOT: Timer 0, bottom: clockevent source for hrtimers - * T0_TOP: Timer 0, top : clocksource for generic timekeeping - * T1_BOT: Timer 1, bottom: (used by DSP in TI DSPLink code) - * T1_TOP: Timer 1, top : + * Bottom half of timer0 is used for clockevent, top half is used for + * clocksource. */ -static struct davinci_timer_info dm355_timer_info = { - .timers = davinci_timer_instance, - .clockevent_id = T0_BOT, - .clocksource_id = T0_TOP, +static const struct davinci_timer_cfg dm355_timer_cfg = { + .reg = DEFINE_RES_IO(DAVINCI_TIMER0_BASE, SZ_4K), + .irq = { + DEFINE_RES_IRQ(DAVINCI_INTC_IRQ(IRQ_TINT0_TINT12)), + DEFINE_RES_IRQ(DAVINCI_INTC_IRQ(IRQ_TINT0_TINT34)), + }, }; static struct plat_serial8250_port dm355_serial0_platform_data[] = { @@ -706,7 +707,6 @@ static const struct davinci_soc_info davinci_soc_info_dm355 = { .pinmux_base = DAVINCI_SYSTEM_MODULE_BASE, .pinmux_pins = dm355_pins, .pinmux_pins_num = ARRAY_SIZE(dm355_pins), - .timer_info = &dm355_timer_info, .sram_dma = 0x00010000, .sram_len = SZ_32K, }; @@ -733,6 +733,7 @@ void __init dm355_init_time(void) { void __iomem *pll1, *psc; struct clk *clk; + int rv; clk_register_fixed_rate(NULL, "ref_clk", NULL, 0, DM355_REF_FREQ); @@ -743,8 +744,13 @@ void __init dm355_init_time(void) dm355_psc_init(NULL, psc); clk = clk_get(NULL, "timer0"); + if (WARN_ON(IS_ERR(clk))) { + pr_err("Unable to get the timer clock\n"); + return; + } - davinci_timer_init(clk); + rv = davinci_timer_register(clk, &dm355_timer_cfg); + WARN(rv, "Unable to register the timer: %d\n", rv); } static struct resource dm355_pll2_resources[] = { diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index 2f9ae6431bf54d627aeecaf7d941db998466f7ea..8062412be70f06dc8d252ca45f9f5ff86bba262e 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -784,6 +784,10 @@ void __init dm365_init_time(void) dm365_psc_init(NULL, psc); clk = clk_get(NULL, "timer0"); + if (WARN_ON(IS_ERR(clk))) { + pr_err("Unable to get the timer clock\n"); + return; + } davinci_timer_init(clk); } diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 1b9e9a6192ef181f22c7b92f05872cabfae13338..24988939ae462430617384b035175ef15d8a213b 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -27,7 +27,8 @@ #include #include #include -#include + +#include #include "asp.h" #include "davinci.h" @@ -561,15 +562,15 @@ static struct davinci_id dm644x_ids[] = { }; /* - * T0_BOT: Timer 0, bottom: clockevent source for hrtimers - * T0_TOP: Timer 0, top : clocksource for generic timekeeping - * T1_BOT: Timer 1, bottom: (used by DSP in TI DSPLink code) - * T1_TOP: Timer 1, top : + * Bottom half of timer0 is used for clockevent, top half is used for + * clocksource. */ -static struct davinci_timer_info dm644x_timer_info = { - .timers = davinci_timer_instance, - .clockevent_id = T0_BOT, - .clocksource_id = T0_TOP, +static const struct davinci_timer_cfg dm644x_timer_cfg = { + .reg = DEFINE_RES_IO(DAVINCI_TIMER0_BASE, SZ_4K), + .irq = { + DEFINE_RES_IRQ(DAVINCI_INTC_IRQ(IRQ_TINT0_TINT12)), + DEFINE_RES_IRQ(DAVINCI_INTC_IRQ(IRQ_TINT0_TINT34)), + }, }; static struct plat_serial8250_port dm644x_serial0_platform_data[] = { @@ -647,7 +648,6 @@ static const struct davinci_soc_info davinci_soc_info_dm644x = { .pinmux_base = DAVINCI_SYSTEM_MODULE_BASE, .pinmux_pins = dm644x_pins, .pinmux_pins_num = ARRAY_SIZE(dm644x_pins), - .timer_info = &dm644x_timer_info, .emac_pdata = &dm644x_emac_pdata, .sram_dma = 0x00008000, .sram_len = SZ_16K, @@ -669,6 +669,7 @@ void __init dm644x_init_time(void) { void __iomem *pll1, *psc; struct clk *clk; + int rv; clk_register_fixed_rate(NULL, "ref_clk", NULL, 0, DM644X_REF_FREQ); @@ -679,8 +680,13 @@ void __init dm644x_init_time(void) dm644x_psc_init(NULL, psc); clk = clk_get(NULL, "timer0"); + if (WARN_ON(IS_ERR(clk))) { + pr_err("Unable to get the timer clock\n"); + return; + } - davinci_timer_init(clk); + rv = davinci_timer_register(clk, &dm644x_timer_cfg); + WARN(rv, "Unable to register the timer: %d\n", rv); } static struct resource dm644x_pll2_resources[] = { diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c index 62ca952fe1613ba125ffbe37f1bac89d9dedf8af..4ffd028ed9978c25c10a80a9175fb6eae4db3823 100644 --- a/arch/arm/mach-davinci/dm646x.c +++ b/arch/arm/mach-davinci/dm646x.c @@ -1,5 +1,5 @@ /* - * TI DaVinci DM644x chip specific setup + * TI DaVinci DM646x chip specific setup * * Author: Kevin Hilman, Deep Root Systems, LLC * @@ -28,7 +28,8 @@ #include #include #include -#include + +#include #include "asp.h" #include "davinci.h" @@ -501,15 +502,15 @@ static struct davinci_id dm646x_ids[] = { }; /* - * T0_BOT: Timer 0, bottom: clockevent source for hrtimers - * T0_TOP: Timer 0, top : clocksource for generic timekeeping - * T1_BOT: Timer 1, bottom: (used by DSP in TI DSPLink code) - * T1_TOP: Timer 1, top : + * Bottom half of timer0 is used for clockevent, top half is used for + * clocksource. */ -static struct davinci_timer_info dm646x_timer_info = { - .timers = davinci_timer_instance, - .clockevent_id = T0_BOT, - .clocksource_id = T0_TOP, +static const struct davinci_timer_cfg dm646x_timer_cfg = { + .reg = DEFINE_RES_IO(DAVINCI_TIMER0_BASE, SZ_4K), + .irq = { + DEFINE_RES_IRQ(DAVINCI_INTC_IRQ(IRQ_TINT0_TINT12)), + DEFINE_RES_IRQ(DAVINCI_INTC_IRQ(IRQ_TINT0_TINT34)), + }, }; static struct plat_serial8250_port dm646x_serial0_platform_data[] = { @@ -587,7 +588,6 @@ static const struct davinci_soc_info davinci_soc_info_dm646x = { .pinmux_base = DAVINCI_SYSTEM_MODULE_BASE, .pinmux_pins = dm646x_pins, .pinmux_pins_num = ARRAY_SIZE(dm646x_pins), - .timer_info = &dm646x_timer_info, .emac_pdata = &dm646x_emac_pdata, .sram_dma = 0x10010000, .sram_len = SZ_32K, @@ -652,6 +652,7 @@ void __init dm646x_init_time(unsigned long ref_clk_rate, { void __iomem *pll1, *psc; struct clk *clk; + int rv; clk_register_fixed_rate(NULL, "ref_clk", NULL, 0, ref_clk_rate); clk_register_fixed_rate(NULL, "aux_clkin", NULL, 0, aux_clkin_rate); @@ -663,8 +664,13 @@ void __init dm646x_init_time(unsigned long ref_clk_rate, dm646x_psc_init(NULL, psc); clk = clk_get(NULL, "timer0"); + if (WARN_ON(IS_ERR(clk))) { + pr_err("Unable to get the timer clock\n"); + return; + } - davinci_timer_init(clk); + rv = davinci_timer_register(clk, &dm646x_timer_cfg); + WARN(rv, "Unable to register the timer: %d\n", rv); } static struct resource dm646x_pll2_resources[] = { diff --git a/arch/arm/mach-davinci/include/mach/time.h b/arch/arm/mach-davinci/include/mach/time.h index 1c971d8d8ba8219e7f6e061a85627486cc727c71..ba913736990f2131770347ff6c496836fac97fb6 100644 --- a/arch/arm/mach-davinci/include/mach/time.h +++ b/arch/arm/mach-davinci/include/mach/time.h @@ -11,9 +11,7 @@ #ifndef __ARCH_ARM_MACH_DAVINCI_TIME_H #define __ARCH_ARM_MACH_DAVINCI_TIME_H -#define DAVINCI_TIMER0_BASE (IO_PHYS + 0x21400) #define DAVINCI_TIMER1_BASE (IO_PHYS + 0x21800) -#define DAVINCI_WDOG_BASE (IO_PHYS + 0x21C00) enum { T0_BOT, diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c index 5a6de5368ab08cb51351ffeac3493870613cadeb..740410a3bb6a5ae1b473fc1bd5aee4365d6f7559 100644 --- a/arch/arm/mach-davinci/time.c +++ b/arch/arm/mach-davinci/time.c @@ -398,17 +398,3 @@ void __init davinci_timer_init(struct clk *timer_clk) for (i=0; i< ARRAY_SIZE(timers); i++) timer32_config(&timers[i]); } - -static int __init of_davinci_timer_init(struct device_node *np) -{ - struct clk *clk; - - clk = of_clk_get(np, 0); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - davinci_timer_init(clk); - - return 0; -} -TIMER_OF_DECLARE(davinci_timer, "ti,da830-timer", of_davinci_timer_init); diff --git a/arch/arm/mach-dove/include/mach/bridge-regs.h b/arch/arm/mach-dove/bridge-regs.h similarity index 96% rename from arch/arm/mach-dove/include/mach/bridge-regs.h rename to arch/arm/mach-dove/bridge-regs.h index f4a5b34489b70285f6ad45445fc32a9031b64ee0..ace0b0bfbf11473e089784058d9709f9119d36b9 100644 --- a/arch/arm/mach-dove/include/mach/bridge-regs.h +++ b/arch/arm/mach-dove/bridge-regs.h @@ -1,6 +1,4 @@ /* - * arch/arm/mach-dove/include/mach/bridge-regs.h - * * Mbus-L to Mbus Bridge Registers * * This file is licensed under the terms of the GNU General Public @@ -11,7 +9,7 @@ #ifndef __ASM_ARCH_BRIDGE_REGS_H #define __ASM_ARCH_BRIDGE_REGS_H -#include +#include "dove.h" #define CPU_CONFIG (BRIDGE_VIRT_BASE + 0x0000) diff --git a/arch/arm/mach-dove/cm-a510.c b/arch/arm/mach-dove/cm-a510.c index b9a7c33db29a8e3665b62a79393ba2cc8119e628..9f25c993d86371fbb7107ac6789744359fb32297 100644 --- a/arch/arm/mach-dove/cm-a510.c +++ b/arch/arm/mach-dove/cm-a510.c @@ -22,8 +22,7 @@ #include #include -#include - +#include "dove.h" #include "common.h" static struct mv643xx_eth_platform_data cm_a510_ge00_data = { diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c index d7b826d2695cde8aa4298d6e35cf9cec8d983667..01b830afcea9fac644134dd99c7c00e8125df7ae 100644 --- a/arch/arm/mach-dove/common.c +++ b/arch/arm/mach-dove/common.c @@ -22,11 +22,11 @@ #include #include #include -#include -#include #include #include #include +#include "bridge-regs.h" +#include "pm.h" #include "common.h" /* These can go away once Dove uses the mvebu-mbus DT binding */ diff --git a/arch/arm/mach-dove/dove-db-setup.c b/arch/arm/mach-dove/dove-db-setup.c index 8971c3c0f0fe829360440c71c87c7e964db7f5b9..418ab21b9d9b28338f9ef66c038347afd2b7c7ed 100644 --- a/arch/arm/mach-dove/dove-db-setup.c +++ b/arch/arm/mach-dove/dove-db-setup.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include "dove.h" #include "common.h" static struct mv643xx_eth_platform_data dove_db_ge00_data = { diff --git a/arch/arm/mach-dove/include/mach/dove.h b/arch/arm/mach-dove/dove.h similarity index 95% rename from arch/arm/mach-dove/include/mach/dove.h rename to arch/arm/mach-dove/dove.h index 00f45458b3ec6a2416ff536ea6c0ae2773f06561..320ed1696abdc0661ab3487bb91e043a8226bc19 100644 --- a/arch/arm/mach-dove/include/mach/dove.h +++ b/arch/arm/mach-dove/dove.h @@ -1,6 +1,4 @@ /* - * arch/arm/mach-dove/include/mach/dove.h - * * Generic definitions for Marvell Dove 88AP510 SoC * * This file is licensed under the terms of the GNU General Public @@ -11,7 +9,7 @@ #ifndef __ASM_ARCH_DOVE_H #define __ASM_ARCH_DOVE_H -#include +#include "irqs.h" /* * Marvell Dove address maps. @@ -20,8 +18,8 @@ * c8000000 fdb00000 1M Cryptographic SRAM * e0000000 @runtime 128M PCIe-0 Memory space * e8000000 @runtime 128M PCIe-1 Memory space - * f1000000 fde00000 8M on-chip south-bridge registers - * f1800000 fe600000 8M on-chip north-bridge registers + * f1000000 fec00000 1M on-chip south-bridge registers + * f1800000 fe400000 8M on-chip north-bridge registers * f2000000 fee00000 1M PCIe-0 I/O space * f2100000 fef00000 1M PCIe-1 I/O space */ @@ -44,11 +42,11 @@ #define DOVE_SCRATCHPAD_SIZE SZ_1M #define DOVE_SB_REGS_PHYS_BASE 0xf1000000 -#define DOVE_SB_REGS_VIRT_BASE IOMEM(0xfde00000) -#define DOVE_SB_REGS_SIZE SZ_8M +#define DOVE_SB_REGS_VIRT_BASE IOMEM(0xfec00000) +#define DOVE_SB_REGS_SIZE SZ_1M #define DOVE_NB_REGS_PHYS_BASE 0xf1800000 -#define DOVE_NB_REGS_VIRT_BASE IOMEM(0xfe600000) +#define DOVE_NB_REGS_VIRT_BASE IOMEM(0xfe400000) #define DOVE_NB_REGS_SIZE SZ_8M #define DOVE_PCIE0_IO_PHYS_BASE 0xf2000000 diff --git a/arch/arm/mach-dove/include/mach/hardware.h b/arch/arm/mach-dove/include/mach/hardware.h deleted file mode 100644 index f1368b9a8ece777b038961b2001b04cd09f3454a..0000000000000000000000000000000000000000 --- a/arch/arm/mach-dove/include/mach/hardware.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * arch/arm/mach-dove/include/mach/hardware.h - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef __ASM_ARCH_HARDWARE_H -#define __ASM_ARCH_HARDWARE_H - -#include "dove.h" - -/* Macros below are required for compatibility with PXA AC'97 driver. */ -#define __REG(x) (*((volatile u32 *)((x) - DOVE_SB_REGS_PHYS_BASE + \ - DOVE_SB_REGS_VIRT_BASE))) -#define __PREG(x) (((u32)&(x)) - DOVE_SB_REGS_VIRT_BASE + \ - DOVE_SB_REGS_PHYS_BASE) -#endif diff --git a/arch/arm/mach-dove/include/mach/uncompress.h b/arch/arm/mach-dove/include/mach/uncompress.h index 5c8ae9b9d39a09753a1bc77afa9fad00e42f62e4..7a4bd8838036ffb7a7233325b6b6696170d173d4 100644 --- a/arch/arm/mach-dove/include/mach/uncompress.h +++ b/arch/arm/mach-dove/include/mach/uncompress.h @@ -1,15 +1,13 @@ /* - * arch/arm/mach-dove/include/mach/uncompress.h - * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ -#include +#define UART0_PHYS_BASE (0xf1000000 + 0x12000) -#define UART_THR ((volatile unsigned char *)(DOVE_UART0_PHYS_BASE + 0x0)) -#define UART_LSR ((volatile unsigned char *)(DOVE_UART0_PHYS_BASE + 0x14)) +#define UART_THR ((volatile unsigned char *)(UART0_PHYS_BASE + 0x0)) +#define UART_LSR ((volatile unsigned char *)(UART0_PHYS_BASE + 0x14)) #define LSR_THRE 0x20 diff --git a/arch/arm/mach-dove/irq.c b/arch/arm/mach-dove/irq.c index d6627c1f7f30bb9691ea5eda9c42059df5c5c9cb..31ccbcee262742f6003dfffffc05eab9f3c3c480 100644 --- a/arch/arm/mach-dove/irq.c +++ b/arch/arm/mach-dove/irq.c @@ -11,9 +11,12 @@ #include #include #include + #include -#include #include + +#include "pm.h" +#include "bridge-regs.h" #include "common.h" static int __initdata gpio0_irqs[4] = { diff --git a/arch/arm/mach-dove/include/mach/irqs.h b/arch/arm/mach-dove/irqs.h similarity index 98% rename from arch/arm/mach-dove/include/mach/irqs.h rename to arch/arm/mach-dove/irqs.h index 8ff0fa8b4fcd16798e654ff85a314275aef79dce..a0742179faffecb7040d07a8c597ed0894bd1941 100644 --- a/arch/arm/mach-dove/include/mach/irqs.h +++ b/arch/arm/mach-dove/irqs.h @@ -1,6 +1,4 @@ /* - * arch/arm/mach-dove/include/mach/irqs.h - * * IRQ definitions for Marvell Dove 88AP510 SoC * * This file is licensed under the terms of the GNU General Public diff --git a/arch/arm/mach-dove/mpp.c b/arch/arm/mach-dove/mpp.c index 8a433a51289c649d3424479863272f57e22f2862..6acd8488bb05f962795bf7508d88ed3802f6ba00 100644 --- a/arch/arm/mach-dove/mpp.c +++ b/arch/arm/mach-dove/mpp.c @@ -12,8 +12,8 @@ #include #include #include -#include #include +#include "dove.h" #include "mpp.h" struct dove_mpp_grp { diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c index dfb62f3f5dcf1722b8a69c2443251126dba56968..ee91ac6b5ebf1a96ca207799adf93a13ff98208b 100644 --- a/arch/arm/mach-dove/pcie.c +++ b/arch/arm/mach-dove/pcie.c @@ -17,9 +17,9 @@ #include #include #include -#include -#include #include +#include "irqs.h" +#include "bridge-regs.h" #include "common.h" struct pcie_port { diff --git a/arch/arm/mach-dove/include/mach/pm.h b/arch/arm/mach-dove/pm.h similarity index 97% rename from arch/arm/mach-dove/include/mach/pm.h rename to arch/arm/mach-dove/pm.h index d22b9b174007fa4c39a82f172542d352d9dd7770..01267746d7072ff8656dd5f245d69fd6300dedd7 100644 --- a/arch/arm/mach-dove/include/mach/pm.h +++ b/arch/arm/mach-dove/pm.h @@ -1,6 +1,4 @@ /* - * arch/arm/mach-dove/include/mach/pm.h - * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. @@ -10,7 +8,7 @@ #define __ASM_ARCH_PM_H #include -#include +#include "irqs.h" #define CLOCK_GATING_CONTROL (DOVE_PMU_VIRT_BASE + 0x38) #define CLOCK_GATING_BIT_USB0 0 diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c index 1f0da76a39de7462d668c4ad2c3f50d0cfd6a727..7b7280c21ee09992127c3edbb48c542294bdcdf0 100644 --- a/arch/arm/mach-ep93xx/edb93xx.c +++ b/arch/arm/mach-ep93xx/edb93xx.c @@ -103,7 +103,7 @@ static struct spi_board_info edb93xx_spi_board_info[] __initdata = { }; static struct gpiod_lookup_table edb93xx_spi_cs_gpio_table = { - .dev_id = "ep93xx-spi.0", + .dev_id = "spi0", .table = { GPIO_LOOKUP("A", 6, "cs", GPIO_ACTIVE_LOW), { }, diff --git a/arch/arm/mach-ep93xx/simone.c b/arch/arm/mach-ep93xx/simone.c index e2658e22bba1d738e4009421c357aeafdb987276..8a53b74dc4b215eb8e77783df379cfc073a2d2f5 100644 --- a/arch/arm/mach-ep93xx/simone.c +++ b/arch/arm/mach-ep93xx/simone.c @@ -73,7 +73,7 @@ static struct spi_board_info simone_spi_devices[] __initdata = { * v1.3 parts will still work, since the signal on SFRMOUT is automatic. */ static struct gpiod_lookup_table simone_spi_cs_gpio_table = { - .dev_id = "ep93xx-spi.0", + .dev_id = "spi0", .table = { GPIO_LOOKUP("A", 1, "cs", GPIO_ACTIVE_LOW), { }, diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c index 582e06e104fd695b797e3aecf97c8cb104cdf452..e0e1b11032f1d3767172dae6929ce0e364373328 100644 --- a/arch/arm/mach-ep93xx/ts72xx.c +++ b/arch/arm/mach-ep93xx/ts72xx.c @@ -267,7 +267,7 @@ static struct spi_board_info bk3_spi_board_info[] __initdata = { * goes through CPLD */ static struct gpiod_lookup_table bk3_spi_cs_gpio_table = { - .dev_id = "ep93xx-spi.0", + .dev_id = "spi0", .table = { GPIO_LOOKUP("F", 3, "cs", GPIO_ACTIVE_LOW), { }, @@ -316,7 +316,7 @@ static struct spi_board_info ts72xx_spi_devices[] __initdata = { }; static struct gpiod_lookup_table ts72xx_spi_cs_gpio_table = { - .dev_id = "ep93xx-spi.0", + .dev_id = "spi0", .table = { /* DIO_17 */ GPIO_LOOKUP("F", 2, "cs", GPIO_ACTIVE_LOW), diff --git a/arch/arm/mach-ep93xx/vision_ep9307.c b/arch/arm/mach-ep93xx/vision_ep9307.c index a88a1d807b325160e25dfdaa72c61fe77cd9f1db..cbcba3136d74a04b9cc45811d9fda0abf80a143e 100644 --- a/arch/arm/mach-ep93xx/vision_ep9307.c +++ b/arch/arm/mach-ep93xx/vision_ep9307.c @@ -242,7 +242,7 @@ static struct spi_board_info vision_spi_board_info[] __initdata = { }; static struct gpiod_lookup_table vision_spi_cs_gpio_table = { - .dev_id = "ep93xx-spi.0", + .dev_id = "spi0", .table = { GPIO_LOOKUP_IDX("A", 6, "cs", 0, GPIO_ACTIVE_LOW), GPIO_LOOKUP_IDX("A", 7, "cs", 1, GPIO_ACTIVE_LOW), diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index d7422233a1306861a7bb99375c13cfef1c451a8d..f83786640f94205da1432b056759dd74c1cd2cc7 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -13,6 +13,7 @@ menuconfig ARCH_EXYNOS select ARM_AMBA select ARM_GIC select COMMON_CLK_SAMSUNG + select EXYNOS_CHIPID select EXYNOS_THERMAL select EXYNOS_PMU select EXYNOS_SROM diff --git a/arch/arm/mach-imx/mach-imx7d.c b/arch/arm/mach-imx/mach-imx7d.c index 95713450591ae7acc98c18768f93118aeff2c088..ebb27592a9f754cce32cb15bb7a86938e5896843 100644 --- a/arch/arm/mach-imx/mach-imx7d.c +++ b/arch/arm/mach-imx/mach-imx7d.c @@ -30,12 +30,6 @@ static int ar8031_phy_fixup(struct phy_device *dev) val &= ~(0x1 << 8); phy_write(dev, 0xe, val); - /* introduce tx clock delay */ - phy_write(dev, 0x1d, 0x5); - val = phy_read(dev, 0x1e); - val |= 0x0100; - phy_write(dev, 0x1e, val); - return 0; } diff --git a/arch/arm/mach-iop13xx/Kconfig b/arch/arm/mach-iop13xx/Kconfig deleted file mode 100644 index c4f04070b4c1a40c50c8894794bd8db0c53979d3..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -if ARCH_IOP13XX - -menu "IOP13XX Implementation Options" - -comment "IOP13XX Platform Support" - -config MACH_IQ81340SC - bool "Enable IQ81340SC Hardware Support" - help - Say Y here if you want to support running on the Intel IQ81340SC - evaluation kit. - -config MACH_IQ81340MC - bool "Enable IQ81340MC Hardware Support" - help - Say Y here if you want to support running on the Intel IQ81340MC - evaluation kit. - -endmenu -endif diff --git a/arch/arm/mach-iop13xx/Makefile b/arch/arm/mach-iop13xx/Makefile deleted file mode 100644 index 5757c8f6e371eba5eefec034d22fb41cd0d23006..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_ARCH_IOP13XX) += setup.o -obj-$(CONFIG_ARCH_IOP13XX) += irq.o -obj-$(CONFIG_ARCH_IOP13XX) += pci.o -obj-$(CONFIG_ARCH_IOP13XX) += io.o -obj-$(CONFIG_ARCH_IOP13XX) += tpmi.o -obj-$(CONFIG_MACH_IQ81340SC) += iq81340sc.o -obj-$(CONFIG_MACH_IQ81340MC) += iq81340mc.o -obj-$(CONFIG_PCI_MSI) += msi.o diff --git a/arch/arm/mach-iop13xx/Makefile.boot b/arch/arm/mach-iop13xx/Makefile.boot deleted file mode 100644 index 4f29554c840191894383333c50109387b01bdb2e..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/Makefile.boot +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only - zreladdr-y += 0x00008000 -params_phys-y := 0x00000100 -initrd_phys-y := 0x00800000 diff --git a/arch/arm/mach-iop13xx/include/mach/adma.h b/arch/arm/mach-iop13xx/include/mach/adma.h deleted file mode 100644 index 51d206f5b09369719afd09becb5ebef32cd85e8e..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/include/mach/adma.h +++ /dev/null @@ -1,608 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright(c) 2006, Intel Corporation. - */ -#ifndef _ADMA_H -#define _ADMA_H -#include -#include -#include -#include - -#define ADMA_ACCR(chan) (chan->mmr_base + 0x0) -#define ADMA_ACSR(chan) (chan->mmr_base + 0x4) -#define ADMA_ADAR(chan) (chan->mmr_base + 0x8) -#define ADMA_IIPCR(chan) (chan->mmr_base + 0x18) -#define ADMA_IIPAR(chan) (chan->mmr_base + 0x1c) -#define ADMA_IIPUAR(chan) (chan->mmr_base + 0x20) -#define ADMA_ANDAR(chan) (chan->mmr_base + 0x24) -#define ADMA_ADCR(chan) (chan->mmr_base + 0x28) -#define ADMA_CARMD(chan) (chan->mmr_base + 0x2c) -#define ADMA_ABCR(chan) (chan->mmr_base + 0x30) -#define ADMA_DLADR(chan) (chan->mmr_base + 0x34) -#define ADMA_DUADR(chan) (chan->mmr_base + 0x38) -#define ADMA_SLAR(src, chan) (chan->mmr_base + (0x3c + (src << 3))) -#define ADMA_SUAR(src, chan) (chan->mmr_base + (0x40 + (src << 3))) - -struct iop13xx_adma_src { - u32 src_addr; - union { - u32 upper_src_addr; - struct { - unsigned int pq_upper_src_addr:24; - unsigned int pq_dmlt:8; - }; - }; -}; - -struct iop13xx_adma_desc_ctrl { - unsigned int int_en:1; - unsigned int xfer_dir:2; - unsigned int src_select:4; - unsigned int zero_result:1; - unsigned int block_fill_en:1; - unsigned int crc_gen_en:1; - unsigned int crc_xfer_dis:1; - unsigned int crc_seed_fetch_dis:1; - unsigned int status_write_back_en:1; - unsigned int endian_swap_en:1; - unsigned int reserved0:2; - unsigned int pq_update_xfer_en:1; - unsigned int dual_xor_en:1; - unsigned int pq_xfer_en:1; - unsigned int p_xfer_dis:1; - unsigned int reserved1:10; - unsigned int relax_order_en:1; - unsigned int no_snoop_en:1; -}; - -struct iop13xx_adma_byte_count { - unsigned int byte_count:24; - unsigned int host_if:3; - unsigned int reserved:2; - unsigned int zero_result_err_q:1; - unsigned int zero_result_err:1; - unsigned int tx_complete:1; -}; - -struct iop13xx_adma_desc_hw { - u32 next_desc; - union { - u32 desc_ctrl; - struct iop13xx_adma_desc_ctrl desc_ctrl_field; - }; - union { - u32 crc_addr; - u32 block_fill_data; - u32 q_dest_addr; - }; - union { - u32 byte_count; - struct iop13xx_adma_byte_count byte_count_field; - }; - union { - u32 dest_addr; - u32 p_dest_addr; - }; - union { - u32 upper_dest_addr; - u32 pq_upper_dest_addr; - }; - struct iop13xx_adma_src src[1]; -}; - -struct iop13xx_adma_desc_dual_xor { - u32 next_desc; - u32 desc_ctrl; - u32 reserved; - u32 byte_count; - u32 h_dest_addr; - u32 h_upper_dest_addr; - u32 src0_addr; - u32 upper_src0_addr; - u32 src1_addr; - u32 upper_src1_addr; - u32 h_src_addr; - u32 h_upper_src_addr; - u32 d_src_addr; - u32 d_upper_src_addr; - u32 d_dest_addr; - u32 d_upper_dest_addr; -}; - -struct iop13xx_adma_desc_pq_update { - u32 next_desc; - u32 desc_ctrl; - u32 reserved; - u32 byte_count; - u32 p_dest_addr; - u32 p_upper_dest_addr; - u32 src0_addr; - u32 upper_src0_addr; - u32 src1_addr; - u32 upper_src1_addr; - u32 p_src_addr; - u32 p_upper_src_addr; - u32 q_src_addr; - struct { - unsigned int q_upper_src_addr:24; - unsigned int q_dmlt:8; - }; - u32 q_dest_addr; - u32 q_upper_dest_addr; -}; - -static inline int iop_adma_get_max_xor(void) -{ - return 16; -} - -#define iop_adma_get_max_pq iop_adma_get_max_xor - -static inline u32 iop_chan_get_current_descriptor(struct iop_adma_chan *chan) -{ - return __raw_readl(ADMA_ADAR(chan)); -} - -static inline void iop_chan_set_next_descriptor(struct iop_adma_chan *chan, - u32 next_desc_addr) -{ - __raw_writel(next_desc_addr, ADMA_ANDAR(chan)); -} - -#define ADMA_STATUS_BUSY (1 << 13) - -static inline char iop_chan_is_busy(struct iop_adma_chan *chan) -{ - if (__raw_readl(ADMA_ACSR(chan)) & - ADMA_STATUS_BUSY) - return 1; - else - return 0; -} - -static inline int -iop_chan_get_desc_align(struct iop_adma_chan *chan, int num_slots) -{ - return 1; -} -#define iop_desc_is_aligned(x, y) 1 - -static inline int -iop_chan_memcpy_slot_count(size_t len, int *slots_per_op) -{ - *slots_per_op = 1; - return 1; -} - -#define iop_chan_interrupt_slot_count(s, c) iop_chan_memcpy_slot_count(0, s) - -static inline int -iop_chan_memset_slot_count(size_t len, int *slots_per_op) -{ - *slots_per_op = 1; - return 1; -} - -static inline int -iop_chan_xor_slot_count(size_t len, int src_cnt, int *slots_per_op) -{ - static const char slot_count_table[] = { 1, 2, 2, 2, - 2, 3, 3, 3, - 3, 4, 4, 4, - 4, 5, 5, 5, - }; - *slots_per_op = slot_count_table[src_cnt - 1]; - return *slots_per_op; -} - -#define ADMA_MAX_BYTE_COUNT (16 * 1024 * 1024) -#define IOP_ADMA_MAX_BYTE_COUNT ADMA_MAX_BYTE_COUNT -#define IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT ADMA_MAX_BYTE_COUNT -#define IOP_ADMA_XOR_MAX_BYTE_COUNT ADMA_MAX_BYTE_COUNT -#define IOP_ADMA_PQ_MAX_BYTE_COUNT ADMA_MAX_BYTE_COUNT -#define iop_chan_zero_sum_slot_count(l, s, o) iop_chan_xor_slot_count(l, s, o) -#define iop_chan_pq_slot_count iop_chan_xor_slot_count -#define iop_chan_pq_zero_sum_slot_count iop_chan_xor_slot_count - -static inline u32 iop_desc_get_byte_count(struct iop_adma_desc_slot *desc, - struct iop_adma_chan *chan) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - return hw_desc->byte_count_field.byte_count; -} - -static inline u32 iop_desc_get_src_addr(struct iop_adma_desc_slot *desc, - struct iop_adma_chan *chan, - int src_idx) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - return hw_desc->src[src_idx].src_addr; -} - -static inline u32 iop_desc_get_src_count(struct iop_adma_desc_slot *desc, - struct iop_adma_chan *chan) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - return hw_desc->desc_ctrl_field.src_select + 1; -} - -static inline void -iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, unsigned long flags) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - union { - u32 value; - struct iop13xx_adma_desc_ctrl field; - } u_desc_ctrl; - - u_desc_ctrl.value = 0; - u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */ - u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT; - hw_desc->desc_ctrl = u_desc_ctrl.value; - hw_desc->crc_addr = 0; -} - -static inline void -iop_desc_init_memset(struct iop_adma_desc_slot *desc, unsigned long flags) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - union { - u32 value; - struct iop13xx_adma_desc_ctrl field; - } u_desc_ctrl; - - u_desc_ctrl.value = 0; - u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */ - u_desc_ctrl.field.block_fill_en = 1; - u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT; - hw_desc->desc_ctrl = u_desc_ctrl.value; - hw_desc->crc_addr = 0; -} - -/* to do: support buffers larger than ADMA_MAX_BYTE_COUNT */ -static inline void -iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt, - unsigned long flags) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - union { - u32 value; - struct iop13xx_adma_desc_ctrl field; - } u_desc_ctrl; - - u_desc_ctrl.value = 0; - u_desc_ctrl.field.src_select = src_cnt - 1; - u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */ - u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT; - hw_desc->desc_ctrl = u_desc_ctrl.value; - hw_desc->crc_addr = 0; - -} -#define iop_desc_init_null_xor(d, s, i) iop_desc_init_xor(d, s, i) - -/* to do: support buffers larger than ADMA_MAX_BYTE_COUNT */ -static inline int -iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, - unsigned long flags) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - union { - u32 value; - struct iop13xx_adma_desc_ctrl field; - } u_desc_ctrl; - - u_desc_ctrl.value = 0; - u_desc_ctrl.field.src_select = src_cnt - 1; - u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */ - u_desc_ctrl.field.zero_result = 1; - u_desc_ctrl.field.status_write_back_en = 1; - u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT; - hw_desc->desc_ctrl = u_desc_ctrl.value; - hw_desc->crc_addr = 0; - - return 1; -} - -static inline void -iop_desc_init_pq(struct iop_adma_desc_slot *desc, int src_cnt, - unsigned long flags) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - union { - u32 value; - struct iop13xx_adma_desc_ctrl field; - } u_desc_ctrl; - - u_desc_ctrl.value = 0; - u_desc_ctrl.field.src_select = src_cnt - 1; - u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */ - u_desc_ctrl.field.pq_xfer_en = 1; - u_desc_ctrl.field.p_xfer_dis = !!(flags & DMA_PREP_PQ_DISABLE_P); - u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT; - hw_desc->desc_ctrl = u_desc_ctrl.value; -} - -static inline void -iop_desc_init_pq_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, - unsigned long flags) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - union { - u32 value; - struct iop13xx_adma_desc_ctrl field; - } u_desc_ctrl; - - u_desc_ctrl.value = 0; - u_desc_ctrl.field.src_select = src_cnt - 1; - u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */ - u_desc_ctrl.field.zero_result = 1; - u_desc_ctrl.field.status_write_back_en = 1; - u_desc_ctrl.field.pq_xfer_en = 1; - u_desc_ctrl.field.p_xfer_dis = !!(flags & DMA_PREP_PQ_DISABLE_P); - u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT; - hw_desc->desc_ctrl = u_desc_ctrl.value; -} - -static inline void iop_desc_set_byte_count(struct iop_adma_desc_slot *desc, - struct iop_adma_chan *chan, - u32 byte_count) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - hw_desc->byte_count = byte_count; -} - -static inline void -iop_desc_set_zero_sum_byte_count(struct iop_adma_desc_slot *desc, u32 len) -{ - int slots_per_op = desc->slots_per_op; - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc, *iter; - int i = 0; - - if (len <= IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT) { - hw_desc->byte_count = len; - } else { - do { - iter = iop_hw_desc_slot_idx(hw_desc, i); - iter->byte_count = IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT; - len -= IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT; - i += slots_per_op; - } while (len > IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT); - - if (len) { - iter = iop_hw_desc_slot_idx(hw_desc, i); - iter->byte_count = len; - } - } -} - -#define iop_desc_set_pq_zero_sum_byte_count iop_desc_set_zero_sum_byte_count - -static inline void iop_desc_set_dest_addr(struct iop_adma_desc_slot *desc, - struct iop_adma_chan *chan, - dma_addr_t addr) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - hw_desc->dest_addr = addr; - hw_desc->upper_dest_addr = 0; -} - -static inline void -iop_desc_set_pq_addr(struct iop_adma_desc_slot *desc, dma_addr_t *addr) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - - hw_desc->dest_addr = addr[0]; - hw_desc->q_dest_addr = addr[1]; - hw_desc->upper_dest_addr = 0; -} - -static inline void iop_desc_set_memcpy_src_addr(struct iop_adma_desc_slot *desc, - dma_addr_t addr) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - hw_desc->src[0].src_addr = addr; - hw_desc->src[0].upper_src_addr = 0; -} - -static inline void iop_desc_set_xor_src_addr(struct iop_adma_desc_slot *desc, - int src_idx, dma_addr_t addr) -{ - int slot_cnt = desc->slot_cnt, slots_per_op = desc->slots_per_op; - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc, *iter; - int i = 0; - - do { - iter = iop_hw_desc_slot_idx(hw_desc, i); - iter->src[src_idx].src_addr = addr; - iter->src[src_idx].upper_src_addr = 0; - slot_cnt -= slots_per_op; - if (slot_cnt) { - i += slots_per_op; - addr += IOP_ADMA_XOR_MAX_BYTE_COUNT; - } - } while (slot_cnt); -} - -static inline void -iop_desc_set_pq_src_addr(struct iop_adma_desc_slot *desc, int src_idx, - dma_addr_t addr, unsigned char coef) -{ - int slot_cnt = desc->slot_cnt, slots_per_op = desc->slots_per_op; - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc, *iter; - struct iop13xx_adma_src *src; - int i = 0; - - do { - iter = iop_hw_desc_slot_idx(hw_desc, i); - src = &iter->src[src_idx]; - src->src_addr = addr; - src->pq_upper_src_addr = 0; - src->pq_dmlt = coef; - slot_cnt -= slots_per_op; - if (slot_cnt) { - i += slots_per_op; - addr += IOP_ADMA_PQ_MAX_BYTE_COUNT; - } - } while (slot_cnt); -} - -static inline void -iop_desc_init_interrupt(struct iop_adma_desc_slot *desc, - struct iop_adma_chan *chan) -{ - iop_desc_init_memcpy(desc, 1); - iop_desc_set_byte_count(desc, chan, 0); - iop_desc_set_dest_addr(desc, chan, 0); - iop_desc_set_memcpy_src_addr(desc, 0); -} - -#define iop_desc_set_zero_sum_src_addr iop_desc_set_xor_src_addr -#define iop_desc_set_pq_zero_sum_src_addr iop_desc_set_pq_src_addr - -static inline void -iop_desc_set_pq_zero_sum_addr(struct iop_adma_desc_slot *desc, int pq_idx, - dma_addr_t *src) -{ - iop_desc_set_xor_src_addr(desc, pq_idx, src[pq_idx]); - iop_desc_set_xor_src_addr(desc, pq_idx+1, src[pq_idx+1]); -} - -static inline void iop_desc_set_next_desc(struct iop_adma_desc_slot *desc, - u32 next_desc_addr) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - - iop_paranoia(hw_desc->next_desc); - hw_desc->next_desc = next_desc_addr; -} - -static inline u32 iop_desc_get_next_desc(struct iop_adma_desc_slot *desc) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - return hw_desc->next_desc; -} - -static inline void iop_desc_clear_next_desc(struct iop_adma_desc_slot *desc) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - hw_desc->next_desc = 0; -} - -static inline void iop_desc_set_block_fill_val(struct iop_adma_desc_slot *desc, - u32 val) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - hw_desc->block_fill_data = val; -} - -static inline enum sum_check_flags -iop_desc_get_zero_result(struct iop_adma_desc_slot *desc) -{ - struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; - struct iop13xx_adma_desc_ctrl desc_ctrl = hw_desc->desc_ctrl_field; - struct iop13xx_adma_byte_count byte_count = hw_desc->byte_count_field; - enum sum_check_flags flags; - - BUG_ON(!(byte_count.tx_complete && desc_ctrl.zero_result)); - - flags = byte_count.zero_result_err_q << SUM_CHECK_Q; - flags |= byte_count.zero_result_err << SUM_CHECK_P; - - return flags; -} - -static inline void iop_chan_append(struct iop_adma_chan *chan) -{ - u32 adma_accr; - - adma_accr = __raw_readl(ADMA_ACCR(chan)); - adma_accr |= 0x2; - __raw_writel(adma_accr, ADMA_ACCR(chan)); -} - -static inline u32 iop_chan_get_status(struct iop_adma_chan *chan) -{ - return __raw_readl(ADMA_ACSR(chan)); -} - -static inline void iop_chan_disable(struct iop_adma_chan *chan) -{ - u32 adma_chan_ctrl = __raw_readl(ADMA_ACCR(chan)); - adma_chan_ctrl &= ~0x1; - __raw_writel(adma_chan_ctrl, ADMA_ACCR(chan)); -} - -static inline void iop_chan_enable(struct iop_adma_chan *chan) -{ - u32 adma_chan_ctrl; - - adma_chan_ctrl = __raw_readl(ADMA_ACCR(chan)); - adma_chan_ctrl |= 0x1; - __raw_writel(adma_chan_ctrl, ADMA_ACCR(chan)); -} - -static inline void iop_adma_device_clear_eot_status(struct iop_adma_chan *chan) -{ - u32 status = __raw_readl(ADMA_ACSR(chan)); - status &= (1 << 12); - __raw_writel(status, ADMA_ACSR(chan)); -} - -static inline void iop_adma_device_clear_eoc_status(struct iop_adma_chan *chan) -{ - u32 status = __raw_readl(ADMA_ACSR(chan)); - status &= (1 << 11); - __raw_writel(status, ADMA_ACSR(chan)); -} - -static inline void iop_adma_device_clear_err_status(struct iop_adma_chan *chan) -{ - u32 status = __raw_readl(ADMA_ACSR(chan)); - status &= (1 << 9) | (1 << 5) | (1 << 4) | (1 << 3); - __raw_writel(status, ADMA_ACSR(chan)); -} - -static inline int -iop_is_err_int_parity(unsigned long status, struct iop_adma_chan *chan) -{ - return test_bit(9, &status); -} - -static inline int -iop_is_err_mcu_abort(unsigned long status, struct iop_adma_chan *chan) -{ - return test_bit(5, &status); -} - -static inline int -iop_is_err_int_tabort(unsigned long status, struct iop_adma_chan *chan) -{ - return test_bit(4, &status); -} - -static inline int -iop_is_err_int_mabort(unsigned long status, struct iop_adma_chan *chan) -{ - return test_bit(3, &status); -} - -static inline int -iop_is_err_pci_tabort(unsigned long status, struct iop_adma_chan *chan) -{ - return 0; -} - -static inline int -iop_is_err_pci_mabort(unsigned long status, struct iop_adma_chan *chan) -{ - return 0; -} - -static inline int -iop_is_err_split_tx(unsigned long status, struct iop_adma_chan *chan) -{ - return 0; -} - -#endif /* _ADMA_H */ diff --git a/arch/arm/mach-iop13xx/include/mach/entry-macro.S b/arch/arm/mach-iop13xx/include/mach/entry-macro.S deleted file mode 100644 index 9f4ecb8861bd68236a555d731c9cec920508b226..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/include/mach/entry-macro.S +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * iop13xx low level irq macros - * Copyright (c) 2005-2006, Intel Corporation. - */ - .macro get_irqnr_preamble, base, tmp - mrc p15, 0, \tmp, c15, c1, 0 - orr \tmp, \tmp, #(1 << 6) - mcr p15, 0, \tmp, c15, c1, 0 @ Enable cp6 access - .endm - - /* - * Note: a 1-cycle window exists where iintvec will return the value - * of iintbase, so we explicitly check for "bad zeros" - */ - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - mrc p6, 0, \irqnr, c3, c2, 0 @ Read IINTVEC - cmp \irqnr, #0 - mrceq p6, 0, \irqnr, c3, c2, 0 @ Re-read on potentially bad zero - adds \irqstat, \irqnr, #1 @ Check for 0xffffffff - movne \irqnr, \irqnr, lsr #2 @ Convert to irqnr - .endm - - .macro arch_ret_to_user, tmp1, tmp2 - mrc p15, 0, \tmp1, c15, c1, 0 - ands \tmp2, \tmp1, #(1 << 6) - bicne \tmp1, \tmp1, #(1 << 6) - mcrne p15, 0, \tmp1, c15, c1, 0 @ Disable cp6 access - .endm diff --git a/arch/arm/mach-iop13xx/include/mach/hardware.h b/arch/arm/mach-iop13xx/include/mach/hardware.h deleted file mode 100644 index 8c943fa6bbd71ddb71036412f2d0737a9a9fb0f0..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/include/mach/hardware.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __ASM_ARCH_HARDWARE_H -#define __ASM_ARCH_HARDWARE_H -#include - -#ifndef __ASSEMBLY__ -extern u16 iop13xx_dev_id(void); -extern void iop13xx_set_atu_mmr_bases(void); -#endif - -/* - * Generic chipset bits - * - */ -#include "iop13xx.h" - -/* - * Board specific bits - */ -#include "iq81340.h" - -#endif /* _ASM_ARCH_HARDWARE_H */ diff --git a/arch/arm/mach-iop13xx/include/mach/iop13xx.h b/arch/arm/mach-iop13xx/include/mach/iop13xx.h deleted file mode 100644 index 04bb6aca12c5d671ddc04159de0d9b8c66d3a125..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/include/mach/iop13xx.h +++ /dev/null @@ -1,508 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _IOP13XX_HW_H_ -#define _IOP13XX_HW_H_ - -#ifndef __ASSEMBLY__ - -enum reboot_mode; - -/* The ATU offsets can change based on the strapping */ -extern u32 iop13xx_atux_pmmr_offset; -extern u32 iop13xx_atue_pmmr_offset; -void iop13xx_init_early(void); -void iop13xx_init_irq(void); -void iop13xx_map_io(void); -void iop13xx_platform_init(void); -void iop13xx_add_tpmi_devices(void); -void iop13xx_init_irq(void); -void iop13xx_restart(enum reboot_mode, const char *); - -/* CPUID CP6 R0 Page 0 */ -static inline int iop13xx_cpu_id(void) -{ - int id; - asm volatile("mrc p6, 0, %0, c0, c0, 0":"=r" (id)); - return id; -} - -/* WDTCR CP6 R7 Page 9 */ -static inline u32 read_wdtcr(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c7, c9, 0":"=r" (val)); - return val; -} -static inline void write_wdtcr(u32 val) -{ - asm volatile("mcr p6, 0, %0, c7, c9, 0"::"r" (val)); -} - -/* WDTSR CP6 R8 Page 9 */ -static inline u32 read_wdtsr(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c8, c9, 0":"=r" (val)); - return val; -} -static inline void write_wdtsr(u32 val) -{ - asm volatile("mcr p6, 0, %0, c8, c9, 0"::"r" (val)); -} - -/* RCSR - Reset Cause Status Register */ -static inline u32 read_rcsr(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c0, c1, 0":"=r" (val)); - return val; -} - -extern unsigned long get_iop_tick_rate(void); -#endif - -/* - * IOP13XX I/O and Mem space regions for PCI autoconfiguration - */ -#define IOP13XX_MAX_RAM_SIZE 0x80000000UL /* 2GB */ -#define IOP13XX_PCI_OFFSET IOP13XX_MAX_RAM_SIZE - -/* PCI MAP - * bus range cpu phys cpu virt note - * 0x0000.0000 + 2GB (n/a) (n/a) inbound, 1:1 mapping with Physical RAM - * 0x8000.0000 + 928M 0x1.8000.0000 (ioremap) PCIX outbound memory window - * 0x8000.0000 + 928M 0x2.8000.0000 (ioremap) PCIE outbound memory window - * - * IO MAP - * 0x00000 + 64K 0x0.fffb.0000 0xfee0.0000 PCIX outbound i/o window - * 0x10000 + 64K 0x0.fffd.0000 0xfee1.0000 PCIE outbound i/o window - */ -#define IOP13XX_PCIX_LOWER_IO_PA 0xfffb0000UL -#define IOP13XX_PCIX_LOWER_IO_BA 0x0UL /* OIOTVR */ - -#define IOP13XX_PCIX_MEM_PHYS_OFFSET 0x100000000ULL -#define IOP13XX_PCIX_MEM_WINDOW_SIZE 0x3a000000UL -#define IOP13XX_PCIX_LOWER_MEM_BA (PHYS_OFFSET + IOP13XX_PCI_OFFSET) -#define IOP13XX_PCIX_LOWER_MEM_PA (IOP13XX_PCIX_MEM_PHYS_OFFSET +\ - IOP13XX_PCIX_LOWER_MEM_BA) -#define IOP13XX_PCIX_UPPER_MEM_PA (IOP13XX_PCIX_LOWER_MEM_PA +\ - IOP13XX_PCIX_MEM_WINDOW_SIZE - 1) -#define IOP13XX_PCIX_UPPER_MEM_BA (IOP13XX_PCIX_LOWER_MEM_BA +\ - IOP13XX_PCIX_MEM_WINDOW_SIZE - 1) - -#define IOP13XX_PCIX_MEM_COOKIE 0x80000000UL -#define IOP13XX_PCIX_LOWER_MEM_RA IOP13XX_PCIX_MEM_COOKIE -#define IOP13XX_PCIX_UPPER_MEM_RA (IOP13XX_PCIX_LOWER_MEM_RA +\ - IOP13XX_PCIX_MEM_WINDOW_SIZE - 1) -#define IOP13XX_PCIX_MEM_OFFSET (IOP13XX_PCIX_MEM_COOKIE -\ - IOP13XX_PCIX_LOWER_MEM_BA) - -/* PCI-E ranges */ -#define IOP13XX_PCIE_LOWER_IO_PA 0xfffd0000UL -#define IOP13XX_PCIE_LOWER_IO_BA 0x10000UL /* OIOTVR */ - -#define IOP13XX_PCIE_MEM_PHYS_OFFSET 0x200000000ULL -#define IOP13XX_PCIE_MEM_WINDOW_SIZE 0x3a000000UL -#define IOP13XX_PCIE_LOWER_MEM_BA (PHYS_OFFSET + IOP13XX_PCI_OFFSET) -#define IOP13XX_PCIE_LOWER_MEM_PA (IOP13XX_PCIE_MEM_PHYS_OFFSET +\ - IOP13XX_PCIE_LOWER_MEM_BA) -#define IOP13XX_PCIE_UPPER_MEM_PA (IOP13XX_PCIE_LOWER_MEM_PA +\ - IOP13XX_PCIE_MEM_WINDOW_SIZE - 1) -#define IOP13XX_PCIE_UPPER_MEM_BA (IOP13XX_PCIE_LOWER_MEM_BA +\ - IOP13XX_PCIE_MEM_WINDOW_SIZE - 1) - -/* All 0xc000.0000 - 0xfdff.ffff addresses belong to PCIe */ -#define IOP13XX_PCIE_MEM_COOKIE 0xc0000000UL -#define IOP13XX_PCIE_LOWER_MEM_RA IOP13XX_PCIE_MEM_COOKIE -#define IOP13XX_PCIE_UPPER_MEM_RA (IOP13XX_PCIE_LOWER_MEM_RA +\ - IOP13XX_PCIE_MEM_WINDOW_SIZE - 1) -#define IOP13XX_PCIE_MEM_OFFSET (IOP13XX_PCIE_MEM_COOKIE -\ - IOP13XX_PCIE_LOWER_MEM_BA) - -/* PBI Ranges */ -#define IOP13XX_PBI_LOWER_MEM_PA 0xf0000000UL -#define IOP13XX_PBI_MEM_WINDOW_SIZE 0x04000000UL -#define IOP13XX_PBI_MEM_COOKIE 0xfa000000UL -#define IOP13XX_PBI_LOWER_MEM_RA IOP13XX_PBI_MEM_COOKIE -#define IOP13XX_PBI_UPPER_MEM_RA (IOP13XX_PBI_LOWER_MEM_RA +\ - IOP13XX_PBI_MEM_WINDOW_SIZE - 1) - -/* - * IOP13XX chipset registers - */ -#define IOP13XX_PMMR_PHYS_MEM_BASE 0xffd80000UL /* PMMR phys. address */ -#define IOP13XX_PMMR_VIRT_MEM_BASE (void __iomem *)(0xfee80000UL) /* PMMR phys. address */ -#define IOP13XX_PMMR_MEM_WINDOW_SIZE 0x80000 -#define IOP13XX_PMMR_UPPER_MEM_VA (IOP13XX_PMMR_VIRT_MEM_BASE +\ - IOP13XX_PMMR_MEM_WINDOW_SIZE - 1) -#define IOP13XX_PMMR_UPPER_MEM_PA (IOP13XX_PMMR_PHYS_MEM_BASE +\ - IOP13XX_PMMR_MEM_WINDOW_SIZE - 1) -#define IOP13XX_PMMR_VIRT_TO_PHYS(addr) (((addr) - IOP13XX_PMMR_VIRT_MEM_BASE)\ - + IOP13XX_PMMR_PHYS_MEM_BASE) -#define IOP13XX_PMMR_PHYS_TO_VIRT(addr) (((addr) - IOP13XX_PMMR_PHYS_MEM_BASE)\ - + IOP13XX_PMMR_VIRT_MEM_BASE) -#define IOP13XX_REG_ADDR32(reg) (IOP13XX_PMMR_VIRT_MEM_BASE + (reg)) -#define IOP13XX_REG_ADDR16(reg) (IOP13XX_PMMR_VIRT_MEM_BASE + (reg)) -#define IOP13XX_REG_ADDR8(reg) (IOP13XX_PMMR_VIRT_MEM_BASE + (reg)) -#define IOP13XX_REG_ADDR32_PHYS(reg) (IOP13XX_PMMR_PHYS_MEM_BASE + (reg)) -#define IOP13XX_REG_ADDR16_PHYS(reg) (IOP13XX_PMMR_PHYS_MEM_BASE + (reg)) -#define IOP13XX_REG_ADDR8_PHYS(reg) (IOP13XX_PMMR_PHYS_MEM_BASE + (reg)) -#define IOP13XX_PMMR_SIZE 0x00080000 - -/*=================== Defines for Platform Devices =====================*/ -#define IOP13XX_UART0_PHYS (IOP13XX_PMMR_PHYS_MEM_BASE + 0x00002300) -#define IOP13XX_UART1_PHYS (IOP13XX_PMMR_PHYS_MEM_BASE + 0x00002340) -#define IOP13XX_UART0_VIRT (IOP13XX_PMMR_VIRT_MEM_BASE + 0x00002300) -#define IOP13XX_UART1_VIRT (IOP13XX_PMMR_VIRT_MEM_BASE + 0x00002340) - -#define IOP13XX_I2C0_PHYS (IOP13XX_PMMR_PHYS_MEM_BASE | 0x00002500) -#define IOP13XX_I2C1_PHYS (IOP13XX_PMMR_PHYS_MEM_BASE | 0x00002520) -#define IOP13XX_I2C2_PHYS (IOP13XX_PMMR_PHYS_MEM_BASE | 0x00002540) -#define IOP13XX_I2C0_VIRT (IOP13XX_PMMR_VIRT_MEM_BASE | 0x00002500) -#define IOP13XX_I2C1_VIRT (IOP13XX_PMMR_VIRT_MEM_BASE | 0x00002520) -#define IOP13XX_I2C2_VIRT (IOP13XX_PMMR_VIRT_MEM_BASE | 0x00002540) - -/* ATU selection flags */ -/* IOP13XX_INIT_ATU_DEFAULT = Rely on CONFIG_IOP13XX_ATU* */ -#define IOP13XX_INIT_ATU_DEFAULT (0) -#define IOP13XX_INIT_ATU_ATUX (1 << 0) -#define IOP13XX_INIT_ATU_ATUE (1 << 1) -#define IOP13XX_INIT_ATU_NONE (1 << 2) - -/* UART selection flags */ -/* IOP13XX_INIT_UART_DEFAULT = Rely on CONFIG_IOP13XX_UART* */ -#define IOP13XX_INIT_UART_DEFAULT (0) -#define IOP13XX_INIT_UART_0 (1 << 0) -#define IOP13XX_INIT_UART_1 (1 << 1) - -/* I2C selection flags */ -/* IOP13XX_INIT_I2C_DEFAULT = Rely on CONFIG_IOP13XX_I2C* */ -#define IOP13XX_INIT_I2C_DEFAULT (0) -#define IOP13XX_INIT_I2C_0 (1 << 0) -#define IOP13XX_INIT_I2C_1 (1 << 1) -#define IOP13XX_INIT_I2C_2 (1 << 2) - -/* ADMA selection flags */ -/* INIT_ADMA_DEFAULT = Rely on CONFIG_IOP13XX_ADMA* */ -#define IOP13XX_INIT_ADMA_DEFAULT (0) -#define IOP13XX_INIT_ADMA_0 (1 << 0) -#define IOP13XX_INIT_ADMA_1 (1 << 1) -#define IOP13XX_INIT_ADMA_2 (1 << 2) - -/* Platform devices */ -#define IQ81340_NUM_UART 2 -#define IQ81340_NUM_I2C 3 -#define IQ81340_NUM_PHYS_MAP_FLASH 1 -#define IQ81340_NUM_ADMA 3 -#define IQ81340_MAX_PLAT_DEVICES (IQ81340_NUM_UART + \ - IQ81340_NUM_I2C + \ - IQ81340_NUM_PHYS_MAP_FLASH + \ - IQ81340_NUM_ADMA) - -/*========================== PMMR offsets for key registers ============*/ -#define IOP13XX_ATU0_PMMR_OFFSET 0x00048000 -#define IOP13XX_ATU1_PMMR_OFFSET 0x0004c000 -#define IOP13XX_ATU2_PMMR_OFFSET 0x0004d000 -#define IOP13XX_ADMA0_PMMR_OFFSET 0x00000000 -#define IOP13XX_ADMA1_PMMR_OFFSET 0x00000200 -#define IOP13XX_ADMA2_PMMR_OFFSET 0x00000400 -#define IOP13XX_PBI_PMMR_OFFSET 0x00001580 -#define IOP13XX_MU_PMMR_OFFSET 0x00004000 -#define IOP13XX_ESSR0_PMMR_OFFSET 0x00002188 -#define IOP13XX_ESSR0 IOP13XX_REG_ADDR32(0x00002188) - -#define IOP13XX_ESSR0_IFACE_MASK 0x00004000 /* Interface PCI-X / PCI-E */ -#define IOP13XX_CONTROLLER_ONLY (1 << 14) -#define IOP13XX_INTERFACE_SEL_PCIX (1 << 15) - -#define IOP13XX_PMON_PMMR_OFFSET 0x0001A000 -#define IOP13XX_PMON_BASE (IOP13XX_PMMR_VIRT_MEM_BASE +\ - IOP13XX_PMON_PMMR_OFFSET) -#define IOP13XX_PMON_PHYSBASE (IOP13XX_PMMR_PHYS_MEM_BASE +\ - IOP13XX_PMON_PMMR_OFFSET) - -#define IOP13XX_PMON_CMD0 (IOP13XX_PMON_BASE + 0x0) -#define IOP13XX_PMON_EVR0 (IOP13XX_PMON_BASE + 0x4) -#define IOP13XX_PMON_STS0 (IOP13XX_PMON_BASE + 0x8) -#define IOP13XX_PMON_DATA0 (IOP13XX_PMON_BASE + 0xC) - -#define IOP13XX_PMON_CMD3 (IOP13XX_PMON_BASE + 0x30) -#define IOP13XX_PMON_EVR3 (IOP13XX_PMON_BASE + 0x34) -#define IOP13XX_PMON_STS3 (IOP13XX_PMON_BASE + 0x38) -#define IOP13XX_PMON_DATA3 (IOP13XX_PMON_BASE + 0x3C) - -#define IOP13XX_PMON_CMD7 (IOP13XX_PMON_BASE + 0x70) -#define IOP13XX_PMON_EVR7 (IOP13XX_PMON_BASE + 0x74) -#define IOP13XX_PMON_STS7 (IOP13XX_PMON_BASE + 0x78) -#define IOP13XX_PMON_DATA7 (IOP13XX_PMON_BASE + 0x7C) - -#define IOP13XX_PMONEN (IOP13XX_PMMR_VIRT_MEM_BASE + 0x4E040) -#define IOP13XX_PMONSTAT (IOP13XX_PMMR_VIRT_MEM_BASE + 0x4E044) - -/*================================ATU===================================*/ -#define IOP13XX_ATUX_OFFSET(ofs) IOP13XX_REG_ADDR32(\ - iop13xx_atux_pmmr_offset + (ofs)) - -#define IOP13XX_ATUX_DID IOP13XX_REG_ADDR16(\ - iop13xx_atux_pmmr_offset + 0x2) - -#define IOP13XX_ATUX_ATUCMD IOP13XX_REG_ADDR16(\ - iop13xx_atux_pmmr_offset + 0x4) -#define IOP13XX_ATUX_ATUSR IOP13XX_REG_ADDR16(\ - iop13xx_atux_pmmr_offset + 0x6) - -#define IOP13XX_ATUX_IABAR0 IOP13XX_ATUX_OFFSET(0x10) -#define IOP13XX_ATUX_IAUBAR0 IOP13XX_ATUX_OFFSET(0x14) -#define IOP13XX_ATUX_IABAR1 IOP13XX_ATUX_OFFSET(0x18) -#define IOP13XX_ATUX_IAUBAR1 IOP13XX_ATUX_OFFSET(0x1c) -#define IOP13XX_ATUX_IABAR2 IOP13XX_ATUX_OFFSET(0x20) -#define IOP13XX_ATUX_IAUBAR2 IOP13XX_ATUX_OFFSET(0x24) -#define IOP13XX_ATUX_IALR0 IOP13XX_ATUX_OFFSET(0x40) -#define IOP13XX_ATUX_IATVR0 IOP13XX_ATUX_OFFSET(0x44) -#define IOP13XX_ATUX_IAUTVR0 IOP13XX_ATUX_OFFSET(0x48) -#define IOP13XX_ATUX_IALR1 IOP13XX_ATUX_OFFSET(0x4c) -#define IOP13XX_ATUX_IATVR1 IOP13XX_ATUX_OFFSET(0x50) -#define IOP13XX_ATUX_IAUTVR1 IOP13XX_ATUX_OFFSET(0x54) -#define IOP13XX_ATUX_IALR2 IOP13XX_ATUX_OFFSET(0x58) -#define IOP13XX_ATUX_IATVR2 IOP13XX_ATUX_OFFSET(0x5c) -#define IOP13XX_ATUX_IAUTVR2 IOP13XX_ATUX_OFFSET(0x60) -#define IOP13XX_ATUX_ATUCR IOP13XX_ATUX_OFFSET(0x70) -#define IOP13XX_ATUX_PCSR IOP13XX_ATUX_OFFSET(0x74) -#define IOP13XX_ATUX_ATUISR IOP13XX_ATUX_OFFSET(0x78) -#define IOP13XX_ATUX_PCIXSR IOP13XX_ATUX_OFFSET(0xD4) -#define IOP13XX_ATUX_IABAR3 IOP13XX_ATUX_OFFSET(0x200) -#define IOP13XX_ATUX_IAUBAR3 IOP13XX_ATUX_OFFSET(0x204) -#define IOP13XX_ATUX_IALR3 IOP13XX_ATUX_OFFSET(0x208) -#define IOP13XX_ATUX_IATVR3 IOP13XX_ATUX_OFFSET(0x20c) -#define IOP13XX_ATUX_IAUTVR3 IOP13XX_ATUX_OFFSET(0x210) - -#define IOP13XX_ATUX_OIOBAR IOP13XX_ATUX_OFFSET(0x300) -#define IOP13XX_ATUX_OIOWTVR IOP13XX_ATUX_OFFSET(0x304) -#define IOP13XX_ATUX_OUMBAR0 IOP13XX_ATUX_OFFSET(0x308) -#define IOP13XX_ATUX_OUMWTVR0 IOP13XX_ATUX_OFFSET(0x30c) -#define IOP13XX_ATUX_OUMBAR1 IOP13XX_ATUX_OFFSET(0x310) -#define IOP13XX_ATUX_OUMWTVR1 IOP13XX_ATUX_OFFSET(0x314) -#define IOP13XX_ATUX_OUMBAR2 IOP13XX_ATUX_OFFSET(0x318) -#define IOP13XX_ATUX_OUMWTVR2 IOP13XX_ATUX_OFFSET(0x31c) -#define IOP13XX_ATUX_OUMBAR3 IOP13XX_ATUX_OFFSET(0x320) -#define IOP13XX_ATUX_OUMWTVR3 IOP13XX_ATUX_OFFSET(0x324) -#define IOP13XX_ATUX_OUDMABAR IOP13XX_ATUX_OFFSET(0x328) -#define IOP13XX_ATUX_OUMSIBAR IOP13XX_ATUX_OFFSET(0x32c) -#define IOP13XX_ATUX_OCCAR IOP13XX_ATUX_OFFSET(0x330) -#define IOP13XX_ATUX_OCCDR IOP13XX_ATUX_OFFSET(0x334) - -#define IOP13XX_ATUX_ATUCR_OUT_EN (1 << 1) -#define IOP13XX_ATUX_PCSR_CENTRAL_RES (1 << 25) -#define IOP13XX_ATUX_PCSR_P_RSTOUT (1 << 21) -#define IOP13XX_ATUX_PCSR_OUT_Q_BUSY (1 << 15) -#define IOP13XX_ATUX_PCSR_IN_Q_BUSY (1 << 14) -#define IOP13XX_ATUX_PCSR_FREQ_OFFSET (16) - -#define IOP13XX_ATUX_STAT_PCI_IFACE_ERR (1 << 18) -#define IOP13XX_ATUX_STAT_VPD_ADDR (1 << 17) -#define IOP13XX_ATUX_STAT_INT_PAR_ERR (1 << 16) -#define IOP13XX_ATUX_STAT_CFG_WRITE (1 << 15) -#define IOP13XX_ATUX_STAT_ERR_COR (1 << 14) -#define IOP13XX_ATUX_STAT_TX_SCEM (1 << 13) -#define IOP13XX_ATUX_STAT_REC_SCEM (1 << 12) -#define IOP13XX_ATUX_STAT_POWER_TRAN (1 << 11) -#define IOP13XX_ATUX_STAT_TX_SERR (1 << 10) -#define IOP13XX_ATUX_STAT_DET_PAR_ERR (1 << 9 ) -#define IOP13XX_ATUX_STAT_BIST (1 << 8 ) -#define IOP13XX_ATUX_STAT_INT_REC_MABORT (1 << 7 ) -#define IOP13XX_ATUX_STAT_REC_SERR (1 << 4 ) -#define IOP13XX_ATUX_STAT_EXT_REC_MABORT (1 << 3 ) -#define IOP13XX_ATUX_STAT_EXT_REC_TABORT (1 << 2 ) -#define IOP13XX_ATUX_STAT_EXT_SIG_TABORT (1 << 1 ) -#define IOP13XX_ATUX_STAT_MASTER_DATA_PAR (1 << 0 ) - -#define IOP13XX_ATUX_PCIXSR_BUS_NUM (8) -#define IOP13XX_ATUX_PCIXSR_DEV_NUM (3) -#define IOP13XX_ATUX_PCIXSR_FUNC_NUM (0) - -#define IOP13XX_ATUX_IALR_DISABLE 0x00000001 -#define IOP13XX_ATUX_OUMBAR_ENABLE 0x80000000 - -#define IOP13XX_ATUE_OFFSET(ofs) IOP13XX_REG_ADDR32(\ - iop13xx_atue_pmmr_offset + (ofs)) - -#define IOP13XX_ATUE_DID IOP13XX_REG_ADDR16(\ - iop13xx_atue_pmmr_offset + 0x2) -#define IOP13XX_ATUE_ATUCMD IOP13XX_REG_ADDR16(\ - iop13xx_atue_pmmr_offset + 0x4) -#define IOP13XX_ATUE_ATUSR IOP13XX_REG_ADDR16(\ - iop13xx_atue_pmmr_offset + 0x6) - -#define IOP13XX_ATUE_IABAR0 IOP13XX_ATUE_OFFSET(0x10) -#define IOP13XX_ATUE_IAUBAR0 IOP13XX_ATUE_OFFSET(0x14) -#define IOP13XX_ATUE_IABAR1 IOP13XX_ATUE_OFFSET(0x18) -#define IOP13XX_ATUE_IAUBAR1 IOP13XX_ATUE_OFFSET(0x1c) -#define IOP13XX_ATUE_IABAR2 IOP13XX_ATUE_OFFSET(0x20) -#define IOP13XX_ATUE_IAUBAR2 IOP13XX_ATUE_OFFSET(0x24) -#define IOP13XX_ATUE_IALR0 IOP13XX_ATUE_OFFSET(0x40) -#define IOP13XX_ATUE_IATVR0 IOP13XX_ATUE_OFFSET(0x44) -#define IOP13XX_ATUE_IAUTVR0 IOP13XX_ATUE_OFFSET(0x48) -#define IOP13XX_ATUE_IALR1 IOP13XX_ATUE_OFFSET(0x4c) -#define IOP13XX_ATUE_IATVR1 IOP13XX_ATUE_OFFSET(0x50) -#define IOP13XX_ATUE_IAUTVR1 IOP13XX_ATUE_OFFSET(0x54) -#define IOP13XX_ATUE_IALR2 IOP13XX_ATUE_OFFSET(0x58) -#define IOP13XX_ATUE_IATVR2 IOP13XX_ATUE_OFFSET(0x5c) -#define IOP13XX_ATUE_IAUTVR2 IOP13XX_ATUE_OFFSET(0x60) -#define IOP13XX_ATUE_PE_LSTS IOP13XX_REG_ADDR16(\ - iop13xx_atue_pmmr_offset + 0xe2) -#define IOP13XX_ATUE_OIOWTVR IOP13XX_ATUE_OFFSET(0x304) -#define IOP13XX_ATUE_OUMBAR0 IOP13XX_ATUE_OFFSET(0x308) -#define IOP13XX_ATUE_OUMWTVR0 IOP13XX_ATUE_OFFSET(0x30c) -#define IOP13XX_ATUE_OUMBAR1 IOP13XX_ATUE_OFFSET(0x310) -#define IOP13XX_ATUE_OUMWTVR1 IOP13XX_ATUE_OFFSET(0x314) -#define IOP13XX_ATUE_OUMBAR2 IOP13XX_ATUE_OFFSET(0x318) -#define IOP13XX_ATUE_OUMWTVR2 IOP13XX_ATUE_OFFSET(0x31c) -#define IOP13XX_ATUE_OUMBAR3 IOP13XX_ATUE_OFFSET(0x320) -#define IOP13XX_ATUE_OUMWTVR3 IOP13XX_ATUE_OFFSET(0x324) - -#define IOP13XX_ATUE_ATUCR IOP13XX_ATUE_OFFSET(0x70) -#define IOP13XX_ATUE_PCSR IOP13XX_ATUE_OFFSET(0x74) -#define IOP13XX_ATUE_ATUISR IOP13XX_ATUE_OFFSET(0x78) -#define IOP13XX_ATUE_OIOBAR IOP13XX_ATUE_OFFSET(0x300) -#define IOP13XX_ATUE_OCCAR IOP13XX_ATUE_OFFSET(0x32c) -#define IOP13XX_ATUE_OCCDR IOP13XX_ATUE_OFFSET(0x330) - -#define IOP13XX_ATUE_PIE_STS IOP13XX_ATUE_OFFSET(0x384) -#define IOP13XX_ATUE_PIE_MSK IOP13XX_ATUE_OFFSET(0x388) - -#define IOP13XX_ATUE_ATUCR_IVM (1 << 6) -#define IOP13XX_ATUE_ATUCR_OUT_EN (1 << 1) -#define IOP13XX_ATUE_OCCAR_BUS_NUM (24) -#define IOP13XX_ATUE_OCCAR_DEV_NUM (19) -#define IOP13XX_ATUE_OCCAR_FUNC_NUM (16) -#define IOP13XX_ATUE_OCCAR_EXT_REG (8) -#define IOP13XX_ATUE_OCCAR_REG (2) - -#define IOP13XX_ATUE_PCSR_BUS_NUM (24) -#define IOP13XX_ATUE_PCSR_DEV_NUM (19) -#define IOP13XX_ATUE_PCSR_FUNC_NUM (16) -#define IOP13XX_ATUE_PCSR_OUT_Q_BUSY (1 << 15) -#define IOP13XX_ATUE_PCSR_IN_Q_BUSY (1 << 14) -#define IOP13XX_ATUE_PCSR_END_POINT (1 << 13) -#define IOP13XX_ATUE_PCSR_LLRB_BUSY (1 << 12) - -#define IOP13XX_ATUE_PCSR_BUS_NUM_MASK (0xff) -#define IOP13XX_ATUE_PCSR_DEV_NUM_MASK (0x1f) -#define IOP13XX_ATUE_PCSR_FUNC_NUM_MASK (0x7) - -#define IOP13XX_ATUE_PCSR_CORE_RESET (8) -#define IOP13XX_ATUE_PCSR_FUNC_NUM (16) - -#define IOP13XX_ATUE_LSTS_TRAINING (1 << 11) -#define IOP13XX_ATUE_STAT_SLOT_PWR_MSG (1 << 28) -#define IOP13XX_ATUE_STAT_PME (1 << 27) -#define IOP13XX_ATUE_STAT_HOT_PLUG_MSG (1 << 26) -#define IOP13XX_ATUE_STAT_IVM (1 << 25) -#define IOP13XX_ATUE_STAT_BIST (1 << 24) -#define IOP13XX_ATUE_STAT_CFG_WRITE (1 << 18) -#define IOP13XX_ATUE_STAT_VPD_ADDR (1 << 17) -#define IOP13XX_ATUE_STAT_POWER_TRAN (1 << 16) -#define IOP13XX_ATUE_STAT_HALT_ON_ERROR (1 << 13) -#define IOP13XX_ATUE_STAT_ROOT_SYS_ERR (1 << 12) -#define IOP13XX_ATUE_STAT_ROOT_ERR_MSG (1 << 11) -#define IOP13XX_ATUE_STAT_PCI_IFACE_ERR (1 << 10) -#define IOP13XX_ATUE_STAT_ERR_COR (1 << 9 ) -#define IOP13XX_ATUE_STAT_ERR_UNCOR (1 << 8 ) -#define IOP13XX_ATUE_STAT_CRS (1 << 7 ) -#define IOP13XX_ATUE_STAT_LNK_DWN (1 << 6 ) -#define IOP13XX_ATUE_STAT_INT_REC_MABORT (1 << 5 ) -#define IOP13XX_ATUE_STAT_DET_PAR_ERR (1 << 4 ) -#define IOP13XX_ATUE_STAT_EXT_REC_MABORT (1 << 3 ) -#define IOP13XX_ATUE_STAT_SIG_TABORT (1 << 2 ) -#define IOP13XX_ATUE_STAT_EXT_REC_TABORT (1 << 1 ) -#define IOP13XX_ATUE_STAT_MASTER_DATA_PAR (1 << 0 ) - -#define IOP13XX_ATUE_ESTAT_REC_UNSUPPORTED_COMP_REQ (1 << 31) -#define IOP13XX_ATUE_ESTAT_REC_COMPLETER_ABORT (1 << 30) -#define IOP13XX_ATUE_ESTAT_TX_POISONED_TLP (1 << 29) -#define IOP13XX_ATUE_ESTAT_TX_PAR_ERR (1 << 28) -#define IOP13XX_ATUE_ESTAT_REC_UNSUPPORTED_REQ (1 << 20) -#define IOP13XX_ATUE_ESTAT_REC_ECRC_ERR (1 << 19) -#define IOP13XX_ATUE_ESTAT_REC_MALFORMED_TLP (1 << 18) -#define IOP13XX_ATUE_ESTAT_TX_RECEIVER_OVERFLOW (1 << 17) -#define IOP13XX_ATUE_ESTAT_REC_UNEXPECTED_COMP (1 << 16) -#define IOP13XX_ATUE_ESTAT_INT_COMP_ABORT (1 << 15) -#define IOP13XX_ATUE_ESTAT_COMP_TIMEOUT (1 << 14) -#define IOP13XX_ATUE_ESTAT_FLOW_CONTROL_ERR (1 << 13) -#define IOP13XX_ATUE_ESTAT_REC_POISONED_TLP (1 << 12) -#define IOP13XX_ATUE_ESTAT_DATA_LNK_ERR (1 << 4 ) -#define IOP13XX_ATUE_ESTAT_TRAINING_ERR (1 << 0 ) - -#define IOP13XX_ATUE_IALR_DISABLE (0x00000001) -#define IOP13XX_ATUE_OUMBAR_ENABLE (0x80000000) -#define IOP13XX_ATU_OUMBAR_FUNC_NUM (28) -#define IOP13XX_ATU_OUMBAR_FUNC_NUM_MASK (0x7) -/*=======================================================================*/ - -/*============================MESSAGING UNIT=============================*/ -#define IOP13XX_MU_OFFSET(ofs) IOP13XX_REG_ADDR32(IOP13XX_MU_PMMR_OFFSET +\ - (ofs)) - -#define IOP13XX_MU_IMR0 IOP13XX_MU_OFFSET(0x10) -#define IOP13XX_MU_IMR1 IOP13XX_MU_OFFSET(0x14) -#define IOP13XX_MU_OMR0 IOP13XX_MU_OFFSET(0x18) -#define IOP13XX_MU_OMR1 IOP13XX_MU_OFFSET(0x1C) -#define IOP13XX_MU_IDR IOP13XX_MU_OFFSET(0x20) -#define IOP13XX_MU_IISR IOP13XX_MU_OFFSET(0x24) -#define IOP13XX_MU_IIMR IOP13XX_MU_OFFSET(0x28) -#define IOP13XX_MU_ODR IOP13XX_MU_OFFSET(0x2C) -#define IOP13XX_MU_OISR IOP13XX_MU_OFFSET(0x30) -#define IOP13XX_MU_OIMR IOP13XX_MU_OFFSET(0x34) -#define IOP13XX_MU_IRCSR IOP13XX_MU_OFFSET(0x38) -#define IOP13XX_MU_ORCSR IOP13XX_MU_OFFSET(0x3C) -#define IOP13XX_MU_MIMR IOP13XX_MU_OFFSET(0x48) -#define IOP13XX_MU_MUCR IOP13XX_MU_OFFSET(0x50) -#define IOP13XX_MU_QBAR IOP13XX_MU_OFFSET(0x54) -#define IOP13XX_MU_MUBAR IOP13XX_MU_OFFSET(0x84) - -#define IOP13XX_MU_WINDOW_SIZE (8 * 1024) -#define IOP13XX_MU_BASE_PHYS (0xff000000) -#define IOP13XX_MU_BASE_PCI (0xff000000) -#define IOP13XX_MU_MIMR_PCI (IOP13XX_MU_BASE_PCI + 0x48) -#define IOP13XX_MU_MIMR_CORE_SELECT (15) -/*=======================================================================*/ - -/*==============================ADMA UNITS===============================*/ -#define IOP13XX_ADMA_PHYS_BASE(chan) IOP13XX_REG_ADDR32_PHYS((chan << 9)) -#define IOP13XX_ADMA_UPPER_PA(chan) (IOP13XX_ADMA_PHYS_BASE(chan) + 0xc0) - -/*==============================XSI BRIDGE===============================*/ -#define IOP13XX_XBG_BECSR IOP13XX_REG_ADDR32(0x178c) -#define IOP13XX_XBG_BERAR IOP13XX_REG_ADDR32(0x1790) -#define IOP13XX_XBG_BERUAR IOP13XX_REG_ADDR32(0x1794) -#define is_atue_occdr_error(x) ((__raw_readl(IOP13XX_XBG_BERAR) == \ - IOP13XX_PMMR_VIRT_TO_PHYS(\ - IOP13XX_ATUE_OCCDR))\ - && (__raw_readl(IOP13XX_XBG_BECSR) & 1)) -#define is_atux_occdr_error(x) ((__raw_readl(IOP13XX_XBG_BERAR) == \ - IOP13XX_PMMR_VIRT_TO_PHYS(\ - IOP13XX_ATUX_OCCDR))\ - && (__raw_readl(IOP13XX_XBG_BECSR) & 1)) -/*=======================================================================*/ - -#define IOP13XX_PBI_OFFSET(ofs) IOP13XX_REG_ADDR32(IOP13XX_PBI_PMMR_OFFSET +\ - (ofs)) - -#define IOP13XX_PBI_CR IOP13XX_PBI_OFFSET(0x0) -#define IOP13XX_PBI_SR IOP13XX_PBI_OFFSET(0x4) -#define IOP13XX_PBI_BAR0 IOP13XX_PBI_OFFSET(0x8) -#define IOP13XX_PBI_LR0 IOP13XX_PBI_OFFSET(0xc) -#define IOP13XX_PBI_BAR1 IOP13XX_PBI_OFFSET(0x10) -#define IOP13XX_PBI_LR1 IOP13XX_PBI_OFFSET(0x14) - -#define IOP13XX_PROCESSOR_FREQ IOP13XX_REG_ADDR32(0x2180) - -/* Watchdog timer definitions */ -#define IOP_WDTCR_EN_ARM 0x1e1e1e1e -#define IOP_WDTCR_EN 0xe1e1e1e1 -#define IOP_WDTCR_DIS_ARM 0x1f1f1f1f -#define IOP_WDTCR_DIS 0xf1f1f1f1 -#define IOP_RCSR_WDT (1 << 5) /* reset caused by watchdog timer */ -#define IOP13XX_WDTSR_WRITE_EN (1 << 31) /* used to speed up reset requests */ -#define IOP13XX_WDTCR_IB_RESET (1 << 0) - -#endif /* _IOP13XX_HW_H_ */ diff --git a/arch/arm/mach-iop13xx/include/mach/iq81340.h b/arch/arm/mach-iop13xx/include/mach/iq81340.h deleted file mode 100644 index d7ad27a955589435f3fe6a28a1aa6264759111c8..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/include/mach/iq81340.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _IQ81340_H_ -#define _IQ81340_H_ - -#define IQ81340_PCE_BAR0 IOP13XX_PBI_LOWER_MEM_RA -#define IQ81340_PCE_BAR1 (IQ81340_PCE_BAR0 + 0x02000000) - -#define IQ81340_FLASHBASE IQ81340_PCE_BAR0 /* Flash */ - -#define IQ81340_PCE_BAR1_OFFSET(a) (IQ81340_PCE_BAR1 + (a)) - -#define IQ81340_PRD_CODE IQ81340_PCE_BAR1_OFFSET(0) -#define IQ81340_BRD_STEP IQ81340_PCE_BAR1_OFFSET(0x10000) -#define IQ81340_CPLD_REV IQ81340_PCE_BAR1_OFFSET(0x20000) -#define IQ81340_LED IQ81340_PCE_BAR1_OFFSET(0x30000) -#define IQ81340_LHEX IQ81340_PCE_BAR1_OFFSET(0x40000) -#define IQ81340_RHEX IQ81340_PCE_BAR1_OFFSET(0x50000) -#define IQ81340_BUZZER IQ81340_PCE_BAR1_OFFSET(0x60000) -#define IQ81340_32K_NVRAM IQ81340_PCE_BAR1_OFFSET(0x70000) -#define IQ81340_256K_NVRAM IQ81340_PCE_BAR1_OFFSET(0x80000) -#define IQ81340_ROTARY_SW IQ81340_PCE_BAR1_OFFSET(0xd0000) -#define IQ81340_BATT_STAT IQ81340_PCE_BAR1_OFFSET(0xf0000) -#define IQ81340_CMP_FLSH IQ81340_PCE_BAR1_OFFSET(0x1000000) /* 16MB */ - -#define PBI_CF_IDE_BASE (IQ81340_CMP_FLSH) -#define PBI_CF_BAR_ADDR (IOP13XX_PBI_BAR1) - - -#endif /* _IQ81340_H_ */ diff --git a/arch/arm/mach-iop13xx/include/mach/irqs.h b/arch/arm/mach-iop13xx/include/mach/irqs.h deleted file mode 100644 index cd6b6375c05066ba0efe3e8baf9a200a9f167f8b..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/include/mach/irqs.h +++ /dev/null @@ -1,195 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _IOP13XX_IRQS_H_ -#define _IOP13XX_IRQS_H_ - -#ifndef __ASSEMBLER__ -#include - -/* INTPND0 CP6 R0 Page 3 - */ -static inline u32 read_intpnd_0(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c0, c3, 0":"=r" (val)); - return val; -} - -/* INTPND1 CP6 R1 Page 3 - */ -static inline u32 read_intpnd_1(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c1, c3, 0":"=r" (val)); - return val; -} - -/* INTPND2 CP6 R2 Page 3 - */ -static inline u32 read_intpnd_2(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c2, c3, 0":"=r" (val)); - return val; -} - -/* INTPND3 CP6 R3 Page 3 - */ -static inline u32 read_intpnd_3(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c3, c3, 0":"=r" (val)); - return val; -} -#endif - -#define INTBASE 0 -#define INTSIZE_4 1 - -/* - * iop34x chipset interrupts - */ -#define IOP13XX_IRQ(x) (IOP13XX_IRQ_OFS + (x)) - -/* - * On IRQ or FIQ register - */ -#define IRQ_IOP13XX_ADMA0_EOT (0) -#define IRQ_IOP13XX_ADMA0_EOC (1) -#define IRQ_IOP13XX_ADMA1_EOT (2) -#define IRQ_IOP13XX_ADMA1_EOC (3) -#define IRQ_IOP13XX_ADMA2_EOT (4) -#define IRQ_IOP13XX_ADMA2_EOC (5) -#define IRQ_IOP134_WATCHDOG (6) -#define IRQ_IOP13XX_RSVD_7 (7) -#define IRQ_IOP13XX_TIMER0 (8) -#define IRQ_IOP13XX_TIMER1 (9) -#define IRQ_IOP13XX_I2C_0 (10) -#define IRQ_IOP13XX_I2C_1 (11) -#define IRQ_IOP13XX_MSG (12) -#define IRQ_IOP13XX_MSGIBQ (13) -#define IRQ_IOP13XX_ATU_IM (14) -#define IRQ_IOP13XX_ATU_BIST (15) -#define IRQ_IOP13XX_PPMU (16) -#define IRQ_IOP13XX_COREPMU (17) -#define IRQ_IOP13XX_CORECACHE (18) -#define IRQ_IOP13XX_RSVD_19 (19) -#define IRQ_IOP13XX_RSVD_20 (20) -#define IRQ_IOP13XX_RSVD_21 (21) -#define IRQ_IOP13XX_RSVD_22 (22) -#define IRQ_IOP13XX_RSVD_23 (23) -#define IRQ_IOP13XX_XINT0 (24) -#define IRQ_IOP13XX_XINT1 (25) -#define IRQ_IOP13XX_XINT2 (26) -#define IRQ_IOP13XX_XINT3 (27) -#define IRQ_IOP13XX_XINT4 (28) -#define IRQ_IOP13XX_XINT5 (29) -#define IRQ_IOP13XX_XINT6 (30) -#define IRQ_IOP13XX_XINT7 (31) - /* IINTSRC1 bit */ -#define IRQ_IOP13XX_XINT8 (32) /* 0 */ -#define IRQ_IOP13XX_XINT9 (33) /* 1 */ -#define IRQ_IOP13XX_XINT10 (34) /* 2 */ -#define IRQ_IOP13XX_XINT11 (35) /* 3 */ -#define IRQ_IOP13XX_XINT12 (36) /* 4 */ -#define IRQ_IOP13XX_XINT13 (37) /* 5 */ -#define IRQ_IOP13XX_XINT14 (38) /* 6 */ -#define IRQ_IOP13XX_XINT15 (39) /* 7 */ -#define IRQ_IOP13XX_RSVD_40 (40) /* 8 */ -#define IRQ_IOP13XX_RSVD_41 (41) /* 9 */ -#define IRQ_IOP13XX_RSVD_42 (42) /* 10 */ -#define IRQ_IOP13XX_RSVD_43 (43) /* 11 */ -#define IRQ_IOP13XX_RSVD_44 (44) /* 12 */ -#define IRQ_IOP13XX_RSVD_45 (45) /* 13 */ -#define IRQ_IOP13XX_RSVD_46 (46) /* 14 */ -#define IRQ_IOP13XX_RSVD_47 (47) /* 15 */ -#define IRQ_IOP13XX_RSVD_48 (48) /* 16 */ -#define IRQ_IOP13XX_RSVD_49 (49) /* 17 */ -#define IRQ_IOP13XX_RSVD_50 (50) /* 18 */ -#define IRQ_IOP13XX_UART0 (51) /* 19 */ -#define IRQ_IOP13XX_UART1 (52) /* 20 */ -#define IRQ_IOP13XX_PBIE (53) /* 21 */ -#define IRQ_IOP13XX_ATU_CRW (54) /* 22 */ -#define IRQ_IOP13XX_ATU_ERR (55) /* 23 */ -#define IRQ_IOP13XX_MCU_ERR (56) /* 24 */ -#define IRQ_IOP13XX_ADMA0_ERR (57) /* 25 */ -#define IRQ_IOP13XX_ADMA1_ERR (58) /* 26 */ -#define IRQ_IOP13XX_ADMA2_ERR (59) /* 27 */ -#define IRQ_IOP13XX_RSVD_60 (60) /* 28 */ -#define IRQ_IOP13XX_RSVD_61 (61) /* 29 */ -#define IRQ_IOP13XX_MSG_ERR (62) /* 30 */ -#define IRQ_IOP13XX_RSVD_63 (63) /* 31 */ - /* IINTSRC2 bit */ -#define IRQ_IOP13XX_INTERPROC (64) /* 0 */ -#define IRQ_IOP13XX_RSVD_65 (65) /* 1 */ -#define IRQ_IOP13XX_RSVD_66 (66) /* 2 */ -#define IRQ_IOP13XX_RSVD_67 (67) /* 3 */ -#define IRQ_IOP13XX_RSVD_68 (68) /* 4 */ -#define IRQ_IOP13XX_RSVD_69 (69) /* 5 */ -#define IRQ_IOP13XX_RSVD_70 (70) /* 6 */ -#define IRQ_IOP13XX_RSVD_71 (71) /* 7 */ -#define IRQ_IOP13XX_RSVD_72 (72) /* 8 */ -#define IRQ_IOP13XX_RSVD_73 (73) /* 9 */ -#define IRQ_IOP13XX_RSVD_74 (74) /* 10 */ -#define IRQ_IOP13XX_RSVD_75 (75) /* 11 */ -#define IRQ_IOP13XX_RSVD_76 (76) /* 12 */ -#define IRQ_IOP13XX_RSVD_77 (77) /* 13 */ -#define IRQ_IOP13XX_RSVD_78 (78) /* 14 */ -#define IRQ_IOP13XX_RSVD_79 (79) /* 15 */ -#define IRQ_IOP13XX_RSVD_80 (80) /* 16 */ -#define IRQ_IOP13XX_RSVD_81 (81) /* 17 */ -#define IRQ_IOP13XX_RSVD_82 (82) /* 18 */ -#define IRQ_IOP13XX_RSVD_83 (83) /* 19 */ -#define IRQ_IOP13XX_RSVD_84 (84) /* 20 */ -#define IRQ_IOP13XX_RSVD_85 (85) /* 21 */ -#define IRQ_IOP13XX_RSVD_86 (86) /* 22 */ -#define IRQ_IOP13XX_RSVD_87 (87) /* 23 */ -#define IRQ_IOP13XX_RSVD_88 (88) /* 24 */ -#define IRQ_IOP13XX_RSVD_89 (89) /* 25 */ -#define IRQ_IOP13XX_RSVD_90 (90) /* 26 */ -#define IRQ_IOP13XX_RSVD_91 (91) /* 27 */ -#define IRQ_IOP13XX_RSVD_92 (92) /* 28 */ -#define IRQ_IOP13XX_RSVD_93 (93) /* 29 */ -#define IRQ_IOP13XX_SIB_ERR (94) /* 30 */ -#define IRQ_IOP13XX_SRAM_ERR (95) /* 31 */ - /* IINTSRC3 bit */ -#define IRQ_IOP13XX_I2C_2 (96) /* 0 */ -#define IRQ_IOP13XX_ATUE_BIST (97) /* 1 */ -#define IRQ_IOP13XX_ATUE_CRW (98) /* 2 */ -#define IRQ_IOP13XX_ATUE_ERR (99) /* 3 */ -#define IRQ_IOP13XX_IMU (100) /* 4 */ -#define IRQ_IOP13XX_RSVD_101 (101) /* 5 */ -#define IRQ_IOP13XX_RSVD_102 (102) /* 6 */ -#define IRQ_IOP13XX_TPMI0_OUT (103) /* 7 */ -#define IRQ_IOP13XX_TPMI1_OUT (104) /* 8 */ -#define IRQ_IOP13XX_TPMI2_OUT (105) /* 9 */ -#define IRQ_IOP13XX_TPMI3_OUT (106) /* 10 */ -#define IRQ_IOP13XX_ATUE_IMA (107) /* 11 */ -#define IRQ_IOP13XX_ATUE_IMB (108) /* 12 */ -#define IRQ_IOP13XX_ATUE_IMC (109) /* 13 */ -#define IRQ_IOP13XX_ATUE_IMD (110) /* 14 */ -#define IRQ_IOP13XX_MU_MSI_TB (111) /* 15 */ -#define IRQ_IOP13XX_RSVD_112 (112) /* 16 */ -#define IRQ_IOP13XX_INBD_MSI (113) /* 17 */ -#define IRQ_IOP13XX_RSVD_114 (114) /* 18 */ -#define IRQ_IOP13XX_RSVD_115 (115) /* 19 */ -#define IRQ_IOP13XX_RSVD_116 (116) /* 20 */ -#define IRQ_IOP13XX_RSVD_117 (117) /* 21 */ -#define IRQ_IOP13XX_RSVD_118 (118) /* 22 */ -#define IRQ_IOP13XX_RSVD_119 (119) /* 23 */ -#define IRQ_IOP13XX_RSVD_120 (120) /* 24 */ -#define IRQ_IOP13XX_RSVD_121 (121) /* 25 */ -#define IRQ_IOP13XX_RSVD_122 (122) /* 26 */ -#define IRQ_IOP13XX_RSVD_123 (123) /* 27 */ -#define IRQ_IOP13XX_RSVD_124 (124) /* 28 */ -#define IRQ_IOP13XX_RSVD_125 (125) /* 29 */ -#define IRQ_IOP13XX_RSVD_126 (126) /* 30 */ -#define IRQ_IOP13XX_HPI (127) /* 31 */ - -#ifdef CONFIG_PCI_MSI -#define IRQ_IOP13XX_MSI_0 (IRQ_IOP13XX_HPI + 1) -#define NR_IOP13XX_IRQS (IRQ_IOP13XX_MSI_0 + 128) -#else -#define NR_IOP13XX_IRQS (IRQ_IOP13XX_HPI + 1) -#endif - -#endif /* _IOP13XX_IRQ_H_ */ diff --git a/arch/arm/mach-iop13xx/include/mach/memory.h b/arch/arm/mach-iop13xx/include/mach/memory.h deleted file mode 100644 index 32da0e09c6a31324e3de3540231c4e3bfb66b160..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/include/mach/memory.h +++ /dev/null @@ -1,68 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __ASM_ARCH_MEMORY_H -#define __ASM_ARCH_MEMORY_H - -#include - -#ifndef __ASSEMBLY__ - -#if defined(CONFIG_ARCH_IOP13XX) -#define IOP13XX_PMMR_V_START (IOP13XX_PMMR_VIRT_MEM_BASE) -#define IOP13XX_PMMR_V_END (IOP13XX_PMMR_VIRT_MEM_BASE + IOP13XX_PMMR_SIZE) -#define IOP13XX_PMMR_P_START (IOP13XX_PMMR_PHYS_MEM_BASE) -#define IOP13XX_PMMR_P_END (IOP13XX_PMMR_PHYS_MEM_BASE + IOP13XX_PMMR_SIZE) - -static inline dma_addr_t __virt_to_lbus(void __iomem *x) -{ - return x + IOP13XX_PMMR_PHYS_MEM_BASE - IOP13XX_PMMR_VIRT_MEM_BASE; -} - -static inline void __iomem *__lbus_to_virt(dma_addr_t x) -{ - return x + IOP13XX_PMMR_VIRT_MEM_BASE - IOP13XX_PMMR_PHYS_MEM_BASE; -} - -#define __is_lbus_dma(a) \ - ((a) >= IOP13XX_PMMR_P_START && (a) < IOP13XX_PMMR_P_END) - -#define __is_lbus_virt(a) \ - ((a) >= IOP13XX_PMMR_V_START && (a) < IOP13XX_PMMR_V_END) - -/* Device is an lbus device if it is on the platform bus of the IOP13XX */ -#define is_lbus_device(dev) \ - (dev && strncmp(dev->bus->name, "platform", 8) == 0) - -#define __arch_dma_to_virt(dev, addr) \ - ({ \ - void * __virt; \ - dma_addr_t __dma = addr; \ - if (is_lbus_device(dev) && __is_lbus_dma(__dma)) \ - __virt = __lbus_to_virt(__dma); \ - else \ - __virt = (void *)__phys_to_virt(__dma); \ - __virt; \ - }) - -#define __arch_virt_to_dma(dev, addr) \ - ({ \ - void * __virt = addr; \ - dma_addr_t __dma; \ - if (is_lbus_device(dev) && __is_lbus_virt(__virt)) \ - __dma = __virt_to_lbus(__virt); \ - else \ - __dma = __virt_to_phys((unsigned long)__virt); \ - __dma; \ - }) - -#define __arch_pfn_to_dma(dev, pfn) \ - ({ \ - /* __is_lbus_virt() can never be true for RAM pages */ \ - (dma_addr_t)__pfn_to_phys(pfn); \ - }) - -#define __arch_dma_to_pfn(dev, addr) __phys_to_pfn(addr) - -#endif /* CONFIG_ARCH_IOP13XX */ -#endif /* !ASSEMBLY */ - -#endif diff --git a/arch/arm/mach-iop13xx/include/mach/time.h b/arch/arm/mach-iop13xx/include/mach/time.h deleted file mode 100644 index 2c2d7532d5c3b43100fd79854ddf68042af93f16..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/include/mach/time.h +++ /dev/null @@ -1,127 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _IOP13XX_TIME_H_ -#define _IOP13XX_TIME_H_ - -#include - -#define IRQ_IOP_TIMER0 IRQ_IOP13XX_TIMER0 - -#define IOP_TMR_EN 0x02 -#define IOP_TMR_RELOAD 0x04 -#define IOP_TMR_PRIVILEGED 0x08 -#define IOP_TMR_RATIO_1_1 0x00 - -#define IOP13XX_XSI_FREQ_RATIO_MASK (3 << 19) -#define IOP13XX_XSI_FREQ_RATIO_2 (0 << 19) -#define IOP13XX_XSI_FREQ_RATIO_3 (1 << 19) -#define IOP13XX_XSI_FREQ_RATIO_4 (2 << 19) -#define IOP13XX_CORE_FREQ_MASK (7 << 16) -#define IOP13XX_CORE_FREQ_600 (0 << 16) -#define IOP13XX_CORE_FREQ_667 (1 << 16) -#define IOP13XX_CORE_FREQ_800 (2 << 16) -#define IOP13XX_CORE_FREQ_933 (3 << 16) -#define IOP13XX_CORE_FREQ_1000 (4 << 16) -#define IOP13XX_CORE_FREQ_1200 (5 << 16) - -void iop_init_time(unsigned long tickrate); - -static inline unsigned long iop13xx_core_freq(void) -{ - unsigned long freq = __raw_readl(IOP13XX_PROCESSOR_FREQ); - freq &= IOP13XX_CORE_FREQ_MASK; - switch (freq) { - case IOP13XX_CORE_FREQ_600: - return 600000000; - case IOP13XX_CORE_FREQ_667: - return 667000000; - case IOP13XX_CORE_FREQ_800: - return 800000000; - case IOP13XX_CORE_FREQ_933: - return 933000000; - case IOP13XX_CORE_FREQ_1000: - return 1000000000; - case IOP13XX_CORE_FREQ_1200: - return 1200000000; - default: - printk("%s: warning unknown frequency, defaulting to 800MHz\n", - __func__); - } - - return 800000000; -} - -static inline unsigned long iop13xx_xsi_bus_ratio(void) -{ - unsigned long ratio = __raw_readl(IOP13XX_PROCESSOR_FREQ); - ratio &= IOP13XX_XSI_FREQ_RATIO_MASK; - switch (ratio) { - case IOP13XX_XSI_FREQ_RATIO_2: - return 2; - case IOP13XX_XSI_FREQ_RATIO_3: - return 3; - case IOP13XX_XSI_FREQ_RATIO_4: - return 4; - default: - printk("%s: warning unknown ratio, defaulting to 2\n", - __func__); - } - - return 2; -} - -static inline u32 read_tmr0(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c0, c9, 0" : "=r" (val)); - return val; -} - -static inline void write_tmr0(u32 val) -{ - asm volatile("mcr p6, 0, %0, c0, c9, 0" : : "r" (val)); -} - -static inline void write_tmr1(u32 val) -{ - asm volatile("mcr p6, 0, %0, c1, c9, 0" : : "r" (val)); -} - -static inline u32 read_tcr0(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c2, c9, 0" : "=r" (val)); - return val; -} - -static inline void write_tcr0(u32 val) -{ - asm volatile("mcr p6, 0, %0, c2, c9, 0" : : "r" (val)); -} - -static inline u32 read_tcr1(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c3, c9, 0" : "=r" (val)); - return val; -} - -static inline void write_tcr1(u32 val) -{ - asm volatile("mcr p6, 0, %0, c3, c9, 0" : : "r" (val)); -} - -static inline void write_trr0(u32 val) -{ - asm volatile("mcr p6, 0, %0, c4, c9, 0" : : "r" (val)); -} - -static inline void write_trr1(u32 val) -{ - asm volatile("mcr p6, 0, %0, c5, c9, 0" : : "r" (val)); -} - -static inline void write_tisr(u32 val) -{ - asm volatile("mcr p6, 0, %0, c6, c9, 0" : : "r" (val)); -} -#endif diff --git a/arch/arm/mach-iop13xx/include/mach/uncompress.h b/arch/arm/mach-iop13xx/include/mach/uncompress.h deleted file mode 100644 index c62903041d119a8c55e25cc951d43034e4e79542..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/include/mach/uncompress.h +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#include -#include -#include - -#define UART_BASE ((volatile u32 *)IOP13XX_UART1_PHYS) -#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE) - -static inline void putc(char c) -{ - while ((UART_BASE[UART_LSR] & TX_DONE) != TX_DONE) - barrier(); - UART_BASE[UART_TX] = c; -} - -static inline void flush(void) -{ -} - -/* - * nothing to do - */ -#define arch_decomp_setup() diff --git a/arch/arm/mach-iop13xx/io.c b/arch/arm/mach-iop13xx/io.c deleted file mode 100644 index 253d446b1f3fcba5680fecb4ed7871ff0b22133e..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/io.c +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * iop13xx custom ioremap implementation - * Copyright (c) 2005-2006, Intel Corporation. - */ -#include -#include -#include -#include - -#include "pci.h" - -static void __iomem *__iop13xx_ioremap_caller(phys_addr_t cookie, - size_t size, unsigned int mtype, void *caller) -{ - void __iomem * retval; - - switch (cookie) { - case IOP13XX_PCIX_LOWER_MEM_RA ... IOP13XX_PCIX_UPPER_MEM_RA: - if (unlikely(!iop13xx_atux_mem_base)) - retval = NULL; - else - retval = (iop13xx_atux_mem_base + - (cookie - IOP13XX_PCIX_LOWER_MEM_RA)); - break; - case IOP13XX_PCIE_LOWER_MEM_RA ... IOP13XX_PCIE_UPPER_MEM_RA: - if (unlikely(!iop13xx_atue_mem_base)) - retval = NULL; - else - retval = (iop13xx_atue_mem_base + - (cookie - IOP13XX_PCIE_LOWER_MEM_RA)); - break; - case IOP13XX_PBI_LOWER_MEM_RA ... IOP13XX_PBI_UPPER_MEM_RA: - retval = __arm_ioremap_caller(IOP13XX_PBI_LOWER_MEM_PA + - (cookie - IOP13XX_PBI_LOWER_MEM_RA), - size, mtype, __builtin_return_address(0)); - break; - case IOP13XX_PMMR_PHYS_MEM_BASE ... IOP13XX_PMMR_UPPER_MEM_PA: - retval = IOP13XX_PMMR_PHYS_TO_VIRT(cookie); - break; - default: - retval = __arm_ioremap_caller(cookie, size, mtype, - caller); - } - - return retval; -} - -static void __iop13xx_iounmap(volatile void __iomem *addr) -{ - if (iop13xx_atue_mem_base) - if (addr >= (void __iomem *) iop13xx_atue_mem_base && - addr < (void __iomem *) (iop13xx_atue_mem_base + - iop13xx_atue_mem_size)) - goto skip; - - if (iop13xx_atux_mem_base) - if (addr >= (void __iomem *) iop13xx_atux_mem_base && - addr < (void __iomem *) (iop13xx_atux_mem_base + - iop13xx_atux_mem_size)) - goto skip; - - switch ((u32) addr) { - case (u32)IOP13XX_PMMR_VIRT_MEM_BASE ... (u32)IOP13XX_PMMR_UPPER_MEM_VA: - goto skip; - } - __iounmap(addr); - -skip: - return; -} - -void __init iop13xx_init_early(void) -{ - arch_ioremap_caller = __iop13xx_ioremap_caller; - arch_iounmap = __iop13xx_iounmap; -} diff --git a/arch/arm/mach-iop13xx/iq81340mc.c b/arch/arm/mach-iop13xx/iq81340mc.c deleted file mode 100644 index b3ce5cb228cc3ef374d4e53ce224ece9e91a3a3d..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/iq81340mc.c +++ /dev/null @@ -1,84 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * iq81340mc board support - * Copyright (c) 2005-2006, Intel Corporation. - */ -#include - -#include -#include -#include -#include -#include -#include "pci.h" -#include -#include - -extern int init_atu; /* Flag to select which ATU(s) to initialize / disable */ - -static int __init -iq81340mc_pcix_map_irq(const struct pci_dev *dev, u8 idsel, u8 pin) -{ - switch (idsel) { - case 1: - switch (pin) { - case 1: return ATUX_INTB; - case 2: return ATUX_INTC; - case 3: return ATUX_INTD; - case 4: return ATUX_INTA; - default: return -1; - } - case 2: - switch (pin) { - case 1: return ATUX_INTC; - case 2: return ATUX_INTD; - case 3: return ATUX_INTC; - case 4: return ATUX_INTD; - default: return -1; - } - default: return -1; - } -} - -static struct hw_pci iq81340mc_pci __initdata = { - .nr_controllers = 0, - .setup = iop13xx_pci_setup, - .map_irq = iq81340mc_pcix_map_irq, - .scan = iop13xx_scan_bus, - .preinit = iop13xx_pci_init, -}; - -static int __init iq81340mc_pci_init(void) -{ - iop13xx_atu_select(&iq81340mc_pci); - pci_common_init(&iq81340mc_pci); - iop13xx_map_pci_memory(); - - return 0; -} - -static void __init iq81340mc_init(void) -{ - iop13xx_platform_init(); - iq81340mc_pci_init(); - iop13xx_add_tpmi_devices(); -} - -static void __init iq81340mc_timer_init(void) -{ - unsigned long bus_freq = iop13xx_core_freq() / iop13xx_xsi_bus_ratio(); - printk(KERN_DEBUG "%s: bus frequency: %lu\n", __func__, bus_freq); - iop_init_time(bus_freq); -} - -MACHINE_START(IQ81340MC, "Intel IQ81340MC") - /* Maintainer: Dan Williams */ - .atag_offset = 0x100, - .init_early = iop13xx_init_early, - .map_io = iop13xx_map_io, - .init_irq = iop13xx_init_irq, - .init_time = iq81340mc_timer_init, - .init_machine = iq81340mc_init, - .restart = iop13xx_restart, - .nr_irqs = NR_IOP13XX_IRQS, -MACHINE_END diff --git a/arch/arm/mach-iop13xx/iq81340sc.c b/arch/arm/mach-iop13xx/iq81340sc.c deleted file mode 100644 index 123845dcf2d3d5c66ba98a3db48a8f9d4aab981c..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/iq81340sc.c +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * iq81340sc board support - * Copyright (c) 2005-2006, Intel Corporation. - */ -#include - -#include -#include -#include -#include -#include -#include "pci.h" -#include -#include - -extern int init_atu; - -static int __init -iq81340sc_atux_map_irq(const struct pci_dev *dev, u8 idsel, u8 pin) -{ - WARN_ON(idsel < 1 || idsel > 2); - - switch (idsel) { - case 1: - switch (pin) { - case 1: return ATUX_INTB; - case 2: return ATUX_INTC; - case 3: return ATUX_INTD; - case 4: return ATUX_INTA; - default: return -1; - } - case 2: - switch (pin) { - case 1: return ATUX_INTC; - case 2: return ATUX_INTC; - case 3: return ATUX_INTC; - case 4: return ATUX_INTC; - default: return -1; - } - default: return -1; - } -} - -static struct hw_pci iq81340sc_pci __initdata = { - .nr_controllers = 0, - .setup = iop13xx_pci_setup, - .scan = iop13xx_scan_bus, - .map_irq = iq81340sc_atux_map_irq, - .preinit = iop13xx_pci_init -}; - -static int __init iq81340sc_pci_init(void) -{ - iop13xx_atu_select(&iq81340sc_pci); - pci_common_init(&iq81340sc_pci); - iop13xx_map_pci_memory(); - - return 0; -} - -static void __init iq81340sc_init(void) -{ - iop13xx_platform_init(); - iq81340sc_pci_init(); - iop13xx_add_tpmi_devices(); -} - -static void __init iq81340sc_timer_init(void) -{ - unsigned long bus_freq = iop13xx_core_freq() / iop13xx_xsi_bus_ratio(); - printk(KERN_DEBUG "%s: bus frequency: %lu\n", __func__, bus_freq); - iop_init_time(bus_freq); -} - -MACHINE_START(IQ81340SC, "Intel IQ81340SC") - /* Maintainer: Dan Williams */ - .atag_offset = 0x100, - .init_early = iop13xx_init_early, - .map_io = iop13xx_map_io, - .init_irq = iop13xx_init_irq, - .init_time = iq81340sc_timer_init, - .init_machine = iq81340sc_init, - .restart = iop13xx_restart, - .nr_irqs = NR_IOP13XX_IRQS, -MACHINE_END diff --git a/arch/arm/mach-iop13xx/irq.c b/arch/arm/mach-iop13xx/irq.c deleted file mode 100644 index 0e24ba7a13097b38b510e22d6a5fb5a2262a96be..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/irq.c +++ /dev/null @@ -1,227 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * iop13xx IRQ handling / support functions - * Copyright (c) 2005-2006, Intel Corporation. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "msi.h" - -/* INTCTL0 CP6 R0 Page 4 - */ -static u32 read_intctl_0(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c0, c4, 0":"=r" (val)); - return val; -} -static void write_intctl_0(u32 val) -{ - asm volatile("mcr p6, 0, %0, c0, c4, 0"::"r" (val)); -} - -/* INTCTL1 CP6 R1 Page 4 - */ -static u32 read_intctl_1(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c1, c4, 0":"=r" (val)); - return val; -} -static void write_intctl_1(u32 val) -{ - asm volatile("mcr p6, 0, %0, c1, c4, 0"::"r" (val)); -} - -/* INTCTL2 CP6 R2 Page 4 - */ -static u32 read_intctl_2(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c2, c4, 0":"=r" (val)); - return val; -} -static void write_intctl_2(u32 val) -{ - asm volatile("mcr p6, 0, %0, c2, c4, 0"::"r" (val)); -} - -/* INTCTL3 CP6 R3 Page 4 - */ -static u32 read_intctl_3(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c3, c4, 0":"=r" (val)); - return val; -} -static void write_intctl_3(u32 val) -{ - asm volatile("mcr p6, 0, %0, c3, c4, 0"::"r" (val)); -} - -/* INTSTR0 CP6 R0 Page 5 - */ -static void write_intstr_0(u32 val) -{ - asm volatile("mcr p6, 0, %0, c0, c5, 0"::"r" (val)); -} - -/* INTSTR1 CP6 R1 Page 5 - */ -static void write_intstr_1(u32 val) -{ - asm volatile("mcr p6, 0, %0, c1, c5, 0"::"r" (val)); -} - -/* INTSTR2 CP6 R2 Page 5 - */ -static void write_intstr_2(u32 val) -{ - asm volatile("mcr p6, 0, %0, c2, c5, 0"::"r" (val)); -} - -/* INTSTR3 CP6 R3 Page 5 - */ -static void write_intstr_3(u32 val) -{ - asm volatile("mcr p6, 0, %0, c3, c5, 0"::"r" (val)); -} - -/* INTBASE CP6 R0 Page 2 - */ -static void write_intbase(u32 val) -{ - asm volatile("mcr p6, 0, %0, c0, c2, 0"::"r" (val)); -} - -/* INTSIZE CP6 R2 Page 2 - */ -static void write_intsize(u32 val) -{ - asm volatile("mcr p6, 0, %0, c2, c2, 0"::"r" (val)); -} - -/* 0 = Interrupt Masked and 1 = Interrupt not masked */ -static void -iop13xx_irq_mask0 (struct irq_data *d) -{ - write_intctl_0(read_intctl_0() & ~(1 << (d->irq - 0))); -} - -static void -iop13xx_irq_mask1 (struct irq_data *d) -{ - write_intctl_1(read_intctl_1() & ~(1 << (d->irq - 32))); -} - -static void -iop13xx_irq_mask2 (struct irq_data *d) -{ - write_intctl_2(read_intctl_2() & ~(1 << (d->irq - 64))); -} - -static void -iop13xx_irq_mask3 (struct irq_data *d) -{ - write_intctl_3(read_intctl_3() & ~(1 << (d->irq - 96))); -} - -static void -iop13xx_irq_unmask0(struct irq_data *d) -{ - write_intctl_0(read_intctl_0() | (1 << (d->irq - 0))); -} - -static void -iop13xx_irq_unmask1(struct irq_data *d) -{ - write_intctl_1(read_intctl_1() | (1 << (d->irq - 32))); -} - -static void -iop13xx_irq_unmask2(struct irq_data *d) -{ - write_intctl_2(read_intctl_2() | (1 << (d->irq - 64))); -} - -static void -iop13xx_irq_unmask3(struct irq_data *d) -{ - write_intctl_3(read_intctl_3() | (1 << (d->irq - 96))); -} - -static struct irq_chip iop13xx_irqchip1 = { - .name = "IOP13xx-1", - .irq_ack = iop13xx_irq_mask0, - .irq_mask = iop13xx_irq_mask0, - .irq_unmask = iop13xx_irq_unmask0, -}; - -static struct irq_chip iop13xx_irqchip2 = { - .name = "IOP13xx-2", - .irq_ack = iop13xx_irq_mask1, - .irq_mask = iop13xx_irq_mask1, - .irq_unmask = iop13xx_irq_unmask1, -}; - -static struct irq_chip iop13xx_irqchip3 = { - .name = "IOP13xx-3", - .irq_ack = iop13xx_irq_mask2, - .irq_mask = iop13xx_irq_mask2, - .irq_unmask = iop13xx_irq_unmask2, -}; - -static struct irq_chip iop13xx_irqchip4 = { - .name = "IOP13xx-4", - .irq_ack = iop13xx_irq_mask3, - .irq_mask = iop13xx_irq_mask3, - .irq_unmask = iop13xx_irq_unmask3, -}; - -extern void iop_init_cp6_handler(void); - -void __init iop13xx_init_irq(void) -{ - unsigned int i; - - iop_init_cp6_handler(); - - /* disable all interrupts */ - write_intctl_0(0); - write_intctl_1(0); - write_intctl_2(0); - write_intctl_3(0); - - /* treat all as IRQ */ - write_intstr_0(0); - write_intstr_1(0); - write_intstr_2(0); - write_intstr_3(0); - - /* initialize the interrupt vector generator */ - write_intbase(INTBASE); - write_intsize(INTSIZE_4); - - for(i = 0; i <= IRQ_IOP13XX_HPI; i++) { - if (i < 32) - irq_set_chip(i, &iop13xx_irqchip1); - else if (i < 64) - irq_set_chip(i, &iop13xx_irqchip2); - else if (i < 96) - irq_set_chip(i, &iop13xx_irqchip3); - else - irq_set_chip(i, &iop13xx_irqchip4); - - irq_set_handler(i, handle_level_irq); - irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE); - } - - iop13xx_msi_init(); -} diff --git a/arch/arm/mach-iop13xx/msi.c b/arch/arm/mach-iop13xx/msi.c deleted file mode 100644 index f4d70cba1dd18cdc0a546363ee325bb6a7107f50..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/msi.c +++ /dev/null @@ -1,152 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * arch/arm/mach-iop13xx/msi.c - * - * PCI MSI support for the iop13xx processor - * - * Copyright (c) 2006, Intel Corporation. - */ -#include -#include -#include -#include -#include - -/* IMIPR0 CP6 R8 Page 1 - */ -static u32 read_imipr_0(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c8, c1, 0":"=r" (val)); - return val; -} -static void write_imipr_0(u32 val) -{ - asm volatile("mcr p6, 0, %0, c8, c1, 0"::"r" (val)); -} - -/* IMIPR1 CP6 R9 Page 1 - */ -static u32 read_imipr_1(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c9, c1, 0":"=r" (val)); - return val; -} -static void write_imipr_1(u32 val) -{ - asm volatile("mcr p6, 0, %0, c9, c1, 0"::"r" (val)); -} - -/* IMIPR2 CP6 R10 Page 1 - */ -static u32 read_imipr_2(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c10, c1, 0":"=r" (val)); - return val; -} -static void write_imipr_2(u32 val) -{ - asm volatile("mcr p6, 0, %0, c10, c1, 0"::"r" (val)); -} - -/* IMIPR3 CP6 R11 Page 1 - */ -static u32 read_imipr_3(void) -{ - u32 val; - asm volatile("mrc p6, 0, %0, c11, c1, 0":"=r" (val)); - return val; -} -static void write_imipr_3(u32 val) -{ - asm volatile("mcr p6, 0, %0, c11, c1, 0"::"r" (val)); -} - -static u32 (*read_imipr[])(void) = { - read_imipr_0, - read_imipr_1, - read_imipr_2, - read_imipr_3, -}; - -static void (*write_imipr[])(u32) = { - write_imipr_0, - write_imipr_1, - write_imipr_2, - write_imipr_3, -}; - -static void iop13xx_msi_handler(struct irq_desc *desc) -{ - int i, j; - unsigned long status; - - /* read IMIPR registers and find any active interrupts, - * then call ISR for each active interrupt - */ - for (i = 0; i < ARRAY_SIZE(read_imipr); i++) { - status = (read_imipr[i])(); - if (!status) - continue; - - do { - j = find_first_bit(&status, 32); - (write_imipr[i])(1 << j); /* write back to clear bit */ - generic_handle_irq(IRQ_IOP13XX_MSI_0 + j + (32*i)); - status = (read_imipr[i])(); - } while (status); - } -} - -void __init iop13xx_msi_init(void) -{ - irq_set_chained_handler(IRQ_IOP13XX_INBD_MSI, iop13xx_msi_handler); -} - -static void iop13xx_msi_nop(struct irq_data *d) -{ - return; -} - -static struct irq_chip iop13xx_msi_chip = { - .name = "PCI-MSI", - .irq_ack = iop13xx_msi_nop, - .irq_enable = pci_msi_unmask_irq, - .irq_disable = pci_msi_mask_irq, - .irq_mask = pci_msi_mask_irq, - .irq_unmask = pci_msi_unmask_irq, -}; - -int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) -{ - int id, irq = irq_alloc_desc_from(IRQ_IOP13XX_MSI_0, -1); - struct msi_msg msg; - - if (irq < 0) - return irq; - - if (irq >= NR_IOP13XX_IRQS) { - irq_free_desc(irq); - return -ENOSPC; - } - - irq_set_msi_desc(irq, desc); - - msg.address_hi = 0x0; - msg.address_lo = IOP13XX_MU_MIMR_PCI; - - id = iop13xx_cpu_id(); - msg.data = (id << IOP13XX_MU_MIMR_CORE_SELECT) | (irq & 0x7f); - - pci_write_msi_msg(irq, &msg); - irq_set_chip_and_handler(irq, &iop13xx_msi_chip, handle_simple_irq); - - return 0; -} - -void arch_teardown_msi_irq(unsigned int irq) -{ - irq_free_desc(irq); -} diff --git a/arch/arm/mach-iop13xx/msi.h b/arch/arm/mach-iop13xx/msi.h deleted file mode 100644 index 766dcfaaa353b109a294841e2c9ced40d63f34a0..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/msi.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _IOP13XX_MSI_H_ -#define _IOP13XX_MSI_H_ -#ifdef CONFIG_PCI_MSI -void iop13xx_msi_init(void); -#else -static inline void iop13xx_msi_init(void) -{ - return; -} -#endif -#endif diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c deleted file mode 100644 index 46ea06e906ccfc99f6c31622808cc448f0aea106..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/pci.c +++ /dev/null @@ -1,1115 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * iop13xx PCI support - * Copyright (c) 2005-2006, Intel Corporation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pci.h" - -#define IOP13XX_PCI_DEBUG 0 -#define PRINTK(x...) ((void)(IOP13XX_PCI_DEBUG && printk(x))) - -u32 iop13xx_atux_pmmr_offset; /* This offset can change based on strapping */ -u32 iop13xx_atue_pmmr_offset; /* This offset can change based on strapping */ -static struct pci_bus *pci_bus_atux = 0; -static struct pci_bus *pci_bus_atue = 0; -void __iomem *iop13xx_atue_mem_base; -void __iomem *iop13xx_atux_mem_base; -size_t iop13xx_atue_mem_size; -size_t iop13xx_atux_mem_size; - -EXPORT_SYMBOL(iop13xx_atue_mem_base); -EXPORT_SYMBOL(iop13xx_atux_mem_base); -EXPORT_SYMBOL(iop13xx_atue_mem_size); -EXPORT_SYMBOL(iop13xx_atux_mem_size); - -int init_atu = 0; /* Flag to select which ATU(s) to initialize / disable */ -static unsigned long atux_trhfa_timeout = 0; /* Trhfa = RST# high to first - access */ - -/* Scan the initialized busses and ioremap the requested memory range - */ -void iop13xx_map_pci_memory(void) -{ - int atu; - struct pci_bus *bus; - struct pci_dev *dev; - resource_size_t end = 0; - - for (atu = 0; atu < 2; atu++) { - bus = atu ? pci_bus_atue : pci_bus_atux; - if (bus) { - list_for_each_entry(dev, &bus->devices, bus_list) { - int i; - int max = 7; - - if (dev->subordinate) - max = DEVICE_COUNT_RESOURCE; - - for (i = 0; i < max; i++) { - struct resource *res = &dev->resource[i]; - if (res->flags & IORESOURCE_MEM) - end = max(res->end, end); - } - } - - switch(atu) { - case 0: - iop13xx_atux_mem_size = - (end - IOP13XX_PCIX_LOWER_MEM_RA) + 1; - - /* 16MB align the request */ - if (iop13xx_atux_mem_size & (SZ_16M - 1)) { - iop13xx_atux_mem_size &= ~(SZ_16M - 1); - iop13xx_atux_mem_size += SZ_16M; - } - - if (end) { - iop13xx_atux_mem_base = __arm_ioremap_pfn( - __phys_to_pfn(IOP13XX_PCIX_LOWER_MEM_PA) - , 0, iop13xx_atux_mem_size, MT_DEVICE); - if (!iop13xx_atux_mem_base) { - printk("%s: atux allocation " - "failed\n", __func__); - BUG(); - } - } else - iop13xx_atux_mem_size = 0; - PRINTK("%s: atu: %d bus_size: %d mem_base: %p\n", - __func__, atu, iop13xx_atux_mem_size, - iop13xx_atux_mem_base); - break; - case 1: - iop13xx_atue_mem_size = - (end - IOP13XX_PCIE_LOWER_MEM_RA) + 1; - - /* 16MB align the request */ - if (iop13xx_atue_mem_size & (SZ_16M - 1)) { - iop13xx_atue_mem_size &= ~(SZ_16M - 1); - iop13xx_atue_mem_size += SZ_16M; - } - - if (end) { - iop13xx_atue_mem_base = __arm_ioremap_pfn( - __phys_to_pfn(IOP13XX_PCIE_LOWER_MEM_PA) - , 0, iop13xx_atue_mem_size, MT_DEVICE); - if (!iop13xx_atue_mem_base) { - printk("%s: atue allocation " - "failed\n", __func__); - BUG(); - } - } else - iop13xx_atue_mem_size = 0; - PRINTK("%s: atu: %d bus_size: %d mem_base: %p\n", - __func__, atu, iop13xx_atue_mem_size, - iop13xx_atue_mem_base); - break; - } - - printk("%s: Initialized (%uM @ resource/virtual: %08lx/%p)\n", - atu ? "ATUE" : "ATUX", - (atu ? iop13xx_atue_mem_size : iop13xx_atux_mem_size) / - SZ_1M, - atu ? IOP13XX_PCIE_LOWER_MEM_RA : - IOP13XX_PCIX_LOWER_MEM_RA, - atu ? iop13xx_atue_mem_base : - iop13xx_atux_mem_base); - end = 0; - } - - } -} - -static int iop13xx_atu_function(int atu) -{ - int func = 0; - /* the function number depends on the value of the - * IOP13XX_INTERFACE_SEL_PCIX reset strap - * see C-Spec section 3.17 - */ - switch(atu) { - case IOP13XX_INIT_ATU_ATUX: - if (__raw_readl(IOP13XX_ESSR0) & IOP13XX_INTERFACE_SEL_PCIX) - func = 5; - else - func = 0; - break; - case IOP13XX_INIT_ATU_ATUE: - if (__raw_readl(IOP13XX_ESSR0) & IOP13XX_INTERFACE_SEL_PCIX) - func = 0; - else - func = 5; - break; - default: - BUG(); - } - - return func; -} - -/* iop13xx_atux_cfg_address - format a configuration address for atux - * @bus: Target bus to access - * @devfn: Combined device number and function number - * @where: Desired register's address offset - * - * Convert the parameters to a configuration address formatted - * according the PCI-X 2.0 specification - */ -static u32 iop13xx_atux_cfg_address(struct pci_bus *bus, int devfn, int where) -{ - struct pci_sys_data *sys = bus->sysdata; - u32 addr; - - if (sys->busnr == bus->number) - addr = 1 << (PCI_SLOT(devfn) + 16) | (PCI_SLOT(devfn) << 11); - else - addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1; - - addr |= PCI_FUNC(devfn) << 8 | ((where & 0xff) & ~3); - addr |= ((where & 0xf00) >> 8) << 24; /* upper register number */ - - return addr; -} - -/* iop13xx_atue_cfg_address - format a configuration address for atue - * @bus: Target bus to access - * @devfn: Combined device number and function number - * @where: Desired register's address offset - * - * Convert the parameters to an address usable by the ATUE_OCCAR - */ -static u32 iop13xx_atue_cfg_address(struct pci_bus *bus, int devfn, int where) -{ - struct pci_sys_data *sys = bus->sysdata; - u32 addr; - - PRINTK("iop13xx_atue_cfg_address: bus: %d dev: %d func: %d", - bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); - addr = ((u32) bus->number) << IOP13XX_ATUE_OCCAR_BUS_NUM | - ((u32) PCI_SLOT(devfn)) << IOP13XX_ATUE_OCCAR_DEV_NUM | - ((u32) PCI_FUNC(devfn)) << IOP13XX_ATUE_OCCAR_FUNC_NUM | - (where & ~0x3); - - if (sys->busnr != bus->number) - addr |= 1; /* type 1 access */ - - return addr; -} - -/* This routine checks the status of the last configuration cycle. If an error - * was detected it returns >0, else it returns a 0. The errors being checked - * are parity, master abort, target abort (master and target). These types of - * errors occur during a config cycle where there is no device, like during - * the discovery stage. - */ -static int iop13xx_atux_pci_status(int clear) -{ - unsigned int status; - int err = 0; - - /* - * Check the status registers. - */ - status = __raw_readw(IOP13XX_ATUX_ATUSR); - if (status & IOP_PCI_STATUS_ERROR) - { - PRINTK("\t\t\tPCI error: ATUSR %#08x", status); - if(clear) - __raw_writew(status & IOP_PCI_STATUS_ERROR, - IOP13XX_ATUX_ATUSR); - err = 1; - } - status = __raw_readl(IOP13XX_ATUX_ATUISR); - if (status & IOP13XX_ATUX_ATUISR_ERROR) - { - PRINTK("\t\t\tPCI error interrupt: ATUISR %#08x", status); - if(clear) - __raw_writel(status & IOP13XX_ATUX_ATUISR_ERROR, - IOP13XX_ATUX_ATUISR); - err = 1; - } - return err; -} - -/* Simply write the address register and read the configuration - * data. Note that the data dependency on %0 encourages an abort - * to be detected before we return. - */ -static u32 iop13xx_atux_read(unsigned long addr) -{ - u32 val; - - __asm__ __volatile__( - "str %1, [%2]\n\t" - "ldr %0, [%3]\n\t" - "mov %0, %0\n\t" - : "=r" (val) - : "r" (addr), "r" (IOP13XX_ATUX_OCCAR), "r" (IOP13XX_ATUX_OCCDR)); - - return val; -} - -/* The read routines must check the error status of the last configuration - * cycle. If there was an error, the routine returns all hex f's. - */ -static int -iop13xx_atux_read_config(struct pci_bus *bus, unsigned int devfn, int where, - int size, u32 *value) -{ - unsigned long addr = iop13xx_atux_cfg_address(bus, devfn, where); - u32 val = iop13xx_atux_read(addr) >> ((where & 3) * 8); - - if (iop13xx_atux_pci_status(1) || is_atux_occdr_error()) { - __raw_writel(__raw_readl(IOP13XX_XBG_BECSR) & 3, - IOP13XX_XBG_BECSR); - val = 0xffffffff; - } - - *value = val; - - return PCIBIOS_SUCCESSFUL; -} - -static int -iop13xx_atux_write_config(struct pci_bus *bus, unsigned int devfn, int where, - int size, u32 value) -{ - unsigned long addr = iop13xx_atux_cfg_address(bus, devfn, where); - u32 val; - - if (size != 4) { - val = iop13xx_atux_read(addr); - if (!iop13xx_atux_pci_status(1) == 0) - return PCIBIOS_SUCCESSFUL; - - where = (where & 3) * 8; - - if (size == 1) - val &= ~(0xff << where); - else - val &= ~(0xffff << where); - - __raw_writel(val | value << where, IOP13XX_ATUX_OCCDR); - } else { - __raw_writel(addr, IOP13XX_ATUX_OCCAR); - __raw_writel(value, IOP13XX_ATUX_OCCDR); - } - - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops iop13xx_atux_ops = { - .read = iop13xx_atux_read_config, - .write = iop13xx_atux_write_config, -}; - -/* This routine checks the status of the last configuration cycle. If an error - * was detected it returns >0, else it returns a 0. The errors being checked - * are parity, master abort, target abort (master and target). These types of - * errors occur during a config cycle where there is no device, like during - * the discovery stage. - */ -static int iop13xx_atue_pci_status(int clear) -{ - unsigned int status; - int err = 0; - - /* - * Check the status registers. - */ - - /* standard pci status register */ - status = __raw_readw(IOP13XX_ATUE_ATUSR); - if (status & IOP_PCI_STATUS_ERROR) { - PRINTK("\t\t\tPCI error: ATUSR %#08x", status); - if(clear) - __raw_writew(status & IOP_PCI_STATUS_ERROR, - IOP13XX_ATUE_ATUSR); - err++; - } - - /* check the normal status bits in the ATUISR */ - status = __raw_readl(IOP13XX_ATUE_ATUISR); - if (status & IOP13XX_ATUE_ATUISR_ERROR) { - PRINTK("\t\t\tPCI error: ATUISR %#08x", status); - if (clear) - __raw_writew(status & IOP13XX_ATUE_ATUISR_ERROR, - IOP13XX_ATUE_ATUISR); - err++; - - /* check the PCI-E status if the ATUISR reports an interface error */ - if (status & IOP13XX_ATUE_STAT_PCI_IFACE_ERR) { - /* get the unmasked errors */ - status = __raw_readl(IOP13XX_ATUE_PIE_STS) & - ~(__raw_readl(IOP13XX_ATUE_PIE_MSK)); - - if (status) { - PRINTK("\t\t\tPCI-E error: ATUE_PIE_STS %#08x", - __raw_readl(IOP13XX_ATUE_PIE_STS)); - err++; - } else { - PRINTK("\t\t\tPCI-E error: ATUE_PIE_STS %#08x", - __raw_readl(IOP13XX_ATUE_PIE_STS)); - PRINTK("\t\t\tPCI-E error: ATUE_PIE_MSK %#08x", - __raw_readl(IOP13XX_ATUE_PIE_MSK)); - BUG(); - } - - if(clear) - __raw_writel(status, IOP13XX_ATUE_PIE_STS); - } - } - - return err; -} - -static int -iop13xx_pcie_map_irq(const struct pci_dev *dev, u8 idsel, u8 pin) -{ - WARN_ON(idsel != 0); - - switch (pin) { - case 1: return ATUE_INTA; - case 2: return ATUE_INTB; - case 3: return ATUE_INTC; - case 4: return ATUE_INTD; - default: return -1; - } -} - -static u32 iop13xx_atue_read(unsigned long addr) -{ - u32 val; - - __raw_writel(addr, IOP13XX_ATUE_OCCAR); - val = __raw_readl(IOP13XX_ATUE_OCCDR); - - rmb(); - - return val; -} - -/* The read routines must check the error status of the last configuration - * cycle. If there was an error, the routine returns all hex f's. - */ -static int -iop13xx_atue_read_config(struct pci_bus *bus, unsigned int devfn, int where, - int size, u32 *value) -{ - u32 val; - unsigned long addr = iop13xx_atue_cfg_address(bus, devfn, where); - - /* Hide device numbers > 0 on the local PCI-E bus (Type 0 access) */ - if (!PCI_SLOT(devfn) || (addr & 1)) { - val = iop13xx_atue_read(addr) >> ((where & 3) * 8); - if( iop13xx_atue_pci_status(1) || is_atue_occdr_error() ) { - __raw_writel(__raw_readl(IOP13XX_XBG_BECSR) & 3, - IOP13XX_XBG_BECSR); - val = 0xffffffff; - } - - PRINTK("addr=%#0lx, val=%#010x", addr, val); - } else - val = 0xffffffff; - - *value = val; - - return PCIBIOS_SUCCESSFUL; -} - -static int -iop13xx_atue_write_config(struct pci_bus *bus, unsigned int devfn, int where, - int size, u32 value) -{ - unsigned long addr = iop13xx_atue_cfg_address(bus, devfn, where); - u32 val; - - if (size != 4) { - val = iop13xx_atue_read(addr); - if (!iop13xx_atue_pci_status(1) == 0) - return PCIBIOS_SUCCESSFUL; - - where = (where & 3) * 8; - - if (size == 1) - val &= ~(0xff << where); - else - val &= ~(0xffff << where); - - __raw_writel(val | value << where, IOP13XX_ATUE_OCCDR); - } else { - __raw_writel(addr, IOP13XX_ATUE_OCCAR); - __raw_writel(value, IOP13XX_ATUE_OCCDR); - } - - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops iop13xx_atue_ops = { - .read = iop13xx_atue_read_config, - .write = iop13xx_atue_write_config, -}; - -/* When a PCI device does not exist during config cycles, the XScale gets a - * bus error instead of returning 0xffffffff. We can't rely on the ATU status - * bits to tell us that it was indeed a configuration cycle that caused this - * error especially in the case when the ATUE link is down. Instead we rely - * on data from the south XSI bridge to validate the abort - */ -int -iop13xx_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) -{ - PRINTK("Data abort: address = 0x%08lx " - "fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx", - addr, fsr, regs->ARM_pc, regs->ARM_lr); - - PRINTK("IOP13XX_XBG_BECSR: %#10x", __raw_readl(IOP13XX_XBG_BECSR)); - PRINTK("IOP13XX_XBG_BERAR: %#10x", __raw_readl(IOP13XX_XBG_BERAR)); - PRINTK("IOP13XX_XBG_BERUAR: %#10x", __raw_readl(IOP13XX_XBG_BERUAR)); - - /* If it was an imprecise abort, then we need to correct the - * return address to be _after_ the instruction. - */ - if (fsr & (1 << 10)) - regs->ARM_pc += 4; - - if (is_atue_occdr_error() || is_atux_occdr_error()) - return 0; - else - return 1; -} - -/* Scan an IOP13XX PCI bus. nr selects which ATU we use. - */ -int iop13xx_scan_bus(int nr, struct pci_host_bridge *bridge) -{ - int which_atu, ret; - struct pci_sys_data *sys = pci_host_bridge_priv(bridge); - - switch (init_atu) { - case IOP13XX_INIT_ATU_ATUX: - which_atu = nr ? 0 : IOP13XX_INIT_ATU_ATUX; - break; - case IOP13XX_INIT_ATU_ATUE: - which_atu = nr ? 0 : IOP13XX_INIT_ATU_ATUE; - break; - case (IOP13XX_INIT_ATU_ATUX | IOP13XX_INIT_ATU_ATUE): - which_atu = nr ? IOP13XX_INIT_ATU_ATUE : IOP13XX_INIT_ATU_ATUX; - break; - default: - which_atu = 0; - } - - if (!which_atu) { - BUG(); - return -ENODEV; - } - - list_splice_init(&sys->resources, &bridge->windows); - bridge->dev.parent = NULL; - bridge->sysdata = sys; - bridge->busnr = sys->busnr; - - switch (which_atu) { - case IOP13XX_INIT_ATU_ATUX: - if (time_after_eq(jiffies + msecs_to_jiffies(1000), - atux_trhfa_timeout)) /* ensure not wrap */ - while(time_before(jiffies, atux_trhfa_timeout)) - udelay(100); - - bridge->ops = &iop13xx_atux_ops; - ret = pci_scan_root_bus_bridge(bridge); - if (!ret) - pci_bus_atux = bridge->bus; - break; - case IOP13XX_INIT_ATU_ATUE: - bridge->ops = &iop13xx_atue_ops; - ret = pci_scan_root_bus_bridge(bridge); - if (!ret) - pci_bus_atue = bridge->bus; - break; - default: - ret = -EINVAL; - } - - return ret; -} - -/* This function is called from iop13xx_pci_init() after assigning valid - * values to iop13xx_atue_pmmr_offset. This is the location for common - * setup of ATUE for all IOP13XX implementations. - */ -void __init iop13xx_atue_setup(void) -{ - int func = iop13xx_atu_function(IOP13XX_INIT_ATU_ATUE); - u32 reg_val; - -#ifdef CONFIG_PCI_MSI - /* BAR 0 (inbound msi window) */ - __raw_writel(IOP13XX_MU_BASE_PHYS, IOP13XX_MU_MUBAR); - __raw_writel(~(IOP13XX_MU_WINDOW_SIZE - 1), IOP13XX_ATUE_IALR0); - __raw_writel(IOP13XX_MU_BASE_PHYS, IOP13XX_ATUE_IATVR0); - __raw_writel(IOP13XX_MU_BASE_PCI, IOP13XX_ATUE_IABAR0); -#endif - - /* BAR 1 (1:1 mapping with Physical RAM) */ - /* Set limit and enable */ - __raw_writel(~(IOP13XX_MAX_RAM_SIZE - PHYS_OFFSET - 1) & ~0x1, - IOP13XX_ATUE_IALR1); - __raw_writel(0x0, IOP13XX_ATUE_IAUBAR1); - - /* Set base at the top of the reserved address space */ - __raw_writel(PHYS_OFFSET | PCI_BASE_ADDRESS_MEM_TYPE_64 | - PCI_BASE_ADDRESS_MEM_PREFETCH, IOP13XX_ATUE_IABAR1); - - /* 1:1 mapping with physical ram - * (leave big endian byte swap disabled) - */ - __raw_writel(0x0, IOP13XX_ATUE_IAUTVR1); - __raw_writel(PHYS_OFFSET, IOP13XX_ATUE_IATVR1); - - /* Outbound window 1 (PCIX/PCIE memory window) */ - /* 32 bit Address Space */ - __raw_writel(0x0, IOP13XX_ATUE_OUMWTVR1); - /* PA[35:32] */ - __raw_writel(IOP13XX_ATUE_OUMBAR_ENABLE | - (IOP13XX_PCIE_MEM_PHYS_OFFSET >> 32), - IOP13XX_ATUE_OUMBAR1); - - /* Setup the I/O Bar - * A[35-16] in 31-12 - */ - __raw_writel(((IOP13XX_PCIE_LOWER_IO_PA >> 0x4) & 0xfffff000), - IOP13XX_ATUE_OIOBAR); - __raw_writel(IOP13XX_PCIE_LOWER_IO_BA, IOP13XX_ATUE_OIOWTVR); - - /* clear startup errors */ - iop13xx_atue_pci_status(1); - - /* OIOBAR function number - */ - reg_val = __raw_readl(IOP13XX_ATUE_OIOBAR); - reg_val &= ~0x7; - reg_val |= func; - __raw_writel(reg_val, IOP13XX_ATUE_OIOBAR); - - /* OUMBAR function numbers - */ - reg_val = __raw_readl(IOP13XX_ATUE_OUMBAR0); - reg_val &= ~(IOP13XX_ATU_OUMBAR_FUNC_NUM_MASK << - IOP13XX_ATU_OUMBAR_FUNC_NUM); - reg_val |= func << IOP13XX_ATU_OUMBAR_FUNC_NUM; - __raw_writel(reg_val, IOP13XX_ATUE_OUMBAR0); - - reg_val = __raw_readl(IOP13XX_ATUE_OUMBAR1); - reg_val &= ~(IOP13XX_ATU_OUMBAR_FUNC_NUM_MASK << - IOP13XX_ATU_OUMBAR_FUNC_NUM); - reg_val |= func << IOP13XX_ATU_OUMBAR_FUNC_NUM; - __raw_writel(reg_val, IOP13XX_ATUE_OUMBAR1); - - reg_val = __raw_readl(IOP13XX_ATUE_OUMBAR2); - reg_val &= ~(IOP13XX_ATU_OUMBAR_FUNC_NUM_MASK << - IOP13XX_ATU_OUMBAR_FUNC_NUM); - reg_val |= func << IOP13XX_ATU_OUMBAR_FUNC_NUM; - __raw_writel(reg_val, IOP13XX_ATUE_OUMBAR2); - - reg_val = __raw_readl(IOP13XX_ATUE_OUMBAR3); - reg_val &= ~(IOP13XX_ATU_OUMBAR_FUNC_NUM_MASK << - IOP13XX_ATU_OUMBAR_FUNC_NUM); - reg_val |= func << IOP13XX_ATU_OUMBAR_FUNC_NUM; - __raw_writel(reg_val, IOP13XX_ATUE_OUMBAR3); - - /* Enable inbound and outbound cycles - */ - reg_val = __raw_readw(IOP13XX_ATUE_ATUCMD); - reg_val |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | - PCI_COMMAND_PARITY | PCI_COMMAND_SERR; - __raw_writew(reg_val, IOP13XX_ATUE_ATUCMD); - - reg_val = __raw_readl(IOP13XX_ATUE_ATUCR); - reg_val |= IOP13XX_ATUE_ATUCR_OUT_EN | - IOP13XX_ATUE_ATUCR_IVM; - __raw_writel(reg_val, IOP13XX_ATUE_ATUCR); -} - -void __init iop13xx_atue_disable(void) -{ - u32 reg_val; - - __raw_writew(0x0, IOP13XX_ATUE_ATUCMD); - __raw_writel(IOP13XX_ATUE_ATUCR_IVM, IOP13XX_ATUE_ATUCR); - - /* wait for cycles to quiesce */ - while (__raw_readl(IOP13XX_ATUE_PCSR) & (IOP13XX_ATUE_PCSR_OUT_Q_BUSY | - IOP13XX_ATUE_PCSR_IN_Q_BUSY | - IOP13XX_ATUE_PCSR_LLRB_BUSY)) - cpu_relax(); - - /* BAR 0 ( Disabled ) */ - __raw_writel(0x0, IOP13XX_ATUE_IAUBAR0); - __raw_writel(0x0, IOP13XX_ATUE_IABAR0); - __raw_writel(0x0, IOP13XX_ATUE_IAUTVR0); - __raw_writel(0x0, IOP13XX_ATUE_IATVR0); - __raw_writel(0x0, IOP13XX_ATUE_IALR0); - reg_val = __raw_readl(IOP13XX_ATUE_OUMBAR0); - reg_val &= ~IOP13XX_ATUE_OUMBAR_ENABLE; - __raw_writel(reg_val, IOP13XX_ATUE_OUMBAR0); - - /* BAR 1 ( Disabled ) */ - __raw_writel(0x0, IOP13XX_ATUE_IAUBAR1); - __raw_writel(0x0, IOP13XX_ATUE_IABAR1); - __raw_writel(0x0, IOP13XX_ATUE_IAUTVR1); - __raw_writel(0x0, IOP13XX_ATUE_IATVR1); - __raw_writel(0x0, IOP13XX_ATUE_IALR1); - reg_val = __raw_readl(IOP13XX_ATUE_OUMBAR1); - reg_val &= ~IOP13XX_ATUE_OUMBAR_ENABLE; - __raw_writel(reg_val, IOP13XX_ATUE_OUMBAR1); - - /* BAR 2 ( Disabled ) */ - __raw_writel(0x0, IOP13XX_ATUE_IAUBAR2); - __raw_writel(0x0, IOP13XX_ATUE_IABAR2); - __raw_writel(0x0, IOP13XX_ATUE_IAUTVR2); - __raw_writel(0x0, IOP13XX_ATUE_IATVR2); - __raw_writel(0x0, IOP13XX_ATUE_IALR2); - reg_val = __raw_readl(IOP13XX_ATUE_OUMBAR2); - reg_val &= ~IOP13XX_ATUE_OUMBAR_ENABLE; - __raw_writel(reg_val, IOP13XX_ATUE_OUMBAR2); - - /* BAR 3 ( Disabled ) */ - reg_val = __raw_readl(IOP13XX_ATUE_OUMBAR3); - reg_val &= ~IOP13XX_ATUE_OUMBAR_ENABLE; - __raw_writel(reg_val, IOP13XX_ATUE_OUMBAR3); - - /* Setup the I/O Bar - * A[35-16] in 31-12 - */ - __raw_writel((IOP13XX_PCIE_LOWER_IO_PA >> 0x4) & 0xfffff000, - IOP13XX_ATUE_OIOBAR); - __raw_writel(IOP13XX_PCIE_LOWER_IO_BA, IOP13XX_ATUE_OIOWTVR); -} - -/* This function is called from iop13xx_pci_init() after assigning valid - * values to iop13xx_atux_pmmr_offset. This is the location for common - * setup of ATUX for all IOP13XX implementations. - */ -void __init iop13xx_atux_setup(void) -{ - u32 reg_val; - int func = iop13xx_atu_function(IOP13XX_INIT_ATU_ATUX); - - /* Take PCI-X bus out of reset if bootloader hasn't already. - * According to spec, we should wait for 2^25 PCI clocks to meet - * the PCI timing parameter Trhfa (RST# high to first access). - * This is rarely necessary and often ignored. - */ - reg_val = __raw_readl(IOP13XX_ATUX_PCSR); - if (reg_val & IOP13XX_ATUX_PCSR_P_RSTOUT) { - int msec = (reg_val >> IOP13XX_ATUX_PCSR_FREQ_OFFSET) & 0x7; - msec = 1000 / (8-msec); /* bits 100=133MHz, 111=>33MHz */ - __raw_writel(reg_val & ~IOP13XX_ATUX_PCSR_P_RSTOUT, - IOP13XX_ATUX_PCSR); - atux_trhfa_timeout = jiffies + msecs_to_jiffies(msec); - } - else - atux_trhfa_timeout = jiffies; - -#ifdef CONFIG_PCI_MSI - /* BAR 0 (inbound msi window) */ - __raw_writel(IOP13XX_MU_BASE_PHYS, IOP13XX_MU_MUBAR); - __raw_writel(~(IOP13XX_MU_WINDOW_SIZE - 1), IOP13XX_ATUX_IALR0); - __raw_writel(IOP13XX_MU_BASE_PHYS, IOP13XX_ATUX_IATVR0); - __raw_writel(IOP13XX_MU_BASE_PCI, IOP13XX_ATUX_IABAR0); -#endif - - /* BAR 1 (1:1 mapping with Physical RAM) */ - /* Set limit and enable */ - __raw_writel(~(IOP13XX_MAX_RAM_SIZE - PHYS_OFFSET - 1) & ~0x1, - IOP13XX_ATUX_IALR1); - __raw_writel(0x0, IOP13XX_ATUX_IAUBAR1); - - /* Set base at the top of the reserved address space */ - __raw_writel(PHYS_OFFSET | PCI_BASE_ADDRESS_MEM_TYPE_64 | - PCI_BASE_ADDRESS_MEM_PREFETCH, IOP13XX_ATUX_IABAR1); - - /* 1:1 mapping with physical ram - * (leave big endian byte swap disabled) - */ - __raw_writel(0x0, IOP13XX_ATUX_IAUTVR1); - __raw_writel(PHYS_OFFSET, IOP13XX_ATUX_IATVR1); - - /* Outbound window 1 (PCIX/PCIE memory window) */ - /* 32 bit Address Space */ - __raw_writel(0x0, IOP13XX_ATUX_OUMWTVR1); - /* PA[35:32] */ - __raw_writel(IOP13XX_ATUX_OUMBAR_ENABLE | - IOP13XX_PCIX_MEM_PHYS_OFFSET >> 32, - IOP13XX_ATUX_OUMBAR1); - - /* Setup the I/O Bar - * A[35-16] in 31-12 - */ - __raw_writel((IOP13XX_PCIX_LOWER_IO_PA >> 0x4) & 0xfffff000, - IOP13XX_ATUX_OIOBAR); - __raw_writel(IOP13XX_PCIX_LOWER_IO_BA, IOP13XX_ATUX_OIOWTVR); - - /* clear startup errors */ - iop13xx_atux_pci_status(1); - - /* OIOBAR function number - */ - reg_val = __raw_readl(IOP13XX_ATUX_OIOBAR); - reg_val &= ~0x7; - reg_val |= func; - __raw_writel(reg_val, IOP13XX_ATUX_OIOBAR); - - /* OUMBAR function numbers - */ - reg_val = __raw_readl(IOP13XX_ATUX_OUMBAR0); - reg_val &= ~(IOP13XX_ATU_OUMBAR_FUNC_NUM_MASK << - IOP13XX_ATU_OUMBAR_FUNC_NUM); - reg_val |= func << IOP13XX_ATU_OUMBAR_FUNC_NUM; - __raw_writel(reg_val, IOP13XX_ATUX_OUMBAR0); - - reg_val = __raw_readl(IOP13XX_ATUX_OUMBAR1); - reg_val &= ~(IOP13XX_ATU_OUMBAR_FUNC_NUM_MASK << - IOP13XX_ATU_OUMBAR_FUNC_NUM); - reg_val |= func << IOP13XX_ATU_OUMBAR_FUNC_NUM; - __raw_writel(reg_val, IOP13XX_ATUX_OUMBAR1); - - reg_val = __raw_readl(IOP13XX_ATUX_OUMBAR2); - reg_val &= ~(IOP13XX_ATU_OUMBAR_FUNC_NUM_MASK << - IOP13XX_ATU_OUMBAR_FUNC_NUM); - reg_val |= func << IOP13XX_ATU_OUMBAR_FUNC_NUM; - __raw_writel(reg_val, IOP13XX_ATUX_OUMBAR2); - - reg_val = __raw_readl(IOP13XX_ATUX_OUMBAR3); - reg_val &= ~(IOP13XX_ATU_OUMBAR_FUNC_NUM_MASK << - IOP13XX_ATU_OUMBAR_FUNC_NUM); - reg_val |= func << IOP13XX_ATU_OUMBAR_FUNC_NUM; - __raw_writel(reg_val, IOP13XX_ATUX_OUMBAR3); - - /* Enable inbound and outbound cycles - */ - reg_val = __raw_readw(IOP13XX_ATUX_ATUCMD); - reg_val |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | - PCI_COMMAND_PARITY | PCI_COMMAND_SERR; - __raw_writew(reg_val, IOP13XX_ATUX_ATUCMD); - - reg_val = __raw_readl(IOP13XX_ATUX_ATUCR); - reg_val |= IOP13XX_ATUX_ATUCR_OUT_EN; - __raw_writel(reg_val, IOP13XX_ATUX_ATUCR); -} - -void __init iop13xx_atux_disable(void) -{ - u32 reg_val; - - __raw_writew(0x0, IOP13XX_ATUX_ATUCMD); - __raw_writel(0x0, IOP13XX_ATUX_ATUCR); - - /* wait for cycles to quiesce */ - while (__raw_readl(IOP13XX_ATUX_PCSR) & (IOP13XX_ATUX_PCSR_OUT_Q_BUSY | - IOP13XX_ATUX_PCSR_IN_Q_BUSY)) - cpu_relax(); - - /* BAR 0 ( Disabled ) */ - __raw_writel(0x0, IOP13XX_ATUX_IAUBAR0); - __raw_writel(0x0, IOP13XX_ATUX_IABAR0); - __raw_writel(0x0, IOP13XX_ATUX_IAUTVR0); - __raw_writel(0x0, IOP13XX_ATUX_IATVR0); - __raw_writel(0x0, IOP13XX_ATUX_IALR0); - reg_val = __raw_readl(IOP13XX_ATUX_OUMBAR0); - reg_val &= ~IOP13XX_ATUX_OUMBAR_ENABLE; - __raw_writel(reg_val, IOP13XX_ATUX_OUMBAR0); - - /* BAR 1 ( Disabled ) */ - __raw_writel(0x0, IOP13XX_ATUX_IAUBAR1); - __raw_writel(0x0, IOP13XX_ATUX_IABAR1); - __raw_writel(0x0, IOP13XX_ATUX_IAUTVR1); - __raw_writel(0x0, IOP13XX_ATUX_IATVR1); - __raw_writel(0x0, IOP13XX_ATUX_IALR1); - reg_val = __raw_readl(IOP13XX_ATUX_OUMBAR1); - reg_val &= ~IOP13XX_ATUX_OUMBAR_ENABLE; - __raw_writel(reg_val, IOP13XX_ATUX_OUMBAR1); - - /* BAR 2 ( Disabled ) */ - __raw_writel(0x0, IOP13XX_ATUX_IAUBAR2); - __raw_writel(0x0, IOP13XX_ATUX_IABAR2); - __raw_writel(0x0, IOP13XX_ATUX_IAUTVR2); - __raw_writel(0x0, IOP13XX_ATUX_IATVR2); - __raw_writel(0x0, IOP13XX_ATUX_IALR2); - reg_val = __raw_readl(IOP13XX_ATUX_OUMBAR2); - reg_val &= ~IOP13XX_ATUX_OUMBAR_ENABLE; - __raw_writel(reg_val, IOP13XX_ATUX_OUMBAR2); - - /* BAR 3 ( Disabled ) */ - __raw_writel(0x0, IOP13XX_ATUX_IAUBAR3); - __raw_writel(0x0, IOP13XX_ATUX_IABAR3); - __raw_writel(0x0, IOP13XX_ATUX_IAUTVR3); - __raw_writel(0x0, IOP13XX_ATUX_IATVR3); - __raw_writel(0x0, IOP13XX_ATUX_IALR3); - reg_val = __raw_readl(IOP13XX_ATUX_OUMBAR3); - reg_val &= ~IOP13XX_ATUX_OUMBAR_ENABLE; - __raw_writel(reg_val, IOP13XX_ATUX_OUMBAR3); - - /* Setup the I/O Bar - * A[35-16] in 31-12 - */ - __raw_writel((IOP13XX_PCIX_LOWER_IO_PA >> 0x4) & 0xfffff000, - IOP13XX_ATUX_OIOBAR); - __raw_writel(IOP13XX_PCIX_LOWER_IO_BA, IOP13XX_ATUX_OIOWTVR); -} - -void __init iop13xx_set_atu_mmr_bases(void) -{ - /* Based on ESSR0, determine the ATU X/E offsets */ - switch(__raw_readl(IOP13XX_ESSR0) & - (IOP13XX_CONTROLLER_ONLY | IOP13XX_INTERFACE_SEL_PCIX)) { - /* both asserted */ - case 0: - iop13xx_atux_pmmr_offset = IOP13XX_ATU1_PMMR_OFFSET; - iop13xx_atue_pmmr_offset = IOP13XX_ATU2_PMMR_OFFSET; - break; - /* IOP13XX_CONTROLLER_ONLY = deasserted - * IOP13XX_INTERFACE_SEL_PCIX = asserted - */ - case IOP13XX_CONTROLLER_ONLY: - iop13xx_atux_pmmr_offset = IOP13XX_ATU0_PMMR_OFFSET; - iop13xx_atue_pmmr_offset = IOP13XX_ATU2_PMMR_OFFSET; - break; - /* IOP13XX_CONTROLLER_ONLY = asserted - * IOP13XX_INTERFACE_SEL_PCIX = deasserted - */ - case IOP13XX_INTERFACE_SEL_PCIX: - iop13xx_atux_pmmr_offset = IOP13XX_ATU1_PMMR_OFFSET; - iop13xx_atue_pmmr_offset = IOP13XX_ATU2_PMMR_OFFSET; - break; - /* both deasserted */ - case IOP13XX_CONTROLLER_ONLY | IOP13XX_INTERFACE_SEL_PCIX: - iop13xx_atux_pmmr_offset = IOP13XX_ATU2_PMMR_OFFSET; - iop13xx_atue_pmmr_offset = IOP13XX_ATU0_PMMR_OFFSET; - break; - default: - BUG(); - } -} - -void __init iop13xx_atu_select(struct hw_pci *plat_pci) -{ - int i; - - /* set system defaults - * note: if "iop13xx_init_atu=" is specified this autodetect - * sequence will be bypassed - */ - if (init_atu == IOP13XX_INIT_ATU_DEFAULT) { - /* check for single/dual interface */ - if (__raw_readl(IOP13XX_ESSR0) & IOP13XX_INTERFACE_SEL_PCIX) { - /* ATUE must be present check the device id - * to see if ATUX is present. - */ - init_atu |= IOP13XX_INIT_ATU_ATUE; - switch (__raw_readw(IOP13XX_ATUE_DID) & 0xf0) { - case 0x70: - case 0x80: - case 0xc0: - init_atu |= IOP13XX_INIT_ATU_ATUX; - break; - } - } else { - /* ATUX must be present check the device id - * to see if ATUE is present. - */ - init_atu |= IOP13XX_INIT_ATU_ATUX; - switch (__raw_readw(IOP13XX_ATUX_DID) & 0xf0) { - case 0x70: - case 0x80: - case 0xc0: - init_atu |= IOP13XX_INIT_ATU_ATUE; - break; - } - } - - /* check central resource and root complex capability */ - if (init_atu & IOP13XX_INIT_ATU_ATUX) - if (!(__raw_readl(IOP13XX_ATUX_PCSR) & - IOP13XX_ATUX_PCSR_CENTRAL_RES)) - init_atu &= ~IOP13XX_INIT_ATU_ATUX; - - if (init_atu & IOP13XX_INIT_ATU_ATUE) - if (__raw_readl(IOP13XX_ATUE_PCSR) & - IOP13XX_ATUE_PCSR_END_POINT) - init_atu &= ~IOP13XX_INIT_ATU_ATUE; - } - - for (i = 0; i < 2; i++) { - if((init_atu & (1 << i)) == (1 << i)) - plat_pci->nr_controllers++; - } -} - -void __init iop13xx_pci_init(void) -{ - /* clear pre-existing south bridge errors */ - __raw_writel(__raw_readl(IOP13XX_XBG_BECSR) & 3, IOP13XX_XBG_BECSR); - - /* Setup the Min Address for PCI memory... */ - pcibios_min_mem = IOP13XX_PCIX_LOWER_MEM_BA; - - /* if Linux is given control of an ATU - * clear out its prior configuration, - * otherwise do not touch the registers - */ - if (init_atu & IOP13XX_INIT_ATU_ATUE) { - iop13xx_atue_disable(); - iop13xx_atue_setup(); - } - - if (init_atu & IOP13XX_INIT_ATU_ATUX) { - iop13xx_atux_disable(); - iop13xx_atux_setup(); - } - - hook_fault_code(16+6, iop13xx_pci_abort, SIGBUS, 0, - "imprecise external abort"); -} - -/* initialize the pci memory space. handle any combination of - * atue and atux enabled/disabled - */ -int iop13xx_pci_setup(int nr, struct pci_sys_data *sys) -{ - struct resource *res; - int which_atu; - u32 pcixsr, pcsr; - - if (nr > 1) - return 0; - - res = kzalloc(sizeof(struct resource), GFP_KERNEL); - if (!res) - panic("PCI: unable to alloc resources"); - - - /* 'nr' assumptions: - * ATUX is always 0 - * ATUE is 1 when ATUX is also enabled - * ATUE is 0 when ATUX is disabled - */ - switch(init_atu) { - case IOP13XX_INIT_ATU_ATUX: - which_atu = nr ? 0 : IOP13XX_INIT_ATU_ATUX; - break; - case IOP13XX_INIT_ATU_ATUE: - which_atu = nr ? 0 : IOP13XX_INIT_ATU_ATUE; - break; - case (IOP13XX_INIT_ATU_ATUX | IOP13XX_INIT_ATU_ATUE): - which_atu = nr ? IOP13XX_INIT_ATU_ATUE : IOP13XX_INIT_ATU_ATUX; - break; - default: - which_atu = 0; - } - - if (!which_atu) { - kfree(res); - return 0; - } - - switch(which_atu) { - case IOP13XX_INIT_ATU_ATUX: - pcixsr = __raw_readl(IOP13XX_ATUX_PCIXSR); - pcixsr &= ~0xffff; - pcixsr |= sys->busnr << IOP13XX_ATUX_PCIXSR_BUS_NUM | - 0 << IOP13XX_ATUX_PCIXSR_DEV_NUM | - iop13xx_atu_function(IOP13XX_INIT_ATU_ATUX) - << IOP13XX_ATUX_PCIXSR_FUNC_NUM; - __raw_writel(pcixsr, IOP13XX_ATUX_PCIXSR); - - pci_ioremap_io(0, IOP13XX_PCIX_LOWER_IO_PA); - - res->start = IOP13XX_PCIX_LOWER_MEM_RA; - res->end = IOP13XX_PCIX_UPPER_MEM_RA; - res->name = "IQ81340 ATUX PCI Memory Space"; - res->flags = IORESOURCE_MEM; - sys->mem_offset = IOP13XX_PCIX_MEM_OFFSET; - break; - case IOP13XX_INIT_ATU_ATUE: - /* Note: the function number field in the PCSR is ro */ - pcsr = __raw_readl(IOP13XX_ATUE_PCSR); - pcsr &= ~(0xfff8 << 16); - pcsr |= sys->busnr << IOP13XX_ATUE_PCSR_BUS_NUM | - 0 << IOP13XX_ATUE_PCSR_DEV_NUM; - - __raw_writel(pcsr, IOP13XX_ATUE_PCSR); - - pci_ioremap_io(SZ_64K, IOP13XX_PCIE_LOWER_IO_PA); - - res->start = IOP13XX_PCIE_LOWER_MEM_RA; - res->end = IOP13XX_PCIE_UPPER_MEM_RA; - res->name = "IQ81340 ATUE PCI Memory Space"; - res->flags = IORESOURCE_MEM; - sys->mem_offset = IOP13XX_PCIE_MEM_OFFSET; - sys->map_irq = iop13xx_pcie_map_irq; - break; - default: - kfree(res); - return 0; - } - - request_resource(&iomem_resource, res); - - pci_add_resource_offset(&sys->resources, res, sys->mem_offset); - - return 1; -} - -u16 iop13xx_dev_id(void) -{ - if (__raw_readl(IOP13XX_ESSR0) & IOP13XX_INTERFACE_SEL_PCIX) - return __raw_readw(IOP13XX_ATUE_DID); - else - return __raw_readw(IOP13XX_ATUX_DID); -} - -static int __init iop13xx_init_atu_setup(char *str) -{ - init_atu = IOP13XX_INIT_ATU_NONE; - if (str) { - while (*str != '\0') { - switch (*str) { - case 'x': - case 'X': - init_atu |= IOP13XX_INIT_ATU_ATUX; - init_atu &= ~IOP13XX_INIT_ATU_NONE; - break; - case 'e': - case 'E': - init_atu |= IOP13XX_INIT_ATU_ATUE; - init_atu &= ~IOP13XX_INIT_ATU_NONE; - break; - case ',': - case '=': - break; - default: - PRINTK("\"iop13xx_init_atu\" malformed at " - "character: \'%c\'", *str); - *(str + 1) = '\0'; - init_atu = IOP13XX_INIT_ATU_DEFAULT; - } - str++; - } - } - return 1; -} - -__setup("iop13xx_init_atu", iop13xx_init_atu_setup); diff --git a/arch/arm/mach-iop13xx/pci.h b/arch/arm/mach-iop13xx/pci.h deleted file mode 100644 index 736168d8c7ac0a999d091ca9a3ee5800315260ef..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/pci.h +++ /dev/null @@ -1,66 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _IOP13XX_PCI_H_ -#define _IOP13XX_PCI_H_ -#include -#include - -#include - -extern void __iomem *iop13xx_atue_mem_base; -extern void __iomem *iop13xx_atux_mem_base; -extern size_t iop13xx_atue_mem_size; -extern size_t iop13xx_atux_mem_size; - -struct pci_sys_data; -struct pci_host_bridge; -struct hw_pci; -int iop13xx_pci_setup(int nr, struct pci_sys_data *sys); -int iop13xx_scan_bus(int nr, struct pci_host_bridge *bridge); -void iop13xx_atu_select(struct hw_pci *plat_pci); -void iop13xx_pci_init(void); -void iop13xx_map_pci_memory(void); - -#define IOP_PCI_STATUS_ERROR (PCI_STATUS_PARITY | \ - PCI_STATUS_SIG_TARGET_ABORT | \ - PCI_STATUS_REC_TARGET_ABORT | \ - PCI_STATUS_REC_TARGET_ABORT | \ - PCI_STATUS_REC_MASTER_ABORT | \ - PCI_STATUS_SIG_SYSTEM_ERROR | \ - PCI_STATUS_DETECTED_PARITY) - -#define IOP13XX_ATUE_ATUISR_ERROR (IOP13XX_ATUE_STAT_HALT_ON_ERROR | \ - IOP13XX_ATUE_STAT_ROOT_SYS_ERR | \ - IOP13XX_ATUE_STAT_PCI_IFACE_ERR | \ - IOP13XX_ATUE_STAT_ERR_COR | \ - IOP13XX_ATUE_STAT_ERR_UNCOR | \ - IOP13XX_ATUE_STAT_CRS | \ - IOP13XX_ATUE_STAT_DET_PAR_ERR | \ - IOP13XX_ATUE_STAT_EXT_REC_MABORT | \ - IOP13XX_ATUE_STAT_SIG_TABORT | \ - IOP13XX_ATUE_STAT_EXT_REC_TABORT | \ - IOP13XX_ATUE_STAT_MASTER_DATA_PAR) - -#define IOP13XX_ATUX_ATUISR_ERROR (IOP13XX_ATUX_STAT_TX_SCEM | \ - IOP13XX_ATUX_STAT_REC_SCEM | \ - IOP13XX_ATUX_STAT_TX_SERR | \ - IOP13XX_ATUX_STAT_DET_PAR_ERR | \ - IOP13XX_ATUX_STAT_INT_REC_MABORT | \ - IOP13XX_ATUX_STAT_REC_SERR | \ - IOP13XX_ATUX_STAT_EXT_REC_MABORT | \ - IOP13XX_ATUX_STAT_EXT_REC_TABORT | \ - IOP13XX_ATUX_STAT_EXT_SIG_TABORT | \ - IOP13XX_ATUX_STAT_MASTER_DATA_PAR) - -/* PCI interrupts - */ -#define ATUX_INTA IRQ_IOP13XX_XINT0 -#define ATUX_INTB IRQ_IOP13XX_XINT1 -#define ATUX_INTC IRQ_IOP13XX_XINT2 -#define ATUX_INTD IRQ_IOP13XX_XINT3 - -#define ATUE_INTA IRQ_IOP13XX_ATUE_IMA -#define ATUE_INTB IRQ_IOP13XX_ATUE_IMB -#define ATUE_INTC IRQ_IOP13XX_ATUE_IMC -#define ATUE_INTD IRQ_IOP13XX_ATUE_IMD - -#endif /* _IOP13XX_PCI_H_ */ diff --git a/arch/arm/mach-iop13xx/setup.c b/arch/arm/mach-iop13xx/setup.c deleted file mode 100644 index c5c84c9ec9eedad2958cbd7f2cd9ebe11d670b3f..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/setup.c +++ /dev/null @@ -1,595 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * iop13xx platform Initialization - * Copyright (c) 2005-2006, Intel Corporation. - */ - -#include -#include -#include -#include -#ifdef CONFIG_MTD_PHYSMAP -#include -#endif -#include -#include -#include -#include -#include - -#define IOP13XX_UART_XTAL 33334000 -#define IOP13XX_SETUP_DEBUG 0 -#define PRINTK(x...) ((void)(IOP13XX_SETUP_DEBUG && printk(x))) - -/* Standard IO mapping for all IOP13XX based systems - */ -static struct map_desc iop13xx_std_desc[] __initdata = { - { /* mem mapped registers */ - .virtual = (unsigned long)IOP13XX_PMMR_VIRT_MEM_BASE, - .pfn = __phys_to_pfn(IOP13XX_PMMR_PHYS_MEM_BASE), - .length = IOP13XX_PMMR_SIZE, - .type = MT_DEVICE, - }, -}; - -static struct resource iop13xx_uart0_resources[] = { - [0] = { - .start = IOP13XX_UART0_PHYS, - .end = IOP13XX_UART0_PHYS + 0x3f, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_IOP13XX_UART0, - .end = IRQ_IOP13XX_UART0, - .flags = IORESOURCE_IRQ - } -}; - -static struct resource iop13xx_uart1_resources[] = { - [0] = { - .start = IOP13XX_UART1_PHYS, - .end = IOP13XX_UART1_PHYS + 0x3f, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_IOP13XX_UART1, - .end = IRQ_IOP13XX_UART1, - .flags = IORESOURCE_IRQ - } -}; - -static struct plat_serial8250_port iop13xx_uart0_data[] = { - { - .membase = IOP13XX_UART0_VIRT, - .mapbase = IOP13XX_UART0_PHYS, - .irq = IRQ_IOP13XX_UART0, - .uartclk = IOP13XX_UART_XTAL, - .regshift = 2, - .iotype = UPIO_MEM, - .flags = UPF_SKIP_TEST, - }, - { }, -}; - -static struct plat_serial8250_port iop13xx_uart1_data[] = { - { - .membase = IOP13XX_UART1_VIRT, - .mapbase = IOP13XX_UART1_PHYS, - .irq = IRQ_IOP13XX_UART1, - .uartclk = IOP13XX_UART_XTAL, - .regshift = 2, - .iotype = UPIO_MEM, - .flags = UPF_SKIP_TEST, - }, - { }, -}; - -/* The ids are fixed up later in iop13xx_platform_init */ -static struct platform_device iop13xx_uart0 = { - .name = "serial8250", - .id = 0, - .dev.platform_data = iop13xx_uart0_data, - .num_resources = 2, - .resource = iop13xx_uart0_resources, -}; - -static struct platform_device iop13xx_uart1 = { - .name = "serial8250", - .id = 0, - .dev.platform_data = iop13xx_uart1_data, - .num_resources = 2, - .resource = iop13xx_uart1_resources -}; - -static struct resource iop13xx_i2c_0_resources[] = { - [0] = { - .start = IOP13XX_I2C0_PHYS, - .end = IOP13XX_I2C0_PHYS + 0x18, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_IOP13XX_I2C_0, - .end = IRQ_IOP13XX_I2C_0, - .flags = IORESOURCE_IRQ - } -}; - -static struct resource iop13xx_i2c_1_resources[] = { - [0] = { - .start = IOP13XX_I2C1_PHYS, - .end = IOP13XX_I2C1_PHYS + 0x18, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_IOP13XX_I2C_1, - .end = IRQ_IOP13XX_I2C_1, - .flags = IORESOURCE_IRQ - } -}; - -static struct resource iop13xx_i2c_2_resources[] = { - [0] = { - .start = IOP13XX_I2C2_PHYS, - .end = IOP13XX_I2C2_PHYS + 0x18, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_IOP13XX_I2C_2, - .end = IRQ_IOP13XX_I2C_2, - .flags = IORESOURCE_IRQ - } -}; - -/* I2C controllers. The IOP13XX uses the same block as the IOP3xx, so - * we just use the same device name. - */ - -/* The ids are fixed up later in iop13xx_platform_init */ -static struct platform_device iop13xx_i2c_0_controller = { - .name = "IOP3xx-I2C", - .id = 0, - .num_resources = 2, - .resource = iop13xx_i2c_0_resources -}; - -static struct platform_device iop13xx_i2c_1_controller = { - .name = "IOP3xx-I2C", - .id = 0, - .num_resources = 2, - .resource = iop13xx_i2c_1_resources -}; - -static struct platform_device iop13xx_i2c_2_controller = { - .name = "IOP3xx-I2C", - .id = 0, - .num_resources = 2, - .resource = iop13xx_i2c_2_resources -}; - -#ifdef CONFIG_MTD_PHYSMAP -/* PBI Flash Device - */ -static struct physmap_flash_data iq8134x_flash_data = { - .width = 2, -}; - -static struct resource iq8134x_flash_resource = { - .start = IQ81340_FLASHBASE, - .end = 0, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device iq8134x_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { .platform_data = &iq8134x_flash_data, }, - .num_resources = 1, - .resource = &iq8134x_flash_resource, -}; - -static unsigned long iq8134x_probe_flash_size(void) -{ - uint8_t __iomem *flash_addr = ioremap(IQ81340_FLASHBASE, PAGE_SIZE); - int i; - char query[3]; - unsigned long size = 0; - int width = iq8134x_flash_data.width; - - if (flash_addr) { - /* send CFI 'query' command */ - writew(0x98, flash_addr); - - /* check for CFI compliance */ - for (i = 0; i < 3 * width; i += width) - query[i / width] = readb(flash_addr + (0x10 * width) + i); - - /* read the size */ - if (memcmp(query, "QRY", 3) == 0) - size = 1 << readb(flash_addr + (0x27 * width)); - - /* send CFI 'read array' command */ - writew(0xff, flash_addr); - - iounmap(flash_addr); - } - - return size; -} -#endif - -/* ADMA Channels */ -static struct resource iop13xx_adma_0_resources[] = { - [0] = { - .start = IOP13XX_ADMA_PHYS_BASE(0), - .end = IOP13XX_ADMA_UPPER_PA(0), - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_IOP13XX_ADMA0_EOT, - .end = IRQ_IOP13XX_ADMA0_EOT, - .flags = IORESOURCE_IRQ - }, - [2] = { - .start = IRQ_IOP13XX_ADMA0_EOC, - .end = IRQ_IOP13XX_ADMA0_EOC, - .flags = IORESOURCE_IRQ - }, - [3] = { - .start = IRQ_IOP13XX_ADMA0_ERR, - .end = IRQ_IOP13XX_ADMA0_ERR, - .flags = IORESOURCE_IRQ - } -}; - -static struct resource iop13xx_adma_1_resources[] = { - [0] = { - .start = IOP13XX_ADMA_PHYS_BASE(1), - .end = IOP13XX_ADMA_UPPER_PA(1), - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_IOP13XX_ADMA1_EOT, - .end = IRQ_IOP13XX_ADMA1_EOT, - .flags = IORESOURCE_IRQ - }, - [2] = { - .start = IRQ_IOP13XX_ADMA1_EOC, - .end = IRQ_IOP13XX_ADMA1_EOC, - .flags = IORESOURCE_IRQ - }, - [3] = { - .start = IRQ_IOP13XX_ADMA1_ERR, - .end = IRQ_IOP13XX_ADMA1_ERR, - .flags = IORESOURCE_IRQ - } -}; - -static struct resource iop13xx_adma_2_resources[] = { - [0] = { - .start = IOP13XX_ADMA_PHYS_BASE(2), - .end = IOP13XX_ADMA_UPPER_PA(2), - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_IOP13XX_ADMA2_EOT, - .end = IRQ_IOP13XX_ADMA2_EOT, - .flags = IORESOURCE_IRQ - }, - [2] = { - .start = IRQ_IOP13XX_ADMA2_EOC, - .end = IRQ_IOP13XX_ADMA2_EOC, - .flags = IORESOURCE_IRQ - }, - [3] = { - .start = IRQ_IOP13XX_ADMA2_ERR, - .end = IRQ_IOP13XX_ADMA2_ERR, - .flags = IORESOURCE_IRQ - } -}; - -static u64 iop13xx_adma_dmamask = DMA_BIT_MASK(32); -static struct iop_adma_platform_data iop13xx_adma_0_data = { - .hw_id = 0, - .pool_size = PAGE_SIZE, -}; - -static struct iop_adma_platform_data iop13xx_adma_1_data = { - .hw_id = 1, - .pool_size = PAGE_SIZE, -}; - -static struct iop_adma_platform_data iop13xx_adma_2_data = { - .hw_id = 2, - .pool_size = PAGE_SIZE, -}; - -/* The ids are fixed up later in iop13xx_platform_init */ -static struct platform_device iop13xx_adma_0_channel = { - .name = "iop-adma", - .id = 0, - .num_resources = 4, - .resource = iop13xx_adma_0_resources, - .dev = { - .dma_mask = &iop13xx_adma_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - .platform_data = (void *) &iop13xx_adma_0_data, - }, -}; - -static struct platform_device iop13xx_adma_1_channel = { - .name = "iop-adma", - .id = 0, - .num_resources = 4, - .resource = iop13xx_adma_1_resources, - .dev = { - .dma_mask = &iop13xx_adma_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - .platform_data = (void *) &iop13xx_adma_1_data, - }, -}; - -static struct platform_device iop13xx_adma_2_channel = { - .name = "iop-adma", - .id = 0, - .num_resources = 4, - .resource = iop13xx_adma_2_resources, - .dev = { - .dma_mask = &iop13xx_adma_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - .platform_data = (void *) &iop13xx_adma_2_data, - }, -}; - -void __init iop13xx_map_io(void) -{ - /* Initialize the Static Page Table maps */ - iotable_init(iop13xx_std_desc, ARRAY_SIZE(iop13xx_std_desc)); -} - -static int init_uart; -static int init_i2c; -static int init_adma; - -void __init iop13xx_platform_init(void) -{ - int i; - u32 uart_idx, i2c_idx, adma_idx, plat_idx; - struct platform_device *iop13xx_devices[IQ81340_MAX_PLAT_DEVICES]; - - /* set the bases so we can read the device id */ - iop13xx_set_atu_mmr_bases(); - - memset(iop13xx_devices, 0, sizeof(iop13xx_devices)); - - if (init_uart == IOP13XX_INIT_UART_DEFAULT) { - switch (iop13xx_dev_id()) { - /* enable both uarts on iop341 */ - case 0x3380: - case 0x3384: - case 0x3388: - case 0x338c: - init_uart |= IOP13XX_INIT_UART_0; - init_uart |= IOP13XX_INIT_UART_1; - break; - /* only enable uart 1 */ - default: - init_uart |= IOP13XX_INIT_UART_1; - } - } - - if (init_i2c == IOP13XX_INIT_I2C_DEFAULT) { - switch (iop13xx_dev_id()) { - /* enable all i2c units on iop341 and iop342 */ - case 0x3380: - case 0x3384: - case 0x3388: - case 0x338c: - case 0x3382: - case 0x3386: - case 0x338a: - case 0x338e: - init_i2c |= IOP13XX_INIT_I2C_0; - init_i2c |= IOP13XX_INIT_I2C_1; - init_i2c |= IOP13XX_INIT_I2C_2; - break; - /* only enable i2c 1 and 2 */ - default: - init_i2c |= IOP13XX_INIT_I2C_1; - init_i2c |= IOP13XX_INIT_I2C_2; - } - } - - if (init_adma == IOP13XX_INIT_ADMA_DEFAULT) { - init_adma |= IOP13XX_INIT_ADMA_0; - init_adma |= IOP13XX_INIT_ADMA_1; - init_adma |= IOP13XX_INIT_ADMA_2; - } - - plat_idx = 0; - uart_idx = 0; - i2c_idx = 0; - - /* uart 1 (if enabled) is ttyS0 */ - if (init_uart & IOP13XX_INIT_UART_1) { - PRINTK("Adding uart1 to platform device list\n"); - iop13xx_uart1.id = uart_idx++; - iop13xx_devices[plat_idx++] = &iop13xx_uart1; - } - if (init_uart & IOP13XX_INIT_UART_0) { - PRINTK("Adding uart0 to platform device list\n"); - iop13xx_uart0.id = uart_idx++; - iop13xx_devices[plat_idx++] = &iop13xx_uart0; - } - - for(i = 0; i < IQ81340_NUM_I2C; i++) { - if ((init_i2c & (1 << i)) && IOP13XX_SETUP_DEBUG) - printk("Adding i2c%d to platform device list\n", i); - switch(init_i2c & (1 << i)) { - case IOP13XX_INIT_I2C_0: - iop13xx_i2c_0_controller.id = i2c_idx++; - iop13xx_devices[plat_idx++] = - &iop13xx_i2c_0_controller; - break; - case IOP13XX_INIT_I2C_1: - iop13xx_i2c_1_controller.id = i2c_idx++; - iop13xx_devices[plat_idx++] = - &iop13xx_i2c_1_controller; - break; - case IOP13XX_INIT_I2C_2: - iop13xx_i2c_2_controller.id = i2c_idx++; - iop13xx_devices[plat_idx++] = - &iop13xx_i2c_2_controller; - break; - } - } - - /* initialize adma channel ids and capabilities */ - adma_idx = 0; - for (i = 0; i < IQ81340_NUM_ADMA; i++) { - struct iop_adma_platform_data *plat_data; - if ((init_adma & (1 << i)) && IOP13XX_SETUP_DEBUG) - printk(KERN_INFO - "Adding adma%d to platform device list\n", i); - switch (init_adma & (1 << i)) { - case IOP13XX_INIT_ADMA_0: - iop13xx_adma_0_channel.id = adma_idx++; - iop13xx_devices[plat_idx++] = &iop13xx_adma_0_channel; - plat_data = &iop13xx_adma_0_data; - dma_cap_set(DMA_MEMCPY, plat_data->cap_mask); - dma_cap_set(DMA_XOR, plat_data->cap_mask); - dma_cap_set(DMA_XOR_VAL, plat_data->cap_mask); - dma_cap_set(DMA_INTERRUPT, plat_data->cap_mask); - break; - case IOP13XX_INIT_ADMA_1: - iop13xx_adma_1_channel.id = adma_idx++; - iop13xx_devices[plat_idx++] = &iop13xx_adma_1_channel; - plat_data = &iop13xx_adma_1_data; - dma_cap_set(DMA_MEMCPY, plat_data->cap_mask); - dma_cap_set(DMA_XOR, plat_data->cap_mask); - dma_cap_set(DMA_XOR_VAL, plat_data->cap_mask); - dma_cap_set(DMA_INTERRUPT, plat_data->cap_mask); - break; - case IOP13XX_INIT_ADMA_2: - iop13xx_adma_2_channel.id = adma_idx++; - iop13xx_devices[plat_idx++] = &iop13xx_adma_2_channel; - plat_data = &iop13xx_adma_2_data; - dma_cap_set(DMA_MEMCPY, plat_data->cap_mask); - dma_cap_set(DMA_XOR, plat_data->cap_mask); - dma_cap_set(DMA_XOR_VAL, plat_data->cap_mask); - dma_cap_set(DMA_INTERRUPT, plat_data->cap_mask); - dma_cap_set(DMA_PQ, plat_data->cap_mask); - dma_cap_set(DMA_PQ_VAL, plat_data->cap_mask); - break; - } - } - -#ifdef CONFIG_MTD_PHYSMAP - iq8134x_flash_resource.end = iq8134x_flash_resource.start + - iq8134x_probe_flash_size() - 1; - if (iq8134x_flash_resource.end > iq8134x_flash_resource.start) - iop13xx_devices[plat_idx++] = &iq8134x_flash; - else - printk(KERN_ERR "%s: Failed to probe flash size\n", __func__); -#endif - - platform_add_devices(iop13xx_devices, plat_idx); -} - -static int __init iop13xx_init_uart_setup(char *str) -{ - if (str) { - while (*str != '\0') { - switch(*str) { - case '0': - init_uart |= IOP13XX_INIT_UART_0; - break; - case '1': - init_uart |= IOP13XX_INIT_UART_1; - break; - case ',': - case '=': - break; - default: - PRINTK("\"iop13xx_init_uart\" malformed" - " at character: \'%c\'", *str); - *(str + 1) = '\0'; - init_uart = IOP13XX_INIT_UART_DEFAULT; - } - str++; - } - } - return 1; -} - -static int __init iop13xx_init_i2c_setup(char *str) -{ - if (str) { - while (*str != '\0') { - switch(*str) { - case '0': - init_i2c |= IOP13XX_INIT_I2C_0; - break; - case '1': - init_i2c |= IOP13XX_INIT_I2C_1; - break; - case '2': - init_i2c |= IOP13XX_INIT_I2C_2; - break; - case ',': - case '=': - break; - default: - PRINTK("\"iop13xx_init_i2c\" malformed" - " at character: \'%c\'", *str); - *(str + 1) = '\0'; - init_i2c = IOP13XX_INIT_I2C_DEFAULT; - } - str++; - } - } - return 1; -} - -static int __init iop13xx_init_adma_setup(char *str) -{ - if (str) { - while (*str != '\0') { - switch (*str) { - case '0': - init_adma |= IOP13XX_INIT_ADMA_0; - break; - case '1': - init_adma |= IOP13XX_INIT_ADMA_1; - break; - case '2': - init_adma |= IOP13XX_INIT_ADMA_2; - break; - case ',': - case '=': - break; - default: - PRINTK("\"iop13xx_init_adma\" malformed" - " at character: \'%c\'", *str); - *(str + 1) = '\0'; - init_adma = IOP13XX_INIT_ADMA_DEFAULT; - } - str++; - } - } - return 1; -} - -__setup("iop13xx_init_adma", iop13xx_init_adma_setup); -__setup("iop13xx_init_uart", iop13xx_init_uart_setup); -__setup("iop13xx_init_i2c", iop13xx_init_i2c_setup); - -void iop13xx_restart(enum reboot_mode mode, const char *cmd) -{ - /* - * Reset the internal bus (warning both cores are reset) - */ - write_wdtcr(IOP_WDTCR_EN_ARM); - write_wdtcr(IOP_WDTCR_EN); - write_wdtsr(IOP13XX_WDTSR_WRITE_EN | IOP13XX_WDTCR_IB_RESET); - write_wdtcr(0x1000); -} diff --git a/arch/arm/mach-iop13xx/tpmi.c b/arch/arm/mach-iop13xx/tpmi.c deleted file mode 100644 index 4f916549e381bc18d72df3f7d3942c85f42eb25a..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop13xx/tpmi.c +++ /dev/null @@ -1,244 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * iop13xx tpmi device resources - * Copyright (c) 2005-2006, Intel Corporation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* assumes CONTROLLER_ONLY# is never asserted in the ESSR register */ -#define IOP13XX_TPMI_MMR(dev) IOP13XX_REG_ADDR32_PHYS(0x48000 + (dev << 12)) -#define IOP13XX_TPMI_MEM(dev) IOP13XX_REG_ADDR32_PHYS(0x60000 + (dev << 13)) -#define IOP13XX_TPMI_CTRL(dev) IOP13XX_REG_ADDR32_PHYS(0x50000 + (dev << 10)) -#define IOP13XX_TPMI_IOP_CTRL(dev) (IOP13XX_TPMI_CTRL(dev) + 0x2000) -#define IOP13XX_TPMI_MMR_SIZE (SZ_4K - 1) -#define IOP13XX_TPMI_MEM_SIZE (255) -#define IOP13XX_TPMI_MEM_CTRL (SZ_1K - 1) -#define IOP13XX_TPMI_RESOURCE_MMR 0 -#define IOP13XX_TPMI_RESOURCE_MEM 1 -#define IOP13XX_TPMI_RESOURCE_CTRL 2 -#define IOP13XX_TPMI_RESOURCE_IOP_CTRL 3 -#define IOP13XX_TPMI_RESOURCE_IRQ 4 - -static struct resource iop13xx_tpmi_0_resources[] = { - [IOP13XX_TPMI_RESOURCE_MMR] = { - .start = IOP13XX_TPMI_MMR(4), /* tpmi0 starts at dev == 4 */ - .end = IOP13XX_TPMI_MMR(4) + IOP13XX_TPMI_MMR_SIZE, - .flags = IORESOURCE_MEM, - }, - [IOP13XX_TPMI_RESOURCE_MEM] = { - .start = IOP13XX_TPMI_MEM(0), - .end = IOP13XX_TPMI_MEM(0) + IOP13XX_TPMI_MEM_SIZE, - .flags = IORESOURCE_MEM, - }, - [IOP13XX_TPMI_RESOURCE_CTRL] = { - .start = IOP13XX_TPMI_CTRL(0), - .end = IOP13XX_TPMI_CTRL(0) + IOP13XX_TPMI_MEM_CTRL, - .flags = IORESOURCE_MEM, - }, - [IOP13XX_TPMI_RESOURCE_IOP_CTRL] = { - .start = IOP13XX_TPMI_IOP_CTRL(0), - .end = IOP13XX_TPMI_IOP_CTRL(0) + IOP13XX_TPMI_MEM_CTRL, - .flags = IORESOURCE_MEM, - }, - [IOP13XX_TPMI_RESOURCE_IRQ] = { - .start = IRQ_IOP13XX_TPMI0_OUT, - .end = IRQ_IOP13XX_TPMI0_OUT, - .flags = IORESOURCE_IRQ - } -}; - -static struct resource iop13xx_tpmi_1_resources[] = { - [IOP13XX_TPMI_RESOURCE_MMR] = { - .start = IOP13XX_TPMI_MMR(1), - .end = IOP13XX_TPMI_MMR(1) + IOP13XX_TPMI_MMR_SIZE, - .flags = IORESOURCE_MEM, - }, - [IOP13XX_TPMI_RESOURCE_MEM] = { - .start = IOP13XX_TPMI_MEM(1), - .end = IOP13XX_TPMI_MEM(1) + IOP13XX_TPMI_MEM_SIZE, - .flags = IORESOURCE_MEM, - }, - [IOP13XX_TPMI_RESOURCE_CTRL] = { - .start = IOP13XX_TPMI_CTRL(1), - .end = IOP13XX_TPMI_CTRL(1) + IOP13XX_TPMI_MEM_CTRL, - .flags = IORESOURCE_MEM, - }, - [IOP13XX_TPMI_RESOURCE_IOP_CTRL] = { - .start = IOP13XX_TPMI_IOP_CTRL(1), - .end = IOP13XX_TPMI_IOP_CTRL(1) + IOP13XX_TPMI_MEM_CTRL, - .flags = IORESOURCE_MEM, - }, - [IOP13XX_TPMI_RESOURCE_IRQ] = { - .start = IRQ_IOP13XX_TPMI1_OUT, - .end = IRQ_IOP13XX_TPMI1_OUT, - .flags = IORESOURCE_IRQ - } -}; - -static struct resource iop13xx_tpmi_2_resources[] = { - [IOP13XX_TPMI_RESOURCE_MMR] = { - .start = IOP13XX_TPMI_MMR(2), - .end = IOP13XX_TPMI_MMR(2) + IOP13XX_TPMI_MMR_SIZE, - .flags = IORESOURCE_MEM, - }, - [IOP13XX_TPMI_RESOURCE_MEM] = { - .start = IOP13XX_TPMI_MEM(2), - .end = IOP13XX_TPMI_MEM(2) + IOP13XX_TPMI_MEM_SIZE, - .flags = IORESOURCE_MEM, - }, - [IOP13XX_TPMI_RESOURCE_CTRL] = { - .start = IOP13XX_TPMI_CTRL(2), - .end = IOP13XX_TPMI_CTRL(2) + IOP13XX_TPMI_MEM_CTRL, - .flags = IORESOURCE_MEM, - }, - [IOP13XX_TPMI_RESOURCE_IOP_CTRL] = { - .start = IOP13XX_TPMI_IOP_CTRL(2), - .end = IOP13XX_TPMI_IOP_CTRL(2) + IOP13XX_TPMI_MEM_CTRL, - .flags = IORESOURCE_MEM, - }, - [IOP13XX_TPMI_RESOURCE_IRQ] = { - .start = IRQ_IOP13XX_TPMI2_OUT, - .end = IRQ_IOP13XX_TPMI2_OUT, - .flags = IORESOURCE_IRQ - } -}; - -static struct resource iop13xx_tpmi_3_resources[] = { - [IOP13XX_TPMI_RESOURCE_MMR] = { - .start = IOP13XX_TPMI_MMR(3), - .end = IOP13XX_TPMI_MMR(3) + IOP13XX_TPMI_MMR_SIZE, - .flags = IORESOURCE_MEM, - }, - [IOP13XX_TPMI_RESOURCE_MEM] = { - .start = IOP13XX_TPMI_MEM(3), - .end = IOP13XX_TPMI_MEM(3) + IOP13XX_TPMI_MEM_SIZE, - .flags = IORESOURCE_MEM, - }, - [IOP13XX_TPMI_RESOURCE_CTRL] = { - .start = IOP13XX_TPMI_CTRL(3), - .end = IOP13XX_TPMI_CTRL(3) + IOP13XX_TPMI_MEM_CTRL, - .flags = IORESOURCE_MEM, - }, - [IOP13XX_TPMI_RESOURCE_IOP_CTRL] = { - .start = IOP13XX_TPMI_IOP_CTRL(3), - .end = IOP13XX_TPMI_IOP_CTRL(3) + IOP13XX_TPMI_MEM_CTRL, - .flags = IORESOURCE_MEM, - }, - [IOP13XX_TPMI_RESOURCE_IRQ] = { - .start = IRQ_IOP13XX_TPMI3_OUT, - .end = IRQ_IOP13XX_TPMI3_OUT, - .flags = IORESOURCE_IRQ - } -}; - -u64 iop13xx_tpmi_mask = DMA_BIT_MASK(32); -static struct platform_device iop13xx_tpmi_0_device = { - .name = "iop-tpmi", - .id = 0, - .num_resources = ARRAY_SIZE(iop13xx_tpmi_0_resources), - .resource = iop13xx_tpmi_0_resources, - .dev = { - .dma_mask = &iop13xx_tpmi_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, -}; - -static struct platform_device iop13xx_tpmi_1_device = { - .name = "iop-tpmi", - .id = 1, - .num_resources = ARRAY_SIZE(iop13xx_tpmi_1_resources), - .resource = iop13xx_tpmi_1_resources, - .dev = { - .dma_mask = &iop13xx_tpmi_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, -}; - -static struct platform_device iop13xx_tpmi_2_device = { - .name = "iop-tpmi", - .id = 2, - .num_resources = ARRAY_SIZE(iop13xx_tpmi_2_resources), - .resource = iop13xx_tpmi_2_resources, - .dev = { - .dma_mask = &iop13xx_tpmi_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, -}; - -static struct platform_device iop13xx_tpmi_3_device = { - .name = "iop-tpmi", - .id = 3, - .num_resources = ARRAY_SIZE(iop13xx_tpmi_3_resources), - .resource = iop13xx_tpmi_3_resources, - .dev = { - .dma_mask = &iop13xx_tpmi_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, -}; - -__init void iop13xx_add_tpmi_devices(void) -{ - unsigned short device_id; - - /* tpmi's not present on iop341 or iop342 */ - if (__raw_readl(IOP13XX_ESSR0) & IOP13XX_INTERFACE_SEL_PCIX) - /* ATUE must be present */ - device_id = __raw_readw(IOP13XX_ATUE_DID); - else - /* ATUX must be present */ - device_id = __raw_readw(IOP13XX_ATUX_DID); - - switch (device_id) { - /* iop34[1|2] 0-tpmi */ - case 0x3380: - case 0x3384: - case 0x3388: - case 0x338c: - case 0x3382: - case 0x3386: - case 0x338a: - case 0x338e: - return; - /* iop348 1-tpmi */ - case 0x3310: - case 0x3312: - case 0x3314: - case 0x3318: - case 0x331a: - case 0x331c: - case 0x33c0: - case 0x33c2: - case 0x33c4: - case 0x33c8: - case 0x33ca: - case 0x33cc: - case 0x33b0: - case 0x33b2: - case 0x33b4: - case 0x33b8: - case 0x33ba: - case 0x33bc: - case 0x3320: - case 0x3322: - case 0x3324: - case 0x3328: - case 0x332a: - case 0x332c: - platform_device_register(&iop13xx_tpmi_0_device); - return; - default: - platform_device_register(&iop13xx_tpmi_0_device); - platform_device_register(&iop13xx_tpmi_1_device); - platform_device_register(&iop13xx_tpmi_2_device); - platform_device_register(&iop13xx_tpmi_3_device); - return; - } -} diff --git a/arch/arm/mach-iop32x/Makefile b/arch/arm/mach-iop32x/Makefile index 71d62447d4d5e7eec6f79de921f824927eb48556..c8018ef5c6a98edbdf82b69fc9ed17a7329916f1 100644 --- a/arch/arm/mach-iop32x/Makefile +++ b/arch/arm/mach-iop32x/Makefile @@ -3,7 +3,15 @@ # Makefile for the linux kernel. # -obj-y := irq.o +obj-$(CONFIG_ARCH_IOP32X) += irq.o +obj-$(CONFIG_ARCH_IOP32X) += i2c.o +obj-$(CONFIG_ARCH_IOP32X) += pci.o +obj-$(CONFIG_ARCH_IOP32X) += setup.o +obj-$(CONFIG_ARCH_IOP32X) += time.o +obj-$(CONFIG_ARCH_IOP32X) += cp6.o +obj-$(CONFIG_ARCH_IOP32X) += adma.o +obj-$(CONFIG_ARCH_IOP32X) += pmu.o +obj-$(CONFIG_ARCH_IOP32X) += restart.o obj-$(CONFIG_MACH_GLANTANK) += glantank.o obj-$(CONFIG_ARCH_IQ80321) += iq80321.o diff --git a/arch/arm/plat-iop/adma.c b/arch/arm/mach-iop32x/adma.c similarity index 75% rename from arch/arm/plat-iop/adma.c rename to arch/arm/mach-iop32x/adma.c index b8e360299293f83d263a8d9b147f2288a11abfa9..764bcbff98dfe23facb3d01a01b8c818ca480812 100644 --- a/arch/arm/plat-iop/adma.c +++ b/arch/arm/mach-iop32x/adma.c @@ -4,12 +4,12 @@ * Copyright © 2006, Intel Corporation. */ #include -#include #include -#include -#include +#include + +#include "iop3xx.h" +#include "irqs.h" -#ifdef CONFIG_ARCH_IOP32X #define IRQ_DMA0_EOT IRQ_IOP32X_DMA0_EOT #define IRQ_DMA0_EOC IRQ_IOP32X_DMA0_EOC #define IRQ_DMA0_ERR IRQ_IOP32X_DMA0_ERR @@ -21,20 +21,7 @@ #define IRQ_AA_EOT IRQ_IOP32X_AA_EOT #define IRQ_AA_EOC IRQ_IOP32X_AA_EOC #define IRQ_AA_ERR IRQ_IOP32X_AA_ERR -#endif -#ifdef CONFIG_ARCH_IOP33X -#define IRQ_DMA0_EOT IRQ_IOP33X_DMA0_EOT -#define IRQ_DMA0_EOC IRQ_IOP33X_DMA0_EOC -#define IRQ_DMA0_ERR IRQ_IOP33X_DMA0_ERR - -#define IRQ_DMA1_EOT IRQ_IOP33X_DMA1_EOT -#define IRQ_DMA1_EOC IRQ_IOP33X_DMA1_EOC -#define IRQ_DMA1_ERR IRQ_IOP33X_DMA1_ERR - -#define IRQ_AA_EOT IRQ_IOP33X_AA_EOT -#define IRQ_AA_EOC IRQ_IOP33X_AA_EOC -#define IRQ_AA_ERR IRQ_IOP33X_AA_ERR -#endif + /* AAU and DMA Channels */ static struct resource iop3xx_dma_0_resources[] = { [0] = { @@ -161,30 +148,14 @@ struct platform_device iop3xx_aau_channel = { static int __init iop3xx_adma_cap_init(void) { - #ifdef CONFIG_ARCH_IOP32X /* the 32x DMA does not perform CRC32C */ - dma_cap_set(DMA_MEMCPY, iop3xx_dma_0_data.cap_mask); - dma_cap_set(DMA_INTERRUPT, iop3xx_dma_0_data.cap_mask); - #else dma_cap_set(DMA_MEMCPY, iop3xx_dma_0_data.cap_mask); dma_cap_set(DMA_INTERRUPT, iop3xx_dma_0_data.cap_mask); - #endif - #ifdef CONFIG_ARCH_IOP32X /* the 32x DMA does not perform CRC32C */ dma_cap_set(DMA_MEMCPY, iop3xx_dma_1_data.cap_mask); dma_cap_set(DMA_INTERRUPT, iop3xx_dma_1_data.cap_mask); - #else - dma_cap_set(DMA_MEMCPY, iop3xx_dma_1_data.cap_mask); - dma_cap_set(DMA_INTERRUPT, iop3xx_dma_1_data.cap_mask); - #endif - #ifdef CONFIG_ARCH_IOP32X /* the 32x AAU does not perform zero sum */ - dma_cap_set(DMA_XOR, iop3xx_aau_data.cap_mask); - dma_cap_set(DMA_INTERRUPT, iop3xx_aau_data.cap_mask); - #else dma_cap_set(DMA_XOR, iop3xx_aau_data.cap_mask); - dma_cap_set(DMA_XOR_VAL, iop3xx_aau_data.cap_mask); dma_cap_set(DMA_INTERRUPT, iop3xx_aau_data.cap_mask); - #endif return 0; } diff --git a/arch/arm/plat-iop/cp6.c b/arch/arm/mach-iop32x/cp6.c similarity index 100% rename from arch/arm/plat-iop/cp6.c rename to arch/arm/mach-iop32x/cp6.c diff --git a/arch/arm/mach-iop32x/em7210.c b/arch/arm/mach-iop32x/em7210.c index 61a1e593f9ecc89e55940cf437e1152393d5b0ac..d43ced3cd4e7c2db05d224d1120b741ff9659f19 100644 --- a/arch/arm/mach-iop32x/em7210.c +++ b/arch/arm/mach-iop32x/em7210.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -29,8 +28,10 @@ #include #include #include -#include + +#include "hardware.h" #include "gpio-iop32x.h" +#include "irqs.h" static void __init em7210_timer_init(void) { diff --git a/arch/arm/mach-iop32x/glantank.c b/arch/arm/mach-iop32x/glantank.c index 5a45d616d9ac2fc0342f5529e770f93682556415..2fe0f77d1f1d15af4f0549523968aa97ac0fa265 100644 --- a/arch/arm/mach-iop32x/glantank.c +++ b/arch/arm/mach-iop32x/glantank.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -30,8 +29,10 @@ #include #include #include -#include + +#include "hardware.h" #include "gpio-iop32x.h" +#include "irqs.h" /* * GLAN Tank timer tick configuration. diff --git a/arch/arm/mach-iop32x/include/mach/glantank.h b/arch/arm/mach-iop32x/glantank.h similarity index 78% rename from arch/arm/mach-iop32x/include/mach/glantank.h rename to arch/arm/mach-iop32x/glantank.h index b9df2e4614cfcf6a5d85188289164e8aa97295af..f38e86b82c3d1ca04d0525f5bdce170150e379e9 100644 --- a/arch/arm/mach-iop32x/include/mach/glantank.h +++ b/arch/arm/mach-iop32x/glantank.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * arch/arm/mach-iop32x/include/mach/glantank.h - * * IO-Data GLAN Tank board registers */ diff --git a/arch/arm/mach-iop32x/include/mach/hardware.h b/arch/arm/mach-iop32x/hardware.h similarity index 90% rename from arch/arm/mach-iop32x/include/mach/hardware.h rename to arch/arm/mach-iop32x/hardware.h index 6e5303e602268d2be6964f5607e5bcc0e8dd6886..43ab4fb8f9b01792def2052759f7a8bf91c3f25e 100644 --- a/arch/arm/mach-iop32x/include/mach/hardware.h +++ b/arch/arm/mach-iop32x/hardware.h @@ -1,8 +1,4 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* - * arch/arm/mach-iop32x/include/mach/hardware.h - */ - #ifndef __HARDWARE_H #define __HARDWARE_H @@ -28,7 +24,7 @@ void iop32x_init_irq(void); /* * Generic chipset bits */ -#include "iop32x.h" +#include "iop3xx.h" /* * Board specific bits diff --git a/arch/arm/plat-iop/i2c.c b/arch/arm/mach-iop32x/i2c.c similarity index 81% rename from arch/arm/plat-iop/i2c.c rename to arch/arm/mach-iop32x/i2c.c index dfbd7c332866a3684e2e537d2a087ae98828ac5b..dc9f6a14ab1b3cad7cf7c340a649f032f550964e 100644 --- a/arch/arm/plat-iop/i2c.c +++ b/arch/arm/mach-iop32x/i2c.c @@ -22,18 +22,11 @@ #include #include #include -#include -#include #include -#ifdef CONFIG_ARCH_IOP32X -#define IRQ_IOP3XX_I2C_0 IRQ_IOP32X_I2C_0 -#define IRQ_IOP3XX_I2C_1 IRQ_IOP32X_I2C_1 -#endif -#ifdef CONFIG_ARCH_IOP33X -#define IRQ_IOP3XX_I2C_0 IRQ_IOP33X_I2C_0 -#define IRQ_IOP3XX_I2C_1 IRQ_IOP33X_I2C_1 -#endif +#include "hardware.h" +#include "iop3xx.h" +#include "irqs.h" /* * Each of the I2C busses have corresponding GPIO lines, and the driver @@ -65,8 +58,8 @@ static struct resource iop3xx_i2c0_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = IRQ_IOP3XX_I2C_0, - .end = IRQ_IOP3XX_I2C_0, + .start = IRQ_IOP32X_I2C_0, + .end = IRQ_IOP32X_I2C_0, .flags = IORESOURCE_IRQ, }, }; @@ -86,8 +79,8 @@ static struct resource iop3xx_i2c1_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = IRQ_IOP3XX_I2C_1, - .end = IRQ_IOP3XX_I2C_1, + .start = IRQ_IOP32X_I2C_1, + .end = IRQ_IOP32X_I2C_1, .flags = IORESOURCE_IRQ, } }; diff --git a/arch/arm/mach-iop32x/include/mach/adma.h b/arch/arm/mach-iop32x/include/mach/adma.h deleted file mode 100644 index 2b20063123ad5e0fa1ef7d6e94b90011eec0991a..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop32x/include/mach/adma.h +++ /dev/null @@ -1,6 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef IOP32X_ADMA_H -#define IOP32X_ADMA_H -#include -#endif - diff --git a/arch/arm/mach-iop32x/include/mach/entry-macro.S b/arch/arm/mach-iop32x/include/mach/entry-macro.S index ea13ae02d9b1ac1e169f455f21a90600c8409b55..8e6766d4621eb7c6bf53afbd575f2eb5ec6f056f 100644 --- a/arch/arm/mach-iop32x/include/mach/entry-macro.S +++ b/arch/arm/mach-iop32x/include/mach/entry-macro.S @@ -7,8 +7,6 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ -#include - .macro get_irqnr_preamble, base, tmp mrc p15, 0, \tmp, c15, c1, 0 orr \tmp, \tmp, #(1 << 6) diff --git a/arch/arm/mach-iop32x/include/mach/iop32x.h b/arch/arm/mach-iop32x/include/mach/iop32x.h deleted file mode 100644 index 84223f86552f8817c76c5b5b09f18f84b22664d8..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop32x/include/mach/iop32x.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-iop32x/include/mach/iop32x.h - * - * Intel IOP32X Chip definitions - * - * Author: Rory Bolt - * Copyright (C) 2002 Rory Bolt - * Copyright (C) 2004 Intel Corp. - */ - -#ifndef __IOP32X_H -#define __IOP32X_H - -/* - * Peripherals that are shared between the iop32x and iop33x but - * located at different addresses. - */ -#define IOP3XX_TIMER_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07e0 + (reg)) - -#include - -/* ATU Parameters - * set up a 1:1 bus to physical ram relationship - * w/ physical ram on top of pci in the memory map - */ -#define IOP32X_MAX_RAM_SIZE 0x40000000UL -#define IOP3XX_MAX_RAM_SIZE IOP32X_MAX_RAM_SIZE -#define IOP3XX_PCI_LOWER_MEM_BA 0x80000000 - -#endif diff --git a/arch/arm/mach-iop32x/include/mach/irqs.h b/arch/arm/mach-iop32x/include/mach/irqs.h index 82b11743e91c2ce572ee4f5b2ba905b3bbf6e276..c4e78df428e860e5b2b13b4bccd96eab8ea44ef2 100644 --- a/arch/arm/mach-iop32x/include/mach/irqs.h +++ b/arch/arm/mach-iop32x/include/mach/irqs.h @@ -9,39 +9,6 @@ #ifndef __IRQS_H #define __IRQS_H -/* - * IOP80321 chipset interrupts - */ -#define IRQ_IOP32X_DMA0_EOT 0 -#define IRQ_IOP32X_DMA0_EOC 1 -#define IRQ_IOP32X_DMA1_EOT 2 -#define IRQ_IOP32X_DMA1_EOC 3 -#define IRQ_IOP32X_AA_EOT 6 -#define IRQ_IOP32X_AA_EOC 7 -#define IRQ_IOP32X_CORE_PMON 8 -#define IRQ_IOP32X_TIMER0 9 -#define IRQ_IOP32X_TIMER1 10 -#define IRQ_IOP32X_I2C_0 11 -#define IRQ_IOP32X_I2C_1 12 -#define IRQ_IOP32X_MESSAGING 13 -#define IRQ_IOP32X_ATU_BIST 14 -#define IRQ_IOP32X_PERFMON 15 -#define IRQ_IOP32X_CORE_PMU 16 -#define IRQ_IOP32X_BIU_ERR 17 -#define IRQ_IOP32X_ATU_ERR 18 -#define IRQ_IOP32X_MCU_ERR 19 -#define IRQ_IOP32X_DMA0_ERR 20 -#define IRQ_IOP32X_DMA1_ERR 21 -#define IRQ_IOP32X_AA_ERR 23 -#define IRQ_IOP32X_MSG_ERR 24 -#define IRQ_IOP32X_SSP 25 -#define IRQ_IOP32X_XINT0 27 -#define IRQ_IOP32X_XINT1 28 -#define IRQ_IOP32X_XINT2 29 -#define IRQ_IOP32X_XINT3 30 -#define IRQ_IOP32X_HPI 31 - #define NR_IRQS 32 - #endif diff --git a/arch/arm/mach-iop32x/include/mach/time.h b/arch/arm/mach-iop32x/include/mach/time.h deleted file mode 100644 index d08950ccebc477590c96a4afe0a5a38595b34f0a..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop32x/include/mach/time.h +++ /dev/null @@ -1,5 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _IOP32X_TIME_H_ -#define _IOP32X_TIME_H_ -#define IRQ_IOP_TIMER0 IRQ_IOP32X_TIMER0 -#endif diff --git a/arch/arm/mach-iop32x/include/mach/uncompress.h b/arch/arm/mach-iop32x/include/mach/uncompress.h index ed4ac3e28fa15eb03d889b8a97c51c355ab94bfb..c8548875d94248d3469c7f1b2702440734d5c9fe 100644 --- a/arch/arm/mach-iop32x/include/mach/uncompress.h +++ b/arch/arm/mach-iop32x/include/mach/uncompress.h @@ -6,9 +6,8 @@ #include #include #include -#include -volatile u8 *uart_base; +#define uart_base ((volatile u8 *)0xfe800000) #define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE) @@ -23,17 +22,4 @@ static inline void flush(void) { } -static __inline__ void __arch_decomp_setup(unsigned long arch_id) -{ - if (machine_is_iq80321()) - uart_base = (volatile u8 *)IQ80321_UART; - else if (machine_is_iq31244() || machine_is_em7210()) - uart_base = (volatile u8 *)IQ31244_UART; - else - uart_base = (volatile u8 *)0xfe800000; -} - -/* - * nothing to do - */ -#define arch_decomp_setup() __arch_decomp_setup(arch_id) +#define arch_decomp_setup() do { } while (0) diff --git a/arch/arm/include/asm/hardware/iop3xx.h b/arch/arm/mach-iop32x/iop3xx.h similarity index 96% rename from arch/arm/include/asm/hardware/iop3xx.h rename to arch/arm/mach-iop32x/iop3xx.h index 3cb6f22f510bfa8352ffcada06576b60e24cda1a..46b4b34a4ad21d06c0591d860d1f2a093c71743c 100644 --- a/arch/arm/include/asm/hardware/iop3xx.h +++ b/arch/arm/mach-iop32x/iop3xx.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * arch/arm/include/asm/hardware/iop3xx.h - * * Intel IOP32X and IOP33X register definitions * * Author: Rory Bolt @@ -12,6 +10,22 @@ #ifndef __IOP3XX_H #define __IOP3XX_H +/* + * Peripherals that are shared between the iop32x and iop33x but + * located at different addresses. + */ +#define IOP3XX_TIMER_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07e0 + (reg)) + +#include "iop3xx.h" + +/* ATU Parameters + * set up a 1:1 bus to physical ram relationship + * w/ physical ram on top of pci in the memory map + */ +#define IOP32X_MAX_RAM_SIZE 0x40000000UL +#define IOP3XX_MAX_RAM_SIZE IOP32X_MAX_RAM_SIZE +#define IOP3XX_PCI_LOWER_MEM_BA 0x80000000 + /* * IOP3XX GPIO handling */ diff --git a/arch/arm/mach-iop32x/iq31244.c b/arch/arm/mach-iop32x/iq31244.c index 8755aa87e591ef6e76ad9bf3f3b351af7f61b024..04a7d389d365a1127d82f96f5cf3569ad8983e2b 100644 --- a/arch/arm/mach-iop32x/iq31244.c +++ b/arch/arm/mach-iop32x/iq31244.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -33,7 +32,9 @@ #include #include #include -#include + +#include "hardware.h" +#include "irqs.h" #include "gpio-iop32x.h" /* diff --git a/arch/arm/mach-iop32x/include/mach/iq31244.h b/arch/arm/mach-iop32x/iq31244.h similarity index 89% rename from arch/arm/mach-iop32x/include/mach/iq31244.h rename to arch/arm/mach-iop32x/iq31244.h index e62da5da6ed4078b706a182ebf6565d2e78206b0..a7ac691e48d3f071b100391ce2cd5774ec7a6e9d 100644 --- a/arch/arm/mach-iop32x/include/mach/iq31244.h +++ b/arch/arm/mach-iop32x/iq31244.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * arch/arm/mach-iop32x/include/mach/iq31244.h - * * Intel IQ31244 evaluation board registers */ diff --git a/arch/arm/mach-iop32x/iq80321.c b/arch/arm/mach-iop32x/iq80321.c index e12699d1c540364c7210ddf68a569eb847adb291..4bd596d6c9c13009e44891ddbed7a05f83bb8c45 100644 --- a/arch/arm/mach-iop32x/iq80321.c +++ b/arch/arm/mach-iop32x/iq80321.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -29,7 +28,9 @@ #include #include #include -#include + +#include "hardware.h" +#include "irqs.h" #include "gpio-iop32x.h" /* diff --git a/arch/arm/mach-iop32x/include/mach/iq80321.h b/arch/arm/mach-iop32x/iq80321.h similarity index 89% rename from arch/arm/mach-iop32x/include/mach/iq80321.h rename to arch/arm/mach-iop32x/iq80321.h index faf62c26f6f8758fed91376b97bbf73645573557..3a5d10626ea6fdaadb002ce47283207e3f0c17a8 100644 --- a/arch/arm/mach-iop32x/include/mach/iq80321.h +++ b/arch/arm/mach-iop32x/iq80321.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * arch/arm/mach-iop32x/include/mach/iq80321.h - * * Intel IQ80321 evaluation board registers */ diff --git a/arch/arm/mach-iop32x/irq.c b/arch/arm/mach-iop32x/irq.c index 2f5d4ec94f9c819a92c8769fffa73cf567680c38..2d48bf1398c10d26c41776b9dfa9d1d6bc505f29 100644 --- a/arch/arm/mach-iop32x/irq.c +++ b/arch/arm/mach-iop32x/irq.c @@ -13,9 +13,10 @@ #include #include #include -#include #include +#include "hardware.h" + static u32 iop32x_mask; static void intctl_write(u32 val) diff --git a/arch/arm/mach-iop32x/irqs.h b/arch/arm/mach-iop32x/irqs.h new file mode 100644 index 0000000000000000000000000000000000000000..69858e4e905d13d37beb484f80459bf3c76cfe6a --- /dev/null +++ b/arch/arm/mach-iop32x/irqs.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Author: Rory Bolt + * Copyright: (C) 2002 Rory Bolt + */ + +#ifndef __IOP32X_IRQS_H +#define __IOP32X_IRQS_H + +/* + * IOP80321 chipset interrupts + */ +#define IRQ_IOP32X_DMA0_EOT 0 +#define IRQ_IOP32X_DMA0_EOC 1 +#define IRQ_IOP32X_DMA1_EOT 2 +#define IRQ_IOP32X_DMA1_EOC 3 +#define IRQ_IOP32X_AA_EOT 6 +#define IRQ_IOP32X_AA_EOC 7 +#define IRQ_IOP32X_CORE_PMON 8 +#define IRQ_IOP32X_TIMER0 9 +#define IRQ_IOP32X_TIMER1 10 +#define IRQ_IOP32X_I2C_0 11 +#define IRQ_IOP32X_I2C_1 12 +#define IRQ_IOP32X_MESSAGING 13 +#define IRQ_IOP32X_ATU_BIST 14 +#define IRQ_IOP32X_PERFMON 15 +#define IRQ_IOP32X_CORE_PMU 16 +#define IRQ_IOP32X_BIU_ERR 17 +#define IRQ_IOP32X_ATU_ERR 18 +#define IRQ_IOP32X_MCU_ERR 19 +#define IRQ_IOP32X_DMA0_ERR 20 +#define IRQ_IOP32X_DMA1_ERR 21 +#define IRQ_IOP32X_AA_ERR 23 +#define IRQ_IOP32X_MSG_ERR 24 +#define IRQ_IOP32X_SSP 25 +#define IRQ_IOP32X_XINT0 27 +#define IRQ_IOP32X_XINT1 28 +#define IRQ_IOP32X_XINT2 29 +#define IRQ_IOP32X_XINT3 30 +#define IRQ_IOP32X_HPI 31 + +#endif diff --git a/arch/arm/mach-iop32x/n2100.c b/arch/arm/mach-iop32x/n2100.c index 26d76b377e799b36ddf783f58b4072f0673f5a83..5382a93ad0f8ce9e8f18ceb7b0497f5d10b59a0c 100644 --- a/arch/arm/mach-iop32x/n2100.c +++ b/arch/arm/mach-iop32x/n2100.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -37,7 +36,9 @@ #include #include #include -#include + +#include "hardware.h" +#include "irqs.h" #include "gpio-iop32x.h" /* diff --git a/arch/arm/mach-iop32x/include/mach/n2100.h b/arch/arm/mach-iop32x/n2100.h similarity index 89% rename from arch/arm/mach-iop32x/include/mach/n2100.h rename to arch/arm/mach-iop32x/n2100.h index 70bb660b643ab00929708cf271f54a3f15a480cd..0b97b940d3e76df345a71b6590c097ac00b4882c 100644 --- a/arch/arm/mach-iop32x/include/mach/n2100.h +++ b/arch/arm/mach-iop32x/n2100.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * arch/arm/mach-iop32x/include/mach/n2100.h - * * Thecus N2100 board registers */ diff --git a/arch/arm/plat-iop/pci.c b/arch/arm/mach-iop32x/pci.c similarity index 99% rename from arch/arm/plat-iop/pci.c rename to arch/arm/mach-iop32x/pci.c index 4c42c95e4bf53b0176ec020cfc7cf25a6dede6f8..ab0010dc314551e5640733ca8fdc7cddd9117fe0 100644 --- a/arch/arm/plat-iop/pci.c +++ b/arch/arm/mach-iop32x/pci.c @@ -17,9 +17,9 @@ #include #include #include -#include #include -#include +#include "hardware.h" +#include "iop3xx.h" // #define DEBUG diff --git a/arch/arm/plat-iop/pmu.c b/arch/arm/mach-iop32x/pmu.c similarity index 79% rename from arch/arm/plat-iop/pmu.c rename to arch/arm/mach-iop32x/pmu.c index 04c44a809b32f66814129c306b62c850552a9c73..bdbc7a3cb8a3141a91329bb426e83bacd9a672f0 100644 --- a/arch/arm/plat-iop/pmu.c +++ b/arch/arm/mach-iop32x/pmu.c @@ -5,17 +5,11 @@ */ #include -#include +#include "irqs.h" static struct resource pmu_resource = { -#ifdef CONFIG_ARCH_IOP32X .start = IRQ_IOP32X_CORE_PMU, .end = IRQ_IOP32X_CORE_PMU, -#endif -#ifdef CONFIG_ARCH_IOP33X - .start = IRQ_IOP33X_CORE_PMU, - .end = IRQ_IOP33X_CORE_PMU, -#endif .flags = IORESOURCE_IRQ, }; diff --git a/arch/arm/plat-iop/restart.c b/arch/arm/mach-iop32x/restart.c similarity index 82% rename from arch/arm/plat-iop/restart.c rename to arch/arm/mach-iop32x/restart.c index cf6d3d9a2112dc5aa5d1afae64f7666bbfe1f6f1..3dfa54d3a7a8a579bc00ba54cc4100ef278803e2 100644 --- a/arch/arm/plat-iop/restart.c +++ b/arch/arm/mach-iop32x/restart.c @@ -4,9 +4,9 @@ * * Copyright (C) 2001 MontaVista Software, Inc. */ -#include #include -#include +#include "hardware.h" +#include "iop3xx.h" void iop3xx_restart(enum reboot_mode mode, const char *cmd) { diff --git a/arch/arm/plat-iop/setup.c b/arch/arm/mach-iop32x/setup.c similarity index 95% rename from arch/arm/plat-iop/setup.c rename to arch/arm/mach-iop32x/setup.c index d10e0102d82c6aef53503ad20b54ffff8fdc32a9..a0a81c28a632bb583f26701186a146980d038b82 100644 --- a/arch/arm/plat-iop/setup.c +++ b/arch/arm/mach-iop32x/setup.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include "iop3xx.h" /* * Standard IO mapping for all IOP3xx based systems. Note that diff --git a/arch/arm/plat-iop/time.c b/arch/arm/mach-iop32x/time.c similarity index 97% rename from arch/arm/plat-iop/time.c rename to arch/arm/mach-iop32x/time.c index f9dd1f50cfe55fae42a7db869b03f469b620b4f4..18a4df5c1baa39d5c0e161c404217fa0b096fcce 100644 --- a/arch/arm/plat-iop/time.c +++ b/arch/arm/mach-iop32x/time.c @@ -19,12 +19,13 @@ #include #include #include -#include #include #include #include #include -#include + +#include "hardware.h" +#include "irqs.h" /* * Minimum clocksource/clockevent timer range in seconds @@ -167,7 +168,7 @@ void __init iop_init_time(unsigned long tick_rate) */ write_tmr0(timer_ctl & ~IOP_TMR_EN); write_tisr(1); - setup_irq(IRQ_IOP_TIMER0, &iop_timer_irq); + setup_irq(IRQ_IOP32X_TIMER0, &iop_timer_irq); iop_clockevent.cpumask = cpumask_of(0); clockevents_config_and_register(&iop_clockevent, tick_rate, 0xf, 0xfffffffe); diff --git a/arch/arm/mach-iop33x/Kconfig b/arch/arm/mach-iop33x/Kconfig deleted file mode 100644 index cd6069c7c56819a563648f50f2e63beefcb5b1ad..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop33x/Kconfig +++ /dev/null @@ -1,22 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -if ARCH_IOP33X - -menu "IOP33x Implementation Options" - -comment "IOP33x Platform Types" - -config ARCH_IQ80331 - bool "Enable support for IQ80331" - help - Say Y here if you want to run your kernel on the Intel IQ80331 - evaluation kit for the IOP331 chipset. - -config MACH_IQ80332 - bool "Enable support for IQ80332" - help - Say Y here if you want to run your kernel on the Intel IQ80332 - evaluation kit for the IOP332 chipset. - -endmenu - -endif diff --git a/arch/arm/mach-iop33x/Makefile b/arch/arm/mach-iop33x/Makefile deleted file mode 100644 index 320ecde1f9072437264594a1c0ca34a5d89c30b0..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop33x/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for the linux kernel. -# - -obj-y := irq.o uart.o - -obj-$(CONFIG_ARCH_IQ80331) += iq80331.o -obj-$(CONFIG_MACH_IQ80332) += iq80332.o diff --git a/arch/arm/mach-iop33x/Makefile.boot b/arch/arm/mach-iop33x/Makefile.boot deleted file mode 100644 index e4dd1d26038f0a0e042c89af0e6dd67e7b333add..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop33x/Makefile.boot +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only - zreladdr-y += 0x00008000 -params_phys-y := 0x00000100 -initrd_phys-y := 0x00800000 diff --git a/arch/arm/mach-iop33x/include/mach/adma.h b/arch/arm/mach-iop33x/include/mach/adma.h deleted file mode 100644 index 8aa7159ab6d856c04c67f6b894fdd361cfd59467..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop33x/include/mach/adma.h +++ /dev/null @@ -1,6 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef IOP33X_ADMA_H -#define IOP33X_ADMA_H -#include -#endif - diff --git a/arch/arm/mach-iop33x/include/mach/entry-macro.S b/arch/arm/mach-iop33x/include/mach/entry-macro.S deleted file mode 100644 index 0a398fe1fba4da25809b6a77548f9a319bbaff8e..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop33x/include/mach/entry-macro.S +++ /dev/null @@ -1,34 +0,0 @@ -/* - * arch/arm/mach-iop33x/include/mach/entry-macro.S - * - * Low-level IRQ helper macros for IOP33x-based platforms - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ -#include - - .macro get_irqnr_preamble, base, tmp - mrc p15, 0, \tmp, c15, c1, 0 - orr \tmp, \tmp, #(1 << 6) - mcr p15, 0, \tmp, c15, c1, 0 @ Enable cp6 access - mrc p15, 0, \tmp, c15, c1, 0 - mov \tmp, \tmp - sub pc, pc, #4 @ cp_wait - .endm - - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - mrc p6, 0, \irqstat, c14, c0, 0 @ Read IINTVEC - cmp \irqstat, #0 - mrceq p6, 0, \irqstat, c14, c0, 0 @ erratum 63 workaround - adds \irqnr, \irqstat, #1 - movne \irqnr, \irqstat, lsr #2 - .endm - - .macro arch_ret_to_user, tmp1, tmp2 - mrc p15, 0, \tmp1, c15, c1, 0 - ands \tmp2, \tmp1, #(1 << 6) - bicne \tmp1, \tmp1, #(1 << 6) - mcrne p15, 0, \tmp1, c15, c1, 0 @ Disable cp6 access - .endm diff --git a/arch/arm/mach-iop33x/include/mach/hardware.h b/arch/arm/mach-iop33x/include/mach/hardware.h deleted file mode 100644 index 020bafbc36a569f8efdf66cf3274ec480bc91cbb..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop33x/include/mach/hardware.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * arch/arm/mach-iop33x/include/mach/hardware.h - */ - -#ifndef __HARDWARE_H -#define __HARDWARE_H - -#include - -/* - * Note about PCI IO space mappings - * - * To make IO space accesses efficient, we store virtual addresses in - * the IO resources. - * - * The PCI IO space is located at virtual 0xfe000000 from physical - * 0x90000000. The PCI BARs must be programmed with physical addresses, - * but when we read them, we convert them to virtual addresses. See - * arch/arm/mach-iop3xx/iop3xx-pci.c - */ - -#ifndef __ASSEMBLY__ -void iop33x_init_irq(void); - -extern struct platform_device iop33x_uart0_device; -extern struct platform_device iop33x_uart1_device; -#endif - - -/* - * Generic chipset bits - * - */ -#include "iop33x.h" - -/* - * Board specific bits - */ -#include "iq80331.h" -#include "iq80332.h" - - -#endif diff --git a/arch/arm/mach-iop33x/include/mach/iop33x.h b/arch/arm/mach-iop33x/include/mach/iop33x.h deleted file mode 100644 index 0c7041ed7a60f5c0b3474d4d216cbb7aee8c3ab2..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop33x/include/mach/iop33x.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-iop33x/include/mach/iop33x.h - * - * Intel IOP33X Chip definitions - * - * Author: Dave Jiang (dave.jiang@intel.com) - * Copyright (C) 2003, 2004 Intel Corp. - */ - -#ifndef __IOP33X_H -#define __IOP33X_H - -/* - * Peripherals that are shared between the iop32x and iop33x but - * located at different addresses. - */ -#define IOP3XX_TIMER_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07d0 + (reg)) - -#include - -/* UARTs */ -#define IOP33X_UART0_PHYS (IOP3XX_PERIPHERAL_PHYS_BASE + 0x1700) -#define IOP33X_UART0_VIRT (IOP3XX_PERIPHERAL_VIRT_BASE + 0x1700) -#define IOP33X_UART1_PHYS (IOP3XX_PERIPHERAL_PHYS_BASE + 0x1740) -#define IOP33X_UART1_VIRT (IOP3XX_PERIPHERAL_VIRT_BASE + 0x1740) - -/* ATU Parameters - * set up a 1:1 bus to physical ram relationship - * w/ pci on top of physical ram in memory map - */ -#define IOP33X_MAX_RAM_SIZE 0x80000000UL -#define IOP3XX_MAX_RAM_SIZE IOP33X_MAX_RAM_SIZE -#define IOP3XX_PCI_LOWER_MEM_BA (PHYS_OFFSET + IOP33X_MAX_RAM_SIZE) - - -#endif diff --git a/arch/arm/mach-iop33x/include/mach/iq80331.h b/arch/arm/mach-iop33x/include/mach/iq80331.h deleted file mode 100644 index c7e68d863e44d4ef81302e985df5ec9dfd681699..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop33x/include/mach/iq80331.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * arch/arm/mach-iop33x/include/mach/iq80331.h - * - * Intel IQ80331 evaluation board registers - */ - -#ifndef __IQ80331_H -#define __IQ80331_H - -#define IQ80331_7SEG_1 0xce840000 /* 7-Segment MSB */ -#define IQ80331_7SEG_0 0xce850000 /* 7-Segment LSB (WO) */ -#define IQ80331_ROTARY_SW 0xce8d0000 /* Rotary Switch */ -#define IQ80331_BATT_STAT 0xce8f0000 /* Battery Status */ - - -#endif diff --git a/arch/arm/mach-iop33x/include/mach/iq80332.h b/arch/arm/mach-iop33x/include/mach/iq80332.h deleted file mode 100644 index 749b44bf7f62b2a9757ac080e87659d8a64e8d8f..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop33x/include/mach/iq80332.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * arch/arm/mach-iop33x/include/mach/iq80332.h - * - * Intel IQ80332 evaluation board registers - */ - -#ifndef __IQ80332_H -#define __IQ80332_H - -#define IQ80332_7SEG_1 0xce840000 /* 7-Segment MSB */ -#define IQ80332_7SEG_0 0xce850000 /* 7-Segment LSB (WO) */ -#define IQ80332_ROTARY_SW 0xce8d0000 /* Rotary Switch */ -#define IQ80332_BATT_STAT 0xce8f0000 /* Battery Status */ - - -#endif diff --git a/arch/arm/mach-iop33x/include/mach/irqs.h b/arch/arm/mach-iop33x/include/mach/irqs.h deleted file mode 100644 index cc3dce0ad4a115c08103558b22eae72e7406d277..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop33x/include/mach/irqs.h +++ /dev/null @@ -1,57 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-iop33x/include/mach/irqs.h - * - * Author: Dave Jiang (dave.jiang@intel.com) - * Copyright: (C) 2003 Intel Corp. - */ - -#ifndef __IRQS_H -#define __IRQS_H - -/* - * IOP80331 chipset interrupts - */ -#define IRQ_IOP33X_DMA0_EOT 0 -#define IRQ_IOP33X_DMA0_EOC 1 -#define IRQ_IOP33X_DMA1_EOT 2 -#define IRQ_IOP33X_DMA1_EOC 3 -#define IRQ_IOP33X_AA_EOT 6 -#define IRQ_IOP33X_AA_EOC 7 -#define IRQ_IOP33X_TIMER0 8 -#define IRQ_IOP33X_TIMER1 9 -#define IRQ_IOP33X_I2C_0 10 -#define IRQ_IOP33X_I2C_1 11 -#define IRQ_IOP33X_MSG 12 -#define IRQ_IOP33X_MSGIBQ 13 -#define IRQ_IOP33X_ATU_BIST 14 -#define IRQ_IOP33X_PERFMON 15 -#define IRQ_IOP33X_CORE_PMU 16 -#define IRQ_IOP33X_XINT0 24 -#define IRQ_IOP33X_XINT1 25 -#define IRQ_IOP33X_XINT2 26 -#define IRQ_IOP33X_XINT3 27 -#define IRQ_IOP33X_XINT8 32 -#define IRQ_IOP33X_XINT9 33 -#define IRQ_IOP33X_XINT10 34 -#define IRQ_IOP33X_XINT11 35 -#define IRQ_IOP33X_XINT12 36 -#define IRQ_IOP33X_XINT13 37 -#define IRQ_IOP33X_XINT14 38 -#define IRQ_IOP33X_XINT15 39 -#define IRQ_IOP33X_UART0 51 -#define IRQ_IOP33X_UART1 52 -#define IRQ_IOP33X_PBIE 53 -#define IRQ_IOP33X_ATU_CRW 54 -#define IRQ_IOP33X_ATU_ERR 55 -#define IRQ_IOP33X_MCU_ERR 56 -#define IRQ_IOP33X_DMA0_ERR 57 -#define IRQ_IOP33X_DMA1_ERR 58 -#define IRQ_IOP33X_AA_ERR 60 -#define IRQ_IOP33X_MSG_ERR 62 -#define IRQ_IOP33X_HPI 63 - -#define NR_IRQS 64 - - -#endif diff --git a/arch/arm/mach-iop33x/include/mach/time.h b/arch/arm/mach-iop33x/include/mach/time.h deleted file mode 100644 index 801f8fd644ad625738d7430d420ab5e6e835229b..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop33x/include/mach/time.h +++ /dev/null @@ -1,5 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _IOP33X_TIME_H_ -#define _IOP33X_TIME_H_ -#define IRQ_IOP_TIMER0 IRQ_IOP33X_TIMER0 -#endif diff --git a/arch/arm/mach-iop33x/include/mach/uncompress.h b/arch/arm/mach-iop33x/include/mach/uncompress.h deleted file mode 100644 index 62b71cde1f793155a6e37c8a94372a3c55c9d5eb..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop33x/include/mach/uncompress.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * arch/arm/mach-iop33x/include/mach/uncompress.h - */ - -#include -#include -#include -#include - -volatile u32 *uart_base; - -#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE) - -static inline void putc(char c) -{ - while ((uart_base[UART_LSR] & TX_DONE) != TX_DONE) - barrier(); - uart_base[UART_TX] = c; -} - -static inline void flush(void) -{ -} - -static __inline__ void __arch_decomp_setup(unsigned long arch_id) -{ - if (machine_is_iq80331() || machine_is_iq80332()) - uart_base = (volatile u32 *)IOP33X_UART0_PHYS; - else - uart_base = (volatile u32 *)0xfe800000; -} - -/* - * nothing to do - */ -#define arch_decomp_setup() __arch_decomp_setup(arch_id) diff --git a/arch/arm/mach-iop33x/iq80331.c b/arch/arm/mach-iop33x/iq80331.c deleted file mode 100644 index ab74fbabc7497ff21f58d5c546d35a8dca20a943..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop33x/iq80331.c +++ /dev/null @@ -1,148 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * arch/arm/mach-iop33x/iq80331.c - * - * Board support code for the Intel IQ80331 platform. - * - * Author: Dave Jiang - * Copyright (C) 2003 Intel Corp. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * IQ80331 timer tick configuration. - */ -static void __init iq80331_timer_init(void) -{ - /* D-Step parts run at a higher internal bus frequency */ - if (*IOP3XX_ATURID >= 0xa) - iop_init_time(333000000); - else - iop_init_time(266000000); -} - - -/* - * IQ80331 PCI. - */ -static int __init -iq80331_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ - int irq; - - if (slot == 1 && pin == 1) { - /* PCI-X Slot INTA */ - irq = IRQ_IOP33X_XINT1; - } else if (slot == 1 && pin == 2) { - /* PCI-X Slot INTB */ - irq = IRQ_IOP33X_XINT2; - } else if (slot == 1 && pin == 3) { - /* PCI-X Slot INTC */ - irq = IRQ_IOP33X_XINT3; - } else if (slot == 1 && pin == 4) { - /* PCI-X Slot INTD */ - irq = IRQ_IOP33X_XINT0; - } else if (slot == 2) { - /* GigE */ - irq = IRQ_IOP33X_XINT2; - } else { - printk(KERN_ERR "iq80331_pci_map_irq() called for unknown " - "device PCI:%d:%d:%d\n", dev->bus->number, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - irq = -1; - } - - return irq; -} - -static struct hw_pci iq80331_pci __initdata = { - .nr_controllers = 1, - .ops = &iop3xx_ops, - .setup = iop3xx_pci_setup, - .preinit = iop3xx_pci_preinit_cond, - .map_irq = iq80331_pci_map_irq, -}; - -static int __init iq80331_pci_init(void) -{ - if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) && - machine_is_iq80331()) - pci_common_init(&iq80331_pci); - - return 0; -} - -subsys_initcall(iq80331_pci_init); - - -/* - * IQ80331 machine initialisation. - */ -static struct physmap_flash_data iq80331_flash_data = { - .width = 1, -}; - -static struct resource iq80331_flash_resource = { - .start = 0xc0000000, - .end = 0xc07fffff, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device iq80331_flash_device = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &iq80331_flash_data, - }, - .num_resources = 1, - .resource = &iq80331_flash_resource, -}; - -static struct resource iq80331_gpio_res[] = { - DEFINE_RES_MEM((IOP3XX_PERIPHERAL_PHYS_BASE + 0x1780), 0x10), -}; - -static void __init iq80331_init_machine(void) -{ - platform_device_register_simple("gpio-iop", 0, - iq80331_gpio_res, - ARRAY_SIZE(iq80331_gpio_res)); - platform_device_register(&iop3xx_i2c0_device); - platform_device_register(&iop3xx_i2c1_device); - platform_device_register(&iop33x_uart0_device); - platform_device_register(&iop33x_uart1_device); - platform_device_register(&iq80331_flash_device); - platform_device_register(&iop3xx_dma_0_channel); - platform_device_register(&iop3xx_dma_1_channel); - platform_device_register(&iop3xx_aau_channel); -} - -MACHINE_START(IQ80331, "Intel IQ80331") - /* Maintainer: Intel Corp. */ - .atag_offset = 0x100, - .map_io = iop3xx_map_io, - .init_irq = iop33x_init_irq, - .init_time = iq80331_timer_init, - .init_machine = iq80331_init_machine, - .restart = iop3xx_restart, -MACHINE_END diff --git a/arch/arm/mach-iop33x/iq80332.c b/arch/arm/mach-iop33x/iq80332.c deleted file mode 100644 index 2e309b197aa4a580ce063b2ec4ec1839e63c8304..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop33x/iq80332.c +++ /dev/null @@ -1,148 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * arch/arm/mach-iop33x/iq80332.c - * - * Board support code for the Intel IQ80332 platform. - * - * Author: Dave Jiang - * Copyright (C) 2004 Intel Corp. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * IQ80332 timer tick configuration. - */ -static void __init iq80332_timer_init(void) -{ - /* D-Step parts and the iop333 run at a higher internal bus frequency */ - if (*IOP3XX_ATURID >= 0xa || *IOP3XX_ATUDID == 0x374) - iop_init_time(333000000); - else - iop_init_time(266000000); -} - - -/* - * IQ80332 PCI. - */ -static int __init -iq80332_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ - int irq; - - if (slot == 4 && pin == 1) { - /* PCI-X Slot INTA */ - irq = IRQ_IOP33X_XINT0; - } else if (slot == 4 && pin == 2) { - /* PCI-X Slot INTB */ - irq = IRQ_IOP33X_XINT1; - } else if (slot == 4 && pin == 3) { - /* PCI-X Slot INTC */ - irq = IRQ_IOP33X_XINT2; - } else if (slot == 4 && pin == 4) { - /* PCI-X Slot INTD */ - irq = IRQ_IOP33X_XINT3; - } else if (slot == 6) { - /* GigE */ - irq = IRQ_IOP33X_XINT2; - } else { - printk(KERN_ERR "iq80332_pci_map_irq() called for unknown " - "device PCI:%d:%d:%d\n", dev->bus->number, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - irq = -1; - } - - return irq; -} - -static struct hw_pci iq80332_pci __initdata = { - .nr_controllers = 1, - .ops = &iop3xx_ops, - .setup = iop3xx_pci_setup, - .preinit = iop3xx_pci_preinit_cond, - .map_irq = iq80332_pci_map_irq, -}; - -static int __init iq80332_pci_init(void) -{ - if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) && - machine_is_iq80332()) - pci_common_init(&iq80332_pci); - - return 0; -} - -subsys_initcall(iq80332_pci_init); - - -/* - * IQ80332 machine initialisation. - */ -static struct physmap_flash_data iq80332_flash_data = { - .width = 1, -}; - -static struct resource iq80332_flash_resource = { - .start = 0xc0000000, - .end = 0xc07fffff, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device iq80332_flash_device = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &iq80332_flash_data, - }, - .num_resources = 1, - .resource = &iq80332_flash_resource, -}; - -static struct resource iq80332_gpio_res[] = { - DEFINE_RES_MEM((IOP3XX_PERIPHERAL_PHYS_BASE + 0x1780), 0x10), -}; - -static void __init iq80332_init_machine(void) -{ - platform_device_register_simple("gpio-iop", 0, - iq80332_gpio_res, - ARRAY_SIZE(iq80332_gpio_res)); - platform_device_register(&iop3xx_i2c0_device); - platform_device_register(&iop3xx_i2c1_device); - platform_device_register(&iop33x_uart0_device); - platform_device_register(&iop33x_uart1_device); - platform_device_register(&iq80332_flash_device); - platform_device_register(&iop3xx_dma_0_channel); - platform_device_register(&iop3xx_dma_1_channel); - platform_device_register(&iop3xx_aau_channel); -} - -MACHINE_START(IQ80332, "Intel IQ80332") - /* Maintainer: Intel Corp. */ - .atag_offset = 0x100, - .map_io = iop3xx_map_io, - .init_irq = iop33x_init_irq, - .init_time = iq80332_timer_init, - .init_machine = iq80332_init_machine, - .restart = iop3xx_restart, -MACHINE_END diff --git a/arch/arm/mach-iop33x/irq.c b/arch/arm/mach-iop33x/irq.c deleted file mode 100644 index 03ad7d3a8f4953b1d5634225803a206f48356b59..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop33x/irq.c +++ /dev/null @@ -1,115 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * arch/arm/mach-iop33x/irq.c - * - * Generic IOP331 IRQ handling functionality - * - * Author: Dave Jiang - * Copyright (C) 2003 Intel Corp. - */ - -#include -#include -#include -#include -#include -#include -#include - -static u32 iop33x_mask0; -static u32 iop33x_mask1; - -static void intctl0_write(u32 val) -{ - asm volatile("mcr p6, 0, %0, c0, c0, 0" : : "r" (val)); -} - -static void intctl1_write(u32 val) -{ - asm volatile("mcr p6, 0, %0, c1, c0, 0" : : "r" (val)); -} - -static void intstr0_write(u32 val) -{ - asm volatile("mcr p6, 0, %0, c2, c0, 0" : : "r" (val)); -} - -static void intstr1_write(u32 val) -{ - asm volatile("mcr p6, 0, %0, c3, c0, 0" : : "r" (val)); -} - -static void intbase_write(u32 val) -{ - asm volatile("mcr p6, 0, %0, c12, c0, 0" : : "r" (val)); -} - -static void intsize_write(u32 val) -{ - asm volatile("mcr p6, 0, %0, c13, c0, 0" : : "r" (val)); -} - -static void -iop33x_irq_mask1 (struct irq_data *d) -{ - iop33x_mask0 &= ~(1 << d->irq); - intctl0_write(iop33x_mask0); -} - -static void -iop33x_irq_mask2 (struct irq_data *d) -{ - iop33x_mask1 &= ~(1 << (d->irq - 32)); - intctl1_write(iop33x_mask1); -} - -static void -iop33x_irq_unmask1(struct irq_data *d) -{ - iop33x_mask0 |= 1 << d->irq; - intctl0_write(iop33x_mask0); -} - -static void -iop33x_irq_unmask2(struct irq_data *d) -{ - iop33x_mask1 |= (1 << (d->irq - 32)); - intctl1_write(iop33x_mask1); -} - -struct irq_chip iop33x_irqchip1 = { - .name = "IOP33x-1", - .irq_ack = iop33x_irq_mask1, - .irq_mask = iop33x_irq_mask1, - .irq_unmask = iop33x_irq_unmask1, -}; - -struct irq_chip iop33x_irqchip2 = { - .name = "IOP33x-2", - .irq_ack = iop33x_irq_mask2, - .irq_mask = iop33x_irq_mask2, - .irq_unmask = iop33x_irq_unmask2, -}; - -void __init iop33x_init_irq(void) -{ - int i; - - iop_init_cp6_handler(); - - intctl0_write(0); - intctl1_write(0); - intstr0_write(0); - intstr1_write(0); - intbase_write(0); - intsize_write(1); - if (machine_is_iq80331()) - *IOP3XX_PCIIRSR = 0x0f; - - for (i = 0; i < NR_IRQS; i++) { - irq_set_chip_and_handler(i, - (i < 32) ? &iop33x_irqchip1 : &iop33x_irqchip2, - handle_level_irq); - irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE); - } -} diff --git a/arch/arm/mach-iop33x/uart.c b/arch/arm/mach-iop33x/uart.c deleted file mode 100644 index 8fa079d2e3c380f8f1d2b3bb0fec5124c0cc5a0e..0000000000000000000000000000000000000000 --- a/arch/arm/mach-iop33x/uart.c +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * arch/arm/mach-iop33x/uart.c - * - * Author: Dave Jiang (dave.jiang@intel.com) - * Copyright (C) 2004 Intel Corporation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define IOP33X_UART_XTAL 33334000 - -static struct plat_serial8250_port iop33x_uart0_data[] = { - { - .membase = (char *)IOP33X_UART0_VIRT, - .mapbase = IOP33X_UART0_PHYS, - .irq = IRQ_IOP33X_UART0, - .uartclk = IOP33X_UART_XTAL, - .regshift = 2, - .iotype = UPIO_MEM, - .flags = UPF_SKIP_TEST, - }, - { }, -}; - -static struct resource iop33x_uart0_resources[] = { - [0] = { - .start = IOP33X_UART0_PHYS, - .end = IOP33X_UART0_PHYS + 0x3f, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_IOP33X_UART0, - .end = IRQ_IOP33X_UART0, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device iop33x_uart0_device = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM, - .dev = { - .platform_data = iop33x_uart0_data, - }, - .num_resources = 2, - .resource = iop33x_uart0_resources, -}; - - -static struct resource iop33x_uart1_resources[] = { - [0] = { - .start = IOP33X_UART1_PHYS, - .end = IOP33X_UART1_PHYS + 0x3f, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_IOP33X_UART1, - .end = IRQ_IOP33X_UART1, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct plat_serial8250_port iop33x_uart1_data[] = { - { - .membase = (char *)IOP33X_UART1_VIRT, - .mapbase = IOP33X_UART1_PHYS, - .irq = IRQ_IOP33X_UART1, - .uartclk = IOP33X_UART_XTAL, - .regshift = 2, - .iotype = UPIO_MEM, - .flags = UPF_SKIP_TEST, - }, - { }, -}; - -struct platform_device iop33x_uart1_device = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM1, - .dev = { - .platform_data = iop33x_uart1_data, - }, - .num_resources = 2, - .resource = iop33x_uart1_resources, -}; diff --git a/arch/arm/mach-ks8695/Kconfig b/arch/arm/mach-ks8695/Kconfig deleted file mode 100644 index 724d7d039f741a0020ceadc9de905ec9852f426f..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/Kconfig +++ /dev/null @@ -1,88 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -if ARCH_KS8695 - -menu "Kendin/Micrel KS8695 Implementations" - -config MACH_KS8695 - bool "KS8695 development board" - select HAVE_PCI - help - Say 'Y' here if you want your kernel to run on the original - Kendin-Micrel KS8695 development board. - -config MACH_DSM320 - bool "DSM-320 Wireless Media Player" - help - Say 'Y' here if you want your kernel to run on the D-Link - DSM-320 Wireless Media Player. - -config MACH_ACS5K - bool "Brivo Systems LLC, ACS-5000 Master board" - help - say 'Y' here if you want your kernel to run on the Brivo - Systems LLC, ACS-5000 Master board. - -config MACH_LITE300 - bool "SecureComputing SG300" - help - Say 'Y' here if you want your kernel to support the - SecureComputing / SnapGear SG300 VPN Internet Router. - See http://www.securecomputing.com for more details. - -config MACH_SG310 - bool "McAfee SG310" - help - Say 'Y' here if you want your kernel to support the - McAfee / SnapGear SG310 VPN Internet Router. - See http://www.mcafee.com for more details. - -config MACH_SE4200 - bool "SecureComputing SE4200" - help - Say 'Y' here if you want your kernel to support the - SecureComputing / SnapGear SE4200 Secure Wireless VPN - Internet Router. - See http://www.securecomputing.com for more details. - -config MACH_CM4002 - bool "OpenGear CM4002" - help - Say 'Y' here if you want your kernel to support the OpenGear - CM4002 Secure Access Server. See http://www.opengear.com for - more details. - -config MACH_CM4008 - bool "OpenGear CM4008" - select HAVE_PCI - help - Say 'Y' here if you want your kernel to support the OpenGear - CM4008 Console Server. See http://www.opengear.com for more - details. - -config MACH_CM41xx - bool "OpenGear CM41xx" - select HAVE_PCI - help - Say 'Y' here if you want your kernel to support the OpenGear - CM4016 or CM4048 Console Servers. See http://www.opengear.com for - more details. - -config MACH_IM4004 - bool "OpenGear IM4004" - select HAVE_PCI - help - Say 'Y' here if you want your kernel to support the OpenGear - IM4004 Secure Access Server. See http://www.opengear.com for - more details. - -config MACH_IM42xx - bool "OpenGear IM42xx" - select HAVE_PCI - help - Say 'Y' here if you want your kernel to support the OpenGear - IM4216 or IM4248 Console Servers. See http://www.opengear.com for - more details. - -endmenu - -endif diff --git a/arch/arm/mach-ks8695/Makefile b/arch/arm/mach-ks8695/Makefile deleted file mode 100644 index 439b22255a3274a9967039b0a186b485d363c0ff..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# arch/arm/mach-ks8695/Makefile -# -# Makefile for KS8695 architecture support -# - -obj-y := cpu.o irq.o time.o devices.o - -# PCI support is optional -obj-$(CONFIG_PCI) += pci.o - -# Board-specific support -obj-$(CONFIG_MACH_KS8695) += board-micrel.o -obj-$(CONFIG_MACH_DSM320) += board-dsm320.o -obj-$(CONFIG_MACH_ACS5K) += board-acs5k.o -obj-$(CONFIG_MACH_LITE300) += board-sg.o -obj-$(CONFIG_MACH_SG310) += board-sg.o -obj-$(CONFIG_MACH_SE4200) += board-sg.o -obj-$(CONFIG_MACH_CM4002) += board-og.o -obj-$(CONFIG_MACH_CM4008) += board-og.o -obj-$(CONFIG_MACH_CM41xx) += board-og.o -obj-$(CONFIG_MACH_IM4004) += board-og.o -obj-$(CONFIG_MACH_IM42xx) += board-og.o diff --git a/arch/arm/mach-ks8695/Makefile.boot b/arch/arm/mach-ks8695/Makefile.boot deleted file mode 100644 index cf32eb605bd8b5303c0cc5a01246edb4f619b221..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/Makefile.boot +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# Note: the following conditions must always be true: -# ZRELADDR == virt_to_phys(TEXTADDR) -# PARAMS_PHYS must be within 4MB of ZRELADDR -# INITRD_PHYS must be in RAM - - zreladdr-y += 0x00008000 -params_phys-y := 0x00000100 -initrd_phys-y := 0x00800000 diff --git a/arch/arm/mach-ks8695/board-acs5k.c b/arch/arm/mach-ks8695/board-acs5k.c deleted file mode 100644 index f319258d1226d76633bc0145a943bfc630feeaf1..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/board-acs5k.c +++ /dev/null @@ -1,238 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * arch/arm/mach-ks8695/board-acs5k.c - * - * Brivo Systems LLC, ACS-5000 Master Board - * - * Copyright 2008 Simtec Electronics - * Daniel Silverstone - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "devices.h" -#include - -#include "generic.h" - -static struct gpiod_lookup_table acs5k_i2c_gpiod_table = { - .dev_id = "i2c-gpio", - .table = { - GPIO_LOOKUP_IDX("KS8695", 4, NULL, 0, - GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), - GPIO_LOOKUP_IDX("KS8695", 5, NULL, 1, - GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), - }, -}; - -static struct i2c_gpio_platform_data acs5k_i2c_device_platdata = { - .udelay = 10, -}; - -static struct platform_device acs5k_i2c_device = { - .name = "i2c-gpio", - .id = -1, - .num_resources = 0, - .resource = NULL, - .dev = { - .platform_data = &acs5k_i2c_device_platdata, - }, -}; - -static int acs5k_pca9555_setup(struct i2c_client *client, - unsigned gpio_base, unsigned ngpio, - void *context) -{ - static int acs5k_gpio_value[] = { - -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, -1, 0, 1, 0, -1, -1 - }; - int n; - - for (n = 0; n < ARRAY_SIZE(acs5k_gpio_value); ++n) { - gpio_request(gpio_base + n, "ACS-5000 GPIO Expander"); - if (acs5k_gpio_value[n] < 0) - gpio_direction_input(gpio_base + n); - else - gpio_direction_output(gpio_base + n, - acs5k_gpio_value[n]); - gpio_export(gpio_base + n, 0); /* Export, direction locked down */ - } - - return 0; -} - -static struct pca953x_platform_data acs5k_i2c_pca9555_platdata = { - .gpio_base = 16, /* Start directly after the CPU's GPIO */ - .invert = 0, /* Do not invert */ - .setup = acs5k_pca9555_setup, -}; - -static struct i2c_board_info acs5k_i2c_devs[] __initdata = { - { - I2C_BOARD_INFO("pcf8563", 0x51), - }, - { - I2C_BOARD_INFO("pca9555", 0x20), - .platform_data = &acs5k_i2c_pca9555_platdata, - }, -}; - -static void __init acs5k_i2c_init(void) -{ - /* The gpio interface */ - gpiod_add_lookup_table(&acs5k_i2c_gpiod_table); - platform_device_register(&acs5k_i2c_device); - /* I2C devices */ - i2c_register_board_info(0, acs5k_i2c_devs, - ARRAY_SIZE(acs5k_i2c_devs)); -} - -static struct mtd_partition acs5k_nor_partitions[] = { - [0] = { - .name = "Boot Agent and config", - .size = SZ_256K, - .offset = 0, - .mask_flags = MTD_WRITEABLE, - }, - [1] = { - .name = "Kernel", - .size = SZ_1M, - .offset = SZ_256K, - }, - [2] = { - .name = "SquashFS1", - .size = SZ_2M, - .offset = SZ_256K + SZ_1M, - }, - [3] = { - .name = "SquashFS2", - .size = SZ_4M + SZ_2M, - .offset = SZ_256K + SZ_1M + SZ_2M, - }, - [4] = { - .name = "Data", - .size = SZ_16M + SZ_4M + SZ_2M + SZ_512K, /* 22.5 MB */ - .offset = SZ_256K + SZ_8M + SZ_1M, - } -}; - -static struct physmap_flash_data acs5k_nor_pdata = { - .width = 4, - .nr_parts = ARRAY_SIZE(acs5k_nor_partitions), - .parts = acs5k_nor_partitions, -}; - -static struct resource acs5k_nor_resource[] = { - [0] = { - .start = SZ_32M, /* We expect the bootloader to map - * the flash here. - */ - .end = SZ_32M + SZ_16M - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = SZ_32M + SZ_16M, - .end = SZ_32M + SZ_32M - SZ_256K - 1, - .flags = IORESOURCE_MEM, - } -}; - -static struct platform_device acs5k_device_nor = { - .name = "physmap-flash", - .id = -1, - .num_resources = ARRAY_SIZE(acs5k_nor_resource), - .resource = acs5k_nor_resource, - .dev = { - .platform_data = &acs5k_nor_pdata, - }, -}; - -static void __init acs5k_register_nor(void) -{ - int ret; - - if (acs5k_nor_partitions[0].mask_flags == 0) - printk(KERN_WARNING "Warning: Unprotecting bootloader and configuration partition\n"); - - ret = platform_device_register(&acs5k_device_nor); - if (ret < 0) - printk(KERN_ERR "failed to register physmap-flash device\n"); -} - -static int __init acs5k_protection_setup(char *s) -{ - /* We can't allocate anything here but we should be able - * to trivially parse s and decide if we can protect the - * bootloader partition or not - */ - if (strcmp(s, "no") == 0) - acs5k_nor_partitions[0].mask_flags = 0; - - return 1; -} - -__setup("protect_bootloader=", acs5k_protection_setup); - -static void __init acs5k_init_gpio(void) -{ - int i; - - ks8695_register_gpios(); - for (i = 0; i < 4; ++i) - gpio_request(i, "ACS5K IRQ"); - gpio_request(7, "ACS5K KS_FRDY"); - for (i = 8; i < 16; ++i) - gpio_request(i, "ACS5K Unused"); - - gpio_request(3, "ACS5K CAN Control"); - gpio_request(6, "ACS5K Heartbeat"); - gpio_direction_output(3, 1); /* Default CAN_RESET high */ - gpio_direction_output(6, 0); /* Default KS8695_ACTIVE low */ - gpio_export(3, 0); /* export CAN_RESET as output only */ - gpio_export(6, 0); /* export KS8695_ACTIVE as output only */ -} - -static void __init acs5k_init(void) -{ - acs5k_init_gpio(); - - /* Network device */ - ks8695_add_device_lan(); /* eth0 = LAN */ - ks8695_add_device_wan(); /* ethX = WAN */ - - /* NOR devices */ - acs5k_register_nor(); - - /* I2C bus */ - acs5k_i2c_init(); -} - -MACHINE_START(ACS5K, "Brivo Systems LLC ACS-5000 Master board") - /* Maintainer: Simtec Electronics. */ - .atag_offset = 0x100, - .map_io = ks8695_map_io, - .init_irq = ks8695_init_irq, - .init_machine = acs5k_init, - .init_time = ks8695_timer_init, - .restart = ks8695_restart, -MACHINE_END diff --git a/arch/arm/mach-ks8695/board-dsm320.c b/arch/arm/mach-ks8695/board-dsm320.c deleted file mode 100644 index d5f435cae6e080480b599345cc6d758e8a7a9064..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/board-dsm320.c +++ /dev/null @@ -1,127 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * arch/arm/mach-ks8695/board-dsm320.c - * - * DSM-320 D-Link Wireless Media Player, board support. - * - * Copyright 2008 Simtec Electronics - * Daniel Silverstone - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "devices.h" -#include - -#include "generic.h" - -#ifdef CONFIG_PCI -static int dsm320_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ - switch (slot) { - case 0: - /* PCI-AHB bridge? */ - return KS8695_IRQ_EXTERN0; - case 18: - /* Mini PCI slot */ - return KS8695_IRQ_EXTERN2; - case 20: - /* RealMAGIC chip */ - return KS8695_IRQ_EXTERN0; - } - BUG(); -} - -static struct ks8695_pci_cfg __initdata dsm320_pci = { - .mode = KS8695_MODE_MINIPCI, - .map_irq = dsm320_pci_map_irq, -}; - -static void __init dsm320_register_pci(void) -{ - /* Initialise the GPIO lines for interrupt mode */ - /* RealMAGIC */ - ks8695_gpio_interrupt(KS8695_GPIO_0, IRQ_TYPE_LEVEL_LOW); - /* MiniPCI Slot */ - ks8695_gpio_interrupt(KS8695_GPIO_2, IRQ_TYPE_LEVEL_LOW); - - ks8695_init_pci(&dsm320_pci); -} - -#else -static inline void __init dsm320_register_pci(void) { } -#endif - -static struct physmap_flash_data dsm320_nor_pdata = { - .width = 4, - .nr_parts = 0, -}; - -static struct resource dsm320_nor_resource[] = { - [0] = { - .start = SZ_32M, /* We expect the bootloader to map - * the flash here. - */ - .end = SZ_32M + SZ_4M - 1, - .flags = IORESOURCE_MEM, - } -}; - -static struct platform_device dsm320_device_nor = { - .name = "physmap-flash", - .id = -1, - .num_resources = ARRAY_SIZE(dsm320_nor_resource), - .resource = dsm320_nor_resource, - .dev = { - .platform_data = &dsm320_nor_pdata, - }, -}; - -void __init dsm320_register_nor(void) -{ - int ret; - - ret = platform_device_register(&dsm320_device_nor); - if (ret < 0) - printk(KERN_ERR "failed to register physmap-flash device\n"); -} - -static void __init dsm320_init(void) -{ - /* GPIO registration */ - ks8695_register_gpios(); - - /* PCI registration */ - dsm320_register_pci(); - - /* Network device */ - ks8695_add_device_lan(); /* eth0 = LAN */ - - /* NOR devices */ - dsm320_register_nor(); -} - -MACHINE_START(DSM320, "D-Link DSM-320 Wireless Media Player") - /* Maintainer: Simtec Electronics. */ - .atag_offset = 0x100, - .map_io = ks8695_map_io, - .init_irq = ks8695_init_irq, - .init_machine = dsm320_init, - .init_time = ks8695_timer_init, - .restart = ks8695_restart, -MACHINE_END diff --git a/arch/arm/mach-ks8695/board-micrel.c b/arch/arm/mach-ks8695/board-micrel.c deleted file mode 100644 index bf8856ce3fbb600ed975a39d2773c97db3456152..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/board-micrel.c +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * arch/arm/mach-ks8695/board-micrel.c - */ -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include "devices.h" - -#include "generic.h" - -#ifdef CONFIG_PCI -static int micrel_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ - return KS8695_IRQ_EXTERN0; -} - -static struct ks8695_pci_cfg __initdata micrel_pci = { - .mode = KS8695_MODE_MINIPCI, - .map_irq = micrel_pci_map_irq, -}; -#endif - - -static void __init micrel_init(void) -{ - printk(KERN_INFO "Micrel KS8695 Development Board initializing\n"); - - ks8695_register_gpios(); - -#ifdef CONFIG_PCI - ks8695_init_pci(&micrel_pci); -#endif - - /* Add devices */ - ks8695_add_device_wan(); /* eth0 = WAN */ - ks8695_add_device_lan(); /* eth1 = LAN */ -} - -MACHINE_START(KS8695, "KS8695 Centaur Development Board") - /* Maintainer: Micrel Semiconductor Inc. */ - .atag_offset = 0x100, - .map_io = ks8695_map_io, - .init_irq = ks8695_init_irq, - .init_machine = micrel_init, - .init_time = ks8695_timer_init, - .restart = ks8695_restart, -MACHINE_END diff --git a/arch/arm/mach-ks8695/board-og.c b/arch/arm/mach-ks8695/board-og.c deleted file mode 100644 index 12ffe9227f9c3f6d0d89f25adbb4d334daed5741..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/board-og.c +++ /dev/null @@ -1,197 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * board-og.c -- support for the OpenGear KS8695 based boards. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "devices.h" -#include -#include -#include "generic.h" - -static int og_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ - if (machine_is_im4004() && (slot == 8)) - return KS8695_IRQ_EXTERN1; - return KS8695_IRQ_EXTERN0; -} - -static struct ks8695_pci_cfg __initdata og_pci = { - .mode = KS8695_MODE_PCI, - .map_irq = og_pci_map_irq, -}; - -static void __init og_register_pci(void) -{ - /* Initialize the GPIO lines for interrupt mode */ - ks8695_gpio_interrupt(KS8695_GPIO_0, IRQ_TYPE_LEVEL_LOW); - - /* Cardbus Slot */ - if (machine_is_im4004()) - ks8695_gpio_interrupt(KS8695_GPIO_1, IRQ_TYPE_LEVEL_LOW); - - if (IS_ENABLED(CONFIG_PCI)) - ks8695_init_pci(&og_pci); -} - -/* - * The PCI bus reset is driven by a dedicated GPIO line. Toggle it here - * and bring the PCI bus out of reset. - */ -static void __init og_pci_bus_reset(void) -{ - unsigned int rstline = 1; - - /* Some boards use a different GPIO as the PCI reset line */ - if (machine_is_im4004()) - rstline = 2; - else if (machine_is_im42xx()) - rstline = 0; - - gpio_request(rstline, "PCI reset"); - gpio_direction_output(rstline, 0); - - /* Drive a reset on the PCI reset line */ - gpio_set_value(rstline, 1); - gpio_set_value(rstline, 0); - mdelay(100); - gpio_set_value(rstline, 1); - mdelay(100); -} - -/* - * Direct connect serial ports (non-PCI that is). - */ -#define S8250_PHYS 0x03800000 -#define S8250_VIRT 0xf4000000 -#define S8250_SIZE 0x00100000 - -static struct map_desc og_io_desc[] __initdata = { - { - .virtual = S8250_VIRT, - .pfn = __phys_to_pfn(S8250_PHYS), - .length = S8250_SIZE, - .type = MT_DEVICE, - } -}; - -static struct resource og_uart_resources[] = { - { - .start = S8250_VIRT, - .end = S8250_VIRT + S8250_SIZE, - .flags = IORESOURCE_MEM - }, -}; - -static struct plat_serial8250_port og_uart_data[] = { - { - .mapbase = S8250_VIRT, - .membase = (char *) S8250_VIRT, - .irq = 3, - .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, - .iotype = UPIO_MEM, - .regshift = 2, - .uartclk = 115200 * 16, - }, - { }, -}; - -static struct platform_device og_uart = { - .name = "serial8250", - .id = 0, - .dev.platform_data = og_uart_data, - .num_resources = 1, - .resource = og_uart_resources -}; - -static struct platform_device *og_devices[] __initdata = { - &og_uart -}; - -static void __init og_init(void) -{ - ks8695_register_gpios(); - - if (machine_is_cm4002()) { - ks8695_gpio_interrupt(KS8695_GPIO_1, IRQ_TYPE_LEVEL_HIGH); - iotable_init(og_io_desc, ARRAY_SIZE(og_io_desc)); - platform_add_devices(og_devices, ARRAY_SIZE(og_devices)); - } else { - og_pci_bus_reset(); - og_register_pci(); - } - - ks8695_add_device_lan(); - ks8695_add_device_wan(); -} - -#ifdef CONFIG_MACH_CM4002 -MACHINE_START(CM4002, "OpenGear/CM4002") - /* OpenGear Inc. */ - .atag_offset = 0x100, - .map_io = ks8695_map_io, - .init_irq = ks8695_init_irq, - .init_machine = og_init, - .init_time = ks8695_timer_init, - .restart = ks8695_restart, -MACHINE_END -#endif - -#ifdef CONFIG_MACH_CM4008 -MACHINE_START(CM4008, "OpenGear/CM4008") - /* OpenGear Inc. */ - .atag_offset = 0x100, - .map_io = ks8695_map_io, - .init_irq = ks8695_init_irq, - .init_machine = og_init, - .init_time = ks8695_timer_init, - .restart = ks8695_restart, -MACHINE_END -#endif - -#ifdef CONFIG_MACH_CM41xx -MACHINE_START(CM41XX, "OpenGear/CM41xx") - /* OpenGear Inc. */ - .atag_offset = 0x100, - .map_io = ks8695_map_io, - .init_irq = ks8695_init_irq, - .init_machine = og_init, - .init_time = ks8695_timer_init, - .restart = ks8695_restart, -MACHINE_END -#endif - -#ifdef CONFIG_MACH_IM4004 -MACHINE_START(IM4004, "OpenGear/IM4004") - /* OpenGear Inc. */ - .atag_offset = 0x100, - .map_io = ks8695_map_io, - .init_irq = ks8695_init_irq, - .init_machine = og_init, - .init_time = ks8695_timer_init, - .restart = ks8695_restart, -MACHINE_END -#endif - -#ifdef CONFIG_MACH_IM42xx -MACHINE_START(IM42XX, "OpenGear/IM42xx") - /* OpenGear Inc. */ - .atag_offset = 0x100, - .map_io = ks8695_map_io, - .init_irq = ks8695_init_irq, - .init_machine = og_init, - .init_time = ks8695_timer_init, - .restart = ks8695_restart, -MACHINE_END -#endif diff --git a/arch/arm/mach-ks8695/board-sg.c b/arch/arm/mach-ks8695/board-sg.c deleted file mode 100644 index d5ec85a56375536fd7a46e805938911c870a69f3..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/board-sg.c +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * board-sg.c -- support for the SnapGear KS8695 based boards - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "devices.h" -#include "generic.h" - -/* - * The SG310 machine type is fitted with a conventional 8MB Strataflash - * device. Define its partitioning. - */ -#define FL_BASE 0x02000000 -#define FL_SIZE SZ_8M - -static struct mtd_partition sg_mtd_partitions[] = { - [0] = { - .name = "SnapGear Boot Loader", - .size = SZ_128K, - }, - [1] = { - .name = "SnapGear non-volatile configuration", - .size = SZ_512K, - .offset = SZ_256K, - }, - [2] = { - .name = "SnapGear image", - .offset = SZ_512K + SZ_256K, - }, - [3] = { - .name = "SnapGear StrataFlash", - }, - [4] = { - .name = "SnapGear Boot Tags", - .size = SZ_128K, - .offset = SZ_128K, - }, -}; - -static struct physmap_flash_data sg_mtd_pdata = { - .width = 1, - .nr_parts = ARRAY_SIZE(sg_mtd_partitions), - .parts = sg_mtd_partitions, -}; - - -static struct resource sg_mtd_resource[] = { - [0] = { - .start = FL_BASE, - .end = FL_BASE + FL_SIZE - 1, - .flags = IORESOURCE_MEM, - }, -}; - -static struct platform_device sg_mtd_device = { - .name = "physmap-flash", - .id = 0, - .num_resources = ARRAY_SIZE(sg_mtd_resource), - .resource = sg_mtd_resource, - .dev = { - .platform_data = &sg_mtd_pdata, - }, -}; - -static void __init sg_init(void) -{ - ks8695_add_device_lan(); - ks8695_add_device_wan(); - - if (machine_is_sg310()) - platform_device_register(&sg_mtd_device); -} - -#ifdef CONFIG_MACH_LITE300 -MACHINE_START(LITE300, "SecureComputing/SG300") - /* SnapGear */ - .atag_offset = 0x100, - .map_io = ks8695_map_io, - .init_irq = ks8695_init_irq, - .init_machine = sg_init, - .init_time = ks8695_timer_init, - .restart = ks8695_restart, -MACHINE_END -#endif - -#ifdef CONFIG_MACH_SG310 -MACHINE_START(SG310, "McAfee/SG310") - /* SnapGear */ - .atag_offset = 0x100, - .map_io = ks8695_map_io, - .init_irq = ks8695_init_irq, - .init_machine = sg_init, - .init_time = ks8695_timer_init, - .restart = ks8695_restart, -MACHINE_END -#endif - -#ifdef CONFIG_MACH_SE4200 -MACHINE_START(SE4200, "SecureComputing/SE4200") - /* SnapGear */ - .atag_offset = 0x100, - .map_io = ks8695_map_io, - .init_irq = ks8695_init_irq, - .init_machine = sg_init, - .init_time = ks8695_timer_init, - .restart = ks8695_restart, -MACHINE_END -#endif diff --git a/arch/arm/mach-ks8695/cpu.c b/arch/arm/mach-ks8695/cpu.c deleted file mode 100644 index aa6bb0c93aa8f8af80ccb02cdc971595d4e5c692..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/cpu.c +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * arch/arm/mach-ks8695/cpu.c - * - * Copyright (C) 2006 Ben Dooks - * Copyright (C) 2006 Simtec Electronics - * - * KS8695 CPU support - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include "regs-sys.h" -#include - - -static struct map_desc ks8695_io_desc[] __initdata = { - { - .virtual = (unsigned long)KS8695_IO_VA, - .pfn = __phys_to_pfn(KS8695_IO_PA), - .length = KS8695_IO_SIZE, - .type = MT_DEVICE, - } -}; - -static void __init ks8695_processor_info(void) -{ - unsigned long id, rev; - - id = __raw_readl(KS8695_MISC_VA + KS8695_DID); - rev = __raw_readl(KS8695_MISC_VA + KS8695_RID); - - printk("KS8695 ID=%04lx SubID=%02lx Revision=%02lx\n", (id & DID_ID), (rev & RID_SUBID), (rev & RID_REVISION)); -} - -static unsigned int sysclk[8] = { 125000000, 100000000, 62500000, 50000000, 41700000, 33300000, 31300000, 25000000 }; -static unsigned int cpuclk[8] = { 166000000, 166000000, 83000000, 83000000, 55300000, 55300000, 41500000, 41500000 }; - -static void __init ks8695_clock_info(void) -{ - unsigned int scdc = __raw_readl(KS8695_SYS_VA + KS8695_CLKCON) & CLKCON_SCDC; - - printk("Clocks: System %u MHz, CPU %u MHz\n", - sysclk[scdc] / 1000000, cpuclk[scdc] / 1000000); -} - -void __init ks8695_map_io(void) -{ - iotable_init(ks8695_io_desc, ARRAY_SIZE(ks8695_io_desc)); - - ks8695_processor_info(); - ks8695_clock_info(); -} diff --git a/arch/arm/mach-ks8695/devices.c b/arch/arm/mach-ks8695/devices.c deleted file mode 100644 index 61cf20beb45f67e9bae637ae878906b262288f54..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/devices.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * arch/arm/mach-ks8695/devices.c - * - * Copyright (C) 2006 Andrew Victor - * - * 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. - * - * 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 - */ - -#include -#include - -#include -#include - -#include -#include "regs-wan.h" -#include "regs-lan.h" -#include "regs-hpna.h" -#include -#include - - -/* -------------------------------------------------------------------- - * Ethernet - * -------------------------------------------------------------------- */ - -static u64 eth_dmamask = 0xffffffffUL; - -static struct resource ks8695_wan_resources[] = { - [0] = { - .start = KS8695_WAN_PA, - .end = KS8695_WAN_PA + 0x00ff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .name = "WAN RX", - .start = KS8695_IRQ_WAN_RX_STATUS, - .end = KS8695_IRQ_WAN_RX_STATUS, - .flags = IORESOURCE_IRQ, - }, - [2] = { - .name = "WAN TX", - .start = KS8695_IRQ_WAN_TX_STATUS, - .end = KS8695_IRQ_WAN_TX_STATUS, - .flags = IORESOURCE_IRQ, - }, - [3] = { - .name = "WAN Link", - .start = KS8695_IRQ_WAN_LINK, - .end = KS8695_IRQ_WAN_LINK, - .flags = IORESOURCE_IRQ, - }, - [4] = { - .name = "WAN PHY", - .start = KS8695_MISC_PA, - .end = KS8695_MISC_PA + 0x1f, - .flags = IORESOURCE_MEM, - }, -}; - -static struct platform_device ks8695_wan_device = { - .name = "ks8695_ether", - .id = 0, - .dev = { - .dma_mask = ð_dmamask, - .coherent_dma_mask = 0xffffffff, - }, - .resource = ks8695_wan_resources, - .num_resources = ARRAY_SIZE(ks8695_wan_resources), -}; - - -static struct resource ks8695_lan_resources[] = { - [0] = { - .start = KS8695_LAN_PA, - .end = KS8695_LAN_PA + 0x00ff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .name = "LAN RX", - .start = KS8695_IRQ_LAN_RX_STATUS, - .end = KS8695_IRQ_LAN_RX_STATUS, - .flags = IORESOURCE_IRQ, - }, - [2] = { - .name = "LAN TX", - .start = KS8695_IRQ_LAN_TX_STATUS, - .end = KS8695_IRQ_LAN_TX_STATUS, - .flags = IORESOURCE_IRQ, - }, - [3] = { - .name = "LAN SWITCH", - .start = KS8695_SWITCH_PA, - .end = KS8695_SWITCH_PA + 0x4f, - .flags = IORESOURCE_MEM, - }, -}; - -static struct platform_device ks8695_lan_device = { - .name = "ks8695_ether", - .id = 1, - .dev = { - .dma_mask = ð_dmamask, - .coherent_dma_mask = 0xffffffff, - }, - .resource = ks8695_lan_resources, - .num_resources = ARRAY_SIZE(ks8695_lan_resources), -}; - - -static struct resource ks8695_hpna_resources[] = { - [0] = { - .start = KS8695_HPNA_PA, - .end = KS8695_HPNA_PA + 0x00ff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .name = "HPNA RX", - .start = KS8695_IRQ_HPNA_RX_STATUS, - .end = KS8695_IRQ_HPNA_RX_STATUS, - .flags = IORESOURCE_IRQ, - }, - [2] = { - .name = "HPNA TX", - .start = KS8695_IRQ_HPNA_TX_STATUS, - .end = KS8695_IRQ_HPNA_TX_STATUS, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device ks8695_hpna_device = { - .name = "ks8695_ether", - .id = 2, - .dev = { - .dma_mask = ð_dmamask, - .coherent_dma_mask = 0xffffffff, - }, - .resource = ks8695_hpna_resources, - .num_resources = ARRAY_SIZE(ks8695_hpna_resources), -}; - -void __init ks8695_add_device_wan(void) -{ - platform_device_register(&ks8695_wan_device); -} - -void __init ks8695_add_device_lan(void) -{ - platform_device_register(&ks8695_lan_device); -} - -void __init ks8696_add_device_hpna(void) -{ - platform_device_register(&ks8695_hpna_device); -} - - -/* -------------------------------------------------------------------- - * Watchdog - * -------------------------------------------------------------------- */ - -static struct platform_device ks8695_wdt_device = { - .name = "ks8695_wdt", - .id = -1, - .num_resources = 0, -}; - -static void __init ks8695_add_device_watchdog(void) -{ - platform_device_register(&ks8695_wdt_device); -} - - -/* -------------------------------------------------------------------- */ - -/* - * These devices are always present and don't need any board-specific - * setup. - */ -static int __init ks8695_add_standard_devices(void) -{ - ks8695_add_device_watchdog(); - return 0; -} - -arch_initcall(ks8695_add_standard_devices); diff --git a/arch/arm/mach-ks8695/devices.h b/arch/arm/mach-ks8695/devices.h deleted file mode 100644 index cc23ee3820ea33f4b3e7ffac5c96ea9f9bc51188..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/devices.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-ks8695/include/mach/devices.h - * - * Copyright (C) 2006 Andrew Victor - */ - -#ifndef __ASM_ARCH_DEVICES_H -#define __ASM_ARCH_DEVICES_H - -#include - - /* Ethernet */ -extern void __init ks8695_add_device_wan(void); -extern void __init ks8695_add_device_lan(void); -extern void __init ks8695_add_device_hpna(void); - - /* PCI */ -#define KS8695_MODE_PCI 0 -#define KS8695_MODE_MINIPCI 1 -#define KS8695_MODE_CARDBUS 2 - -struct ks8695_pci_cfg { - short mode; - int (*map_irq)(const struct pci_dev *, u8, u8); -}; -extern __init void ks8695_init_pci(struct ks8695_pci_cfg *); - -#endif diff --git a/arch/arm/mach-ks8695/generic.h b/arch/arm/mach-ks8695/generic.h deleted file mode 100644 index 9e9cbdd436a9f965978c7d0ae64b9d9cafbc5cde..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/generic.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * arch/arm/mach-ks8695/generic.h - * - * Copyright (C) 2006 Ben Dooks - * Copyright (C) 2006 Simtec Electronics -*/ - -extern __init void ks8695_map_io(void); -extern __init void ks8695_init_irq(void); -extern void ks8695_restart(enum reboot_mode, const char *); -extern void ks8695_timer_init(void); diff --git a/arch/arm/mach-ks8695/include/mach/entry-macro.S b/arch/arm/mach-ks8695/include/mach/entry-macro.S deleted file mode 100644 index 7ff812cb010bb5e53f7cca7c1cb7552c1a2974a2..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/include/mach/entry-macro.S +++ /dev/null @@ -1,47 +0,0 @@ -/* - * arch/arm/mach-ks8695/include/mach/entry-macro.S - * - * Copyright (C) 2006 Ben Dooks - * Copyright (C) 2006 Simtec Electronics - * - * Low-level IRQ helper macros for KS8695 - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. -*/ - -#include -#include - - .macro get_irqnr_preamble, base, tmp - ldr \base, =KS8695_IRQ_VA @ Base address of interrupt controller - .endm - - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - ldr \irqstat, [\base, #KS8695_INTMS] @ Mask Status register - - teq \irqstat, #0 - beq 1001f - - mov \irqnr, #0 - - tst \irqstat, #0xff - moveq \irqstat, \irqstat, lsr #8 - addeq \irqnr, \irqnr, #8 - tsteq \irqstat, #0xff - moveq \irqstat, \irqstat, lsr #8 - addeq \irqnr, \irqnr, #8 - tsteq \irqstat, #0xff - moveq \irqstat, \irqstat, lsr #8 - addeq \irqnr, \irqnr, #8 - tst \irqstat, #0x0f - moveq \irqstat, \irqstat, lsr #4 - addeq \irqnr, \irqnr, #4 - tst \irqstat, #0x03 - moveq \irqstat, \irqstat, lsr #2 - addeq \irqnr, \irqnr, #2 - tst \irqstat, #0x01 - addseq \irqnr, \irqnr, #1 -1001: - .endm diff --git a/arch/arm/mach-ks8695/include/mach/gpio-ks8695.h b/arch/arm/mach-ks8695/include/mach/gpio-ks8695.h deleted file mode 100644 index 600115f48fb3ea9650834b5085d8e9e78aa43a76..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/include/mach/gpio-ks8695.h +++ /dev/null @@ -1,36 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2006 Andrew Victor - */ - -#ifndef __MACH_KS8659_GPIO_H -#define __MACH_KS8659_GPIO_H - -#include - -#define KS8695_GPIO_0 0 -#define KS8695_GPIO_1 1 -#define KS8695_GPIO_2 2 -#define KS8695_GPIO_3 3 -#define KS8695_GPIO_4 4 -#define KS8695_GPIO_5 5 -#define KS8695_GPIO_6 6 -#define KS8695_GPIO_7 7 -#define KS8695_GPIO_8 8 -#define KS8695_GPIO_9 9 -#define KS8695_GPIO_10 10 -#define KS8695_GPIO_11 11 -#define KS8695_GPIO_12 12 -#define KS8695_GPIO_13 13 -#define KS8695_GPIO_14 14 -#define KS8695_GPIO_15 15 - -/* - * Configure GPIO pin as external interrupt source. - */ -extern int ks8695_gpio_interrupt(unsigned int pin, unsigned int type); - -/* Register the GPIOs */ -extern void ks8695_register_gpios(void); - -#endif /* __MACH_KS8659_GPIO_H */ diff --git a/arch/arm/mach-ks8695/include/mach/hardware.h b/arch/arm/mach-ks8695/include/mach/hardware.h deleted file mode 100644 index 0fb889be8112c9959e8c0663d766617aebf02be0..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/include/mach/hardware.h +++ /dev/null @@ -1,42 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-ks8695/include/mach/hardware.h - * - * Copyright (C) 2006 Ben Dooks - * Copyright (C) 2006 Simtec Electronics - * - * KS8695 - Memory Map definitions -*/ - -#ifndef __ASM_ARCH_HARDWARE_H -#define __ASM_ARCH_HARDWARE_H - -#include - -/* - * Clocks are derived from MCLK, which is 25MHz - */ -#define KS8695_CLOCK_RATE 25000000 - -/* - * Physical RAM address. - */ -#define KS8695_SDRAM_PA 0x00000000 - - -/* - * We map an entire MiB with the System Configuration Registers in even - * though only 64KiB is needed. This makes it easier for use with the - * head debug code as the initial MMU setup only deals in L1 sections. - */ -#define KS8695_IO_PA 0x03F00000 -#define KS8695_IO_VA IOMEM(0xF0000000) -#define KS8695_IO_SIZE SZ_1M - -#define KS8695_PCIMEM_PA 0x60000000 -#define KS8695_PCIMEM_SIZE SZ_512M - -#define KS8695_PCIIO_PA 0x80000000 -#define KS8695_PCIIO_SIZE SZ_64K - -#endif diff --git a/arch/arm/mach-ks8695/include/mach/irqs.h b/arch/arm/mach-ks8695/include/mach/irqs.h deleted file mode 100644 index 0cbb30672427ca357d938e0b77457578558bd309..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/include/mach/irqs.h +++ /dev/null @@ -1,51 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-ks8695/include/mach/irqs.h - * - * Copyright (C) 2006 Simtec Electronics - * Ben Dooks - */ - -#ifndef __ASM_ARCH_IRQS_H -#define __ASM_ARCH_IRQS_H - - -#define NR_IRQS 32 - -/* - * IRQ definitions - */ -#define KS8695_IRQ_COMM_RX 0 -#define KS8695_IRQ_COMM_TX 1 -#define KS8695_IRQ_EXTERN0 2 -#define KS8695_IRQ_EXTERN1 3 -#define KS8695_IRQ_EXTERN2 4 -#define KS8695_IRQ_EXTERN3 5 -#define KS8695_IRQ_TIMER0 6 -#define KS8695_IRQ_TIMER1 7 -#define KS8695_IRQ_UART_TX 8 -#define KS8695_IRQ_UART_RX 9 -#define KS8695_IRQ_UART_LINE_STATUS 10 -#define KS8695_IRQ_UART_MODEM_STATUS 11 -#define KS8695_IRQ_LAN_RX_STOP 12 -#define KS8695_IRQ_LAN_TX_STOP 13 -#define KS8695_IRQ_LAN_RX_BUF 14 -#define KS8695_IRQ_LAN_TX_BUF 15 -#define KS8695_IRQ_LAN_RX_STATUS 16 -#define KS8695_IRQ_LAN_TX_STATUS 17 -#define KS8695_IRQ_HPNA_RX_STOP 18 -#define KS8695_IRQ_HPNA_TX_STOP 19 -#define KS8695_IRQ_HPNA_RX_BUF 20 -#define KS8695_IRQ_HPNA_TX_BUF 21 -#define KS8695_IRQ_HPNA_RX_STATUS 22 -#define KS8695_IRQ_HPNA_TX_STATUS 23 -#define KS8695_IRQ_BUS_ERROR 24 -#define KS8695_IRQ_WAN_RX_STOP 25 -#define KS8695_IRQ_WAN_TX_STOP 26 -#define KS8695_IRQ_WAN_RX_BUF 27 -#define KS8695_IRQ_WAN_TX_BUF 28 -#define KS8695_IRQ_WAN_RX_STATUS 29 -#define KS8695_IRQ_WAN_TX_STATUS 30 -#define KS8695_IRQ_WAN_LINK 31 - -#endif diff --git a/arch/arm/mach-ks8695/include/mach/memory.h b/arch/arm/mach-ks8695/include/mach/memory.h deleted file mode 100644 index ab0d27fa896935555622e0975e16dec4313a2817..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/include/mach/memory.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * arch/arm/mach-ks8695/include/mach/memory.h - * - * Copyright (C) 2006 Andrew Victor - * - * KS8695 Memory definitions - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef __ASM_ARCH_MEMORY_H -#define __ASM_ARCH_MEMORY_H - -#include - -#ifndef __ASSEMBLY__ - -#ifdef CONFIG_PCI - -/* PCI mappings */ -#define __virt_to_bus(x) ((x) - PAGE_OFFSET + KS8695_PCIMEM_PA) -#define __bus_to_virt(x) ((x) - KS8695_PCIMEM_PA + PAGE_OFFSET) - -/* Platform-bus mapping */ -extern struct bus_type platform_bus_type; -#define is_lbus_device(dev) (dev && dev->bus == &platform_bus_type) -#define __arch_dma_to_virt(dev, x) ({ (void *) (is_lbus_device(dev) ? \ - __phys_to_virt(x) : __bus_to_virt(x)); }) -#define __arch_virt_to_dma(dev, x) ({ is_lbus_device(dev) ? \ - (dma_addr_t)__virt_to_phys((unsigned long)x) \ - : (dma_addr_t)__virt_to_bus(x); }) -#define __arch_pfn_to_dma(dev, pfn) \ - ({ dma_addr_t __dma = __pfn_to_phys(pfn); \ - if (!is_lbus_device(dev)) \ - __dma = __dma - PHYS_OFFSET + KS8695_PCIMEM_PA; \ - __dma; }) - -#define __arch_dma_to_pfn(dev, x) \ - ({ dma_addr_t __dma = x; \ - if (!is_lbus_device(dev)) \ - __dma += PHYS_OFFSET - KS8695_PCIMEM_PA; \ - __phys_to_pfn(__dma); \ - }) - -#endif - -#endif - -#endif diff --git a/arch/arm/mach-ks8695/include/mach/regs-gpio.h b/arch/arm/mach-ks8695/include/mach/regs-gpio.h deleted file mode 100644 index 90614a7d05486a1e7fb785c5622041a24147446c..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/include/mach/regs-gpio.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * arch/arm/mach-ks8695/include/mach/regs-gpio.h - * - * Copyright (C) 2007 Andrew Victor - * - * KS8695 - GPIO control registers and bit definitions. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef KS8695_GPIO_H -#define KS8695_GPIO_H - -#define KS8695_GPIO_OFFSET (0xF0000 + 0xE600) -#define KS8695_GPIO_VA (KS8695_IO_VA + KS8695_GPIO_OFFSET) -#define KS8695_GPIO_PA (KS8695_IO_PA + KS8695_GPIO_OFFSET) - - -#define KS8695_IOPM (0x00) /* I/O Port Mode Register */ -#define KS8695_IOPC (0x04) /* I/O Port Control Register */ -#define KS8695_IOPD (0x08) /* I/O Port Data Register */ - - -/* Port Mode Register */ -#define IOPM(x) (1 << (x)) /* Mode for GPIO Pin x */ - -/* Port Control Register */ -#define IOPC_IOTIM1EN (1 << 17) /* GPIO Pin for Timer1 Enable */ -#define IOPC_IOTIM0EN (1 << 16) /* GPIO Pin for Timer0 Enable */ -#define IOPC_IOEINT3EN (1 << 15) /* GPIO Pin for External/Soft Interrupt 3 Enable */ -#define IOPC_IOEINT3TM (7 << 12) /* GPIO Pin for External/Soft Interrupt 3 Trigger Mode */ -#define IOPC_IOEINT3_MODE(x) ((x) << 12) -#define IOPC_IOEINT2EN (1 << 11) /* GPIO Pin for External/Soft Interrupt 2 Enable */ -#define IOPC_IOEINT2TM (7 << 8) /* GPIO Pin for External/Soft Interrupt 2 Trigger Mode */ -#define IOPC_IOEINT2_MODE(x) ((x) << 8) -#define IOPC_IOEINT1EN (1 << 7) /* GPIO Pin for External/Soft Interrupt 1 Enable */ -#define IOPC_IOEINT1TM (7 << 4) /* GPIO Pin for External/Soft Interrupt 1 Trigger Mode */ -#define IOPC_IOEINT1_MODE(x) ((x) << 4) -#define IOPC_IOEINT0EN (1 << 3) /* GPIO Pin for External/Soft Interrupt 0 Enable */ -#define IOPC_IOEINT0TM (7 << 0) /* GPIO Pin for External/Soft Interrupt 0 Trigger Mode */ -#define IOPC_IOEINT0_MODE(x) ((x) << 0) - - /* Trigger Modes */ -#define IOPC_TM_LOW (0) /* Level Detection (Active Low) */ -#define IOPC_TM_HIGH (1) /* Level Detection (Active High) */ -#define IOPC_TM_RISING (2) /* Rising Edge Detection */ -#define IOPC_TM_FALLING (4) /* Falling Edge Detection */ -#define IOPC_TM_EDGE (6) /* Both Edge Detection */ - -/* Port Data Register */ -#define IOPD(x) (1 << (x)) /* Signal Level of GPIO Pin x */ - -#endif diff --git a/arch/arm/mach-ks8695/include/mach/regs-irq.h b/arch/arm/mach-ks8695/include/mach/regs-irq.h deleted file mode 100644 index 352b7e8704d5fdedf4e203719d6f14d52c982ff4..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/include/mach/regs-irq.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * arch/arm/mach-ks8695/include/mach/regs-irq.h - * - * Copyright (C) 2006 Ben Dooks - * Copyright (C) 2006 Simtec Electronics - * - * KS8695 - IRQ registers and bit definitions - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef KS8695_IRQ_H -#define KS8695_IRQ_H - -#define KS8695_IRQ_OFFSET (0xF0000 + 0xE200) -#define KS8695_IRQ_VA (KS8695_IO_VA + KS8695_IRQ_OFFSET) -#define KS8695_IRQ_PA (KS8695_IO_PA + KS8695_IRQ_OFFSET) - - -/* - * Interrupt Controller registers - */ -#define KS8695_INTMC (0x00) /* Mode Control Register */ -#define KS8695_INTEN (0x04) /* Interrupt Enable Register */ -#define KS8695_INTST (0x08) /* Interrupt Status Register */ -#define KS8695_INTPW (0x0c) /* Interrupt Priority (WAN MAC) */ -#define KS8695_INTPH (0x10) /* Interrupt Priority (HPNA) [KS8695 only] */ -#define KS8695_INTPL (0x14) /* Interrupt Priority (LAN MAC) */ -#define KS8695_INTPT (0x18) /* Interrupt Priority (Timer) */ -#define KS8695_INTPU (0x1c) /* Interrupt Priority (UART) */ -#define KS8695_INTPE (0x20) /* Interrupt Priority (External Interrupt) */ -#define KS8695_INTPC (0x24) /* Interrupt Priority (Communications Channel) */ -#define KS8695_INTPBE (0x28) /* Interrupt Priority (Bus Error Response) */ -#define KS8695_INTMS (0x2c) /* Interrupt Mask Status Register */ -#define KS8695_INTHPF (0x30) /* Interrupt Pending Highest Priority (FIQ) */ -#define KS8695_INTHPI (0x34) /* Interrupt Pending Highest Priority (IRQ) */ - - -#endif diff --git a/arch/arm/mach-ks8695/include/mach/regs-misc.h b/arch/arm/mach-ks8695/include/mach/regs-misc.h deleted file mode 100644 index 2740c52494a0923554a0d6207510eca5841c1af9..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/include/mach/regs-misc.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * arch/arm/mach-ks8695/include/mach/regs-misc.h - * - * Copyright (C) 2006 Andrew Victor - * - * KS8695 - Miscellaneous Registers - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef KS8695_MISC_H -#define KS8695_MISC_H - -#define KS8695_MISC_OFFSET (0xF0000 + 0xEA00) -#define KS8695_MISC_VA (KS8695_IO_VA + KS8695_MISC_OFFSET) -#define KS8695_MISC_PA (KS8695_IO_PA + KS8695_MISC_OFFSET) - - -/* - * Miscellaneous registers - */ -#define KS8695_DID (0x00) /* Device ID */ -#define KS8695_RID (0x04) /* Revision ID */ -#define KS8695_HMC (0x08) /* HPNA Miscellaneous Control [KS8695 only] */ -#define KS8695_WMC (0x0c) /* WAN Miscellaneous Control */ -#define KS8695_WPPM (0x10) /* WAN PHY Power Management */ -#define KS8695_PPS (0x1c) /* PHY PowerSave */ - -/* Device ID Register */ -#define DID_ID (0xffff << 0) /* Device ID */ - -/* Revision ID Register */ -#define RID_SUBID (0xf << 4) /* Sub-Device ID */ -#define RID_REVISION (0xf << 0) /* Revision ID */ - -/* HPNA Miscellaneous Control Register */ -#define HMC_HSS (1 << 1) /* Speed */ -#define HMC_HDS (1 << 0) /* Duplex */ - -/* WAN Miscellaneous Control Register */ -#define WMC_WANC (1 << 30) /* Auto-negotiation complete */ -#define WMC_WANR (1 << 29) /* Auto-negotiation restart */ -#define WMC_WANAP (1 << 28) /* Advertise Pause */ -#define WMC_WANA100F (1 << 27) /* Advertise 100 FDX */ -#define WMC_WANA100H (1 << 26) /* Advertise 100 HDX */ -#define WMC_WANA10F (1 << 25) /* Advertise 10 FDX */ -#define WMC_WANA10H (1 << 24) /* Advertise 10 HDX */ -#define WMC_WLS (1 << 23) /* Link status */ -#define WMC_WDS (1 << 22) /* Duplex status */ -#define WMC_WSS (1 << 21) /* Speed status */ -#define WMC_WLPP (1 << 20) /* Link Partner Pause */ -#define WMC_WLP100F (1 << 19) /* Link Partner 100 FDX */ -#define WMC_WLP100H (1 << 18) /* Link Partner 100 HDX */ -#define WMC_WLP10F (1 << 17) /* Link Partner 10 FDX */ -#define WMC_WLP10H (1 << 16) /* Link Partner 10 HDX */ -#define WMC_WAND (1 << 15) /* Auto-negotiation disable */ -#define WMC_WANF100 (1 << 14) /* Force 100 */ -#define WMC_WANFF (1 << 13) /* Force FDX */ -#define WMC_WLED1S (7 << 4) /* LED1 Select */ -#define WLED1S_SPEED (0 << 4) -#define WLED1S_LINK (1 << 4) -#define WLED1S_DUPLEX (2 << 4) -#define WLED1S_COLLISION (3 << 4) -#define WLED1S_ACTIVITY (4 << 4) -#define WLED1S_FDX_COLLISION (5 << 4) -#define WLED1S_LINK_ACTIVITY (6 << 4) -#define WMC_WLED0S (7 << 0) /* LED0 Select */ -#define WLED0S_SPEED (0 << 0) -#define WLED0S_LINK (1 << 0) -#define WLED0S_DUPLEX (2 << 0) -#define WLED0S_COLLISION (3 << 0) -#define WLED0S_ACTIVITY (4 << 0) -#define WLED0S_FDX_COLLISION (5 << 0) -#define WLED0S_LINK_ACTIVITY (6 << 0) - -/* WAN PHY Power Management Register */ -#define WPPM_WLPBK (1 << 14) /* Local Loopback */ -#define WPPM_WRLPKB (1 << 13) /* Remove Loopback */ -#define WPPM_WPI (1 << 12) /* PHY isolate */ -#define WPPM_WFL (1 << 10) /* Force link */ -#define WPPM_MDIXS (1 << 9) /* MDIX Status */ -#define WPPM_FEF (1 << 8) /* Far End Fault */ -#define WPPM_AMDIXP (1 << 7) /* Auto MDIX Parameter */ -#define WPPM_TXDIS (1 << 6) /* Disable transmitter */ -#define WPPM_DFEF (1 << 5) /* Disable Far End Fault */ -#define WPPM_PD (1 << 4) /* Power Down */ -#define WPPM_DMDX (1 << 3) /* Disable Auto MDI/MDIX */ -#define WPPM_FMDX (1 << 2) /* Force MDIX */ -#define WPPM_LPBK (1 << 1) /* MAX Loopback */ - -/* PHY Power Save Register */ -#define PPS_PPSM (1 << 0) /* PHY Power Save Mode */ - - -#endif diff --git a/arch/arm/mach-ks8695/include/mach/regs-switch.h b/arch/arm/mach-ks8695/include/mach/regs-switch.h deleted file mode 100644 index 97e8acb1cf6c3137ff29a33bc5ee9205c7dfca75..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/include/mach/regs-switch.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * arch/arm/mach-ks8695/include/mach/regs-switch.h - * - * Copyright (C) 2006 Andrew Victor - * - * KS8695 - Switch Registers and bit definitions. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef KS8695_SWITCH_H -#define KS8695_SWITCH_H - -#define KS8695_SWITCH_OFFSET (0xF0000 + 0xe800) -#define KS8695_SWITCH_VA (KS8695_IO_VA + KS8695_SWITCH_OFFSET) -#define KS8695_SWITCH_PA (KS8695_IO_PA + KS8695_SWITCH_OFFSET) - - -/* - * Switch registers - */ -#define KS8695_SEC0 (0x00) /* Switch Engine Control 0 */ -#define KS8695_SEC1 (0x04) /* Switch Engine Control 1 */ -#define KS8695_SEC2 (0x08) /* Switch Engine Control 2 */ - -#define KS8695_SEPXCZ(x,z) (0x0c + (((x)-1)*3 + ((z)-1))*4) /* Port Configuration Registers */ - -#define KS8695_SEP12AN (0x48) /* Port 1 & 2 Auto-Negotiation */ -#define KS8695_SEP34AN (0x4c) /* Port 3 & 4 Auto-Negotiation */ -#define KS8695_SEIAC (0x50) /* Indirect Access Control */ -#define KS8695_SEIADH2 (0x54) /* Indirect Access Data High 2 */ -#define KS8695_SEIADH1 (0x58) /* Indirect Access Data High 1 */ -#define KS8695_SEIADL (0x5c) /* Indirect Access Data Low */ -#define KS8695_SEAFC (0x60) /* Advance Feature Control */ -#define KS8695_SEDSCPH (0x64) /* TOS Priority High */ -#define KS8695_SEDSCPL (0x68) /* TOS Priority Low */ -#define KS8695_SEMAH (0x6c) /* Switch Engine MAC Address High */ -#define KS8695_SEMAL (0x70) /* Switch Engine MAC Address Low */ -#define KS8695_LPPM12 (0x74) /* Port 1 & 2 PHY Power Management */ -#define KS8695_LPPM34 (0x78) /* Port 3 & 4 PHY Power Management */ - - -/* Switch Engine Control 0 */ -#define SEC0_LLED1S (7 << 25) /* LED1 Select */ -#define LLED1S_SPEED (0 << 25) -#define LLED1S_LINK (1 << 25) -#define LLED1S_DUPLEX (2 << 25) -#define LLED1S_COLLISION (3 << 25) -#define LLED1S_ACTIVITY (4 << 25) -#define LLED1S_FDX_COLLISION (5 << 25) -#define LLED1S_LINK_ACTIVITY (6 << 25) -#define SEC0_LLED0S (7 << 22) /* LED0 Select */ -#define LLED0S_SPEED (0 << 22) -#define LLED0S_LINK (1 << 22) -#define LLED0S_DUPLEX (2 << 22) -#define LLED0S_COLLISION (3 << 22) -#define LLED0S_ACTIVITY (4 << 22) -#define LLED0S_FDX_COLLISION (5 << 22) -#define LLED0S_LINK_ACTIVITY (6 << 22) -#define SEC0_ENABLE (1 << 0) /* Enable Switch */ - - - -#endif diff --git a/arch/arm/mach-ks8695/include/mach/regs-uart.h b/arch/arm/mach-ks8695/include/mach/regs-uart.h deleted file mode 100644 index 941a542c5f232875f8e58f5b7b908b5a45900287..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/include/mach/regs-uart.h +++ /dev/null @@ -1,89 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-ks8695/include/mach/regs-uart.h - * - * Copyright (C) 2006 Ben Dooks - * Copyright (C) 2006 Simtec Electronics - * - * KS8695 - UART register and bit definitions. - */ - -#ifndef KS8695_UART_H -#define KS8695_UART_H - -#define KS8695_UART_OFFSET (0xF0000 + 0xE000) -#define KS8695_UART_VA (KS8695_IO_VA + KS8695_UART_OFFSET) -#define KS8695_UART_PA (KS8695_IO_PA + KS8695_UART_OFFSET) - - -/* - * UART registers - */ -#define KS8695_URRB (0x00) /* Receive Buffer Register */ -#define KS8695_URTH (0x04) /* Transmit Holding Register */ -#define KS8695_URFC (0x08) /* FIFO Control Register */ -#define KS8695_URLC (0x0C) /* Line Control Register */ -#define KS8695_URMC (0x10) /* Modem Control Register */ -#define KS8695_URLS (0x14) /* Line Status Register */ -#define KS8695_URMS (0x18) /* Modem Status Register */ -#define KS8695_URBD (0x1C) /* Baud Rate Divisor Register */ -#define KS8695_USR (0x20) /* Status Register */ - - -/* FIFO Control Register */ -#define URFC_URFRT (3 << 6) /* Receive FIFO Trigger Level */ -#define URFC_URFRT_1 (0 << 6) -#define URFC_URFRT_4 (1 << 6) -#define URFC_URFRT_8 (2 << 6) -#define URFC_URFRT_14 (3 << 6) -#define URFC_URTFR (1 << 2) /* Transmit FIFO Reset */ -#define URFC_URRFR (1 << 1) /* Receive FIFO Reset */ -#define URFC_URFE (1 << 0) /* FIFO Enable */ - -/* Line Control Register */ -#define URLC_URSBC (1 << 6) /* Set Break Condition */ -#define URLC_PARITY (7 << 3) /* Parity */ -#define URPE_NONE (0 << 3) -#define URPE_ODD (1 << 3) -#define URPE_EVEN (3 << 3) -#define URPE_MARK (5 << 3) -#define URPE_SPACE (7 << 3) -#define URLC_URSB (1 << 2) /* Stop Bits */ -#define URLC_URCL (3 << 0) /* Character Length */ -#define URCL_5 (0 << 0) -#define URCL_6 (1 << 0) -#define URCL_7 (2 << 0) -#define URCL_8 (3 << 0) - -/* Modem Control Register */ -#define URMC_URLB (1 << 4) /* Loop-back mode */ -#define URMC_UROUT2 (1 << 3) /* OUT2 signal */ -#define URMC_UROUT1 (1 << 2) /* OUT1 signal */ -#define URMC_URRTS (1 << 1) /* Request to Send */ -#define URMC_URDTR (1 << 0) /* Data Terminal Ready */ - -/* Line Status Register */ -#define URLS_URRFE (1 << 7) /* Receive FIFO Error */ -#define URLS_URTE (1 << 6) /* Transmit Empty */ -#define URLS_URTHRE (1 << 5) /* Transmit Holding Register Empty */ -#define URLS_URBI (1 << 4) /* Break Interrupt */ -#define URLS_URFE (1 << 3) /* Framing Error */ -#define URLS_URPE (1 << 2) /* Parity Error */ -#define URLS_URROE (1 << 1) /* Receive Overrun Error */ -#define URLS_URDR (1 << 0) /* Receive Data Ready */ - -/* Modem Status Register */ -#define URMS_URDCD (1 << 7) /* Data Carrier Detect */ -#define URMS_URRI (1 << 6) /* Ring Indicator */ -#define URMS_URDSR (1 << 5) /* Data Set Ready */ -#define URMS_URCTS (1 << 4) /* Clear to Send */ -#define URMS_URDDCD (1 << 3) /* Delta Data Carrier Detect */ -#define URMS_URTERI (1 << 2) /* Trailing Edge Ring Indicator */ -#define URMS_URDDST (1 << 1) /* Delta Data Set Ready */ -#define URMS_URDCTS (1 << 0) /* Delta Clear to Send */ - -/* Status Register */ -#define USR_UTI (1 << 0) /* Timeout Indication */ - - -#endif diff --git a/arch/arm/mach-ks8695/include/mach/uncompress.h b/arch/arm/mach-ks8695/include/mach/uncompress.h deleted file mode 100644 index dc78a29759b55fc562d1a5f659dd49c3cd81062e..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/include/mach/uncompress.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-ks8695/include/mach/uncompress.h - * - * Copyright (C) 2006 Ben Dooks - * Copyright (C) 2006 Simtec Electronics - * - * KS8695 - Kernel uncompressor - */ - -#ifndef __ASM_ARCH_UNCOMPRESS_H -#define __ASM_ARCH_UNCOMPRESS_H - -#include -#include - -static inline void putc(char c) -{ - while (!(__raw_readl((void __iomem*)KS8695_UART_PA + KS8695_URLS) & URLS_URTHRE)) - barrier(); - - __raw_writel(c, (void __iomem*)KS8695_UART_PA + KS8695_URTH); -} - -static inline void flush(void) -{ - while (!(__raw_readl((void __iomem*)KS8695_UART_PA + KS8695_URLS) & URLS_URTE)) - barrier(); -} - -#define arch_decomp_setup() - -#endif diff --git a/arch/arm/mach-ks8695/irq.c b/arch/arm/mach-ks8695/irq.c deleted file mode 100644 index 4b7ec8d9300c3695bd6a89b3b0e053580d5d50c4..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/irq.c +++ /dev/null @@ -1,164 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * arch/arm/mach-ks8695/irq.c - * - * Copyright (C) 2006 Ben Dooks - * Copyright (C) 2006 Simtec Electronics - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include - -static void ks8695_irq_mask(struct irq_data *d) -{ - unsigned long inten; - - inten = __raw_readl(KS8695_IRQ_VA + KS8695_INTEN); - inten &= ~(1 << d->irq); - - __raw_writel(inten, KS8695_IRQ_VA + KS8695_INTEN); -} - -static void ks8695_irq_unmask(struct irq_data *d) -{ - unsigned long inten; - - inten = __raw_readl(KS8695_IRQ_VA + KS8695_INTEN); - inten |= (1 << d->irq); - - __raw_writel(inten, KS8695_IRQ_VA + KS8695_INTEN); -} - -static void ks8695_irq_ack(struct irq_data *d) -{ - __raw_writel((1 << d->irq), KS8695_IRQ_VA + KS8695_INTST); -} - - -static struct irq_chip ks8695_irq_level_chip; -static struct irq_chip ks8695_irq_edge_chip; - - -static int ks8695_irq_set_type(struct irq_data *d, unsigned int type) -{ - unsigned long ctrl, mode; - unsigned short level_triggered = 0; - - ctrl = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC); - - switch (type) { - case IRQ_TYPE_LEVEL_HIGH: - mode = IOPC_TM_HIGH; - level_triggered = 1; - break; - case IRQ_TYPE_LEVEL_LOW: - mode = IOPC_TM_LOW; - level_triggered = 1; - break; - case IRQ_TYPE_EDGE_RISING: - mode = IOPC_TM_RISING; - break; - case IRQ_TYPE_EDGE_FALLING: - mode = IOPC_TM_FALLING; - break; - case IRQ_TYPE_EDGE_BOTH: - mode = IOPC_TM_EDGE; - break; - default: - return -EINVAL; - } - - switch (d->irq) { - case KS8695_IRQ_EXTERN0: - ctrl &= ~IOPC_IOEINT0TM; - ctrl |= IOPC_IOEINT0_MODE(mode); - break; - case KS8695_IRQ_EXTERN1: - ctrl &= ~IOPC_IOEINT1TM; - ctrl |= IOPC_IOEINT1_MODE(mode); - break; - case KS8695_IRQ_EXTERN2: - ctrl &= ~IOPC_IOEINT2TM; - ctrl |= IOPC_IOEINT2_MODE(mode); - break; - case KS8695_IRQ_EXTERN3: - ctrl &= ~IOPC_IOEINT3TM; - ctrl |= IOPC_IOEINT3_MODE(mode); - break; - default: - return -EINVAL; - } - - if (level_triggered) { - irq_set_chip_and_handler(d->irq, &ks8695_irq_level_chip, - handle_level_irq); - } - else { - irq_set_chip_and_handler(d->irq, &ks8695_irq_edge_chip, - handle_edge_irq); - } - - __raw_writel(ctrl, KS8695_GPIO_VA + KS8695_IOPC); - return 0; -} - -static struct irq_chip ks8695_irq_level_chip = { - .irq_ack = ks8695_irq_mask, - .irq_mask = ks8695_irq_mask, - .irq_unmask = ks8695_irq_unmask, - .irq_set_type = ks8695_irq_set_type, -}; - -static struct irq_chip ks8695_irq_edge_chip = { - .irq_ack = ks8695_irq_ack, - .irq_mask = ks8695_irq_mask, - .irq_unmask = ks8695_irq_unmask, - .irq_set_type = ks8695_irq_set_type, -}; - -void __init ks8695_init_irq(void) -{ - unsigned int irq; - - /* Disable all interrupts initially */ - __raw_writel(0, KS8695_IRQ_VA + KS8695_INTMC); - __raw_writel(0, KS8695_IRQ_VA + KS8695_INTEN); - - for (irq = 0; irq < NR_IRQS; irq++) { - switch (irq) { - /* Level-triggered interrupts */ - case KS8695_IRQ_BUS_ERROR: - case KS8695_IRQ_UART_MODEM_STATUS: - case KS8695_IRQ_UART_LINE_STATUS: - case KS8695_IRQ_UART_RX: - case KS8695_IRQ_COMM_TX: - case KS8695_IRQ_COMM_RX: - irq_set_chip_and_handler(irq, - &ks8695_irq_level_chip, - handle_level_irq); - break; - - /* Edge-triggered interrupts */ - default: - /* clear pending bit */ - ks8695_irq_ack(irq_get_irq_data(irq)); - irq_set_chip_and_handler(irq, - &ks8695_irq_edge_chip, - handle_edge_irq); - } - - irq_clear_status_flags(irq, IRQ_NOREQUEST); - } -} diff --git a/arch/arm/mach-ks8695/pci.c b/arch/arm/mach-ks8695/pci.c deleted file mode 100644 index 83f330bf07ddbaef8400fb7babf7436b63864492..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/pci.c +++ /dev/null @@ -1,247 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * arch/arm/mach-ks8695/pci.c - * - * Copyright (C) 2003, Micrel Semiconductors - * Copyright (C) 2006, Greg Ungerer - * Copyright (C) 2006, Ben Dooks - * Copyright (C) 2007, Andrew Victor - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "devices.h" -#include "regs-pci.h" - - -static int pci_dbg; - -static void ks8695_pci_setupconfig(unsigned int bus_nr, unsigned int devfn, unsigned int where) -{ - unsigned long pbca; - - pbca = PBCA_ENABLE | (where & ~3); - pbca |= PCI_SLOT(devfn) << 11 ; - pbca |= PCI_FUNC(devfn) << 8; - pbca |= bus_nr << 16; - - if (bus_nr == 0) { - /* use Type-0 transaction */ - __raw_writel(pbca, KS8695_PCI_VA + KS8695_PBCA); - } else { - /* use Type-1 transaction */ - __raw_writel(pbca | PBCA_TYPE1, KS8695_PCI_VA + KS8695_PBCA); - } -} - -static void __iomem *ks8695_pci_map_bus(struct pci_bus *bus, unsigned int devfn, - int where) -{ - ks8695_pci_setupconfig(bus->number, devfn, where); - return KS8695_PCI_VA + KS8695_PBCD; -} - -static void ks8695_local_writeconfig(int where, u32 value) -{ - ks8695_pci_setupconfig(0, 0, where); - __raw_writel(value, KS8695_PCI_VA + KS8695_PBCD); -} - -static struct pci_ops ks8695_pci_ops = { - .map_bus = ks8695_pci_map_bus, - .read = pci_generic_config_read32, - .write = pci_generic_config_write32, -}; - -static struct resource pci_mem = { - .name = "PCI Memory space", - .start = KS8695_PCIMEM_PA, - .end = KS8695_PCIMEM_PA + (KS8695_PCIMEM_SIZE - 1), - .flags = IORESOURCE_MEM, -}; - -static struct resource pci_io = { - .name = "PCI IO space", - .start = KS8695_PCIIO_PA, - .end = KS8695_PCIIO_PA + (KS8695_PCIIO_SIZE - 1), - .flags = IORESOURCE_IO, -}; - -static int __init ks8695_pci_setup(int nr, struct pci_sys_data *sys) -{ - if (nr > 0) - return 0; - - request_resource(&iomem_resource, &pci_mem); - request_resource(&ioport_resource, &pci_io); - - pci_add_resource_offset(&sys->resources, &pci_io, sys->io_offset); - pci_add_resource_offset(&sys->resources, &pci_mem, sys->mem_offset); - - /* Assign and enable processor bridge */ - ks8695_local_writeconfig(PCI_BASE_ADDRESS_0, KS8695_PCIMEM_PA); - - /* Enable bus-master & Memory Space access */ - ks8695_local_writeconfig(PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); - - /* Set cache-line size & latency. */ - ks8695_local_writeconfig(PCI_CACHE_LINE_SIZE, (32 << 8) | (L1_CACHE_BYTES / sizeof(u32))); - - /* Reserve PCI memory space for PCI-AHB resources */ - if (!request_mem_region(KS8695_PCIMEM_PA, SZ_64M, "PCI-AHB Bridge")) { - printk(KERN_ERR "Cannot allocate PCI-AHB Bridge memory.\n"); - return -EBUSY; - } - - return 1; -} - -static inline unsigned int size_mask(unsigned long size) -{ - return (~size) + 1; -} - -static int ks8695_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) -{ - unsigned long pc = instruction_pointer(regs); - unsigned long instr = *(unsigned long *)pc; - unsigned long cmdstat; - - cmdstat = __raw_readl(KS8695_PCI_VA + KS8695_CRCFCS); - - printk(KERN_ERR "PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx [%s%s%s%s%s]\n", - addr, fsr, regs->ARM_pc, regs->ARM_lr, - cmdstat & (PCI_STATUS_SIG_TARGET_ABORT << 16) ? "GenTarget" : " ", - cmdstat & (PCI_STATUS_REC_TARGET_ABORT << 16) ? "RecvTarget" : " ", - cmdstat & (PCI_STATUS_REC_MASTER_ABORT << 16) ? "MasterAbort" : " ", - cmdstat & (PCI_STATUS_SIG_SYSTEM_ERROR << 16) ? "SysError" : " ", - cmdstat & (PCI_STATUS_DETECTED_PARITY << 16) ? "Parity" : " " - ); - - __raw_writel(cmdstat, KS8695_PCI_VA + KS8695_CRCFCS); - - /* - * If the instruction being executed was a read, - * make it look like it read all-ones. - */ - if ((instr & 0x0c100000) == 0x04100000) { - int reg = (instr >> 12) & 15; - unsigned long val; - - if (instr & 0x00400000) - val = 255; - else - val = -1; - - regs->uregs[reg] = val; - regs->ARM_pc += 4; - return 0; - } - - if ((instr & 0x0e100090) == 0x00100090) { - int reg = (instr >> 12) & 15; - - regs->uregs[reg] = -1; - regs->ARM_pc += 4; - return 0; - } - - return 1; -} - -static void __init ks8695_pci_preinit(void) -{ - /* make software reset to avoid freeze if PCI bus was messed up */ - __raw_writel(0x80000000, KS8695_PCI_VA + KS8695_PBCS); - - /* stage 1 initialization, subid, subdevice = 0x0001 */ - __raw_writel(0x00010001, KS8695_PCI_VA + KS8695_CRCSID); - - /* stage 2 initialization */ - /* prefetch limits with 16 words, retry enable */ - __raw_writel(0x40000000, KS8695_PCI_VA + KS8695_PBCS); - - /* configure memory mapping */ - __raw_writel(KS8695_PCIMEM_PA, KS8695_PCI_VA + KS8695_PMBA); - __raw_writel(size_mask(KS8695_PCIMEM_SIZE), KS8695_PCI_VA + KS8695_PMBAM); - __raw_writel(KS8695_PCIMEM_PA, KS8695_PCI_VA + KS8695_PMBAT); - __raw_writel(0, KS8695_PCI_VA + KS8695_PMBAC); - - /* configure IO mapping */ - __raw_writel(KS8695_PCIIO_PA, KS8695_PCI_VA + KS8695_PIOBA); - __raw_writel(size_mask(KS8695_PCIIO_SIZE), KS8695_PCI_VA + KS8695_PIOBAM); - __raw_writel(KS8695_PCIIO_PA, KS8695_PCI_VA + KS8695_PIOBAT); - __raw_writel(0, KS8695_PCI_VA + KS8695_PIOBAC); - - /* hook in fault handlers */ - hook_fault_code(8, ks8695_pci_fault, SIGBUS, 0, "external abort on non-linefetch"); - hook_fault_code(10, ks8695_pci_fault, SIGBUS, 0, "external abort on non-linefetch"); -} - -static void ks8695_show_pciregs(void) -{ - if (!pci_dbg) - return; - - printk(KERN_INFO "PCI: CRCFID = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCFID)); - printk(KERN_INFO "PCI: CRCFCS = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCFCS)); - printk(KERN_INFO "PCI: CRCFRV = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCFRV)); - printk(KERN_INFO "PCI: CRCFLT = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCFLT)); - printk(KERN_INFO "PCI: CRCBMA = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCBMA)); - printk(KERN_INFO "PCI: CRCSID = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCSID)); - printk(KERN_INFO "PCI: CRCFIT = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCFIT)); - - printk(KERN_INFO "PCI: PBM = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PBM)); - printk(KERN_INFO "PCI: PBCS = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PBCS)); - - printk(KERN_INFO "PCI: PMBA = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PMBA)); - printk(KERN_INFO "PCI: PMBAC = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PMBAC)); - printk(KERN_INFO "PCI: PMBAM = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PMBAM)); - printk(KERN_INFO "PCI: PMBAT = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PMBAT)); - - printk(KERN_INFO "PCI: PIOBA = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PIOBA)); - printk(KERN_INFO "PCI: PIOBAC = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PIOBAC)); - printk(KERN_INFO "PCI: PIOBAM = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PIOBAM)); - printk(KERN_INFO "PCI: PIOBAT = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PIOBAT)); -} - - -static struct hw_pci ks8695_pci __initdata = { - .nr_controllers = 1, - .ops = &ks8695_pci_ops, - .preinit = ks8695_pci_preinit, - .setup = ks8695_pci_setup, - .postinit = NULL, - .map_irq = NULL, -}; - -void __init ks8695_init_pci(struct ks8695_pci_cfg *cfg) -{ - if (__raw_readl(KS8695_PCI_VA + KS8695_CRCFRV) & CFRV_GUEST) { - printk("PCI: KS8695 in guest mode, not initialising\n"); - return; - } - - pcibios_min_io = 0; - pcibios_min_mem = 0; - - printk(KERN_INFO "PCI: Initialising\n"); - ks8695_show_pciregs(); - - /* set Mode */ - __raw_writel(cfg->mode << 29, KS8695_PCI_VA + KS8695_PBM); - - ks8695_pci.map_irq = cfg->map_irq; /* board-specific map_irq method */ - - pci_common_init(&ks8695_pci); -} diff --git a/arch/arm/mach-ks8695/regs-hpna.h b/arch/arm/mach-ks8695/regs-hpna.h deleted file mode 100644 index 815ce5c2e3b9b7afd6d62f9fed7d92186fab1c4e..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/regs-hpna.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * arch/arm/mach-ks8695/include/mach/regs-wan.h - * - * Copyright (C) 2006 Andrew Victor - * - * KS8695 - HPNA Registers and bit definitions. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef KS8695_HPNA_H -#define KS8695_HPNA_H - -#define KS8695_HPNA_OFFSET (0xF0000 + 0xA000) -#define KS8695_HPNA_VA (KS8695_IO_VA + KS8695_HPNA_OFFSET) -#define KS8695_HPNA_PA (KS8695_IO_PA + KS8695_HPNA_OFFSET) - - -/* - * HPNA registers - */ - -#endif diff --git a/arch/arm/mach-ks8695/regs-lan.h b/arch/arm/mach-ks8695/regs-lan.h deleted file mode 100644 index 82c5f3791afbc38dca37ce46056c1358ee2055d5..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/regs-lan.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * arch/arm/mach-ks8695/include/mach/regs-lan.h - * - * Copyright (C) 2006 Andrew Victor - * - * KS8695 - LAN Registers and bit definitions. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef KS8695_LAN_H -#define KS8695_LAN_H - -#define KS8695_LAN_OFFSET (0xF0000 + 0x8000) -#define KS8695_LAN_VA (KS8695_IO_VA + KS8695_LAN_OFFSET) -#define KS8695_LAN_PA (KS8695_IO_PA + KS8695_LAN_OFFSET) - - -/* - * LAN registers - */ -#define KS8695_LMDTXC (0x00) /* DMA Transmit Control */ -#define KS8695_LMDRXC (0x04) /* DMA Receive Control */ -#define KS8695_LMDTSC (0x08) /* DMA Transmit Start Command */ -#define KS8695_LMDRSC (0x0c) /* DMA Receive Start Command */ -#define KS8695_LTDLB (0x10) /* Transmit Descriptor List Base Address */ -#define KS8695_LRDLB (0x14) /* Receive Descriptor List Base Address */ -#define KS8695_LMAL (0x18) /* MAC Station Address Low */ -#define KS8695_LMAH (0x1c) /* MAC Station Address High */ -#define KS8695_LMAAL(n) (0x80 + ((n)*8)) /* MAC Additional Station Address (0..15) Low */ -#define KS8695_LMAAH(n) (0x84 + ((n)*8)) /* MAC Additional Station Address (0..15) High */ - - -/* DMA Transmit Control Register */ -#define LMDTXC_LMTRST (1 << 31) /* Soft Reset */ -#define LMDTXC_LMTBS (0x3f << 24) /* Transmit Burst Size */ -#define LMDTXC_LMTUCG (1 << 18) /* Transmit UDP Checksum Generate */ -#define LMDTXC_LMTTCG (1 << 17) /* Transmit TCP Checksum Generate */ -#define LMDTXC_LMTICG (1 << 16) /* Transmit IP Checksum Generate */ -#define LMDTXC_LMTFCE (1 << 9) /* Transmit Flow Control Enable */ -#define LMDTXC_LMTLB (1 << 8) /* Loopback mode */ -#define LMDTXC_LMTEP (1 << 2) /* Transmit Enable Padding */ -#define LMDTXC_LMTAC (1 << 1) /* Transmit Add CRC */ -#define LMDTXC_LMTE (1 << 0) /* TX Enable */ - -/* DMA Receive Control Register */ -#define LMDRXC_LMRBS (0x3f << 24) /* Receive Burst Size */ -#define LMDRXC_LMRUCC (1 << 18) /* Receive UDP Checksum check */ -#define LMDRXC_LMRTCG (1 << 17) /* Receive TCP Checksum check */ -#define LMDRXC_LMRICG (1 << 16) /* Receive IP Checksum check */ -#define LMDRXC_LMRFCE (1 << 9) /* Receive Flow Control Enable */ -#define LMDRXC_LMRB (1 << 6) /* Receive Broadcast */ -#define LMDRXC_LMRM (1 << 5) /* Receive Multicast */ -#define LMDRXC_LMRU (1 << 4) /* Receive Unicast */ -#define LMDRXC_LMRERR (1 << 3) /* Receive Error Frame */ -#define LMDRXC_LMRA (1 << 2) /* Receive All */ -#define LMDRXC_LMRE (1 << 1) /* RX Enable */ - -/* Additional Station Address High */ -#define LMAAH_E (1 << 31) /* Address Enabled */ - - -#endif diff --git a/arch/arm/mach-ks8695/regs-mem.h b/arch/arm/mach-ks8695/regs-mem.h deleted file mode 100644 index 55806bc68ce36c1d4dd7da09b7070a4aadd501c4..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/regs-mem.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * arch/arm/mach-ks8695/include/mach/regs-mem.h - * - * Copyright (C) 2006 Andrew Victor - * - * KS8695 - Memory Controller registers and bit definitions - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef KS8695_MEM_H -#define KS8695_MEM_H - -#define KS8695_MEM_OFFSET (0xF0000 + 0x4000) -#define KS8695_MEM_VA (KS8695_IO_VA + KS8695_MEM_OFFSET) -#define KS8695_MEM_PA (KS8695_IO_PA + KS8695_MEM_OFFSET) - - -/* - * Memory Controller Registers - */ -#define KS8695_EXTACON0 (0x00) /* External I/O 0 Access Control */ -#define KS8695_EXTACON1 (0x04) /* External I/O 1 Access Control */ -#define KS8695_EXTACON2 (0x08) /* External I/O 2 Access Control */ -#define KS8695_ROMCON0 (0x10) /* ROM/SRAM/Flash 1 Control Register */ -#define KS8695_ROMCON1 (0x14) /* ROM/SRAM/Flash 2 Control Register */ -#define KS8695_ERGCON (0x20) /* External I/O and ROM/SRAM/Flash General Register */ -#define KS8695_SDCON0 (0x30) /* SDRAM Control Register 0 */ -#define KS8695_SDCON1 (0x34) /* SDRAM Control Register 1 */ -#define KS8695_SDGCON (0x38) /* SDRAM General Control */ -#define KS8695_SDBCON (0x3c) /* SDRAM Buffer Control */ -#define KS8695_REFTIM (0x40) /* SDRAM Refresh Timer */ - - -/* External I/O Access Control Registers */ -#define EXTACON_EBNPTR (0x3ff << 22) /* Last Address Pointer */ -#define EXTACON_EBBPTR (0x3ff << 12) /* Base Pointer */ -#define EXTACON_EBTACT (7 << 9) /* Write Enable/Output Enable Active Time */ -#define EXTACON_EBTCOH (7 << 6) /* Chip Select Hold Time */ -#define EXTACON_EBTACS (7 << 3) /* Address Setup Time before ECSN */ -#define EXTACON_EBTCOS (7 << 0) /* Chip Select Time before OEN */ - -/* ROM/SRAM/Flash Control Register */ -#define ROMCON_RBNPTR (0x3ff << 22) /* Next Pointer */ -#define ROMCON_RBBPTR (0x3ff << 12) /* Base Pointer */ -#define ROMCON_RBTACC (7 << 4) /* Access Cycle Time */ -#define ROMCON_RBTPA (3 << 2) /* Page Address Access Time */ -#define ROMCON_PMC (3 << 0) /* Page Mode Configuration */ -#define PMC_NORMAL (0 << 0) -#define PMC_4WORD (1 << 0) -#define PMC_8WORD (2 << 0) -#define PMC_16WORD (3 << 0) - -/* External I/O and ROM/SRAM/Flash General Register */ -#define ERGCON_TMULT (3 << 28) /* Time Multiplier */ -#define ERGCON_DSX2 (3 << 20) /* Data Width (External I/O Bank 2) */ -#define ERGCON_DSX1 (3 << 18) /* Data Width (External I/O Bank 1) */ -#define ERGCON_DSX0 (3 << 16) /* Data Width (External I/O Bank 0) */ -#define ERGCON_DSR1 (3 << 2) /* Data Width (ROM/SRAM/Flash Bank 1) */ -#define ERGCON_DSR0 (3 << 0) /* Data Width (ROM/SRAM/Flash Bank 0) */ - -/* SDRAM Control Register */ -#define SDCON_DBNPTR (0x3ff << 22) /* Last Address Pointer */ -#define SDCON_DBBPTR (0x3ff << 12) /* Base Pointer */ -#define SDCON_DBCAB (3 << 8) /* Column Address Bits */ -#define SDCON_DBBNUM (1 << 3) /* Number of Banks */ -#define SDCON_DBDBW (3 << 1) /* Data Bus Width */ - -/* SDRAM General Control Register */ -#define SDGCON_SDTRC (3 << 2) /* RAS to CAS latency */ -#define SDGCON_SDCAS (3 << 0) /* CAS latency */ - -/* SDRAM Buffer Control Register */ -#define SDBCON_SDESTA (1 << 31) /* SDRAM Engine Status */ -#define SDBCON_RBUFBDIS (1 << 24) /* Read Buffer Burst Enable */ -#define SDBCON_WFIFOEN (1 << 23) /* Write FIFO Enable */ -#define SDBCON_RBUFEN (1 << 22) /* Read Buffer Enable */ -#define SDBCON_FLUSHWFIFO (1 << 21) /* Flush Write FIFO */ -#define SDBCON_RBUFINV (1 << 20) /* Read Buffer Invalidate */ -#define SDBCON_SDINI (3 << 16) /* SDRAM Initialization Control */ -#define SDBCON_SDMODE (0x3fff << 0) /* SDRAM Mode Register Value Program */ - -/* SDRAM Refresh Timer Register */ -#define REFTIM_REFTIM (0xffff << 0) /* Refresh Timer Value */ - - -#endif diff --git a/arch/arm/mach-ks8695/regs-pci.h b/arch/arm/mach-ks8695/regs-pci.h deleted file mode 100644 index 75a9db6edbd9663323b0cd080e1db212461a3e3b..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/regs-pci.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * arch/arm/mach-ks8695/include/mach/regs-pci.h - * - * Copyright (C) 2006 Ben Dooks - * Copyright (C) 2006 Simtec Electronics - * - * KS8695 - PCI bridge registers and bit definitions. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#define KS8695_PCI_OFFSET (0xF0000 + 0x2000) -#define KS8695_PCI_VA (KS8695_IO_VA + KS8695_PCI_OFFSET) -#define KS8695_PCI_PA (KS8695_IO_PA + KS8695_PCI_OFFSET) - - -#define KS8695_CRCFID (0x000) /* Configuration: Identification */ -#define KS8695_CRCFCS (0x004) /* Configuration: Command and Status */ -#define KS8695_CRCFRV (0x008) /* Configuration: Revision */ -#define KS8695_CRCFLT (0x00C) /* Configuration: Latency Timer */ -#define KS8695_CRCBMA (0x010) /* Configuration: Base Memory Address */ -#define KS8695_CRCSID (0x02C) /* Configuration: Subsystem ID */ -#define KS8695_CRCFIT (0x03C) /* Configuration: Interrupt */ -#define KS8695_PBCA (0x100) /* Bridge Configuration Address */ -#define KS8695_PBCD (0x104) /* Bridge Configuration Data */ -#define KS8695_PBM (0x200) /* Bridge Mode */ -#define KS8695_PBCS (0x204) /* Bridge Control and Status */ -#define KS8695_PMBA (0x208) /* Bridge Memory Base Address */ -#define KS8695_PMBAC (0x20C) /* Bridge Memory Base Address Control */ -#define KS8695_PMBAM (0x210) /* Bridge Memory Base Address Mask */ -#define KS8695_PMBAT (0x214) /* Bridge Memory Base Address Translation */ -#define KS8695_PIOBA (0x218) /* Bridge I/O Base Address */ -#define KS8695_PIOBAC (0x21C) /* Bridge I/O Base Address Control */ -#define KS8695_PIOBAM (0x220) /* Bridge I/O Base Address Mask */ -#define KS8695_PIOBAT (0x224) /* Bridge I/O Base Address Translation */ - - -/* Configuration: Identification */ - -/* Configuration: Command and Status */ - -/* Configuration: Revision */ - - - -#define CFRV_GUEST (1 << 23) - -#define PBCA_TYPE1 (1) -#define PBCA_ENABLE (1 << 31) - - diff --git a/arch/arm/mach-ks8695/regs-sys.h b/arch/arm/mach-ks8695/regs-sys.h deleted file mode 100644 index 57c20be0c129e85ec96121d8a564963924ee56a4..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/regs-sys.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * arch/arm/mach-ks8695/include/mach/regs-sys.h - * - * Copyright (C) 2006 Ben Dooks - * Copyright (C) 2006 Simtec Electronics - * - * KS8695 - System control registers and bit definitions - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef KS8695_SYS_H -#define KS8695_SYS_H - -#define KS8695_SYS_OFFSET (0xF0000 + 0x0000) -#define KS8695_SYS_VA (KS8695_IO_VA + KS8695_SYS_OFFSET) -#define KS8695_SYS_PA (KS8695_IO_PA + KS8695_SYS_OFFSET) - - -#define KS8695_SYSCFG (0x00) /* System Configuration Register */ -#define KS8695_CLKCON (0x04) /* System Clock and Bus Control Register */ - - -/* System Configuration Register */ -#define SYSCFG_SPRBP (0x3ff << 16) /* Register Bank Base Pointer */ - -/* System Clock and Bus Control Register */ -#define CLKCON_SFMODE (1 << 8) /* System Fast Mode for Simulation */ -#define CLKCON_SCDC (7 << 0) /* System Clock Divider Select */ - - -#endif diff --git a/arch/arm/mach-ks8695/regs-wan.h b/arch/arm/mach-ks8695/regs-wan.h deleted file mode 100644 index c475bed22b8ebceeaad05ebaf0de41cbf6547924..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/regs-wan.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * arch/arm/mach-ks8695/include/mach/regs-wan.h - * - * Copyright (C) 2006 Andrew Victor - * - * KS8695 - WAN Registers and bit definitions. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef KS8695_WAN_H -#define KS8695_WAN_H - -#define KS8695_WAN_OFFSET (0xF0000 + 0x6000) -#define KS8695_WAN_VA (KS8695_IO_VA + KS8695_WAN_OFFSET) -#define KS8695_WAN_PA (KS8695_IO_PA + KS8695_WAN_OFFSET) - - -/* - * WAN registers - */ -#define KS8695_WMDTXC (0x00) /* DMA Transmit Control */ -#define KS8695_WMDRXC (0x04) /* DMA Receive Control */ -#define KS8695_WMDTSC (0x08) /* DMA Transmit Start Command */ -#define KS8695_WMDRSC (0x0c) /* DMA Receive Start Command */ -#define KS8695_WTDLB (0x10) /* Transmit Descriptor List Base Address */ -#define KS8695_WRDLB (0x14) /* Receive Descriptor List Base Address */ -#define KS8695_WMAL (0x18) /* MAC Station Address Low */ -#define KS8695_WMAH (0x1c) /* MAC Station Address High */ -#define KS8695_WMAAL(n) (0x80 + ((n)*8)) /* MAC Additional Station Address (0..15) Low */ -#define KS8695_WMAAH(n) (0x84 + ((n)*8)) /* MAC Additional Station Address (0..15) High */ - - -/* DMA Transmit Control Register */ -#define WMDTXC_WMTRST (1 << 31) /* Soft Reset */ -#define WMDTXC_WMTBS (0x3f << 24) /* Transmit Burst Size */ -#define WMDTXC_WMTUCG (1 << 18) /* Transmit UDP Checksum Generate */ -#define WMDTXC_WMTTCG (1 << 17) /* Transmit TCP Checksum Generate */ -#define WMDTXC_WMTICG (1 << 16) /* Transmit IP Checksum Generate */ -#define WMDTXC_WMTFCE (1 << 9) /* Transmit Flow Control Enable */ -#define WMDTXC_WMTLB (1 << 8) /* Loopback mode */ -#define WMDTXC_WMTEP (1 << 2) /* Transmit Enable Padding */ -#define WMDTXC_WMTAC (1 << 1) /* Transmit Add CRC */ -#define WMDTXC_WMTE (1 << 0) /* TX Enable */ - -/* DMA Receive Control Register */ -#define WMDRXC_WMRBS (0x3f << 24) /* Receive Burst Size */ -#define WMDRXC_WMRUCC (1 << 18) /* Receive UDP Checksum check */ -#define WMDRXC_WMRTCG (1 << 17) /* Receive TCP Checksum check */ -#define WMDRXC_WMRICG (1 << 16) /* Receive IP Checksum check */ -#define WMDRXC_WMRFCE (1 << 9) /* Receive Flow Control Enable */ -#define WMDRXC_WMRB (1 << 6) /* Receive Broadcast */ -#define WMDRXC_WMRM (1 << 5) /* Receive Multicast */ -#define WMDRXC_WMRU (1 << 4) /* Receive Unicast */ -#define WMDRXC_WMRERR (1 << 3) /* Receive Error Frame */ -#define WMDRXC_WMRA (1 << 2) /* Receive All */ -#define WMDRXC_WMRE (1 << 0) /* RX Enable */ - -/* Additional Station Address High */ -#define WMAAH_E (1 << 31) /* Address Enabled */ - - -#endif diff --git a/arch/arm/mach-ks8695/time.c b/arch/arm/mach-ks8695/time.c deleted file mode 100644 index 50561eec0c3273f04aa34d5a1262fbe416bade34..0000000000000000000000000000000000000000 --- a/arch/arm/mach-ks8695/time.c +++ /dev/null @@ -1,159 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * arch/arm/mach-ks8695/time.c - * - * Copyright (C) 2006 Ben Dooks - * Copyright (C) 2006 Simtec Electronics - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "generic.h" - -#define KS8695_TMR_OFFSET (0xF0000 + 0xE400) -#define KS8695_TMR_VA (KS8695_IO_VA + KS8695_TMR_OFFSET) -#define KS8695_TMR_PA (KS8695_IO_PA + KS8695_TMR_OFFSET) - -/* - * Timer registers - */ -#define KS8695_TMCON (0x00) /* Timer Control Register */ -#define KS8695_T1TC (0x04) /* Timer 1 Timeout Count Register */ -#define KS8695_T0TC (0x08) /* Timer 0 Timeout Count Register */ -#define KS8695_T1PD (0x0C) /* Timer 1 Pulse Count Register */ -#define KS8695_T0PD (0x10) /* Timer 0 Pulse Count Register */ - -/* Timer Control Register */ -#define TMCON_T1EN (1 << 1) /* Timer 1 Enable */ -#define TMCON_T0EN (1 << 0) /* Timer 0 Enable */ - -/* Timer0 Timeout Counter Register */ -#define T0TC_WATCHDOG (0xff) /* Enable watchdog mode */ - -static int ks8695_set_periodic(struct clock_event_device *evt) -{ - u32 rate = DIV_ROUND_CLOSEST(KS8695_CLOCK_RATE, HZ); - u32 half = DIV_ROUND_CLOSEST(rate, 2); - u32 tmcon; - - /* Disable timer 1 */ - tmcon = readl_relaxed(KS8695_TMR_VA + KS8695_TMCON); - tmcon &= ~TMCON_T1EN; - writel_relaxed(tmcon, KS8695_TMR_VA + KS8695_TMCON); - - /* Both registers need to count down */ - writel_relaxed(half, KS8695_TMR_VA + KS8695_T1TC); - writel_relaxed(half, KS8695_TMR_VA + KS8695_T1PD); - - /* Re-enable timer1 */ - tmcon |= TMCON_T1EN; - writel_relaxed(tmcon, KS8695_TMR_VA + KS8695_TMCON); - return 0; -} - -static int ks8695_set_next_event(unsigned long cycles, - struct clock_event_device *evt) - -{ - u32 half = DIV_ROUND_CLOSEST(cycles, 2); - u32 tmcon; - - /* Disable timer 1 */ - tmcon = readl_relaxed(KS8695_TMR_VA + KS8695_TMCON); - tmcon &= ~TMCON_T1EN; - writel_relaxed(tmcon, KS8695_TMR_VA + KS8695_TMCON); - - /* Both registers need to count down */ - writel_relaxed(half, KS8695_TMR_VA + KS8695_T1TC); - writel_relaxed(half, KS8695_TMR_VA + KS8695_T1PD); - - /* Re-enable timer1 */ - tmcon |= TMCON_T1EN; - writel_relaxed(tmcon, KS8695_TMR_VA + KS8695_TMCON); - - return 0; -} - -static struct clock_event_device clockevent_ks8695 = { - .name = "ks8695_t1tc", - /* Reasonably fast and accurate clock event */ - .rating = 300, - .features = CLOCK_EVT_FEAT_ONESHOT | - CLOCK_EVT_FEAT_PERIODIC, - .set_next_event = ks8695_set_next_event, - .set_state_periodic = ks8695_set_periodic, -}; - -/* - * IRQ handler for the timer. - */ -static irqreturn_t ks8695_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = &clockevent_ks8695; - - evt->event_handler(evt); - return IRQ_HANDLED; -} - -static struct irqaction ks8695_timer_irq = { - .name = "ks8695_tick", - .flags = IRQF_TIMER, - .handler = ks8695_timer_interrupt, -}; - -static void ks8695_timer_setup(void) -{ - unsigned long tmcon; - - /* Disable timer 0 and 1 */ - tmcon = readl_relaxed(KS8695_TMR_VA + KS8695_TMCON); - tmcon &= ~TMCON_T0EN; - tmcon &= ~TMCON_T1EN; - writel_relaxed(tmcon, KS8695_TMR_VA + KS8695_TMCON); - - /* - * Use timer 1 to fire IRQs on the timeline, minimum 2 cycles - * (one on each counter) maximum 2*2^32, but the API will only - * accept up to a 32bit full word (0xFFFFFFFFU). - */ - clockevents_config_and_register(&clockevent_ks8695, - KS8695_CLOCK_RATE, 2, - 0xFFFFFFFFU); -} - -void __init ks8695_timer_init(void) -{ - ks8695_timer_setup(); - - /* Enable timer interrupts */ - setup_irq(KS8695_IRQ_TIMER1, &ks8695_timer_irq); -} - -void ks8695_restart(enum reboot_mode reboot_mode, const char *cmd) -{ - unsigned int reg; - - if (reboot_mode == REBOOT_SOFT) - soft_restart(0); - - /* disable timer0 */ - reg = readl_relaxed(KS8695_TMR_VA + KS8695_TMCON); - writel_relaxed(reg & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); - - /* enable watchdog mode */ - writel_relaxed((10 << 8) | T0TC_WATCHDOG, KS8695_TMR_VA + KS8695_T0TC); - - /* re-enable timer0 */ - writel_relaxed(reg | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); -} diff --git a/arch/arm/mach-lpc32xx/Kconfig b/arch/arm/mach-lpc32xx/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..ec87c65f453621f56694b303d3f236b72b9999b2 --- /dev/null +++ b/arch/arm/mach-lpc32xx/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config ARCH_LPC32XX + bool "NXP LPC32XX" + depends on ARCH_MULTI_V5 + select ARM_AMBA + select CLKSRC_LPC32XX + select CPU_ARM926T + select GPIOLIB + help + Support for the NXP LPC32XX family of processors diff --git a/arch/arm/mach-lpc32xx/common.c b/arch/arm/mach-lpc32xx/common.c index 5b71b4fab2cd94dbe373568f8d33210b44af8cc7..304ea61a07160b6d3beb17b651e66be7bcd25d25 100644 --- a/arch/arm/mach-lpc32xx/common.c +++ b/arch/arm/mach-lpc32xx/common.c @@ -8,12 +8,12 @@ */ #include +#include #include #include -#include -#include +#include "lpc32xx.h" #include "common.h" /* @@ -32,7 +32,7 @@ void lpc32xx_get_uid(u32 devid[4]) */ #define LPC32XX_IRAM_BANK_SIZE SZ_128K static u32 iram_size; -u32 lpc32xx_return_iram_size(void) +u32 lpc32xx_return_iram(void __iomem **mapbase, dma_addr_t *dmaaddr) { if (iram_size == 0) { u32 savedval1, savedval2; @@ -53,10 +53,26 @@ u32 lpc32xx_return_iram_size(void) } else iram_size = LPC32XX_IRAM_BANK_SIZE * 2; } + if (dmaaddr) + *dmaaddr = LPC32XX_IRAM_BASE; + if (mapbase) + *mapbase = io_p2v(LPC32XX_IRAM_BASE); return iram_size; } -EXPORT_SYMBOL_GPL(lpc32xx_return_iram_size); +EXPORT_SYMBOL_GPL(lpc32xx_return_iram); + +void lpc32xx_set_phy_interface_mode(phy_interface_t mode) +{ + u32 tmp = __raw_readl(LPC32XX_CLKPWR_MACCLK_CTRL); + tmp &= ~LPC32XX_CLKPWR_MACCTRL_PINS_MSK; + if (mode == PHY_INTERFACE_MODE_MII) + tmp |= LPC32XX_CLKPWR_MACCTRL_USE_MII_PINS; + else + tmp |= LPC32XX_CLKPWR_MACCTRL_USE_RMII_PINS; + __raw_writel(tmp, LPC32XX_CLKPWR_MACCLK_CTRL); +} +EXPORT_SYMBOL_GPL(lpc32xx_set_phy_interface_mode); static struct map_desc lpc32xx_io_desc[] __initdata = { { diff --git a/arch/arm/mach-lpc32xx/common.h b/arch/arm/mach-lpc32xx/common.h index 8e597ce48a730fe70d761824858c8f89f779b615..32f0ad2178077a9d3b225a92138efcd74bd83be5 100644 --- a/arch/arm/mach-lpc32xx/common.h +++ b/arch/arm/mach-lpc32xx/common.h @@ -23,7 +23,6 @@ extern void __init lpc32xx_serial_init(void); */ extern void lpc32xx_get_uid(u32 devid[4]); -extern u32 lpc32xx_return_iram_size(void); /* * Pointers used for sizing and copying suspend function data */ diff --git a/arch/arm/mach-lpc32xx/include/mach/board.h b/arch/arm/mach-lpc32xx/include/mach/board.h deleted file mode 100644 index 476513d970a4491ad76197cc00e4c1f37cfc3c2e..0000000000000000000000000000000000000000 --- a/arch/arm/mach-lpc32xx/include/mach/board.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * arm/arch/mach-lpc32xx/include/mach/board.h - * - * Author: Kevin Wells - * - * Copyright (C) 2010 NXP Semiconductors - */ - -#ifndef __ASM_ARCH_BOARD_H -#define __ASM_ARCH_BOARD_H - -extern u32 lpc32xx_return_iram_size(void); - -#endif /* __ASM_ARCH_BOARD_H */ diff --git a/arch/arm/mach-lpc32xx/include/mach/entry-macro.S b/arch/arm/mach-lpc32xx/include/mach/entry-macro.S deleted file mode 100644 index eec0f5f7e722e541c634e0ab48bd8c72d9179bb1..0000000000000000000000000000000000000000 --- a/arch/arm/mach-lpc32xx/include/mach/entry-macro.S +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * arch/arm/mach-lpc32xx/include/mach/entry-macro.S - * - * Author: Kevin Wells - * - * Copyright (C) 2010 NXP Semiconductors - */ - -#include -#include - -#define LPC32XX_INTC_MASKED_STATUS_OFS 0x8 - - .macro get_irqnr_preamble, base, tmp - ldr \base, =IO_ADDRESS(LPC32XX_MIC_BASE) - .endm - -/* - * Return IRQ number in irqnr. Also return processor Z flag status in CPSR - * as set if an interrupt is pending. - */ - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - ldr \irqstat, [\base, #LPC32XX_INTC_MASKED_STATUS_OFS] - clz \irqnr, \irqstat - rsb \irqnr, \irqnr, #31 - teq \irqstat, #0 - .endm diff --git a/arch/arm/mach-lpc32xx/include/mach/hardware.h b/arch/arm/mach-lpc32xx/include/mach/hardware.h deleted file mode 100644 index 4866f096ffce228bec7f540e824034c57949edea..0000000000000000000000000000000000000000 --- a/arch/arm/mach-lpc32xx/include/mach/hardware.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * arch/arm/mach-lpc32xx/include/mach/hardware.h - * - * Copyright (c) 2005 MontaVista Software, Inc. - */ - -#ifndef __ASM_ARCH_HARDWARE_H -#define __ASM_ARCH_HARDWARE_H - -/* - * Start of virtual addresses for IO devices - */ -#define IO_BASE 0xF0000000 - -/* - * This macro relies on fact that for all HW i/o addresses bits 20-23 are 0 - */ -#define IO_ADDRESS(x) IOMEM(((((x) & 0xff000000) >> 4) | ((x) & 0xfffff)) |\ - IO_BASE) - -#define io_p2v(x) ((void __iomem *) (unsigned long) IO_ADDRESS(x)) -#define io_v2p(x) ((((x) & 0x0ff00000) << 4) | ((x) & 0x000fffff)) - -#endif diff --git a/arch/arm/mach-lpc32xx/include/mach/uncompress.h b/arch/arm/mach-lpc32xx/include/mach/uncompress.h deleted file mode 100644 index a568812a0b916fe86da6b0b2382a25e7ec0a87db..0000000000000000000000000000000000000000 --- a/arch/arm/mach-lpc32xx/include/mach/uncompress.h +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * arch/arm/mach-lpc32xx/include/mach/uncompress.h - * - * Author: Kevin Wells - * - * Copyright (C) 2010 NXP Semiconductors - */ - -#ifndef __ASM_ARM_ARCH_UNCOMPRESS_H -#define __ASM_ARM_ARCH_UNCOMPRESS_H - -#include - -#include -#include - -/* - * Uncompress output is hardcoded to standard UART 5 - */ - -#define UART_FIFO_CTL_TX_RESET (1 << 2) -#define UART_STATUS_TX_MT (1 << 6) - -#define _UARTREG(x) (void __iomem *)(LPC32XX_UART5_BASE + (x)) - -#define LPC32XX_UART_DLLFIFO_O 0x00 -#define LPC32XX_UART_IIRFCR_O 0x08 -#define LPC32XX_UART_LSR_O 0x14 - -static inline void putc(int ch) -{ - /* Wait for transmit FIFO to empty */ - while ((__raw_readl(_UARTREG(LPC32XX_UART_LSR_O)) & - UART_STATUS_TX_MT) == 0) - ; - - __raw_writel((u32) ch, _UARTREG(LPC32XX_UART_DLLFIFO_O)); -} - -static inline void flush(void) -{ - __raw_writel(__raw_readl(_UARTREG(LPC32XX_UART_IIRFCR_O)) | - UART_FIFO_CTL_TX_RESET, _UARTREG(LPC32XX_UART_IIRFCR_O)); -} - -/* NULL functions; we don't presently need them */ -#define arch_decomp_setup() - -#endif diff --git a/arch/arm/mach-lpc32xx/include/mach/platform.h b/arch/arm/mach-lpc32xx/lpc32xx.h similarity index 98% rename from arch/arm/mach-lpc32xx/include/mach/platform.h rename to arch/arm/mach-lpc32xx/lpc32xx.h index 1c53790444fc17810fa6c015f1542f26a6e6f7de..5eeb884a19939ffa319586152f4efec9f61406da 100644 --- a/arch/arm/mach-lpc32xx/include/mach/platform.h +++ b/arch/arm/mach-lpc32xx/lpc32xx.h @@ -7,8 +7,8 @@ * Copyright (C) 2010 NXP Semiconductors */ -#ifndef __ASM_ARCH_PLATFORM_H -#define __ASM_ARCH_PLATFORM_H +#ifndef __ARM_LPC32XX_H +#define __ARM_LPC32XX_H #define _SBF(f, v) ((v) << (f)) #define _BIT(n) _SBF(n, 1) @@ -700,4 +700,18 @@ #define LPC32XX_USB_OTG_DEV_CLOCK_ON _BIT(1) #define LPC32XX_USB_OTG_HOST_CLOCK_ON _BIT(0) +/* + * Start of virtual addresses for IO devices + */ +#define IO_BASE 0xF0000000 + +/* + * This macro relies on fact that for all HW i/o addresses bits 20-23 are 0 + */ +#define IO_ADDRESS(x) IOMEM(((((x) & 0xff000000) >> 4) | ((x) & 0xfffff)) |\ + IO_BASE) + +#define io_p2v(x) ((void __iomem *) (unsigned long) IO_ADDRESS(x)) +#define io_v2p(x) ((((x) & 0x0ff00000) << 4) | ((x) & 0x000fffff)) + #endif diff --git a/arch/arm/mach-lpc32xx/pm.c b/arch/arm/mach-lpc32xx/pm.c index 32bca351a73b9cae8db47cf9a774c23d2d15edc3..b27fa1b9f56c1dd0f2d00571615c7307aacbcfda 100644 --- a/arch/arm/mach-lpc32xx/pm.c +++ b/arch/arm/mach-lpc32xx/pm.c @@ -70,8 +70,7 @@ #include -#include -#include +#include "lpc32xx.h" #include "common.h" #define TEMP_IRAM_AREA IO_ADDRESS(LPC32XX_IRAM_BASE) diff --git a/arch/arm/mach-lpc32xx/serial.c b/arch/arm/mach-lpc32xx/serial.c index 3f9b30df9f0e6bb0f321f55b9ac937be4ec8e66a..3e765c4bf986091eb881fd588e549165d3edf7f3 100644 --- a/arch/arm/mach-lpc32xx/serial.c +++ b/arch/arm/mach-lpc32xx/serial.c @@ -16,8 +16,7 @@ #include #include -#include -#include +#include "lpc32xx.h" #include "common.h" #define LPC32XX_SUART_FIFO_SIZE 64 @@ -60,6 +59,36 @@ static struct uartinit uartinit_data[] __initdata = { }, }; +/* LPC3250 Errata HSUART.1: Hang workaround via loopback mode on inactivity */ +void lpc32xx_loopback_set(resource_size_t mapbase, int state) +{ + int bit; + u32 tmp; + + switch (mapbase) { + case LPC32XX_HS_UART1_BASE: + bit = 0; + break; + case LPC32XX_HS_UART2_BASE: + bit = 1; + break; + case LPC32XX_HS_UART7_BASE: + bit = 6; + break; + default: + WARN(1, "lpc32xx_hs: Warning: Unknown port at %08x\n", mapbase); + return; + } + + tmp = readl(LPC32XX_UARTCTL_CLOOP); + if (state) + tmp |= (1 << bit); + else + tmp &= ~(1 << bit); + writel(tmp, LPC32XX_UARTCTL_CLOOP); +} +EXPORT_SYMBOL_GPL(lpc32xx_loopback_set); + void __init lpc32xx_serial_init(void) { u32 tmp, clkmodes = 0; diff --git a/arch/arm/mach-lpc32xx/suspend.S b/arch/arm/mach-lpc32xx/suspend.S index 374f9f07fe480ead6bac9c1c79378c91f61f1b84..3f0a8282ef6fd2edfb9dd308689ef94350fccd39 100644 --- a/arch/arm/mach-lpc32xx/suspend.S +++ b/arch/arm/mach-lpc32xx/suspend.S @@ -11,8 +11,7 @@ */ #include #include -#include -#include +#include "lpc32xx.h" /* Using named register defines makes the code easier to follow */ #define WORK1_REG r0 diff --git a/arch/arm/mach-mmp/regs-icu.h b/arch/arm/mach-mmp/regs-icu.h index 0375d5a7fcb2b82a1df95e20bfbbfa5b888c3223..410743d2b4020e30c6b5c78295f07bb861b319e4 100644 --- a/arch/arm/mach-mmp/regs-icu.h +++ b/arch/arm/mach-mmp/regs-icu.h @@ -11,6 +11,9 @@ #define ICU_VIRT_BASE (AXI_VIRT_BASE + 0x82000) #define ICU_REG(x) (ICU_VIRT_BASE + (x)) +#define ICU2_VIRT_BASE (AXI_VIRT_BASE + 0x84000) +#define ICU2_REG(x) (ICU2_VIRT_BASE + (x)) + #define ICU_INT_CONF(n) ICU_REG((n) << 2) #define ICU_INT_CONF_MASK (0xf) diff --git a/arch/arm/mach-mv78xx0/mv78xx0.h b/arch/arm/mach-mv78xx0/mv78xx0.h index 2db1265ec12189cfc22eee5ddd1441a2fc3fd19d..c1a9a1d1b29574af98c558311fcf78def80cf49c 100644 --- a/arch/arm/mach-mv78xx0/mv78xx0.h +++ b/arch/arm/mach-mv78xx0/mv78xx0.h @@ -37,7 +37,7 @@ * fee50000 f0d00000 64K PCIe #5 I/O space * fee60000 f0e00000 64K PCIe #6 I/O space * fee70000 f0f00000 64K PCIe #7 I/O space - * fd000000 f1000000 1M on-chip peripheral registers + * fec00000 f1000000 1M on-chip peripheral registers */ #define MV78XX0_CORE0_REGS_PHYS_BASE 0xf1020000 #define MV78XX0_CORE1_REGS_PHYS_BASE 0xf1024000 @@ -49,7 +49,7 @@ #define MV78XX0_PCIE_IO_SIZE SZ_1M #define MV78XX0_REGS_PHYS_BASE 0xf1000000 -#define MV78XX0_REGS_VIRT_BASE IOMEM(0xfd000000) +#define MV78XX0_REGS_VIRT_BASE IOMEM(0xfec00000) #define MV78XX0_REGS_SIZE SZ_1M #define MV78XX0_PCIE_MEM_PHYS_BASE 0xc0000000 diff --git a/arch/arm/mach-nspire/Makefile b/arch/arm/mach-nspire/Makefile index 1d568c600452e9eb3a8f10979f9d0873a803ce21..4716b9b9aa7bba2cb62df7fe688a26ef05754757 100644 --- a/arch/arm/mach-nspire/Makefile +++ b/arch/arm/mach-nspire/Makefile @@ -1,3 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y += nspire.o -obj-y += clcd.o diff --git a/arch/arm/mach-nspire/clcd.c b/arch/arm/mach-nspire/clcd.c deleted file mode 100644 index 44738dcb391df459d601d520c57cd2dd2fab5bc3..0000000000000000000000000000000000000000 --- a/arch/arm/mach-nspire/clcd.c +++ /dev/null @@ -1,114 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-nspire/clcd.c - * - * Copyright (C) 2013 Daniel Tang - */ - -#include -#include -#include -#include -#include - -static struct clcd_panel nspire_cx_lcd_panel = { - .mode = { - .name = "Color LCD", - .refresh = 60, - .xres = 320, - .yres = 240, - .sync = 0, - .vmode = FB_VMODE_NONINTERLACED, - .pixclock = 1, - .hsync_len = 6, - .vsync_len = 1, - .right_margin = 50, - .left_margin = 38, - .lower_margin = 3, - .upper_margin = 17, - }, - .width = 65, /* ~6.50 cm */ - .height = 49, /* ~4.87 cm */ - .tim2 = TIM2_IPC, - .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), - .bpp = 16, - .caps = CLCD_CAP_565, -}; - -static struct clcd_panel nspire_classic_lcd_panel = { - .mode = { - .name = "Grayscale LCD", - .refresh = 60, - .xres = 320, - .yres = 240, - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - .vmode = FB_VMODE_NONINTERLACED, - .pixclock = 1, - .hsync_len = 6, - .vsync_len = 1, - .right_margin = 6, - .left_margin = 6, - }, - .width = 71, /* 7.11cm */ - .height = 53, /* 5.33cm */ - .tim2 = 0x80007d0, - .cntl = CNTL_LCDMONO8, - .bpp = 8, - .grayscale = 1, - .caps = CLCD_CAP_5551, -}; - -int nspire_clcd_setup(struct clcd_fb *fb) -{ - struct clcd_panel *panel; - size_t panel_size; - const char *type; - dma_addr_t dma; - int err; - - BUG_ON(!fb->dev->dev.of_node); - - err = of_property_read_string(fb->dev->dev.of_node, "lcd-type", &type); - if (err) { - pr_err("CLCD: Could not find lcd-type property\n"); - return err; - } - - if (!strcmp(type, "cx")) { - panel = &nspire_cx_lcd_panel; - } else if (!strcmp(type, "classic")) { - panel = &nspire_classic_lcd_panel; - } else { - pr_err("CLCD: Unknown lcd-type %s\n", type); - return -EINVAL; - } - - panel_size = ((panel->mode.xres * panel->mode.yres) * panel->bpp) / 8; - panel_size = ALIGN(panel_size, PAGE_SIZE); - - fb->fb.screen_base = dma_alloc_wc(&fb->dev->dev, panel_size, &dma, - GFP_KERNEL); - - if (!fb->fb.screen_base) { - pr_err("CLCD: unable to map framebuffer\n"); - return -ENOMEM; - } - - fb->fb.fix.smem_start = dma; - fb->fb.fix.smem_len = panel_size; - fb->panel = panel; - - return 0; -} - -int nspire_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) -{ - return dma_mmap_wc(&fb->dev->dev, vma, fb->fb.screen_base, - fb->fb.fix.smem_start, fb->fb.fix.smem_len); -} - -void nspire_clcd_remove(struct clcd_fb *fb) -{ - dma_free_wc(&fb->dev->dev, fb->fb.fix.smem_len, fb->fb.screen_base, - fb->fb.fix.smem_start); -} diff --git a/arch/arm/mach-nspire/clcd.h b/arch/arm/mach-nspire/clcd.h deleted file mode 100644 index 7f36bd8511c53ec79dbadc595b968e5e6e38f377..0000000000000000000000000000000000000000 --- a/arch/arm/mach-nspire/clcd.h +++ /dev/null @@ -1,10 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * linux/arch/arm/mach-nspire/clcd.h - * - * Copyright (C) 2013 Daniel Tang - */ - -int nspire_clcd_setup(struct clcd_fb *fb); -int nspire_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma); -void nspire_clcd_remove(struct clcd_fb *fb); diff --git a/arch/arm/mach-nspire/nspire.c b/arch/arm/mach-nspire/nspire.c index 957bd0c0fbd54c75f414dd28397005a29b43ad05..2d4abb0288b9d3af7036c59f6c1d01b858dbd660 100644 --- a/arch/arm/mach-nspire/nspire.c +++ b/arch/arm/mach-nspire/nspire.c @@ -12,14 +12,12 @@ #include #include #include -#include #include #include #include #include "mmio.h" -#include "clcd.h" static const char *const nspire_dt_match[] __initconst = { "ti,nspire", @@ -29,28 +27,6 @@ static const char *const nspire_dt_match[] __initconst = { NULL, }; -static struct clcd_board nspire_clcd_data = { - .name = "LCD", - .caps = CLCD_CAP_5551 | CLCD_CAP_565, - .check = clcdfb_check, - .decode = clcdfb_decode, - .setup = nspire_clcd_setup, - .mmap = nspire_clcd_mmap, - .remove = nspire_clcd_remove, -}; - - -static struct of_dev_auxdata nspire_auxdata[] __initdata = { - OF_DEV_AUXDATA("arm,pl111", NSPIRE_LCD_PHYS_BASE, - NULL, &nspire_clcd_data), - { } -}; - -static void __init nspire_init(void) -{ - of_platform_default_populate(NULL, nspire_auxdata, NULL); -} - static void nspire_restart(enum reboot_mode mode, const char *cmd) { void __iomem *base = ioremap(NSPIRE_MISC_PHYS_BASE, SZ_4K); @@ -62,6 +38,5 @@ static void nspire_restart(enum reboot_mode mode, const char *cmd) DT_MACHINE_START(NSPIRE, "TI-NSPIRE") .dt_compat = nspire_dt_match, - .init_machine = nspire_init, .restart = nspire_restart, MACHINE_END diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c index e47a6fbcfd6e5e100c056869a0304734c1e07fe1..a2aa7a12b3742fd8d15ba9bc4af53a56ca1f1ab2 100644 --- a/arch/arm/mach-omap1/board-ams-delta.c +++ b/arch/arm/mach-omap1/board-ams-delta.c @@ -246,8 +246,8 @@ static struct platform_device latch2_gpio_device = { #define LATCH2_PIN_SCARD_CMDVCC 11 #define LATCH2_PIN_MODEM_NRESET 12 #define LATCH2_PIN_MODEM_CODEC 13 -#define LATCH2_PIN_AUDIO_MUTE 14 -#define LATCH2_PIN_HOOKFLASH 15 +#define LATCH2_PIN_HANDSFREE_MUTE 14 +#define LATCH2_PIN_HANDSET_MUTE 15 static struct regulator_consumer_supply modem_nreset_consumers[] = { REGULATOR_SUPPLY("RESET#", "serial8250.1"), @@ -476,6 +476,10 @@ static struct gpiod_lookup_table ams_delta_audio_gpio_table = { "hook_switch", 0), GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_MODEM_CODEC, "modem_codec", 0), + GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_HANDSFREE_MUTE, + "handsfree_mute", 0), + GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_HANDSET_MUTE, + "handset_mute", 0), { }, }, }; @@ -590,8 +594,6 @@ static int gpiochip_match_by_label(struct gpio_chip *chip, void *data) static struct gpiod_hog ams_delta_gpio_hogs[] = { GPIO_HOG(LATCH2_LABEL, LATCH2_PIN_KEYBRD_DATAOUT, "keybrd_dataout", GPIO_ACTIVE_HIGH, GPIOD_OUT_LOW), - GPIO_HOG(LATCH2_LABEL, LATCH2_PIN_AUDIO_MUTE, "audio_mute", - GPIO_ACTIVE_HIGH, GPIOD_OUT_LOW), {}, }; diff --git a/arch/arm/mach-omap2/.gitignore b/arch/arm/mach-omap2/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..79a8d6ea7152033e961abd60d982e89c220f9bba --- /dev/null +++ b/arch/arm/mach-omap2/.gitignore @@ -0,0 +1 @@ +pm-asm-offsets.h diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 60065055162199dc4188fff1e448acb37e6d4627..8f208197988fe848c52cd83583d97c30f6c476ae 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -223,9 +223,12 @@ obj-y += omap_phy_internal.o obj-$(CONFIG_MACH_OMAP2_TUSB6010) += usb-tusb6010.o -include/generated/ti-pm-asm-offsets.h: arch/arm/mach-omap2/pm-asm-offsets.s FORCE +$(obj)/pm-asm-offsets.h: $(obj)/pm-asm-offsets.s FORCE $(call filechk,offsets,__TI_PM_ASM_OFFSETS_H__) -$(obj)/sleep33xx.o $(obj)/sleep43xx.o: include/generated/ti-pm-asm-offsets.h +$(obj)/sleep33xx.o $(obj)/sleep43xx.o: $(obj)/pm-asm-offsets.h targets += pm-asm-offsets.s +clean-files += pm-asm-offsets.h + +obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index cc0d08dad1419978d0919baa1e1140be5c321644..5a2e198e7db103843b3fc159f14f7a1b160b587d 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -43,11 +44,17 @@ static struct resource omap_vout_resource[2] = { }; #endif +static u64 omap_vout_dma_mask = DMA_BIT_MASK(32); + static struct platform_device omap_vout_device = { .name = "omap_vout", .num_resources = ARRAY_SIZE(omap_vout_resource), .resource = &omap_vout_resource[0], .id = -1, + .dev = { + .dma_mask = &omap_vout_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, }; int __init omap_init_vout(void) diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 14b9c13c1fa0cb022a9a97874a661ef213aa648a..63423ea6a2408f6d1889a426e8bb1553b2b3075c 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -32,10 +32,8 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, char *hc_name; hc_name = kzalloc(HSMMC_NAME_LEN + 1, GFP_KERNEL); - if (!hc_name) { - kfree(hc_name); + if (!hc_name) return -ENOMEM; - } snprintf(hc_name, (HSMMC_NAME_LEN + 1), "mmc%islot%i", c->mmc, 1); mmc->name = hc_name; diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c new file mode 100644 index 0000000000000000000000000000000000000000..f1a6ece8108e47ad049416e682a730fe319dcab1 --- /dev/null +++ b/arch/arm/mach-omap2/omap-iommu.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * OMAP IOMMU quirks for various TI SoCs + * + * Copyright (C) 2015-2019 Texas Instruments Incorporated - http://www.ti.com/ + * Suman Anna + */ + +#include +#include + +#include "omap_hwmod.h" +#include "omap_device.h" +#include "powerdomain.h" + +int omap_iommu_set_pwrdm_constraint(struct platform_device *pdev, bool request, + u8 *pwrst) +{ + struct powerdomain *pwrdm; + struct omap_device *od; + u8 next_pwrst; + + od = to_omap_device(pdev); + if (!od) + return -ENODEV; + + if (od->hwmods_cnt != 1) + return -EINVAL; + + pwrdm = omap_hwmod_get_pwrdm(od->hwmods[0]); + if (!pwrdm) + return -EINVAL; + + if (request) + *pwrst = pwrdm_read_next_pwrst(pwrdm); + + if (*pwrst > PWRDM_POWER_RET) + return 0; + + next_pwrst = request ? PWRDM_POWER_ON : *pwrst; + + return pwrdm_set_next_pwrst(pwrdm, next_pwrst); +} diff --git a/arch/arm/mach-omap2/sleep33xx.S b/arch/arm/mach-omap2/sleep33xx.S index 68fee339d3f12755bf0172bc27eac07e2743838e..dc221249bc22c88ae95b94ce4461781cc9c1c999 100644 --- a/arch/arm/mach-omap2/sleep33xx.S +++ b/arch/arm/mach-omap2/sleep33xx.S @@ -6,7 +6,6 @@ * Dave Gerlach, Vaibhav Bedia */ -#include #include #include #include @@ -15,6 +14,7 @@ #include "iomap.h" #include "cm33xx.h" +#include "pm-asm-offsets.h" #define AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED 0x00030000 #define AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE 0x0003 diff --git a/arch/arm/mach-omap2/sleep43xx.S b/arch/arm/mach-omap2/sleep43xx.S index c1f4e4852644e7e1e917e216d20fd50485c57530..90d2907a2eb27eba605421c1252dd98caa228025 100644 --- a/arch/arm/mach-omap2/sleep43xx.S +++ b/arch/arm/mach-omap2/sleep43xx.S @@ -6,7 +6,6 @@ * Dave Gerlach, Vaibhav Bedia */ -#include #include #include #include @@ -19,6 +18,7 @@ #include "iomap.h" #include "omap-secure.h" #include "omap44xx.h" +#include "pm-asm-offsets.h" #include "prm33xx.h" #include "prcm43xx.h" diff --git a/arch/arm/mach-orion5x/orion5x.h b/arch/arm/mach-orion5x/orion5x.h index 3364df331f01e4a992c90d3cc157c37c9a23d678..2b66120fba86cded9d255b5e802abfc56cc4abdb 100644 --- a/arch/arm/mach-orion5x/orion5x.h +++ b/arch/arm/mach-orion5x/orion5x.h @@ -31,13 +31,13 @@ * fc000000 device bus mappings (cs0/cs1) * * virt phys size - * fe000000 f1000000 1M on-chip peripheral registers + * fec00000 f1000000 1M on-chip peripheral registers * fee00000 f2000000 64K PCIe I/O space * fee10000 f2100000 64K PCI I/O space * fd000000 f0000000 16M PCIe WA space (Orion-1/Orion-NAS only) ****************************************************************************/ #define ORION5X_REGS_PHYS_BASE 0xf1000000 -#define ORION5X_REGS_VIRT_BASE IOMEM(0xfe000000) +#define ORION5X_REGS_VIRT_BASE IOMEM(0xfec00000) #define ORION5X_REGS_SIZE SZ_1M #define ORION5X_PCIE_IO_PHYS_BASE 0xf2000000 diff --git a/arch/arm/mach-s3c64xx/setup-usb-phy.c b/arch/arm/mach-s3c64xx/setup-usb-phy.c index 46a9e955607fd422e271ed054a7f46e7af2ec336..6aaaa1d8e8b9297649668ab6aa64b5095f7a1487 100644 --- a/arch/arm/mach-s3c64xx/setup-usb-phy.c +++ b/arch/arm/mach-s3c64xx/setup-usb-phy.c @@ -15,6 +15,11 @@ #include "regs-sys.h" #include "regs-usb-hsotg-phy.h" +enum samsung_usb_phy_type { + USB_PHY_TYPE_DEVICE, + USB_PHY_TYPE_HOST, +}; + static int s3c_usb_otgphy_init(struct platform_device *pdev) { struct clk *xusbxti; diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c index 9580525102dab810e944a1af441209baa82e2653..3875027ef8fcbb644ac26a25ce93603cec008654 100644 --- a/arch/arm/mach-ux500/cpu-db8500.c +++ b/arch/arm/mach-ux500/cpu-db8500.c @@ -110,7 +110,6 @@ static void ux500_restart(enum reboot_mode mode, const char *cmd) static const struct of_device_id u8500_local_bus_nodes[] = { /* only create devices below soc node */ { .compatible = "stericsson,db8500", }, - { .compatible = "stericsson,db8500-prcmu", }, { .compatible = "simple-bus"}, { }, }; diff --git a/arch/arm/mach-vexpress/spc.c b/arch/arm/mach-vexpress/spc.c index 0f5381d1349418c5de2723be59811be30a402f8e..354e0e7025aec5c1da2145ae4037f7e805868970 100644 --- a/arch/arm/mach-vexpress/spc.c +++ b/arch/arm/mach-vexpress/spc.c @@ -69,7 +69,7 @@ #define A7_PERFVAL_BASE 0xC30 /* Config interface control bits */ -#define SYSCFG_START (1 << 31) +#define SYSCFG_START BIT(31) #define SYSCFG_SCC (6 << 20) #define SYSCFG_STAT (14 << 20) @@ -162,7 +162,7 @@ void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set) if (cluster >= MAX_CLUSTERS) return; - mask = 1 << cpu; + mask = BIT(cpu); if (!cluster_is_a15(cluster)) mask <<= 4; diff --git a/arch/arm/mach-w90x900/Kconfig b/arch/arm/mach-w90x900/Kconfig deleted file mode 100644 index b16ffc03bbe598a9dfdb48b5bc98819d03791a98..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/Kconfig +++ /dev/null @@ -1,50 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -if ARCH_W90X900 - -config CPU_W90P910 - bool - help - Support for W90P910 of Nuvoton W90X900 CPUs. - -config CPU_NUC950 - bool - help - Support for NUCP950 of Nuvoton NUC900 CPUs. - -config CPU_NUC960 - bool - help - Support for NUCP960 of Nuvoton NUC900 CPUs. - -menu "W90P910 Machines" - -config MACH_W90P910EVB - bool "Nuvoton W90P910 Evaluation Board" - default y - select CPU_W90P910 - help - Say Y here if you are using the Nuvoton W90P910EVB - -endmenu - -menu "NUC950 Machines" - -config MACH_W90P950EVB - bool "Nuvoton NUC950 Evaluation Board" - select CPU_NUC950 - help - Say Y here if you are using the Nuvoton NUC950EVB - -endmenu - -menu "NUC960 Machines" - -config MACH_W90N960EVB - bool "Nuvoton NUC960 Evaluation Board" - select CPU_NUC960 - help - Say Y here if you are using the Nuvoton NUC960EVB - -endmenu - -endif diff --git a/arch/arm/mach-w90x900/Makefile b/arch/arm/mach-w90x900/Makefile deleted file mode 100644 index 33b5bf53990fb6a25d1b691fd615a617ab97e63f..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the linux kernel. -# - -# Object file lists. - -obj-y := irq.o time.o mfp.o gpio.o clock.o -obj-y += clksel.o dev.o cpu.o -# W90X900 CPU support files - -obj-$(CONFIG_CPU_W90P910) += nuc910.o -obj-$(CONFIG_CPU_NUC950) += nuc950.o -obj-$(CONFIG_CPU_NUC960) += nuc960.o - -# machine support - -obj-$(CONFIG_MACH_W90P910EVB) += mach-nuc910evb.o -obj-$(CONFIG_MACH_W90P950EVB) += mach-nuc950evb.o -obj-$(CONFIG_MACH_W90N960EVB) += mach-nuc960evb.o diff --git a/arch/arm/mach-w90x900/Makefile.boot b/arch/arm/mach-w90x900/Makefile.boot deleted file mode 100644 index 07d1b3b23ac09bc6f719bfbfa5df9366c5e0417a..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/Makefile.boot +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -zreladdr-y += 0x00008000 -params_phys-y := 0x00000100 - diff --git a/arch/arm/mach-w90x900/clksel.c b/arch/arm/mach-w90x900/clksel.c deleted file mode 100644 index b50577a5a840c7244cae9cac91a1ca25026935c6..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/clksel.c +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-w90x900/clksel.c - * - * Copyright (c) 2008 Nuvoton technology corporation - * - * Wan ZongShun - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define PLL0 0x00 -#define PLL1 0x01 -#define OTHER 0x02 -#define EXT 0x03 -#define MSOFFSET 0x0C -#define ATAOFFSET 0x0a -#define LCDOFFSET 0x06 -#define AUDOFFSET 0x04 -#define CPUOFFSET 0x00 - -static DEFINE_MUTEX(clksel_sem); - -static void clock_source_select(const char *dev_id, unsigned int clkval) -{ - unsigned int clksel, offset; - - clksel = __raw_readl(REG_CLKSEL); - - if (strcmp(dev_id, "nuc900-ms") == 0) - offset = MSOFFSET; - else if (strcmp(dev_id, "nuc900-atapi") == 0) - offset = ATAOFFSET; - else if (strcmp(dev_id, "nuc900-lcd") == 0) - offset = LCDOFFSET; - else if (strcmp(dev_id, "nuc900-ac97") == 0) - offset = AUDOFFSET; - else - offset = CPUOFFSET; - - clksel &= ~(0x03 << offset); - clksel |= (clkval << offset); - - __raw_writel(clksel, REG_CLKSEL); -} - -void nuc900_clock_source(struct device *dev, unsigned char *src) -{ - unsigned int clkval; - const char *dev_id; - - BUG_ON(!src); - clkval = 0; - - mutex_lock(&clksel_sem); - - if (dev) - dev_id = dev_name(dev); - else - dev_id = "cpufreq"; - - if (strcmp(src, "pll0") == 0) - clkval = PLL0; - else if (strcmp(src, "pll1") == 0) - clkval = PLL1; - else if (strcmp(src, "ext") == 0) - clkval = EXT; - else if (strcmp(src, "oth") == 0) - clkval = OTHER; - - clock_source_select(dev_id, clkval); - - mutex_unlock(&clksel_sem); -} -EXPORT_SYMBOL(nuc900_clock_source); - diff --git a/arch/arm/mach-w90x900/clock.c b/arch/arm/mach-w90x900/clock.c deleted file mode 100644 index df55aa8ce5ffb9b2ae09abc4f7d991efd2ac1f00..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/clock.c +++ /dev/null @@ -1,121 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-w90x900/clock.c - * - * Copyright (c) 2008 Nuvoton technology corporation - * - * Wan ZongShun - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "clock.h" - -#define SUBCLK 0x24 - -static DEFINE_SPINLOCK(clocks_lock); - -int clk_enable(struct clk *clk) -{ - unsigned long flags; - - spin_lock_irqsave(&clocks_lock, flags); - if (clk->enabled++ == 0) - (clk->enable)(clk, 1); - spin_unlock_irqrestore(&clocks_lock, flags); - - return 0; -} -EXPORT_SYMBOL(clk_enable); - -void clk_disable(struct clk *clk) -{ - unsigned long flags; - - if (!clk) - return; - - WARN_ON(clk->enabled == 0); - - spin_lock_irqsave(&clocks_lock, flags); - if (--clk->enabled == 0) - (clk->enable)(clk, 0); - spin_unlock_irqrestore(&clocks_lock, flags); -} -EXPORT_SYMBOL(clk_disable); - -unsigned long clk_get_rate(struct clk *clk) -{ - return 15000000; -} -EXPORT_SYMBOL(clk_get_rate); - -void nuc900_clk_enable(struct clk *clk, int enable) -{ - unsigned int clocks = clk->cken; - unsigned long clken; - - clken = __raw_readl(W90X900_VA_CLKPWR); - - if (enable) - clken |= clocks; - else - clken &= ~clocks; - - __raw_writel(clken, W90X900_VA_CLKPWR); -} - -void nuc900_subclk_enable(struct clk *clk, int enable) -{ - unsigned int clocks = clk->cken; - unsigned long clken; - - clken = __raw_readl(W90X900_VA_CLKPWR + SUBCLK); - - if (enable) - clken |= clocks; - else - clken &= ~clocks; - - __raw_writel(clken, W90X900_VA_CLKPWR + SUBCLK); -} - -/* dummy functions, should not be called */ -long clk_round_rate(struct clk *clk, unsigned long rate) -{ - WARN_ON(clk); - return 0; -} -EXPORT_SYMBOL(clk_round_rate); - -int clk_set_rate(struct clk *clk, unsigned long rate) -{ - WARN_ON(clk); - return 0; -} -EXPORT_SYMBOL(clk_set_rate); - -int clk_set_parent(struct clk *clk, struct clk *parent) -{ - WARN_ON(clk); - return 0; -} -EXPORT_SYMBOL(clk_set_parent); - -struct clk *clk_get_parent(struct clk *clk) -{ - WARN_ON(clk); - return NULL; -} -EXPORT_SYMBOL(clk_get_parent); diff --git a/arch/arm/mach-w90x900/clock.h b/arch/arm/mach-w90x900/clock.h deleted file mode 100644 index e81c369430b32a95512f03f2b3ec045307f4fdb1..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/clock.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * linux/arch/arm/mach-w90x900/clock.h - * - * Copyright (c) 2008 Nuvoton technology corporation - * - * Wan ZongShun - */ - -#include - -void nuc900_clk_enable(struct clk *clk, int enable); -void nuc900_subclk_enable(struct clk *clk, int enable); - -struct clk { - unsigned long cken; - unsigned int enabled; - void (*enable)(struct clk *, int enable); -}; - -#define DEFINE_CLK(_name, _ctrlbit) \ -struct clk clk_##_name = { \ - .enable = nuc900_clk_enable, \ - .cken = (1 << _ctrlbit), \ - } - -#define DEFINE_SUBCLK(_name, _ctrlbit) \ -struct clk clk_##_name = { \ - .enable = nuc900_subclk_enable, \ - .cken = (1 << _ctrlbit), \ - } - - -#define DEF_CLKLOOK(_clk, _devname, _conname) \ - { \ - .clk = _clk, \ - .dev_id = _devname, \ - .con_id = _conname, \ - } - diff --git a/arch/arm/mach-w90x900/cpu.c b/arch/arm/mach-w90x900/cpu.c deleted file mode 100644 index aeaafc2ebb0137b234d2fea249107a75b18f51de..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/cpu.c +++ /dev/null @@ -1,238 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-w90x900/cpu.c - * - * Copyright (c) 2009 Nuvoton corporation. - * - * Wan ZongShun - * - * NUC900 series cpu common support - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include "regs-ebi.h" -#include "regs-timer.h" - -#include "cpu.h" -#include "clock.h" -#include "nuc9xx.h" - -/* Initial IO mappings */ - -static struct map_desc nuc900_iodesc[] __initdata = { - IODESC_ENT(IRQ), - IODESC_ENT(GCR), - IODESC_ENT(UART), - IODESC_ENT(TIMER), - IODESC_ENT(EBI), - IODESC_ENT(GPIO), -}; - -/* Initial clock declarations. */ -static DEFINE_CLK(lcd, 0); -static DEFINE_CLK(audio, 1); -static DEFINE_CLK(fmi, 4); -static DEFINE_SUBCLK(ms, 0); -static DEFINE_SUBCLK(sd, 1); -static DEFINE_CLK(dmac, 5); -static DEFINE_CLK(atapi, 6); -static DEFINE_CLK(emc, 7); -static DEFINE_SUBCLK(rmii, 2); -static DEFINE_CLK(usbd, 8); -static DEFINE_CLK(usbh, 9); -static DEFINE_CLK(g2d, 10); -static DEFINE_CLK(pwm, 18); -static DEFINE_CLK(ps2, 24); -static DEFINE_CLK(kpi, 25); -static DEFINE_CLK(wdt, 26); -static DEFINE_CLK(gdma, 27); -static DEFINE_CLK(adc, 28); -static DEFINE_CLK(usi, 29); -static DEFINE_CLK(ext, 0); -static DEFINE_CLK(timer0, 19); -static DEFINE_CLK(timer1, 20); -static DEFINE_CLK(timer2, 21); -static DEFINE_CLK(timer3, 22); -static DEFINE_CLK(timer4, 23); - -static struct clk_lookup nuc900_clkregs[] = { - DEF_CLKLOOK(&clk_lcd, "nuc900-lcd", NULL), - DEF_CLKLOOK(&clk_audio, "nuc900-ac97", NULL), - DEF_CLKLOOK(&clk_fmi, "nuc900-fmi", NULL), - DEF_CLKLOOK(&clk_ms, "nuc900-fmi", "MS"), - DEF_CLKLOOK(&clk_sd, "nuc900-fmi", "SD"), - DEF_CLKLOOK(&clk_dmac, "nuc900-dmac", NULL), - DEF_CLKLOOK(&clk_atapi, "nuc900-atapi", NULL), - DEF_CLKLOOK(&clk_emc, "nuc900-emc", NULL), - DEF_CLKLOOK(&clk_rmii, "nuc900-emc", "RMII"), - DEF_CLKLOOK(&clk_usbd, "nuc900-usbd", NULL), - DEF_CLKLOOK(&clk_usbh, "nuc900-usbh", NULL), - DEF_CLKLOOK(&clk_g2d, "nuc900-g2d", NULL), - DEF_CLKLOOK(&clk_pwm, "nuc900-pwm", NULL), - DEF_CLKLOOK(&clk_ps2, "nuc900-ps2", NULL), - DEF_CLKLOOK(&clk_kpi, "nuc900-kpi", NULL), - DEF_CLKLOOK(&clk_wdt, "nuc900-wdt", NULL), - DEF_CLKLOOK(&clk_gdma, "nuc900-gdma", NULL), - DEF_CLKLOOK(&clk_adc, "nuc900-ts", NULL), - DEF_CLKLOOK(&clk_usi, "nuc900-spi", NULL), - DEF_CLKLOOK(&clk_ext, NULL, "ext"), - DEF_CLKLOOK(&clk_timer0, NULL, "timer0"), - DEF_CLKLOOK(&clk_timer1, NULL, "timer1"), - DEF_CLKLOOK(&clk_timer2, NULL, "timer2"), - DEF_CLKLOOK(&clk_timer3, NULL, "timer3"), - DEF_CLKLOOK(&clk_timer4, NULL, "timer4"), -}; - -/* Initial serial platform data */ - -struct plat_serial8250_port nuc900_uart_data[] = { - NUC900_8250PORT(UART0), - {}, -}; - -struct platform_device nuc900_serial_device = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM, - .dev = { - .platform_data = nuc900_uart_data, - }, -}; - -/*Set NUC900 series cpu frequence*/ -static int __init nuc900_set_clkval(unsigned int cpufreq) -{ - unsigned int pllclk, ahbclk, apbclk, val; - - pllclk = 0; - ahbclk = 0; - apbclk = 0; - - switch (cpufreq) { - case 66: - pllclk = PLL_66MHZ; - ahbclk = AHB_CPUCLK_1_1; - apbclk = APB_AHB_1_2; - break; - - case 100: - pllclk = PLL_100MHZ; - ahbclk = AHB_CPUCLK_1_1; - apbclk = APB_AHB_1_2; - break; - - case 120: - pllclk = PLL_120MHZ; - ahbclk = AHB_CPUCLK_1_2; - apbclk = APB_AHB_1_2; - break; - - case 166: - pllclk = PLL_166MHZ; - ahbclk = AHB_CPUCLK_1_2; - apbclk = APB_AHB_1_2; - break; - - case 200: - pllclk = PLL_200MHZ; - ahbclk = AHB_CPUCLK_1_2; - apbclk = APB_AHB_1_2; - break; - } - - __raw_writel(pllclk, REG_PLLCON0); - - val = __raw_readl(REG_CLKDIV); - val &= ~(0x03 << 24 | 0x03 << 26); - val |= (ahbclk << 24 | apbclk << 26); - __raw_writel(val, REG_CLKDIV); - - return 0; -} -static int __init nuc900_set_cpufreq(char *str) -{ - unsigned long cpufreq, val; - - if (!*str) - return 0; - - if (kstrtoul(str, 0, &cpufreq)) - return 0; - - nuc900_clock_source(NULL, "ext"); - - nuc900_set_clkval(cpufreq); - - mdelay(1); - - val = __raw_readl(REG_CKSKEW); - val &= ~0xff; - val |= DEFAULTSKEW; - __raw_writel(val, REG_CKSKEW); - - nuc900_clock_source(NULL, "pll0"); - - return 1; -} - -__setup("cpufreq=", nuc900_set_cpufreq); - -/*Init NUC900 evb io*/ - -void __init nuc900_map_io(struct map_desc *mach_desc, int mach_size) -{ - unsigned long idcode = 0x0; - - iotable_init(mach_desc, mach_size); - iotable_init(nuc900_iodesc, ARRAY_SIZE(nuc900_iodesc)); - - idcode = __raw_readl(NUC900PDID); - if (idcode == NUC910_CPUID) - printk(KERN_INFO "CPU type 0x%08lx is NUC910\n", idcode); - else if (idcode == NUC920_CPUID) - printk(KERN_INFO "CPU type 0x%08lx is NUC920\n", idcode); - else if (idcode == NUC950_CPUID) - printk(KERN_INFO "CPU type 0x%08lx is NUC950\n", idcode); - else if (idcode == NUC960_CPUID) - printk(KERN_INFO "CPU type 0x%08lx is NUC960\n", idcode); -} - -/*Init NUC900 clock*/ - -void __init nuc900_init_clocks(void) -{ - clkdev_add_table(nuc900_clkregs, ARRAY_SIZE(nuc900_clkregs)); -} - -#define WTCR (TMR_BA + 0x1C) -#define WTCLK (1 << 10) -#define WTE (1 << 7) -#define WTRE (1 << 1) - -void nuc9xx_restart(enum reboot_mode mode, const char *cmd) -{ - if (mode == REBOOT_SOFT) { - /* Jump into ROM at address 0 */ - soft_restart(0); - } else { - __raw_writel(WTE | WTRE | WTCLK, WTCR); - } -} diff --git a/arch/arm/mach-w90x900/cpu.h b/arch/arm/mach-w90x900/cpu.h deleted file mode 100644 index a56f36d04bac5469d6c167291c60dfc8940b4c62..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/cpu.h +++ /dev/null @@ -1,56 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-w90x900/cpu.h - * - * Based on linux/include/asm-arm/plat-s3c24xx/cpu.h by Ben Dooks - * - * Copyright (c) 2008 Nuvoton technology corporation - * All rights reserved. - * - * Header file for NUC900 CPU support - * - * Wan ZongShun - */ - -#define IODESC_ENT(y) \ -{ \ - .virtual = (unsigned long)W90X900_VA_##y, \ - .pfn = __phys_to_pfn(W90X900_PA_##y), \ - .length = W90X900_SZ_##y, \ - .type = MT_DEVICE, \ -} - -#define NUC900_8250PORT(name) \ -{ \ - .membase = name##_BA, \ - .mapbase = name##_PA, \ - .irq = IRQ_##name, \ - .uartclk = 11313600, \ - .regshift = 2, \ - .iotype = UPIO_MEM, \ - .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \ -} - -/*Cpu identifier register*/ - -#define NUC900PDID W90X900_VA_GCR -#define NUC910_CPUID 0x02900910 -#define NUC920_CPUID 0x02900920 -#define NUC950_CPUID 0x02900950 -#define NUC960_CPUID 0x02900960 - -/* extern file from cpu.c */ - -extern void nuc900_clock_source(struct device *dev, unsigned char *src); -extern void nuc900_init_clocks(void); -extern void nuc900_map_io(struct map_desc *mach_desc, int mach_size); -extern void nuc900_board_init(struct platform_device **device, int size); - -/* for either public between 910 and 920, or between 920 and 950 */ - -extern struct platform_device nuc900_serial_device; -extern struct platform_device nuc900_device_fmi; -extern struct platform_device nuc900_device_kpi; -extern struct platform_device nuc900_device_rtc; -extern struct platform_device nuc900_device_ts; -extern struct platform_device nuc900_device_lcd; diff --git a/arch/arm/mach-w90x900/dev.c b/arch/arm/mach-w90x900/dev.c deleted file mode 100644 index ce5fe400cb99d6487e42cebf4cd288814df26477..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/dev.c +++ /dev/null @@ -1,537 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-w90x900/dev.c - * - * Copyright (C) 2009 Nuvoton corporation. - * - * Wan ZongShun - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "cpu.h" - -/*NUC900 evb norflash driver data */ - -#define NUC900_FLASH_BASE 0xA0000000 -#define NUC900_FLASH_SIZE 0x400000 -#define SPIOFFSET 0x200 -#define SPIOREG_SIZE 0x100 - -static struct mtd_partition nuc900_flash_partitions[] = { - { - .name = "NOR Partition 1 for kernel (960K)", - .size = 0xF0000, - .offset = 0x10000, - }, - { - .name = "NOR Partition 2 for image (1M)", - .size = 0x100000, - .offset = 0x100000, - }, - { - .name = "NOR Partition 3 for user (2M)", - .size = 0x200000, - .offset = 0x00200000, - } -}; - -static struct physmap_flash_data nuc900_flash_data = { - .width = 2, - .parts = nuc900_flash_partitions, - .nr_parts = ARRAY_SIZE(nuc900_flash_partitions), -}; - -static struct resource nuc900_flash_resources[] = { - { - .start = NUC900_FLASH_BASE, - .end = NUC900_FLASH_BASE + NUC900_FLASH_SIZE - 1, - .flags = IORESOURCE_MEM, - } -}; - -static struct platform_device nuc900_flash_device = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &nuc900_flash_data, - }, - .resource = nuc900_flash_resources, - .num_resources = ARRAY_SIZE(nuc900_flash_resources), -}; - -/* USB EHCI Host Controller */ - -static struct resource nuc900_usb_ehci_resource[] = { - [0] = { - .start = W90X900_PA_USBEHCIHOST, - .end = W90X900_PA_USBEHCIHOST + W90X900_SZ_USBEHCIHOST - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_USBH, - .end = IRQ_USBH, - .flags = IORESOURCE_IRQ, - } -}; - -static u64 nuc900_device_usb_ehci_dmamask = 0xffffffffUL; - -static struct platform_device nuc900_device_usb_ehci = { - .name = "nuc900-ehci", - .id = -1, - .num_resources = ARRAY_SIZE(nuc900_usb_ehci_resource), - .resource = nuc900_usb_ehci_resource, - .dev = { - .dma_mask = &nuc900_device_usb_ehci_dmamask, - .coherent_dma_mask = 0xffffffffUL - } -}; - -/* USB OHCI Host Controller */ - -static struct resource nuc900_usb_ohci_resource[] = { - [0] = { - .start = W90X900_PA_USBOHCIHOST, - .end = W90X900_PA_USBOHCIHOST + W90X900_SZ_USBOHCIHOST - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_USBH, - .end = IRQ_USBH, - .flags = IORESOURCE_IRQ, - } -}; - -static u64 nuc900_device_usb_ohci_dmamask = 0xffffffffUL; -static struct platform_device nuc900_device_usb_ohci = { - .name = "nuc900-ohci", - .id = -1, - .num_resources = ARRAY_SIZE(nuc900_usb_ohci_resource), - .resource = nuc900_usb_ohci_resource, - .dev = { - .dma_mask = &nuc900_device_usb_ohci_dmamask, - .coherent_dma_mask = 0xffffffffUL - } -}; - -/* USB Device (Gadget)*/ - -static struct resource nuc900_usbgadget_resource[] = { - [0] = { - .start = W90X900_PA_USBDEV, - .end = W90X900_PA_USBDEV + W90X900_SZ_USBDEV - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_USBD, - .end = IRQ_USBD, - .flags = IORESOURCE_IRQ, - } -}; - -static struct platform_device nuc900_device_usbgadget = { - .name = "nuc900-usbgadget", - .id = -1, - .num_resources = ARRAY_SIZE(nuc900_usbgadget_resource), - .resource = nuc900_usbgadget_resource, -}; - -/* MAC device */ - -static struct resource nuc900_emc_resource[] = { - [0] = { - .start = W90X900_PA_EMC, - .end = W90X900_PA_EMC + W90X900_SZ_EMC - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_EMCTX, - .end = IRQ_EMCTX, - .flags = IORESOURCE_IRQ, - }, - [2] = { - .start = IRQ_EMCRX, - .end = IRQ_EMCRX, - .flags = IORESOURCE_IRQ, - } -}; - -static u64 nuc900_device_emc_dmamask = 0xffffffffUL; -static struct platform_device nuc900_device_emc = { - .name = "nuc900-emc", - .id = -1, - .num_resources = ARRAY_SIZE(nuc900_emc_resource), - .resource = nuc900_emc_resource, - .dev = { - .dma_mask = &nuc900_device_emc_dmamask, - .coherent_dma_mask = 0xffffffffUL - } -}; - -/* SPI device */ - -static struct nuc900_spi_info nuc900_spiflash_data = { - .num_cs = 1, - .lsb = 0, - .txneg = 1, - .rxneg = 0, - .divider = 24, - .sleep = 0, - .txnum = 0, - .txbitlen = 8, - .bus_num = 0, -}; - -static struct resource nuc900_spi_resource[] = { - [0] = { - .start = W90X900_PA_I2C + SPIOFFSET, - .end = W90X900_PA_I2C + SPIOFFSET + SPIOREG_SIZE - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_SSP, - .end = IRQ_SSP, - .flags = IORESOURCE_IRQ, - } -}; - -static struct platform_device nuc900_device_spi = { - .name = "nuc900-spi", - .id = -1, - .num_resources = ARRAY_SIZE(nuc900_spi_resource), - .resource = nuc900_spi_resource, - .dev = { - .platform_data = &nuc900_spiflash_data, - } -}; - -/* spi device, spi flash info */ - -static struct mtd_partition nuc900_spi_flash_partitions[] = { - { - .name = "bootloader(spi)", - .size = 0x0100000, - .offset = 0, - }, -}; - -static struct flash_platform_data nuc900_spi_flash_data = { - .name = "m25p80", - .parts = nuc900_spi_flash_partitions, - .nr_parts = ARRAY_SIZE(nuc900_spi_flash_partitions), - .type = "w25x16", -}; - -static struct spi_board_info nuc900_spi_board_info[] __initdata = { - { - .modalias = "m25p80", - .max_speed_hz = 20000000, - .bus_num = 0, - .chip_select = 0, - .platform_data = &nuc900_spi_flash_data, - .mode = SPI_MODE_0, - }, -}; - -/* WDT Device */ - -static struct resource nuc900_wdt_resource[] = { - [0] = { - .start = W90X900_PA_TIMER, - .end = W90X900_PA_TIMER + W90X900_SZ_TIMER - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_WDT, - .end = IRQ_WDT, - .flags = IORESOURCE_IRQ, - } -}; - -static struct platform_device nuc900_device_wdt = { - .name = "nuc900-wdt", - .id = -1, - .num_resources = ARRAY_SIZE(nuc900_wdt_resource), - .resource = nuc900_wdt_resource, -}; - -/* - * public device definition between 910 and 920, or 910 - * and 950 or 950 and 960...,their dev platform register - * should be in specific file such as nuc950, nuc960 c - * files rather than the public dev.c file here. so the - * corresponding platform_device definition should not be - * static. -*/ - -/* RTC controller*/ - -static struct resource nuc900_rtc_resource[] = { - [0] = { - .start = W90X900_PA_RTC, - .end = W90X900_PA_RTC + 0xff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_RTC, - .end = IRQ_RTC, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device nuc900_device_rtc = { - .name = "nuc900-rtc", - .id = -1, - .num_resources = ARRAY_SIZE(nuc900_rtc_resource), - .resource = nuc900_rtc_resource, -}; - -/*TouchScreen controller*/ - -static struct resource nuc900_ts_resource[] = { - [0] = { - .start = W90X900_PA_ADC, - .end = W90X900_PA_ADC + W90X900_SZ_ADC-1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_ADC, - .end = IRQ_ADC, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device nuc900_device_ts = { - .name = "nuc900-ts", - .id = -1, - .resource = nuc900_ts_resource, - .num_resources = ARRAY_SIZE(nuc900_ts_resource), -}; - -/* FMI Device */ - -static struct resource nuc900_fmi_resource[] = { - [0] = { - .start = W90X900_PA_FMI, - .end = W90X900_PA_FMI + W90X900_SZ_FMI - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_FMI, - .end = IRQ_FMI, - .flags = IORESOURCE_IRQ, - } -}; - -struct platform_device nuc900_device_fmi = { - .name = "nuc900-fmi", - .id = -1, - .num_resources = ARRAY_SIZE(nuc900_fmi_resource), - .resource = nuc900_fmi_resource, -}; - -/* KPI controller*/ - -static int nuc900_keymap[] = { - KEY(0, 0, KEY_A), - KEY(0, 1, KEY_B), - KEY(0, 2, KEY_C), - KEY(0, 3, KEY_D), - - KEY(1, 0, KEY_E), - KEY(1, 1, KEY_F), - KEY(1, 2, KEY_G), - KEY(1, 3, KEY_H), - - KEY(2, 0, KEY_I), - KEY(2, 1, KEY_J), - KEY(2, 2, KEY_K), - KEY(2, 3, KEY_L), - - KEY(3, 0, KEY_M), - KEY(3, 1, KEY_N), - KEY(3, 2, KEY_O), - KEY(3, 3, KEY_P), -}; - -static struct matrix_keymap_data nuc900_map_data = { - .keymap = nuc900_keymap, - .keymap_size = ARRAY_SIZE(nuc900_keymap), -}; - -struct w90p910_keypad_platform_data nuc900_keypad_info = { - .keymap_data = &nuc900_map_data, - .prescale = 0xfa, - .debounce = 0x50, -}; - -static struct resource nuc900_kpi_resource[] = { - [0] = { - .start = W90X900_PA_KPI, - .end = W90X900_PA_KPI + W90X900_SZ_KPI - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_KPI, - .end = IRQ_KPI, - .flags = IORESOURCE_IRQ, - } - -}; - -struct platform_device nuc900_device_kpi = { - .name = "nuc900-kpi", - .id = -1, - .num_resources = ARRAY_SIZE(nuc900_kpi_resource), - .resource = nuc900_kpi_resource, - .dev = { - .platform_data = &nuc900_keypad_info, - } -}; - -/* LCD controller*/ - -static struct nuc900fb_display nuc900_lcd_info[] = { - /* Giantplus Technology GPM1040A0 320x240 Color TFT LCD */ - [0] = { - .type = LCM_DCCS_VA_SRC_RGB565, - .width = 320, - .height = 240, - .xres = 320, - .yres = 240, - .bpp = 16, - .pixclock = 200000, - .left_margin = 34, - .right_margin = 54, - .hsync_len = 10, - .upper_margin = 18, - .lower_margin = 4, - .vsync_len = 1, - .dccs = 0x8e00041a, - .devctl = 0x060800c0, - .fbctrl = 0x00a000a0, - .scale = 0x04000400, - }, -}; - -static struct nuc900fb_mach_info nuc900_fb_info = { -#if defined(CONFIG_GPM1040A0_320X240) - .displays = &nuc900_lcd_info[0], -#else - .displays = nuc900_lcd_info, -#endif - .num_displays = ARRAY_SIZE(nuc900_lcd_info), - .default_display = 0, - .gpio_dir = 0x00000004, - .gpio_dir_mask = 0xFFFFFFFD, - .gpio_data = 0x00000004, - .gpio_data_mask = 0xFFFFFFFD, -}; - -static struct resource nuc900_lcd_resource[] = { - [0] = { - .start = W90X900_PA_LCD, - .end = W90X900_PA_LCD + W90X900_SZ_LCD - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_LCD, - .end = IRQ_LCD, - .flags = IORESOURCE_IRQ, - } -}; - -static u64 nuc900_device_lcd_dmamask = -1; -struct platform_device nuc900_device_lcd = { - .name = "nuc900-lcd", - .id = -1, - .num_resources = ARRAY_SIZE(nuc900_lcd_resource), - .resource = nuc900_lcd_resource, - .dev = { - .dma_mask = &nuc900_device_lcd_dmamask, - .coherent_dma_mask = -1, - .platform_data = &nuc900_fb_info, - } -}; - -/* AUDIO controller*/ -static u64 nuc900_device_audio_dmamask = -1; -static struct resource nuc900_ac97_resource[] = { - [0] = { - .start = W90X900_PA_ACTL, - .end = W90X900_PA_ACTL + W90X900_SZ_ACTL - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_ACTL, - .end = IRQ_ACTL, - .flags = IORESOURCE_IRQ, - } - -}; - -struct platform_device nuc900_device_ac97 = { - .name = "nuc900-ac97", - .id = -1, - .num_resources = ARRAY_SIZE(nuc900_ac97_resource), - .resource = nuc900_ac97_resource, - .dev = { - .dma_mask = &nuc900_device_audio_dmamask, - .coherent_dma_mask = -1, - } -}; - -/*Here should be your evb resourse,such as LCD*/ - -static struct platform_device *nuc900_public_dev[] __initdata = { - &nuc900_serial_device, - &nuc900_flash_device, - &nuc900_device_usb_ehci, - &nuc900_device_usb_ohci, - &nuc900_device_usbgadget, - &nuc900_device_emc, - &nuc900_device_spi, - &nuc900_device_wdt, - &nuc900_device_ac97, -}; - -/* Provide adding specific CPU platform devices API */ - -void __init nuc900_board_init(struct platform_device **device, int size) -{ - cpu_idle_poll_ctrl(true); - platform_add_devices(device, size); - platform_add_devices(nuc900_public_dev, ARRAY_SIZE(nuc900_public_dev)); - spi_register_board_info(nuc900_spi_board_info, - ARRAY_SIZE(nuc900_spi_board_info)); -} - diff --git a/arch/arm/mach-w90x900/gpio.c b/arch/arm/mach-w90x900/gpio.c deleted file mode 100644 index cb5df211f1ed6abf160a3b92aacfda45b24b41e2..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/gpio.c +++ /dev/null @@ -1,150 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-w90x900/gpio.c - * - * Generic nuc900 GPIO handling - * - * Wan ZongShun - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define GPIO_BASE (W90X900_VA_GPIO) -#define GPIO_DIR (0x04) -#define GPIO_OUT (0x08) -#define GPIO_IN (0x0C) -#define GROUPINERV (0x10) -#define GPIO_GPIO(Nb) (0x00000001 << (Nb)) - -#define NUC900_GPIO_CHIP(name, base_gpio, nr_gpio) \ - { \ - .chip = { \ - .label = name, \ - .direction_input = nuc900_dir_input, \ - .direction_output = nuc900_dir_output, \ - .get = nuc900_gpio_get, \ - .set = nuc900_gpio_set, \ - .base = base_gpio, \ - .ngpio = nr_gpio, \ - } \ - } - -struct nuc900_gpio_chip { - struct gpio_chip chip; - void __iomem *regbase; /* Base of group register*/ - spinlock_t gpio_lock; -}; - -static int nuc900_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - struct nuc900_gpio_chip *nuc900_gpio = gpiochip_get_data(chip); - void __iomem *pio = nuc900_gpio->regbase + GPIO_IN; - unsigned int regval; - - regval = __raw_readl(pio); - regval &= GPIO_GPIO(offset); - - return (regval != 0); -} - -static void nuc900_gpio_set(struct gpio_chip *chip, unsigned offset, int val) -{ - struct nuc900_gpio_chip *nuc900_gpio = gpiochip_get_data(chip); - void __iomem *pio = nuc900_gpio->regbase + GPIO_OUT; - unsigned int regval; - unsigned long flags; - - spin_lock_irqsave(&nuc900_gpio->gpio_lock, flags); - - regval = __raw_readl(pio); - - if (val) - regval |= GPIO_GPIO(offset); - else - regval &= ~GPIO_GPIO(offset); - - __raw_writel(regval, pio); - - spin_unlock_irqrestore(&nuc900_gpio->gpio_lock, flags); -} - -static int nuc900_dir_input(struct gpio_chip *chip, unsigned offset) -{ - struct nuc900_gpio_chip *nuc900_gpio = gpiochip_get_data(chip); - void __iomem *pio = nuc900_gpio->regbase + GPIO_DIR; - unsigned int regval; - unsigned long flags; - - spin_lock_irqsave(&nuc900_gpio->gpio_lock, flags); - - regval = __raw_readl(pio); - regval &= ~GPIO_GPIO(offset); - __raw_writel(regval, pio); - - spin_unlock_irqrestore(&nuc900_gpio->gpio_lock, flags); - - return 0; -} - -static int nuc900_dir_output(struct gpio_chip *chip, unsigned offset, int val) -{ - struct nuc900_gpio_chip *nuc900_gpio = gpiochip_get_data(chip); - void __iomem *outreg = nuc900_gpio->regbase + GPIO_OUT; - void __iomem *pio = nuc900_gpio->regbase + GPIO_DIR; - unsigned int regval; - unsigned long flags; - - spin_lock_irqsave(&nuc900_gpio->gpio_lock, flags); - - regval = __raw_readl(pio); - regval |= GPIO_GPIO(offset); - __raw_writel(regval, pio); - - regval = __raw_readl(outreg); - - if (val) - regval |= GPIO_GPIO(offset); - else - regval &= ~GPIO_GPIO(offset); - - __raw_writel(regval, outreg); - - spin_unlock_irqrestore(&nuc900_gpio->gpio_lock, flags); - - return 0; -} - -static struct nuc900_gpio_chip nuc900_gpio[] = { - NUC900_GPIO_CHIP("GROUPC", 0, 16), - NUC900_GPIO_CHIP("GROUPD", 16, 10), - NUC900_GPIO_CHIP("GROUPE", 26, 14), - NUC900_GPIO_CHIP("GROUPF", 40, 10), - NUC900_GPIO_CHIP("GROUPG", 50, 17), - NUC900_GPIO_CHIP("GROUPH", 67, 8), - NUC900_GPIO_CHIP("GROUPI", 75, 17), -}; - -void __init nuc900_init_gpio(int nr_group) -{ - unsigned i; - struct nuc900_gpio_chip *gpio_chip; - - for (i = 0; i < nr_group; i++) { - gpio_chip = &nuc900_gpio[i]; - spin_lock_init(&gpio_chip->gpio_lock); - gpio_chip->regbase = GPIO_BASE + i * GROUPINERV; - gpiochip_add_data(&gpio_chip->chip, gpio_chip); - } -} diff --git a/arch/arm/mach-w90x900/include/mach/entry-macro.S b/arch/arm/mach-w90x900/include/mach/entry-macro.S deleted file mode 100644 index 0ff612ac95ba198eaf4964622abe17364d954694..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/include/mach/entry-macro.S +++ /dev/null @@ -1,26 +0,0 @@ -/* - * arch/arm/mach-w90x900/include/mach/entry-macro.S - * - * Low-level IRQ helper macros for W90P910-based platforms - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * - */ - -#include -#include - - .macro get_irqnr_preamble, base, tmp - .endm - - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - - mov \base, #AIC_BA - - ldr \irqnr, [\base, #AIC_IPER] - ldr \irqnr, [\base, #AIC_ISNR] - cmp \irqnr, #0 - - .endm diff --git a/arch/arm/mach-w90x900/include/mach/hardware.h b/arch/arm/mach-w90x900/include/mach/hardware.h deleted file mode 100644 index 137403960483edeeb46899468325dce640525786..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/include/mach/hardware.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * arch/arm/mach-w90x900/include/mach/hardware.h - * - * Copyright (c) 2008 Nuvoton technology corporation - * All rights reserved. - * - * Wan ZongShun - * - * Based on arch/arm/mach-s3c2410/include/mach/hardware.h - */ - -#ifndef __ASM_ARCH_HARDWARE_H -#define __ASM_ARCH_HARDWARE_H - -#include -#include - -#endif /* __ASM_ARCH_HARDWARE_H */ diff --git a/arch/arm/mach-w90x900/include/mach/irqs.h b/arch/arm/mach-w90x900/include/mach/irqs.h deleted file mode 100644 index 23ea01d97a022169da48b949d415bcde1a30e272..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/include/mach/irqs.h +++ /dev/null @@ -1,82 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-w90x900/include/mach/irqs.h - * - * Copyright (c) 2008 Nuvoton technology corporation. - * - * Wan ZongShun - * - * Based on arch/arm/mach-s3c2410/include/mach/irqs.h - */ - -#ifndef __ASM_ARCH_IRQS_H -#define __ASM_ARCH_IRQS_H - -/* - * we keep the first set of CPU IRQs out of the range of - * the ISA space, so that the PC104 has them to itself - * and we don't end up having to do horrible things to the - * standard ISA drivers.... - * - */ - -#define W90X900_IRQ(x) (x) - -/* Main cpu interrupts */ - -#define IRQ_WDT W90X900_IRQ(1) -#define IRQ_GROUP0 W90X900_IRQ(2) -#define IRQ_GROUP1 W90X900_IRQ(3) -#define IRQ_ACTL W90X900_IRQ(4) -#define IRQ_LCD W90X900_IRQ(5) -#define IRQ_RTC W90X900_IRQ(6) -#define IRQ_UART0 W90X900_IRQ(7) -#define IRQ_UART1 W90X900_IRQ(8) -#define IRQ_UART2 W90X900_IRQ(9) -#define IRQ_UART3 W90X900_IRQ(10) -#define IRQ_UART4 W90X900_IRQ(11) -#define IRQ_TIMER0 W90X900_IRQ(12) -#define IRQ_TIMER1 W90X900_IRQ(13) -#define IRQ_T_INT_GROUP W90X900_IRQ(14) -#define IRQ_USBH W90X900_IRQ(15) -#define IRQ_EMCTX W90X900_IRQ(16) -#define IRQ_EMCRX W90X900_IRQ(17) -#define IRQ_GDMAGROUP W90X900_IRQ(18) -#define IRQ_DMAC W90X900_IRQ(19) -#define IRQ_FMI W90X900_IRQ(20) -#define IRQ_USBD W90X900_IRQ(21) -#define IRQ_ATAPI W90X900_IRQ(22) -#define IRQ_G2D W90X900_IRQ(23) -#define IRQ_PCI W90X900_IRQ(24) -#define IRQ_SCGROUP W90X900_IRQ(25) -#define IRQ_I2CGROUP W90X900_IRQ(26) -#define IRQ_SSP W90X900_IRQ(27) -#define IRQ_PWM W90X900_IRQ(28) -#define IRQ_KPI W90X900_IRQ(29) -#define IRQ_P2SGROUP W90X900_IRQ(30) -#define IRQ_ADC W90X900_IRQ(31) -#define NR_IRQS (IRQ_ADC+1) - -/*for irq group*/ - -#define IRQ_PS2_PORT0 0x10000000 -#define IRQ_PS2_PORT1 0x20000000 -#define IRQ_I2C_LINE0 0x04000000 -#define IRQ_I2C_LINE1 0x08000000 -#define IRQ_SC_CARD0 0x01000000 -#define IRQ_SC_CARD1 0x02000000 -#define IRQ_GDMA_CH0 0x00100000 -#define IRQ_GDMA_CH1 0x00200000 -#define IRQ_TIMER2 0x00010000 -#define IRQ_TIMER3 0x00020000 -#define IRQ_TIMER4 0x00040000 -#define IRQ_GROUP0_IRQ0 0x00000001 -#define IRQ_GROUP0_IRQ1 0x00000002 -#define IRQ_GROUP0_IRQ2 0x00000004 -#define IRQ_GROUP0_IRQ3 0x00000008 -#define IRQ_GROUP1_IRQ4 0x00000010 -#define IRQ_GROUP1_IRQ5 0x00000020 -#define IRQ_GROUP1_IRQ6 0x00000040 -#define IRQ_GROUP1_IRQ7 0x00000080 - -#endif /* __ASM_ARCH_IRQ_H */ diff --git a/arch/arm/mach-w90x900/include/mach/map.h b/arch/arm/mach-w90x900/include/mach/map.h deleted file mode 100644 index 570a74e04b1ca76d72e32e5e4a21a59e4da98814..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/include/mach/map.h +++ /dev/null @@ -1,153 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-w90x900/include/mach/map.h - * - * Copyright (c) 2008 Nuvoton technology corporation. - * - * Wan ZongShun - * - * Based on arch/arm/mach-s3c2410/include/mach/map.h - */ - -#ifndef __ASM_ARCH_MAP_H -#define __ASM_ARCH_MAP_H - -#ifndef __ASSEMBLY__ -#define W90X900_ADDR(x) ((void __iomem *)(0xF0000000 + (x))) -#else -#define W90X900_ADDR(x) (0xF0000000 + (x)) -#endif - -#define AHB_IO_BASE 0xB0000000 -#define APB_IO_BASE 0xB8000000 -#define CLOCKPW_BASE (APB_IO_BASE+0x200) -#define AIC_IO_BASE (APB_IO_BASE+0x2000) -#define TIMER_IO_BASE (APB_IO_BASE+0x1000) - -/* - * interrupt controller is the first thing we put in, to make - * the assembly code for the irq detection easier - */ -#define W90X900_VA_IRQ W90X900_ADDR(0x00000000) -#define W90X900_PA_IRQ (0xB8002000) -#define W90X900_SZ_IRQ SZ_4K - -#define W90X900_VA_GCR W90X900_ADDR(0x08002000) -#define W90X900_PA_GCR (0xB0000000) -#define W90X900_SZ_GCR SZ_4K - -/* Clock and Power management */ -#define W90X900_VA_CLKPWR (W90X900_VA_GCR+0x200) -#define W90X900_PA_CLKPWR (0xB0000200) -#define W90X900_SZ_CLKPWR SZ_4K - -/* EBI management */ -#define W90X900_VA_EBI W90X900_ADDR(0x00001000) -#define W90X900_PA_EBI (0xB0001000) -#define W90X900_SZ_EBI SZ_4K - -/* UARTs */ -#define W90X900_VA_UART W90X900_ADDR(0x08000000) -#define W90X900_PA_UART (0xB8000000) -#define W90X900_SZ_UART SZ_4K - -/* Timers */ -#define W90X900_VA_TIMER W90X900_ADDR(0x08001000) -#define W90X900_PA_TIMER (0xB8001000) -#define W90X900_SZ_TIMER SZ_4K - -/* GPIO ports */ -#define W90X900_VA_GPIO W90X900_ADDR(0x08003000) -#define W90X900_PA_GPIO (0xB8003000) -#define W90X900_SZ_GPIO SZ_4K - -/* GDMA control */ -#define W90X900_VA_GDMA W90X900_ADDR(0x00004000) -#define W90X900_PA_GDMA (0xB0004000) -#define W90X900_SZ_GDMA SZ_4K - -/* USB host controller*/ -#define W90X900_VA_USBEHCIHOST W90X900_ADDR(0x00005000) -#define W90X900_PA_USBEHCIHOST (0xB0005000) -#define W90X900_SZ_USBEHCIHOST SZ_4K - -#define W90X900_VA_USBOHCIHOST W90X900_ADDR(0x00007000) -#define W90X900_PA_USBOHCIHOST (0xB0007000) -#define W90X900_SZ_USBOHCIHOST SZ_4K - -/* I2C hardware controller */ -#define W90X900_VA_I2C W90X900_ADDR(0x08006000) -#define W90X900_PA_I2C (0xB8006000) -#define W90X900_SZ_I2C SZ_4K - -/* Keypad Interface*/ -#define W90X900_VA_KPI W90X900_ADDR(0x08008000) -#define W90X900_PA_KPI (0xB8008000) -#define W90X900_SZ_KPI SZ_4K - -/* Smart card host*/ -#define W90X900_VA_SC W90X900_ADDR(0x08005000) -#define W90X900_PA_SC (0xB8005000) -#define W90X900_SZ_SC SZ_4K - -/* LCD controller*/ -#define W90X900_VA_LCD W90X900_ADDR(0x00008000) -#define W90X900_PA_LCD (0xB0008000) -#define W90X900_SZ_LCD SZ_4K - -/* 2D controller*/ -#define W90X900_VA_GE W90X900_ADDR(0x0000B000) -#define W90X900_PA_GE (0xB000B000) -#define W90X900_SZ_GE SZ_4K - -/* ATAPI */ -#define W90X900_VA_ATAPI W90X900_ADDR(0x0000A000) -#define W90X900_PA_ATAPI (0xB000A000) -#define W90X900_SZ_ATAPI SZ_4K - -/* ADC */ -#define W90X900_VA_ADC W90X900_ADDR(0x0800A000) -#define W90X900_PA_ADC (0xB800A000) -#define W90X900_SZ_ADC SZ_4K - -/* PS2 Interface*/ -#define W90X900_VA_PS2 W90X900_ADDR(0x08009000) -#define W90X900_PA_PS2 (0xB8009000) -#define W90X900_SZ_PS2 SZ_4K - -/* RTC */ -#define W90X900_VA_RTC W90X900_ADDR(0x08004000) -#define W90X900_PA_RTC (0xB8004000) -#define W90X900_SZ_RTC SZ_4K - -/* Pulse Width Modulation(PWM) Registers */ -#define W90X900_VA_PWM W90X900_ADDR(0x08007000) -#define W90X900_PA_PWM (0xB8007000) -#define W90X900_SZ_PWM SZ_4K - -/* Audio Controller controller */ -#define W90X900_VA_ACTL W90X900_ADDR(0x00009000) -#define W90X900_PA_ACTL (0xB0009000) -#define W90X900_SZ_ACTL SZ_4K - -/* DMA controller */ -#define W90X900_VA_DMA W90X900_ADDR(0x0000c000) -#define W90X900_PA_DMA (0xB000c000) -#define W90X900_SZ_DMA SZ_4K - -/* FMI controller */ -#define W90X900_VA_FMI W90X900_ADDR(0x0000d000) -#define W90X900_PA_FMI (0xB000d000) -#define W90X900_SZ_FMI SZ_4K - -/* USB Device port */ -#define W90X900_VA_USBDEV W90X900_ADDR(0x00006000) -#define W90X900_PA_USBDEV (0xB0006000) -#define W90X900_SZ_USBDEV SZ_4K - -/* External MAC control*/ -#define W90X900_VA_EMC W90X900_ADDR(0x00003000) -#define W90X900_PA_EMC (0xB0003000) -#define W90X900_SZ_EMC SZ_4K - -#endif /* __ASM_ARCH_MAP_H */ diff --git a/arch/arm/mach-w90x900/include/mach/mfp.h b/arch/arm/mach-w90x900/include/mach/mfp.h deleted file mode 100644 index be5485efab0a2270c8d0019bca1507f39c16b8cc..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/include/mach/mfp.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-w90x900/include/mach/mfp.h - * - * Copyright (c) 2010 Nuvoton technology corporation. - * - * Wan ZongShun - * - * Based on arch/arm/mach-s3c2410/include/mach/map.h - */ - -#ifndef __ASM_ARCH_MFP_H -#define __ASM_ARCH_MFP_H - -extern void mfp_set_groupf(struct device *dev); -extern void mfp_set_groupc(struct device *dev); -extern void mfp_set_groupi(struct device *dev); -extern void mfp_set_groupg(struct device *dev, const char *subname); -extern void mfp_set_groupd(struct device *dev, const char *subname); - -#endif /* __ASM_ARCH_MFP_H */ diff --git a/arch/arm/mach-w90x900/include/mach/regs-clock.h b/arch/arm/mach-w90x900/include/mach/regs-clock.h deleted file mode 100644 index f06245d26bd79c315dbcd1825c858fe4b4067b1f..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/include/mach/regs-clock.h +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-w90x900/include/mach/regs-clock.h - * - * Copyright (c) 2008 Nuvoton technology corporation. - * - * Wan ZongShun - */ - -#ifndef __ASM_ARCH_REGS_CLOCK_H -#define __ASM_ARCH_REGS_CLOCK_H - -/* Clock Control Registers */ -#define CLK_BA W90X900_VA_CLKPWR -#define REG_CLKEN (CLK_BA + 0x00) -#define REG_CLKSEL (CLK_BA + 0x04) -#define REG_CLKDIV (CLK_BA + 0x08) -#define REG_PLLCON0 (CLK_BA + 0x0C) -#define REG_PLLCON1 (CLK_BA + 0x10) -#define REG_PMCON (CLK_BA + 0x14) -#define REG_IRQWAKECON (CLK_BA + 0x18) -#define REG_IRQWAKEFLAG (CLK_BA + 0x1C) -#define REG_IPSRST (CLK_BA + 0x20) -#define REG_CLKEN1 (CLK_BA + 0x24) -#define REG_CLKDIV1 (CLK_BA + 0x28) - -/* Define PLL freq setting */ -#define PLL_DISABLE 0x12B63 -#define PLL_66MHZ 0x2B63 -#define PLL_100MHZ 0x4F64 -#define PLL_120MHZ 0x4F63 -#define PLL_166MHZ 0x4124 -#define PLL_200MHZ 0x4F24 - -/* Define AHB:CPUFREQ ratio */ -#define AHB_CPUCLK_1_1 0x00 -#define AHB_CPUCLK_1_2 0x01 -#define AHB_CPUCLK_1_4 0x02 -#define AHB_CPUCLK_1_8 0x03 - -/* Define APB:AHB ratio */ -#define APB_AHB_1_2 0x01 -#define APB_AHB_1_4 0x02 -#define APB_AHB_1_8 0x03 - -/* Define clock skew */ -#define DEFAULTSKEW 0x48 - -#endif /* __ASM_ARCH_REGS_CLOCK_H */ diff --git a/arch/arm/mach-w90x900/include/mach/regs-irq.h b/arch/arm/mach-w90x900/include/mach/regs-irq.h deleted file mode 100644 index 89fcbc60b60a2910a631b53bde294f1a129e7ca0..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/include/mach/regs-irq.h +++ /dev/null @@ -1,46 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * arch/arm/mach-w90x900/include/mach/regs-irq.h - * - * Copyright (c) 2008 Nuvoton technology corporation - * All rights reserved. - * - * Wan ZongShun - * - * Based on arch/arm/mach-s3c2410/include/mach/regs-irq.h - */ - -#ifndef ___ASM_ARCH_REGS_IRQ_H -#define ___ASM_ARCH_REGS_IRQ_H - -/* Advance Interrupt Controller (AIC) Registers */ - -#define AIC_BA W90X900_VA_IRQ - -#define REG_AIC_IRQSC (AIC_BA+0x80) -#define REG_AIC_GEN (AIC_BA+0x84) -#define REG_AIC_GASR (AIC_BA+0x88) -#define REG_AIC_GSCR (AIC_BA+0x8C) -#define REG_AIC_IRSR (AIC_BA+0x100) -#define REG_AIC_IASR (AIC_BA+0x104) -#define REG_AIC_ISR (AIC_BA+0x108) -#define REG_AIC_IPER (AIC_BA+0x10C) -#define REG_AIC_ISNR (AIC_BA+0x110) -#define REG_AIC_IMR (AIC_BA+0x114) -#define REG_AIC_OISR (AIC_BA+0x118) -#define REG_AIC_MECR (AIC_BA+0x120) -#define REG_AIC_MDCR (AIC_BA+0x124) -#define REG_AIC_SSCR (AIC_BA+0x128) -#define REG_AIC_SCCR (AIC_BA+0x12C) -#define REG_AIC_EOSCR (AIC_BA+0x130) -#define AIC_IPER (0x10C) -#define AIC_ISNR (0x110) - -/*16-18 bits of REG_AIC_GEN define irq(2-4) group*/ - -#define TIMER2_IRQ (1 << 16) -#define TIMER3_IRQ (1 << 17) -#define TIMER4_IRQ (1 << 18) -#define TIME_GROUP_IRQ (TIMER2_IRQ|TIMER3_IRQ|TIMER4_IRQ) - -#endif /* ___ASM_ARCH_REGS_IRQ_H */ diff --git a/arch/arm/mach-w90x900/include/mach/regs-ldm.h b/arch/arm/mach-w90x900/include/mach/regs-ldm.h deleted file mode 100644 index ffe7e67c99ded0d7652c1328f98777ae5bc4b751..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/include/mach/regs-ldm.h +++ /dev/null @@ -1,248 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * arch/arm/mach-w90x900/include/mach/regs-serial.h - * - * Copyright (c) 2009 Nuvoton technology corporation - * All rights reserved. - * - * Description: - * Nuvoton Display, LCM Register list - * Author: Wang Qiang (rurality.linux@gmail.com) 2009/12/11 - */ - - -#ifndef __ASM_ARM_W90X900_REGS_LDM_H -#define __ASM_ARM_W90X900_REGS_LDM_H - -#include - -/* Display Controller Control/Status Register */ -#define REG_LCM_DCCS (0x00) - -#define LCM_DCCS_ENG_RST (1 << 0) -#define LCM_DCCS_VA_EN (1 << 1) -#define LCM_DCCS_OSD_EN (1 << 2) -#define LCM_DCCS_DISP_OUT_EN (1 << 3) -#define LCM_DCCS_DISP_INT_EN (1 << 4) -#define LCM_DCCS_CMD_ON (1 << 5) -#define LCM_DCCS_FIELD_INTR (1 << 6) -#define LCM_DCCS_SINGLE (1 << 7) - -enum LCM_DCCS_VA_SRC { - LCM_DCCS_VA_SRC_YUV422 = (0 << 8), - LCM_DCCS_VA_SRC_YCBCR422 = (1 << 8), - LCM_DCCS_VA_SRC_RGB888 = (2 << 8), - LCM_DCCS_VA_SRC_RGB666 = (3 << 8), - LCM_DCCS_VA_SRC_RGB565 = (4 << 8), - LCM_DCCS_VA_SRC_RGB444LOW = (5 << 8), - LCM_DCCS_VA_SRC_RGB444HIGH = (7 << 8) -}; - - -/* Display Device Control Register */ -#define REG_LCM_DEV_CTRL (0x04) - -enum LCM_DEV_CTRL_SWAP_YCbCr { - LCM_DEV_CTRL_SWAP_UYVY = (0 << 1), - LCM_DEV_CTRL_SWAP_YUYV = (1 << 1), - LCM_DEV_CTRL_SWAP_VYUY = (2 << 1), - LCM_DEV_CTRL_SWAP_YVYU = (3 << 1) -}; - -enum LCM_DEV_CTRL_RGB_SHIFT { - LCM_DEV_CTRL_RGB_SHIFT_NOT = (0 << 3), - LCM_DEV_CTRL_RGB_SHIFT_ONECYCLE = (1 << 3), - LCM_DEV_CTRL_RGB_SHIFT_TWOCYCLE = (2 << 3), - LCM_DEV_CTRL_RGB_SHIFT_NOT_DEF = (3 << 3) -}; - -enum LCM_DEV_CTRL_DEVICE { - LCM_DEV_CTRL_DEVICE_YUV422 = (0 << 5), - LCM_DEV_CTRL_DEVICE_YUV444 = (1 << 5), - LCM_DEV_CTRL_DEVICE_UNIPAC = (4 << 5), - LCM_DEV_CTRL_DEVICE_SEIKO_EPSON = (5 << 5), - LCM_DEV_CTRL_DEVICE_HIGH_COLOR = (6 << 5), - LCM_DEV_CTRL_DEVICE_MPU = (7 << 5) -}; - -#define LCM_DEV_CTRL_LCD_DDA (8) -#define LCM_DEV_CTRL_YUV2CCIR (16) - -enum LCM_DEV_CTRL_LCD_SEL { - LCM_DEV_CTRL_LCD_SEL_RGB_GBR = (0 << 17), - LCM_DEV_CTRL_LCD_SEL_BGR_RBG = (1 << 17), - LCM_DEV_CTRL_LCD_SEL_GBR_RGB = (2 << 17), - LCM_DEV_CTRL_LCD_SEL_RBG_BGR = (3 << 17) -}; - -enum LCM_DEV_CTRL_FAL_D { - LCM_DEV_CTRL_FAL_D_FALLING = (0 << 19), - LCM_DEV_CTRL_FAL_D_RISING = (1 << 19), -}; - -enum LCM_DEV_CTRL_H_POL { - LCM_DEV_CTRL_H_POL_LOW = (0 << 20), - LCM_DEV_CTRL_H_POL_HIGH = (1 << 20), -}; - -enum LCM_DEV_CTRL_V_POL { - LCM_DEV_CTRL_V_POL_LOW = (0 << 21), - LCM_DEV_CTRL_V_POL_HIGH = (1 << 21), -}; - -enum LCM_DEV_CTRL_VR_LACE { - LCM_DEV_CTRL_VR_LACE_NINTERLACE = (0 << 22), - LCM_DEV_CTRL_VR_LACE_INTERLACE = (1 << 22), -}; - -enum LCM_DEV_CTRL_LACE { - LCM_DEV_CTRL_LACE_NINTERLACE = (0 << 23), - LCM_DEV_CTRL_LACE_INTERLACE = (1 << 23), -}; - -enum LCM_DEV_CTRL_RGB_SCALE { - LCM_DEV_CTRL_RGB_SCALE_4096 = (0 << 24), - LCM_DEV_CTRL_RGB_SCALE_65536 = (1 << 24), - LCM_DEV_CTRL_RGB_SCALE_262144 = (2 << 24), - LCM_DEV_CTRL_RGB_SCALE_16777216 = (3 << 24), -}; - -enum LCM_DEV_CTRL_DBWORD { - LCM_DEV_CTRL_DBWORD_HALFWORD = (0 << 26), - LCM_DEV_CTRL_DBWORD_FULLWORD = (1 << 26), -}; - -enum LCM_DEV_CTRL_MPU68 { - LCM_DEV_CTRL_MPU68_80_SERIES = (0 << 27), - LCM_DEV_CTRL_MPU68_68_SERIES = (1 << 27), -}; - -enum LCM_DEV_CTRL_DE_POL { - LCM_DEV_CTRL_DE_POL_HIGH = (0 << 28), - LCM_DEV_CTRL_DE_POL_LOW = (1 << 28), -}; - -#define LCM_DEV_CTRL_CMD16 (29) -#define LCM_DEV_CTRL_CM16t18 (30) -#define LCM_DEV_CTRL_CMD_LOW (31) - -/* MPU-Interface LCD Write Command */ -#define REG_LCM_MPU_CMD (0x08) - -/* Interrupt Control/Status Register */ -#define REG_LCM_INT_CS (0x0c) -#define LCM_INT_CS_DISP_F_EN (1 << 0) -#define LCM_INT_CS_UNDERRUN_EN (1 << 1) -#define LCM_INT_CS_BUS_ERROR_INT (1 << 28) -#define LCM_INT_CS_UNDERRUN_INT (1 << 29) -#define LCM_INT_CS_DISP_F_STATUS (1 << 30) -#define LCM_INT_CS_DISP_F_INT (1 << 31) - -/* CRTC Display Size Control Register */ -#define REG_LCM_CRTC_SIZE (0x10) -#define LCM_CRTC_SIZE_VTTVAL(x) ((x) << 16) -#define LCM_CRTC_SIZE_HTTVAL(x) ((x) << 0) - -/* CRTC Display Enable End */ -#define REG_LCM_CRTC_DEND (0x14) -#define LCM_CRTC_DEND_VDENDVAL(x) ((x) << 16) -#define LCM_CRTC_DEND_HDENDVAL(x) ((x) << 0) - -/* CRTC Internal Horizontal Retrace Control Register */ -#define REG_LCM_CRTC_HR (0x18) -#define LCM_CRTC_HR_EVAL(x) ((x) << 16) -#define LCM_CRTC_HR_SVAL(x) ((x) << 0) - -/* CRTC Horizontal Sync Control Register */ -#define REG_LCM_CRTC_HSYNC (0x1C) -#define LCM_CRTC_HSYNC_SHIFTVAL(x) ((x) << 30) -#define LCM_CRTC_HSYNC_EVAL(x) ((x) << 16) -#define LCM_CRTC_HSYNC_SVAL(x) ((x) << 0) - -/* CRTC Internal Vertical Retrace Control Register */ -#define REG_LCM_CRTC_VR (0x20) -#define LCM_CRTC_VR_EVAL(x) ((x) << 16) -#define LCM_CRTC_VR_SVAL(x) ((x) << 0) - -/* Video Stream Frame Buffer-0 Starting Address */ -#define REG_LCM_VA_BADDR0 (0x24) - -/* Video Stream Frame Buffer-1 Starting Address */ -#define REG_LCM_VA_BADDR1 (0x28) - -/* Video Stream Frame Buffer Control Register */ -#define REG_LCM_VA_FBCTRL (0x2C) -#define LCM_VA_FBCTRL_IO_REGION_HALF (1 << 28) -#define LCM_VA_FBCTRL_FIELD_DUAL (1 << 29) -#define LCM_VA_FBCTRL_START_BUF (1 << 30) -#define LCM_VA_FBCTRL_DB_EN (1 << 31) - -/* Video Stream Scaling Control Register */ -#define REG_LCM_VA_SCALE (0x30) -#define LCM_VA_SCALE_XCOPY_INTERPOLATION (0 << 15) -#define LCM_VA_SCALE_XCOPY_DUPLICATION (1 << 15) - -/* Image Stream Active Window Coordinates */ -#define REG_LCM_VA_WIN (0x38) - -/* Image Stream Stuff Pixel */ -#define REG_LCM_VA_STUFF (0x3C) - -/* OSD Window Starting Coordinates */ -#define REG_LCM_OSD_WINS (0x40) - -/* OSD Window Ending Coordinates */ -#define REG_LCM_OSD_WINE (0x44) - -/* OSD Stream Frame Buffer Starting Address */ -#define REG_LCM_OSD_BADDR (0x48) - -/* OSD Stream Frame Buffer Control Register */ -#define REG_LCM_OSD_FBCTRL (0x4c) - -/* OSD Overlay Control Register */ -#define REG_LCM_OSD_OVERLAY (0x50) - -/* OSD Overlay Color-Key Pattern Register */ -#define REG_LCM_OSD_CKEY (0x54) - -/* OSD Overlay Color-Key Mask Register */ -#define REG_LCM_OSD_CMASK (0x58) - -/* OSD Window Skip1 Register */ -#define REG_LCM_OSD_SKIP1 (0x5C) - -/* OSD Window Skip2 Register */ -#define REG_LCM_OSD_SKIP2 (0x60) - -/* OSD horizontal up scaling control register */ -#define REG_LCM_OSD_SCALE (0x64) - -/* MPU Vsync control register */ -#define REG_LCM_MPU_VSYNC (0x68) - -/* Hardware cursor control Register */ -#define REG_LCM_HC_CTRL (0x6C) - -/* Hardware cursot tip point potison on va picture */ -#define REG_LCM_HC_POS (0x70) - -/* Hardware Cursor Window Buffer Control Register */ -#define REG_LCM_HC_WBCTRL (0x74) - -/* Hardware cursor memory base address register */ -#define REG_LCM_HC_BADDR (0x78) - -/* Hardware cursor color ram register mapped to bpp = 0 */ -#define REG_LCM_HC_COLOR0 (0x7C) - -/* Hardware cursor color ram register mapped to bpp = 1 */ -#define REG_LCM_HC_COLOR1 (0x80) - -/* Hardware cursor color ram register mapped to bpp = 2 */ -#define REG_LCM_HC_COLOR2 (0x84) - -/* Hardware cursor color ram register mapped to bpp = 3 */ -#define REG_LCM_HC_COLOR3 (0x88) - -#endif /* __ASM_ARM_W90X900_REGS_LDM_H */ diff --git a/arch/arm/mach-w90x900/include/mach/regs-serial.h b/arch/arm/mach-w90x900/include/mach/regs-serial.h deleted file mode 100644 index 797c9727a15704cd6baad42e8290a057fd0abf23..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/include/mach/regs-serial.h +++ /dev/null @@ -1,54 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * arch/arm/mach-w90x900/include/mach/regs-serial.h - * - * Copyright (c) 2008 Nuvoton technology corporation - * All rights reserved. - * - * Wan ZongShun - * - * Based on arch/arm/mach-s3c2410/include/mach/regs-serial.h - */ - -#ifndef __ASM_ARM_REGS_SERIAL_H -#define __ASM_ARM_REGS_SERIAL_H - -#define UART0_BA W90X900_VA_UART -#define UART1_BA (W90X900_VA_UART+0x100) -#define UART2_BA (W90X900_VA_UART+0x200) -#define UART3_BA (W90X900_VA_UART+0x300) -#define UART4_BA (W90X900_VA_UART+0x400) - -#define UART0_PA W90X900_PA_UART -#define UART1_PA (W90X900_PA_UART+0x100) -#define UART2_PA (W90X900_PA_UART+0x200) -#define UART3_PA (W90X900_PA_UART+0x300) -#define UART4_PA (W90X900_PA_UART+0x400) - -#ifndef __ASSEMBLY__ - -struct w90x900_uart_clksrc { - const char *name; - unsigned int divisor; - unsigned int min_baud; - unsigned int max_baud; -}; - -struct w90x900_uartcfg { - unsigned char hwport; - unsigned char unused; - unsigned short flags; - unsigned long uart_flags; - - unsigned long ucon; - unsigned long ulcon; - unsigned long ufcon; - - struct w90x900_uart_clksrc *clocks; - unsigned int clocks_size; -}; - -#endif /* __ASSEMBLY__ */ - -#endif /* __ASM_ARM_REGS_SERIAL_H */ - diff --git a/arch/arm/mach-w90x900/include/mach/uncompress.h b/arch/arm/mach-w90x900/include/mach/uncompress.h deleted file mode 100644 index 32e92a77ccae57d148c5c0e0a100b3bcfcb811e7..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/include/mach/uncompress.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * arch/arm/mach-w90x900/include/mach/uncompress.h - * - * Copyright (c) 2008 Nuvoton technology corporation - * All rights reserved. - * - * Wan ZongShun - * - * Based on arch/arm/mach-s3c2410/include/mach/uncompress.h - */ - -#ifndef __ASM_ARCH_UNCOMPRESS_H -#define __ASM_ARCH_UNCOMPRESS_H - -/* Defines for UART registers */ - -#include -#include -#include - -#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE) -static volatile u32 * const uart_base = (u32 *)UART0_PA; - -static inline void putc(int ch) -{ - /* Check THRE and TEMT bits before we transmit the character. - */ - while ((uart_base[UART_LSR] & TX_DONE) != TX_DONE) - barrier(); - - *uart_base = ch; -} - -static inline void flush(void) -{ -} - -static void arch_decomp_setup(void) -{ -} - -#endif/* __ASM_W90X900_UNCOMPRESS_H */ diff --git a/arch/arm/mach-w90x900/irq.c b/arch/arm/mach-w90x900/irq.c deleted file mode 100644 index 081b0f65477af06034949c44d941b4581c0fd3b2..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/irq.c +++ /dev/null @@ -1,212 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-w90x900/irq.c - * - * based on linux/arch/arm/plat-s3c24xx/irq.c by Ben Dooks - * - * Copyright (c) 2008 Nuvoton technology corporation - * All rights reserved. - * - * Wan ZongShun - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "nuc9xx.h" - -struct group_irq { - unsigned long gpen; - unsigned int enabled; - void (*enable)(struct group_irq *, int enable); -}; - -static DEFINE_SPINLOCK(groupirq_lock); - -#define DEFINE_GROUP(_name, _ctrlbit, _num) \ -struct group_irq group_##_name = { \ - .enable = nuc900_group_enable, \ - .gpen = ((1 << _num) - 1) << _ctrlbit, \ - } - -static void nuc900_group_enable(struct group_irq *gpirq, int enable); - -static DEFINE_GROUP(nirq0, 0, 4); -static DEFINE_GROUP(nirq1, 4, 4); -static DEFINE_GROUP(usbh, 8, 2); -static DEFINE_GROUP(ottimer, 16, 3); -static DEFINE_GROUP(gdma, 20, 2); -static DEFINE_GROUP(sc, 24, 2); -static DEFINE_GROUP(i2c, 26, 2); -static DEFINE_GROUP(ps2, 28, 2); - -static int group_irq_enable(struct group_irq *group_irq) -{ - unsigned long flags; - - spin_lock_irqsave(&groupirq_lock, flags); - if (group_irq->enabled++ == 0) - (group_irq->enable)(group_irq, 1); - spin_unlock_irqrestore(&groupirq_lock, flags); - - return 0; -} - -static void group_irq_disable(struct group_irq *group_irq) -{ - unsigned long flags; - - WARN_ON(group_irq->enabled == 0); - - spin_lock_irqsave(&groupirq_lock, flags); - if (--group_irq->enabled == 0) - (group_irq->enable)(group_irq, 0); - spin_unlock_irqrestore(&groupirq_lock, flags); -} - -static void nuc900_group_enable(struct group_irq *gpirq, int enable) -{ - unsigned int groupen = gpirq->gpen; - unsigned long regval; - - regval = __raw_readl(REG_AIC_GEN); - - if (enable) - regval |= groupen; - else - regval &= ~groupen; - - __raw_writel(regval, REG_AIC_GEN); -} - -static void nuc900_irq_mask(struct irq_data *d) -{ - struct group_irq *group_irq; - - group_irq = NULL; - - __raw_writel(1 << d->irq, REG_AIC_MDCR); - - switch (d->irq) { - case IRQ_GROUP0: - group_irq = &group_nirq0; - break; - - case IRQ_GROUP1: - group_irq = &group_nirq1; - break; - - case IRQ_USBH: - group_irq = &group_usbh; - break; - - case IRQ_T_INT_GROUP: - group_irq = &group_ottimer; - break; - - case IRQ_GDMAGROUP: - group_irq = &group_gdma; - break; - - case IRQ_SCGROUP: - group_irq = &group_sc; - break; - - case IRQ_I2CGROUP: - group_irq = &group_i2c; - break; - - case IRQ_P2SGROUP: - group_irq = &group_ps2; - break; - } - - if (group_irq) - group_irq_disable(group_irq); -} - -/* - * By the w90p910 spec,any irq,only write 1 - * to REG_AIC_EOSCR for ACK - */ - -static void nuc900_irq_ack(struct irq_data *d) -{ - __raw_writel(0x01, REG_AIC_EOSCR); -} - -static void nuc900_irq_unmask(struct irq_data *d) -{ - struct group_irq *group_irq; - - group_irq = NULL; - - __raw_writel(1 << d->irq, REG_AIC_MECR); - - switch (d->irq) { - case IRQ_GROUP0: - group_irq = &group_nirq0; - break; - - case IRQ_GROUP1: - group_irq = &group_nirq1; - break; - - case IRQ_USBH: - group_irq = &group_usbh; - break; - - case IRQ_T_INT_GROUP: - group_irq = &group_ottimer; - break; - - case IRQ_GDMAGROUP: - group_irq = &group_gdma; - break; - - case IRQ_SCGROUP: - group_irq = &group_sc; - break; - - case IRQ_I2CGROUP: - group_irq = &group_i2c; - break; - - case IRQ_P2SGROUP: - group_irq = &group_ps2; - break; - } - - if (group_irq) - group_irq_enable(group_irq); -} - -static struct irq_chip nuc900_irq_chip = { - .irq_ack = nuc900_irq_ack, - .irq_mask = nuc900_irq_mask, - .irq_unmask = nuc900_irq_unmask, -}; - -void __init nuc900_init_irq(void) -{ - int irqno; - - __raw_writel(0xFFFFFFFE, REG_AIC_MDCR); - - for (irqno = IRQ_WDT; irqno <= IRQ_ADC; irqno++) { - irq_set_chip_and_handler(irqno, &nuc900_irq_chip, - handle_level_irq); - irq_clear_status_flags(irqno, IRQ_NOREQUEST); - } -} diff --git a/arch/arm/mach-w90x900/mach-nuc910evb.c b/arch/arm/mach-w90x900/mach-nuc910evb.c deleted file mode 100644 index e6d30af3e35aa58444ab4f1d1e30652995584ed7..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/mach-nuc910evb.c +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-w90x900/mach-nuc910evb.c - * - * Based on mach-s3c2410/mach-smdk2410.c by Jonas Dietsche - * - * Copyright (C) 2008 Nuvoton technology corporation. - * - * Wan ZongShun - */ - -#include -#include -#include -#include -#include - -#include "nuc910.h" - -static void __init nuc910evb_map_io(void) -{ - nuc910_map_io(); - nuc910_init_clocks(); -} - -static void __init nuc910evb_init(void) -{ - nuc910_board_init(); -} - -MACHINE_START(W90P910EVB, "W90P910EVB") - /* Maintainer: Wan ZongShun */ - .map_io = nuc910evb_map_io, - .init_irq = nuc900_init_irq, - .init_machine = nuc910evb_init, - .init_time = nuc900_timer_init, - .restart = nuc9xx_restart, -MACHINE_END diff --git a/arch/arm/mach-w90x900/mach-nuc950evb.c b/arch/arm/mach-w90x900/mach-nuc950evb.c deleted file mode 100644 index 62547308c344ae5776efbc128b599879e9024e98..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/mach-nuc950evb.c +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-w90x900/mach-nuc950evb.c - * - * Based on mach-s3c2410/mach-smdk2410.c by Jonas Dietsche - * - * Copyright (C) 2008 Nuvoton technology corporation. - * - * Wan ZongShun - * - * history: - * Wang Qiang (rurality.linux@gmail.com) add LCD support - */ - -#include -#include -#include -#include -#include -#include - -#include "nuc950.h" - -static void __init nuc950evb_map_io(void) -{ - nuc950_map_io(); - nuc950_init_clocks(); -} - -static void __init nuc950evb_init(void) -{ - nuc950_board_init(); -} - -MACHINE_START(W90P950EVB, "W90P950EVB") - /* Maintainer: Wan ZongShun */ - .map_io = nuc950evb_map_io, - .init_irq = nuc900_init_irq, - .init_machine = nuc950evb_init, - .init_time = nuc900_timer_init, - .restart = nuc9xx_restart, -MACHINE_END diff --git a/arch/arm/mach-w90x900/mach-nuc960evb.c b/arch/arm/mach-w90x900/mach-nuc960evb.c deleted file mode 100644 index 35a53459d0d2148c268a0a9d9674b245f579e73f..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/mach-nuc960evb.c +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-w90x900/mach-nuc960evb.c - * - * Based on mach-s3c2410/mach-smdk2410.c by Jonas Dietsche - * - * Copyright (C) 2008 Nuvoton technology corporation. - * - * Wan ZongShun - */ - -#include -#include -#include -#include -#include - -#include "nuc960.h" - -static void __init nuc960evb_map_io(void) -{ - nuc960_map_io(); - nuc960_init_clocks(); -} - -static void __init nuc960evb_init(void) -{ - nuc960_board_init(); -} - -MACHINE_START(W90N960EVB, "W90N960EVB") - /* Maintainer: Wan ZongShun */ - .map_io = nuc960evb_map_io, - .init_irq = nuc900_init_irq, - .init_machine = nuc960evb_init, - .init_time = nuc900_timer_init, - .restart = nuc9xx_restart, -MACHINE_END diff --git a/arch/arm/mach-w90x900/mfp.c b/arch/arm/mach-w90x900/mfp.c deleted file mode 100644 index 05f3779a36189cd70baebdfe9a42233a6f10dfeb..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/mfp.c +++ /dev/null @@ -1,197 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-w90x900/mfp.c - * - * Copyright (c) 2008 Nuvoton technology corporation - * - * Wan ZongShun - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define REG_MFSEL (W90X900_VA_GCR + 0xC) - -#define GPSELF (0x01 << 1) -#define GPSELC (0x03 << 2) -#define GPSELD (0x0f << 4) - -#define GPSELEI0 (0x01 << 26) -#define GPSELEI1 (0x01 << 27) - -#define GPIOG0TO1 (0x03 << 14) -#define GPIOG2TO3 (0x03 << 16) -#define GPIOG22TO23 (0x03 << 22) -#define GPIOG18TO20 (0x07 << 18) - -#define ENSPI (0x0a << 14) -#define ENI2C0 (0x01 << 14) -#define ENI2C1 (0x01 << 16) -#define ENAC97 (0x02 << 22) -#define ENSD1 (0x02 << 18) -#define ENSD0 (0x0a << 4) -#define ENKPI (0x02 << 2) -#define ENNAND (0x01 << 2) - -static DEFINE_MUTEX(mfp_mutex); - -void mfp_set_groupf(struct device *dev) -{ - unsigned long mfpen; - const char *dev_id; - - BUG_ON(!dev); - - mutex_lock(&mfp_mutex); - - dev_id = dev_name(dev); - - mfpen = __raw_readl(REG_MFSEL); - - if (strcmp(dev_id, "nuc900-emc") == 0) - mfpen |= GPSELF;/*enable mac*/ - else - mfpen &= ~GPSELF;/*GPIOF[9:0]*/ - - __raw_writel(mfpen, REG_MFSEL); - - mutex_unlock(&mfp_mutex); -} -EXPORT_SYMBOL(mfp_set_groupf); - -void mfp_set_groupc(struct device *dev) -{ - unsigned long mfpen; - const char *dev_id; - - BUG_ON(!dev); - - mutex_lock(&mfp_mutex); - - dev_id = dev_name(dev); - - mfpen = __raw_readl(REG_MFSEL); - - if (strcmp(dev_id, "nuc900-lcd") == 0) - mfpen |= GPSELC;/*enable lcd*/ - else if (strcmp(dev_id, "nuc900-kpi") == 0) { - mfpen &= (~GPSELC);/*enable kpi*/ - mfpen |= ENKPI; - } else if (strcmp(dev_id, "nuc900-nand") == 0) { - mfpen &= (~GPSELC);/*enable nand*/ - mfpen |= ENNAND; - } else - mfpen &= (~GPSELC);/*GPIOC[14:0]*/ - - __raw_writel(mfpen, REG_MFSEL); - - mutex_unlock(&mfp_mutex); -} -EXPORT_SYMBOL(mfp_set_groupc); - -void mfp_set_groupi(struct device *dev) -{ - unsigned long mfpen; - const char *dev_id; - - BUG_ON(!dev); - - mutex_lock(&mfp_mutex); - - dev_id = dev_name(dev); - - mfpen = __raw_readl(REG_MFSEL); - - mfpen &= ~GPSELEI1;/*default gpio16*/ - - if (strcmp(dev_id, "nuc900-wdog") == 0) - mfpen |= GPSELEI1;/*enable wdog*/ - else if (strcmp(dev_id, "nuc900-atapi") == 0) - mfpen |= GPSELEI0;/*enable atapi*/ - else if (strcmp(dev_id, "nuc900-keypad") == 0) - mfpen &= ~GPSELEI0;/*enable keypad*/ - - __raw_writel(mfpen, REG_MFSEL); - - mutex_unlock(&mfp_mutex); -} -EXPORT_SYMBOL(mfp_set_groupi); - -void mfp_set_groupg(struct device *dev, const char *subname) -{ - unsigned long mfpen; - const char *dev_id; - - BUG_ON((!dev) && (!subname)); - - mutex_lock(&mfp_mutex); - - if (subname != NULL) - dev_id = subname; - else - dev_id = dev_name(dev); - - mfpen = __raw_readl(REG_MFSEL); - - if (strcmp(dev_id, "nuc900-spi") == 0) { - mfpen &= ~(GPIOG0TO1 | GPIOG2TO3); - mfpen |= ENSPI;/*enable spi*/ - } else if (strcmp(dev_id, "nuc900-i2c0") == 0) { - mfpen &= ~(GPIOG0TO1); - mfpen |= ENI2C0;/*enable i2c0*/ - } else if (strcmp(dev_id, "nuc900-i2c1") == 0) { - mfpen &= ~(GPIOG2TO3); - mfpen |= ENI2C1;/*enable i2c1*/ - } else if (strcmp(dev_id, "nuc900-ac97") == 0) { - mfpen &= ~(GPIOG22TO23); - mfpen |= ENAC97;/*enable AC97*/ - } else if (strcmp(dev_id, "nuc900-mmc-port1") == 0) { - mfpen &= ~(GPIOG18TO20); - mfpen |= (ENSD1 | 0x01);/*enable sd1*/ - } else { - mfpen &= ~(GPIOG0TO1 | GPIOG2TO3);/*GPIOG[3:0]*/ - } - - __raw_writel(mfpen, REG_MFSEL); - - mutex_unlock(&mfp_mutex); -} -EXPORT_SYMBOL(mfp_set_groupg); - -void mfp_set_groupd(struct device *dev, const char *subname) -{ - unsigned long mfpen; - const char *dev_id; - - BUG_ON((!dev) && (!subname)); - - mutex_lock(&mfp_mutex); - - if (subname != NULL) - dev_id = subname; - else - dev_id = dev_name(dev); - - mfpen = __raw_readl(REG_MFSEL); - - if (strcmp(dev_id, "nuc900-mmc-port0") == 0) { - mfpen &= ~GPSELD;/*enable sd0*/ - mfpen |= ENSD0; - } else - mfpen &= (~GPSELD); - - __raw_writel(mfpen, REG_MFSEL); - - mutex_unlock(&mfp_mutex); -} -EXPORT_SYMBOL(mfp_set_groupd); diff --git a/arch/arm/mach-w90x900/nuc910.c b/arch/arm/mach-w90x900/nuc910.c deleted file mode 100644 index 45ae8285bfc9e3f6cc4bda4f8eca28d3e62df702..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/nuc910.c +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-w90x900/nuc910.c - * - * Based on linux/arch/arm/plat-s3c24xx/s3c244x.c by Ben Dooks - * - * Copyright (c) 2009 Nuvoton corporation. - * - * Wan ZongShun - * - * NUC910 cpu support - */ - -#include -#include -#include -#include "cpu.h" -#include "clock.h" - -/* define specific CPU platform device */ - -static struct platform_device *nuc910_dev[] __initdata = { - &nuc900_device_ts, - &nuc900_device_rtc, - &nuc900_device_lcd, - &nuc900_device_kpi, -}; - -/* define specific CPU platform io map */ - -static struct map_desc nuc910evb_iodesc[] __initdata = { - IODESC_ENT(USBEHCIHOST), - IODESC_ENT(USBOHCIHOST), - IODESC_ENT(KPI), - IODESC_ENT(USBDEV), - IODESC_ENT(ADC), -}; - -/*Init NUC910 evb io*/ - -void __init nuc910_map_io(void) -{ - nuc900_map_io(nuc910evb_iodesc, ARRAY_SIZE(nuc910evb_iodesc)); -} - -/*Init NUC910 clock*/ - -void __init nuc910_init_clocks(void) -{ - nuc900_init_clocks(); -} - -/*Init NUC910 board info*/ - -void __init nuc910_board_init(void) -{ - nuc900_board_init(nuc910_dev, ARRAY_SIZE(nuc910_dev)); -} diff --git a/arch/arm/mach-w90x900/nuc910.h b/arch/arm/mach-w90x900/nuc910.h deleted file mode 100644 index 53be3323736fd34e55e5bae650423b51724f71a3..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/nuc910.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-w90x900/nuc910.h - * - * Copyright (c) 2008 Nuvoton corporation - * - * Header file for NUC900 CPU support - * - * Wan ZongShun - */ -#include "nuc9xx.h" - -/* extern file from nuc910.c */ - -extern void nuc910_board_init(void); -extern void nuc910_init_clocks(void); -extern void nuc910_map_io(void); diff --git a/arch/arm/mach-w90x900/nuc950.c b/arch/arm/mach-w90x900/nuc950.c deleted file mode 100644 index 3be114249cd81dfbbedfde225f275ed1eae6048b..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/nuc950.c +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-w90x900/nuc950.c - * - * Based on linux/arch/arm/plat-s3c24xx/s3c244x.c by Ben Dooks - * - * Copyright (c) 2008 Nuvoton technology corporation. - * - * Wan ZongShun - * - * NUC950 cpu support - */ - -#include -#include -#include - -#include "cpu.h" - -/* define specific CPU platform device */ - -static struct platform_device *nuc950_dev[] __initdata = { - &nuc900_device_kpi, - &nuc900_device_fmi, - &nuc900_device_lcd, -}; - -/* define specific CPU platform io map */ - -static struct map_desc nuc950evb_iodesc[] __initdata = { -}; - -/*Init NUC950 evb io*/ - -void __init nuc950_map_io(void) -{ - nuc900_map_io(nuc950evb_iodesc, ARRAY_SIZE(nuc950evb_iodesc)); -} - -/*Init NUC950 clock*/ - -void __init nuc950_init_clocks(void) -{ - nuc900_init_clocks(); -} - -/*Init NUC950 board info*/ - -void __init nuc950_board_init(void) -{ - nuc900_board_init(nuc950_dev, ARRAY_SIZE(nuc950_dev)); -} diff --git a/arch/arm/mach-w90x900/nuc950.h b/arch/arm/mach-w90x900/nuc950.h deleted file mode 100644 index 23cff81ea63087a653e5c2d01194b2f9940efbad..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/nuc950.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-w90x900/nuc950.h - * - * Copyright (c) 2008 Nuvoton corporation - * - * Header file for NUC900 CPU support - * - * Wan ZongShun - */ -#include "nuc9xx.h" - -/* extern file from nuc950.c */ - -extern void nuc950_board_init(void); -extern void nuc950_init_clocks(void); -extern void nuc950_map_io(void); diff --git a/arch/arm/mach-w90x900/nuc960.c b/arch/arm/mach-w90x900/nuc960.c deleted file mode 100644 index 8a27d74b975ec8c03ea9d8e8ea54f5bbf497ecfc..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/nuc960.c +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-w90x900/nuc960.c - * - * Based on linux/arch/arm/plat-s3c24xx/s3c244x.c by Ben Dooks - * - * Copyright (c) 2008 Nuvoton technology corporation. - * - * Wan ZongShun - * - * NUC960 cpu support - */ - -#include -#include -#include -#include "cpu.h" - -/* define specific CPU platform device */ - -static struct platform_device *nuc960_dev[] __initdata = { - &nuc900_device_kpi, - &nuc900_device_fmi, -}; - -/* define specific CPU platform io map */ - -static struct map_desc nuc960evb_iodesc[] __initdata = { -}; - -/*Init NUC960 evb io*/ - -void __init nuc960_map_io(void) -{ - nuc900_map_io(nuc960evb_iodesc, ARRAY_SIZE(nuc960evb_iodesc)); -} - -/*Init NUC960 clock*/ - -void __init nuc960_init_clocks(void) -{ - nuc900_init_clocks(); -} - -/*Init NUC960 board info*/ - -void __init nuc960_board_init(void) -{ - nuc900_board_init(nuc960_dev, ARRAY_SIZE(nuc960_dev)); -} diff --git a/arch/arm/mach-w90x900/nuc960.h b/arch/arm/mach-w90x900/nuc960.h deleted file mode 100644 index 88bb13c971dcfe986db1cab5364f7f000537c29c..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/nuc960.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-w90x900/nuc960.h - * - * Copyright (c) 2008 Nuvoton corporation - * - * Header file for NUC900 CPU support - * - * Wan ZongShun - */ -#include "nuc9xx.h" - -/* extern file from nuc960.c */ - -extern void nuc960_board_init(void); -extern void nuc960_init_clocks(void); -extern void nuc960_map_io(void); diff --git a/arch/arm/mach-w90x900/nuc9xx.h b/arch/arm/mach-w90x900/nuc9xx.h deleted file mode 100644 index 21f6f9c304e85cbc80aca611053aeb8324f436c9..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/nuc9xx.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-w90x900/nuc9xx.h - * - * Copied from nuc910.h, which had: - * - * Copyright (c) 2008 Nuvoton corporation - * - * Header file for NUC900 CPU support - * - * Wan ZongShun - */ - -#include - -struct map_desc; - -/* core initialisation functions */ - -extern void nuc900_init_irq(void); -extern void nuc900_timer_init(void); -extern void nuc9xx_restart(enum reboot_mode, const char *); diff --git a/arch/arm/mach-w90x900/regs-ebi.h b/arch/arm/mach-w90x900/regs-ebi.h deleted file mode 100644 index 3fb22702cfc0c0c46e85cec1b7e78b37ce0d1fbc..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/regs-ebi.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-w90x900/include/mach/regs-ebi.h - * - * Copyright (c) 2009 Nuvoton technology corporation. - * - * Wan ZongShun - */ - -#ifndef __ASM_ARCH_REGS_EBI_H -#define __ASM_ARCH_REGS_EBI_H - -/* EBI Control Registers */ - -#define EBI_BA W90X900_VA_EBI -#define REG_EBICON (EBI_BA + 0x00) -#define REG_ROMCON (EBI_BA + 0x04) -#define REG_SDCONF0 (EBI_BA + 0x08) -#define REG_SDCONF1 (EBI_BA + 0x0C) -#define REG_SDTIME0 (EBI_BA + 0x10) -#define REG_SDTIME1 (EBI_BA + 0x14) -#define REG_EXT0CON (EBI_BA + 0x18) -#define REG_EXT1CON (EBI_BA + 0x1C) -#define REG_EXT2CON (EBI_BA + 0x20) -#define REG_EXT3CON (EBI_BA + 0x24) -#define REG_EXT4CON (EBI_BA + 0x28) -#define REG_CKSKEW (EBI_BA + 0x2C) - -#endif /* __ASM_ARCH_REGS_EBI_H */ diff --git a/arch/arm/mach-w90x900/regs-gcr.h b/arch/arm/mach-w90x900/regs-gcr.h deleted file mode 100644 index caf1090ecad832fd34c3f002f5a7a228da78cd38..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/regs-gcr.h +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * arch/arm/mach-w90x900/include/mach/regs-gcr.h - * - * Copyright (c) 2010 Nuvoton technology corporation - * All rights reserved. - * - * Wan ZongShun - */ - -#ifndef __ASM_ARCH_REGS_GCR_H -#define __ASM_ARCH_REGS_GCR_H - -/* Global control registers */ - -#define GCR_BA W90X900_VA_GCR -#define REG_PDID (GCR_BA+0x000) -#define REG_PWRON (GCR_BA+0x004) -#define REG_ARBCON (GCR_BA+0x008) -#define REG_MFSEL (GCR_BA+0x00C) -#define REG_EBIDPE (GCR_BA+0x010) -#define REG_LCDDPE (GCR_BA+0x014) -#define REG_GPIOCPE (GCR_BA+0x018) -#define REG_GPIODPE (GCR_BA+0x01C) -#define REG_GPIOEPE (GCR_BA+0x020) -#define REG_GPIOFPE (GCR_BA+0x024) -#define REG_GPIOGPE (GCR_BA+0x028) -#define REG_GPIOHPE (GCR_BA+0x02C) -#define REG_GPIOIPE (GCR_BA+0x030) -#define REG_GTMP1 (GCR_BA+0x034) -#define REG_GTMP2 (GCR_BA+0x038) -#define REG_GTMP3 (GCR_BA+0x03C) - -#endif /* __ASM_ARCH_REGS_GCR_H */ diff --git a/arch/arm/mach-w90x900/regs-timer.h b/arch/arm/mach-w90x900/regs-timer.h deleted file mode 100644 index d12807fd1e3e1e1a1e35b96b4daea2c5c7e9b248..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/regs-timer.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * arch/arm/mach-w90x900/include/mach/regs-timer.h - * - * Copyright (c) 2008 Nuvoton technology corporation - * All rights reserved. - * - * Wan ZongShun - * - * Based on arch/arm/mach-s3c2410/include/mach/regs-timer.h - */ - -#ifndef __ASM_ARCH_REGS_TIMER_H -#define __ASM_ARCH_REGS_TIMER_H - -/* Timer Registers */ - -#define TMR_BA W90X900_VA_TIMER -#define REG_TCSR0 (TMR_BA+0x00) -#define REG_TCSR1 (TMR_BA+0x04) -#define REG_TICR0 (TMR_BA+0x08) -#define REG_TICR1 (TMR_BA+0x0C) -#define REG_TDR0 (TMR_BA+0x10) -#define REG_TDR1 (TMR_BA+0x14) -#define REG_TISR (TMR_BA+0x18) -#define REG_WTCR (TMR_BA+0x1C) -#define REG_TCSR2 (TMR_BA+0x20) -#define REG_TCSR3 (TMR_BA+0x24) -#define REG_TICR2 (TMR_BA+0x28) -#define REG_TICR3 (TMR_BA+0x2C) -#define REG_TDR2 (TMR_BA+0x30) -#define REG_TDR3 (TMR_BA+0x34) -#define REG_TCSR4 (TMR_BA+0x40) -#define REG_TICR4 (TMR_BA+0x48) -#define REG_TDR4 (TMR_BA+0x50) - -#endif /* __ASM_ARCH_REGS_TIMER_H */ diff --git a/arch/arm/mach-w90x900/regs-usb.h b/arch/arm/mach-w90x900/regs-usb.h deleted file mode 100644 index 98046c811bf7a2feab3e0c4236ddf955a657a0d0..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/regs-usb.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-w90x900/include/mach/regs-usb.h - * - * Copyright (c) 2008 Nuvoton technology corporation. - * - * Wan ZongShun - */ - -#ifndef __ASM_ARCH_REGS_USB_H -#define __ASM_ARCH_REGS_USB_H - -/* usb Control Registers */ -#define USBH_BA W90X900_VA_USBEHCIHOST -#define USBD_BA W90X900_VA_USBDEV -#define USBO_BA W90X900_VA_USBOHCIHOST - -/* USB Host Control Registers */ -#define REG_UPSCR0 (USBH_BA+0x064) -#define REG_UPSCR1 (USBH_BA+0x068) -#define REG_USBPCR0 (USBH_BA+0x0C4) -#define REG_USBPCR1 (USBH_BA+0x0C8) - -/* USBH OHCI Control Registers */ -#define REG_OpModEn (USBO_BA+0x204) -/*This bit controls the polarity of over -*current flag from external power IC. -*/ -#define OCALow 0x08 - -#endif /* __ASM_ARCH_REGS_USB_H */ diff --git a/arch/arm/mach-w90x900/time.c b/arch/arm/mach-w90x900/time.c deleted file mode 100644 index dd20fab9a960508b7907da8e0e3c03397f35b186..0000000000000000000000000000000000000000 --- a/arch/arm/mach-w90x900/time.c +++ /dev/null @@ -1,168 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * linux/arch/arm/mach-w90x900/time.c - * - * Based on linux/arch/arm/plat-s3c24xx/time.c by Ben Dooks - * - * Copyright (c) 2009 Nuvoton technology corporation - * All rights reserved. - * - * Wan ZongShun - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include "regs-timer.h" - -#include "nuc9xx.h" - -#define RESETINT 0x1f -#define PERIOD (0x01 << 27) -#define ONESHOT (0x00 << 27) -#define COUNTEN (0x01 << 30) -#define INTEN (0x01 << 29) - -#define TICKS_PER_SEC 100 -#define PRESCALE 0x63 /* Divider = prescale + 1 */ - -#define TDR_SHIFT 24 - -static unsigned int timer0_load; - -static int nuc900_clockevent_shutdown(struct clock_event_device *evt) -{ - unsigned int val = __raw_readl(REG_TCSR0) & ~(0x03 << 27); - - __raw_writel(val, REG_TCSR0); - return 0; -} - -static int nuc900_clockevent_set_oneshot(struct clock_event_device *evt) -{ - unsigned int val = __raw_readl(REG_TCSR0) & ~(0x03 << 27); - - val |= (ONESHOT | COUNTEN | INTEN | PRESCALE); - - __raw_writel(val, REG_TCSR0); - return 0; -} - -static int nuc900_clockevent_set_periodic(struct clock_event_device *evt) -{ - unsigned int val = __raw_readl(REG_TCSR0) & ~(0x03 << 27); - - __raw_writel(timer0_load, REG_TICR0); - val |= (PERIOD | COUNTEN | INTEN | PRESCALE); - __raw_writel(val, REG_TCSR0); - return 0; -} - -static int nuc900_clockevent_setnextevent(unsigned long evt, - struct clock_event_device *clk) -{ - unsigned int val; - - __raw_writel(evt, REG_TICR0); - - val = __raw_readl(REG_TCSR0); - val |= (COUNTEN | INTEN | PRESCALE); - __raw_writel(val, REG_TCSR0); - - return 0; -} - -static struct clock_event_device nuc900_clockevent_device = { - .name = "nuc900-timer0", - .features = CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_ONESHOT, - .set_state_shutdown = nuc900_clockevent_shutdown, - .set_state_periodic = nuc900_clockevent_set_periodic, - .set_state_oneshot = nuc900_clockevent_set_oneshot, - .tick_resume = nuc900_clockevent_shutdown, - .set_next_event = nuc900_clockevent_setnextevent, - .rating = 300, -}; - -/*IRQ handler for the timer*/ - -static irqreturn_t nuc900_timer0_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = &nuc900_clockevent_device; - - __raw_writel(0x01, REG_TISR); /* clear TIF0 */ - - evt->event_handler(evt); - return IRQ_HANDLED; -} - -static struct irqaction nuc900_timer0_irq = { - .name = "nuc900-timer0", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = nuc900_timer0_interrupt, -}; - -static void __init nuc900_clockevents_init(void) -{ - unsigned int rate; - struct clk *clk = clk_get(NULL, "timer0"); - - BUG_ON(IS_ERR(clk)); - - __raw_writel(0x00, REG_TCSR0); - - clk_enable(clk); - rate = clk_get_rate(clk) / (PRESCALE + 1); - - timer0_load = (rate / TICKS_PER_SEC); - - __raw_writel(RESETINT, REG_TISR); - setup_irq(IRQ_TIMER0, &nuc900_timer0_irq); - - nuc900_clockevent_device.cpumask = cpumask_of(0); - - clockevents_config_and_register(&nuc900_clockevent_device, rate, - 0xf, 0xffffffff); -} - -static void __init nuc900_clocksource_init(void) -{ - unsigned int val; - unsigned int rate; - struct clk *clk = clk_get(NULL, "timer1"); - - BUG_ON(IS_ERR(clk)); - - __raw_writel(0x00, REG_TCSR1); - - clk_enable(clk); - rate = clk_get_rate(clk) / (PRESCALE + 1); - - __raw_writel(0xffffffff, REG_TICR1); - - val = __raw_readl(REG_TCSR1); - val |= (COUNTEN | PERIOD | PRESCALE); - __raw_writel(val, REG_TCSR1); - - clocksource_mmio_init(REG_TDR1, "nuc900-timer1", rate, 200, - TDR_SHIFT, clocksource_mmio_readl_down); -} - -void __init nuc900_timer_init(void) -{ - nuc900_clocksource_init(); - nuc900_clockevents_init(); -} diff --git a/arch/arm/mach-zynq/headsmp.S b/arch/arm/mach-zynq/headsmp.S index ab85003cf9ad21f56c8c34949a4a2981d878b8d8..3449e0d1f9900db4890489dd39a77ffc05599115 100644 --- a/arch/arm/mach-zynq/headsmp.S +++ b/arch/arm/mach-zynq/headsmp.S @@ -7,6 +7,8 @@ #include #include + .arm + ENTRY(zynq_secondary_trampoline) ARM_BE8(setend be) @ ensure we are in BE8 mode ldr r0, zynq_secondary_trampoline_jump diff --git a/arch/arm/mach-zynq/platsmp.c b/arch/arm/mach-zynq/platsmp.c index a7cfe07156f467fc188e6ecaf1d8f4d3640cefa7..a10085be9073b5e11c733fd5b82d07ec68be5e11 100644 --- a/arch/arm/mach-zynq/platsmp.c +++ b/arch/arm/mach-zynq/platsmp.c @@ -57,7 +57,7 @@ int zynq_cpun_start(u32 address, int cpu) * 0x4: Jump by mov instruction * 0x8: Jumping address */ - memcpy((__force void *)zero, &zynq_secondary_trampoline, + memcpy_toio(zero, &zynq_secondary_trampoline, trampoline_size); writel(address, zero + trampoline_size); @@ -81,7 +81,7 @@ EXPORT_SYMBOL(zynq_cpun_start); static int zynq_boot_secondary(unsigned int cpu, struct task_struct *idle) { - return zynq_cpun_start(__pa_symbol(secondary_startup), cpu); + return zynq_cpun_start(__pa_symbol(secondary_startup_arm), cpu); } /* diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index c1222c0e9fd3bebb6a64f209e80e8d924375d041..0ab3a86b1f52377f2836f0df4a4589ea1593dde5 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -106,7 +106,7 @@ config CPU_ARM922T help The ARM922T is a version of the ARM920T, but with smaller instruction and data caches. It is used in Altera's - Excalibur XA device family and Micrel's KS8695 Centaur. + Excalibur XA device family and the ARM Integrator. Say Y if you want support for the ARM922T processor. Otherwise, say N. diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c index 61d834157bc0529f74bb8617272288cb9ea2c919..382e1c2855e85211041af5a17e70ea670252fe07 100644 --- a/arch/arm/mm/copypage-xscale.c +++ b/arch/arm/mm/copypage-xscale.c @@ -42,6 +42,7 @@ static void mc_copy_user_page(void *from, void *to) * when prefetching destination as well. (NP) */ asm volatile ("\ +.arch xscale \n\ pld [%0, #0] \n\ pld [%0, #32] \n\ pld [%1, #0] \n\ @@ -106,8 +107,9 @@ void xscale_mc_clear_user_highpage(struct page *page, unsigned long vaddr) { void *ptr, *kaddr = kmap_atomic(page); - asm volatile( - "mov r1, %2 \n\ + asm volatile("\ +.arch xscale \n\ + mov r1, %2 \n\ mov r2, #0 \n\ mov r3, #0 \n\ 1: mov ip, %0 \n\ diff --git a/arch/arm/plat-iop/Makefile b/arch/arm/plat-iop/Makefile deleted file mode 100644 index 4d839a3cf2845ec38291bcd570f0c00dd1770f19..0000000000000000000000000000000000000000 --- a/arch/arm/plat-iop/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the linux kernel. -# - -# IOP32X -obj-$(CONFIG_ARCH_IOP32X) += i2c.o -obj-$(CONFIG_ARCH_IOP32X) += pci.o -obj-$(CONFIG_ARCH_IOP32X) += setup.o -obj-$(CONFIG_ARCH_IOP32X) += time.o -obj-$(CONFIG_ARCH_IOP32X) += cp6.o -obj-$(CONFIG_ARCH_IOP32X) += adma.o -obj-$(CONFIG_ARCH_IOP32X) += pmu.o -obj-$(CONFIG_ARCH_IOP32X) += restart.o - -# IOP33X -obj-$(CONFIG_ARCH_IOP33X) += i2c.o -obj-$(CONFIG_ARCH_IOP33X) += pci.o -obj-$(CONFIG_ARCH_IOP33X) += setup.o -obj-$(CONFIG_ARCH_IOP33X) += time.o -obj-$(CONFIG_ARCH_IOP33X) += cp6.o -obj-$(CONFIG_ARCH_IOP33X) += adma.o -obj-$(CONFIG_ARCH_IOP33X) += pmu.o -obj-$(CONFIG_ARCH_IOP33X) += restart.o - -# IOP13XX -obj-$(CONFIG_ARCH_IOP13XX) += cp6.o -obj-$(CONFIG_ARCH_IOP13XX) += time.o diff --git a/arch/arm/plat-samsung/include/plat/gpio-core.h b/arch/arm/plat-samsung/include/plat/gpio-core.h index 51e721f5e4915ac82d27bc070ec5079bb595fa53..c0bfceb88340c52d9d093f2dcedd2db0aad896c3 100644 --- a/arch/arm/plat-samsung/include/plat/gpio-core.h +++ b/arch/arm/plat-samsung/include/plat/gpio-core.h @@ -12,6 +12,7 @@ /* Bring in machine-local definitions, especially S3C_GPIO_END */ #include +#include #define GPIOCON_OFF (0x00) #define GPIODAT_OFF (0x04) diff --git a/arch/arm/plat-samsung/include/plat/usb-phy.h b/arch/arm/plat-samsung/include/plat/usb-phy.h index 6d0c788beb9dffa123c7e6c46b68d00e7d26bc66..94da89ecbd3bd18031dcaf1a2202b7f0faddf350 100644 --- a/arch/arm/plat-samsung/include/plat/usb-phy.h +++ b/arch/arm/plat-samsung/include/plat/usb-phy.h @@ -7,8 +7,6 @@ #ifndef __PLAT_SAMSUNG_USB_PHY_H #define __PLAT_SAMSUNG_USB_PHY_H __FILE__ -#include - extern int s5p_usb_phy_init(struct platform_device *pdev, int type); extern int s5p_usb_phy_exit(struct platform_device *pdev, int type); diff --git a/arch/arm64/Kbuild b/arch/arm64/Kbuild new file mode 100644 index 0000000000000000000000000000000000000000..d6465823b28102eb6510bb2367ebc2da9975722b --- /dev/null +++ b/arch/arm64/Kbuild @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-y += kernel/ mm/ +obj-$(CONFIG_NET) += net/ +obj-$(CONFIG_KVM) += kvm/ +obj-$(CONFIG_XEN) += xen/ +obj-$(CONFIG_CRYPTO) += crypto/ diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index b1dd948f9665942cb94848e81e0fceba5aa490ca..ca5a36eeeac6d9f45d0e8445421ad702002eb979 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -148,6 +148,7 @@ config ARM64 select HAVE_FAST_GUP select HAVE_FTRACE_MCOUNT_RECORD select HAVE_FUNCTION_TRACER + select HAVE_FUNCTION_ERROR_INJECTION select HAVE_FUNCTION_GRAPH_TRACER select HAVE_GCC_PLUGINS select HAVE_HW_BREAKPOINT if PERF_EVENTS @@ -286,7 +287,7 @@ config PGTABLE_LEVELS int default 2 if ARM64_16K_PAGES && ARM64_VA_BITS_36 default 2 if ARM64_64K_PAGES && ARM64_VA_BITS_42 - default 3 if ARM64_64K_PAGES && (ARM64_VA_BITS_48 || ARM64_USER_VA_BITS_52) + default 3 if ARM64_64K_PAGES && (ARM64_VA_BITS_48 || ARM64_VA_BITS_52) default 3 if ARM64_4K_PAGES && ARM64_VA_BITS_39 default 3 if ARM64_16K_PAGES && ARM64_VA_BITS_47 default 4 if !ARM64_64K_PAGES && ARM64_VA_BITS_48 @@ -297,6 +298,21 @@ config ARCH_SUPPORTS_UPROBES config ARCH_PROC_KCORE_TEXT def_bool y +config KASAN_SHADOW_OFFSET + hex + depends on KASAN + default 0xdfffa00000000000 if (ARM64_VA_BITS_48 || ARM64_VA_BITS_52) && !KASAN_SW_TAGS + default 0xdfffd00000000000 if ARM64_VA_BITS_47 && !KASAN_SW_TAGS + default 0xdffffe8000000000 if ARM64_VA_BITS_42 && !KASAN_SW_TAGS + default 0xdfffffd000000000 if ARM64_VA_BITS_39 && !KASAN_SW_TAGS + default 0xdffffffa00000000 if ARM64_VA_BITS_36 && !KASAN_SW_TAGS + default 0xefff900000000000 if (ARM64_VA_BITS_48 || ARM64_VA_BITS_52) && KASAN_SW_TAGS + default 0xefffc80000000000 if ARM64_VA_BITS_47 && KASAN_SW_TAGS + default 0xeffffe4000000000 if ARM64_VA_BITS_42 && KASAN_SW_TAGS + default 0xefffffc800000000 if ARM64_VA_BITS_39 && KASAN_SW_TAGS + default 0xeffffff900000000 if ARM64_VA_BITS_36 && KASAN_SW_TAGS + default 0xffffffffffffffff + source "arch/arm64/Kconfig.platforms" menu "Kernel Features" @@ -744,13 +760,14 @@ config ARM64_VA_BITS_47 config ARM64_VA_BITS_48 bool "48-bit" -config ARM64_USER_VA_BITS_52 - bool "52-bit (user)" +config ARM64_VA_BITS_52 + bool "52-bit" depends on ARM64_64K_PAGES && (ARM64_PAN || !ARM64_SW_TTBR0_PAN) help Enable 52-bit virtual addressing for userspace when explicitly - requested via a hint to mmap(). The kernel will continue to - use 48-bit virtual addresses for its own mappings. + requested via a hint to mmap(). The kernel will also use 52-bit + virtual addresses for its own mappings (provided HW support for + this feature is available, otherwise it reverts to 48-bit). NOTE: Enabling 52-bit virtual addressing in conjunction with ARMv8.3 Pointer Authentication will result in the PAC being @@ -763,7 +780,7 @@ endchoice config ARM64_FORCE_52BIT bool "Force 52-bit virtual addresses for userspace" - depends on ARM64_USER_VA_BITS_52 && EXPERT + depends on ARM64_VA_BITS_52 && EXPERT help For systems with 52-bit userspace VAs enabled, the kernel will attempt to maintain compatibility with older software by providing 48-bit VAs @@ -780,7 +797,8 @@ config ARM64_VA_BITS default 39 if ARM64_VA_BITS_39 default 42 if ARM64_VA_BITS_42 default 47 if ARM64_VA_BITS_47 - default 48 if ARM64_VA_BITS_48 || ARM64_USER_VA_BITS_52 + default 48 if ARM64_VA_BITS_48 + default 52 if ARM64_VA_BITS_52 choice prompt "Physical address space size" @@ -1110,6 +1128,15 @@ config ARM64_SW_TTBR0_PAN zeroed area and reserved ASID. The user access routines restore the valid TTBR0_EL1 temporarily. +config ARM64_TAGGED_ADDR_ABI + bool "Enable the tagged user addresses syscall ABI" + default y + help + When this option is enabled, user applications can opt in to a + relaxed ABI via prctl() allowing tagged addresses to be passed + to system calls as pointer arguments. For details, see + Documentation/arm64/tagged-address-abi.txt. + menuconfig COMPAT bool "Kernel support for 32-bit EL0" depends on ARM64_4K_PAGES || EXPERT @@ -1263,6 +1290,7 @@ config ARM64_PAN config ARM64_LSE_ATOMICS bool "Atomic instructions" + depends on JUMP_LABEL default y help As part of the Large System Extensions, ARMv8.1 introduces new @@ -1467,6 +1495,7 @@ endif config RELOCATABLE bool + select ARCH_HAS_RELR help This builds the kernel as a Position Independent Executable (PIE), which retains all relocation metadata required to relocate the diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 4778c775de1ba056ee071bea079063586135f1b4..16d761475a8600670438e946b8fd4cc9b12930c2 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -77,6 +77,7 @@ config ARCH_BRCMSTB config ARCH_EXYNOS bool "ARMv8 based Samsung Exynos SoC family" select COMMON_CLK_SAMSUNG + select EXYNOS_CHIPID select EXYNOS_PM_DOMAINS if PM_GENERIC_DOMAINS select EXYNOS_PMU select HAVE_S3C2410_WATCHDOG if WATCHDOG @@ -173,6 +174,7 @@ config ARCH_MXC select PM select PM_GENERIC_DOMAINS select SOC_BUS + select TIMER_IMX_SYS_CTR help This enables support for the ARMv8 based SoCs in the NXP i.MX family. diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 61de992bbea3fad61895e4f1e796cea460fd9deb..f843d298792dcb606bb87066cb40edc5d2c9a050 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -39,6 +39,12 @@ $(warning LSE atomics not supported by binutils) endif endif +cc_has_k_constraint := $(call try-run,echo \ + 'int main(void) { \ + asm volatile("and w0, w0, %w0" :: "K" (4294967295)); \ + return 0; \ + }' | $(CC) -S -x c -o "$$TMP" -,,-DCONFIG_CC_HAS_K_CONSTRAINT=1) + ifeq ($(CONFIG_ARM64), y) brokengasinst := $(call as-instr,1:\n.inst 0\n.rept . - 1b\n\nnop\n.endr\n,,-DCONFIG_BROKEN_GAS_INST=1) @@ -63,7 +69,8 @@ ifeq ($(CONFIG_GENERIC_COMPAT_VDSO), y) endif endif -KBUILD_CFLAGS += -mgeneral-regs-only $(lseinstr) $(brokengasinst) $(compat_vdso) +KBUILD_CFLAGS += -mgeneral-regs-only $(lseinstr) $(brokengasinst) \ + $(compat_vdso) $(cc_has_k_constraint) KBUILD_CFLAGS += -fno-asynchronous-unwind-tables KBUILD_CFLAGS += $(call cc-disable-warning, psabi) KBUILD_AFLAGS += $(lseinstr) $(brokengasinst) $(compat_vdso) @@ -126,21 +133,9 @@ KBUILD_CFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT) KBUILD_CPPFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT) KBUILD_AFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT) -# KASAN_SHADOW_OFFSET = VA_START + (1 << (VA_BITS - KASAN_SHADOW_SCALE_SHIFT)) -# - (1 << (64 - KASAN_SHADOW_SCALE_SHIFT)) -# in 32-bit arithmetic -KASAN_SHADOW_OFFSET := $(shell printf "0x%08x00000000\n" $$(( \ - (0xffffffff & (-1 << ($(CONFIG_ARM64_VA_BITS) - 32))) \ - + (1 << ($(CONFIG_ARM64_VA_BITS) - 32 - $(KASAN_SHADOW_SCALE_SHIFT))) \ - - (1 << (64 - 32 - $(KASAN_SHADOW_SCALE_SHIFT))) )) ) - export TEXT_OFFSET GZFLAGS -core-y += arch/arm64/kernel/ arch/arm64/mm/ -core-$(CONFIG_NET) += arch/arm64/net/ -core-$(CONFIG_KVM) += arch/arm64/kvm/ -core-$(CONFIG_XEN) += arch/arm64/xen/ -core-$(CONFIG_CRYPTO) += arch/arm64/crypto/ +core-y += arch/arm64/ libs-y := arch/arm64/lib/ $(libs-y) core-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a diff --git a/arch/arm64/boot/dts/allwinner/Makefile b/arch/arm64/boot/dts/allwinner/Makefile index f6db0611cb85c48186d60cf460cb1fa5bc386977..d2418021768b2ffcd0a31ac6de168ded8ed0495b 100644 --- a/arch/arm64/boot/dts/allwinner/Makefile +++ b/arch/arm64/boot/dts/allwinner/Makefile @@ -4,6 +4,7 @@ dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-bananapi-m64.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-nanopi-a64.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-oceanic-5205-5inmfd.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-olinuxino.dtb +dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-olinuxino-emmc.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-orangepi-win.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pine64-lts.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pine64-plus.dtb sun50i-a64-pine64.dtb @@ -25,3 +26,4 @@ dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-orangepi-3.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-orangepi-lite2.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-orangepi-one-plus.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-pine-h64.dtb +dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-tanix-tx6.dtb diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino-emmc.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino-emmc.dts new file mode 100644 index 0000000000000000000000000000000000000000..96ab0227e82d187bc3b5eb50e3064dcabbe3ef3f --- /dev/null +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino-emmc.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2018 Martin Ayotte + * Copyright (C) 2019 Sunil Mohan Adapa + */ + +#include "sun50i-a64-olinuxino.dts" + +/ { + model = "Olimex A64-Olinuxino-eMMC"; + compatible = "olimex,a64-olinuxino-emmc", "allwinner,sun50i-a64"; +}; + +&mmc2 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc2_pins>; + vmmc-supply = <®_dcdc1>; + vqmmc-supply = <®_dcdc1>; + bus-width = <8>; + non-removable; + cap-mmc-hw-reset; + status = "okay"; +}; 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 5ef3c62c765eb7a6698c57cee4db18f935beb236..04446e4716c44cb5c00c2995638d83b17a022059 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts @@ -190,6 +190,10 @@ status = "okay"; }; +&r_ir { + status = "okay"; +}; + &r_rsb { status = "okay"; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi index 9cc9bdde81ac22dc670e6f35d55fcc905591b40d..69128a6dfc46f0a2e45d1acd02380192b9905da7 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi @@ -228,10 +228,10 @@ display_clocks: clock@0 { compatible = "allwinner,sun50i-a64-de2-clk"; reg = <0x0 0x100000>; - clocks = <&ccu CLK_DE>, - <&ccu CLK_BUS_DE>; - clock-names = "mod", - "bus"; + clocks = <&ccu CLK_BUS_DE>, + <&ccu CLK_DE>; + clock-names = "bus", + "mod"; resets = <&ccu RST_BUS_DE>; #clock-cells = <1>; #reset-cells = <1>; @@ -1015,7 +1015,7 @@ resets = <&ccu RST_BUS_HDMI1>; reset-names = "ctrl"; phys = <&hdmi_phy>; - phy-names = "hdmi-phy"; + phy-names = "phy"; status = "disabled"; ports { @@ -1094,6 +1094,19 @@ #size-cells = <0>; }; + r_ir: ir@1f02000 { + compatible = "allwinner,sun50i-a64-ir", + "allwinner,sun6i-a31-ir"; + reg = <0x01f02000 0x400>; + clocks = <&r_ccu CLK_APB0_IR>, <&r_ccu CLK_IR>; + clock-names = "apb", "ir"; + resets = <&r_ccu RST_APB0_IR>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&r_ir_rx_pin>; + status = "disabled"; + }; + r_pwm: pwm@1f03800 { compatible = "allwinner,sun50i-a64-pwm", "allwinner,sun5i-a13-pwm"; @@ -1121,6 +1134,11 @@ function = "s_i2c"; }; + r_ir_rx_pin: r-ir-rx-pin { + pins = "PL11"; + function = "s_cir_rx"; + }; + r_pwm_pin: r-pwm-pin { pins = "PL10"; function = "s_pwm"; @@ -1151,6 +1169,7 @@ "allwinner,sun6i-a31-wdt"; reg = <0x01c20ca0 0x20>; interrupts = ; + clocks = <&osc24M>; }; }; }; 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 0dc33c90dd60e567ab4b6412adfac43dd2c69872..1d05d570142fa020be2ab84fec87c6f615bc5d4b 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts @@ -25,6 +25,7 @@ connector { compatible = "hdmi-connector"; type = "a"; + ddc-en-gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>; /* PH2 */ port { hdmi_con_in: endpoint { @@ -51,6 +52,24 @@ regulator-max-microvolt = <5000000>; regulator-always-on; }; + + sound-spdif { + compatible = "simple-audio-card"; + simple-audio-card,name = "sun50i-h6-spdif"; + + simple-audio-card,cpu { + sound-dai = <&spdif>; + }; + + simple-audio-card,codec { + sound-dai = <&spdif_out>; + }; + }; + + spdif_out: spdif-out { + #sound-dai-cells = <0>; + compatible = "linux,spdif-dit"; + }; }; &de { @@ -232,6 +251,10 @@ }; }; +&r_ir { + status = "okay"; +}; + &r_pio { /* * PL0 and PL1 are used for PMIC I2C @@ -243,6 +266,10 @@ vcc-pm-supply = <®_aldo1>; }; +&spdif { + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_ph_pins>; 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 17d496990108664cf8a7cf16fa461e278bcdc408..eb379cd402ac451ef2db36c222ccd5e97ed0947c 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts @@ -21,6 +21,18 @@ stdout-path = "serial0:115200n8"; }; + connector { + compatible = "hdmi-connector"; + ddc-en-gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>; /* PH2 */ + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; + leds { compatible = "gpio-leds"; @@ -44,12 +56,44 @@ regulator-max-microvolt = <5000000>; regulator-always-on; }; + + reg_vcc33_wifi: vcc33-wifi { + /* Always on 3.3V regulator for WiFi and BT */ + compatible = "regulator-fixed"; + regulator-name = "vcc33-wifi"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + vin-supply = <®_vcc5v>; + }; + + reg_vcc_wifi_io: vcc-wifi-io { + /* Always on 1.8V/300mA regulator for WiFi and BT IO */ + compatible = "regulator-fixed"; + regulator-name = "vcc-wifi-io"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + vin-supply = <®_vcc33_wifi>; + }; + + wifi_pwrseq: wifi-pwrseq { + compatible = "mmc-pwrseq-simple"; + clocks = <&rtc 1>; + clock-names = "ext_clock"; + reset-gpios = <&r_pio 1 3 GPIO_ACTIVE_LOW>; /* PM3 */ + post-power-on-delay-ms = <200>; + }; }; &cpu0 { cpu-supply = <®_dcdca>; }; +&de { + status = "okay"; +}; + &ehci0 { status = "okay"; }; @@ -58,6 +102,16 @@ status = "okay"; }; +&hdmi { + status = "okay"; +}; + +&hdmi_out { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + &mmc0 { vmmc-supply = <®_cldo1>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ @@ -65,6 +119,23 @@ status = "okay"; }; +&mmc1 { + vmmc-supply = <®_vcc33_wifi>; + vqmmc-supply = <®_vcc_wifi_io>; + mmc-pwrseq = <&wifi_pwrseq>; + bus-width = <4>; + non-removable; + status = "okay"; + + brcm: sdio-wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + interrupt-parent = <&r_pio>; + interrupts = <1 0 IRQ_TYPE_LEVEL_LOW>; /* PM0 */ + interrupt-names = "host-wake"; + }; +}; + &ohci0 { status = "okay"; }; @@ -76,6 +147,7 @@ &pio { vcc-pc-supply = <®_bldo2>; vcc-pd-supply = <®_cldo1>; + vcc-pg-supply = <®_vcc_wifi_io>; }; &r_i2c { diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi index 62e27948a3faed9d7ae7f022fedf2b1cd2cd6eb5..ec9b6a578e3f760cc8088c1d63ebbb2476372696 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi @@ -189,6 +189,10 @@ }; }; +&r_ir { + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_ph_pins>; 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 189834518391009a83c92629ead862e2f71af331..30102daf83cc67d7e343e1a8ecc638eccfaa4dd6 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts @@ -255,6 +255,10 @@ }; }; +&r_ir { + status = "okay"; +}; + &r_pio { vcc-pm-supply = <®_aldo1>; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts new file mode 100644 index 0000000000000000000000000000000000000000..7e7cb10e3d967da3b80e8efec91449eb1f4ea5ef --- /dev/null +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (c) 2019 Jernej Skrabec + */ + +/dts-v1/; + +#include "sun50i-h6.dtsi" + +#include + +/ { + model = "Tanix TX6"; + compatible = "oranth,tanix-tx6", "allwinner,sun50i-h6"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + connector { + compatible = "hdmi-connector"; + ddc-en-gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>; /* PH2 */ + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; + + reg_vcc3v3: vcc3v3 { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; +}; + +&de { + status = "okay"; +}; + +&ehci0 { + status = "okay"; +}; + +&ehci3 { + status = "okay"; +}; + +&hdmi { + status = "okay"; +}; + +&hdmi_out { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + +&mmc0 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_pins>; + vmmc-supply = <®_vcc3v3>; + cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; + bus-width = <4>; + status = "okay"; +}; + +&ohci0 { + status = "okay"; +}; + +&ohci3 { + status = "okay"; +}; + +&r_ir { + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_ph_pins>; + status = "okay"; +}; + +&usb2otg { + dr_mode = "host"; + status = "okay"; +}; + +&usb2phy { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi index 7628a7c8309641ce24b2c9b22350a8d4bc19d005..4020a1aafa3e33bdd79caba258751bb19091be89 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi @@ -56,14 +56,6 @@ status = "disabled"; }; - iosc: internal-osc-clk { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <16000000>; - clock-accuracy = <300000000>; - clock-output-names = "iosc"; - }; - osc24M: osc24M_clk { #clock-cells = <0>; compatible = "fixed-clock"; @@ -71,11 +63,11 @@ clock-output-names = "osc24M"; }; - osc32k: osc32k_clk { + ext_osc32k: ext_osc32k_clk { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <32768>; - clock-output-names = "osc32k"; + clock-output-names = "ext_osc32k"; }; psci { @@ -197,7 +189,7 @@ ccu: clock@3001000 { compatible = "allwinner,sun50i-h6-ccu"; reg = <0x03001000 0x1000>; - clocks = <&osc24M>, <&osc32k>, <&iosc>; + clocks = <&osc24M>, <&rtc 0>, <&rtc 2>; clock-names = "hosc", "losc", "iosc"; #clock-cells = <1>; #reset-cells = <1>; @@ -215,7 +207,7 @@ #dma-cells = <1>; }; - sid: sid@3006000 { + sid: efuse@3006000 { compatible = "allwinner,sun50i-h6-sid"; reg = <0x03006000 0x400>; }; @@ -225,6 +217,7 @@ "allwinner,sun6i-a31-wdt"; reg = <0x030090a0 0x20>; interrupts = ; + clocks = <&osc24M>; /* Broken on some H6 boards */ status = "disabled"; }; @@ -236,7 +229,7 @@ , , ; - clocks = <&ccu CLK_APB1>, <&osc24M>, <&osc32k>; + clocks = <&ccu CLK_APB1>, <&osc24M>, <&rtc 0>; clock-names = "apb", "hosc", "losc"; gpio-controller; #gpio-cells = <3>; @@ -256,6 +249,21 @@ function = "hdmi"; }; + i2c0_pins: i2c0-pins { + pins = "PD25", "PD26"; + function = "i2c0"; + }; + + i2c1_pins: i2c1-pins { + pins = "PH5", "PH6"; + function = "i2c1"; + }; + + i2c2_pins: i2c2-pins { + pins = "PD23", "PD24"; + function = "i2c2"; + }; + mmc0_pins: mmc0-pins { pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5"; @@ -282,6 +290,11 @@ bias-pull-up; }; + spdif_tx_pin: spdif-tx-pin { + pins = "PH7"; + function = "spdif"; + }; + uart0_ph_pins: uart0-ph-pins { pins = "PH0", "PH1"; function = "uart0"; @@ -391,6 +404,48 @@ status = "disabled"; }; + i2c0: i2c@5002000 { + compatible = "allwinner,sun50i-h6-i2c", + "allwinner,sun6i-a31-i2c"; + reg = <0x05002000 0x400>; + interrupts = ; + clocks = <&ccu CLK_BUS_I2C0>; + resets = <&ccu RST_BUS_I2C0>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c1: i2c@5002400 { + compatible = "allwinner,sun50i-h6-i2c", + "allwinner,sun6i-a31-i2c"; + reg = <0x05002400 0x400>; + interrupts = ; + clocks = <&ccu CLK_BUS_I2C1>; + resets = <&ccu RST_BUS_I2C1>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c2: i2c@5002800 { + compatible = "allwinner,sun50i-h6-i2c", + "allwinner,sun6i-a31-i2c"; + reg = <0x05002800 0x400>; + interrupts = ; + clocks = <&ccu CLK_BUS_I2C2>; + resets = <&ccu RST_BUS_I2C2>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + emac: ethernet@5020000 { compatible = "allwinner,sun50i-h6-emac", "allwinner,sun50i-a64-emac"; @@ -411,6 +466,21 @@ }; }; + spdif: spdif@5093000 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun50i-h6-spdif"; + reg = <0x05093000 0x400>; + interrupts = ; + clocks = <&ccu CLK_BUS_SPDIF>, <&ccu CLK_SPDIF>; + clock-names = "apb", "spdif"; + resets = <&ccu RST_BUS_SPDIF>; + dmas = <&dma 2>; + dma-names = "tx"; + pinctrl-names = "default"; + pinctrl-0 = <&spdif_tx_pin>; + status = "disabled"; + }; + usb2otg: usb@5100000 { compatible = "allwinner,sun50i-h6-musb", "allwinner,sun8i-a33-musb"; @@ -504,7 +574,7 @@ resets = <&ccu RST_BUS_HDMI_SUB>, <&ccu RST_BUS_HDCP>; reset-names = "ctrl", "hdcp"; phys = <&hdmi_phy>; - phy-names = "hdmi-phy"; + phy-names = "phy"; pinctrl-names = "default"; pinctrl-0 = <&hdmi_pins>; status = "disabled"; @@ -633,10 +703,20 @@ }; }; + rtc: rtc@7000000 { + compatible = "allwinner,sun50i-h6-rtc"; + reg = <0x07000000 0x400>; + interrupts = , + ; + clock-output-names = "osc32k", "osc32k-out", "iosc"; + clocks = <&ext_osc32k>; + #clock-cells = <1>; + }; + r_ccu: clock@7010000 { compatible = "allwinner,sun50i-h6-r-ccu"; reg = <0x07010000 0x400>; - clocks = <&osc24M>, <&osc32k>, <&iosc>, + clocks = <&osc24M>, <&rtc 0>, <&rtc 2>, <&ccu CLK_PLL_PERIPH0>; clock-names = "hosc", "losc", "iosc", "pll-periph"; #clock-cells = <1>; @@ -648,6 +728,7 @@ "allwinner,sun6i-a31-wdt"; reg = <0x07020400 0x20>; interrupts = ; + clocks = <&osc24M>; }; r_intc: interrupt-controller@7021000 { @@ -664,7 +745,7 @@ reg = <0x07022000 0x400>; interrupts = , ; - clocks = <&r_ccu CLK_R_APB1>, <&osc24M>, <&osc32k>; + clocks = <&r_ccu CLK_R_APB1>, <&osc24M>, <&rtc 0>; clock-names = "apb", "hosc", "losc"; gpio-controller; #gpio-cells = <3>; @@ -675,10 +756,30 @@ pins = "PL0", "PL1"; function = "s_i2c"; }; + + r_ir_rx_pin: r-ir-rx-pin { + pins = "PL9"; + function = "s_cir_rx"; + }; + }; + + r_ir: ir@7040000 { + compatible = "allwinner,sun50i-h6-ir", + "allwinner,sun6i-a31-ir"; + reg = <0x07040000 0x400>; + interrupts = ; + clocks = <&r_ccu CLK_R_APB1_IR>, + <&r_ccu CLK_IR>; + clock-names = "apb", "ir"; + resets = <&r_ccu RST_R_APB1_IR>; + pinctrl-names = "default"; + pinctrl-0 = <&r_ir_rx_pin>; + status = "disabled"; }; r_i2c: i2c@7081400 { - compatible = "allwinner,sun6i-a31-i2c"; + compatible = "allwinner,sun50i-h6-i2c", + "allwinner,sun6i-a31-i2c"; reg = <0x07081400 0x400>; interrupts = ; clocks = <&r_ccu CLK_R_APB2_I2C>; diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi index b05d78164fc178a64446e1b070b0d4dd7f023688..144a2c19ac02659a4b288d0df130ae26303d92cf 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi @@ -302,6 +302,22 @@ status = "disabled"; }; + nand: nand@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>; + clocks = <&clkmgr STRATIX10_NAND_CLK>, + <&clkmgr STRATIX10_NAND_X_CLK>, + <&clkmgr STRATIX10_NAND_ECC_CLK>; + clock-names = "nand", "nand_x", "ecc"; + resets = <&rst NAND_RESET>, <&rst NAND_OCP_RESET>; + status = "disabled"; + }; + ocram: sram@ffe00000 { compatible = "mmio-sram"; reg = <0xffe00000 0x100000>; @@ -324,6 +340,8 @@ #dma-requests = <32>; clocks = <&clkmgr STRATIX10_L4_MAIN_CLK>; clock-names = "apb_pclk"; + resets = <&rst DMA_RESET>, <&rst DMA_OCP_RESET>; + reset-names = "dma", "dma-ocp"; }; rst: rstmgr@ffd11000 { diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile index 07b861fe5fa5f43c8be0ff48e9d836af7da3e53c..84afecba9ec0a04cb76ce57abb39fda9ab257d07 100644 --- a/arch/arm64/boot/dts/amlogic/Makefile +++ b/arch/arm64/boot/dts/amlogic/Makefile @@ -3,6 +3,8 @@ dtb-$(CONFIG_ARCH_MESON) += meson-axg-s400.dtb dtb-$(CONFIG_ARCH_MESON) += meson-g12a-sei510.dtb dtb-$(CONFIG_ARCH_MESON) += meson-g12a-u200.dtb dtb-$(CONFIG_ARCH_MESON) += meson-g12a-x96-max.dtb +dtb-$(CONFIG_ARCH_MESON) += meson-g12b-a311d-khadas-vim3.dtb +dtb-$(CONFIG_ARCH_MESON) += meson-g12b-s922x-khadas-vim3.dtb dtb-$(CONFIG_ARCH_MESON) += meson-g12b-odroid-n2.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nanopi-k2.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nexbox-a95x.dtb @@ -32,3 +34,5 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxm-q200.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxm-q201.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxm-rbox-pro.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxm-vega-s96.dtb +dtb-$(CONFIG_ARCH_MESON) += meson-sm1-sei610.dtb +dtb-$(CONFIG_ARCH_MESON) += meson-sm1-khadas-vim3l.dtb diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi index 6219337033a0b7a344d84bda656e18079c820309..82919b106010abccad0d848f6a39035a2e495bb6 100644 --- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi @@ -174,14 +174,16 @@ compatible = "amlogic,meson-axg-dwmac", "snps,dwmac-3.70a", "snps,dwmac"; - reg = <0x0 0xff3f0000 0x0 0x10000 - 0x0 0xff634540 0x0 0x8>; + reg = <0x0 0xff3f0000 0x0 0x10000>, + <0x0 0xff634540 0x0 0x8>; interrupts = ; interrupt-names = "macirq"; clocks = <&clkc CLKID_ETH>, <&clkc CLKID_FCLK_DIV2>, <&clkc CLKID_MPLL2>; clock-names = "stmmaceth", "clkin0", "clkin1"; + rx-fifo-depth = <4096>; + tx-fifo-depth = <2048>; status = "disabled"; }; @@ -1116,7 +1118,7 @@ }; mailbox: mailbox@ff63c404 { - compatible = "amlogic,meson-gx-mhu", "amlogic,meson-gxbb-mhu"; + compatible = "amlogic,meson-gxbb-mhu"; reg = <0 0xff63c404 0 0x4c>; interrupts = , , diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3f39e020f74e62ede06732b5ac4046324f2adada --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi @@ -0,0 +1,2435 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2018 Amlogic, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/ { + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + tdmif_a: audio-controller-0 { + compatible = "amlogic,axg-tdm-iface"; + #sound-dai-cells = <0>; + sound-name-prefix = "TDM_A"; + clocks = <&clkc_audio AUD_CLKID_MST_A_MCLK>, + <&clkc_audio AUD_CLKID_MST_A_SCLK>, + <&clkc_audio AUD_CLKID_MST_A_LRCLK>; + clock-names = "mclk", "sclk", "lrclk"; + status = "disabled"; + }; + + tdmif_b: audio-controller-1 { + compatible = "amlogic,axg-tdm-iface"; + #sound-dai-cells = <0>; + sound-name-prefix = "TDM_B"; + clocks = <&clkc_audio AUD_CLKID_MST_B_MCLK>, + <&clkc_audio AUD_CLKID_MST_B_SCLK>, + <&clkc_audio AUD_CLKID_MST_B_LRCLK>; + clock-names = "mclk", "sclk", "lrclk"; + status = "disabled"; + }; + + tdmif_c: audio-controller-2 { + compatible = "amlogic,axg-tdm-iface"; + #sound-dai-cells = <0>; + sound-name-prefix = "TDM_C"; + clocks = <&clkc_audio AUD_CLKID_MST_C_MCLK>, + <&clkc_audio AUD_CLKID_MST_C_SCLK>, + <&clkc_audio AUD_CLKID_MST_C_LRCLK>; + clock-names = "mclk", "sclk", "lrclk"; + status = "disabled"; + }; + + efuse: efuse { + compatible = "amlogic,meson-gxbb-efuse"; + clocks = <&clkc CLKID_EFUSE>; + #address-cells = <1>; + #size-cells = <1>; + read-only; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* 3 MiB reserved for ARM Trusted Firmware (BL31) */ + secmon_reserved: secmon@5000000 { + reg = <0x0 0x05000000 0x0 0x300000>; + no-map; + }; + + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x0 0x10000000>; + alignment = <0x0 0x400000>; + linux,cma-default; + }; + }; + + sm: secure-monitor { + compatible = "amlogic,meson-gxbb-sm"; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + ethmac: ethernet@ff3f0000 { + compatible = "amlogic,meson-axg-dwmac", + "snps,dwmac-3.70a", + "snps,dwmac"; + reg = <0x0 0xff3f0000 0x0 0x10000>, + <0x0 0xff634540 0x0 0x8>; + interrupts = ; + interrupt-names = "macirq"; + clocks = <&clkc CLKID_ETH>, + <&clkc CLKID_FCLK_DIV2>, + <&clkc CLKID_MPLL2>; + clock-names = "stmmaceth", "clkin0", "clkin1"; + rx-fifo-depth = <4096>; + tx-fifo-depth = <2048>; + status = "disabled"; + + mdio0: mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + }; + }; + + apb: bus@ff600000 { + compatible = "simple-bus"; + reg = <0x0 0xff600000 0x0 0x200000>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0xff600000 0x0 0x200000>; + + hdmi_tx: hdmi-tx@0 { + compatible = "amlogic,meson-g12a-dw-hdmi"; + reg = <0x0 0x0 0x0 0x10000>; + interrupts = ; + resets = <&reset RESET_HDMITX_CAPB3>, + <&reset RESET_HDMITX_PHY>, + <&reset RESET_HDMITX>; + reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy"; + clocks = <&clkc CLKID_HDMI>, + <&clkc CLKID_HTX_PCLK>, + <&clkc CLKID_VPU_INTR>; + clock-names = "isfr", "iahb", "venci"; + #address-cells = <1>; + #size-cells = <0>; + #sound-dai-cells = <0>; + status = "disabled"; + + /* VPU VENC Input */ + hdmi_tx_venc_port: port@0 { + reg = <0>; + + hdmi_tx_in: endpoint { + remote-endpoint = <&hdmi_tx_out>; + }; + }; + + /* TMDS Output */ + hdmi_tx_tmds_port: port@1 { + reg = <1>; + }; + }; + + apb_efuse: bus@30000 { + compatible = "simple-bus"; + reg = <0x0 0x30000 0x0 0x2000>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0x30000 0x0 0x2000>; + + hwrng: rng@218 { + compatible = "amlogic,meson-rng"; + reg = <0x0 0x218 0x0 0x4>; + }; + }; + + periphs: bus@34400 { + compatible = "simple-bus"; + reg = <0x0 0x34400 0x0 0x400>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0x34400 0x0 0x400>; + + periphs_pinctrl: pinctrl@40 { + compatible = "amlogic,meson-g12a-periphs-pinctrl"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gpio: bank@40 { + reg = <0x0 0x40 0x0 0x4c>, + <0x0 0xe8 0x0 0x18>, + <0x0 0x120 0x0 0x18>, + <0x0 0x2c0 0x0 0x40>, + <0x0 0x340 0x0 0x1c>; + reg-names = "gpio", + "pull", + "pull-enable", + "mux", + "ds"; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&periphs_pinctrl 0 0 86>; + }; + + cec_ao_a_h_pins: cec_ao_a_h { + mux { + groups = "cec_ao_a_h"; + function = "cec_ao_a_h"; + bias-disable; + }; + }; + + cec_ao_b_h_pins: cec_ao_b_h { + mux { + groups = "cec_ao_b_h"; + function = "cec_ao_b_h"; + bias-disable; + }; + }; + + emmc_pins: emmc { + mux-0 { + groups = "emmc_nand_d0", + "emmc_nand_d1", + "emmc_nand_d2", + "emmc_nand_d3", + "emmc_nand_d4", + "emmc_nand_d5", + "emmc_nand_d6", + "emmc_nand_d7", + "emmc_cmd"; + function = "emmc"; + bias-pull-up; + drive-strength-microamp = <4000>; + }; + + mux-1 { + groups = "emmc_clk"; + function = "emmc"; + bias-disable; + drive-strength-microamp = <4000>; + }; + }; + + emmc_ds_pins: emmc-ds { + mux { + groups = "emmc_nand_ds"; + function = "emmc"; + bias-pull-down; + drive-strength-microamp = <4000>; + }; + }; + + emmc_clk_gate_pins: emmc_clk_gate { + mux { + groups = "BOOT_8"; + function = "gpio_periphs"; + bias-pull-down; + drive-strength-microamp = <4000>; + }; + }; + + hdmitx_ddc_pins: hdmitx_ddc { + mux { + groups = "hdmitx_sda", + "hdmitx_sck"; + function = "hdmitx"; + bias-disable; + drive-strength-microamp = <4000>; + }; + }; + + hdmitx_hpd_pins: hdmitx_hpd { + mux { + groups = "hdmitx_hpd_in"; + function = "hdmitx"; + bias-disable; + }; + }; + + + i2c0_sda_c_pins: i2c0-sda-c { + mux { + groups = "i2c0_sda_c"; + function = "i2c0"; + bias-disable; + drive-strength-microamp = <3000>; + + }; + }; + + i2c0_sck_c_pins: i2c0-sck-c { + mux { + groups = "i2c0_sck_c"; + function = "i2c0"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c0_sda_z0_pins: i2c0-sda-z0 { + mux { + groups = "i2c0_sda_z0"; + function = "i2c0"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c0_sck_z1_pins: i2c0-sck-z1 { + mux { + groups = "i2c0_sck_z1"; + function = "i2c0"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c0_sda_z7_pins: i2c0-sda-z7 { + mux { + groups = "i2c0_sda_z7"; + function = "i2c0"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c0_sda_z8_pins: i2c0-sda-z8 { + mux { + groups = "i2c0_sda_z8"; + function = "i2c0"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c1_sda_x_pins: i2c1-sda-x { + mux { + groups = "i2c1_sda_x"; + function = "i2c1"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c1_sck_x_pins: i2c1-sck-x { + mux { + groups = "i2c1_sck_x"; + function = "i2c1"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c1_sda_h2_pins: i2c1-sda-h2 { + mux { + groups = "i2c1_sda_h2"; + function = "i2c1"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c1_sck_h3_pins: i2c1-sck-h3 { + mux { + groups = "i2c1_sck_h3"; + function = "i2c1"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c1_sda_h6_pins: i2c1-sda-h6 { + mux { + groups = "i2c1_sda_h6"; + function = "i2c1"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c1_sck_h7_pins: i2c1-sck-h7 { + mux { + groups = "i2c1_sck_h7"; + function = "i2c1"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c2_sda_x_pins: i2c2-sda-x { + mux { + groups = "i2c2_sda_x"; + function = "i2c2"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c2_sck_x_pins: i2c2-sck-x { + mux { + groups = "i2c2_sck_x"; + function = "i2c2"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c2_sda_z_pins: i2c2-sda-z { + mux { + groups = "i2c2_sda_z"; + function = "i2c2"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c2_sck_z_pins: i2c2-sck-z { + mux { + groups = "i2c2_sck_z"; + function = "i2c2"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c3_sda_h_pins: i2c3-sda-h { + mux { + groups = "i2c3_sda_h"; + function = "i2c3"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c3_sck_h_pins: i2c3-sck-h { + mux { + groups = "i2c3_sck_h"; + function = "i2c3"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c3_sda_a_pins: i2c3-sda-a { + mux { + groups = "i2c3_sda_a"; + function = "i2c3"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c3_sck_a_pins: i2c3-sck-a { + mux { + groups = "i2c3_sck_a"; + function = "i2c3"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + mclk0_a_pins: mclk0-a { + mux { + groups = "mclk0_a"; + function = "mclk0"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + mclk1_a_pins: mclk1-a { + mux { + groups = "mclk1_a"; + function = "mclk1"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + mclk1_x_pins: mclk1-x { + mux { + groups = "mclk1_x"; + function = "mclk1"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + mclk1_z_pins: mclk1-z { + mux { + groups = "mclk1_z"; + function = "mclk1"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + pdm_din0_a_pins: pdm-din0-a { + mux { + groups = "pdm_din0_a"; + function = "pdm"; + bias-disable; + }; + }; + + pdm_din0_c_pins: pdm-din0-c { + mux { + groups = "pdm_din0_c"; + function = "pdm"; + bias-disable; + }; + }; + + pdm_din0_x_pins: pdm-din0-x { + mux { + groups = "pdm_din0_x"; + function = "pdm"; + bias-disable; + }; + }; + + pdm_din0_z_pins: pdm-din0-z { + mux { + groups = "pdm_din0_z"; + function = "pdm"; + bias-disable; + }; + }; + + pdm_din1_a_pins: pdm-din1-a { + mux { + groups = "pdm_din1_a"; + function = "pdm"; + bias-disable; + }; + }; + + pdm_din1_c_pins: pdm-din1-c { + mux { + groups = "pdm_din1_c"; + function = "pdm"; + bias-disable; + }; + }; + + pdm_din1_x_pins: pdm-din1-x { + mux { + groups = "pdm_din1_x"; + function = "pdm"; + bias-disable; + }; + }; + + pdm_din1_z_pins: pdm-din1-z { + mux { + groups = "pdm_din1_z"; + function = "pdm"; + bias-disable; + }; + }; + + pdm_din2_a_pins: pdm-din2-a { + mux { + groups = "pdm_din2_a"; + function = "pdm"; + bias-disable; + }; + }; + + pdm_din2_c_pins: pdm-din2-c { + mux { + groups = "pdm_din2_c"; + function = "pdm"; + bias-disable; + }; + }; + + pdm_din2_x_pins: pdm-din2-x { + mux { + groups = "pdm_din2_x"; + function = "pdm"; + bias-disable; + }; + }; + + pdm_din2_z_pins: pdm-din2-z { + mux { + groups = "pdm_din2_z"; + function = "pdm"; + bias-disable; + }; + }; + + pdm_din3_a_pins: pdm-din3-a { + mux { + groups = "pdm_din3_a"; + function = "pdm"; + bias-disable; + }; + }; + + pdm_din3_c_pins: pdm-din3-c { + mux { + groups = "pdm_din3_c"; + function = "pdm"; + bias-disable; + }; + }; + + pdm_din3_x_pins: pdm-din3-x { + mux { + groups = "pdm_din3_x"; + function = "pdm"; + bias-disable; + }; + }; + + pdm_din3_z_pins: pdm-din3-z { + mux { + groups = "pdm_din3_z"; + function = "pdm"; + bias-disable; + }; + }; + + pdm_dclk_a_pins: pdm-dclk-a { + mux { + groups = "pdm_dclk_a"; + function = "pdm"; + bias-disable; + drive-strength-microamp = <500>; + }; + }; + + pdm_dclk_c_pins: pdm-dclk-c { + mux { + groups = "pdm_dclk_c"; + function = "pdm"; + bias-disable; + drive-strength-microamp = <500>; + }; + }; + + pdm_dclk_x_pins: pdm-dclk-x { + mux { + groups = "pdm_dclk_x"; + function = "pdm"; + bias-disable; + drive-strength-microamp = <500>; + }; + }; + + pdm_dclk_z_pins: pdm-dclk-z { + mux { + groups = "pdm_dclk_z"; + function = "pdm"; + bias-disable; + drive-strength-microamp = <500>; + }; + }; + + pwm_a_pins: pwm-a { + mux { + groups = "pwm_a"; + function = "pwm_a"; + bias-disable; + }; + }; + + pwm_b_x7_pins: pwm-b-x7 { + mux { + groups = "pwm_b_x7"; + function = "pwm_b"; + bias-disable; + }; + }; + + pwm_b_x19_pins: pwm-b-x19 { + mux { + groups = "pwm_b_x19"; + function = "pwm_b"; + bias-disable; + }; + }; + + pwm_c_c_pins: pwm-c-c { + mux { + groups = "pwm_c_c"; + function = "pwm_c"; + bias-disable; + }; + }; + + pwm_c_x5_pins: pwm-c-x5 { + mux { + groups = "pwm_c_x5"; + function = "pwm_c"; + bias-disable; + }; + }; + + pwm_c_x8_pins: pwm-c-x8 { + mux { + groups = "pwm_c_x8"; + function = "pwm_c"; + bias-disable; + }; + }; + + pwm_d_x3_pins: pwm-d-x3 { + mux { + groups = "pwm_d_x3"; + function = "pwm_d"; + bias-disable; + }; + }; + + pwm_d_x6_pins: pwm-d-x6 { + mux { + groups = "pwm_d_x6"; + function = "pwm_d"; + bias-disable; + }; + }; + + pwm_e_pins: pwm-e { + mux { + groups = "pwm_e"; + function = "pwm_e"; + bias-disable; + }; + }; + + pwm_f_x_pins: pwm-f-x { + mux { + groups = "pwm_f_x"; + function = "pwm_f"; + bias-disable; + }; + }; + + pwm_f_h_pins: pwm-f-h { + mux { + groups = "pwm_f_h"; + function = "pwm_f"; + bias-disable; + }; + }; + + sdcard_c_pins: sdcard_c { + mux-0 { + groups = "sdcard_d0_c", + "sdcard_d1_c", + "sdcard_d2_c", + "sdcard_d3_c", + "sdcard_cmd_c"; + function = "sdcard"; + bias-pull-up; + drive-strength-microamp = <4000>; + }; + + mux-1 { + groups = "sdcard_clk_c"; + function = "sdcard"; + bias-disable; + drive-strength-microamp = <4000>; + }; + }; + + sdcard_clk_gate_c_pins: sdcard_clk_gate_c { + mux { + groups = "GPIOC_4"; + function = "gpio_periphs"; + bias-pull-down; + drive-strength-microamp = <4000>; + }; + }; + + sdcard_z_pins: sdcard_z { + mux-0 { + groups = "sdcard_d0_z", + "sdcard_d1_z", + "sdcard_d2_z", + "sdcard_d3_z", + "sdcard_cmd_z"; + function = "sdcard"; + bias-pull-up; + drive-strength-microamp = <4000>; + }; + + mux-1 { + groups = "sdcard_clk_z"; + function = "sdcard"; + bias-disable; + drive-strength-microamp = <4000>; + }; + }; + + sdcard_clk_gate_z_pins: sdcard_clk_gate_z { + mux { + groups = "GPIOZ_6"; + function = "gpio_periphs"; + bias-pull-down; + drive-strength-microamp = <4000>; + }; + }; + + sdio_pins: sdio { + mux { + groups = "sdio_d0", + "sdio_d1", + "sdio_d2", + "sdio_d3", + "sdio_clk", + "sdio_cmd"; + function = "sdio"; + bias-disable; + drive-strength-microamp = <4000>; + }; + }; + + sdio_clk_gate_pins: sdio_clk_gate { + mux { + groups = "GPIOX_4"; + function = "gpio_periphs"; + bias-pull-down; + drive-strength-microamp = <4000>; + }; + }; + + spdif_in_a10_pins: spdif-in-a10 { + mux { + groups = "spdif_in_a10"; + function = "spdif_in"; + bias-disable; + }; + }; + + spdif_in_a12_pins: spdif-in-a12 { + mux { + groups = "spdif_in_a12"; + function = "spdif_in"; + bias-disable; + }; + }; + + spdif_in_h_pins: spdif-in-h { + mux { + groups = "spdif_in_h"; + function = "spdif_in"; + bias-disable; + }; + }; + + spdif_out_h_pins: spdif-out-h { + mux { + groups = "spdif_out_h"; + function = "spdif_out"; + drive-strength-microamp = <500>; + bias-disable; + }; + }; + + spdif_out_a11_pins: spdif-out-a11 { + mux { + groups = "spdif_out_a11"; + function = "spdif_out"; + drive-strength-microamp = <500>; + bias-disable; + }; + }; + + spdif_out_a13_pins: spdif-out-a13 { + mux { + groups = "spdif_out_a13"; + function = "spdif_out"; + drive-strength-microamp = <500>; + bias-disable; + }; + }; + + tdm_a_din0_pins: tdm-a-din0 { + mux { + groups = "tdm_a_din0"; + function = "tdm_a"; + bias-disable; + }; + }; + + + tdm_a_din1_pins: tdm-a-din1 { + mux { + groups = "tdm_a_din1"; + function = "tdm_a"; + bias-disable; + }; + }; + + tdm_a_dout0_pins: tdm-a-dout0 { + mux { + groups = "tdm_a_dout0"; + function = "tdm_a"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_a_dout1_pins: tdm-a-dout1 { + mux { + groups = "tdm_a_dout1"; + function = "tdm_a"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_a_fs_pins: tdm-a-fs { + mux { + groups = "tdm_a_fs"; + function = "tdm_a"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_a_sclk_pins: tdm-a-sclk { + mux { + groups = "tdm_a_sclk"; + function = "tdm_a"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_a_slv_fs_pins: tdm-a-slv-fs { + mux { + groups = "tdm_a_slv_fs"; + function = "tdm_a"; + bias-disable; + }; + }; + + + tdm_a_slv_sclk_pins: tdm-a-slv-sclk { + mux { + groups = "tdm_a_slv_sclk"; + function = "tdm_a"; + bias-disable; + }; + }; + + tdm_b_din0_pins: tdm-b-din0 { + mux { + groups = "tdm_b_din0"; + function = "tdm_b"; + bias-disable; + }; + }; + + tdm_b_din1_pins: tdm-b-din1 { + mux { + groups = "tdm_b_din1"; + function = "tdm_b"; + bias-disable; + }; + }; + + tdm_b_din2_pins: tdm-b-din2 { + mux { + groups = "tdm_b_din2"; + function = "tdm_b"; + bias-disable; + }; + }; + + tdm_b_din3_a_pins: tdm-b-din3-a { + mux { + groups = "tdm_b_din3_a"; + function = "tdm_b"; + bias-disable; + }; + }; + + tdm_b_din3_h_pins: tdm-b-din3-h { + mux { + groups = "tdm_b_din3_h"; + function = "tdm_b"; + bias-disable; + }; + }; + + tdm_b_dout0_pins: tdm-b-dout0 { + mux { + groups = "tdm_b_dout0"; + function = "tdm_b"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_b_dout1_pins: tdm-b-dout1 { + mux { + groups = "tdm_b_dout1"; + function = "tdm_b"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_b_dout2_pins: tdm-b-dout2 { + mux { + groups = "tdm_b_dout2"; + function = "tdm_b"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_b_dout3_a_pins: tdm-b-dout3-a { + mux { + groups = "tdm_b_dout3_a"; + function = "tdm_b"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_b_dout3_h_pins: tdm-b-dout3-h { + mux { + groups = "tdm_b_dout3_h"; + function = "tdm_b"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_b_fs_pins: tdm-b-fs { + mux { + groups = "tdm_b_fs"; + function = "tdm_b"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_b_sclk_pins: tdm-b-sclk { + mux { + groups = "tdm_b_sclk"; + function = "tdm_b"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_b_slv_fs_pins: tdm-b-slv-fs { + mux { + groups = "tdm_b_slv_fs"; + function = "tdm_b"; + bias-disable; + }; + }; + + tdm_b_slv_sclk_pins: tdm-b-slv-sclk { + mux { + groups = "tdm_b_slv_sclk"; + function = "tdm_b"; + bias-disable; + }; + }; + + tdm_c_din0_a_pins: tdm-c-din0-a { + mux { + groups = "tdm_c_din0_a"; + function = "tdm_c"; + bias-disable; + }; + }; + + tdm_c_din0_z_pins: tdm-c-din0-z { + mux { + groups = "tdm_c_din0_z"; + function = "tdm_c"; + bias-disable; + }; + }; + + tdm_c_din1_a_pins: tdm-c-din1-a { + mux { + groups = "tdm_c_din1_a"; + function = "tdm_c"; + bias-disable; + }; + }; + + tdm_c_din1_z_pins: tdm-c-din1-z { + mux { + groups = "tdm_c_din1_z"; + function = "tdm_c"; + bias-disable; + }; + }; + + tdm_c_din2_a_pins: tdm-c-din2-a { + mux { + groups = "tdm_c_din2_a"; + function = "tdm_c"; + bias-disable; + }; + }; + + eth_leds_pins: eth-leds { + mux { + groups = "eth_link_led", + "eth_act_led"; + function = "eth"; + bias-disable; + }; + }; + + eth_pins: eth { + mux { + groups = "eth_mdio", + "eth_mdc", + "eth_rgmii_rx_clk", + "eth_rx_dv", + "eth_rxd0", + "eth_rxd1", + "eth_txen", + "eth_txd0", + "eth_txd1"; + function = "eth"; + drive-strength-microamp = <4000>; + bias-disable; + }; + }; + + eth_rgmii_pins: eth-rgmii { + mux { + groups = "eth_rxd2_rgmii", + "eth_rxd3_rgmii", + "eth_rgmii_tx_clk", + "eth_txd2_rgmii", + "eth_txd3_rgmii"; + function = "eth"; + drive-strength-microamp = <4000>; + bias-disable; + }; + }; + + tdm_c_din2_z_pins: tdm-c-din2-z { + mux { + groups = "tdm_c_din2_z"; + function = "tdm_c"; + bias-disable; + }; + }; + + tdm_c_din3_a_pins: tdm-c-din3-a { + mux { + groups = "tdm_c_din3_a"; + function = "tdm_c"; + bias-disable; + }; + }; + + tdm_c_din3_z_pins: tdm-c-din3-z { + mux { + groups = "tdm_c_din3_z"; + function = "tdm_c"; + bias-disable; + }; + }; + + tdm_c_dout0_a_pins: tdm-c-dout0-a { + mux { + groups = "tdm_c_dout0_a"; + function = "tdm_c"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_c_dout0_z_pins: tdm-c-dout0-z { + mux { + groups = "tdm_c_dout0_z"; + function = "tdm_c"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_c_dout1_a_pins: tdm-c-dout1-a { + mux { + groups = "tdm_c_dout1_a"; + function = "tdm_c"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_c_dout1_z_pins: tdm-c-dout1-z { + mux { + groups = "tdm_c_dout1_z"; + function = "tdm_c"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_c_dout2_a_pins: tdm-c-dout2-a { + mux { + groups = "tdm_c_dout2_a"; + function = "tdm_c"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_c_dout2_z_pins: tdm-c-dout2-z { + mux { + groups = "tdm_c_dout2_z"; + function = "tdm_c"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_c_dout3_a_pins: tdm-c-dout3-a { + mux { + groups = "tdm_c_dout3_a"; + function = "tdm_c"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_c_dout3_z_pins: tdm-c-dout3-z { + mux { + groups = "tdm_c_dout3_z"; + function = "tdm_c"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_c_fs_a_pins: tdm-c-fs-a { + mux { + groups = "tdm_c_fs_a"; + function = "tdm_c"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_c_fs_z_pins: tdm-c-fs-z { + mux { + groups = "tdm_c_fs_z"; + function = "tdm_c"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_c_sclk_a_pins: tdm-c-sclk-a { + mux { + groups = "tdm_c_sclk_a"; + function = "tdm_c"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_c_sclk_z_pins: tdm-c-sclk-z { + mux { + groups = "tdm_c_sclk_z"; + function = "tdm_c"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_c_slv_fs_a_pins: tdm-c-slv-fs-a { + mux { + groups = "tdm_c_slv_fs_a"; + function = "tdm_c"; + bias-disable; + }; + }; + + tdm_c_slv_fs_z_pins: tdm-c-slv-fs-z { + mux { + groups = "tdm_c_slv_fs_z"; + function = "tdm_c"; + bias-disable; + }; + }; + + tdm_c_slv_sclk_a_pins: tdm-c-slv-sclk-a { + mux { + groups = "tdm_c_slv_sclk_a"; + function = "tdm_c"; + bias-disable; + }; + }; + + tdm_c_slv_sclk_z_pins: tdm-c-slv-sclk-z { + mux { + groups = "tdm_c_slv_sclk_z"; + function = "tdm_c"; + bias-disable; + }; + }; + + uart_a_pins: uart-a { + mux { + groups = "uart_a_tx", + "uart_a_rx"; + function = "uart_a"; + bias-disable; + }; + }; + + uart_a_cts_rts_pins: uart-a-cts-rts { + mux { + groups = "uart_a_cts", + "uart_a_rts"; + function = "uart_a"; + bias-disable; + }; + }; + + uart_b_pins: uart-b { + mux { + groups = "uart_b_tx", + "uart_b_rx"; + function = "uart_b"; + bias-disable; + }; + }; + + uart_c_pins: uart-c { + mux { + groups = "uart_c_tx", + "uart_c_rx"; + function = "uart_c"; + bias-disable; + }; + }; + + uart_c_cts_rts_pins: uart-c-cts-rts { + mux { + groups = "uart_c_cts", + "uart_c_rts"; + function = "uart_c"; + bias-disable; + }; + }; + }; + }; + + usb2_phy0: phy@36000 { + compatible = "amlogic,g12a-usb2-phy"; + reg = <0x0 0x36000 0x0 0x2000>; + clocks = <&xtal>; + clock-names = "xtal"; + resets = <&reset RESET_USB_PHY20>; + reset-names = "phy"; + #phy-cells = <0>; + }; + + dmc: bus@38000 { + compatible = "simple-bus"; + reg = <0x0 0x38000 0x0 0x400>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0x38000 0x0 0x400>; + + canvas: video-lut@48 { + compatible = "amlogic,canvas"; + reg = <0x0 0x48 0x0 0x14>; + }; + }; + + usb2_phy1: phy@3a000 { + compatible = "amlogic,g12a-usb2-phy"; + reg = <0x0 0x3a000 0x0 0x2000>; + clocks = <&xtal>; + clock-names = "xtal"; + resets = <&reset RESET_USB_PHY21>; + reset-names = "phy"; + #phy-cells = <0>; + }; + + hiu: bus@3c000 { + compatible = "simple-bus"; + reg = <0x0 0x3c000 0x0 0x1400>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0x3c000 0x0 0x1400>; + + hhi: system-controller@0 { + compatible = "amlogic,meson-gx-hhi-sysctrl", + "simple-mfd", "syscon"; + reg = <0 0 0 0x400>; + + clkc: clock-controller { + compatible = "amlogic,g12a-clkc"; + #clock-cells = <1>; + clocks = <&xtal>; + clock-names = "xtal"; + }; + + pwrc: power-controller { + compatible = "amlogic,meson-g12a-pwrc"; + #power-domain-cells = <1>; + amlogic,ao-sysctrl = <&rti>; + resets = <&reset RESET_VIU>, + <&reset RESET_VENC>, + <&reset RESET_VCBUS>, + <&reset RESET_BT656>, + <&reset RESET_RDMA>, + <&reset RESET_VENCI>, + <&reset RESET_VENCP>, + <&reset RESET_VDAC>, + <&reset RESET_VDI6>, + <&reset RESET_VENCL>, + <&reset RESET_VID_LOCK>; + reset-names = "viu", "venc", "vcbus", "bt656", + "rdma", "venci", "vencp", "vdac", + "vdi6", "vencl", "vid_lock"; + clocks = <&clkc CLKID_VPU>, + <&clkc CLKID_VAPB>; + clock-names = "vpu", "vapb"; + /* + * VPU clocking is provided by two identical clock paths + * VPU_0 and VPU_1 muxed to a single clock by a glitch + * free mux to safely change frequency while running. + * Same for VAPB but with a final gate after the glitch free mux. + */ + assigned-clocks = <&clkc CLKID_VPU_0_SEL>, + <&clkc CLKID_VPU_0>, + <&clkc CLKID_VPU>, /* Glitch free mux */ + <&clkc CLKID_VAPB_0_SEL>, + <&clkc CLKID_VAPB_0>, + <&clkc CLKID_VAPB_SEL>; /* Glitch free mux */ + assigned-clock-parents = <&clkc CLKID_FCLK_DIV3>, + <0>, /* Do Nothing */ + <&clkc CLKID_VPU_0>, + <&clkc CLKID_FCLK_DIV4>, + <0>, /* Do Nothing */ + <&clkc CLKID_VAPB_0>; + assigned-clock-rates = <0>, /* Do Nothing */ + <666666666>, + <0>, /* Do Nothing */ + <0>, /* Do Nothing */ + <250000000>, + <0>; /* Do Nothing */ + }; + }; + }; + + pdm: audio-controller@40000 { + compatible = "amlogic,g12a-pdm", + "amlogic,axg-pdm"; + reg = <0x0 0x40000 0x0 0x34>; + #sound-dai-cells = <0>; + sound-name-prefix = "PDM"; + clocks = <&clkc_audio AUD_CLKID_PDM>, + <&clkc_audio AUD_CLKID_PDM_DCLK>, + <&clkc_audio AUD_CLKID_PDM_SYSCLK>; + clock-names = "pclk", "dclk", "sysclk"; + status = "disabled"; + }; + + audio: bus@42000 { + compatible = "simple-bus"; + reg = <0x0 0x42000 0x0 0x2000>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0x42000 0x0 0x2000>; + + clkc_audio: clock-controller@0 { + status = "disabled"; + compatible = "amlogic,g12a-audio-clkc"; + reg = <0x0 0x0 0x0 0xb4>; + #clock-cells = <1>; + #reset-cells = <1>; + + clocks = <&clkc CLKID_AUDIO>, + <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>, + <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL3>, + <&clkc CLKID_HIFI_PLL>, + <&clkc CLKID_FCLK_DIV3>, + <&clkc CLKID_FCLK_DIV4>, + <&clkc CLKID_GP0_PLL>; + clock-names = "pclk", + "mst_in0", + "mst_in1", + "mst_in2", + "mst_in3", + "mst_in4", + "mst_in5", + "mst_in6", + "mst_in7"; + + resets = <&reset RESET_AUDIO>; + }; + + toddr_a: audio-controller@100 { + compatible = "amlogic,g12a-toddr", + "amlogic,axg-toddr"; + reg = <0x0 0x100 0x0 0x1c>; + #sound-dai-cells = <0>; + sound-name-prefix = "TODDR_A"; + interrupts = ; + clocks = <&clkc_audio AUD_CLKID_TODDR_A>; + resets = <&arb AXG_ARB_TODDR_A>; + status = "disabled"; + }; + + toddr_b: audio-controller@140 { + compatible = "amlogic,g12a-toddr", + "amlogic,axg-toddr"; + reg = <0x0 0x140 0x0 0x1c>; + #sound-dai-cells = <0>; + sound-name-prefix = "TODDR_B"; + interrupts = ; + clocks = <&clkc_audio AUD_CLKID_TODDR_B>; + resets = <&arb AXG_ARB_TODDR_B>; + status = "disabled"; + }; + + toddr_c: audio-controller@180 { + compatible = "amlogic,g12a-toddr", + "amlogic,axg-toddr"; + reg = <0x0 0x180 0x0 0x1c>; + #sound-dai-cells = <0>; + sound-name-prefix = "TODDR_C"; + interrupts = ; + clocks = <&clkc_audio AUD_CLKID_TODDR_C>; + resets = <&arb AXG_ARB_TODDR_C>; + status = "disabled"; + }; + + frddr_a: audio-controller@1c0 { + compatible = "amlogic,g12a-frddr", + "amlogic,axg-frddr"; + reg = <0x0 0x1c0 0x0 0x1c>; + #sound-dai-cells = <0>; + sound-name-prefix = "FRDDR_A"; + interrupts = ; + clocks = <&clkc_audio AUD_CLKID_FRDDR_A>; + resets = <&arb AXG_ARB_FRDDR_A>; + status = "disabled"; + }; + + frddr_b: audio-controller@200 { + compatible = "amlogic,g12a-frddr", + "amlogic,axg-frddr"; + reg = <0x0 0x200 0x0 0x1c>; + #sound-dai-cells = <0>; + sound-name-prefix = "FRDDR_B"; + interrupts = ; + clocks = <&clkc_audio AUD_CLKID_FRDDR_B>; + resets = <&arb AXG_ARB_FRDDR_B>; + status = "disabled"; + }; + + frddr_c: audio-controller@240 { + compatible = "amlogic,g12a-frddr", + "amlogic,axg-frddr"; + reg = <0x0 0x240 0x0 0x1c>; + #sound-dai-cells = <0>; + sound-name-prefix = "FRDDR_C"; + interrupts = ; + clocks = <&clkc_audio AUD_CLKID_FRDDR_C>; + resets = <&arb AXG_ARB_FRDDR_C>; + status = "disabled"; + }; + + arb: reset-controller@280 { + status = "disabled"; + compatible = "amlogic,meson-axg-audio-arb"; + reg = <0x0 0x280 0x0 0x4>; + #reset-cells = <1>; + clocks = <&clkc_audio AUD_CLKID_DDR_ARB>; + }; + + tdmin_a: audio-controller@300 { + compatible = "amlogic,g12a-tdmin", + "amlogic,axg-tdmin"; + reg = <0x0 0x300 0x0 0x40>; + sound-name-prefix = "TDMIN_A"; + resets = <&clkc_audio AUD_RESET_TDMIN_A>; + clocks = <&clkc_audio AUD_CLKID_TDMIN_A>, + <&clkc_audio AUD_CLKID_TDMIN_A_SCLK>, + <&clkc_audio AUD_CLKID_TDMIN_A_SCLK_SEL>, + <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>, + <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>; + clock-names = "pclk", "sclk", "sclk_sel", + "lrclk", "lrclk_sel"; + status = "disabled"; + }; + + tdmin_b: audio-controller@340 { + compatible = "amlogic,g12a-tdmin", + "amlogic,axg-tdmin"; + reg = <0x0 0x340 0x0 0x40>; + sound-name-prefix = "TDMIN_B"; + resets = <&clkc_audio AUD_RESET_TDMIN_B>; + clocks = <&clkc_audio AUD_CLKID_TDMIN_B>, + <&clkc_audio AUD_CLKID_TDMIN_B_SCLK>, + <&clkc_audio AUD_CLKID_TDMIN_B_SCLK_SEL>, + <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>, + <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>; + clock-names = "pclk", "sclk", "sclk_sel", + "lrclk", "lrclk_sel"; + status = "disabled"; + }; + + tdmin_c: audio-controller@380 { + compatible = "amlogic,g12a-tdmin", + "amlogic,axg-tdmin"; + reg = <0x0 0x380 0x0 0x40>; + sound-name-prefix = "TDMIN_C"; + resets = <&clkc_audio AUD_RESET_TDMIN_C>; + clocks = <&clkc_audio AUD_CLKID_TDMIN_C>, + <&clkc_audio AUD_CLKID_TDMIN_C_SCLK>, + <&clkc_audio AUD_CLKID_TDMIN_C_SCLK_SEL>, + <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>, + <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>; + clock-names = "pclk", "sclk", "sclk_sel", + "lrclk", "lrclk_sel"; + status = "disabled"; + }; + + tdmin_lb: audio-controller@3c0 { + compatible = "amlogic,g12a-tdmin", + "amlogic,axg-tdmin"; + reg = <0x0 0x3c0 0x0 0x40>; + sound-name-prefix = "TDMIN_LB"; + resets = <&clkc_audio AUD_RESET_TDMIN_LB>; + clocks = <&clkc_audio AUD_CLKID_TDMIN_LB>, + <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK>, + <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK_SEL>, + <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>, + <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>; + clock-names = "pclk", "sclk", "sclk_sel", + "lrclk", "lrclk_sel"; + status = "disabled"; + }; + + spdifin: audio-controller@400 { + compatible = "amlogic,g12a-spdifin", + "amlogic,axg-spdifin"; + reg = <0x0 0x400 0x0 0x30>; + #sound-dai-cells = <0>; + sound-name-prefix = "SPDIFIN"; + interrupts = ; + clocks = <&clkc_audio AUD_CLKID_SPDIFIN>, + <&clkc_audio AUD_CLKID_SPDIFIN_CLK>; + clock-names = "pclk", "refclk"; + status = "disabled"; + }; + + spdifout: audio-controller@480 { + compatible = "amlogic,g12a-spdifout", + "amlogic,axg-spdifout"; + reg = <0x0 0x480 0x0 0x50>; + #sound-dai-cells = <0>; + sound-name-prefix = "SPDIFOUT"; + clocks = <&clkc_audio AUD_CLKID_SPDIFOUT>, + <&clkc_audio AUD_CLKID_SPDIFOUT_CLK>; + clock-names = "pclk", "mclk"; + status = "disabled"; + }; + + tdmout_a: audio-controller@500 { + compatible = "amlogic,g12a-tdmout"; + reg = <0x0 0x500 0x0 0x40>; + sound-name-prefix = "TDMOUT_A"; + resets = <&clkc_audio AUD_RESET_TDMOUT_A>; + clocks = <&clkc_audio AUD_CLKID_TDMOUT_A>, + <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK>, + <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK_SEL>, + <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>, + <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>; + clock-names = "pclk", "sclk", "sclk_sel", + "lrclk", "lrclk_sel"; + status = "disabled"; + }; + + tdmout_b: audio-controller@540 { + compatible = "amlogic,g12a-tdmout"; + reg = <0x0 0x540 0x0 0x40>; + sound-name-prefix = "TDMOUT_B"; + resets = <&clkc_audio AUD_RESET_TDMOUT_B>; + clocks = <&clkc_audio AUD_CLKID_TDMOUT_B>, + <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK>, + <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK_SEL>, + <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>, + <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>; + clock-names = "pclk", "sclk", "sclk_sel", + "lrclk", "lrclk_sel"; + status = "disabled"; + }; + + tdmout_c: audio-controller@580 { + compatible = "amlogic,g12a-tdmout"; + reg = <0x0 0x580 0x0 0x40>; + sound-name-prefix = "TDMOUT_C"; + resets = <&clkc_audio AUD_RESET_TDMOUT_C>; + clocks = <&clkc_audio AUD_CLKID_TDMOUT_C>, + <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK>, + <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK_SEL>, + <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>, + <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>; + clock-names = "pclk", "sclk", "sclk_sel", + "lrclk", "lrclk_sel"; + status = "disabled"; + }; + + spdifout_b: audio-controller@680 { + compatible = "amlogic,g12a-spdifout", + "amlogic,axg-spdifout"; + reg = <0x0 0x680 0x0 0x50>; + #sound-dai-cells = <0>; + sound-name-prefix = "SPDIFOUT_B"; + clocks = <&clkc_audio AUD_CLKID_SPDIFOUT_B>, + <&clkc_audio AUD_CLKID_SPDIFOUT_B_CLK>; + clock-names = "pclk", "mclk"; + status = "disabled"; + }; + + tohdmitx: audio-controller@744 { + compatible = "amlogic,g12a-tohdmitx"; + reg = <0x0 0x744 0x0 0x4>; + #sound-dai-cells = <1>; + sound-name-prefix = "TOHDMITX"; + status = "disabled"; + }; + }; + + usb3_pcie_phy: phy@46000 { + compatible = "amlogic,g12a-usb3-pcie-phy"; + reg = <0x0 0x46000 0x0 0x2000>; + clocks = <&clkc CLKID_PCIE_PLL>; + clock-names = "ref_clk"; + resets = <&reset RESET_PCIE_PHY>; + reset-names = "phy"; + assigned-clocks = <&clkc CLKID_PCIE_PLL>; + assigned-clock-rates = <100000000>; + #phy-cells = <1>; + }; + + eth_phy: mdio-multiplexer@4c000 { + compatible = "amlogic,g12a-mdio-mux"; + reg = <0x0 0x4c000 0x0 0xa4>; + clocks = <&clkc CLKID_ETH_PHY>, + <&xtal>, + <&clkc CLKID_MPLL_50M>; + clock-names = "pclk", "clkin0", "clkin1"; + mdio-parent-bus = <&mdio0>; + #address-cells = <1>; + #size-cells = <0>; + + ext_mdio: mdio@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + int_mdio: mdio@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + internal_ephy: ethernet_phy@8 { + compatible = "ethernet-phy-id0180.3301", + "ethernet-phy-ieee802.3-c22"; + interrupts = ; + reg = <8>; + max-speed = <100>; + }; + }; + }; + }; + + aobus: bus@ff800000 { + compatible = "simple-bus"; + reg = <0x0 0xff800000 0x0 0x100000>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0xff800000 0x0 0x100000>; + + rti: sys-ctrl@0 { + compatible = "amlogic,meson-gx-ao-sysctrl", + "simple-mfd", "syscon"; + reg = <0x0 0x0 0x0 0x100>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0x0 0x0 0x100>; + + clkc_AO: clock-controller { + compatible = "amlogic,meson-g12a-aoclkc"; + #clock-cells = <1>; + #reset-cells = <1>; + clocks = <&xtal>, <&clkc CLKID_CLK81>; + clock-names = "xtal", "mpeg-clk"; + }; + + ao_pinctrl: pinctrl@14 { + compatible = "amlogic,meson-g12a-aobus-pinctrl"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gpio_ao: bank@14 { + reg = <0x0 0x14 0x0 0x8>, + <0x0 0x1c 0x0 0x8>, + <0x0 0x24 0x0 0x14>; + reg-names = "mux", + "ds", + "gpio"; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&ao_pinctrl 0 0 15>; + }; + + i2c_ao_sck_pins: i2c_ao_sck_pins { + mux { + groups = "i2c_ao_sck"; + function = "i2c_ao"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c_ao_sda_pins: i2c_ao_sda { + mux { + groups = "i2c_ao_sda"; + function = "i2c_ao"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c_ao_sck_e_pins: i2c_ao_sck_e { + mux { + groups = "i2c_ao_sck_e"; + function = "i2c_ao"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + i2c_ao_sda_e_pins: i2c_ao_sda_e { + mux { + groups = "i2c_ao_sda_e"; + function = "i2c_ao"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + mclk0_ao_pins: mclk0-ao { + mux { + groups = "mclk0_ao"; + function = "mclk0_ao"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_ao_b_din0_pins: tdm-ao-b-din0 { + mux { + groups = "tdm_ao_b_din0"; + function = "tdm_ao_b"; + bias-disable; + }; + }; + + spdif_ao_out_pins: spdif-ao-out { + mux { + groups = "spdif_ao_out"; + function = "spdif_ao_out"; + drive-strength-microamp = <500>; + bias-disable; + }; + }; + + tdm_ao_b_din1_pins: tdm-ao-b-din1 { + mux { + groups = "tdm_ao_b_din1"; + function = "tdm_ao_b"; + bias-disable; + }; + }; + + tdm_ao_b_din2_pins: tdm-ao-b-din2 { + mux { + groups = "tdm_ao_b_din2"; + function = "tdm_ao_b"; + bias-disable; + }; + }; + + tdm_ao_b_dout0_pins: tdm-ao-b-dout0 { + mux { + groups = "tdm_ao_b_dout0"; + function = "tdm_ao_b"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_ao_b_dout1_pins: tdm-ao-b-dout1 { + mux { + groups = "tdm_ao_b_dout1"; + function = "tdm_ao_b"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_ao_b_dout2_pins: tdm-ao-b-dout2 { + mux { + groups = "tdm_ao_b_dout2"; + function = "tdm_ao_b"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_ao_b_fs_pins: tdm-ao-b-fs { + mux { + groups = "tdm_ao_b_fs"; + function = "tdm_ao_b"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_ao_b_sclk_pins: tdm-ao-b-sclk { + mux { + groups = "tdm_ao_b_sclk"; + function = "tdm_ao_b"; + bias-disable; + drive-strength-microamp = <3000>; + }; + }; + + tdm_ao_b_slv_fs_pins: tdm-ao-b-slv-fs { + mux { + groups = "tdm_ao_b_slv_fs"; + function = "tdm_ao_b"; + bias-disable; + }; + }; + + tdm_ao_b_slv_sclk_pins: tdm-ao-b-slv-sclk { + mux { + groups = "tdm_ao_b_slv_sclk"; + function = "tdm_ao_b"; + bias-disable; + }; + }; + + uart_ao_a_pins: uart-a-ao { + mux { + groups = "uart_ao_a_tx", + "uart_ao_a_rx"; + function = "uart_ao_a"; + bias-disable; + }; + }; + + uart_ao_a_cts_rts_pins: uart-ao-a-cts-rts { + mux { + groups = "uart_ao_a_cts", + "uart_ao_a_rts"; + function = "uart_ao_a"; + bias-disable; + }; + }; + + pwm_a_e_pins: pwm-a-e { + mux { + groups = "pwm_a_e"; + function = "pwm_a_e"; + bias-disable; + }; + }; + + pwm_ao_a_pins: pwm-ao-a { + mux { + groups = "pwm_ao_a"; + function = "pwm_ao_a"; + bias-disable; + }; + }; + + pwm_ao_b_pins: pwm-ao-b { + mux { + groups = "pwm_ao_b"; + function = "pwm_ao_b"; + bias-disable; + }; + }; + + pwm_ao_c_4_pins: pwm-ao-c-4 { + mux { + groups = "pwm_ao_c_4"; + function = "pwm_ao_c"; + bias-disable; + }; + }; + + pwm_ao_c_6_pins: pwm-ao-c-6 { + mux { + groups = "pwm_ao_c_6"; + function = "pwm_ao_c"; + bias-disable; + }; + }; + + pwm_ao_d_5_pins: pwm-ao-d-5 { + mux { + groups = "pwm_ao_d_5"; + function = "pwm_ao_d"; + bias-disable; + }; + }; + + pwm_ao_d_10_pins: pwm-ao-d-10 { + mux { + groups = "pwm_ao_d_10"; + function = "pwm_ao_d"; + bias-disable; + }; + }; + + pwm_ao_d_e_pins: pwm-ao-d-e { + mux { + groups = "pwm_ao_d_e"; + function = "pwm_ao_d"; + }; + }; + + remote_input_ao_pins: remote-input-ao { + mux { + groups = "remote_ao_input"; + function = "remote_ao_input"; + bias-disable; + }; + }; + }; + }; + + vrtc: rtc@0a8 { + compatible = "amlogic,meson-vrtc"; + reg = <0x0 0x000a8 0x0 0x4>; + }; + + cec_AO: cec@100 { + compatible = "amlogic,meson-gx-ao-cec"; + reg = <0x0 0x00100 0x0 0x14>; + interrupts = ; + clocks = <&clkc_AO CLKID_AO_CEC>; + clock-names = "core"; + status = "disabled"; + }; + + sec_AO: ao-secure@140 { + compatible = "amlogic,meson-gx-ao-secure", "syscon"; + reg = <0x0 0x140 0x0 0x140>; + amlogic,has-chip-id; + }; + + cecb_AO: cec@280 { + compatible = "amlogic,meson-g12a-ao-cec"; + reg = <0x0 0x00280 0x0 0x1c>; + interrupts = ; + clocks = <&clkc_AO CLKID_AO_CTS_OSCIN>; + clock-names = "oscin"; + status = "disabled"; + }; + + pwm_AO_cd: pwm@2000 { + compatible = "amlogic,meson-g12a-ao-pwm-cd"; + reg = <0x0 0x2000 0x0 0x20>; + #pwm-cells = <3>; + status = "disabled"; + }; + + uart_AO: serial@3000 { + compatible = "amlogic,meson-gx-uart", + "amlogic,meson-ao-uart"; + reg = <0x0 0x3000 0x0 0x18>; + interrupts = ; + clocks = <&xtal>, <&clkc_AO CLKID_AO_UART>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; + status = "disabled"; + }; + + uart_AO_B: serial@4000 { + compatible = "amlogic,meson-gx-uart", + "amlogic,meson-ao-uart"; + reg = <0x0 0x4000 0x0 0x18>; + interrupts = ; + clocks = <&xtal>, <&clkc_AO CLKID_AO_UART2>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; + status = "disabled"; + }; + + i2c_AO: i2c@5000 { + compatible = "amlogic,meson-axg-i2c"; + status = "disabled"; + reg = <0x0 0x05000 0x0 0x20>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clkc CLKID_I2C>; + }; + + pwm_AO_ab: pwm@7000 { + compatible = "amlogic,meson-g12a-ao-pwm-ab"; + reg = <0x0 0x7000 0x0 0x20>; + #pwm-cells = <3>; + status = "disabled"; + }; + + ir: ir@8000 { + compatible = "amlogic,meson-gxbb-ir"; + reg = <0x0 0x8000 0x0 0x20>; + interrupts = ; + status = "disabled"; + }; + + saradc: adc@9000 { + compatible = "amlogic,meson-g12a-saradc", + "amlogic,meson-saradc"; + reg = <0x0 0x9000 0x0 0x48>; + #io-channel-cells = <1>; + interrupts = ; + clocks = <&xtal>, + <&clkc_AO CLKID_AO_SAR_ADC>, + <&clkc_AO CLKID_AO_SAR_ADC_CLK>, + <&clkc_AO CLKID_AO_SAR_ADC_SEL>; + clock-names = "clkin", "core", "adc_clk", "adc_sel"; + status = "disabled"; + }; + }; + + vpu: vpu@ff900000 { + compatible = "amlogic,meson-g12a-vpu"; + reg = <0x0 0xff900000 0x0 0x100000>, + <0x0 0xff63c000 0x0 0x1000>; + reg-names = "vpu", "hhi"; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + amlogic,canvas = <&canvas>; + + /* CVBS VDAC output port */ + cvbs_vdac_port: port@0 { + reg = <0>; + }; + + /* HDMI-TX output port */ + hdmi_tx_port: port@1 { + reg = <1>; + + hdmi_tx_out: endpoint { + remote-endpoint = <&hdmi_tx_in>; + }; + }; + }; + + gic: interrupt-controller@ffc01000 { + compatible = "arm,gic-400"; + reg = <0x0 0xffc01000 0 0x1000>, + <0x0 0xffc02000 0 0x2000>, + <0x0 0xffc04000 0 0x2000>, + <0x0 0xffc06000 0 0x2000>; + interrupt-controller; + interrupts = ; + #interrupt-cells = <3>; + #address-cells = <0>; + }; + + cbus: bus@ffd00000 { + compatible = "simple-bus"; + reg = <0x0 0xffd00000 0x0 0x100000>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0xffd00000 0x0 0x100000>; + + reset: reset-controller@1004 { + compatible = "amlogic,meson-axg-reset"; + reg = <0x0 0x1004 0x0 0x9c>; + #reset-cells = <1>; + }; + + gpio_intc: interrupt-controller@f080 { + compatible = "amlogic,meson-g12a-gpio-intc", + "amlogic,meson-gpio-intc"; + reg = <0x0 0xf080 0x0 0x10>; + interrupt-controller; + #interrupt-cells = <2>; + amlogic,channel-interrupts = <64 65 66 67 68 69 70 71>; + }; + + pwm_ef: pwm@19000 { + compatible = "amlogic,meson-g12a-ee-pwm"; + reg = <0x0 0x19000 0x0 0x20>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm_cd: pwm@1a000 { + compatible = "amlogic,meson-g12a-ee-pwm"; + reg = <0x0 0x1a000 0x0 0x20>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm_ab: pwm@1b000 { + compatible = "amlogic,meson-g12a-ee-pwm"; + reg = <0x0 0x1b000 0x0 0x20>; + #pwm-cells = <3>; + status = "disabled"; + }; + + i2c3: i2c@1c000 { + compatible = "amlogic,meson-axg-i2c"; + status = "disabled"; + reg = <0x0 0x1c000 0x0 0x20>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clkc CLKID_I2C>; + }; + + i2c2: i2c@1d000 { + compatible = "amlogic,meson-axg-i2c"; + status = "disabled"; + reg = <0x0 0x1d000 0x0 0x20>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clkc CLKID_I2C>; + }; + + i2c1: i2c@1e000 { + compatible = "amlogic,meson-axg-i2c"; + status = "disabled"; + reg = <0x0 0x1e000 0x0 0x20>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clkc CLKID_I2C>; + }; + + i2c0: i2c@1f000 { + compatible = "amlogic,meson-axg-i2c"; + status = "disabled"; + reg = <0x0 0x1f000 0x0 0x20>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clkc CLKID_I2C>; + }; + + clk_msr: clock-measure@18000 { + compatible = "amlogic,meson-g12a-clk-measure"; + reg = <0x0 0x18000 0x0 0x10>; + }; + + uart_C: serial@22000 { + compatible = "amlogic,meson-gx-uart"; + reg = <0x0 0x22000 0x0 0x18>; + interrupts = ; + clocks = <&xtal>, <&clkc CLKID_UART2>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; + status = "disabled"; + }; + + uart_B: serial@23000 { + compatible = "amlogic,meson-gx-uart"; + reg = <0x0 0x23000 0x0 0x18>; + interrupts = ; + clocks = <&xtal>, <&clkc CLKID_UART1>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; + status = "disabled"; + }; + + uart_A: serial@24000 { + compatible = "amlogic,meson-gx-uart"; + reg = <0x0 0x24000 0x0 0x18>; + interrupts = ; + clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; + status = "disabled"; + }; + }; + + sd_emmc_a: sd@ffe03000 { + compatible = "amlogic,meson-axg-mmc"; + reg = <0x0 0xffe03000 0x0 0x800>; + interrupts = ; + status = "disabled"; + clocks = <&clkc CLKID_SD_EMMC_A>, + <&clkc CLKID_SD_EMMC_A_CLK0>, + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; + }; + + sd_emmc_b: sd@ffe05000 { + compatible = "amlogic,meson-axg-mmc"; + reg = <0x0 0xffe05000 0x0 0x800>; + interrupts = ; + status = "disabled"; + clocks = <&clkc CLKID_SD_EMMC_B>, + <&clkc CLKID_SD_EMMC_B_CLK0>, + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; + }; + + sd_emmc_c: mmc@ffe07000 { + compatible = "amlogic,meson-axg-mmc"; + reg = <0x0 0xffe07000 0x0 0x800>; + interrupts = ; + status = "disabled"; + clocks = <&clkc CLKID_SD_EMMC_C>, + <&clkc CLKID_SD_EMMC_C_CLK0>, + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; + }; + + usb: usb@ffe09000 { + status = "disabled"; + compatible = "amlogic,meson-g12a-usb-ctrl"; + reg = <0x0 0xffe09000 0x0 0xa0>; + interrupts = ; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + clocks = <&clkc CLKID_USB>; + resets = <&reset RESET_USB>; + + dr_mode = "otg"; + + phys = <&usb2_phy0>, <&usb2_phy1>, + <&usb3_pcie_phy PHY_TYPE_USB3>; + phy-names = "usb2-phy0", "usb2-phy1", "usb3-phy0"; + + dwc2: usb@ff400000 { + compatible = "amlogic,meson-g12a-usb", "snps,dwc2"; + reg = <0x0 0xff400000 0x0 0x40000>; + interrupts = ; + clocks = <&clkc CLKID_USB1_DDR_BRIDGE>; + clock-names = "ddr"; + phys = <&usb2_phy1>; + phy-names = "usb2-phy"; + dr_mode = "peripheral"; + g-rx-fifo-size = <192>; + g-np-tx-fifo-size = <128>; + g-tx-fifo-size = <128 128 16 16 16>; + }; + + dwc3: usb@ff500000 { + compatible = "snps,dwc3"; + reg = <0x0 0xff500000 0x0 0x100000>; + interrupts = ; + dr_mode = "host"; + snps,dis_u2_susphy_quirk; + snps,quirk-frame-length-adjustment; + }; + }; + + mali: gpu@ffe40000 { + compatible = "amlogic,meson-g12a-mali", "arm,mali-bifrost"; + reg = <0x0 0xffe40000 0x0 0x40000>; + interrupt-parent = <&gic>; + interrupts = , + , + ; + interrupt-names = "gpu", "mmu", "job"; + clocks = <&clkc CLKID_MALI>; + resets = <&reset RESET_DVALIN_CAPB3>, <&reset RESET_DVALIN>; + + /* + * Mali clocking is provided by two identical clock paths + * MALI_0 and MALI_1 muxed to a single clock by a glitch + * free mux to safely change frequency while running. + */ + assigned-clocks = <&clkc CLKID_MALI_0_SEL>, + <&clkc CLKID_MALI_0>, + <&clkc CLKID_MALI>; /* Glitch free mux */ + assigned-clock-parents = <&clkc CLKID_FCLK_DIV2P5>, + <0>, /* Do Nothing */ + <&clkc CLKID_MALI_0>; + assigned-clock-rates = <0>, /* Do Nothing */ + <800000000>, + <0>; /* Do Nothing */ + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + arm,no-tick-in-suspend; + }; + + xtal: xtal-clk { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "xtal"; + #clock-cells = <0>; + }; + +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts index 12aa7eaeaf6800bb3374114be1027adb58036e74..c9fa23a565624bca62dbfcf5b1e0faa038cc2ea8 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts @@ -129,6 +129,25 @@ enable-active-high; }; + vddcpu: regulator-vddcpu { + /* + * SY8120B1ABC DC/DC Regulator. + */ + compatible = "pwm-regulator"; + + regulator-name = "VDDCPU"; + regulator-min-microvolt = <721000>; + regulator-max-microvolt = <1022000>; + + vin-supply = <&dc_in>; + + pwms = <&pwm_AO_cd 1 1250 0>; + pwm-dutycycle-range = <100 0>; + + regulator-boot-on; + regulator-always-on; + }; + vddio_ao1v8: regulator-vddio_ao1v8 { compatible = "regulator-fixed"; regulator-name = "VDDIO_AO1V8"; @@ -297,6 +316,34 @@ status = "okay"; }; +&cpu0 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu1 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu2 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu3 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + &cvbs_vdac_port { cvbs_vdac_out: endpoint { remote-endpoint = <&cvbs_connector_in>; @@ -345,6 +392,14 @@ pinctrl-names = "default"; }; +&pwm_AO_cd { + pinctrl-0 = <&pwm_ao_d_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin1"; + status = "okay"; +}; + &pwm_ef { status = "okay"; pinctrl-0 = <&pwm_e_pins>; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts index 8551fbd4a488cfd358c160104177e3a9e613108d..2a324f0136e3fc404dc243d4985e889634b79352 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts @@ -129,6 +129,24 @@ regulator-always-on; }; + vddcpu: regulator-vddcpu { + /* + * MP8756GD Regulator. + */ + compatible = "pwm-regulator"; + + regulator-name = "VDDCPU"; + regulator-min-microvolt = <721000>; + regulator-max-microvolt = <1022000>; + + vin-supply = <&main_12v>; + + pwms = <&pwm_AO_cd 1 1250 0>; + pwm-dutycycle-range = <100 0>; + + regulator-boot-on; + regulator-always-on; + }; }; &cec_AO { @@ -145,6 +163,34 @@ hdmi-phandle = <&hdmi_tx>; }; +&cpu0 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu1 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu2 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu3 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + &cvbs_vdac_port { cvbs_vdac_out: endpoint { remote-endpoint = <&cvbs_connector_in>; @@ -197,6 +243,14 @@ pinctrl-names = "default"; }; +&pwm_AO_cd { + pinctrl-0 = <&pwm_ao_d_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin1"; + status = "okay"; +}; + /* SD card */ &sd_emmc_b { status = "okay"; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts index fe4013cca87643f60d8238133b0ab2353a4b1666..17155fb73fce977bf904e02e321962b2b0f4d11b 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts @@ -11,7 +11,7 @@ #include / { - compatible = "amediatech,x96-max", "amlogic,u200", "amlogic,g12a"; + compatible = "amediatech,x96-max", "amlogic,g12a"; model = "Shenzhen Amediatech Technology Co., Ltd X96 Max"; aliases { @@ -132,6 +132,22 @@ regulator-always-on; }; + vddcpu: regulator-vddcpu { + compatible = "pwm-regulator"; + + regulator-name = "VDDCPU"; + regulator-min-microvolt = <721000>; + regulator-max-microvolt = <1022000>; + + vin-supply = <&dc_in>; + + pwms = <&pwm_AO_cd 1 1250 0>; + pwm-dutycycle-range = <100 0>; + + regulator-boot-on; + regulator-always-on; + }; + sound { compatible = "amlogic,axg-sound-card"; model = "G12A-X96-MAX"; @@ -242,6 +258,34 @@ status = "okay"; }; +&cpu0 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu1 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu2 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu3 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + &cvbs_vdac_port { cvbs_vdac_out: endpoint { remote-endpoint = <&cvbs_connector_in>; @@ -277,6 +321,15 @@ status = "okay"; pinctrl-0 = <&remote_input_ao_pins>; pinctrl-names = "default"; + linux,rc-map-name = "rc-x96max"; +}; + +&pwm_AO_cd { + pinctrl-0 = <&pwm_ao_d_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin1"; + status = "okay"; }; &ext_mdio { diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi index 1785552d450c448066c76d7251745eb54035b9b1..eb5d177d7a999311e21ff1cc8ceb8350908c8611 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi @@ -3,56 +3,12 @@ * Copyright (c) 2018 Amlogic, Inc. All rights reserved. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "meson-g12-common.dtsi" +#include / { compatible = "amlogic,g12a"; - interrupt-parent = <&gic>; - #address-cells = <2>; - #size-cells = <2>; - - tdmif_a: audio-controller-0 { - compatible = "amlogic,axg-tdm-iface"; - #sound-dai-cells = <0>; - sound-name-prefix = "TDM_A"; - clocks = <&clkc_audio AUD_CLKID_MST_A_MCLK>, - <&clkc_audio AUD_CLKID_MST_A_SCLK>, - <&clkc_audio AUD_CLKID_MST_A_LRCLK>; - clock-names = "mclk", "sclk", "lrclk"; - status = "disabled"; - }; - - tdmif_b: audio-controller-1 { - compatible = "amlogic,axg-tdm-iface"; - #sound-dai-cells = <0>; - sound-name-prefix = "TDM_B"; - clocks = <&clkc_audio AUD_CLKID_MST_B_MCLK>, - <&clkc_audio AUD_CLKID_MST_B_SCLK>, - <&clkc_audio AUD_CLKID_MST_B_LRCLK>; - clock-names = "mclk", "sclk", "lrclk"; - status = "disabled"; - }; - - tdmif_c: audio-controller-2 { - compatible = "amlogic,axg-tdm-iface"; - #sound-dai-cells = <0>; - sound-name-prefix = "TDM_C"; - clocks = <&clkc_audio AUD_CLKID_MST_C_MCLK>, - <&clkc_audio AUD_CLKID_MST_C_SCLK>, - <&clkc_audio AUD_CLKID_MST_C_LRCLK>; - clock-names = "mclk", "sclk", "lrclk"; - status = "disabled"; - }; - cpus { #address-cells = <0x2>; #size-cells = <0x0>; @@ -94,2360 +50,75 @@ }; }; - efuse: efuse { - compatible = "amlogic,meson-gxbb-efuse"; - clocks = <&clkc CLKID_EFUSE>; - #address-cells = <1>; - #size-cells = <1>; - read-only; - }; + cpu_opp_table: opp-table { + compatible = "operating-points-v2"; + opp-shared; - psci { - compatible = "arm,psci-1.0"; - method = "smc"; - }; - - reserved-memory { - #address-cells = <2>; - #size-cells = <2>; - ranges; - - /* 3 MiB reserved for ARM Trusted Firmware (BL31) */ - secmon_reserved: secmon@5000000 { - reg = <0x0 0x05000000 0x0 0x300000>; - no-map; + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + opp-microvolt = <731000>; }; - linux,cma { - compatible = "shared-dma-pool"; - reusable; - size = <0x0 0x10000000>; - alignment = <0x0 0x400000>; - linux,cma-default; + opp-250000000 { + opp-hz = /bits/ 64 <250000000>; + opp-microvolt = <731000>; }; - }; - - sm: secure-monitor { - compatible = "amlogic,meson-gxbb-sm"; - }; - - soc { - compatible = "simple-bus"; - #address-cells = <2>; - #size-cells = <2>; - ranges; - ethmac: ethernet@ff3f0000 { - compatible = "amlogic,meson-axg-dwmac", - "snps,dwmac-3.70a", - "snps,dwmac"; - reg = <0x0 0xff3f0000 0x0 0x10000 - 0x0 0xff634540 0x0 0x8>; - interrupts = ; - interrupt-names = "macirq"; - clocks = <&clkc CLKID_ETH>, - <&clkc CLKID_FCLK_DIV2>, - <&clkc CLKID_MPLL2>; - clock-names = "stmmaceth", "clkin0", "clkin1"; - status = "disabled"; - - mdio0: mdio { - #address-cells = <1>; - #size-cells = <0>; - compatible = "snps,dwmac-mdio"; - }; + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <731000>; }; - apb: bus@ff600000 { - compatible = "simple-bus"; - reg = <0x0 0xff600000 0x0 0x200000>; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0xff600000 0x0 0x200000>; - - hdmi_tx: hdmi-tx@0 { - compatible = "amlogic,meson-g12a-dw-hdmi"; - reg = <0x0 0x0 0x0 0x10000>; - interrupts = ; - resets = <&reset RESET_HDMITX_CAPB3>, - <&reset RESET_HDMITX_PHY>, - <&reset RESET_HDMITX>; - reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy"; - clocks = <&clkc CLKID_HDMI>, - <&clkc CLKID_HTX_PCLK>, - <&clkc CLKID_VPU_INTR>; - clock-names = "isfr", "iahb", "venci"; - #address-cells = <1>; - #size-cells = <0>; - #sound-dai-cells = <0>; - status = "disabled"; - - /* VPU VENC Input */ - hdmi_tx_venc_port: port@0 { - reg = <0>; - - hdmi_tx_in: endpoint { - remote-endpoint = <&hdmi_tx_out>; - }; - }; - - /* TMDS Output */ - hdmi_tx_tmds_port: port@1 { - reg = <1>; - }; - }; - - apb_efuse: bus@30000 { - compatible = "simple-bus"; - reg = <0x0 0x30000 0x0 0x2000>; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0x30000 0x0 0x2000>; - - hwrng: rng@218 { - compatible = "amlogic,meson-rng"; - reg = <0x0 0x218 0x0 0x4>; - }; - }; - - periphs: bus@34400 { - compatible = "simple-bus"; - reg = <0x0 0x34400 0x0 0x400>; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0x34400 0x0 0x400>; - - periphs_pinctrl: pinctrl@40 { - compatible = "amlogic,meson-g12a-periphs-pinctrl"; - #address-cells = <2>; - #size-cells = <2>; - ranges; - - gpio: bank@40 { - reg = <0x0 0x40 0x0 0x4c>, - <0x0 0xe8 0x0 0x18>, - <0x0 0x120 0x0 0x18>, - <0x0 0x2c0 0x0 0x40>, - <0x0 0x340 0x0 0x1c>; - reg-names = "gpio", - "pull", - "pull-enable", - "mux", - "ds"; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&periphs_pinctrl 0 0 86>; - }; - - cec_ao_a_h_pins: cec_ao_a_h { - mux { - groups = "cec_ao_a_h"; - function = "cec_ao_a_h"; - bias-disable; - }; - }; - - cec_ao_b_h_pins: cec_ao_b_h { - mux { - groups = "cec_ao_b_h"; - function = "cec_ao_b_h"; - bias-disable; - }; - }; - - emmc_pins: emmc { - mux-0 { - groups = "emmc_nand_d0", - "emmc_nand_d1", - "emmc_nand_d2", - "emmc_nand_d3", - "emmc_nand_d4", - "emmc_nand_d5", - "emmc_nand_d6", - "emmc_nand_d7", - "emmc_cmd"; - function = "emmc"; - bias-pull-up; - drive-strength-microamp = <4000>; - }; - - mux-1 { - groups = "emmc_clk"; - function = "emmc"; - bias-disable; - drive-strength-microamp = <4000>; - }; - }; - - emmc_ds_pins: emmc-ds { - mux { - groups = "emmc_nand_ds"; - function = "emmc"; - bias-pull-down; - drive-strength-microamp = <4000>; - }; - }; - - emmc_clk_gate_pins: emmc_clk_gate { - mux { - groups = "BOOT_8"; - function = "gpio_periphs"; - bias-pull-down; - drive-strength-microamp = <4000>; - }; - }; - - hdmitx_ddc_pins: hdmitx_ddc { - mux { - groups = "hdmitx_sda", - "hdmitx_sck"; - function = "hdmitx"; - bias-disable; - drive-strength-microamp = <4000>; - }; - }; - - hdmitx_hpd_pins: hdmitx_hpd { - mux { - groups = "hdmitx_hpd_in"; - function = "hdmitx"; - bias-disable; - }; - }; - - - i2c0_sda_c_pins: i2c0-sda-c { - mux { - groups = "i2c0_sda_c"; - function = "i2c0"; - bias-disable; - drive-strength-microamp = <3000>; - - }; - }; - - i2c0_sck_c_pins: i2c0-sck-c { - mux { - groups = "i2c0_sck_c"; - function = "i2c0"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c0_sda_z0_pins: i2c0-sda-z0 { - mux { - groups = "i2c0_sda_z0"; - function = "i2c0"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c0_sck_z1_pins: i2c0-sck-z1 { - mux { - groups = "i2c0_sck_z1"; - function = "i2c0"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c0_sda_z7_pins: i2c0-sda-z7 { - mux { - groups = "i2c0_sda_z7"; - function = "i2c0"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c0_sda_z8_pins: i2c0-sda-z8 { - mux { - groups = "i2c0_sda_z8"; - function = "i2c0"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c1_sda_x_pins: i2c1-sda-x { - mux { - groups = "i2c1_sda_x"; - function = "i2c1"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c1_sck_x_pins: i2c1-sck-x { - mux { - groups = "i2c1_sck_x"; - function = "i2c1"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c1_sda_h2_pins: i2c1-sda-h2 { - mux { - groups = "i2c1_sda_h2"; - function = "i2c1"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c1_sck_h3_pins: i2c1-sck-h3 { - mux { - groups = "i2c1_sck_h3"; - function = "i2c1"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c1_sda_h6_pins: i2c1-sda-h6 { - mux { - groups = "i2c1_sda_h6"; - function = "i2c1"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c1_sck_h7_pins: i2c1-sck-h7 { - mux { - groups = "i2c1_sck_h7"; - function = "i2c1"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c2_sda_x_pins: i2c2-sda-x { - mux { - groups = "i2c2_sda_x"; - function = "i2c2"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c2_sck_x_pins: i2c2-sck-x { - mux { - groups = "i2c2_sck_x"; - function = "i2c2"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c2_sda_z_pins: i2c2-sda-z { - mux { - groups = "i2c2_sda_z"; - function = "i2c2"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c2_sck_z_pins: i2c2-sck-z { - mux { - groups = "i2c2_sck_z"; - function = "i2c2"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c3_sda_h_pins: i2c3-sda-h { - mux { - groups = "i2c3_sda_h"; - function = "i2c3"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c3_sck_h_pins: i2c3-sck-h { - mux { - groups = "i2c3_sck_h"; - function = "i2c3"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c3_sda_a_pins: i2c3-sda-a { - mux { - groups = "i2c3_sda_a"; - function = "i2c3"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c3_sck_a_pins: i2c3-sck-a { - mux { - groups = "i2c3_sck_a"; - function = "i2c3"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - mclk0_a_pins: mclk0-a { - mux { - groups = "mclk0_a"; - function = "mclk0"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - mclk1_a_pins: mclk1-a { - mux { - groups = "mclk1_a"; - function = "mclk1"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - mclk1_x_pins: mclk1-x { - mux { - groups = "mclk1_x"; - function = "mclk1"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - mclk1_z_pins: mclk1-z { - mux { - groups = "mclk1_z"; - function = "mclk1"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - pdm_din0_a_pins: pdm-din0-a { - mux { - groups = "pdm_din0_a"; - function = "pdm"; - bias-disable; - }; - }; - - pdm_din0_c_pins: pdm-din0-c { - mux { - groups = "pdm_din0_c"; - function = "pdm"; - bias-disable; - }; - }; - - pdm_din0_x_pins: pdm-din0-x { - mux { - groups = "pdm_din0_x"; - function = "pdm"; - bias-disable; - }; - }; - - pdm_din0_z_pins: pdm-din0-z { - mux { - groups = "pdm_din0_z"; - function = "pdm"; - bias-disable; - }; - }; - - pdm_din1_a_pins: pdm-din1-a { - mux { - groups = "pdm_din1_a"; - function = "pdm"; - bias-disable; - }; - }; - - pdm_din1_c_pins: pdm-din1-c { - mux { - groups = "pdm_din1_c"; - function = "pdm"; - bias-disable; - }; - }; - - pdm_din1_x_pins: pdm-din1-x { - mux { - groups = "pdm_din1_x"; - function = "pdm"; - bias-disable; - }; - }; - - pdm_din1_z_pins: pdm-din1-z { - mux { - groups = "pdm_din1_z"; - function = "pdm"; - bias-disable; - }; - }; - - pdm_din2_a_pins: pdm-din2-a { - mux { - groups = "pdm_din2_a"; - function = "pdm"; - bias-disable; - }; - }; - - pdm_din2_c_pins: pdm-din2-c { - mux { - groups = "pdm_din2_c"; - function = "pdm"; - bias-disable; - }; - }; - - pdm_din2_x_pins: pdm-din2-x { - mux { - groups = "pdm_din2_x"; - function = "pdm"; - bias-disable; - }; - }; - - pdm_din2_z_pins: pdm-din2-z { - mux { - groups = "pdm_din2_z"; - function = "pdm"; - bias-disable; - }; - }; - - pdm_din3_a_pins: pdm-din3-a { - mux { - groups = "pdm_din3_a"; - function = "pdm"; - bias-disable; - }; - }; - - pdm_din3_c_pins: pdm-din3-c { - mux { - groups = "pdm_din3_c"; - function = "pdm"; - bias-disable; - }; - }; - - pdm_din3_x_pins: pdm-din3-x { - mux { - groups = "pdm_din3_x"; - function = "pdm"; - bias-disable; - }; - }; - - pdm_din3_z_pins: pdm-din3-z { - mux { - groups = "pdm_din3_z"; - function = "pdm"; - bias-disable; - }; - }; - - pdm_dclk_a_pins: pdm-dclk-a { - mux { - groups = "pdm_dclk_a"; - function = "pdm"; - bias-disable; - drive-strength-microamp = <500>; - }; - }; - - pdm_dclk_c_pins: pdm-dclk-c { - mux { - groups = "pdm_dclk_c"; - function = "pdm"; - bias-disable; - drive-strength-microamp = <500>; - }; - }; - - pdm_dclk_x_pins: pdm-dclk-x { - mux { - groups = "pdm_dclk_x"; - function = "pdm"; - bias-disable; - drive-strength-microamp = <500>; - }; - }; - - pdm_dclk_z_pins: pdm-dclk-z { - mux { - groups = "pdm_dclk_z"; - function = "pdm"; - bias-disable; - drive-strength-microamp = <500>; - }; - }; - - pwm_a_pins: pwm-a { - mux { - groups = "pwm_a"; - function = "pwm_a"; - bias-disable; - }; - }; - - pwm_b_x7_pins: pwm-b-x7 { - mux { - groups = "pwm_b_x7"; - function = "pwm_b"; - bias-disable; - }; - }; - - pwm_b_x19_pins: pwm-b-x19 { - mux { - groups = "pwm_b_x19"; - function = "pwm_b"; - bias-disable; - }; - }; - - pwm_c_c_pins: pwm-c-c { - mux { - groups = "pwm_c_c"; - function = "pwm_c"; - bias-disable; - }; - }; - - pwm_c_x5_pins: pwm-c-x5 { - mux { - groups = "pwm_c_x5"; - function = "pwm_c"; - bias-disable; - }; - }; - - pwm_c_x8_pins: pwm-c-x8 { - mux { - groups = "pwm_c_x8"; - function = "pwm_c"; - bias-disable; - }; - }; - - pwm_d_x3_pins: pwm-d-x3 { - mux { - groups = "pwm_d_x3"; - function = "pwm_d"; - bias-disable; - }; - }; - - pwm_d_x6_pins: pwm-d-x6 { - mux { - groups = "pwm_d_x6"; - function = "pwm_d"; - bias-disable; - }; - }; - - pwm_e_pins: pwm-e { - mux { - groups = "pwm_e"; - function = "pwm_e"; - bias-disable; - }; - }; - - pwm_f_x_pins: pwm-f-x { - mux { - groups = "pwm_f_x"; - function = "pwm_f"; - bias-disable; - }; - }; - - pwm_f_h_pins: pwm-f-h { - mux { - groups = "pwm_f_h"; - function = "pwm_f"; - bias-disable; - }; - }; - - sdcard_c_pins: sdcard_c { - mux-0 { - groups = "sdcard_d0_c", - "sdcard_d1_c", - "sdcard_d2_c", - "sdcard_d3_c", - "sdcard_cmd_c"; - function = "sdcard"; - bias-pull-up; - drive-strength-microamp = <4000>; - }; - - mux-1 { - groups = "sdcard_clk_c"; - function = "sdcard"; - bias-disable; - drive-strength-microamp = <4000>; - }; - }; - - sdcard_clk_gate_c_pins: sdcard_clk_gate_c { - mux { - groups = "GPIOC_4"; - function = "gpio_periphs"; - bias-pull-down; - drive-strength-microamp = <4000>; - }; - }; - - sdcard_z_pins: sdcard_z { - mux-0 { - groups = "sdcard_d0_z", - "sdcard_d1_z", - "sdcard_d2_z", - "sdcard_d3_z", - "sdcard_cmd_z"; - function = "sdcard"; - bias-pull-up; - drive-strength-microamp = <4000>; - }; - - mux-1 { - groups = "sdcard_clk_z"; - function = "sdcard"; - bias-disable; - drive-strength-microamp = <4000>; - }; - }; - - sdcard_clk_gate_z_pins: sdcard_clk_gate_z { - mux { - groups = "GPIOZ_6"; - function = "gpio_periphs"; - bias-pull-down; - drive-strength-microamp = <4000>; - }; - }; - - sdio_pins: sdio { - mux { - groups = "sdio_d0", - "sdio_d1", - "sdio_d2", - "sdio_d3", - "sdio_clk", - "sdio_cmd"; - function = "sdio"; - bias-disable; - drive-strength-microamp = <4000>; - }; - }; - - sdio_clk_gate_pins: sdio_clk_gate { - mux { - groups = "GPIOX_4"; - function = "gpio_periphs"; - bias-pull-down; - drive-strength-microamp = <4000>; - }; - }; - - spdif_in_a10_pins: spdif-in-a10 { - mux { - groups = "spdif_in_a10"; - function = "spdif_in"; - bias-disable; - }; - }; - - spdif_in_a12_pins: spdif-in-a12 { - mux { - groups = "spdif_in_a12"; - function = "spdif_in"; - bias-disable; - }; - }; - - spdif_in_h_pins: spdif-in-h { - mux { - groups = "spdif_in_h"; - function = "spdif_in"; - bias-disable; - }; - }; - - spdif_out_h_pins: spdif-out-h { - mux { - groups = "spdif_out_h"; - function = "spdif_out"; - drive-strength-microamp = <500>; - bias-disable; - }; - }; - - spdif_out_a11_pins: spdif-out-a11 { - mux { - groups = "spdif_out_a11"; - function = "spdif_out"; - drive-strength-microamp = <500>; - bias-disable; - }; - }; - - spdif_out_a13_pins: spdif-out-a13 { - mux { - groups = "spdif_out_a13"; - function = "spdif_out"; - drive-strength-microamp = <500>; - bias-disable; - }; - }; - - tdm_a_din0_pins: tdm-a-din0 { - mux { - groups = "tdm_a_din0"; - function = "tdm_a"; - bias-disable; - }; - }; - - - tdm_a_din1_pins: tdm-a-din1 { - mux { - groups = "tdm_a_din1"; - function = "tdm_a"; - bias-disable; - }; - }; - - tdm_a_dout0_pins: tdm-a-dout0 { - mux { - groups = "tdm_a_dout0"; - function = "tdm_a"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_a_dout1_pins: tdm-a-dout1 { - mux { - groups = "tdm_a_dout1"; - function = "tdm_a"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_a_fs_pins: tdm-a-fs { - mux { - groups = "tdm_a_fs"; - function = "tdm_a"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_a_sclk_pins: tdm-a-sclk { - mux { - groups = "tdm_a_sclk"; - function = "tdm_a"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_a_slv_fs_pins: tdm-a-slv-fs { - mux { - groups = "tdm_a_slv_fs"; - function = "tdm_a"; - bias-disable; - }; - }; - - - tdm_a_slv_sclk_pins: tdm-a-slv-sclk { - mux { - groups = "tdm_a_slv_sclk"; - function = "tdm_a"; - bias-disable; - }; - }; - - tdm_b_din0_pins: tdm-b-din0 { - mux { - groups = "tdm_b_din0"; - function = "tdm_b"; - bias-disable; - }; - }; - - tdm_b_din1_pins: tdm-b-din1 { - mux { - groups = "tdm_b_din1"; - function = "tdm_b"; - bias-disable; - }; - }; - - tdm_b_din2_pins: tdm-b-din2 { - mux { - groups = "tdm_b_din2"; - function = "tdm_b"; - bias-disable; - }; - }; - - tdm_b_din3_a_pins: tdm-b-din3-a { - mux { - groups = "tdm_b_din3_a"; - function = "tdm_b"; - bias-disable; - }; - }; - - tdm_b_din3_h_pins: tdm-b-din3-h { - mux { - groups = "tdm_b_din3_h"; - function = "tdm_b"; - bias-disable; - }; - }; - - tdm_b_dout0_pins: tdm-b-dout0 { - mux { - groups = "tdm_b_dout0"; - function = "tdm_b"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_b_dout1_pins: tdm-b-dout1 { - mux { - groups = "tdm_b_dout1"; - function = "tdm_b"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_b_dout2_pins: tdm-b-dout2 { - mux { - groups = "tdm_b_dout2"; - function = "tdm_b"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_b_dout3_a_pins: tdm-b-dout3-a { - mux { - groups = "tdm_b_dout3_a"; - function = "tdm_b"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_b_dout3_h_pins: tdm-b-dout3-h { - mux { - groups = "tdm_b_dout3_h"; - function = "tdm_b"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_b_fs_pins: tdm-b-fs { - mux { - groups = "tdm_b_fs"; - function = "tdm_b"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_b_sclk_pins: tdm-b-sclk { - mux { - groups = "tdm_b_sclk"; - function = "tdm_b"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_b_slv_fs_pins: tdm-b-slv-fs { - mux { - groups = "tdm_b_slv_fs"; - function = "tdm_b"; - bias-disable; - }; - }; - - tdm_b_slv_sclk_pins: tdm-b-slv-sclk { - mux { - groups = "tdm_b_slv_sclk"; - function = "tdm_b"; - bias-disable; - }; - }; - - tdm_c_din0_a_pins: tdm-c-din0-a { - mux { - groups = "tdm_c_din0_a"; - function = "tdm_c"; - bias-disable; - }; - }; - - tdm_c_din0_z_pins: tdm-c-din0-z { - mux { - groups = "tdm_c_din0_z"; - function = "tdm_c"; - bias-disable; - }; - }; - - tdm_c_din1_a_pins: tdm-c-din1-a { - mux { - groups = "tdm_c_din1_a"; - function = "tdm_c"; - bias-disable; - }; - }; - - tdm_c_din1_z_pins: tdm-c-din1-z { - mux { - groups = "tdm_c_din1_z"; - function = "tdm_c"; - bias-disable; - }; - }; - - tdm_c_din2_a_pins: tdm-c-din2-a { - mux { - groups = "tdm_c_din2_a"; - function = "tdm_c"; - bias-disable; - }; - }; - - eth_leds_pins: eth-leds { - mux { - groups = "eth_link_led", - "eth_act_led"; - function = "eth"; - bias-disable; - }; - }; - - eth_pins: eth { - mux { - groups = "eth_mdio", - "eth_mdc", - "eth_rgmii_rx_clk", - "eth_rx_dv", - "eth_rxd0", - "eth_rxd1", - "eth_txen", - "eth_txd0", - "eth_txd1"; - function = "eth"; - drive-strength-microamp = <4000>; - bias-disable; - }; - }; - - eth_rgmii_pins: eth-rgmii { - mux { - groups = "eth_rxd2_rgmii", - "eth_rxd3_rgmii", - "eth_rgmii_tx_clk", - "eth_txd2_rgmii", - "eth_txd3_rgmii"; - function = "eth"; - drive-strength-microamp = <4000>; - bias-disable; - }; - }; - - tdm_c_din2_z_pins: tdm-c-din2-z { - mux { - groups = "tdm_c_din2_z"; - function = "tdm_c"; - bias-disable; - }; - }; - - tdm_c_din3_a_pins: tdm-c-din3-a { - mux { - groups = "tdm_c_din3_a"; - function = "tdm_c"; - bias-disable; - }; - }; - - tdm_c_din3_z_pins: tdm-c-din3-z { - mux { - groups = "tdm_c_din3_z"; - function = "tdm_c"; - bias-disable; - }; - }; - - tdm_c_dout0_a_pins: tdm-c-dout0-a { - mux { - groups = "tdm_c_dout0_a"; - function = "tdm_c"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_c_dout0_z_pins: tdm-c-dout0-z { - mux { - groups = "tdm_c_dout0_z"; - function = "tdm_c"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_c_dout1_a_pins: tdm-c-dout1-a { - mux { - groups = "tdm_c_dout1_a"; - function = "tdm_c"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_c_dout1_z_pins: tdm-c-dout1-z { - mux { - groups = "tdm_c_dout1_z"; - function = "tdm_c"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_c_dout2_a_pins: tdm-c-dout2-a { - mux { - groups = "tdm_c_dout2_a"; - function = "tdm_c"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_c_dout2_z_pins: tdm-c-dout2-z { - mux { - groups = "tdm_c_dout2_z"; - function = "tdm_c"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_c_dout3_a_pins: tdm-c-dout3-a { - mux { - groups = "tdm_c_dout3_a"; - function = "tdm_c"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_c_dout3_z_pins: tdm-c-dout3-z { - mux { - groups = "tdm_c_dout3_z"; - function = "tdm_c"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_c_fs_a_pins: tdm-c-fs-a { - mux { - groups = "tdm_c_fs_a"; - function = "tdm_c"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_c_fs_z_pins: tdm-c-fs-z { - mux { - groups = "tdm_c_fs_z"; - function = "tdm_c"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_c_sclk_a_pins: tdm-c-sclk-a { - mux { - groups = "tdm_c_sclk_a"; - function = "tdm_c"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_c_sclk_z_pins: tdm-c-sclk-z { - mux { - groups = "tdm_c_sclk_z"; - function = "tdm_c"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_c_slv_fs_a_pins: tdm-c-slv-fs-a { - mux { - groups = "tdm_c_slv_fs_a"; - function = "tdm_c"; - bias-disable; - }; - }; - - tdm_c_slv_fs_z_pins: tdm-c-slv-fs-z { - mux { - groups = "tdm_c_slv_fs_z"; - function = "tdm_c"; - bias-disable; - }; - }; - - tdm_c_slv_sclk_a_pins: tdm-c-slv-sclk-a { - mux { - groups = "tdm_c_slv_sclk_a"; - function = "tdm_c"; - bias-disable; - }; - }; - - tdm_c_slv_sclk_z_pins: tdm-c-slv-sclk-z { - mux { - groups = "tdm_c_slv_sclk_z"; - function = "tdm_c"; - bias-disable; - }; - }; - - uart_a_pins: uart-a { - mux { - groups = "uart_a_tx", - "uart_a_rx"; - function = "uart_a"; - bias-disable; - }; - }; - - uart_a_cts_rts_pins: uart-a-cts-rts { - mux { - groups = "uart_a_cts", - "uart_a_rts"; - function = "uart_a"; - bias-disable; - }; - }; - - uart_b_pins: uart-b { - mux { - groups = "uart_b_tx", - "uart_b_rx"; - function = "uart_b"; - bias-disable; - }; - }; - - uart_c_pins: uart-c { - mux { - groups = "uart_c_tx", - "uart_c_rx"; - function = "uart_c"; - bias-disable; - }; - }; - - uart_c_cts_rts_pins: uart-c-cts-rts { - mux { - groups = "uart_c_cts", - "uart_c_rts"; - function = "uart_c"; - bias-disable; - }; - }; - }; - }; - - usb2_phy0: phy@36000 { - compatible = "amlogic,g12a-usb2-phy"; - reg = <0x0 0x36000 0x0 0x2000>; - clocks = <&xtal>; - clock-names = "xtal"; - resets = <&reset RESET_USB_PHY20>; - reset-names = "phy"; - #phy-cells = <0>; - }; - - dmc: bus@38000 { - compatible = "simple-bus"; - reg = <0x0 0x38000 0x0 0x400>; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0x38000 0x0 0x400>; - - canvas: video-lut@48 { - compatible = "amlogic,canvas"; - reg = <0x0 0x48 0x0 0x14>; - }; - }; - - usb2_phy1: phy@3a000 { - compatible = "amlogic,g12a-usb2-phy"; - reg = <0x0 0x3a000 0x0 0x2000>; - clocks = <&xtal>; - clock-names = "xtal"; - resets = <&reset RESET_USB_PHY21>; - reset-names = "phy"; - #phy-cells = <0>; - }; - - hiu: bus@3c000 { - compatible = "simple-bus"; - reg = <0x0 0x3c000 0x0 0x1400>; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0x3c000 0x0 0x1400>; - - hhi: system-controller@0 { - compatible = "amlogic,meson-gx-hhi-sysctrl", - "simple-mfd", "syscon"; - reg = <0 0 0 0x400>; - - clkc: clock-controller { - compatible = "amlogic,g12a-clkc"; - #clock-cells = <1>; - clocks = <&xtal>; - clock-names = "xtal"; - }; - }; - }; - - pdm: audio-controller@40000 { - compatible = "amlogic,g12a-pdm", - "amlogic,axg-pdm"; - reg = <0x0 0x40000 0x0 0x34>; - #sound-dai-cells = <0>; - sound-name-prefix = "PDM"; - clocks = <&clkc_audio AUD_CLKID_PDM>, - <&clkc_audio AUD_CLKID_PDM_DCLK>, - <&clkc_audio AUD_CLKID_PDM_SYSCLK>; - clock-names = "pclk", "dclk", "sysclk"; - status = "disabled"; - }; - - audio: bus@42000 { - compatible = "simple-bus"; - reg = <0x0 0x42000 0x0 0x2000>; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0x42000 0x0 0x2000>; - - clkc_audio: clock-controller@0 { - status = "disabled"; - compatible = "amlogic,g12a-audio-clkc"; - reg = <0x0 0x0 0x0 0xb4>; - #clock-cells = <1>; - - clocks = <&clkc CLKID_AUDIO>, - <&clkc CLKID_MPLL0>, - <&clkc CLKID_MPLL1>, - <&clkc CLKID_MPLL2>, - <&clkc CLKID_MPLL3>, - <&clkc CLKID_HIFI_PLL>, - <&clkc CLKID_FCLK_DIV3>, - <&clkc CLKID_FCLK_DIV4>, - <&clkc CLKID_GP0_PLL>; - clock-names = "pclk", - "mst_in0", - "mst_in1", - "mst_in2", - "mst_in3", - "mst_in4", - "mst_in5", - "mst_in6", - "mst_in7"; - - resets = <&reset RESET_AUDIO>; - }; - - toddr_a: audio-controller@100 { - compatible = "amlogic,g12a-toddr", - "amlogic,axg-toddr"; - reg = <0x0 0x100 0x0 0x1c>; - #sound-dai-cells = <0>; - sound-name-prefix = "TODDR_A"; - interrupts = ; - clocks = <&clkc_audio AUD_CLKID_TODDR_A>; - resets = <&arb AXG_ARB_TODDR_A>; - status = "disabled"; - }; - - toddr_b: audio-controller@140 { - compatible = "amlogic,g12a-toddr", - "amlogic,axg-toddr"; - reg = <0x0 0x140 0x0 0x1c>; - #sound-dai-cells = <0>; - sound-name-prefix = "TODDR_B"; - interrupts = ; - clocks = <&clkc_audio AUD_CLKID_TODDR_B>; - resets = <&arb AXG_ARB_TODDR_B>; - status = "disabled"; - }; - - toddr_c: audio-controller@180 { - compatible = "amlogic,g12a-toddr", - "amlogic,axg-toddr"; - reg = <0x0 0x180 0x0 0x1c>; - #sound-dai-cells = <0>; - sound-name-prefix = "TODDR_C"; - interrupts = ; - clocks = <&clkc_audio AUD_CLKID_TODDR_C>; - resets = <&arb AXG_ARB_TODDR_C>; - status = "disabled"; - }; - - frddr_a: audio-controller@1c0 { - compatible = "amlogic,g12a-frddr", - "amlogic,axg-frddr"; - reg = <0x0 0x1c0 0x0 0x1c>; - #sound-dai-cells = <0>; - sound-name-prefix = "FRDDR_A"; - interrupts = ; - clocks = <&clkc_audio AUD_CLKID_FRDDR_A>; - resets = <&arb AXG_ARB_FRDDR_A>; - status = "disabled"; - }; - - frddr_b: audio-controller@200 { - compatible = "amlogic,g12a-frddr", - "amlogic,axg-frddr"; - reg = <0x0 0x200 0x0 0x1c>; - #sound-dai-cells = <0>; - sound-name-prefix = "FRDDR_B"; - interrupts = ; - clocks = <&clkc_audio AUD_CLKID_FRDDR_B>; - resets = <&arb AXG_ARB_FRDDR_B>; - status = "disabled"; - }; - - frddr_c: audio-controller@240 { - compatible = "amlogic,g12a-frddr", - "amlogic,axg-frddr"; - reg = <0x0 0x240 0x0 0x1c>; - #sound-dai-cells = <0>; - sound-name-prefix = "FRDDR_C"; - interrupts = ; - clocks = <&clkc_audio AUD_CLKID_FRDDR_C>; - resets = <&arb AXG_ARB_FRDDR_C>; - status = "disabled"; - }; - - arb: reset-controller@280 { - status = "disabled"; - compatible = "amlogic,meson-axg-audio-arb"; - reg = <0x0 0x280 0x0 0x4>; - #reset-cells = <1>; - clocks = <&clkc_audio AUD_CLKID_DDR_ARB>; - }; - - tdmin_a: audio-controller@300 { - compatible = "amlogic,g12a-tdmin", - "amlogic,axg-tdmin"; - reg = <0x0 0x300 0x0 0x40>; - sound-name-prefix = "TDMIN_A"; - clocks = <&clkc_audio AUD_CLKID_TDMIN_A>, - <&clkc_audio AUD_CLKID_TDMIN_A_SCLK>, - <&clkc_audio AUD_CLKID_TDMIN_A_SCLK_SEL>, - <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>, - <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>; - clock-names = "pclk", "sclk", "sclk_sel", - "lrclk", "lrclk_sel"; - status = "disabled"; - }; - - tdmin_b: audio-controller@340 { - compatible = "amlogic,g12a-tdmin", - "amlogic,axg-tdmin"; - reg = <0x0 0x340 0x0 0x40>; - sound-name-prefix = "TDMIN_B"; - clocks = <&clkc_audio AUD_CLKID_TDMIN_B>, - <&clkc_audio AUD_CLKID_TDMIN_B_SCLK>, - <&clkc_audio AUD_CLKID_TDMIN_B_SCLK_SEL>, - <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>, - <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>; - clock-names = "pclk", "sclk", "sclk_sel", - "lrclk", "lrclk_sel"; - status = "disabled"; - }; - - tdmin_c: audio-controller@380 { - compatible = "amlogic,g12a-tdmin", - "amlogic,axg-tdmin"; - reg = <0x0 0x380 0x0 0x40>; - sound-name-prefix = "TDMIN_C"; - clocks = <&clkc_audio AUD_CLKID_TDMIN_C>, - <&clkc_audio AUD_CLKID_TDMIN_C_SCLK>, - <&clkc_audio AUD_CLKID_TDMIN_C_SCLK_SEL>, - <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>, - <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>; - clock-names = "pclk", "sclk", "sclk_sel", - "lrclk", "lrclk_sel"; - status = "disabled"; - }; - - tdmin_lb: audio-controller@3c0 { - compatible = "amlogic,g12a-tdmin", - "amlogic,axg-tdmin"; - reg = <0x0 0x3c0 0x0 0x40>; - sound-name-prefix = "TDMIN_LB"; - clocks = <&clkc_audio AUD_CLKID_TDMIN_LB>, - <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK>, - <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK_SEL>, - <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>, - <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>; - clock-names = "pclk", "sclk", "sclk_sel", - "lrclk", "lrclk_sel"; - status = "disabled"; - }; - - spdifin: audio-controller@400 { - compatible = "amlogic,g12a-spdifin", - "amlogic,axg-spdifin"; - reg = <0x0 0x400 0x0 0x30>; - #sound-dai-cells = <0>; - sound-name-prefix = "SPDIFIN"; - interrupts = ; - clocks = <&clkc_audio AUD_CLKID_SPDIFIN>, - <&clkc_audio AUD_CLKID_SPDIFIN_CLK>; - clock-names = "pclk", "refclk"; - status = "disabled"; - }; - - spdifout: audio-controller@480 { - compatible = "amlogic,g12a-spdifout", - "amlogic,axg-spdifout"; - reg = <0x0 0x480 0x0 0x50>; - #sound-dai-cells = <0>; - sound-name-prefix = "SPDIFOUT"; - clocks = <&clkc_audio AUD_CLKID_SPDIFOUT>, - <&clkc_audio AUD_CLKID_SPDIFOUT_CLK>; - clock-names = "pclk", "mclk"; - status = "disabled"; - }; - - tdmout_a: audio-controller@500 { - compatible = "amlogic,g12a-tdmout"; - reg = <0x0 0x500 0x0 0x40>; - sound-name-prefix = "TDMOUT_A"; - clocks = <&clkc_audio AUD_CLKID_TDMOUT_A>, - <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK>, - <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK_SEL>, - <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>, - <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>; - clock-names = "pclk", "sclk", "sclk_sel", - "lrclk", "lrclk_sel"; - status = "disabled"; - }; - - tdmout_b: audio-controller@540 { - compatible = "amlogic,g12a-tdmout"; - reg = <0x0 0x540 0x0 0x40>; - sound-name-prefix = "TDMOUT_B"; - clocks = <&clkc_audio AUD_CLKID_TDMOUT_B>, - <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK>, - <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK_SEL>, - <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>, - <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>; - clock-names = "pclk", "sclk", "sclk_sel", - "lrclk", "lrclk_sel"; - status = "disabled"; - }; - - tdmout_c: audio-controller@580 { - compatible = "amlogic,g12a-tdmout"; - reg = <0x0 0x580 0x0 0x40>; - sound-name-prefix = "TDMOUT_C"; - clocks = <&clkc_audio AUD_CLKID_TDMOUT_C>, - <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK>, - <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK_SEL>, - <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>, - <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>; - clock-names = "pclk", "sclk", "sclk_sel", - "lrclk", "lrclk_sel"; - status = "disabled"; - }; - - spdifout_b: audio-controller@680 { - compatible = "amlogic,g12a-spdifout", - "amlogic,axg-spdifout"; - reg = <0x0 0x680 0x0 0x50>; - #sound-dai-cells = <0>; - sound-name-prefix = "SPDIFOUT_B"; - clocks = <&clkc_audio AUD_CLKID_SPDIFOUT_B>, - <&clkc_audio AUD_CLKID_SPDIFOUT_B_CLK>; - clock-names = "pclk", "mclk"; - status = "disabled"; - }; - - tohdmitx: audio-controller@744 { - compatible = "amlogic,g12a-tohdmitx"; - reg = <0x0 0x744 0x0 0x4>; - #sound-dai-cells = <1>; - sound-name-prefix = "TOHDMITX"; - status = "disabled"; - }; - }; - - usb3_pcie_phy: phy@46000 { - compatible = "amlogic,g12a-usb3-pcie-phy"; - reg = <0x0 0x46000 0x0 0x2000>; - clocks = <&clkc CLKID_PCIE_PLL>; - clock-names = "ref_clk"; - resets = <&reset RESET_PCIE_PHY>; - reset-names = "phy"; - assigned-clocks = <&clkc CLKID_PCIE_PLL>; - assigned-clock-rates = <100000000>; - #phy-cells = <1>; - }; - - eth_phy: mdio-multiplexer@4c000 { - compatible = "amlogic,g12a-mdio-mux"; - reg = <0x0 0x4c000 0x0 0xa4>; - clocks = <&clkc CLKID_ETH_PHY>, - <&xtal>, - <&clkc CLKID_MPLL_50M>; - clock-names = "pclk", "clkin0", "clkin1"; - mdio-parent-bus = <&mdio0>; - #address-cells = <1>; - #size-cells = <0>; - - ext_mdio: mdio@0 { - reg = <0>; - #address-cells = <1>; - #size-cells = <0>; - }; - - int_mdio: mdio@1 { - reg = <1>; - #address-cells = <1>; - #size-cells = <0>; - - internal_ephy: ethernet_phy@8 { - compatible = "ethernet-phy-id0180.3301", - "ethernet-phy-ieee802.3-c22"; - interrupts = ; - reg = <8>; - max-speed = <100>; - }; - }; - }; + opp-667000000 { + opp-hz = /bits/ 64 <666666666>; + opp-microvolt = <731000>; }; - aobus: bus@ff800000 { - compatible = "simple-bus"; - reg = <0x0 0xff800000 0x0 0x100000>; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0xff800000 0x0 0x100000>; - - rti: sys-ctrl@0 { - compatible = "amlogic,meson-gx-ao-sysctrl", - "simple-mfd", "syscon"; - reg = <0x0 0x0 0x0 0x100>; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0x0 0x0 0x100>; - - clkc_AO: clock-controller { - compatible = "amlogic,meson-g12a-aoclkc"; - #clock-cells = <1>; - #reset-cells = <1>; - clocks = <&xtal>, <&clkc CLKID_CLK81>; - clock-names = "xtal", "mpeg-clk"; - }; - - pwrc_vpu: power-controller-vpu { - compatible = "amlogic,meson-g12a-pwrc-vpu"; - #power-domain-cells = <0>; - amlogic,hhi-sysctrl = <&hhi>; - resets = <&reset RESET_VIU>, - <&reset RESET_VENC>, - <&reset RESET_VCBUS>, - <&reset RESET_BT656>, - <&reset RESET_RDMA>, - <&reset RESET_VENCI>, - <&reset RESET_VENCP>, - <&reset RESET_VDAC>, - <&reset RESET_VDI6>, - <&reset RESET_VENCL>, - <&reset RESET_VID_LOCK>; - clocks = <&clkc CLKID_VPU>, - <&clkc CLKID_VAPB>; - clock-names = "vpu", "vapb"; - /* - * VPU clocking is provided by two identical clock paths - * VPU_0 and VPU_1 muxed to a single clock by a glitch - * free mux to safely change frequency while running. - * Same for VAPB but with a final gate after the glitch free mux. - */ - assigned-clocks = <&clkc CLKID_VPU_0_SEL>, - <&clkc CLKID_VPU_0>, - <&clkc CLKID_VPU>, /* Glitch free mux */ - <&clkc CLKID_VAPB_0_SEL>, - <&clkc CLKID_VAPB_0>, - <&clkc CLKID_VAPB_SEL>; /* Glitch free mux */ - assigned-clock-parents = <&clkc CLKID_FCLK_DIV3>, - <0>, /* Do Nothing */ - <&clkc CLKID_VPU_0>, - <&clkc CLKID_FCLK_DIV4>, - <0>, /* Do Nothing */ - <&clkc CLKID_VAPB_0>; - assigned-clock-rates = <0>, /* Do Nothing */ - <666666666>, - <0>, /* Do Nothing */ - <0>, /* Do Nothing */ - <250000000>, - <0>; /* Do Nothing */ - }; - - ao_pinctrl: pinctrl@14 { - compatible = "amlogic,meson-g12a-aobus-pinctrl"; - #address-cells = <2>; - #size-cells = <2>; - ranges; - - gpio_ao: bank@14 { - reg = <0x0 0x14 0x0 0x8>, - <0x0 0x1c 0x0 0x8>, - <0x0 0x24 0x0 0x14>; - reg-names = "mux", - "ds", - "gpio"; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&ao_pinctrl 0 0 15>; - }; - - i2c_ao_sck_pins: i2c_ao_sck_pins { - mux { - groups = "i2c_ao_sck"; - function = "i2c_ao"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c_ao_sda_pins: i2c_ao_sda { - mux { - groups = "i2c_ao_sda"; - function = "i2c_ao"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c_ao_sck_e_pins: i2c_ao_sck_e { - mux { - groups = "i2c_ao_sck_e"; - function = "i2c_ao"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - i2c_ao_sda_e_pins: i2c_ao_sda_e { - mux { - groups = "i2c_ao_sda_e"; - function = "i2c_ao"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - mclk0_ao_pins: mclk0-ao { - mux { - groups = "mclk0_ao"; - function = "mclk0_ao"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_ao_b_din0_pins: tdm-ao-b-din0 { - mux { - groups = "tdm_ao_b_din0"; - function = "tdm_ao_b"; - bias-disable; - }; - }; - - spdif_ao_out_pins: spdif-ao-out { - mux { - groups = "spdif_ao_out"; - function = "spdif_ao_out"; - drive-strength-microamp = <500>; - bias-disable; - }; - }; - - tdm_ao_b_din1_pins: tdm-ao-b-din1 { - mux { - groups = "tdm_ao_b_din1"; - function = "tdm_ao_b"; - bias-disable; - }; - }; - - tdm_ao_b_din2_pins: tdm-ao-b-din2 { - mux { - groups = "tdm_ao_b_din2"; - function = "tdm_ao_b"; - bias-disable; - }; - }; - - tdm_ao_b_dout0_pins: tdm-ao-b-dout0 { - mux { - groups = "tdm_ao_b_dout0"; - function = "tdm_ao_b"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_ao_b_dout1_pins: tdm-ao-b-dout1 { - mux { - groups = "tdm_ao_b_dout1"; - function = "tdm_ao_b"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_ao_b_dout2_pins: tdm-ao-b-dout2 { - mux { - groups = "tdm_ao_b_dout2"; - function = "tdm_ao_b"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_ao_b_fs_pins: tdm-ao-b-fs { - mux { - groups = "tdm_ao_b_fs"; - function = "tdm_ao_b"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_ao_b_sclk_pins: tdm-ao-b-sclk { - mux { - groups = "tdm_ao_b_sclk"; - function = "tdm_ao_b"; - bias-disable; - drive-strength-microamp = <3000>; - }; - }; - - tdm_ao_b_slv_fs_pins: tdm-ao-b-slv-fs { - mux { - groups = "tdm_ao_b_slv_fs"; - function = "tdm_ao_b"; - bias-disable; - }; - }; - - tdm_ao_b_slv_sclk_pins: tdm-ao-b-slv-sclk { - mux { - groups = "tdm_ao_b_slv_sclk"; - function = "tdm_ao_b"; - bias-disable; - }; - }; - - uart_ao_a_pins: uart-a-ao { - mux { - groups = "uart_ao_a_tx", - "uart_ao_a_rx"; - function = "uart_ao_a"; - bias-disable; - }; - }; - - uart_ao_a_cts_rts_pins: uart-ao-a-cts-rts { - mux { - groups = "uart_ao_a_cts", - "uart_ao_a_rts"; - function = "uart_ao_a"; - bias-disable; - }; - }; - - pwm_ao_a_pins: pwm-ao-a { - mux { - groups = "pwm_ao_a"; - function = "pwm_ao_a"; - bias-disable; - }; - }; - - pwm_ao_b_pins: pwm-ao-b { - mux { - groups = "pwm_ao_b"; - function = "pwm_ao_b"; - bias-disable; - }; - }; - - pwm_ao_c_4_pins: pwm-ao-c-4 { - mux { - groups = "pwm_ao_c_4"; - function = "pwm_ao_c"; - bias-disable; - }; - }; - - pwm_ao_c_6_pins: pwm-ao-c-6 { - mux { - groups = "pwm_ao_c_6"; - function = "pwm_ao_c"; - bias-disable; - }; - }; - - pwm_ao_d_5_pins: pwm-ao-d-5 { - mux { - groups = "pwm_ao_d_5"; - function = "pwm_ao_d"; - bias-disable; - }; - }; - - pwm_ao_d_10_pins: pwm-ao-d-10 { - mux { - groups = "pwm_ao_d_10"; - function = "pwm_ao_d"; - bias-disable; - }; - }; - - pwm_ao_d_e_pins: pwm-ao-d-e { - mux { - groups = "pwm_ao_d_e"; - function = "pwm_ao_d"; - }; - }; - - remote_input_ao_pins: remote-input-ao { - mux { - groups = "remote_ao_input"; - function = "remote_ao_input"; - bias-disable; - }; - }; - }; - }; - - cec_AO: cec@100 { - compatible = "amlogic,meson-gx-ao-cec"; - reg = <0x0 0x00100 0x0 0x14>; - interrupts = ; - clocks = <&clkc_AO CLKID_AO_CEC>; - clock-names = "core"; - status = "disabled"; - }; - - sec_AO: ao-secure@140 { - compatible = "amlogic,meson-gx-ao-secure", "syscon"; - reg = <0x0 0x140 0x0 0x140>; - amlogic,has-chip-id; - }; - - cecb_AO: cec@280 { - compatible = "amlogic,meson-g12a-ao-cec"; - reg = <0x0 0x00280 0x0 0x1c>; - interrupts = ; - clocks = <&clkc_AO CLKID_AO_CTS_OSCIN>; - clock-names = "oscin"; - status = "disabled"; - }; - - pwm_AO_cd: pwm@2000 { - compatible = "amlogic,meson-g12a-ao-pwm-cd"; - reg = <0x0 0x2000 0x0 0x20>; - #pwm-cells = <3>; - status = "disabled"; - }; - - uart_AO: serial@3000 { - compatible = "amlogic,meson-gx-uart", - "amlogic,meson-ao-uart"; - reg = <0x0 0x3000 0x0 0x18>; - interrupts = ; - clocks = <&xtal>, <&clkc_AO CLKID_AO_UART>, <&xtal>; - clock-names = "xtal", "pclk", "baud"; - status = "disabled"; - }; - - uart_AO_B: serial@4000 { - compatible = "amlogic,meson-gx-uart", - "amlogic,meson-ao-uart"; - reg = <0x0 0x4000 0x0 0x18>; - interrupts = ; - clocks = <&xtal>, <&clkc_AO CLKID_AO_UART2>, <&xtal>; - clock-names = "xtal", "pclk", "baud"; - status = "disabled"; - }; - - i2c_AO: i2c@5000 { - compatible = "amlogic,meson-axg-i2c"; - status = "disabled"; - reg = <0x0 0x05000 0x0 0x20>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&clkc CLKID_I2C>; - }; - - pwm_AO_ab: pwm@7000 { - compatible = "amlogic,meson-g12a-ao-pwm-ab"; - reg = <0x0 0x7000 0x0 0x20>; - #pwm-cells = <3>; - status = "disabled"; - }; - - ir: ir@8000 { - compatible = "amlogic,meson-gxbb-ir"; - reg = <0x0 0x8000 0x0 0x20>; - interrupts = ; - status = "disabled"; - }; - - saradc: adc@9000 { - compatible = "amlogic,meson-g12a-saradc", - "amlogic,meson-saradc"; - reg = <0x0 0x9000 0x0 0x48>; - #io-channel-cells = <1>; - interrupts = ; - clocks = <&xtal>, - <&clkc_AO CLKID_AO_SAR_ADC>, - <&clkc_AO CLKID_AO_SAR_ADC_CLK>, - <&clkc_AO CLKID_AO_SAR_ADC_SEL>; - clock-names = "clkin", "core", "adc_clk", "adc_sel"; - status = "disabled"; - }; + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <731000>; }; - vpu: vpu@ff900000 { - compatible = "amlogic,meson-g12a-vpu"; - reg = <0x0 0xff900000 0x0 0x100000>, - <0x0 0xff63c000 0x0 0x1000>; - reg-names = "vpu", "hhi"; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - amlogic,canvas = <&canvas>; - power-domains = <&pwrc_vpu>; - - /* CVBS VDAC output port */ - cvbs_vdac_port: port@0 { - reg = <0>; - }; - - /* HDMI-TX output port */ - hdmi_tx_port: port@1 { - reg = <1>; - - hdmi_tx_out: endpoint { - remote-endpoint = <&hdmi_tx_in>; - }; - }; + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <731000>; }; - gic: interrupt-controller@ffc01000 { - compatible = "arm,gic-400"; - reg = <0x0 0xffc01000 0 0x1000>, - <0x0 0xffc02000 0 0x2000>, - <0x0 0xffc04000 0 0x2000>, - <0x0 0xffc06000 0 0x2000>; - interrupt-controller; - interrupts = ; - #interrupt-cells = <3>; - #address-cells = <0>; + opp-1398000000 { + opp-hz = /bits/ 64 <1398000000>; + opp-microvolt = <761000>; }; - cbus: bus@ffd00000 { - compatible = "simple-bus"; - reg = <0x0 0xffd00000 0x0 0x100000>; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0xffd00000 0x0 0x100000>; - - reset: reset-controller@1004 { - compatible = "amlogic,meson-g12a-reset", - "amlogic,meson-axg-reset"; - reg = <0x0 0x1004 0x0 0x9c>; - #reset-cells = <1>; - }; - - gpio_intc: interrupt-controller@f080 { - compatible = "amlogic,meson-g12a-gpio-intc", - "amlogic,meson-gpio-intc"; - reg = <0x0 0xf080 0x0 0x10>; - interrupt-controller; - #interrupt-cells = <2>; - amlogic,channel-interrupts = <64 65 66 67 68 69 70 71>; - }; - - pwm_ef: pwm@19000 { - compatible = "amlogic,meson-g12a-ee-pwm"; - reg = <0x0 0x19000 0x0 0x20>; - #pwm-cells = <3>; - status = "disabled"; - }; - - pwm_cd: pwm@1a000 { - compatible = "amlogic,meson-g12a-ee-pwm"; - reg = <0x0 0x1a000 0x0 0x20>; - #pwm-cells = <3>; - status = "disabled"; - }; - - pwm_ab: pwm@1b000 { - compatible = "amlogic,meson-g12a-ee-pwm"; - reg = <0x0 0x1b000 0x0 0x20>; - #pwm-cells = <3>; - status = "disabled"; - }; - - i2c3: i2c@1c000 { - compatible = "amlogic,meson-axg-i2c"; - status = "disabled"; - reg = <0x0 0x1c000 0x0 0x20>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&clkc CLKID_I2C>; - }; - - i2c2: i2c@1d000 { - compatible = "amlogic,meson-axg-i2c"; - status = "disabled"; - reg = <0x0 0x1d000 0x0 0x20>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&clkc CLKID_I2C>; - }; - - i2c1: i2c@1e000 { - compatible = "amlogic,meson-axg-i2c"; - status = "disabled"; - reg = <0x0 0x1e000 0x0 0x20>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&clkc CLKID_I2C>; - }; - - i2c0: i2c@1f000 { - compatible = "amlogic,meson-axg-i2c"; - status = "disabled"; - reg = <0x0 0x1f000 0x0 0x20>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&clkc CLKID_I2C>; - }; - - clk_msr: clock-measure@18000 { - compatible = "amlogic,meson-g12a-clk-measure"; - reg = <0x0 0x18000 0x0 0x10>; - }; - - uart_C: serial@22000 { - compatible = "amlogic,meson-gx-uart"; - reg = <0x0 0x22000 0x0 0x18>; - interrupts = ; - clocks = <&xtal>, <&clkc CLKID_UART2>, <&xtal>; - clock-names = "xtal", "pclk", "baud"; - status = "disabled"; - }; - - uart_B: serial@23000 { - compatible = "amlogic,meson-gx-uart"; - reg = <0x0 0x23000 0x0 0x18>; - interrupts = ; - clocks = <&xtal>, <&clkc CLKID_UART1>, <&xtal>; - clock-names = "xtal", "pclk", "baud"; - status = "disabled"; - }; - - uart_A: serial@24000 { - compatible = "amlogic,meson-gx-uart"; - reg = <0x0 0x24000 0x0 0x18>; - interrupts = ; - clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>; - clock-names = "xtal", "pclk", "baud"; - status = "disabled"; - }; - }; - - sd_emmc_a: sd@ffe03000 { - compatible = "amlogic,meson-axg-mmc"; - reg = <0x0 0xffe03000 0x0 0x800>; - interrupts = ; - status = "disabled"; - clocks = <&clkc CLKID_SD_EMMC_A>, - <&clkc CLKID_SD_EMMC_A_CLK0>, - <&clkc CLKID_FCLK_DIV2>; - clock-names = "core", "clkin0", "clkin1"; - resets = <&reset RESET_SD_EMMC_A>; - amlogic,dram-access-quirk; - }; - - sd_emmc_b: sd@ffe05000 { - compatible = "amlogic,meson-axg-mmc"; - reg = <0x0 0xffe05000 0x0 0x800>; - interrupts = ; - status = "disabled"; - clocks = <&clkc CLKID_SD_EMMC_B>, - <&clkc CLKID_SD_EMMC_B_CLK0>, - <&clkc CLKID_FCLK_DIV2>; - clock-names = "core", "clkin0", "clkin1"; - resets = <&reset RESET_SD_EMMC_B>; + opp-1512000000 { + opp-hz = /bits/ 64 <1512000000>; + opp-microvolt = <791000>; }; - sd_emmc_c: mmc@ffe07000 { - compatible = "amlogic,meson-axg-mmc"; - reg = <0x0 0xffe07000 0x0 0x800>; - interrupts = ; - status = "disabled"; - clocks = <&clkc CLKID_SD_EMMC_C>, - <&clkc CLKID_SD_EMMC_C_CLK0>, - <&clkc CLKID_FCLK_DIV2>; - clock-names = "core", "clkin0", "clkin1"; - resets = <&reset RESET_SD_EMMC_C>; + opp-1608000000 { + opp-hz = /bits/ 64 <1608000000>; + opp-microvolt = <831000>; }; - usb: usb@ffe09000 { - status = "disabled"; - compatible = "amlogic,meson-g12a-usb-ctrl"; - reg = <0x0 0xffe09000 0x0 0xa0>; - interrupts = ; - #address-cells = <2>; - #size-cells = <2>; - ranges; - - clocks = <&clkc CLKID_USB>; - resets = <&reset RESET_USB>; - - dr_mode = "otg"; - - phys = <&usb2_phy0>, <&usb2_phy1>, - <&usb3_pcie_phy PHY_TYPE_USB3>; - phy-names = "usb2-phy0", "usb2-phy1", "usb3-phy0"; - - dwc2: usb@ff400000 { - compatible = "amlogic,meson-g12a-usb", "snps,dwc2"; - reg = <0x0 0xff400000 0x0 0x40000>; - interrupts = ; - clocks = <&clkc CLKID_USB1_DDR_BRIDGE>; - clock-names = "ddr"; - phys = <&usb2_phy1>; - phy-names = "usb2-phy"; - dr_mode = "peripheral"; - g-rx-fifo-size = <192>; - g-np-tx-fifo-size = <128>; - g-tx-fifo-size = <128 128 16 16 16>; - }; - - dwc3: usb@ff500000 { - compatible = "snps,dwc3"; - reg = <0x0 0xff500000 0x0 0x100000>; - interrupts = ; - dr_mode = "host"; - snps,dis_u2_susphy_quirk; - snps,quirk-frame-length-adjustment; - }; + opp-1704000000 { + opp-hz = /bits/ 64 <1704000000>; + opp-microvolt = <861000>; }; - mali: gpu@ffe40000 { - compatible = "amlogic,meson-g12a-mali", "arm,mali-bifrost"; - reg = <0x0 0xffe40000 0x0 0x40000>; - interrupt-parent = <&gic>; - interrupts = , - , - ; - interrupt-names = "gpu", "mmu", "job"; - clocks = <&clkc CLKID_MALI>; - resets = <&reset RESET_DVALIN_CAPB3>, <&reset RESET_DVALIN>; - - /* - * Mali clocking is provided by two identical clock paths - * MALI_0 and MALI_1 muxed to a single clock by a glitch - * free mux to safely change frequency while running. - */ - assigned-clocks = <&clkc CLKID_MALI_0_SEL>, - <&clkc CLKID_MALI_0>, - <&clkc CLKID_MALI>; /* Glitch free mux */ - assigned-clock-parents = <&clkc CLKID_FCLK_DIV2P5>, - <0>, /* Do Nothing */ - <&clkc CLKID_MALI_0>; - assigned-clock-rates = <0>, /* Do Nothing */ - <800000000>, - <0>; /* Do Nothing */ + opp-1800000000 { + opp-hz = /bits/ 64 <1800000000>; + opp-microvolt = <981000>; }; }; +}; - timer { - compatible = "arm,armv8-timer"; - interrupts = , - , - , - ; - }; +ðmac { + power-domains = <&pwrc PWRC_G12A_ETH_ID>; +}; - xtal: xtal-clk { - compatible = "fixed-clock"; - clock-frequency = <24000000>; - clock-output-names = "xtal"; - #clock-cells = <0>; - }; +&vpu { + power-domains = <&pwrc PWRC_G12A_VPU_ID>; +}; +&sd_emmc_a { + amlogic,dram-access-quirk; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-a311d-khadas-vim3.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-a311d-khadas-vim3.dts new file mode 100644 index 0000000000000000000000000000000000000000..3a6a1e0c1e32c5cd4101e25bc979ac6ff091cdbc --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-a311d-khadas-vim3.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS + * Author: Neil Armstrong + * Copyright (c) 2019 Christian Hewitt + */ + +/dts-v1/; + +#include "meson-g12b-a311d.dtsi" +#include "meson-khadas-vim3.dtsi" +#include "meson-g12b-khadas-vim3.dtsi" + +/ { + compatible = "khadas,vim3", "amlogic,a311d", "amlogic,g12b"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-a311d.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-a311d.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d61f43052a344597a131a2d582e8443b2e5e77f5 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-a311d.dtsi @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS + * Author: Neil Armstrong + */ + +#include "meson-g12b.dtsi" + +/ { + cpu_opp_table_0: opp-table-0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + opp-microvolt = <731000>; + }; + + opp-250000000 { + opp-hz = /bits/ 64 <250000000>; + opp-microvolt = <731000>; + }; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <731000>; + }; + + opp-667000000 { + opp-hz = /bits/ 64 <667000000>; + opp-microvolt = <731000>; + }; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <761000>; + }; + + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <781000>; + }; + + opp-1398000000 { + opp-hz = /bits/ 64 <1398000000>; + opp-microvolt = <811000>; + }; + + opp-1512000000 { + opp-hz = /bits/ 64 <1512000000>; + opp-microvolt = <861000>; + }; + + opp-1608000000 { + opp-hz = /bits/ 64 <1608000000>; + opp-microvolt = <901000>; + }; + + opp-1704000000 { + opp-hz = /bits/ 64 <1704000000>; + opp-microvolt = <951000>; + }; + + opp-1800000000 { + opp-hz = /bits/ 64 <1800000000>; + opp-microvolt = <1001000>; + }; + }; + + cpub_opp_table_1: opp-table-1 { + compatible = "operating-points-v2"; + opp-shared; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + opp-microvolt = <731000>; + }; + + opp-250000000 { + opp-hz = /bits/ 64 <250000000>; + opp-microvolt = <731000>; + }; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <731000>; + }; + + opp-667000000 { + opp-hz = /bits/ 64 <667000000>; + opp-microvolt = <731000>; + }; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <731000>; + }; + + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <751000>; + }; + + opp-1398000000 { + opp-hz = /bits/ 64 <1398000000>; + opp-microvolt = <771000>; + }; + + opp-1512000000 { + opp-hz = /bits/ 64 <1512000000>; + opp-microvolt = <771000>; + }; + + opp-1608000000 { + opp-hz = /bits/ 64 <1608000000>; + opp-microvolt = <781000>; + }; + + opp-1704000000 { + opp-hz = /bits/ 64 <1704000000>; + opp-microvolt = <791000>; + }; + + opp-1800000000 { + opp-hz = /bits/ 64 <1800000000>; + opp-microvolt = <831000>; + }; + + opp-1908000000 { + opp-hz = /bits/ 64 <1908000000>; + opp-microvolt = <861000>; + }; + + opp-2016000000 { + opp-hz = /bits/ 64 <2016000000>; + opp-microvolt = <911000>; + }; + + opp-2108000000 { + opp-hz = /bits/ 64 <2108000000>; + opp-microvolt = <951000>; + }; + + opp-2208000000 { + opp-hz = /bits/ 64 <2208000000>; + opp-microvolt = <1011000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..554863429aa6d5d3687283b349b0c571dbe0388c --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS + * Author: Neil Armstrong + * Copyright (c) 2019 Christian Hewitt + */ + +#include + +/ { + vddcpu_a: regulator-vddcpu-a { + /* + * MP8756GD Regulator. + */ + compatible = "pwm-regulator"; + + regulator-name = "VDDCPU_A"; + regulator-min-microvolt = <690000>; + regulator-max-microvolt = <1050000>; + + vin-supply = <&dc_in>; + + pwms = <&pwm_ab 0 1250 0>; + pwm-dutycycle-range = <100 0>; + + regulator-boot-on; + regulator-always-on; + }; + + vddcpu_b: regulator-vddcpu-b { + /* + * Silergy SY8030DEC Regulator. + */ + compatible = "pwm-regulator"; + + regulator-name = "VDDCPU_B"; + regulator-min-microvolt = <690000>; + regulator-max-microvolt = <1050000>; + + vin-supply = <&vsys_3v3>; + + pwms = <&pwm_AO_cd 1 1250 0>; + pwm-dutycycle-range = <100 0>; + + regulator-boot-on; + regulator-always-on; + }; + + sound { + compatible = "amlogic,axg-sound-card"; + model = "G12A-KHADAS-VIM3"; + audio-aux-devs = <&tdmout_b>; + audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1", + "TDMOUT_B IN 1", "FRDDR_B OUT 1", + "TDMOUT_B IN 2", "FRDDR_C OUT 1", + "TDM_B Playback", "TDMOUT_B OUT"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>; + assigned-clock-parents = <0>, <0>, <0>; + assigned-clock-rates = <294912000>, + <270950400>, + <393216000>; + status = "okay"; + + dai-link-0 { + sound-dai = <&frddr_a>; + }; + + dai-link-1 { + sound-dai = <&frddr_b>; + }; + + dai-link-2 { + sound-dai = <&frddr_c>; + }; + + /* 8ch hdmi interface */ + dai-link-3 { + sound-dai = <&tdmif_b>; + dai-format = "i2s"; + dai-tdm-slot-tx-mask-0 = <1 1>; + dai-tdm-slot-tx-mask-1 = <1 1>; + dai-tdm-slot-tx-mask-2 = <1 1>; + dai-tdm-slot-tx-mask-3 = <1 1>; + mclk-fs = <256>; + + codec { + sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>; + }; + }; + + /* hdmi glue */ + dai-link-4 { + sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>; + + codec { + sound-dai = <&hdmi_tx>; + }; + }; + }; +}; + +&arb { + status = "okay"; +}; + +&clkc_audio { + status = "okay"; +}; + +&cpu0 { + cpu-supply = <&vddcpu_b>; + operating-points-v2 = <&cpu_opp_table_0>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu1 { + cpu-supply = <&vddcpu_b>; + operating-points-v2 = <&cpu_opp_table_0>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu100 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu101 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu102 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu103 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&frddr_b { + status = "okay"; +}; + +&frddr_c { + status = "okay"; +}; + +&pwm_ab { + pinctrl-0 = <&pwm_a_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin0"; + status = "okay"; +}; + +&pwm_AO_cd { + pinctrl-0 = <&pwm_ao_d_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin1"; + status = "okay"; +}; + +&tdmif_b { + status = "okay"; +}; + +&tdmout_b { + status = "okay"; +}; + +&tohdmitx { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts index 4e916e1f71f768623a336eebfecf21d75d825d3c..42f15405750cd9f7ed1f01373580c86db0ee3b73 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts @@ -6,7 +6,7 @@ /dts-v1/; -#include "meson-g12b.dtsi" +#include "meson-g12b-s922x.dtsi" #include #include #include @@ -66,8 +66,8 @@ gpios = <&gpio_ao GPIOAO_9 GPIO_ACTIVE_HIGH>; gpios-states = <0>; - states = <3300000 0 - 1800000 1>; + states = <3300000 0>, + <1800000 1>; }; flash_1v8: regulator-flash_1v8 { @@ -115,6 +115,44 @@ /* FIXME: actually controlled by VDDCPU_B_EN */ }; + vddcpu_a: regulator-vddcpu-a { + /* + * MP8756GD Regulator. + */ + compatible = "pwm-regulator"; + + regulator-name = "VDDCPU_A"; + regulator-min-microvolt = <721000>; + regulator-max-microvolt = <1022000>; + + vin-supply = <&main_12v>; + + pwms = <&pwm_ab 0 1250 0>; + pwm-dutycycle-range = <100 0>; + + regulator-boot-on; + regulator-always-on; + }; + + vddcpu_b: regulator-vddcpu-b { + /* + * Silergy SY8120B1ABC Regulator. + */ + compatible = "pwm-regulator"; + + regulator-name = "VDDCPU_B"; + regulator-min-microvolt = <721000>; + regulator-max-microvolt = <1022000>; + + vin-supply = <&main_12v>; + + pwms = <&pwm_AO_cd 1 1250 0>; + pwm-dutycycle-range = <100 0>; + + regulator-boot-on; + regulator-always-on; + }; + hub_5v: regulator-hub_5v { compatible = "regulator-fixed"; regulator-name = "HUB_5V"; @@ -246,6 +284,48 @@ status = "okay"; }; +&cpu0 { + cpu-supply = <&vddcpu_b>; + operating-points-v2 = <&cpu_opp_table_0>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu1 { + cpu-supply = <&vddcpu_b>; + operating-points-v2 = <&cpu_opp_table_0>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu100 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu101 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu102 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu103 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + &ext_mdio { external_phy: ethernet-phy@0 { /* Realtek RTL8211F (0x001cc916) */ @@ -315,6 +395,23 @@ status = "okay"; pinctrl-0 = <&remote_input_ao_pins>; pinctrl-names = "default"; + linux,rc-map-name = "rc-odroid"; +}; + +&pwm_ab { + pinctrl-0 = <&pwm_a_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin0"; + status = "okay"; +}; + +&pwm_AO_cd { + pinctrl-0 = <&pwm_ao_d_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin1"; + status = "okay"; }; /* SD card */ diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-s922x-khadas-vim3.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-s922x-khadas-vim3.dts new file mode 100644 index 0000000000000000000000000000000000000000..b73deb28212059b414473ee021d89834fdedeabc --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-s922x-khadas-vim3.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS + * Author: Neil Armstrong + * Copyright (c) 2019 Christian Hewitt + */ + +/dts-v1/; + +#include "meson-g12b-s922x.dtsi" +#include "meson-khadas-vim3.dtsi" +#include "meson-g12b-khadas-vim3.dtsi" + +/ { + compatible = "khadas,vim3", "amlogic,s922x", "amlogic,g12b"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-s922x.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-s922x.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..046cc332d07f95ada816f47955be6adce4255d8d --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-s922x.dtsi @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS + * Author: Neil Armstrong + */ + +#include "meson-g12b.dtsi" + +/ { + cpu_opp_table_0: opp-table-0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + opp-microvolt = <731000>; + }; + + opp-250000000 { + opp-hz = /bits/ 64 <250000000>; + opp-microvolt = <731000>; + }; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <731000>; + }; + + opp-667000000 { + opp-hz = /bits/ 64 <667000000>; + opp-microvolt = <731000>; + }; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <731000>; + }; + + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <731000>; + }; + + opp-1398000000 { + opp-hz = /bits/ 64 <1398000000>; + opp-microvolt = <761000>; + }; + + opp-1512000000 { + opp-hz = /bits/ 64 <1512000000>; + opp-microvolt = <791000>; + }; + + opp-1608000000 { + opp-hz = /bits/ 64 <1608000000>; + opp-microvolt = <831000>; + }; + + opp-1704000000 { + opp-hz = /bits/ 64 <1704000000>; + opp-microvolt = <861000>; + }; + + opp-1896000000 { + opp-hz = /bits/ 64 <1896000000>; + opp-microvolt = <981000>; + }; + }; + + cpub_opp_table_1: opp-table-1 { + compatible = "operating-points-v2"; + opp-shared; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + opp-microvolt = <751000>; + }; + + opp-250000000 { + opp-hz = /bits/ 64 <250000000>; + opp-microvolt = <751000>; + }; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <751000>; + }; + + opp-667000000 { + opp-hz = /bits/ 64 <667000000>; + opp-microvolt = <751000>; + }; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <771000>; + }; + + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <771000>; + }; + + opp-1398000000 { + opp-hz = /bits/ 64 <1398000000>; + opp-microvolt = <791000>; + }; + + opp-1512000000 { + opp-hz = /bits/ 64 <1512000000>; + opp-microvolt = <821000>; + }; + + opp-1608000000 { + opp-hz = /bits/ 64 <1608000000>; + opp-microvolt = <861000>; + }; + + opp-1704000000 { + opp-hz = /bits/ 64 <1704000000>; + opp-microvolt = <891000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi index 9e88e513b22d2aadb25489bc5dcbf45e83941eac..5628ccd54531ac28e11d5eb3683344c6cef25991 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi @@ -4,12 +4,16 @@ * Author: Neil Armstrong */ -#include "meson-g12a.dtsi" +#include "meson-g12-common.dtsi" +#include / { compatible = "amlogic,g12b"; cpus { + #address-cells = <0x2>; + #size-cells = <0x0>; + cpu-map { cluster0 { core0 { @@ -40,8 +44,21 @@ }; }; - /delete-node/ cpu@2; - /delete-node/ cpu@3; + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x0 0x0>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x0 0x1>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; cpu100: cpu@100 { device_type = "cpu"; @@ -74,9 +91,25 @@ enable-method = "psci"; next-level-cache = <&l2>; }; + + l2: l2-cache0 { + compatible = "cache"; + }; }; }; &clkc { compatible = "amlogic,g12b-clkc"; }; + +ðmac { + power-domains = <&pwrc PWRC_G12A_ETH_ID>; +}; + +&vpu { + power-domains = <&pwrc PWRC_G12A_VPU_ID>; +}; + +&sd_emmc_a { + amlogic,dram-access-quirk; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi index 74d03fc706be1525d21dd7d07fec217ef289b9c0..6733050d735fe12daede2be8fd2fb6b3fa0e69af 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi @@ -220,7 +220,7 @@ }; reset: reset-controller@4404 { - compatible = "amlogic,meson-gx-reset", "amlogic,meson-gxbb-reset"; + compatible = "amlogic,meson-gxbb-reset"; reg = <0x0 0x04404 0x0 0x9c>; #reset-cells = <1>; }; @@ -317,7 +317,7 @@ }; spifc: spi@8c80 { - compatible = "amlogic,meson-gx-spifc", "amlogic,meson-gxbb-spifc"; + compatible = "amlogic,meson-gxbb-spifc"; reg = <0x0 0x08c80 0x0 0x80>; #address-cells = <1>; #size-cells = <0>; @@ -325,7 +325,7 @@ }; watchdog@98d0 { - compatible = "amlogic,meson-gx-wdt", "amlogic,meson-gxbb-wdt"; + compatible = "amlogic,meson-gxbb-wdt"; reg = <0x0 0x098d0 0x0 0x10>; clocks = <&xtal>; }; @@ -437,7 +437,21 @@ }; }; - periphs: periphs@c8834000 { + vdec: video-codec@c8820000 { + compatible = "amlogic,gx-vdec"; + reg = <0x0 0xc8820000 0x0 0x10000>, + <0x0 0xc110a580 0x0 0xe4>; + reg-names = "dos", "esparser"; + + interrupts = , + ; + interrupt-names = "vdec", "esparser"; + + amlogic,ao-sysctrl = <&sysctrl_AO>; + amlogic,canvas = <&canvas>; + }; + + periphs: bus@c8834000 { compatible = "simple-bus"; reg = <0x0 0xc8834000 0x0 0x2000>; #address-cells = <2>; @@ -476,7 +490,7 @@ }; mailbox: mailbox@404 { - compatible = "amlogic,meson-gx-mhu", "amlogic,meson-gxbb-mhu"; + compatible = "amlogic,meson-gxbb-mhu"; reg = <0 0x404 0 0x4c>; interrupts = , , @@ -489,10 +503,12 @@ compatible = "amlogic,meson-gxbb-dwmac", "snps,dwmac-3.70a", "snps,dwmac"; - reg = <0x0 0xc9410000 0x0 0x10000 - 0x0 0xc8834540 0x0 0x4>; + reg = <0x0 0xc9410000 0x0 0x10000>, + <0x0 0xc8834540 0x0 0x4>; interrupts = ; interrupt-names = "macirq"; + rx-fifo-depth = <4096>; + tx-fifo-depth = <2048>; status = "disabled"; }; @@ -528,9 +544,8 @@ vpu: vpu@d0100000 { compatible = "amlogic,meson-gx-vpu"; reg = <0x0 0xd0100000 0x0 0x100000>, - <0x0 0xc883c000 0x0 0x1000>, - <0x0 0xc8838000 0x0 0x1000>; - reg-names = "vpu", "hhi", "dmc"; + <0x0 0xc883c000 0x0 0x1000>; + reg-names = "vpu", "hhi"; interrupts = ; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts index c34c1c90ccb6b91a387007f4b70e219ddb1ad59f..233eb1cd7967153fa467e7600fd746301c8525a9 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts @@ -10,6 +10,7 @@ / { compatible = "friendlyarm,nanopi-k2", "amlogic,meson-gxbb"; + model = "FriendlyARM NanoPi K2"; aliases { serial0 = &uart_AO; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts index b636912a271578f89a8836bb796f6d07b432737a..afcf8a9f667b9757e6d79b7fc4fafbea70fad424 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts @@ -75,8 +75,8 @@ gpios-states = <1>; /* Based on P200 schematics, signal CARD_1.8V/3.3V_CTR */ - states = <1800000 0 - 3300000 1>; + states = <1800000 0>, + <3300000 1>; }; vddio_boot: regulator-vddio_boot { diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts index 9972b1515da617993c7a872db083bd37ba10b32b..6039adda12eecf091f4809fcd1f7df3f2c7d9a05 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts @@ -77,8 +77,8 @@ gpios = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_HIGH>; gpios-states = <0>; - states = <3300000 0 - 1800000 1>; + states = <3300000 0>, + <1800000 1>; }; vcc1v8: regulator-vcc1v8 { diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p201.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-p201.dts index 56e0dd1ff55c684f93937fec5a78cea46f98cc59..150a82f3b2d77cdab89f376e440e4470d80588a9 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p201.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p201.dts @@ -21,6 +21,6 @@ phy-mode = "rmii"; snps,reset-gpio = <&gpio GPIOZ_14 0>; - snps,reset-delays-us = <0 10000 1000000>; + snps,reset-delays-us = <0>, <10000>, <1000000>; snps,reset-active-low; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi index e8f925871edfc5a98dfe2e6852b952eba0757bb5..89f7b41b0e9efe5b220590b566b475589b42dcda 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi @@ -46,8 +46,8 @@ gpios-states = <1>; /* Based on P200 schematics, signal CARD_1.8V/3.3V_CTR */ - states = <1800000 0 - 3300000 1>; + states = <1800000 0>, + <3300000 1>; regulator-settling-time-up-us = <10000>; regulator-settling-time-down-us = <150000>; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts index 2bfe69902552e4cede17384ea16949f04750d819..83b985bb015ebac706516552152c486291eb0b37 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts @@ -12,3 +12,7 @@ compatible = "wetek,hub", "amlogic,meson-gxbb"; model = "WeTek Hub"; }; + +&ir { + linux,rc-map-name = "rc-wetek-hub"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts index 0038522315de7164b0e92eb5fc211773060541a2..1d32d1f6d03274181d737be2227703b3953b6381 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts @@ -54,3 +54,7 @@ &usb1 { status = "okay"; }; + +&ir { + linux,rc-map-name = "rc-wetek-play2"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi index f734faaf7b78afd783769c44c965926f76feef8e..0cb40326b0d3fc9251c5ba0c14914dacf277fbf5 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi @@ -845,3 +845,14 @@ compatible = "amlogic,meson-gxbb-vpu", "amlogic,meson-gx-vpu"; power-domains = <&pwrc_vpu>; }; + +&vdec { + compatible = "amlogic,gxbb-vdec", "amlogic,gx-vdec"; + clocks = <&clkc CLKID_DOS_PARSER>, + <&clkc CLKID_DOS>, + <&clkc CLKID_VDEC_1>, + <&clkc CLKID_VDEC_HEVC>; + clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc"; + resets = <&reset RESET_PARSER>; + reset-names = "esparser"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905w-tx3-mini.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905w-tx3-mini.dts index 789c819c99c4f5ad0c00272cd6b6170229ec3ab8..dd729ac2300dac36404a7e31ed2f3b3b406ca85e 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905w-tx3-mini.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905w-tx3-mini.dts @@ -20,3 +20,7 @@ reg = <0x0 0x0 0x0 0x40000000>; /* 1 GiB or 2 GiB */ }; }; + +&ir { + linux,rc-map-name = "rc-tanix-tx3mini"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-hwacom-amazetv.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-hwacom-amazetv.dts index 796baea7a0bfb7f89b083d19bf034214cb7e7ca2..c8d74e61dec182a5b4cfa54d87dc936cd72ce70f 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-hwacom-amazetv.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-hwacom-amazetv.dts @@ -38,8 +38,8 @@ gpios-states = <1>; /* Based on P200 schematics, signal CARD_1.8V/3.3V_CTR */ - states = <1800000 0 - 3300000 1>; + states = <1800000 0>, + <3300000 1>; }; vddio_boot: regulator-vddio_boot { diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts index 5499e8de5c74c04125ee90a81dd4fdc1ea6673ae..2a5cd303123de4e4ba82b18a12ef81ec20aa1237 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts @@ -110,7 +110,7 @@ }; &ir { - linux,rc-map-name = "rc-geekbox"; + linux,rc-map-name = "rc-khadas"; }; &gpio_ao { diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts index 26907ac829301ef69f182b94ef41f36654a2b997..c433a031841f6230cac8dea5e02f25c00e69a609 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts @@ -38,8 +38,8 @@ gpios-states = <1>; /* Based on P200 schematics, signal CARD_1.8V/3.3V_CTR */ - states = <1800000 0 - 3300000 1>; + states = <1800000 0>, + <3300000 1>; }; vddio_boot: regulator-vddio_boot { diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi index c959456bacc667ca6f7c27741aaf894806c744a0..49ff0a7d0210f35bbc7c230f3085793b5bb79a22 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi @@ -80,9 +80,6 @@ }; ðmac { - reg = <0x0 0xc9410000 0x0 0x10000 - 0x0 0xc8834540 0x0 0x4>; - clocks = <&clkc CLKID_ETH>, <&clkc CLKID_FCLK_DIV2>, <&clkc CLKID_MPLL2>; @@ -712,7 +709,7 @@ #size-cells = <0>; internal_phy: ethernet-phy@8 { - compatible = "ethernet-phy-id0181.4400", "ethernet-phy-ieee802.3-c22"; + compatible = "ethernet-phy-id0181.4400"; interrupts = ; reg = <8>; max-speed = <100>; @@ -848,3 +845,14 @@ compatible = "amlogic,meson-gxl-vpu", "amlogic,meson-gx-vpu"; power-domains = <&pwrc_vpu>; }; + +&vdec { + compatible = "amlogic,gxl-vdec", "amlogic,gx-vdec"; + clocks = <&clkc CLKID_DOS_PARSER>, + <&clkc CLKID_DOS>, + <&clkc CLKID_VDEC_1>, + <&clkc CLKID_VDEC_HEVC>; + clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc"; + resets = <&reset RESET_PARSER>; + reset-names = "esparser"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts index 989d33ac6eae80d69976ae15b4287784487b932d..f25ddd18a607e033c93d79b0f9d9808f33e60c20 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts @@ -299,7 +299,7 @@ status = "okay"; pinctrl-0 = <&remote_input_ao_pins>; pinctrl-names = "default"; - linux,rc-map-name = "rc-geekbox"; + linux,rc-map-name = "rc-khadas"; }; &pwm_AO_ab { diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi index 7a85a82bf65d874ed42510824824d9d331e73272..a0e677d5a8f72c7d21f6021219990bf19b9452d0 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi @@ -144,3 +144,7 @@ &dwc3 { phys = <&usb3_phy>, <&usb2_phy0>, <&usb2_phy1>, <&usb2_phy2>; }; + +&vdec { + compatible = "amlogic,gxm-vdec", "amlogic,gx-vdec"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi b/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8647da7d6609b05089bcced0dd21d9a19b3a41d2 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi @@ -0,0 +1,360 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS + * Author: Neil Armstrong + * Copyright (c) 2019 Christian Hewitt + */ + +#include +#include + +/ { + model = "Khadas VIM3"; + + aliases { + serial0 = &uart_AO; + ethernet0 = ðmac; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x80000000>; + }; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 2>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1710000>; + + button-function { + label = "Function"; + linux,code = ; + press-threshold-microvolt = <10000>; + }; + }; + + leds { + compatible = "gpio-leds"; + + white { + label = "vim3:white:sys"; + gpios = <&gpio_ao GPIOAO_4 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + + red { + label = "vim3:red"; + gpios = <&gpio_expander 5 GPIO_ACTIVE_LOW>; + }; + }; + + emmc_pwrseq: emmc-pwrseq { + compatible = "mmc-pwrseq-emmc"; + reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + poll-interval = <100>; + + power-button { + label = "power"; + linux,code = ; + gpios = <&gpio_ao GPIOAO_7 GPIO_ACTIVE_LOW>; + }; + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; + clocks = <&wifi32k>; + clock-names = "ext_clock"; + }; + + dc_in: regulator-dc_in { + compatible = "regulator-fixed"; + regulator-name = "DC_IN"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + vcc_5v: regulator-vcc_5v { + compatible = "regulator-fixed"; + regulator-name = "VCC_5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&dc_in>; + + gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; + enable-active-high; + }; + + vcc_1v8: regulator-vcc_1v8 { + compatible = "regulator-fixed"; + regulator-name = "VCC_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vcc_3v3>; + regulator-always-on; + }; + + vcc_3v3: regulator-vcc_3v3 { + compatible = "regulator-fixed"; + regulator-name = "VCC_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vsys_3v3>; + regulator-always-on; + /* FIXME: actually controlled by VDDCPU_B_EN */ + }; + + vddao_1v8: regulator-vddao_1v8 { + compatible = "regulator-fixed"; + regulator-name = "VDDIO_AO1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vsys_3v3>; + regulator-always-on; + }; + + emmc_1v8: regulator-emmc_1v8 { + compatible = "regulator-fixed"; + regulator-name = "EMMC_AO1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vcc_3v3>; + regulator-always-on; + }; + + vsys_3v3: regulator-vsys_3v3 { + compatible = "regulator-fixed"; + regulator-name = "VSYS_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&dc_in>; + regulator-always-on; + }; + + usb_pwr: regulator-usb_pwr { + compatible = "regulator-fixed"; + regulator-name = "USB_PWR"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc_5v>; + + gpio = <&gpio GPIOA_6 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_tmds_out>; + }; + }; + }; + + wifi32k: wifi32k { + compatible = "pwm-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ + }; +}; + +&cec_AO { + pinctrl-0 = <&cec_ao_a_h_pins>; + pinctrl-names = "default"; + status = "disabled"; + hdmi-phandle = <&hdmi_tx>; +}; + +&cecb_AO { + pinctrl-0 = <&cec_ao_b_h_pins>; + pinctrl-names = "default"; + status = "okay"; + hdmi-phandle = <&hdmi_tx>; +}; + +&ext_mdio { + external_phy: ethernet-phy@0 { + /* Realtek RTL8211F (0x001cc916) */ + reg = <0>; + max-speed = <1000>; + + interrupt-parent = <&gpio_intc>; + /* MAC_INTR on GPIOZ_14 */ + interrupts = <26 IRQ_TYPE_LEVEL_LOW>; + }; +}; + +ðmac { + pinctrl-0 = <ð_pins>, <ð_rgmii_pins>; + pinctrl-names = "default"; + status = "okay"; + phy-mode = "rgmii"; + phy-handle = <&external_phy>; + amlogic,tx-delay-ns = <2>; +}; + +&hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; + pinctrl-names = "default"; + hdmi-supply = <&vcc_5v>; +}; + +&hdmi_tx_tmds_port { + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; +}; + +&i2c_AO { + status = "okay"; + pinctrl-0 = <&i2c_ao_sck_pins>, <&i2c_ao_sda_pins>; + pinctrl-names = "default"; + + gpio_expander: gpio-controller@20 { + compatible = "ti,tca6408"; + reg = <0x20>; + vcc-supply = <&vcc_3v3>; + gpio-controller; + #gpio-cells = <2>; + }; + + rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + #clock-cells = <0>; + }; +}; + +&ir { + status = "okay"; + pinctrl-0 = <&remote_input_ao_pins>; + pinctrl-names = "default"; + linux,rc-map-name = "rc-khadas"; +}; + +&pwm_ef { + status = "okay"; + pinctrl-0 = <&pwm_e_pins>; + pinctrl-names = "default"; +}; + +&saradc { + status = "okay"; + vref-supply = <&vddao_1v8>; +}; + +/* SDIO */ +&sd_emmc_a { + status = "okay"; + pinctrl-0 = <&sdio_pins>; + pinctrl-1 = <&sdio_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; + #address-cells = <1>; + #size-cells = <0>; + + bus-width = <4>; + cap-sd-highspeed; + sd-uhs-sdr50; + max-frequency = <100000000>; + + non-removable; + disable-wp; + + mmc-pwrseq = <&sdio_pwrseq>; + + vmmc-supply = <&vsys_3v3>; + vqmmc-supply = <&vddao_1v8>; + + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; +}; + +/* SD card */ +&sd_emmc_b { + status = "okay"; + pinctrl-0 = <&sdcard_c_pins>; + pinctrl-1 = <&sdcard_clk_gate_c_pins>; + pinctrl-names = "default", "clk-gate"; + + bus-width = <4>; + cap-sd-highspeed; + max-frequency = <50000000>; + disable-wp; + + cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>; + vmmc-supply = <&vsys_3v3>; + vqmmc-supply = <&vsys_3v3>; +}; + +/* eMMC */ +&sd_emmc_c { + status = "okay"; + pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; + pinctrl-1 = <&emmc_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; + + bus-width = <8>; + cap-mmc-highspeed; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + max-frequency = <200000000>; + disable-wp; + + mmc-pwrseq = <&emmc_pwrseq>; + vmmc-supply = <&vcc_3v3>; + vqmmc-supply = <&emmc_1v8>; +}; + +&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"; + }; +}; + +&uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; + pinctrl-names = "default"; +}; + +&usb2_phy0 { + phy-supply = <&dc_in>; +}; + +&usb2_phy1 { + phy-supply = <&usb_pwr>; +}; + +&usb3_pcie_phy { + phy-supply = <&usb_pwr>; +}; + +&usb { + status = "okay"; + dr_mode = "peripheral"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-khadas-vim3l.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-khadas-vim3l.dts new file mode 100644 index 0000000000000000000000000000000000000000..5233bd7cacfb2394fba21ee168d12657f2cddb46 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-sm1-khadas-vim3l.dts @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS + * Author: Neil Armstrong + */ + +/dts-v1/; + +#include "meson-sm1.dtsi" +#include "meson-khadas-vim3.dtsi" + +/ { + compatible = "khadas,vim3l", "amlogic,sm1"; + model = "Khadas VIM3L"; + + vddcpu: regulator-vddcpu { + /* + * Silergy SY8030DEC Regulator. + */ + compatible = "pwm-regulator"; + + regulator-name = "VDDCPU"; + regulator-min-microvolt = <690000>; + regulator-max-microvolt = <1050000>; + + vin-supply = <&vsys_3v3>; + + pwms = <&pwm_AO_cd 1 1250 0>; + pwm-dutycycle-range = <100 0>; + + regulator-boot-on; + regulator-always-on; + }; +}; + +&cpu0 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu1 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU1_CLK>; + clock-latency = <50000>; +}; + +&cpu2 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU2_CLK>; + clock-latency = <50000>; +}; + +&cpu3 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU3_CLK>; + clock-latency = <50000>; +}; + +&pwm_AO_cd { + pinctrl-0 = <&pwm_ao_d_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin1"; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts new file mode 100644 index 0000000000000000000000000000000000000000..3435aaa4e8db50c7f28c0b08f2b802faf8e6f20f --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts @@ -0,0 +1,383 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre SAS. All rights reserved. + */ + +/dts-v1/; + +#include "meson-sm1.dtsi" +#include +#include +#include + +/ { + compatible = "seirobotics,sei610", "amlogic,sm1"; + model = "SEI Robotics SEI610"; + + aliases { + serial0 = &uart_AO; + ethernet0 = ðmac; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + emmc_pwrseq: emmc-pwrseq { + compatible = "mmc-pwrseq-emmc"; + reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; + }; + + gpio-keys { + compatible = "gpio-keys-polled"; + poll-interval = <100>; + + key1 { + label = "A"; + linux,code = ; + gpios = <&gpio GPIOH_6 GPIO_ACTIVE_LOW>; + }; + + key2 { + label = "B"; + linux,code = ; + gpios = <&gpio GPIOH_7 GPIO_ACTIVE_LOW>; + }; + + key3 { + label = "C"; + linux,code = ; + gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>; + }; + }; + + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_tmds_out>; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + + bluetooth { + label = "sei610:blue:bt"; + gpios = <&gpio GPIOC_7 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>; + default-state = "off"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + + power { + label = "sei610:red:power"; + pwms = <&pwm_AO_ab 0 30518 0>; + max-brightness = <255>; + linux,default-trigger = "default-on"; + active-low; + }; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x40000000>; + }; + + ao_5v: regulator-ao_5v { + compatible = "regulator-fixed"; + regulator-name = "AO_5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&dc_in>; + regulator-always-on; + }; + + dc_in: regulator-dc_in { + compatible = "regulator-fixed"; + regulator-name = "DC_IN"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + emmc_1v8: regulator-emmc_1v8 { + compatible = "regulator-fixed"; + regulator-name = "EMMC_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vddao_3v3>; + regulator-always-on; + }; + + vddao_3v3: regulator-vddao_3v3 { + compatible = "regulator-fixed"; + regulator-name = "VDDAO_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&dc_in>; + regulator-always-on; + }; + + /* Used by Tuner, RGB Led & IR Emitter LED array */ + vddao_3v3_t: regulator-vddao_3v3_t { + compatible = "regulator-fixed"; + regulator-name = "VDDAO_3V3_T"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vddao_3v3>; + gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; + enable-active-low; + regulator-always-on; + }; + + vddcpu: regulator-vddcpu { + /* + * SY8120B1ABC DC/DC Regulator. + */ + compatible = "pwm-regulator"; + + regulator-name = "VDDCPU"; + regulator-min-microvolt = <690000>; + regulator-max-microvolt = <1050000>; + + vin-supply = <&dc_in>; + + pwms = <&pwm_AO_cd 1 1500 0>; + pwm-dutycycle-range = <100 0>; + + regulator-boot-on; + regulator-always-on; + }; + + vddio_ao1v8: regulator-vddio_ao1v8 { + compatible = "regulator-fixed"; + regulator-name = "VDDIO_AO1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vddao_3v3>; + regulator-always-on; + }; + + reserved-memory { + /* TEE Reserved Memory */ + bl32_reserved: bl32@5000000 { + reg = <0x0 0x05300000 0x0 0x2000000>; + no-map; + }; + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; + clocks = <&wifi32k>; + clock-names = "ext_clock"; + }; + + wifi32k: wifi32k { + compatible = "pwm-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ + }; +}; + +&cec_AO { + pinctrl-0 = <&cec_ao_a_h_pins>; + pinctrl-names = "default"; + status = "disabled"; + hdmi-phandle = <&hdmi_tx>; +}; + +&cecb_AO { + pinctrl-0 = <&cec_ao_b_h_pins>; + pinctrl-names = "default"; + status = "okay"; + hdmi-phandle = <&hdmi_tx>; +}; + +&cpu0 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu1 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU1_CLK>; + clock-latency = <50000>; +}; + +&cpu2 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU2_CLK>; + clock-latency = <50000>; +}; + +&cpu3 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU3_CLK>; + clock-latency = <50000>; +}; + +ðmac { + status = "okay"; + phy-handle = <&internal_ephy>; + phy-mode = "rmii"; +}; + +&hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; + pinctrl-names = "default"; +}; + +&hdmi_tx_tmds_port { + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; +}; + +&i2c3 { + status = "okay"; + pinctrl-0 = <&i2c3_sda_a_pins>, <&i2c3_sck_a_pins>; + pinctrl-names = "default"; +}; + +&ir { + status = "okay"; + pinctrl-0 = <&remote_input_ao_pins>; + pinctrl-names = "default"; +}; + +&pwm_AO_ab { + status = "okay"; + pinctrl-0 = <&pwm_ao_a_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin0"; +}; + +&pwm_AO_cd { + pinctrl-0 = <&pwm_ao_d_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin1"; + status = "okay"; +}; + +&pwm_ef { + status = "okay"; + pinctrl-0 = <&pwm_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin0"; +}; + +&saradc { + status = "okay"; + vref-supply = <&vddio_ao1v8>; +}; + +/* SDIO */ +&sd_emmc_a { + status = "okay"; + pinctrl-0 = <&sdio_pins>; + pinctrl-1 = <&sdio_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; + #address-cells = <1>; + #size-cells = <0>; + + bus-width = <4>; + cap-sd-highspeed; + sd-uhs-sdr50; + max-frequency = <100000000>; + + non-removable; + disable-wp; + + mmc-pwrseq = <&sdio_pwrseq>; + + vmmc-supply = <&vddao_3v3>; + vqmmc-supply = <&vddio_ao1v8>; + + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; +}; + +/* SD card */ +&sd_emmc_b { + status = "okay"; + pinctrl-0 = <&sdcard_c_pins>; + pinctrl-1 = <&sdcard_clk_gate_c_pins>; + pinctrl-names = "default", "clk-gate"; + + bus-width = <4>; + cap-sd-highspeed; + max-frequency = <50000000>; + disable-wp; + + cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>; + vmmc-supply = <&vddao_3v3>; + vqmmc-supply = <&vddao_3v3>; +}; + +/* eMMC */ +&sd_emmc_c { + status = "okay"; + pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; + pinctrl-1 = <&emmc_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; + + bus-width = <8>; + cap-mmc-highspeed; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + max-frequency = <200000000>; + non-removable; + disable-wp; + + mmc-pwrseq = <&emmc_pwrseq>; + vmmc-supply = <&vddao_3v3>; + vqmmc-supply = <&emmc_1v8>; +}; + +&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"; + vbat-supply = <&vddao_3v3>; + vddio-supply = <&vddio_ao1v8>; + }; +}; + +/* Exposed via the on-board USB to Serial FT232RL IC */ +&uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; + pinctrl-names = "default"; +}; + +&usb { + status = "okay"; + dr_mode = "otg"; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi b/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..521573f3a5babef270b05b6080c846ef1def4431 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS + * Author: Neil Armstrong + */ + +#include "meson-g12-common.dtsi" +#include + +/ { + compatible = "amlogic,sm1"; + + cpus { + #address-cells = <0x2>; + #size-cells = <0x0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x0>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x1>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x2>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x3>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + l2: l2-cache0 { + compatible = "cache"; + }; + }; + + cpu_opp_table: opp-table { + compatible = "operating-points-v2"; + opp-shared; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + opp-microvolt = <730000>; + }; + + opp-250000000 { + opp-hz = /bits/ 64 <250000000>; + opp-microvolt = <730000>; + }; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <730000>; + }; + + opp-667000000 { + opp-hz = /bits/ 64 <666666666>; + opp-microvolt = <750000>; + }; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <770000>; + }; + + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <780000>; + }; + + opp-1404000000 { + opp-hz = /bits/ 64 <1404000000>; + opp-microvolt = <790000>; + }; + + opp-1512000000 { + opp-hz = /bits/ 64 <1500000000>; + opp-microvolt = <800000>; + }; + + opp-1608000000 { + opp-hz = /bits/ 64 <1608000000>; + opp-microvolt = <810000>; + }; + + opp-1704000000 { + opp-hz = /bits/ 64 <1704000000>; + opp-microvolt = <850000>; + }; + + opp-1800000000 { + opp-hz = /bits/ 64 <1800000000>; + opp-microvolt = <900000>; + }; + + opp-1908000000 { + opp-hz = /bits/ 64 <1908000000>; + opp-microvolt = <950000>; + }; + }; +}; + +&cecb_AO { + compatible = "amlogic,meson-sm1-ao-cec"; +}; + +&clk_msr { + compatible = "amlogic,meson-sm1-clk-measure"; +}; + + +&clkc { + compatible = "amlogic,sm1-clkc"; +}; + +ðmac { + power-domains = <&pwrc PWRC_SM1_ETH_ID>; +}; + +&pwrc { + compatible = "amlogic,meson-sm1-pwrc"; +}; + +&vpu { + power-domains = <&pwrc PWRC_SM1_VPU_ID>; +}; + +&usb { + power-domains = <&pwrc PWRC_SM1_USB_ID>; +}; diff --git a/arch/arm64/boot/dts/arm/fvp-base-revc.dts b/arch/arm64/boot/dts/arm/fvp-base-revc.dts index 687707020ec13dd5b80b20ea890c48f616345024..62ab0d54ff71ed4f513837d24fdfae1a743f773f 100644 --- a/arch/arm64/boot/dts/arm/fvp-base-revc.dts +++ b/arch/arm64/boot/dts/arm/fvp-base-revc.dts @@ -265,13 +265,5 @@ <0 0 42 &gic 0 0 GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>, <0 0 43 &gic 0 0 GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>, <0 0 44 &gic 0 0 GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>; - - motherboard { - iofpga@3,00000000 { - clcd@1f0000 { - max-memory-bandwidth = <130000000>; /* 16bpp @ 63.5MHz */ - }; - }; - }; }; }; diff --git a/arch/arm64/boot/dts/arm/rtsm_ve-motherboard.dtsi b/arch/arm64/boot/dts/arm/rtsm_ve-motherboard.dtsi index 454cf6c44c497119d5475cb362cc6bfb71644de0..03a7bf079c8ffd26f3d4c225b82d585ee55a8353 100644 --- a/arch/arm64/boot/dts/arm/rtsm_ve-motherboard.dtsi +++ b/arch/arm64/boot/dts/arm/rtsm_ve-motherboard.dtsi @@ -188,8 +188,6 @@ interrupts = <14>; clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>; clock-names = "clcdclk", "apb_pclk"; - /* 800x600 16bpp @36MHz works fine */ - max-memory-bandwidth = <54000000>; memory-region = <&vram>; port { diff --git a/arch/arm64/boot/dts/bitmain/bm1880.dtsi b/arch/arm64/boot/dts/bitmain/bm1880.dtsi index 7726fd4c6be6f68bf9cfaef8cf038a73ae445d7d..d65453f99a993a1d4ad7a5132798b1a109663b34 100644 --- a/arch/arm64/boot/dts/bitmain/bm1880.dtsi +++ b/arch/arm64/boot/dts/bitmain/bm1880.dtsi @@ -5,6 +5,7 @@ */ #include +#include / { compatible = "bitmain,bm1880"; @@ -88,9 +89,15 @@ #size-cells = <1>; ranges = <0x0 0x0 0x50010000 0x1000>; - pinctrl: pinctrl@50 { + pinctrl: pinctrl@400 { compatible = "bitmain,bm1880-pinctrl"; - reg = <0x50 0x4B0>; + reg = <0x400 0x120>; + }; + + rst: reset-controller@c00 { + compatible = "bitmain,bm1880-reset"; + reg = <0xc00 0x8>; + #reset-cells = <1>; }; }; @@ -154,6 +161,7 @@ interrupts = ; reg-shift = <2>; reg-io-width = <4>; + resets = <&rst BM1880_RST_UART0_1_CLK>; status = "disabled"; }; @@ -163,6 +171,7 @@ interrupts = ; reg-shift = <2>; reg-io-width = <4>; + resets = <&rst BM1880_RST_UART0_1_ACLK>; status = "disabled"; }; @@ -172,6 +181,7 @@ interrupts = ; reg-shift = <2>; reg-io-width = <4>; + resets = <&rst BM1880_RST_UART2_3_CLK>; status = "disabled"; }; @@ -181,6 +191,7 @@ interrupts = ; reg-shift = <2>; reg-io-width = <4>; + resets = <&rst BM1880_RST_UART2_3_ACLK>; status = "disabled"; }; }; diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile index c043aca665726c09eb595a43da2fa0d8b588b8a6..93fce8f0c66d83edaadf6b257c95d9b9f7609885 100644 --- a/arch/arm64/boot/dts/freescale/Makefile +++ b/arch/arm64/boot/dts/freescale/Makefile @@ -8,6 +8,7 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb.dtb +dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-frwy.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-qds.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1088a-qds.dtb @@ -21,8 +22,13 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-qds.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-rdb.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr4-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mq-hummingboard-pulse.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mq-librem5-devkit.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mq-nitrogen.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mq-pico-pi.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mq-zii-ultra-rmb3.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mq-zii-ultra-zest.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8qxp-ai_ml.dtb dtb-$(CONFIG_ARCH_MXC) += imx8qxp-mek.dtb diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi index ec6257a5b251504f23dcd752a6fa61757a57d92e..124a7e2d8442f0d30ae3be6494683d0522dddf3c 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi @@ -323,7 +323,7 @@ #size-cells = <0>; reg = <0x0 0x2180000 0x0 0x10000>; interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clockgen 4 0>; + clocks = <&clockgen 4 3>; status = "disabled"; }; @@ -333,7 +333,7 @@ #size-cells = <0>; reg = <0x0 0x2190000 0x0 0x10000>; interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clockgen 4 0>; + clocks = <&clockgen 4 3>; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts index de6ef39f3118ac27fe0a61ed347cf66b0080ab3f..d98346da01df5d7ab4f7081e14151ec29210cd7b 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts @@ -85,6 +85,26 @@ system-clock-frequency = <25000000>; }; }; + + mdio-mux { + compatible = "mdio-mux-multiplexer"; + mux-controls = <&mux 0>; + mdio-parent-bus = <&enetc_mdio_pf3>; + #address-cells=<1>; + #size-cells = <0>; + + /* on-board RGMII PHY */ + mdio@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + qds_phy1: ethernet-phy@5 { + /* Atheros 8035 */ + reg = <5>; + }; + }; + }; }; &duart0 { @@ -95,6 +115,14 @@ status = "okay"; }; +&esdhc { + status = "okay"; +}; + +&esdhc1 { + status = "okay"; +}; + &i2c0 { status = "okay"; @@ -164,6 +192,26 @@ }; }; }; + + fpga@66 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,ls1028aqds-fpga", "fsl,fpga-qixis-i2c", + "simple-mfd"; + reg = <0x66>; + + mux: mux-controller { + compatible = "reg-mux"; + #mux-control-cells = <1>; + mux-reg-masks = <0x54 0xf0>; /* 0: reg 0x54, bits 7:4 */ + }; + }; + +}; + +&enetc_port1 { + phy-handle = <&qds_phy1>; + phy-connection-type = "rgmii-id"; }; &sai1 { diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts index 9fb911317ecd6c98c9f350c14431e99a0f968f80..1a69221d9a1b0d95dc36ce98ed4566220d6e67f3 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts @@ -83,6 +83,19 @@ }; }; +&esdhc { + sd-uhs-sdr104; + sd-uhs-sdr50; + sd-uhs-sdr25; + sd-uhs-sdr12; + status = "okay"; +}; + +&esdhc1 { + mmc-hs200-1_8v; + status = "okay"; +}; + &i2c0 { status = "okay"; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi index 7975519b4f5616f9b43c180224c20ddf438ea185..72b9a75976a1f0a3dc4837cbfdd7e02570e3dde7 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi @@ -29,6 +29,7 @@ clocks = <&clockgen 1 0>; next-level-cache = <&l2>; cpu-idle-states = <&CPU_PW20>; + #cooling-cells = <2>; }; cpu1: cpu@1 { @@ -39,6 +40,7 @@ clocks = <&clockgen 1 0>; next-level-cache = <&l2>; cpu-idle-states = <&CPU_PW20>; + #cooling-cells = <2>; }; l2: l2-cache { @@ -70,11 +72,18 @@ clock-output-names = "sysclk"; }; - dpclk: clock-dp { + osc_27m: clock-osc-27m { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <27000000>; - clock-output-names= "dpclk"; + clock-output-names = "phy_27m"; + }; + + dpclk: clock-controller@f1f0000 { + compatible = "fsl,ls1028a-plldig"; + reg = <0x0 0xf1f0000 0x0 0xffff>; + #clock-cells = <1>; + clocks = <&osc_27m>; }; aclk: clock-axi { @@ -171,7 +180,7 @@ #size-cells = <0>; reg = <0x0 0x2000000 0x0 0x10000>; interrupts = ; - clocks = <&clockgen 4 1>; + clocks = <&clockgen 4 3>; status = "disabled"; }; @@ -181,7 +190,7 @@ #size-cells = <0>; reg = <0x0 0x2010000 0x0 0x10000>; interrupts = ; - clocks = <&clockgen 4 1>; + clocks = <&clockgen 4 3>; status = "disabled"; }; @@ -191,7 +200,7 @@ #size-cells = <0>; reg = <0x0 0x2020000 0x0 0x10000>; interrupts = ; - clocks = <&clockgen 4 1>; + clocks = <&clockgen 4 3>; status = "disabled"; }; @@ -201,7 +210,7 @@ #size-cells = <0>; reg = <0x0 0x2030000 0x0 0x10000>; interrupts = ; - clocks = <&clockgen 4 1>; + clocks = <&clockgen 4 3>; status = "disabled"; }; @@ -211,7 +220,7 @@ #size-cells = <0>; reg = <0x0 0x2040000 0x0 0x10000>; interrupts = ; - clocks = <&clockgen 4 1>; + clocks = <&clockgen 4 3>; status = "disabled"; }; @@ -221,7 +230,7 @@ #size-cells = <0>; reg = <0x0 0x2050000 0x0 0x10000>; interrupts = ; - clocks = <&clockgen 4 1>; + clocks = <&clockgen 4 3>; status = "disabled"; }; @@ -231,7 +240,7 @@ #size-cells = <0>; reg = <0x0 0x2060000 0x0 0x10000>; interrupts = ; - clocks = <&clockgen 4 1>; + clocks = <&clockgen 4 3>; status = "disabled"; }; @@ -241,7 +250,34 @@ #size-cells = <0>; reg = <0x0 0x2070000 0x0 0x10000>; interrupts = ; - clocks = <&clockgen 4 1>; + clocks = <&clockgen 4 3>; + status = "disabled"; + }; + + esdhc: mmc@2140000 { + compatible = "fsl,ls1028a-esdhc", "fsl,esdhc"; + reg = <0x0 0x2140000 0x0 0x10000>; + interrupts = ; + clock-frequency = <0>; /* fixed up by bootloader */ + clocks = <&clockgen 2 1>; + voltage-ranges = <1800 1800 3300 3300>; + sdhci,auto-cmd12; + little-endian; + bus-width = <4>; + status = "disabled"; + }; + + esdhc1: mmc@2150000 { + compatible = "fsl,ls1028a-esdhc", "fsl,esdhc"; + reg = <0x0 0x2150000 0x0 0x10000>; + interrupts = ; + clock-frequency = <0>; /* fixed up by bootloader */ + clocks = <&clockgen 2 1>; + voltage-ranges = <1800 1800 3300 3300>; + sdhci,auto-cmd12; + broken-cd; + little-endian; + bus-width = <4>; status = "disabled"; }; @@ -277,33 +313,36 @@ }; gpio1: gpio@2300000 { - compatible = "fsl,qoriq-gpio"; + compatible = "fsl,ls1028a-gpio","fsl,qoriq-gpio"; reg = <0x0 0x2300000 0x0 0x10000>; interrupts = ; gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + little-endian; }; gpio2: gpio@2310000 { - compatible = "fsl,qoriq-gpio"; + compatible = "fsl,ls1028a-gpio","fsl,qoriq-gpio"; reg = <0x0 0x2310000 0x0 0x10000>; interrupts = ; gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + little-endian; }; gpio3: gpio@2320000 { - compatible = "fsl,qoriq-gpio"; + compatible = "fsl,ls1028a-gpio","fsl,qoriq-gpio"; reg = <0x0 0x2320000 0x0 0x10000>; interrupts = ; gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + little-endian; }; usb0: usb@3100000 { @@ -503,6 +542,89 @@ status = "disabled"; }; + tmu: tmu@1f00000 { + compatible = "fsl,qoriq-tmu"; + reg = <0x0 0x1f80000 0x0 0x10000>; + interrupts = <0 23 0x4>; + fsl,tmu-range = <0xb0000 0xa0026 0x80048 0x70061>; + fsl,tmu-calibration = <0x00000000 0x00000024 + 0x00000001 0x0000002b + 0x00000002 0x00000031 + 0x00000003 0x00000038 + 0x00000004 0x0000003f + 0x00000005 0x00000045 + 0x00000006 0x0000004c + 0x00000007 0x00000053 + 0x00000008 0x00000059 + 0x00000009 0x00000060 + 0x0000000a 0x00000066 + 0x0000000b 0x0000006d + + 0x00010000 0x0000001c + 0x00010001 0x00000024 + 0x00010002 0x0000002c + 0x00010003 0x00000035 + 0x00010004 0x0000003d + 0x00010005 0x00000045 + 0x00010006 0x0000004d + 0x00010007 0x00000045 + 0x00010008 0x0000005e + 0x00010009 0x00000066 + 0x0001000a 0x0000006e + + 0x00020000 0x00000018 + 0x00020001 0x00000022 + 0x00020002 0x0000002d + 0x00020003 0x00000038 + 0x00020004 0x00000043 + 0x00020005 0x0000004d + 0x00020006 0x00000058 + 0x00020007 0x00000063 + 0x00020008 0x0000006e + + 0x00030000 0x00000010 + 0x00030001 0x0000001c + 0x00030002 0x00000029 + 0x00030003 0x00000036 + 0x00030004 0x00000042 + 0x00030005 0x0000004f + 0x00030006 0x0000005b + 0x00030007 0x00000068>; + little-endian; + #thermal-sensor-cells = <1>; + }; + + thermal-zones { + core-cluster { + polling-delay-passive = <1000>; + polling-delay = <5000>; + thermal-sensors = <&tmu 0>; + + trips { + core_cluster_alert: core-cluster-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + core_cluster_crit: core-cluster-crit { + temperature = <95000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&core_cluster_alert>; + cooling-device = + <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + }; + pcie@1f0000000 { /* Integrated Endpoint Root Complex */ compatible = "pci-host-ecam-generic"; reg = <0x01 0xf0000000 0x0 0x100000>; @@ -536,6 +658,12 @@ compatible = "fsl,enetc"; reg = <0x000100 0 0 0 0>; }; + enetc_mdio_pf3: mdio@0,3 { + compatible = "fsl,enetc-mdio"; + reg = <0x000300 0 0 0 0>; + #address-cells = <1>; + #size-cells = <0>; + }; ethernet@0,4 { compatible = "fsl,enetc-ptp"; reg = <0x000400 0 0 0 0>; @@ -551,9 +679,10 @@ interrupts = <0 222 IRQ_TYPE_LEVEL_HIGH>, <0 223 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "DE", "SE"; - clocks = <&dpclk>, <&aclk>, <&aclk>, <&pclk>; + clocks = <&dpclk 0>, <&aclk>, <&aclk>, <&pclk>; clock-names = "pxlclk", "mclk", "aclk", "pclk"; arm,malidp-output-port-lines = /bits/ 8 <8 8 8>; + arm,malidp-arqos-value = <0xd000d000>; port { dp0_out: endpoint { diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy.dts b/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy.dts new file mode 100644 index 0000000000000000000000000000000000000000..3595be0f2527731e34555dc74800d3ead3c06e4e --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy.dts @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Device Tree Include file for Freescale Layerscape-1046A family SoC. + * + * Copyright 2019 NXP. + * + */ + +/dts-v1/; + +#include "fsl-ls1046a.dtsi" + +/ { + model = "LS1046A FRWY Board"; + compatible = "fsl,ls1046a-frwy", "fsl,ls1046a"; + + aliases { + serial0 = &duart0; + serial1 = &duart1; + serial2 = &duart2; + serial3 = &duart3; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + sb_3v3: regulator-sb3v3 { + compatible = "regulator-fixed"; + regulator-name = "LT8642SEV-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; +}; + +&duart0 { + status = "okay"; +}; + +&duart1 { + status = "okay"; +}; + +&duart2 { + status = "okay"; +}; + +&duart3 { + status = "okay"; +}; + +&i2c0 { + status = "okay"; + + i2c-mux@77 { + compatible = "nxp,pca9546"; + reg = <0x77>; + #address-cells = <1>; + #size-cells = <0>; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + power-monitor@40 { + compatible = "ti,ina220"; + reg = <0x40>; + shunt-resistor = <1000>; + }; + + temperature-sensor@4c { + compatible = "nxp,sa56004"; + reg = <0x4c>; + vcc-supply = <&sb_3v3>; + }; + + rtc@51 { + compatible = "nxp,pcf2129"; + reg = <0x51>; + }; + + eeprom@52 { + compatible = "atmel,24c512"; + reg = <0x52>; + }; + + eeprom@53 { + compatible = "atmel,24c512"; + reg = <0x53>; + }; + + }; + }; +}; + +&ifc { + #address-cells = <2>; + #size-cells = <1>; + /* NAND Flash */ + ranges = <0x0 0x0 0x0 0x7e800000 0x00010000>; + status = "okay"; + + nand@0,0 { + compatible = "fsl,ifc-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x0 0x0 0x10000>; + }; + +}; + +#include "fsl-ls1046-post.dtsi" + +&fman0 { + ethernet@e0000 { + phy-handle = <&qsgmii_phy4>; + phy-connection-type = "qsgmii"; + }; + + ethernet@e8000 { + phy-handle = <&qsgmii_phy2>; + phy-connection-type = "qsgmii"; + }; + + ethernet@ea000 { + phy-handle = <&qsgmii_phy1>; + phy-connection-type = "qsgmii"; + }; + + ethernet@f2000 { + phy-handle = <&qsgmii_phy3>; + phy-connection-type = "qsgmii"; + }; + + mdio@fd000 { + qsgmii_phy1: ethernet-phy@1c { + reg = <0x1c>; + }; + + qsgmii_phy2: ethernet-phy@1d { + reg = <0x1d>; + }; + + qsgmii_phy3: ethernet-phy@1e { + reg = <0x1e>; + }; + + qsgmii_phy4: ethernet-phy@1f { + reg = <0x1f>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts index 6f48d21b97c0450386ff3c1503e384faa0625e23..120e62dad1542d99daaeb0d97036c13376692e58 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts @@ -17,6 +17,39 @@ compatible = "fsl,ls1088a-qds", "fsl,ls1088a"; }; +&dspi { + bus-num = <0>; + status = "okay"; + + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + + flash@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + spi-cpol; + spi-cpha; + spi-max-frequency = <3500000>; + reg = <1>; + }; + + flash@2 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + spi-cpol; + spi-cpha; + spi-max-frequency = <3500000>; + reg = <2>; + }; +}; + &i2c0 { status = "okay"; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi index dacd8cf03a7f7a77969042707893b6fe8df8f589..d1469b0747c75092bdace963a0d3bceffe2f7913 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi @@ -252,6 +252,19 @@ #thermal-sensor-cells = <1>; }; + dspi: spi@2100000 { + compatible = "fsl,ls1088a-dspi", + "fsl,ls1021a-v1.0-dspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x2100000 0x0 0x10000>; + interrupts = ; + clock-names = "dspi"; + clocks = <&clockgen 4 1>; + spi-num-chipselects = <6>; + status = "disabled"; + }; + duart0: serial@21c0500 { compatible = "fsl,ns16550", "ns16550a"; reg = <0x0 0x21c0500 0x0 0x100>; @@ -269,9 +282,10 @@ }; gpio0: gpio@2300000 { - compatible = "fsl,qoriq-gpio"; + compatible = "fsl,ls1088a-gpio", "fsl,qoriq-gpio"; reg = <0x0 0x2300000 0x0 0x10000>; interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>; + little-endian; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -279,9 +293,10 @@ }; gpio1: gpio@2310000 { - compatible = "fsl,qoriq-gpio"; + compatible = "fsl,ls1088a-gpio", "fsl,qoriq-gpio"; reg = <0x0 0x2310000 0x0 0x10000>; interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>; + little-endian; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -289,9 +304,10 @@ }; gpio2: gpio@2320000 { - compatible = "fsl,qoriq-gpio"; + compatible = "fsl,ls1088a-gpio", "fsl,qoriq-gpio"; reg = <0x0 0x2320000 0x0 0x10000>; interrupts = <0 37 IRQ_TYPE_LEVEL_HIGH>; + little-endian; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -299,9 +315,10 @@ }; gpio3: gpio@2330000 { - compatible = "fsl,qoriq-gpio"; + compatible = "fsl,ls1088a-gpio", "fsl,qoriq-gpio"; reg = <0x0 0x2330000 0x0 0x10000>; interrupts = <0 37 IRQ_TYPE_LEVEL_HIGH>; + little-endian; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -324,7 +341,7 @@ #size-cells = <0>; reg = <0x0 0x2000000 0x0 0x10000>; interrupts = <0 34 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clockgen 4 3>; + clocks = <&clockgen 4 7>; status = "disabled"; }; @@ -334,7 +351,7 @@ #size-cells = <0>; reg = <0x0 0x2010000 0x0 0x10000>; interrupts = <0 34 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clockgen 4 3>; + clocks = <&clockgen 4 7>; status = "disabled"; }; @@ -344,7 +361,7 @@ #size-cells = <0>; reg = <0x0 0x2020000 0x0 0x10000>; interrupts = <0 35 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clockgen 4 3>; + clocks = <&clockgen 4 7>; status = "disabled"; }; @@ -354,7 +371,7 @@ #size-cells = <0>; reg = <0x0 0x2030000 0x0 0x10000>; interrupts = <0 35 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clockgen 4 3>; + clocks = <&clockgen 4 7>; status = "disabled"; }; @@ -609,6 +626,11 @@ ; }; + console@8340020 { + compatible = "fsl,dpaa2-console"; + reg = <0x00000000 0x08340020 0 0x2>; + }; + ptp-timer@8b95000 { compatible = "fsl,dpaa2-ptp"; reg = <0x0 0x8b95000 0x0 0x100>; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi index 3ace91945b726fc25ede7be1e80e4737f3d37660..64101c9962ce1ee6e7063ebd7b573bef4652193b 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi @@ -321,6 +321,11 @@ }; }; + console@8340020 { + compatible = "fsl,dpaa2-console"; + reg = <0x00000000 0x08340020 0 0x2>; + }; + ptp-timer@8b95000 { compatible = "fsl,dpaa2-ptp"; reg = <0x0 0x8b95000 0x0 0x100>; diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi index e6fdba39453c389f77d2bf19e47620e793cb167b..408e0ecdce6a5b2024fb89bed1cc7902dafb5180 100644 --- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi @@ -485,7 +485,7 @@ reg = <0x0 0x2000000 0x0 0x10000>; interrupts = ; clock-names = "i2c"; - clocks = <&clockgen 4 7>; + clocks = <&clockgen 4 15>; scl-gpio = <&gpio2 15 GPIO_ACTIVE_HIGH>; status = "disabled"; }; @@ -497,7 +497,7 @@ reg = <0x0 0x2010000 0x0 0x10000>; interrupts = ; clock-names = "i2c"; - clocks = <&clockgen 4 7>; + clocks = <&clockgen 4 15>; status = "disabled"; }; @@ -508,7 +508,7 @@ reg = <0x0 0x2020000 0x0 0x10000>; interrupts = ; clock-names = "i2c"; - clocks = <&clockgen 4 7>; + clocks = <&clockgen 4 15>; status = "disabled"; }; @@ -519,7 +519,7 @@ reg = <0x0 0x2030000 0x0 0x10000>; interrupts = ; clock-names = "i2c"; - clocks = <&clockgen 4 7>; + clocks = <&clockgen 4 15>; status = "disabled"; }; @@ -530,7 +530,7 @@ reg = <0x0 0x2040000 0x0 0x10000>; interrupts = ; clock-names = "i2c"; - clocks = <&clockgen 4 7>; + clocks = <&clockgen 4 15>; scl-gpio = <&gpio2 16 GPIO_ACTIVE_HIGH>; status = "disabled"; }; @@ -542,7 +542,7 @@ reg = <0x0 0x2050000 0x0 0x10000>; interrupts = ; clock-names = "i2c"; - clocks = <&clockgen 4 7>; + clocks = <&clockgen 4 15>; status = "disabled"; }; @@ -553,7 +553,7 @@ reg = <0x0 0x2060000 0x0 0x10000>; interrupts = ; clock-names = "i2c"; - clocks = <&clockgen 4 7>; + clocks = <&clockgen 4 15>; status = "disabled"; }; @@ -564,7 +564,7 @@ reg = <0x0 0x2070000 0x0 0x10000>; interrupts = ; clock-names = "i2c"; - clocks = <&clockgen 4 7>; + clocks = <&clockgen 4 15>; status = "disabled"; }; @@ -848,6 +848,11 @@ dma-coherent; }; + console@8340020 { + compatible = "fsl,dpaa2-console"; + reg = <0x00000000 0x08340020 0 0x2>; + }; + ptp-timer@8b95000 { compatible = "fsl,dpaa2-ptp"; reg = <0x0 0x8b95000 0x0 0x100>; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk.dts index ee7f2b2fc1ffa7e3cd00ca1770b278de3146308d..f7a15f3904c2ca74254d80d4aafffb41f746def4 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-evk.dts @@ -5,6 +5,7 @@ /dts-v1/; +#include #include "imx8mm.dtsi" / { @@ -89,9 +90,6 @@ ethphy0: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c22"; reg = <0>; - at803x,led-act-blind-workaround; - at803x,eee-okay; - at803x,vddio-1p8v; }; }; }; @@ -115,6 +113,21 @@ status = "okay"; }; +&usbotg1 { + dr_mode = "otg"; + hnp-disable; + srp-disable; + adp-disable; + usb-role-switch; + status = "okay"; + + port { + usb1_drd_sw: endpoint { + remote-endpoint = <&typec1_dr_sw>; + }; + }; +}; + &usdhc2 { pinctrl-names = "default", "state_100mhz", "state_200mhz"; pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>; @@ -257,6 +270,42 @@ }; }; +&i2c2 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + ptn5110: tcpc@50 { + compatible = "nxp,ptn5110"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_typec1>; + reg = <0x50>; + interrupt-parent = <&gpio2>; + interrupts = <11 8>; + status = "okay"; + + port { + typec1_dr_sw: endpoint { + remote-endpoint = <&usb1_drd_sw>; + }; + }; + + typec1_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + power-role = "dual"; + data-role = "dual"; + try-power-role = "sink"; + source-pdos = ; + sink-pdos = ; + op-sink-microwatt = <15000000>; + self-powered; + }; + }; +}; + &iomuxc { pinctrl-names = "default"; @@ -299,6 +348,13 @@ >; }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL 0x400001c3 + MX8MM_IOMUXC_I2C2_SDA_I2C2_SDA 0x400001c3 + >; + }; + pinctrl_pmic: pmicirq { fsl,pins = < MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x41 @@ -320,6 +376,12 @@ >; }; + pinctrl_typec1: typec1grp { + fsl,pins = < + MX8MM_IOMUXC_SD1_STROBE_GPIO2_IO11 0x159 + >; + }; + pinctrl_uart2: uart2grp { fsl,pins = < MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX 0x140 diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi index 232a7412755a917210d5e3bc44208b3d1cf42b93..5f9d0da196e13c695ccc340a2f5ab5bc96985f67 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi @@ -44,6 +44,19 @@ #address-cells = <1>; #size-cells = <0>; + idle-states { + entry-method = "psci"; + + cpu_pd_wait: cpu-pd-wait { + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x0010033>; + local-timer-stop; + entry-latency-us = <1000>; + exit-latency-us = <700>; + min-residency-us = <2700>; + }; + }; + A53_0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a53"; @@ -55,6 +68,7 @@ operating-points-v2 = <&a53_opp_table>; nvmem-cells = <&cpu_speed_grade>; nvmem-cell-names = "speed_grade"; + cpu-idle-states = <&cpu_pd_wait>; }; A53_1: cpu@1 { @@ -66,6 +80,7 @@ enable-method = "psci"; next-level-cache = <&A53_L2>; operating-points-v2 = <&a53_opp_table>; + cpu-idle-states = <&cpu_pd_wait>; }; A53_2: cpu@2 { @@ -77,6 +92,7 @@ enable-method = "psci"; next-level-cache = <&A53_L2>; operating-points-v2 = <&a53_opp_table>; + cpu-idle-states = <&cpu_pd_wait>; }; A53_3: cpu@3 { @@ -88,6 +104,7 @@ enable-method = "psci"; next-level-cache = <&A53_L2>; operating-points-v2 = <&a53_opp_table>; + cpu-idle-states = <&cpu_pd_wait>; }; A53_L2: l2-cache0 { @@ -104,6 +121,7 @@ opp-microvolt = <850000>; opp-supported-hw = <0xe>, <0x7>; clock-latency-ns = <150000>; + opp-suspend; }; opp-1600000000 { @@ -111,14 +129,15 @@ opp-microvolt = <900000>; opp-supported-hw = <0xc>, <0x7>; clock-latency-ns = <150000>; + opp-suspend; }; opp-1800000000 { opp-hz = /bits/ 64 <1800000000>; opp-microvolt = <1000000>; - /* Consumer only but rely on speed grading */ - opp-supported-hw = <0x8>, <0x7>; + opp-supported-hw = <0x8>, <0x3>; clock-latency-ns = <150000>; + opp-suspend; }; }; @@ -295,6 +314,7 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 10 30>; }; gpio2: gpio@30210000 { @@ -307,6 +327,7 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 40 21>; }; gpio3: gpio@30220000 { @@ -319,6 +340,7 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 61 26>; }; gpio4: gpio@30230000 { @@ -331,6 +353,7 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 87 32>; }; gpio5: gpio@30240000 { @@ -343,6 +366,7 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 119 30>; }; wdog1: watchdog@30280000 { @@ -451,10 +475,22 @@ <&clk_ext3>, <&clk_ext4>; clock-names = "osc_32k", "osc_24m", "clk_ext1", "clk_ext2", "clk_ext3", "clk_ext4"; + assigned-clocks = <&clk IMX8MM_CLK_NOC>, + <&clk IMX8MM_CLK_AUDIO_AHB>, + <&clk IMX8MM_CLK_IPG_AUDIO_ROOT>, + <&clk IMX8MM_SYS_PLL3>, + <&clk IMX8MM_VIDEO_PLL1>; + assigned-clock-parents = <&clk IMX8MM_SYS_PLL3_OUT>, + <&clk IMX8MM_SYS_PLL1_800M>; + assigned-clock-rates = <0>, + <400000000>, + <400000000>, + <750000000>, + <594000000>; }; src: reset-controller@30390000 { - compatible = "fsl,imx8mm-src", "syscon"; + compatible = "fsl,imx8mm-src", "fsl,imx8mq-src", "syscon"; reg = <0x30390000 0x10000>; interrupts = ; #reset-cells = <1>; @@ -510,6 +546,14 @@ #pwm-cells = <2>; status = "disabled"; }; + + system_counter: timer@306a0000 { + compatible = "nxp,sysctr-timer"; + reg = <0x306a0000 0x20000>; + interrupts = ; + clocks = <&osc_24m>; + clock-names = "per"; + }; }; aips3: bus@30800000 { @@ -743,10 +787,8 @@ interrupts = ; clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>; clock-names = "usb1_ctrl_root_clk"; - assigned-clocks = <&clk IMX8MM_CLK_USB_BUS>, - <&clk IMX8MM_CLK_USB_CORE_REF>; - assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_500M>, - <&clk IMX8MM_SYS_PLL1_100M>; + assigned-clocks = <&clk IMX8MM_CLK_USB_BUS>; + assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_500M>; fsl,usbphy = <&usbphynop1>; fsl,usbmisc = <&usbmisc1 0>; status = "disabled"; @@ -764,10 +806,8 @@ interrupts = ; clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>; clock-names = "usb1_ctrl_root_clk"; - assigned-clocks = <&clk IMX8MM_CLK_USB_BUS>, - <&clk IMX8MM_CLK_USB_CORE_REF>; - assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_500M>, - <&clk IMX8MM_SYS_PLL1_100M>; + assigned-clocks = <&clk IMX8MM_CLK_USB_BUS>; + assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_500M>; fsl,usbphy = <&usbphynop2>; fsl,usbmisc = <&usbmisc2 0>; status = "disabled"; @@ -818,5 +858,12 @@ interrupt-controller; interrupts = ; }; + + ddr-pmu@3d800000 { + compatible = "fsl,imx8mm-ddr-pmu", "fsl,imx8m-ddr-pmu"; + reg = <0x3d800000 0x400000>; + interrupt-parent = <&gic>; + interrupts = ; + }; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mn-ddr4-evk.dts b/arch/arm64/boot/dts/freescale/imx8mn-ddr4-evk.dts new file mode 100644 index 0000000000000000000000000000000000000000..11c705d225d02ff4c1d70cc6efdc3c5703643f0b --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mn-ddr4-evk.dts @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2019 NXP + */ + +/dts-v1/; + +#include "imx8mn.dtsi" + +/ { + model = "NXP i.MX8MNano DDR4 EVK board"; + compatible = "fsl,imx8mn-ddr4-evk", "fsl,imx8mn"; + + chosen { + stdout-path = &uart2; + }; + + reg_usdhc2_vmmc: regulator-usdhc2 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>; + regulator-name = "VSD_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&A53_0 { + cpu-supply = <&buck2_reg>; +}; + +&iomuxc { + pinctrl-names = "default"; + + pinctrl_fec1: fec1grp { + fsl,pins = < + MX8MN_IOMUXC_ENET_MDC_ENET1_MDC 0x3 + MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO 0x3 + MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3 0x1f + MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2 0x1f + MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1 0x1f + MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0 0x1f + MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3 0x91 + MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2 0x91 + MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1 0x91 + MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0 0x91 + MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC 0x1f + MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC 0x91 + MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL 0x91 + MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL 0x1f + MX8MN_IOMUXC_SAI2_RXC_GPIO4_IO22 0x19 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX8MN_IOMUXC_I2C1_SCL_I2C1_SCL 0x400001c3 + MX8MN_IOMUXC_I2C1_SDA_I2C1_SDA 0x400001c3 + >; + }; + + pinctrl_pmic: pmicirq { + fsl,pins = < + MX8MN_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x41 + >; + }; + + pinctrl_reg_usdhc2_vmmc: regusdhc2vmmc { + fsl,pins = < + MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19 0x41 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX8MN_IOMUXC_UART2_RXD_UART2_DCE_RX 0x140 + MX8MN_IOMUXC_UART2_TXD_UART2_DCE_TX 0x140 + >; + }; + + pinctrl_usdhc2_gpio: usdhc2grpgpio { + fsl,pins = < + MX8MN_IOMUXC_GPIO1_IO15_GPIO1_IO15 0x1c4 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK 0x190 + MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d0 + MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d0 + MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d0 + MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d0 + MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d0 + MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2grp100mhz { + fsl,pins = < + MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK 0x194 + MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d4 + MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d4 + MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d4 + MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d4 + MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d4 + MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2grp200mhz { + fsl,pins = < + MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK 0x196 + MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d6 + MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d6 + MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d6 + MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d6 + MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d6 + MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK 0x40000190 + MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD 0x1d0 + MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0 0x1d0 + MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1 0x1d0 + MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2 0x1d0 + MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3 0x1d0 + MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4 0x1d0 + MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5 0x1d0 + MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6 0x1d0 + MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7 0x1d0 + MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE 0x190 + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3grp100mhz { + fsl,pins = < + MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK 0x40000194 + MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD 0x1d4 + MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0 0x1d4 + MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1 0x1d4 + MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2 0x1d4 + MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3 0x1d4 + MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4 0x1d4 + MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5 0x1d4 + MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6 0x1d4 + MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7 0x1d4 + MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE 0x194 + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3grp200mhz { + fsl,pins = < + MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK 0x40000196 + MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD 0x1d6 + MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0 0x1d6 + MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1 0x1d6 + MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2 0x1d6 + MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3 0x1d6 + MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4 0x1d6 + MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5 0x1d6 + MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6 0x1d6 + MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7 0x1d6 + MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE 0x196 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B 0xc6 + >; + }; +}; + +&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>; + at803x,led-act-blind-workaround; + at803x,eee-disabled; + at803x,vddio-1p8v; + }; + }; +}; + +&i2c1 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pmic@4b { + compatible = "rohm,bd71847"; + reg = <0x4b>; + pinctrl-0 = <&pinctrl_pmic>; + interrupt-parent = <&gpio1>; + interrupts = <3 GPIO_ACTIVE_LOW>; + rohm,reset-snvs-powered; + + regulators { + buck1_reg: BUCK1 { + regulator-name = "BUCK1"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <1250>; + }; + + buck2_reg: BUCK2 { + regulator-name = "BUCK2"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <1250>; + }; + + buck3_reg: BUCK3 { + // BUCK5 in datasheet + regulator-name = "BUCK3"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1350000>; + }; + + buck4_reg: BUCK4 { + // BUCK6 in datasheet + regulator-name = "BUCK4"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + buck5_reg: BUCK5 { + // BUCK7 in datasheet + regulator-name = "BUCK5"; + regulator-min-microvolt = <1605000>; + regulator-max-microvolt = <1995000>; + regulator-boot-on; + regulator-always-on; + }; + + buck6_reg: BUCK6 { + // BUCK8 in datasheet + regulator-name = "BUCK6"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo1_reg: LDO1 { + regulator-name = "LDO1"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo2_reg: LDO2 { + regulator-name = "LDO2"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo3_reg: LDO3 { + regulator-name = "LDO3"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo4_reg: LDO4 { + regulator-name = "LDO4"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo6_reg: LDO6 { + regulator-name = "LDO6"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; + +&snvs_pwrkey { + status = "okay"; +}; + +&uart2 { /* console */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>; + cd-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; + bus-width = <4>; + vmmc-supply = <®_usdhc2_vmmc>; + status = "okay"; +}; + +&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"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mn.dtsi b/arch/arm64/boot/dts/freescale/imx8mn.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..785f4c420fa4c518dad3bc0e20ad4528279b96e7 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mn.dtsi @@ -0,0 +1,758 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2019 NXP + */ + +#include +#include +#include +#include + +#include "imx8mn-pinfunc.h" + +/ { + compatible = "fsl,imx8mn"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + ethernet0 = &fec1; + gpio0 = &gpio1; + gpio1 = &gpio2; + gpio2 = &gpio3; + gpio3 = &gpio4; + gpio4 = &gpio5; + i2c0 = &i2c1; + i2c1 = &i2c2; + i2c2 = &i2c3; + i2c3 = &i2c4; + mmc0 = &usdhc1; + mmc1 = &usdhc2; + mmc2 = &usdhc3; + serial0 = &uart1; + serial1 = &uart2; + serial2 = &uart3; + serial3 = &uart4; + spi0 = &ecspi1; + spi1 = &ecspi2; + spi2 = &ecspi3; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + A53_0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x0>; + clock-latency = <61036>; + clocks = <&clk IMX8MN_CLK_ARM>; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + operating-points-v2 = <&a53_opp_table>; + nvmem-cells = <&cpu_speed_grade>; + nvmem-cell-names = "speed_grade"; + }; + + A53_1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x1>; + clock-latency = <61036>; + clocks = <&clk IMX8MN_CLK_ARM>; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + operating-points-v2 = <&a53_opp_table>; + }; + + A53_2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x2>; + clock-latency = <61036>; + clocks = <&clk IMX8MN_CLK_ARM>; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + operating-points-v2 = <&a53_opp_table>; + }; + + A53_3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x3>; + clock-latency = <61036>; + clocks = <&clk IMX8MN_CLK_ARM>; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + operating-points-v2 = <&a53_opp_table>; + }; + + A53_L2: l2-cache0 { + compatible = "cache"; + }; + }; + + a53_opp_table: opp-table { + compatible = "operating-points-v2"; + opp-shared; + + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <850000>; + opp-supported-hw = <0xb00>, <0x7>; + clock-latency-ns = <150000>; + opp-suspend; + }; + + opp-1400000000 { + opp-hz = /bits/ 64 <1400000000>; + opp-microvolt = <950000>; + opp-supported-hw = <0x300>, <0x7>; + clock-latency-ns = <150000>; + opp-suspend; + }; + + opp-1500000000 { + opp-hz = /bits/ 64 <1500000000>; + opp-microvolt = <1000000>; + opp-supported-hw = <0x100>, <0x3>; + clock-latency-ns = <150000>; + opp-suspend; + }; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0x0 0x40000000 0 0x80000000>; + }; + + osc_32k: clock-osc-32k { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + clock-output-names = "osc_32k"; + }; + + osc_24m: clock-osc-24m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "osc_24m"; + }; + + clk_ext1: clock-ext1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <133000000>; + clock-output-names = "clk_ext1"; + }; + + clk_ext2: clock-ext2 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <133000000>; + clock-output-names = "clk_ext2"; + }; + + clk_ext3: clock-ext3 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <133000000>; + clock-output-names = "clk_ext3"; + }; + + clk_ext4: clock-ext4 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency= <133000000>; + clock-output-names = "clk_ext4"; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + clock-frequency = <8000000>; + arm,no-tick-in-suspend; + }; + + soc@0 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x0 0x3e000000>; + + aips1: bus@30000000 { + compatible = "fsl,aips-bus", "simple-bus"; + reg = <0x30000000 0x400000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gpio1: gpio@30200000 { + compatible = "fsl,imx8mn-gpio", "fsl,imx35-gpio"; + reg = <0x30200000 0x10000>; + interrupts = , + ; + clocks = <&clk IMX8MN_CLK_GPIO1_ROOT>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 10 30>; + }; + + gpio2: gpio@30210000 { + compatible = "fsl,imx8mn-gpio", "fsl,imx35-gpio"; + reg = <0x30210000 0x10000>; + interrupts = , + ; + clocks = <&clk IMX8MN_CLK_GPIO2_ROOT>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 40 21>; + }; + + gpio3: gpio@30220000 { + compatible = "fsl,imx8mn-gpio", "fsl,imx35-gpio"; + reg = <0x30220000 0x10000>; + interrupts = , + ; + clocks = <&clk IMX8MN_CLK_GPIO3_ROOT>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 61 26>; + }; + + gpio4: gpio@30230000 { + compatible = "fsl,imx8mn-gpio", "fsl,imx35-gpio"; + reg = <0x30230000 0x10000>; + interrupts = , + ; + clocks = <&clk IMX8MN_CLK_GPIO4_ROOT>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 21 108 11>; + }; + + gpio5: gpio@30240000 { + compatible = "fsl,imx8mn-gpio", "fsl,imx35-gpio"; + reg = <0x30240000 0x10000>; + interrupts = , + ; + clocks = <&clk IMX8MN_CLK_GPIO5_ROOT>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 119 30>; + }; + + wdog1: watchdog@30280000 { + compatible = "fsl,imx8mn-wdt", "fsl,imx21-wdt"; + reg = <0x30280000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_WDOG1_ROOT>; + status = "disabled"; + }; + + wdog2: watchdog@30290000 { + compatible = "fsl,imx8mn-wdt", "fsl,imx21-wdt"; + reg = <0x30290000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_WDOG2_ROOT>; + status = "disabled"; + }; + + wdog3: watchdog@302a0000 { + compatible = "fsl,imx8mn-wdt", "fsl,imx21-wdt"; + reg = <0x302a0000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_WDOG3_ROOT>; + status = "disabled"; + }; + + sdma3: dma-controller@302b0000 { + compatible = "fsl,imx8mn-sdma", "fsl,imx7d-sdma"; + reg = <0x302b0000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_SDMA3_ROOT>, + <&clk IMX8MN_CLK_SDMA3_ROOT>; + clock-names = "ipg", "ahb"; + #dma-cells = <3>; + fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin"; + }; + + sdma2: dma-controller@302c0000 { + compatible = "fsl,imx8mn-sdma", "fsl,imx7d-sdma"; + reg = <0x302c0000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_SDMA2_ROOT>, + <&clk IMX8MN_CLK_SDMA2_ROOT>; + clock-names = "ipg", "ahb"; + #dma-cells = <3>; + fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin"; + }; + + iomuxc: pinctrl@30330000 { + compatible = "fsl,imx8mn-iomuxc"; + reg = <0x30330000 0x10000>; + }; + + gpr: iomuxc-gpr@30340000 { + compatible = "fsl,imx8mn-iomuxc-gpr", "syscon"; + reg = <0x30340000 0x10000>; + }; + + ocotp: ocotp-ctrl@30350000 { + compatible = "fsl,imx8mn-ocotp", "fsl,imx7d-ocotp", "syscon"; + reg = <0x30350000 0x10000>; + clocks = <&clk IMX8MN_CLK_OCOTP_ROOT>; + #address-cells = <1>; + #size-cells = <1>; + + cpu_speed_grade: speed-grade@10 { + reg = <0x10 4>; + }; + }; + + anatop: anatop@30360000 { + compatible = "fsl,imx8mn-anatop", "fsl,imx8mm-anatop", + "syscon", "simple-bus"; + reg = <0x30360000 0x10000>; + }; + + snvs: snvs@30370000 { + compatible = "fsl,sec-v4.0-mon","syscon", "simple-mfd"; + reg = <0x30370000 0x10000>; + + snvs_rtc: snvs-rtc-lp { + compatible = "fsl,sec-v4.0-mon-rtc-lp"; + regmap = <&snvs>; + offset = <0x34>; + interrupts = , + ; + clock-names = "snvs-rtc"; + }; + + snvs_pwrkey: snvs-powerkey { + compatible = "fsl,sec-v4.0-pwrkey"; + regmap = <&snvs>; + interrupts = ; + linux,keycode = ; + wakeup-source; + status = "disabled"; + }; + }; + + clk: clock-controller@30380000 { + compatible = "fsl,imx8mn-ccm"; + reg = <0x30380000 0x10000>; + #clock-cells = <1>; + clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>, + <&clk_ext3>, <&clk_ext4>; + clock-names = "osc_32k", "osc_24m", "clk_ext1", "clk_ext2", + "clk_ext3", "clk_ext4"; + }; + + src: reset-controller@30390000 { + compatible = "fsl,imx8mn-src", "syscon"; + reg = <0x30390000 0x10000>; + interrupts = ; + #reset-cells = <1>; + }; + }; + + aips2: bus@30400000 { + compatible = "fsl,aips-bus", "simple-bus"; + reg = <0x30400000 0x400000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + pwm1: pwm@30660000 { + compatible = "fsl,imx8mn-pwm", "fsl,imx27-pwm"; + reg = <0x30660000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_PWM1_ROOT>, + <&clk IMX8MN_CLK_PWM1_ROOT>; + clock-names = "ipg", "per"; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm2: pwm@30670000 { + compatible = "fsl,imx8mn-pwm", "fsl,imx27-pwm"; + reg = <0x30670000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_PWM2_ROOT>, + <&clk IMX8MN_CLK_PWM2_ROOT>; + clock-names = "ipg", "per"; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm3: pwm@30680000 { + compatible = "fsl,imx8mn-pwm", "fsl,imx27-pwm"; + reg = <0x30680000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_PWM3_ROOT>, + <&clk IMX8MN_CLK_PWM3_ROOT>; + clock-names = "ipg", "per"; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm4: pwm@30690000 { + compatible = "fsl,imx8mn-pwm", "fsl,imx27-pwm"; + reg = <0x30690000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_PWM4_ROOT>, + <&clk IMX8MN_CLK_PWM4_ROOT>; + clock-names = "ipg", "per"; + #pwm-cells = <2>; + status = "disabled"; + }; + }; + + aips3: bus@30800000 { + compatible = "fsl,aips-bus", "simple-bus"; + reg = <0x30800000 0x400000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + ecspi1: spi@30820000 { + compatible = "fsl,imx8mn-ecspi", "fsl,imx51-ecspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x30820000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_ECSPI1_ROOT>, + <&clk IMX8MN_CLK_ECSPI1_ROOT>; + clock-names = "ipg", "per"; + dmas = <&sdma1 0 7 1>, <&sdma1 1 7 2>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + ecspi2: spi@30830000 { + compatible = "fsl,imx8mn-ecspi", "fsl,imx51-ecspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x30830000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_ECSPI2_ROOT>, + <&clk IMX8MN_CLK_ECSPI2_ROOT>; + clock-names = "ipg", "per"; + dmas = <&sdma1 2 7 1>, <&sdma1 3 7 2>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + ecspi3: spi@30840000 { + compatible = "fsl,imx8mn-ecspi", "fsl,imx51-ecspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x30840000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_ECSPI3_ROOT>, + <&clk IMX8MN_CLK_ECSPI3_ROOT>; + clock-names = "ipg", "per"; + dmas = <&sdma1 4 7 1>, <&sdma1 5 7 2>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + uart1: serial@30860000 { + compatible = "fsl,imx8mn-uart", "fsl,imx6q-uart"; + reg = <0x30860000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_UART1_ROOT>, + <&clk IMX8MN_CLK_UART1_ROOT>; + clock-names = "ipg", "per"; + dmas = <&sdma1 22 4 0>, <&sdma1 23 4 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + uart3: serial@30880000 { + compatible = "fsl,imx8mn-uart", "fsl,imx6q-uart"; + reg = <0x30880000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_UART3_ROOT>, + <&clk IMX8MN_CLK_UART3_ROOT>; + clock-names = "ipg", "per"; + dmas = <&sdma1 26 4 0>, <&sdma1 27 4 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + uart2: serial@30890000 { + compatible = "fsl,imx8mn-uart", "fsl,imx6q-uart"; + reg = <0x30890000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_UART2_ROOT>, + <&clk IMX8MN_CLK_UART2_ROOT>; + clock-names = "ipg", "per"; + status = "disabled"; + }; + + i2c1: i2c@30a20000 { + compatible = "fsl,imx8mn-i2c", "fsl,imx21-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x30a20000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_I2C1_ROOT>; + status = "disabled"; + }; + + i2c2: i2c@30a30000 { + compatible = "fsl,imx8mn-i2c", "fsl,imx21-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x30a30000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_I2C2_ROOT>; + status = "disabled"; + }; + + i2c3: i2c@30a40000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx8mn-i2c", "fsl,imx21-i2c"; + reg = <0x30a40000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_I2C3_ROOT>; + status = "disabled"; + }; + + i2c4: i2c@30a50000 { + compatible = "fsl,imx8mn-i2c", "fsl,imx21-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x30a50000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_I2C4_ROOT>; + status = "disabled"; + }; + + uart4: serial@30a60000 { + compatible = "fsl,imx8mn-uart", "fsl,imx6q-uart"; + reg = <0x30a60000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_UART4_ROOT>, + <&clk IMX8MN_CLK_UART4_ROOT>; + clock-names = "ipg", "per"; + dmas = <&sdma1 28 4 0>, <&sdma1 29 4 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + usdhc1: mmc@30b40000 { + compatible = "fsl,imx8mn-usdhc", "fsl,imx7d-usdhc"; + reg = <0x30b40000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_DUMMY>, + <&clk IMX8MN_CLK_NAND_USDHC_BUS>, + <&clk IMX8MN_CLK_USDHC1_ROOT>; + clock-names = "ipg", "ahb", "per"; + assigned-clocks = <&clk IMX8MN_CLK_USDHC1>; + assigned-clock-rates = <400000000>; + fsl,tuning-start-tap = <20>; + fsl,tuning-step= <2>; + bus-width = <4>; + status = "disabled"; + }; + + usdhc2: mmc@30b50000 { + compatible = "fsl,imx8mn-usdhc", "fsl,imx7d-usdhc"; + reg = <0x30b50000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_DUMMY>, + <&clk IMX8MN_CLK_NAND_USDHC_BUS>, + <&clk IMX8MN_CLK_USDHC2_ROOT>; + clock-names = "ipg", "ahb", "per"; + fsl,tuning-start-tap = <20>; + fsl,tuning-step= <2>; + bus-width = <4>; + status = "disabled"; + }; + + usdhc3: mmc@30b60000 { + compatible = "fsl,imx8mn-usdhc", "fsl,imx7d-usdhc"; + reg = <0x30b60000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_DUMMY>, + <&clk IMX8MN_CLK_NAND_USDHC_BUS>, + <&clk IMX8MN_CLK_USDHC3_ROOT>; + clock-names = "ipg", "ahb", "per"; + assigned-clocks = <&clk IMX8MN_CLK_USDHC3_ROOT>; + assigned-clock-rates = <400000000>; + fsl,tuning-start-tap = <20>; + fsl,tuning-step= <2>; + bus-width = <4>; + status = "disabled"; + }; + + sdma1: dma-controller@30bd0000 { + compatible = "fsl,imx8mn-sdma", "fsl,imx7d-sdma"; + reg = <0x30bd0000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_SDMA1_ROOT>, + <&clk IMX8MN_CLK_SDMA1_ROOT>; + clock-names = "ipg", "ahb"; + #dma-cells = <3>; + fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin"; + }; + + fec1: ethernet@30be0000 { + compatible = "fsl,imx8mn-fec", "fsl,imx6sx-fec"; + reg = <0x30be0000 0x10000>; + interrupts = , + , + ; + clocks = <&clk IMX8MN_CLK_ENET1_ROOT>, + <&clk IMX8MN_CLK_ENET1_ROOT>, + <&clk IMX8MN_CLK_ENET_TIMER>, + <&clk IMX8MN_CLK_ENET_REF>, + <&clk IMX8MN_CLK_ENET_PHY_REF>; + clock-names = "ipg", "ahb", "ptp", + "enet_clk_ref", "enet_out"; + assigned-clocks = <&clk IMX8MN_CLK_ENET_AXI>, + <&clk IMX8MN_CLK_ENET_TIMER>, + <&clk IMX8MN_CLK_ENET_REF>, + <&clk IMX8MN_CLK_ENET_TIMER>; + assigned-clock-parents = <&clk IMX8MN_SYS_PLL1_266M>, + <&clk IMX8MN_SYS_PLL2_100M>, + <&clk IMX8MN_SYS_PLL2_125M>; + assigned-clock-rates = <0>, <0>, <125000000>, <100000000>; + fsl,num-tx-queues = <3>; + fsl,num-rx-queues = <3>; + status = "disabled"; + }; + + }; + + aips4: bus@32c00000 { + compatible = "fsl,aips-bus", "simple-bus"; + reg = <0x32c00000 0x400000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + usbotg1: usb@32e40000 { + compatible = "fsl,imx8mn-usb", "fsl,imx7d-usb"; + reg = <0x32e40000 0x200>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_USB1_CTRL_ROOT>; + clock-names = "usb1_ctrl_root_clk"; + assigned-clocks = <&clk IMX8MN_CLK_USB_BUS>, + <&clk IMX8MN_CLK_USB_CORE_REF>; + assigned-clock-parents = <&clk IMX8MN_SYS_PLL2_500M>, + <&clk IMX8MN_SYS_PLL1_100M>; + fsl,usbphy = <&usbphynop1>; + fsl,usbmisc = <&usbmisc1 0>; + status = "disabled"; + }; + + usbmisc1: usbmisc@32e40200 { + compatible = "fsl,imx8mn-usbmisc", "fsl,imx7d-usbmisc"; + #index-cells = <1>; + reg = <0x32e40200 0x200>; + }; + + usbotg2: usb@32e50000 { + compatible = "fsl,imx8mn-usb", "fsl,imx7d-usb"; + reg = <0x32e50000 0x200>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_USB1_CTRL_ROOT>; + clock-names = "usb1_ctrl_root_clk"; + assigned-clocks = <&clk IMX8MN_CLK_USB_BUS>, + <&clk IMX8MN_CLK_USB_CORE_REF>; + assigned-clock-parents = <&clk IMX8MN_SYS_PLL2_500M>, + <&clk IMX8MN_SYS_PLL1_100M>; + fsl,usbphy = <&usbphynop2>; + fsl,usbmisc = <&usbmisc2 0>; + status = "disabled"; + }; + + usbmisc2: usbmisc@32e50200 { + compatible = "fsl,imx8mn-usbmisc", "fsl,imx7d-usbmisc"; + #index-cells = <1>; + reg = <0x32e50200 0x200>; + }; + + }; + + dma_apbh: dma-controller@33000000 { + compatible = "fsl,imx7d-dma-apbh", "fsl,imx28-dma-apbh"; + reg = <0x33000000 0x2000>; + interrupts = , + , + , + ; + interrupt-names = "gpmi0", "gpmi1", "gpmi2", "gpmi3"; + #dma-cells = <1>; + dma-channels = <4>; + clocks = <&clk IMX8MN_CLK_NAND_USDHC_BUS_RAWNAND_CLK>; + }; + + gpmi: nand-controller@33002000 { + compatible = "fsl,imx8mn-gpmi-nand", "fsl,imx7d-gpmi-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x33002000 0x2000>, <0x33004000 0x4000>; + reg-names = "gpmi-nand", "bch"; + interrupts = ; + interrupt-names = "bch"; + clocks = <&clk IMX8MN_CLK_NAND_ROOT>, + <&clk IMX8MN_CLK_NAND_USDHC_BUS_RAWNAND_CLK>; + clock-names = "gpmi_io", "gpmi_bch_apb"; + dmas = <&dma_apbh 0>; + dma-names = "rx-tx"; + status = "disabled"; + }; + + gic: interrupt-controller@38800000 { + compatible = "arm,gic-v3"; + reg = <0x38800000 0x10000>, + <0x38880000 0xc0000>; + #interrupt-cells = <3>; + interrupt-controller; + interrupts = ; + }; + }; + + usbphynop1: usbphynop1 { + compatible = "usb-nop-xceiv"; + clocks = <&clk IMX8MN_CLK_USB_PHY_REF>; + assigned-clocks = <&clk IMX8MN_CLK_USB_PHY_REF>; + assigned-clock-parents = <&clk IMX8MN_SYS_PLL1_100M>; + clock-names = "main_clk"; + }; + + usbphynop2: usbphynop2 { + compatible = "usb-nop-xceiv"; + clocks = <&clk IMX8MN_CLK_USB_PHY_REF>; + assigned-clocks = <&clk IMX8MN_CLK_USB_PHY_REF>; + assigned-clock-parents = <&clk IMX8MN_SYS_PLL1_100M>; + clock-names = "main_clk"; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts index e3df9b8cd9cac44125df2468501454e9303514d6..05958124f173c61bf180c39b62fc77534218b3e0 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts @@ -118,9 +118,9 @@ &sai2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sai2>; - assigned-clocks = <&clk IMX8MQ_CLK_SAI2>; - assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1_OUT>; - assigned-clock-rates = <24576000>; + assigned-clocks = <&clk IMX8MQ_AUDIO_PLL1_BYPASS>, <&clk IMX8MQ_CLK_SAI2>; + assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1>, <&clk IMX8MQ_AUDIO_PLL1_OUT>; + assigned-clock-rates = <0>, <24576000>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mq-hummingboard-pulse.dts b/arch/arm64/boot/dts/freescale/imx8mq-hummingboard-pulse.dts new file mode 100644 index 0000000000000000000000000000000000000000..f52e872ac96ffd49a0b562b17ad8480588de61c3 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mq-hummingboard-pulse.dts @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2018 Jon Nettleton + */ + +/dts-v1/; + +#include "dt-bindings/usb/pd.h" +#include "imx8mq-sr-som.dtsi" + +/ { + model = "SolidRun i.MX8MQ HummingBoard Pulse"; + compatible = "solidrun,hummingboard-pulse", "fsl,imx8mq"; + + chosen { + stdout-path = &uart1; + }; + + reg_usdhc2_vmmc: regulator-usdhc2-vmmc { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2_vmmc>; + regulator-name = "VSD_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio1 13 GPIO_ACTIVE_LOW>; + }; + + reg_v_5v0: regulator-v-5v0 { + compatible = "regulator-fixed"; + regulator-name = "v_5v0"; + regulator-max-microvolt = <5000000>; + regulator-min-microvolt = <5000000>; + regulator-always-on; + }; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + clock-frequency = <100000>; + status = "okay"; + + typec_ptn5100: usb-typec@50 { + compatible = "nxp,ptn5110"; + reg = <0x50>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_typec>; + interrupt-parent = <&gpio1>; + interrupts = <6 IRQ_TYPE_LEVEL_LOW>; + + connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "dual"; + power-role = "dual"; + try-power-role = "sink"; + source-pdos = ; + sink-pdos = ; + op-sink-microwatt = <9000000>; + + port { + typec1_dr_sw: endpoint { + remote-endpoint = <&usb1_drd_sw>; + }; + }; + }; + }; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + clock-frequency = <100000>; + status = "okay"; + + rtc@69 { + compatible = "abracon,ab1805"; + reg = <0x69>; + abracon,tc-diode = "schottky"; + abracon,tc-resistor = <3>; + }; +}; + +&uart2 { /* J35 header */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + assigned-clocks = <&clk IMX8MQ_CLK_UART2>; + assigned-clock-parents = <&clk IMX8MQ_CLK_25M>; + status = "okay"; +}; + +&uart3 { /* Mikrobus */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + assigned-clocks = <&clk IMX8MQ_CLK_UART3>; + assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_80M>; + uart-has-rtscts; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>; + cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>; + vmmc-supply = <®_usdhc2_vmmc>; + status = "okay"; +}; + +&usb_dwc3_0 { + dr_mode = "otg"; + status = "okay"; + + port { + usb1_drd_sw: endpoint { + remote-endpoint = <&typec1_dr_sw>; + }; + }; +}; + +&usb_dwc3_1 { + dr_mode = "host"; + status = "okay"; +}; + +&usb3_phy0 { + status = "okay"; +}; + +&usb3_phy1 { + status = "okay"; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + pinctrl_hog: hoggrp { + fsl,pins = < + /* MikroBus Analog */ + MX8MQ_IOMUXC_NAND_DATA05_GPIO3_IO11 0x41 + /* MikroBus Reset */ + MX8MQ_IOMUXC_SAI2_RXD0_GPIO4_IO23 0x41 + /* + * The following 2 pins need to be commented out and + * reconfigured to enable RTS/CTS on UART3 + */ + /* MikroBus PWM */ + MX8MQ_IOMUXC_ECSPI1_MISO_GPIO5_IO8 0x41 + /* MikroBus INT */ + MX8MQ_IOMUXC_ECSPI1_SS0_GPIO5_IO9 0x41 + >; + }; + + 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_typec: typecgrp { + fsl,pins = < + MX8MQ_IOMUXC_NAND_RE_B_GPIO3_IO15 0x16 + MX8MQ_IOMUXC_GPIO1_IO06_GPIO1_IO6 0x17059 + >; + }; + + 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 + /* + * These pins are by default GPIO on the Mikro Bus + * Header. To use RTS/CTS on UART3 comment them out + * of the hoggrp and enable them here + */ + /* MX8MQ_IOMUXC_ECSPI1_MISO_UART3_DCE_CTS_B 0x49 */ + /* MX8MQ_IOMUXC_ECSPI1_SS0_UART3_DCE_RTS_B 0x49 */ + >; + }; + + pinctrl_usdhc2_gpio: usdhc2grpgpio { + fsl,pins = < + MX8MQ_IOMUXC_SD2_CD_B_GPIO2_IO12 0x41 + >; + }; + + pinctrl_usdhc2_vmmc: usdhc2vmmcgpio { + fsl,pins = < + MX8MQ_IOMUXC_GPIO1_IO13_GPIO1_IO13 0x41 + >; + }; + + 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: usdhc2grp100mhz { + 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: usdhc2grp200mhz { + 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 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts b/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts index 5179e22f5126a7d6c140f47fbaa8d21dbe0ea8a0..683a110356431873781866070efc5395eb7074ff 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts +++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts @@ -174,6 +174,10 @@ assigned-clock-rates = <786432000>, <722534400>; }; +&dphy { + status = "okay"; +}; + &fec1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_fec1>; diff --git a/arch/arm64/boot/dts/freescale/imx8mq-nitrogen.dts b/arch/arm64/boot/dts/freescale/imx8mq-nitrogen.dts new file mode 100644 index 0000000000000000000000000000000000000000..c832bf0fcc6070cd63925116537214639a3629fa --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mq-nitrogen.dts @@ -0,0 +1,405 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2018 Boundary Devices + */ + +/dts-v1/; + +#include +#include "imx8mq.dtsi" + +/ { + model = "Boundary Devices i.MX8MQ Nitrogen8M"; + compatible = "boundary,imx8mq-nitrogen8m", "fsl,imx8mq"; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0x00000000 0x40000000 0 0x80000000>; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_keys>; + + power { + label = "Power Button"; + gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + }; + + reg_vref_0v9: regulator-vref-0v9 { + compatible = "regulator-fixed"; + regulator-name = "vref-0v9"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + }; + + reg_vref_1v8: regulator-vref-1v8 { + compatible = "regulator-fixed"; + regulator-name = "vref-1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + reg_vref_2v5: regulator-vref-2v5 { + compatible = "regulator-fixed"; + regulator-name = "vref-2v5"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + }; + + reg_vref_3v3: regulator-vref-3v3 { + compatible = "regulator-fixed"; + regulator-name = "vref-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + reg_vref_5v: regulator-vref-5v { + compatible = "regulator-fixed"; + regulator-name = "vref-5v"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; +}; + + +&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@4 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <4>; + interrupts-extended = <&gpio1 11 IRQ_TYPE_LEVEL_LOW>; + }; + }; +}; + +&i2c1 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + i2cmux@70 { + compatible = "nxp,pca9546"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1_pca9546>; + reg = <0x70>; + reset-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; + #address-cells = <1>; + #size-cells = <0>; + + i2c1a: i2c1@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + reg_arm_dram: regulator@60 { + compatible = "fcs,fan53555"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_arm_dram>; + reg = <0x60>; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + vsel-gpios = <&gpio3 24 GPIO_ACTIVE_HIGH>; + }; + }; + + i2c1b: i2c1@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + reg_dram_1p1v: regulator@60 { + compatible = "fcs,fan53555"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_dram_1p1v>; + reg = <0x60>; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + vsel-gpios = <&gpio2 11 GPIO_ACTIVE_HIGH>; + }; + }; + + i2c1c: i2c1@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + + reg_soc_gpu_vpu: regulator@60 { + compatible = "fcs,fan53555"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_soc_gpu_vpu>; + reg = <0x60>; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + vsel-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>; + }; + }; + + i2c1d: i2c1@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + rtc@68 { + compatible = "microcrystal,rv4162"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1d_rv4162>; + reg = <0x68>; + interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_LOW>; + wakeup-source; + }; + }; + }; +}; + +&uart1 { /* console */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + assigned-clocks = <&clk IMX8MQ_CLK_UART1>; + assigned-clock-parents = <&clk IMX8MQ_CLK_25M>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + assigned-clocks = <&clk IMX8MQ_CLK_UART2>; + assigned-clock-parents = <&clk IMX8MQ_CLK_25M>; + status = "okay"; +}; + +&usdhc1 { + bus-width = <8>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc1>; + non-removable; + vmmc-supply = <®_vref_1v8>; + 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 = < + /* J17 connector, odd */ + MX8MQ_IOMUXC_SAI1_RXFS_GPIO4_IO0 0x19 /* Pin 19 */ + MX8MQ_IOMUXC_SAI1_RXC_GPIO4_IO1 0x19 /* Pin 21 */ + MX8MQ_IOMUXC_SAI1_RXD1_GPIO4_IO3 0x19 /* Pin 23 */ + MX8MQ_IOMUXC_SAI1_RXD2_GPIO4_IO4 0x19 /* Pin 25 */ + MX8MQ_IOMUXC_SAI1_RXD3_GPIO4_IO5 0x19 /* Pin 27 */ + MX8MQ_IOMUXC_SAI1_RXD4_GPIO4_IO6 0x19 /* Pin 29 */ + MX8MQ_IOMUXC_SAI1_RXD5_GPIO4_IO7 0x19 /* Pin 31 */ + MX8MQ_IOMUXC_SAI1_RXD6_GPIO4_IO8 0x19 /* Pin 33 */ + MX8MQ_IOMUXC_SAI1_RXD7_GPIO4_IO9 0x19 /* Pin 35 */ + MX8MQ_IOMUXC_SAI1_TXD1_GPIO4_IO13 0x19 /* Pin 39 */ + MX8MQ_IOMUXC_SAI1_TXD2_GPIO4_IO14 0x19 /* Pin 41 */ + MX8MQ_IOMUXC_SAI1_TXD3_GPIO4_IO15 0x19 /* Pin 43 */ + MX8MQ_IOMUXC_SAI1_TXD4_GPIO4_IO16 0x19 /* Pin 45 */ + MX8MQ_IOMUXC_SAI1_TXD5_GPIO4_IO17 0x19 /* Pin 47 */ + MX8MQ_IOMUXC_SAI1_TXD6_GPIO4_IO18 0x19 /* Pin 49 */ + MX8MQ_IOMUXC_SAI1_TXD7_GPIO4_IO19 0x19 /* Pin 51 */ + + /* J17 connector, even */ + MX8MQ_IOMUXC_SAI3_RXFS_GPIO4_IO28 0x19 /* Pin 44 */ + MX8MQ_IOMUXC_SAI3_RXC_GPIO4_IO29 0x19 /* Pin 48 */ + MX8MQ_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x19 /* Pin 50 */ + MX8MQ_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x19 /* Pin 54 */ + MX8MQ_IOMUXC_GPIO1_IO05_GPIO1_IO5 0x19 /* Pin 56 */ + + /* J18 connector, odd */ + MX8MQ_IOMUXC_NAND_CE3_B_GPIO3_IO4 0x19 /* Pin 41 */ + MX8MQ_IOMUXC_NAND_CLE_GPIO3_IO5 0x19 /* Pin 43 */ + MX8MQ_IOMUXC_NAND_READY_B_GPIO3_IO16 0x19 /* Pin 45 */ + MX8MQ_IOMUXC_NAND_DATA05_GPIO3_IO11 0x19 /* Pin 47 */ + MX8MQ_IOMUXC_NAND_WP_B_GPIO3_IO18 0x19 /* Pin 49 */ + MX8MQ_IOMUXC_NAND_DQS_GPIO3_IO14 0x19 /* Pin 53 */ + + /* J18 connector, even */ + MX8MQ_IOMUXC_NAND_ALE_GPIO3_IO0 0x19 /* Pin 32 */ + MX8MQ_IOMUXC_NAND_CE0_B_GPIO3_IO1 0x19 /* Pin 36 */ + MX8MQ_IOMUXC_NAND_DATA00_GPIO3_IO6 0x19 /* Pin 38 */ + MX8MQ_IOMUXC_NAND_DATA01_GPIO3_IO7 0x19 /* Pin 40 */ + MX8MQ_IOMUXC_NAND_DATA02_GPIO3_IO8 0x19 /* Pin 42 */ + MX8MQ_IOMUXC_NAND_DATA03_GPIO3_IO9 0x19 /* Pin 44 */ + MX8MQ_IOMUXC_NAND_DATA04_GPIO3_IO10 0x19 /* Pin 46 */ + + /* J13 Pin 2, WL_WAKE */ + MX8MQ_IOMUXC_SAI5_RXD2_GPIO3_IO23 0xd6 + /* J13 Pin 4, WL_IRQ, not needed for Silex */ + MX8MQ_IOMUXC_SAI5_RXD0_GPIO3_IO21 0xd6 + /* J13 pin 9, unused */ + MX8MQ_IOMUXC_SD2_CD_B_GPIO2_IO12 0x19 + /* J13 Pin 41, BT_CLK_REQ */ + MX8MQ_IOMUXC_SAI5_RXD1_GPIO3_IO22 0xd6 + /* J13 Pin 42, BT_HOST_WAKE */ + MX8MQ_IOMUXC_SAI5_MCLK_GPIO3_IO25 0xd6 + + /* Clock for both CSI1 and CSI2 */ + MX8MQ_IOMUXC_GPIO1_IO15_CCMSRCGPCMIX_CLKO2 0x07 + /* test points */ + MX8MQ_IOMUXC_GPIO1_IO04_GPIO1_IO4 0xc1 /* TP87 */ + >; + }; + + pinctrl_fec1: fec1grp { + fsl,pins = < + MX8MQ_IOMUXC_ENET_MDC_ENET1_MDC 0x3 + MX8MQ_IOMUXC_ENET_MDIO_ENET1_MDIO 0x23 + MX8MQ_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL 0x1f + MX8MQ_IOMUXC_ENET_TXC_ENET1_RGMII_TXC 0x1f + MX8MQ_IOMUXC_ENET_TD0_ENET1_RGMII_TD0 0x1f + MX8MQ_IOMUXC_ENET_TD1_ENET1_RGMII_TD1 0x1f + MX8MQ_IOMUXC_ENET_TD2_ENET1_RGMII_TD2 0x1f + MX8MQ_IOMUXC_ENET_TD3_ENET1_RGMII_TD3 0x1f + MX8MQ_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL 0x91 + MX8MQ_IOMUXC_ENET_RXC_ENET1_RGMII_RXC 0x91 + MX8MQ_IOMUXC_ENET_RD0_ENET1_RGMII_RD0 0x91 + MX8MQ_IOMUXC_ENET_RD1_ENET1_RGMII_RD1 0x91 + MX8MQ_IOMUXC_ENET_RD2_ENET1_RGMII_RD2 0x91 + MX8MQ_IOMUXC_ENET_RD3_ENET1_RGMII_RD3 0x91 + MX8MQ_IOMUXC_GPIO1_IO09_GPIO1_IO9 0x19 + MX8MQ_IOMUXC_GPIO1_IO11_GPIO1_IO11 0x59 + >; + }; + + pinctrl_gpio_keys: gpio-keysgrp { + fsl,pins = < + MX8MQ_IOMUXC_GPIO1_IO07_GPIO1_IO7 0x19 + >; + }; + + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX8MQ_IOMUXC_I2C1_SCL_I2C1_SCL 0x4000007f + MX8MQ_IOMUXC_I2C1_SDA_I2C1_SDA 0x4000007f + >; + }; + + pinctrl_i2c1_pca9546: i2c1-pca9546grp { + fsl,pins = < + MX8MQ_IOMUXC_GPIO1_IO08_GPIO1_IO8 0x49 + >; + }; + + pinctrl_i2c1d_rv4162: i2c1d-rv4162grp { + fsl,pins = < + MX8MQ_IOMUXC_GPIO1_IO06_GPIO1_IO6 0x49 + >; + }; + + pinctrl_reg_arm_dram: reg-arm-dramgrp { + fsl,pins = < + MX8MQ_IOMUXC_SAI5_RXD3_GPIO3_IO24 0x16 + >; + }; + + pinctrl_reg_dram_1p1v: reg-dram-1p1vgrp { + fsl,pins = < + MX8MQ_IOMUXC_SD1_STROBE_GPIO2_IO11 0x16 + >; + }; + + pinctrl_reg_soc_gpu_vpu: reg-soc-gpu-vpugrp { + fsl,pins = < + MX8MQ_IOMUXC_SD2_WP_GPIO2_IO20 0x16 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX 0x45 + MX8MQ_IOMUXC_UART1_TXD_UART1_DCE_TX 0x45 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX8MQ_IOMUXC_UART2_RXD_UART2_DCE_RX 0x45 + MX8MQ_IOMUXC_UART2_TXD_UART2_DCE_TX 0x45 + >; + }; + + 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_RESET_B_GPIO2_IO10 0x41 + >; + }; + + pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp { + 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 + >; + }; + + pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp { + 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 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX8MQ_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B 0xc6 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mq-pico-pi.dts b/arch/arm64/boot/dts/freescale/imx8mq-pico-pi.dts new file mode 100644 index 0000000000000000000000000000000000000000..8a4aee2348ee39f1d5e9c3e7563716ba76bf6a31 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mq-pico-pi.dts @@ -0,0 +1,413 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 Wandboard, Org. + * Copyright 2017 NXP + * + * Author: Richard Hu + */ + +/dts-v1/; + +#include "imx8mq.dtsi" + +/ { + model = "TechNexion PICO-PI-8M"; + compatible = "technexion,pico-pi-imx8m", "fsl,imx8mq"; + + chosen { + stdout-path = &uart1; + }; + + pmic_osc: clock-pmic { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + clock-output-names = "pmic_osc"; + }; + + reg_usb_otg_vbus: regulator-usb-otg-vbus { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_otg_vbus>; + compatible = "regulator-fixed"; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio3 14 GPIO_ACTIVE_LOW>; + }; +}; + +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec1 &pinctrl_enet_3v3>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy0>; + fsl,magic-packet; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; + }; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pmic: pmic@4b { + reg = <0x4b>; + compatible = "rohm,bd71837"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pmic>; + clocks = <&pmic_osc>; + clock-names = "osc"; + clock-output-names = "pmic_clk"; + interrupt-parent = <&gpio1>; + interrupts = <3 GPIO_ACTIVE_LOW>; + interrupt-names = "irq"; + + regulators { + buck1: BUCK1 { + regulator-name = "buck1"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + regulator-ramp-delay = <1250>; + rohm,dvs-run-voltage = <900000>; + rohm,dvs-idle-voltage = <850000>; + rohm,dvs-suspend-voltage = <800000>; + }; + + buck2: BUCK2 { + regulator-name = "buck2"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + regulator-ramp-delay = <1250>; + rohm,dvs-run-voltage = <1000000>; + rohm,dvs-idle-voltage = <900000>; + }; + + buck3: BUCK3 { + regulator-name = "buck3"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + rohm,dvs-run-voltage = <1000000>; + }; + + buck4: BUCK4 { + regulator-name = "buck4"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + rohm,dvs-run-voltage = <1000000>; + }; + + buck5: BUCK5 { + regulator-name = "buck5"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1350000>; + regulator-boot-on; + }; + + buck6: BUCK6 { + regulator-name = "buck6"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + + buck7: BUCK7 { + regulator-name = "buck7"; + regulator-min-microvolt = <1605000>; + regulator-max-microvolt = <1995000>; + regulator-boot-on; + }; + + buck8: BUCK8 { + regulator-name = "buck8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + }; + + ldo1: LDO1 { + regulator-name = "ldo1"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo2: LDO2 { + regulator-name = "ldo2"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo3: LDO3 { + regulator-name = "ldo3"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + + ldo4: LDO4 { + regulator-name = "ldo4"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + }; + + ldo5: LDO5 { + regulator-name = "ldo5"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + + ldo6: LDO6 { + regulator-name = "ldo6"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + }; + + ldo7: LDO7 { + regulator-name = "ldo7"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + }; + }; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; +}; + +&uart1 { /* console */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&usdhc1 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc1>; + pinctrl-1 = <&pinctrl_usdhc1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>; + bus-width = <8>; + non-removable; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>; + bus-width = <4>; + cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&usb3_phy0 { + status = "okay"; +}; + +&usb3_phy1 { + status = "okay"; +}; + +&usb_dwc3_1 { + dr_mode = "host"; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; + status = "okay"; +}; + +&iomuxc { + pinctrl_enet_3v3: enet3v3grp { + fsl,pins = < + MX8MQ_IOMUXC_GPIO1_IO00_GPIO1_IO0 0x19 + >; + }; + + 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_IO09_GPIO1_IO9 0x19 + >; + }; + + 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_otg_vbus: otgvbusgrp { + fsl,pins = < + MX8MQ_IOMUXC_NAND_DQS_GPIO3_IO14 0x19 /* USB OTG VBUS Enable */ + >; + }; + + pinctrl_pmic: pmicirq { + fsl,pins = < + MX8MQ_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x41 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX 0x49 + MX8MQ_IOMUXC_UART1_TXD_UART1_DCE_TX 0x49 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX8MQ_IOMUXC_UART2_RXD_UART2_DCE_RX 0x49 + MX8MQ_IOMUXC_UART2_TXD_UART2_DCE_TX 0x49 + MX8MQ_IOMUXC_UART4_RXD_UART2_DCE_CTS_B 0x49 + MX8MQ_IOMUXC_UART4_TXD_UART2_DCE_RTS_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 + >; + }; + + pinctrl_usdhc1_100mhz: usdhc1grp100mhz { + fsl,pins = < + MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK 0x85 + MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD 0xc5 + MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0 0xc5 + MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1 0xc5 + MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2 0xc5 + MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3 0xc5 + MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4 0xc5 + MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5 0xc5 + MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6 0xc5 + MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7 0xc5 + MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE 0x85 + >; + }; + + pinctrl_usdhc1_200mhz: usdhc1grp200mhz { + fsl,pins = < + MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK 0x87 + MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD 0xc7 + MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0 0xc7 + MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1 0xc7 + MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2 0xc7 + MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3 0xc7 + MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4 0xc7 + MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5 0xc7 + MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6 0xc7 + MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7 0xc7 + MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE 0x87 + >; + }; + + pinctrl_usdhc2_gpio: usdhc2grpgpio { + fsl,pins = < + MX8MQ_IOMUXC_SD2_CD_B_GPIO2_IO12 0x41 + >; + }; + + 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: usdhc2grp100mhz { + fsl,pins = < + MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK 0x85 + MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD 0xc5 + MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0 0xc5 + MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1 0xc5 + MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2 0xc5 + MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3 0xc5 + MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xc1 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2grp200mhz { + fsl,pins = < + MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK 0x87 + MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD 0xc7 + MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0 0xc7 + MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1 0xc7 + MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2 0xc7 + MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3 0xc7 + MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xc1 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX8MQ_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B 0xc6 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mq-sr-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mq-sr-som.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d7f03c65832b48bdbaa74f52d71862ebe3d2da88 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mq-sr-som.dtsi @@ -0,0 +1,309 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2018 Jon Nettleton + */ + +#include "imx8mq.dtsi" + +/ { + reg_vdd_3v3: regulator-vdd-3v3 { + compatible = "regulator-fixed"; + regulator-always-on; + regulator-name = "vdd_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; +}; + +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec1>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy0>; + phy-reset-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; + phy-reset-duration = <2>; + fsl,magic-packet; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@4 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <4>; + }; + }; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + clock-frequency = <400000>; + status = "okay"; + + pmic: pmic@8 { + compatible = "fsl,pfuze100"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + }; + + sw1c_reg: sw1c { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + sw3a_reg: sw3ab { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-always-on; + }; + + vgen1_reg: vgen1 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen2_reg: vgen2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + regulator-always-on; + }; + + vgen3_reg: vgen3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen4_reg: vgen4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vgen5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vgen6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + }; + }; +}; + +&pgc_gpu{ + power-supply = <&sw1a_reg>; +}; + +&pgc_vpu { + power-supply = <&sw1c_reg>; +}; + +&qspi0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi>; + status = "okay"; + + /* SPI flash; not assembled by default */ + spi_flash: flash@0 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0>; + compatible = "micron,n25q256a", "jedec,spi-nor"; + spi-max-frequency = <29000000>; + status = "disabled"; + }; +}; + +&uart1 { /* console */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + assigned-clocks = <&clk IMX8MQ_CLK_UART1>; + assigned-clock-parents = <&clk IMX8MQ_CLK_25M>; + assigned-clock-rates = <25000000>; + status = "okay"; +}; + +&uart4 { /* ublox BT */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; + assigned-clocks = <&clk IMX8MQ_CLK_UART4>; + assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_80M>; + assigned-clock-rates = <80000000>; + status = "okay"; +}; + +&usdhc1 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc1>; + pinctrl-1 = <&pinctrl_usdhc1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>; + bus-width = <8>; + non-removable; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; + status = "okay"; +}; + +&iomuxc { + pinctrl_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_IO09_GPIO1_IO9 0x19 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX8MQ_IOMUXC_I2C1_SCL_I2C1_SCL 0x4000007f + MX8MQ_IOMUXC_I2C1_SDA_I2C1_SDA 0x4000007f + >; + }; + + pinctrl_pcie0: pcie0grp { + fsl,pins = < + MX8MQ_IOMUXC_I2C4_SCL_PCIE1_CLKREQ_B 0x74 + MX8MQ_IOMUXC_SPDIF_EXT_CLK_GPIO5_IO5 0x16 + MX8MQ_IOMUXC_SAI2_RXFS_GPIO4_IO21 0x16 + >; + }; + + 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_uart1: uart1grp { + fsl,pins = < + MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX 0x49 + MX8MQ_IOMUXC_UART1_TXD_UART1_DCE_TX 0x49 + MX8MQ_IOMUXC_NAND_CE1_B_GPIO3_IO2 0x19 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX8MQ_IOMUXC_UART4_TXD_UART4_DCE_TX 0x49 + MX8MQ_IOMUXC_UART4_RXD_UART4_DCE_RX 0x49 + MX8MQ_IOMUXC_SAI3_TXD_GPIO5_IO1 0x19 + >; + }; + + 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: usdhc1grp100mhz { + 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: usdhc1grp200mhz { + 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_wdog: wdoggrp { + fsl,pins = < + MX8MQ_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B 0xc6 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mq-zii-ultra.dtsi b/arch/arm64/boot/dts/freescale/imx8mq-zii-ultra.dtsi index 7a1706f969f0950a63c48747c6462eb263264453..af99473ada04377fd32af9304f5eeac8d74b1fba 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq-zii-ultra.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mq-zii-ultra.dtsi @@ -68,18 +68,6 @@ regulator-always-on; }; - reg_5p0_user_usb: regulator-5p0-user-usb { - compatible = "regulator-fixed"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_reg_user_usb>; - vin-supply = <®_5p0_main>; - regulator-name = "5V_USER_USB"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&gpio3 12 GPIO_ACTIVE_LOW>; - startup-delay-us = <1000>; - }; - reg_usdhc2_vmmc: regulator-vsd-3v3 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_reg_usdhc2>; @@ -244,6 +232,13 @@ line-name = "usb-mode1"; }; + usb-pwr { + gpio-hog; + gpios = <12 GPIO_ACTIVE_LOW>; + output-high; + line-name = "usb-pwr-ctrl-en-n"; + }; + usb-mode2 { gpio-hog; gpios = <13 GPIO_ACTIVE_HIGH>; @@ -257,6 +252,17 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c1>; status = "okay"; + + ucs1002: charger@32 { + compatible = "microchip,ucs1002"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ucs1002>; + reg = <0x32>; + interrupt-parent = <&gpio3>; + interrupts = <17 IRQ_TYPE_EDGE_BOTH>, + <18 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "a_det", "alert"; + }; }; &i2c2 { @@ -428,7 +434,7 @@ }; &usb3_phy0 { - vbus-supply = <®_5p0_user_usb>; + vbus-supply = <&ucs1002>; status = "okay"; }; @@ -532,6 +538,7 @@ fsl,pins = < MX8MQ_IOMUXC_NAND_DATA04_GPIO3_IO10 0x6 MX8MQ_IOMUXC_NAND_DATA05_GPIO3_IO11 0x6 + MX8MQ_IOMUXC_NAND_DATA06_GPIO3_IO12 0x6 MX8MQ_IOMUXC_NAND_DATA07_GPIO3_IO13 0x6 >; }; @@ -597,12 +604,6 @@ >; }; - pinctrl_reg_user_usb: reguserusbgrp { - fsl,pins = < - MX8MQ_IOMUXC_NAND_DATA06_GPIO3_IO12 0x6 - >; - }; - pinctrl_switch_irq: switchgrp { fsl,pins = < MX8MQ_IOMUXC_GPIO1_IO15_GPIO1_IO15 0x41 @@ -630,6 +631,13 @@ >; }; + pinctrl_ucs1002: ucs1002grp { + fsl,pins = < + MX8MQ_IOMUXC_NAND_WE_B_GPIO3_IO17 0x41 + MX8MQ_IOMUXC_NAND_WP_B_GPIO3_IO18 0x41 + >; + }; + pinctrl_usbhub: usbhubgrp { fsl,pins = < MX8MQ_IOMUXC_SAI5_MCLK_GPIO3_IO25 0x41 diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi index 52aae341d0da5046e997026a7bbede672b74318b..04115ca6bfb528c40a7f7cf207c57d2377c1a1ba 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi @@ -156,6 +156,7 @@ /* Industrial only */ opp-supported-hw = <0xf>, <0x4>; clock-latency-ns = <150000>; + opp-suspend; }; opp-1000000000 { @@ -164,21 +165,23 @@ /* Consumer only */ opp-supported-hw = <0xe>, <0x3>; clock-latency-ns = <150000>; + opp-suspend; }; opp-1300000000 { opp-hz = /bits/ 64 <1300000000>; opp-microvolt = <1000000>; - opp-supported-hw = <0xc>, <0x7>; + opp-supported-hw = <0xc>, <0x4>; clock-latency-ns = <150000>; + opp-suspend; }; opp-1500000000 { opp-hz = /bits/ 64 <1500000000>; opp-microvolt = <1000000>; - /* Consumer only but rely on speed grading */ - opp-supported-hw = <0x8>, <0x7>; + opp-supported-hw = <0x8>, <0x3>; clock-latency-ns = <150000>; + opp-suspend; }; }; @@ -288,6 +291,7 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 10 30>; }; gpio2: gpio@30210000 { @@ -300,6 +304,7 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 40 21>; }; gpio3: gpio@30220000 { @@ -312,6 +317,7 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 61 26>; }; gpio4: gpio@30230000 { @@ -324,6 +330,7 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 87 32>; }; gpio5: gpio@30240000 { @@ -336,12 +343,14 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 119 30>; }; tmu: tmu@30260000 { compatible = "fsl,imx8mq-tmu"; reg = <0x30260000 0x10000>; interrupt = ; + clocks = <&clk IMX8MQ_CLK_TMU_ROOT>; little-endian; fsl,tmu-range = <0xb0000 0xa0026 0x80048 0x70061>; fsl,tmu-calibration = <0x00000000 0x00000023 @@ -431,8 +440,15 @@ }; iomuxc_gpr: syscon@30340000 { - compatible = "fsl,imx8mq-iomuxc-gpr", "fsl,imx6q-iomuxc-gpr", "syscon"; + compatible = "fsl,imx8mq-iomuxc-gpr", "fsl,imx6q-iomuxc-gpr", + "syscon", "simple-mfd"; reg = <0x30340000 0x10000>; + + mux: mux-controller { + compatible = "mmio-mux"; + #mux-control-cells = <1>; + mux-reg-masks = <0x34 0x00000004>; /* MIPI_MUX_SEL */ + }; }; ocotp: ocotp-ctrl@30350000 { @@ -635,6 +651,14 @@ #pwm-cells = <2>; status = "disabled"; }; + + system_counter: timer@306a0000 { + compatible = "nxp,sysctr-timer"; + reg = <0x306a0000 0x20000>; + interrupts = ; + clocks = <&osc_25m>; + clock-names = "per"; + }; }; bus@30800000 { /* AIPS3 */ @@ -727,6 +751,49 @@ status = "disabled"; }; + crypto: crypto@30900000 { + compatible = "fsl,sec-v4.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x30900000 0x40000>; + ranges = <0 0x30900000 0x40000>; + interrupts = ; + clocks = <&clk IMX8MQ_CLK_AHB>, + <&clk IMX8MQ_CLK_IPG_ROOT>; + clock-names = "aclk", "ipg"; + + sec_jr0: jr@1000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x1000 0x1000>; + interrupts = ; + }; + + sec_jr1: jr@2000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x2000 0x1000>; + interrupts = ; + }; + + sec_jr2: jr@3000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x3000 0x1000>; + interrupts = ; + }; + }; + + dphy: dphy@30a00300 { + compatible = "fsl,imx8mq-mipi-dphy"; + reg = <0x30a00300 0x100>; + clocks = <&clk IMX8MQ_CLK_DSI_PHY_REF>; + clock-names = "phy_ref"; + assigned-clocks = <&clk IMX8MQ_CLK_DSI_PHY_REF>; + assigned-clock-parents = <&clk IMX8MQ_VIDEO_PLL1_OUT>; + assigned-clock-rates = <24000000>; + #phy-cells = <0>; + power-domains = <&pgc_mipi>; + status = "disabled"; + }; + i2c1: i2c@30a20000 { compatible = "fsl,imx8mq-i2c", "fsl,imx21-i2c"; reg = <0x30a20000 0x10000>; @@ -900,9 +967,9 @@ usb_dwc3_0: usb@38100000 { compatible = "fsl,imx8mq-dwc3", "snps,dwc3"; reg = <0x38100000 0x10000>; - clocks = <&clk IMX8MQ_CLK_USB_BUS>, + clocks = <&clk IMX8MQ_CLK_USB1_CTRL_ROOT>, <&clk IMX8MQ_CLK_USB_CORE_REF>, - <&clk IMX8MQ_CLK_USB1_CTRL_ROOT>; + <&clk IMX8MQ_CLK_32K>; clock-names = "bus_early", "ref", "suspend"; assigned-clocks = <&clk IMX8MQ_CLK_USB_BUS>, <&clk IMX8MQ_CLK_USB_CORE_REF>; @@ -932,9 +999,9 @@ usb_dwc3_1: usb@38200000 { compatible = "fsl,imx8mq-dwc3", "snps,dwc3"; reg = <0x38200000 0x10000>; - clocks = <&clk IMX8MQ_CLK_USB_BUS>, + clocks = <&clk IMX8MQ_CLK_USB2_CTRL_ROOT>, <&clk IMX8MQ_CLK_USB_CORE_REF>, - <&clk IMX8MQ_CLK_USB2_CTRL_ROOT>; + <&clk IMX8MQ_CLK_32K>; clock-names = "bus_early", "ref", "suspend"; assigned-clocks = <&clk IMX8MQ_CLK_USB_BUS>, <&clk IMX8MQ_CLK_USB_CORE_REF>; @@ -1032,5 +1099,12 @@ interrupts = ; interrupt-parent = <&gic>; }; + + ddr-pmu@3d800000 { + compatible = "fsl,imx8mq-ddr-pmu", "fsl,imx8m-ddr-pmu"; + reg = <0x3d800000 0x400000>; + interrupt-parent = <&gic>; + interrupts = ; + }; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-ai_ml.dts b/arch/arm64/boot/dts/freescale/imx8qxp-ai_ml.dts new file mode 100644 index 0000000000000000000000000000000000000000..91eef9754101f5d715da1c30cbf173b061954abf --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8qxp-ai_ml.dts @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 Einfochips + * Copyright 2019 Linaro Ltd. + */ + +/dts-v1/; + +#include "imx8qxp.dtsi" + +/ { + model = "Einfochips i.MX8QXP AI_ML"; + compatible = "einfochips,imx8qxp-ai_ml", "fsl,imx8qxp"; + + aliases { + serial1 = &adma_lpuart1; + serial2 = &adma_lpuart2; + serial3 = &adma_lpuart3; + }; + + chosen { + stdout-path = &adma_lpuart2; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x00000000 0x80000000 0 0x80000000>; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_leds>; + + user-led1 { + label = "green:user1"; + gpios = <&lsio_gpio4 16 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + + user-led2 { + label = "green:user2"; + gpios = <&lsio_gpio0 6 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "none"; + }; + + user-led3 { + label = "green:user3"; + gpios = <&lsio_gpio0 7 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc1"; + default-state = "off"; + }; + + user-led4 { + label = "green:user4"; + gpios = <&lsio_gpio4 21 GPIO_ACTIVE_HIGH>; + panic-indicator; + linux,default-trigger = "none"; + }; + + wlan-active-led { + label = "yellow:wlan"; + gpios = <&lsio_gpio4 17 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "phy0tx"; + default-state = "off"; + }; + + bt-active-led { + label = "blue:bt"; + gpios = <&lsio_gpio4 18 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "hci0-power"; + default-state = "off"; + }; + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wifi_reg_on>; + reset-gpios = <&lsio_gpio3 24 GPIO_ACTIVE_LOW>; + }; +}; + +/* BT */ +&adma_lpuart0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lpuart0>; + uart-has-rtscts; + status = "okay"; +}; + +/* LS-UART0 */ +&adma_lpuart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lpuart1>; + status = "okay"; +}; + +/* Debug */ +&adma_lpuart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lpuart2>; + status = "okay"; +}; + +/* PCI-E UART */ +&adma_lpuart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lpuart3>; + 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>; + }; + }; +}; + +/* WiFi */ +&usdhc1 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc1>; + bus-width = <4>; + no-sd; + non-removable; + mmc-pwrseq = <&sdio_pwrseq>; + status = "okay"; + + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; +}; + +/* SD */ +&usdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2>; + bus-width = <4>; + cd-gpios = <&lsio_gpio4 22 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&iomuxc { + pinctrl_fec1: fec1grp { + fsl,pins = < + IMX8QXP_ENET0_MDC_CONN_ENET0_MDC 0x06000020 + IMX8QXP_ENET0_MDIO_CONN_ENET0_MDIO 0x06000020 + IMX8QXP_ENET0_RGMII_TX_CTL_CONN_ENET0_RGMII_TX_CTL 0x06000020 + IMX8QXP_ENET0_RGMII_TXC_CONN_ENET0_RGMII_TXC 0x06000020 + IMX8QXP_ENET0_RGMII_TXD0_CONN_ENET0_RGMII_TXD0 0x06000020 + IMX8QXP_ENET0_RGMII_TXD1_CONN_ENET0_RGMII_TXD1 0x06000020 + IMX8QXP_ENET0_RGMII_TXD2_CONN_ENET0_RGMII_TXD2 0x06000020 + IMX8QXP_ENET0_RGMII_TXD3_CONN_ENET0_RGMII_TXD3 0x06000020 + IMX8QXP_ENET0_RGMII_RXC_CONN_ENET0_RGMII_RXC 0x06000020 + IMX8QXP_ENET0_RGMII_RX_CTL_CONN_ENET0_RGMII_RX_CTL 0x06000020 + IMX8QXP_ENET0_RGMII_RXD0_CONN_ENET0_RGMII_RXD0 0x06000020 + IMX8QXP_ENET0_RGMII_RXD1_CONN_ENET0_RGMII_RXD1 0x06000020 + IMX8QXP_ENET0_RGMII_RXD2_CONN_ENET0_RGMII_RXD2 0x06000020 + IMX8QXP_ENET0_RGMII_RXD3_CONN_ENET0_RGMII_RXD3 0x06000020 + >; + }; + + pinctrl_leds: ledsgrp{ + fsl,pins = < + IMX8QXP_ESAI0_TX2_RX3_LSIO_GPIO0_IO06 0x00000021 + IMX8QXP_ESAI0_TX3_RX2_LSIO_GPIO0_IO07 0x00000021 + IMX8QXP_EMMC0_DATA7_LSIO_GPIO4_IO16 0x00000021 + IMX8QXP_USDHC1_WP_LSIO_GPIO4_IO21 0x00000021 + IMX8QXP_EMMC0_STROBE_LSIO_GPIO4_IO17 0x00000021 + IMX8QXP_EMMC0_RESET_B_LSIO_GPIO4_IO18 0x00000021 + >; + }; + + pinctrl_lpuart0: lpuart0grp { + fsl,pins = < + IMX8QXP_UART0_RX_ADMA_UART0_RX 0X06000020 + IMX8QXP_UART0_TX_ADMA_UART0_TX 0X06000020 + IMX8QXP_FLEXCAN0_TX_ADMA_UART0_CTS_B 0x06000020 + IMX8QXP_FLEXCAN0_RX_ADMA_UART0_RTS_B 0x06000020 + >; + }; + + pinctrl_lpuart1: lpuart1grp { + fsl,pins = < + IMX8QXP_UART1_RX_ADMA_UART1_RX 0X06000020 + IMX8QXP_UART1_TX_ADMA_UART1_TX 0X06000020 + >; + }; + + pinctrl_lpuart2: lpuart2grp { + fsl,pins = < + IMX8QXP_UART2_RX_ADMA_UART2_RX 0X06000020 + IMX8QXP_UART2_TX_ADMA_UART2_TX 0X06000020 + >; + }; + + pinctrl_lpuart3: lpuart3grp { + fsl,pins = < + IMX8QXP_FLEXCAN2_RX_ADMA_UART3_RX 0X06000020 + IMX8QXP_FLEXCAN2_TX_ADMA_UART3_TX 0X06000020 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + IMX8QXP_EMMC0_CLK_CONN_EMMC0_CLK 0x06000041 + IMX8QXP_EMMC0_CMD_CONN_EMMC0_CMD 0x00000021 + IMX8QXP_EMMC0_DATA0_CONN_EMMC0_DATA0 0x00000021 + IMX8QXP_EMMC0_DATA1_CONN_EMMC0_DATA1 0x00000021 + IMX8QXP_EMMC0_DATA2_CONN_EMMC0_DATA2 0x00000021 + IMX8QXP_EMMC0_DATA3_CONN_EMMC0_DATA3 0x00000021 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + IMX8QXP_USDHC1_CLK_CONN_USDHC1_CLK 0x06000041 + IMX8QXP_USDHC1_CMD_CONN_USDHC1_CMD 0x00000021 + IMX8QXP_USDHC1_DATA0_CONN_USDHC1_DATA0 0x00000021 + IMX8QXP_USDHC1_DATA1_CONN_USDHC1_DATA1 0x00000021 + IMX8QXP_USDHC1_DATA2_CONN_USDHC1_DATA2 0x00000021 + IMX8QXP_USDHC1_DATA3_CONN_USDHC1_DATA3 0x00000021 + IMX8QXP_USDHC1_VSELECT_CONN_USDHC1_VSELECT 0x00000021 + IMX8QXP_USDHC1_CD_B_LSIO_GPIO4_IO22 0x00000021 + >; + }; + + pinctrl_wifi_reg_on: wifiregongrp { + fsl,pins = < + IMX8QXP_QSPI0B_SS1_B_LSIO_GPIO3_IO24 0x00000021 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts index bfdada2db176ca07cbb392a67aa55272e6a6d717..19468058e6ae4d409770a2d03b8ecf5dfffb79e0 100644 --- a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts +++ b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts @@ -230,3 +230,7 @@ >; }; }; + +&adma_dsp { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp.dtsi index 05fa0b7f36bb18375a14d8255e4af2c0c02e5296..1133b412182aba7ac3a47b4ea66a7506f41bdc66 100644 --- a/arch/arm64/boot/dts/freescale/imx8qxp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8qxp.dtsi @@ -30,6 +30,9 @@ mmc2 = &usdhc3; mu1 = &lsio_mu1; serial0 = &adma_lpuart0; + serial1 = &adma_lpuart1; + serial2 = &adma_lpuart2; + serial3 = &adma_lpuart3; }; cpus { @@ -113,6 +116,17 @@ interrupts = ; }; + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + dsp_reserved: dsp@92400000 { + reg = <0 0x92400000 0 0x2000000>; + no-map; + }; + }; + pmu { compatible = "arm,armv8-pmuv3"; interrupts = ; @@ -204,13 +218,35 @@ #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 = ; interrupt-parent = <&gic>; - clocks = <&adma_lpcg IMX_ADMA_LPCG_UART0_BAUD_CLK>; - clock-names = "ipg"; + 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"; }; @@ -220,8 +256,9 @@ reg = <0x5a070000 0x1000>; interrupts = ; interrupt-parent = <&gic>; - clocks = <&adma_lpcg IMX_ADMA_LPCG_UART1_BAUD_CLK>; - clock-names = "ipg"; + 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"; }; @@ -231,8 +268,9 @@ reg = <0x5a080000 0x1000>; interrupts = ; interrupt-parent = <&gic>; - clocks = <&adma_lpcg IMX_ADMA_LPCG_UART2_BAUD_CLK>; - clock-names = "ipg"; + 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"; }; @@ -242,8 +280,9 @@ reg = <0x5a090000 0x1000>; interrupts = ; interrupt-parent = <&gic>; - clocks = <&adma_lpcg IMX_ADMA_LPCG_UART3_BAUD_CLK>; - clock-names = "ipg"; + 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"; }; diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi b/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi index e4ceb3a73c81ae4a19d5d4cab574122ad82e740c..36abc25320a81a8860b2ea0c7edb5bf41988d5f4 100644 --- a/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi +++ b/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi @@ -249,6 +249,8 @@ #dma-cells = <1>; #dma-channels = <8>; #dma-requests = <32>; + resets = <&rst DMA_RESET>, <&rst DMA_OCP_RESET>; + reset-names = "dma", "dma-ocp"; }; rst: rstmgr@ffd11000 { diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi index f43c43168b002560435e029dda89ea9013fca55d..7f69e3dfcb13ae85034c5210ad19740ed7d736ca 100644 --- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi @@ -419,6 +419,13 @@ clocks = <&nb_periph_clk 15>; }; + rwtm: mailbox@b0000 { + compatible = "marvell,armada-3700-rwtm-mailbox"; + reg = <0xb0000 0x100>; + interrupts = ; + #mbox-cells = <1>; + }; + sdhci1: sdhci@d0000 { compatible = "marvell,armada-3700-sdhci", "marvell,sdhci-xenon"; diff --git a/arch/arm64/boot/dts/marvell/armada-7040-db.dts b/arch/arm64/boot/dts/marvell/armada-7040-db.dts index f34ee87a0f569e1fecab273a28c01b0ccd1e0b49..a7eb4e7697a25a73c8aea1de38de6c851bdcacbf 100644 --- a/arch/arm64/boot/dts/marvell/armada-7040-db.dts +++ b/arch/arm64/boot/dts/marvell/armada-7040-db.dts @@ -73,16 +73,6 @@ gpio = <&expander0 1 GPIO_ACTIVE_HIGH>; vin-supply = <&cp0_exp_usb3_1_current_regulator>; }; - - cp0_usb3_0_phy: cp0-usb3-0-phy { - compatible = "usb-nop-xceiv"; - vcc-supply = <&cp0_reg_usb3_0_vbus>; - }; - - cp0_usb3_1_phy: cp0-usb3-1-phy { - compatible = "usb-nop-xceiv"; - vcc-supply = <&cp0_reg_usb3_1_vbus>; - }; }; &i2c0 { @@ -124,6 +114,8 @@ &cp0_pcie2 { status = "okay"; + phys = <&cp0_comphy5 2>; + phy-names = "cp0-pcie2-x1-phy"; }; &cp0_i2c0 { @@ -219,15 +211,36 @@ &cp0_sata0 { status = "okay"; + + sata-port@1 { + phys = <&cp0_comphy3 1>; + phy-names = "cp0-sata0-1-phy"; + }; +}; + +&cp0_comphy1 { + cp0_usbh0_con: connector { + compatible = "usb-a-connector"; + phy-supply = <&cp0_reg_usb3_0_vbus>; + }; }; &cp0_usb3_0 { - usb-phy = <&cp0_usb3_0_phy>; + phys = <&cp0_comphy1 0>; + phy-names = "cp0-usb3h0-comphy"; status = "okay"; }; +&cp0_comphy4 { + cp0_usbh1_con: connector { + compatible = "usb-a-connector"; + phy-supply = <&cp0_reg_usb3_1_vbus>; + }; +}; + &cp0_usb3_1 { - usb-phy = <&cp0_usb3_1_phy>; + phys = <&cp0_comphy4 1>; + phy-names = "cp0-usb3h1-comphy"; 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 f275d9420d5be9c68fb003a37b56f9c8270145bb..bd881497b8729c7f6f6b304454dfbb12a91752a3 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 @@ -51,11 +51,6 @@ status = "okay"; }; - usb3h0_phy: usb3_phy0 { - compatible = "usb-nop-xceiv"; - vcc-supply = <&v_5v0_usb3_hst_vbus>; - }; - sfp_cp0_eth0: sfp-cp0-eth0 { compatible = "sff,sfp"; i2c-bus = <&cp0_i2c1>; @@ -243,6 +238,8 @@ pinctrl-names = "default"; pinctrl-0 = <&cp0_pci0_reset_pins &cp0_wlan_disable_pins>; reset-gpios = <&cp0_gpio2 0 GPIO_ACTIVE_LOW>; + phys = <&cp0_comphy0 0>; + phy-names = "cp0-pcie0-x1-phy"; status = "okay"; }; @@ -348,6 +345,11 @@ &cp1_sata0 { pinctrl-0 = <&cp0_pci1_reset_pins>; status = "okay"; + + sata-port@1 { + phys = <&cp1_comphy0 1>; + phy-names = "cp1-sata0-1-phy"; + }; }; &cp1_mdio { @@ -467,7 +469,15 @@ }; }; +&cp1_comphy2 { + cp1_usbh0_con: connector { + compatible = "usb-a-connector"; + phy-supply = <&v_5v0_usb3_hst_vbus>; + }; +}; + &cp1_usb3_0 { - usb-phy = <&usb3h0_phy>; + phys = <&cp1_comphy2 0>; + phy-names = "cp1-usb3h0-comphy"; status = "okay"; }; diff --git a/arch/arm64/boot/dts/marvell/armada-8040-db.dts b/arch/arm64/boot/dts/marvell/armada-8040-db.dts index d6e9c014c2f98a9834fcd93dfc534631e7e39342..09fb5256f1db12ef8dca938b4d3c82322cb2619e 100644 --- a/arch/arm64/boot/dts/marvell/armada-8040-db.dts +++ b/arch/arm64/boot/dts/marvell/armada-8040-db.dts @@ -54,11 +54,6 @@ vcc-supply = <&cp0_reg_usb3_0_vbus>; }; - cp0_usb3_1_phy: cp0-usb3-1-phy { - compatible = "usb-nop-xceiv"; - vcc-supply = <&cp0_reg_usb3_1_vbus>; - }; - cp1_reg_usb3_0_vbus: cp1-usb3-0-vbus { compatible = "regulator-fixed"; regulator-name = "cp1-usb3h0-vbus"; @@ -108,11 +103,15 @@ /* CON6 on CP0 expansion */ &cp0_pcie0 { + phys = <&cp0_comphy0 0>; + phy-names = "cp0-pcie0-x1-phy"; status = "okay"; }; /* CON5 on CP0 expansion */ &cp0_pcie2 { + phys = <&cp0_comphy5 2>; + phy-names = "cp0-pcie2-x1-phy"; status = "okay"; }; @@ -143,6 +142,15 @@ /* CON4 on CP0 expansion */ &cp0_sata0 { status = "okay"; + + sata-port@0 { + phys = <&cp0_comphy1 0>; + phy-names = "cp0-sata0-0-phy"; + }; + sata-port@1 { + phys = <&cp0_comphy3 1>; + phy-names = "cp0-sata0-1-phy"; + }; }; /* CON9 on CP0 expansion */ @@ -151,9 +159,17 @@ status = "okay"; }; +&cp0_comphy4 { + cp0_usbh1_con: connector { + compatible = "usb-a-connector"; + phy-supply = <&cp0_reg_usb3_1_vbus>; + }; +}; + /* CON10 on CP0 expansion */ &cp0_usb3_1 { - usb-phy = <&cp0_usb3_1_phy>; + phys = <&cp0_comphy4 1>; + phy-names = "cp0-usb3h1-comphy"; status = "okay"; }; @@ -187,16 +203,22 @@ /* CON6 on CP1 expansion */ &cp1_pcie0 { + phys = <&cp1_comphy0 0>; + phy-names = "cp1-pcie0-x1-phy"; status = "okay"; }; /* CON7 on CP1 expansion */ &cp1_pcie1 { + phys = <&cp1_comphy4 1>; + phy-names = "cp1-pcie1-x1-phy"; status = "okay"; }; /* CON5 on CP1 expansion */ &cp1_pcie2 { + phys = <&cp1_comphy5 2>; + phy-names = "cp1-pcie2-x1-phy"; status = "okay"; }; @@ -273,6 +295,15 @@ /* CON4 on CP1 expansion */ &cp1_sata0 { status = "okay"; + + sata-port@0 { + phys = <&cp1_comphy1 0>; + phy-names = "cp1-sata0-0-phy"; + }; + sata-port@1 { + phys = <&cp1_comphy3 1>; + phy-names = "cp1-sata0-1-phy"; + }; }; /* CON9 on CP1 expansion */ diff --git a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi index 205071b45a324988ed140c44204850d37a9a4843..d250f4b2bfedbd45662f29b1eb04793a21765985 100644 --- a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi @@ -61,11 +61,6 @@ status = "okay"; }; - usb3h0_phy: usb3_phy0 { - compatible = "usb-nop-xceiv"; - vcc-supply = <&v_5v0_usb3_hst_vbus>; - }; - sfp_eth0: sfp-eth0 { /* CON15,16 - CPM lane 4 */ compatible = "sff,sfp"; @@ -186,6 +181,10 @@ reset-gpios = <&cp0_gpio2 20 GPIO_ACTIVE_LOW>; ranges = <0x81000000 0x0 0xf9010000 0x0 0xf9010000 0x0 0x10000 0x82000000 0x0 0xc0000000 0x0 0xc0000000 0x0 0x20000000>; + phys = <&cp0_comphy0 0>, <&cp0_comphy1 0>, + <&cp0_comphy2 0>, <&cp0_comphy3 0>; + phy-names = "cp0-pcie0-x4-lane0-phy", "cp0-pcie0-x4-lane1-phy", + "cp0-pcie0-x4-lane2-phy", "cp0-pcie0-x4-lane3-phy"; status = "okay"; }; @@ -239,8 +238,13 @@ }; &cp0_sata0 { - /* CPM Lane 0 - U29 */ status = "okay"; + + /* CPM Lane 5 - U29 */ + sata-port@1 { + phys = <&cp0_comphy5 1>; + phy-names = "cp0-sata0-1-phy"; + }; }; &cp0_sdhci0 { @@ -324,9 +328,19 @@ }; &cp1_sata0 { + status = "okay"; + /* CPS Lane 1 - U32 */ + sata-port@0 { + phys = <&cp1_comphy1 0>; + phy-names = "cp1-sata0-0-phy"; + }; + /* CPS Lane 3 - U31 */ - status = "okay"; + sata-port@1 { + phys = <&cp1_comphy3 1>; + phy-names = "cp1-sata0-1-phy"; + }; }; &cp1_spi1 { @@ -341,8 +355,16 @@ }; }; +&cp1_comphy2 { + cp1_usbh0_con: connector { + compatible = "usb-a-connector"; + phy-supply = <&v_5v0_usb3_hst_vbus>; + }; +}; + &cp1_usb3_0 { /* CPS Lane 2 - CON7 */ - usb-phy = <&usb3h0_phy>; + phys = <&cp1_comphy2 0>; + phy-names = "cp1-usb3h0-comphy"; status = "okay"; }; diff --git a/arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi b/arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi index ea13ae78f50d3a3faade97c54825d01d24007794..c25bc65727b5436be752af9d891f84843aab6395 100644 --- a/arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi @@ -21,6 +21,7 @@ reg = <0x000>; enable-method = "psci"; #cooling-cells = <2>; + clocks = <&cpu_clk 0>; }; cpu1: cpu@1 { device_type = "cpu"; @@ -28,6 +29,7 @@ reg = <0x001>; enable-method = "psci"; #cooling-cells = <2>; + clocks = <&cpu_clk 0>; }; cpu2: cpu@100 { device_type = "cpu"; @@ -35,6 +37,7 @@ reg = <0x100>; enable-method = "psci"; #cooling-cells = <2>; + clocks = <&cpu_clk 1>; }; cpu3: cpu@101 { device_type = "cpu"; @@ -42,7 +45,7 @@ reg = <0x101>; enable-method = "psci"; #cooling-cells = <2>; + clocks = <&cpu_clk 1>; }; }; - }; diff --git a/arch/arm64/boot/dts/marvell/armada-ap806.dtsi b/arch/arm64/boot/dts/marvell/armada-ap806.dtsi index 96228f93b2722af71107247c87dd7eefa6958c22..d06dd198f2c7864f19a7f8921a985f7a31aae696 100644 --- a/arch/arm64/boot/dts/marvell/armada-ap806.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-ap806.dtsi @@ -280,6 +280,13 @@ #address-cells = <1>; #size-cells = <1>; + cpu_clk: clock-cpu@278 { + compatible = "marvell,ap806-cpu-clock"; + clocks = <&ap_clk 0>, <&ap_clk 1>; + #clock-cells = <1>; + reg = <0x278 0xa30>; + }; + ap_thermal: thermal-sensor@80 { compatible = "marvell,armada-ap806-thermal"; reg = <0x80 0x10>; diff --git a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi index f71afb1de18f88a5373756e60c16622a2c825e3f..d81944902650257ded56789c052e783179e606a0 100644 --- a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi @@ -133,6 +133,9 @@ compatible = "marvell,comphy-cp110"; reg = <0x120000 0x6000>; marvell,system-controller = <&CP110_LABEL(syscon0)>; + clocks = <&CP110_LABEL(clk) 1 5>, <&CP110_LABEL(clk) 1 6>, + <&CP110_LABEL(clk) 1 18>; + clock-names = "mg_clk", "mg_core_clk", "axi_clk"; #address-cells = <1>; #size-cells = <0>; @@ -306,7 +309,17 @@ interrupts = <107 IRQ_TYPE_LEVEL_HIGH>; clocks = <&CP110_LABEL(clk) 1 15>, <&CP110_LABEL(clk) 1 16>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; + + sata-port@0 { + reg = <0>; + }; + + sata-port@1 { + reg = <1>; + }; }; CP110_LABEL(xor0): xor@6a0000 { diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts index 710c5c3d87d30ef7dcb1657bb2081883f8b04aa0..83e10591e0e5d9ba633c18ca6631a18047f75e97 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts @@ -115,24 +115,34 @@ }; ð { - pinctrl-names = "default"; - pinctrl-0 = <ð_pins>; status = "okay"; + gmac0: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-mode = "2500base-x"; + + fixed-link { + speed = <2500>; + full-duplex; + pause; + }; + }; gmac1: mac@1 { compatible = "mediatek,eth-mac"; reg = <1>; - phy-handle = <&phy5>; + phy-mode = "rgmii"; + + fixed-link { + speed = <1000>; + full-duplex; + pause; + }; }; - mdio-bus { + mdio: mdio-bus { #address-cells = <1>; #size-cells = <0>; - - phy5: ethernet-phy@5 { - reg = <5>; - phy-mode = "sgmii"; - }; }; }; diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi index d1e13d340e26756eef87e6cf0f9e85d809c27b10..dac51e98204c0352b404e7dd723d7e32ac043734 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi @@ -931,6 +931,5 @@ "syscon"; reg = <0 0x1b128000 0 0x3000>; #clock-cells = <1>; - mediatek,physpeed = "2500"; }; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-evb.dts b/arch/arm64/boot/dts/mediatek/mt8183-evb.dts index d8e555cbb5d3a458ffdf9110fe8e7b942e883698..1fb195c683c3d019280b624ccb7918ed5d210f34 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-evb.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-evb.dts @@ -30,7 +30,103 @@ 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 = <1000000>; +}; + +&i2c5 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins_5>; + status = "okay"; + clock-frequency = <1000000>; +}; + &pio { + i2c_pins_0: i2c0{ + pins_i2c{ + pinmux = , + ; + mediatek,pull-up-adv = <3>; + mediatek,drive-strength-adv = <00>; + }; + }; + + i2c_pins_1: i2c1{ + pins_i2c{ + pinmux = , + ; + mediatek,pull-up-adv = <3>; + mediatek,drive-strength-adv = <00>; + }; + }; + + i2c_pins_2: i2c2{ + pins_i2c{ + pinmux = , + ; + mediatek,pull-up-adv = <3>; + mediatek,drive-strength-adv = <00>; + }; + }; + + i2c_pins_3: i2c3{ + pins_i2c{ + pinmux = , + ; + mediatek,pull-up-adv = <3>; + mediatek,drive-strength-adv = <00>; + }; + }; + + i2c_pins_4: i2c4{ + pins_i2c{ + pinmux = , + ; + mediatek,pull-up-adv = <3>; + mediatek,drive-strength-adv = <00>; + }; + }; + + i2c_pins_5: i2c5{ + pins_i2c{ + pinmux = , + ; + mediatek,pull-up-adv = <3>; + mediatek,drive-strength-adv = <00>; + }; + }; + spi_pins_0: spi0{ pins_spi{ pinmux = , diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi index c2749c4631bcd9e91950388a71e17f2808c1fab9..97f84aa9fc6e1c193455f0e74af373d220aea68f 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi @@ -16,6 +16,21 @@ #address-cells = <2>; #size-cells = <2>; + aliases { + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; + i2c4 = &i2c4; + i2c5 = &i2c5; + i2c6 = &i2c6; + i2c7 = &i2c7; + i2c8 = &i2c8; + i2c9 = &i2c9; + i2c10 = &i2c10; + i2c11 = &i2c11; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -248,7 +263,7 @@ compatible = "mediatek,mt8183-pwrap"; reg = <0 0x1000d000 0 0x1000>; reg-names = "pwrap"; - interrupts = ; + interrupts = ; clocks = <&topckgen CLK_TOP_MUX_PMICSPI>, <&infracfg CLK_INFRA_PMIC_AP>; clock-names = "spi", "wrap"; @@ -294,6 +309,64 @@ status = "disabled"; }; + i2c6: i2c@11005000 { + compatible = "mediatek,mt8183-i2c"; + reg = <0 0x11005000 0 0x1000>, + <0 0x11000600 0 0x80>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_I2C6>, + <&infracfg CLK_INFRA_AP_DMA>; + clock-names = "main", "dma"; + clock-div = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c0: i2c@11007000 { + compatible = "mediatek,mt8183-i2c"; + reg = <0 0x11007000 0 0x1000>, + <0 0x11000080 0 0x80>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_I2C0>, + <&infracfg CLK_INFRA_AP_DMA>; + clock-names = "main", "dma"; + clock-div = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c4: i2c@11008000 { + compatible = "mediatek,mt8183-i2c"; + reg = <0 0x11008000 0 0x1000>, + <0 0x11000100 0 0x80>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_I2C1>, + <&infracfg CLK_INFRA_AP_DMA>, + <&infracfg CLK_INFRA_I2C1_ARBITER>; + clock-names = "main", "dma","arb"; + clock-div = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@11009000 { + compatible = "mediatek,mt8183-i2c"; + reg = <0 0x11009000 0 0x1000>, + <0 0x11000280 0 0x80>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_I2C2>, + <&infracfg CLK_INFRA_AP_DMA>, + <&infracfg CLK_INFRA_I2C2_ARBITER>; + clock-names = "main", "dma", "arb"; + clock-div = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + spi0: spi@1100a000 { compatible = "mediatek,mt8183-spi"; #address-cells = <1>; @@ -307,6 +380,20 @@ status = "disabled"; }; + i2c3: i2c@1100f000 { + compatible = "mediatek,mt8183-i2c"; + reg = <0 0x1100f000 0 0x1000>, + <0 0x11000400 0 0x80>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_I2C3>, + <&infracfg CLK_INFRA_AP_DMA>; + clock-names = "main", "dma"; + clock-div = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + spi1: spi@11010000 { compatible = "mediatek,mt8183-spi"; #address-cells = <1>; @@ -320,6 +407,20 @@ status = "disabled"; }; + i2c1: i2c@11011000 { + compatible = "mediatek,mt8183-i2c"; + reg = <0 0x11011000 0 0x1000>, + <0 0x11000480 0 0x80>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_I2C4>, + <&infracfg CLK_INFRA_AP_DMA>; + clock-names = "main", "dma"; + clock-div = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + spi2: spi@11012000 { compatible = "mediatek,mt8183-spi"; #address-cells = <1>; @@ -346,6 +447,66 @@ status = "disabled"; }; + i2c9: i2c@11014000 { + compatible = "mediatek,mt8183-i2c"; + reg = <0 0x11014000 0 0x1000>, + <0 0x11000180 0 0x80>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_I2C1_IMM>, + <&infracfg CLK_INFRA_AP_DMA>, + <&infracfg CLK_INFRA_I2C1_ARBITER>; + clock-names = "main", "dma", "arb"; + clock-div = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c10: i2c@11015000 { + compatible = "mediatek,mt8183-i2c"; + reg = <0 0x11015000 0 0x1000>, + <0 0x11000300 0 0x80>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_I2C2_IMM>, + <&infracfg CLK_INFRA_AP_DMA>, + <&infracfg CLK_INFRA_I2C2_ARBITER>; + clock-names = "main", "dma", "arb"; + clock-div = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c5: i2c@11016000 { + compatible = "mediatek,mt8183-i2c"; + reg = <0 0x11016000 0 0x1000>, + <0 0x11000500 0 0x80>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_I2C5>, + <&infracfg CLK_INFRA_AP_DMA>, + <&infracfg CLK_INFRA_I2C5_ARBITER>; + clock-names = "main", "dma", "arb"; + clock-div = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c11: i2c@11017000 { + compatible = "mediatek,mt8183-i2c"; + reg = <0 0x11017000 0 0x1000>, + <0 0x11000580 0 0x80>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_I2C5_IMM>, + <&infracfg CLK_INFRA_AP_DMA>, + <&infracfg CLK_INFRA_I2C5_ARBITER>; + clock-names = "main", "dma", "arb"; + clock-div = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + spi4: spi@11018000 { compatible = "mediatek,mt8183-spi"; #address-cells = <1>; @@ -372,6 +533,34 @@ status = "disabled"; }; + i2c7: i2c@1101a000 { + compatible = "mediatek,mt8183-i2c"; + reg = <0 0x1101a000 0 0x1000>, + <0 0x11000680 0 0x80>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_I2C7>, + <&infracfg CLK_INFRA_AP_DMA>; + clock-names = "main", "dma"; + clock-div = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c8: i2c@1101b000 { + compatible = "mediatek,mt8183-i2c"; + reg = <0 0x1101b000 0 0x1000>, + <0 0x11000700 0 0x80>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_I2C8>, + <&infracfg CLK_INFRA_AP_DMA>; + clock-names = "main", "dma"; + clock-div = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + audiosys: syscon@11220000 { compatible = "mediatek,mt8183-audiosys", "syscon"; reg = <0 0x11220000 0 0x1000>; diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 0a7e5dfce6f793a7c9c6665dcac5245588a0c672..6498a1ec893f4792c073862e5f0a7b1932fd4dd5 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -3,14 +3,22 @@ dtb-$(CONFIG_ARCH_QCOM) += apq8016-sbc.dtb dtb-$(CONFIG_ARCH_QCOM) += apq8096-db820c.dtb dtb-$(CONFIG_ARCH_QCOM) += ipq8074-hk01.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-mtp.dtb +dtb-$(CONFIG_ARCH_QCOM) += msm8916-longcheer-l8150.dtb +dtb-$(CONFIG_ARCH_QCOM) += msm8916-samsung-a3u-eur.dtb +dtb-$(CONFIG_ARCH_QCOM) += msm8916-samsung-a5u-eur.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8992-bullhead-rev-101.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8994-angler-rev-101.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8996-mtp.dtb +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) += sdm845-cheza-r1.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm845-cheza-r2.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm845-cheza-r3.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm845-db845c.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm845-mtp.dtb +dtb-$(CONFIG_ARCH_QCOM) += sdm850-lenovo-yoga-c630.dtb +dtb-$(CONFIG_ARCH_QCOM) += sm8150-mtp.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-1000.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-4000.dtb diff --git a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts new file mode 100644 index 0000000000000000000000000000000000000000..2b28e383fd0bddadd4590f510ce6841b6885b9c4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/dts-v1/; + +#include "msm8916.dtsi" +#include "pm8916.dtsi" +#include + +/ { + model = "Longcheer L8150"; + compatible = "longcheer,l8150", "qcom,msm8916-v1-qrd/9-v1", "qcom,msm8916"; + + aliases { + serial0 = &blsp1_uart2; + }; + + chosen { + stdout-path = "serial0"; + }; + + soc { + sdhci@7824000 { + status = "okay"; + + vmmc-supply = <&pm8916_l8>; + vqmmc-supply = <&pm8916_l5>; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>; + }; + + sdhci@7864000 { + status = "okay"; + + vmmc-supply = <&pm8916_l11>; + vqmmc-supply = <&pm8916_l12>; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + + non-removable; + }; + + serial@78b0000 { + status = "okay"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&blsp1_uart2_default>; + pinctrl-1 = <&blsp1_uart2_sleep>; + }; + + usb@78d9000 { + status = "okay"; + dr_mode = "peripheral"; + extcon = <&usb_vbus>; + + hnp-disable; + srp-disable; + adp-disable; + + ulpi { + phy { + extcon = <&usb_vbus>; + v1p8-supply = <&pm8916_l7>; + v3p3-supply = <&pm8916_l13>; + }; + }; + }; + + /* + * Attempting to enable these devices causes a "synchronous + * external abort". Suspected cause is that the debug power + * domain is not enabled by default on this device. + * Disable these devices for now to avoid the crash. + * + * See: https://lore.kernel.org/linux-arm-msm/20190618202623.GA53651@gerhold.net/ + */ + tpiu@820000 { status = "disabled"; }; + funnel@821000 { status = "disabled"; }; + replicator@824000 { status = "disabled"; }; + etf@825000 { status = "disabled"; }; + etr@826000 { status = "disabled"; }; + funnel@841000 { status = "disabled"; }; + debug@850000 { status = "disabled"; }; + debug@852000 { status = "disabled"; }; + debug@854000 { status = "disabled"; }; + debug@856000 { status = "disabled"; }; + etm@85c000 { status = "disabled"; }; + etm@85d000 { status = "disabled"; }; + etm@85e000 { status = "disabled"; }; + etm@85f000 { status = "disabled"; }; + }; + + // FIXME: Use extcon device provided by charger driver when available + usb_vbus: usb-vbus { + compatible = "linux,extcon-usb-gpio"; + vbus-gpio = <&msmgpio 62 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_vbus_default>; + }; +}; + +&msmgpio { + usb_vbus_default: usb-vbus-default { + pinmux { + function = "gpio"; + pins = "gpio62"; + }; + pinconf { + pins = "gpio62"; + bias-pull-up; + }; + }; +}; + +&smd_rpm_regulators { + vdd_l1_l2_l3-supply = <&pm8916_s3>; + vdd_l4_l5_l6-supply = <&pm8916_s4>; + vdd_l7-supply = <&pm8916_s4>; + + s1 { + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1300000>; + }; + + s3 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1300000>; + }; + + s4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2100000>; + }; + + l1 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + }; + + l2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + l3 { + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1287500>; + }; + + l4 { + regulator-min-microvolt = <2050000>; + regulator-max-microvolt = <2050000>; + }; + + l5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + l6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + l7 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + l8 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2900000>; + }; + + l9 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + l10 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2800000>; + }; + + l11 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + regulator-allow-set-load; + regulator-system-load = <200000>; + }; + + l12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + }; + + l13 { + regulator-min-microvolt = <3075000>; + regulator-max-microvolt = <3075000>; + }; + + l14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + l15 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + l16 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + l17 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + }; + + l18 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2700000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e675ff48fdd24e3ba76bf273492618501bcbdf62 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include "msm8916.dtsi" +#include "pm8916.dtsi" +#include +#include + +/ { + aliases { + serial0 = &blsp1_uart2; + }; + + chosen { + stdout-path = "serial0"; + }; + + soc { + sdhci@7824000 { + status = "okay"; + + vmmc-supply = <&pm8916_l8>; + vqmmc-supply = <&pm8916_l5>; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>; + }; + + sdhci@7864000 { + status = "okay"; + + vmmc-supply = <&pm8916_l11>; + vqmmc-supply = <&pm8916_l12>; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&msmgpio 38 GPIO_ACTIVE_LOW>; + }; + + serial@78b0000 { + status = "okay"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&blsp1_uart2_default>; + pinctrl-1 = <&blsp1_uart2_sleep>; + }; + + usb@78d9000 { + status = "okay"; + extcon = <&muic>, <&muic>; + + hnp-disable; + srp-disable; + adp-disable; + + ulpi { + phy { + extcon = <&muic>; + v1p8-supply = <&pm8916_l7>; + v3p3-supply = <&pm8916_l13>; + }; + }; + }; + + /* + * Attempting to enable these devices causes a "synchronous + * external abort". Suspected cause is that the debug power + * domain is not enabled by default on this device. + * Disable these devices for now to avoid the crash. + * + * See: https://lore.kernel.org/linux-arm-msm/20190618202623.GA53651@gerhold.net/ + */ + tpiu@820000 { status = "disabled"; }; + funnel@821000 { status = "disabled"; }; + replicator@824000 { status = "disabled"; }; + etf@825000 { status = "disabled"; }; + etr@826000 { status = "disabled"; }; + funnel@841000 { status = "disabled"; }; + debug@850000 { status = "disabled"; }; + debug@852000 { status = "disabled"; }; + debug@854000 { status = "disabled"; }; + debug@856000 { status = "disabled"; }; + etm@85c000 { status = "disabled"; }; + etm@85d000 { status = "disabled"; }; + etm@85e000 { status = "disabled"; }; + etm@85f000 { status = "disabled"; }; + }; + + i2c-muic { + compatible = "i2c-gpio"; + sda-gpios = <&msmgpio 105 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + scl-gpios = <&msmgpio 106 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + + #address-cells = <1>; + #size-cells = <0>; + + muic: sm5502@25 { + compatible = "siliconmitus,sm5502-muic"; + + reg = <0x25>; + interrupt-parent = <&msmgpio>; + interrupts = <12 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-names = "default"; + pinctrl-0 = <&muic_int_default>; + }; + }; +}; + +&msmgpio { + muic_int_default: muic_int_default { + pinmux { + function = "gpio"; + pins = "gpio12"; + }; + pinconf { + pins = "gpio12"; + drive-strength = <2>; + bias-disable; + }; + }; +}; + +&smd_rpm_regulators { + vdd_l1_l2_l3-supply = <&pm8916_s3>; + vdd_l4_l5_l6-supply = <&pm8916_s4>; + vdd_l7-supply = <&pm8916_s4>; + + s1 { + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1300000>; + }; + + s3 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1300000>; + }; + + s4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2100000>; + }; + + l1 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + }; + + l2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + l3 { + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1287500>; + }; + + l4 { + regulator-min-microvolt = <2050000>; + regulator-max-microvolt = <2050000>; + }; + + l5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + l6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + l7 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + l8 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2900000>; + }; + + l9 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + l10 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2800000>; + }; + + l11 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + regulator-allow-set-load; + regulator-system-load = <200000>; + }; + + l12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + }; + + l13 { + regulator-min-microvolt = <3075000>; + regulator-max-microvolt = <3075000>; + }; + + l14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + l15 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + l16 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + l17 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + }; + + l18 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2700000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts new file mode 100644 index 0000000000000000000000000000000000000000..d10f7ac5089f2cd12bc1d2d8c34e1f71797faa7d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/dts-v1/; + +#include "msm8916-samsung-a2015-common.dtsi" + +/ { + model = "Samsung Galaxy A3U (EUR)"; + compatible = "samsung,a3u-eur", "qcom,msm8916"; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts new file mode 100644 index 0000000000000000000000000000000000000000..1aa59da9849553217406041558231e8a590fecb6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/dts-v1/; + +#include "msm8916-samsung-a2015-common.dtsi" + +/ { + model = "Samsung Galaxy A5U (EUR)"; + compatible = "samsung,a5u-eur", "qcom,msm8916"; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi index 96c0a481f454eaeea74536dccec9f65f7aa73c03..87f4d9c1b0d4c92f25550b8b95edfbd2afa36f73 100644 --- a/arch/arm64/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi @@ -633,6 +633,474 @@ reg = <0x300000 0x90000>; }; + stm@3002000 { + compatible = "arm,coresight-stm", "arm,primecell"; + reg = <0x3002000 0x1000>, + <0x8280000 0x180000>; + reg-names = "stm-base", "stm-stimulus-base"; + + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + out-ports { + port { + stm_out: endpoint { + remote-endpoint = + <&funnel0_in>; + }; + }; + }; + }; + + tpiu@3020000 { + compatible = "arm,coresight-tpiu", "arm,primecell"; + reg = <0x3020000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + in-ports { + port { + tpiu_in: endpoint { + remote-endpoint = + <&replicator_out1>; + }; + }; + }; + }; + + funnel@3021000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x3021000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@7 { + reg = <7>; + funnel0_in: endpoint { + remote-endpoint = + <&stm_out>; + }; + }; + }; + + out-ports { + port { + funnel0_out: endpoint { + remote-endpoint = + <&merge_funnel_in0>; + }; + }; + }; + }; + + funnel@3022000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x3022000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@6 { + reg = <6>; + funnel1_in: endpoint { + remote-endpoint = + <&apss_merge_funnel_out>; + }; + }; + }; + + out-ports { + port { + funnel1_out: endpoint { + remote-endpoint = + <&merge_funnel_in1>; + }; + }; + }; + }; + + funnel@3023000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x3023000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + + out-ports { + port { + funnel2_out: endpoint { + remote-endpoint = + <&merge_funnel_in2>; + }; + }; + }; + }; + + funnel@3025000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x3025000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + 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>; + }; + }; + + port@2 { + reg = <2>; + merge_funnel_in2: endpoint { + remote-endpoint = + <&funnel2_out>; + }; + }; + }; + + out-ports { + port { + merge_funnel_out: endpoint { + remote-endpoint = + <&etf_in>; + }; + }; + }; + }; + + replicator@3026000 { + compatible = "arm,coresight-dynamic-replicator", "arm,primecell"; + reg = <0x3026000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + in-ports { + port { + replicator_in: endpoint { + remote-endpoint = + <&etf_out>; + }; + }; + }; + + out-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + replicator_out0: endpoint { + remote-endpoint = + <&etr_in>; + }; + }; + + port@1 { + reg = <1>; + replicator_out1: endpoint { + remote-endpoint = + <&tpiu_in>; + }; + }; + }; + }; + + etf@3027000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x3027000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + in-ports { + port { + etf_in: endpoint { + remote-endpoint = + <&merge_funnel_out>; + }; + }; + }; + + out-ports { + port { + etf_out: endpoint { + remote-endpoint = + <&replicator_in>; + }; + }; + }; + }; + + etr@3028000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x3028000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + arm,scatter-gather; + + in-ports { + port { + etr_in: endpoint { + remote-endpoint = + <&replicator_out0>; + }; + }; + }; + }; + + debug@3810000 { + compatible = "arm,coresight-cpu-debug", "arm,primecell"; + reg = <0x3810000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>; + clock-names = "apb_pclk"; + + cpu = <&CPU0>; + }; + + etm@3840000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0x3840000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + cpu = <&CPU0>; + + out-ports { + port { + etm0_out: endpoint { + remote-endpoint = + <&apss_funnel0_in0>; + }; + }; + }; + }; + + debug@3910000 { + compatible = "arm,coresight-cpu-debug", "arm,primecell"; + reg = <0x3910000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>; + clock-names = "apb_pclk"; + + cpu = <&CPU1>; + }; + + etm@3940000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0x3940000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + cpu = <&CPU1>; + + out-ports { + port { + etm1_out: endpoint { + remote-endpoint = + <&apss_funnel0_in1>; + }; + }; + }; + }; + + funnel@39b0000 { /* APSS Funnel 0 */ + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x39b0000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + apss_funnel0_in0: endpoint { + remote-endpoint = <&etm0_out>; + }; + }; + + port@1 { + reg = <1>; + apss_funnel0_in1: endpoint { + remote-endpoint = <&etm1_out>; + }; + }; + }; + + out-ports { + port { + apss_funnel0_out: endpoint { + remote-endpoint = + <&apss_merge_funnel_in0>; + }; + }; + }; + }; + + debug@3a10000 { + compatible = "arm,coresight-cpu-debug", "arm,primecell"; + reg = <0x3a10000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>; + clock-names = "apb_pclk"; + + cpu = <&CPU2>; + }; + + etm@3a40000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0x3a40000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + cpu = <&CPU2>; + + out-ports { + port { + etm2_out: endpoint { + remote-endpoint = + <&apss_funnel1_in0>; + }; + }; + }; + }; + + debug@3b10000 { + compatible = "arm,coresight-cpu-debug", "arm,primecell"; + reg = <0x3b10000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>; + clock-names = "apb_pclk"; + + cpu = <&CPU3>; + }; + + etm@3b40000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0x3b40000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + cpu = <&CPU3>; + + out-ports { + port { + etm3_out: endpoint { + remote-endpoint = + <&apss_funnel1_in1>; + }; + }; + }; + }; + + funnel@3bb0000 { /* APSS Funnel 1 */ + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x3bb0000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + apss_funnel1_in0: endpoint { + remote-endpoint = <&etm2_out>; + }; + }; + + port@1 { + reg = <1>; + apss_funnel1_in1: endpoint { + remote-endpoint = <&etm3_out>; + }; + }; + }; + + out-ports { + port { + apss_funnel1_out: endpoint { + remote-endpoint = + <&apss_merge_funnel_in1>; + }; + }; + }; + }; + + funnel@3bc0000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x3bc0000 0x1000>; + + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + apss_merge_funnel_in0: endpoint { + remote-endpoint = + <&apss_funnel0_out>; + }; + }; + + port@1 { + reg = <1>; + apss_merge_funnel_in1: endpoint { + remote-endpoint = + <&apss_funnel1_out>; + }; + }; + }; + + out-ports { + port { + apss_merge_funnel_out: endpoint { + remote-endpoint = + <&funnel1_in>; + }; + }; + }; + }; + kryocc: clock-controller@6400000 { compatible = "qcom,apcc-msm8996"; reg = <0x6400000 0x90000>; @@ -1163,7 +1631,7 @@ }; }; - vfe_smmu: arm,smmu@da0000 { + vfe_smmu: iommu@da0000 { compatible = "qcom,msm8996-smmu-v2", "qcom,smmu-v2"; reg = <0xda0000 0x10000>; @@ -1314,7 +1782,7 @@ }; }; - adreno_smmu: arm,smmu@b40000 { + adreno_smmu: iommu@b40000 { compatible = "qcom,msm8996-smmu-v2", "qcom,smmu-v2"; reg = <0xb40000 0x10000>; @@ -1331,7 +1799,7 @@ power-domains = <&mmcc GPU_GDSC>; }; - mdp_smmu: arm,smmu@d00000 { + mdp_smmu: iommu@d00000 { compatible = "qcom,msm8996-smmu-v2", "qcom,smmu-v2"; reg = <0xd00000 0x10000>; @@ -1347,7 +1815,7 @@ power-domains = <&mmcc MDSS_GDSC>; }; - lpass_q6_smmu: arm,smmu-lpass_q6@1600000 { + lpass_q6_smmu: iommu@1600000 { compatible = "qcom,msm8996-smmu-v2", "qcom,smmu-v2"; reg = <0x1600000 0x20000>; #iommu-cells = <1>; @@ -1794,6 +2262,74 @@ "ref"; }; }; + + venus_smmu: arm,smmu-venus@d40000 { + compatible = "qcom,msm8996-smmu-v2", "qcom,smmu-v2"; + reg = <0xd40000 0x20000>; + #global-interrupts = <1>; + interrupts = , + , + , + , + , + , + , + ; + power-domains = <&mmcc MMAGIC_VIDEO_GDSC>; + clocks = <&mmcc SMMU_VIDEO_AHB_CLK>, + <&mmcc SMMU_VIDEO_AXI_CLK>; + clock-names = "iface", "bus"; + #iommu-cells = <1>; + status = "okay"; + }; + + video-codec@c00000 { + compatible = "qcom,msm8996-venus"; + reg = <0x00c00000 0xff000>; + interrupts = ; + power-domains = <&mmcc VENUS_GDSC>; + clocks = <&mmcc VIDEO_CORE_CLK>, + <&mmcc VIDEO_AHB_CLK>, + <&mmcc VIDEO_AXI_CLK>, + <&mmcc VIDEO_MAXI_CLK>; + clock-names = "core", "iface", "bus", "mbus"; + iommus = <&venus_smmu 0x00>, + <&venus_smmu 0x01>, + <&venus_smmu 0x0a>, + <&venus_smmu 0x07>, + <&venus_smmu 0x0e>, + <&venus_smmu 0x0f>, + <&venus_smmu 0x08>, + <&venus_smmu 0x09>, + <&venus_smmu 0x0b>, + <&venus_smmu 0x0c>, + <&venus_smmu 0x0d>, + <&venus_smmu 0x10>, + <&venus_smmu 0x11>, + <&venus_smmu 0x21>, + <&venus_smmu 0x28>, + <&venus_smmu 0x29>, + <&venus_smmu 0x2b>, + <&venus_smmu 0x2c>, + <&venus_smmu 0x2d>, + <&venus_smmu 0x31>; + memory-region = <&venus_region>; + status = "okay"; + + video-decoder { + compatible = "venus-decoder"; + clocks = <&mmcc VIDEO_SUBCORE0_CLK>; + clock-names = "core"; + power-domains = <&mmcc VENUS_CORE0_GDSC>; + }; + + video-encoder { + compatible = "venus-encoder"; + clocks = <&mmcc VIDEO_SUBCORE1_CLK>; + clock-names = "core"; + power-domains = <&mmcc VENUS_CORE1_GDSC>; + }; + }; }; sound: sound { diff --git a/arch/arm64/boot/dts/qcom/msm8998-asus-novago-tp370ql.dts b/arch/arm64/boot/dts/qcom/msm8998-asus-novago-tp370ql.dts new file mode 100644 index 0000000000000000000000000000000000000000..db5821be1e2fe75c431e79ecb31e858f154be4cc --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8998-asus-novago-tp370ql.dts @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019, Jeffrey Hugo. All rights reserved. */ + +/dts-v1/; + +#include "msm8998-clamshell.dtsi" + +/ { + model = "Asus NovaGo TP370QL"; + compatible = "asus,novago-tp370ql", "qcom,msm8998"; +}; + +&blsp1_i2c6 { + status = "okay"; + + touchpad@15 { + compatible = "hid-over-i2c"; + interrupt-parent = <&tlmm>; + interrupts = <0x7b IRQ_TYPE_LEVEL_LOW>; + reg = <0x15>; + hid-descr-addr = <0x0001>; + + pinctrl-names = "default"; + pinctrl-0 = <&touchpad>; + }; + + keyboard@3a { + compatible = "hid-over-i2c"; + interrupt-parent = <&tlmm>; + interrupts = <0x25 IRQ_TYPE_LEVEL_LOW>; + reg = <0x3a>; + hid-descr-addr = <0x0001>; + }; +}; + +&sdhc2 { + cd-gpios = <&tlmm 95 GPIO_ACTIVE_HIGH>; +}; + +&tlmm { + touchpad: touchpad { + config { + pins = "gpio123"; + bias-pull-up; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi b/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9682d4dd7496e56c695f4988856db04bce296ba3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019, Jeffrey Hugo. All rights reserved. */ + +/* + * Common include for MSM8998 clamshell devices, ie the Lenovo Miix 630, + * Asus NovaGo TP370QL, and HP Envy x2. All three devices are basically the + * same, with differences in peripherals. + */ + +#include "msm8998.dtsi" +#include "pm8998.dtsi" +#include "pm8005.dtsi" + +/ { + chosen { + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-always-on; + regulator-boot-on; + }; +}; + +&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 = <&vph_pwr>; + vdd_l10_l23_l25-supply = <&vph_pwr>; + vdd_l13_l19_l21-supply = <&vph_pwr>; + vdd_l16_l28-supply = <&vph_pwr>; + vdd_l18_l22-supply = <&vph_pwr>; + vdd_l20_l24-supply = <&vph_pwr>; + 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>; + regulator-allow-set-load; + }; + vreg_l2a_1p2: l2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-allow-set-load; + }; + 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_15a_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>; + }; + vreg_l28_3p0: l28 { + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3008000>; + }; + + vreg_lvs1a_1p8: lvs1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + vreg_lvs2a_1p8: lvs2 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + }; +}; + +&tlmm { + gpio-reserved-ranges = <0 4>, <81 4>; + + touchpad: touchpad { + config { + pins = "gpio123"; + bias-pull-up; /* pull up */ + }; + }; +}; + +&sdhc2 { + status = "okay"; + + vmmc-supply = <&vreg_l21a_2p95>; + vqmmc-supply = <&vreg_l13a_2p95>; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; +}; + +&usb3 { + status = "okay"; +}; + +&usb3_dwc3 { + dr_mode = "host"; /* Force to host until we have Type-C hooked up */ +}; + +&usb3phy { + status = "okay"; + + vdda-phy-supply = <&vreg_l1a_0p875>; + vdda-pll-supply = <&vreg_l2a_1p2>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8998-hp-envy-x2.dts b/arch/arm64/boot/dts/qcom/msm8998-hp-envy-x2.dts new file mode 100644 index 0000000000000000000000000000000000000000..24073127091f6b7549de8f286330d938b850c9b7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8998-hp-envy-x2.dts @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019, Jeffrey Hugo. All rights reserved. */ + +/dts-v1/; + +#include "msm8998-clamshell.dtsi" + +/ { + model = "HP Envy x2"; + compatible = "hp,envy-x2", "qcom,msm8998"; +}; + +&blsp1_i2c6 { + status = "okay"; + + keyboard@3a { + compatible = "hid-over-i2c"; + interrupt-parent = <&tlmm>; + interrupts = <0x79 IRQ_TYPE_LEVEL_LOW>; + reg = <0x3a>; + hid-descr-addr = <0x0001>; + + pinctrl-names = "default"; + pinctrl-0 = <&touchpad>; + }; +}; + +&sdhc2 { + cd-gpios = <&tlmm 95 GPIO_ACTIVE_LOW>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts b/arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts new file mode 100644 index 0000000000000000000000000000000000000000..407c6a32911cce009da32a6dadae2bed365e597d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019, Jeffrey Hugo. All rights reserved. */ + +/dts-v1/; + +#include "msm8998-clamshell.dtsi" + +/ { + model = "Lenovo Miix 630"; + compatible = "lenovo,miix-630", "qcom,msm8998"; +}; + +&blsp1_i2c6 { + status = "okay"; + + keyboard@3a { + compatible = "hid-over-i2c"; + interrupt-parent = <&tlmm>; + interrupts = <0x79 IRQ_TYPE_LEVEL_LOW>; + reg = <0x3a>; + hid-descr-addr = <0x0001>; + + pinctrl-names = "default"; + pinctrl-0 = <&touchpad>; + }; +}; + +&sdhc2 { + cd-gpios = <&tlmm 95 GPIO_ACTIVE_HIGH>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi index c13ed7aeb1e0cfd313773c81ffd8b8d34fdea5e1..c6f81431983eea7480f450658630e90a084a82ba 100644 --- a/arch/arm64/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi @@ -787,14 +787,22 @@ ranges = <0 0 0 0xffffffff>; compatible = "simple-bus"; - rpm_msg_ram: memory@68000 { + gcc: clock-controller@100000 { + compatible = "qcom,gcc-msm8998"; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + reg = <0x00100000 0xb0000>; + }; + + rpm_msg_ram: memory@778000 { compatible = "qcom,rpm-msg-ram"; - reg = <0x778000 0x7000>; + reg = <0x00778000 0x7000>; }; qfprom: qfprom@780000 { compatible = "qcom,qfprom"; - reg = <0x780000 0x621c>; + reg = <0x00780000 0x621c>; #address-cells = <1>; #size-cells = <1>; @@ -804,47 +812,10 @@ }; }; - gcc: clock-controller@100000 { - compatible = "qcom,gcc-msm8998"; - #clock-cells = <1>; - #reset-cells = <1>; - #power-domain-cells = <1>; - reg = <0x100000 0xb0000>; - }; - - tlmm: pinctrl@3400000 { - compatible = "qcom,msm8998-pinctrl"; - reg = <0x3400000 0xc00000>; - interrupts = ; - gpio-controller; - #gpio-cells = <0x2>; - interrupt-controller; - #interrupt-cells = <0x2>; - }; - - spmi_bus: spmi@800f000 { - compatible = "qcom,spmi-pmic-arb"; - reg = <0x800f000 0x1000>, - <0x8400000 0x1000000>, - <0x9400000 0x1000000>, - <0xa400000 0x220000>, - <0x800a000 0x3000>; - reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; - interrupt-names = "periph_irq"; - interrupts = ; - qcom,ee = <0>; - qcom,channel = <0>; - #address-cells = <2>; - #size-cells = <0>; - interrupt-controller; - #interrupt-cells = <4>; - cell-index = <0>; - }; - tsens0: thermal@10ab000 { compatible = "qcom,msm8998-tsens", "qcom,tsens-v2"; - reg = <0x10ab000 0x1000>, /* TM */ - <0x10aa000 0x1000>; /* SROT */ + reg = <0x010ab000 0x1000>, /* TM */ + <0x010aa000 0x1000>; /* SROT */ #qcom,sensors = <14>; #thermal-sensor-cells = <1>; @@ -852,8 +823,8 @@ tsens1: thermal@10ae000 { compatible = "qcom,msm8998-tsens", "qcom,tsens-v2"; - reg = <0x10ae000 0x1000>, /* TM */ - <0x10ad000 0x1000>; /* SROT */ + reg = <0x010ae000 0x1000>, /* TM */ + <0x010ad000 0x1000>; /* SROT */ #qcom,sensors = <8>; #thermal-sensor-cells = <1>; @@ -943,16 +914,542 @@ }; }; + ufshc: ufshc@1da4000 { + compatible = "qcom,msm8998-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; + reg = <0x01da4000 0x2500>; + interrupts = ; + phys = <&ufsphy_lanes>; + phy-names = "ufsphy"; + lanes-per-direction = <2>; + power-domains = <&gcc UFS_GDSC>; + #reset-cells = <1>; + + clock-names = + "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 = + <&gcc GCC_UFS_AXI_CLK>, + <&gcc GCC_AGGRE1_UFS_AXI_CLK>, + <&gcc GCC_UFS_AHB_CLK>, + <&gcc GCC_UFS_UNIPRO_CORE_CLK>, + <&rpmcc RPM_SMD_LN_BB_CLK1>, + <&gcc GCC_UFS_TX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_RX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_RX_SYMBOL_1_CLK>; + freq-table-hz = + <50000000 200000000>, + <0 0>, + <0 0>, + <37500000 150000000>, + <0 0>, + <0 0>, + <0 0>, + <0 0>; + + resets = <&gcc GCC_UFS_BCR>; + reset-names = "rst"; + }; + + ufsphy: phy@1da7000 { + compatible = "qcom,msm8998-qmp-ufs-phy"; + reg = <0x01da7000 0x18c>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + clock-names = + "ref", + "ref_aux"; + clocks = + <&gcc GCC_UFS_CLKREF_CLK>, + <&gcc GCC_UFS_PHY_AUX_CLK>; + + reset-names = "ufsphy"; + resets = <&ufshc 0>; + + ufsphy_lanes: lanes@1da7400 { + reg = <0x01da7400 0x128>, + <0x01da7600 0x1fc>, + <0x01da7c00 0x1dc>, + <0x01da7800 0x128>, + <0x01da7a00 0x1fc>; + #phy-cells = <0>; + }; + }; + tcsr_mutex_regs: syscon@1f40000 { compatible = "syscon"; - reg = <0x1f40000 0x20000>; + reg = <0x01f40000 0x20000>; }; - apcs_glb: mailbox@9820000 { - compatible = "qcom,msm8998-apcs-hmss-global"; - reg = <0x17911000 0x1000>; + tlmm: pinctrl@3400000 { + compatible = "qcom,msm8998-pinctrl"; + reg = <0x03400000 0xc00000>; + interrupts = ; + gpio-controller; + #gpio-cells = <0x2>; + interrupt-controller; + #interrupt-cells = <0x2>; + }; - #mbox-cells = <1>; + stm@6002000 { + compatible = "arm,coresight-stm", "arm,primecell"; + reg = <0x06002000 0x1000>, + <0x16280000 0x180000>; + reg-names = "stm-base", "stm-data-base"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + out-ports { + port { + stm_out: endpoint { + remote-endpoint = <&funnel0_in7>; + }; + }; + }; + }; + + funnel@6041000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x06041000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + 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 = <0x06042000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + out-ports { + port { + funnel1_out: endpoint { + remote-endpoint = + <&merge_funnel_in1>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@6 { + reg = <6>; + funnel1_in6: endpoint { + remote-endpoint = + <&apss_merge_funnel_out>; + }; + }; + }; + }; + + funnel@6045000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x06045000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + out-ports { + port { + merge_funnel_out: endpoint { + remote-endpoint = + <&etf_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 = <0x06046000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + out-ports { + port { + replicator_out: endpoint { + remote-endpoint = <&etr_in>; + }; + }; + }; + + in-ports { + port { + replicator_in: endpoint { + remote-endpoint = <&etf_out>; + }; + }; + }; + }; + + etf@6047000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x06047000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + out-ports { + port { + etf_out: endpoint { + remote-endpoint = + <&replicator_in>; + }; + }; + }; + + in-ports { + port { + etf_in: endpoint { + remote-endpoint = + <&merge_funnel_out>; + }; + }; + }; + }; + + etr@6048000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x06048000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + arm,scatter-gather; + + in-ports { + port { + etr_in: endpoint { + remote-endpoint = + <&replicator_out>; + }; + }; + }; + }; + + etm@7840000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0x07840000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + cpu = <&CPU0>; + + out-ports { + port { + etm0_out: endpoint { + remote-endpoint = + <&apss_funnel_in0>; + }; + }; + }; + }; + + etm@7940000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0x07940000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + cpu = <&CPU1>; + + out-ports { + port { + etm1_out: endpoint { + remote-endpoint = + <&apss_funnel_in1>; + }; + }; + }; + }; + + etm@7a40000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0x07a40000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + cpu = <&CPU2>; + + out-ports { + port { + etm2_out: endpoint { + remote-endpoint = + <&apss_funnel_in2>; + }; + }; + }; + }; + + etm@7b40000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0x07b40000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + cpu = <&CPU3>; + + out-ports { + port { + etm3_out: endpoint { + remote-endpoint = + <&apss_funnel_in3>; + }; + }; + }; + }; + + funnel@7b60000 { /* APSS Funnel */ + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0x07b60000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + 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@7b70000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x07b70000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + out-ports { + port { + apss_merge_funnel_out: endpoint { + remote-endpoint = + <&funnel1_in6>; + }; + }; + }; + + in-ports { + port { + apss_merge_funnel_in: endpoint { + remote-endpoint = + <&apss_funnel_out>; + }; + }; + }; + }; + + etm@7c40000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0x07c40000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + cpu = <&CPU4>; + + port{ + etm4_out: endpoint { + remote-endpoint = <&apss_funnel_in4>; + }; + }; + }; + + etm@7d40000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0x07d40000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + cpu = <&CPU5>; + + port{ + etm5_out: endpoint { + remote-endpoint = <&apss_funnel_in5>; + }; + }; + }; + + etm@7e40000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0x07e40000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + cpu = <&CPU6>; + + port{ + etm6_out: endpoint { + remote-endpoint = <&apss_funnel_in6>; + }; + }; + }; + + etm@7f40000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0x07f40000 0x1000>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + + cpu = <&CPU7>; + + port{ + etm7_out: endpoint { + remote-endpoint = <&apss_funnel_in7>; + }; + }; + }; + + spmi_bus: spmi@800f000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0x0800f000 0x1000>, + <0x08400000 0x1000000>, + <0x09400000 0x1000000>, + <0x0a400000 0x220000>, + <0x0800a000 0x3000>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupt-names = "periph_irq"; + interrupts = ; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + cell-index = <0>; }; usb3: usb@a8f8800 { @@ -1044,7 +1541,7 @@ sdhc2: sdhci@c0a4900 { compatible = "qcom,sdhci-msm-v4"; - reg = <0xc0a4900 0x314>, <0xc0a4000 0x800>; + reg = <0x0c0a4900 0x314>, <0x0c0a4000 0x800>; reg-names = "hc_mem", "core_mem"; interrupts = , @@ -1149,6 +1646,16 @@ #size-cells = <0>; }; + blsp2_uart1: serial@c1b0000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0x0c1b0000 0x1000>; + interrupts = ; + clocks = <&gcc GCC_BLSP2_UART2_APPS_CLK>, + <&gcc GCC_BLSP2_AHB_CLK>; + clock-names = "core", "iface"; + status = "disabled"; + }; + blsp2_i2c0: i2c@c1b5000 { compatible = "qcom,i2c-qup-v2.2.1"; reg = <0x0c1b5000 0x600>; @@ -1239,14 +1746,11 @@ #size-cells = <0>; }; - blsp2_uart1: serial@c1b0000 { - compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; - reg = <0xc1b0000 0x1000>; - interrupts = ; - clocks = <&gcc GCC_BLSP2_UART2_APPS_CLK>, - <&gcc GCC_BLSP2_AHB_CLK>; - clock-names = "core", "iface"; - status = "disabled"; + apcs_glb: mailbox@17911000 { + compatible = "qcom,msm8998-apcs-hmss-global"; + reg = <0x17911000 0x1000>; + + #mbox-cells = <1>; }; timer@17920000 { @@ -1320,75 +1824,6 @@ redistributor-stride = <0x0 0x20000>; interrupts = ; }; - - ufshc: ufshc@1da4000 { - compatible = "qcom,msm8998-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; - reg = <0x01da4000 0x2500>; - interrupts = ; - phys = <&ufsphy_lanes>; - phy-names = "ufsphy"; - lanes-per-direction = <2>; - power-domains = <&gcc UFS_GDSC>; - #reset-cells = <1>; - - clock-names = - "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 = - <&gcc GCC_UFS_AXI_CLK>, - <&gcc GCC_AGGRE1_UFS_AXI_CLK>, - <&gcc GCC_UFS_AHB_CLK>, - <&gcc GCC_UFS_UNIPRO_CORE_CLK>, - <&rpmcc RPM_SMD_LN_BB_CLK1>, - <&gcc GCC_UFS_TX_SYMBOL_0_CLK>, - <&gcc GCC_UFS_RX_SYMBOL_0_CLK>, - <&gcc GCC_UFS_RX_SYMBOL_1_CLK>; - freq-table-hz = - <50000000 200000000>, - <0 0>, - <0 0>, - <37500000 150000000>, - <0 0>, - <0 0>, - <0 0>, - <0 0>; - - resets = <&gcc GCC_UFS_BCR>; - reset-names = "rst"; - }; - - ufsphy: phy@1da7000 { - compatible = "qcom,msm8998-qmp-ufs-phy"; - reg = <0x01da7000 0x18c>; - #address-cells = <1>; - #size-cells = <1>; - ranges; - - clock-names = - "ref", - "ref_aux"; - clocks = - <&gcc GCC_UFS_CLKREF_CLK>, - <&gcc GCC_UFS_PHY_AUX_CLK>; - - reset-names = "ufsphy"; - resets = <&ufshc 0>; - - ufsphy_lanes: lanes@1da7400 { - reg = <0x01da7400 0x128>, - <0x01da7600 0x1fc>, - <0x01da7c00 0x1dc>, - <0x01da7800 0x128>, - <0x01da7a00 0x1fc>; - #phy-cells = <0>; - }; - }; }; }; diff --git a/arch/arm64/boot/dts/qcom/pm8150.dtsi b/arch/arm64/boot/dts/qcom/pm8150.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b6e304748a5760a9e2d9c6a29799111f36bfbd42 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm8150.dtsi @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019, Linaro Limited + */ + +#include +#include +#include +#include + +&spmi_bus { + pm8150_0: pmic@0 { + compatible = "qcom,pm8150", "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pon: power-on@800 { + compatible = "qcom,pm8916-pon"; + reg = <0x0800>; + pwrkey { + compatible = "qcom,pm8941-pwrkey"; + interrupts = <0x0 0x8 0x0 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + linux,code = ; + + status = "disabled"; + }; + }; + + pm8150_adc: adc@3100 { + compatible = "qcom,spmi-adc5"; + reg = <0x3100>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + + status = "disabled"; + + ref-gnd@0 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "ref_gnd"; + }; + + vref-1p25@1 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "vref_1p25"; + }; + + die-temp@6 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "die_temp"; + }; + }; + + 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 { + compatible = "qcom,pm8150-gpio"; + reg = <0xc000>; + gpio-controller; + #gpio-cells = <2>; + interrupts = <0x0 0xc0 0x0 IRQ_TYPE_NONE>, + <0x0 0xc1 0x0 IRQ_TYPE_NONE>, + <0x0 0xc2 0x0 IRQ_TYPE_NONE>, + <0x0 0xc3 0x0 IRQ_TYPE_NONE>, + <0x0 0xc4 0x0 IRQ_TYPE_NONE>, + <0x0 0xc5 0x0 IRQ_TYPE_NONE>, + <0x0 0xc6 0x0 IRQ_TYPE_NONE>, + <0x0 0xc7 0x0 IRQ_TYPE_NONE>, + <0x0 0xc8 0x0 IRQ_TYPE_NONE>, + <0x0 0xc9 0x0 IRQ_TYPE_NONE>, + <0x0 0xca 0x0 IRQ_TYPE_NONE>, + <0x0 0xcb 0x0 IRQ_TYPE_NONE>; + }; + }; + + pmic@1 { + compatible = "qcom,pm8150", "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8150b.dtsi b/arch/arm64/boot/dts/qcom/pm8150b.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..322379d5c31f9e3c2b0149692c53846d1c22bb0a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm8150b.dtsi @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019, Linaro Limited + */ + +#include +#include +#include + +&spmi_bus { + pmic@2 { + compatible = "qcom,pm8150b", "qcom,spmi-pmic"; + reg = <0x2 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + power-on@800 { + compatible = "qcom,pm8916-pon"; + reg = <0x0800>; + + status = "disabled"; + }; + + adc@3100 { + compatible = "qcom,spmi-adc5"; + reg = <0x3100>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + interrupts = <0x2 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + + status = "disabled"; + + ref-gnd@0 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "ref_gnd"; + }; + + vref-1p25@1 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "vref_1p25"; + }; + + die-temp@6 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "die_temp"; + }; + + chg-temp@9 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "chg_temp"; + }; + }; + + pm8150b_gpios: gpio@c000 { + compatible = "qcom,pm8150b-gpio"; + reg = <0xc000>; + gpio-controller; + #gpio-cells = <2>; + interrupts = <0x2 0xc0 0x0 IRQ_TYPE_NONE>, + <0x2 0xc1 0x0 IRQ_TYPE_NONE>, + <0x2 0xc2 0x0 IRQ_TYPE_NONE>, + <0x2 0xc3 0x0 IRQ_TYPE_NONE>, + <0x2 0xc4 0x0 IRQ_TYPE_NONE>, + <0x2 0xc5 0x0 IRQ_TYPE_NONE>, + <0x2 0xc6 0x0 IRQ_TYPE_NONE>, + <0x2 0xc7 0x0 IRQ_TYPE_NONE>, + <0x2 0xc8 0x0 IRQ_TYPE_NONE>, + <0x2 0xc9 0x0 IRQ_TYPE_NONE>, + <0x2 0xca 0x0 IRQ_TYPE_NONE>, + <0x2 0xcb 0x0 IRQ_TYPE_NONE>; + }; + }; + + pmic@3 { + compatible = "qcom,pm8150b", "qcom,spmi-pmic"; + reg = <0x3 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8150l.dtsi b/arch/arm64/boot/dts/qcom/pm8150l.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..eb0e9a090e42067878aca6c282ebcc447b3de6d8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm8150l.dtsi @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019, Linaro Limited + */ + +#include +#include +#include + +&spmi_bus { + pmic@4 { + compatible = "qcom,pm8150l", "qcom,spmi-pmic"; + reg = <0x4 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + power-on@800 { + compatible = "qcom,pm8916-pon"; + reg = <0x0800>; + + status = "disabled"; + }; + + adc@3100 { + compatible = "qcom,spmi-adc5"; + reg = <0x3100>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + interrupts = <0x4 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + + status = "disabled"; + + ref-gnd@0 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "ref_gnd"; + }; + + vref-1p25@1 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "vref_1p25"; + }; + + die-temp@6 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "die_temp"; + }; + }; + + pm8150l_gpios: gpio@c000 { + compatible = "qcom,pm8150l-gpio"; + reg = <0xc000>; + gpio-controller; + #gpio-cells = <2>; + interrupts = <0x4 0xc0 0x0 IRQ_TYPE_NONE>, + <0x4 0xc1 0x0 IRQ_TYPE_NONE>, + <0x4 0xc2 0x0 IRQ_TYPE_NONE>, + <0x4 0xc3 0x0 IRQ_TYPE_NONE>, + <0x4 0xc4 0x0 IRQ_TYPE_NONE>, + <0x4 0xc5 0x0 IRQ_TYPE_NONE>, + <0x4 0xc6 0x0 IRQ_TYPE_NONE>, + <0x4 0xc7 0x0 IRQ_TYPE_NONE>, + <0x4 0xc8 0x0 IRQ_TYPE_NONE>, + <0x4 0xc9 0x0 IRQ_TYPE_NONE>, + <0x4 0xca 0x0 IRQ_TYPE_NONE>, + <0x4 0xcb 0x0 IRQ_TYPE_NONE>; + }; + }; + + pmic@5 { + compatible = "qcom,pm8150l", "qcom,spmi-pmic"; + reg = <0x5 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8998.dtsi b/arch/arm64/boot/dts/qcom/pm8998.dtsi index 051a52df80f9eb2e0e0bedfc9e62b38fba557cb9..dc2ce23cde0545be93f0e7dd9dded52d3c528772 100644 --- a/arch/arm64/boot/dts/qcom/pm8998.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8998.dtsi @@ -78,7 +78,7 @@ #size-cells = <0>; #io-channel-cells = <1>; - adc-chan@ADC5_DIE_TEMP { + adc-chan@6 { reg = ; label = "die_temp"; }; diff --git a/arch/arm64/boot/dts/qcom/pms405.dtsi b/arch/arm64/boot/dts/qcom/pms405.dtsi index 14240fedd916c7a000f2c08cbf366d96a719c5ec..ff40051868951e4adfc100e5c7b465305b138c9e 100644 --- a/arch/arm64/boot/dts/qcom/pms405.dtsi +++ b/arch/arm64/boot/dts/qcom/pms405.dtsi @@ -88,41 +88,41 @@ #size-cells = <0>; #io-channel-cells = <1>; - ref_gnd { + ref_gnd@0 { reg = ; qcom,pre-scaling = <1 1>; }; - vref_1p25 { + vref_1p25@1 { reg = ; qcom,pre-scaling = <1 1>; }; - pon_1: vph_pwr { + pon_1: vph_pwr@131 { reg = ; qcom,pre-scaling = <1 3>; }; - die_temp { + die_temp@6 { reg = ; qcom,pre-scaling = <1 1>; }; - pa_therm1: thermistor1 { + pa_therm1: thermistor1@77 { reg = ; qcom,ratiometric; qcom,hw-settle-time = <200>; qcom,pre-scaling = <1 1>; }; - pa_therm3: thermistor3 { + pa_therm3: thermistor3@79 { reg = ; qcom,ratiometric; qcom,hw-settle-time = <200>; qcom,pre-scaling = <1 1>; }; - xo_therm: xo_temp { + xo_therm: xo_temp@76 { reg = ; qcom,ratiometric; qcom,hw-settle-time = <200>; @@ -141,8 +141,6 @@ pms405_1: pms405@1 { compatible = "qcom,spmi-pmic"; reg = <0x1 SPMI_USID>; - #address-cells = <1>; - #size-cells = <0>; pms405_spmi_regulators: regulators { compatible = "qcom,pms405-regulators"; diff --git a/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi b/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi index 11c0a7137823dab9257d8d90841a25851dee8b44..501a7330dbc882f3ef11ac0af512d631b0a5fd58 100644 --- a/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi @@ -61,7 +61,9 @@ protected-clocks = , , , - ; + , + <141>, /* GCC_WCSS_Q6_AHB_CLK */ + <142>; /* GCC_WCSS_Q6_AXIM_CLK */ }; &pms405_spmi_regulators { @@ -270,6 +272,9 @@ &wifi { status = "okay"; + vdd-0.8-cx-mx-supply = <&vreg_l2_1p275>; + vdd-1.8-xo-supply = <&vreg_l5_1p8>; + vdd-1.3-rfa-supply = <&vreg_l1_1p3>; }; /* PINCTRL - additions to nodes defined in qcs404.dtsi */ diff --git a/arch/arm64/boot/dts/qcom/qcs404.dtsi b/arch/arm64/boot/dts/qcom/qcs404.dtsi index 3d0789775009c1d88ea639fe0cbca26d7d2cfa1d..a97eeb4569c00dcfc57aa588727881d9936003ae 100644 --- a/arch/arm64/boot/dts/qcom/qcs404.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs404.dtsi @@ -111,8 +111,13 @@ #size-cells = <2>; ranges; - memory@85600000 { - reg = <0 0x85600000 0 0x90000>; + tz_apps_mem: memory@85900000 { + reg = <0 0x85900000 0 0x500000>; + no-map; + }; + + xbl_mem: memory@85e00000 { + reg = <0 0x85e00000 0 0x100000>; no-map; }; @@ -121,28 +126,33 @@ no-map; }; - memory@86100000 { + tz_mem: memory@86100000 { reg = <0 0x86100000 0 0x300000>; no-map; }; wlan_fw_mem: memory@86400000 { - reg = <0 0x86400000 0 0x1c00000>; + reg = <0 0x86400000 0 0x1100000>; + no-map; + }; + + adsp_fw_mem: memory@87500000 { + reg = <0 0x87500000 0 0x1a00000>; no-map; }; - adsp_fw_mem: memory@88000000 { - reg = <0 0x88000000 0 0x1a00000>; + cdsp_fw_mem: memory@88f00000 { + reg = <0 0x88f00000 0 0x600000>; no-map; }; - cdsp_fw_mem: memory@89a00000 { - reg = <0 0x89a00000 0 0x600000>; + wlan_msa_mem: memory@89500000 { + reg = <0 0x89500000 0 0x100000>; no-map; }; - wlan_msa_mem: memory@8a000000 { - reg = <0 0x8a000000 0 0x100000>; + uefi_mem: memory@9f800000 { + reg = <0 0x9f800000 0 0x800000>; no-map; }; }; @@ -1077,7 +1087,7 @@ thermal-sensors = <&tsens 0>; trips { - aoss_alert0: trip-point@0 { + aoss_alert0: trip-point0 { temperature = <105000>; hysteresis = <2000>; type = "hot"; @@ -1092,7 +1102,7 @@ thermal-sensors = <&tsens 1>; trips { - q6_hvx_alert0: trip-point@0 { + q6_hvx_alert0: trip-point0 { temperature = <105000>; hysteresis = <2000>; type = "hot"; @@ -1107,7 +1117,7 @@ thermal-sensors = <&tsens 2>; trips { - lpass_alert0: trip-point@0 { + lpass_alert0: trip-point0 { temperature = <105000>; hysteresis = <2000>; type = "hot"; @@ -1122,7 +1132,7 @@ thermal-sensors = <&tsens 3>; trips { - wlan_alert0: trip-point@0 { + wlan_alert0: trip-point0 { temperature = <105000>; hysteresis = <2000>; type = "hot"; @@ -1137,12 +1147,12 @@ thermal-sensors = <&tsens 4>; trips { - cluster_alert0: trip-point@0 { + cluster_alert0: trip-point0 { temperature = <95000>; hysteresis = <2000>; type = "hot"; }; - cluster_alert1: trip-point@1 { + cluster_alert1: trip-point1 { temperature = <105000>; hysteresis = <2000>; type = "passive"; @@ -1171,12 +1181,12 @@ thermal-sensors = <&tsens 5>; trips { - cpu0_alert0: trip-point@0 { + cpu0_alert0: trip-point0 { temperature = <95000>; hysteresis = <2000>; type = "hot"; }; - cpu0_alert1: trip-point@1 { + cpu0_alert1: trip-point1 { temperature = <105000>; hysteresis = <2000>; type = "passive"; @@ -1205,12 +1215,12 @@ thermal-sensors = <&tsens 6>; trips { - cpu1_alert0: trip-point@0 { + cpu1_alert0: trip-point0 { temperature = <95000>; hysteresis = <2000>; type = "hot"; }; - cpu1_alert1: trip-point@1 { + cpu1_alert1: trip-point1 { temperature = <105000>; hysteresis = <2000>; type = "passive"; @@ -1239,12 +1249,12 @@ thermal-sensors = <&tsens 7>; trips { - cpu2_alert0: trip-point@0 { + cpu2_alert0: trip-point0 { temperature = <95000>; hysteresis = <2000>; type = "hot"; }; - cpu2_alert1: trip-point@1 { + cpu2_alert1: trip-point1 { temperature = <105000>; hysteresis = <2000>; type = "passive"; @@ -1273,12 +1283,12 @@ thermal-sensors = <&tsens 8>; trips { - cpu3_alert0: trip-point@0 { + cpu3_alert0: trip-point0 { temperature = <95000>; hysteresis = <2000>; type = "hot"; }; - cpu3_alert1: trip-point@1 { + cpu3_alert1: trip-point1 { temperature = <105000>; hysteresis = <2000>; type = "passive"; @@ -1307,7 +1317,7 @@ thermal-sensors = <&tsens 9>; trips { - gpu_alert0: trip-point@0 { + gpu_alert0: trip-point0 { temperature = <95000>; hysteresis = <2000>; type = "hot"; diff --git a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi index 1ebbd568dfd72cab82400ef69d73b2b8921e0935..34881c0113cb6dded141ea3de1f8d68b0e237bba 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi @@ -745,7 +745,7 @@ ap_ts_i2c: &i2c14 { * All the hardware muxes would allow us to hook things up in different * ways to some potential benefit for static configurations (you could * achieve extra USB2 bandwidth by using two different ports for the - * two conenctors or possibly even get USB3 peripheral mode), but in + * two connectors or possibly even get USB3 peripheral mode), but in * each case you end up forcing to disconnect/reconnect an in-use * USB session in some cases depending on what you hotplug into the * other connector. Thus hardcoding this as peripheral makes sense. @@ -963,27 +963,27 @@ ap_ts_i2c: &i2c14 { }; &pm8998_adc { - adc-chan@ADC5_AMUX_THM1_100K_PU { + adc-chan@4d { reg = ; label = "sdm_temp"; }; - adc-chan@ADC5_AMUX_THM2_100K_PU { + adc-chan@4e { reg = ; label = "quiet_temp"; }; - adc-chan@ADC5_AMUX_THM3_100K_PU { + adc-chan@4f { reg = ; label = "lte_temp_1"; }; - adc-chan@ADC5_AMUX_THM4_100K_PU { + adc-chan@50 { reg = ; label = "lte_temp_2"; }; - adc-chan@ADC5_AMUX_THM5_100K_PU { + adc-chan@51 { reg = ; label = "charger_temp"; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 4babff5f19b5c35b3a6ad8a85adbc2dc4345ce66..f406a4340b05e716003005830489d800f18f088d 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -194,6 +194,7 @@ &LITTLE_CPU_SLEEP_1 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <607>; + dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; next-level-cache = <&L2_0>; @@ -215,6 +216,7 @@ &LITTLE_CPU_SLEEP_1 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <607>; + dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; next-level-cache = <&L2_100>; @@ -233,6 +235,7 @@ &LITTLE_CPU_SLEEP_1 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <607>; + dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; next-level-cache = <&L2_200>; @@ -251,6 +254,7 @@ &LITTLE_CPU_SLEEP_1 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <607>; + dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; next-level-cache = <&L2_300>; @@ -269,6 +273,7 @@ cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1 &CLUSTER_SLEEP_0>; + dynamic-power-coefficient = <396>; qcom,freq-domain = <&cpufreq_hw 1>; #cooling-cells = <2>; next-level-cache = <&L2_400>; @@ -287,6 +292,7 @@ cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1 &CLUSTER_SLEEP_0>; + dynamic-power-coefficient = <396>; qcom,freq-domain = <&cpufreq_hw 1>; #cooling-cells = <2>; next-level-cache = <&L2_500>; @@ -305,6 +311,7 @@ cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1 &CLUSTER_SLEEP_0>; + dynamic-power-coefficient = <396>; qcom,freq-domain = <&cpufreq_hw 1>; #cooling-cells = <2>; next-level-cache = <&L2_600>; @@ -323,6 +330,7 @@ cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1 &CLUSTER_SLEEP_0>; + dynamic-power-coefficient = <396>; qcom,freq-domain = <&cpufreq_hw 1>; #cooling-cells = <2>; next-level-cache = <&L2_700>; @@ -483,6 +491,25 @@ label = "lpass"; qcom,remote-pid = <2>; mboxes = <&apss_shared 8>; + fastrpc { + compatible = "qcom,fastrpc"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + label = "adsp"; + #address-cells = <1>; + #size-cells = <0>; + + compute-cb@3 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <3>; + iommus = <&apps_smmu 0x1823 0x0>; + }; + + compute-cb@4 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <4>; + iommus = <&apps_smmu 0x1824 0x0>; + }; + }; }; }; @@ -512,6 +539,61 @@ label = "turing"; qcom,remote-pid = <5>; mboxes = <&apss_shared 4>; + fastrpc { + compatible = "qcom,fastrpc"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + label = "cdsp"; + #address-cells = <1>; + #size-cells = <0>; + + compute-cb@1 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <1>; + iommus = <&apps_smmu 0x1401 0x30>; + }; + + compute-cb@2 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <2>; + iommus = <&apps_smmu 0x1402 0x30>; + }; + + compute-cb@3 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <3>; + iommus = <&apps_smmu 0x1403 0x30>; + }; + + compute-cb@4 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <4>; + iommus = <&apps_smmu 0x1404 0x30>; + }; + + compute-cb@5 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <5>; + iommus = <&apps_smmu 0x1405 0x30>; + }; + + compute-cb@6 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <6>; + iommus = <&apps_smmu 0x1406 0x30>; + }; + + compute-cb@7 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <7>; + iommus = <&apps_smmu 0x1407 0x30>; + }; + + compute-cb@8 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <8>; + iommus = <&apps_smmu 0x1408 0x30>; + }; + }; }; }; @@ -620,7 +702,7 @@ method = "smc"; }; - soc: soc { + soc: soc@0 { #address-cells = <2>; #size-cells = <2>; ranges = <0 0 0 0 0x10 0>; @@ -1275,6 +1357,13 @@ }; }; + cache-controller@1100000 { + compatible = "qcom,sdm845-llcc"; + reg = <0 0x01100000 0 0x200000>, <0 0x01300000 0 0x50000>; + reg-names = "llcc_base", "llcc_broadcast_base"; + interrupts = ; + }; + ufs_mem_hc: ufshc@1d84000 { compatible = "qcom,sdm845-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; @@ -1815,6 +1904,457 @@ clock-names = "xo"; }; + 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@6043000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0 0x06043000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + funnel2_out: endpoint { + remote-endpoint = + <&merge_funnel_in2>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@5 { + reg = <5>; + funnel2_in5: 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 = <&etf_in>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + merge_funnel_in0: endpoint { + remote-endpoint = + <&funnel0_out>; + }; + }; + + port@2 { + reg = <2>; + merge_funnel_in2: endpoint { + remote-endpoint = + <&funnel2_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 = <&etf_out>; + }; + }; + }; + }; + + etf@6047000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0 0x06047000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + etf_out: endpoint { + remote-endpoint = + <&replicator_in>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + etf_in: endpoint { + remote-endpoint = + <&merge_funnel_out>; + }; + }; + }; + }; + + etr@6048000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0 0x06048000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,scatter-gather; + + in-ports { + port { + etr_in: endpoint { + remote-endpoint = + <&replicator_out>; + }; + }; + }; + }; + + etm@7040000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07040000 0 0x1000>; + + cpu = <&CPU0>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + 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"; + + 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"; + + 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"; + + 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"; + + 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"; + + 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"; + + 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"; + + 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 = + <&funnel2_in5>; + }; + }; + }; + + in-ports { + port { + apss_merge_funnel_in: endpoint { + remote-endpoint = + <&apss_funnel_out>; + }; + }; + }; + }; + sdhc_2: sdhci@8804000 { compatible = "qcom,sdm845-sdhci", "qcom,sdhci-msm-v5"; reg = <0 0x08804000 0 0x1000>; @@ -2027,6 +2567,36 @@ }; }; + video-codec@aa00000 { + compatible = "qcom,sdm845-venus"; + reg = <0 0x0aa00000 0 0xff000>; + interrupts = ; + power-domains = <&videocc VENUS_GDSC>; + clocks = <&videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, + <&videocc VIDEO_CC_VENUS_AHB_CLK>, + <&videocc VIDEO_CC_VENUS_CTL_AXI_CLK>; + clock-names = "core", "iface", "bus"; + iommus = <&apps_smmu 0x10a0 0x8>, + <&apps_smmu 0x10b0 0x0>; + memory-region = <&venus_mem>; + + video-core0 { + compatible = "venus-decoder"; + clocks = <&videocc VIDEO_CC_VCODEC0_CORE_CLK>, + <&videocc VIDEO_CC_VCODEC0_AXI_CLK>; + clock-names = "core", "bus"; + power-domains = <&videocc VCODEC0_GDSC>; + }; + + video-core1 { + compatible = "venus-encoder"; + clocks = <&videocc VIDEO_CC_VCODEC1_CORE_CLK>, + <&videocc VIDEO_CC_VCODEC1_AXI_CLK>; + clock-names = "core", "bus"; + power-domains = <&videocc VCODEC1_GDSC>; + }; + }; + videocc: clock-controller@ab00000 { compatible = "qcom,sdm845-videocc"; reg = <0 0x0ab00000 0 0x10000>; @@ -2131,9 +2701,6 @@ status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - ports { #address-cells = <1>; #size-cells = <0>; @@ -2198,9 +2765,6 @@ status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - ports { #address-cells = <1>; #size-cells = <0>; @@ -2411,6 +2975,14 @@ #clock-cells = <0>; #power-domain-cells = <1>; + + cx_cdev: cx { + #cooling-cells = <2>; + }; + + ebi_cdev: ebi { + #cooling-cells = <2>; + }; }; spmi_bus: spmi@c440000 { @@ -2538,6 +3110,8 @@ rpmhcc: clock-controller { compatible = "qcom,sdm845-rpmh-clk"; #clock-cells = <1>; + clock-names = "xo"; + clocks = <&xo_board>; }; rpmhpd: power-controller { @@ -2718,13 +3292,13 @@ thermal-sensors = <&tsens0 1>; trips { - cpu0_alert0: trip-point@0 { + cpu0_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "passive"; }; - cpu0_alert1: trip-point@1 { + cpu0_alert1: trip-point1 { temperature = <95000>; hysteresis = <2000>; type = "passive"; @@ -2762,13 +3336,13 @@ thermal-sensors = <&tsens0 2>; trips { - cpu1_alert0: trip-point@0 { + cpu1_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "passive"; }; - cpu1_alert1: trip-point@1 { + cpu1_alert1: trip-point1 { temperature = <95000>; hysteresis = <2000>; type = "passive"; @@ -2806,13 +3380,13 @@ thermal-sensors = <&tsens0 3>; trips { - cpu2_alert0: trip-point@0 { + cpu2_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "passive"; }; - cpu2_alert1: trip-point@1 { + cpu2_alert1: trip-point1 { temperature = <95000>; hysteresis = <2000>; type = "passive"; @@ -2850,13 +3424,13 @@ thermal-sensors = <&tsens0 4>; trips { - cpu3_alert0: trip-point@0 { + cpu3_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "passive"; }; - cpu3_alert1: trip-point@1 { + cpu3_alert1: trip-point1 { temperature = <95000>; hysteresis = <2000>; type = "passive"; @@ -2894,13 +3468,13 @@ thermal-sensors = <&tsens0 7>; trips { - cpu4_alert0: trip-point@0 { + cpu4_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "passive"; }; - cpu4_alert1: trip-point@1 { + cpu4_alert1: trip-point1 { temperature = <95000>; hysteresis = <2000>; type = "passive"; @@ -2938,13 +3512,13 @@ thermal-sensors = <&tsens0 8>; trips { - cpu5_alert0: trip-point@0 { + cpu5_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "passive"; }; - cpu5_alert1: trip-point@1 { + cpu5_alert1: trip-point1 { temperature = <95000>; hysteresis = <2000>; type = "passive"; @@ -2982,13 +3556,13 @@ thermal-sensors = <&tsens0 9>; trips { - cpu6_alert0: trip-point@0 { + cpu6_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "passive"; }; - cpu6_alert1: trip-point@1 { + cpu6_alert1: trip-point1 { temperature = <95000>; hysteresis = <2000>; type = "passive"; @@ -3026,13 +3600,13 @@ thermal-sensors = <&tsens0 10>; trips { - cpu7_alert0: trip-point@0 { + cpu7_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "passive"; }; - cpu7_alert1: trip-point@1 { + cpu7_alert1: trip-point1 { temperature = <95000>; hysteresis = <2000>; type = "passive"; @@ -3070,7 +3644,7 @@ thermal-sensors = <&tsens0 0>; trips { - aoss0_alert0: trip-point@0 { + aoss0_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "hot"; @@ -3085,7 +3659,7 @@ thermal-sensors = <&tsens0 5>; trips { - cluster0_alert0: trip-point@0 { + cluster0_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "hot"; @@ -3105,7 +3679,7 @@ thermal-sensors = <&tsens0 6>; trips { - cluster1_alert0: trip-point@0 { + cluster1_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "hot"; @@ -3125,7 +3699,7 @@ thermal-sensors = <&tsens0 11>; trips { - gpu1_alert0: trip-point@0 { + gpu1_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "hot"; @@ -3140,7 +3714,7 @@ thermal-sensors = <&tsens0 12>; trips { - gpu2_alert0: trip-point@0 { + gpu2_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "hot"; @@ -3155,7 +3729,7 @@ thermal-sensors = <&tsens1 0>; trips { - aoss1_alert0: trip-point@0 { + aoss1_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "hot"; @@ -3170,7 +3744,7 @@ thermal-sensors = <&tsens1 1>; trips { - q6_modem_alert0: trip-point@0 { + q6_modem_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "hot"; @@ -3185,7 +3759,7 @@ thermal-sensors = <&tsens1 2>; trips { - mem_alert0: trip-point@0 { + mem_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "hot"; @@ -3200,7 +3774,7 @@ thermal-sensors = <&tsens1 3>; trips { - wlan_alert0: trip-point@0 { + wlan_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "hot"; @@ -3215,7 +3789,7 @@ thermal-sensors = <&tsens1 4>; trips { - q6_hvx_alert0: trip-point@0 { + q6_hvx_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "hot"; @@ -3230,7 +3804,7 @@ thermal-sensors = <&tsens1 5>; trips { - camera_alert0: trip-point@0 { + camera_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "hot"; @@ -3245,7 +3819,7 @@ thermal-sensors = <&tsens1 6>; trips { - video_alert0: trip-point@0 { + video_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "hot"; @@ -3260,7 +3834,7 @@ thermal-sensors = <&tsens1 7>; trips { - modem_alert0: trip-point@0 { + modem_alert0: trip-point0 { temperature = <90000>; hysteresis = <2000>; type = "hot"; diff --git a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts new file mode 100644 index 0000000000000000000000000000000000000000..ded120d3aef58e1e8ea16377ca2dc565bf6a668d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts @@ -0,0 +1,446 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Lenovo Yoga C630 + * + * Copyright (c) 2019, Linaro Ltd. + */ + +/dts-v1/; + +#include +#include "sdm845.dtsi" +#include "pm8998.dtsi" + +/ { + model = "Lenovo Yoga C630"; + compatible = "lenovo,yoga-c630", "qcom,sdm845"; + + aliases { + hsuart0 = &uart6; + }; +}; + +&apps_rsc { + pm8998-rpmh-regulators { + compatible = "qcom,pm8998-rpmh-regulators"; + qcom,pmic-id = "a"; + + vdd-l2-l8-l17-supply = <&vreg_s3a_1p35>; + vdd-l7-l12-l14-l15-supply = <&vreg_s5a_2p04>; + + vreg_s2a_1p125: smps2 { + }; + + vreg_s3a_1p35: smps3 { + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + regulator-initial-mode = ; + }; + + vreg_s4a_1p8: smps4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_s5a_2p04: smps5 { + regulator-min-microvolt = <2040000>; + regulator-max-microvolt = <2040000>; + regulator-initial-mode = ; + }; + + vreg_s7a_1p025: smps7 { + }; + + vdd_qusb_hs0: + vdda_hp_pcie_core: + vdda_mipi_csi0_0p9: + vdda_mipi_csi1_0p9: + vdda_mipi_csi2_0p9: + vdda_mipi_dsi0_pll: + vdda_mipi_dsi1_pll: + vdda_qlink_lv: + vdda_qlink_lv_ck: + vdda_qrefs_0p875: + vdda_pcie_core: + vdda_pll_cc_ebi01: + vdda_pll_cc_ebi23: + vdda_sp_sensor: + vdda_ufs1_core: + vdda_ufs2_core: + vdda_usb1_ss_core: + vdda_usb2_ss_core: + vreg_l1a_0p875: ldo1 { + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + }; + + vddpx_10: + vreg_l2a_1p2: ldo2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-always-on; + }; + + vreg_l3a_1p0: ldo3 { + }; + + vdd_wcss_cx: + vdd_wcss_mx: + vdda_wcss_pll: + vreg_l5a_0p8: ldo5 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-initial-mode = ; + }; + + vddpx_13: + vreg_l6a_1p8: ldo6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l7a_1p8: ldo7 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l8a_1p2: ldo8 { + }; + + vreg_l9a_1p8: ldo9 { + }; + + vreg_l10a_1p8: ldo10 { + }; + + vreg_l11a_1p0: ldo11 { + }; + + vdd_qfprom: + vdd_qfprom_sp: + vdda_apc1_cs_1p8: + vdda_gfx_cs_1p8: + vdda_qrefs_1p8: + vdda_qusb_hs0_1p8: + vddpx_11: + vreg_l12a_1p8: ldo12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vddpx_2: + vreg_l13a_2p95: ldo13 { + }; + + vreg_l14a_1p88: ldo14 { + regulator-min-microvolt = <1880000>; + regulator-max-microvolt = <1880000>; + regulator-initial-mode = ; + regulator-always-on; + }; + + vreg_l15a_1p8: ldo15 { + }; + + vreg_l16a_2p7: ldo16 { + }; + + vreg_l17a_1p3: ldo17 { + regulator-min-microvolt = <1304000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l18a_2p7: ldo18 { + }; + + vreg_l19a_3p0: ldo19 { + regulator-min-microvolt = <3100000>; + regulator-max-microvolt = <3108000>; + regulator-initial-mode = ; + }; + + vreg_l20a_2p95: ldo20 { + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l21a_2p95: ldo21 { + }; + + vreg_l22a_2p85: ldo22 { + }; + + vreg_l23a_3p3: ldo23 { + }; + + vdda_qusb_hs0_3p1: + vreg_l24a_3p075: ldo24 { + regulator-min-microvolt = <3075000>; + regulator-max-microvolt = <3083000>; + regulator-initial-mode = ; + }; + + vreg_l25a_3p3: ldo25 { + regulator-min-microvolt = <3104000>; + regulator-max-microvolt = <3112000>; + regulator-initial-mode = ; + }; + + vdda_hp_pcie_1p2: + vdda_hv_ebi0: + vdda_hv_ebi1: + vdda_hv_ebi2: + vdda_hv_ebi3: + vdda_mipi_csi_1p25: + vdda_mipi_dsi0_1p2: + vdda_mipi_dsi1_1p2: + vdda_pcie_1p2: + vdda_ufs1_1p2: + vdda_ufs2_1p2: + vdda_usb1_ss_1p2: + vdda_usb2_ss_1p2: + vreg_l26a_1p2: ldo26 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1208000>; + regulator-initial-mode = ; + }; + + vreg_l28a_3p0: ldo28 { + }; + + vreg_lvs1a_1p8: lvs1 { + }; + + vreg_lvs2a_1p8: lvs2 { + }; + }; +}; + +&apps_smmu { + /* TODO: Figure out how to survive booting with this enabled */ + status = "disabled"; +}; + +&gcc { + protected-clocks = , + , + ; +}; + +&i2c1 { + status = "okay"; + clock-frequency = <400000>; +}; + +&i2c3 { + status = "okay"; + clock-frequency = <400000>; + + hid@15 { + compatible = "hid-over-i2c"; + reg = <0x15>; + hid-descr-addr = <0x1>; + + interrupts-extended = <&tlmm 37 IRQ_TYPE_EDGE_RISING>; + }; + + hid@2c { + compatible = "hid-over-i2c"; + reg = <0x2c>; + hid-descr-addr = <0x20>; + + interrupts-extended = <&tlmm 37 IRQ_TYPE_EDGE_RISING>; + + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_hid_active>; + }; +}; + +&i2c5 { + status = "okay"; + clock-frequency = <400000>; + + hid@10 { + compatible = "hid-over-i2c"; + reg = <0x10>; + hid-descr-addr = <0x1>; + + interrupts-extended = <&tlmm 125 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-names = "default"; + pinctrl-0 = <&i2c6_hid_active>; + }; +}; + +&i2c11 { + status = "okay"; + clock-frequency = <400000>; + + hid@5c { + compatible = "hid-over-i2c"; + reg = <0x5c>; + hid-descr-addr = <0x1>; + + interrupts-extended = <&tlmm 92 IRQ_TYPE_LEVEL_LOW>; + + pinctrl-names = "default"; + pinctrl-0 = <&i2c12_hid_active>; + }; +}; + +&qup_i2c12_default { + drive-strength = <2>; + bias-disable; +}; + +&qup_uart6_default { + pinmux { + pins = "gpio45", "gpio46", "gpio47", "gpio48"; + function = "qup6"; + }; + + cts { + pins = "gpio45"; + bias-pull-down; + }; + + rts-tx { + pins = "gpio46", "gpio47"; + drive-strength = <2>; + bias-disable; + }; + + rx { + pins = "gpio48"; + bias-pull-up; + }; +}; + +&qupv3_id_0 { + status = "okay"; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&tlmm { + gpio-reserved-ranges = <0 4>, <81 4>; + + i2c2_hid_active: i2c2-hid-active { + pins = <37>; + function = "gpio"; + + input-enable; + bias-pull-up; + drive-strength = <2>; + }; + + i2c6_hid_active: i2c6-hid-active { + pins = <125>; + function = "gpio"; + + input-enable; + bias-pull-up; + drive-strength = <2>; + }; + + i2c12_hid_active: i2c12-hid-active { + pins = <92>; + function = "gpio"; + + input-enable; + bias-pull-up; + drive-strength = <2>; + }; +}; + +&uart6 { + 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>; + }; +}; + +&ufs_mem_hc { + status = "okay"; + + vcc-supply = <&vreg_l20a_2p95>; + vcc-max-microamp = <600000>; +}; + +&ufs_mem_phy { + status = "okay"; + + vdda-phy-supply = <&vdda_ufs1_core>; + vdda-pll-supply = <&vdda_ufs1_1p2>; +}; + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "host"; +}; + +&usb_1_hsphy { + status = "okay"; + + vdd-supply = <&vdda_usb1_ss_core>; + vdda-pll-supply = <&vdda_qusb_hs0_1p8>; + vdda-phy-dpdm-supply = <&vdda_qusb_hs0_3p1>; + + qcom,imp-res-offset-value = <8>; + qcom,hstx-trim-value = ; + qcom,preemphasis-level = ; + qcom,preemphasis-width = ; +}; + +&usb_1_qmpphy { + status = "okay"; + + vdda-phy-supply = <&vdda_usb1_ss_1p2>; + vdda-pll-supply = <&vdda_usb1_ss_core>; +}; + +&usb_2 { + status = "okay"; +}; + +&usb_2_dwc3 { + dr_mode = "host"; +}; + +&usb_2_hsphy { + status = "okay"; + + vdd-supply = <&vdda_usb2_ss_core>; + vdda-pll-supply = <&vdda_qusb_hs0_1p8>; + vdda-phy-dpdm-supply = <&vdda_qusb_hs0_3p1>; + + qcom,imp-res-offset-value = <8>; + qcom,hstx-trim-value = ; +}; + +&usb_2_qmpphy { + status = "okay"; + + vdda-phy-supply = <&vdda_usb2_ss_1p2>; + vdda-pll-supply = <&vdda_usb2_ss_core>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-mtp.dts b/arch/arm64/boot/dts/qcom/sm8150-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..aa5de42fcae45ba67fa4637468adfb16bfc6f942 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-mtp.dts @@ -0,0 +1,375 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019, Linaro Limited + */ + +/dts-v1/; + +#include +#include "sm8150.dtsi" +#include "pm8150.dtsi" +#include "pm8150b.dtsi" +#include "pm8150l.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8150 MTP"; + compatible = "qcom,sm8150-mtp"; + + 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>; + }; + + /* + * Apparently RPMh does not provide support for PM8150 S4 because it + * is always-on; model it as a fixed regulator. + */ + vreg_s4a_1p8: pm8150-s4 { + compatible = "regulator-fixed"; + regulator-name = "vreg_s4a_1p8"; + + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-always-on; + regulator-boot-on; + + vin-supply = <&vph_pwr>; + }; +}; + +&apps_rsc { + pm8150-rpmh-regulators { + compatible = "qcom,pm8150-rpmh-regulators"; + qcom,pmic-id = "a"; + + 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-l8-l11-supply = <&vreg_s6a_0p9>; + vdd-l2-l10-supply = <&vreg_bob>; + vdd-l3-l4-l5-l18-supply = <&vreg_s6a_0p9>; + vdd-l6-l9-supply = <&vreg_s8c_1p3>; + vdd-l7-l12-l14-l15-supply = <&vreg_s5a_2p0>; + vdd-l13-l16-l17-supply = <&vreg_bob>; + + vreg_s5a_2p0: smps5 { + regulator-min-microvolt = <1904000>; + regulator-max-microvolt = <2000000>; + }; + + vreg_s6a_0p9: smps6 { + regulator-min-microvolt = <920000>; + regulator-max-microvolt = <1128000>; + }; + + vdda_wcss_pll: + vreg_l1a_0p75: ldo1 { + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <752000>; + regulator-initial-mode = ; + }; + + vdd_pdphy: + vdda_usb_hs_3p1: + vreg_l2a_3p1: ldo2 { + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l3a_0p8: ldo3 { + regulator-min-microvolt = <480000>; + regulator-max-microvolt = <932000>; + regulator-initial-mode = ; + }; + + vdd_usb_hs_core: + vdda_csi_0_0p9: + vdda_csi_1_0p9: + vdda_csi_2_0p9: + vdda_csi_3_0p9: + vdda_dsi_0_0p9: + vdda_dsi_1_0p9: + vdda_dsi_0_pll_0p9: + vdda_dsi_1_pll_0p9: + vdda_pcie_1ln_core: + vdda_pcie_2ln_core: + vdda_pll_hv_cc_ebi01: + vdda_pll_hv_cc_ebi23: + vdda_qrefs_0p875_5: + vdda_sp_sensor: + vdda_ufs_2ln_core_1: + vdda_ufs_2ln_core_2: + vdda_usb_ss_dp_core_1: + vdda_usb_ss_dp_core_2: + vdda_qlink_lv: + vdda_qlink_lv_ck: + vreg_l5a_0p875: ldo5 { + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + }; + + vreg_l6a_1p2: ldo6 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l7a_1p8: ldo7 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vddpx_10: + vreg_l9a_1p2: ldo9 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l10a_2p5: ldo10 { + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l11a_0p8: ldo11 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-initial-mode = ; + }; + + vdd_qfprom: + vdd_qfprom_sp: + vdda_apc_cs_1p8: + vdda_gfx_cs_1p8: + vdda_usb_hs_1p8: + vdda_qrefs_vref_1p8: + vddpx_10_a: + vreg_l12a_1p8: ldo12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l13a_2p7: ldo13 { + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2704000>; + regulator-initial-mode = ; + }; + + vreg_l14a_1p8: ldo14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1880000>; + regulator-initial-mode = ; + }; + + vreg_l15a_1p7: ldo15 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1704000>; + regulator-initial-mode = ; + }; + + vreg_l16a_2p7: ldo16 { + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l17a_3p0: ldo17 { + regulator-min-microvolt = <2856000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + }; + + pm8150l-rpmh-regulators { + compatible = "qcom,pm8150l-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-l1-l8-supply = <&vreg_s4a_1p8>; + vdd-l2-l3-supply = <&vreg_s8c_1p3>; + vdd-l4-l5-l6-supply = <&vreg_bob>; + vdd-l7-l11-supply = <&vreg_bob>; + vdd-l9-l10-supply = <&vreg_bob>; + + vdd-bob-supply = <&vph_pwr>; + vdd-flash-supply = <&vreg_bob>; + vdd-rgb-supply = <&vreg_bob>; + + vreg_bob: bob { + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <4000000>; + regulator-initial-mode = ; + regulator-allow-bypass; + }; + + vreg_s8c_1p3: smps8 { + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + }; + + vreg_l1c_1p8: ldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vdda_wcss_adcdac_1: + vdda_wcss_adcdac_22: + vreg_l2c_1p3: ldo2 { + regulator-min-microvolt = <1304000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vdda_hv_ebi0: + vdda_hv_ebi1: + vdda_hv_ebi2: + vdda_hv_ebi3: + vdda_hv_refgen0: + vdda_qlink_hv_ck: + vreg_l3c_1p2: ldo3 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vddpx_5: + vreg_l4c_1p8: ldo4 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <2928000>; + regulator-initial-mode = ; + }; + + vddpx_6: + vreg_l5c_1p8: ldo5 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <2928000>; + regulator-initial-mode = ; + }; + + vddpx_2: + vreg_l6c_2p9: ldo6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l7c_3p0: ldo7 { + regulator-min-microvolt = <2856000>; + regulator-max-microvolt = <3104000>; + regulator-initial-mode = ; + }; + + vreg_l8c_1p8: ldo8 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l9c_2p9: ldo9 { + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l10c_3p3: ldo10 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + regulator-initial-mode = ; + }; + + vreg_l11c_3p3: ldo11 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + regulator-initial-mode = ; + }; + }; + + pm8009-rpmh-regulators { + compatible = "qcom,pm8009-rpmh-regulators"; + qcom,pmic-id = "f"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vreg_bob>; + + vdd-l2-supply = <&vreg_s8c_1p3>; + vdd-l5-l6-supply = <&vreg_bob>; + + vreg_l2f_1p2: ldo2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l5f_2p85: ldo5 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l6f_2p85: ldo6 { + regulator-initial-mode = ; + regulator-min-microvolt = <2856000>; + regulator-max-microvolt = <2856000>; + }; + }; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&pon { + pwrkey { + status = "okay"; + }; + + resin { + compatible = "qcom,pm8941-resin"; + interrupts = <0x0 0x8 0x1 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + linux,code = ; + }; +}; + +&tlmm { + gpio-reserved-ranges = <0 4>, <126 4>; +}; + +&uart2 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8f23fcadecb895d05d338920ea2fb6777d201c22 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -0,0 +1,482 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019, Linaro Limited + */ + +#include +#include +#include + +/ { + interrupt-parent = <&intc>; + + #address-cells = <2>; + #size-cells = <2>; + + chosen { }; + + clocks { + xo_board: xo-board { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <38400000>; + clock-output-names = "xo_board"; + }; + + sleep_clk: sleep-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32764>; + clock-output-names = "sleep_clk"; + }; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "qcom,kryo485"; + reg = <0x0 0x0>; + enable-method = "psci"; + 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 = "qcom,kryo485"; + reg = <0x0 0x100>; + enable-method = "psci"; + next-level-cache = <&L2_100>; + L2_100: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + + }; + + CPU2: cpu@200 { + device_type = "cpu"; + compatible = "qcom,kryo485"; + reg = <0x0 0x200>; + enable-method = "psci"; + next-level-cache = <&L2_200>; + L2_200: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU3: cpu@300 { + device_type = "cpu"; + compatible = "qcom,kryo485"; + reg = <0x0 0x300>; + enable-method = "psci"; + next-level-cache = <&L2_300>; + L2_300: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU4: cpu@400 { + device_type = "cpu"; + compatible = "qcom,kryo485"; + reg = <0x0 0x400>; + enable-method = "psci"; + next-level-cache = <&L2_400>; + L2_400: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU5: cpu@500 { + device_type = "cpu"; + compatible = "qcom,kryo485"; + reg = <0x0 0x500>; + enable-method = "psci"; + next-level-cache = <&L2_500>; + L2_500: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU6: cpu@600 { + device_type = "cpu"; + compatible = "qcom,kryo485"; + reg = <0x0 0x600>; + enable-method = "psci"; + next-level-cache = <&L2_600>; + L2_600: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU7: cpu@700 { + device_type = "cpu"; + compatible = "qcom,kryo485"; + reg = <0x0 0x700>; + enable-method = "psci"; + next-level-cache = <&L2_700>; + L2_700: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + }; + + firmware { + scm: scm { + compatible = "qcom,scm-sm8150", "qcom,scm"; + #reset-cells = <1>; + }; + }; + + tcsr_mutex: hwlock { + compatible = "qcom,tcsr-mutex"; + syscon = <&tcsr_mutex_regs 0 0x1000>; + #hwlock-cells = <1>; + }; + + memory@80000000 { + device_type = "memory"; + /* We expect the bootloader to fill in the size */ + reg = <0x0 0x80000000 0x0 0x0>; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = ; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + hyp_mem: memory@85700000 { + reg = <0x0 0x85700000 0x0 0x600000>; + no-map; + }; + + xbl_mem: memory@85d00000 { + reg = <0x0 0x85d00000 0x0 0x140000>; + no-map; + }; + + aop_mem: memory@85f00000 { + reg = <0x0 0x85f00000 0x0 0x20000>; + no-map; + }; + + aop_cmd_db: memory@85f20000 { + compatible = "qcom,cmd-db"; + reg = <0x0 0x85f20000 0x0 0x20000>; + no-map; + }; + + smem_mem: memory@86000000 { + reg = <0x0 0x86000000 0x0 0x200000>; + no-map; + }; + + tz_mem: memory@86200000 { + reg = <0x0 0x86200000 0x0 0x3900000>; + no-map; + }; + + rmtfs_mem: memory@89b00000 { + compatible = "qcom,rmtfs-mem"; + reg = <0x0 0x89b00000 0x0 0x200000>; + no-map; + + qcom,client-id = <1>; + qcom,vmid = <15>; + }; + + camera_mem: memory@8b700000 { + reg = <0x0 0x8b700000 0x0 0x500000>; + no-map; + }; + + wlan_mem: memory@8bc00000 { + reg = <0x0 0x8bc00000 0x0 0x180000>; + no-map; + }; + + npu_mem: memory@8bd80000 { + reg = <0x0 0x8bd80000 0x0 0x80000>; + no-map; + }; + + adsp_mem: memory@8be00000 { + reg = <0x0 0x8be00000 0x0 0x1a00000>; + no-map; + }; + + mpss_mem: memory@8d800000 { + reg = <0x0 0x8d800000 0x0 0x9600000>; + no-map; + }; + + venus_mem: memory@96e00000 { + reg = <0x0 0x96e00000 0x0 0x500000>; + no-map; + }; + + slpi_mem: memory@97300000 { + reg = <0x0 0x97300000 0x0 0x1400000>; + no-map; + }; + + ipa_fw_mem: memory@98700000 { + reg = <0x0 0x98700000 0x0 0x10000>; + no-map; + }; + + ipa_gsi_mem: memory@98710000 { + reg = <0x0 0x98710000 0x0 0x5000>; + no-map; + }; + + gpu_mem: memory@98715000 { + reg = <0x0 0x98715000 0x0 0x2000>; + no-map; + }; + + spss_mem: memory@98800000 { + reg = <0x0 0x98800000 0x0 0x100000>; + no-map; + }; + + cdsp_mem: memory@98900000 { + reg = <0x0 0x98900000 0x0 0x1400000>; + no-map; + }; + + qseecom_mem: memory@9e400000 { + reg = <0x0 0x9e400000 0x0 0x1400000>; + no-map; + }; + }; + + smem { + compatible = "qcom,smem"; + memory-region = <&smem_mem>; + hwlocks = <&tcsr_mutex 3>; + }; + + 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-sm8150"; + reg = <0x0 0x00100000 0x0 0x1f0000>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + clock-names = "bi_tcxo", + "sleep_clk"; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&sleep_clk>; + }; + + qupv3_id_1: geniqup@ac0000 { + compatible = "qcom,geni-se-qup"; + reg = <0x0 0x00ac0000 0x0 0x6000>; + clock-names = "m-ahb", "s-ahb"; + clocks = <&gcc 123>, + <&gcc 124>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + uart2: serial@a90000 { + compatible = "qcom,geni-debug-uart"; + reg = <0x0 0x00a90000 0x0 0x4000>; + clock-names = "se"; + clocks = <&gcc 105>; + interrupts = ; + status = "disabled"; + }; + }; + + tcsr_mutex_regs: syscon@1f40000 { + compatible = "syscon"; + reg = <0x0 0x01f40000 0x0 0x40000>; + }; + + tlmm: pinctrl@3100000 { + compatible = "qcom,sm8150-pinctrl"; + reg = <0x0 0x03100000 0x0 0x300000>, + <0x0 0x03500000 0x0 0x300000>, + <0x0 0x03900000 0x0 0x300000>, + <0x0 0x03D00000 0x0 0x300000>; + reg-names = "west", "east", "north", "south"; + interrupts = ; + gpio-ranges = <&tlmm 0 0 175>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + aoss_qmp: power-controller@c300000 { + compatible = "qcom,sm8150-aoss-qmp"; + reg = <0x0 0x0c300000 0x0 0x100000>; + interrupts = ; + mboxes = <&apss_shared 0>; + + #clock-cells = <0>; + #power-domain-cells = <1>; + }; + + spmi_bus: spmi@c440000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0x0 0x0c440000 0x0 0x0001100>, + <0x0 0x0c600000 0x0 0x2000000>, + <0x0 0x0e600000 0x0 0x0100000>, + <0x0 0x0e700000 0x0 0x00a0000>, + <0x0 0x0c40a000 0x0 0x0026000>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupt-names = "periph_irq"; + interrupts = ; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + cell-index = <0>; + }; + + intc: interrupt-controller@17a00000 { + compatible = "arm,gic-v3"; + interrupt-controller; + #interrupt-cells = <3>; + reg = <0x0 0x17a00000 0x0 0x10000>, /* GICD */ + <0x0 0x17a60000 0x0 0x100000>; /* GICR * 8 */ + interrupts = ; + }; + + apss_shared: mailbox@17c00000 { + compatible = "qcom,sm8150-apss-shared"; + reg = <0x0 0x17c00000 0x0 0x1000>; + #mbox-cells = <1>; + }; + + timer@17c20000 { + #address-cells = <2>; + #size-cells = <2>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0x0 0x17c20000 0x0 0x1000>; + clock-frequency = <19200000>; + + frame@17c21000{ + frame-number = <0>; + interrupts = , + ; + reg = <0x0 0x17c21000 0x0 0x1000>, + <0x0 0x17c22000 0x0 0x1000>; + }; + + frame@17c23000 { + frame-number = <1>; + interrupts = ; + reg = <0x0 0x17c23000 0x0 0x1000>; + status = "disabled"; + }; + + frame@17c25000 { + frame-number = <2>; + interrupts = ; + reg = <0x0 0x17c25000 0x0 0x1000>; + status = "disabled"; + }; + + frame@17c27000 { + frame-number = <3>; + interrupts = ; + reg = <0x0 0x17c26000 0x0 0x1000>; + status = "disabled"; + }; + + frame@17c29000 { + frame-number = <4>; + interrupts = ; + reg = <0x0 0x17c29000 0x0 0x1000>; + status = "disabled"; + }; + + frame@17c2b000 { + frame-number = <5>; + interrupts = ; + reg = <0x0 0x17c2b000 0x0 0x1000>; + status = "disabled"; + }; + + frame@17c2d000 { + frame-number = <6>; + interrupts = ; + reg = <0x0 0x17c2d000 0x0 0x1000>; + status = "disabled"; + }; + }; + + apps_rsc: rsc@18200000 { + label = "apps_rsc"; + compatible = "qcom,rpmh-rsc"; + reg = <0x0 0x18200000 0x0 0x10000>, + <0x0 0x18210000 0x0 0x10000>, + <0x0 0x18220000 0x0 0x10000>; + reg-names = "drv-0", "drv-1", "drv-2"; + interrupts = , + , + ; + qcom,tcs-offset = <0xd00>; + qcom,drv-id = <2>; + qcom,tcs-config = , + , + , + ; + + rpmhcc: clock-controller { + compatible = "qcom,sm8150-rpmh-clk"; + #clock-cells = <1>; + clock-names = "xo"; + clocks = <&xo_board>; + }; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; +}; diff --git a/arch/arm64/boot/dts/renesas/hihope-common.dtsi b/arch/arm64/boot/dts/renesas/hihope-common.dtsi index 23fd0224ca90e103c20af7dee574abf8af9b590d..3e376d29a73002e04edaf7edc543ed2fa1dfe53c 100644 --- a/arch/arm64/boot/dts/renesas/hihope-common.dtsi +++ b/arch/arm64/boot/dts/renesas/hihope-common.dtsi @@ -10,6 +10,7 @@ / { aliases { serial0 = &scif2; + serial1 = &hscif0; }; chosen { @@ -31,6 +32,13 @@ leds { compatible = "gpio-leds"; + bt_active_led { + label = "blue:bt"; + gpios = <&gpio7 0 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "hci0-power"; + default-state = "off"; + }; + led0 { gpios = <&gpio6 11 GPIO_ACTIVE_HIGH>; }; @@ -46,6 +54,13 @@ led3 { gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; }; + + wlan_active_led { + label = "yellow:wlan"; + gpios = <&gpio7 1 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "phy0tx"; + default-state = "off"; + }; }; reg_1p8v: regulator0 { @@ -66,6 +81,14 @@ regulator-always-on; }; + sound_card: sound { + compatible = "audio-graph-card"; + + label = "rcar-sound"; + + dais = <&rsnd_port0>; + }; + vbus0_usb2: regulator-vbus0-usb2 { compatible = "regulator-fixed"; @@ -90,6 +113,17 @@ 1800000 0>; }; + wlan_en_reg: regulator-wlan_en { + compatible = "regulator-fixed"; + regulator-name = "wlan-en-regulator"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + startup-delay-us = <70000>; + + gpio = <&gpio_expander 1 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + x302_clk: x302-clock { compatible = "fixed-clock"; #clock-cells = <0>; @@ -103,6 +137,10 @@ }; }; +&audio_clk_a { + clock-frequency = <22579200>; +}; + &du { clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>, @@ -150,6 +188,25 @@ remote-endpoint = <&hdmi0_con>; }; }; + port@2 { + reg = <2>; + dw_hdmi0_snd_in: endpoint { + remote-endpoint = <&rsnd_endpoint0>; + }; + }; + }; +}; + +&hscif0 { + pinctrl-0 = <&hscif0_pins>; + pinctrl-names = "default"; + + uart-has-rtscts; + status = "okay"; + + bluetooth { + compatible = "ti,wl1837-st"; + enable-gpios = <&gpio_expander 2 GPIO_ACTIVE_HIGH>; }; }; @@ -162,6 +219,13 @@ clock-frequency = <400000>; status = "okay"; + gpio_expander: gpio@20 { + compatible = "onnn,pca9654"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + }; + versaclock5: clock-generator@6a { compatible = "idt,5p49v5923"; reg = <0x6a>; @@ -187,6 +251,11 @@ pinctrl-0 = <&scif_clk_pins>; pinctrl-names = "default"; + hscif0_pins: hscif0 { + groups = "hscif0_data", "hscif0_ctrl"; + function = "hscif0"; + }; + scif2_pins: scif2 { groups = "scif2_data_a"; function = "scif2"; @@ -209,12 +278,23 @@ power-source = <1800>; }; + sdhi2_pins: sd2 { + groups = "sdhi2_data4", "sdhi2_ctrl"; + function = "sdhi2"; + power-source = <1800>; + }; + sdhi3_pins: sd3 { groups = "sdhi3_data8", "sdhi3_ctrl", "sdhi3_ds"; function = "sdhi3"; power-source = <1800>; }; + sound_clk_pins: sound_clk { + groups = "audio_clk_a_a"; + function = "audio_clk"; + }; + usb0_pins: usb0 { groups = "usb0"; function = "usb0"; @@ -238,6 +318,30 @@ }; }; +&rcar_sound { + pinctrl-0 = <&sound_clk_pins>; + pinctrl-names = "default"; + + status = "okay"; + + /* Single DAI */ + #sound-dai-cells = <0>; + + ports { + rsnd_port0: port@0 { + rsnd_endpoint0: endpoint { + remote-endpoint = <&dw_hdmi0_snd_in>; + + dai-format = "i2s"; + bitclock-master = <&rsnd_endpoint0>; + frame-master = <&rsnd_endpoint0>; + + playback = <&ssi2>; + }; + }; + }; +}; + &rwdt { timeout-sec = <60>; status = "okay"; @@ -268,6 +372,27 @@ status = "okay"; }; +&sdhi2 { + status = "okay"; + pinctrl-0 = <&sdhi2_pins>; + pinctrl-names = "default"; + + vmmc-supply = <&wlan_en_reg>; + bus-width = <4>; + non-removable; + cap-power-off-card; + keep-power-in-suspend; + + #address-cells = <1>; + #size-cells = <0>; + wlcore: wlcore@2 { + compatible = "ti,wl1837"; + reg = <2>; + interrupt-parent = <&gpio2>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; + }; +}; + &sdhi3 { pinctrl-0 = <&sdhi3_pins>; pinctrl-1 = <&sdhi3_pins>; diff --git a/arch/arm64/boot/dts/renesas/hihope-rzg2-ex.dtsi b/arch/arm64/boot/dts/renesas/hihope-rzg2-ex.dtsi index 07a6eeaed12e18270fd99a476ed3a5111e59e49f..4280b190dc6820c33e5b9fca34a9d118cd03e9ef 100644 --- a/arch/arm64/boot/dts/renesas/hihope-rzg2-ex.dtsi +++ b/arch/arm64/boot/dts/renesas/hihope-rzg2-ex.dtsi @@ -31,6 +31,18 @@ }; }; +&can0 { + pinctrl-0 = <&can0_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&can1 { + pinctrl-0 = <&can1_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &pciec0 { status = "okay"; }; @@ -60,4 +72,14 @@ drive-strength = <12>; }; }; + + can0_pins: can0 { + groups = "can0_data_a"; + function = "can0"; + }; + + can1_pins: can1 { + groups = "can1_data"; + function = "can1"; + }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a774a1.dtsi b/arch/arm64/boot/dts/renesas/r8a774a1.dtsi index f209457c7807b06301eecb86845717fb9a6c0963..06c7c849c8ab98102dc023f10f1017ca892e3986 100644 --- a/arch/arm64/boot/dts/renesas/r8a774a1.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a774a1.dtsi @@ -1128,6 +1128,8 @@ <&cpg CPG_CORE R8A774A1_CLK_CANFD>, <&can_clk>; clock-names = "clkp1", "clkp2", "can_clk"; + assigned-clocks = <&cpg CPG_CORE R8A774A1_CLK_CANFD>; + assigned-clock-rates = <40000000>; power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>; resets = <&cpg 916>; status = "disabled"; @@ -1142,11 +1144,38 @@ <&cpg CPG_CORE R8A774A1_CLK_CANFD>, <&can_clk>; clock-names = "clkp1", "clkp2", "can_clk"; + assigned-clocks = <&cpg CPG_CORE R8A774A1_CLK_CANFD>; + assigned-clock-rates = <40000000>; power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>; resets = <&cpg 915>; status = "disabled"; }; + canfd: can@e66c0000 { + compatible = "renesas,r8a774a1-canfd", + "renesas,rcar-gen3-canfd"; + reg = <0 0xe66c0000 0 0x8000>; + interrupts = , + ; + clocks = <&cpg CPG_MOD 914>, + <&cpg CPG_CORE R8A774A1_CLK_CANFD>, + <&can_clk>; + clock-names = "fck", "canfd", "can_clk"; + assigned-clocks = <&cpg CPG_CORE R8A774A1_CLK_CANFD>; + assigned-clock-rates = <40000000>; + power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>; + resets = <&cpg 914>; + status = "disabled"; + + channel0 { + status = "disabled"; + }; + + channel1 { + status = "disabled"; + }; + }; + pwm0: pwm@e6e30000 { compatible = "renesas,pwm-r8a774a1", "renesas,pwm-rcar"; reg = <0 0xe6e30000 0 0x8>; @@ -1653,7 +1682,7 @@ <0 0xec5a0000 0 0x100>, /* ADG */ <0 0xec540000 0 0x1000>, /* SSIU */ <0 0xec541000 0 0x280>, /* SSI */ - <0 0xec740000 0 0x200>; /* Audio DMAC peri peri*/ + <0 0xec760000 0 0x200>; /* Audio DMAC peri peri*/ reg-names = "scu", "adg", "ssiu", "ssi", "audmapp"; clocks = <&cpg CPG_MOD 1005>, @@ -1697,6 +1726,28 @@ "ssi.1", "ssi.0"; status = "disabled"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + }; + port@1 { + reg = <1>; + }; + }; + + rcar_sound,ctu { + ctu00: ctu-0 { }; + ctu01: ctu-1 { }; + ctu02: ctu-2 { }; + ctu03: ctu-3 { }; + ctu10: ctu-4 { }; + ctu11: ctu-5 { }; + ctu12: ctu-6 { }; + ctu13: ctu-7 { }; + }; + rcar_sound,dvc { dvc0: dvc-0 { dmas = <&audma1 0xbc>; @@ -1713,17 +1764,6 @@ mix1: mix-1 { }; }; - rcar_sound,ctu { - ctu00: ctu-0 { }; - ctu01: ctu-1 { }; - ctu02: ctu-2 { }; - ctu03: ctu-3 { }; - ctu10: ctu-4 { }; - ctu11: ctu-5 { }; - ctu12: ctu-6 { }; - ctu13: ctu-7 { }; - }; - rcar_sound,src { src0: src-0 { interrupts = ; @@ -1780,64 +1820,264 @@ rcar_sound,ssi { ssi0: ssi-0 { interrupts = ; - dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>; - dma-names = "rx", "tx", "rxu", "txu"; + dmas = <&audma0 0x01>, <&audma1 0x02>; + dma-names = "rx", "tx"; }; ssi1: ssi-1 { interrupts = ; - dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>; - dma-names = "rx", "tx", "rxu", "txu"; + dmas = <&audma0 0x03>, <&audma1 0x04>; + dma-names = "rx", "tx"; }; ssi2: ssi-2 { interrupts = ; - dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>; - dma-names = "rx", "tx", "rxu", "txu"; + dmas = <&audma0 0x05>, <&audma1 0x06>; + dma-names = "rx", "tx"; }; ssi3: ssi-3 { interrupts = ; - dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>; - dma-names = "rx", "tx", "rxu", "txu"; + dmas = <&audma0 0x07>, <&audma1 0x08>; + dma-names = "rx", "tx"; }; ssi4: ssi-4 { interrupts = ; - dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>; - dma-names = "rx", "tx", "rxu", "txu"; + dmas = <&audma0 0x09>, <&audma1 0x0a>; + dma-names = "rx", "tx"; }; ssi5: ssi-5 { interrupts = ; - dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>; - dma-names = "rx", "tx", "rxu", "txu"; + dmas = <&audma0 0x0b>, <&audma1 0x0c>; + dma-names = "rx", "tx"; }; ssi6: ssi-6 { interrupts = ; - dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>; - dma-names = "rx", "tx", "rxu", "txu"; + dmas = <&audma0 0x0d>, <&audma1 0x0e>; + dma-names = "rx", "tx"; }; ssi7: ssi-7 { interrupts = ; - dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>; - dma-names = "rx", "tx", "rxu", "txu"; + dmas = <&audma0 0x0f>, <&audma1 0x10>; + dma-names = "rx", "tx"; }; ssi8: ssi-8 { interrupts = ; - dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>; - dma-names = "rx", "tx", "rxu", "txu"; + dmas = <&audma0 0x11>, <&audma1 0x12>; + dma-names = "rx", "tx"; }; ssi9: ssi-9 { interrupts = ; - dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>; - dma-names = "rx", "tx", "rxu", "txu"; + dmas = <&audma0 0x13>, <&audma1 0x14>; + dma-names = "rx", "tx"; }; }; - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; + rcar_sound,ssiu { + ssiu00: ssiu-0 { + dmas = <&audma0 0x15>, <&audma1 0x16>; + dma-names = "rx", "tx"; }; - port@1 { - reg = <1>; + ssiu01: ssiu-1 { + dmas = <&audma0 0x35>, <&audma1 0x36>; + dma-names = "rx", "tx"; + }; + ssiu02: ssiu-2 { + dmas = <&audma0 0x37>, <&audma1 0x38>; + dma-names = "rx", "tx"; + }; + ssiu03: ssiu-3 { + dmas = <&audma0 0x47>, <&audma1 0x48>; + dma-names = "rx", "tx"; + }; + ssiu04: ssiu-4 { + dmas = <&audma0 0x3F>, <&audma1 0x40>; + dma-names = "rx", "tx"; + }; + ssiu05: ssiu-5 { + dmas = <&audma0 0x43>, <&audma1 0x44>; + dma-names = "rx", "tx"; + }; + ssiu06: ssiu-6 { + dmas = <&audma0 0x4F>, <&audma1 0x50>; + dma-names = "rx", "tx"; + }; + ssiu07: ssiu-7 { + dmas = <&audma0 0x53>, <&audma1 0x54>; + dma-names = "rx", "tx"; + }; + ssiu10: ssiu-8 { + dmas = <&audma0 0x49>, <&audma1 0x4a>; + dma-names = "rx", "tx"; + }; + ssiu11: ssiu-9 { + dmas = <&audma0 0x4B>, <&audma1 0x4C>; + dma-names = "rx", "tx"; + }; + ssiu12: ssiu-10 { + dmas = <&audma0 0x57>, <&audma1 0x58>; + dma-names = "rx", "tx"; + }; + ssiu13: ssiu-11 { + dmas = <&audma0 0x59>, <&audma1 0x5A>; + dma-names = "rx", "tx"; + }; + ssiu14: ssiu-12 { + dmas = <&audma0 0x5F>, <&audma1 0x60>; + dma-names = "rx", "tx"; + }; + ssiu15: ssiu-13 { + dmas = <&audma0 0xC3>, <&audma1 0xC4>; + dma-names = "rx", "tx"; + }; + ssiu16: ssiu-14 { + dmas = <&audma0 0xC7>, <&audma1 0xC8>; + dma-names = "rx", "tx"; + }; + ssiu17: ssiu-15 { + dmas = <&audma0 0xCB>, <&audma1 0xCC>; + dma-names = "rx", "tx"; + }; + ssiu20: ssiu-16 { + dmas = <&audma0 0x63>, <&audma1 0x64>; + dma-names = "rx", "tx"; + }; + ssiu21: ssiu-17 { + dmas = <&audma0 0x67>, <&audma1 0x68>; + dma-names = "rx", "tx"; + }; + ssiu22: ssiu-18 { + dmas = <&audma0 0x6B>, <&audma1 0x6C>; + dma-names = "rx", "tx"; + }; + ssiu23: ssiu-19 { + dmas = <&audma0 0x6D>, <&audma1 0x6E>; + dma-names = "rx", "tx"; + }; + ssiu24: ssiu-20 { + dmas = <&audma0 0xCF>, <&audma1 0xCE>; + dma-names = "rx", "tx"; + }; + ssiu25: ssiu-21 { + dmas = <&audma0 0xEB>, <&audma1 0xEC>; + dma-names = "rx", "tx"; + }; + ssiu26: ssiu-22 { + dmas = <&audma0 0xED>, <&audma1 0xEE>; + dma-names = "rx", "tx"; + }; + ssiu27: ssiu-23 { + dmas = <&audma0 0xEF>, <&audma1 0xF0>; + dma-names = "rx", "tx"; + }; + ssiu30: ssiu-24 { + dmas = <&audma0 0x6f>, <&audma1 0x70>; + dma-names = "rx", "tx"; + }; + ssiu31: ssiu-25 { + dmas = <&audma0 0x21>, <&audma1 0x22>; + dma-names = "rx", "tx"; + }; + ssiu32: ssiu-26 { + dmas = <&audma0 0x23>, <&audma1 0x24>; + dma-names = "rx", "tx"; + }; + ssiu33: ssiu-27 { + dmas = <&audma0 0x25>, <&audma1 0x26>; + dma-names = "rx", "tx"; + }; + ssiu34: ssiu-28 { + dmas = <&audma0 0x27>, <&audma1 0x28>; + dma-names = "rx", "tx"; + }; + ssiu35: ssiu-29 { + dmas = <&audma0 0x29>, <&audma1 0x2A>; + dma-names = "rx", "tx"; + }; + ssiu36: ssiu-30 { + dmas = <&audma0 0x2B>, <&audma1 0x2C>; + dma-names = "rx", "tx"; + }; + ssiu37: ssiu-31 { + dmas = <&audma0 0x2D>, <&audma1 0x2E>; + dma-names = "rx", "tx"; + }; + ssiu40: ssiu-32 { + dmas = <&audma0 0x71>, <&audma1 0x72>; + dma-names = "rx", "tx"; + }; + ssiu41: ssiu-33 { + dmas = <&audma0 0x17>, <&audma1 0x18>; + dma-names = "rx", "tx"; + }; + ssiu42: ssiu-34 { + dmas = <&audma0 0x19>, <&audma1 0x1A>; + dma-names = "rx", "tx"; + }; + ssiu43: ssiu-35 { + dmas = <&audma0 0x1B>, <&audma1 0x1C>; + dma-names = "rx", "tx"; + }; + ssiu44: ssiu-36 { + dmas = <&audma0 0x1D>, <&audma1 0x1E>; + dma-names = "rx", "tx"; + }; + ssiu45: ssiu-37 { + dmas = <&audma0 0x1F>, <&audma1 0x20>; + dma-names = "rx", "tx"; + }; + ssiu46: ssiu-38 { + dmas = <&audma0 0x31>, <&audma1 0x32>; + dma-names = "rx", "tx"; + }; + ssiu47: ssiu-39 { + dmas = <&audma0 0x33>, <&audma1 0x34>; + dma-names = "rx", "tx"; + }; + ssiu50: ssiu-40 { + dmas = <&audma0 0x73>, <&audma1 0x74>; + dma-names = "rx", "tx"; + }; + ssiu60: ssiu-41 { + dmas = <&audma0 0x75>, <&audma1 0x76>; + dma-names = "rx", "tx"; + }; + ssiu70: ssiu-42 { + dmas = <&audma0 0x79>, <&audma1 0x7a>; + dma-names = "rx", "tx"; + }; + ssiu80: ssiu-43 { + dmas = <&audma0 0x7b>, <&audma1 0x7c>; + dma-names = "rx", "tx"; + }; + ssiu90: ssiu-44 { + dmas = <&audma0 0x7d>, <&audma1 0x7e>; + dma-names = "rx", "tx"; + }; + ssiu91: ssiu-45 { + dmas = <&audma0 0x7F>, <&audma1 0x80>; + dma-names = "rx", "tx"; + }; + ssiu92: ssiu-46 { + dmas = <&audma0 0x81>, <&audma1 0x82>; + dma-names = "rx", "tx"; + }; + ssiu93: ssiu-47 { + dmas = <&audma0 0x83>, <&audma1 0x84>; + dma-names = "rx", "tx"; + }; + ssiu94: ssiu-48 { + dmas = <&audma0 0xA3>, <&audma1 0xA4>; + dma-names = "rx", "tx"; + }; + ssiu95: ssiu-49 { + dmas = <&audma0 0xA5>, <&audma1 0xA6>; + dma-names = "rx", "tx"; + }; + ssiu96: ssiu-50 { + dmas = <&audma0 0xA7>, <&audma1 0xA8>; + dma-names = "rx", "tx"; + }; + ssiu97: ssiu-51 { + dmas = <&audma0 0xA9>, <&audma1 0xAA>; + dma-names = "rx", "tx"; }; }; }; @@ -2506,6 +2746,18 @@ thermal-sensors = <&tsc 2>; sustainable-power = <3874>; + cooling-maps { + map0 { + trip = <&target>; + cooling-device = <&a57_0 0 2>; + contribution = <1024>; + }; + map1 { + trip = <&target>; + cooling-device = <&a53_0 0 2>; + contribution = <1024>; + }; + }; trips { target: trip-point1 { temperature = <100000>; @@ -2519,18 +2771,6 @@ type = "critical"; }; }; - cooling-maps { - map0 { - trip = <&target>; - cooling-device = <&a57_0 0 2>; - contribution = <1024>; - }; - map1 { - trip = <&target>; - cooling-device = <&a53_0 0 2>; - contribution = <1024>; - }; - }; }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a774c0-cat874.dts b/arch/arm64/boot/dts/renesas/r8a774c0-cat874.dts index 46a77eefa53614054cdd9ec5f219caf25ff4d920..c99b1dec52ef65f8519a296c309103060397b5ac 100644 --- a/arch/arm64/boot/dts/renesas/r8a774c0-cat874.dts +++ b/arch/arm64/boot/dts/renesas/r8a774c0-cat874.dts @@ -65,6 +65,15 @@ reg = <0x0 0x48000000 0x0 0x78000000>; }; + reg_12p0v: regulator-12p0v { + compatible = "regulator-fixed"; + regulator-name = "D12.0V"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-boot-on; + regulator-always-on; + }; + sound: sound { compatible = "simple-audio-card"; @@ -73,13 +82,13 @@ simple-audio-card,bitclock-master = <&sndcpu>; simple-audio-card,frame-master = <&sndcpu>; - sndcpu: simple-audio-card,cpu { - sound-dai = <&rcar_sound>; - }; - sndcodec: simple-audio-card,codec { sound-dai = <&tda19988>; }; + + sndcpu: simple-audio-card,cpu { + sound-dai = <&rcar_sound>; + }; }; vcc_sdhi0: regulator-vcc-sdhi0 { @@ -271,16 +280,16 @@ function = "du"; }; - i2c1_pins: i2c1 { - groups = "i2c1_b"; - function = "i2c1"; - }; - hscif2_pins: hscif2 { groups = "hscif2_data_a", "hscif2_ctrl_a"; function = "hscif2"; }; + i2c1_pins: i2c1 { + groups = "i2c1_b"; + function = "i2c1"; + }; + scif2_pins: scif2 { groups = "scif2_data_a"; function = "scif2"; @@ -304,16 +313,16 @@ power-source = <1800>; }; - sound_pins: sound { - groups = "ssi01239_ctrl", "ssi0_data"; - function = "ssi"; - }; - sound_clk_pins: sound_clk { groups = "audio_clkout1_a"; function = "audio_clk"; }; + sound_pins: sound { + groups = "ssi01239_ctrl", "ssi0_data"; + function = "ssi"; + }; + usb30_pins: usb30 { groups = "usb30", "usb30_id"; function = "usb30"; diff --git a/arch/arm64/boot/dts/renesas/r8a774c0.dtsi b/arch/arm64/boot/dts/renesas/r8a774c0.dtsi index e7b5bf23f978b846b5cacffb5da2b9cb18f1c285..a1c2de90e4706ba3d91e4d83f8defa15f213caad 100644 --- a/arch/arm64/boot/dts/renesas/r8a774c0.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a774c0.dtsi @@ -973,6 +973,8 @@ <&cpg CPG_CORE R8A774C0_CLK_CANFD>, <&can_clk>; clock-names = "clkp1", "clkp2", "can_clk"; + assigned-clocks = <&cpg CPG_CORE R8A774C0_CLK_CANFD>; + assigned-clock-rates = <40000000>; power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>; resets = <&cpg 916>; status = "disabled"; @@ -987,6 +989,8 @@ <&cpg CPG_CORE R8A774C0_CLK_CANFD>, <&can_clk>; clock-names = "clkp1", "clkp2", "can_clk"; + assigned-clocks = <&cpg CPG_CORE R8A774C0_CLK_CANFD>; + assigned-clock-rates = <40000000>; power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>; resets = <&cpg 915>; status = "disabled"; @@ -1367,6 +1371,17 @@ "ssi.1", "ssi.0"; status = "disabled"; + rcar_sound,ctu { + ctu00: ctu-0 { }; + ctu01: ctu-1 { }; + ctu02: ctu-2 { }; + ctu03: ctu-3 { }; + ctu10: ctu-4 { }; + ctu11: ctu-5 { }; + ctu12: ctu-6 { }; + ctu13: ctu-7 { }; + }; + rcar_sound,dvc { dvc0: dvc-0 { dmas = <&audma0 0xbc>; @@ -1383,17 +1398,6 @@ mix1: mix-1 { }; }; - rcar_sound,ctu { - ctu00: ctu-0 { }; - ctu01: ctu-1 { }; - ctu02: ctu-2 { }; - ctu03: ctu-3 { }; - ctu10: ctu-4 { }; - ctu11: ctu-5 { }; - ctu12: ctu-6 { }; - ctu13: ctu-7 { }; - }; - rcar_sound,src { src0: src-0 { interrupts = ; @@ -1702,13 +1706,24 @@ renesas,fcp = <&fcpvb0>; }; - fcpvb0: fcp@fe96f000 { - compatible = "renesas,fcpv"; - reg = <0 0xfe96f000 0 0x200>; - clocks = <&cpg CPG_MOD 607>; + vspd0: vsp@fea20000 { + compatible = "renesas,vsp2"; + reg = <0 0xfea20000 0 0x7000>; + interrupts = ; + clocks = <&cpg CPG_MOD 623>; power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>; - resets = <&cpg 607>; - iommus = <&ipmmu_vp0 5>; + resets = <&cpg 623>; + renesas,fcp = <&fcpvd0>; + }; + + vspd1: vsp@fea28000 { + compatible = "renesas,vsp2"; + reg = <0 0xfea28000 0 0x7000>; + interrupts = ; + clocks = <&cpg CPG_MOD 622>; + power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>; + resets = <&cpg 622>; + renesas,fcp = <&fcpvd1>; }; vspi0: vsp@fe9a0000 { @@ -1721,23 +1736,13 @@ renesas,fcp = <&fcpvi0>; }; - fcpvi0: fcp@fe9af000 { + fcpvb0: fcp@fe96f000 { compatible = "renesas,fcpv"; - reg = <0 0xfe9af000 0 0x200>; - clocks = <&cpg CPG_MOD 611>; - power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>; - resets = <&cpg 611>; - iommus = <&ipmmu_vp0 8>; - }; - - vspd0: vsp@fea20000 { - compatible = "renesas,vsp2"; - reg = <0 0xfea20000 0 0x7000>; - interrupts = ; - clocks = <&cpg CPG_MOD 623>; + reg = <0 0xfe96f000 0 0x200>; + clocks = <&cpg CPG_MOD 607>; power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>; - resets = <&cpg 623>; - renesas,fcp = <&fcpvd0>; + resets = <&cpg 607>; + iommus = <&ipmmu_vp0 5>; }; fcpvd0: fcp@fea27000 { @@ -1749,16 +1754,6 @@ iommus = <&ipmmu_vi0 8>; }; - vspd1: vsp@fea28000 { - compatible = "renesas,vsp2"; - reg = <0 0xfea28000 0 0x7000>; - interrupts = ; - clocks = <&cpg CPG_MOD 622>; - power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>; - resets = <&cpg 622>; - renesas,fcp = <&fcpvd1>; - }; - fcpvd1: fcp@fea2f000 { compatible = "renesas,fcpv"; reg = <0 0xfea2f000 0 0x200>; @@ -1768,6 +1763,15 @@ iommus = <&ipmmu_vi0 9>; }; + fcpvi0: fcp@fe9af000 { + compatible = "renesas,fcpv"; + reg = <0 0xfe9af000 0 0x200>; + clocks = <&cpg CPG_MOD 611>; + power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>; + resets = <&cpg 611>; + iommus = <&ipmmu_vp0 8>; + }; + csi40: csi2@feaa0000 { compatible = "renesas,r8a774c0-csi2"; reg = <0 0xfeaa0000 0 0x10000>; @@ -1801,13 +1805,13 @@ du: display@feb00000 { compatible = "renesas,du-r8a774c0"; - reg = <0 0xfeb00000 0 0x80000>; + reg = <0 0xfeb00000 0 0x40000>; interrupts = , ; clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>; clock-names = "du.0", "du.1"; - vsps = <&vspd0 0 &vspd1 0>; + vsps = <&vspd0 0>, <&vspd1 0>; status = "disabled"; ports { @@ -1844,6 +1848,8 @@ resets = <&cpg 727>; status = "disabled"; + renesas,companion = <&lvds1>; + ports { #address-cells = <1>; #size-cells = <0>; @@ -1902,6 +1908,9 @@ polling-delay = <1000>; thermal-sensors = <&thermal>; + cooling-maps { + }; + trips { cpu-crit { temperature = <120000>; @@ -1909,9 +1918,6 @@ type = "critical"; }; }; - - cooling-maps { - }; }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts index c1a56eab7b2483dbf102cd9f33ed7177ab4a6a61..c72968623e94b79047a794c6edfcaa66847594df 100644 --- a/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts +++ b/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts @@ -52,12 +52,6 @@ status = "okay"; }; -&sound_card { - dais = <&rsnd_port0 /* ak4613 */ - &rsnd_port1 /* HDMI0 */ - &rsnd_port2>; /* HDMI1 */ -}; - &hdmi0 { status = "okay"; @@ -108,6 +102,13 @@ status = "okay"; }; +&pfc { + usb2_pins: usb2 { + groups = "usb2"; + function = "usb2"; + }; +}; + &rcar_sound { ports { /* rsnd_port0 is on salvator-common */ @@ -138,17 +139,16 @@ }; }; -&pfc { - usb2_pins: usb2 { - groups = "usb2"; - function = "usb2"; - }; -}; - &sata { status = "okay"; }; +&sound_card { + dais = <&rsnd_port0 /* ak4613 */ + &rsnd_port1 /* HDMI0 */ + &rsnd_port2>; /* HDMI1 */ +}; + &usb2_phy2 { pinctrl-0 = <&usb2_pins>; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi b/arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi index 40d10daca85201aaeed0f920255db40ed7e68e14..e4650ae5b75aca81b0fd5a67d0217086993ef32c 100644 --- a/arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi @@ -7,22 +7,75 @@ #include "r8a7795.dtsi" -&soc { - xhci1: usb@ee040000 { - compatible = "renesas,xhci-r8a7795", "renesas,rcar-gen3-xhci"; - reg = <0 0xee040000 0 0xc00>; - interrupts = ; - clocks = <&cpg CPG_MOD 327>; - power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; - resets = <&cpg 327>; - status = "disabled"; - }; +&audma0 { + iommus = <&ipmmu_mp1 0>, <&ipmmu_mp1 1>, + <&ipmmu_mp1 2>, <&ipmmu_mp1 3>, + <&ipmmu_mp1 4>, <&ipmmu_mp1 5>, + <&ipmmu_mp1 6>, <&ipmmu_mp1 7>, + <&ipmmu_mp1 8>, <&ipmmu_mp1 9>, + <&ipmmu_mp1 10>, <&ipmmu_mp1 11>, + <&ipmmu_mp1 12>, <&ipmmu_mp1 13>, + <&ipmmu_mp1 14>, <&ipmmu_mp1 15>; +}; - /delete-node/ mmu@febe0000; - /delete-node/ mmu@fe980000; - /delete-node/ mmu@fd950000; - /delete-node/ mmu@fd960000; - /delete-node/ mmu@fd970000; +&audma1 { + iommus = <&ipmmu_mp1 16>, <&ipmmu_mp1 17>, + <&ipmmu_mp1 18>, <&ipmmu_mp1 19>, + <&ipmmu_mp1 20>, <&ipmmu_mp1 21>, + <&ipmmu_mp1 22>, <&ipmmu_mp1 23>, + <&ipmmu_mp1 24>, <&ipmmu_mp1 25>, + <&ipmmu_mp1 26>, <&ipmmu_mp1 27>, + <&ipmmu_mp1 28>, <&ipmmu_mp1 29>, + <&ipmmu_mp1 30>, <&ipmmu_mp1 31>; +}; + +&du { + vsps = <&vspd0 &vspd1 &vspd2 &vspd3>; +}; + +&fcpvb1 { + iommus = <&ipmmu_vp0 7>; +}; + +&fcpf1 { + iommus = <&ipmmu_vp0 1>; +}; + +&fcpvi1 { + iommus = <&ipmmu_vp0 9>; +}; + +&fcpvd2 { + iommus = <&ipmmu_vi0 10>; +}; + +&gpio1 { + gpio-ranges = <&pfc 0 32 28>; +}; + +&ipmmu_vi0 { + renesas,ipmmu-main = <&ipmmu_mm 11>; +}; + +&ipmmu_vp0 { + renesas,ipmmu-main = <&ipmmu_mm 12>; +}; + +&ipmmu_vc0 { + renesas,ipmmu-main = <&ipmmu_mm 9>; +}; + +&ipmmu_vc1 { + renesas,ipmmu-main = <&ipmmu_mm 10>; +}; + +&ipmmu_rt { + renesas,ipmmu-main = <&ipmmu_mm 7>; +}; + +&soc { + /delete-node/ dma-controller@e6460000; + /delete-node/ dma-controller@e6470000; ipmmu_mp1: mmu@ec680000 { compatible = "renesas,ipmmu-r8a7795"; @@ -40,13 +93,37 @@ #iommu-cells = <1>; }; - /delete-node/ usb-phy@ee0e0200; - /delete-node/ usb@ee0e0100; - /delete-node/ usb@ee0e0000; + /delete-node/ mmu@fd950000; + /delete-node/ mmu@fd960000; + /delete-node/ mmu@fd970000; + /delete-node/ mmu@febe0000; + /delete-node/ mmu@fe980000; + + xhci1: usb@ee040000 { + compatible = "renesas,xhci-r8a7795", "renesas,rcar-gen3-xhci"; + reg = <0 0xee040000 0 0xc00>; + interrupts = ; + clocks = <&cpg CPG_MOD 327>; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 327>; + status = "disabled"; + }; + /delete-node/ usb@e659c000; + /delete-node/ usb@ee0e0000; + /delete-node/ usb@ee0e0100; - /delete-node/ dma-controller@e6460000; - /delete-node/ dma-controller@e6470000; + /delete-node/ usb-phy@ee0e0200; + + fdp1@fe948000 { + compatible = "renesas,fdp1"; + reg = <0 0xfe948000 0 0x2400>; + interrupts = ; + clocks = <&cpg CPG_MOD 117>; + power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 117>; + renesas,fcp = <&fcpf2>; + }; fcpf2: fcp@fe952000 { compatible = "renesas,fcpf"; @@ -57,15 +134,13 @@ iommus = <&ipmmu_vp0 2>; }; - vspi2: vsp@fe9c0000 { - compatible = "renesas,vsp2"; - reg = <0 0xfe9c0000 0 0x8000>; - interrupts = ; - clocks = <&cpg CPG_MOD 629>; - power-domains = <&sysc R8A7795_PD_A3VP>; - resets = <&cpg 629>; - - renesas,fcp = <&fcpvi2>; + fcpvd3: fcp@fea3f000 { + compatible = "renesas,fcpv"; + reg = <0 0xfea3f000 0 0x200>; + clocks = <&cpg CPG_MOD 600>; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 600>; + iommus = <&ipmmu_vi0 11>; }; fcpvi2: fcp@fe9cf000 { @@ -88,23 +163,15 @@ renesas,fcp = <&fcpvd3>; }; - fcpvd3: fcp@fea3f000 { - compatible = "renesas,fcpv"; - reg = <0 0xfea3f000 0 0x200>; - clocks = <&cpg CPG_MOD 600>; - power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; - resets = <&cpg 600>; - iommus = <&ipmmu_vi0 11>; - }; - - fdp1@fe948000 { - compatible = "renesas,fdp1"; - reg = <0 0xfe948000 0 0x2400>; - interrupts = ; - clocks = <&cpg CPG_MOD 117>; + vspi2: vsp@fe9c0000 { + compatible = "renesas,vsp2"; + reg = <0 0xfe9c0000 0 0x8000>; + interrupts = ; + clocks = <&cpg CPG_MOD 629>; power-domains = <&sysc R8A7795_PD_A3VP>; - resets = <&cpg 117>; - renesas,fcp = <&fcpf2>; + resets = <&cpg 629>; + + renesas,fcp = <&fcpvi2>; }; csi21: csi2@fea90000 { @@ -163,72 +230,6 @@ }; }; -&gpio1 { - gpio-ranges = <&pfc 0 32 28>; -}; - -&ipmmu_vi0 { - renesas,ipmmu-main = <&ipmmu_mm 11>; -}; - -&ipmmu_vp0 { - renesas,ipmmu-main = <&ipmmu_mm 12>; -}; - -&ipmmu_vc0 { - renesas,ipmmu-main = <&ipmmu_mm 9>; -}; - -&ipmmu_vc1 { - renesas,ipmmu-main = <&ipmmu_mm 10>; -}; - -&ipmmu_rt { - renesas,ipmmu-main = <&ipmmu_mm 7>; -}; - -&audma0 { - iommus = <&ipmmu_mp1 0>, <&ipmmu_mp1 1>, - <&ipmmu_mp1 2>, <&ipmmu_mp1 3>, - <&ipmmu_mp1 4>, <&ipmmu_mp1 5>, - <&ipmmu_mp1 6>, <&ipmmu_mp1 7>, - <&ipmmu_mp1 8>, <&ipmmu_mp1 9>, - <&ipmmu_mp1 10>, <&ipmmu_mp1 11>, - <&ipmmu_mp1 12>, <&ipmmu_mp1 13>, - <&ipmmu_mp1 14>, <&ipmmu_mp1 15>; -}; - -&audma1 { - iommus = <&ipmmu_mp1 16>, <&ipmmu_mp1 17>, - <&ipmmu_mp1 18>, <&ipmmu_mp1 19>, - <&ipmmu_mp1 20>, <&ipmmu_mp1 21>, - <&ipmmu_mp1 22>, <&ipmmu_mp1 23>, - <&ipmmu_mp1 24>, <&ipmmu_mp1 25>, - <&ipmmu_mp1 26>, <&ipmmu_mp1 27>, - <&ipmmu_mp1 28>, <&ipmmu_mp1 29>, - <&ipmmu_mp1 30>, <&ipmmu_mp1 31>; -}; - -&fcpvb1 { - iommus = <&ipmmu_vp0 7>; -}; - -&fcpf1 { - iommus = <&ipmmu_vp0 1>; -}; - -&fcpvi1 { - iommus = <&ipmmu_vp0 9>; -}; - -&fcpvd2 { - iommus = <&ipmmu_vi0 10>; -}; - -&du { - vsps = <&vspd0 &vspd1 &vspd2 &vspd3>; -}; - &vin0 { ports { port@1 { diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts index d2d48b33b37f471b504b289bd909e6ab772b7c37..72874f675359e7a4060553732a10dafb21f33d85 100644 --- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts +++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts @@ -52,12 +52,6 @@ status = "okay"; }; -&sound_card { - dais = <&rsnd_port0 /* ak4613 */ - &rsnd_port1 /* HDMI0 */ - &rsnd_port2>; /* HDMI1 */ -}; - &hdmi0 { status = "okay"; @@ -108,6 +102,13 @@ status = "okay"; }; +&pfc { + usb2_pins: usb2 { + groups = "usb2"; + function = "usb2"; + }; +}; + &rcar_sound { ports { /* rsnd_port0 is on salvator-common */ @@ -138,17 +139,16 @@ }; }; -&pfc { - usb2_pins: usb2 { - groups = "usb2"; - function = "usb2"; - }; -}; - &sata { status = "okay"; }; +&sound_card { + dais = <&rsnd_port0 /* ak4613 */ + &rsnd_port1 /* HDMI0 */ + &rsnd_port2>; /* HDMI1 */ +}; + &usb2_phy2 { pinctrl-0 = <&usb2_pins>; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts index 42101fc76837a0e3138f12c38af6a39c4cf355a0..36667c81d43d517b2e8dea66ab486520aa5eec3a 100644 --- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts +++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts @@ -57,17 +57,6 @@ status = "okay"; }; -&hsusb3 { - dr_mode = "otg"; - status = "okay"; -}; - -&sound_card { - dais = <&rsnd_port0 /* ak4613 */ - &rsnd_port1 /* HDMI0 */ - &rsnd_port2>; /* HDMI1 */ -}; - &hdmi0 { status = "okay"; @@ -114,6 +103,11 @@ remote-endpoint = <&rcar_dw_hdmi1_out>; }; +&hsusb3 { + dr_mode = "otg"; + status = "okay"; +}; + &ohci2 { status = "okay"; }; @@ -123,36 +117,6 @@ status = "okay"; }; -&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_port2: port@2 { - reg = <2>; - rsnd_endpoint2: endpoint { - remote-endpoint = <&dw_hdmi1_snd_in>; - - dai-format = "i2s"; - bitclock-master = <&rsnd_endpoint2>; - frame-master = <&rsnd_endpoint2>; - - playback = <&ssi3>; - }; - }; - }; -}; - &pca9654 { pcie_sata_switch { gpio-hog; @@ -186,11 +150,47 @@ }; }; +&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_port2: port@2 { + reg = <2>; + rsnd_endpoint2: endpoint { + remote-endpoint = <&dw_hdmi1_snd_in>; + + dai-format = "i2s"; + bitclock-master = <&rsnd_endpoint2>; + frame-master = <&rsnd_endpoint2>; + + playback = <&ssi3>; + }; + }; + }; +}; + /* 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 */ + &rsnd_port2>; /* HDMI1 */ +}; + &usb2_phy2 { pinctrl-0 = <&usb2_pins>; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi index 1745ac4b307eb0eee9240edbad08e52a8b6861ea..95deff66eeb6111e2cdc5de8b957ee586d841b46 100644 --- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi @@ -2731,6 +2731,83 @@ resets = <&cpg 820>; }; + vspbc: vsp@fe920000 { + compatible = "renesas,vsp2"; + reg = <0 0xfe920000 0 0x8000>; + interrupts = ; + clocks = <&cpg CPG_MOD 624>; + power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 624>; + + renesas,fcp = <&fcpvb1>; + }; + + vspbd: vsp@fe960000 { + compatible = "renesas,vsp2"; + reg = <0 0xfe960000 0 0x8000>; + interrupts = ; + clocks = <&cpg CPG_MOD 626>; + power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 626>; + + renesas,fcp = <&fcpvb0>; + }; + + vspd0: vsp@fea20000 { + compatible = "renesas,vsp2"; + reg = <0 0xfea20000 0 0x5000>; + interrupts = ; + clocks = <&cpg CPG_MOD 623>; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 623>; + + renesas,fcp = <&fcpvd0>; + }; + + vspd1: vsp@fea28000 { + compatible = "renesas,vsp2"; + reg = <0 0xfea28000 0 0x5000>; + interrupts = ; + clocks = <&cpg CPG_MOD 622>; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 622>; + + renesas,fcp = <&fcpvd1>; + }; + + vspd2: vsp@fea30000 { + compatible = "renesas,vsp2"; + reg = <0 0xfea30000 0 0x5000>; + interrupts = ; + clocks = <&cpg CPG_MOD 621>; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 621>; + + renesas,fcp = <&fcpvd2>; + }; + + vspi0: vsp@fe9a0000 { + compatible = "renesas,vsp2"; + reg = <0 0xfe9a0000 0 0x8000>; + interrupts = ; + clocks = <&cpg CPG_MOD 631>; + power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 631>; + + renesas,fcp = <&fcpvi0>; + }; + + vspi1: vsp@fe9b0000 { + compatible = "renesas,vsp2"; + reg = <0 0xfe9b0000 0 0x8000>; + interrupts = ; + clocks = <&cpg CPG_MOD 630>; + power-domains = <&sysc R8A7795_PD_A3VP>; + resets = <&cpg 630>; + + renesas,fcp = <&fcpvi1>; + }; + fdp1@fe940000 { compatible = "renesas,fdp1"; reg = <0 0xfe940000 0 0x2400>; @@ -2832,83 +2909,6 @@ iommus = <&ipmmu_vi1 10>; }; - vspbd: vsp@fe960000 { - compatible = "renesas,vsp2"; - reg = <0 0xfe960000 0 0x8000>; - interrupts = ; - clocks = <&cpg CPG_MOD 626>; - power-domains = <&sysc R8A7795_PD_A3VP>; - resets = <&cpg 626>; - - renesas,fcp = <&fcpvb0>; - }; - - vspbc: vsp@fe920000 { - compatible = "renesas,vsp2"; - reg = <0 0xfe920000 0 0x8000>; - interrupts = ; - clocks = <&cpg CPG_MOD 624>; - power-domains = <&sysc R8A7795_PD_A3VP>; - resets = <&cpg 624>; - - renesas,fcp = <&fcpvb1>; - }; - - vspd0: vsp@fea20000 { - compatible = "renesas,vsp2"; - reg = <0 0xfea20000 0 0x5000>; - interrupts = ; - clocks = <&cpg CPG_MOD 623>; - power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; - resets = <&cpg 623>; - - renesas,fcp = <&fcpvd0>; - }; - - vspd1: vsp@fea28000 { - compatible = "renesas,vsp2"; - reg = <0 0xfea28000 0 0x5000>; - interrupts = ; - clocks = <&cpg CPG_MOD 622>; - power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; - resets = <&cpg 622>; - - renesas,fcp = <&fcpvd1>; - }; - - vspd2: vsp@fea30000 { - compatible = "renesas,vsp2"; - reg = <0 0xfea30000 0 0x5000>; - interrupts = ; - clocks = <&cpg CPG_MOD 621>; - power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; - resets = <&cpg 621>; - - renesas,fcp = <&fcpvd2>; - }; - - vspi0: vsp@fe9a0000 { - compatible = "renesas,vsp2"; - reg = <0 0xfe9a0000 0 0x8000>; - interrupts = ; - clocks = <&cpg CPG_MOD 631>; - power-domains = <&sysc R8A7795_PD_A3VP>; - resets = <&cpg 631>; - - renesas,fcp = <&fcpvi0>; - }; - - vspi1: vsp@fe9b0000 { - compatible = "renesas,vsp2"; - reg = <0 0xfe9b0000 0 0x8000>; - interrupts = ; - clocks = <&cpg CPG_MOD 630>; - power-domains = <&sysc R8A7795_PD_A3VP>; - resets = <&cpg 630>; - - renesas,fcp = <&fcpvi1>; - }; - csi20: csi2@fea80000 { compatible = "renesas,r8a7795-csi2"; reg = <0 0xfea80000 0 0x10000>; @@ -3112,7 +3112,7 @@ <&cpg CPG_MOD 722>, <&cpg CPG_MOD 721>; clock-names = "du.0", "du.1", "du.2", "du.3"; - vsps = <&vspd0 0 &vspd1 0 &vspd2 0 &vspd0 1>; + vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd0 1>; status = "disabled"; ports { diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts index 2aefa53cb16b8cf18a06951e49ea76a3d289e81b..de37e91e3b7ac31dd48185f2d3ed3051b0f0067f 100644 --- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts +++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts @@ -36,11 +36,6 @@ "dclkin.0", "dclkin.1", "dclkin.2"; }; -&sound_card { - dais = <&rsnd_port0 /* ak4613 */ - &rsnd_port1>; /* HDMI0 */ -}; - &hdmi0 { status = "okay"; @@ -81,3 +76,8 @@ }; }; }; + +&sound_card { + dais = <&rsnd_port0 /* ak4613 */ + &rsnd_port1>; /* HDMI0 */ +}; diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts index d58ede18108d1accbd7d5b538dd719cec34ee305..a1cbfef2053fe40812258a96ac75f3a649a9fe48 100644 --- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts +++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts @@ -36,11 +36,6 @@ "dclkin.0", "dclkin.1", "dclkin.2"; }; -&sound_card { - dais = <&rsnd_port0 /* ak4613 */ - &rsnd_port1>; /* HDMI0 */ -}; - &hdmi0 { status = "okay"; @@ -81,3 +76,8 @@ }; }; }; + +&sound_card { + dais = <&rsnd_port0 /* ak4613 */ + &rsnd_port1>; /* HDMI0 */ +}; diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi index 26df5b88efd761e41f6ff006557a580baccf54a8..3dc9d73f589af25b593ad93a4d11482c688b0107 100644 --- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi @@ -1833,6 +1833,17 @@ "ssi.1", "ssi.0"; status = "disabled"; + rcar_sound,ctu { + ctu00: ctu-0 { }; + ctu01: ctu-1 { }; + ctu02: ctu-2 { }; + ctu03: ctu-3 { }; + ctu10: ctu-4 { }; + ctu11: ctu-5 { }; + ctu12: ctu-6 { }; + ctu13: ctu-7 { }; + }; + rcar_sound,dvc { dvc0: dvc-0 { dmas = <&audma1 0xbc>; @@ -1849,17 +1860,6 @@ mix1: mix-1 { }; }; - rcar_sound,ctu { - ctu00: ctu-0 { }; - ctu01: ctu-1 { }; - ctu02: ctu-2 { }; - ctu03: ctu-3 { }; - ctu10: ctu-4 { }; - ctu11: ctu-5 { }; - ctu12: ctu-6 { }; - ctu13: ctu-7 { }; - }; - rcar_sound,src { src0: src-0 { interrupts = ; @@ -1913,6 +1913,59 @@ }; }; + rcar_sound,ssi { + ssi0: ssi-0 { + interrupts = ; + dmas = <&audma0 0x01>, <&audma1 0x02>; + dma-names = "rx", "tx"; + }; + ssi1: ssi-1 { + interrupts = ; + dmas = <&audma0 0x03>, <&audma1 0x04>; + dma-names = "rx", "tx"; + }; + ssi2: ssi-2 { + interrupts = ; + dmas = <&audma0 0x05>, <&audma1 0x06>; + dma-names = "rx", "tx"; + }; + ssi3: ssi-3 { + interrupts = ; + dmas = <&audma0 0x07>, <&audma1 0x08>; + dma-names = "rx", "tx"; + }; + ssi4: ssi-4 { + interrupts = ; + dmas = <&audma0 0x09>, <&audma1 0x0a>; + dma-names = "rx", "tx"; + }; + ssi5: ssi-5 { + interrupts = ; + dmas = <&audma0 0x0b>, <&audma1 0x0c>; + dma-names = "rx", "tx"; + }; + ssi6: ssi-6 { + interrupts = ; + dmas = <&audma0 0x0d>, <&audma1 0x0e>; + dma-names = "rx", "tx"; + }; + ssi7: ssi-7 { + interrupts = ; + dmas = <&audma0 0x0f>, <&audma1 0x10>; + dma-names = "rx", "tx"; + }; + ssi8: ssi-8 { + interrupts = ; + dmas = <&audma0 0x11>, <&audma1 0x12>; + dma-names = "rx", "tx"; + }; + ssi9: ssi-9 { + interrupts = ; + dmas = <&audma0 0x13>, <&audma1 0x14>; + dma-names = "rx", "tx"; + }; + }; + rcar_sound,ssiu { ssiu00: ssiu-0 { dmas = <&audma0 0x15>, <&audma1 0x16>; @@ -2123,59 +2176,6 @@ dma-names = "rx", "tx"; }; }; - - rcar_sound,ssi { - ssi0: ssi-0 { - interrupts = ; - dmas = <&audma0 0x01>, <&audma1 0x02>; - dma-names = "rx", "tx"; - }; - ssi1: ssi-1 { - interrupts = ; - dmas = <&audma0 0x03>, <&audma1 0x04>; - dma-names = "rx", "tx"; - }; - ssi2: ssi-2 { - interrupts = ; - dmas = <&audma0 0x05>, <&audma1 0x06>; - dma-names = "rx", "tx"; - }; - ssi3: ssi-3 { - interrupts = ; - dmas = <&audma0 0x07>, <&audma1 0x08>; - dma-names = "rx", "tx"; - }; - ssi4: ssi-4 { - interrupts = ; - dmas = <&audma0 0x09>, <&audma1 0x0a>; - dma-names = "rx", "tx"; - }; - ssi5: ssi-5 { - interrupts = ; - dmas = <&audma0 0x0b>, <&audma1 0x0c>; - dma-names = "rx", "tx"; - }; - ssi6: ssi-6 { - interrupts = ; - dmas = <&audma0 0x0d>, <&audma1 0x0e>; - dma-names = "rx", "tx"; - }; - ssi7: ssi-7 { - interrupts = ; - dmas = <&audma0 0x0f>, <&audma1 0x10>; - dma-names = "rx", "tx"; - }; - ssi8: ssi-8 { - interrupts = ; - dmas = <&audma0 0x11>, <&audma1 0x12>; - dma-names = "rx", "tx"; - }; - ssi9: ssi-9 { - interrupts = ; - dmas = <&audma0 0x13>, <&audma1 0x14>; - dma-names = "rx", "tx"; - }; - }; }; audma0: dma-controller@ec700000 { @@ -2860,6 +2860,18 @@ thermal-sensors = <&tsc 2>; sustainable-power = <3874>; + cooling-maps { + map0 { + trip = <&target>; + cooling-device = <&a57_0 2 4>; + contribution = <1024>; + }; + map1 { + trip = <&target>; + cooling-device = <&a53_0 0 2>; + contribution = <1024>; + }; + }; trips { target: trip-point1 { temperature = <100000>; @@ -2873,18 +2885,6 @@ type = "critical"; }; }; - cooling-maps { - map0 { - trip = <&target>; - cooling-device = <&a57_0 2 4>; - contribution = <1024>; - }; - map1 { - trip = <&target>; - cooling-device = <&a53_0 0 2>; - contribution = <1024>; - }; - }; }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts index 340a3c72b65aad6c11638768b931718ad19c02c9..660a0240eec56268cd6ad661562f496b93cb0c94 100644 --- a/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts +++ b/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts @@ -41,9 +41,37 @@ 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 f03a5e9e0c427e0dc8ac9e05d95f2a0d4d7f87d7..5cef6460546411e0a747e526241b420efa939329 100644 --- a/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts +++ b/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts @@ -41,6 +41,12 @@ remote-endpoint = <&hdmi0_con>; }; }; + port@2 { + reg = <2>; + dw_hdmi0_snd_in: endpoint { + remote-endpoint = <&rsnd_endpoint1>; + }; + }; }; }; @@ -57,7 +63,29 @@ }; }; +&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/r8a77965.dtsi b/arch/arm64/boot/dts/renesas/r8a77965.dtsi index 131f895ab778c9042c2f98366f5867b22de24841..4ae163220f6000b55e09844b75529a249dd4fd5d 100644 --- a/arch/arm64/boot/dts/renesas/r8a77965.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77965.dtsi @@ -2255,14 +2255,6 @@ renesas,fcp = <&fcpvb0>; }; - fcpvb0: fcp@fe96f000 { - compatible = "renesas,fcpv"; - reg = <0 0xfe96f000 0 0x200>; - clocks = <&cpg CPG_MOD 607>; - power-domains = <&sysc R8A77965_PD_A3VP>; - resets = <&cpg 607>; - }; - vspi0: vsp@fe9a0000 { compatible = "renesas,vsp2"; reg = <0 0xfe9a0000 0 0x8000>; @@ -2274,14 +2266,6 @@ renesas,fcp = <&fcpvi0>; }; - fcpvi0: fcp@fe9af000 { - compatible = "renesas,fcpv"; - reg = <0 0xfe9af000 0 0x200>; - clocks = <&cpg CPG_MOD 611>; - power-domains = <&sysc R8A77965_PD_A3VP>; - resets = <&cpg 611>; - }; - vspd0: vsp@fea20000 { compatible = "renesas,vsp2"; reg = <0 0xfea20000 0 0x5000>; @@ -2293,14 +2277,6 @@ renesas,fcp = <&fcpvd0>; }; - fcpvd0: fcp@fea27000 { - compatible = "renesas,fcpv"; - reg = <0 0xfea27000 0 0x200>; - clocks = <&cpg CPG_MOD 603>; - power-domains = <&sysc R8A77965_PD_ALWAYS_ON>; - resets = <&cpg 603>; - }; - vspd1: vsp@fea28000 { compatible = "renesas,vsp2"; reg = <0 0xfea28000 0 0x5000>; @@ -2312,6 +2288,22 @@ renesas,fcp = <&fcpvd1>; }; + fcpvb0: fcp@fe96f000 { + compatible = "renesas,fcpv"; + reg = <0 0xfe96f000 0 0x200>; + clocks = <&cpg CPG_MOD 607>; + power-domains = <&sysc R8A77965_PD_A3VP>; + resets = <&cpg 607>; + }; + + fcpvd0: fcp@fea27000 { + compatible = "renesas,fcpv"; + reg = <0 0xfea27000 0 0x200>; + clocks = <&cpg CPG_MOD 603>; + power-domains = <&sysc R8A77965_PD_ALWAYS_ON>; + resets = <&cpg 603>; + }; + fcpvd1: fcp@fea2f000 { compatible = "renesas,fcpv"; reg = <0 0xfea2f000 0 0x200>; @@ -2320,6 +2312,14 @@ resets = <&cpg 602>; }; + fcpvi0: fcp@fe9af000 { + compatible = "renesas,fcpv"; + reg = <0 0xfe9af000 0 0x200>; + clocks = <&cpg CPG_MOD 611>; + power-domains = <&sysc R8A77965_PD_A3VP>; + resets = <&cpg 611>; + }; + csi20: csi2@fea80000 { compatible = "renesas,r8a77965-csi2"; reg = <0 0xfea80000 0 0x10000>; @@ -2469,7 +2469,7 @@ clock-names = "du.0", "du.1", "du.3"; status = "disabled"; - vsps = <&vspd0 0 &vspd1 0 &vspd0 1>; + vsps = <&vspd0 0>, <&vspd1 0>, <&vspd0 1>; ports { #address-cells = <1>; diff --git a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts index 233f26fbec17c35c1ad4c60d585e142356dee48e..2afb91ec9c8d92cd9fc8016325780deefb3cb3c0 100644 --- a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts +++ b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts @@ -23,10 +23,13 @@ stdout-path = "serial0:115200n8"; }; - memory@48000000 { - device_type = "memory"; - /* first 128MB is reserved for secure area. */ - reg = <0x0 0x48000000 0x0 0x38000000>; + d3p3: regulator-fixed { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; }; hdmi-out { @@ -40,15 +43,6 @@ }; }; - d3p3: regulator-fixed { - compatible = "regulator-fixed"; - regulator-name = "fixed-3.3V"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - regulator-always-on; - }; - lvds-decoder { compatible = "thine,thc63lvd1024"; @@ -73,6 +67,12 @@ }; }; }; + + memory@48000000 { + device_type = "memory"; + /* first 128MB is reserved for secure area. */ + reg = <0x0 0x48000000 0x0 0x38000000>; + }; }; &avb { @@ -102,6 +102,10 @@ }; }; +&du { + status = "okay"; +}; + &extal_clk { clock-frequency = <16666666>; }; @@ -157,6 +161,18 @@ }; }; +&lvds0 { + status = "okay"; + + ports { + port@1 { + lvds0_out: endpoint { + remote-endpoint = <&thc63lvd1024_in>; + }; + }; + }; +}; + &pfc { avb_pins: avb0 { groups = "avb0_mdio", "avb0_rgmii", "avb0_txcrefclk"; @@ -190,19 +206,3 @@ status = "okay"; }; - -&du { - status = "okay"; -}; - -&lvds0 { - status = "okay"; - - ports { - port@1 { - lvds0_out: endpoint { - remote-endpoint = <&thc63lvd1024_in>; - }; - }; - }; -}; diff --git a/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts b/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts index 15cc9fed2e16b8ce39e002da7b640beb47413a6f..d7c7b9156e08241cfc8fe4f194cb7a79847b2c24 100644 --- a/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts +++ b/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts @@ -21,6 +21,41 @@ stdout-path = "serial0:115200n8"; }; + hdmi-out { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con: endpoint { + remote-endpoint = <&adv7511_out>; + }; + }; + }; + + lvds-decoder { + compatible = "thine,thc63lvd1024"; + vcc-supply = <&vcc_d3_3v>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + thc63lvd1024_in: endpoint { + remote-endpoint = <&lvds0_out>; + }; + }; + + port@2 { + reg = <2>; + thc63lvd1024_out: endpoint { + remote-endpoint = <&adv7511_in>; + }; + }; + }; + }; + memory@48000000 { device_type = "memory"; /* first 128MB is reserved for secure area. */ @@ -59,41 +94,6 @@ regulator-boot-on; regulator-always-on; }; - - lvds-decoder { - compatible = "thine,thc63lvd1024"; - vcc-supply = <&vcc_d3_3v>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - thc63lvd1024_in: endpoint { - remote-endpoint = <&lvds0_out>; - }; - }; - - port@2 { - reg = <2>; - thc63lvd1024_out: endpoint { - remote-endpoint = <&adv7511_in>; - }; - }; - }; - }; - - hdmi-out { - compatible = "hdmi-connector"; - type = "a"; - - port { - hdmi_con: endpoint { - remote-endpoint = <&adv7511_out>; - }; - }; - }; }; &avb { @@ -128,29 +128,6 @@ clock-frequency = <32768>; }; -&pfc { - avb_pins: avb0 { - groups = "avb0_mdio", "avb0_rgmii", "avb0_txcrefclk"; - function = "avb0"; - }; - - i2c0_pins: i2c0 { - groups = "i2c0"; - function = "i2c0"; - }; - - mmc_pins: mmc_3_3v { - groups = "mmc_data8", "mmc_ctrl"; - function = "mmc"; - power-source = <3300>; - }; - - scif0_pins: scif0 { - groups = "scif0_data"; - function = "scif0"; - }; -}; - &i2c0 { pinctrl-0 = <&i2c0_pins>; pinctrl-names = "default"; @@ -220,6 +197,29 @@ status = "okay"; }; +&pfc { + avb_pins: avb0 { + groups = "avb0_mdio", "avb0_rgmii", "avb0_txcrefclk"; + function = "avb0"; + }; + + i2c0_pins: i2c0 { + groups = "i2c0"; + function = "i2c0"; + }; + + mmc_pins: mmc_3_3v { + groups = "mmc_data8", "mmc_ctrl"; + function = "mmc"; + power-source = <3300>; + }; + + scif0_pins: scif0 { + groups = "scif0_data"; + function = "scif0"; + }; +}; + &scif0 { pinctrl-0 = <&scif0_pins>; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/renesas/r8a77970.dtsi b/arch/arm64/boot/dts/renesas/r8a77970.dtsi index 5b6164d4b8e3630dee473449e53c07d8d85901d2..0cd3b376635d83f0235b3a00f67f106ca060c213 100644 --- a/arch/arm64/boot/dts/renesas/r8a77970.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77970.dtsi @@ -1181,6 +1181,9 @@ polling-delay = <1000>; thermal-sensors = <&thermal>; + cooling-maps { + }; + trips { cpu-crit { temperature = <120000>; @@ -1188,9 +1191,6 @@ type = "critical"; }; }; - - cooling-maps { - }; }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a77980-condor.dts b/arch/arm64/boot/dts/renesas/r8a77980-condor.dts index 5a7012be0d6ad953198c035df5626f2ff8ce0fe9..3dde028e22a6d9c9f4ba6c691d1b507f56f37cde 100644 --- a/arch/arm64/boot/dts/renesas/r8a77980-condor.dts +++ b/arch/arm64/boot/dts/renesas/r8a77980-condor.dts @@ -22,35 +22,20 @@ stdout-path = "serial0:115200n8"; }; - memory@48000000 { - device_type = "memory"; - /* first 128MB is reserved for secure area. */ - reg = <0 0x48000000 0 0x78000000>; - }; - - d3_3v: regulator-0 { - compatible = "regulator-fixed"; - regulator-name = "D3.3V"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - regulator-always-on; - }; - - vddq_vin01: regulator-1 { + d1_8v: regulator-2 { compatible = "regulator-fixed"; - regulator-name = "VDDQ_VIN01"; + regulator-name = "D1.8V"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; regulator-boot-on; regulator-always-on; }; - d1_8v: regulator-2 { + d3_3v: regulator-0 { compatible = "regulator-fixed"; - regulator-name = "D1.8V"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; + regulator-name = "D3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; regulator-boot-on; regulator-always-on; }; @@ -90,6 +75,21 @@ }; }; + memory@48000000 { + device_type = "memory"; + /* first 128MB is reserved for secure area. */ + reg = <0 0x48000000 0 0x78000000>; + }; + + vddq_vin01: regulator-1 { + compatible = "regulator-fixed"; + regulator-name = "VDDQ_VIN01"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + x1_clk: x1-clock { compatible = "fixed-clock"; #clock-cells = <0>; diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts index dd14a41b32cdf242e779fd27330aa311e51240ce..adbfd8f07d06a3a46a1ee26f49166adea1f231bd 100644 --- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts +++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts @@ -22,12 +22,6 @@ stdout-path = "serial0:115200n8"; }; - memory@48000000 { - device_type = "memory"; - /* first 128MB is reserved for secure area. */ - reg = <0 0x48000000 0 0x78000000>; - }; - hdmi-out { compatible = "hdmi-connector"; type = "a"; @@ -63,6 +57,12 @@ }; }; + memory@48000000 { + device_type = "memory"; + /* first 128MB is reserved for secure area. */ + reg = <0 0x48000000 0 0x78000000>; + }; + osc1_clk: osc1-clock { compatible = "fixed-clock"; #clock-cells = <0>; diff --git a/arch/arm64/boot/dts/renesas/r8a77980.dtsi b/arch/arm64/boot/dts/renesas/r8a77980.dtsi index a901a341dcf71981a435ad5e098fd3d4a8cefea6..461a47ea656dabdf7a2b3c9dfc10c8d0599d7b59 100644 --- a/arch/arm64/boot/dts/renesas/r8a77980.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77980.dtsi @@ -1299,9 +1299,9 @@ #iommu-cells = <1>; }; - ipmmu_vc0: mmu@fe6b0000 { + ipmmu_vc0: mmu@fe990000 { compatible = "renesas,ipmmu-r8a77980"; - reg = <0 0xfe6b0000 0 0x1000>; + reg = <0 0xfe990000 0 0x1000>; renesas,ipmmu-main = <&ipmmu_mm 12>; power-domains = <&sysc R8A77980_PD_ALWAYS_ON>; #iommu-cells = <1>; diff --git a/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts b/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts index 83fc13ac3fa1098c8ad8fe4f9512836c0ffa7f82..b38f9d442fc08f2c7e5a606e0ddc8fe9ac6dfd78 100644 --- a/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts +++ b/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts @@ -23,12 +23,6 @@ stdout-path = "serial0:115200n8"; }; - memory@48000000 { - device_type = "memory"; - /* first 128MB is reserved for secure area. */ - reg = <0x0 0x48000000 0x0 0x38000000>; - }; - audio_clkout: audio-clkout { /* * This is same as <&rcar_sound 0> @@ -107,36 +101,10 @@ }; }; - vga { - compatible = "vga-connector"; - - port { - vga_in: endpoint { - remote-endpoint = <&adv7123_out>; - }; - }; - }; - - vga-encoder { - compatible = "adi,adv7123"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - adv7123_in: endpoint { - remote-endpoint = <&du_out_rgb>; - }; - }; - port@1 { - reg = <1>; - adv7123_out: endpoint { - remote-endpoint = <&vga_in>; - }; - }; - }; + memory@48000000 { + device_type = "memory"; + /* first 128MB is reserved for secure area. */ + reg = <0x0 0x48000000 0x0 0x38000000>; }; reg_1p8v: regulator0 { @@ -157,15 +125,13 @@ regulator-always-on; }; - vbus0_usb2: regulator-vbus0-usb2 { + reg_12p0v: regulator2 { compatible = "regulator-fixed"; - - regulator-name = "USB20_VBUS_CN"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - - gpio = <&gpio6 4 GPIO_ACTIVE_HIGH>; - enable-active-high; + regulator-name = "D12.0V"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-boot-on; + regulator-always-on; }; rsnd_ak4613: sound { @@ -176,34 +142,24 @@ simple-audio-card,bitclock-master = <&sndcpu>; simple-audio-card,frame-master = <&sndcpu>; - sndcpu: simple-audio-card,cpu { - sound-dai = <&rcar_sound>; - }; - sndcodec: simple-audio-card,codec { sound-dai = <&ak4613>; }; - }; - x12_clk: x12 { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <24576000>; + sndcpu: simple-audio-card,cpu { + sound-dai = <&rcar_sound>; + }; }; - reg_12p0v: regulator2 { + vbus0_usb2: regulator-vbus0-usb2 { compatible = "regulator-fixed"; - regulator-name = "D12.0V"; - regulator-min-microvolt = <12000000>; - regulator-max-microvolt = <12000000>; - regulator-boot-on; - regulator-always-on; - }; - x13_clk: x13 { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <74250000>; + regulator-name = "USB20_VBUS_CN"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + + gpio = <&gpio6 4 GPIO_ACTIVE_HIGH>; + enable-active-high; }; vcc_sdhi0: regulator-vcc-sdhi0 { @@ -253,6 +209,50 @@ states = <3300000 1 1800000 0>; }; + + vga { + compatible = "vga-connector"; + + port { + vga_in: endpoint { + remote-endpoint = <&adv7123_out>; + }; + }; + }; + + vga-encoder { + compatible = "adi,adv7123"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + adv7123_in: endpoint { + remote-endpoint = <&du_out_rgb>; + }; + }; + port@1 { + reg = <1>; + adv7123_out: endpoint { + remote-endpoint = <&vga_in>; + }; + }; + }; + }; + + x12_clk: x12 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24576000>; + }; + + x13_clk: x13 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <74250000>; + }; }; &audio_clk_a { @@ -271,6 +271,14 @@ interrupt-parent = <&gpio2>; interrupts = <21 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>; + /* + * TX clock internal delay mode is required for reliable + * 1Gbps communication using the KSZ9031RNX phy present on + * the Ebisu board, however, TX clock internal delay mode + * isn't supported on r8a77990. Thus, limit speed to + * 100Mbps for reliable communication. + */ + max-speed = <100>; }; }; @@ -547,6 +555,11 @@ function = "pwm5"; }; + scif2_pins: scif2 { + groups = "scif2_data_a"; + function = "scif2"; + }; + sdhi0_pins: sd0 { groups = "sdhi0_data4", "sdhi0_ctrl"; function = "sdhi0"; @@ -577,20 +590,15 @@ power-source = <1800>; }; - sound_pins: sound { - groups = "ssi01239_ctrl", "ssi0_data", "ssi1_data"; - function = "ssi"; - }; - sound_clk_pins: sound_clk { groups = "audio_clk_a", "audio_clk_b_a", "audio_clk_c_a", "audio_clkout_a", "audio_clkout1_a"; function = "audio_clk"; }; - scif2_pins: scif2 { - groups = "scif2_data_a"; - function = "scif2"; + sound_pins: sound { + groups = "ssi01239_ctrl", "ssi0_data", "ssi1_data"; + function = "ssi"; }; usb0_pins: usb { @@ -671,38 +679,6 @@ status = "okay"; }; -&ssi1 { - shared-pin; -}; - -&usb2_phy0 { - pinctrl-0 = <&usb0_pins>; - pinctrl-names = "default"; - - vbus-supply = <&vbus0_usb2>; - status = "okay"; -}; - -&usb3_peri0 { - companion = <&xhci0>; - status = "okay"; -}; - -&vin4 { - status = "okay"; -}; - -&vin5 { - status = "okay"; -}; - -&xhci0 { - pinctrl-0 = <&usb30_pins>; - pinctrl-names = "default"; - - status = "okay"; -}; - &sdhi0 { pinctrl-0 = <&sdhi0_pins>; pinctrl-1 = <&sdhi0_pins_uhs>; @@ -746,3 +722,35 @@ non-removable; status = "okay"; }; + +&ssi1 { + shared-pin; +}; + +&usb2_phy0 { + pinctrl-0 = <&usb0_pins>; + pinctrl-names = "default"; + + vbus-supply = <&vbus0_usb2>; + status = "okay"; +}; + +&usb3_peri0 { + companion = <&xhci0>; + status = "okay"; +}; + +&vin4 { + status = "okay"; +}; + +&vin5 { + status = "okay"; +}; + +&xhci0 { + pinctrl-0 = <&usb30_pins>; + pinctrl-names = "default"; + + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/renesas/r8a77990.dtsi b/arch/arm64/boot/dts/renesas/r8a77990.dtsi index b4318661f35e43ebc24159044e4c3ee5a64de2c7..455954c3d98ea9eaa0f4d5f5500578c72d1e3ce7 100644 --- a/arch/arm64/boot/dts/renesas/r8a77990.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77990.dtsi @@ -1326,6 +1326,17 @@ "ssi.1", "ssi.0"; status = "disabled"; + rcar_sound,ctu { + ctu00: ctu-0 { }; + ctu01: ctu-1 { }; + ctu02: ctu-2 { }; + ctu03: ctu-3 { }; + ctu10: ctu-4 { }; + ctu11: ctu-5 { }; + ctu12: ctu-6 { }; + ctu13: ctu-7 { }; + }; + rcar_sound,dvc { dvc0: dvc-0 { dmas = <&audma0 0xbc>; @@ -1342,17 +1353,6 @@ mix1: mix-1 { }; }; - rcar_sound,ctu { - ctu00: ctu-0 { }; - ctu01: ctu-1 { }; - ctu02: ctu-2 { }; - ctu03: ctu-3 { }; - ctu10: ctu-4 { }; - ctu11: ctu-5 { }; - ctu12: ctu-6 { }; - ctu13: ctu-7 { }; - }; - rcar_sound,src { src0: src-0 { interrupts = ; @@ -1766,7 +1766,9 @@ clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>; clock-names = "du.0", "du.1"; - vsps = <&vspd0 0 &vspd1 0>; + resets = <&cpg 724>; + reset-names = "du.0"; + vsps = <&vspd0 0>, <&vspd1 0>; status = "disabled"; ports { @@ -1864,25 +1866,25 @@ thermal-sensors = <&thermal 0>; sustainable-power = <717>; - trips { - target: trip-point1 { - temperature = <100000>; - hysteresis = <2000>; - type = "passive"; + cooling-maps { + map0 { + trip = <&target>; + cooling-device = <&a53_0 0 2>; + contribution = <1024>; }; + }; + trips { sensor1_crit: sensor1-crit { temperature = <120000>; hysteresis = <2000>; type = "critical"; }; - }; - cooling-maps { - map0 { - trip = <&target>; - cooling-device = <&a53_0 0 2>; - contribution = <1024>; + target: trip-point1 { + temperature = <100000>; + hysteresis = <2000>; + type = "passive"; }; }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a77995-draak.dts b/arch/arm64/boot/dts/renesas/r8a77995-draak.dts index 3aa2564dfdc25fff2d09a121f7048390202b2a94..67634cb01d6b68567e23d1554b969915181df26c 100644 --- a/arch/arm64/boot/dts/renesas/r8a77995-draak.dts +++ b/arch/arm64/boot/dts/renesas/r8a77995-draak.dts @@ -19,11 +19,6 @@ ethernet0 = &avb; }; - chosen { - bootargs = "ignore_loglevel rw root=/dev/nfs ip=on"; - stdout-path = "serial0:115200n8"; - }; - backlight: backlight { compatible = "pwm-backlight"; pwms = <&pwm1 0 50000>; @@ -35,6 +30,11 @@ enable-gpios = <&gpio4 0 GPIO_ACTIVE_HIGH>; }; + chosen { + bootargs = "ignore_loglevel rw root=/dev/nfs ip=on"; + stdout-path = "serial0:115200n8"; + }; + composite-in { compatible = "composite-video-connector"; @@ -175,6 +175,14 @@ reg = <0>; interrupt-parent = <&gpio5>; interrupts = <19 IRQ_TYPE_LEVEL_LOW>; + /* + * TX clock internal delay mode is required for reliable + * 1Gbps communication using the KSZ9031RNX phy present on + * the Draak board, however, TX clock internal delay mode + * isn't supported on r8a77995. Thus, limit speed to + * 100Mbps for reliable communication. + */ + max-speed = <100>; }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a77995.dtsi b/arch/arm64/boot/dts/renesas/r8a77995.dtsi index 0a344eb55094d2c9183bb7665580b72bf875eb94..183fef86cf7c1e157798f8f8268a4cb88311a689 100644 --- a/arch/arm64/boot/dts/renesas/r8a77995.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77995.dtsi @@ -242,41 +242,6 @@ resets = <&cpg 407>; }; - hscif0: serial@e6540000 { - compatible = "renesas,hscif-r8a77995", - "renesas,rcar-gen3-hscif", - "renesas,hscif"; - reg = <0 0xe6540000 0 0x60>; - interrupts = ; - clocks = <&cpg CPG_MOD 520>, - <&cpg CPG_CORE R8A77995_CLK_S3D1C>, - <&scif_clk>; - clock-names = "fck", "brg_int", "scif_clk"; - dmas = <&dmac1 0x31>, <&dmac1 0x30>, - <&dmac2 0x31>, <&dmac2 0x30>; - dma-names = "tx", "rx", "tx", "rx"; - power-domains = <&sysc R8A77995_PD_ALWAYS_ON>; - resets = <&cpg 520>; - status = "disabled"; - }; - - hscif3: serial@e66a0000 { - compatible = "renesas,hscif-r8a77995", - "renesas,rcar-gen3-hscif", - "renesas,hscif"; - reg = <0 0xe66a0000 0 0x60>; - interrupts = ; - clocks = <&cpg CPG_MOD 517>, - <&cpg CPG_CORE R8A77995_CLK_S3D1C>, - <&scif_clk>; - clock-names = "fck", "brg_int", "scif_clk"; - dmas = <&dmac0 0x37>, <&dmac0 0x36>; - dma-names = "tx", "rx"; - power-domains = <&sysc R8A77995_PD_ALWAYS_ON>; - resets = <&cpg 517>; - status = "disabled"; - }; - i2c0: i2c@e6500000 { #address-cells = <1>; #size-cells = <0>; @@ -344,6 +309,41 @@ status = "disabled"; }; + hscif0: serial@e6540000 { + compatible = "renesas,hscif-r8a77995", + "renesas,rcar-gen3-hscif", + "renesas,hscif"; + reg = <0 0xe6540000 0 0x60>; + interrupts = ; + clocks = <&cpg CPG_MOD 520>, + <&cpg CPG_CORE R8A77995_CLK_S3D1C>, + <&scif_clk>; + clock-names = "fck", "brg_int", "scif_clk"; + dmas = <&dmac1 0x31>, <&dmac1 0x30>, + <&dmac2 0x31>, <&dmac2 0x30>; + dma-names = "tx", "rx", "tx", "rx"; + power-domains = <&sysc R8A77995_PD_ALWAYS_ON>; + resets = <&cpg 520>; + status = "disabled"; + }; + + hscif3: serial@e66a0000 { + compatible = "renesas,hscif-r8a77995", + "renesas,rcar-gen3-hscif", + "renesas,hscif"; + reg = <0 0xe66a0000 0 0x60>; + interrupts = ; + clocks = <&cpg CPG_MOD 517>, + <&cpg CPG_CORE R8A77995_CLK_S3D1C>, + <&scif_clk>; + clock-names = "fck", "brg_int", "scif_clk"; + dmas = <&dmac0 0x37>, <&dmac0 0x36>; + dma-names = "tx", "rx"; + power-domains = <&sysc R8A77995_PD_ALWAYS_ON>; + resets = <&cpg 517>; + status = "disabled"; + }; + hsusb: usb@e6590000 { compatible = "renesas,usbhs-r8a77995", "renesas,rcar-gen3-usbhs"; @@ -995,13 +995,15 @@ du: display@feb00000 { compatible = "renesas,du-r8a77995"; - reg = <0 0xfeb00000 0 0x80000>; + reg = <0 0xfeb00000 0 0x40000>; interrupts = , ; clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>; clock-names = "du.0", "du.1"; - vsps = <&vspd0 0 &vspd1 0>; + resets = <&cpg 724>; + reset-names = "du.0"; + vsps = <&vspd0 0>, <&vspd1 0>; status = "disabled"; ports { @@ -1098,6 +1100,9 @@ polling-delay = <1000>; thermal-sensors = <&thermal>; + cooling-maps { + }; + trips { cpu-crit { temperature = <120000>; @@ -1105,9 +1110,6 @@ type = "critical"; }; }; - - cooling-maps { - }; }; }; diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi index 5c2c84723ec5b672beb106bb244ac98097d9cf0d..21e01056e759e77638a636a002dbfa2cc0082dfd 100644 --- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi +++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi @@ -87,6 +87,28 @@ }; }; + hdmi0-out { + compatible = "hdmi-connector"; + label = "HDMI0 OUT"; + type = "a"; + + port { + hdmi0_con: endpoint { + }; + }; + }; + + hdmi1-out { + compatible = "hdmi-connector"; + label = "HDMI1 OUT"; + type = "a"; + + port { + hdmi1_con: endpoint { + }; + }; + }; + keys { compatible = "gpio-keys"; @@ -238,28 +260,6 @@ 1800000 0>; }; - hdmi0-out { - compatible = "hdmi-connector"; - label = "HDMI0 OUT"; - type = "a"; - - port { - hdmi0_con: endpoint { - }; - }; - }; - - hdmi1-out { - compatible = "hdmi-connector"; - label = "HDMI1 OUT"; - type = "a"; - - port { - hdmi1_con: endpoint { - }; - }; - }; - vga { compatible = "vga-connector"; @@ -462,20 +462,6 @@ #gpio-cells = <2>; }; - csa_vdd: adc@7c { - compatible = "maxim,max9611"; - reg = <0x7c>; - - shunt-resistor-micro-ohms = <5000>; - }; - - csa_dvfs: adc@7f { - compatible = "maxim,max9611"; - reg = <0x7f>; - - shunt-resistor-micro-ohms = <5000>; - }; - video-receiver@70 { compatible = "adi,adv7482"; reg = <0x70 0x71 0x72 0x73 0x74 0x75 @@ -527,6 +513,20 @@ }; }; }; + + csa_vdd: adc@7c { + compatible = "maxim,max9611"; + reg = <0x7c>; + + shunt-resistor-micro-ohms = <5000>; + }; + + csa_dvfs: adc@7f { + compatible = "maxim,max9611"; + reg = <0x7f>; + + shunt-resistor-micro-ohms = <5000>; + }; }; &i2c_dvfs { diff --git a/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi b/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi index 27851a77f5381547f90e28e46467d96b94f4aa3c..202177706cdeb959e0591fac9d60047557a1d444 100644 --- a/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi +++ b/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi @@ -83,6 +83,56 @@ }; &i2c2 { + i2cswitch2: i2c-switch@71 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + reset-gpios = <&gpio5 3 GPIO_ACTIVE_LOW>; + + /* Audio_SDA, Audio_SCL */ + i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + + pcm3168a: audio-codec@44 { + #sound-dai-cells = <0>; + compatible = "ti,pcm3168a"; + reg = <0x44>; + clocks = <&clksndsel>; + clock-names = "scki"; + + VDD1-supply = <&snd_3p3v>; + VDD2-supply = <&snd_3p3v>; + VCCAD1-supply = <&snd_vcc5v>; + VCCAD2-supply = <&snd_vcc5v>; + VCCDA1-supply = <&snd_vcc5v>; + VCCDA2-supply = <&snd_vcc5v>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + mclk-fs = <512>; + port@0 { + reg = <0>; + pcm3168a_endpoint_p: endpoint { + remote-endpoint = <&rsnd_for_pcm3168a_play>; + clocks = <&clksndsel>; + }; + }; + port@1 { + reg = <1>; + pcm3168a_endpoint_c: endpoint { + remote-endpoint = <&rsnd_for_pcm3168a_capture>; + clocks = <&clksndsel>; + }; + }; + }; + }; + }; + }; + /* U11 */ gpio_exp_74: gpio@74 { compatible = "ti,tca9539"; @@ -100,13 +150,6 @@ line-name = "Audio_Out_OFF"; }; - sd-wifi-mux { - gpio-hog; - gpios = <5 GPIO_ACTIVE_HIGH>; - output-low; /* Connect WL1837 */ - line-name = "SD WiFi mux"; - }; - hub_pwen { gpio-hog; gpios = <6 GPIO_ACTIVE_HIGH>; @@ -121,6 +164,13 @@ line-name = "HUB rst"; }; + otg_extlpn { + gpio-hog; + gpios = <9 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "OTG EXTLPn"; + }; + otg_offvbusn { gpio-hog; gpios = <8 GPIO_ACTIVE_HIGH>; @@ -128,11 +178,11 @@ line-name = "OTG OFFVBUSn"; }; - otg_extlpn { + sd-wifi-mux { gpio-hog; - gpios = <9 GPIO_ACTIVE_HIGH>; - output-high; - line-name = "OTG EXTLPn"; + gpios = <5 GPIO_ACTIVE_HIGH>; + output-low; /* Connect WL1837 */ + line-name = "SD WiFi mux"; }; snd_rst { @@ -153,59 +203,17 @@ interrupt-parent = <&gpio6>; interrupts = <4 IRQ_TYPE_EDGE_FALLING>; }; +}; - i2cswitch2: i2c-switch@71 { +&i2c4 { + i2cswitch4: i2c-switch@71 { compatible = "nxp,pca9548"; #address-cells = <1>; #size-cells = <0>; reg = <0x71>; - reset-gpios = <&gpio5 3 GPIO_ACTIVE_LOW>; - - /* Audio_SDA, Audio_SCL */ - i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - - pcm3168a: audio-codec@44 { - #sound-dai-cells = <0>; - compatible = "ti,pcm3168a"; - reg = <0x44>; - clocks = <&clksndsel>; - clock-names = "scki"; - - VDD1-supply = <&snd_3p3v>; - VDD2-supply = <&snd_3p3v>; - VCCAD1-supply = <&snd_vcc5v>; - VCCAD2-supply = <&snd_vcc5v>; - VCCDA1-supply = <&snd_vcc5v>; - VCCDA2-supply = <&snd_vcc5v>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - mclk-fs = <512>; - port@0 { - reg = <0>; - pcm3168a_endpoint_p: endpoint { - remote-endpoint = <&rsnd_for_pcm3168a_play>; - clocks = <&clksndsel>; - }; - }; - port@1 { - reg = <1>; - pcm3168a_endpoint_c: endpoint { - remote-endpoint = <&rsnd_for_pcm3168a_capture>; - clocks = <&clksndsel>; - }; - }; - }; - }; - }; + reset-gpios = <&gpio3 15 GPIO_ACTIVE_LOW>; }; -}; -&i2c4 { gpio_exp_76: gpio@76 { compatible = "ti,tca9539"; reg = <0x76>; @@ -225,14 +233,6 @@ interrupt-parent = <&gpio5>; interrupts = <9 IRQ_TYPE_EDGE_FALLING>; }; - - i2cswitch4: i2c-switch@71 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x71>; - reset-gpios = <&gpio3 15 GPIO_ACTIVE_LOW>; - }; }; &ohci0 { @@ -279,14 +279,50 @@ power-source = <3300>; }; + sound_pcm_pins: sound-pcm { + groups = "ssi349_ctrl", "ssi3_data", "ssi4_data"; + function = "ssi"; + }; + usb0_pins: usb0 { groups = "usb0"; function = "usb0"; }; +}; - sound_pcm_pins: sound-pcm { - groups = "ssi349_ctrl", "ssi3_data", "ssi4_data"; - function = "ssi"; +&rcar_sound { + pinctrl-0 = <&sound_pins + &sound_clk_pins + &sound_pcm_pins>; + + ports { + /* rsnd_port0/1 are on salvator-common */ + rsnd_port2: port@2 { + reg = <2>; + rsnd_for_pcm3168a_play: endpoint { + remote-endpoint = <&pcm3168a_endpoint_p>; + + dai-format = "i2s"; + bitclock-master = <&rsnd_for_pcm3168a_play>; + frame-master = <&rsnd_for_pcm3168a_play>; + dai-tdm-slot-num = <8>; + + playback = <&ssi3>; + }; + }; + rsnd_port3: port@3 { + reg = <3>; + rsnd_for_pcm3168a_capture: endpoint { + remote-endpoint = <&pcm3168a_endpoint_c>; + + dai-format = "i2s"; + bitclock-master = <&rsnd_for_pcm3168a_capture>; + frame-master = <&rsnd_for_pcm3168a_capture>; + dai-tdm-slot-num = <6>; + + capture = <&ssi4>; + }; + }; }; }; @@ -322,17 +358,6 @@ }; }; -&usb2_phy0 { - pinctrl-0 = <&usb0_pins>; - pinctrl-names = "default"; - - status = "okay"; -}; - -&xhci0 { - status = "okay"; -}; - &sound_card { dais = <&rsnd_port0 /* ak4613 */ &rsnd_port1 /* HDMI0 */ @@ -341,42 +366,17 @@ >; }; -&rcar_sound { - pinctrl-0 = <&sound_pins - &sound_clk_pins - &sound_pcm_pins>; - - ports { - /* rsnd_port0/1 are on salvator-common */ - rsnd_port2: port@2 { - reg = <2>; - rsnd_for_pcm3168a_play: endpoint { - remote-endpoint = <&pcm3168a_endpoint_p>; - - dai-format = "i2s"; - bitclock-master = <&rsnd_for_pcm3168a_play>; - frame-master = <&rsnd_for_pcm3168a_play>; - dai-tdm-slot-num = <8>; - - playback = <&ssi3>; - }; - }; - rsnd_port3: port@3 { - reg = <3>; - rsnd_for_pcm3168a_capture: endpoint { - remote-endpoint = <&pcm3168a_endpoint_c>; +&ssi4 { + shared-pin; +}; - dai-format = "i2s"; - bitclock-master = <&rsnd_for_pcm3168a_capture>; - frame-master = <&rsnd_for_pcm3168a_capture>; - dai-tdm-slot-num = <6>; +&usb2_phy0 { + pinctrl-0 = <&usb0_pins>; + pinctrl-names = "default"; - capture = <&ssi4>; - }; - }; - }; + status = "okay"; }; -&ssi4 { - shared-pin; +&xhci0 { + status = "okay"; }; diff --git a/arch/arm64/boot/dts/renesas/ulcb.dtsi b/arch/arm64/boot/dts/renesas/ulcb.dtsi index 7e498b46e9aee1ba0da98e9e701f28ed5b7c455b..3ef89171538ffd03ae8b4b67a80f679a1eb3c9e1 100644 --- a/arch/arm64/boot/dts/renesas/ulcb.dtsi +++ b/arch/arm64/boot/dts/renesas/ulcb.dtsi @@ -428,6 +428,11 @@ }; }; +&rwdt { + timeout-sec = <60>; + status = "okay"; +}; + &scif2 { pinctrl-0 = <&scif2_pins>; pinctrl-names = "default"; @@ -478,8 +483,3 @@ status = "okay"; }; - -&rwdt { - timeout-sec = <60>; - status = "okay"; -}; diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index daa2c78e22c3019d9274c9239837f762f6eb8ed6..1f18a9392d15205c07d9f9ca1be2357e9ebd90b9 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -20,6 +20,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-hugsun-x99.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-khadas-edge.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-khadas-edge-captain.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-khadas-edge-v.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-leez-p710.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopc-t4.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-m4.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-neo4.dtb diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts index 7cfd5ca6cc858259cc37142e459ea38c49b56335..62936b432f9a57f9718d3fa56ba8228eca6393c3 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts @@ -34,10 +34,9 @@ vcc_host_5v: vcc-host-5v-regulator { compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>; + gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; - pinctrl-0 = <&usb30_host_drv>; + pinctrl-0 = <&usb20_host_drv>; regulator-name = "vcc_host_5v"; regulator-always-on; regulator-boot-on; @@ -320,12 +319,6 @@ rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; }; }; - - usb3 { - usb30_host_drv: usb30-host-drv { - rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; }; &sdmmc { diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi index e9fefd8a7e02d3a81054b304f1986018a9069478..31cc1541f1f596ee781f011e1998b87e89b1a628 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi @@ -278,6 +278,7 @@ }; pd_vpu@RK3328_PD_VPU { reg = ; + clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; }; }; @@ -596,6 +597,17 @@ status = "disabled"; }; + vpu: video-codec@ff350000 { + compatible = "rockchip,rk3328-vpu"; + reg = <0x0 0xff350000 0x0 0x800>; + interrupts = ; + interrupt-names = "vdpu"; + clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; + clock-names = "aclk", "hclk"; + iommus = <&vpu_mmu>; + power-domains = <&power RK3328_PD_VPU>; + }; + vpu_mmu: iommu@ff350800 { compatible = "rockchip,iommu"; reg = <0x0 0xff350800 0x0 0x40>; @@ -604,7 +616,7 @@ clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; clock-names = "aclk", "iface"; #iommu-cells = <0>; - status = "disabled"; + power-domains = <&power RK3328_PD_VPU>; }; rkvdec_mmu: iommu@ff360480 { @@ -801,6 +813,7 @@ <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>; clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; + max-frequency = <150000000>; status = "disabled"; }; @@ -812,6 +825,7 @@ <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>; clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; + max-frequency = <150000000>; status = "disabled"; }; @@ -823,6 +837,7 @@ <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>; clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; + max-frequency = <150000000>; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts index 3e2272b56eb7cd652c0894e1fd1f9a22ea90e632..e152b0ca0290c7f69e86f6b3c96a7ed16c5e3091 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts @@ -43,6 +43,20 @@ backlight = <&backlight>; power-supply = <&pp3300_disp>; + panel-timing { + clock-frequency = <266604720>; + hactive = <2400>; + hfront-porch = <48>; + hback-porch = <84>; + hsync-len = <32>; + hsync-active = <0>; + vactive = <1600>; + vfront-porch = <3>; + vback-porch = <120>; + vsync-len = <10>; + vsync-active = <0>; + }; + port { panel_in_edp: endpoint { remote-endpoint = <&edp_out_panel>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts b/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts new file mode 100644 index 0000000000000000000000000000000000000000..73be38a537960ed9d551a453e81d26c7d2c89126 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts @@ -0,0 +1,645 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 Andy Yan + */ + +/dts-v1/; +#include +#include +#include "rk3399.dtsi" +#include "rk3399-opp.dtsi" + +/ { + model = "Leez RK3399 P710"; + compatible = "leez,p710", "rockchip,rk3399"; + + chosen { + stdout-path = "serial2:1500000n8"; + }; + + clkin_gmac: external-gmac-clock { + compatible = "fixed-clock"; + clock-frequency = <125000000>; + clock-output-names = "clkin_gmac"; + #clock-cells = <0>; + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + clocks = <&rk808 1>; + clock-names = "ext_clock"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_reg_on_h>; + reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>; + }; + + dc5v_adp: dc5v-adp { + compatible = "regulator-fixed"; + regulator-name = "dc5v_adapter"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + vcc3v3_lan: vcc3v3-lan { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3_lan"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vim-supply = <&vcc3v3_sys>; + }; + + vcc3v3_sys: vcc3v3-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc5v0_host0: vcc5v0_host1: vcc5v0-host { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_host"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <5500000>; + regulator-max-microvolt = <5500000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc5v0_host3: vcc5v0-host3 { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_host3"; + enable-active-high; + gpio = <&gpio2 RK_PA2 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc5v0_host3_en>; + regulator-always-on; + vin-supply = <&vcc5v0_sys>; + }; + + vcc5v0_sys: vcc5v0-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&dc5v_adp>; + }; + + vdd_log: vdd-log { + compatible = "pwm-regulator"; + pwms = <&pwm2 0 25000 1>; + regulator-name = "vdd_log"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1400000>; + vin-supply = <&vcc5v0_sys>; + }; +}; + +&cpu_l0 { + cpu-supply = <&vdd_cpu_l>; +}; + +&cpu_l1 { + cpu-supply = <&vdd_cpu_l>; +}; + +&cpu_l2 { + cpu-supply = <&vdd_cpu_l>; +}; + +&cpu_l3 { + cpu-supply = <&vdd_cpu_l>; +}; + +&cpu_b0 { + cpu-supply = <&vdd_cpu_b>; +}; + +&cpu_b1 { + cpu-supply = <&vdd_cpu_b>; +}; + +&emmc_phy { + status = "okay"; +}; + +&gmac { + assigned-clocks = <&cru SCLK_RMII_SRC>; + assigned-clock-parents = <&clkin_gmac>; + clock_in_out = "input"; + phy-supply = <&vcc3v3_lan>; + phy-mode = "rgmii"; + pinctrl-names = "default"; + pinctrl-0 = <&rgmii_pins>; + snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 50000>; + tx_delay = <0x28>; + rx_delay = <0x11>; + status = "okay"; +}; + +&gpu { + mali-supply = <&vdd_gpu>; + status = "okay"; +}; + +&hdmi { + ddc-i2c-bus = <&i2c7>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_cec>; + status = "okay"; +}; + +&hdmi_sound { + status = "okay"; +}; + +&i2c0 { + clock-frequency = <400000>; + i2c-scl-rising-time-ns = <168>; + i2c-scl-falling-time-ns = <4>; + status = "okay"; + + rk808: pmic@1b { + compatible = "rockchip,rk808"; + reg = <0x1b>; + interrupt-parent = <&gpio1>; + interrupts = <21 IRQ_TYPE_LEVEL_LOW>; + #clock-cells = <1>; + clock-output-names = "xin32k", "rk808-clkout2"; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int_l>; + rockchip,system-power-controller; + wakeup-source; + + vcc1-supply = <&vcc5v0_sys>; + vcc2-supply = <&vcc5v0_sys>; + vcc3-supply = <&vcc5v0_sys>; + vcc4-supply = <&vcc5v0_sys>; + vcc6-supply = <&vcc5v0_sys>; + vcc7-supply = <&vcc5v0_sys>; + vcc8-supply = <&vcc3v3_sys>; + vcc9-supply = <&vcc5v0_sys>; + vcc10-supply = <&vcc5v0_sys>; + vcc11-supply = <&vcc5v0_sys>; + vcc12-supply = <&vcc3v3_sys>; + vddio-supply = <&vcc_1v8>; + + regulators { + vdd_center: DCDC_REG1 { + regulator-name = "vdd_center"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <6001>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_l: DCDC_REG2 { + regulator-name = "vdd_cpu_l"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <6001>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_ddr: DCDC_REG3 { + regulator-name = "vcc_ddr"; + regulator-always-on; + regulator-boot-on; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_1v8: DCDC_REG4 { + regulator-name = "vcc_1v8"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc1v8_dvp: LDO_REG1 { + regulator-name = "vcc1v8_dvp"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc1v8_hdmi: LDO_REG2 { + regulator-name = "vcc1v8_hdmi"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcca_1v8: LDO_REG3 { + regulator-name = "vcca_1v8"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vccio_sd: LDO_REG4 { + regulator-name = "vccio_sd"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3000000>; + }; + }; + + vcca3v0_codec: LDO_REG5 { + regulator-name = "vcca3v0_codec"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v5: LDO_REG6 { + regulator-name = "vcc_1v5"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1500000>; + }; + }; + + vcc0v9_hdmi: LDO_REG7 { + regulator-name = "vcc0v9_hdmi"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_3v0: LDO_REG8 { + regulator-name = "vcc_3v0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3000000>; + }; + }; + }; + }; + + vdd_cpu_b: regulator@40 { + compatible = "silergy,syr827"; + reg = <0x40>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&vsel1_gpio>; + regulator-name = "vdd_cpu_b"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; + regulator-ramp-delay = <1000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_gpu: regulator@41 { + compatible = "silergy,syr828"; + reg = <0x41>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&vsel2_gpio>; + regulator-name = "vdd_gpu"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; + regulator-ramp-delay = <1000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&i2c1 { + i2c-scl-rising-time-ns = <300>; + i2c-scl-falling-time-ns = <15>; + status = "okay"; +}; + +&i2c3 { + i2c-scl-rising-time-ns = <450>; + i2c-scl-falling-time-ns = <15>; + status = "okay"; +}; + +&i2c4 { + i2c-scl-rising-time-ns = <600>; + i2c-scl-falling-time-ns = <20>; + status = "okay"; +}; + +&i2c7 { + status = "okay"; +}; + +&i2s0 { + rockchip,playback-channels = <8>; + rockchip,capture-channels = <8>; + status = "okay"; +}; + +&i2s1 { + rockchip,playback-channels = <2>; + rockchip,capture-channels = <2>; + status = "okay"; +}; + +&i2s2 { + status = "okay"; +}; + +&io_domains { + status = "okay"; + + bt656-supply = <&vcc1v8_dvp>; + audio-supply = <&vcc_1v8>; + sdmmc-supply = <&vccio_sd>; + gpio1830-supply = <&vcc_3v0>; +}; + +&pmu_io_domains { + status = "okay"; + pmu1830-supply = <&vcc_3v0>; +}; + +&pinctrl { + bt { + bt_reg_on_h: bt-reg-on-h { + rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + bt_host_wake_l: bt-host-wake-l { + rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + bt_wake_l: bt-wake-l { + rockchip,pins = <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pmic { + pmic_int_l: pmic-int-l { + rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + vsel1_gpio: vsel1-gpio { + rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; + }; + + vsel2_gpio: vsel2-gpio { + rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + usb2 { + vcc5v0_host3_en: vcc5v0-host3-en { + rockchip,pins = <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + wifi { + wifi_reg_on_h: wifi-reg-on-h { + rockchip,pins = + <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + wifi_host_wake_l: wifi-host-wake-l { + rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pwm2 { + status = "okay"; +}; + +&saradc { + status = "okay"; + + vref-supply = <&vcc_1v8>; +}; + +&sdio0 { + #address-cells = <1>; + #size-cells = <0>; + bus-width = <4>; + clock-frequency = <50000000>; + cap-sdio-irq; + cap-sd-highspeed; + keep-power-in-suspend; + mmc-pwrseq = <&sdio_pwrseq>; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>; + sd-uhs-sdr104; + status = "okay"; + + brcmf: wifi@1 { + compatible = "brcm,bcm4329-fmac"; + reg = <1>; + interrupt-parent = <&gpio0>; + interrupts = ; + interrupt-names = "host-wake"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_host_wake_l>; + }; +}; + +&sdhci { + bus-width = <8>; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + non-removable; + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + cd-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>; + disable-wp; + max-frequency = <150000000>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_clk &sdmmc_cd &sdmmc_cmd &sdmmc_bus4>; + status = "okay"; +}; + +&tcphy0 { + status = "okay"; +}; + +&tcphy1 { + status = "okay"; +}; + +&tsadc { + status = "okay"; + + /* tshut mode 0:CRU 1:GPIO */ + rockchip,hw-tshut-mode = <1>; + /* tshut polarity 0:LOW 1:HIGH */ + rockchip,hw-tshut-polarity = <1>; +}; + +&u2phy0 { + status = "okay"; + + u2phy0_otg: otg-port { + status = "okay"; + }; + + u2phy0_host: host-port { + phy-supply = <&vcc5v0_host0>; + status = "okay"; + }; +}; + +&u2phy1 { + status = "okay"; + + u2phy1_otg: otg-port { + status = "okay"; + }; + + u2phy1_host: host-port { + phy-supply = <&vcc5v0_host1>; + status = "okay"; + }; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>; + status = "okay"; + + bluetooth { + compatible = "brcm,bcm43438-bt"; + clocks = <&rk808 1>; + clock-names = "ext_clock"; + device-wakeup-gpios = <&gpio2 RK_PD2 GPIO_ACTIVE_HIGH>; + host-wakeup-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>; + shutdown-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&bt_host_wake_l &bt_wake_l &bt_reg_on_h>; + }; +}; + +&uart2 { + status = "okay"; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_ohci { + status = "okay"; +}; + +&usb_host1_ehci { + status = "okay"; +}; + +&usb_host1_ohci { + status = "okay"; +}; + +&usbdrd3_0 { + status = "okay"; +}; + +&usbdrd_dwc3_0 { + status = "okay"; + dr_mode = "otg"; +}; + +&usbdrd3_1 { + status = "okay"; +}; + +&usbdrd_dwc3_1 { + status = "okay"; + dr_mode = "host"; +}; + +&vopb { + status = "okay"; +}; + +&vopb_mmu { + status = "okay"; +}; + +&vopl { + status = "okay"; +}; + +&vopl_mmu { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dts b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dts index eb55940620060679b488582e9812029f16e55e0d..0401d4ec1f4527067485d864b183fb6103962624 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dts @@ -58,6 +58,13 @@ }; }; + fan: pwm-fan { + compatible = "pwm-fan"; + #cooling-cells = <2>; + fan-supply = <&vcc12v_dcin>; + pwms = <&pwm1 0 50000 0>; + }; + sdio_pwrseq: sdio-pwrseq { compatible = "mmc-pwrseq-simple"; clocks = <&rk808 1>; @@ -602,6 +609,10 @@ status = "okay"; }; +&pwm1 { + status = "okay"; +}; + &pwm2 { status = "okay"; }; @@ -631,6 +642,16 @@ status = "okay"; }; +&spi1 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <10000000>; + }; +}; + &tcphy0 { status = "okay"; }; diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 0e58ef02880c1df01061019aac6dd5f4711db9c6..8e05c39eab08aae420357e7714ce0e140a7c4947 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -72,6 +72,7 @@ CONFIG_RANDOMIZE_BASE=y CONFIG_HIBERNATION=y CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y CONFIG_ARM_CPUIDLE=y +CONFIG_ARM_PSCI_CPUIDLE=y CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_GOV_POWERSAVE=m @@ -84,6 +85,7 @@ CONFIG_ACPI_CPPC_CPUFREQ=m CONFIG_ARM_ARMADA_37XX_CPUFREQ=y CONFIG_ARM_SCPI_CPUFREQ=y CONFIG_ARM_IMX_CPUFREQ_DT=m +CONFIG_ARM_RASPBERRYPI_CPUFREQ=m CONFIG_ARM_TEGRA186_CPUFREQ=y CONFIG_ARM_SCPI_PROTOCOL=y CONFIG_RASPBERRYPI_FIRMWARE=y @@ -95,6 +97,7 @@ CONFIG_IMX_SCU_PD=y CONFIG_ACPI=y CONFIG_ACPI_APEI=y CONFIG_ACPI_APEI_GHES=y +CONFIG_ACPI_APEI_PCIEAER=y CONFIG_ACPI_APEI_MEMORY_FAILURE=y CONFIG_ACPI_APEI_EINJ=y CONFIG_VIRTUALIZATION=y @@ -196,6 +199,8 @@ CONFIG_PCIE_HISI_STB=y CONFIG_PCIE_TEGRA194=m CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y CONFIG_HISILICON_LPC=y CONFIG_SIMPLE_PM_BUS=y CONFIG_MTD=y @@ -366,6 +371,7 @@ CONFIG_I2C_IMX_LPI2C=y CONFIG_I2C_MESON=y CONFIG_I2C_MV64XXX=y CONFIG_I2C_PXA=y +CONFIG_I2C_QCOM_GENI=m CONFIG_I2C_QUP=y CONFIG_I2C_RK3X=y CONFIG_I2C_SH_MOBILE=y @@ -392,6 +398,7 @@ CONFIG_SPMI=y CONFIG_PINCTRL_SINGLE=y CONFIG_PINCTRL_MAX77620=y CONFIG_PINCTRL_IMX8MM=y +CONFIG_PINCTRL_IMX8MN=y CONFIG_PINCTRL_IMX8MQ=y CONFIG_PINCTRL_IMX8QXP=y CONFIG_PINCTRL_IPQ8074=y @@ -403,6 +410,7 @@ CONFIG_PINCTRL_QCS404=y CONFIG_PINCTRL_QDF2XXX=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_PINCTRL_SDM845=y +CONFIG_PINCTRL_SM8150=y CONFIG_GPIO_DWAPB=y CONFIG_GPIO_MB86S7X=y CONFIG_GPIO_PL061=y @@ -445,6 +453,7 @@ CONFIG_UNIPHIER_THERMAL=y CONFIG_WATCHDOG=y CONFIG_ARM_SP805_WATCHDOG=y CONFIG_S3C2410_WATCHDOG=y +CONFIG_DW_WATCHDOG=y CONFIG_SUNXI_WATCHDOG=m CONFIG_IMX2_WDT=y CONFIG_IMX_SC_WDT=m @@ -489,6 +498,7 @@ CONFIG_RC_CORE=m CONFIG_RC_DECODERS=y CONFIG_RC_DEVICES=y CONFIG_IR_MESON=m +CONFIG_IR_SUNXI=m CONFIG_MEDIA_SUPPORT=m CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_ANALOG_TV_SUPPORT=y @@ -526,11 +536,13 @@ CONFIG_DRM_RCAR_DU=m CONFIG_DRM_SUN4I=m CONFIG_DRM_SUN8I_DW_HDMI=m CONFIG_DRM_SUN8I_MIXER=m +CONFIG_DRM_MSM=m CONFIG_DRM_TEGRA=m CONFIG_DRM_PANEL_SIMPLE=m CONFIG_DRM_SII902X=m CONFIG_DRM_I2C_ADV7511=m CONFIG_DRM_VC4=m +CONFIG_DRM_ETNAVIV=m CONFIG_DRM_HISI_HIBMC=m CONFIG_DRM_HISI_KIRIN=m CONFIG_DRM_MESON=m @@ -539,6 +551,7 @@ CONFIG_DRM_LIMA=m CONFIG_DRM_PANFROST=m CONFIG_FB=y CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_EFI=y CONFIG_BACKLIGHT_GENERIC=m CONFIG_BACKLIGHT_PWM=m CONFIG_BACKLIGHT_LP855X=m @@ -558,6 +571,7 @@ CONFIG_SND_SOC_ROCKCHIP_RT5645=m CONFIG_SND_SOC_RK3399_GRU_SOUND=m CONFIG_SND_SOC_SAMSUNG=y CONFIG_SND_SOC_RCAR=m +CONFIG_SND_SUN4I_SPDIF=m CONFIG_SND_SOC_AK4613=m CONFIG_SND_SOC_ES7134=m CONFIG_SND_SOC_ES7241=m @@ -651,6 +665,7 @@ CONFIG_DMADEVICES=y CONFIG_FSL_EDMA=y CONFIG_DMA_BCM2835=m CONFIG_DMA_SUN6I=m +CONFIG_IMX_SDMA=y CONFIG_K3_DMA=y CONFIG_MV_XOR=y CONFIG_MV_XOR_V2=y @@ -676,11 +691,15 @@ CONFIG_COMMON_CLK_CS2000_CP=y CONFIG_COMMON_CLK_S2MPS11=y CONFIG_CLK_QORIQ=y CONFIG_COMMON_CLK_PWM=y +CONFIG_CLK_RASPBERRYPI=m CONFIG_CLK_IMX8MM=y +CONFIG_CLK_IMX8MN=y CONFIG_CLK_IMX8MQ=y CONFIG_CLK_IMX8QXP=y CONFIG_TI_SCI_CLK=y CONFIG_COMMON_CLK_QCOM=y +CONFIG_QCOM_A53PLL=y +CONFIG_QCOM_CLK_APCS_MSM8916=y CONFIG_QCOM_CLK_SMD_RPM=y CONFIG_QCOM_CLK_RPMH=y CONFIG_IPQ_GCC_8074=y @@ -690,6 +709,7 @@ CONFIG_MSM_MMCC_8996=y CONFIG_MSM_GCC_8998=y CONFIG_QCS_GCC_404=y CONFIG_SDM_GCC_845=y +CONFIG_SM_GCC_8150=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_ARM_MHU=y @@ -768,6 +788,7 @@ CONFIG_PHY_HISTB_COMBPHY=y CONFIG_PHY_HISI_INNO_USB2=y CONFIG_PHY_MVEBU_CP110_COMPHY=y CONFIG_PHY_QCOM_QMP=m +CONFIG_PHY_QCOM_QUSB2=m CONFIG_PHY_QCOM_USB_HS=y CONFIG_PHY_RCAR_GEN3_PCIE=y CONFIG_PHY_RCAR_GEN3_USB2=y @@ -780,6 +801,7 @@ CONFIG_PHY_ROCKCHIP_TYPEC=y CONFIG_PHY_UNIPHIER_USB2=y CONFIG_PHY_UNIPHIER_USB3=y CONFIG_PHY_TEGRA_XUSB=y +CONFIG_FSL_IMX8_DDR_PMU=m CONFIG_HISI_PMU=y CONFIG_QCOM_L2_PMU=y CONFIG_QCOM_L3_PMU=y diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig index d9a523ecdd836d54e5742135b6ff9e2fb4c7d520..4922c4451e7c3a57030ef86a4d2373ffc1ef4a7d 100644 --- a/arch/arm64/crypto/Kconfig +++ b/arch/arm64/crypto/Kconfig @@ -58,8 +58,7 @@ config CRYPTO_GHASH_ARM64_CE depends on KERNEL_MODE_NEON select CRYPTO_HASH select CRYPTO_GF128MUL - select CRYPTO_AES - select CRYPTO_AES_ARM64 + select CRYPTO_LIB_AES config CRYPTO_CRCT10DIF_ARM64_CE tristate "CRCT10DIF digest algorithm using PMULL instructions" @@ -74,15 +73,15 @@ config CRYPTO_AES_ARM64_CE tristate "AES core cipher using ARMv8 Crypto Extensions" depends on ARM64 && KERNEL_MODE_NEON select CRYPTO_ALGAPI - select CRYPTO_AES_ARM64 + select CRYPTO_LIB_AES config CRYPTO_AES_ARM64_CE_CCM tristate "AES in CCM mode using ARMv8 Crypto Extensions" depends on ARM64 && KERNEL_MODE_NEON select CRYPTO_ALGAPI select CRYPTO_AES_ARM64_CE - select CRYPTO_AES_ARM64 select CRYPTO_AEAD + select CRYPTO_LIB_AES config CRYPTO_AES_ARM64_CE_BLK tristate "AES in ECB/CBC/CTR/XTS modes using ARMv8 Crypto Extensions" @@ -97,7 +96,7 @@ config CRYPTO_AES_ARM64_NEON_BLK depends on KERNEL_MODE_NEON select CRYPTO_BLKCIPHER select CRYPTO_AES_ARM64 - select CRYPTO_AES + select CRYPTO_LIB_AES select CRYPTO_SIMD config CRYPTO_CHACHA20_NEON @@ -117,6 +116,7 @@ config CRYPTO_AES_ARM64_BS select CRYPTO_BLKCIPHER select CRYPTO_AES_ARM64_NEON_BLK select CRYPTO_AES_ARM64 + select CRYPTO_LIB_AES select CRYPTO_SIMD endif diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c index 827e5473e5de7601dc0637755502b70a999df4cf..541cf9165748f31c722b4508121890ddc779f715 100644 --- a/arch/arm64/crypto/aes-ce-ccm-glue.c +++ b/arch/arm64/crypto/aes-ce-ccm-glue.c @@ -43,8 +43,6 @@ asmlinkage void ce_aes_ccm_decrypt(u8 out[], u8 const in[], u32 cbytes, asmlinkage void ce_aes_ccm_final(u8 mac[], u8 const ctr[], u32 const rk[], u32 rounds); -asmlinkage void __aes_arm64_encrypt(u32 *rk, u8 *out, const u8 *in, int rounds); - static int ccm_setkey(struct crypto_aead *tfm, const u8 *in_key, unsigned int key_len) { @@ -124,8 +122,7 @@ static void ccm_update_mac(struct crypto_aes_ctx *key, u8 mac[], u8 const in[], } while (abytes >= AES_BLOCK_SIZE) { - __aes_arm64_encrypt(key->key_enc, mac, mac, - num_rounds(key)); + aes_encrypt(key, mac, mac); crypto_xor(mac, in, AES_BLOCK_SIZE); in += AES_BLOCK_SIZE; @@ -133,8 +130,7 @@ static void ccm_update_mac(struct crypto_aes_ctx *key, u8 mac[], u8 const in[], } if (abytes > 0) { - __aes_arm64_encrypt(key->key_enc, mac, mac, - num_rounds(key)); + aes_encrypt(key, mac, mac); crypto_xor(mac, in, abytes); *macp = abytes; } @@ -206,10 +202,8 @@ static int ccm_crypt_fallback(struct skcipher_walk *walk, u8 mac[], u8 iv0[], bsize = nbytes; crypto_inc(walk->iv, AES_BLOCK_SIZE); - __aes_arm64_encrypt(ctx->key_enc, buf, walk->iv, - num_rounds(ctx)); - __aes_arm64_encrypt(ctx->key_enc, mac, mac, - num_rounds(ctx)); + aes_encrypt(ctx, buf, walk->iv); + aes_encrypt(ctx, mac, mac); if (enc) crypto_xor(mac, src, bsize); crypto_xor_cpy(dst, src, buf, bsize); @@ -224,8 +218,8 @@ static int ccm_crypt_fallback(struct skcipher_walk *walk, u8 mac[], u8 iv0[], } if (!err) { - __aes_arm64_encrypt(ctx->key_enc, buf, iv0, num_rounds(ctx)); - __aes_arm64_encrypt(ctx->key_enc, mac, mac, num_rounds(ctx)); + aes_encrypt(ctx, buf, iv0); + aes_encrypt(ctx, mac, mac); crypto_xor(mac, buf, AES_BLOCK_SIZE); } return err; diff --git a/arch/arm64/crypto/aes-ce-glue.c b/arch/arm64/crypto/aes-ce-glue.c index d3bc97afde203c61f785290648a776dcbf7c8ffc..6d085dc56c5123b8c0c053f256f73a2744f070b3 100644 --- a/arch/arm64/crypto/aes-ce-glue.c +++ b/arch/arm64/crypto/aes-ce-glue.c @@ -20,9 +20,6 @@ MODULE_DESCRIPTION("Synchronous AES cipher using ARMv8 Crypto Extensions"); MODULE_AUTHOR("Ard Biesheuvel "); MODULE_LICENSE("GPL v2"); -asmlinkage void __aes_arm64_encrypt(u32 *rk, u8 *out, const u8 *in, int rounds); -asmlinkage void __aes_arm64_decrypt(u32 *rk, u8 *out, const u8 *in, int rounds); - struct aes_block { u8 b[AES_BLOCK_SIZE]; }; @@ -51,7 +48,7 @@ static void aes_cipher_encrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]) struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); if (!crypto_simd_usable()) { - __aes_arm64_encrypt(ctx->key_enc, dst, src, num_rounds(ctx)); + aes_encrypt(ctx, dst, src); return; } @@ -65,7 +62,7 @@ static void aes_cipher_decrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]) struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); if (!crypto_simd_usable()) { - __aes_arm64_decrypt(ctx->key_dec, dst, src, num_rounds(ctx)); + aes_decrypt(ctx, dst, src); return; } diff --git a/arch/arm64/crypto/aes-ce.S b/arch/arm64/crypto/aes-ce.S index 00bd2885feaa5a17fd85f29ee71f5bbae955a038..c132c49c89a8c4427fd2a252ddd4874a5ad44dfa 100644 --- a/arch/arm64/crypto/aes-ce.S +++ b/arch/arm64/crypto/aes-ce.S @@ -21,6 +21,9 @@ .macro xts_reload_mask, tmp .endm + .macro xts_cts_skip_tw, reg, lbl + .endm + /* preload all round keys */ .macro load_round_keys, rounds, rk cmp \rounds, #12 diff --git a/arch/arm64/crypto/aes-cipher-core.S b/arch/arm64/crypto/aes-cipher-core.S index f06df0d2080cf6453df914f2e23bf6420252c162..423d0aebc570f0350b8a6055b769161c559f2afc 100644 --- a/arch/arm64/crypto/aes-cipher-core.S +++ b/arch/arm64/crypto/aes-cipher-core.S @@ -128,43 +128,5 @@ ENDPROC(__aes_arm64_encrypt) .align 5 ENTRY(__aes_arm64_decrypt) - do_crypt iround, crypto_it_tab, __aes_arm64_inverse_sbox, 0 + do_crypt iround, crypto_it_tab, crypto_aes_inv_sbox, 0 ENDPROC(__aes_arm64_decrypt) - - .section ".rodata", "a" - .align L1_CACHE_SHIFT - .type __aes_arm64_inverse_sbox, %object -__aes_arm64_inverse_sbox: - .byte 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38 - .byte 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb - .byte 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87 - .byte 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb - .byte 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d - .byte 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e - .byte 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2 - .byte 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 - .byte 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16 - .byte 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 - .byte 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda - .byte 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 - .byte 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a - .byte 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 - .byte 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02 - .byte 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b - .byte 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea - .byte 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 - .byte 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85 - .byte 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e - .byte 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89 - .byte 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b - .byte 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20 - .byte 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 - .byte 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31 - .byte 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f - .byte 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d - .byte 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef - .byte 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0 - .byte 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 - .byte 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26 - .byte 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d - .size __aes_arm64_inverse_sbox, . - __aes_arm64_inverse_sbox diff --git a/arch/arm64/crypto/aes-cipher-glue.c b/arch/arm64/crypto/aes-cipher-glue.c index 0913966aa6fa56e2bfcd7f54cf87fa2d73585029..8caf6dfefce88ec91cd0b3f5e510a30ebcde7849 100644 --- a/arch/arm64/crypto/aes-cipher-glue.c +++ b/arch/arm64/crypto/aes-cipher-glue.c @@ -10,12 +10,9 @@ #include asmlinkage void __aes_arm64_encrypt(u32 *rk, u8 *out, const u8 *in, int rounds); -EXPORT_SYMBOL(__aes_arm64_encrypt); - asmlinkage void __aes_arm64_decrypt(u32 *rk, u8 *out, const u8 *in, int rounds); -EXPORT_SYMBOL(__aes_arm64_decrypt); -static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +static void aes_arm64_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); int rounds = 6 + ctx->key_length / 4; @@ -23,7 +20,7 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) __aes_arm64_encrypt(ctx->key_enc, out, in, rounds); } -static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +static void aes_arm64_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); int rounds = 6 + ctx->key_length / 4; @@ -43,8 +40,8 @@ static struct crypto_alg aes_alg = { .cra_cipher.cia_min_keysize = AES_MIN_KEY_SIZE, .cra_cipher.cia_max_keysize = AES_MAX_KEY_SIZE, .cra_cipher.cia_setkey = crypto_aes_set_key, - .cra_cipher.cia_encrypt = aes_encrypt, - .cra_cipher.cia_decrypt = aes_decrypt + .cra_cipher.cia_encrypt = aes_arm64_encrypt, + .cra_cipher.cia_decrypt = aes_arm64_decrypt }; static int __init aes_init(void) diff --git a/arch/arm64/crypto/aes-ctr-fallback.h b/arch/arm64/crypto/aes-ctr-fallback.h deleted file mode 100644 index 3ac911990ec72932aa516e1146e828aefa8ec734..0000000000000000000000000000000000000000 --- a/arch/arm64/crypto/aes-ctr-fallback.h +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Fallback for sync aes(ctr) in contexts where kernel mode NEON - * is not allowed - * - * Copyright (C) 2017 Linaro Ltd - */ - -#include -#include - -asmlinkage void __aes_arm64_encrypt(u32 *rk, u8 *out, const u8 *in, int rounds); - -static inline int aes_ctr_encrypt_fallback(struct crypto_aes_ctx *ctx, - struct skcipher_request *req) -{ - struct skcipher_walk walk; - u8 buf[AES_BLOCK_SIZE]; - int err; - - err = skcipher_walk_virt(&walk, req, true); - - while (walk.nbytes > 0) { - u8 *dst = walk.dst.virt.addr; - u8 *src = walk.src.virt.addr; - int nbytes = walk.nbytes; - int tail = 0; - - if (nbytes < walk.total) { - nbytes = round_down(nbytes, AES_BLOCK_SIZE); - tail = walk.nbytes % AES_BLOCK_SIZE; - } - - do { - int bsize = min(nbytes, AES_BLOCK_SIZE); - - __aes_arm64_encrypt(ctx->key_enc, buf, walk.iv, - 6 + ctx->key_length / 4); - crypto_xor_cpy(dst, src, buf, bsize); - crypto_inc(walk.iv, AES_BLOCK_SIZE); - - dst += AES_BLOCK_SIZE; - src += AES_BLOCK_SIZE; - nbytes -= AES_BLOCK_SIZE; - } while (nbytes > 0); - - err = skcipher_walk_done(&walk, tail); - } - return err; -} diff --git a/arch/arm64/crypto/aes-glue.c b/arch/arm64/crypto/aes-glue.c index 8d6c8932c84148e0b5345e251a6a23668b80b98a..aa57dc639f77fbef95a1dc3c042fdaa58487c44d 100644 --- a/arch/arm64/crypto/aes-glue.c +++ b/arch/arm64/crypto/aes-glue.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include @@ -18,12 +20,10 @@ #include #include "aes-ce-setkey.h" -#include "aes-ctr-fallback.h" #ifdef USE_V8_CRYPTO_EXTENSIONS #define MODE "ce" #define PRIO 300 -#define aes_setkey ce_aes_setkey #define aes_expandkey ce_aes_expandkey #define aes_ecb_encrypt ce_aes_ecb_encrypt #define aes_ecb_decrypt ce_aes_ecb_decrypt @@ -31,6 +31,8 @@ #define aes_cbc_decrypt ce_aes_cbc_decrypt #define aes_cbc_cts_encrypt ce_aes_cbc_cts_encrypt #define aes_cbc_cts_decrypt ce_aes_cbc_cts_decrypt +#define aes_essiv_cbc_encrypt ce_aes_essiv_cbc_encrypt +#define aes_essiv_cbc_decrypt ce_aes_essiv_cbc_decrypt #define aes_ctr_encrypt ce_aes_ctr_encrypt #define aes_xts_encrypt ce_aes_xts_encrypt #define aes_xts_decrypt ce_aes_xts_decrypt @@ -39,27 +41,31 @@ MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 Crypto Extensions"); #else #define MODE "neon" #define PRIO 200 -#define aes_setkey crypto_aes_set_key -#define aes_expandkey crypto_aes_expand_key #define aes_ecb_encrypt neon_aes_ecb_encrypt #define aes_ecb_decrypt neon_aes_ecb_decrypt #define aes_cbc_encrypt neon_aes_cbc_encrypt #define aes_cbc_decrypt neon_aes_cbc_decrypt #define aes_cbc_cts_encrypt neon_aes_cbc_cts_encrypt #define aes_cbc_cts_decrypt neon_aes_cbc_cts_decrypt +#define aes_essiv_cbc_encrypt neon_aes_essiv_cbc_encrypt +#define aes_essiv_cbc_decrypt neon_aes_essiv_cbc_decrypt #define aes_ctr_encrypt neon_aes_ctr_encrypt #define aes_xts_encrypt neon_aes_xts_encrypt #define aes_xts_decrypt neon_aes_xts_decrypt #define aes_mac_update neon_aes_mac_update MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 NEON"); +#endif +#if defined(USE_V8_CRYPTO_EXTENSIONS) || !defined(CONFIG_CRYPTO_AES_ARM64_BS) MODULE_ALIAS_CRYPTO("ecb(aes)"); MODULE_ALIAS_CRYPTO("cbc(aes)"); MODULE_ALIAS_CRYPTO("ctr(aes)"); MODULE_ALIAS_CRYPTO("xts(aes)"); +#endif +MODULE_ALIAS_CRYPTO("cts(cbc(aes))"); +MODULE_ALIAS_CRYPTO("essiv(cbc(aes),sha256)"); MODULE_ALIAS_CRYPTO("cmac(aes)"); MODULE_ALIAS_CRYPTO("xcbc(aes)"); MODULE_ALIAS_CRYPTO("cbcmac(aes)"); -#endif MODULE_AUTHOR("Ard Biesheuvel "); MODULE_LICENSE("GPL v2"); @@ -84,25 +90,32 @@ asmlinkage void aes_ctr_encrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, int blocks, u8 ctr[]); asmlinkage void aes_xts_encrypt(u8 out[], u8 const in[], u32 const rk1[], - int rounds, int blocks, u32 const rk2[], u8 iv[], + int rounds, int bytes, u32 const rk2[], u8 iv[], int first); asmlinkage void aes_xts_decrypt(u8 out[], u8 const in[], u32 const rk1[], - int rounds, int blocks, u32 const rk2[], u8 iv[], + int rounds, int bytes, u32 const rk2[], u8 iv[], int first); +asmlinkage void aes_essiv_cbc_encrypt(u8 out[], u8 const in[], u32 const rk1[], + int rounds, int blocks, u8 iv[], + u32 const rk2[]); +asmlinkage void aes_essiv_cbc_decrypt(u8 out[], u8 const in[], u32 const rk1[], + int rounds, int blocks, u8 iv[], + u32 const rk2[]); + asmlinkage void aes_mac_update(u8 const in[], u32 const rk[], int rounds, int blocks, u8 dg[], int enc_before, int enc_after); -struct cts_cbc_req_ctx { - struct scatterlist sg_src[2]; - struct scatterlist sg_dst[2]; - struct skcipher_request subreq; +struct crypto_aes_xts_ctx { + struct crypto_aes_ctx key1; + struct crypto_aes_ctx __aligned(8) key2; }; -struct crypto_aes_xts_ctx { +struct crypto_aes_essiv_cbc_ctx { struct crypto_aes_ctx key1; struct crypto_aes_ctx __aligned(8) key2; + struct crypto_shash *hash; }; struct mac_tfm_ctx { @@ -118,11 +131,18 @@ struct mac_desc_ctx { static int skcipher_aes_setkey(struct crypto_skcipher *tfm, const u8 *in_key, unsigned int key_len) { - return aes_setkey(crypto_skcipher_tfm(tfm), in_key, key_len); + struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); + int ret; + + ret = aes_expandkey(ctx, in_key, key_len); + if (ret) + crypto_skcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + + return ret; } -static int xts_set_key(struct crypto_skcipher *tfm, const u8 *in_key, - unsigned int key_len) +static int __maybe_unused xts_set_key(struct crypto_skcipher *tfm, + const u8 *in_key, unsigned int key_len) { struct crypto_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm); int ret; @@ -142,7 +162,33 @@ static int xts_set_key(struct crypto_skcipher *tfm, const u8 *in_key, return -EINVAL; } -static int ecb_encrypt(struct skcipher_request *req) +static int __maybe_unused essiv_cbc_set_key(struct crypto_skcipher *tfm, + const u8 *in_key, + unsigned int key_len) +{ + struct crypto_aes_essiv_cbc_ctx *ctx = crypto_skcipher_ctx(tfm); + SHASH_DESC_ON_STACK(desc, ctx->hash); + u8 digest[SHA256_DIGEST_SIZE]; + int ret; + + ret = aes_expandkey(&ctx->key1, in_key, key_len); + if (ret) + goto out; + + desc->tfm = ctx->hash; + crypto_shash_digest(desc, in_key, key_len, digest); + + ret = aes_expandkey(&ctx->key2, digest, sizeof(digest)); + if (ret) + goto out; + + return 0; +out: + crypto_skcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; +} + +static int __maybe_unused ecb_encrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); @@ -162,7 +208,7 @@ static int ecb_encrypt(struct skcipher_request *req) return err; } -static int ecb_decrypt(struct skcipher_request *req) +static int __maybe_unused ecb_decrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); @@ -182,63 +228,78 @@ static int ecb_decrypt(struct skcipher_request *req) return err; } -static int cbc_encrypt(struct skcipher_request *req) +static int cbc_encrypt_walk(struct skcipher_request *req, + struct skcipher_walk *walk) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); - int err, rounds = 6 + ctx->key_length / 4; - struct skcipher_walk walk; + int err = 0, rounds = 6 + ctx->key_length / 4; unsigned int blocks; - err = skcipher_walk_virt(&walk, req, false); - - while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { + while ((blocks = (walk->nbytes / AES_BLOCK_SIZE))) { kernel_neon_begin(); - aes_cbc_encrypt(walk.dst.virt.addr, walk.src.virt.addr, - ctx->key_enc, rounds, blocks, walk.iv); + aes_cbc_encrypt(walk->dst.virt.addr, walk->src.virt.addr, + ctx->key_enc, rounds, blocks, walk->iv); kernel_neon_end(); - err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); + err = skcipher_walk_done(walk, walk->nbytes % AES_BLOCK_SIZE); } return err; } -static int cbc_decrypt(struct skcipher_request *req) +static int __maybe_unused cbc_encrypt(struct skcipher_request *req) { - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); - int err, rounds = 6 + ctx->key_length / 4; struct skcipher_walk walk; - unsigned int blocks; + int err; err = skcipher_walk_virt(&walk, req, false); + if (err) + return err; + return cbc_encrypt_walk(req, &walk); +} - while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { +static int cbc_decrypt_walk(struct skcipher_request *req, + struct skcipher_walk *walk) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); + int err = 0, rounds = 6 + ctx->key_length / 4; + unsigned int blocks; + + while ((blocks = (walk->nbytes / AES_BLOCK_SIZE))) { kernel_neon_begin(); - aes_cbc_decrypt(walk.dst.virt.addr, walk.src.virt.addr, - ctx->key_dec, rounds, blocks, walk.iv); + aes_cbc_decrypt(walk->dst.virt.addr, walk->src.virt.addr, + ctx->key_dec, rounds, blocks, walk->iv); kernel_neon_end(); - err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); + err = skcipher_walk_done(walk, walk->nbytes % AES_BLOCK_SIZE); } return err; } -static int cts_cbc_init_tfm(struct crypto_skcipher *tfm) +static int __maybe_unused cbc_decrypt(struct skcipher_request *req) { - crypto_skcipher_set_reqsize(tfm, sizeof(struct cts_cbc_req_ctx)); - return 0; + struct skcipher_walk walk; + int err; + + err = skcipher_walk_virt(&walk, req, false); + if (err) + return err; + return cbc_decrypt_walk(req, &walk); } static int cts_cbc_encrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); - struct cts_cbc_req_ctx *rctx = skcipher_request_ctx(req); int err, rounds = 6 + ctx->key_length / 4; int cbc_blocks = DIV_ROUND_UP(req->cryptlen, AES_BLOCK_SIZE) - 2; struct scatterlist *src = req->src, *dst = req->dst; + struct scatterlist sg_src[2], sg_dst[2]; + struct skcipher_request subreq; struct skcipher_walk walk; - skcipher_request_set_tfm(&rctx->subreq, tfm); + skcipher_request_set_tfm(&subreq, tfm); + skcipher_request_set_callback(&subreq, skcipher_request_flags(req), + NULL, NULL); if (req->cryptlen <= AES_BLOCK_SIZE) { if (req->cryptlen < AES_BLOCK_SIZE) @@ -247,41 +308,30 @@ static int cts_cbc_encrypt(struct skcipher_request *req) } if (cbc_blocks > 0) { - unsigned int blocks; - - skcipher_request_set_crypt(&rctx->subreq, req->src, req->dst, + skcipher_request_set_crypt(&subreq, req->src, req->dst, cbc_blocks * AES_BLOCK_SIZE, req->iv); - err = skcipher_walk_virt(&walk, &rctx->subreq, false); - - while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { - kernel_neon_begin(); - aes_cbc_encrypt(walk.dst.virt.addr, walk.src.virt.addr, - ctx->key_enc, rounds, blocks, walk.iv); - kernel_neon_end(); - err = skcipher_walk_done(&walk, - walk.nbytes % AES_BLOCK_SIZE); - } + err = skcipher_walk_virt(&walk, &subreq, false) ?: + cbc_encrypt_walk(&subreq, &walk); if (err) return err; if (req->cryptlen == AES_BLOCK_SIZE) return 0; - dst = src = scatterwalk_ffwd(rctx->sg_src, req->src, - rctx->subreq.cryptlen); + dst = src = scatterwalk_ffwd(sg_src, req->src, subreq.cryptlen); if (req->dst != req->src) - dst = scatterwalk_ffwd(rctx->sg_dst, req->dst, - rctx->subreq.cryptlen); + dst = scatterwalk_ffwd(sg_dst, req->dst, + subreq.cryptlen); } /* handle ciphertext stealing */ - skcipher_request_set_crypt(&rctx->subreq, src, dst, + skcipher_request_set_crypt(&subreq, src, dst, req->cryptlen - cbc_blocks * AES_BLOCK_SIZE, req->iv); - err = skcipher_walk_virt(&walk, &rctx->subreq, false); + err = skcipher_walk_virt(&walk, &subreq, false); if (err) return err; @@ -297,13 +347,16 @@ static int cts_cbc_decrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); - struct cts_cbc_req_ctx *rctx = skcipher_request_ctx(req); int err, rounds = 6 + ctx->key_length / 4; int cbc_blocks = DIV_ROUND_UP(req->cryptlen, AES_BLOCK_SIZE) - 2; struct scatterlist *src = req->src, *dst = req->dst; + struct scatterlist sg_src[2], sg_dst[2]; + struct skcipher_request subreq; struct skcipher_walk walk; - skcipher_request_set_tfm(&rctx->subreq, tfm); + skcipher_request_set_tfm(&subreq, tfm); + skcipher_request_set_callback(&subreq, skcipher_request_flags(req), + NULL, NULL); if (req->cryptlen <= AES_BLOCK_SIZE) { if (req->cryptlen < AES_BLOCK_SIZE) @@ -312,41 +365,30 @@ static int cts_cbc_decrypt(struct skcipher_request *req) } if (cbc_blocks > 0) { - unsigned int blocks; - - skcipher_request_set_crypt(&rctx->subreq, req->src, req->dst, + skcipher_request_set_crypt(&subreq, req->src, req->dst, cbc_blocks * AES_BLOCK_SIZE, req->iv); - err = skcipher_walk_virt(&walk, &rctx->subreq, false); - - while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { - kernel_neon_begin(); - aes_cbc_decrypt(walk.dst.virt.addr, walk.src.virt.addr, - ctx->key_dec, rounds, blocks, walk.iv); - kernel_neon_end(); - err = skcipher_walk_done(&walk, - walk.nbytes % AES_BLOCK_SIZE); - } + err = skcipher_walk_virt(&walk, &subreq, false) ?: + cbc_decrypt_walk(&subreq, &walk); if (err) return err; if (req->cryptlen == AES_BLOCK_SIZE) return 0; - dst = src = scatterwalk_ffwd(rctx->sg_src, req->src, - rctx->subreq.cryptlen); + dst = src = scatterwalk_ffwd(sg_src, req->src, subreq.cryptlen); if (req->dst != req->src) - dst = scatterwalk_ffwd(rctx->sg_dst, req->dst, - rctx->subreq.cryptlen); + dst = scatterwalk_ffwd(sg_dst, req->dst, + subreq.cryptlen); } /* handle ciphertext stealing */ - skcipher_request_set_crypt(&rctx->subreq, src, dst, + skcipher_request_set_crypt(&subreq, src, dst, req->cryptlen - cbc_blocks * AES_BLOCK_SIZE, req->iv); - err = skcipher_walk_virt(&walk, &rctx->subreq, false); + err = skcipher_walk_virt(&walk, &subreq, false); if (err) return err; @@ -358,6 +400,66 @@ static int cts_cbc_decrypt(struct skcipher_request *req) return skcipher_walk_done(&walk, 0); } +static int __maybe_unused essiv_cbc_init_tfm(struct crypto_skcipher *tfm) +{ + struct crypto_aes_essiv_cbc_ctx *ctx = crypto_skcipher_ctx(tfm); + + ctx->hash = crypto_alloc_shash("sha256", 0, 0); + + return PTR_ERR_OR_ZERO(ctx->hash); +} + +static void __maybe_unused essiv_cbc_exit_tfm(struct crypto_skcipher *tfm) +{ + struct crypto_aes_essiv_cbc_ctx *ctx = crypto_skcipher_ctx(tfm); + + crypto_free_shash(ctx->hash); +} + +static int __maybe_unused essiv_cbc_encrypt(struct skcipher_request *req) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct crypto_aes_essiv_cbc_ctx *ctx = crypto_skcipher_ctx(tfm); + int err, rounds = 6 + ctx->key1.key_length / 4; + struct skcipher_walk walk; + unsigned int blocks; + + err = skcipher_walk_virt(&walk, req, false); + + blocks = walk.nbytes / AES_BLOCK_SIZE; + if (blocks) { + kernel_neon_begin(); + aes_essiv_cbc_encrypt(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key1.key_enc, rounds, blocks, + req->iv, ctx->key2.key_enc); + kernel_neon_end(); + err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); + } + return err ?: cbc_encrypt_walk(req, &walk); +} + +static int __maybe_unused essiv_cbc_decrypt(struct skcipher_request *req) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct crypto_aes_essiv_cbc_ctx *ctx = crypto_skcipher_ctx(tfm); + int err, rounds = 6 + ctx->key1.key_length / 4; + struct skcipher_walk walk; + unsigned int blocks; + + err = skcipher_walk_virt(&walk, req, false); + + blocks = walk.nbytes / AES_BLOCK_SIZE; + if (blocks) { + kernel_neon_begin(); + aes_essiv_cbc_decrypt(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key1.key_dec, rounds, blocks, + req->iv, ctx->key2.key_enc); + kernel_neon_end(); + err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); + } + return err ?: cbc_decrypt_walk(req, &walk); +} + static int ctr_encrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); @@ -397,62 +499,176 @@ static int ctr_encrypt(struct skcipher_request *req) return err; } -static int ctr_encrypt_sync(struct skcipher_request *req) +static void ctr_encrypt_one(struct crypto_skcipher *tfm, const u8 *src, u8 *dst) { - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); + const struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); + unsigned long flags; + + /* + * Temporarily disable interrupts to avoid races where + * cachelines are evicted when the CPU is interrupted + * to do something else. + */ + local_irq_save(flags); + aes_encrypt(ctx, dst, src); + local_irq_restore(flags); +} +static int __maybe_unused ctr_encrypt_sync(struct skcipher_request *req) +{ if (!crypto_simd_usable()) - return aes_ctr_encrypt_fallback(ctx, req); + return crypto_ctr_encrypt_walk(req, ctr_encrypt_one); return ctr_encrypt(req); } -static int xts_encrypt(struct skcipher_request *req) +static int __maybe_unused xts_encrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct crypto_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm); int err, first, rounds = 6 + ctx->key1.key_length / 4; + int tail = req->cryptlen % AES_BLOCK_SIZE; + struct scatterlist sg_src[2], sg_dst[2]; + struct skcipher_request subreq; + struct scatterlist *src, *dst; struct skcipher_walk walk; - unsigned int blocks; + + if (req->cryptlen < AES_BLOCK_SIZE) + return -EINVAL; err = skcipher_walk_virt(&walk, req, false); - for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) { + if (unlikely(tail > 0 && walk.nbytes < walk.total)) { + int xts_blocks = DIV_ROUND_UP(req->cryptlen, + AES_BLOCK_SIZE) - 2; + + skcipher_walk_abort(&walk); + + skcipher_request_set_tfm(&subreq, tfm); + skcipher_request_set_callback(&subreq, + skcipher_request_flags(req), + NULL, NULL); + skcipher_request_set_crypt(&subreq, req->src, req->dst, + xts_blocks * AES_BLOCK_SIZE, + req->iv); + req = &subreq; + err = skcipher_walk_virt(&walk, req, false); + } else { + tail = 0; + } + + for (first = 1; walk.nbytes >= AES_BLOCK_SIZE; first = 0) { + int nbytes = walk.nbytes; + + if (walk.nbytes < walk.total) + nbytes &= ~(AES_BLOCK_SIZE - 1); + kernel_neon_begin(); aes_xts_encrypt(walk.dst.virt.addr, walk.src.virt.addr, - ctx->key1.key_enc, rounds, blocks, + ctx->key1.key_enc, rounds, nbytes, ctx->key2.key_enc, walk.iv, first); kernel_neon_end(); - err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); + err = skcipher_walk_done(&walk, walk.nbytes - nbytes); } - return err; + if (err || likely(!tail)) + return err; + + dst = src = scatterwalk_ffwd(sg_src, req->src, req->cryptlen); + if (req->dst != req->src) + dst = scatterwalk_ffwd(sg_dst, req->dst, req->cryptlen); + + skcipher_request_set_crypt(req, src, dst, AES_BLOCK_SIZE + tail, + req->iv); + + err = skcipher_walk_virt(&walk, &subreq, false); + if (err) + return err; + + kernel_neon_begin(); + aes_xts_encrypt(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key1.key_enc, rounds, walk.nbytes, + ctx->key2.key_enc, walk.iv, first); + kernel_neon_end(); + + return skcipher_walk_done(&walk, 0); } -static int xts_decrypt(struct skcipher_request *req) +static int __maybe_unused xts_decrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct crypto_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm); int err, first, rounds = 6 + ctx->key1.key_length / 4; + int tail = req->cryptlen % AES_BLOCK_SIZE; + struct scatterlist sg_src[2], sg_dst[2]; + struct skcipher_request subreq; + struct scatterlist *src, *dst; struct skcipher_walk walk; - unsigned int blocks; + + if (req->cryptlen < AES_BLOCK_SIZE) + return -EINVAL; err = skcipher_walk_virt(&walk, req, false); - for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) { + if (unlikely(tail > 0 && walk.nbytes < walk.total)) { + int xts_blocks = DIV_ROUND_UP(req->cryptlen, + AES_BLOCK_SIZE) - 2; + + skcipher_walk_abort(&walk); + + skcipher_request_set_tfm(&subreq, tfm); + skcipher_request_set_callback(&subreq, + skcipher_request_flags(req), + NULL, NULL); + skcipher_request_set_crypt(&subreq, req->src, req->dst, + xts_blocks * AES_BLOCK_SIZE, + req->iv); + req = &subreq; + err = skcipher_walk_virt(&walk, req, false); + } else { + tail = 0; + } + + for (first = 1; walk.nbytes >= AES_BLOCK_SIZE; first = 0) { + int nbytes = walk.nbytes; + + if (walk.nbytes < walk.total) + nbytes &= ~(AES_BLOCK_SIZE - 1); + kernel_neon_begin(); aes_xts_decrypt(walk.dst.virt.addr, walk.src.virt.addr, - ctx->key1.key_dec, rounds, blocks, + ctx->key1.key_dec, rounds, nbytes, ctx->key2.key_enc, walk.iv, first); kernel_neon_end(); - err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); + err = skcipher_walk_done(&walk, walk.nbytes - nbytes); } - return err; + if (err || likely(!tail)) + return err; + + dst = src = scatterwalk_ffwd(sg_src, req->src, req->cryptlen); + if (req->dst != req->src) + dst = scatterwalk_ffwd(sg_dst, req->dst, req->cryptlen); + + skcipher_request_set_crypt(req, src, dst, AES_BLOCK_SIZE + tail, + req->iv); + + err = skcipher_walk_virt(&walk, &subreq, false); + if (err) + return err; + + + kernel_neon_begin(); + aes_xts_decrypt(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key1.key_dec, rounds, walk.nbytes, + ctx->key2.key_enc, walk.iv, first); + kernel_neon_end(); + + return skcipher_walk_done(&walk, 0); } static struct skcipher_alg aes_algs[] = { { +#if defined(USE_V8_CRYPTO_EXTENSIONS) || !defined(CONFIG_CRYPTO_AES_ARM64_BS) .base = { .cra_name = "__ecb(aes)", .cra_driver_name = "__ecb-aes-" MODE, @@ -483,24 +699,6 @@ static struct skcipher_alg aes_algs[] = { { .setkey = skcipher_aes_setkey, .encrypt = cbc_encrypt, .decrypt = cbc_decrypt, -}, { - .base = { - .cra_name = "__cts(cbc(aes))", - .cra_driver_name = "__cts-cbc-aes-" MODE, - .cra_priority = PRIO, - .cra_flags = CRYPTO_ALG_INTERNAL, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypto_aes_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - .walksize = 2 * AES_BLOCK_SIZE, - .setkey = skcipher_aes_setkey, - .encrypt = cts_cbc_encrypt, - .decrypt = cts_cbc_decrypt, - .init = cts_cbc_init_tfm, }, { .base = { .cra_name = "__ctr(aes)", @@ -547,9 +745,46 @@ static struct skcipher_alg aes_algs[] = { { .min_keysize = 2 * AES_MIN_KEY_SIZE, .max_keysize = 2 * AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, + .walksize = 2 * AES_BLOCK_SIZE, .setkey = xts_set_key, .encrypt = xts_encrypt, .decrypt = xts_decrypt, +}, { +#endif + .base = { + .cra_name = "__cts(cbc(aes))", + .cra_driver_name = "__cts-cbc-aes-" MODE, + .cra_priority = PRIO, + .cra_flags = CRYPTO_ALG_INTERNAL, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypto_aes_ctx), + .cra_module = THIS_MODULE, + }, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .walksize = 2 * AES_BLOCK_SIZE, + .setkey = skcipher_aes_setkey, + .encrypt = cts_cbc_encrypt, + .decrypt = cts_cbc_decrypt, +}, { + .base = { + .cra_name = "__essiv(cbc(aes),sha256)", + .cra_driver_name = "__essiv-cbc-aes-sha256-" MODE, + .cra_priority = PRIO + 1, + .cra_flags = CRYPTO_ALG_INTERNAL, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypto_aes_essiv_cbc_ctx), + .cra_module = THIS_MODULE, + }, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = essiv_cbc_set_key, + .encrypt = essiv_cbc_encrypt, + .decrypt = essiv_cbc_decrypt, + .init = essiv_cbc_init_tfm, + .exit = essiv_cbc_exit_tfm, } }; static int cbcmac_setkey(struct crypto_shash *tfm, const u8 *in_key, @@ -646,15 +881,14 @@ static void mac_do_update(struct crypto_aes_ctx *ctx, u8 const in[], int blocks, kernel_neon_end(); } else { if (enc_before) - __aes_arm64_encrypt(ctx->key_enc, dg, dg, rounds); + aes_encrypt(ctx, dg, dg); while (blocks--) { crypto_xor(dg, in, AES_BLOCK_SIZE); in += AES_BLOCK_SIZE; if (blocks || enc_after) - __aes_arm64_encrypt(ctx->key_enc, dg, dg, - rounds); + aes_encrypt(ctx, dg, dg); } } } @@ -837,5 +1071,7 @@ module_cpu_feature_match(AES, aes_init); module_init(aes_init); EXPORT_SYMBOL(neon_aes_ecb_encrypt); EXPORT_SYMBOL(neon_aes_cbc_encrypt); +EXPORT_SYMBOL(neon_aes_xts_encrypt); +EXPORT_SYMBOL(neon_aes_xts_decrypt); #endif module_exit(aes_exit); diff --git a/arch/arm64/crypto/aes-modes.S b/arch/arm64/crypto/aes-modes.S index 324039b720942f1a29b2b874eb10a1ccf7a4c1d6..131618389f1fda7fd3744ce0584a33ce5cc20388 100644 --- a/arch/arm64/crypto/aes-modes.S +++ b/arch/arm64/crypto/aes-modes.S @@ -118,8 +118,23 @@ AES_ENDPROC(aes_ecb_decrypt) * int blocks, u8 iv[]) * aes_cbc_decrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, * int blocks, u8 iv[]) + * aes_essiv_cbc_encrypt(u8 out[], u8 const in[], u32 const rk1[], + * int rounds, int blocks, u8 iv[], + * u32 const rk2[]); + * aes_essiv_cbc_decrypt(u8 out[], u8 const in[], u32 const rk1[], + * int rounds, int blocks, u8 iv[], + * u32 const rk2[]); */ +AES_ENTRY(aes_essiv_cbc_encrypt) + ld1 {v4.16b}, [x5] /* get iv */ + + mov w8, #14 /* AES-256: 14 rounds */ + enc_prepare w8, x6, x7 + encrypt_block v4, w8, x6, x7, w9 + enc_switch_key w3, x2, x6 + b .Lcbcencloop4x + AES_ENTRY(aes_cbc_encrypt) ld1 {v4.16b}, [x5] /* get iv */ enc_prepare w3, x2, x6 @@ -153,13 +168,25 @@ AES_ENTRY(aes_cbc_encrypt) st1 {v4.16b}, [x5] /* return iv */ ret AES_ENDPROC(aes_cbc_encrypt) +AES_ENDPROC(aes_essiv_cbc_encrypt) +AES_ENTRY(aes_essiv_cbc_decrypt) + stp x29, x30, [sp, #-16]! + mov x29, sp + + ld1 {cbciv.16b}, [x5] /* get iv */ + + mov w8, #14 /* AES-256: 14 rounds */ + enc_prepare w8, x6, x7 + encrypt_block cbciv, w8, x6, x7, w9 + b .Lessivcbcdecstart AES_ENTRY(aes_cbc_decrypt) stp x29, x30, [sp, #-16]! mov x29, sp ld1 {cbciv.16b}, [x5] /* get iv */ +.Lessivcbcdecstart: dec_prepare w3, x2, x6 .LcbcdecloopNx: @@ -212,6 +239,7 @@ ST5( st1 {v4.16b}, [x0], #16 ) ldp x29, x30, [sp], #16 ret AES_ENDPROC(aes_cbc_decrypt) +AES_ENDPROC(aes_essiv_cbc_decrypt) /* @@ -265,12 +293,11 @@ AES_ENTRY(aes_cbc_cts_decrypt) ld1 {v5.16b}, [x5] /* get iv */ dec_prepare w3, x2, x6 - tbl v2.16b, {v1.16b}, v4.16b decrypt_block v0, w3, x2, x6, w7 - eor v2.16b, v2.16b, v0.16b + tbl v2.16b, {v0.16b}, v3.16b + eor v2.16b, v2.16b, v1.16b tbx v0.16b, {v1.16b}, v4.16b - tbl v2.16b, {v2.16b}, v3.16b decrypt_block v0, w3, x2, x6, w7 eor v0.16b, v0.16b, v5.16b /* xor with iv */ @@ -386,10 +413,10 @@ AES_ENDPROC(aes_ctr_encrypt) /* + * aes_xts_encrypt(u8 out[], u8 const in[], u8 const rk1[], int rounds, + * int bytes, u8 const rk2[], u8 iv[], int first) * aes_xts_decrypt(u8 out[], u8 const in[], u8 const rk1[], int rounds, - * int blocks, u8 const rk2[], u8 iv[], int first) - * aes_xts_decrypt(u8 out[], u8 const in[], u8 const rk1[], int rounds, - * int blocks, u8 const rk2[], u8 iv[], int first) + * int bytes, u8 const rk2[], u8 iv[], int first) */ .macro next_tweak, out, in, tmp @@ -415,6 +442,7 @@ AES_ENTRY(aes_xts_encrypt) cbz w7, .Lxtsencnotfirst enc_prepare w3, x5, x8 + xts_cts_skip_tw w7, .LxtsencNx encrypt_block v4, w3, x5, x8, w7 /* first tweak */ enc_switch_key w3, x2, x8 b .LxtsencNx @@ -424,7 +452,7 @@ AES_ENTRY(aes_xts_encrypt) .LxtsencloopNx: next_tweak v4, v4, v8 .LxtsencNx: - subs w4, w4, #4 + subs w4, w4, #64 bmi .Lxtsenc1x ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 pt blocks */ next_tweak v5, v4, v8 @@ -441,39 +469,74 @@ AES_ENTRY(aes_xts_encrypt) eor v2.16b, v2.16b, v6.16b st1 {v0.16b-v3.16b}, [x0], #64 mov v4.16b, v7.16b - cbz w4, .Lxtsencout + cbz w4, .Lxtsencret xts_reload_mask v8 b .LxtsencloopNx .Lxtsenc1x: - adds w4, w4, #4 + adds w4, w4, #64 beq .Lxtsencout + subs w4, w4, #16 + bmi .LxtsencctsNx .Lxtsencloop: - ld1 {v1.16b}, [x1], #16 - eor v0.16b, v1.16b, v4.16b + ld1 {v0.16b}, [x1], #16 +.Lxtsencctsout: + eor v0.16b, v0.16b, v4.16b encrypt_block v0, w3, x2, x8, w7 eor v0.16b, v0.16b, v4.16b - st1 {v0.16b}, [x0], #16 - subs w4, w4, #1 - beq .Lxtsencout + cbz w4, .Lxtsencout + subs w4, w4, #16 next_tweak v4, v4, v8 + bmi .Lxtsenccts + st1 {v0.16b}, [x0], #16 b .Lxtsencloop .Lxtsencout: + st1 {v0.16b}, [x0] +.Lxtsencret: st1 {v4.16b}, [x6] ldp x29, x30, [sp], #16 ret -AES_ENDPROC(aes_xts_encrypt) +.LxtsencctsNx: + mov v0.16b, v3.16b + sub x0, x0, #16 +.Lxtsenccts: + adr_l x8, .Lcts_permute_table + + add x1, x1, w4, sxtw /* rewind input pointer */ + add w4, w4, #16 /* # bytes in final block */ + add x9, x8, #32 + add x8, x8, x4 + sub x9, x9, x4 + add x4, x0, x4 /* output address of final block */ + + ld1 {v1.16b}, [x1] /* load final block */ + ld1 {v2.16b}, [x8] + ld1 {v3.16b}, [x9] + + tbl v2.16b, {v0.16b}, v2.16b + tbx v0.16b, {v1.16b}, v3.16b + st1 {v2.16b}, [x4] /* overlapping stores */ + mov w4, wzr + b .Lxtsencctsout +AES_ENDPROC(aes_xts_encrypt) AES_ENTRY(aes_xts_decrypt) stp x29, x30, [sp, #-16]! mov x29, sp + /* subtract 16 bytes if we are doing CTS */ + sub w8, w4, #0x10 + tst w4, #0xf + csel w4, w4, w8, eq + ld1 {v4.16b}, [x6] xts_load_mask v8 + xts_cts_skip_tw w7, .Lxtsdecskiptw cbz w7, .Lxtsdecnotfirst enc_prepare w3, x5, x8 encrypt_block v4, w3, x5, x8, w7 /* first tweak */ +.Lxtsdecskiptw: dec_prepare w3, x2, x8 b .LxtsdecNx @@ -482,7 +545,7 @@ AES_ENTRY(aes_xts_decrypt) .LxtsdecloopNx: next_tweak v4, v4, v8 .LxtsdecNx: - subs w4, w4, #4 + subs w4, w4, #64 bmi .Lxtsdec1x ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 ct blocks */ next_tweak v5, v4, v8 @@ -503,22 +566,52 @@ AES_ENTRY(aes_xts_decrypt) xts_reload_mask v8 b .LxtsdecloopNx .Lxtsdec1x: - adds w4, w4, #4 + adds w4, w4, #64 beq .Lxtsdecout + subs w4, w4, #16 .Lxtsdecloop: - ld1 {v1.16b}, [x1], #16 - eor v0.16b, v1.16b, v4.16b + ld1 {v0.16b}, [x1], #16 + bmi .Lxtsdeccts +.Lxtsdecctsout: + eor v0.16b, v0.16b, v4.16b decrypt_block v0, w3, x2, x8, w7 eor v0.16b, v0.16b, v4.16b st1 {v0.16b}, [x0], #16 - subs w4, w4, #1 - beq .Lxtsdecout + cbz w4, .Lxtsdecout + subs w4, w4, #16 next_tweak v4, v4, v8 b .Lxtsdecloop .Lxtsdecout: st1 {v4.16b}, [x6] ldp x29, x30, [sp], #16 ret + +.Lxtsdeccts: + adr_l x8, .Lcts_permute_table + + add x1, x1, w4, sxtw /* rewind input pointer */ + add w4, w4, #16 /* # bytes in final block */ + add x9, x8, #32 + add x8, x8, x4 + sub x9, x9, x4 + add x4, x0, x4 /* output address of final block */ + + next_tweak v5, v4, v8 + + ld1 {v1.16b}, [x1] /* load final block */ + ld1 {v2.16b}, [x8] + ld1 {v3.16b}, [x9] + + eor v0.16b, v0.16b, v5.16b + decrypt_block v0, w3, x2, x8, w7 + eor v0.16b, v0.16b, v5.16b + + tbl v2.16b, {v0.16b}, v2.16b + tbx v0.16b, {v1.16b}, v3.16b + + st1 {v2.16b}, [x4] /* overlapping stores */ + mov w4, wzr + b .Lxtsdecctsout AES_ENDPROC(aes_xts_decrypt) /* diff --git a/arch/arm64/crypto/aes-neon.S b/arch/arm64/crypto/aes-neon.S index 2bebccc738690069e94aa5aefbe5605adfd07e11..22d9b110cf78b1838ea1ef5c7643a9817e737756 100644 --- a/arch/arm64/crypto/aes-neon.S +++ b/arch/arm64/crypto/aes-neon.S @@ -19,6 +19,11 @@ xts_load_mask \tmp .endm + /* special case for the neon-bs driver calling into this one for CTS */ + .macro xts_cts_skip_tw, reg, lbl + tbnz \reg, #1, \lbl + .endm + /* multiply by polynomial 'x' in GF(2^8) */ .macro mul_by_x, out, in, temp, const sshr \temp, \in, #7 @@ -49,7 +54,7 @@ /* do preload for encryption */ .macro enc_prepare, ignore0, ignore1, temp - prepare .LForward_Sbox, .LForward_ShiftRows, \temp + prepare crypto_aes_sbox, .LForward_ShiftRows, \temp .endm .macro enc_switch_key, ignore0, ignore1, temp @@ -58,7 +63,7 @@ /* do preload for decryption */ .macro dec_prepare, ignore0, ignore1, temp - prepare .LReverse_Sbox, .LReverse_ShiftRows, \temp + prepare crypto_aes_inv_sbox, .LReverse_ShiftRows, \temp .endm /* apply SubBytes transformation using the the preloaded Sbox */ @@ -234,75 +239,7 @@ #include "aes-modes.S" .section ".rodata", "a" - .align 6 -.LForward_Sbox: - .byte 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5 - .byte 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76 - .byte 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0 - .byte 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0 - .byte 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc - .byte 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15 - .byte 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a - .byte 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75 - .byte 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0 - .byte 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84 - .byte 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b - .byte 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf - .byte 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85 - .byte 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8 - .byte 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5 - .byte 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2 - .byte 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17 - .byte 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73 - .byte 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88 - .byte 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb - .byte 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c - .byte 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79 - .byte 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9 - .byte 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08 - .byte 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6 - .byte 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a - .byte 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e - .byte 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e - .byte 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94 - .byte 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf - .byte 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68 - .byte 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 - -.LReverse_Sbox: - .byte 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38 - .byte 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb - .byte 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87 - .byte 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb - .byte 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d - .byte 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e - .byte 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2 - .byte 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 - .byte 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16 - .byte 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 - .byte 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda - .byte 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 - .byte 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a - .byte 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 - .byte 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02 - .byte 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b - .byte 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea - .byte 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 - .byte 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85 - .byte 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e - .byte 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89 - .byte 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b - .byte 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20 - .byte 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 - .byte 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31 - .byte 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f - .byte 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d - .byte 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef - .byte 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0 - .byte 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 - .byte 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26 - .byte 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d - + .align 4 .LForward_ShiftRows: .octa 0x0b06010c07020d08030e09040f0a0500 diff --git a/arch/arm64/crypto/aes-neonbs-core.S b/arch/arm64/crypto/aes-neonbs-core.S index cf10ff8878a3d9387b8e9ac2f4e4740f1603c391..65982039fa3653faf9d9dc369c8b163b5ae95cc1 100644 --- a/arch/arm64/crypto/aes-neonbs-core.S +++ b/arch/arm64/crypto/aes-neonbs-core.S @@ -730,11 +730,6 @@ ENDPROC(aesbs_cbc_decrypt) eor \out\().16b, \out\().16b, \tmp\().16b .endm - .align 4 -.Lxts_mul_x: -CPU_LE( .quad 1, 0x87 ) -CPU_BE( .quad 0x87, 1 ) - /* * aesbs_xts_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, * int blocks, u8 iv[]) @@ -806,7 +801,9 @@ ENDPROC(__xts_crypt8) mov x23, x4 mov x24, x5 -0: ldr q30, .Lxts_mul_x +0: movi v30.2s, #0x1 + movi v25.2s, #0x87 + uzp1 v30.4s, v30.4s, v25.4s ld1 {v25.16b}, [x24] 99: adr x7, \do8 diff --git a/arch/arm64/crypto/aes-neonbs-glue.c b/arch/arm64/crypto/aes-neonbs-glue.c index 281d230876972b4f592f99af23529a88181f7020..ea873b8904c49c6bc5e2a11795494e947cd2b5cf 100644 --- a/arch/arm64/crypto/aes-neonbs-glue.c +++ b/arch/arm64/crypto/aes-neonbs-glue.c @@ -8,13 +8,13 @@ #include #include #include +#include #include #include +#include #include #include -#include "aes-ctr-fallback.h" - MODULE_AUTHOR("Ard Biesheuvel "); MODULE_LICENSE("GPL v2"); @@ -46,6 +46,12 @@ asmlinkage void neon_aes_ecb_encrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, int blocks); asmlinkage void neon_aes_cbc_encrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, int blocks, u8 iv[]); +asmlinkage void neon_aes_xts_encrypt(u8 out[], u8 const in[], + u32 const rk1[], int rounds, int bytes, + u32 const rk2[], u8 iv[], int first); +asmlinkage void neon_aes_xts_decrypt(u8 out[], u8 const in[], + u32 const rk1[], int rounds, int bytes, + u32 const rk2[], u8 iv[], int first); struct aesbs_ctx { u8 rk[13 * (8 * AES_BLOCK_SIZE) + 32]; @@ -65,6 +71,7 @@ struct aesbs_ctr_ctx { struct aesbs_xts_ctx { struct aesbs_ctx key; u32 twkey[AES_MAX_KEYLENGTH_U32]; + struct crypto_aes_ctx cts; }; static int aesbs_setkey(struct crypto_skcipher *tfm, const u8 *in_key, @@ -74,7 +81,7 @@ static int aesbs_setkey(struct crypto_skcipher *tfm, const u8 *in_key, struct crypto_aes_ctx rk; int err; - err = crypto_aes_expand_key(&rk, in_key, key_len); + err = aes_expandkey(&rk, in_key, key_len); if (err) return err; @@ -133,7 +140,7 @@ static int aesbs_cbc_setkey(struct crypto_skcipher *tfm, const u8 *in_key, struct crypto_aes_ctx rk; int err; - err = crypto_aes_expand_key(&rk, in_key, key_len); + err = aes_expandkey(&rk, in_key, key_len); if (err) return err; @@ -205,7 +212,7 @@ static int aesbs_ctr_setkey_sync(struct crypto_skcipher *tfm, const u8 *in_key, struct aesbs_ctr_ctx *ctx = crypto_skcipher_ctx(tfm); int err; - err = crypto_aes_expand_key(&ctx->fallback, in_key, key_len); + err = aes_expandkey(&ctx->fallback, in_key, key_len); if (err) return err; @@ -271,7 +278,11 @@ static int aesbs_xts_setkey(struct crypto_skcipher *tfm, const u8 *in_key, return err; key_len /= 2; - err = crypto_aes_expand_key(&rk, in_key + key_len, key_len); + err = aes_expandkey(&ctx->cts, in_key, key_len); + if (err) + return err; + + err = aes_expandkey(&rk, in_key + key_len, key_len); if (err) return err; @@ -280,59 +291,142 @@ static int aesbs_xts_setkey(struct crypto_skcipher *tfm, const u8 *in_key, return aesbs_setkey(tfm, in_key, key_len); } -static int ctr_encrypt_sync(struct skcipher_request *req) +static void ctr_encrypt_one(struct crypto_skcipher *tfm, const u8 *src, u8 *dst) { - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct aesbs_ctr_ctx *ctx = crypto_skcipher_ctx(tfm); + unsigned long flags; + + /* + * Temporarily disable interrupts to avoid races where + * cachelines are evicted when the CPU is interrupted + * to do something else. + */ + local_irq_save(flags); + aes_encrypt(&ctx->fallback, dst, src); + local_irq_restore(flags); +} +static int ctr_encrypt_sync(struct skcipher_request *req) +{ if (!crypto_simd_usable()) - return aes_ctr_encrypt_fallback(&ctx->fallback, req); + return crypto_ctr_encrypt_walk(req, ctr_encrypt_one); return ctr_encrypt(req); } -static int __xts_crypt(struct skcipher_request *req, +static int __xts_crypt(struct skcipher_request *req, bool encrypt, void (*fn)(u8 out[], u8 const in[], u8 const rk[], int rounds, int blocks, u8 iv[])) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct aesbs_xts_ctx *ctx = crypto_skcipher_ctx(tfm); + int tail = req->cryptlen % (8 * AES_BLOCK_SIZE); + struct scatterlist sg_src[2], sg_dst[2]; + struct skcipher_request subreq; + struct scatterlist *src, *dst; struct skcipher_walk walk; - int err; + int nbytes, err; + int first = 1; + u8 *out, *in; + + if (req->cryptlen < AES_BLOCK_SIZE) + return -EINVAL; + + /* ensure that the cts tail is covered by a single step */ + if (unlikely(tail > 0 && tail < AES_BLOCK_SIZE)) { + int xts_blocks = DIV_ROUND_UP(req->cryptlen, + AES_BLOCK_SIZE) - 2; + + skcipher_request_set_tfm(&subreq, tfm); + skcipher_request_set_callback(&subreq, + skcipher_request_flags(req), + NULL, NULL); + skcipher_request_set_crypt(&subreq, req->src, req->dst, + xts_blocks * AES_BLOCK_SIZE, + req->iv); + req = &subreq; + } else { + tail = 0; + } err = skcipher_walk_virt(&walk, req, false); if (err) return err; - kernel_neon_begin(); - neon_aes_ecb_encrypt(walk.iv, walk.iv, ctx->twkey, ctx->key.rounds, 1); - kernel_neon_end(); - while (walk.nbytes >= AES_BLOCK_SIZE) { unsigned int blocks = walk.nbytes / AES_BLOCK_SIZE; - if (walk.nbytes < walk.total) + if (walk.nbytes < walk.total || walk.nbytes % AES_BLOCK_SIZE) blocks = round_down(blocks, walk.stride / AES_BLOCK_SIZE); + out = walk.dst.virt.addr; + in = walk.src.virt.addr; + nbytes = walk.nbytes; + kernel_neon_begin(); - fn(walk.dst.virt.addr, walk.src.virt.addr, ctx->key.rk, - ctx->key.rounds, blocks, walk.iv); + if (likely(blocks > 6)) { /* plain NEON is faster otherwise */ + if (first) + neon_aes_ecb_encrypt(walk.iv, walk.iv, + ctx->twkey, + ctx->key.rounds, 1); + first = 0; + + fn(out, in, ctx->key.rk, ctx->key.rounds, blocks, + walk.iv); + + out += blocks * AES_BLOCK_SIZE; + in += blocks * AES_BLOCK_SIZE; + nbytes -= blocks * AES_BLOCK_SIZE; + } + + if (walk.nbytes == walk.total && nbytes > 0) + goto xts_tail; + kernel_neon_end(); - err = skcipher_walk_done(&walk, - walk.nbytes - blocks * AES_BLOCK_SIZE); + skcipher_walk_done(&walk, nbytes); } - return err; + + if (err || likely(!tail)) + return err; + + /* handle ciphertext stealing */ + dst = src = scatterwalk_ffwd(sg_src, req->src, req->cryptlen); + if (req->dst != req->src) + dst = scatterwalk_ffwd(sg_dst, req->dst, req->cryptlen); + + skcipher_request_set_crypt(req, src, dst, AES_BLOCK_SIZE + tail, + req->iv); + + err = skcipher_walk_virt(&walk, req, false); + if (err) + return err; + + out = walk.dst.virt.addr; + in = walk.src.virt.addr; + nbytes = walk.nbytes; + + kernel_neon_begin(); +xts_tail: + if (encrypt) + neon_aes_xts_encrypt(out, in, ctx->cts.key_enc, ctx->key.rounds, + nbytes, ctx->twkey, walk.iv, first ?: 2); + else + neon_aes_xts_decrypt(out, in, ctx->cts.key_dec, ctx->key.rounds, + nbytes, ctx->twkey, walk.iv, first ?: 2); + kernel_neon_end(); + + return skcipher_walk_done(&walk, 0); } static int xts_encrypt(struct skcipher_request *req) { - return __xts_crypt(req, aesbs_xts_encrypt); + return __xts_crypt(req, true, aesbs_xts_encrypt); } static int xts_decrypt(struct skcipher_request *req) { - return __xts_crypt(req, aesbs_xts_decrypt); + return __xts_crypt(req, false, aesbs_xts_decrypt); } static struct skcipher_alg aes_algs[] = { { diff --git a/arch/arm64/crypto/ghash-ce-glue.c b/arch/arm64/crypto/ghash-ce-glue.c index 16c5da9be9fb436912cec1a4a1fed669938261a6..70b1469783f9bd376465369d1df328f193efc642 100644 --- a/arch/arm64/crypto/ghash-ce-glue.c +++ b/arch/arm64/crypto/ghash-ce-glue.c @@ -70,8 +70,6 @@ asmlinkage void pmull_gcm_decrypt(int blocks, u64 dg[], u8 dst[], asmlinkage void pmull_gcm_encrypt_block(u8 dst[], u8 const src[], u32 const rk[], int rounds); -asmlinkage void __aes_arm64_encrypt(u32 *rk, u8 *out, const u8 *in, int rounds); - static int ghash_init(struct shash_desc *desc) { struct ghash_desc_ctx *ctx = shash_desc_ctx(desc); @@ -309,14 +307,13 @@ static int gcm_setkey(struct crypto_aead *tfm, const u8 *inkey, u8 key[GHASH_BLOCK_SIZE]; int ret; - ret = crypto_aes_expand_key(&ctx->aes_key, inkey, keylen); + ret = aes_expandkey(&ctx->aes_key, inkey, keylen); if (ret) { tfm->base.crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; return -EINVAL; } - __aes_arm64_encrypt(ctx->aes_key.key_enc, key, (u8[AES_BLOCK_SIZE]){}, - num_rounds(&ctx->aes_key)); + aes_encrypt(&ctx->aes_key, key, (u8[AES_BLOCK_SIZE]){}); return __ghash_setkey(&ctx->ghash_key, key, sizeof(be128)); } @@ -467,7 +464,7 @@ static int gcm_encrypt(struct aead_request *req) rk = ctx->aes_key.key_enc; } while (walk.nbytes >= 2 * AES_BLOCK_SIZE); } else { - __aes_arm64_encrypt(ctx->aes_key.key_enc, tag, iv, nrounds); + aes_encrypt(&ctx->aes_key, tag, iv); put_unaligned_be32(2, iv + GCM_IV_SIZE); while (walk.nbytes >= (2 * AES_BLOCK_SIZE)) { @@ -478,8 +475,7 @@ static int gcm_encrypt(struct aead_request *req) int remaining = blocks; do { - __aes_arm64_encrypt(ctx->aes_key.key_enc, - ks, iv, nrounds); + aes_encrypt(&ctx->aes_key, ks, iv); crypto_xor_cpy(dst, src, ks, AES_BLOCK_SIZE); crypto_inc(iv, AES_BLOCK_SIZE); @@ -495,13 +491,10 @@ static int gcm_encrypt(struct aead_request *req) walk.nbytes % (2 * AES_BLOCK_SIZE)); } if (walk.nbytes) { - __aes_arm64_encrypt(ctx->aes_key.key_enc, ks, iv, - nrounds); + aes_encrypt(&ctx->aes_key, ks, iv); if (walk.nbytes > AES_BLOCK_SIZE) { crypto_inc(iv, AES_BLOCK_SIZE); - __aes_arm64_encrypt(ctx->aes_key.key_enc, - ks + AES_BLOCK_SIZE, iv, - nrounds); + aes_encrypt(&ctx->aes_key, ks + AES_BLOCK_SIZE, iv); } } } @@ -605,7 +598,7 @@ static int gcm_decrypt(struct aead_request *req) rk = ctx->aes_key.key_enc; } while (walk.nbytes >= 2 * AES_BLOCK_SIZE); } else { - __aes_arm64_encrypt(ctx->aes_key.key_enc, tag, iv, nrounds); + aes_encrypt(&ctx->aes_key, tag, iv); put_unaligned_be32(2, iv + GCM_IV_SIZE); while (walk.nbytes >= (2 * AES_BLOCK_SIZE)) { @@ -618,8 +611,7 @@ static int gcm_decrypt(struct aead_request *req) pmull_ghash_update_p64); do { - __aes_arm64_encrypt(ctx->aes_key.key_enc, - buf, iv, nrounds); + aes_encrypt(&ctx->aes_key, buf, iv); crypto_xor_cpy(dst, src, buf, AES_BLOCK_SIZE); crypto_inc(iv, AES_BLOCK_SIZE); @@ -637,11 +629,9 @@ static int gcm_decrypt(struct aead_request *req) memcpy(iv2, iv, AES_BLOCK_SIZE); crypto_inc(iv2, AES_BLOCK_SIZE); - __aes_arm64_encrypt(ctx->aes_key.key_enc, iv2, - iv2, nrounds); + aes_encrypt(&ctx->aes_key, iv2, iv2); } - __aes_arm64_encrypt(ctx->aes_key.key_enc, iv, iv, - nrounds); + aes_encrypt(&ctx->aes_key, iv, iv); } } diff --git a/arch/arm64/crypto/sha256-glue.c b/arch/arm64/crypto/sha256-glue.c index 04b9d17b07331c33c7b1393191c2a498677ba9d0..e273faca924f9a9344e1ed14c3c23932df4133a1 100644 --- a/arch/arm64/crypto/sha256-glue.c +++ b/arch/arm64/crypto/sha256-glue.c @@ -30,15 +30,15 @@ EXPORT_SYMBOL(sha256_block_data_order); asmlinkage void sha256_block_neon(u32 *digest, const void *data, unsigned int num_blks); -static int sha256_update(struct shash_desc *desc, const u8 *data, - unsigned int len) +static int crypto_sha256_arm64_update(struct shash_desc *desc, const u8 *data, + unsigned int len) { return sha256_base_do_update(desc, data, len, (sha256_block_fn *)sha256_block_data_order); } -static int sha256_finup(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *out) +static int crypto_sha256_arm64_finup(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) { if (len) sha256_base_do_update(desc, data, len, @@ -49,17 +49,17 @@ static int sha256_finup(struct shash_desc *desc, const u8 *data, return sha256_base_finish(desc, out); } -static int sha256_final(struct shash_desc *desc, u8 *out) +static int crypto_sha256_arm64_final(struct shash_desc *desc, u8 *out) { - return sha256_finup(desc, NULL, 0, out); + return crypto_sha256_arm64_finup(desc, NULL, 0, out); } static struct shash_alg algs[] = { { .digestsize = SHA256_DIGEST_SIZE, .init = sha256_base_init, - .update = sha256_update, - .final = sha256_final, - .finup = sha256_finup, + .update = crypto_sha256_arm64_update, + .final = crypto_sha256_arm64_final, + .finup = crypto_sha256_arm64_finup, .descsize = sizeof(struct sha256_state), .base.cra_name = "sha256", .base.cra_driver_name = "sha256-arm64", @@ -69,9 +69,9 @@ static struct shash_alg algs[] = { { }, { .digestsize = SHA224_DIGEST_SIZE, .init = sha224_base_init, - .update = sha256_update, - .final = sha256_final, - .finup = sha256_finup, + .update = crypto_sha256_arm64_update, + .final = crypto_sha256_arm64_final, + .finup = crypto_sha256_arm64_finup, .descsize = sizeof(struct sha256_state), .base.cra_name = "sha224", .base.cra_driver_name = "sha224-arm64", diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index e3a15c751b1398e911c19c3a879e9d1e766410f4..b8cf7c85ffa2a2e7c5cacd15910185d44fe751a8 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -123,17 +123,6 @@ alternative_else alternative_endif .endm -/* - * Sanitise a 64-bit bounded index wrt speculation, returning zero if out - * of bounds. - */ - .macro mask_nospec64, idx, limit, tmp - sub \tmp, \idx, \limit - bic \tmp, \tmp, \idx - and \idx, \idx, \tmp, asr #63 - csdb - .endm - /* * NOP sequence */ @@ -349,6 +338,13 @@ alternative_endif bfi \valreg, \t0sz, #TCR_T0SZ_OFFSET, #TCR_TxSZ_WIDTH .endm +/* + * tcr_set_t1sz - update TCR.T1SZ + */ + .macro tcr_set_t1sz, valreg, t1sz + bfi \valreg, \t1sz, #TCR_T1SZ_OFFSET, #TCR_TxSZ_WIDTH + .endm + /* * tcr_compute_pa_size - set TCR.(I)PS to the highest supported * ID_AA64MMFR0_EL1.PARange value @@ -538,9 +534,13 @@ USER(\label, ic ivau, \tmp2) // invalidate I line PoU * In future this may be nop'ed out when dealing with 52-bit kernel VAs. * ttbr: Value of ttbr to set, modified. */ - .macro offset_ttbr1, ttbr -#ifdef CONFIG_ARM64_USER_VA_BITS_52 + .macro offset_ttbr1, ttbr, tmp +#ifdef CONFIG_ARM64_VA_BITS_52 + mrs_s \tmp, SYS_ID_AA64MMFR2_EL1 + and \tmp, \tmp, #(0xf << ID_AA64MMFR2_LVA_SHIFT) + cbnz \tmp, .Lskipoffs_\@ orr \ttbr, \ttbr, #TTBR1_BADDR_4852_OFFSET +.Lskipoffs_\@ : #endif .endm @@ -550,7 +550,7 @@ USER(\label, ic ivau, \tmp2) // invalidate I line PoU * to be nop'ed out when dealing with 52-bit kernel VAs. */ .macro restore_ttbr1, ttbr -#ifdef CONFIG_ARM64_USER_VA_BITS_52 +#ifdef CONFIG_ARM64_VA_BITS_52 bic \ttbr, \ttbr, #TTBR1_BADDR_4852_OFFSET #endif .endm diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 657b0457d83cf1ebd5cdf92bc5d66adee25fe4a5..9543b5e0534d216f52d517de1c200d20762fc414 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -13,21 +13,91 @@ #include #include +#include #include -#ifdef __KERNEL__ - -#define __ARM64_IN_ATOMIC_IMPL - -#if defined(CONFIG_ARM64_LSE_ATOMICS) && defined(CONFIG_AS_LSE) -#include -#else -#include -#endif - -#undef __ARM64_IN_ATOMIC_IMPL - -#include +#define ATOMIC_OP(op) \ +static inline void arch_##op(int i, atomic_t *v) \ +{ \ + __lse_ll_sc_body(op, i, v); \ +} + +ATOMIC_OP(atomic_andnot) +ATOMIC_OP(atomic_or) +ATOMIC_OP(atomic_xor) +ATOMIC_OP(atomic_add) +ATOMIC_OP(atomic_and) +ATOMIC_OP(atomic_sub) + +#undef ATOMIC_OP + +#define ATOMIC_FETCH_OP(name, op) \ +static inline int arch_##op##name(int i, atomic_t *v) \ +{ \ + return __lse_ll_sc_body(op##name, i, v); \ +} + +#define ATOMIC_FETCH_OPS(op) \ + ATOMIC_FETCH_OP(_relaxed, op) \ + ATOMIC_FETCH_OP(_acquire, op) \ + ATOMIC_FETCH_OP(_release, op) \ + ATOMIC_FETCH_OP( , op) + +ATOMIC_FETCH_OPS(atomic_fetch_andnot) +ATOMIC_FETCH_OPS(atomic_fetch_or) +ATOMIC_FETCH_OPS(atomic_fetch_xor) +ATOMIC_FETCH_OPS(atomic_fetch_add) +ATOMIC_FETCH_OPS(atomic_fetch_and) +ATOMIC_FETCH_OPS(atomic_fetch_sub) +ATOMIC_FETCH_OPS(atomic_add_return) +ATOMIC_FETCH_OPS(atomic_sub_return) + +#undef ATOMIC_FETCH_OP +#undef ATOMIC_FETCH_OPS + +#define ATOMIC64_OP(op) \ +static inline void arch_##op(long i, atomic64_t *v) \ +{ \ + __lse_ll_sc_body(op, i, v); \ +} + +ATOMIC64_OP(atomic64_andnot) +ATOMIC64_OP(atomic64_or) +ATOMIC64_OP(atomic64_xor) +ATOMIC64_OP(atomic64_add) +ATOMIC64_OP(atomic64_and) +ATOMIC64_OP(atomic64_sub) + +#undef ATOMIC64_OP + +#define ATOMIC64_FETCH_OP(name, op) \ +static inline long arch_##op##name(long i, atomic64_t *v) \ +{ \ + return __lse_ll_sc_body(op##name, i, v); \ +} + +#define ATOMIC64_FETCH_OPS(op) \ + ATOMIC64_FETCH_OP(_relaxed, op) \ + ATOMIC64_FETCH_OP(_acquire, op) \ + ATOMIC64_FETCH_OP(_release, op) \ + ATOMIC64_FETCH_OP( , op) + +ATOMIC64_FETCH_OPS(atomic64_fetch_andnot) +ATOMIC64_FETCH_OPS(atomic64_fetch_or) +ATOMIC64_FETCH_OPS(atomic64_fetch_xor) +ATOMIC64_FETCH_OPS(atomic64_fetch_add) +ATOMIC64_FETCH_OPS(atomic64_fetch_and) +ATOMIC64_FETCH_OPS(atomic64_fetch_sub) +ATOMIC64_FETCH_OPS(atomic64_add_return) +ATOMIC64_FETCH_OPS(atomic64_sub_return) + +#undef ATOMIC64_FETCH_OP +#undef ATOMIC64_FETCH_OPS + +static inline long arch_atomic64_dec_if_positive(atomic64_t *v) +{ + return __lse_ll_sc_body(atomic64_dec_if_positive, v); +} #define ATOMIC_INIT(i) { (i) } @@ -157,5 +227,4 @@ #include -#endif -#endif +#endif /* __ASM_ATOMIC_H */ diff --git a/arch/arm64/include/asm/atomic_ll_sc.h b/arch/arm64/include/asm/atomic_ll_sc.h index c8c850bc3dfb0cd8c6aad369e161cd18aa2f02c8..7b012148bfd6c1ccbd6f47a437ca1323d92428ed 100644 --- a/arch/arm64/include/asm/atomic_ll_sc.h +++ b/arch/arm64/include/asm/atomic_ll_sc.h @@ -10,83 +10,92 @@ #ifndef __ASM_ATOMIC_LL_SC_H #define __ASM_ATOMIC_LL_SC_H -#ifndef __ARM64_IN_ATOMIC_IMPL -#error "please don't include this file directly" +#include + +#if IS_ENABLED(CONFIG_ARM64_LSE_ATOMICS) && IS_ENABLED(CONFIG_AS_LSE) +#define __LL_SC_FALLBACK(asm_ops) \ +" b 3f\n" \ +" .subsection 1\n" \ +"3:\n" \ +asm_ops "\n" \ +" b 4f\n" \ +" .previous\n" \ +"4:\n" +#else +#define __LL_SC_FALLBACK(asm_ops) asm_ops +#endif + +#ifndef CONFIG_CC_HAS_K_CONSTRAINT +#define K #endif /* * AArch64 UP and SMP safe atomic ops. We use load exclusive and * store exclusive to ensure that these are atomic. We may loop * to ensure that the update happens. - * - * NOTE: these functions do *not* follow the PCS and must explicitly - * save any clobbered registers other than x0 (regardless of return - * value). This is achieved through -fcall-saved-* compiler flags for - * this file, which unfortunately don't work on a per-function basis - * (the optimize attribute silently ignores these options). */ -#define ATOMIC_OP(op, asm_op) \ -__LL_SC_INLINE void \ -__LL_SC_PREFIX(arch_atomic_##op(int i, atomic_t *v)) \ +#define ATOMIC_OP(op, asm_op, constraint) \ +static inline void \ +__ll_sc_atomic_##op(int i, atomic_t *v) \ { \ unsigned long tmp; \ int result; \ \ asm volatile("// atomic_" #op "\n" \ + __LL_SC_FALLBACK( \ " prfm pstl1strm, %2\n" \ "1: ldxr %w0, %2\n" \ " " #asm_op " %w0, %w0, %w3\n" \ " stxr %w1, %w0, %2\n" \ -" cbnz %w1, 1b" \ +" cbnz %w1, 1b\n") \ : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ - : "Ir" (i)); \ -} \ -__LL_SC_EXPORT(arch_atomic_##op); + : __stringify(constraint) "r" (i)); \ +} -#define ATOMIC_OP_RETURN(name, mb, acq, rel, cl, op, asm_op) \ -__LL_SC_INLINE int \ -__LL_SC_PREFIX(arch_atomic_##op##_return##name(int i, atomic_t *v)) \ +#define ATOMIC_OP_RETURN(name, mb, acq, rel, cl, op, asm_op, constraint)\ +static inline int \ +__ll_sc_atomic_##op##_return##name(int i, atomic_t *v) \ { \ unsigned long tmp; \ int result; \ \ asm volatile("// atomic_" #op "_return" #name "\n" \ + __LL_SC_FALLBACK( \ " prfm pstl1strm, %2\n" \ "1: ld" #acq "xr %w0, %2\n" \ " " #asm_op " %w0, %w0, %w3\n" \ " st" #rel "xr %w1, %w0, %2\n" \ " cbnz %w1, 1b\n" \ -" " #mb \ +" " #mb ) \ : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ - : "Ir" (i) \ + : __stringify(constraint) "r" (i) \ : cl); \ \ return result; \ -} \ -__LL_SC_EXPORT(arch_atomic_##op##_return##name); +} -#define ATOMIC_FETCH_OP(name, mb, acq, rel, cl, op, asm_op) \ -__LL_SC_INLINE int \ -__LL_SC_PREFIX(arch_atomic_fetch_##op##name(int i, atomic_t *v)) \ +#define ATOMIC_FETCH_OP(name, mb, acq, rel, cl, op, asm_op, constraint) \ +static inline int \ +__ll_sc_atomic_fetch_##op##name(int i, atomic_t *v) \ { \ unsigned long tmp; \ int val, result; \ \ asm volatile("// atomic_fetch_" #op #name "\n" \ + __LL_SC_FALLBACK( \ " prfm pstl1strm, %3\n" \ "1: ld" #acq "xr %w0, %3\n" \ " " #asm_op " %w1, %w0, %w4\n" \ " st" #rel "xr %w2, %w1, %3\n" \ " cbnz %w2, 1b\n" \ -" " #mb \ +" " #mb ) \ : "=&r" (result), "=&r" (val), "=&r" (tmp), "+Q" (v->counter) \ - : "Ir" (i) \ + : __stringify(constraint) "r" (i) \ : cl); \ \ return result; \ -} \ -__LL_SC_EXPORT(arch_atomic_fetch_##op##name); +} #define ATOMIC_OPS(...) \ ATOMIC_OP(__VA_ARGS__) \ @@ -99,8 +108,8 @@ __LL_SC_EXPORT(arch_atomic_fetch_##op##name); ATOMIC_FETCH_OP (_acquire, , a, , "memory", __VA_ARGS__)\ ATOMIC_FETCH_OP (_release, , , l, "memory", __VA_ARGS__) -ATOMIC_OPS(add, add) -ATOMIC_OPS(sub, sub) +ATOMIC_OPS(add, add, I) +ATOMIC_OPS(sub, sub, J) #undef ATOMIC_OPS #define ATOMIC_OPS(...) \ @@ -110,77 +119,82 @@ ATOMIC_OPS(sub, sub) ATOMIC_FETCH_OP (_acquire, , a, , "memory", __VA_ARGS__)\ ATOMIC_FETCH_OP (_release, , , l, "memory", __VA_ARGS__) -ATOMIC_OPS(and, and) -ATOMIC_OPS(andnot, bic) -ATOMIC_OPS(or, orr) -ATOMIC_OPS(xor, eor) +ATOMIC_OPS(and, and, K) +ATOMIC_OPS(or, orr, K) +ATOMIC_OPS(xor, eor, K) +/* + * GAS converts the mysterious and undocumented BIC (immediate) alias to + * an AND (immediate) instruction with the immediate inverted. We don't + * have a constraint for this, so fall back to register. + */ +ATOMIC_OPS(andnot, bic, ) #undef ATOMIC_OPS #undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -#define ATOMIC64_OP(op, asm_op) \ -__LL_SC_INLINE void \ -__LL_SC_PREFIX(arch_atomic64_##op(s64 i, atomic64_t *v)) \ +#define ATOMIC64_OP(op, asm_op, constraint) \ +static inline void \ +__ll_sc_atomic64_##op(s64 i, atomic64_t *v) \ { \ s64 result; \ unsigned long tmp; \ \ asm volatile("// atomic64_" #op "\n" \ + __LL_SC_FALLBACK( \ " prfm pstl1strm, %2\n" \ "1: ldxr %0, %2\n" \ " " #asm_op " %0, %0, %3\n" \ " stxr %w1, %0, %2\n" \ -" cbnz %w1, 1b" \ +" cbnz %w1, 1b") \ : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ - : "Ir" (i)); \ -} \ -__LL_SC_EXPORT(arch_atomic64_##op); + : __stringify(constraint) "r" (i)); \ +} -#define ATOMIC64_OP_RETURN(name, mb, acq, rel, cl, op, asm_op) \ -__LL_SC_INLINE s64 \ -__LL_SC_PREFIX(arch_atomic64_##op##_return##name(s64 i, atomic64_t *v))\ +#define ATOMIC64_OP_RETURN(name, mb, acq, rel, cl, op, asm_op, constraint)\ +static inline long \ +__ll_sc_atomic64_##op##_return##name(s64 i, atomic64_t *v) \ { \ s64 result; \ unsigned long tmp; \ \ asm volatile("// atomic64_" #op "_return" #name "\n" \ + __LL_SC_FALLBACK( \ " prfm pstl1strm, %2\n" \ "1: ld" #acq "xr %0, %2\n" \ " " #asm_op " %0, %0, %3\n" \ " st" #rel "xr %w1, %0, %2\n" \ " cbnz %w1, 1b\n" \ -" " #mb \ +" " #mb ) \ : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ - : "Ir" (i) \ + : __stringify(constraint) "r" (i) \ : cl); \ \ return result; \ -} \ -__LL_SC_EXPORT(arch_atomic64_##op##_return##name); +} -#define ATOMIC64_FETCH_OP(name, mb, acq, rel, cl, op, asm_op) \ -__LL_SC_INLINE s64 \ -__LL_SC_PREFIX(arch_atomic64_fetch_##op##name(s64 i, atomic64_t *v)) \ +#define ATOMIC64_FETCH_OP(name, mb, acq, rel, cl, op, asm_op, constraint)\ +static inline long \ +__ll_sc_atomic64_fetch_##op##name(s64 i, atomic64_t *v) \ { \ s64 result, val; \ unsigned long tmp; \ \ asm volatile("// atomic64_fetch_" #op #name "\n" \ + __LL_SC_FALLBACK( \ " prfm pstl1strm, %3\n" \ "1: ld" #acq "xr %0, %3\n" \ " " #asm_op " %1, %0, %4\n" \ " st" #rel "xr %w2, %1, %3\n" \ " cbnz %w2, 1b\n" \ -" " #mb \ +" " #mb ) \ : "=&r" (result), "=&r" (val), "=&r" (tmp), "+Q" (v->counter) \ - : "Ir" (i) \ + : __stringify(constraint) "r" (i) \ : cl); \ \ return result; \ -} \ -__LL_SC_EXPORT(arch_atomic64_fetch_##op##name); +} #define ATOMIC64_OPS(...) \ ATOMIC64_OP(__VA_ARGS__) \ @@ -193,8 +207,8 @@ __LL_SC_EXPORT(arch_atomic64_fetch_##op##name); ATOMIC64_FETCH_OP (_acquire,, a, , "memory", __VA_ARGS__) \ ATOMIC64_FETCH_OP (_release,, , l, "memory", __VA_ARGS__) -ATOMIC64_OPS(add, add) -ATOMIC64_OPS(sub, sub) +ATOMIC64_OPS(add, add, I) +ATOMIC64_OPS(sub, sub, J) #undef ATOMIC64_OPS #define ATOMIC64_OPS(...) \ @@ -204,23 +218,29 @@ ATOMIC64_OPS(sub, sub) ATOMIC64_FETCH_OP (_acquire,, a, , "memory", __VA_ARGS__) \ ATOMIC64_FETCH_OP (_release,, , l, "memory", __VA_ARGS__) -ATOMIC64_OPS(and, and) -ATOMIC64_OPS(andnot, bic) -ATOMIC64_OPS(or, orr) -ATOMIC64_OPS(xor, eor) +ATOMIC64_OPS(and, and, L) +ATOMIC64_OPS(or, orr, L) +ATOMIC64_OPS(xor, eor, L) +/* + * GAS converts the mysterious and undocumented BIC (immediate) alias to + * an AND (immediate) instruction with the immediate inverted. We don't + * have a constraint for this, so fall back to register. + */ +ATOMIC64_OPS(andnot, bic, ) #undef ATOMIC64_OPS #undef ATOMIC64_FETCH_OP #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP -__LL_SC_INLINE s64 -__LL_SC_PREFIX(arch_atomic64_dec_if_positive(atomic64_t *v)) +static inline s64 +__ll_sc_atomic64_dec_if_positive(atomic64_t *v) { s64 result; unsigned long tmp; asm volatile("// atomic64_dec_if_positive\n" + __LL_SC_FALLBACK( " prfm pstl1strm, %2\n" "1: ldxr %0, %2\n" " subs %0, %0, #1\n" @@ -228,20 +248,19 @@ __LL_SC_PREFIX(arch_atomic64_dec_if_positive(atomic64_t *v)) " stlxr %w1, %0, %2\n" " cbnz %w1, 1b\n" " dmb ish\n" -"2:" +"2:") : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) : : "cc", "memory"); return result; } -__LL_SC_EXPORT(arch_atomic64_dec_if_positive); -#define __CMPXCHG_CASE(w, sfx, name, sz, mb, acq, rel, cl) \ -__LL_SC_INLINE u##sz \ -__LL_SC_PREFIX(__cmpxchg_case_##name##sz(volatile void *ptr, \ +#define __CMPXCHG_CASE(w, sfx, name, sz, mb, acq, rel, cl, constraint) \ +static inline u##sz \ +__ll_sc__cmpxchg_case_##name##sz(volatile void *ptr, \ unsigned long old, \ - u##sz new)) \ + u##sz new) \ { \ unsigned long tmp; \ u##sz oldval; \ @@ -255,6 +274,7 @@ __LL_SC_PREFIX(__cmpxchg_case_##name##sz(volatile void *ptr, \ old = (u##sz)old; \ \ asm volatile( \ + __LL_SC_FALLBACK( \ " prfm pstl1strm, %[v]\n" \ "1: ld" #acq "xr" #sfx "\t%" #w "[oldval], %[v]\n" \ " eor %" #w "[tmp], %" #w "[oldval], %" #w "[old]\n" \ @@ -262,46 +282,51 @@ __LL_SC_PREFIX(__cmpxchg_case_##name##sz(volatile void *ptr, \ " st" #rel "xr" #sfx "\t%w[tmp], %" #w "[new], %[v]\n" \ " cbnz %w[tmp], 1b\n" \ " " #mb "\n" \ - "2:" \ + "2:") \ : [tmp] "=&r" (tmp), [oldval] "=&r" (oldval), \ [v] "+Q" (*(u##sz *)ptr) \ - : [old] "Kr" (old), [new] "r" (new) \ + : [old] __stringify(constraint) "r" (old), [new] "r" (new) \ : cl); \ \ return oldval; \ -} \ -__LL_SC_EXPORT(__cmpxchg_case_##name##sz); +} -__CMPXCHG_CASE(w, b, , 8, , , , ) -__CMPXCHG_CASE(w, h, , 16, , , , ) -__CMPXCHG_CASE(w, , , 32, , , , ) -__CMPXCHG_CASE( , , , 64, , , , ) -__CMPXCHG_CASE(w, b, acq_, 8, , a, , "memory") -__CMPXCHG_CASE(w, h, acq_, 16, , a, , "memory") -__CMPXCHG_CASE(w, , acq_, 32, , a, , "memory") -__CMPXCHG_CASE( , , acq_, 64, , a, , "memory") -__CMPXCHG_CASE(w, b, rel_, 8, , , l, "memory") -__CMPXCHG_CASE(w, h, rel_, 16, , , l, "memory") -__CMPXCHG_CASE(w, , rel_, 32, , , l, "memory") -__CMPXCHG_CASE( , , rel_, 64, , , l, "memory") -__CMPXCHG_CASE(w, b, mb_, 8, dmb ish, , l, "memory") -__CMPXCHG_CASE(w, h, mb_, 16, dmb ish, , l, "memory") -__CMPXCHG_CASE(w, , mb_, 32, dmb ish, , l, "memory") -__CMPXCHG_CASE( , , mb_, 64, dmb ish, , l, "memory") +/* + * Earlier versions of GCC (no later than 8.1.0) appear to incorrectly + * handle the 'K' constraint for the value 4294967295 - thus we use no + * constraint for 32 bit operations. + */ +__CMPXCHG_CASE(w, b, , 8, , , , , K) +__CMPXCHG_CASE(w, h, , 16, , , , , K) +__CMPXCHG_CASE(w, , , 32, , , , , K) +__CMPXCHG_CASE( , , , 64, , , , , L) +__CMPXCHG_CASE(w, b, acq_, 8, , a, , "memory", K) +__CMPXCHG_CASE(w, h, acq_, 16, , a, , "memory", K) +__CMPXCHG_CASE(w, , acq_, 32, , a, , "memory", K) +__CMPXCHG_CASE( , , acq_, 64, , a, , "memory", L) +__CMPXCHG_CASE(w, b, rel_, 8, , , l, "memory", K) +__CMPXCHG_CASE(w, h, rel_, 16, , , l, "memory", K) +__CMPXCHG_CASE(w, , rel_, 32, , , l, "memory", K) +__CMPXCHG_CASE( , , rel_, 64, , , l, "memory", L) +__CMPXCHG_CASE(w, b, mb_, 8, dmb ish, , l, "memory", K) +__CMPXCHG_CASE(w, h, mb_, 16, dmb ish, , l, "memory", K) +__CMPXCHG_CASE(w, , mb_, 32, dmb ish, , l, "memory", K) +__CMPXCHG_CASE( , , mb_, 64, dmb ish, , l, "memory", L) #undef __CMPXCHG_CASE #define __CMPXCHG_DBL(name, mb, rel, cl) \ -__LL_SC_INLINE long \ -__LL_SC_PREFIX(__cmpxchg_double##name(unsigned long old1, \ +static inline long \ +__ll_sc__cmpxchg_double##name(unsigned long old1, \ unsigned long old2, \ unsigned long new1, \ unsigned long new2, \ - volatile void *ptr)) \ + volatile void *ptr) \ { \ unsigned long tmp, ret; \ \ asm volatile("// __cmpxchg_double" #name "\n" \ + __LL_SC_FALLBACK( \ " prfm pstl1strm, %2\n" \ "1: ldxp %0, %1, %2\n" \ " eor %0, %0, %3\n" \ @@ -311,18 +336,18 @@ __LL_SC_PREFIX(__cmpxchg_double##name(unsigned long old1, \ " st" #rel "xp %w0, %5, %6, %2\n" \ " cbnz %w0, 1b\n" \ " " #mb "\n" \ - "2:" \ + "2:") \ : "=&r" (tmp), "=&r" (ret), "+Q" (*(unsigned long *)ptr) \ : "r" (old1), "r" (old2), "r" (new1), "r" (new2) \ : cl); \ \ return ret; \ -} \ -__LL_SC_EXPORT(__cmpxchg_double##name); +} __CMPXCHG_DBL( , , , ) __CMPXCHG_DBL(_mb, dmb ish, l, "memory") #undef __CMPXCHG_DBL +#undef K #endif /* __ASM_ATOMIC_LL_SC_H */ diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h index 69acb1c19a15ab9b878ce252ff00a736294580fa..c6bd87d2915b4de23210ab3eba9eee4b249377db 100644 --- a/arch/arm64/include/asm/atomic_lse.h +++ b/arch/arm64/include/asm/atomic_lse.h @@ -10,22 +10,13 @@ #ifndef __ASM_ATOMIC_LSE_H #define __ASM_ATOMIC_LSE_H -#ifndef __ARM64_IN_ATOMIC_IMPL -#error "please don't include this file directly" -#endif - -#define __LL_SC_ATOMIC(op) __LL_SC_CALL(arch_atomic_##op) #define ATOMIC_OP(op, asm_op) \ -static inline void arch_atomic_##op(int i, atomic_t *v) \ +static inline void __lse_atomic_##op(int i, atomic_t *v) \ { \ - register int w0 asm ("w0") = i; \ - register atomic_t *x1 asm ("x1") = v; \ - \ - asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC(op), \ -" " #asm_op " %w[i], %[v]\n") \ - : [i] "+r" (w0), [v] "+Q" (v->counter) \ - : "r" (x1) \ - : __LL_SC_CLOBBERS); \ + asm volatile( \ +" " #asm_op " %w[i], %[v]\n" \ + : [i] "+r" (i), [v] "+Q" (v->counter) \ + : "r" (v)); \ } ATOMIC_OP(andnot, stclr) @@ -36,21 +27,15 @@ ATOMIC_OP(add, stadd) #undef ATOMIC_OP #define ATOMIC_FETCH_OP(name, mb, op, asm_op, cl...) \ -static inline int arch_atomic_fetch_##op##name(int i, atomic_t *v) \ +static inline int __lse_atomic_fetch_##op##name(int i, atomic_t *v) \ { \ - register int w0 asm ("w0") = i; \ - register atomic_t *x1 asm ("x1") = v; \ - \ - asm volatile(ARM64_LSE_ATOMIC_INSN( \ - /* LL/SC */ \ - __LL_SC_ATOMIC(fetch_##op##name), \ - /* LSE atomics */ \ -" " #asm_op #mb " %w[i], %w[i], %[v]") \ - : [i] "+r" (w0), [v] "+Q" (v->counter) \ - : "r" (x1) \ - : __LL_SC_CLOBBERS, ##cl); \ + asm volatile( \ +" " #asm_op #mb " %w[i], %w[i], %[v]" \ + : [i] "+r" (i), [v] "+Q" (v->counter) \ + : "r" (v) \ + : cl); \ \ - return w0; \ + return i; \ } #define ATOMIC_FETCH_OPS(op, asm_op) \ @@ -68,23 +53,18 @@ ATOMIC_FETCH_OPS(add, ldadd) #undef ATOMIC_FETCH_OPS #define ATOMIC_OP_ADD_RETURN(name, mb, cl...) \ -static inline int arch_atomic_add_return##name(int i, atomic_t *v) \ +static inline int __lse_atomic_add_return##name(int i, atomic_t *v) \ { \ - register int w0 asm ("w0") = i; \ - register atomic_t *x1 asm ("x1") = v; \ + u32 tmp; \ \ - asm volatile(ARM64_LSE_ATOMIC_INSN( \ - /* LL/SC */ \ - __LL_SC_ATOMIC(add_return##name) \ - __nops(1), \ - /* LSE atomics */ \ - " ldadd" #mb " %w[i], w30, %[v]\n" \ - " add %w[i], %w[i], w30") \ - : [i] "+r" (w0), [v] "+Q" (v->counter) \ - : "r" (x1) \ - : __LL_SC_CLOBBERS, ##cl); \ + asm volatile( \ + " ldadd" #mb " %w[i], %w[tmp], %[v]\n" \ + " add %w[i], %w[i], %w[tmp]" \ + : [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) \ + : "r" (v) \ + : cl); \ \ - return w0; \ + return i; \ } ATOMIC_OP_ADD_RETURN(_relaxed, ) @@ -94,41 +74,26 @@ ATOMIC_OP_ADD_RETURN( , al, "memory") #undef ATOMIC_OP_ADD_RETURN -static inline void arch_atomic_and(int i, atomic_t *v) +static inline void __lse_atomic_and(int i, atomic_t *v) { - register int w0 asm ("w0") = i; - register atomic_t *x1 asm ("x1") = v; - - asm volatile(ARM64_LSE_ATOMIC_INSN( - /* LL/SC */ - __LL_SC_ATOMIC(and) - __nops(1), - /* LSE atomics */ + asm volatile( " mvn %w[i], %w[i]\n" - " stclr %w[i], %[v]") - : [i] "+&r" (w0), [v] "+Q" (v->counter) - : "r" (x1) - : __LL_SC_CLOBBERS); + " stclr %w[i], %[v]" + : [i] "+&r" (i), [v] "+Q" (v->counter) + : "r" (v)); } #define ATOMIC_FETCH_OP_AND(name, mb, cl...) \ -static inline int arch_atomic_fetch_and##name(int i, atomic_t *v) \ +static inline int __lse_atomic_fetch_and##name(int i, atomic_t *v) \ { \ - register int w0 asm ("w0") = i; \ - register atomic_t *x1 asm ("x1") = v; \ - \ - asm volatile(ARM64_LSE_ATOMIC_INSN( \ - /* LL/SC */ \ - __LL_SC_ATOMIC(fetch_and##name) \ - __nops(1), \ - /* LSE atomics */ \ + asm volatile( \ " mvn %w[i], %w[i]\n" \ - " ldclr" #mb " %w[i], %w[i], %[v]") \ - : [i] "+&r" (w0), [v] "+Q" (v->counter) \ - : "r" (x1) \ - : __LL_SC_CLOBBERS, ##cl); \ + " ldclr" #mb " %w[i], %w[i], %[v]" \ + : [i] "+&r" (i), [v] "+Q" (v->counter) \ + : "r" (v) \ + : cl); \ \ - return w0; \ + return i; \ } ATOMIC_FETCH_OP_AND(_relaxed, ) @@ -138,42 +103,29 @@ ATOMIC_FETCH_OP_AND( , al, "memory") #undef ATOMIC_FETCH_OP_AND -static inline void arch_atomic_sub(int i, atomic_t *v) +static inline void __lse_atomic_sub(int i, atomic_t *v) { - register int w0 asm ("w0") = i; - register atomic_t *x1 asm ("x1") = v; - - asm volatile(ARM64_LSE_ATOMIC_INSN( - /* LL/SC */ - __LL_SC_ATOMIC(sub) - __nops(1), - /* LSE atomics */ + asm volatile( " neg %w[i], %w[i]\n" - " stadd %w[i], %[v]") - : [i] "+&r" (w0), [v] "+Q" (v->counter) - : "r" (x1) - : __LL_SC_CLOBBERS); + " stadd %w[i], %[v]" + : [i] "+&r" (i), [v] "+Q" (v->counter) + : "r" (v)); } #define ATOMIC_OP_SUB_RETURN(name, mb, cl...) \ -static inline int arch_atomic_sub_return##name(int i, atomic_t *v) \ +static inline int __lse_atomic_sub_return##name(int i, atomic_t *v) \ { \ - register int w0 asm ("w0") = i; \ - register atomic_t *x1 asm ("x1") = v; \ + u32 tmp; \ \ - asm volatile(ARM64_LSE_ATOMIC_INSN( \ - /* LL/SC */ \ - __LL_SC_ATOMIC(sub_return##name) \ - __nops(2), \ - /* LSE atomics */ \ + asm volatile( \ " neg %w[i], %w[i]\n" \ - " ldadd" #mb " %w[i], w30, %[v]\n" \ - " add %w[i], %w[i], w30") \ - : [i] "+&r" (w0), [v] "+Q" (v->counter) \ - : "r" (x1) \ - : __LL_SC_CLOBBERS , ##cl); \ + " ldadd" #mb " %w[i], %w[tmp], %[v]\n" \ + " add %w[i], %w[i], %w[tmp]" \ + : [i] "+&r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) \ + : "r" (v) \ + : cl); \ \ - return w0; \ + return i; \ } ATOMIC_OP_SUB_RETURN(_relaxed, ) @@ -184,23 +136,16 @@ ATOMIC_OP_SUB_RETURN( , al, "memory") #undef ATOMIC_OP_SUB_RETURN #define ATOMIC_FETCH_OP_SUB(name, mb, cl...) \ -static inline int arch_atomic_fetch_sub##name(int i, atomic_t *v) \ +static inline int __lse_atomic_fetch_sub##name(int i, atomic_t *v) \ { \ - register int w0 asm ("w0") = i; \ - register atomic_t *x1 asm ("x1") = v; \ - \ - asm volatile(ARM64_LSE_ATOMIC_INSN( \ - /* LL/SC */ \ - __LL_SC_ATOMIC(fetch_sub##name) \ - __nops(1), \ - /* LSE atomics */ \ + asm volatile( \ " neg %w[i], %w[i]\n" \ - " ldadd" #mb " %w[i], %w[i], %[v]") \ - : [i] "+&r" (w0), [v] "+Q" (v->counter) \ - : "r" (x1) \ - : __LL_SC_CLOBBERS, ##cl); \ + " ldadd" #mb " %w[i], %w[i], %[v]" \ + : [i] "+&r" (i), [v] "+Q" (v->counter) \ + : "r" (v) \ + : cl); \ \ - return w0; \ + return i; \ } ATOMIC_FETCH_OP_SUB(_relaxed, ) @@ -209,20 +154,14 @@ ATOMIC_FETCH_OP_SUB(_release, l, "memory") ATOMIC_FETCH_OP_SUB( , al, "memory") #undef ATOMIC_FETCH_OP_SUB -#undef __LL_SC_ATOMIC -#define __LL_SC_ATOMIC64(op) __LL_SC_CALL(arch_atomic64_##op) #define ATOMIC64_OP(op, asm_op) \ -static inline void arch_atomic64_##op(s64 i, atomic64_t *v) \ +static inline void __lse_atomic64_##op(s64 i, atomic64_t *v) \ { \ - register s64 x0 asm ("x0") = i; \ - register atomic64_t *x1 asm ("x1") = v; \ - \ - asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(op), \ -" " #asm_op " %[i], %[v]\n") \ - : [i] "+r" (x0), [v] "+Q" (v->counter) \ - : "r" (x1) \ - : __LL_SC_CLOBBERS); \ + asm volatile( \ +" " #asm_op " %[i], %[v]\n" \ + : [i] "+r" (i), [v] "+Q" (v->counter) \ + : "r" (v)); \ } ATOMIC64_OP(andnot, stclr) @@ -233,21 +172,15 @@ ATOMIC64_OP(add, stadd) #undef ATOMIC64_OP #define ATOMIC64_FETCH_OP(name, mb, op, asm_op, cl...) \ -static inline s64 arch_atomic64_fetch_##op##name(s64 i, atomic64_t *v) \ +static inline long __lse_atomic64_fetch_##op##name(s64 i, atomic64_t *v)\ { \ - register s64 x0 asm ("x0") = i; \ - register atomic64_t *x1 asm ("x1") = v; \ - \ - asm volatile(ARM64_LSE_ATOMIC_INSN( \ - /* LL/SC */ \ - __LL_SC_ATOMIC64(fetch_##op##name), \ - /* LSE atomics */ \ -" " #asm_op #mb " %[i], %[i], %[v]") \ - : [i] "+r" (x0), [v] "+Q" (v->counter) \ - : "r" (x1) \ - : __LL_SC_CLOBBERS, ##cl); \ + asm volatile( \ +" " #asm_op #mb " %[i], %[i], %[v]" \ + : [i] "+r" (i), [v] "+Q" (v->counter) \ + : "r" (v) \ + : cl); \ \ - return x0; \ + return i; \ } #define ATOMIC64_FETCH_OPS(op, asm_op) \ @@ -265,23 +198,18 @@ ATOMIC64_FETCH_OPS(add, ldadd) #undef ATOMIC64_FETCH_OPS #define ATOMIC64_OP_ADD_RETURN(name, mb, cl...) \ -static inline s64 arch_atomic64_add_return##name(s64 i, atomic64_t *v) \ +static inline long __lse_atomic64_add_return##name(s64 i, atomic64_t *v)\ { \ - register s64 x0 asm ("x0") = i; \ - register atomic64_t *x1 asm ("x1") = v; \ + unsigned long tmp; \ \ - asm volatile(ARM64_LSE_ATOMIC_INSN( \ - /* LL/SC */ \ - __LL_SC_ATOMIC64(add_return##name) \ - __nops(1), \ - /* LSE atomics */ \ - " ldadd" #mb " %[i], x30, %[v]\n" \ - " add %[i], %[i], x30") \ - : [i] "+r" (x0), [v] "+Q" (v->counter) \ - : "r" (x1) \ - : __LL_SC_CLOBBERS, ##cl); \ + asm volatile( \ + " ldadd" #mb " %[i], %x[tmp], %[v]\n" \ + " add %[i], %[i], %x[tmp]" \ + : [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) \ + : "r" (v) \ + : cl); \ \ - return x0; \ + return i; \ } ATOMIC64_OP_ADD_RETURN(_relaxed, ) @@ -291,41 +219,26 @@ ATOMIC64_OP_ADD_RETURN( , al, "memory") #undef ATOMIC64_OP_ADD_RETURN -static inline void arch_atomic64_and(s64 i, atomic64_t *v) +static inline void __lse_atomic64_and(s64 i, atomic64_t *v) { - register s64 x0 asm ("x0") = i; - register atomic64_t *x1 asm ("x1") = v; - - asm volatile(ARM64_LSE_ATOMIC_INSN( - /* LL/SC */ - __LL_SC_ATOMIC64(and) - __nops(1), - /* LSE atomics */ + asm volatile( " mvn %[i], %[i]\n" - " stclr %[i], %[v]") - : [i] "+&r" (x0), [v] "+Q" (v->counter) - : "r" (x1) - : __LL_SC_CLOBBERS); + " stclr %[i], %[v]" + : [i] "+&r" (i), [v] "+Q" (v->counter) + : "r" (v)); } #define ATOMIC64_FETCH_OP_AND(name, mb, cl...) \ -static inline s64 arch_atomic64_fetch_and##name(s64 i, atomic64_t *v) \ +static inline long __lse_atomic64_fetch_and##name(s64 i, atomic64_t *v) \ { \ - register s64 x0 asm ("x0") = i; \ - register atomic64_t *x1 asm ("x1") = v; \ - \ - asm volatile(ARM64_LSE_ATOMIC_INSN( \ - /* LL/SC */ \ - __LL_SC_ATOMIC64(fetch_and##name) \ - __nops(1), \ - /* LSE atomics */ \ + asm volatile( \ " mvn %[i], %[i]\n" \ - " ldclr" #mb " %[i], %[i], %[v]") \ - : [i] "+&r" (x0), [v] "+Q" (v->counter) \ - : "r" (x1) \ - : __LL_SC_CLOBBERS, ##cl); \ + " ldclr" #mb " %[i], %[i], %[v]" \ + : [i] "+&r" (i), [v] "+Q" (v->counter) \ + : "r" (v) \ + : cl); \ \ - return x0; \ + return i; \ } ATOMIC64_FETCH_OP_AND(_relaxed, ) @@ -335,42 +248,29 @@ ATOMIC64_FETCH_OP_AND( , al, "memory") #undef ATOMIC64_FETCH_OP_AND -static inline void arch_atomic64_sub(s64 i, atomic64_t *v) +static inline void __lse_atomic64_sub(s64 i, atomic64_t *v) { - register s64 x0 asm ("x0") = i; - register atomic64_t *x1 asm ("x1") = v; - - asm volatile(ARM64_LSE_ATOMIC_INSN( - /* LL/SC */ - __LL_SC_ATOMIC64(sub) - __nops(1), - /* LSE atomics */ + asm volatile( " neg %[i], %[i]\n" - " stadd %[i], %[v]") - : [i] "+&r" (x0), [v] "+Q" (v->counter) - : "r" (x1) - : __LL_SC_CLOBBERS); + " stadd %[i], %[v]" + : [i] "+&r" (i), [v] "+Q" (v->counter) + : "r" (v)); } #define ATOMIC64_OP_SUB_RETURN(name, mb, cl...) \ -static inline s64 arch_atomic64_sub_return##name(s64 i, atomic64_t *v) \ +static inline long __lse_atomic64_sub_return##name(s64 i, atomic64_t *v) \ { \ - register s64 x0 asm ("x0") = i; \ - register atomic64_t *x1 asm ("x1") = v; \ + unsigned long tmp; \ \ - asm volatile(ARM64_LSE_ATOMIC_INSN( \ - /* LL/SC */ \ - __LL_SC_ATOMIC64(sub_return##name) \ - __nops(2), \ - /* LSE atomics */ \ + asm volatile( \ " neg %[i], %[i]\n" \ - " ldadd" #mb " %[i], x30, %[v]\n" \ - " add %[i], %[i], x30") \ - : [i] "+&r" (x0), [v] "+Q" (v->counter) \ - : "r" (x1) \ - : __LL_SC_CLOBBERS, ##cl); \ + " ldadd" #mb " %[i], %x[tmp], %[v]\n" \ + " add %[i], %[i], %x[tmp]" \ + : [i] "+&r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) \ + : "r" (v) \ + : cl); \ \ - return x0; \ + return i; \ } ATOMIC64_OP_SUB_RETURN(_relaxed, ) @@ -381,23 +281,16 @@ ATOMIC64_OP_SUB_RETURN( , al, "memory") #undef ATOMIC64_OP_SUB_RETURN #define ATOMIC64_FETCH_OP_SUB(name, mb, cl...) \ -static inline s64 arch_atomic64_fetch_sub##name(s64 i, atomic64_t *v) \ +static inline long __lse_atomic64_fetch_sub##name(s64 i, atomic64_t *v) \ { \ - register s64 x0 asm ("x0") = i; \ - register atomic64_t *x1 asm ("x1") = v; \ - \ - asm volatile(ARM64_LSE_ATOMIC_INSN( \ - /* LL/SC */ \ - __LL_SC_ATOMIC64(fetch_sub##name) \ - __nops(1), \ - /* LSE atomics */ \ + asm volatile( \ " neg %[i], %[i]\n" \ - " ldadd" #mb " %[i], %[i], %[v]") \ - : [i] "+&r" (x0), [v] "+Q" (v->counter) \ - : "r" (x1) \ - : __LL_SC_CLOBBERS, ##cl); \ + " ldadd" #mb " %[i], %[i], %[v]" \ + : [i] "+&r" (i), [v] "+Q" (v->counter) \ + : "r" (v) \ + : cl); \ \ - return x0; \ + return i; \ } ATOMIC64_FETCH_OP_SUB(_relaxed, ) @@ -407,54 +300,44 @@ ATOMIC64_FETCH_OP_SUB( , al, "memory") #undef ATOMIC64_FETCH_OP_SUB -static inline s64 arch_atomic64_dec_if_positive(atomic64_t *v) +static inline s64 __lse_atomic64_dec_if_positive(atomic64_t *v) { - register long x0 asm ("x0") = (long)v; - - asm volatile(ARM64_LSE_ATOMIC_INSN( - /* LL/SC */ - __LL_SC_ATOMIC64(dec_if_positive) - __nops(6), - /* LSE atomics */ - "1: ldr x30, %[v]\n" - " subs %[ret], x30, #1\n" + unsigned long tmp; + + asm volatile( + "1: ldr %x[tmp], %[v]\n" + " subs %[ret], %x[tmp], #1\n" " b.lt 2f\n" - " casal x30, %[ret], %[v]\n" - " sub x30, x30, #1\n" - " sub x30, x30, %[ret]\n" - " cbnz x30, 1b\n" - "2:") - : [ret] "+&r" (x0), [v] "+Q" (v->counter) + " casal %x[tmp], %[ret], %[v]\n" + " sub %x[tmp], %x[tmp], #1\n" + " sub %x[tmp], %x[tmp], %[ret]\n" + " cbnz %x[tmp], 1b\n" + "2:" + : [ret] "+&r" (v), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) : - : __LL_SC_CLOBBERS, "cc", "memory"); + : "cc", "memory"); - return x0; + return (long)v; } -#undef __LL_SC_ATOMIC64 - -#define __LL_SC_CMPXCHG(op) __LL_SC_CALL(__cmpxchg_case_##op) - #define __CMPXCHG_CASE(w, sfx, name, sz, mb, cl...) \ -static inline u##sz __cmpxchg_case_##name##sz(volatile void *ptr, \ +static inline u##sz __lse__cmpxchg_case_##name##sz(volatile void *ptr, \ u##sz old, \ u##sz new) \ { \ register unsigned long x0 asm ("x0") = (unsigned long)ptr; \ register u##sz x1 asm ("x1") = old; \ register u##sz x2 asm ("x2") = new; \ + unsigned long tmp; \ \ - asm volatile(ARM64_LSE_ATOMIC_INSN( \ - /* LL/SC */ \ - __LL_SC_CMPXCHG(name##sz) \ - __nops(2), \ - /* LSE atomics */ \ - " mov " #w "30, %" #w "[old]\n" \ - " cas" #mb #sfx "\t" #w "30, %" #w "[new], %[v]\n" \ - " mov %" #w "[ret], " #w "30") \ - : [ret] "+r" (x0), [v] "+Q" (*(unsigned long *)ptr) \ + asm volatile( \ + " mov %" #w "[tmp], %" #w "[old]\n" \ + " cas" #mb #sfx "\t%" #w "[tmp], %" #w "[new], %[v]\n" \ + " mov %" #w "[ret], %" #w "[tmp]" \ + : [ret] "+r" (x0), [v] "+Q" (*(unsigned long *)ptr), \ + [tmp] "=&r" (tmp) \ : [old] "r" (x1), [new] "r" (x2) \ - : __LL_SC_CLOBBERS, ##cl); \ + : cl); \ \ return x0; \ } @@ -476,13 +359,10 @@ __CMPXCHG_CASE(w, h, mb_, 16, al, "memory") __CMPXCHG_CASE(w, , mb_, 32, al, "memory") __CMPXCHG_CASE(x, , mb_, 64, al, "memory") -#undef __LL_SC_CMPXCHG #undef __CMPXCHG_CASE -#define __LL_SC_CMPXCHG_DBL(op) __LL_SC_CALL(__cmpxchg_double##op) - #define __CMPXCHG_DBL(name, mb, cl...) \ -static inline long __cmpxchg_double##name(unsigned long old1, \ +static inline long __lse__cmpxchg_double##name(unsigned long old1, \ unsigned long old2, \ unsigned long new1, \ unsigned long new2, \ @@ -496,20 +376,16 @@ static inline long __cmpxchg_double##name(unsigned long old1, \ register unsigned long x3 asm ("x3") = new2; \ register unsigned long x4 asm ("x4") = (unsigned long)ptr; \ \ - asm volatile(ARM64_LSE_ATOMIC_INSN( \ - /* LL/SC */ \ - __LL_SC_CMPXCHG_DBL(name) \ - __nops(3), \ - /* LSE atomics */ \ + asm volatile( \ " casp" #mb "\t%[old1], %[old2], %[new1], %[new2], %[v]\n"\ " eor %[old1], %[old1], %[oldval1]\n" \ " eor %[old2], %[old2], %[oldval2]\n" \ - " orr %[old1], %[old1], %[old2]") \ + " orr %[old1], %[old1], %[old2]" \ : [old1] "+&r" (x0), [old2] "+&r" (x1), \ [v] "+Q" (*(unsigned long *)ptr) \ : [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4), \ [oldval1] "r" (oldval1), [oldval2] "r" (oldval2) \ - : __LL_SC_CLOBBERS, ##cl); \ + : cl); \ \ return x0; \ } @@ -517,7 +393,6 @@ static inline long __cmpxchg_double##name(unsigned long old1, \ __CMPXCHG_DBL( , ) __CMPXCHG_DBL(_mb, al, "memory") -#undef __LL_SC_CMPXCHG_DBL #undef __CMPXCHG_DBL #endif /* __ASM_ATOMIC_LSE_H */ diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h index 64eeaa41e7caa2c76083ffdafd993abc7df17f4f..43da6dd295920798debddb2854563a909ba5e19b 100644 --- a/arch/arm64/include/asm/cache.h +++ b/arch/arm64/include/asm/cache.h @@ -78,7 +78,7 @@ static inline u32 cache_type_cwg(void) return (read_cpuid_cachetype() >> CTR_CWG_SHIFT) & CTR_CWG_MASK; } -#define __read_mostly __attribute__((__section__(".data..read_mostly"))) +#define __read_mostly __section(.data..read_mostly) static inline int cache_line_size_of_cpu(void) { diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h index 7a299a20f6dcc558219d452287767d64cd9c73e0..a1398f2f9994fcdc0e110731feffa550ab765964 100644 --- a/arch/arm64/include/asm/cmpxchg.h +++ b/arch/arm64/include/asm/cmpxchg.h @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -104,6 +103,50 @@ __XCHG_GEN(_mb) #define arch_xchg_release(...) __xchg_wrapper(_rel, __VA_ARGS__) #define arch_xchg(...) __xchg_wrapper( _mb, __VA_ARGS__) +#define __CMPXCHG_CASE(name, sz) \ +static inline u##sz __cmpxchg_case_##name##sz(volatile void *ptr, \ + u##sz old, \ + u##sz new) \ +{ \ + return __lse_ll_sc_body(_cmpxchg_case_##name##sz, \ + ptr, old, new); \ +} + +__CMPXCHG_CASE( , 8) +__CMPXCHG_CASE( , 16) +__CMPXCHG_CASE( , 32) +__CMPXCHG_CASE( , 64) +__CMPXCHG_CASE(acq_, 8) +__CMPXCHG_CASE(acq_, 16) +__CMPXCHG_CASE(acq_, 32) +__CMPXCHG_CASE(acq_, 64) +__CMPXCHG_CASE(rel_, 8) +__CMPXCHG_CASE(rel_, 16) +__CMPXCHG_CASE(rel_, 32) +__CMPXCHG_CASE(rel_, 64) +__CMPXCHG_CASE(mb_, 8) +__CMPXCHG_CASE(mb_, 16) +__CMPXCHG_CASE(mb_, 32) +__CMPXCHG_CASE(mb_, 64) + +#undef __CMPXCHG_CASE + +#define __CMPXCHG_DBL(name) \ +static inline long __cmpxchg_double##name(unsigned long old1, \ + unsigned long old2, \ + unsigned long new1, \ + unsigned long new2, \ + volatile void *ptr) \ +{ \ + return __lse_ll_sc_body(_cmpxchg_double##name, \ + old1, old2, new1, new2, ptr); \ +} + +__CMPXCHG_DBL( ) +__CMPXCHG_DBL(_mb) + +#undef __CMPXCHG_DBL + #define __CMPXCHG_GEN(sfx) \ static inline unsigned long __cmpxchg##sfx(volatile void *ptr, \ unsigned long old, \ diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h index fb8ad4616b3bfff87e8e8e418755bbebb2174e39..b0d53a265f1d510cbb6372685b39a53de2361eed 100644 --- a/arch/arm64/include/asm/compat.h +++ b/arch/arm64/include/asm/compat.h @@ -4,7 +4,6 @@ */ #ifndef __ASM_COMPAT_H #define __ASM_COMPAT_H -#ifdef __KERNEL__ #ifdef CONFIG_COMPAT /* @@ -215,5 +214,4 @@ static inline int is_compat_thread(struct thread_info *thread) } #endif /* CONFIG_COMPAT */ -#endif /* __KERNEL__ */ #endif /* __ASM_COMPAT_H */ diff --git a/arch/arm64/include/asm/cpu_ops.h b/arch/arm64/include/asm/cpu_ops.h index c09d633c3109f4b1560aa359a1daca89d8b8b7b0..86aabf1e019932c70a0d1964750e59905d3f0861 100644 --- a/arch/arm64/include/asm/cpu_ops.h +++ b/arch/arm64/include/asm/cpu_ops.h @@ -23,6 +23,8 @@ * @cpu_boot: Boots a cpu into the kernel. * @cpu_postboot: Optionally, perform any post-boot cleanup or necesary * synchronisation. Called from the cpu being booted. + * @cpu_can_disable: Determines whether a CPU can be disabled based on + * mechanism-specific information. * @cpu_disable: Prepares a cpu to die. May fail for some mechanism-specific * reason, which will cause the hot unplug to be aborted. Called * from the cpu to be killed. @@ -42,6 +44,7 @@ struct cpu_operations { int (*cpu_boot)(unsigned int); void (*cpu_postboot)(void); #ifdef CONFIG_HOTPLUG_CPU + bool (*cpu_can_disable)(unsigned int cpu); int (*cpu_disable)(unsigned int cpu); void (*cpu_die)(unsigned int cpu); int (*cpu_kill)(unsigned int cpu); diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index c96ffa4722d33cba234afdc64ce4483926eba26c..9cde5d2e768f43160d7322361a9dfc2c77293b68 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -289,9 +289,16 @@ struct arm64_cpu_capabilities { u16 type; bool (*matches)(const struct arm64_cpu_capabilities *caps, int scope); /* - * Take the appropriate actions to enable this capability for this CPU. - * For each successfully booted CPU, this method is called for each - * globally detected capability. + * Take the appropriate actions to configure this capability + * for this CPU. If the capability is detected by the kernel + * this will be called on all the CPUs in the system, + * including the hotplugged CPUs, regardless of whether the + * capability is available on that specific CPU. This is + * useful for some capabilities (e.g, working around CPU + * errata), where all the CPUs must take some action (e.g, + * changing system control/configuration). Thus, if an action + * is required only if the CPU has the capability, then the + * routine must check it before taking any action. */ void (*cpu_enable)(const struct arm64_cpu_capabilities *cap); union { @@ -363,21 +370,6 @@ cpucap_multi_entry_cap_matches(const struct arm64_cpu_capabilities *entry, return false; } -/* - * Take appropriate action for all matching entries in the shared capability - * entry. - */ -static inline void -cpucap_multi_entry_cap_cpu_enable(const struct arm64_cpu_capabilities *entry) -{ - const struct arm64_cpu_capabilities *caps; - - for (caps = entry->match_list; caps->matches; caps++) - if (caps->matches(caps, SCOPE_LOCAL_CPU) && - caps->cpu_enable) - caps->cpu_enable(caps); -} - extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS); extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS]; extern struct static_key_false arm64_const_caps_ready; diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index e7d46631cc42ba1bd18adf6a279a2c1f74575e85..b1454d117cd2c69582d519f123fcaa66f5f81c44 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -51,14 +51,6 @@ #define MIDR_CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \ MIDR_ARCHITECTURE_MASK) -#define MIDR_IS_CPU_MODEL_RANGE(midr, model, rv_min, rv_max) \ -({ \ - u32 _model = (midr) & MIDR_CPU_MODEL_MASK; \ - u32 rv = (midr) & (MIDR_REVISION_MASK | MIDR_VARIANT_MASK); \ - \ - _model == (model) && rv >= (rv_min) && rv <= (rv_max); \ - }) - #define ARM_CPU_IMP_ARM 0x41 #define ARM_CPU_IMP_APM 0x50 #define ARM_CPU_IMP_CAVIUM 0x43 @@ -159,10 +151,19 @@ struct midr_range { #define MIDR_REV(m, v, r) MIDR_RANGE(m, v, r, v, r) #define MIDR_ALL_VERSIONS(m) MIDR_RANGE(m, 0, 0, 0xf, 0xf) +static inline bool midr_is_cpu_model_range(u32 midr, u32 model, u32 rv_min, + u32 rv_max) +{ + u32 _model = midr & MIDR_CPU_MODEL_MASK; + u32 rv = midr & (MIDR_REVISION_MASK | MIDR_VARIANT_MASK); + + return _model == model && rv >= rv_min && rv <= rv_max; +} + static inline bool is_midr_in_range(u32 midr, struct midr_range const *range) { - return MIDR_IS_CPU_MODEL_RANGE(midr, range->model, - range->rv_min, range->rv_max); + return midr_is_cpu_model_range(midr, range->model, + range->rv_min, range->rv_max); } static inline bool diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h index d8ec5bb881c26700d013b08ef35cffda8468fd1d..7619f473155f2fac2dabfc9ebddfcb797475f285 100644 --- a/arch/arm64/include/asm/debug-monitors.h +++ b/arch/arm64/include/asm/debug-monitors.h @@ -5,8 +5,6 @@ #ifndef __ASM_DEBUG_MONITORS_H #define __ASM_DEBUG_MONITORS_H -#ifdef __KERNEL__ - #include #include #include @@ -128,5 +126,4 @@ static inline int reinstall_suspended_bps(struct pt_regs *regs) int aarch32_break_handler(struct pt_regs *regs); #endif /* __ASSEMBLY */ -#endif /* __KERNEL__ */ #endif /* __ASM_DEBUG_MONITORS_H */ diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h index bdcb0922a40c953d28c263cf46a01b0f46eb23f1..fb3e5044f473a36cf3b36c19686060c4bd9ad133 100644 --- a/arch/arm64/include/asm/dma-mapping.h +++ b/arch/arm64/include/asm/dma-mapping.h @@ -5,8 +5,6 @@ #ifndef __ASM_DMA_MAPPING_H #define __ASM_DMA_MAPPING_H -#ifdef __KERNEL__ - #include #include @@ -27,5 +25,4 @@ static inline bool is_device_dma_coherent(struct device *dev) return dev->dma_coherent; } -#endif /* __KERNEL__ */ #endif /* __ASM_DMA_MAPPING_H */ diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index 76a14470258693743eb29a09028751e0f710a2c3..b54d3a86c44446735bfbfe4e49ab217460fc5b27 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -79,7 +79,7 @@ static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base) /* * On arm64, we have to ensure that the initrd ends up in the linear region, - * which is a 1 GB aligned region of size '1UL << (VA_BITS - 1)' that is + * which is a 1 GB aligned region of size '1UL << (VA_BITS_MIN - 1)' that is * guaranteed to cover the kernel Image. * * Since the EFI stub is part of the kernel Image, we can relax the @@ -90,7 +90,7 @@ static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base) static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base, unsigned long image_addr) { - return (image_addr & ~(SZ_1G - 1UL)) + (1UL << (VA_BITS - 1)); + return (image_addr & ~(SZ_1G - 1UL)) + (1UL << (VA_BITS_MIN - 1)); } #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__) diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h index 65ac184009798ca2831646fdc46a4c82018cce68..cb29253ae86b00ee09844b567620c7fb2c19e24f 100644 --- a/arch/arm64/include/asm/esr.h +++ b/arch/arm64/include/asm/esr.h @@ -34,7 +34,8 @@ #define ESR_ELx_EC_SMC64 (0x17) /* EL2 and above */ #define ESR_ELx_EC_SYS64 (0x18) #define ESR_ELx_EC_SVE (0x19) -/* Unallocated EC: 0x1A - 0x1E */ +#define ESR_ELx_EC_ERET (0x1a) /* EL2 only */ +/* Unallocated EC: 0x1b - 0x1E */ #define ESR_ELx_EC_IMP_DEF (0x1f) /* EL3 only */ #define ESR_ELx_EC_IABT_LOW (0x20) #define ESR_ELx_EC_IABT_CUR (0x21) diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h index ed57b760f38cf2497ad37a91041b6f806026f817..a17393ff6677425e676d0e6dd958f8862f87e913 100644 --- a/arch/arm64/include/asm/exception.h +++ b/arch/arm64/include/asm/exception.h @@ -30,4 +30,6 @@ static inline u32 disr_to_esr(u64 disr) return esr; } +asmlinkage void enter_from_user_mode(void); + #endif /* __ASM_EXCEPTION_H */ diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h index b6a2c352f4c3fd64726115f478d1c6a4fd60b040..59f10dd13f121e3acb156740ff6c17e0d12856da 100644 --- a/arch/arm64/include/asm/fpsimd.h +++ b/arch/arm64/include/asm/fpsimd.h @@ -21,7 +21,7 @@ #include #include -#if defined(__KERNEL__) && defined(CONFIG_COMPAT) +#ifdef CONFIG_COMPAT /* Masks for extracting the FPSR and FPCR from the FPSCR */ #define VFP_FPSCR_STAT_MASK 0xf800009f #define VFP_FPSCR_CTRL_MASK 0x07f79f00 diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h index 6211e3105491e033f16d372916733ab88f7c6b37..6cc26a1278197a60d8f275a3b3ba0df7aba0a265 100644 --- a/arch/arm64/include/asm/futex.h +++ b/arch/arm64/include/asm/futex.h @@ -5,8 +5,6 @@ #ifndef __ASM_FUTEX_H #define __ASM_FUTEX_H -#ifdef __KERNEL__ - #include #include @@ -129,5 +127,4 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *_uaddr, return ret; } -#endif /* __KERNEL__ */ #endif /* __ASM_FUTEX_H */ diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h index db9ab760e6fdd9b239c97c954975503df9368a55..bc7aaed4b34e958386ae844a6795ba6d576bc182 100644 --- a/arch/arm64/include/asm/hw_breakpoint.h +++ b/arch/arm64/include/asm/hw_breakpoint.h @@ -10,8 +10,6 @@ #include #include -#ifdef __KERNEL__ - struct arch_hw_breakpoint_ctrl { u32 __reserved : 19, len : 8, @@ -156,5 +154,4 @@ static inline int get_num_wrps(void) ID_AA64DFR0_WRPS_SHIFT); } -#endif /* __KERNEL__ */ #endif /* __ASM_BREAKPOINT_H */ diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h index 7ed92626949d7d001d6f84a4402d9f419d01e637..323cb306bd2884a3ea1c6877df5829ae87deb440 100644 --- a/arch/arm64/include/asm/io.h +++ b/arch/arm64/include/asm/io.h @@ -8,8 +8,6 @@ #ifndef __ASM_IO_H #define __ASM_IO_H -#ifdef __KERNEL__ - #include #include @@ -97,7 +95,7 @@ static inline u64 __raw_readq(const volatile void __iomem *addr) ({ \ unsigned long tmp; \ \ - rmb(); \ + dma_rmb(); \ \ /* \ * Create a dummy control dependency from the IO read to any \ @@ -111,7 +109,7 @@ static inline u64 __raw_readq(const volatile void __iomem *addr) }) #define __io_par(v) __iormb(v) -#define __iowmb() wmb() +#define __iowmb() dma_wmb() /* * Relaxed I/O memory access primitives. These follow the Device memory @@ -165,14 +163,13 @@ extern void __memset_io(volatile void __iomem *, int, size_t); * I/O memory mapping functions. */ extern void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot); -extern void __iounmap(volatile void __iomem *addr); +extern void iounmap(volatile void __iomem *addr); 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_nocache(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE)) #define ioremap_wc(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC)) #define ioremap_wt(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE)) -#define iounmap __iounmap /* * PCI configuration space mapping function. @@ -207,5 +204,4 @@ extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size); extern int devmem_is_allowed(unsigned long pfn); -#endif /* __KERNEL__ */ #endif /* __ASM_IO_H */ diff --git a/arch/arm64/include/asm/irqflags.h b/arch/arm64/include/asm/irqflags.h index 7872f260c9ee3e14755e916230be06095a936dbf..1a59f0ed1ae392ac06fe26d2da2a9274239c0432 100644 --- a/arch/arm64/include/asm/irqflags.h +++ b/arch/arm64/include/asm/irqflags.h @@ -5,8 +5,6 @@ #ifndef __ASM_IRQFLAGS_H #define __ASM_IRQFLAGS_H -#ifdef __KERNEL__ - #include #include #include @@ -128,5 +126,4 @@ static inline void arch_local_irq_restore(unsigned long flags) : "memory"); } -#endif -#endif +#endif /* __ASM_IRQFLAGS_H */ diff --git a/arch/arm64/include/asm/kasan.h b/arch/arm64/include/asm/kasan.h index b52aacd2c5261ada9d417f2a6de2dbb96658ff1c..b0dc4abc358911237956c24ed12a3d64d09c4474 100644 --- a/arch/arm64/include/asm/kasan.h +++ b/arch/arm64/include/asm/kasan.h @@ -18,11 +18,8 @@ * KASAN_SHADOW_START: beginning of the kernel virtual addresses. * KASAN_SHADOW_END: KASAN_SHADOW_START + 1/N of kernel virtual addresses, * where N = (1 << KASAN_SHADOW_SCALE_SHIFT). - */ -#define KASAN_SHADOW_START (VA_START) -#define KASAN_SHADOW_END (KASAN_SHADOW_START + KASAN_SHADOW_SIZE) - -/* + * + * KASAN_SHADOW_OFFSET: * This value is used to map an address to the corresponding shadow * address by the following formula: * shadow_addr = (address >> KASAN_SHADOW_SCALE_SHIFT) + KASAN_SHADOW_OFFSET @@ -33,8 +30,8 @@ * KASAN_SHADOW_OFFSET = KASAN_SHADOW_END - * (1ULL << (64 - KASAN_SHADOW_SCALE_SHIFT)) */ -#define KASAN_SHADOW_OFFSET (KASAN_SHADOW_END - (1ULL << \ - (64 - KASAN_SHADOW_SCALE_SHIFT))) +#define _KASAN_SHADOW_START(va) (KASAN_SHADOW_END - (1UL << ((va) - KASAN_SHADOW_SCALE_SHIFT))) +#define KASAN_SHADOW_START _KASAN_SHADOW_START(vabits_actual) void kasan_init(void); void kasan_copy_shadow(pgd_t *pgdir); diff --git a/arch/arm64/include/asm/lse.h b/arch/arm64/include/asm/lse.h index 8262325e2fc66ec3d42f83ae6621ea4ec7e19651..80b388278149681cbf968449bd3681d7080a8f52 100644 --- a/arch/arm64/include/asm/lse.h +++ b/arch/arm64/include/asm/lse.h @@ -2,56 +2,47 @@ #ifndef __ASM_LSE_H #define __ASM_LSE_H +#include + #if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS) #include #include +#include #include #include +#include #include -#ifdef __ASSEMBLER__ - -.arch_extension lse - -.macro alt_lse, llsc, lse - alternative_insn "\llsc", "\lse", ARM64_HAS_LSE_ATOMICS -.endm - -#else /* __ASSEMBLER__ */ - __asm__(".arch_extension lse"); -/* Move the ll/sc atomics out-of-line */ -#define __LL_SC_INLINE notrace -#define __LL_SC_PREFIX(x) __ll_sc_##x -#define __LL_SC_EXPORT(x) EXPORT_SYMBOL(__LL_SC_PREFIX(x)) +extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS]; +extern struct static_key_false arm64_const_caps_ready; + +static inline bool system_uses_lse_atomics(void) +{ + return (static_branch_likely(&arm64_const_caps_ready)) && + static_branch_likely(&cpu_hwcap_keys[ARM64_HAS_LSE_ATOMICS]); +} -/* Macro for constructing calls to out-of-line ll/sc atomics */ -#define __LL_SC_CALL(op) "bl\t" __stringify(__LL_SC_PREFIX(op)) "\n" -#define __LL_SC_CLOBBERS "x16", "x17", "x30" +#define __lse_ll_sc_body(op, ...) \ +({ \ + system_uses_lse_atomics() ? \ + __lse_##op(__VA_ARGS__) : \ + __ll_sc_##op(__VA_ARGS__); \ +}) /* In-line patching at runtime */ #define ARM64_LSE_ATOMIC_INSN(llsc, lse) \ ALTERNATIVE(llsc, lse, ARM64_HAS_LSE_ATOMICS) -#endif /* __ASSEMBLER__ */ #else /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */ -#ifdef __ASSEMBLER__ - -.macro alt_lse, llsc, lse - \llsc -.endm - -#else /* __ASSEMBLER__ */ +static inline bool system_uses_lse_atomics(void) { return false; } -#define __LL_SC_INLINE static inline -#define __LL_SC_PREFIX(x) x -#define __LL_SC_EXPORT(x) +#define __lse_ll_sc_body(op, ...) __ll_sc_##op(__VA_ARGS__) #define ARM64_LSE_ATOMIC_INSN(llsc, lse) llsc -#endif /* __ASSEMBLER__ */ #endif /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */ #endif /* __ASM_LSE_H */ diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index fb04f10a78ab35c462e251d0bacce3a05da9be32..b61b50bf68b1893024e997d268fbbb3c91153d91 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -12,10 +12,10 @@ #include #include +#include #include #include #include -#include /* * Size of the PCI I/O space. This must remain a power of two so that @@ -26,37 +26,50 @@ /* * VMEMMAP_SIZE - allows the whole linear region to be covered by * a struct page array + * + * If we are configured with a 52-bit kernel VA then our VMEMMAP_SIZE + * needs to cover the memory region from the beginning of the 52-bit + * PAGE_OFFSET all the way to PAGE_END for 48-bit. This allows us to + * keep a constant PAGE_OFFSET and "fallback" to using the higher end + * of the VMEMMAP where 52-bit support is not available in hardware. */ -#define VMEMMAP_SIZE (UL(1) << (VA_BITS - PAGE_SHIFT - 1 + STRUCT_PAGE_MAX_SHIFT)) +#define VMEMMAP_SIZE ((_PAGE_END(VA_BITS_MIN) - PAGE_OFFSET) \ + >> (PAGE_SHIFT - STRUCT_PAGE_MAX_SHIFT)) /* - * PAGE_OFFSET - the virtual address of the start of the linear map (top - * (VA_BITS - 1)) - * KIMAGE_VADDR - the virtual address of the start of the kernel image + * PAGE_OFFSET - the virtual address of the start of the linear map, at the + * start of the TTBR1 address space. + * PAGE_END - the end of the linear map, where all other kernel mappings begin. + * KIMAGE_VADDR - the virtual address of the start of the kernel image. * VA_BITS - the maximum number of bits for virtual addresses. - * VA_START - the first kernel virtual address. */ #define VA_BITS (CONFIG_ARM64_VA_BITS) -#define VA_START (UL(0xffffffffffffffff) - \ - (UL(1) << VA_BITS) + 1) -#define PAGE_OFFSET (UL(0xffffffffffffffff) - \ - (UL(1) << (VA_BITS - 1)) + 1) +#define _PAGE_OFFSET(va) (-(UL(1) << (va))) +#define PAGE_OFFSET (_PAGE_OFFSET(VA_BITS)) #define KIMAGE_VADDR (MODULES_END) -#define BPF_JIT_REGION_START (VA_START + KASAN_SHADOW_SIZE) +#define BPF_JIT_REGION_START (KASAN_SHADOW_END) #define BPF_JIT_REGION_SIZE (SZ_128M) #define BPF_JIT_REGION_END (BPF_JIT_REGION_START + BPF_JIT_REGION_SIZE) #define MODULES_END (MODULES_VADDR + MODULES_VSIZE) #define MODULES_VADDR (BPF_JIT_REGION_END) #define MODULES_VSIZE (SZ_128M) -#define VMEMMAP_START (PAGE_OFFSET - VMEMMAP_SIZE) +#define VMEMMAP_START (-VMEMMAP_SIZE - SZ_2M) #define PCI_IO_END (VMEMMAP_START - SZ_2M) #define PCI_IO_START (PCI_IO_END - PCI_IO_SIZE) #define FIXADDR_TOP (PCI_IO_START - SZ_2M) -#define KERNEL_START _text -#define KERNEL_END _end +#if VA_BITS > 48 +#define VA_BITS_MIN (48) +#else +#define VA_BITS_MIN (VA_BITS) +#endif + +#define _PAGE_END(va) (-(UL(1) << ((va) - 1))) -#ifdef CONFIG_ARM64_USER_VA_BITS_52 +#define KERNEL_START _text +#define KERNEL_END _end + +#ifdef CONFIG_ARM64_VA_BITS_52 #define MAX_USER_VA_BITS 52 #else #define MAX_USER_VA_BITS VA_BITS @@ -68,12 +81,14 @@ * significantly, so double the (minimum) stack size when they are in use. */ #ifdef CONFIG_KASAN -#define KASAN_SHADOW_SIZE (UL(1) << (VA_BITS - KASAN_SHADOW_SCALE_SHIFT)) +#define KASAN_SHADOW_OFFSET _AC(CONFIG_KASAN_SHADOW_OFFSET, UL) +#define KASAN_SHADOW_END ((UL(1) << (64 - KASAN_SHADOW_SCALE_SHIFT)) \ + + KASAN_SHADOW_OFFSET) #define KASAN_THREAD_SHIFT 1 #else -#define KASAN_SHADOW_SIZE (0) #define KASAN_THREAD_SHIFT 0 -#endif +#define KASAN_SHADOW_END (_PAGE_END(VA_BITS_MIN)) +#endif /* CONFIG_KASAN */ #define MIN_THREAD_SHIFT (14 + KASAN_THREAD_SHIFT) @@ -117,14 +132,14 @@ * 16 KB granule: 128 level 3 entries, with contiguous bit * 64 KB granule: 32 level 3 entries, with contiguous bit */ -#define SEGMENT_ALIGN SZ_2M +#define SEGMENT_ALIGN SZ_2M #else /* * 4 KB granule: 16 level 3 entries, with contiguous bit * 16 KB granule: 4 level 3 entries, without contiguous bit * 64 KB granule: 1 level 3 entry */ -#define SEGMENT_ALIGN SZ_64K +#define SEGMENT_ALIGN SZ_64K #endif /* @@ -157,10 +172,13 @@ #endif #ifndef __ASSEMBLY__ +extern u64 vabits_actual; +#define PAGE_END (_PAGE_END(vabits_actual)) #include #include +extern s64 physvirt_offset; extern s64 memstart_addr; /* PHYS_OFFSET - the physical address of the start of memory. */ #define PHYS_OFFSET ({ VM_BUG_ON(memstart_addr & 1); memstart_addr; }) @@ -176,9 +194,6 @@ static inline unsigned long kaslr_offset(void) return kimage_vaddr - KIMAGE_VADDR; } -/* the actual size of a user virtual address */ -extern u64 vabits_user; - /* * Allow all memory at the discovery stage. We will clip it later. */ @@ -201,24 +216,24 @@ extern u64 vabits_user; * pass on to access_ok(), for instance. */ #define untagged_addr(addr) \ - ((__typeof__(addr))sign_extend64((u64)(addr), 55)) + ((__force __typeof__(addr))sign_extend64((__force u64)(addr), 55)) #ifdef CONFIG_KASAN_SW_TAGS #define __tag_shifted(tag) ((u64)(tag) << 56) -#define __tag_set(addr, tag) (__typeof__(addr))( \ - ((u64)(addr) & ~__tag_shifted(0xff)) | __tag_shifted(tag)) #define __tag_reset(addr) untagged_addr(addr) #define __tag_get(addr) (__u8)((u64)(addr) >> 56) #else +#define __tag_shifted(tag) 0UL +#define __tag_reset(addr) (addr) +#define __tag_get(addr) 0 +#endif /* CONFIG_KASAN_SW_TAGS */ + static inline const void *__tag_set(const void *addr, u8 tag) { - return addr; + u64 __addr = (u64)addr & ~__tag_shifted(0xff); + return (const void *)(__addr | __tag_shifted(tag)); } -#define __tag_reset(addr) (addr) -#define __tag_get(addr) 0 -#endif - /* * Physical vs virtual RAM address space conversion. These are * private definitions which should NOT be used outside memory.h @@ -227,19 +242,18 @@ static inline const void *__tag_set(const void *addr, u8 tag) /* - * The linear kernel range starts in the middle of the virtual adddress + * The linear kernel range starts at the bottom of the virtual address * space. Testing the top bit for the start of the region is a - * sufficient check. + * sufficient check and avoids having to worry about the tag. */ -#define __is_lm_address(addr) (!!((addr) & BIT(VA_BITS - 1))) +#define __is_lm_address(addr) (!(((u64)addr) & BIT(vabits_actual - 1))) -#define __lm_to_phys(addr) (((addr) & ~PAGE_OFFSET) + PHYS_OFFSET) +#define __lm_to_phys(addr) (((addr) + physvirt_offset)) #define __kimg_to_phys(addr) ((addr) - kimage_voffset) #define __virt_to_phys_nodebug(x) ({ \ - phys_addr_t __x = (phys_addr_t)(x); \ - __is_lm_address(__x) ? __lm_to_phys(__x) : \ - __kimg_to_phys(__x); \ + phys_addr_t __x = (phys_addr_t)(__tag_reset(x)); \ + __is_lm_address(__x) ? __lm_to_phys(__x) : __kimg_to_phys(__x); \ }) #define __pa_symbol_nodebug(x) __kimg_to_phys((phys_addr_t)(x)) @@ -250,9 +264,9 @@ extern phys_addr_t __phys_addr_symbol(unsigned long x); #else #define __virt_to_phys(x) __virt_to_phys_nodebug(x) #define __phys_addr_symbol(x) __pa_symbol_nodebug(x) -#endif +#endif /* CONFIG_DEBUG_VIRTUAL */ -#define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET) +#define __phys_to_virt(x) ((unsigned long)((x) - physvirt_offset)) #define __phys_to_kimg(x) ((unsigned long)((x) + kimage_voffset)) /* @@ -286,41 +300,38 @@ static inline void *phys_to_virt(phys_addr_t x) #define __pa_nodebug(x) __virt_to_phys_nodebug((unsigned long)(x)) #define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) -#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)) +#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)) /* - * virt_to_page(k) convert a _valid_ virtual address to struct page * - * virt_addr_valid(k) indicates whether a virtual address is valid + * virt_to_page(x) convert a _valid_ virtual address to struct page * + * virt_addr_valid(x) indicates whether a virtual address is valid */ #define ARCH_PFN_OFFSET ((unsigned long)PHYS_PFN_OFFSET) #if !defined(CONFIG_SPARSEMEM_VMEMMAP) || defined(CONFIG_DEBUG_VIRTUAL) -#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) -#define _virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) +#define virt_to_page(x) pfn_to_page(virt_to_pfn(x)) #else -#define __virt_to_pgoff(kaddr) (((u64)(kaddr) & ~PAGE_OFFSET) / PAGE_SIZE * sizeof(struct page)) -#define __page_to_voff(kaddr) (((u64)(kaddr) & ~VMEMMAP_START) * PAGE_SIZE / sizeof(struct page)) - -#define page_to_virt(page) ({ \ - unsigned long __addr = \ - ((__page_to_voff(page)) | PAGE_OFFSET); \ - const void *__addr_tag = \ - __tag_set((void *)__addr, page_kasan_tag(page)); \ - ((void *)__addr_tag); \ +#define page_to_virt(x) ({ \ + __typeof__(x) __page = x; \ + u64 __idx = ((u64)__page - VMEMMAP_START) / sizeof(struct page);\ + u64 __addr = PAGE_OFFSET + (__idx * PAGE_SIZE); \ + (void *)__tag_set((const void *)__addr, page_kasan_tag(__page));\ }) -#define virt_to_page(vaddr) ((struct page *)((__virt_to_pgoff(vaddr)) | VMEMMAP_START)) +#define virt_to_page(x) ({ \ + u64 __idx = (__tag_reset((u64)x) - PAGE_OFFSET) / PAGE_SIZE; \ + u64 __addr = VMEMMAP_START + (__idx * sizeof(struct page)); \ + (struct page *)__addr; \ +}) +#endif /* !CONFIG_SPARSEMEM_VMEMMAP || CONFIG_DEBUG_VIRTUAL */ -#define _virt_addr_valid(kaddr) pfn_valid((((u64)(kaddr) & ~PAGE_OFFSET) \ - + PHYS_OFFSET) >> PAGE_SHIFT) -#endif -#endif +#define virt_addr_valid(addr) ({ \ + __typeof__(addr) __addr = addr; \ + __is_lm_address(__addr) && pfn_valid(virt_to_pfn(__addr)); \ +}) -#define _virt_addr_is_linear(kaddr) \ - (__tag_reset((u64)(kaddr)) >= PAGE_OFFSET) -#define virt_addr_valid(kaddr) \ - (_virt_addr_is_linear(kaddr) && _virt_addr_valid(kaddr)) +#endif /* !ASSEMBLY */ /* * Given that the GIC architecture permits ITS implementations that can only be @@ -335,4 +346,4 @@ static inline void *phys_to_virt(phys_addr_t x) #include -#endif +#endif /* __ASM_MEMORY_H */ diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index fd6161336653664f0c0d1fa297c63e6f3c884cab..f217e32929193114d0cf8e5f85fd0bff35ba9cfe 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -126,7 +126,7 @@ extern void init_mem_pgprot(void); extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot, bool page_mappings_only); -extern void *fixmap_remap_fdt(phys_addr_t dt_phys); +extern void *fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot); extern void mark_linear_text_alias_ro(void); #define INIT_MM_CONTEXT(name) \ diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h index 7ed0adb187a8aa06320dc44402a5dfe31a7d97b2..3827ff4040a3f71da95de705ac5e905b25b8a15d 100644 --- a/arch/arm64/include/asm/mmu_context.h +++ b/arch/arm64/include/asm/mmu_context.h @@ -63,7 +63,7 @@ extern u64 idmap_ptrs_per_pgd; static inline bool __cpu_uses_extended_idmap(void) { - if (IS_ENABLED(CONFIG_ARM64_USER_VA_BITS_52)) + if (IS_ENABLED(CONFIG_ARM64_VA_BITS_52)) return false; return unlikely(idmap_t0sz != TCR_T0SZ(VA_BITS)); @@ -95,7 +95,7 @@ static inline void __cpu_set_tcr_t0sz(unsigned long t0sz) isb(); } -#define cpu_set_default_tcr_t0sz() __cpu_set_tcr_t0sz(TCR_T0SZ(VA_BITS)) +#define cpu_set_default_tcr_t0sz() __cpu_set_tcr_t0sz(TCR_T0SZ(vabits_actual)) #define cpu_set_idmap_tcr_t0sz() __cpu_set_tcr_t0sz(idmap_t0sz) /* diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h index 9e690686e8aad3fac10fd838dc75d8b7e77a8cde..70b323cf83000d51c1d823c5f4c8eb8fe47bebda 100644 --- a/arch/arm64/include/asm/pci.h +++ b/arch/arm64/include/asm/pci.h @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __ASM_PCI_H #define __ASM_PCI_H -#ifdef __KERNEL__ #include #include @@ -35,5 +34,4 @@ static inline int pci_proc_domain(struct pci_bus *bus) } #endif /* CONFIG_PCI */ -#endif /* __KERNEL__ */ #endif /* __ASM_PCI_H */ diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h index db92950bb1a0f3a888069643dded8af7e41d6282..3df60f97da1f2c86d3287ac02c1122d46ea1ef24 100644 --- a/arch/arm64/include/asm/pgtable-hwdef.h +++ b/arch/arm64/include/asm/pgtable-hwdef.h @@ -304,7 +304,7 @@ #define TTBR_BADDR_MASK_52 (((UL(1) << 46) - 1) << 2) #endif -#ifdef CONFIG_ARM64_USER_VA_BITS_52 +#ifdef CONFIG_ARM64_VA_BITS_52 /* Must be at least 64-byte aligned to prevent corruption of the TTBR */ #define TTBR1_BADDR_4852_OFFSET (((UL(1) << (52 - PGDIR_SHIFT)) - \ (UL(1) << (48 - PGDIR_SHIFT))) * 8) diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h index 92d2e9f28f28c74afe33cfda6d8c4c12d8de1015..9a21b84536f2e04bdf0698e20dc52aa81d952783 100644 --- a/arch/arm64/include/asm/pgtable-prot.h +++ b/arch/arm64/include/asm/pgtable-prot.h @@ -77,7 +77,7 @@ }) #define PAGE_S2 __pgprot(_PROT_DEFAULT | PAGE_S2_MEMATTR(NORMAL) | PTE_S2_RDONLY | PAGE_S2_XN) -#define PAGE_S2_DEVICE __pgprot(_PROT_DEFAULT | PAGE_S2_MEMATTR(DEVICE_nGnRE) | PTE_S2_RDONLY | PAGE_S2_XN) +#define PAGE_S2_DEVICE __pgprot(_PROT_DEFAULT | PAGE_S2_MEMATTR(DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_S2_XN) #define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN) #define PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE) diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index e09760ece844fe55cbd39dc8c32910a7bfdb6708..470ba7ae88218272c2567e5fb22197d4ea06e8b6 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -21,9 +21,7 @@ * and fixed mappings */ #define VMALLOC_START (MODULES_END) -#define VMALLOC_END (PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - SZ_64K) - -#define vmemmap ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT)) +#define VMALLOC_END (- PUD_SIZE - VMEMMAP_SIZE - SZ_64K) #define FIRST_USER_ADDRESS 0UL @@ -35,6 +33,8 @@ #include #include +extern struct page *vmemmap; + extern void __pte_error(const char *file, int line, unsigned long val); extern void __pmd_error(const char *file, int line, unsigned long val); extern void __pud_error(const char *file, int line, unsigned long val); @@ -220,8 +220,10 @@ static inline void set_pte(pte_t *ptep, pte_t pte) * Only if the new pte is valid and kernel, otherwise TLB maintenance * or update_mmu_cache() have the necessary barriers. */ - if (pte_valid_not_user(pte)) + if (pte_valid_not_user(pte)) { dsb(ishst); + isb(); + } } extern void __sync_icache_dcache(pte_t pteval); @@ -484,8 +486,10 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) WRITE_ONCE(*pmdp, pmd); - if (pmd_valid(pmd)) + if (pmd_valid(pmd)) { dsb(ishst); + isb(); + } } static inline void pmd_clear(pmd_t *pmdp) @@ -543,8 +547,10 @@ static inline void set_pud(pud_t *pudp, pud_t pud) WRITE_ONCE(*pudp, pud); - if (pud_valid(pud)) + if (pud_valid(pud)) { dsb(ishst); + isb(); + } } static inline void pud_clear(pud_t *pudp) @@ -602,6 +608,7 @@ static inline void set_pgd(pgd_t *pgdp, pgd_t pgd) WRITE_ONCE(*pgdp, pgd); dsb(ishst); + isb(); } static inline void pgd_clear(pgd_t *pgdp) @@ -859,8 +866,8 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, #define update_mmu_cache_pmd(vma, address, pmd) do { } while (0) -#define kc_vaddr_to_offset(v) ((v) & ~VA_START) -#define kc_offset_to_vaddr(o) ((o) | VA_START) +#define kc_vaddr_to_offset(v) ((v) & ~PAGE_END) +#define kc_offset_to_vaddr(o) ((o) | PAGE_END) #ifdef CONFIG_ARM64_PA_BITS_52 #define phys_to_ttbr(addr) (((addr) | ((addr) >> 46)) & TTBR_BADDR_MASK_52) diff --git a/arch/arm64/include/asm/pointer_auth.h b/arch/arm64/include/asm/pointer_auth.h index d328540cb85edc5f272190e3d36481b4c1987694..7a24bad1a58b89a38390eabf909515082a3b9aaa 100644 --- a/arch/arm64/include/asm/pointer_auth.h +++ b/arch/arm64/include/asm/pointer_auth.h @@ -69,7 +69,7 @@ extern int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg); * The EL0 pointer bits used by a pointer authentication code. * This is dependent on TBI0 being enabled, or bits 63:56 would also apply. */ -#define ptrauth_user_pac_mask() GENMASK(54, vabits_user) +#define ptrauth_user_pac_mask() GENMASK(54, vabits_actual) /* Only valid for EL0 TTBR0 instruction pointers */ static inline unsigned long ptrauth_strip_insn_pac(unsigned long ptr) diff --git a/arch/arm64/include/asm/proc-fns.h b/arch/arm64/include/asm/proc-fns.h index 368d90a9d0e5fa893f53bad7f34e54ec33ab3353..a2ce65a0c1fa9d539e1f38a73d18ae11537f7b27 100644 --- a/arch/arm64/include/asm/proc-fns.h +++ b/arch/arm64/include/asm/proc-fns.h @@ -9,7 +9,6 @@ #ifndef __ASM_PROCFNS_H #define __ASM_PROCFNS_H -#ifdef __KERNEL__ #ifndef __ASSEMBLY__ #include @@ -25,5 +24,4 @@ extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr); #include #endif /* __ASSEMBLY__ */ -#endif /* __KERNEL__ */ #endif /* __ASM_PROCFNS_H */ diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index 844e2964b0f5e5b0aad4b866283f24e26f794afe..c67848c55009d9744ff68deea54eb58844d1c7f1 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -20,7 +20,6 @@ #define NET_IP_ALIGN 0 #ifndef __ASSEMBLY__ -#ifdef __KERNEL__ #include #include @@ -42,8 +41,8 @@ * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area. */ -#define DEFAULT_MAP_WINDOW_64 (UL(1) << VA_BITS) -#define TASK_SIZE_64 (UL(1) << vabits_user) +#define DEFAULT_MAP_WINDOW_64 (UL(1) << VA_BITS_MIN) +#define TASK_SIZE_64 (UL(1) << vabits_actual) #ifdef CONFIG_COMPAT #if defined(CONFIG_ARM64_64K_PAGES) && defined(CONFIG_KUSER_HELPERS) @@ -283,8 +282,6 @@ static inline void spin_lock_prefetch(const void *ptr) #define HAVE_ARCH_PICK_MMAP_LAYOUT -#endif - extern unsigned long __ro_after_init signal_minsigstksz; /* sigframe size */ extern void __init minsigstksz_setup(void); @@ -306,6 +303,14 @@ extern void __init minsigstksz_setup(void); /* PR_PAC_RESET_KEYS prctl */ #define PAC_RESET_KEYS(tsk, arg) ptrauth_prctl_reset_keys(tsk, arg) +#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI +/* PR_{SET,GET}_TAGGED_ADDR_CTRL prctl */ +long set_tagged_addr_ctrl(unsigned long arg); +long get_tagged_addr_ctrl(void); +#define SET_TAGGED_ADDR_CTRL(arg) set_tagged_addr_ctrl(arg) +#define GET_TAGGED_ADDR_CTRL() get_tagged_addr_ctrl() +#endif + /* * For CONFIG_GCC_PLUGIN_STACKLEAK * diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h index 1dcf63a9ac1f313975f7fd318f783acd3f21147c..fbebb411ae202c1ea22acaaf5a666fe79c7a63fe 100644 --- a/arch/arm64/include/asm/ptrace.h +++ b/arch/arm64/include/asm/ptrace.h @@ -301,6 +301,11 @@ static inline unsigned long regs_return_value(struct pt_regs *regs) return regs->regs[0]; } +static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc) +{ + regs->regs[0] = rc; +} + /** * regs_get_kernel_argument() - get Nth function argument in kernel * @regs: pt_regs of that context diff --git a/arch/arm64/include/asm/signal32.h b/arch/arm64/include/asm/signal32.h index bd43d1cf724b175f1bc187bf83554492402cefa7..7e9f163d02ecad97d4df2992395bce32bdef2375 100644 --- a/arch/arm64/include/asm/signal32.h +++ b/arch/arm64/include/asm/signal32.h @@ -5,7 +5,6 @@ #ifndef __ASM_SIGNAL32_H #define __ASM_SIGNAL32_H -#ifdef __KERNEL__ #ifdef CONFIG_COMPAT #include @@ -79,5 +78,4 @@ static inline void compat_setup_restart_syscall(struct pt_regs *regs) { } #endif /* CONFIG_COMPAT */ -#endif /* __KERNEL__ */ #endif /* __ASM_SIGNAL32_H */ diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 06ebcfef73df965dfaa9b2bda97946218b6711d0..972d196c7714689ab46d22b6366453b7e018c721 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -212,6 +212,9 @@ #define SYS_FAR_EL1 sys_reg(3, 0, 6, 0, 0) #define SYS_PAR_EL1 sys_reg(3, 0, 7, 4, 0) +#define SYS_PAR_EL1_F BIT(1) +#define SYS_PAR_EL1_FST GENMASK(6, 1) + /*** Statistical Profiling Extension ***/ /* ID registers */ #define SYS_PMSIDR_EL1 sys_reg(3, 0, 9, 9, 7) @@ -499,28 +502,11 @@ #define SCTLR_EL2_RES1 ((BIT(4)) | (BIT(5)) | (BIT(11)) | (BIT(16)) | \ (BIT(18)) | (BIT(22)) | (BIT(23)) | (BIT(28)) | \ (BIT(29))) -#define SCTLR_EL2_RES0 ((BIT(6)) | (BIT(7)) | (BIT(8)) | (BIT(9)) | \ - (BIT(10)) | (BIT(13)) | (BIT(14)) | (BIT(15)) | \ - (BIT(17)) | (BIT(20)) | (BIT(24)) | (BIT(26)) | \ - (BIT(27)) | (BIT(30)) | (BIT(31)) | \ - (0xffffefffUL << 32)) #ifdef CONFIG_CPU_BIG_ENDIAN #define ENDIAN_SET_EL2 SCTLR_ELx_EE -#define ENDIAN_CLEAR_EL2 0 #else #define ENDIAN_SET_EL2 0 -#define ENDIAN_CLEAR_EL2 SCTLR_ELx_EE -#endif - -/* SCTLR_EL2 value used for the hyp-stub */ -#define SCTLR_EL2_SET (SCTLR_ELx_IESB | ENDIAN_SET_EL2 | SCTLR_EL2_RES1) -#define SCTLR_EL2_CLEAR (SCTLR_ELx_M | SCTLR_ELx_A | SCTLR_ELx_C | \ - SCTLR_ELx_SA | SCTLR_ELx_I | SCTLR_ELx_WXN | \ - SCTLR_ELx_DSSBS | ENDIAN_CLEAR_EL2 | SCTLR_EL2_RES0) - -#if (SCTLR_EL2_SET ^ SCTLR_EL2_CLEAR) != 0xffffffffffffffffUL -#error "Inconsistent SCTLR_EL2 set/clear bits" #endif /* SCTLR_EL1 specific flags. */ @@ -539,16 +525,11 @@ #define SCTLR_EL1_RES1 ((BIT(11)) | (BIT(20)) | (BIT(22)) | (BIT(28)) | \ (BIT(29))) -#define SCTLR_EL1_RES0 ((BIT(6)) | (BIT(10)) | (BIT(13)) | (BIT(17)) | \ - (BIT(27)) | (BIT(30)) | (BIT(31)) | \ - (0xffffefffUL << 32)) #ifdef CONFIG_CPU_BIG_ENDIAN #define ENDIAN_SET_EL1 (SCTLR_EL1_E0E | SCTLR_ELx_EE) -#define ENDIAN_CLEAR_EL1 0 #else #define ENDIAN_SET_EL1 0 -#define ENDIAN_CLEAR_EL1 (SCTLR_EL1_E0E | SCTLR_ELx_EE) #endif #define SCTLR_EL1_SET (SCTLR_ELx_M | SCTLR_ELx_C | SCTLR_ELx_SA |\ @@ -556,13 +537,6 @@ SCTLR_EL1_DZE | SCTLR_EL1_UCT |\ SCTLR_EL1_NTWE | SCTLR_ELx_IESB | SCTLR_EL1_SPAN |\ ENDIAN_SET_EL1 | SCTLR_EL1_UCI | SCTLR_EL1_RES1) -#define SCTLR_EL1_CLEAR (SCTLR_ELx_A | SCTLR_EL1_CP15BEN | SCTLR_EL1_ITD |\ - SCTLR_EL1_UMA | SCTLR_ELx_WXN | ENDIAN_CLEAR_EL1 |\ - SCTLR_ELx_DSSBS | SCTLR_EL1_NTWI | SCTLR_EL1_RES0) - -#if (SCTLR_EL1_SET ^ SCTLR_EL1_CLEAR) != 0xffffffffffffffffUL -#error "Inconsistent SCTLR_EL1 set/clear bits" -#endif /* id_aa64isar0 */ #define ID_AA64ISAR0_TS_SHIFT 52 diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index 180b34ec59650a9bcbca37ae4c7fbba373251e09..f0cec4160136e9cc62233ee43b01bb152fe5891c 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -8,8 +8,6 @@ #ifndef __ASM_THREAD_INFO_H #define __ASM_THREAD_INFO_H -#ifdef __KERNEL__ - #include #ifndef __ASSEMBLY__ @@ -59,29 +57,18 @@ void arch_release_task_struct(struct task_struct *tsk); #endif -/* - * thread information flags: - * TIF_SYSCALL_TRACE - syscall trace active - * TIF_SYSCALL_TRACEPOINT - syscall tracepoint for ftrace - * TIF_SYSCALL_AUDIT - syscall auditing - * TIF_SECCOMP - syscall secure computing - * TIF_SYSCALL_EMU - syscall emulation active - * TIF_SIGPENDING - signal pending - * TIF_NEED_RESCHED - rescheduling necessary - * TIF_NOTIFY_RESUME - callback before returning to user - */ -#define TIF_SIGPENDING 0 -#define TIF_NEED_RESCHED 1 +#define TIF_SIGPENDING 0 /* signal pending */ +#define TIF_NEED_RESCHED 1 /* rescheduling necessary */ #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ #define TIF_FOREIGN_FPSTATE 3 /* CPU's FP state is not current's */ #define TIF_UPROBE 4 /* uprobe breakpoint or singlestep */ #define TIF_FSCHECK 5 /* Check FS is USER_DS on return */ #define TIF_NOHZ 7 -#define TIF_SYSCALL_TRACE 8 -#define TIF_SYSCALL_AUDIT 9 -#define TIF_SYSCALL_TRACEPOINT 10 -#define TIF_SECCOMP 11 -#define TIF_SYSCALL_EMU 12 +#define TIF_SYSCALL_TRACE 8 /* syscall trace active */ +#define TIF_SYSCALL_AUDIT 9 /* syscall auditing */ +#define TIF_SYSCALL_TRACEPOINT 10 /* syscall tracepoint for ftrace */ +#define TIF_SECCOMP 11 /* syscall secure computing */ +#define TIF_SYSCALL_EMU 12 /* syscall emulation active */ #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ #define TIF_FREEZE 19 #define TIF_RESTORE_SIGMASK 20 @@ -90,6 +77,7 @@ void arch_release_task_struct(struct task_struct *tsk); #define TIF_SVE 23 /* Scalable Vector Extension in use */ #define TIF_SVE_VL_INHERIT 24 /* Inherit sve_vl_onexec across exec */ #define TIF_SSBD 25 /* Wants SSB mitigation */ +#define TIF_TAGGED_ADDR 26 /* Allow tagged user addresses */ #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) @@ -121,5 +109,4 @@ void arch_release_task_struct(struct task_struct *tsk); .addr_limit = KERNEL_DS, \ } -#endif /* __KERNEL__ */ #endif /* __ASM_THREAD_INFO_H */ diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h index 8af7a85f76bdb0b61637d5f4b18bb976d487820d..bc39490647259aeaf54c6bc9645dbaea3d07bd4f 100644 --- a/arch/arm64/include/asm/tlbflush.h +++ b/arch/arm64/include/asm/tlbflush.h @@ -251,6 +251,7 @@ static inline void __flush_tlb_kernel_pgtable(unsigned long kaddr) dsb(ishst); __tlbi(vaae1is, addr); dsb(ish); + isb(); } #endif diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h index 0524f243864931087c1227fc3b8cf970d471ce5b..a4d945db95a299f5f2c733d7cc4aa931ace67ed0 100644 --- a/arch/arm64/include/asm/topology.h +++ b/arch/arm64/include/asm/topology.h @@ -4,29 +4,6 @@ #include -struct cpu_topology { - int thread_id; - int core_id; - int package_id; - int llc_id; - cpumask_t thread_sibling; - cpumask_t core_sibling; - cpumask_t llc_sibling; -}; - -extern struct cpu_topology cpu_topology[NR_CPUS]; - -#define topology_physical_package_id(cpu) (cpu_topology[cpu].package_id) -#define topology_core_id(cpu) (cpu_topology[cpu].core_id) -#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling) -#define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_sibling) -#define topology_llc_cpumask(cpu) (&cpu_topology[cpu].llc_sibling) - -void init_cpu_topology(void); -void store_cpu_topology(unsigned int cpuid); -void remove_cpu_topology(unsigned int cpuid); -const struct cpumask *cpu_coregroup_mask(int cpu); - #ifdef CONFIG_NUMA struct pci_bus; diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 5a1c32260c1f6885e2c4215828296343b3892ffb..097d6bfac0b74b93b842959d724d67d3cf8cd8a3 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -62,6 +62,10 @@ static inline unsigned long __range_ok(const void __user *addr, unsigned long si { unsigned long ret, limit = current_thread_info()->addr_limit; + if (IS_ENABLED(CONFIG_ARM64_TAGGED_ADDR_ABI) && + test_thread_flag(TIF_TAGGED_ADDR)) + addr = untagged_addr(addr); + __chk_user_ptr(addr); asm volatile( // A + B <= C + 1 for all A,B,C, in four easy steps: @@ -215,7 +219,8 @@ static inline void uaccess_enable_not_uao(void) /* * Sanitise a uaccess pointer such that it becomes NULL if above the - * current addr_limit. + * current addr_limit. In case the pointer is tagged (has the top byte set), + * untag the pointer before checking. */ #define uaccess_mask_ptr(ptr) (__typeof__(ptr))__uaccess_mask_ptr(ptr) static inline void __user *__uaccess_mask_ptr(const void __user *ptr) @@ -223,10 +228,11 @@ static inline void __user *__uaccess_mask_ptr(const void __user *ptr) void __user *safe_ptr; asm volatile( - " bics xzr, %1, %2\n" + " bics xzr, %3, %2\n" " csel %0, %1, xzr, eq\n" : "=&r" (safe_ptr) - : "r" (ptr), "r" (current_thread_info()->addr_limit) + : "r" (ptr), "r" (current_thread_info()->addr_limit), + "r" (untagged_addr(ptr)) : "cc"); csdb(); diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h index 9c15e0a063017ad27677b958b85c36ce329873d3..07468428fd2907a6e9453e840da0d95694fcf541 100644 --- a/arch/arm64/include/asm/vdso.h +++ b/arch/arm64/include/asm/vdso.h @@ -5,8 +5,6 @@ #ifndef __ASM_VDSO_H #define __ASM_VDSO_H -#ifdef __KERNEL__ - /* * Default link address for the vDSO. * Since we randomise the VDSO mapping, there's little point in trying @@ -28,6 +26,4 @@ #endif /* !__ASSEMBLY__ */ -#endif /* __KERNEL__ */ - #endif /* __ASM_VDSO_H */ diff --git a/arch/arm64/include/asm/vdso_datapage.h b/arch/arm64/include/asm/vdso_datapage.h index ba6dbc3de86480129727fda5fa150ee5b1df2f30..1f38bf330a6efe4d89803b7a86c4417f3cf33862 100644 --- a/arch/arm64/include/asm/vdso_datapage.h +++ b/arch/arm64/include/asm/vdso_datapage.h @@ -5,8 +5,6 @@ #ifndef __ASM_VDSO_DATAPAGE_H #define __ASM_VDSO_DATAPAGE_H -#ifdef __KERNEL__ - #ifndef __ASSEMBLY__ struct vdso_data { @@ -32,6 +30,4 @@ struct vdso_data { #endif /* !__ASSEMBLY__ */ -#endif /* __KERNEL__ */ - #endif /* __ASM_VDSO_DATAPAGE_H */ diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 9a507716ae2fe723624d7c7de3c1b88501d5f9a3..67c21f9bdbad2556be4114dfa09b8006a11e708e 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -325,8 +325,10 @@ struct kvm_vcpu_events { #define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1 /* KVM_IRQ_LINE irq field index values */ +#define KVM_ARM_IRQ_VCPU2_SHIFT 28 +#define KVM_ARM_IRQ_VCPU2_MASK 0xf #define KVM_ARM_IRQ_TYPE_SHIFT 24 -#define KVM_ARM_IRQ_TYPE_MASK 0xff +#define KVM_ARM_IRQ_TYPE_MASK 0xf #define KVM_ARM_IRQ_VCPU_SHIFT 16 #define KVM_ARM_IRQ_VCPU_MASK 0xff #define KVM_ARM_IRQ_NUM_SHIFT 0 diff --git a/arch/arm64/include/uapi/asm/stat.h b/arch/arm64/include/uapi/asm/stat.h deleted file mode 100644 index 313325fa22fa7c4ae24e7327b4ce9c1a5f5be199..0000000000000000000000000000000000000000 --- a/arch/arm64/include/uapi/asm/stat.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright (C) 2012 ARM Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index b1fdc486aed8239c681acdcab1d98550bbdf60d9..9323bcc40a58a7c34d2ec502c35fad4633a5d118 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -894,7 +894,7 @@ static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry, int _ u32 midr = read_cpuid_id(); /* Cavium ThunderX pass 1.x and 2.x */ - return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX, + return midr_is_cpu_model_range(midr, MIDR_THUNDERX, MIDR_CPU_VAR_REV(0, 0), MIDR_CPU_VAR_REV(1, MIDR_REVISION_MASK)); } diff --git a/arch/arm64/kernel/cpuidle.c b/arch/arm64/kernel/cpuidle.c index d1048173fd8a1bdcf77b607def93b4d629dae71c..e4d6af2fdec716ae36028f8e060dda92fb5127d2 100644 --- a/arch/arm64/kernel/cpuidle.c +++ b/arch/arm64/kernel/cpuidle.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -46,17 +47,58 @@ int arm_cpuidle_suspend(int index) #define ARM64_LPI_IS_RETENTION_STATE(arch_flags) (!(arch_flags)) +static int psci_acpi_cpu_init_idle(unsigned int cpu) +{ + int i, count; + struct acpi_lpi_state *lpi; + struct acpi_processor *pr = per_cpu(processors, cpu); + + /* + * If the PSCI cpu_suspend function hook has not been initialized + * idle states must not be enabled, so bail out + */ + if (!psci_ops.cpu_suspend) + return -EOPNOTSUPP; + + if (unlikely(!pr || !pr->flags.has_lpi)) + return -EINVAL; + + count = pr->power.count - 1; + if (count <= 0) + return -ENODEV; + + for (i = 0; i < count; i++) { + u32 state; + + lpi = &pr->power.lpi_states[i + 1]; + /* + * Only bits[31:0] represent a PSCI power_state while + * bits[63:32] must be 0x0 as per ARM ACPI FFH Specification + */ + state = lpi->address; + if (!psci_power_state_is_valid(state)) { + pr_warn("Invalid PSCI power state %#x\n", state); + return -EINVAL; + } + } + + return 0; +} + int acpi_processor_ffh_lpi_probe(unsigned int cpu) { - return arm_cpuidle_init(cpu); + return psci_acpi_cpu_init_idle(cpu); } int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi) { + u32 state = lpi->address; + if (ARM64_LPI_IS_RETENTION_STATE(lpi->arch_flags)) - return CPU_PM_CPU_IDLE_ENTER_RETENTION(arm_cpuidle_suspend, - lpi->index); + return CPU_PM_CPU_IDLE_ENTER_RETENTION_PARAM(psci_cpu_suspend_enter, + lpi->index, state); else - return CPU_PM_CPU_IDLE_ENTER(arm_cpuidle_suspend, lpi->index); + return CPU_PM_CPU_IDLE_ENTER_PARAM(psci_cpu_suspend_enter, + lpi->index, state); } #endif diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index 876055e373525999e1775dbd2a1bc482c9359b62..05933c065732b8cc5dac245d2baea0f1ccd4147f 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -33,7 +33,7 @@ DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data); static struct cpuinfo_arm64 boot_cpu_data; -static char *icache_policy_str[] = { +static const char *icache_policy_str[] = { [0 ... ICACHE_POLICY_PIPT] = "RESERVED/UNKNOWN", [ICACHE_POLICY_VIPT] = "VIPT", [ICACHE_POLICY_PIPT] = "PIPT", diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 320a30dbe35efb02e4f7d5bd52c82189e1f4400c..84a822748c84e58c85fc19a62d63053b97f0b2c2 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -30,9 +30,9 @@ * Context tracking subsystem. Used to instrument transitions * between user and kernel mode. */ - .macro ct_user_exit + .macro ct_user_exit_irqoff #ifdef CONFIG_CONTEXT_TRACKING - bl context_tracking_user_exit + bl enter_from_user_mode #endif .endm @@ -792,8 +792,8 @@ el0_cp15: /* * Trapped CP15 (MRC, MCR, MRRC, MCRR) instructions */ + ct_user_exit_irqoff enable_daif - ct_user_exit mov x0, x25 mov x1, sp bl do_cp15instr @@ -805,8 +805,8 @@ el0_da: * Data abort handling */ mrs x26, far_el1 + ct_user_exit_irqoff enable_daif - ct_user_exit clear_address_tag x0, x26 mov x1, x25 mov x2, sp @@ -818,11 +818,11 @@ el0_ia: */ mrs x26, far_el1 gic_prio_kentry_setup tmp=x0 + ct_user_exit_irqoff enable_da_f #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_off #endif - ct_user_exit mov x0, x26 mov x1, x25 mov x2, sp @@ -832,8 +832,8 @@ el0_fpsimd_acc: /* * Floating Point or Advanced SIMD access */ + ct_user_exit_irqoff enable_daif - ct_user_exit mov x0, x25 mov x1, sp bl do_fpsimd_acc @@ -842,8 +842,8 @@ el0_sve_acc: /* * Scalable Vector Extension access */ + ct_user_exit_irqoff enable_daif - ct_user_exit mov x0, x25 mov x1, sp bl do_sve_acc @@ -852,8 +852,8 @@ el0_fpsimd_exc: /* * Floating Point, Advanced SIMD or SVE exception */ + ct_user_exit_irqoff enable_daif - ct_user_exit mov x0, x25 mov x1, sp bl do_fpsimd_exc @@ -868,11 +868,11 @@ el0_sp_pc: * Stack or PC alignment exception handling */ gic_prio_kentry_setup tmp=x0 + ct_user_exit_irqoff enable_da_f #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_off #endif - ct_user_exit mov x0, x26 mov x1, x25 mov x2, sp @@ -882,8 +882,8 @@ el0_undef: /* * Undefined instruction */ + ct_user_exit_irqoff enable_daif - ct_user_exit mov x0, sp bl do_undefinstr b ret_to_user @@ -891,8 +891,8 @@ el0_sys: /* * System instructions, for trapped cache maintenance instructions */ + ct_user_exit_irqoff enable_daif - ct_user_exit mov x0, x25 mov x1, sp bl do_sysinstr @@ -902,17 +902,18 @@ el0_dbg: * Debug exception handling */ tbnz x24, #0, el0_inv // EL0 only + mrs x24, far_el1 gic_prio_kentry_setup tmp=x3 - mrs x0, far_el1 + ct_user_exit_irqoff + mov x0, x24 mov x1, x25 mov x2, sp bl do_debug_exception enable_da_f - ct_user_exit b ret_to_user el0_inv: + ct_user_exit_irqoff enable_daif - ct_user_exit mov x0, sp mov x1, #BAD_SYNC mov x2, x25 @@ -925,13 +926,13 @@ el0_irq: kernel_entry 0 el0_irq_naked: gic_prio_irq_setup pmr=x20, tmp=x0 + ct_user_exit_irqoff enable_da_f #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_off #endif - ct_user_exit #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR tbz x22, #55, 1f bl do_el0_irq_bp_hardening @@ -958,13 +959,14 @@ ENDPROC(el1_error) el0_error: kernel_entry 0 el0_error_naked: - mrs x1, esr_el1 + mrs x25, esr_el1 gic_prio_kentry_setup tmp=x2 + ct_user_exit_irqoff enable_dbg mov x0, sp + mov x1, x25 bl do_serror enable_da_f - ct_user_exit b ret_to_user ENDPROC(el0_error) diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 2cdacd1c141b97295192e9685ffca9ef32765939..989b1944cb719bb5afcd1f4fe1547ba4e2511d4e 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -102,6 +102,8 @@ pe_header: * x23 stext() .. start_kernel() physical misalignment/KASLR offset * x28 __create_page_tables() callee preserved temp register * x19/x20 __primary_switch() callee preserved temp registers + * x24 __primary_switch() .. relocate_kernel() + * current RELR displacement */ ENTRY(stext) bl preserve_boot_args @@ -308,15 +310,15 @@ __create_page_tables: adrp x0, idmap_pg_dir adrp x3, __idmap_text_start // __pa(__idmap_text_start) -#ifdef CONFIG_ARM64_USER_VA_BITS_52 +#ifdef CONFIG_ARM64_VA_BITS_52 mrs_s x6, SYS_ID_AA64MMFR2_EL1 and x6, x6, #(0xf << ID_AA64MMFR2_LVA_SHIFT) mov x5, #52 cbnz x6, 1f #endif - mov x5, #VA_BITS + mov x5, #VA_BITS_MIN 1: - adr_l x6, vabits_user + adr_l x6, vabits_actual str x5, [x6] dmb sy dc ivac, x6 // Invalidate potentially stale cache line @@ -724,14 +726,22 @@ __secondary_switched: adr_l x0, secondary_data ldr x1, [x0, #CPU_BOOT_STACK] // get secondary_data.stack + cbz x1, __secondary_too_slow mov sp, x1 ldr x2, [x0, #CPU_BOOT_TASK] + cbz x2, __secondary_too_slow msr sp_el0, x2 mov x29, #0 mov x30, #0 b secondary_start_kernel ENDPROC(__secondary_switched) +__secondary_too_slow: + wfe + wfi + b __secondary_too_slow +ENDPROC(__secondary_too_slow) + /* * The booting CPU updates the failed status @__early_cpu_boot_status, * with MMU turned off. @@ -772,7 +782,7 @@ ENTRY(__enable_mmu) phys_to_ttbr x1, x1 phys_to_ttbr x2, x2 msr ttbr0_el1, x2 // load TTBR0 - offset_ttbr1 x1 + offset_ttbr1 x1, x3 msr ttbr1_el1, x1 // load TTBR1 isb msr sctlr_el1, x0 @@ -789,8 +799,8 @@ ENTRY(__enable_mmu) ENDPROC(__enable_mmu) ENTRY(__cpu_secondary_check52bitva) -#ifdef CONFIG_ARM64_USER_VA_BITS_52 - ldr_l x0, vabits_user +#ifdef CONFIG_ARM64_VA_BITS_52 + ldr_l x0, vabits_actual cmp x0, #52 b.ne 2f @@ -834,14 +844,93 @@ __relocate_kernel: 0: cmp x9, x10 b.hs 1f - ldp x11, x12, [x9], #24 - ldr x13, [x9, #-8] - cmp w12, #R_AARCH64_RELATIVE + ldp x12, x13, [x9], #24 + ldr x14, [x9, #-8] + cmp w13, #R_AARCH64_RELATIVE b.ne 0b - add x13, x13, x23 // relocate - str x13, [x11, x23] + add x14, x14, x23 // relocate + str x14, [x12, x23] b 0b -1: ret + +1: +#ifdef CONFIG_RELR + /* + * Apply RELR relocations. + * + * RELR is a compressed format for storing relative relocations. The + * encoded sequence of entries looks like: + * [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ] + * + * i.e. start with an address, followed by any number of bitmaps. The + * address entry encodes 1 relocation. The subsequent bitmap entries + * encode up to 63 relocations each, at subsequent offsets following + * the last address entry. + * + * The bitmap entries must have 1 in the least significant bit. The + * assumption here is that an address cannot have 1 in lsb. Odd + * addresses are not supported. Any odd addresses are stored in the RELA + * section, which is handled above. + * + * Excluding the least significant bit in the bitmap, each non-zero + * bit in the bitmap represents a relocation to be applied to + * a corresponding machine word that follows the base address + * word. The second least significant bit represents the machine + * word immediately following the initial address, and each bit + * that follows represents the next word, in linear order. As such, + * a single bitmap can encode up to 63 relocations in a 64-bit object. + * + * In this implementation we store the address of the next RELR table + * entry in x9, the address being relocated by the current address or + * bitmap entry in x13 and the address being relocated by the current + * bit in x14. + * + * Because addends are stored in place in the binary, RELR relocations + * cannot be applied idempotently. We use x24 to keep track of the + * currently applied displacement so that we can correctly relocate if + * __relocate_kernel is called twice with non-zero displacements (i.e. + * if there is both a physical misalignment and a KASLR displacement). + */ + ldr w9, =__relr_offset // offset to reloc table + ldr w10, =__relr_size // size of reloc table + add x9, x9, x11 // __va(.relr) + add x10, x9, x10 // __va(.relr) + sizeof(.relr) + + sub x15, x23, x24 // delta from previous offset + cbz x15, 7f // nothing to do if unchanged + mov x24, x23 // save new offset + +2: cmp x9, x10 + b.hs 7f + ldr x11, [x9], #8 + tbnz x11, #0, 3f // branch to handle bitmaps + add x13, x11, x23 + ldr x12, [x13] // relocate address entry + add x12, x12, x15 + str x12, [x13], #8 // adjust to start of bitmap + b 2b + +3: mov x14, x13 +4: lsr x11, x11, #1 + cbz x11, 6f + tbz x11, #0, 5f // skip bit if not set + ldr x12, [x14] // relocate bit + add x12, x12, x15 + str x12, [x14] + +5: add x14, x14, #8 // move to next bit's address + b 4b + +6: /* + * Move to the next bitmap's address. 8 is the word size, and 63 is the + * number of significant bits in a bitmap entry. + */ + add x13, x13, #(8 * 63) + b 2b + +7: +#endif + ret + ENDPROC(__relocate_kernel) #endif @@ -854,6 +943,9 @@ __primary_switch: adrp x1, init_pg_dir bl __enable_mmu #ifdef CONFIG_RELOCATABLE +#ifdef CONFIG_RELR + mov x24, #0 // no RELR displacement yet +#endif bl __relocate_kernel #ifdef CONFIG_RANDOMIZE_BASE ldr x8, =__primary_switched diff --git a/arch/arm64/kernel/hibernate-asm.S b/arch/arm64/kernel/hibernate-asm.S index 2f4a2ce7264b8f9c7441305727feca6b98259965..38bcd4d4e43bb1314f103f5ac477e1143c019240 100644 --- a/arch/arm64/kernel/hibernate-asm.S +++ b/arch/arm64/kernel/hibernate-asm.S @@ -22,14 +22,14 @@ * Even switching to our copied tables will cause a changed output address at * each stage of the walk. */ -.macro break_before_make_ttbr_switch zero_page, page_table, tmp +.macro break_before_make_ttbr_switch zero_page, page_table, tmp, tmp2 phys_to_ttbr \tmp, \zero_page msr ttbr1_el1, \tmp isb tlbi vmalle1 dsb nsh phys_to_ttbr \tmp, \page_table - offset_ttbr1 \tmp + offset_ttbr1 \tmp, \tmp2 msr ttbr1_el1, \tmp isb .endm @@ -70,7 +70,7 @@ ENTRY(swsusp_arch_suspend_exit) * We execute from ttbr0, change ttbr1 to our copied linear map tables * with a break-before-make via the zero page */ - break_before_make_ttbr_switch x5, x0, x6 + break_before_make_ttbr_switch x5, x0, x6, x8 mov x21, x1 mov x30, x2 @@ -101,7 +101,7 @@ ENTRY(swsusp_arch_suspend_exit) dsb ish /* wait for PoU cleaning to finish */ /* switch to the restored kernels page tables */ - break_before_make_ttbr_switch x25, x21, x6 + break_before_make_ttbr_switch x25, x21, x6, x8 ic ialluis dsb ish diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c index 9341fcc6e809bc678872fa4574666a85ada5ec6f..e0a7fce0e01c1d5533a6dd19fed7431dd3fa3ed5 100644 --- a/arch/arm64/kernel/hibernate.c +++ b/arch/arm64/kernel/hibernate.c @@ -496,7 +496,7 @@ int swsusp_arch_resume(void) rc = -ENOMEM; goto out; } - rc = copy_page_tables(tmp_pg_dir, PAGE_OFFSET, 0); + rc = copy_page_tables(tmp_pg_dir, PAGE_OFFSET, PAGE_END); if (rc) goto out; diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h new file mode 100644 index 0000000000000000000000000000000000000000..25a2a9b479c2f052174f9af5b26bb213ff35fac0 --- /dev/null +++ b/arch/arm64/kernel/image-vars.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Linker script variables to be set after section resolution, as + * ld.lld does not like variables assigned before SECTIONS is processed. + */ +#ifndef __ARM64_KERNEL_IMAGE_VARS_H +#define __ARM64_KERNEL_IMAGE_VARS_H + +#ifndef LINKER_SCRIPT +#error This file should only be included in vmlinux.lds.S +#endif + +#ifdef CONFIG_EFI + +__efistub_stext_offset = stext - _text; + +/* + * The EFI stub has its own symbol namespace prefixed by __efistub_, to + * isolate it from the kernel proper. The following symbols are legally + * accessed by the stub, so provide some aliases to make them accessible. + * Only include data symbols here, or text symbols of functions that are + * guaranteed to be safe when executed at another offset than they were + * linked at. The routines below are all implemented in assembler in a + * position independent manner + */ +__efistub_memcmp = __pi_memcmp; +__efistub_memchr = __pi_memchr; +__efistub_memcpy = __pi_memcpy; +__efistub_memmove = __pi_memmove; +__efistub_memset = __pi_memset; +__efistub_strlen = __pi_strlen; +__efistub_strnlen = __pi_strnlen; +__efistub_strcmp = __pi_strcmp; +__efistub_strncmp = __pi_strncmp; +__efistub_strrchr = __pi_strrchr; +__efistub___flush_dcache_area = __pi___flush_dcache_area; + +#ifdef CONFIG_KASAN +__efistub___memcpy = __pi_memcpy; +__efistub___memmove = __pi_memmove; +__efistub___memset = __pi_memset; +#endif + +__efistub__text = _text; +__efistub__end = _end; +__efistub__edata = _edata; +__efistub_screen_info = screen_info; + +#endif + +#endif /* __ARM64_KERNEL_IMAGE_VARS_H */ diff --git a/arch/arm64/kernel/image.h b/arch/arm64/kernel/image.h index 2b85c0d6fa3d12df5a471302f5facb3a2a1ee7c1..c7d38c660372c4a1494e35fac2a9d3a8b1c453e8 100644 --- a/arch/arm64/kernel/image.h +++ b/arch/arm64/kernel/image.h @@ -65,46 +65,4 @@ DEFINE_IMAGE_LE64(_kernel_offset_le, TEXT_OFFSET); \ DEFINE_IMAGE_LE64(_kernel_flags_le, __HEAD_FLAGS); -#ifdef CONFIG_EFI - -/* - * Use ABSOLUTE() to avoid ld.lld treating this as a relative symbol: - * https://github.com/ClangBuiltLinux/linux/issues/561 - */ -__efistub_stext_offset = ABSOLUTE(stext - _text); - -/* - * The EFI stub has its own symbol namespace prefixed by __efistub_, to - * isolate it from the kernel proper. The following symbols are legally - * accessed by the stub, so provide some aliases to make them accessible. - * Only include data symbols here, or text symbols of functions that are - * guaranteed to be safe when executed at another offset than they were - * linked at. The routines below are all implemented in assembler in a - * position independent manner - */ -__efistub_memcmp = __pi_memcmp; -__efistub_memchr = __pi_memchr; -__efistub_memcpy = __pi_memcpy; -__efistub_memmove = __pi_memmove; -__efistub_memset = __pi_memset; -__efistub_strlen = __pi_strlen; -__efistub_strnlen = __pi_strnlen; -__efistub_strcmp = __pi_strcmp; -__efistub_strncmp = __pi_strncmp; -__efistub_strrchr = __pi_strrchr; -__efistub___flush_dcache_area = __pi___flush_dcache_area; - -#ifdef CONFIG_KASAN -__efistub___memcpy = __pi_memcpy; -__efistub___memmove = __pi_memmove; -__efistub___memset = __pi_memset; -#endif - -__efistub__text = _text; -__efistub__end = _end; -__efistub__edata = _edata; -__efistub_screen_info = screen_info; - -#endif - #endif /* __ARM64_KERNEL_IMAGE_H */ diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c index 84b059ed04fc2b461ff7ba4e8182d4be4cd11012..d801a7094076e40b3dc1606d3b1b6f012f89dbf3 100644 --- a/arch/arm64/kernel/insn.c +++ b/arch/arm64/kernel/insn.c @@ -26,7 +26,7 @@ #define AARCH64_INSN_N_BIT BIT(22) #define AARCH64_INSN_LSL_12 BIT(22) -static int aarch64_insn_encoding_class[] = { +static const int aarch64_insn_encoding_class[] = { AARCH64_INSN_CLS_UNKNOWN, AARCH64_INSN_CLS_UNKNOWN, AARCH64_INSN_CLS_UNKNOWN, diff --git a/arch/arm64/kernel/kaslr.c b/arch/arm64/kernel/kaslr.c index 708051655ad9c597138419af816583c9f5ed2299..416f537bf6142818c15267be2cc54c82716201c2 100644 --- a/arch/arm64/kernel/kaslr.c +++ b/arch/arm64/kernel/kaslr.c @@ -62,9 +62,6 @@ static __init const u8 *kaslr_get_cmdline(void *fdt) return default_cmdline; } -extern void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, - pgprot_t prot); - /* * This routine will be executed with the kernel mapped at its default virtual * address, and if it returns successfully, the kernel will be remapped, and @@ -93,7 +90,7 @@ u64 __init kaslr_early_init(u64 dt_phys) * attempt at mapping the FDT in setup_machine() */ early_fixmap_init(); - fdt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL); + fdt = fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL); if (!fdt) return 0; @@ -116,15 +113,15 @@ u64 __init kaslr_early_init(u64 dt_phys) /* * OK, so we are proceeding with KASLR enabled. Calculate a suitable * kernel image offset from the seed. Let's place the kernel in the - * middle half of the VMALLOC area (VA_BITS - 2), and stay clear of + * middle half of the VMALLOC area (VA_BITS_MIN - 2), and stay clear of * the lower and upper quarters to avoid colliding with other * allocations. * Even if we could randomize at page granularity for 16k and 64k pages, * let's always round to 2 MB so we don't interfere with the ability to * map using contiguous PTEs */ - mask = ((1UL << (VA_BITS - 2)) - 1) & ~(SZ_2M - 1); - offset = BIT(VA_BITS - 3) + (seed & mask); + mask = ((1UL << (VA_BITS_MIN - 2)) - 1) & ~(SZ_2M - 1); + offset = BIT(VA_BITS_MIN - 3) + (seed & mask); /* use the top 16 bits to randomize the linear region */ memstart_offset_seed = seed >> 48; diff --git a/arch/arm64/kernel/kexec_image.c b/arch/arm64/kernel/kexec_image.c index 2514fd6f12cbd15797963755f2ca70827a6ce294..29a9428486a5778e229d83aaa464644f33c29c09 100644 --- a/arch/arm64/kernel/kexec_image.c +++ b/arch/arm64/kernel/kexec_image.c @@ -84,7 +84,7 @@ static void *image_load(struct kimage *image, kbuf.buffer = kernel; kbuf.bufsz = kernel_len; - kbuf.mem = 0; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; kbuf.memsz = le64_to_cpu(h->image_size); text_offset = le64_to_cpu(h->text_offset); kbuf.buf_align = MIN_KIMG_ALIGN; diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c index 58871333737a4e5458d723dcb0fd6e5e609548da..7b08bf9499b6b5a338d68d3f8baa08741e720c53 100644 --- a/arch/arm64/kernel/machine_kexec_file.c +++ b/arch/arm64/kernel/machine_kexec_file.c @@ -27,6 +27,8 @@ #define FDT_PROP_INITRD_END "linux,initrd-end" #define FDT_PROP_BOOTARGS "bootargs" #define FDT_PROP_KASLR_SEED "kaslr-seed" +#define FDT_PROP_RNG_SEED "rng-seed" +#define RNG_SEED_SIZE 128 const struct kexec_file_ops * const kexec_file_loaders[] = { &kexec_image_ops, @@ -102,6 +104,19 @@ static int setup_dtb(struct kimage *image, FDT_PROP_KASLR_SEED); } + /* add rng-seed */ + if (rng_is_initialized()) { + u8 rng_seed[RNG_SEED_SIZE]; + get_random_bytes(rng_seed, RNG_SEED_SIZE); + ret = fdt_setprop(dtb, off, FDT_PROP_RNG_SEED, rng_seed, + RNG_SEED_SIZE); + if (ret) + goto out; + } else { + pr_notice("RNG is not initialised: omitting \"%s\" property\n", + FDT_PROP_RNG_SEED); + } + out: if (ret) return (ret == -FDT_ERR_NOSPACE) ? -ENOMEM : -EINVAL; @@ -110,7 +125,8 @@ static int setup_dtb(struct kimage *image, } /* - * More space needed so that we can add initrd, bootargs and kaslr-seed. + * More space needed so that we can add initrd, bootargs, kaslr-seed, and + * rng-seed. */ #define DTB_EXTRA_SPACE 0x1000 @@ -177,7 +193,7 @@ int load_other_segments(struct kimage *image, if (initrd) { kbuf.buffer = initrd; kbuf.bufsz = initrd_len; - kbuf.mem = 0; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; kbuf.memsz = initrd_len; kbuf.buf_align = 0; /* within 1GB-aligned window of up to 32GB in size */ @@ -204,7 +220,7 @@ int load_other_segments(struct kimage *image, dtb_len = fdt_totalsize(dtb); kbuf.buffer = dtb; kbuf.bufsz = dtb_len; - kbuf.mem = 0; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; kbuf.memsz = dtb_len; /* not across 2MB boundary */ kbuf.buf_align = SZ_2M; diff --git a/arch/arm64/kernel/module-plts.c b/arch/arm64/kernel/module-plts.c index 044c0ae4d6c85eac6db5000facc151b805e4b05e..b182442b87a32fcf4836f2179466c50508a6372d 100644 --- a/arch/arm64/kernel/module-plts.c +++ b/arch/arm64/kernel/module-plts.c @@ -302,7 +302,7 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, /* sort by type, symbol index and addend */ sort(rels, numrels, sizeof(Elf64_Rela), cmp_rela, NULL); - if (strncmp(secstrings + dstsec->sh_name, ".init", 5) != 0) + if (!str_has_prefix(secstrings + dstsec->sh_name, ".init")) core_plts += count_plts(syms, rels, numrels, sechdrs[i].sh_info, dstsec); else diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 96e90e270042de1846e19c077325fcd4db276e25..a0b4f1bca4917e0fea04beac112e4814de1980ec 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -19,6 +19,7 @@ #include #include #include +#include /* ARMv8 Cortex-A53 specific event types. */ #define ARMV8_A53_PERFCTR_PREF_LINEFILL 0xC2 @@ -157,7 +158,6 @@ armv8pmu_events_sysfs_show(struct device *dev, return sprintf(page, "event=0x%03llx\n", pmu_attr->id); } -#define ARMV8_EVENT_ATTR_RESOLVE(m) #m #define ARMV8_EVENT_ATTR(name, config) \ PMU_EVENT_ATTR(name, armv8_event_attr_##name, \ config, armv8pmu_events_sysfs_show) diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index f674f28df663b29aa26f4856aa837c14e1da4234..03689c0beb34863ee501274a959efce24c067d88 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include #include +#include #include #include @@ -307,11 +309,18 @@ static void tls_thread_flush(void) } } +static void flush_tagged_addr_state(void) +{ + if (IS_ENABLED(CONFIG_ARM64_TAGGED_ADDR_ABI)) + clear_thread_flag(TIF_TAGGED_ADDR); +} + void flush_thread(void) { fpsimd_flush_thread(); tls_thread_flush(); flush_ptrace_hw_breakpoint(current); + flush_tagged_addr_state(); } void release_thread(struct task_struct *dead_task) @@ -565,3 +574,70 @@ void arch_setup_new_exec(void) ptrauth_thread_init_user(current); } + +#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI +/* + * Control the relaxed ABI allowing tagged user addresses into the kernel. + */ +static unsigned int tagged_addr_disabled; + +long set_tagged_addr_ctrl(unsigned long arg) +{ + if (is_compat_task()) + return -EINVAL; + if (arg & ~PR_TAGGED_ADDR_ENABLE) + return -EINVAL; + + /* + * Do not allow the enabling of the tagged address ABI if globally + * disabled via sysctl abi.tagged_addr_disabled. + */ + if (arg & PR_TAGGED_ADDR_ENABLE && tagged_addr_disabled) + return -EINVAL; + + update_thread_flag(TIF_TAGGED_ADDR, arg & PR_TAGGED_ADDR_ENABLE); + + return 0; +} + +long get_tagged_addr_ctrl(void) +{ + if (is_compat_task()) + return -EINVAL; + + if (test_thread_flag(TIF_TAGGED_ADDR)) + return PR_TAGGED_ADDR_ENABLE; + + return 0; +} + +/* + * Global sysctl to disable the tagged user addresses support. This control + * only prevents the tagged address ABI enabling via prctl() and does not + * disable it for tasks that already opted in to the relaxed ABI. + */ +static int zero; +static int one = 1; + +static struct ctl_table tagged_addr_sysctl_table[] = { + { + .procname = "tagged_addr_disabled", + .mode = 0644, + .data = &tagged_addr_disabled, + .maxlen = sizeof(int), + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, + { } +}; + +static int __init tagged_addr_init(void) +{ + if (!register_sysctl("abi", tagged_addr_sysctl_table)) + return -EINVAL; + return 0; +} + +core_initcall(tagged_addr_init); +#endif /* CONFIG_ARM64_TAGGED_ADDR_ABI */ diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index 85ee7d07889e785c6128a09e1b04dbe5639695eb..c9f72b2665f1cc26cd7cc877fca628473be8e8bd 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -46,6 +46,11 @@ static int cpu_psci_cpu_boot(unsigned int cpu) } #ifdef CONFIG_HOTPLUG_CPU +static bool cpu_psci_cpu_can_disable(unsigned int cpu) +{ + return !psci_tos_resident_on(cpu); +} + static int cpu_psci_cpu_disable(unsigned int cpu) { /* Fail early if we don't have CPU_OFF support */ @@ -105,14 +110,11 @@ static int cpu_psci_cpu_kill(unsigned int cpu) const struct cpu_operations cpu_psci_ops = { .name = "psci", -#ifdef CONFIG_CPU_IDLE - .cpu_init_idle = psci_cpu_init_idle, - .cpu_suspend = psci_cpu_suspend_enter, -#endif .cpu_init = cpu_psci_cpu_init, .cpu_prepare = cpu_psci_cpu_prepare, .cpu_boot = cpu_psci_cpu_boot, #ifdef CONFIG_HOTPLUG_CPU + .cpu_can_disable = cpu_psci_cpu_can_disable, .cpu_disable = cpu_psci_cpu_disable, .cpu_die = cpu_psci_cpu_die, .cpu_kill = cpu_psci_cpu_kill, diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 3cf3b135027e3fae6e26017ba8406f8a80b19f0f..21176d02e21a1c1b8e4977087717c816ba4329e5 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -870,7 +870,7 @@ static int sve_set(struct task_struct *target, goto out; /* - * Apart from PT_SVE_REGS_MASK, all PT_SVE_* flags are consumed by + * Apart from SVE_PT_REGS_MASK, all SVE_PT_* flags are consumed by * sve_set_vector_length(), which will also validate them for us: */ ret = sve_set_vector_length(target, header.vl, diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 9c4bad7d71317ef927e6766a0eefaf4352e7840f..56f6645617548600de5c0fa25133753d357895e3 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -170,9 +170,13 @@ static void __init smp_build_mpidr_hash(void) static void __init setup_machine_fdt(phys_addr_t dt_phys) { - void *dt_virt = fixmap_remap_fdt(dt_phys); + int size; + void *dt_virt = fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL); const char *name; + if (dt_virt) + memblock_reserve(dt_phys, size); + if (!dt_virt || !early_init_dt_scan(dt_virt)) { pr_crit("\n" "Error: invalid device tree blob at physical address %pa (virtual address 0x%p)\n" @@ -184,6 +188,9 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys) cpu_relax(); } + /* Early fixups are done, map the FDT as read-only now */ + fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO); + name = of_flat_dt_get_machine_name(); if (!name) return; @@ -357,6 +364,15 @@ void __init setup_arch(char **cmdline_p) } } +static inline bool cpu_can_disable(unsigned int cpu) +{ +#ifdef CONFIG_HOTPLUG_CPU + if (cpu_ops[cpu] && cpu_ops[cpu]->cpu_can_disable) + return cpu_ops[cpu]->cpu_can_disable(cpu); +#endif + return false; +} + static int __init topology_init(void) { int i; @@ -366,7 +382,7 @@ static int __init topology_init(void) for_each_possible_cpu(i) { struct cpu *cpu = &per_cpu(cpu_data.cpu, i); - cpu->hotpluggable = 1; + cpu->hotpluggable = cpu_can_disable(i); register_cpu(cpu, i); } diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 018a33e01b0ed2fdac2997b34d6065979bc343e1..dc9fe879c27932ef413dc99df73f39994855f052 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -123,7 +123,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) * time out. */ wait_for_completion_timeout(&cpu_running, - msecs_to_jiffies(1000)); + msecs_to_jiffies(5000)); if (!cpu_online(cpu)) { pr_crit("CPU%u: failed to come online\n", cpu); @@ -136,6 +136,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) secondary_data.task = NULL; secondary_data.stack = NULL; + __flush_dcache_area(&secondary_data, sizeof(secondary_data)); status = READ_ONCE(secondary_data.status); if (ret && status) { @@ -146,6 +147,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) default: pr_err("CPU%u: failed in unknown state : 0x%lx\n", cpu, status); + cpus_stuck_in_kernel++; break; case CPU_KILL_ME: if (!op_cpu_kill(cpu)) { diff --git a/arch/arm64/kernel/smp_spin_table.c b/arch/arm64/kernel/smp_spin_table.c index 76c2739ba8a483c8a77ba4ae9d1ed25cc7caf6ca..c8a3fee00c11329910ae63f6fe3ac98e0fd60fdb 100644 --- a/arch/arm64/kernel/smp_spin_table.c +++ b/arch/arm64/kernel/smp_spin_table.c @@ -19,7 +19,7 @@ #include extern void secondary_holding_pen(void); -volatile unsigned long __section(".mmuoff.data.read") +volatile unsigned long __section(.mmuoff.data.read) secondary_holding_pen_release = INVALID_HWID; static phys_addr_t cpu_release_addr[NR_CPUS]; diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index 0825c4a856e33da0d794f403fd2a6464543467c3..fa9528dfd0ce3cf4331d4d05169a05146a49b0d6 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -14,250 +14,13 @@ #include #include #include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include -static int __init get_cpu_for_node(struct device_node *node) -{ - struct device_node *cpu_node; - int cpu; - - cpu_node = of_parse_phandle(node, "cpu", 0); - if (!cpu_node) - return -1; - - cpu = of_cpu_node_to_id(cpu_node); - if (cpu >= 0) - topology_parse_cpu_capacity(cpu_node, cpu); - else - pr_crit("Unable to find CPU node for %pOF\n", cpu_node); - - of_node_put(cpu_node); - return cpu; -} - -static int __init parse_core(struct device_node *core, int package_id, - int core_id) -{ - char name[10]; - bool leaf = true; - int i = 0; - int cpu; - struct device_node *t; - - do { - snprintf(name, sizeof(name), "thread%d", i); - t = of_get_child_by_name(core, name); - if (t) { - leaf = false; - cpu = get_cpu_for_node(t); - if (cpu >= 0) { - cpu_topology[cpu].package_id = package_id; - cpu_topology[cpu].core_id = core_id; - cpu_topology[cpu].thread_id = i; - } else { - pr_err("%pOF: Can't get CPU for thread\n", - t); - of_node_put(t); - return -EINVAL; - } - of_node_put(t); - } - i++; - } while (t); - - cpu = get_cpu_for_node(core); - if (cpu >= 0) { - if (!leaf) { - pr_err("%pOF: Core has both threads and CPU\n", - core); - return -EINVAL; - } - - cpu_topology[cpu].package_id = package_id; - cpu_topology[cpu].core_id = core_id; - } else if (leaf) { - pr_err("%pOF: Can't get CPU for leaf core\n", core); - return -EINVAL; - } - - return 0; -} - -static int __init parse_cluster(struct device_node *cluster, int depth) -{ - char name[10]; - bool leaf = true; - bool has_cores = false; - struct device_node *c; - static int package_id __initdata; - int core_id = 0; - int i, ret; - - /* - * First check for child clusters; we currently ignore any - * information about the nesting of clusters and present the - * scheduler with a flat list of them. - */ - i = 0; - do { - snprintf(name, sizeof(name), "cluster%d", i); - c = of_get_child_by_name(cluster, name); - if (c) { - leaf = false; - ret = parse_cluster(c, depth + 1); - of_node_put(c); - if (ret != 0) - return ret; - } - i++; - } while (c); - - /* Now check for cores */ - i = 0; - do { - snprintf(name, sizeof(name), "core%d", i); - c = of_get_child_by_name(cluster, name); - if (c) { - has_cores = true; - - if (depth == 0) { - pr_err("%pOF: cpu-map children should be clusters\n", - c); - of_node_put(c); - return -EINVAL; - } - - if (leaf) { - ret = parse_core(c, package_id, core_id++); - } else { - pr_err("%pOF: Non-leaf cluster with core %s\n", - cluster, name); - ret = -EINVAL; - } - - of_node_put(c); - if (ret != 0) - return ret; - } - i++; - } while (c); - - if (leaf && !has_cores) - pr_warn("%pOF: empty cluster\n", cluster); - - if (leaf) - package_id++; - - return 0; -} - -static int __init parse_dt_topology(void) -{ - struct device_node *cn, *map; - int ret = 0; - int cpu; - - cn = of_find_node_by_path("/cpus"); - if (!cn) { - pr_err("No CPU information found in DT\n"); - return 0; - } - - /* - * When topology is provided cpu-map is essentially a root - * cluster with restricted subnodes. - */ - map = of_get_child_by_name(cn, "cpu-map"); - if (!map) - goto out; - - ret = parse_cluster(map, 0); - if (ret != 0) - goto out_map; - - topology_normalize_cpu_scale(); - - /* - * Check that all cores are in the topology; the SMP code will - * only mark cores described in the DT as possible. - */ - for_each_possible_cpu(cpu) - if (cpu_topology[cpu].package_id == -1) - ret = -EINVAL; - -out_map: - of_node_put(map); -out: - of_node_put(cn); - return ret; -} - -/* - * cpu topology table - */ -struct cpu_topology cpu_topology[NR_CPUS]; -EXPORT_SYMBOL_GPL(cpu_topology); - -const struct cpumask *cpu_coregroup_mask(int cpu) -{ - const cpumask_t *core_mask = cpumask_of_node(cpu_to_node(cpu)); - - /* Find the smaller of NUMA, core or LLC siblings */ - if (cpumask_subset(&cpu_topology[cpu].core_sibling, core_mask)) { - /* not numa in package, lets use the package siblings */ - core_mask = &cpu_topology[cpu].core_sibling; - } - if (cpu_topology[cpu].llc_id != -1) { - if (cpumask_subset(&cpu_topology[cpu].llc_sibling, core_mask)) - core_mask = &cpu_topology[cpu].llc_sibling; - } - - return core_mask; -} - -static void update_siblings_masks(unsigned int cpuid) -{ - struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid]; - int cpu; - - /* update core and thread sibling masks */ - for_each_online_cpu(cpu) { - cpu_topo = &cpu_topology[cpu]; - - if (cpuid_topo->llc_id == cpu_topo->llc_id) { - cpumask_set_cpu(cpu, &cpuid_topo->llc_sibling); - cpumask_set_cpu(cpuid, &cpu_topo->llc_sibling); - } - - if (cpuid_topo->package_id != cpu_topo->package_id) - continue; - - cpumask_set_cpu(cpuid, &cpu_topo->core_sibling); - cpumask_set_cpu(cpu, &cpuid_topo->core_sibling); - - if (cpuid_topo->core_id != cpu_topo->core_id) - continue; - - cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling); - cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling); - } -} - void store_cpu_topology(unsigned int cpuid) { struct cpu_topology *cpuid_topo = &cpu_topology[cpuid]; @@ -296,60 +59,31 @@ void store_cpu_topology(unsigned int cpuid) update_siblings_masks(cpuid); } -static void clear_cpu_topology(int cpu) -{ - struct cpu_topology *cpu_topo = &cpu_topology[cpu]; - - cpumask_clear(&cpu_topo->llc_sibling); - cpumask_set_cpu(cpu, &cpu_topo->llc_sibling); - - cpumask_clear(&cpu_topo->core_sibling); - cpumask_set_cpu(cpu, &cpu_topo->core_sibling); - cpumask_clear(&cpu_topo->thread_sibling); - cpumask_set_cpu(cpu, &cpu_topo->thread_sibling); -} - -static void __init reset_cpu_topology(void) -{ - unsigned int cpu; - - for_each_possible_cpu(cpu) { - struct cpu_topology *cpu_topo = &cpu_topology[cpu]; - - cpu_topo->thread_id = -1; - cpu_topo->core_id = 0; - cpu_topo->package_id = -1; - cpu_topo->llc_id = -1; - - clear_cpu_topology(cpu); - } -} - -void remove_cpu_topology(unsigned int cpu) +#ifdef CONFIG_ACPI +static bool __init acpi_cpu_is_threaded(int cpu) { - int sibling; + int is_threaded = acpi_pptt_cpu_is_thread(cpu); - for_each_cpu(sibling, topology_core_cpumask(cpu)) - cpumask_clear_cpu(cpu, topology_core_cpumask(sibling)); - for_each_cpu(sibling, topology_sibling_cpumask(cpu)) - cpumask_clear_cpu(cpu, topology_sibling_cpumask(sibling)); - for_each_cpu(sibling, topology_llc_cpumask(cpu)) - cpumask_clear_cpu(cpu, topology_llc_cpumask(sibling)); + /* + * if the PPTT doesn't have thread information, assume a homogeneous + * machine and return the current CPU's thread state. + */ + if (is_threaded < 0) + is_threaded = read_cpuid_mpidr() & MPIDR_MT_BITMASK; - clear_cpu_topology(cpu); + return !!is_threaded; } -#ifdef CONFIG_ACPI /* * Propagate the topology information of the processor_topology_node tree to the * cpu_topology array. */ -static int __init parse_acpi_topology(void) +int __init parse_acpi_topology(void) { - bool is_threaded; int cpu, topology_id; - is_threaded = read_cpuid_mpidr() & MPIDR_MT_BITMASK; + if (acpi_disabled) + return 0; for_each_possible_cpu(cpu) { int i, cache_id; @@ -358,7 +92,7 @@ static int __init parse_acpi_topology(void) if (topology_id < 0) return topology_id; - if (is_threaded) { + if (acpi_cpu_is_threaded(cpu)) { cpu_topology[cpu].thread_id = topology_id; topology_id = find_acpi_cpu_topology(cpu, 1); cpu_topology[cpu].core_id = topology_id; @@ -384,24 +118,6 @@ static int __init parse_acpi_topology(void) return 0; } - -#else -static inline int __init parse_acpi_topology(void) -{ - return -EINVAL; -} #endif -void __init init_cpu_topology(void) -{ - reset_cpu_topology(); - /* - * Discard anything that was parsed if we hit an error so we - * don't use partial information. - */ - if (!acpi_disabled && parse_acpi_topology()) - reset_cpu_topology(); - else if (of_have_populated_dt() && parse_dt_topology()) - reset_cpu_topology(); -} diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 32893b3d9164e70ec7d0dcf11619840f07def078..34739e80211bc5f59f88be6793b0e4a8d15d67c8 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -7,9 +7,11 @@ */ #include +#include #include #include #include +#include #include #include #include @@ -511,7 +513,7 @@ struct sys64_hook { void (*handler)(unsigned int esr, struct pt_regs *regs); }; -static struct sys64_hook sys64_hooks[] = { +static const struct sys64_hook sys64_hooks[] = { { .esr_mask = ESR_ELx_SYS64_ISS_EL0_CACHE_OP_MASK, .esr_val = ESR_ELx_SYS64_ISS_EL0_CACHE_OP_VAL, @@ -636,7 +638,7 @@ static void compat_cntfrq_read_handler(unsigned int esr, struct pt_regs *regs) arm64_compat_skip_faulting_instruction(regs, 4); } -static struct sys64_hook cp15_32_hooks[] = { +static const struct sys64_hook cp15_32_hooks[] = { { .esr_mask = ESR_ELx_CP15_32_ISS_SYS_MASK, .esr_val = ESR_ELx_CP15_32_ISS_SYS_CNTFRQ, @@ -656,7 +658,7 @@ static void compat_cntvct_read_handler(unsigned int esr, struct pt_regs *regs) arm64_compat_skip_faulting_instruction(regs, 4); } -static struct sys64_hook cp15_64_hooks[] = { +static const struct sys64_hook cp15_64_hooks[] = { { .esr_mask = ESR_ELx_CP15_64_ISS_SYS_MASK, .esr_val = ESR_ELx_CP15_64_ISS_SYS_CNTVCT, @@ -667,7 +669,7 @@ static struct sys64_hook cp15_64_hooks[] = { asmlinkage void __exception do_cp15instr(unsigned int esr, struct pt_regs *regs) { - struct sys64_hook *hook, *hook_base; + const struct sys64_hook *hook, *hook_base; if (!cp15_cond_valid(esr, regs)) { /* @@ -707,7 +709,7 @@ asmlinkage void __exception do_cp15instr(unsigned int esr, struct pt_regs *regs) asmlinkage void __exception do_sysinstr(unsigned int esr, struct pt_regs *regs) { - struct sys64_hook *hook; + const struct sys64_hook *hook; for (hook = sys64_hooks; hook->handler; hook++) if ((hook->esr_mask & esr) == hook->esr_val) { @@ -744,6 +746,7 @@ static const char *esr_class_str[] = { [ESR_ELx_EC_SMC64] = "SMC (AArch64)", [ESR_ELx_EC_SYS64] = "MSR/MRS (AArch64)", [ESR_ELx_EC_SVE] = "SVE", + [ESR_ELx_EC_ERET] = "ERET/ERETAA/ERETAB", [ESR_ELx_EC_IMP_DEF] = "EL3 IMP DEF", [ESR_ELx_EC_IABT_LOW] = "IABT (lower EL)", [ESR_ELx_EC_IABT_CUR] = "IABT (current EL)", @@ -900,6 +903,13 @@ asmlinkage void do_serror(struct pt_regs *regs, unsigned int esr) nmi_exit(); } +asmlinkage void enter_from_user_mode(void) +{ + CT_WARN_ON(ct_state() != CONTEXT_USER); + user_exit_irqoff(); +} +NOKPROBE_SYMBOL(enter_from_user_mode); + void __pte_error(const char *file, int line, unsigned long val) { pr_err("%s:%d: bad pte %016lx.\n", file, line, val); diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index 7fa00837490787c35a5554430f01812418d76dcc..aa76f725966853ec8f2c6418bbc3fccf80920f16 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -200,6 +200,15 @@ SECTIONS __rela_offset = ABSOLUTE(ADDR(.rela.dyn) - KIMAGE_VADDR); __rela_size = SIZEOF(.rela.dyn); +#ifdef CONFIG_RELR + .relr.dyn : ALIGN(8) { + *(.relr.dyn) + } + + __relr_offset = ABSOLUTE(ADDR(.relr.dyn) - KIMAGE_VADDR); + __relr_size = SIZEOF(.relr.dyn); +#endif + . = ALIGN(SEGMENT_ALIGN); __initdata_end = .; __init_end = .; @@ -245,6 +254,8 @@ SECTIONS HEAD_SYMBOLS } +#include "image-vars.h" + /* * The HYP init code and ID map text can't be longer than a page each, * and should not cross a page boundary. diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index adaf266d8de88f818954a1414c7f7ca729fb1a32..bd978ad71936dc7413c0d077f7d6c18cdc8f48ac 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c @@ -264,7 +264,7 @@ static bool __hyp_text __translate_far_to_hpfar(u64 far, u64 *hpfar) tmp = read_sysreg(par_el1); write_sysreg(par, par_el1); - if (unlikely(tmp & 1)) + if (unlikely(tmp & SYS_PAR_EL1_F)) return false; /* Translation failed, back to guest */ /* Convert PAR to HPFAR format */ diff --git a/arch/arm64/kvm/hyp/tlb.c b/arch/arm64/kvm/hyp/tlb.c index d49a14497715f1ea09b38b681338ee9be911bb32..c466060b76d69d11630244be356a0d46fad08371 100644 --- a/arch/arm64/kvm/hyp/tlb.c +++ b/arch/arm64/kvm/hyp/tlb.c @@ -193,6 +193,18 @@ void __hyp_text __kvm_flush_vm_context(void) { dsb(ishst); __tlbi(alle1is); - asm volatile("ic ialluis" : : ); + + /* + * VIPT and PIPT caches are not affected by VMID, so no maintenance + * is necessary across a VMID rollover. + * + * VPIPT caches constrain lookup and maintenance to the active VMID, + * so we need to invalidate lines with a stale VMID to avoid an ABA + * race after multiple rollovers. + * + */ + if (icache_is_vpipt()) + asm volatile("ic ialluis"); + dsb(ish); } diff --git a/arch/arm64/kvm/va_layout.c b/arch/arm64/kvm/va_layout.c index acd8084f1f2c1055adc0335d87644542018aa5da..2cf7d4b606c38d1f32e9772bc08716bd331950b8 100644 --- a/arch/arm64/kvm/va_layout.c +++ b/arch/arm64/kvm/va_layout.c @@ -29,25 +29,25 @@ static void compute_layout(void) int kva_msb; /* Where is my RAM region? */ - hyp_va_msb = idmap_addr & BIT(VA_BITS - 1); - hyp_va_msb ^= BIT(VA_BITS - 1); + hyp_va_msb = idmap_addr & BIT(vabits_actual - 1); + hyp_va_msb ^= BIT(vabits_actual - 1); kva_msb = fls64((u64)phys_to_virt(memblock_start_of_DRAM()) ^ (u64)(high_memory - 1)); - if (kva_msb == (VA_BITS - 1)) { + if (kva_msb == (vabits_actual - 1)) { /* * No space in the address, let's compute the mask so - * that it covers (VA_BITS - 1) bits, and the region + * that it covers (vabits_actual - 1) bits, and the region * bit. The tag stays set to zero. */ - va_mask = BIT(VA_BITS - 1) - 1; + va_mask = BIT(vabits_actual - 1) - 1; va_mask |= hyp_va_msb; } else { /* * We do have some free bits to insert a random tag. * Hyp VAs are now created from kernel linear map VAs - * using the following formula (with V == VA_BITS): + * using the following formula (with V == vabits_actual): * * 63 ... V | V-1 | V-2 .. tag_lsb | tag_lsb - 1 .. 0 * --------------------------------------------------------- @@ -55,7 +55,7 @@ static void compute_layout(void) */ tag_lsb = kva_msb; va_mask = GENMASK_ULL(tag_lsb - 1, 0); - tag_val = get_random_long() & GENMASK_ULL(VA_BITS - 2, tag_lsb); + tag_val = get_random_long() & GENMASK_ULL(vabits_actual - 2, tag_lsb); tag_val |= hyp_va_msb; tag_val >>= tag_lsb; } diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile index 33c2a4abda046532c733b1fcc55f90ff8fa68d7c..c21b936dc01db20c086f816e0b71fa954319a768 100644 --- a/arch/arm64/lib/Makefile +++ b/arch/arm64/lib/Makefile @@ -11,25 +11,8 @@ CFLAGS_REMOVE_xor-neon.o += -mgeneral-regs-only CFLAGS_xor-neon.o += -ffreestanding endif -# Tell the compiler to treat all general purpose registers (with the -# exception of the IP registers, which are already handled by the caller -# in case of a PLT) as callee-saved, which allows for efficient runtime -# patching of the bl instruction in the caller with an atomic instruction -# when supported by the CPU. Result and argument registers are handled -# correctly, based on the function prototype. -lib-$(CONFIG_ARM64_LSE_ATOMICS) += atomic_ll_sc.o -CFLAGS_atomic_ll_sc.o := -ffixed-x1 -ffixed-x2 \ - -ffixed-x3 -ffixed-x4 -ffixed-x5 -ffixed-x6 \ - -ffixed-x7 -fcall-saved-x8 -fcall-saved-x9 \ - -fcall-saved-x10 -fcall-saved-x11 -fcall-saved-x12 \ - -fcall-saved-x13 -fcall-saved-x14 -fcall-saved-x15 \ - -fcall-saved-x18 -fomit-frame-pointer -CFLAGS_REMOVE_atomic_ll_sc.o := $(CC_FLAGS_FTRACE) -GCOV_PROFILE_atomic_ll_sc.o := n -KASAN_SANITIZE_atomic_ll_sc.o := n -KCOV_INSTRUMENT_atomic_ll_sc.o := n -UBSAN_SANITIZE_atomic_ll_sc.o := n - lib-$(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) += uaccess_flushcache.o obj-$(CONFIG_CRC32) += crc32.o + +obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o diff --git a/arch/arm64/lib/atomic_ll_sc.c b/arch/arm64/lib/atomic_ll_sc.c deleted file mode 100644 index b0c538b0da28c6332082544900cd7af77ad4d79f..0000000000000000000000000000000000000000 --- a/arch/arm64/lib/atomic_ll_sc.c +++ /dev/null @@ -1,3 +0,0 @@ -#include -#define __ARM64_IN_ATOMIC_IMPL -#include diff --git a/arch/arm64/lib/error-inject.c b/arch/arm64/lib/error-inject.c new file mode 100644 index 0000000000000000000000000000000000000000..ed15021da3ed0c77f4574ac6a3eda70a6464d565 --- /dev/null +++ b/arch/arm64/lib/error-inject.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +void override_function_with_return(struct pt_regs *regs) +{ + /* + * 'regs' represents the state on entry of a predefined function in + * the kernel/module and which is captured on a kprobe. + * + * When kprobe returns back from exception it will override the end + * of probed function and directly return to the predefined + * function's caller. + */ + instruction_pointer_set(regs, procedure_link_pointer(regs)); +} +NOKPROBE_SYMBOL(override_function_with_return); diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c index 82b3a7fdb4a68b83c1be6e5b65b7c8b2eb0bbe3c..93f9f77582ae38e32c93fbe42508cd4987ef2d85 100644 --- a/arch/arm64/mm/dump.c +++ b/arch/arm64/mm/dump.c @@ -25,9 +25,20 @@ #include #include -static const struct addr_marker address_markers[] = { + +enum address_markers_idx { + PAGE_OFFSET_NR = 0, + PAGE_END_NR, #ifdef CONFIG_KASAN - { KASAN_SHADOW_START, "Kasan shadow start" }, + KASAN_START_NR, +#endif +}; + +static struct addr_marker address_markers[] = { + { PAGE_OFFSET, "Linear Mapping start" }, + { 0 /* PAGE_END */, "Linear Mapping end" }, +#ifdef CONFIG_KASAN + { 0 /* KASAN_SHADOW_START */, "Kasan shadow start" }, { KASAN_SHADOW_END, "Kasan shadow end" }, #endif { MODULES_VADDR, "Modules start" }, @@ -42,7 +53,6 @@ static const struct addr_marker address_markers[] = { { VMEMMAP_START, "vmemmap start" }, { VMEMMAP_START + VMEMMAP_SIZE, "vmemmap end" }, #endif - { PAGE_OFFSET, "Linear mapping" }, { -1, NULL }, }; @@ -376,7 +386,7 @@ static void ptdump_initialize(void) static struct ptdump_info kernel_ptdump_info = { .mm = &init_mm, .markers = address_markers, - .base_addr = VA_START, + .base_addr = PAGE_OFFSET, }; void ptdump_check_wx(void) @@ -390,7 +400,7 @@ void ptdump_check_wx(void) .check_wx = true, }; - walk_pgd(&st, &init_mm, VA_START); + walk_pgd(&st, &init_mm, PAGE_OFFSET); note_page(&st, 0, 0, 0); if (st.wx_pages || st.uxn_pages) pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found, %lu non-UXN pages found\n", @@ -401,6 +411,10 @@ void ptdump_check_wx(void) static int ptdump_init(void) { + address_markers[PAGE_END_NR].start_address = PAGE_END; +#ifdef CONFIG_KASAN + address_markers[KASAN_START_NR].start_address = KASAN_SHADOW_START; +#endif ptdump_initialize(); ptdump_debugfs_register(&kernel_ptdump_info, "kernel_page_tables"); return 0; diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index cfd65b63f36fd05f15557e872bb9e6ec96efa973..115d7a0e4b082679ed2a651c90d8393609f6d1c2 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -86,8 +87,8 @@ static void mem_abort_decode(unsigned int esr) pr_alert("Mem abort info:\n"); pr_alert(" ESR = 0x%08x\n", esr); - pr_alert(" Exception class = %s, IL = %u bits\n", - esr_get_class_string(esr), + pr_alert(" EC = 0x%02lx: %s, IL = %u bits\n", + ESR_ELx_EC(esr), esr_get_class_string(esr), (esr & ESR_ELx_IL) ? 32 : 16); pr_alert(" SET = %lu, FnV = %lu\n", (esr & ESR_ELx_SET_MASK) >> ESR_ELx_SET_SHIFT, @@ -109,7 +110,7 @@ static inline bool is_ttbr0_addr(unsigned long addr) static inline bool is_ttbr1_addr(unsigned long addr) { /* TTBR1 addresses may have a tag if KASAN_SW_TAGS is in use */ - return arch_kasan_reset_tag(addr) >= VA_START; + return arch_kasan_reset_tag(addr) >= PAGE_OFFSET; } /* @@ -138,10 +139,9 @@ static void show_pte(unsigned long addr) return; } - pr_alert("%s pgtable: %luk pages, %u-bit VAs, pgdp=%016lx\n", + pr_alert("%s pgtable: %luk pages, %llu-bit VAs, pgdp=%016lx\n", mm == &init_mm ? "swapper" : "user", PAGE_SIZE / SZ_1K, - mm == &init_mm ? VA_BITS : (int)vabits_user, - (unsigned long)virt_to_phys(mm->pgd)); + vabits_actual, (unsigned long)virt_to_phys(mm->pgd)); pgdp = pgd_offset(mm, addr); pgd = READ_ONCE(*pgdp); pr_alert("[%016lx] pgd=%016llx", addr, pgd_val(pgd)); @@ -242,6 +242,34 @@ static inline bool is_el1_permission_fault(unsigned long addr, unsigned int esr, return false; } +static bool __kprobes is_spurious_el1_translation_fault(unsigned long addr, + unsigned int esr, + struct pt_regs *regs) +{ + unsigned long flags; + u64 par, dfsc; + + if (ESR_ELx_EC(esr) != ESR_ELx_EC_DABT_CUR || + (esr & ESR_ELx_FSC_TYPE) != ESR_ELx_FSC_FAULT) + return false; + + local_irq_save(flags); + asm volatile("at s1e1r, %0" :: "r" (addr)); + isb(); + par = read_sysreg(par_el1); + local_irq_restore(flags); + + if (!(par & SYS_PAR_EL1_F)) + return false; + + /* + * If we got a different type of fault from the AT instruction, + * treat the translation fault as spurious. + */ + dfsc = FIELD_PREP(SYS_PAR_EL1_FST, par); + return (dfsc & ESR_ELx_FSC_TYPE) != ESR_ELx_FSC_FAULT; +} + static void die_kernel_fault(const char *msg, unsigned long addr, unsigned int esr, struct pt_regs *regs) { @@ -270,6 +298,10 @@ static void __do_kernel_fault(unsigned long addr, unsigned int esr, if (!is_el1_instruction_abort(esr) && fixup_exception(regs)) return; + if (WARN_RATELIMIT(is_spurious_el1_translation_fault(addr, esr, regs), + "Ignoring spurious kernel translation fault at virtual address %016lx\n", addr)) + return; + if (is_el1_permission_fault(addr, esr, regs)) { if (esr & ESR_ELx_WNR) msg = "write to read-only memory"; diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index f3c795278def0ea01704c6b38fe3d2d140351224..45c00a54909c9b83bbf6b352a00ca1a02b5feff0 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -50,6 +50,12 @@ s64 memstart_addr __ro_after_init = -1; EXPORT_SYMBOL(memstart_addr); +s64 physvirt_offset __ro_after_init; +EXPORT_SYMBOL(physvirt_offset); + +struct page *vmemmap __ro_after_init; +EXPORT_SYMBOL(vmemmap); + phys_addr_t arm64_dma_phys_limit __ro_after_init; #ifdef CONFIG_KEXEC_CORE @@ -301,7 +307,7 @@ static void __init fdt_enforce_memory_region(void) void __init arm64_memblock_init(void) { - const s64 linear_region_size = -(s64)PAGE_OFFSET; + const s64 linear_region_size = BIT(vabits_actual - 1); /* Handle linux,usable-memory-range property */ fdt_enforce_memory_region(); @@ -309,19 +315,26 @@ void __init arm64_memblock_init(void) /* Remove memory above our supported physical address size */ memblock_remove(1ULL << PHYS_MASK_SHIFT, ULLONG_MAX); - /* - * Ensure that the linear region takes up exactly half of the kernel - * virtual address space. This way, we can distinguish a linear address - * from a kernel/module/vmalloc address by testing a single bit. - */ - BUILD_BUG_ON(linear_region_size != BIT(VA_BITS - 1)); - /* * Select a suitable value for the base of physical memory. */ memstart_addr = round_down(memblock_start_of_DRAM(), ARM64_MEMSTART_ALIGN); + physvirt_offset = PHYS_OFFSET - PAGE_OFFSET; + + vmemmap = ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT)); + + /* + * If we are running with a 52-bit kernel VA config on a system that + * does not support it, we have to offset our vmemmap and physvirt_offset + * s.t. we avoid the 52-bit portion of the direct linear map + */ + if (IS_ENABLED(CONFIG_ARM64_VA_BITS_52) && (vabits_actual != 52)) { + vmemmap += (_PAGE_OFFSET(48) - _PAGE_OFFSET(52)) >> PAGE_SHIFT; + physvirt_offset = PHYS_OFFSET - _PAGE_OFFSET(48); + } + /* * Remove the memory that we will not be able to cover with the * linear mapping. Take care not to clip the kernel which may be @@ -570,8 +583,12 @@ void free_initmem(void) #ifdef CONFIG_BLK_DEV_INITRD void __init free_initrd_mem(unsigned long start, unsigned long end) { + unsigned long aligned_start, aligned_end; + + aligned_start = __virt_to_phys(start) & PAGE_MASK; + aligned_end = PAGE_ALIGN(__virt_to_phys(end)); + memblock_free(aligned_start, aligned_end - aligned_start); free_reserved_area((void *)start, (void *)end, 0, "initrd"); - memblock_free(__virt_to_phys(start), end - start); } #endif diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c index fdb595a5d65f8741d00f2bd3b7f0450adee64cbd..9be71bee902ca890c911ec864b2c869724fcc57b 100644 --- a/arch/arm64/mm/ioremap.c +++ b/arch/arm64/mm/ioremap.c @@ -69,7 +69,7 @@ void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot) } EXPORT_SYMBOL(__ioremap); -void __iounmap(volatile void __iomem *io_addr) +void iounmap(volatile void __iomem *io_addr) { unsigned long addr = (unsigned long)io_addr & PAGE_MASK; @@ -80,7 +80,7 @@ void __iounmap(volatile void __iomem *io_addr) if (is_vmalloc_addr((void *)addr)) vunmap((void *)addr); } -EXPORT_SYMBOL(__iounmap); +EXPORT_SYMBOL(iounmap); void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size) { diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c index 6cf97b904ebb4a29c8b7c18462d2799ad9b77872..f87a32484ea82c16eb45717b81b641024f915f17 100644 --- a/arch/arm64/mm/kasan_init.c +++ b/arch/arm64/mm/kasan_init.c @@ -156,7 +156,8 @@ asmlinkage void __init kasan_early_init(void) { BUILD_BUG_ON(KASAN_SHADOW_OFFSET != KASAN_SHADOW_END - (1UL << (64 - KASAN_SHADOW_SCALE_SHIFT))); - BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_START, PGDIR_SIZE)); + BUILD_BUG_ON(!IS_ALIGNED(_KASAN_SHADOW_START(VA_BITS), PGDIR_SIZE)); + BUILD_BUG_ON(!IS_ALIGNED(_KASAN_SHADOW_START(VA_BITS_MIN), PGDIR_SIZE)); BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_END, PGDIR_SIZE)); kasan_pgd_populate(KASAN_SHADOW_START, KASAN_SHADOW_END, NUMA_NO_NODE, true); @@ -225,10 +226,10 @@ void __init kasan_init(void) kasan_map_populate(kimg_shadow_start, kimg_shadow_end, early_pfn_to_nid(virt_to_pfn(lm_alias(_text)))); - kasan_populate_early_shadow((void *)KASAN_SHADOW_START, - (void *)mod_shadow_start); + kasan_populate_early_shadow(kasan_mem_to_shadow((void *)PAGE_END), + (void *)mod_shadow_start); kasan_populate_early_shadow((void *)kimg_shadow_end, - kasan_mem_to_shadow((void *)PAGE_OFFSET)); + (void *)KASAN_SHADOW_END); if (kimg_shadow_start > mod_shadow_end) kasan_populate_early_shadow((void *)mod_shadow_end, diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 750a69dde39bdd76a425b4f7e4d59a093936c5b6..53dc6f24cfb72e66e6b3f77bccad4dce435c6c4b 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -40,8 +40,9 @@ u64 idmap_t0sz = TCR_T0SZ(VA_BITS); u64 idmap_ptrs_per_pgd = PTRS_PER_PGD; -u64 vabits_user __ro_after_init; -EXPORT_SYMBOL(vabits_user); + +u64 __section(".mmuoff.data.write") vabits_actual; +EXPORT_SYMBOL(vabits_actual); u64 kimage_voffset __ro_after_init; EXPORT_SYMBOL(kimage_voffset); @@ -398,7 +399,7 @@ static phys_addr_t pgd_pgtable_alloc(int shift) static void __init create_mapping_noalloc(phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot) { - if (virt < VMALLOC_START) { + if ((virt >= PAGE_END) && (virt < VMALLOC_START)) { pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n", &phys, virt); return; @@ -425,7 +426,7 @@ void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, static void update_mapping_prot(phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot) { - if (virt < VMALLOC_START) { + if ((virt >= PAGE_END) && (virt < VMALLOC_START)) { pr_warn("BUG: not updating mapping for %pa at 0x%016lx - outside kernel range\n", &phys, virt); return; @@ -646,6 +647,8 @@ static void __init map_kernel(pgd_t *pgdp) set_pgd(pgd_offset_raw(pgdp, FIXADDR_START), READ_ONCE(*pgd_offset_k(FIXADDR_START))); } else if (CONFIG_PGTABLE_LEVELS > 3) { + pgd_t *bm_pgdp; + pud_t *bm_pudp; /* * The fixmap shares its top level pgd entry with the kernel * mapping. This can really only occur when we are running @@ -653,9 +656,9 @@ static void __init map_kernel(pgd_t *pgdp) * entry instead. */ BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES)); - pud_populate(&init_mm, - pud_set_fixmap_offset(pgdp, FIXADDR_START), - lm_alias(bm_pmd)); + bm_pgdp = pgd_offset_raw(pgdp, FIXADDR_START); + bm_pudp = pud_set_fixmap_offset(bm_pgdp, FIXADDR_START); + pud_populate(&init_mm, bm_pudp, lm_alias(bm_pmd)); pud_clear_fixmap(); } else { BUG(); @@ -876,7 +879,7 @@ void __set_fixmap(enum fixed_addresses idx, } } -void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot) +void *__init fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot) { const u64 dt_virt_base = __fix_to_virt(FIX_FDT); int offset; @@ -929,19 +932,6 @@ void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot) return dt_virt; } -void *__init fixmap_remap_fdt(phys_addr_t dt_phys) -{ - void *dt_virt; - int size; - - dt_virt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO); - if (!dt_virt) - return NULL; - - memblock_reserve(dt_phys, size); - return dt_virt; -} - int __init arch_ioremap_p4d_supported(void) { return 0; diff --git a/arch/arm64/mm/numa.c b/arch/arm64/mm/numa.c index 4f241cc7cc3b1262dfe0d083e3dc48468bd62c11..4decf16597008925206085b9e8efacc9ba537a71 100644 --- a/arch/arm64/mm/numa.c +++ b/arch/arm64/mm/numa.c @@ -29,7 +29,7 @@ static __init int numa_parse_early_param(char *opt) { if (!opt) return -EINVAL; - if (!strncmp(opt, "off", 3)) + if (str_has_prefix(opt, "off")) numa_off = true; return 0; diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c index 03c53f16ee7767bf1028bad813209ee992774f42..9ce7bd9d4d9ceaf3de79ce4ae67318f2988abdb8 100644 --- a/arch/arm64/mm/pageattr.c +++ b/arch/arm64/mm/pageattr.c @@ -128,7 +128,6 @@ int set_memory_nx(unsigned long addr, int numpages) __pgprot(PTE_PXN), __pgprot(0)); } -EXPORT_SYMBOL_GPL(set_memory_nx); int set_memory_x(unsigned long addr, int numpages) { @@ -136,7 +135,6 @@ int set_memory_x(unsigned long addr, int numpages) __pgprot(0), __pgprot(PTE_PXN)); } -EXPORT_SYMBOL_GPL(set_memory_x); int set_memory_valid(unsigned long addr, int numpages, int enable) { diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 7dbf2be470f6c01d548a8d681ad4a35bd08cefaa..a1e0592d1fbcd8833e41b2486869d7ae9898981b 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -168,7 +168,7 @@ ENDPROC(cpu_do_switch_mm) .macro __idmap_cpu_set_reserved_ttbr1, tmp1, tmp2 adrp \tmp1, empty_zero_page phys_to_ttbr \tmp2, \tmp1 - offset_ttbr1 \tmp2 + offset_ttbr1 \tmp2, \tmp1 msr ttbr1_el1, \tmp2 isb tlbi vmalle1 @@ -187,7 +187,7 @@ ENTRY(idmap_cpu_replace_ttbr1) __idmap_cpu_set_reserved_ttbr1 x1, x3 - offset_ttbr1 x0 + offset_ttbr1 x0, x3 msr ttbr1_el1, x0 isb @@ -286,6 +286,15 @@ skip_pgd: msr sctlr_el1, x18 isb + /* + * Invalidate the local I-cache so that any instructions fetched + * speculatively from the PoC are discarded, since they may have + * been dynamically patched at the PoU. + */ + ic iallu + dsb nsh + isb + /* Set the flag to zero to indicate that we're all done */ str wzr, [flag_ptr] ret @@ -362,7 +371,7 @@ __idmap_kpti_secondary: cbnz w18, 1b /* All done, act like nothing happened */ - offset_ttbr1 swapper_ttb + offset_ttbr1 swapper_ttb, x18 msr ttbr1_el1, swapper_ttb isb ret @@ -438,10 +447,11 @@ ENTRY(__cpu_setup) TCR_TBI0 | TCR_A1 | TCR_KASAN_FLAGS tcr_clear_errata_bits x10, x9, x5 -#ifdef CONFIG_ARM64_USER_VA_BITS_52 - ldr_l x9, vabits_user +#ifdef CONFIG_ARM64_VA_BITS_52 + ldr_l x9, vabits_actual sub x9, xzr, x9 add x9, x9, #64 + tcr_set_t1sz x10, x9 #else ldr_l x9, idmap_t0sz #endif diff --git a/arch/arm64/net/bpf_jit.h b/arch/arm64/net/bpf_jit.h index cb7ab50b76579067d29fbb575396fa47b0a36127..eb73f9f72c467a1bbacecb7ea270b75066b8d2ab 100644 --- a/arch/arm64/net/bpf_jit.h +++ b/arch/arm64/net/bpf_jit.h @@ -171,6 +171,9 @@ /* Rd = Ra + Rn * Rm */ #define A64_MADD(sf, Rd, Ra, Rn, Rm) aarch64_insn_gen_data3(Rd, Ra, Rn, Rm, \ A64_VARIANT(sf), AARCH64_INSN_DATA3_MADD) +/* Rd = Ra - Rn * Rm */ +#define A64_MSUB(sf, Rd, Ra, Rn, Rm) aarch64_insn_gen_data3(Rd, Ra, Rn, Rm, \ + A64_VARIANT(sf), AARCH64_INSN_DATA3_MSUB) /* Rd = Rn * Rm */ #define A64_MUL(sf, Rd, Rn, Rm) A64_MADD(sf, Rd, A64_ZR, Rn, Rm) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index f5b437f8a22b4042f29d4e8c55b181efd3350210..cdc79de0c794af4e46176c6924b14fd127426f54 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -409,8 +409,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, break; case BPF_MOD: emit(A64_UDIV(is64, tmp, dst, src), ctx); - emit(A64_MUL(is64, tmp, tmp, src), ctx); - emit(A64_SUB(is64, dst, dst, tmp), ctx); + emit(A64_MSUB(is64, dst, dst, tmp, src), ctx); break; } break; @@ -516,8 +515,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, case BPF_ALU64 | BPF_MOD | BPF_K: emit_a64_mov_i(is64, tmp2, imm, ctx); emit(A64_UDIV(is64, tmp, dst, tmp2), ctx); - emit(A64_MUL(is64, tmp, tmp, tmp2), ctx); - emit(A64_SUB(is64, dst, dst, tmp), ctx); + emit(A64_MSUB(is64, dst, dst, tmp, tmp2), ctx); break; case BPF_ALU | BPF_LSH | BPF_K: case BPF_ALU64 | BPF_LSH | BPF_K: diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 7468d8e504672a711e34a09984f2601f0cad6b1b..9711cf73092948678423b9d474030eecd24d4032 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -10,12 +10,14 @@ config IA64 bool select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_SERIO - select ACPI if (!IA64_HP_SIM) - select ARCH_SUPPORTS_ACPI if (!IA64_HP_SIM) + select ACPI + select ACPI_NUMA if NUMA + select ARCH_SUPPORTS_ACPI select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI - select FORCE_PCI if (!IA64_HP_SIM) + select FORCE_PCI select PCI_DOMAINS if PCI + select PCI_MSI select PCI_SYSCALL if PCI select HAVE_UNSTABLE_SCHED_CLOCK select HAVE_EXIT_THREAD @@ -30,8 +32,8 @@ config IA64 select HAVE_ARCH_TRACEHOOK select HAVE_MEMBLOCK_NODE_MAP select HAVE_VIRT_CPU_ACCOUNTING - select ARCH_HAS_DMA_COHERENT_TO_PFN if SWIOTLB - select ARCH_HAS_SYNC_DMA_FOR_CPU if SWIOTLB + select ARCH_HAS_DMA_COHERENT_TO_PFN + select ARCH_HAS_SYNC_DMA_FOR_CPU select VIRT_TO_BUS select GENERIC_IRQ_PROBE select GENERIC_PENDING_IRQ if SMP @@ -45,6 +47,7 @@ config IA64 select ARCH_THREAD_STACK_ALLOCATOR select ARCH_CLOCKSOURCE_DATA select GENERIC_TIME_VSYSCALL + select SWIOTLB select SYSCTL_ARCH_UNALIGN_NO_WARN select HAVE_MOD_ARCH_SPECIFIC select MODULES_USE_ELF_RELA @@ -52,6 +55,7 @@ config IA64 select HAVE_ARCH_AUDITSYSCALL select NEED_DMA_MAP_STATE select NEED_SG_DMA_LENGTH + select NUMA if !FLATMEM default y help The Itanium Processor Family is Intel's 64-bit successor to @@ -66,7 +70,6 @@ config 64BIT config ZONE_DMA32 def_bool y - depends on !IA64_SGI_SN2 config QUICKLIST bool @@ -120,87 +123,6 @@ config AUDIT_ARCH bool default y -choice - prompt "System type" - default IA64_GENERIC - -config IA64_GENERIC - bool "generic" - select NUMA - select ACPI_NUMA - select SWIOTLB - select PCI_MSI - help - This selects the system type of your hardware. A "generic" kernel - will run on any supported IA-64 system. However, if you configure - a kernel for your specific system, it will be faster and smaller. - - generic For any supported IA-64 system - DIG-compliant For DIG ("Developer's Interface Guide") compliant systems - DIG+Intel+IOMMU For DIG systems with Intel IOMMU - HP-zx1/sx1000 For HP systems - HP-zx1/sx1000+swiotlb For HP systems with (broken) DMA-constrained devices. - SGI-SN2 For SGI Altix systems - SGI-UV For SGI UV systems - Ski-simulator For the HP simulator - - If you don't know what to do, choose "generic". - -config IA64_DIG - bool "DIG-compliant" - select SWIOTLB - -config IA64_DIG_VTD - bool "DIG+Intel+IOMMU" - select INTEL_IOMMU - select PCI_MSI - -config IA64_HP_ZX1 - bool "HP-zx1/sx1000" - help - Build a kernel that runs on HP zx1 and sx1000 systems. This adds - support for the HP I/O MMU. - -config IA64_HP_ZX1_SWIOTLB - bool "HP-zx1/sx1000 with software I/O TLB" - select SWIOTLB - help - Build a kernel that runs on HP zx1 and sx1000 systems even when they - have broken PCI devices which cannot DMA to full 32 bits. Apart - from support for the HP I/O MMU, this includes support for the software - I/O TLB, which allows supporting the broken devices at the expense of - wasting some kernel memory (about 2MB by default). - -config IA64_SGI_SN2 - bool "SGI-SN2" - select NUMA - select ACPI_NUMA - help - Selecting this option will optimize the kernel for use on sn2 based - systems, but the resulting kernel binary will not run on other - types of ia64 systems. If you have an SGI Altix system, it's safe - to select this option. If in doubt, select ia64 generic support - instead. - -config IA64_SGI_UV - bool "SGI-UV" - select NUMA - select ACPI_NUMA - select SWIOTLB - help - Selecting this option will optimize the kernel for use on UV based - systems, but the resulting kernel binary will not run on other - types of ia64 systems. If you have an SGI UV system, it's safe - to select this option. If in doubt, select ia64 generic support - instead. - -config IA64_HP_SIM - bool "Ski-simulator" - select SWIOTLB - depends on !PM - -endchoice - choice prompt "Processor type" default ITANIUM @@ -252,14 +174,7 @@ config IA64_PAGE_SIZE_64KB endchoice -if IA64_HP_SIM -config HZ - default 32 -endif - -if !IA64_HP_SIM source "kernel/Kconfig.hz" -endif config IA64_BRL_EMU bool @@ -272,17 +187,26 @@ config IA64_L1_CACHE_SHIFT default "7" if MCKINLEY default "6" if ITANIUM +config IA64_SGI_UV + bool "SGI-UV support" + help + Selecting this option will add specific support for running on SGI + UV based systems. If you have an SGI UV system or are building a + distro kernel, select this option. + +config IA64_HP_SBA_IOMMU + bool "HP SBA IOMMU support" + default y + help + Say Y here to add support for the SBA IOMMU found on HP zx1 and + sx1000 systems. If you're unsure, answer Y. + config IA64_CYCLONE bool "Cyclone (EXA) Time Source support" help Say Y here to enable support for IBM EXA Cyclone time source. If you're unsure, answer N. -config IOSAPIC - bool - depends on !IA64_HP_SIM - default y - config FORCE_MAX_ZONEORDER int "MAX_ORDER (11 - 17)" if !HUGETLB_PAGE range 11 17 if !HUGETLB_PAGE @@ -381,14 +305,13 @@ config ARCH_SPARSEMEM_ENABLE select SPARSEMEM_VMEMMAP_ENABLE config ARCH_DISCONTIGMEM_DEFAULT - def_bool y if (IA64_SGI_SN2 || IA64_GENERIC || IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB) + def_bool y depends on ARCH_DISCONTIGMEM_ENABLE config NUMA bool "NUMA support" - depends on !IA64_HP_SIM && !FLATMEM - default y if IA64_SGI_SN2 - select ACPI_NUMA if ACPI + depends on !FLATMEM + select SMP help Say Y to compile the kernel to support NUMA (Non-Uniform Memory Access). This option is for configuring high-end multiprocessor @@ -409,7 +332,7 @@ config NODES_SHIFT config VIRTUAL_MEM_MAP bool "Virtual mem map" depends on !SPARSEMEM - default y if !IA64_HP_SIM + default y help Say Y to compile the kernel with support for a virtual mem map. This code also only takes effect if a memory hole of greater than @@ -472,9 +395,6 @@ config IA64_MC_ERR_INJECT If you're unsure, do not select this option. -config SGI_SN - def_bool y if (IA64_SGI_SN2 || IA64_GENERIC) - config IA64_ESI bool "ESI (Extensible SAL Interface) support" help @@ -493,11 +413,9 @@ config IA64_HP_AML_NFW the "force" module parameter, e.g., with the "aml_nfw.force" kernel command line option. -source "drivers/sn/Kconfig" - config KEXEC bool "kexec system call" - depends on !IA64_HP_SIM && (!SMP || HOTPLUG_CPU) + depends on !SMP || HOTPLUG_CPU select KEXEC_CORE help kexec is a system call that implements the ability to shutdown your @@ -515,7 +433,7 @@ config KEXEC config CRASH_DUMP bool "kernel crash dumps" - depends on IA64_MCA_RECOVERY && !IA64_HP_SIM && (!SMP || HOTPLUG_CPU) + depends on IA64_MCA_RECOVERY && (!SMP || HOTPLUG_CPU) help Generate crash dump after being started by kexec. @@ -537,8 +455,6 @@ endif endmenu -source "arch/ia64/hp/sim/Kconfig" - config MSPEC tristate "Memory special operations driver" depends on IA64 diff --git a/arch/ia64/Kconfig.debug b/arch/ia64/Kconfig.debug index 1371efc9b0055e195fc92f3a8bf41ee8dd9cbee3..40ca23bd228d69a8e16a0aa060ef0ab3e2b909f6 100644 --- a/arch/ia64/Kconfig.debug +++ b/arch/ia64/Kconfig.debug @@ -14,7 +14,7 @@ config IA64_GRANULE_16MB config IA64_GRANULE_64MB bool "64MB" - depends on !(IA64_GENERIC || IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB || IA64_SGI_SN2) + depends on BROKEN endchoice diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index 171290f9f1de48a5d0a8eb627c9468d1fafa1b0a..e0bb2b6aaa35e9049d6dcae7c48370109fa97765 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile @@ -39,29 +39,23 @@ $(error Sorry, you need a newer version of the assember, one that is built from ftp://ftp.hpl.hp.com/pub/linux-ia64/gas-030124.tar.gz) endif +quiet_cmd_gzip = GZIP $@ +cmd_gzip = cat $(real-prereqs) | gzip -n -f -9 > $@ + +quiet_cmd_objcopy = OBJCOPY $@ +cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@ + KBUILD_CFLAGS += $(cflags-y) head-y := arch/ia64/kernel/head.o libs-y += arch/ia64/lib/ core-y += arch/ia64/kernel/ arch/ia64/mm/ -core-$(CONFIG_IA64_DIG) += arch/ia64/dig/ -core-$(CONFIG_IA64_DIG_VTD) += arch/ia64/dig/ -core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/ -core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/ -core-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/dig/ -core-$(CONFIG_IA64_SGI_SN2) += arch/ia64/sn/ core-$(CONFIG_IA64_SGI_UV) += arch/ia64/uv/ -drivers-$(CONFIG_PCI) += arch/ia64/pci/ -drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/ -drivers-$(CONFIG_IA64_HP_ZX1) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ -drivers-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ -drivers-$(CONFIG_IA64_GENERIC) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/ arch/ia64/sn/ arch/ia64/uv/ +drivers-y += arch/ia64/pci/ arch/ia64/hp/common/ drivers-$(CONFIG_OPROFILE) += arch/ia64/oprofile/ -boot := arch/ia64/hp/sim/boot - -PHONY += boot compressed check +PHONY += compressed check all: compressed unwcheck @@ -69,22 +63,21 @@ compressed: vmlinux.gz vmlinuz: vmlinux.gz -vmlinux.gz: vmlinux - $(Q)$(MAKE) $(build)=$(boot) $@ +vmlinux.gz: vmlinux.bin FORCE + $(call if_changed,gzip) + +vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) unwcheck: vmlinux -$(Q)READELF=$(READELF) $(PYTHON) $(srctree)/arch/ia64/scripts/unwcheck.py $< archclean: - $(Q)$(MAKE) $(clean)=$(boot) archheaders: $(Q)$(MAKE) $(build)=arch/ia64/kernel/syscalls all -CLEAN_FILES += vmlinux.gz bootloader - -boot: lib/lib.a vmlinux - $(Q)$(MAKE) $(build)=$(boot) $@ +CLEAN_FILES += vmlinux.gz install: vmlinux.gz sh $(srctree)/arch/ia64/install.sh $(KERNELRELEASE) $< System.map "$(INSTALL_PATH)" @@ -92,7 +85,6 @@ install: vmlinux.gz define archhelp echo '* compressed - Build compressed kernel image' echo ' install - Install compressed kernel image' - echo ' boot - Build vmlinux and bootloader for Ski simulator' echo '* unwcheck - Check vmlinux for invalid unwind info' endef diff --git a/arch/ia64/configs/bigsur_defconfig b/arch/ia64/configs/bigsur_defconfig index b6bda183862902cb3476d72683fb0997287d086b..b630bd7351c41dea031fbfe4b6d141332e6134a8 100644 --- a/arch/ia64/configs/bigsur_defconfig +++ b/arch/ia64/configs/bigsur_defconfig @@ -7,7 +7,6 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_PARTITION_ADVANCED=y CONFIG_SGI_PARTITION=y -CONFIG_IA64_DIG=y CONFIG_SMP=y CONFIG_NR_CPUS=2 CONFIG_PREEMPT=y diff --git a/arch/ia64/configs/generic_defconfig b/arch/ia64/configs/generic_defconfig index 81f686dee53c0107b276a3424bf76e787962effb..661d90b3e148b0e10f3ce2737bbfde4c643933b0 100644 --- a/arch/ia64/configs/generic_defconfig +++ b/arch/ia64/configs/generic_defconfig @@ -44,14 +44,12 @@ CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y -CONFIG_SGI_IOC4=y CONFIG_SGI_XP=m CONFIG_IDE=y CONFIG_BLK_DEV_IDECD=y CONFIG_BLK_DEV_GENERIC=y CONFIG_BLK_DEV_CMD64X=y CONFIG_BLK_DEV_PIIX=y -CONFIG_BLK_DEV_SGIIOC4=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m CONFIG_BLK_DEV_SR=m @@ -90,16 +88,11 @@ CONFIG_IGB=y # CONFIG_SERIO_SERPORT is not set CONFIG_GAMEPORT=m CONFIG_SERIAL_NONSTANDARD=y -CONFIG_SGI_SNSC=y -CONFIG_SGI_TIOCX=y -CONFIG_SGI_MBCS=m CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=6 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_SHARE_IRQ=y -CONFIG_SERIAL_SGI_L1_CONSOLE=y -CONFIG_SERIAL_SGI_IOC4=y # CONFIG_HW_RANDOM is not set CONFIG_EFI_RTC=y CONFIG_RAW_DRIVER=m @@ -107,7 +100,6 @@ CONFIG_HPET=y CONFIG_AGP=m CONFIG_AGP_I460=m CONFIG_AGP_HP_ZX1=m -CONFIG_AGP_SGI_TIOCA=m CONFIG_DRM=m CONFIG_DRM_TDFX=m CONFIG_DRM_R128=m diff --git a/arch/ia64/configs/gensparse_defconfig b/arch/ia64/configs/gensparse_defconfig index 5b4fcdd514576b0eccc7b5c058fbc5ac67118bfc..7844e6a956a4daf011fb2fb61776962da0218196 100644 --- a/arch/ia64/configs/gensparse_defconfig +++ b/arch/ia64/configs/gensparse_defconfig @@ -19,7 +19,6 @@ CONFIG_SPARSEMEM_MANUAL=y CONFIG_IA64_MCA_RECOVERY=y CONFIG_PERFMON=y CONFIG_IA64_PALINFO=y -CONFIG_SGI_IOC3=y CONFIG_EFI_VARS=y CONFIG_BINFMT_MISC=m CONFIG_ACPI_BUTTON=m @@ -37,14 +36,12 @@ CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y -CONFIG_SGI_IOC4=y CONFIG_IDE=y CONFIG_BLK_DEV_IDECD=y CONFIG_IDE_GENERIC=y CONFIG_BLK_DEV_GENERIC=y CONFIG_BLK_DEV_CMD64X=y CONFIG_BLK_DEV_PIIX=y -CONFIG_BLK_DEV_SGIIOC4=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m @@ -79,17 +76,11 @@ CONFIG_E1000=y # CONFIG_SERIO_SERPORT is not set CONFIG_GAMEPORT=m CONFIG_SERIAL_NONSTANDARD=y -CONFIG_SGI_SNSC=y -CONFIG_SGI_TIOCX=y -CONFIG_SGI_MBCS=m CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=6 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_SHARE_IRQ=y -CONFIG_SERIAL_SGI_L1_CONSOLE=y -CONFIG_SERIAL_SGI_IOC4=y -CONFIG_SERIAL_SGI_IOC3=y # CONFIG_HW_RANDOM is not set CONFIG_EFI_RTC=y CONFIG_RAW_DRIVER=m @@ -97,7 +88,6 @@ CONFIG_HPET=y CONFIG_AGP=m CONFIG_AGP_I460=m CONFIG_AGP_HP_ZX1=m -CONFIG_AGP_SGI_TIOCA=m CONFIG_DRM=m CONFIG_DRM_TDFX=m CONFIG_DRM_R128=m diff --git a/arch/ia64/configs/sim_defconfig b/arch/ia64/configs/sim_defconfig deleted file mode 100644 index f0f69fdbddaeb7b2de127819cc462e7ac4e24ae8..0000000000000000000000000000000000000000 --- a/arch/ia64/configs/sim_defconfig +++ /dev/null @@ -1,52 +0,0 @@ -CONFIG_SYSVIPC=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=16 -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -CONFIG_MODVERSIONS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_IA64_HP_SIM=y -CONFIG_MCKINLEY=y -CONFIG_IA64_PAGE_SIZE_64KB=y -CONFIG_SMP=y -CONFIG_NR_CPUS=64 -CONFIG_PREEMPT=y -CONFIG_IA64_PALINFO=m -CONFIG_EFI_VARS=y -CONFIG_BINFMT_MISC=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IPV6 is not set -# CONFIG_STANDALONE is not set -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_SCSI=y -CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y -CONFIG_SCSI_SPI_ATTRS=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO_I8042 is not set -# CONFIG_LEGACY_PTYS is not set -CONFIG_EFI_RTC=y -# CONFIG_VGA_CONSOLE is not set -CONFIG_HP_SIMETH=y -CONFIG_HP_SIMSERIAL=y -CONFIG_HP_SIMSERIAL_CONSOLE=y -CONFIG_HP_SIMSCSI=y -CONFIG_EXT2_FS=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_FS_XATTR is not set -CONFIG_PROC_KCORE=y -CONFIG_HUGETLBFS=y -CONFIG_NFS_FS=y -CONFIG_NFSD=y -CONFIG_NFSD_V3=y -CONFIG_DEBUG_INFO=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_MUTEXES=y diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig index 192ed157c9ceac72fc3c3d66511654ac8a1cf660..1d6e2a01452b1397323f85d80f7cfcdb5b04d477 100644 --- a/arch/ia64/configs/tiger_defconfig +++ b/arch/ia64/configs/tiger_defconfig @@ -12,7 +12,6 @@ CONFIG_MODULE_SRCVERSION_ALL=y # CONFIG_BLK_DEV_BSG is not set CONFIG_PARTITION_ADVANCED=y CONFIG_SGI_PARTITION=y -CONFIG_IA64_DIG=y CONFIG_MCKINLEY=y CONFIG_IA64_PAGE_SIZE_64KB=y CONFIG_IA64_CYCLONE=y diff --git a/arch/ia64/configs/zx1_defconfig b/arch/ia64/configs/zx1_defconfig index b504c8e2fd52b230bf1ca89efcb4d2677ad57b4c..8c92e095f8bb98fc5a26f32e0f84f6a4f952dd5d 100644 --- a/arch/ia64/configs/zx1_defconfig +++ b/arch/ia64/configs/zx1_defconfig @@ -4,7 +4,6 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_KPROBES=y CONFIG_MODULES=y CONFIG_PARTITION_ADVANCED=y -CONFIG_IA64_HP_ZX1=y CONFIG_MCKINLEY=y CONFIG_SMP=y CONFIG_NR_CPUS=16 diff --git a/arch/ia64/dig/Makefile b/arch/ia64/dig/Makefile deleted file mode 100644 index e7f83082547009e3d5fbe3ddc339ad254cc2f3bc..0000000000000000000000000000000000000000 --- a/arch/ia64/dig/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# ia64/platform/dig/Makefile -# -# Copyright (C) 1999 Silicon Graphics, Inc. -# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) -# - -obj-y := setup.o -ifeq ($(CONFIG_INTEL_IOMMU), y) -obj-$(CONFIG_IA64_GENERIC) += machvec.o machvec_vtd.o -else -obj-$(CONFIG_IA64_GENERIC) += machvec.o -endif - diff --git a/arch/ia64/dig/machvec.c b/arch/ia64/dig/machvec.c deleted file mode 100644 index 0c55bdafb473b1720ca2d099f2cd865e14b44177..0000000000000000000000000000000000000000 --- a/arch/ia64/dig/machvec.c +++ /dev/null @@ -1,3 +0,0 @@ -#define MACHVEC_PLATFORM_NAME dig -#define MACHVEC_PLATFORM_HEADER -#include diff --git a/arch/ia64/dig/machvec_vtd.c b/arch/ia64/dig/machvec_vtd.c deleted file mode 100644 index 7cd3eb471cad3f7c51dc0591cf5442019e4a033b..0000000000000000000000000000000000000000 --- a/arch/ia64/dig/machvec_vtd.c +++ /dev/null @@ -1,3 +0,0 @@ -#define MACHVEC_PLATFORM_NAME dig_vtd -#define MACHVEC_PLATFORM_HEADER -#include diff --git a/arch/ia64/dig/setup.c b/arch/ia64/dig/setup.c deleted file mode 100644 index cc14fdce6db6b783b7e880766f9983f44fe4d73c..0000000000000000000000000000000000000000 --- a/arch/ia64/dig/setup.c +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Platform dependent support for DIG64 platforms. - * - * Copyright (C) 1999 Intel Corp. - * Copyright (C) 1999, 2001 Hewlett-Packard Co - * Copyright (C) 1999, 2001, 2003 David Mosberger-Tang - * Copyright (C) 1999 VA Linux Systems - * Copyright (C) 1999 Walt Drummond - * Copyright (C) 1999 Vijay Chander - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -void __init -dig_setup (char **cmdline_p) -{ - unsigned int orig_x, orig_y, num_cols, num_rows, font_height; - - /* - * Default to /dev/sda2. This assumes that the EFI partition - * is physical disk 1 partition 1 and the Linux root disk is - * physical disk 1 partition 2. - */ - ROOT_DEV = Root_SDA2; /* default to second partition on first drive */ - -#ifdef CONFIG_SMP - init_smp_config(); -#endif - - memset(&screen_info, 0, sizeof(screen_info)); - - if (!ia64_boot_param->console_info.num_rows - || !ia64_boot_param->console_info.num_cols) - { - printk(KERN_WARNING "dig_setup: warning: invalid screen-info, guessing 80x25\n"); - orig_x = 0; - orig_y = 0; - num_cols = 80; - num_rows = 25; - font_height = 16; - } else { - orig_x = ia64_boot_param->console_info.orig_x; - orig_y = ia64_boot_param->console_info.orig_y; - num_cols = ia64_boot_param->console_info.num_cols; - num_rows = ia64_boot_param->console_info.num_rows; - font_height = 400 / num_rows; - } - - screen_info.orig_x = orig_x; - screen_info.orig_y = orig_y; - screen_info.orig_video_cols = num_cols; - screen_info.orig_video_lines = num_rows; - screen_info.orig_video_points = font_height; - screen_info.orig_video_mode = 3; /* XXX fake */ - screen_info.orig_video_isVGA = 1; /* XXX fake */ - screen_info.orig_video_ega_bx = 3; /* XXX fake */ -} diff --git a/arch/ia64/hp/common/Makefile b/arch/ia64/hp/common/Makefile index 6026308f9a62656336ffcaca52390623f8434898..11a56ed3822905e077fb7ae03ec2fa5012db6efa 100644 --- a/arch/ia64/hp/common/Makefile +++ b/arch/ia64/hp/common/Makefile @@ -6,7 +6,5 @@ # Copyright (C) Alex Williamson (alex_williamson@hp.com) # -obj-y := sba_iommu.o -obj-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += hwsw_iommu.o -obj-$(CONFIG_IA64_GENERIC) += hwsw_iommu.o +obj-$(CONFIG_IA64_HP_SBA_IOMMU) += sba_iommu.o obj-$(CONFIG_IA64_HP_AML_NFW) += aml_nfw.o diff --git a/arch/ia64/hp/common/hwsw_iommu.c b/arch/ia64/hp/common/hwsw_iommu.c deleted file mode 100644 index 8840ed97712f2c5798366a8d27d1840568935c1e..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/common/hwsw_iommu.c +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2004 Hewlett-Packard Development Company, L.P. - * Contributed by David Mosberger-Tang - * - * This is a pseudo I/O MMU which dispatches to the hardware I/O MMU - * whenever possible. We assume that the hardware I/O MMU requires - * full 32-bit addressability, as is the case, e.g., for HP zx1-based - * systems (there, the I/O MMU window is mapped at 3-4GB). If a - * device doesn't provide full 32-bit addressability, we fall back on - * the sw I/O TLB. This is good enough to let us support broken - * hardware such as soundcards which have a DMA engine that can - * address only 28 bits. - */ - -#include -#include -#include -#include -#include - -extern const struct dma_map_ops sba_dma_ops; - -/* swiotlb declarations & definitions: */ -extern int swiotlb_late_init_with_default_size (size_t size); - -/* - * Note: we need to make the determination of whether or not to use - * the sw I/O TLB based purely on the device structure. Anything else - * would be unreliable or would be too intrusive. - */ -static inline int use_swiotlb(struct device *dev) -{ - return dev && dev->dma_mask && - !sba_dma_ops.dma_supported(dev, *dev->dma_mask); -} - -const struct dma_map_ops *hwsw_dma_get_ops(struct device *dev) -{ - if (use_swiotlb(dev)) - return NULL; - return &sba_dma_ops; -} -EXPORT_SYMBOL(hwsw_dma_get_ops); - -void __init -hwsw_init (void) -{ - /* default to a smallish 2MB sw I/O TLB */ - if (swiotlb_late_init_with_default_size (2 * (1<<20)) != 0) { -#ifdef CONFIG_IA64_GENERIC - /* Better to have normal DMA than panic */ - printk(KERN_WARNING "%s: Failed to initialize software I/O TLB," - " reverting to hpzx1 platform vector\n", __func__); - machvec_init("hpzx1"); -#else - panic("Unable to initialize software I/O TLB services"); -#endif - } -} diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index 3d24cc43385b73061bb33d5fe7611d4d16558ab2..a7eff5e6d2606376c3fc176e5c71dbee14d9c7ca 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -35,6 +35,7 @@ #include #include #include +#include #include /* ia64_get_itc() */ #include @@ -43,8 +44,6 @@ #include -extern int swiotlb_late_init_with_default_size (size_t size); - #define PFX "IOC: " /* @@ -251,12 +250,8 @@ static SBA_INLINE void sba_free_range(struct ioc *, dma_addr_t, size_t); static u64 prefetch_spill_page; #endif -#ifdef CONFIG_PCI -# define GET_IOC(dev) ((dev_is_pci(dev)) \ +#define GET_IOC(dev) ((dev_is_pci(dev)) \ ? ((struct ioc *) PCI_CONTROLLER(to_pci_dev(dev))->iommu) : NULL) -#else -# define GET_IOC(dev) NULL -#endif /* ** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up @@ -1741,9 +1736,7 @@ ioc_sac_init(struct ioc *ioc) controller->iommu = ioc; sac->sysdata = controller; sac->dma_mask = 0xFFFFFFFFUL; -#ifdef CONFIG_PCI sac->dev.bus = &pci_bus_type; -#endif ioc->sac_only_dev = sac; } @@ -2062,27 +2055,33 @@ static int __init acpi_sba_ioc_init_acpi(void) /* This has to run before acpi_scan_init(). */ arch_initcall(acpi_sba_ioc_init_acpi); +static int sba_dma_supported (struct device *dev, u64 mask) +{ + /* make sure it's at least 32bit capable */ + return ((mask & 0xFFFFFFFFUL) == 0xFFFFFFFFUL); +} + +static const struct dma_map_ops sba_dma_ops = { + .alloc = sba_alloc_coherent, + .free = sba_free_coherent, + .map_page = sba_map_page, + .unmap_page = sba_unmap_page, + .map_sg = sba_map_sg_attrs, + .unmap_sg = sba_unmap_sg_attrs, + .dma_supported = sba_dma_supported, +}; + static int __init sba_init(void) { - if (!ia64_platform_is("hpzx1") && !ia64_platform_is("hpzx1_swiotlb")) - return 0; - -#if defined(CONFIG_IA64_GENERIC) - /* If we are booting a kdump kernel, the sba_iommu will - * cause devices that were not shutdown properly to MCA - * as soon as they are turned back on. Our only option for - * a successful kdump kernel boot is to use the swiotlb. + /* + * If we are booting a kdump kernel, the sba_iommu will cause devices + * that were not shutdown properly to MCA as soon as they are turned + * back on. Our only option for a successful kdump kernel boot is to + * use swiotlb. */ - if (is_kdump_kernel()) { - dma_ops = NULL; - if (swiotlb_late_init_with_default_size(64 * (1<<20)) != 0) - panic("Unable to initialize software I/O TLB:" - " Try machvec=dig boot option"); - machvec_init("dig"); + if (is_kdump_kernel()) return 0; - } -#endif /* * ioc_found should be populated by the acpi_sba_ioc_handler's .attach() @@ -2091,43 +2090,18 @@ sba_init(void) while (ioc_found) acpi_sba_ioc_add(ioc_found); - if (!ioc_list) { -#ifdef CONFIG_IA64_GENERIC - /* - * If we didn't find something sba_iommu can claim, we - * need to setup the swiotlb and switch to the dig machvec. - */ - dma_ops = NULL; - if (swiotlb_late_init_with_default_size(64 * (1<<20)) != 0) - panic("Unable to find SBA IOMMU or initialize " - "software I/O TLB: Try machvec=dig boot option"); - machvec_init("dig"); -#else - panic("Unable to find SBA IOMMU: Try a generic or DIG kernel"); -#endif + if (!ioc_list) return 0; - } -#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_HP_ZX1_SWIOTLB) - /* - * hpzx1_swiotlb needs to have a fairly small swiotlb bounce - * buffer setup to support devices with smaller DMA masks than - * sba_iommu can handle. - */ - if (ia64_platform_is("hpzx1_swiotlb")) { - extern void hwsw_init(void); - - hwsw_init(); - } -#endif - -#ifdef CONFIG_PCI { struct pci_bus *b = NULL; while ((b = pci_find_next_bus(b)) != NULL) sba_connect_bus(b); } -#endif + + /* no need for swiotlb with the iommu */ + swiotlb_exit(); + dma_ops = &sba_dma_ops; #ifdef CONFIG_PROC_FS ioc_proc_init(); @@ -2144,12 +2118,6 @@ nosbagart(char *str) return 1; } -static int sba_dma_supported (struct device *dev, u64 mask) -{ - /* make sure it's at least 32bit capable */ - return ((mask & 0xFFFFFFFFUL) == 0xFFFFFFFFUL); -} - __setup("nosbagart", nosbagart); static int __init @@ -2174,18 +2142,3 @@ sba_page_override(char *str) } __setup("sbapagesize=",sba_page_override); - -const struct dma_map_ops sba_dma_ops = { - .alloc = sba_alloc_coherent, - .free = sba_free_coherent, - .map_page = sba_map_page, - .unmap_page = sba_unmap_page, - .map_sg = sba_map_sg_attrs, - .unmap_sg = sba_unmap_sg_attrs, - .dma_supported = sba_dma_supported, -}; - -void sba_dma_init(void) -{ - dma_ops = &sba_dma_ops; -} diff --git a/arch/ia64/hp/sim/Kconfig b/arch/ia64/hp/sim/Kconfig deleted file mode 100644 index 56fb4f1d4f7c7c501567f41dd9e18f17da89ff97..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -menu "HP Simulator drivers" - depends on IA64_HP_SIM || IA64_GENERIC - -config HP_SIMETH - bool "Simulated Ethernet " - depends on NET - -config HP_SIMSERIAL - bool "Simulated serial driver support" - depends on TTY - -config HP_SIMSERIAL_CONSOLE - bool "Console for HP simulator" - depends on HP_SIMSERIAL - -config HP_SIMSCSI - bool "Simulated SCSI disk" - depends on SCSI=y - -endmenu - diff --git a/arch/ia64/hp/sim/Makefile b/arch/ia64/hp/sim/Makefile deleted file mode 100644 index 0224a13d2c5b88efafe94aa183e6a598d2316ba2..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# ia64/platform/hp/sim/Makefile -# -# Copyright (C) 2002 Hewlett-Packard Co. -# David Mosberger-Tang -# Copyright (C) 1999 Silicon Graphics, Inc. -# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) -# - -obj-y := hpsim_irq.o hpsim_setup.o hpsim.o -obj-$(CONFIG_IA64_GENERIC) += hpsim_machvec.o - -obj-$(CONFIG_HP_SIMETH) += simeth.o -obj-$(CONFIG_HP_SIMSERIAL) += simserial.o -obj-$(CONFIG_HP_SIMSERIAL_CONSOLE) += hpsim_console.o -obj-$(CONFIG_HP_SIMSCSI) += simscsi.o diff --git a/arch/ia64/hp/sim/boot/Makefile b/arch/ia64/hp/sim/boot/Makefile deleted file mode 100644 index df6e9968c84541c0dafdd3306b452fa762e3185f..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/boot/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -# -# ia64/boot/Makefile -# -# This file is subject to the terms and conditions of the GNU General Public -# License. See the file "COPYING" in the main directory of this archive -# for more details. -# -# Copyright (C) 1998, 2003 by David Mosberger-Tang -# - -targets-$(CONFIG_IA64_HP_SIM) += bootloader -targets := vmlinux.bin vmlinux.gz $(targets-y) - -quiet_cmd_cptotop = LN $@ - cmd_cptotop = ln -f $< $@ - -vmlinux.gz: $(obj)/vmlinux.gz $(addprefix $(obj)/,$(targets-y)) - $(call cmd,cptotop) - @echo ' Kernel: $@ is ready' - -boot: bootloader - -bootloader: $(obj)/bootloader - $(call cmd,cptotop) - -$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE - $(call if_changed,gzip) - -$(obj)/vmlinux.bin: vmlinux FORCE - $(call if_changed,objcopy) - - -LDFLAGS_bootloader = -static -T - -$(obj)/bootloader: $(src)/bootloader.lds $(obj)/bootloader.o $(obj)/boot_head.o $(obj)/fw-emu.o \ - lib/lib.a arch/ia64/lib/lib.a FORCE - $(call if_changed,ld) diff --git a/arch/ia64/hp/sim/boot/boot_head.S b/arch/ia64/hp/sim/boot/boot_head.S deleted file mode 100644 index a7d178fb41e8f5360824fe06a1589909b681bfa5..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/boot/boot_head.S +++ /dev/null @@ -1,165 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 1998-2003 Hewlett-Packard Co - * David Mosberger-Tang - */ - -#include -#include - - .bss - .align 16 -stack_mem: - .skip 16834 - - .text - -/* This needs to be defined because lib/string.c:strlcat() calls it in case of error... */ -GLOBAL_ENTRY(printk) - break 0 -END(printk) - -GLOBAL_ENTRY(_start) - .prologue - .save rp, r0 - .body - movl gp = __gp - movl sp = stack_mem+16384-16 - bsw.1 - br.call.sptk.many rp=start_bootloader -0: nop 0 /* dummy nop to make unwinding work */ -END(_start) - -/* - * Set a break point on this function so that symbols are available to set breakpoints in - * the kernel being debugged. - */ -GLOBAL_ENTRY(debug_break) - br.ret.sptk.many b0 -END(debug_break) - -GLOBAL_ENTRY(ssc) - .regstk 5,0,0,0 - mov r15=in4 - break 0x80001 - br.ret.sptk.many b0 -END(ssc) - -GLOBAL_ENTRY(jmp_to_kernel) - .regstk 2,0,0,0 - mov r28=in0 - mov b7=in1 - br.sptk.few b7 -END(jmp_to_kernel) - -/* - * r28 contains the index of the PAL function - * r29--31 the args - * Return values in ret0--3 (r8--11) - */ -GLOBAL_ENTRY(pal_emulator_static) - mov r8=-1 - mov r9=256 - ;; - cmp.gtu p6,p7=r9,r28 /* r28 <= 255? */ -(p6) br.cond.sptk.few static - ;; - mov r9=512 - ;; - cmp.gtu p6,p7=r9,r28 -(p6) br.cond.sptk.few stacked - ;; -static: cmp.eq p6,p7=PAL_PTCE_INFO,r28 -(p7) br.cond.sptk.few 1f - ;; - mov r8=0 /* status = 0 */ - movl r9=0x100000000 /* tc.base */ - movl r10=0x0000000200000003 /* count[0], count[1] */ - movl r11=0x1000000000002000 /* stride[0], stride[1] */ - br.cond.sptk.few rp -1: cmp.eq p6,p7=PAL_FREQ_RATIOS,r28 -(p7) br.cond.sptk.few 1f - mov r8=0 /* status = 0 */ - movl r9 =0x100000064 /* proc_ratio (1/100) */ - movl r10=0x100000100 /* bus_ratio<<32 (1/256) */ - movl r11=0x100000064 /* itc_ratio<<32 (1/100) */ - ;; -1: cmp.eq p6,p7=PAL_RSE_INFO,r28 -(p7) br.cond.sptk.few 1f - mov r8=0 /* status = 0 */ - mov r9=96 /* num phys stacked */ - mov r10=0 /* hints */ - mov r11=0 - br.cond.sptk.few rp -1: cmp.eq p6,p7=PAL_CACHE_FLUSH,r28 /* PAL_CACHE_FLUSH */ -(p7) br.cond.sptk.few 1f - mov r9=ar.lc - movl r8=524288 /* flush 512k million cache lines (16MB) */ - ;; - mov ar.lc=r8 - movl r8=0xe000000000000000 - ;; -.loop: fc r8 - add r8=32,r8 - br.cloop.sptk.few .loop - sync.i - ;; - srlz.i - ;; - mov ar.lc=r9 - mov r8=r0 - ;; -1: cmp.eq p6,p7=PAL_PERF_MON_INFO,r28 -(p7) br.cond.sptk.few 1f - mov r8=0 /* status = 0 */ - movl r9 =0x08122f04 /* generic=4 width=47 retired=8 cycles=18 */ - mov r10=0 /* reserved */ - mov r11=0 /* reserved */ - mov r16=0xffff /* implemented PMC */ - mov r17=0x3ffff /* implemented PMD */ - add r18=8,r29 /* second index */ - ;; - st8 [r29]=r16,16 /* store implemented PMC */ - st8 [r18]=r0,16 /* clear remaining bits */ - ;; - st8 [r29]=r0,16 /* clear remaining bits */ - st8 [r18]=r0,16 /* clear remaining bits */ - ;; - st8 [r29]=r17,16 /* store implemented PMD */ - st8 [r18]=r0,16 /* clear remaining bits */ - mov r16=0xf0 /* cycles count capable PMC */ - ;; - st8 [r29]=r0,16 /* clear remaining bits */ - st8 [r18]=r0,16 /* clear remaining bits */ - mov r17=0xf0 /* retired bundles capable PMC */ - ;; - st8 [r29]=r16,16 /* store cycles capable */ - st8 [r18]=r0,16 /* clear remaining bits */ - ;; - st8 [r29]=r0,16 /* clear remaining bits */ - st8 [r18]=r0,16 /* clear remaining bits */ - ;; - st8 [r29]=r17,16 /* store retired bundle capable */ - st8 [r18]=r0,16 /* clear remaining bits */ - ;; - st8 [r29]=r0,16 /* clear remaining bits */ - st8 [r18]=r0,16 /* clear remaining bits */ - ;; -1: cmp.eq p6,p7=PAL_VM_SUMMARY,r28 -(p7) br.cond.sptk.few 1f - mov r8=0 /* status = 0 */ - movl r9=0x2044040020F1865 /* num_tc_levels=2, num_unique_tcs=4 */ - /* max_itr_entry=64, max_dtr_entry=64 */ - /* hash_tag_id=2, max_pkr=15 */ - /* key_size=24, phys_add_size=50, vw=1 */ - movl r10=0x183C /* rid_size=24, impl_va_msb=60 */ - ;; -1: cmp.eq p6,p7=PAL_MEM_ATTRIB,r28 -(p7) br.cond.sptk.few 1f - mov r8=0 /* status = 0 */ - mov r9=0x80|0x01 /* NatPage|WB */ - ;; -1: br.cond.sptk.few rp -stacked: - br.ret.sptk.few rp -END(pal_emulator_static) diff --git a/arch/ia64/hp/sim/boot/bootloader.c b/arch/ia64/hp/sim/boot/bootloader.c deleted file mode 100644 index 6d804608dc812e4246af9ac7ed117cd0f4799cba..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/boot/bootloader.c +++ /dev/null @@ -1,175 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * arch/ia64/hp/sim/boot/bootloader.c - * - * Loads an ELF kernel. - * - * Copyright (C) 1998-2003 Hewlett-Packard Co - * David Mosberger-Tang - * Stephane Eranian - * - * 01/07/99 S.Eranian modified to pass command line arguments to kernel - */ -struct task_struct; /* forward declaration for elf.h */ - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "ssc.h" - -struct disk_req { - unsigned long addr; - unsigned len; -}; - -struct disk_stat { - int fd; - unsigned count; -}; - -extern void jmp_to_kernel (unsigned long bp, unsigned long e_entry); -extern struct ia64_boot_param *sys_fw_init (const char *args, int arglen); -extern void debug_break (void); - -static void -cons_write (const char *buf) -{ - unsigned long ch; - - while ((ch = *buf++) != '\0') { - ssc(ch, 0, 0, 0, SSC_PUTCHAR); - if (ch == '\n') - ssc('\r', 0, 0, 0, SSC_PUTCHAR); - } -} - -#define MAX_ARGS 32 - -void -start_bootloader (void) -{ - static char mem[4096]; - static char buffer[1024]; - unsigned long off; - int fd, i; - struct disk_req req; - struct disk_stat stat; - struct elfhdr *elf; - struct elf_phdr *elf_phdr; /* program header */ - unsigned long e_entry, e_phoff, e_phnum; - register struct ia64_boot_param *bp; - char *kpath, *args; - long arglen = 0; - - ssc(0, 0, 0, 0, SSC_CONSOLE_INIT); - - /* - * S.Eranian: extract the commandline argument from the simulator - * - * The expected format is as follows: - * - * kernelname args... - * - * Both are optional but you can't have the second one without the first. - */ - arglen = ssc((long) buffer, 0, 0, 0, SSC_GET_ARGS); - - kpath = "vmlinux"; - args = buffer; - if (arglen > 0) { - kpath = buffer; - while (*args != ' ' && *args != '\0') - ++args, --arglen; - if (*args == ' ') - *args++ = '\0', --arglen; - } - - if (arglen <= 0) { - args = ""; - arglen = 1; - } - - fd = ssc((long) kpath, 1, 0, 0, SSC_OPEN); - - if (fd < 0) { - cons_write(kpath); - cons_write(": file not found, reboot now\n"); - for(;;); - } - stat.fd = fd; - off = 0; - - req.len = sizeof(mem); - req.addr = (long) mem; - ssc(fd, 1, (long) &req, off, SSC_READ); - ssc((long) &stat, 0, 0, 0, SSC_WAIT_COMPLETION); - - elf = (struct elfhdr *) mem; - if (elf->e_ident[0] == 0x7f && strncmp(elf->e_ident + 1, "ELF", 3) != 0) { - cons_write("not an ELF file\n"); - return; - } - if (elf->e_type != ET_EXEC) { - cons_write("not an ELF executable\n"); - return; - } - if (!elf_check_arch(elf)) { - cons_write("kernel not for this processor\n"); - return; - } - - e_entry = elf->e_entry; - e_phnum = elf->e_phnum; - e_phoff = elf->e_phoff; - - cons_write("loading "); - cons_write(kpath); - cons_write("...\n"); - - for (i = 0; i < e_phnum; ++i) { - req.len = sizeof(*elf_phdr); - req.addr = (long) mem; - ssc(fd, 1, (long) &req, e_phoff, SSC_READ); - ssc((long) &stat, 0, 0, 0, SSC_WAIT_COMPLETION); - if (stat.count != sizeof(*elf_phdr)) { - cons_write("failed to read phdr\n"); - return; - } - e_phoff += sizeof(*elf_phdr); - - elf_phdr = (struct elf_phdr *) mem; - - if (elf_phdr->p_type != PT_LOAD) - continue; - - req.len = elf_phdr->p_filesz; - req.addr = __pa(elf_phdr->p_paddr); - ssc(fd, 1, (long) &req, elf_phdr->p_offset, SSC_READ); - ssc((long) &stat, 0, 0, 0, SSC_WAIT_COMPLETION); - memset((char *)__pa(elf_phdr->p_paddr) + elf_phdr->p_filesz, 0, - elf_phdr->p_memsz - elf_phdr->p_filesz); - } - ssc(fd, 0, 0, 0, SSC_CLOSE); - - cons_write("starting kernel...\n"); - - /* fake an I/O base address: */ - ia64_setreg(_IA64_REG_AR_KR0, 0xffffc000000UL); - - bp = sys_fw_init(args, arglen); - - ssc(0, (long) kpath, 0, 0, SSC_LOAD_SYMBOLS); - - debug_break(); - jmp_to_kernel((unsigned long) bp, e_entry); - - cons_write("kernel returned!\n"); - ssc(-1, 0, 0, 0, SSC_EXIT); -} diff --git a/arch/ia64/hp/sim/boot/bootloader.lds b/arch/ia64/hp/sim/boot/bootloader.lds deleted file mode 100644 index f3f284d6514caf7c934ff0ae398bcf5601e683c2..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/boot/bootloader.lds +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -OUTPUT_FORMAT("elf64-ia64-little") -OUTPUT_ARCH(ia64) -ENTRY(_start) -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = 0x100000; - - _text = .; - .text : { *(__ivt_section) *(.text) } - _etext = .; - - /* Global data */ - _data = .; - .rodata : { *(.rodata) *(.rodata.*) } - .data : { *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS } - __gp = ALIGN (8) + 0x200000; - .got : { *(.got.plt) *(.got) } - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : { *(.sdata) } - _edata = .; - - __bss_start = .; - .sbss : { *(.sbss) *(.scommon) } - .bss : { *(.bss) *(COMMON) } - . = ALIGN(64 / 8); - __bss_stop = .; - _end = . ; - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - /* These must appear regardless of . */ -} diff --git a/arch/ia64/hp/sim/boot/fw-emu.c b/arch/ia64/hp/sim/boot/fw-emu.c deleted file mode 100644 index 517fb2822e04b2ec365f9a5649f278b4e520836c..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/boot/fw-emu.c +++ /dev/null @@ -1,374 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * PAL & SAL emulation. - * - * Copyright (C) 1998-2001 Hewlett-Packard Co - * David Mosberger-Tang - */ - -#ifdef CONFIG_PCI -# include -#endif - -#include -#include -#include -#include -#include - -#include "ssc.h" - -#define MB (1024*1024UL) - -#define SIMPLE_MEMMAP 1 - -#if SIMPLE_MEMMAP -# define NUM_MEM_DESCS 4 -#else -# define NUM_MEM_DESCS 16 -#endif - -static char fw_mem[( sizeof(struct ia64_boot_param) - + sizeof(efi_system_table_t) - + sizeof(efi_runtime_services_t) - + 1*sizeof(efi_config_table_t) - + sizeof(struct ia64_sal_systab) - + sizeof(struct ia64_sal_desc_entry_point) - + NUM_MEM_DESCS*(sizeof(efi_memory_desc_t)) - + 1024)] __attribute__ ((aligned (8))); - -#define SECS_PER_HOUR (60 * 60) -#define SECS_PER_DAY (SECS_PER_HOUR * 24) - -/* Compute the `struct tm' representation of *T, - offset OFFSET seconds east of UTC, - and store year, yday, mon, mday, wday, hour, min, sec into *TP. - Return nonzero if successful. */ -int -offtime (unsigned long t, efi_time_t *tp) -{ - const unsigned short int __mon_yday[2][13] = - { - /* Normal years. */ - { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, - /* Leap years. */ - { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } - }; - long int days, rem, y; - const unsigned short int *ip; - - days = t / SECS_PER_DAY; - rem = t % SECS_PER_DAY; - while (rem < 0) { - rem += SECS_PER_DAY; - --days; - } - while (rem >= SECS_PER_DAY) { - rem -= SECS_PER_DAY; - ++days; - } - tp->hour = rem / SECS_PER_HOUR; - rem %= SECS_PER_HOUR; - tp->minute = rem / 60; - tp->second = rem % 60; - /* January 1, 1970 was a Thursday. */ - y = 1970; - -# define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) -# define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) -# define __isleap(year) \ - ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) - - while (days < 0 || days >= (__isleap (y) ? 366 : 365)) { - /* Guess a corrected year, assuming 365 days per year. */ - long int yg = y + days / 365 - (days % 365 < 0); - - /* Adjust DAYS and Y to match the guessed year. */ - days -= ((yg - y) * 365 + LEAPS_THRU_END_OF (yg - 1) - - LEAPS_THRU_END_OF (y - 1)); - y = yg; - } - tp->year = y; - ip = __mon_yday[__isleap(y)]; - for (y = 11; days < (long int) ip[y]; --y) - continue; - days -= ip[y]; - tp->month = y + 1; - tp->day = days + 1; - return 1; -} - -extern void pal_emulator_static (void); - -/* Macro to emulate SAL call using legacy IN and OUT calls to CF8, CFC etc.. */ - -#define BUILD_CMD(addr) ((0x80000000 | (addr)) & ~3) - -#define REG_OFFSET(addr) (0x00000000000000FF & (addr)) -#define DEVICE_FUNCTION(addr) (0x000000000000FF00 & (addr)) -#define BUS_NUMBER(addr) (0x0000000000FF0000 & (addr)) - -static efi_status_t -fw_efi_get_time (efi_time_t *tm, efi_time_cap_t *tc) -{ -#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_GENERIC) - struct { - int tv_sec; /* must be 32bits to work */ - int tv_usec; - } tv32bits; - - ssc((unsigned long) &tv32bits, 0, 0, 0, SSC_GET_TOD); - - memset(tm, 0, sizeof(*tm)); - offtime(tv32bits.tv_sec, tm); - - if (tc) - memset(tc, 0, sizeof(*tc)); -#else -# error Not implemented yet... -#endif - return EFI_SUCCESS; -} - -static void -efi_reset_system (int reset_type, efi_status_t status, unsigned long data_size, efi_char16_t *data) -{ -#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_GENERIC) - ssc(status, 0, 0, 0, SSC_EXIT); -#else -# error Not implemented yet... -#endif -} - -static efi_status_t -efi_unimplemented (void) -{ - return EFI_UNSUPPORTED; -} - -static struct sal_ret_values -sal_emulator (long index, unsigned long in1, unsigned long in2, - unsigned long in3, unsigned long in4, unsigned long in5, - unsigned long in6, unsigned long in7) -{ - long r9 = 0; - long r10 = 0; - long r11 = 0; - long status; - - /* - * Don't do a "switch" here since that gives us code that - * isn't self-relocatable. - */ - status = 0; - if (index == SAL_FREQ_BASE) { - if (in1 == SAL_FREQ_BASE_PLATFORM) - r9 = 200000000; - else if (in1 == SAL_FREQ_BASE_INTERVAL_TIMER) { - /* - * Is this supposed to be the cr.itc frequency - * or something platform specific? The SAL - * doc ain't exactly clear on this... - */ - r9 = 700000000; - } else if (in1 == SAL_FREQ_BASE_REALTIME_CLOCK) - r9 = 1; - else - status = -1; - } else if (index == SAL_SET_VECTORS) { - ; - } else if (index == SAL_GET_STATE_INFO) { - ; - } else if (index == SAL_GET_STATE_INFO_SIZE) { - ; - } else if (index == SAL_CLEAR_STATE_INFO) { - ; - } else if (index == SAL_MC_RENDEZ) { - ; - } else if (index == SAL_MC_SET_PARAMS) { - ; - } else if (index == SAL_CACHE_FLUSH) { - ; - } else if (index == SAL_CACHE_INIT) { - ; -#ifdef CONFIG_PCI - } else if (index == SAL_PCI_CONFIG_READ) { - /* - * in1 contains the PCI configuration address and in2 - * the size of the read. The value that is read is - * returned via the general register r9. - */ - outl(BUILD_CMD(in1), 0xCF8); - if (in2 == 1) /* Reading byte */ - r9 = inb(0xCFC + ((REG_OFFSET(in1) & 3))); - else if (in2 == 2) /* Reading word */ - r9 = inw(0xCFC + ((REG_OFFSET(in1) & 2))); - else /* Reading dword */ - r9 = inl(0xCFC); - status = PCIBIOS_SUCCESSFUL; - } else if (index == SAL_PCI_CONFIG_WRITE) { - /* - * in1 contains the PCI configuration address, in2 the - * size of the write, and in3 the actual value to be - * written out. - */ - outl(BUILD_CMD(in1), 0xCF8); - if (in2 == 1) /* Writing byte */ - outb(in3, 0xCFC + ((REG_OFFSET(in1) & 3))); - else if (in2 == 2) /* Writing word */ - outw(in3, 0xCFC + ((REG_OFFSET(in1) & 2))); - else /* Writing dword */ - outl(in3, 0xCFC); - status = PCIBIOS_SUCCESSFUL; -#endif /* CONFIG_PCI */ - } else if (index == SAL_UPDATE_PAL) { - ; - } else { - status = -1; - } - return ((struct sal_ret_values) {status, r9, r10, r11}); -} - -struct ia64_boot_param * -sys_fw_init (const char *args, int arglen) -{ - efi_system_table_t *efi_systab; - efi_runtime_services_t *efi_runtime; - efi_config_table_t *efi_tables; - struct ia64_sal_systab *sal_systab; - efi_memory_desc_t *efi_memmap, *md; - unsigned long *pal_desc, *sal_desc; - struct ia64_sal_desc_entry_point *sal_ed; - struct ia64_boot_param *bp; - unsigned char checksum = 0; - char *cp, *cmd_line; - int i = 0; -# define MAKE_MD(typ, attr, start, end) \ - do { \ - md = efi_memmap + i++; \ - md->type = typ; \ - md->pad = 0; \ - md->phys_addr = start; \ - md->virt_addr = 0; \ - md->num_pages = (end - start) >> 12; \ - md->attribute = attr; \ - } while (0) - - memset(fw_mem, 0, sizeof(fw_mem)); - - pal_desc = (unsigned long *) &pal_emulator_static; - sal_desc = (unsigned long *) &sal_emulator; - - cp = fw_mem; - efi_systab = (void *) cp; cp += sizeof(*efi_systab); - efi_runtime = (void *) cp; cp += sizeof(*efi_runtime); - efi_tables = (void *) cp; cp += sizeof(*efi_tables); - sal_systab = (void *) cp; cp += sizeof(*sal_systab); - sal_ed = (void *) cp; cp += sizeof(*sal_ed); - efi_memmap = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap); - bp = (void *) cp; cp += sizeof(*bp); - cmd_line = (void *) cp; - - if (args) { - if (arglen >= 1024) - arglen = 1023; - memcpy(cmd_line, args, arglen); - } else { - arglen = 0; - } - cmd_line[arglen] = '\0'; - - memset(efi_systab, 0, sizeof(*efi_systab)); - efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE; - efi_systab->hdr.revision = ((1 << 16) | 00); - efi_systab->hdr.headersize = sizeof(efi_systab->hdr); - efi_systab->fw_vendor = __pa("H\0e\0w\0l\0e\0t\0t\0-\0P\0a\0c\0k\0a\0r\0d\0\0"); - efi_systab->fw_revision = 1; - efi_systab->runtime = (void *) __pa(efi_runtime); - efi_systab->nr_tables = 1; - efi_systab->tables = __pa(efi_tables); - - efi_runtime->hdr.signature = EFI_RUNTIME_SERVICES_SIGNATURE; - efi_runtime->hdr.revision = EFI_RUNTIME_SERVICES_REVISION; - efi_runtime->hdr.headersize = sizeof(efi_runtime->hdr); - efi_runtime->get_time = (void *)__pa(&fw_efi_get_time); - efi_runtime->set_time = (void *)__pa(&efi_unimplemented); - efi_runtime->get_wakeup_time = (void *)__pa(&efi_unimplemented); - efi_runtime->set_wakeup_time = (void *)__pa(&efi_unimplemented); - efi_runtime->set_virtual_address_map = (void *)__pa(&efi_unimplemented); - efi_runtime->get_variable = (void *)__pa(&efi_unimplemented); - efi_runtime->get_next_variable = (void *)__pa(&efi_unimplemented); - efi_runtime->set_variable = (void *)__pa(&efi_unimplemented); - efi_runtime->get_next_high_mono_count = (void *)__pa(&efi_unimplemented); - efi_runtime->reset_system = (void *)__pa(&efi_reset_system); - - efi_tables->guid = SAL_SYSTEM_TABLE_GUID; - efi_tables->table = __pa(sal_systab); - - /* fill in the SAL system table: */ - memcpy(sal_systab->signature, "SST_", 4); - sal_systab->size = sizeof(*sal_systab); - sal_systab->sal_rev_minor = 1; - sal_systab->sal_rev_major = 0; - sal_systab->entry_count = 1; - -#ifdef CONFIG_IA64_GENERIC - strcpy(sal_systab->oem_id, "Generic"); - strcpy(sal_systab->product_id, "IA-64 system"); -#endif - -#ifdef CONFIG_IA64_HP_SIM - strcpy(sal_systab->oem_id, "Hewlett-Packard"); - strcpy(sal_systab->product_id, "HP-simulator"); -#endif - - /* fill in an entry point: */ - sal_ed->type = SAL_DESC_ENTRY_POINT; - sal_ed->pal_proc = __pa(pal_desc[0]); - sal_ed->sal_proc = __pa(sal_desc[0]); - sal_ed->gp = __pa(sal_desc[1]); - - for (cp = (char *) sal_systab; cp < (char *) efi_memmap; ++cp) - checksum += *cp; - - sal_systab->checksum = -checksum; - -#if SIMPLE_MEMMAP - /* simulate free memory at physical address zero */ - MAKE_MD(EFI_BOOT_SERVICES_DATA, EFI_MEMORY_WB, 0*MB, 1*MB); - MAKE_MD(EFI_PAL_CODE, EFI_MEMORY_WB, 1*MB, 2*MB); - MAKE_MD(EFI_CONVENTIONAL_MEMORY, EFI_MEMORY_WB, 2*MB, 130*MB); - MAKE_MD(EFI_CONVENTIONAL_MEMORY, EFI_MEMORY_WB, 4096*MB, 4128*MB); -#else - MAKE_MD( 4, 0x9, 0x0000000000000000, 0x0000000000001000); - MAKE_MD( 7, 0x9, 0x0000000000001000, 0x000000000008a000); - MAKE_MD( 4, 0x9, 0x000000000008a000, 0x00000000000a0000); - MAKE_MD( 5, 0x8000000000000009, 0x00000000000c0000, 0x0000000000100000); - MAKE_MD( 7, 0x9, 0x0000000000100000, 0x0000000004400000); - MAKE_MD( 2, 0x9, 0x0000000004400000, 0x0000000004be5000); - MAKE_MD( 7, 0x9, 0x0000000004be5000, 0x000000007f77e000); - MAKE_MD( 6, 0x8000000000000009, 0x000000007f77e000, 0x000000007fb94000); - MAKE_MD( 6, 0x8000000000000009, 0x000000007fb94000, 0x000000007fb95000); - MAKE_MD( 6, 0x8000000000000009, 0x000000007fb95000, 0x000000007fc00000); - MAKE_MD(13, 0x8000000000000009, 0x000000007fc00000, 0x000000007fc3a000); - MAKE_MD( 7, 0x9, 0x000000007fc3a000, 0x000000007fea0000); - MAKE_MD( 5, 0x8000000000000009, 0x000000007fea0000, 0x000000007fea8000); - MAKE_MD( 7, 0x9, 0x000000007fea8000, 0x000000007feab000); - MAKE_MD( 5, 0x8000000000000009, 0x000000007feab000, 0x000000007ffff000); - MAKE_MD( 7, 0x9, 0x00000000ff400000, 0x0000000104000000); -#endif - - bp->efi_systab = __pa(&fw_mem); - bp->efi_memmap = __pa(efi_memmap); - bp->efi_memmap_size = NUM_MEM_DESCS*sizeof(efi_memory_desc_t); - bp->efi_memdesc_size = sizeof(efi_memory_desc_t); - bp->efi_memdesc_version = 1; - bp->command_line = __pa(cmd_line); - bp->console_info.num_cols = 80; - bp->console_info.num_rows = 25; - bp->console_info.orig_x = 0; - bp->console_info.orig_y = 24; - bp->fpswa = 0; - - return bp; -} diff --git a/arch/ia64/hp/sim/boot/ssc.h b/arch/ia64/hp/sim/boot/ssc.h deleted file mode 100644 index 88752c7509e04dd91ab93388761f0b8f692482f8..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/boot/ssc.h +++ /dev/null @@ -1,36 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 1998-2003 Hewlett-Packard Co - * David Mosberger-Tang - * Stephane Eranian - */ -#ifndef ssc_h -#define ssc_h - -/* Simulator system calls: */ - -#define SSC_CONSOLE_INIT 20 -#define SSC_GETCHAR 21 -#define SSC_PUTCHAR 31 -#define SSC_OPEN 50 -#define SSC_CLOSE 51 -#define SSC_READ 52 -#define SSC_WRITE 53 -#define SSC_GET_COMPLETION 54 -#define SSC_WAIT_COMPLETION 55 -#define SSC_CONNECT_INTERRUPT 58 -#define SSC_GENERATE_INTERRUPT 59 -#define SSC_SET_PERIODIC_INTERRUPT 60 -#define SSC_GET_RTC 65 -#define SSC_EXIT 66 -#define SSC_LOAD_SYMBOLS 69 -#define SSC_GET_TOD 74 - -#define SSC_GET_ARGS 75 - -/* - * Simulator system call. - */ -extern long ssc (long arg0, long arg1, long arg2, long arg3, int nr); - -#endif /* ssc_h */ diff --git a/arch/ia64/hp/sim/hpsim.S b/arch/ia64/hp/sim/hpsim.S deleted file mode 100644 index 44b4d53e1689cee99eee576daad6abaf5ef5dd1e..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/hpsim.S +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#include - -/* - * Simulator system call. - */ -GLOBAL_ENTRY(ia64_ssc) - mov r15=r36 - break 0x80001 - br.ret.sptk.many rp -END(ia64_ssc) diff --git a/arch/ia64/hp/sim/hpsim_console.c b/arch/ia64/hp/sim/hpsim_console.c deleted file mode 100644 index bffd9f67a8a17b13ee11d7c29331ada9400cad7c..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/hpsim_console.c +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Platform dependent support for HP simulator. - * - * Copyright (C) 1998, 1999, 2002 Hewlett-Packard Co - * David Mosberger-Tang - * Copyright (C) 1999 Vijay Chander - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "hpsim_ssc.h" - -static int simcons_init (struct console *, char *); -static void simcons_write (struct console *, const char *, unsigned); -static struct tty_driver *simcons_console_device (struct console *, int *); - -static struct console hpsim_cons = { - .name = "simcons", - .write = simcons_write, - .device = simcons_console_device, - .setup = simcons_init, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -static int -simcons_init (struct console *cons, char *options) -{ - return 0; -} - -static void -simcons_write (struct console *cons, const char *buf, unsigned count) -{ - unsigned long ch; - - while (count-- > 0) { - ch = *buf++; - ia64_ssc(ch, 0, 0, 0, SSC_PUTCHAR); - if (ch == '\n') - ia64_ssc('\r', 0, 0, 0, SSC_PUTCHAR); - } -} - -static struct tty_driver *simcons_console_device (struct console *c, int *index) -{ - *index = c->index; - return hp_simserial_driver; -} - -int simcons_register(void) -{ - if (!ia64_platform_is("hpsim")) - return 1; - - if (hpsim_cons.flags & CON_ENABLED) - return 1; - - register_console(&hpsim_cons); - return 0; -} diff --git a/arch/ia64/hp/sim/hpsim_irq.c b/arch/ia64/hp/sim/hpsim_irq.c deleted file mode 100644 index 2f1cc59650ab58a1ae6ab8b2cc9ab484c7713bf8..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/hpsim_irq.c +++ /dev/null @@ -1,76 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Platform dependent support for HP simulator. - * - * Copyright (C) 1998-2001 Hewlett-Packard Co - * Copyright (C) 1998-2001 David Mosberger-Tang - */ - -#include -#include -#include -#include - -#include "hpsim_ssc.h" - -static unsigned int -hpsim_irq_startup(struct irq_data *data) -{ - return 0; -} - -static void -hpsim_irq_noop(struct irq_data *data) -{ -} - -static int -hpsim_set_affinity_noop(struct irq_data *d, const struct cpumask *b, bool f) -{ - return 0; -} - -static struct irq_chip irq_type_hp_sim = { - .name = "hpsim", - .irq_startup = hpsim_irq_startup, - .irq_shutdown = hpsim_irq_noop, - .irq_enable = hpsim_irq_noop, - .irq_disable = hpsim_irq_noop, - .irq_ack = hpsim_irq_noop, - .irq_set_affinity = hpsim_set_affinity_noop, -}; - -static void hpsim_irq_set_chip(int irq) -{ - struct irq_chip *chip = irq_get_chip(irq); - - if (chip == &no_irq_chip) - irq_set_chip(irq, &irq_type_hp_sim); -} - -static void hpsim_connect_irq(int intr, int irq) -{ - ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT); -} - -int hpsim_get_irq(int intr) -{ - int irq = assign_irq_vector(AUTO_ASSIGN); - - if (irq >= 0) { - hpsim_irq_set_chip(irq); - irq_set_handler(irq, handle_simple_irq); - hpsim_connect_irq(intr, irq); - } - - return irq; -} - -void __init -hpsim_irq_init (void) -{ - int i; - - for_each_active_irq(i) - hpsim_irq_set_chip(i); -} diff --git a/arch/ia64/hp/sim/hpsim_machvec.c b/arch/ia64/hp/sim/hpsim_machvec.c deleted file mode 100644 index c21419359185ad0f0667986556e79f8dcb9e4f7f..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/hpsim_machvec.c +++ /dev/null @@ -1,3 +0,0 @@ -#define MACHVEC_PLATFORM_NAME hpsim -#define MACHVEC_PLATFORM_HEADER -#include diff --git a/arch/ia64/hp/sim/hpsim_setup.c b/arch/ia64/hp/sim/hpsim_setup.c deleted file mode 100644 index 41d21d51dc4d0b5697cbbffaf81523ae7291a7fc..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/hpsim_setup.c +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Platform dependent support for HP simulator. - * - * Copyright (C) 1998, 1999, 2002 Hewlett-Packard Co - * David Mosberger-Tang - * Copyright (C) 1999 Vijay Chander - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "hpsim_ssc.h" - -void -ia64_ctl_trace (long on) -{ - ia64_ssc(on, 0, 0, 0, SSC_CTL_TRACE); -} - -void __init -hpsim_setup (char **cmdline_p) -{ - ROOT_DEV = Root_SDA1; /* default to first SCSI drive */ - - simcons_register(); -} diff --git a/arch/ia64/hp/sim/hpsim_ssc.h b/arch/ia64/hp/sim/hpsim_ssc.h deleted file mode 100644 index 6fd97a487811ab32a9b965bfc4d0d1383ae374bb..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/hpsim_ssc.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Platform dependent support for HP simulator. - * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang - * Copyright (C) 1999 Vijay Chander - */ -#ifndef _IA64_PLATFORM_HPSIM_SSC_H -#define _IA64_PLATFORM_HPSIM_SSC_H - -/* Simulator system calls: */ - -#define SSC_CONSOLE_INIT 20 -#define SSC_GETCHAR 21 -#define SSC_PUTCHAR 31 -#define SSC_CONNECT_INTERRUPT 58 -#define SSC_GENERATE_INTERRUPT 59 -#define SSC_SET_PERIODIC_INTERRUPT 60 -#define SSC_GET_RTC 65 -#define SSC_EXIT 66 -#define SSC_LOAD_SYMBOLS 69 -#define SSC_GET_TOD 74 -#define SSC_CTL_TRACE 76 - -#define SSC_NETDEV_PROBE 100 -#define SSC_NETDEV_SEND 101 -#define SSC_NETDEV_RECV 102 -#define SSC_NETDEV_ATTACH 103 -#define SSC_NETDEV_DETACH 104 - -/* - * Simulator system call. - */ -extern long ia64_ssc (long arg0, long arg1, long arg2, long arg3, int nr); - -#endif /* _IA64_PLATFORM_HPSIM_SSC_H */ diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c deleted file mode 100644 index f39ef2b4ed72a3f25193404fa69363624f17ee6f..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/simeth.c +++ /dev/null @@ -1,510 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Simulated Ethernet Driver - * - * Copyright (C) 1999-2001, 2003 Hewlett-Packard Co - * Stephane Eranian - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hpsim_ssc.h" - -#define SIMETH_RECV_MAX 10 - -/* - * Maximum possible received frame for Ethernet. - * We preallocate an sk_buff of that size to avoid costly - * memcpy for temporary buffer into sk_buff. We do basically - * what's done in other drivers, like eepro with a ring. - * The difference is, of course, that we don't have real DMA !!! - */ -#define SIMETH_FRAME_SIZE ETH_FRAME_LEN - - -#define NETWORK_INTR 8 - -struct simeth_local { - struct net_device_stats stats; - int simfd; /* descriptor in the simulator */ -}; - -static int simeth_probe1(void); -static int simeth_open(struct net_device *dev); -static int simeth_close(struct net_device *dev); -static int simeth_tx(struct sk_buff *skb, struct net_device *dev); -static int simeth_rx(struct net_device *dev); -static struct net_device_stats *simeth_get_stats(struct net_device *dev); -static irqreturn_t simeth_interrupt(int irq, void *dev_id); -static void set_multicast_list(struct net_device *dev); -static int simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr); - -static char *simeth_version="0.3"; - -/* - * This variable is used to establish a mapping between the Linux/ia64 kernel - * and the host linux kernel. - * - * As of today, we support only one card, even though most of the code - * is ready for many more. The mapping is then: - * linux/ia64 -> linux/x86 - * eth0 -> eth1 - * - * In the future, we some string operations, we could easily support up - * to 10 cards (0-9). - * - * The default mapping can be changed on the kernel command line by - * specifying simeth=ethX (or whatever string you want). - */ -static char *simeth_device="eth0"; /* default host interface to use */ - - - -static volatile unsigned int card_count; /* how many cards "found" so far */ -static int simeth_debug; /* set to 1 to get debug information */ - -/* - * Used to catch IFF_UP & IFF_DOWN events - */ -static struct notifier_block simeth_dev_notifier = { - simeth_device_event, - NULL -}; - - -/* - * Function used when using a kernel command line option. - * - * Format: simeth=interface_name (like eth0) - */ -static int __init -simeth_setup(char *str) -{ - simeth_device = str; - return 1; -} - -__setup("simeth=", simeth_setup); - -/* - * Function used to probe for simeth devices when not installed - * as a loadable module - */ - -int __init -simeth_probe (void) -{ - int r; - - printk(KERN_INFO "simeth: v%s\n", simeth_version); - - r = simeth_probe1(); - - if (r == 0) register_netdevice_notifier(&simeth_dev_notifier); - - return r; -} - -static inline int -netdev_probe(char *name, unsigned char *ether) -{ - return ia64_ssc(__pa(name), __pa(ether), 0,0, SSC_NETDEV_PROBE); -} - - -static inline int -netdev_attach(int fd, int irq, unsigned int ipaddr) -{ - /* this puts the host interface in the right mode (start interrupting) */ - return ia64_ssc(fd, ipaddr, 0,0, SSC_NETDEV_ATTACH); -} - - -static inline int -netdev_detach(int fd) -{ - /* - * inactivate the host interface (don't interrupt anymore) */ - return ia64_ssc(fd, 0,0,0, SSC_NETDEV_DETACH); -} - -static inline int -netdev_send(int fd, unsigned char *buf, unsigned int len) -{ - return ia64_ssc(fd, __pa(buf), len, 0, SSC_NETDEV_SEND); -} - -static inline int -netdev_read(int fd, unsigned char *buf, unsigned int len) -{ - return ia64_ssc(fd, __pa(buf), len, 0, SSC_NETDEV_RECV); -} - -static const struct net_device_ops simeth_netdev_ops = { - .ndo_open = simeth_open, - .ndo_stop = simeth_close, - .ndo_start_xmit = simeth_tx, - .ndo_get_stats = simeth_get_stats, - .ndo_set_rx_mode = set_multicast_list, /* not yet used */ - -}; - -/* - * Function shared with module code, so cannot be in init section - * - * So far this function "detects" only one card (test_&_set) but could - * be extended easily. - * - * Return: - * - -ENODEV is no device found - * - -ENOMEM is no more memory - * - 0 otherwise - */ -static int -simeth_probe1(void) -{ - unsigned char mac_addr[ETH_ALEN]; - struct simeth_local *local; - struct net_device *dev; - int fd, err, rc; - - /* - * XXX Fix me - * let's support just one card for now - */ - if (test_and_set_bit(0, &card_count)) - return -ENODEV; - - /* - * check with the simulator for the device - */ - fd = netdev_probe(simeth_device, mac_addr); - if (fd == -1) - return -ENODEV; - - dev = alloc_etherdev(sizeof(struct simeth_local)); - if (!dev) - return -ENOMEM; - - memcpy(dev->dev_addr, mac_addr, sizeof(mac_addr)); - - local = netdev_priv(dev); - local->simfd = fd; /* keep track of underlying file descriptor */ - - dev->netdev_ops = &simeth_netdev_ops; - - err = register_netdev(dev); - if (err) { - free_netdev(dev); - return err; - } - - /* - * attach the interrupt in the simulator, this does enable interrupts - * until a netdev_attach() is called - */ - if ((rc = hpsim_get_irq(NETWORK_INTR)) < 0) - panic("%s: out of interrupt vectors!\n", __func__); - dev->irq = rc; - - printk(KERN_INFO "%s: hosteth=%s simfd=%d, HwAddr=%pm, IRQ %d\n", - dev->name, simeth_device, local->simfd, dev->dev_addr, dev->irq); - - return 0; -} - -/* - * actually binds the device to an interrupt vector - */ -static int -simeth_open(struct net_device *dev) -{ - if (request_irq(dev->irq, simeth_interrupt, 0, "simeth", dev)) { - printk(KERN_WARNING "simeth: unable to get IRQ %d.\n", dev->irq); - return -EAGAIN; - } - - netif_start_queue(dev); - - return 0; -} - -/* copied from lapbether.c */ -static __inline__ int dev_is_ethdev(struct net_device *dev) -{ - return ( dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5)); -} - - -/* - * Handler for IFF_UP or IFF_DOWN - * - * The reason for that is that we don't want to be interrupted when the - * interface is down. There is no way to unconnect in the simualtor. Instead - * we use this function to shutdown packet processing in the frame filter - * in the simulator. Thus no interrupts are generated - * - * - * That's also the place where we pass the IP address of this device to the - * simulator so that that we can start filtering packets for it - * - * There may be a better way of doing this, but I don't know which yet. - */ -static int -simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct simeth_local *local; - struct in_device *in_dev; - struct in_ifaddr **ifap = NULL; - struct in_ifaddr *ifa = NULL; - int r; - - - if ( ! dev ) { - printk(KERN_WARNING "simeth_device_event dev=0\n"); - return NOTIFY_DONE; - } - - if (dev_net(dev) != &init_net) - return NOTIFY_DONE; - - if ( event != NETDEV_UP && event != NETDEV_DOWN ) return NOTIFY_DONE; - - /* - * Check whether or not it's for an ethernet device - * - * XXX Fixme: This works only as long as we support one - * type of ethernet device. - */ - if ( !dev_is_ethdev(dev) ) return NOTIFY_DONE; - - if ((in_dev=dev->ip_ptr) != NULL) { - for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next) - if (strcmp(dev->name, ifa->ifa_label) == 0) break; - } - if ( ifa == NULL ) { - printk(KERN_ERR "simeth_open: can't find device %s's ifa\n", dev->name); - return NOTIFY_DONE; - } - - printk(KERN_INFO "simeth_device_event: %s ipaddr=0x%x\n", - dev->name, ntohl(ifa->ifa_local)); - - /* - * XXX Fix me - * if the device was up, and we're simply reconfiguring it, not sure - * we get DOWN then UP. - */ - - local = netdev_priv(dev); - /* now do it for real */ - r = event == NETDEV_UP ? - netdev_attach(local->simfd, dev->irq, ntohl(ifa->ifa_local)): - netdev_detach(local->simfd); - - printk(KERN_INFO "simeth: netdev_attach/detach: event=%s ->%d\n", - event == NETDEV_UP ? "attach":"detach", r); - - return NOTIFY_DONE; -} - -static int -simeth_close(struct net_device *dev) -{ - netif_stop_queue(dev); - - free_irq(dev->irq, dev); - - return 0; -} - -/* - * Only used for debug - */ -static void -frame_print(unsigned char *from, unsigned char *frame, int len) -{ - int i; - - printk("%s: (%d) %02x", from, len, frame[0] & 0xff); - for(i=1; i < 6; i++ ) { - printk(":%02x", frame[i] &0xff); - } - printk(" %2x", frame[6] &0xff); - for(i=7; i < 12; i++ ) { - printk(":%02x", frame[i] &0xff); - } - printk(" [%02x%02x]\n", frame[12], frame[13]); - - for(i=14; i < len; i++ ) { - printk("%02x ", frame[i] &0xff); - if ( (i%10)==0) printk("\n"); - } - printk("\n"); -} - - -/* - * Function used to transmit of frame, very last one on the path before - * going to the simulator. - */ -static int -simeth_tx(struct sk_buff *skb, struct net_device *dev) -{ - struct simeth_local *local = netdev_priv(dev); - -#if 0 - /* ensure we have at least ETH_ZLEN bytes (min frame size) */ - unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - /* Where do the extra padding bytes comes from inthe skbuff ? */ -#else - /* the real driver in the host system is going to take care of that - * or maybe it's the NIC itself. - */ - unsigned int length = skb->len; -#endif - - local->stats.tx_bytes += skb->len; - local->stats.tx_packets++; - - - if (simeth_debug > 5) frame_print("simeth_tx", skb->data, length); - - netdev_send(local->simfd, skb->data, length); - - /* - * we are synchronous on write, so we don't simulate a - * trasnmit complete interrupt, thus we don't need to arm a tx - */ - - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - -static inline struct sk_buff * -make_new_skb(struct net_device *dev) -{ - struct sk_buff *nskb; - - /* - * The +2 is used to make sure that the IP header is nicely - * aligned (on 4byte boundary I assume 14+2=16) - */ - nskb = dev_alloc_skb(SIMETH_FRAME_SIZE + 2); - if ( nskb == NULL ) { - printk(KERN_NOTICE "%s: memory squeeze. dropping packet.\n", dev->name); - return NULL; - } - - skb_reserve(nskb, 2); /* Align IP on 16 byte boundaries */ - - skb_put(nskb,SIMETH_FRAME_SIZE); - - return nskb; -} - -/* - * called from interrupt handler to process a received frame - */ -static int -simeth_rx(struct net_device *dev) -{ - struct simeth_local *local; - struct sk_buff *skb; - int len; - int rcv_count = SIMETH_RECV_MAX; - - local = netdev_priv(dev); - /* - * the loop concept has been borrowed from other drivers - * looks to me like it's a throttling thing to avoid pushing to many - * packets at one time into the stack. Making sure we can process them - * upstream and make forward progress overall - */ - do { - if ( (skb=make_new_skb(dev)) == NULL ) { - printk(KERN_NOTICE "%s: memory squeeze. dropping packet.\n", dev->name); - local->stats.rx_dropped++; - return 0; - } - /* - * Read only one frame at a time - */ - len = netdev_read(local->simfd, skb->data, SIMETH_FRAME_SIZE); - if ( len == 0 ) { - if ( simeth_debug > 0 ) printk(KERN_WARNING "%s: count=%d netdev_read=0\n", - dev->name, SIMETH_RECV_MAX-rcv_count); - break; - } -#if 0 - /* - * XXX Fix me - * Should really do a csum+copy here - */ - skb_copy_to_linear_data(skb, frame, len); -#endif - skb->protocol = eth_type_trans(skb, dev); - - if ( simeth_debug > 6 ) frame_print("simeth_rx", skb->data, len); - - /* - * push the packet up & trigger software interrupt - */ - netif_rx(skb); - - local->stats.rx_packets++; - local->stats.rx_bytes += len; - - } while ( --rcv_count ); - - return len; /* 0 = nothing left to read, otherwise, we can try again */ -} - -/* - * Interrupt handler (Yes, we can do it too !!!) - */ -static irqreturn_t -simeth_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - - /* - * very simple loop because we get interrupts only when receiving - */ - while (simeth_rx(dev)); - return IRQ_HANDLED; -} - -static struct net_device_stats * -simeth_get_stats(struct net_device *dev) -{ - struct simeth_local *local = netdev_priv(dev); - - return &local->stats; -} - -/* fake multicast ability */ -static void -set_multicast_list(struct net_device *dev) -{ - printk(KERN_WARNING "%s: set_multicast_list called\n", dev->name); -} - -__initcall(simeth_probe); diff --git a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c deleted file mode 100644 index 0a8a7427117306a922fbcd3f72de5ccccdab96c1..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/simscsi.c +++ /dev/null @@ -1,373 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Simulated SCSI driver. - * - * Copyright (C) 1999, 2001-2003 Hewlett-Packard Co - * David Mosberger-Tang - * Stephane Eranian - * - * 02/01/15 David Mosberger Updated for v2.5.1 - * 99/12/18 David Mosberger Added support for READ10/WRITE10 needed by linux v2.3.33 - */ -#include -#include -#include -#include -#include -#include -#include "hpsim_ssc.h" - -#include -#include -#include -#include - -#define DEBUG_SIMSCSI 0 - -#define SIMSCSI_REQ_QUEUE_LEN 64 -#define DEFAULT_SIMSCSI_ROOT "/var/ski-disks/sd" - -/* Simulator system calls: */ - -#define SSC_OPEN 50 -#define SSC_CLOSE 51 -#define SSC_READ 52 -#define SSC_WRITE 53 -#define SSC_GET_COMPLETION 54 -#define SSC_WAIT_COMPLETION 55 - -#define SSC_WRITE_ACCESS 2 -#define SSC_READ_ACCESS 1 - -#if DEBUG_SIMSCSI - int simscsi_debug; -# define DBG simscsi_debug -#else -# define DBG 0 -#endif - -static struct Scsi_Host *host; - -static void simscsi_interrupt (unsigned long val); -static DECLARE_TASKLET(simscsi_tasklet, simscsi_interrupt, 0); - -struct disk_req { - unsigned long addr; - unsigned len; -}; - -struct disk_stat { - int fd; - unsigned count; -}; - -static int desc[16] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 -}; - -static struct queue_entry { - struct scsi_cmnd *sc; -} queue[SIMSCSI_REQ_QUEUE_LEN]; - -static int rd, wr; -static atomic_t num_reqs = ATOMIC_INIT(0); - -/* base name for default disks */ -static char *simscsi_root = DEFAULT_SIMSCSI_ROOT; - -#define MAX_ROOT_LEN 128 - -/* - * used to setup a new base for disk images - * to use /foo/bar/disk[a-z] as disk images - * you have to specify simscsi=/foo/bar/disk on the command line - */ -static int __init -simscsi_setup (char *s) -{ - /* XXX Fix me we may need to strcpy() ? */ - if (strlen(s) > MAX_ROOT_LEN) { - printk(KERN_ERR "simscsi_setup: prefix too long---using default %s\n", - simscsi_root); - } else - simscsi_root = s; - return 1; -} - -__setup("simscsi=", simscsi_setup); - -static void -simscsi_interrupt (unsigned long val) -{ - struct scsi_cmnd *sc; - - while ((sc = queue[rd].sc) != NULL) { - atomic_dec(&num_reqs); - queue[rd].sc = NULL; - if (DBG) - printk("simscsi_interrupt: done with %u\n", - sc->request->tag); - (*sc->scsi_done)(sc); - rd = (rd + 1) % SIMSCSI_REQ_QUEUE_LEN; - } -} - -static int -simscsi_biosparam (struct scsi_device *sdev, struct block_device *n, - sector_t capacity, int ip[]) -{ - ip[0] = 64; /* heads */ - ip[1] = 32; /* sectors */ - ip[2] = capacity >> 11; /* cylinders */ - return 0; -} - -static void -simscsi_sg_readwrite (struct scsi_cmnd *sc, int mode, unsigned long offset) -{ - int i; - struct scatterlist *sl; - struct disk_stat stat; - struct disk_req req; - - stat.fd = desc[sc->device->id]; - - scsi_for_each_sg(sc, sl, scsi_sg_count(sc), i) { - req.addr = __pa(sg_virt(sl)); - req.len = sl->length; - if (DBG) - printk("simscsi_sg_%s @ %lx (off %lx) use_sg=%d len=%d\n", - mode == SSC_READ ? "read":"write", req.addr, offset, - scsi_sg_count(sc) - i, sl->length); - ia64_ssc(stat.fd, 1, __pa(&req), offset, mode); - ia64_ssc(__pa(&stat), 0, 0, 0, SSC_WAIT_COMPLETION); - - /* should not happen in our case */ - if (stat.count != req.len) { - sc->result = DID_ERROR << 16; - return; - } - offset += sl->length; - } - sc->result = GOOD; -} - -/* - * function handling both READ_6/WRITE_6 (non-scatter/gather mode) - * commands. - * Added 02/26/99 S.Eranian - */ -static void -simscsi_readwrite6 (struct scsi_cmnd *sc, int mode) -{ - unsigned long offset; - - offset = (((sc->cmnd[1] & 0x1f) << 16) | (sc->cmnd[2] << 8) | sc->cmnd[3])*512; - simscsi_sg_readwrite(sc, mode, offset); -} - -static size_t -simscsi_get_disk_size (int fd) -{ - struct disk_stat stat; - size_t bit, sectors = 0; - struct disk_req req; - char buf[512]; - - /* - * This is a bit kludgey: the simulator doesn't provide a - * direct way of determining the disk size, so we do a binary - * search, assuming a maximum disk size of 128GB. - */ - for (bit = (128UL << 30)/512; bit != 0; bit >>= 1) { - req.addr = __pa(&buf); - req.len = sizeof(buf); - ia64_ssc(fd, 1, __pa(&req), ((sectors | bit) - 1)*512, SSC_READ); - stat.fd = fd; - ia64_ssc(__pa(&stat), 0, 0, 0, SSC_WAIT_COMPLETION); - if (stat.count == sizeof(buf)) - sectors |= bit; - } - return sectors - 1; /* return last valid sector number */ -} - -static void -simscsi_readwrite10 (struct scsi_cmnd *sc, int mode) -{ - unsigned long offset; - - offset = (((unsigned long)sc->cmnd[2] << 24) - | ((unsigned long)sc->cmnd[3] << 16) - | ((unsigned long)sc->cmnd[4] << 8) - | ((unsigned long)sc->cmnd[5] << 0))*512UL; - simscsi_sg_readwrite(sc, mode, offset); -} - -static int -simscsi_queuecommand_lck (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) -{ - unsigned int target_id = sc->device->id; - char fname[MAX_ROOT_LEN+16]; - size_t disk_size; - char *buf; - char localbuf[36]; -#if DEBUG_SIMSCSI - register long sp asm ("sp"); - - if (DBG) - printk("simscsi_queuecommand: target=%d,cmnd=%u,sc=%u,sp=%lx,done=%p\n", - target_id, sc->cmnd[0], sc->request->tag, sp, done); -#endif - - sc->result = DID_BAD_TARGET << 16; - sc->scsi_done = done; - if (target_id <= 15 && sc->device->lun == 0) { - switch (sc->cmnd[0]) { - case INQUIRY: - if (scsi_bufflen(sc) < 35) { - break; - } - sprintf (fname, "%s%c", simscsi_root, 'a' + target_id); - desc[target_id] = ia64_ssc(__pa(fname), SSC_READ_ACCESS|SSC_WRITE_ACCESS, - 0, 0, SSC_OPEN); - if (desc[target_id] < 0) { - /* disk doesn't exist... */ - break; - } - buf = localbuf; - buf[0] = 0; /* magnetic disk */ - buf[1] = 0; /* not a removable medium */ - buf[2] = 2; /* SCSI-2 compliant device */ - buf[3] = 2; /* SCSI-2 response data format */ - buf[4] = 31; /* additional length (bytes) */ - buf[5] = 0; /* reserved */ - buf[6] = 0; /* reserved */ - buf[7] = 0; /* various flags */ - memcpy(buf + 8, "HP SIMULATED DISK 0.00", 28); - scsi_sg_copy_from_buffer(sc, buf, 36); - sc->result = GOOD; - break; - - case TEST_UNIT_READY: - sc->result = GOOD; - break; - - case READ_6: - if (desc[target_id] < 0 ) - break; - simscsi_readwrite6(sc, SSC_READ); - break; - - case READ_10: - if (desc[target_id] < 0 ) - break; - simscsi_readwrite10(sc, SSC_READ); - break; - - case WRITE_6: - if (desc[target_id] < 0) - break; - simscsi_readwrite6(sc, SSC_WRITE); - break; - - case WRITE_10: - if (desc[target_id] < 0) - break; - simscsi_readwrite10(sc, SSC_WRITE); - break; - - case READ_CAPACITY: - if (desc[target_id] < 0 || scsi_bufflen(sc) < 8) { - break; - } - buf = localbuf; - disk_size = simscsi_get_disk_size(desc[target_id]); - - buf[0] = (disk_size >> 24) & 0xff; - buf[1] = (disk_size >> 16) & 0xff; - buf[2] = (disk_size >> 8) & 0xff; - buf[3] = (disk_size >> 0) & 0xff; - /* set block size of 512 bytes: */ - buf[4] = 0; - buf[5] = 0; - buf[6] = 2; - buf[7] = 0; - scsi_sg_copy_from_buffer(sc, buf, 8); - sc->result = GOOD; - break; - - case MODE_SENSE: - case MODE_SENSE_10: - /* sd.c uses this to determine whether disk does write-caching. */ - scsi_sg_copy_from_buffer(sc, (char *)empty_zero_page, - PAGE_SIZE); - sc->result = GOOD; - break; - - case START_STOP: - printk(KERN_ERR "START_STOP\n"); - break; - - default: - panic("simscsi: unknown SCSI command %u\n", sc->cmnd[0]); - } - } - if (sc->result == DID_BAD_TARGET) { - sc->result |= DRIVER_SENSE << 24; - sc->sense_buffer[0] = 0x70; - sc->sense_buffer[2] = 0x00; - } - if (atomic_read(&num_reqs) >= SIMSCSI_REQ_QUEUE_LEN) { - panic("Attempt to queue command while command is pending!!"); - } - atomic_inc(&num_reqs); - queue[wr].sc = sc; - wr = (wr + 1) % SIMSCSI_REQ_QUEUE_LEN; - - tasklet_schedule(&simscsi_tasklet); - return 0; -} - -static DEF_SCSI_QCMD(simscsi_queuecommand) - -static int -simscsi_host_reset (struct scsi_cmnd *sc) -{ - printk(KERN_ERR "simscsi_host_reset: not implemented\n"); - return 0; -} - -static struct scsi_host_template driver_template = { - .name = "simulated SCSI host adapter", - .proc_name = "simscsi", - .queuecommand = simscsi_queuecommand, - .eh_host_reset_handler = simscsi_host_reset, - .bios_param = simscsi_biosparam, - .can_queue = SIMSCSI_REQ_QUEUE_LEN, - .this_id = -1, - .sg_tablesize = SG_ALL, - .max_sectors = 1024, - .cmd_per_lun = SIMSCSI_REQ_QUEUE_LEN, - .dma_boundary = PAGE_SIZE - 1, -}; - -static int __init -simscsi_init(void) -{ - int error; - - host = scsi_host_alloc(&driver_template, 0); - if (!host) - return -ENOMEM; - - error = scsi_add_host(host, NULL); - if (error) - goto free_host; - scsi_scan_host(host); - return 0; - - free_host: - scsi_host_put(host); - return error; -} -device_initcall(simscsi_init); diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c deleted file mode 100644 index 1a338e54133420905a23fb4c68d8a7bcf323053e..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/sim/simserial.c +++ /dev/null @@ -1,521 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Simulated Serial Driver (fake serial) - * - * This driver is mostly used for bringup purposes and will go away. - * It has a strong dependency on the system console. All outputs - * are rerouted to the same facility as the one used by printk which, in our - * case means sys_sim.c console (goes via the simulator). - * - * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co - * Stephane Eranian - * David Mosberger-Tang - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "hpsim_ssc.h" - -#undef SIMSERIAL_DEBUG /* define this to get some debug information */ - -#define KEYBOARD_INTR 3 /* must match with simulator! */ - -#define NR_PORTS 1 /* only one port for now */ - -struct serial_state { - struct tty_port port; - struct circ_buf xmit; - int irq; - int x_char; -}; - -static struct serial_state rs_table[NR_PORTS]; - -struct tty_driver *hp_simserial_driver; - -static struct console *console; - -static void receive_chars(struct tty_port *port) -{ - unsigned char ch; - static unsigned char seen_esc = 0; - - while ( (ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR)) ) { - if (ch == 27 && seen_esc == 0) { - seen_esc = 1; - continue; - } else if (seen_esc == 1 && ch == 'O') { - seen_esc = 2; - continue; - } else if (seen_esc == 2) { - if (ch == 'P') /* F1 */ - show_state(); -#ifdef CONFIG_MAGIC_SYSRQ - if (ch == 'S') { /* F4 */ - do { - ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR); - } while (!ch); - handle_sysrq(ch); - } -#endif - seen_esc = 0; - continue; - } - seen_esc = 0; - - if (tty_insert_flip_char(port, ch, TTY_NORMAL) == 0) - break; - } - tty_flip_buffer_push(port); -} - -/* - * This is the serial driver's interrupt routine for a single port - */ -static irqreturn_t rs_interrupt_single(int irq, void *dev_id) -{ - struct serial_state *info = dev_id; - - receive_chars(&info->port); - - return IRQ_HANDLED; -} - -/* - * ------------------------------------------------------------------- - * Here ends the serial interrupt routines. - * ------------------------------------------------------------------- - */ - -static int rs_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct serial_state *info = tty->driver_data; - unsigned long flags; - - if (!info->xmit.buf) - return 0; - - local_irq_save(flags); - if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) { - local_irq_restore(flags); - return 0; - } - info->xmit.buf[info->xmit.head] = ch; - info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1); - local_irq_restore(flags); - return 1; -} - -static void transmit_chars(struct tty_struct *tty, struct serial_state *info, - int *intr_done) -{ - int count; - unsigned long flags; - - local_irq_save(flags); - - if (info->x_char) { - char c = info->x_char; - - console->write(console, &c, 1); - - info->x_char = 0; - - goto out; - } - - if (info->xmit.head == info->xmit.tail || tty->stopped) { -#ifdef SIMSERIAL_DEBUG - printk("transmit_chars: head=%d, tail=%d, stopped=%d\n", - info->xmit.head, info->xmit.tail, tty->stopped); -#endif - goto out; - } - /* - * We removed the loop and try to do it in to chunks. We need - * 2 operations maximum because it's a ring buffer. - * - * First from current to tail if possible. - * Then from the beginning of the buffer until necessary - */ - - count = min(CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE), - SERIAL_XMIT_SIZE - info->xmit.tail); - console->write(console, info->xmit.buf+info->xmit.tail, count); - - info->xmit.tail = (info->xmit.tail+count) & (SERIAL_XMIT_SIZE-1); - - /* - * We have more at the beginning of the buffer - */ - count = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); - if (count) { - console->write(console, info->xmit.buf, count); - info->xmit.tail += count; - } -out: - local_irq_restore(flags); -} - -static void rs_flush_chars(struct tty_struct *tty) -{ - struct serial_state *info = tty->driver_data; - - if (info->xmit.head == info->xmit.tail || tty->stopped || - !info->xmit.buf) - return; - - transmit_chars(tty, info, NULL); -} - -static int rs_write(struct tty_struct * tty, - const unsigned char *buf, int count) -{ - struct serial_state *info = tty->driver_data; - int c, ret = 0; - unsigned long flags; - - if (!info->xmit.buf) - return 0; - - local_irq_save(flags); - while (1) { - c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); - if (count < c) - c = count; - if (c <= 0) { - break; - } - memcpy(info->xmit.buf + info->xmit.head, buf, c); - info->xmit.head = ((info->xmit.head + c) & - (SERIAL_XMIT_SIZE-1)); - buf += c; - count -= c; - ret += c; - } - local_irq_restore(flags); - /* - * Hey, we transmit directly from here in our case - */ - if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) && - !tty->stopped) - transmit_chars(tty, info, NULL); - - return ret; -} - -static int rs_write_room(struct tty_struct *tty) -{ - struct serial_state *info = tty->driver_data; - - return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); -} - -static int rs_chars_in_buffer(struct tty_struct *tty) -{ - struct serial_state *info = tty->driver_data; - - return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); -} - -static void rs_flush_buffer(struct tty_struct *tty) -{ - struct serial_state *info = tty->driver_data; - unsigned long flags; - - local_irq_save(flags); - info->xmit.head = info->xmit.tail = 0; - local_irq_restore(flags); - - tty_wakeup(tty); -} - -/* - * This function is used to send a high-priority XON/XOFF character to - * the device - */ -static void rs_send_xchar(struct tty_struct *tty, char ch) -{ - struct serial_state *info = tty->driver_data; - - info->x_char = ch; - if (ch) { - /* - * I guess we could call console->write() directly but - * let's do that for now. - */ - transmit_chars(tty, info, NULL); - } -} - -/* - * ------------------------------------------------------------ - * rs_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ - */ -static void rs_throttle(struct tty_struct * tty) -{ - if (I_IXOFF(tty)) - rs_send_xchar(tty, STOP_CHAR(tty)); - - printk(KERN_INFO "simrs_throttle called\n"); -} - -static void rs_unthrottle(struct tty_struct * tty) -{ - struct serial_state *info = tty->driver_data; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - rs_send_xchar(tty, START_CHAR(tty)); - } - printk(KERN_INFO "simrs_unthrottle called\n"); -} - -static int rs_setserial(struct tty_struct *tty, struct serial_struct *ss) -{ - return 0; -} - -static int rs_getserial(struct tty_struct *tty, struct serial_struct *ss) -{ - return 0; -} - -static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) -{ - if ((cmd != TIOCSERCONFIG) && (cmd != TIOCMIWAIT)) { - if (tty_io_error(tty)) - return -EIO; - } - - switch (cmd) { - case TIOCMIWAIT: - return 0; - case TIOCSERCONFIG: - case TIOCSERGETLSR: /* Get line status register */ - return -EINVAL; - } - return -ENOIOCTLCMD; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void shutdown(struct tty_port *port) -{ - struct serial_state *info = container_of(port, struct serial_state, - port); - unsigned long flags; - - local_irq_save(flags); - if (info->irq) - free_irq(info->irq, info); - - if (info->xmit.buf) { - free_page((unsigned long) info->xmit.buf); - info->xmit.buf = NULL; - } - local_irq_restore(flags); -} - -static void rs_close(struct tty_struct *tty, struct file * filp) -{ - struct serial_state *info = tty->driver_data; - - tty_port_close(&info->port, tty, filp); -} - -static void rs_hangup(struct tty_struct *tty) -{ - struct serial_state *info = tty->driver_data; - - rs_flush_buffer(tty); - tty_port_hangup(&info->port); -} - -static int activate(struct tty_port *port, struct tty_struct *tty) -{ - struct serial_state *state = container_of(port, struct serial_state, - port); - unsigned long flags, page; - int retval = 0; - - page = get_zeroed_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - local_irq_save(flags); - - if (state->xmit.buf) - free_page(page); - else - state->xmit.buf = (unsigned char *) page; - - if (state->irq) { - retval = request_irq(state->irq, rs_interrupt_single, 0, - "simserial", state); - if (retval) - goto errout; - } - - state->xmit.head = state->xmit.tail = 0; -errout: - local_irq_restore(flags); - return retval; -} - - -/* - * 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 int rs_open(struct tty_struct *tty, struct file * filp) -{ - struct serial_state *info = rs_table + tty->index; - struct tty_port *port = &info->port; - - tty->driver_data = info; - port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; - - /* - * figure out which console to use (should be one already) - */ - console = console_drivers; - while (console) { - if ((console->flags & CON_ENABLED) && console->write) break; - console = console->next; - } - - return tty_port_open(port, tty, filp); -} - -/* - * /proc fs routines.... - */ - -static int rs_proc_show(struct seq_file *m, void *v) -{ - int i; - - seq_printf(m, "simserinfo:1.0\n"); - for (i = 0; i < NR_PORTS; i++) - seq_printf(m, "%d: uart:16550 port:3F8 irq:%d\n", - i, rs_table[i].irq); - return 0; -} - -static const struct tty_operations hp_ops = { - .open = rs_open, - .close = rs_close, - .write = rs_write, - .put_char = rs_put_char, - .flush_chars = rs_flush_chars, - .write_room = rs_write_room, - .chars_in_buffer = rs_chars_in_buffer, - .flush_buffer = rs_flush_buffer, - .ioctl = rs_ioctl, - .throttle = rs_throttle, - .unthrottle = rs_unthrottle, - .send_xchar = rs_send_xchar, - .set_serial = rs_setserial, - .get_serial = rs_getserial, - .hangup = rs_hangup, - .proc_show = rs_proc_show, -}; - -static const struct tty_port_operations hp_port_ops = { - .activate = activate, - .shutdown = shutdown, -}; - -static int __init simrs_init(void) -{ - struct serial_state *state; - int retval; - - if (!ia64_platform_is("hpsim")) - return -ENODEV; - - hp_simserial_driver = alloc_tty_driver(NR_PORTS); - if (!hp_simserial_driver) - return -ENOMEM; - - printk(KERN_INFO "SimSerial driver with no serial options enabled\n"); - - /* Initialize the tty_driver structure */ - - hp_simserial_driver->driver_name = "simserial"; - hp_simserial_driver->name = "ttyS"; - hp_simserial_driver->major = TTY_MAJOR; - hp_simserial_driver->minor_start = 64; - hp_simserial_driver->type = TTY_DRIVER_TYPE_SERIAL; - hp_simserial_driver->subtype = SERIAL_TYPE_NORMAL; - hp_simserial_driver->init_termios = tty_std_termios; - hp_simserial_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - hp_simserial_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(hp_simserial_driver, &hp_ops); - - state = rs_table; - tty_port_init(&state->port); - state->port.ops = &hp_port_ops; - state->port.close_delay = 0; /* XXX really 0? */ - - retval = hpsim_get_irq(KEYBOARD_INTR); - if (retval < 0) { - printk(KERN_ERR "%s: out of interrupt vectors!\n", - __func__); - goto err_free_tty; - } - - state->irq = retval; - - /* the port is imaginary */ - printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq); - - tty_port_link_device(&state->port, hp_simserial_driver, 0); - retval = tty_register_driver(hp_simserial_driver); - if (retval) { - printk(KERN_ERR "Couldn't register simserial driver\n"); - goto err_free_tty; - } - - return 0; -err_free_tty: - put_tty_driver(hp_simserial_driver); - tty_port_destroy(&state->port); - return retval; -} - -#ifndef MODULE -__initcall(simrs_init); -#endif diff --git a/arch/ia64/hp/zx1/Makefile b/arch/ia64/hp/zx1/Makefile deleted file mode 100644 index 46b37d820b590e1a5dec067bcc51983a468d944a..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/zx1/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# ia64/hp/zx1/Makefile -# -# Copyright (C) 2002 Hewlett Packard -# Copyright (C) Alex Williamson (alex_williamson@hp.com) -# - -obj-$(CONFIG_IA64_GENERIC) += hpzx1_machvec.o hpzx1_swiotlb_machvec.o diff --git a/arch/ia64/hp/zx1/hpzx1_machvec.c b/arch/ia64/hp/zx1/hpzx1_machvec.c deleted file mode 100644 index 32518b0f923e865f861aba47eab27e6f67d46ecc..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/zx1/hpzx1_machvec.c +++ /dev/null @@ -1,3 +0,0 @@ -#define MACHVEC_PLATFORM_NAME hpzx1 -#define MACHVEC_PLATFORM_HEADER -#include diff --git a/arch/ia64/hp/zx1/hpzx1_swiotlb_machvec.c b/arch/ia64/hp/zx1/hpzx1_swiotlb_machvec.c deleted file mode 100644 index 4392a96b3c582c28ea50af7f0be14d99492f2867..0000000000000000000000000000000000000000 --- a/arch/ia64/hp/zx1/hpzx1_swiotlb_machvec.c +++ /dev/null @@ -1,3 +0,0 @@ -#define MACHVEC_PLATFORM_NAME hpzx1_swiotlb -#define MACHVEC_PLATFORM_HEADER -#include diff --git a/arch/ia64/include/asm/acpi.h b/arch/ia64/include/asm/acpi.h index 0ea569040c5bf0171186ca1fac1473ba671d9e29..f886d4dc9d55297f6548ae45f53dc4d48c42ef01 100644 --- a/arch/ia64/include/asm/acpi.h +++ b/arch/ia64/include/asm/acpi.h @@ -17,7 +17,7 @@ #include #include -#ifdef CONFIG_ACPI + extern int acpi_lapic; #define acpi_disabled 0 /* ACPI always enabled on IA64 */ #define acpi_noirq 0 /* ACPI always enabled on IA64 */ @@ -28,34 +28,10 @@ static inline bool acpi_has_cpu_in_madt(void) { return !!acpi_lapic; } -#endif + #define acpi_processor_cstate_check(x) (x) /* no idle limits on IA64 :) */ static inline void disable_acpi(void) { } -#ifdef CONFIG_IA64_GENERIC -const char *acpi_get_sysname (void); -#else -static inline const char *acpi_get_sysname (void) -{ -# if defined (CONFIG_IA64_HP_SIM) - return "hpsim"; -# elif defined (CONFIG_IA64_HP_ZX1) - return "hpzx1"; -# elif defined (CONFIG_IA64_HP_ZX1_SWIOTLB) - return "hpzx1_swiotlb"; -# elif defined (CONFIG_IA64_SGI_SN2) - return "sn2"; -# elif defined (CONFIG_IA64_SGI_UV) - return "uv"; -# elif defined (CONFIG_IA64_DIG) - return "dig"; -# elif defined(CONFIG_IA64_DIG_VTD) - return "dig_vtd"; -# else -# error Unknown platform. Fix acpi.c. -# endif -} -#endif int acpi_request_vector (u32 int_type); int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h index f7ec71e4001e7d6e0eef60abca31fcd1d8710483..a5d9d788eede1f1d85181704ac4578ed1ad0caa2 100644 --- a/arch/ia64/include/asm/dma-mapping.h +++ b/arch/ia64/include/asm/dma-mapping.h @@ -6,17 +6,11 @@ * Copyright (C) 2003-2004 Hewlett-Packard Co * David Mosberger-Tang */ -#include -#include -#include - extern const struct dma_map_ops *dma_ops; -extern struct ia64_machine_vector ia64_mv; -extern void set_iommu_machvec(void); static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus) { - return platform_dma_get_ops(NULL); + return dma_ops; } #endif /* _ASM_IA64_DMA_MAPPING_H */ diff --git a/arch/ia64/include/asm/dma.h b/arch/ia64/include/asm/dma.h index 23604d6a2cb2430e76dfbb6d501505fcd4f3afa3..59625e9c1f9c5d549916b577125719b6af522639 100644 --- a/arch/ia64/include/asm/dma.h +++ b/arch/ia64/include/asm/dma.h @@ -12,11 +12,7 @@ extern unsigned long MAX_DMA_ADDRESS; -#ifdef CONFIG_PCI - extern int isa_dma_bridge_buggy; -#else -# define isa_dma_bridge_buggy (0) -#endif +extern int isa_dma_bridge_buggy; #define free_dma(x) diff --git a/arch/ia64/include/asm/hpsim.h b/arch/ia64/include/asm/hpsim.h deleted file mode 100644 index 00fbd5cc8ab86d6a15ea043efb4a3750a3f44514..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/hpsim.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASMIA64_HPSIM_H -#define _ASMIA64_HPSIM_H - -#ifndef CONFIG_HP_SIMSERIAL_CONSOLE -static inline int simcons_register(void) { return 1; } -#else -int simcons_register(void); -#endif - -struct tty_driver; -extern struct tty_driver *hp_simserial_driver; - -extern int hpsim_get_irq(int intr); -void ia64_ctl_trace(long on); - -#endif diff --git a/arch/ia64/include/asm/hw_irq.h b/arch/ia64/include/asm/hw_irq.h index 5dd3c6485c3aaf54e471dfc5bee1754cdc443d7c..e6385c7bdeb001d1ad2be8be3d3d64e9a4dd407c 100644 --- a/arch/ia64/include/asm/hw_irq.h +++ b/arch/ia64/include/asm/hw_irq.h @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -56,7 +55,7 @@ typedef u8 ia64_vector; extern int ia64_first_device_vector; extern int ia64_last_device_vector; -#if defined(CONFIG_SMP) && (defined(CONFIG_IA64_GENERIC) || defined (CONFIG_IA64_DIG)) +#ifdef CONFIG_SMP /* Reserve the lower priority vector than device vectors for "move IRQ" IPI */ #define IA64_IRQ_MOVE_VECTOR 0x30 /* "move IRQ" IPI */ #define IA64_DEF_FIRST_DEVICE_VECTOR 0x31 @@ -127,7 +126,7 @@ extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect) extern void ia64_native_register_percpu_irq (ia64_vector vec, struct irqaction *action); extern void destroy_and_reserve_irq (unsigned int irq); -#if defined(CONFIG_SMP) && (defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_DIG)) +#ifdef CONFIG_SMP extern int irq_prepare_move(int irq, int cpu); extern void irq_complete_move(unsigned int irq); #else @@ -137,25 +136,9 @@ static inline void irq_complete_move(unsigned int irq) {} static inline void ia64_native_resend_irq(unsigned int vector) { - platform_send_ipi(smp_processor_id(), vector, IA64_IPI_DM_INT, 0); + ia64_send_ipi(smp_processor_id(), vector, IA64_IPI_DM_INT, 0); } -/* - * Default implementations for the irq-descriptor API: - */ -#ifndef CONFIG_IA64_GENERIC -static inline ia64_vector __ia64_irq_to_vector(int irq) -{ - return irq_cfg[irq].vector; -} - -static inline unsigned int -__ia64_local_vector_to_irq (ia64_vector vec) -{ - return __this_cpu_read(vector_irq[vec]); -} -#endif - /* * Next follows the irq descriptor interface. On IA-64, each CPU supports 256 interrupt * vectors. On smaller systems, there is a one-to-one correspondence between interrupt @@ -170,7 +153,7 @@ __ia64_local_vector_to_irq (ia64_vector vec) static inline ia64_vector irq_to_vector (int irq) { - return platform_irq_to_vector(irq); + return irq_cfg[irq].vector; } /* @@ -181,7 +164,7 @@ irq_to_vector (int irq) static inline unsigned int local_vector_to_irq (ia64_vector vec) { - return platform_local_vector_to_irq(vec); + return __this_cpu_read(vector_irq[vec]); } #endif /* _ASM_IA64_HW_IRQ_H */ diff --git a/arch/ia64/include/asm/io.h b/arch/ia64/include/asm/io.h index a511d62d447ac1b3071a64cb2ee50c20bfaa76a9..54e70c21352a50b9c1033c2e19fa390bb6e54803 100644 --- a/arch/ia64/include/asm/io.h +++ b/arch/ia64/include/asm/io.h @@ -71,7 +71,6 @@ extern unsigned int num_io_spaces; #define HAVE_ARCH_PIO_SIZE #include -#include #include #include @@ -129,25 +128,6 @@ __ia64_mk_io_addr (unsigned long port) return (void *) (space->mmio_base | offset); } -#define __ia64_inb ___ia64_inb -#define __ia64_inw ___ia64_inw -#define __ia64_inl ___ia64_inl -#define __ia64_outb ___ia64_outb -#define __ia64_outw ___ia64_outw -#define __ia64_outl ___ia64_outl -#define __ia64_readb ___ia64_readb -#define __ia64_readw ___ia64_readw -#define __ia64_readl ___ia64_readl -#define __ia64_readq ___ia64_readq -#define __ia64_readb_relaxed ___ia64_readb -#define __ia64_readw_relaxed ___ia64_readw -#define __ia64_readl_relaxed ___ia64_readl -#define __ia64_readq_relaxed ___ia64_readq -#define __ia64_writeb ___ia64_writeb -#define __ia64_writew ___ia64_writew -#define __ia64_writel ___ia64_writel -#define __ia64_writeq ___ia64_writeq - /* * For the in/out routines, we need to do "mf.a" _after_ doing the I/O access to ensure * that the access has completed before executing other I/O accesses. Since we're doing @@ -156,8 +136,8 @@ __ia64_mk_io_addr (unsigned long port) * during optimization, which is why we use "volatile" pointers. */ -static inline unsigned int -___ia64_inb (unsigned long port) +#define inb inb +static inline unsigned int inb(unsigned long port) { volatile unsigned char *addr = __ia64_mk_io_addr(port); unsigned char ret; @@ -167,8 +147,8 @@ ___ia64_inb (unsigned long port) return ret; } -static inline unsigned int -___ia64_inw (unsigned long port) +#define inw inw +static inline unsigned int inw(unsigned long port) { volatile unsigned short *addr = __ia64_mk_io_addr(port); unsigned short ret; @@ -178,8 +158,8 @@ ___ia64_inw (unsigned long port) return ret; } -static inline unsigned int -___ia64_inl (unsigned long port) +#define inl inl +static inline unsigned int inl(unsigned long port) { volatile unsigned int *addr = __ia64_mk_io_addr(port); unsigned int ret; @@ -189,8 +169,8 @@ ___ia64_inl (unsigned long port) return ret; } -static inline void -___ia64_outb (unsigned char val, unsigned long port) +#define outb outb +static inline void outb(unsigned char val, unsigned long port) { volatile unsigned char *addr = __ia64_mk_io_addr(port); @@ -198,8 +178,8 @@ ___ia64_outb (unsigned char val, unsigned long port) __ia64_mf_a(); } -static inline void -___ia64_outw (unsigned short val, unsigned long port) +#define outw outw +static inline void outw(unsigned short val, unsigned long port) { volatile unsigned short *addr = __ia64_mk_io_addr(port); @@ -207,8 +187,8 @@ ___ia64_outw (unsigned short val, unsigned long port) __ia64_mf_a(); } -static inline void -___ia64_outl (unsigned int val, unsigned long port) +#define outl outl +static inline void outl(unsigned int val, unsigned long port) { volatile unsigned int *addr = __ia64_mk_io_addr(port); @@ -216,199 +196,63 @@ ___ia64_outl (unsigned int val, unsigned long port) __ia64_mf_a(); } -static inline void -__insb (unsigned long port, void *dst, unsigned long count) +#define insb insb +static inline void insb(unsigned long port, void *dst, unsigned long count) { unsigned char *dp = dst; while (count--) - *dp++ = platform_inb(port); + *dp++ = inb(port); } -static inline void -__insw (unsigned long port, void *dst, unsigned long count) +#define insw insw +static inline void insw(unsigned long port, void *dst, unsigned long count) { unsigned short *dp = dst; while (count--) - put_unaligned(platform_inw(port), dp++); + put_unaligned(inw(port), dp++); } -static inline void -__insl (unsigned long port, void *dst, unsigned long count) +#define insl insl +static inline void insl(unsigned long port, void *dst, unsigned long count) { unsigned int *dp = dst; while (count--) - put_unaligned(platform_inl(port), dp++); + put_unaligned(inl(port), dp++); } -static inline void -__outsb (unsigned long port, const void *src, unsigned long count) +#define outsb outsb +static inline void outsb(unsigned long port, const void *src, + unsigned long count) { const unsigned char *sp = src; while (count--) - platform_outb(*sp++, port); + outb(*sp++, port); } -static inline void -__outsw (unsigned long port, const void *src, unsigned long count) +#define outsw outsw +static inline void outsw(unsigned long port, const void *src, + unsigned long count) { const unsigned short *sp = src; while (count--) - platform_outw(get_unaligned(sp++), port); + outw(get_unaligned(sp++), port); } -static inline void -__outsl (unsigned long port, const void *src, unsigned long count) +#define outsl outsl +static inline void outsl(unsigned long port, const void *src, + unsigned long count) { const unsigned int *sp = src; while (count--) - platform_outl(get_unaligned(sp++), port); + outl(get_unaligned(sp++), port); } -/* - * Unfortunately, some platforms are broken and do not follow the IA-64 architecture - * specification regarding legacy I/O support. Thus, we have to make these operations - * platform dependent... - */ -#define __inb platform_inb -#define __inw platform_inw -#define __inl platform_inl -#define __outb platform_outb -#define __outw platform_outw -#define __outl platform_outl - -#define inb(p) __inb(p) -#define inw(p) __inw(p) -#define inl(p) __inl(p) -#define insb(p,d,c) __insb(p,d,c) -#define insw(p,d,c) __insw(p,d,c) -#define insl(p,d,c) __insl(p,d,c) -#define outb(v,p) __outb(v,p) -#define outw(v,p) __outw(v,p) -#define outl(v,p) __outl(v,p) -#define outsb(p,s,c) __outsb(p,s,c) -#define outsw(p,s,c) __outsw(p,s,c) -#define outsl(p,s,c) __outsl(p,s,c) - -/* - * The address passed to these functions are ioremap()ped already. - * - * We need these to be machine vectors since some platforms don't provide - * DMA coherence via PIO reads (PCI drivers and the spec imply that this is - * a good idea). Writes are ok though for all existing ia64 platforms (and - * hopefully it'll stay that way). - */ -static inline unsigned char -___ia64_readb (const volatile void __iomem *addr) -{ - return *(volatile unsigned char __force *)addr; -} - -static inline unsigned short -___ia64_readw (const volatile void __iomem *addr) -{ - return *(volatile unsigned short __force *)addr; -} - -static inline unsigned int -___ia64_readl (const volatile void __iomem *addr) -{ - return *(volatile unsigned int __force *) addr; -} - -static inline unsigned long -___ia64_readq (const volatile void __iomem *addr) -{ - return *(volatile unsigned long __force *) addr; -} - -static inline void -__writeb (unsigned char val, volatile void __iomem *addr) -{ - *(volatile unsigned char __force *) addr = val; -} - -static inline void -__writew (unsigned short val, volatile void __iomem *addr) -{ - *(volatile unsigned short __force *) addr = val; -} - -static inline void -__writel (unsigned int val, volatile void __iomem *addr) -{ - *(volatile unsigned int __force *) addr = val; -} - -static inline void -__writeq (unsigned long val, volatile void __iomem *addr) -{ - *(volatile unsigned long __force *) addr = val; -} - -#define __readb platform_readb -#define __readw platform_readw -#define __readl platform_readl -#define __readq platform_readq -#define __readb_relaxed platform_readb_relaxed -#define __readw_relaxed platform_readw_relaxed -#define __readl_relaxed platform_readl_relaxed -#define __readq_relaxed platform_readq_relaxed - -#define readb(a) __readb((a)) -#define readw(a) __readw((a)) -#define readl(a) __readl((a)) -#define readq(a) __readq((a)) -#define readb_relaxed(a) __readb_relaxed((a)) -#define readw_relaxed(a) __readw_relaxed((a)) -#define readl_relaxed(a) __readl_relaxed((a)) -#define readq_relaxed(a) __readq_relaxed((a)) -#define __raw_readb readb -#define __raw_readw readw -#define __raw_readl readl -#define __raw_readq readq -#define __raw_readb_relaxed readb_relaxed -#define __raw_readw_relaxed readw_relaxed -#define __raw_readl_relaxed readl_relaxed -#define __raw_readq_relaxed readq_relaxed -#define writeb(v,a) __writeb((v), (a)) -#define writew(v,a) __writew((v), (a)) -#define writel(v,a) __writel((v), (a)) -#define writeq(v,a) __writeq((v), (a)) -#define writeb_relaxed(v,a) __writeb((v), (a)) -#define writew_relaxed(v,a) __writew((v), (a)) -#define writel_relaxed(v,a) __writel((v), (a)) -#define writeq_relaxed(v,a) __writeq((v), (a)) -#define __raw_writeb writeb -#define __raw_writew writew -#define __raw_writel writel -#define __raw_writeq writeq - -#ifndef inb_p -# define inb_p inb -#endif -#ifndef inw_p -# define inw_p inw -#endif -#ifndef inl_p -# define inl_p inl -#endif - -#ifndef outb_p -# define outb_p outb -#endif -#ifndef outw_p -# define outw_p outw -#endif -#ifndef outl_p -# define outl_p outl -#endif - # ifdef __KERNEL__ extern void __iomem * ioremap(unsigned long offset, unsigned long size); diff --git a/arch/ia64/include/asm/iommu.h b/arch/ia64/include/asm/iommu.h index 7429a72f3f921996643c48d19dc206fe3034b7dd..7904f591a79bc0188677aef9ca086eb97ad651dc 100644 --- a/arch/ia64/include/asm/iommu.h +++ b/arch/ia64/include/asm/iommu.h @@ -8,13 +8,10 @@ extern void no_iommu_init(void); #ifdef CONFIG_INTEL_IOMMU extern int force_iommu, no_iommu; -extern int iommu_pass_through; extern int iommu_detected; #else -#define iommu_pass_through (0) #define no_iommu (1) #define iommu_detected (0) #endif -extern void machvec_init(const char *name); #endif diff --git a/arch/ia64/include/asm/iosapic.h b/arch/ia64/include/asm/iosapic.h index f48556cb8afccf2980b65f7e78ecd1fadfc2b96d..a91aeb413e17b4c542e734ad5b6df8a3678332c4 100644 --- a/arch/ia64/include/asm/iosapic.h +++ b/arch/ia64/include/asm/iosapic.h @@ -52,8 +52,6 @@ #ifndef __ASSEMBLY__ -#ifdef CONFIG_IOSAPIC - #define NR_IOSAPICS 256 #define iosapic_pcat_compat_init ia64_native_iosapic_pcat_compat_init @@ -103,16 +101,6 @@ extern int __init iosapic_register_platform_intr (u32 int_type, #ifdef CONFIG_NUMA extern void map_iosapic_to_node (unsigned int, int); #endif -#else -#define iosapic_system_init(pcat_compat) do { } while (0) -#define iosapic_init(address,gsi_base) (-EINVAL) -#define iosapic_remove(gsi_base) (-ENODEV) -#define iosapic_register_intr(gsi,polarity,trigger) (gsi) -#define iosapic_unregister_intr(irq) do { } while (0) -#define iosapic_override_isa_irq(isa_irq,gsi,polarity,trigger) do { } while (0) -#define iosapic_register_platform_intr(type,gsi,pmi,eid,id, \ - polarity,trigger) (gsi) -#endif # endif /* !__ASSEMBLY__ */ #endif /* __ASM_IA64_IOSAPIC_H */ diff --git a/arch/ia64/include/asm/irq.h b/arch/ia64/include/asm/irq.h index 8b84a55ed38a11a1b2e503ffe6b0d2cb9c454390..5acf52e908722c0a3cbeaaba96ed7e310a042707 100644 --- a/arch/ia64/include/asm/irq.h +++ b/arch/ia64/include/asm/irq.h @@ -28,9 +28,6 @@ irq_canonicalize (int irq) } extern void set_irq_affinity_info (unsigned int irq, int dest, int redir); -bool is_affinity_mask_valid(const struct cpumask *cpumask); - -#define is_affinity_mask_valid is_affinity_mask_valid int create_irq(void); void destroy_irq(unsigned int irq); diff --git a/arch/ia64/include/asm/machvec.h b/arch/ia64/include/asm/machvec.h deleted file mode 100644 index beae261fbcb415b2321af6c333bd9ce5e304896f..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/machvec.h +++ /dev/null @@ -1,347 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Machine vector for IA-64. - * - * Copyright (C) 1999 Silicon Graphics, Inc. - * Copyright (C) Srinivasa Thirumalachar - * Copyright (C) Vijay Chander - * Copyright (C) 1999-2001, 2003-2004 Hewlett-Packard Co. - * David Mosberger-Tang - */ -#ifndef _ASM_IA64_MACHVEC_H -#define _ASM_IA64_MACHVEC_H - -#include - -/* forward declarations: */ -struct device; -struct pt_regs; -struct scatterlist; -struct page; -struct mm_struct; -struct pci_bus; -struct task_struct; -struct pci_dev; -struct msi_desc; - -typedef void ia64_mv_setup_t (char **); -typedef void ia64_mv_cpu_init_t (void); -typedef void ia64_mv_irq_init_t (void); -typedef void ia64_mv_send_ipi_t (int, int, int, int); -typedef void ia64_mv_timer_interrupt_t (int, void *); -typedef void ia64_mv_global_tlb_purge_t (struct mm_struct *, unsigned long, unsigned long, unsigned long); -typedef u8 ia64_mv_irq_to_vector (int); -typedef unsigned int ia64_mv_local_vector_to_irq (u8); -typedef char *ia64_mv_pci_get_legacy_mem_t (struct pci_bus *); -typedef int ia64_mv_pci_legacy_read_t (struct pci_bus *, u16 port, u32 *val, - u8 size); -typedef int ia64_mv_pci_legacy_write_t (struct pci_bus *, u16 port, u32 val, - u8 size); -typedef void ia64_mv_migrate_t(struct task_struct * task); -typedef void ia64_mv_pci_fixup_bus_t (struct pci_bus *); -typedef void ia64_mv_kernel_launch_event_t(void); - -/* DMA-mapping interface: */ -typedef void ia64_mv_dma_init (void); -typedef const struct dma_map_ops *ia64_mv_dma_get_ops(struct device *); - -/* - * WARNING: The legacy I/O space is _architected_. Platforms are - * expected to follow this architected model (see Section 10.7 in the - * IA-64 Architecture Software Developer's Manual). Unfortunately, - * some broken machines do not follow that model, which is why we have - * to make the inX/outX operations part of the machine vector. - * Platform designers should follow the architected model whenever - * possible. - */ -typedef unsigned int ia64_mv_inb_t (unsigned long); -typedef unsigned int ia64_mv_inw_t (unsigned long); -typedef unsigned int ia64_mv_inl_t (unsigned long); -typedef void ia64_mv_outb_t (unsigned char, unsigned long); -typedef void ia64_mv_outw_t (unsigned short, unsigned long); -typedef void ia64_mv_outl_t (unsigned int, unsigned long); -typedef void ia64_mv_mmiowb_t (void); -typedef unsigned char ia64_mv_readb_t (const volatile void __iomem *); -typedef unsigned short ia64_mv_readw_t (const volatile void __iomem *); -typedef unsigned int ia64_mv_readl_t (const volatile void __iomem *); -typedef unsigned long ia64_mv_readq_t (const volatile void __iomem *); -typedef unsigned char ia64_mv_readb_relaxed_t (const volatile void __iomem *); -typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *); -typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *); -typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *); - -typedef int ia64_mv_setup_msi_irq_t (struct pci_dev *pdev, struct msi_desc *); -typedef void ia64_mv_teardown_msi_irq_t (unsigned int irq); - -static inline void -machvec_noop (void) -{ -} - -static inline void -machvec_noop_task (struct task_struct *task) -{ -} - -static inline void -machvec_noop_bus (struct pci_bus *bus) -{ -} - -extern void machvec_setup (char **); -extern void machvec_timer_interrupt (int, void *); - -# if defined (CONFIG_IA64_HP_SIM) -# include -# elif defined (CONFIG_IA64_DIG) -# include -# elif defined(CONFIG_IA64_DIG_VTD) -# include -# elif defined (CONFIG_IA64_HP_ZX1) -# include -# elif defined (CONFIG_IA64_HP_ZX1_SWIOTLB) -# include -# elif defined (CONFIG_IA64_SGI_SN2) -# include -# elif defined (CONFIG_IA64_SGI_UV) -# include -# elif defined (CONFIG_IA64_GENERIC) - -# ifdef MACHVEC_PLATFORM_HEADER -# include MACHVEC_PLATFORM_HEADER -# else -# define ia64_platform_name ia64_mv.name -# define platform_setup ia64_mv.setup -# define platform_cpu_init ia64_mv.cpu_init -# define platform_irq_init ia64_mv.irq_init -# define platform_send_ipi ia64_mv.send_ipi -# define platform_timer_interrupt ia64_mv.timer_interrupt -# define platform_global_tlb_purge ia64_mv.global_tlb_purge -# define platform_dma_init ia64_mv.dma_init -# define platform_dma_get_ops ia64_mv.dma_get_ops -# define platform_irq_to_vector ia64_mv.irq_to_vector -# define platform_local_vector_to_irq ia64_mv.local_vector_to_irq -# define platform_pci_get_legacy_mem ia64_mv.pci_get_legacy_mem -# define platform_pci_legacy_read ia64_mv.pci_legacy_read -# define platform_pci_legacy_write ia64_mv.pci_legacy_write -# define platform_inb ia64_mv.inb -# define platform_inw ia64_mv.inw -# define platform_inl ia64_mv.inl -# define platform_outb ia64_mv.outb -# define platform_outw ia64_mv.outw -# define platform_outl ia64_mv.outl -# define platform_mmiowb ia64_mv.mmiowb -# define platform_readb ia64_mv.readb -# define platform_readw ia64_mv.readw -# define platform_readl ia64_mv.readl -# define platform_readq ia64_mv.readq -# define platform_readb_relaxed ia64_mv.readb_relaxed -# define platform_readw_relaxed ia64_mv.readw_relaxed -# define platform_readl_relaxed ia64_mv.readl_relaxed -# define platform_readq_relaxed ia64_mv.readq_relaxed -# define platform_migrate ia64_mv.migrate -# define platform_setup_msi_irq ia64_mv.setup_msi_irq -# define platform_teardown_msi_irq ia64_mv.teardown_msi_irq -# define platform_pci_fixup_bus ia64_mv.pci_fixup_bus -# define platform_kernel_launch_event ia64_mv.kernel_launch_event -# endif - -/* __attribute__((__aligned__(16))) is required to make size of the - * structure multiple of 16 bytes. - * This will fillup the holes created because of section 3.3.1 in - * Software Conventions guide. - */ -struct ia64_machine_vector { - const char *name; - ia64_mv_setup_t *setup; - ia64_mv_cpu_init_t *cpu_init; - ia64_mv_irq_init_t *irq_init; - ia64_mv_send_ipi_t *send_ipi; - ia64_mv_timer_interrupt_t *timer_interrupt; - ia64_mv_global_tlb_purge_t *global_tlb_purge; - ia64_mv_dma_init *dma_init; - ia64_mv_dma_get_ops *dma_get_ops; - ia64_mv_irq_to_vector *irq_to_vector; - ia64_mv_local_vector_to_irq *local_vector_to_irq; - ia64_mv_pci_get_legacy_mem_t *pci_get_legacy_mem; - ia64_mv_pci_legacy_read_t *pci_legacy_read; - ia64_mv_pci_legacy_write_t *pci_legacy_write; - ia64_mv_inb_t *inb; - ia64_mv_inw_t *inw; - ia64_mv_inl_t *inl; - ia64_mv_outb_t *outb; - ia64_mv_outw_t *outw; - ia64_mv_outl_t *outl; - ia64_mv_mmiowb_t *mmiowb; - ia64_mv_readb_t *readb; - ia64_mv_readw_t *readw; - ia64_mv_readl_t *readl; - ia64_mv_readq_t *readq; - ia64_mv_readb_relaxed_t *readb_relaxed; - ia64_mv_readw_relaxed_t *readw_relaxed; - ia64_mv_readl_relaxed_t *readl_relaxed; - ia64_mv_readq_relaxed_t *readq_relaxed; - ia64_mv_migrate_t *migrate; - ia64_mv_setup_msi_irq_t *setup_msi_irq; - ia64_mv_teardown_msi_irq_t *teardown_msi_irq; - ia64_mv_pci_fixup_bus_t *pci_fixup_bus; - ia64_mv_kernel_launch_event_t *kernel_launch_event; -} __attribute__((__aligned__(16))); /* align attrib? see above comment */ - -#define MACHVEC_INIT(name) \ -{ \ - #name, \ - platform_setup, \ - platform_cpu_init, \ - platform_irq_init, \ - platform_send_ipi, \ - platform_timer_interrupt, \ - platform_global_tlb_purge, \ - platform_dma_init, \ - platform_dma_get_ops, \ - platform_irq_to_vector, \ - platform_local_vector_to_irq, \ - platform_pci_get_legacy_mem, \ - platform_pci_legacy_read, \ - platform_pci_legacy_write, \ - platform_inb, \ - platform_inw, \ - platform_inl, \ - platform_outb, \ - platform_outw, \ - platform_outl, \ - platform_mmiowb, \ - platform_readb, \ - platform_readw, \ - platform_readl, \ - platform_readq, \ - platform_readb_relaxed, \ - platform_readw_relaxed, \ - platform_readl_relaxed, \ - platform_readq_relaxed, \ - platform_migrate, \ - platform_setup_msi_irq, \ - platform_teardown_msi_irq, \ - platform_pci_fixup_bus, \ - platform_kernel_launch_event \ -} - -extern struct ia64_machine_vector ia64_mv; -extern void machvec_init (const char *name); -extern void machvec_init_from_cmdline(const char *cmdline); - -# else -# error Unknown configuration. Update arch/ia64/include/asm/machvec.h. -# endif /* CONFIG_IA64_GENERIC */ - -extern void swiotlb_dma_init(void); -extern const struct dma_map_ops *dma_get_ops(struct device *); - -/* - * Define default versions so we can extend machvec for new platforms without having - * to update the machvec files for all existing platforms. - */ -#ifndef platform_setup -# define platform_setup machvec_setup -#endif -#ifndef platform_cpu_init -# define platform_cpu_init machvec_noop -#endif -#ifndef platform_irq_init -# define platform_irq_init machvec_noop -#endif - -#ifndef platform_send_ipi -# define platform_send_ipi ia64_send_ipi /* default to architected version */ -#endif -#ifndef platform_timer_interrupt -# define platform_timer_interrupt machvec_timer_interrupt -#endif -#ifndef platform_global_tlb_purge -# define platform_global_tlb_purge ia64_global_tlb_purge /* default to architected version */ -#endif -#ifndef platform_kernel_launch_event -# define platform_kernel_launch_event machvec_noop -#endif -#ifndef platform_dma_init -# define platform_dma_init swiotlb_dma_init -#endif -#ifndef platform_dma_get_ops -# define platform_dma_get_ops dma_get_ops -#endif -#ifndef platform_irq_to_vector -# define platform_irq_to_vector __ia64_irq_to_vector -#endif -#ifndef platform_local_vector_to_irq -# define platform_local_vector_to_irq __ia64_local_vector_to_irq -#endif -#ifndef platform_pci_get_legacy_mem -# define platform_pci_get_legacy_mem ia64_pci_get_legacy_mem -#endif -#ifndef platform_pci_legacy_read -# define platform_pci_legacy_read ia64_pci_legacy_read -extern int ia64_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size); -#endif -#ifndef platform_pci_legacy_write -# define platform_pci_legacy_write ia64_pci_legacy_write -extern int ia64_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size); -#endif -#ifndef platform_inb -# define platform_inb __ia64_inb -#endif -#ifndef platform_inw -# define platform_inw __ia64_inw -#endif -#ifndef platform_inl -# define platform_inl __ia64_inl -#endif -#ifndef platform_outb -# define platform_outb __ia64_outb -#endif -#ifndef platform_outw -# define platform_outw __ia64_outw -#endif -#ifndef platform_outl -# define platform_outl __ia64_outl -#endif -#ifndef platform_mmiowb -# define platform_mmiowb __ia64_mmiowb -#endif -#ifndef platform_readb -# define platform_readb __ia64_readb -#endif -#ifndef platform_readw -# define platform_readw __ia64_readw -#endif -#ifndef platform_readl -# define platform_readl __ia64_readl -#endif -#ifndef platform_readq -# define platform_readq __ia64_readq -#endif -#ifndef platform_readb_relaxed -# define platform_readb_relaxed __ia64_readb_relaxed -#endif -#ifndef platform_readw_relaxed -# define platform_readw_relaxed __ia64_readw_relaxed -#endif -#ifndef platform_readl_relaxed -# define platform_readl_relaxed __ia64_readl_relaxed -#endif -#ifndef platform_readq_relaxed -# define platform_readq_relaxed __ia64_readq_relaxed -#endif -#ifndef platform_migrate -# define platform_migrate machvec_noop_task -#endif -#ifndef platform_setup_msi_irq -# define platform_setup_msi_irq ((ia64_mv_setup_msi_irq_t*)NULL) -#endif -#ifndef platform_teardown_msi_irq -# define platform_teardown_msi_irq ((ia64_mv_teardown_msi_irq_t*)NULL) -#endif -#ifndef platform_pci_fixup_bus -# define platform_pci_fixup_bus machvec_noop_bus -#endif - -#endif /* _ASM_IA64_MACHVEC_H */ diff --git a/arch/ia64/include/asm/machvec_dig.h b/arch/ia64/include/asm/machvec_dig.h deleted file mode 100644 index bc230f69faebcee28337e74591eff78ccf65f726..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/machvec_dig.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_IA64_MACHVEC_DIG_h -#define _ASM_IA64_MACHVEC_DIG_h - -extern ia64_mv_setup_t dig_setup; - -/* - * This stuff has dual use! - * - * For a generic kernel, the macros are used to initialize the - * platform's machvec structure. When compiling a non-generic kernel, - * the macros are used directly. - */ -#define ia64_platform_name "dig" -#define platform_setup dig_setup - -#endif /* _ASM_IA64_MACHVEC_DIG_h */ diff --git a/arch/ia64/include/asm/machvec_dig_vtd.h b/arch/ia64/include/asm/machvec_dig_vtd.h deleted file mode 100644 index bb44eb9039ddf80e0b1cfb09c31fb97ad80b613a..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/machvec_dig_vtd.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_IA64_MACHVEC_DIG_VTD_h -#define _ASM_IA64_MACHVEC_DIG_VTD_h - -extern ia64_mv_setup_t dig_setup; -extern ia64_mv_dma_init pci_iommu_alloc; - -/* - * This stuff has dual use! - * - * For a generic kernel, the macros are used to initialize the - * platform's machvec structure. When compiling a non-generic kernel, - * the macros are used directly. - */ -#define ia64_platform_name "dig_vtd" -#define platform_setup dig_setup -#define platform_dma_init pci_iommu_alloc - -#endif /* _ASM_IA64_MACHVEC_DIG_VTD_h */ diff --git a/arch/ia64/include/asm/machvec_hpsim.h b/arch/ia64/include/asm/machvec_hpsim.h deleted file mode 100644 index 056f8405822eda428ed9023182464fa6af0b2122..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/machvec_hpsim.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_IA64_MACHVEC_HPSIM_h -#define _ASM_IA64_MACHVEC_HPSIM_h - -extern ia64_mv_setup_t hpsim_setup; -extern ia64_mv_irq_init_t hpsim_irq_init; - -/* - * This stuff has dual use! - * - * For a generic kernel, the macros are used to initialize the - * platform's machvec structure. When compiling a non-generic kernel, - * the macros are used directly. - */ -#define ia64_platform_name "hpsim" -#define platform_setup hpsim_setup -#define platform_irq_init hpsim_irq_init - -#endif /* _ASM_IA64_MACHVEC_HPSIM_h */ diff --git a/arch/ia64/include/asm/machvec_hpzx1.h b/arch/ia64/include/asm/machvec_hpzx1.h deleted file mode 100644 index 5299ac38bfb6d018c959ce85896df46d79c2a8b9..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/machvec_hpzx1.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_IA64_MACHVEC_HPZX1_h -#define _ASM_IA64_MACHVEC_HPZX1_h - -extern ia64_mv_setup_t dig_setup; -extern ia64_mv_dma_init sba_dma_init; - -/* - * This stuff has dual use! - * - * For a generic kernel, the macros are used to initialize the - * platform's machvec structure. When compiling a non-generic kernel, - * the macros are used directly. - */ -#define ia64_platform_name "hpzx1" -#define platform_setup dig_setup -#define platform_dma_init sba_dma_init - -#endif /* _ASM_IA64_MACHVEC_HPZX1_h */ diff --git a/arch/ia64/include/asm/machvec_hpzx1_swiotlb.h b/arch/ia64/include/asm/machvec_hpzx1_swiotlb.h deleted file mode 100644 index 5aec6a008c61312aa6a603fed7eb64d4b7e9f9ae..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/machvec_hpzx1_swiotlb.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_IA64_MACHVEC_HPZX1_SWIOTLB_h -#define _ASM_IA64_MACHVEC_HPZX1_SWIOTLB_h - -extern ia64_mv_setup_t dig_setup; -extern ia64_mv_dma_get_ops hwsw_dma_get_ops; - -/* - * This stuff has dual use! - * - * For a generic kernel, the macros are used to initialize the - * platform's machvec structure. When compiling a non-generic kernel, - * the macros are used directly. - */ -#define ia64_platform_name "hpzx1_swiotlb" -#define platform_setup dig_setup -#define platform_dma_init machvec_noop -#define platform_dma_get_ops hwsw_dma_get_ops - -#endif /* _ASM_IA64_MACHVEC_HPZX1_SWIOTLB_h */ diff --git a/arch/ia64/include/asm/machvec_init.h b/arch/ia64/include/asm/machvec_init.h deleted file mode 100644 index 2aafb69a37874dd5a7f0d0a098a28ed2b0ef8aba..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/machvec_init.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#include -#include - -extern ia64_mv_send_ipi_t ia64_send_ipi; -extern ia64_mv_global_tlb_purge_t ia64_global_tlb_purge; -extern ia64_mv_irq_to_vector __ia64_irq_to_vector; -extern ia64_mv_local_vector_to_irq __ia64_local_vector_to_irq; -extern ia64_mv_pci_get_legacy_mem_t ia64_pci_get_legacy_mem; -extern ia64_mv_pci_legacy_read_t ia64_pci_legacy_read; -extern ia64_mv_pci_legacy_write_t ia64_pci_legacy_write; - -extern ia64_mv_inb_t __ia64_inb; -extern ia64_mv_inw_t __ia64_inw; -extern ia64_mv_inl_t __ia64_inl; -extern ia64_mv_outb_t __ia64_outb; -extern ia64_mv_outw_t __ia64_outw; -extern ia64_mv_outl_t __ia64_outl; -extern ia64_mv_mmiowb_t __ia64_mmiowb; -extern ia64_mv_readb_t __ia64_readb; -extern ia64_mv_readw_t __ia64_readw; -extern ia64_mv_readl_t __ia64_readl; -extern ia64_mv_readq_t __ia64_readq; -extern ia64_mv_readb_t __ia64_readb_relaxed; -extern ia64_mv_readw_t __ia64_readw_relaxed; -extern ia64_mv_readl_t __ia64_readl_relaxed; -extern ia64_mv_readq_t __ia64_readq_relaxed; - -#define MACHVEC_HELPER(name) \ - struct ia64_machine_vector machvec_##name __attribute__ ((unused, __section__ (".machvec"))) \ - = MACHVEC_INIT(name); - -#define MACHVEC_DEFINE(name) MACHVEC_HELPER(name) - -MACHVEC_DEFINE(MACHVEC_PLATFORM_NAME) diff --git a/arch/ia64/include/asm/machvec_sn2.h b/arch/ia64/include/asm/machvec_sn2.h deleted file mode 100644 index a243e4fb4877d7416949359ae6b52d59d25d803d..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/machvec_sn2.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2002-2003,2006 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#ifndef _ASM_IA64_MACHVEC_SN2_H -#define _ASM_IA64_MACHVEC_SN2_H - -extern ia64_mv_setup_t sn_setup; -extern ia64_mv_cpu_init_t sn_cpu_init; -extern ia64_mv_irq_init_t sn_irq_init; -extern ia64_mv_send_ipi_t sn2_send_IPI; -extern ia64_mv_timer_interrupt_t sn_timer_interrupt; -extern ia64_mv_global_tlb_purge_t sn2_global_tlb_purge; -extern ia64_mv_irq_to_vector sn_irq_to_vector; -extern ia64_mv_local_vector_to_irq sn_local_vector_to_irq; -extern ia64_mv_pci_get_legacy_mem_t sn_pci_get_legacy_mem; -extern ia64_mv_pci_legacy_read_t sn_pci_legacy_read; -extern ia64_mv_pci_legacy_write_t sn_pci_legacy_write; -extern ia64_mv_inb_t __sn_inb; -extern ia64_mv_inw_t __sn_inw; -extern ia64_mv_inl_t __sn_inl; -extern ia64_mv_outb_t __sn_outb; -extern ia64_mv_outw_t __sn_outw; -extern ia64_mv_outl_t __sn_outl; -extern ia64_mv_mmiowb_t __sn_mmiowb; -extern ia64_mv_readb_t __sn_readb; -extern ia64_mv_readw_t __sn_readw; -extern ia64_mv_readl_t __sn_readl; -extern ia64_mv_readq_t __sn_readq; -extern ia64_mv_readb_t __sn_readb_relaxed; -extern ia64_mv_readw_t __sn_readw_relaxed; -extern ia64_mv_readl_t __sn_readl_relaxed; -extern ia64_mv_readq_t __sn_readq_relaxed; -extern ia64_mv_dma_init sn_dma_init; -extern ia64_mv_migrate_t sn_migrate; -extern ia64_mv_kernel_launch_event_t sn_kernel_launch_event; -extern ia64_mv_setup_msi_irq_t sn_setup_msi_irq; -extern ia64_mv_teardown_msi_irq_t sn_teardown_msi_irq; -extern ia64_mv_pci_fixup_bus_t sn_pci_fixup_bus; - - -/* - * This stuff has dual use! - * - * For a generic kernel, the macros are used to initialize the - * platform's machvec structure. When compiling a non-generic kernel, - * the macros are used directly. - */ -#define ia64_platform_name "sn2" -#define platform_setup sn_setup -#define platform_cpu_init sn_cpu_init -#define platform_irq_init sn_irq_init -#define platform_send_ipi sn2_send_IPI -#define platform_timer_interrupt sn_timer_interrupt -#define platform_global_tlb_purge sn2_global_tlb_purge -#define platform_pci_fixup sn_pci_fixup -#define platform_inb __sn_inb -#define platform_inw __sn_inw -#define platform_inl __sn_inl -#define platform_outb __sn_outb -#define platform_outw __sn_outw -#define platform_outl __sn_outl -#define platform_mmiowb __sn_mmiowb -#define platform_readb __sn_readb -#define platform_readw __sn_readw -#define platform_readl __sn_readl -#define platform_readq __sn_readq -#define platform_readb_relaxed __sn_readb_relaxed -#define platform_readw_relaxed __sn_readw_relaxed -#define platform_readl_relaxed __sn_readl_relaxed -#define platform_readq_relaxed __sn_readq_relaxed -#define platform_irq_to_vector sn_irq_to_vector -#define platform_local_vector_to_irq sn_local_vector_to_irq -#define platform_pci_get_legacy_mem sn_pci_get_legacy_mem -#define platform_pci_legacy_read sn_pci_legacy_read -#define platform_pci_legacy_write sn_pci_legacy_write -#define platform_dma_init sn_dma_init -#define platform_migrate sn_migrate -#define platform_kernel_launch_event sn_kernel_launch_event -#ifdef CONFIG_PCI_MSI -#define platform_setup_msi_irq sn_setup_msi_irq -#define platform_teardown_msi_irq sn_teardown_msi_irq -#else -#define platform_setup_msi_irq ((ia64_mv_setup_msi_irq_t*)NULL) -#define platform_teardown_msi_irq ((ia64_mv_teardown_msi_irq_t*)NULL) -#endif -#define platform_pci_fixup_bus sn_pci_fixup_bus - -#include - -#endif /* _ASM_IA64_MACHVEC_SN2_H */ diff --git a/arch/ia64/include/asm/machvec_uv.h b/arch/ia64/include/asm/machvec_uv.h deleted file mode 100644 index 2c50853f35ac0037297d0860c26ffb5ecb9b88a3..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/machvec_uv.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * SGI UV Core Functions - * - * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_MACHVEC_UV_H -#define _ASM_IA64_MACHVEC_UV_H - -extern ia64_mv_setup_t uv_setup; - -/* - * This stuff has dual use! - * - * For a generic kernel, the macros are used to initialize the - * platform's machvec structure. When compiling a non-generic kernel, - * the macros are used directly. - */ -#define ia64_platform_name "uv" -#define platform_setup uv_setup - -#endif /* _ASM_IA64_MACHVEC_UV_H */ diff --git a/arch/ia64/include/asm/mmiowb.h b/arch/ia64/include/asm/mmiowb.h index 297b85ac84a01b04f779e919b2257515934f005b..d67aab4ea3b4226d20162fde39c49572fd941b32 100644 --- a/arch/ia64/include/asm/mmiowb.h +++ b/arch/ia64/include/asm/mmiowb.h @@ -3,22 +3,14 @@ #ifndef _ASM_IA64_MMIOWB_H #define _ASM_IA64_MMIOWB_H -#include - /** - * ___ia64_mmiowb - I/O write barrier + * mmiowb - I/O write barrier * * Ensure ordering of I/O space writes. This will make sure that writes * following the barrier will arrive after all previous writes. For most * ia64 platforms, this is a simple 'mf.a' instruction. */ -static inline void ___ia64_mmiowb(void) -{ - ia64_mfa(); -} - -#define __ia64_mmiowb ___ia64_mmiowb -#define mmiowb() platform_mmiowb() +#define mmiowb() ia64_mfa() #include diff --git a/arch/ia64/include/asm/mmzone.h b/arch/ia64/include/asm/mmzone.h index e0de61709cf13bc937869e61d436a18b5d6bf6b6..767201f66c93e8dffdbf77992ec57af263f83475 100644 --- a/arch/ia64/include/asm/mmzone.h +++ b/arch/ia64/include/asm/mmzone.h @@ -27,16 +27,9 @@ static inline int pfn_to_nid(unsigned long pfn) return nid; } -#ifdef CONFIG_IA64_DIG /* DIG systems are small */ -# define MAX_PHYSNODE_ID 8 -# define NR_NODE_MEMBLKS (MAX_NUMNODES * 8) -#else /* sn2 is the biggest case, so we use that if !DIG */ -# define MAX_PHYSNODE_ID 2048 -# define NR_NODE_MEMBLKS (MAX_NUMNODES * 4) -#endif - -#else /* CONFIG_NUMA */ -# define NR_NODE_MEMBLKS (MAX_NUMNODES * 4) +#define MAX_PHYSNODE_ID 2048 #endif /* CONFIG_NUMA */ +#define NR_NODE_MEMBLKS (MAX_NUMNODES * 4) + #endif /* _ASM_IA64_MMZONE_H */ diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h index 780e8744ba85dce10e70d6506ee98c7092a5a565..8c163d1d01891a1f62eb17119a55b8b95a648016 100644 --- a/arch/ia64/include/asm/pci.h +++ b/arch/ia64/include/asm/pci.h @@ -39,9 +39,9 @@ extern int pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma, enum pci_mmap_state mmap_state); -#define pci_get_legacy_mem platform_pci_get_legacy_mem -#define pci_legacy_read platform_pci_legacy_read -#define pci_legacy_write platform_pci_legacy_write +char *pci_get_legacy_mem(struct pci_bus *bus); +int pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size); +int pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size); struct pci_controller { struct acpi_device *companion; @@ -69,7 +69,4 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) return channel ? isa_irq_to_vector(15) : isa_irq_to_vector(14); } -#ifdef CONFIG_INTEL_IOMMU -extern void pci_iommu_alloc(void); -#endif #endif /* _ASM_IA64_PCI_H */ diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h index c91ef98ed6bf15d97485f7987ceee6ee715f0e08..95a2ec37400fb7d7b76c9d1b04909f96cdbc52e0 100644 --- a/arch/ia64/include/asm/processor.h +++ b/arch/ia64/include/asm/processor.h @@ -679,8 +679,6 @@ enum idle_boot_override {IDLE_NO_OVERRIDE=0, IDLE_HALT, IDLE_FORCE_MWAIT, void default_idle(void); -#define ia64_platform_is(x) (strcmp(x, ia64_platform_name) == 0) - #endif /* !__ASSEMBLY__ */ #endif /* _ASM_IA64_PROCESSOR_H */ diff --git a/arch/ia64/include/asm/sal.h b/arch/ia64/include/asm/sal.h index 588f33156da6901053bc1022856b59ca86a1aea6..08f5b6aaed7324096e0d07cc39503c7d65b1dc9d 100644 --- a/arch/ia64/include/asm/sal.h +++ b/arch/ia64/include/asm/sal.h @@ -43,6 +43,7 @@ #include #include +extern unsigned long sal_systab_phys; extern spinlock_t sal_lock; /* SAL spec _requires_ eight args for each call. */ diff --git a/arch/ia64/include/asm/sn/acpi.h b/arch/ia64/include/asm/sn/acpi.h deleted file mode 100644 index fd480db255659bfe85d8bc29ae9f3dd5ebb3000e..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/acpi.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2006 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_ACPI_H -#define _ASM_IA64_SN_ACPI_H - -extern int sn_acpi_rev; -#define SN_ACPI_BASE_SUPPORT() (sn_acpi_rev >= 0x20101) - -#endif /* _ASM_IA64_SN_ACPI_H */ diff --git a/arch/ia64/include/asm/sn/addrs.h b/arch/ia64/include/asm/sn/addrs.h deleted file mode 100644 index e715c794b1865d0216cc9697b8b716e139f89c93..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/addrs.h +++ /dev/null @@ -1,299 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 1992-1999,2001-2005 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_ADDRS_H -#define _ASM_IA64_SN_ADDRS_H - -#include -#include -#include -#include - -/* - * Memory/SHUB Address Format: - * +-+---------+--+--------------+ - * |0| NASID |AS| NodeOffset | - * +-+---------+--+--------------+ - * - * NASID: (low NASID bit is 0) Memory and SHUB MMRs - * AS: 2-bit Address Space Identifier. Used only if low NASID bit is 0 - * 00: Local Resources and MMR space - * Top bit of NodeOffset - * 0: Local resources space - * node id: - * 0: IA64/NT compatibility space - * 2: Local MMR Space - * 4: Local memory, regardless of local node id - * 1: Global MMR space - * 01: GET space. - * 10: AMO space. - * 11: Cacheable memory space. - * - * NodeOffset: byte offset - * - * - * TIO address format: - * +-+----------+--+--------------+ - * |0| NASID |AS| Nodeoffset | - * +-+----------+--+--------------+ - * - * NASID: (low NASID bit is 1) TIO - * AS: 2-bit Chiplet Identifier - * 00: TIO LB (Indicates TIO MMR access.) - * 01: TIO ICE (indicates coretalk space access.) - * - * NodeOffset: top bit must be set. - * - * - * Note that in both of the above address formats, the low - * NASID bit indicates if the reference is to the SHUB or TIO MMRs. - */ - - -/* - * Define basic shift & mask constants for manipulating NASIDs and AS values. - */ -#define NASID_BITMASK (sn_hub_info->nasid_bitmask) -#define NASID_SHIFT (sn_hub_info->nasid_shift) -#define AS_SHIFT (sn_hub_info->as_shift) -#define AS_BITMASK 0x3UL - -#define NASID_MASK ((u64)NASID_BITMASK << NASID_SHIFT) -#define AS_MASK ((u64)AS_BITMASK << AS_SHIFT) - - -/* - * AS values. These are the same on both SHUB1 & SHUB2. - */ -#define AS_GET_VAL 1UL -#define AS_AMO_VAL 2UL -#define AS_CAC_VAL 3UL -#define AS_GET_SPACE (AS_GET_VAL << AS_SHIFT) -#define AS_AMO_SPACE (AS_AMO_VAL << AS_SHIFT) -#define AS_CAC_SPACE (AS_CAC_VAL << AS_SHIFT) - - -/* - * Virtual Mode Local & Global MMR space. - */ -#define SH1_LOCAL_MMR_OFFSET 0x8000000000UL -#define SH2_LOCAL_MMR_OFFSET 0x0200000000UL -#define LOCAL_MMR_OFFSET (is_shub2() ? SH2_LOCAL_MMR_OFFSET : SH1_LOCAL_MMR_OFFSET) -#define LOCAL_MMR_SPACE (__IA64_UNCACHED_OFFSET | LOCAL_MMR_OFFSET) -#define LOCAL_PHYS_MMR_SPACE (RGN_BASE(RGN_HPAGE) | LOCAL_MMR_OFFSET) - -#define SH1_GLOBAL_MMR_OFFSET 0x0800000000UL -#define SH2_GLOBAL_MMR_OFFSET 0x0300000000UL -#define GLOBAL_MMR_OFFSET (is_shub2() ? SH2_GLOBAL_MMR_OFFSET : SH1_GLOBAL_MMR_OFFSET) -#define GLOBAL_MMR_SPACE (__IA64_UNCACHED_OFFSET | GLOBAL_MMR_OFFSET) - -/* - * Physical mode addresses - */ -#define GLOBAL_PHYS_MMR_SPACE (RGN_BASE(RGN_HPAGE) | GLOBAL_MMR_OFFSET) - - -/* - * Clear region & AS bits. - */ -#define TO_PHYS_MASK (~(RGN_BITS | AS_MASK)) - - -/* - * Misc NASID manipulation. - */ -#define NASID_SPACE(n) ((u64)(n) << NASID_SHIFT) -#define REMOTE_ADDR(n,a) (NASID_SPACE(n) | (a)) -#define NODE_OFFSET(x) ((x) & (NODE_ADDRSPACE_SIZE - 1)) -#define NODE_ADDRSPACE_SIZE (1UL << AS_SHIFT) -#define NASID_GET(x) (int) (((u64) (x) >> NASID_SHIFT) & NASID_BITMASK) -#define LOCAL_MMR_ADDR(a) (LOCAL_MMR_SPACE | (a)) -#define GLOBAL_MMR_ADDR(n,a) (GLOBAL_MMR_SPACE | REMOTE_ADDR(n,a)) -#define GLOBAL_MMR_PHYS_ADDR(n,a) (GLOBAL_PHYS_MMR_SPACE | REMOTE_ADDR(n,a)) -#define GLOBAL_CAC_ADDR(n,a) (CAC_BASE | REMOTE_ADDR(n,a)) -#define CHANGE_NASID(n,x) ((void *)(((u64)(x) & ~NASID_MASK) | NASID_SPACE(n))) -#define IS_TIO_NASID(n) ((n) & 1) - - -/* non-II mmr's start at top of big window space (4G) */ -#define BWIN_TOP 0x0000000100000000UL - -/* - * general address defines - */ -#define CAC_BASE (PAGE_OFFSET | AS_CAC_SPACE) -#define AMO_BASE (__IA64_UNCACHED_OFFSET | AS_AMO_SPACE) -#define AMO_PHYS_BASE (RGN_BASE(RGN_HPAGE) | AS_AMO_SPACE) -#define GET_BASE (PAGE_OFFSET | AS_GET_SPACE) - -/* - * Convert Memory addresses between various addressing modes. - */ -#define TO_PHYS(x) (TO_PHYS_MASK & (x)) -#define TO_CAC(x) (CAC_BASE | TO_PHYS(x)) -#ifdef CONFIG_SGI_SN -#define TO_AMO(x) (AMO_BASE | TO_PHYS(x)) -#define TO_GET(x) (GET_BASE | TO_PHYS(x)) -#else -#define TO_AMO(x) ({ BUG(); x; }) -#define TO_GET(x) ({ BUG(); x; }) -#endif - -/* - * Covert from processor physical address to II/TIO physical address: - * II - squeeze out the AS bits - * TIO- requires a chiplet id in bits 38-39. For DMA to memory, - * the chiplet id is zero. If we implement TIO-TIO dma, we might need - * to insert a chiplet id into this macro. However, it is our belief - * right now that this chiplet id will be ICE, which is also zero. - */ -#define SH1_TIO_PHYS_TO_DMA(x) \ - ((((u64)(NASID_GET(x))) << 40) | NODE_OFFSET(x)) - -#define SH2_NETWORK_BANK_OFFSET(x) \ - ((u64)(x) & ((1UL << (sn_hub_info->nasid_shift - 4)) -1)) - -#define SH2_NETWORK_BANK_SELECT(x) \ - ((((u64)(x) & (0x3UL << (sn_hub_info->nasid_shift - 4))) \ - >> (sn_hub_info->nasid_shift - 4)) << 36) - -#define SH2_NETWORK_ADDRESS(x) \ - (SH2_NETWORK_BANK_OFFSET(x) | SH2_NETWORK_BANK_SELECT(x)) - -#define SH2_TIO_PHYS_TO_DMA(x) \ - (((u64)(NASID_GET(x)) << 40) | SH2_NETWORK_ADDRESS(x)) - -#define PHYS_TO_TIODMA(x) \ - (is_shub1() ? SH1_TIO_PHYS_TO_DMA(x) : SH2_TIO_PHYS_TO_DMA(x)) - -#define PHYS_TO_DMA(x) \ - ((((u64)(x) & NASID_MASK) >> 2) | NODE_OFFSET(x)) - - -/* - * Macros to test for address type. - */ -#define IS_AMO_ADDRESS(x) (((u64)(x) & (RGN_BITS | AS_MASK)) == AMO_BASE) -#define IS_AMO_PHYS_ADDRESS(x) (((u64)(x) & (RGN_BITS | AS_MASK)) == AMO_PHYS_BASE) - - -/* - * The following definitions pertain to the IO special address - * space. They define the location of the big and little windows - * of any given node. - */ -#define BWIN_SIZE_BITS 29 /* big window size: 512M */ -#define TIO_BWIN_SIZE_BITS 30 /* big window size: 1G */ -#define NODE_SWIN_BASE(n, w) ((w == 0) ? NODE_BWIN_BASE((n), SWIN0_BIGWIN) \ - : RAW_NODE_SWIN_BASE(n, w)) -#define TIO_SWIN_BASE(n, w) (TIO_IO_BASE(n) + \ - ((u64) (w) << TIO_SWIN_SIZE_BITS)) -#define NODE_IO_BASE(n) (GLOBAL_MMR_SPACE | NASID_SPACE(n)) -#define TIO_IO_BASE(n) (__IA64_UNCACHED_OFFSET | NASID_SPACE(n)) -#define BWIN_SIZE (1UL << BWIN_SIZE_BITS) -#define NODE_BWIN_BASE0(n) (NODE_IO_BASE(n) + BWIN_SIZE) -#define NODE_BWIN_BASE(n, w) (NODE_BWIN_BASE0(n) + ((u64) (w) << BWIN_SIZE_BITS)) -#define RAW_NODE_SWIN_BASE(n, w) (NODE_IO_BASE(n) + ((u64) (w) << SWIN_SIZE_BITS)) -#define BWIN_WIDGET_MASK 0x7 -#define BWIN_WINDOWNUM(x) (((x) >> BWIN_SIZE_BITS) & BWIN_WIDGET_MASK) -#define SH1_IS_BIG_WINDOW_ADDR(x) ((x) & BWIN_TOP) - -#define TIO_BWIN_WINDOW_SELECT_MASK 0x7 -#define TIO_BWIN_WINDOWNUM(x) (((x) >> TIO_BWIN_SIZE_BITS) & TIO_BWIN_WINDOW_SELECT_MASK) - -#define TIO_HWIN_SHIFT_BITS 33 -#define TIO_HWIN(x) (NODE_OFFSET(x) >> TIO_HWIN_SHIFT_BITS) - -/* - * The following definitions pertain to the IO special address - * space. They define the location of the big and little windows - * of any given node. - */ - -#define SWIN_SIZE_BITS 24 -#define SWIN_WIDGET_MASK 0xF - -#define TIO_SWIN_SIZE_BITS 28 -#define TIO_SWIN_SIZE (1UL << TIO_SWIN_SIZE_BITS) -#define TIO_SWIN_WIDGET_MASK 0x3 - -/* - * Convert smallwindow address to xtalk address. - * - * 'addr' can be physical or virtual address, but will be converted - * to Xtalk address in the range 0 -> SWINZ_SIZEMASK - */ -#define SWIN_WIDGETNUM(x) (((x) >> SWIN_SIZE_BITS) & SWIN_WIDGET_MASK) -#define TIO_SWIN_WIDGETNUM(x) (((x) >> TIO_SWIN_SIZE_BITS) & TIO_SWIN_WIDGET_MASK) - - -/* - * The following macros produce the correct base virtual address for - * the hub registers. The REMOTE_HUB_* macro produce - * the address for the specified hub's registers. The intent is - * that the appropriate PI, MD, NI, or II register would be substituted - * for x. - * - * WARNING: - * When certain Hub chip workaround are defined, it's not sufficient - * to dereference the *_HUB_ADDR() macros. You should instead use - * HUB_L() and HUB_S() if you must deal with pointers to hub registers. - * Otherwise, the recommended approach is to use *_HUB_L() and *_HUB_S(). - * They're always safe. - */ -/* Shub1 TIO & MMR addressing macros */ -#define SH1_TIO_IOSPACE_ADDR(n,x) \ - GLOBAL_MMR_ADDR(n,x) - -#define SH1_REMOTE_BWIN_MMR(n,x) \ - GLOBAL_MMR_ADDR(n,x) - -#define SH1_REMOTE_SWIN_MMR(n,x) \ - (NODE_SWIN_BASE(n,1) + 0x800000UL + (x)) - -#define SH1_REMOTE_MMR(n,x) \ - (SH1_IS_BIG_WINDOW_ADDR(x) ? SH1_REMOTE_BWIN_MMR(n,x) : \ - SH1_REMOTE_SWIN_MMR(n,x)) - -/* Shub1 TIO & MMR addressing macros */ -#define SH2_TIO_IOSPACE_ADDR(n,x) \ - ((__IA64_UNCACHED_OFFSET | REMOTE_ADDR(n,x) | 1UL << (NASID_SHIFT - 2))) - -#define SH2_REMOTE_MMR(n,x) \ - GLOBAL_MMR_ADDR(n,x) - - -/* TIO & MMR addressing macros that work on both shub1 & shub2 */ -#define TIO_IOSPACE_ADDR(n,x) \ - ((u64 *)(is_shub1() ? SH1_TIO_IOSPACE_ADDR(n,x) : \ - SH2_TIO_IOSPACE_ADDR(n,x))) - -#define SH_REMOTE_MMR(n,x) \ - (is_shub1() ? SH1_REMOTE_MMR(n,x) : SH2_REMOTE_MMR(n,x)) - -#define REMOTE_HUB_ADDR(n,x) \ - (IS_TIO_NASID(n) ? ((volatile u64*)TIO_IOSPACE_ADDR(n,x)) : \ - ((volatile u64*)SH_REMOTE_MMR(n,x))) - - -#define HUB_L(x) (*((volatile typeof(*x) *)x)) -#define HUB_S(x,d) (*((volatile typeof(*x) *)x) = (d)) - -#define REMOTE_HUB_L(n, a) HUB_L(REMOTE_HUB_ADDR((n), (a))) -#define REMOTE_HUB_S(n, a, d) HUB_S(REMOTE_HUB_ADDR((n), (a)), (d)) - -/* - * Coretalk address breakdown - */ -#define CTALK_NASID_SHFT 40 -#define CTALK_NASID_MASK (0x3FFFULL << CTALK_NASID_SHFT) -#define CTALK_CID_SHFT 38 -#define CTALK_CID_MASK (0x3ULL << CTALK_CID_SHFT) -#define CTALK_NODE_OFFSET 0x3FFFFFFFFF - -#endif /* _ASM_IA64_SN_ADDRS_H */ diff --git a/arch/ia64/include/asm/sn/arch.h b/arch/ia64/include/asm/sn/arch.h deleted file mode 100644 index 31eb784866f899331d9a0afecffe76a2d775eda3..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/arch.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * SGI specific setup. - * - * Copyright (C) 1995-1997,1999,2001-2005 Silicon Graphics, Inc. All rights reserved. - * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org) - */ -#ifndef _ASM_IA64_SN_ARCH_H -#define _ASM_IA64_SN_ARCH_H - -#include -#include -#include -#include -#include - -/* - * This is the maximum number of NUMALINK nodes that can be part of a single - * SSI kernel. This number includes C-brick, M-bricks, and TIOs. Nodes in - * remote partitions are NOT included in this number. - * The number of compact nodes cannot exceed size of a coherency domain. - * The purpose of this define is to specify a node count that includes - * all C/M/TIO nodes in an SSI system. - * - * SGI system can currently support up to 256 C/M nodes plus additional TIO nodes. - * - * Note: ACPI20 has an architectural limit of 256 nodes. When we upgrade - * to ACPI3.0, this limit will be removed. The notion of "compact nodes" - * should be deleted and TIOs should be included in MAX_NUMNODES. - */ -#define MAX_TIO_NODES MAX_NUMNODES -#define MAX_COMPACT_NODES (MAX_NUMNODES + MAX_TIO_NODES) - -/* - * Maximum number of nodes in all partitions and in all coherency domains. - * This is the total number of nodes accessible in the numalink fabric. It - * includes all C & M bricks, plus all TIOs. - * - * This value is also the value of the maximum number of NASIDs in the numalink - * fabric. - */ -#define MAX_NUMALINK_NODES 16384 - -/* - * The following defines attributes of the HUB chip. These attributes are - * frequently referenced. They are kept in the per-cpu data areas of each cpu. - * They are kept together in a struct to minimize cache misses. - */ -struct sn_hub_info_s { - u8 shub2; - u8 nasid_shift; - u8 as_shift; - u8 shub_1_1_found; - u16 nasid_bitmask; -}; -DECLARE_PER_CPU(struct sn_hub_info_s, __sn_hub_info); -#define sn_hub_info this_cpu_ptr(&__sn_hub_info) -#define is_shub2() (sn_hub_info->shub2) -#define is_shub1() (sn_hub_info->shub2 == 0) - -/* - * Use this macro to test if shub 1.1 wars should be enabled - */ -#define enable_shub_wars_1_1() (sn_hub_info->shub_1_1_found) - - -/* - * Compact node ID to nasid mappings kept in the per-cpu data areas of each - * cpu. - */ -DECLARE_PER_CPU(short, __sn_cnodeid_to_nasid[MAX_COMPACT_NODES]); -#define sn_cnodeid_to_nasid this_cpu_ptr(&__sn_cnodeid_to_nasid[0]) - - -extern u8 sn_partition_id; -extern u8 sn_system_size; -extern u8 sn_sharing_domain_size; -extern u8 sn_region_size; - -extern void sn_flush_all_caches(long addr, long bytes); -extern bool sn_cpu_disable_allowed(int cpu); - -#endif /* _ASM_IA64_SN_ARCH_H */ diff --git a/arch/ia64/include/asm/sn/bte.h b/arch/ia64/include/asm/sn/bte.h deleted file mode 100644 index cd71ab5faf627f4f744150e05cb053f85b2bb10a..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/bte.h +++ /dev/null @@ -1,236 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2000-2007 Silicon Graphics, Inc. All Rights Reserved. - */ - - -#ifndef _ASM_IA64_SN_BTE_H -#define _ASM_IA64_SN_BTE_H - -#include -#include -#include -#include -#include -#include - -struct nodepda_s; - -#define IBCT_NOTIFY (0x1UL << 4) -#define IBCT_ZFIL_MODE (0x1UL << 0) - -/* #define BTE_DEBUG */ -/* #define BTE_DEBUG_VERBOSE */ - -#ifdef BTE_DEBUG -# define BTE_PRINTK(x) printk x /* Terse */ -# ifdef BTE_DEBUG_VERBOSE -# define BTE_PRINTKV(x) printk x /* Verbose */ -# else -# define BTE_PRINTKV(x) -# endif /* BTE_DEBUG_VERBOSE */ -#else -# define BTE_PRINTK(x) -# define BTE_PRINTKV(x) -#endif /* BTE_DEBUG */ - - -/* BTE status register only supports 16 bits for length field */ -#define BTE_LEN_BITS (16) -#define BTE_LEN_MASK ((1 << BTE_LEN_BITS) - 1) -#define BTE_MAX_XFER (BTE_LEN_MASK << L1_CACHE_SHIFT) - - -/* Define hardware */ -#define BTES_PER_NODE (is_shub2() ? 4 : 2) -#define MAX_BTES_PER_NODE 4 - -#define BTE2OFF_CTRL 0 -#define BTE2OFF_SRC (SH2_BT_ENG_SRC_ADDR_0 - SH2_BT_ENG_CSR_0) -#define BTE2OFF_DEST (SH2_BT_ENG_DEST_ADDR_0 - SH2_BT_ENG_CSR_0) -#define BTE2OFF_NOTIFY (SH2_BT_ENG_NOTIF_ADDR_0 - SH2_BT_ENG_CSR_0) - -#define BTE_BASE_ADDR(interface) \ - (is_shub2() ? (interface == 0) ? SH2_BT_ENG_CSR_0 : \ - (interface == 1) ? SH2_BT_ENG_CSR_1 : \ - (interface == 2) ? SH2_BT_ENG_CSR_2 : \ - SH2_BT_ENG_CSR_3 \ - : (interface == 0) ? IIO_IBLS0 : IIO_IBLS1) - -#define BTE_SOURCE_ADDR(base) \ - (is_shub2() ? base + (BTE2OFF_SRC/8) \ - : base + (BTEOFF_SRC/8)) - -#define BTE_DEST_ADDR(base) \ - (is_shub2() ? base + (BTE2OFF_DEST/8) \ - : base + (BTEOFF_DEST/8)) - -#define BTE_CTRL_ADDR(base) \ - (is_shub2() ? base + (BTE2OFF_CTRL/8) \ - : base + (BTEOFF_CTRL/8)) - -#define BTE_NOTIF_ADDR(base) \ - (is_shub2() ? base + (BTE2OFF_NOTIFY/8) \ - : base + (BTEOFF_NOTIFY/8)) - -/* Define hardware modes */ -#define BTE_NOTIFY IBCT_NOTIFY -#define BTE_NORMAL BTE_NOTIFY -#define BTE_ZERO_FILL (BTE_NOTIFY | IBCT_ZFIL_MODE) -/* Use a reserved bit to let the caller specify a wait for any BTE */ -#define BTE_WACQUIRE 0x4000 -/* Use the BTE on the node with the destination memory */ -#define BTE_USE_DEST (BTE_WACQUIRE << 1) -/* Use any available BTE interface on any node for the transfer */ -#define BTE_USE_ANY (BTE_USE_DEST << 1) -/* macro to force the IBCT0 value valid */ -#define BTE_VALID_MODE(x) ((x) & (IBCT_NOTIFY | IBCT_ZFIL_MODE)) - -#define BTE_ACTIVE (IBLS_BUSY | IBLS_ERROR) -#define BTE_WORD_AVAILABLE (IBLS_BUSY << 1) -#define BTE_WORD_BUSY (~BTE_WORD_AVAILABLE) - -/* - * Some macros to simplify reading. - * Start with macros to locate the BTE control registers. - */ -#define BTE_LNSTAT_LOAD(_bte) \ - HUB_L(_bte->bte_base_addr) -#define BTE_LNSTAT_STORE(_bte, _x) \ - HUB_S(_bte->bte_base_addr, (_x)) -#define BTE_SRC_STORE(_bte, _x) \ -({ \ - u64 __addr = ((_x) & ~AS_MASK); \ - if (is_shub2()) \ - __addr = SH2_TIO_PHYS_TO_DMA(__addr); \ - HUB_S(_bte->bte_source_addr, __addr); \ -}) -#define BTE_DEST_STORE(_bte, _x) \ -({ \ - u64 __addr = ((_x) & ~AS_MASK); \ - if (is_shub2()) \ - __addr = SH2_TIO_PHYS_TO_DMA(__addr); \ - HUB_S(_bte->bte_destination_addr, __addr); \ -}) -#define BTE_CTRL_STORE(_bte, _x) \ - HUB_S(_bte->bte_control_addr, (_x)) -#define BTE_NOTIF_STORE(_bte, _x) \ -({ \ - u64 __addr = ia64_tpa((_x) & ~AS_MASK); \ - if (is_shub2()) \ - __addr = SH2_TIO_PHYS_TO_DMA(__addr); \ - HUB_S(_bte->bte_notify_addr, __addr); \ -}) - -#define BTE_START_TRANSFER(_bte, _len, _mode) \ - is_shub2() ? BTE_CTRL_STORE(_bte, IBLS_BUSY | (_mode << 24) | _len) \ - : BTE_LNSTAT_STORE(_bte, _len); \ - BTE_CTRL_STORE(_bte, _mode) - -/* Possible results from bte_copy and bte_unaligned_copy */ -/* The following error codes map into the BTE hardware codes - * IIO_ICRB_ECODE_* (in shubio.h). The hardware uses - * an error code of 0 (IIO_ICRB_ECODE_DERR), but we want zero - * to mean BTE_SUCCESS, so add one (BTEFAIL_OFFSET) to the error - * codes to give the following error codes. - */ -#define BTEFAIL_OFFSET 1 - -typedef enum { - BTE_SUCCESS, /* 0 is success */ - BTEFAIL_DIR, /* Directory error due to IIO access*/ - BTEFAIL_POISON, /* poison error on IO access (write to poison page) */ - BTEFAIL_WERR, /* Write error (ie WINV to a Read only line) */ - BTEFAIL_ACCESS, /* access error (protection violation) */ - BTEFAIL_PWERR, /* Partial Write Error */ - BTEFAIL_PRERR, /* Partial Read Error */ - BTEFAIL_TOUT, /* CRB Time out */ - BTEFAIL_XTERR, /* Incoming xtalk pkt had error bit */ - BTEFAIL_NOTAVAIL, /* BTE not available */ -} bte_result_t; - -#define BTEFAIL_SH2_RESP_SHORT 0x1 /* bit 000001 */ -#define BTEFAIL_SH2_RESP_LONG 0x2 /* bit 000010 */ -#define BTEFAIL_SH2_RESP_DSP 0x4 /* bit 000100 */ -#define BTEFAIL_SH2_RESP_ACCESS 0x8 /* bit 001000 */ -#define BTEFAIL_SH2_CRB_TO 0x10 /* bit 010000 */ -#define BTEFAIL_SH2_NACK_LIMIT 0x20 /* bit 100000 */ -#define BTEFAIL_SH2_ALL 0x3F /* bit 111111 */ - -#define BTE_ERR_BITS 0x3FUL -#define BTE_ERR_SHIFT 36 -#define BTE_ERR_MASK (BTE_ERR_BITS << BTE_ERR_SHIFT) - -#define BTE_ERROR_RETRY(value) \ - (is_shub2() ? (value != BTEFAIL_SH2_CRB_TO) \ - : (value != BTEFAIL_TOUT)) - -/* - * On shub1 BTE_ERR_MASK will always be false, so no need for is_shub2() - */ -#define BTE_SHUB2_ERROR(_status) \ - ((_status & BTE_ERR_MASK) \ - ? (((_status >> BTE_ERR_SHIFT) & BTE_ERR_BITS) | IBLS_ERROR) \ - : _status) - -#define BTE_GET_ERROR_STATUS(_status) \ - (BTE_SHUB2_ERROR(_status) & ~IBLS_ERROR) - -#define BTE_VALID_SH2_ERROR(value) \ - ((value >= BTEFAIL_SH2_RESP_SHORT) && (value <= BTEFAIL_SH2_ALL)) - -/* - * Structure defining a bte. An instance of this - * structure is created in the nodepda for each - * bte on that node (as defined by BTES_PER_NODE) - * This structure contains everything necessary - * to work with a BTE. - */ -struct bteinfo_s { - volatile u64 notify ____cacheline_aligned; - u64 *bte_base_addr ____cacheline_aligned; - u64 *bte_source_addr; - u64 *bte_destination_addr; - u64 *bte_control_addr; - u64 *bte_notify_addr; - spinlock_t spinlock; - cnodeid_t bte_cnode; /* cnode */ - int bte_error_count; /* Number of errors encountered */ - int bte_num; /* 0 --> BTE0, 1 --> BTE1 */ - int cleanup_active; /* Interface is locked for cleanup */ - volatile bte_result_t bh_error; /* error while processing */ - volatile u64 *most_rcnt_na; - struct bteinfo_s *btes_to_try[MAX_BTES_PER_NODE]; -}; - - -/* - * Function prototypes (functions defined in bte.c, used elsewhere) - */ -extern bte_result_t bte_copy(u64, u64, u64, u64, void *); -extern bte_result_t bte_unaligned_copy(u64, u64, u64, u64); -extern void bte_error_handler(struct nodepda_s *); - -#define bte_zero(dest, len, mode, notification) \ - bte_copy(0, dest, len, ((mode) | BTE_ZERO_FILL), notification) - -/* - * The following is the preferred way of calling bte_unaligned_copy - * If the copy is fully cache line aligned, then bte_copy is - * used instead. Since bte_copy is inlined, this saves a call - * stack. NOTE: bte_copy is called synchronously and does block - * until the transfer is complete. In order to get the asynch - * version of bte_copy, you must perform this check yourself. - */ -#define BTE_UNALIGNED_COPY(src, dest, len, mode) \ - (((len & (L1_CACHE_BYTES - 1)) || \ - (src & (L1_CACHE_BYTES - 1)) || \ - (dest & (L1_CACHE_BYTES - 1))) ? \ - bte_unaligned_copy(src, dest, len, mode) : \ - bte_copy(src, dest, len, mode, NULL)) - - -#endif /* _ASM_IA64_SN_BTE_H */ diff --git a/arch/ia64/include/asm/sn/clksupport.h b/arch/ia64/include/asm/sn/clksupport.h deleted file mode 100644 index d340c365a824cbec5e3c056b11024c4bea3cda32..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/clksupport.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * This file contains definitions for accessing a platform supported high resolution - * clock. The clock is monitonically increasing and can be accessed from any node - * in the system. The clock is synchronized across nodes - all nodes see the - * same value. - * - * RTC_COUNTER_ADDR - contains the address of the counter - * - */ - -#ifndef _ASM_IA64_SN_CLKSUPPORT_H -#define _ASM_IA64_SN_CLKSUPPORT_H - -extern unsigned long sn_rtc_cycles_per_second; - -#define RTC_COUNTER_ADDR ((long *)LOCAL_MMR_ADDR(SH_RTC)) - -#define rtc_time() (*RTC_COUNTER_ADDR) - -#endif /* _ASM_IA64_SN_CLKSUPPORT_H */ diff --git a/arch/ia64/include/asm/sn/geo.h b/arch/ia64/include/asm/sn/geo.h deleted file mode 100644 index f083c94340663319cda9ccccdcfbcc8a8409875d..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/geo.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_GEO_H -#define _ASM_IA64_SN_GEO_H - -/* The geoid_t implementation below is based loosely on the pcfg_t - implementation in sys/SN/promcfg.h. */ - -/* Type declaractions */ - -/* Size of a geoid_t structure (must be before decl. of geoid_u) */ -#define GEOID_SIZE 8 /* Would 16 be better? The size can - be different on different platforms. */ - -#define MAX_SLOTS 0xf /* slots per module */ -#define MAX_SLABS 0xf /* slabs per slot */ - -typedef unsigned char geo_type_t; - -/* Fields common to all substructures */ -typedef struct geo_common_s { - moduleid_t module; /* The module (box) this h/w lives in */ - geo_type_t type; /* What type of h/w is named by this geoid_t */ - slabid_t slab:4; /* slab (ASIC), 0 .. 15 within slot */ - slotid_t slot:4; /* slot (Blade), 0 .. 15 within module */ -} geo_common_t; - -/* Additional fields for particular types of hardware */ -typedef struct geo_node_s { - geo_common_t common; /* No additional fields needed */ -} geo_node_t; - -typedef struct geo_rtr_s { - geo_common_t common; /* No additional fields needed */ -} geo_rtr_t; - -typedef struct geo_iocntl_s { - geo_common_t common; /* No additional fields needed */ -} geo_iocntl_t; - -typedef struct geo_pcicard_s { - geo_iocntl_t common; - char bus; /* Bus/widget number */ - char slot; /* PCI slot number */ -} geo_pcicard_t; - -/* Subcomponents of a node */ -typedef struct geo_cpu_s { - geo_node_t node; - char slice; /* Which CPU on the node */ -} geo_cpu_t; - -typedef struct geo_mem_s { - geo_node_t node; - char membus; /* The memory bus on the node */ - char memslot; /* The memory slot on the bus */ -} geo_mem_t; - - -typedef union geoid_u { - geo_common_t common; - geo_node_t node; - geo_iocntl_t iocntl; - geo_pcicard_t pcicard; - geo_rtr_t rtr; - geo_cpu_t cpu; - geo_mem_t mem; - char padsize[GEOID_SIZE]; -} geoid_t; - - -/* Preprocessor macros */ - -#define GEO_MAX_LEN 48 /* max. formatted length, plus some pad: - module/001c07/slab/5/node/memory/2/slot/4 */ - -/* Values for geo_type_t */ -#define GEO_TYPE_INVALID 0 -#define GEO_TYPE_MODULE 1 -#define GEO_TYPE_NODE 2 -#define GEO_TYPE_RTR 3 -#define GEO_TYPE_IOCNTL 4 -#define GEO_TYPE_IOCARD 5 -#define GEO_TYPE_CPU 6 -#define GEO_TYPE_MEM 7 -#define GEO_TYPE_MAX (GEO_TYPE_MEM+1) - -/* Parameter for hwcfg_format_geoid_compt() */ -#define GEO_COMPT_MODULE 1 -#define GEO_COMPT_SLAB 2 -#define GEO_COMPT_IOBUS 3 -#define GEO_COMPT_IOSLOT 4 -#define GEO_COMPT_CPU 5 -#define GEO_COMPT_MEMBUS 6 -#define GEO_COMPT_MEMSLOT 7 - -#define GEO_INVALID_STR "" - -#define INVALID_NASID ((nasid_t)-1) -#define INVALID_CNODEID ((cnodeid_t)-1) -#define INVALID_PNODEID ((pnodeid_t)-1) -#define INVALID_SLAB (slabid_t)-1 -#define INVALID_SLOT (slotid_t)-1 -#define INVALID_MODULE ((moduleid_t)-1) - -static inline slabid_t geo_slab(geoid_t g) -{ - return (g.common.type == GEO_TYPE_INVALID) ? - INVALID_SLAB : g.common.slab; -} - -static inline slotid_t geo_slot(geoid_t g) -{ - return (g.common.type == GEO_TYPE_INVALID) ? - INVALID_SLOT : g.common.slot; -} - -static inline moduleid_t geo_module(geoid_t g) -{ - return (g.common.type == GEO_TYPE_INVALID) ? - INVALID_MODULE : g.common.module; -} - -extern geoid_t cnodeid_get_geoid(cnodeid_t cnode); - -#endif /* _ASM_IA64_SN_GEO_H */ diff --git a/arch/ia64/include/asm/sn/intr.h b/arch/ia64/include/asm/sn/intr.h index e0487aa974183516593df3b3d54c316de63eaf28..3885a77b21dfda6d8783f3aaf7d8cfafba81f454 100644 --- a/arch/ia64/include/asm/sn/intr.h +++ b/arch/ia64/include/asm/sn/intr.h @@ -9,60 +9,7 @@ #ifndef _ASM_IA64_SN_INTR_H #define _ASM_IA64_SN_INTR_H -#include -#include - -#define SGI_UART_VECTOR 0xe9 - -/* Reserved IRQs : Note, not to exceed IA64_SN2_FIRST_DEVICE_VECTOR */ #define SGI_XPC_ACTIVATE 0x30 -#define SGI_II_ERROR 0x31 -#define SGI_XBOW_ERROR 0x32 -#define SGI_PCIASIC_ERROR 0x33 -#define SGI_ACPI_SCI_INT 0x34 -#define SGI_TIOCA_ERROR 0x35 -#define SGI_TIO_ERROR 0x36 -#define SGI_TIOCX_ERROR 0x37 -#define SGI_MMTIMER_VECTOR 0x38 #define SGI_XPC_NOTIFY 0xe7 -#define IA64_SN2_FIRST_DEVICE_VECTOR 0x3c -#define IA64_SN2_LAST_DEVICE_VECTOR 0xe6 - -#define SN2_IRQ_RESERVED 0x1 -#define SN2_IRQ_CONNECTED 0x2 -#define SN2_IRQ_SHARED 0x4 - -// The SN PROM irq struct -struct sn_irq_info { - struct sn_irq_info *irq_next; /* deprecated DO NOT USE */ - short irq_nasid; /* Nasid IRQ is assigned to */ - int irq_slice; /* slice IRQ is assigned to */ - int irq_cpuid; /* kernel logical cpuid */ - int irq_irq; /* the IRQ number */ - int irq_int_bit; /* Bridge interrupt pin */ - /* <0 means MSI */ - u64 irq_xtalkaddr; /* xtalkaddr IRQ is sent to */ - int irq_bridge_type;/* pciio asic type (pciio.h) */ - void *irq_bridge; /* bridge generating irq */ - void *irq_pciioinfo; /* associated pciio_info_t */ - int irq_last_intr; /* For Shub lb lost intr WAR */ - int irq_cookie; /* unique cookie */ - int irq_flags; /* flags */ - int irq_share_cnt; /* num devices sharing IRQ */ - struct list_head list; /* list of sn_irq_info structs */ - struct rcu_head rcu; /* rcu callback list */ -}; - -extern void sn_send_IPI_phys(int, long, int, int); -extern u64 sn_intr_alloc(nasid_t, int, - struct sn_irq_info *, - int, nasid_t, int); -extern void sn_intr_free(nasid_t, int, struct sn_irq_info *); -extern struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *, nasid_t, int); -extern void sn_set_err_irq_affinity(unsigned int); -extern struct list_head **sn_irq_lh; - -#define CPU_VECTOR_TO_IRQ(cpuid,vector) (vector) - #endif /* _ASM_IA64_SN_INTR_H */ diff --git a/arch/ia64/include/asm/sn/io.h b/arch/ia64/include/asm/sn/io.h deleted file mode 100644 index 41c73a73562844f0a4d8e601d6e737cece6b35e0..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/io.h +++ /dev/null @@ -1,274 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_SN_IO_H -#define _ASM_SN_IO_H -#include -#include - -extern void * sn_io_addr(unsigned long port) __attribute_const__; /* Forward definition */ -extern void __sn_mmiowb(void); /* Forward definition */ - -extern int num_cnodes; - -#define __sn_mf_a() ia64_mfa() - -extern void sn_dma_flush(unsigned long); - -#define __sn_inb ___sn_inb -#define __sn_inw ___sn_inw -#define __sn_inl ___sn_inl -#define __sn_outb ___sn_outb -#define __sn_outw ___sn_outw -#define __sn_outl ___sn_outl -#define __sn_readb ___sn_readb -#define __sn_readw ___sn_readw -#define __sn_readl ___sn_readl -#define __sn_readq ___sn_readq -#define __sn_readb_relaxed ___sn_readb_relaxed -#define __sn_readw_relaxed ___sn_readw_relaxed -#define __sn_readl_relaxed ___sn_readl_relaxed -#define __sn_readq_relaxed ___sn_readq_relaxed - -/* - * Convenience macros for setting/clearing bits using the above accessors - */ - -#define __sn_setq_relaxed(addr, val) \ - writeq((__sn_readq_relaxed(addr) | (val)), (addr)) -#define __sn_clrq_relaxed(addr, val) \ - writeq((__sn_readq_relaxed(addr) & ~(val)), (addr)) - -/* - * The following routines are SN Platform specific, called when - * a reference is made to inX/outX set macros. SN Platform - * inX set of macros ensures that Posted DMA writes on the - * Bridge is flushed. - * - * The routines should be self explainatory. - */ - -static inline unsigned int -___sn_inb (unsigned long port) -{ - volatile unsigned char *addr; - unsigned char ret = -1; - - if ((addr = sn_io_addr(port))) { - ret = *addr; - __sn_mf_a(); - sn_dma_flush((unsigned long)addr); - } - return ret; -} - -static inline unsigned int -___sn_inw (unsigned long port) -{ - volatile unsigned short *addr; - unsigned short ret = -1; - - if ((addr = sn_io_addr(port))) { - ret = *addr; - __sn_mf_a(); - sn_dma_flush((unsigned long)addr); - } - return ret; -} - -static inline unsigned int -___sn_inl (unsigned long port) -{ - volatile unsigned int *addr; - unsigned int ret = -1; - - if ((addr = sn_io_addr(port))) { - ret = *addr; - __sn_mf_a(); - sn_dma_flush((unsigned long)addr); - } - return ret; -} - -static inline void -___sn_outb (unsigned char val, unsigned long port) -{ - volatile unsigned char *addr; - - if ((addr = sn_io_addr(port))) { - *addr = val; - __sn_mmiowb(); - } -} - -static inline void -___sn_outw (unsigned short val, unsigned long port) -{ - volatile unsigned short *addr; - - if ((addr = sn_io_addr(port))) { - *addr = val; - __sn_mmiowb(); - } -} - -static inline void -___sn_outl (unsigned int val, unsigned long port) -{ - volatile unsigned int *addr; - - if ((addr = sn_io_addr(port))) { - *addr = val; - __sn_mmiowb(); - } -} - -/* - * The following routines are SN Platform specific, called when - * a reference is made to readX/writeX set macros. SN Platform - * readX set of macros ensures that Posted DMA writes on the - * Bridge is flushed. - * - * The routines should be self explainatory. - */ - -static inline unsigned char -___sn_readb (const volatile void __iomem *addr) -{ - unsigned char val; - - val = *(volatile unsigned char __force *)addr; - __sn_mf_a(); - sn_dma_flush((unsigned long)addr); - return val; -} - -static inline unsigned short -___sn_readw (const volatile void __iomem *addr) -{ - unsigned short val; - - val = *(volatile unsigned short __force *)addr; - __sn_mf_a(); - sn_dma_flush((unsigned long)addr); - return val; -} - -static inline unsigned int -___sn_readl (const volatile void __iomem *addr) -{ - unsigned int val; - - val = *(volatile unsigned int __force *)addr; - __sn_mf_a(); - sn_dma_flush((unsigned long)addr); - return val; -} - -static inline unsigned long -___sn_readq (const volatile void __iomem *addr) -{ - unsigned long val; - - val = *(volatile unsigned long __force *)addr; - __sn_mf_a(); - sn_dma_flush((unsigned long)addr); - return val; -} - -/* - * For generic and SN2 kernels, we have a set of fast access - * PIO macros. These macros are provided on SN Platform - * because the normal inX and readX macros perform an - * additional task of flushing Post DMA request on the Bridge. - * - * These routines should be self explainatory. - */ - -static inline unsigned int -sn_inb_fast (unsigned long port) -{ - volatile unsigned char *addr = (unsigned char *)port; - unsigned char ret; - - ret = *addr; - __sn_mf_a(); - return ret; -} - -static inline unsigned int -sn_inw_fast (unsigned long port) -{ - volatile unsigned short *addr = (unsigned short *)port; - unsigned short ret; - - ret = *addr; - __sn_mf_a(); - return ret; -} - -static inline unsigned int -sn_inl_fast (unsigned long port) -{ - volatile unsigned int *addr = (unsigned int *)port; - unsigned int ret; - - ret = *addr; - __sn_mf_a(); - return ret; -} - -static inline unsigned char -___sn_readb_relaxed (const volatile void __iomem *addr) -{ - return *(volatile unsigned char __force *)addr; -} - -static inline unsigned short -___sn_readw_relaxed (const volatile void __iomem *addr) -{ - return *(volatile unsigned short __force *)addr; -} - -static inline unsigned int -___sn_readl_relaxed (const volatile void __iomem *addr) -{ - return *(volatile unsigned int __force *) addr; -} - -static inline unsigned long -___sn_readq_relaxed (const volatile void __iomem *addr) -{ - return *(volatile unsigned long __force *) addr; -} - -struct pci_dev; - -static inline int -sn_pci_set_vchan(struct pci_dev *pci_dev, unsigned long *addr, int vchan) -{ - - if (vchan > 1) { - return -1; - } - - if (!(*addr >> 32)) /* Using a mask here would be cleaner */ - return 0; /* but this generates better code */ - - if (vchan == 1) { - /* Set Bit 57 */ - *addr |= (1UL << 57); - } else { - /* Clear Bit 57 */ - *addr &= ~(1UL << 57); - } - - return 0; -} - -#endif /* _ASM_SN_IO_H */ diff --git a/arch/ia64/include/asm/sn/ioc3.h b/arch/ia64/include/asm/sn/ioc3.h deleted file mode 100644 index d4a524951df36276c9141e97b162d9ad2863ec32..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/ioc3.h +++ /dev/null @@ -1,242 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2005 Silicon Graphics, Inc. - */ -#ifndef IA64_SN_IOC3_H -#define IA64_SN_IOC3_H - -/* serial port register map */ -struct ioc3_serialregs { - uint32_t sscr; - uint32_t stpir; - uint32_t stcir; - uint32_t srpir; - uint32_t srcir; - uint32_t srtr; - uint32_t shadow; -}; - -/* SUPERIO uart register map */ -struct ioc3_uartregs { - char iu_lcr; - union { - char iir; /* read only */ - char fcr; /* write only */ - } u3; - union { - char ier; /* DLAB == 0 */ - char dlm; /* DLAB == 1 */ - } u2; - union { - char rbr; /* read only, DLAB == 0 */ - char thr; /* write only, DLAB == 0 */ - char dll; /* DLAB == 1 */ - } u1; - char iu_scr; - char iu_msr; - char iu_lsr; - char iu_mcr; -}; - -#define iu_rbr u1.rbr -#define iu_thr u1.thr -#define iu_dll u1.dll -#define iu_ier u2.ier -#define iu_dlm u2.dlm -#define iu_iir u3.iir -#define iu_fcr u3.fcr - -struct ioc3_sioregs { - char fill[0x170]; - struct ioc3_uartregs uartb; - struct ioc3_uartregs uarta; -}; - -/* PCI IO/mem space register map */ -struct ioc3 { - uint32_t pci_id; - uint32_t pci_scr; - uint32_t pci_rev; - uint32_t pci_lat; - uint32_t pci_addr; - uint32_t pci_err_addr_l; - uint32_t pci_err_addr_h; - - uint32_t sio_ir; - /* these registers are read-only for general kernel code. To - * modify them use the functions in ioc3.c - */ - uint32_t sio_ies; - uint32_t sio_iec; - uint32_t sio_cr; - uint32_t int_out; - uint32_t mcr; - uint32_t gpcr_s; - uint32_t gpcr_c; - uint32_t gpdr; - uint32_t gppr[9]; - char fill[0x4c]; - - /* serial port registers */ - uint32_t sbbr_h; - uint32_t sbbr_l; - - struct ioc3_serialregs port_a; - struct ioc3_serialregs port_b; - char fill1[0x1ff10]; - /* superio registers */ - struct ioc3_sioregs sregs; -}; - -/* These don't exist on the ioc3 serial card... */ -#define eier fill1[8] -#define eisr fill1[4] - -#define PCI_LAT 0xc /* Latency Timer */ -#define PCI_SCR_DROP_MODE_EN 0x00008000 /* drop pios on parity err */ -#define UARTA_BASE 0x178 -#define UARTB_BASE 0x170 - - -/* bitmasks for serial RX status byte */ -#define RXSB_OVERRUN 0x01 /* char(s) lost */ -#define RXSB_PAR_ERR 0x02 /* parity error */ -#define RXSB_FRAME_ERR 0x04 /* framing error */ -#define RXSB_BREAK 0x08 /* break character */ -#define RXSB_CTS 0x10 /* state of CTS */ -#define RXSB_DCD 0x20 /* state of DCD */ -#define RXSB_MODEM_VALID 0x40 /* DCD, CTS and OVERRUN are valid */ -#define RXSB_DATA_VALID 0x80 /* FRAME_ERR PAR_ERR & BREAK valid */ - -/* bitmasks for serial TX control byte */ -#define TXCB_INT_WHEN_DONE 0x20 /* interrupt after this byte is sent */ -#define TXCB_INVALID 0x00 /* byte is invalid */ -#define TXCB_VALID 0x40 /* byte is valid */ -#define TXCB_MCR 0x80 /* data<7:0> to modem cntrl register */ -#define TXCB_DELAY 0xc0 /* delay data<7:0> mSec */ - -/* bitmasks for SBBR_L */ -#define SBBR_L_SIZE 0x00000001 /* 0 1KB rings, 1 4KB rings */ - -/* bitmasks for SSCR_ */ -#define SSCR_RX_THRESHOLD 0x000001ff /* hiwater mark */ -#define SSCR_TX_TIMER_BUSY 0x00010000 /* TX timer in progress */ -#define SSCR_HFC_EN 0x00020000 /* h/w flow cntrl enabled */ -#define SSCR_RX_RING_DCD 0x00040000 /* postRX record on delta-DCD */ -#define SSCR_RX_RING_CTS 0x00080000 /* postRX record on delta-CTS */ -#define SSCR_HIGH_SPD 0x00100000 /* 4X speed */ -#define SSCR_DIAG 0x00200000 /* bypass clock divider */ -#define SSCR_RX_DRAIN 0x08000000 /* drain RX buffer to memory */ -#define SSCR_DMA_EN 0x10000000 /* enable ring buffer DMA */ -#define SSCR_DMA_PAUSE 0x20000000 /* pause DMA */ -#define SSCR_PAUSE_STATE 0x40000000 /* set when PAUSE takes effect*/ -#define SSCR_RESET 0x80000000 /* reset DMA channels */ - -/* all producer/consumer pointers are the same bitfield */ -#define PROD_CONS_PTR_4K 0x00000ff8 /* for 4K buffers */ -#define PROD_CONS_PTR_1K 0x000003f8 /* for 1K buffers */ -#define PROD_CONS_PTR_OFF 3 - -/* bitmasks for SRCIR_ */ -#define SRCIR_ARM 0x80000000 /* arm RX timer */ - -/* bitmasks for SHADOW_ */ -#define SHADOW_DR 0x00000001 /* data ready */ -#define SHADOW_OE 0x00000002 /* overrun error */ -#define SHADOW_PE 0x00000004 /* parity error */ -#define SHADOW_FE 0x00000008 /* framing error */ -#define SHADOW_BI 0x00000010 /* break interrupt */ -#define SHADOW_THRE 0x00000020 /* transmit holding reg empty */ -#define SHADOW_TEMT 0x00000040 /* transmit shift reg empty */ -#define SHADOW_RFCE 0x00000080 /* char in RX fifo has error */ -#define SHADOW_DCTS 0x00010000 /* delta clear to send */ -#define SHADOW_DDCD 0x00080000 /* delta data carrier detect */ -#define SHADOW_CTS 0x00100000 /* clear to send */ -#define SHADOW_DCD 0x00800000 /* data carrier detect */ -#define SHADOW_DTR 0x01000000 /* data terminal ready */ -#define SHADOW_RTS 0x02000000 /* request to send */ -#define SHADOW_OUT1 0x04000000 /* 16550 OUT1 bit */ -#define SHADOW_OUT2 0x08000000 /* 16550 OUT2 bit */ -#define SHADOW_LOOP 0x10000000 /* loopback enabled */ - -/* bitmasks for SRTR_ */ -#define SRTR_CNT 0x00000fff /* reload value for RX timer */ -#define SRTR_CNT_VAL 0x0fff0000 /* current value of RX timer */ -#define SRTR_CNT_VAL_SHIFT 16 -#define SRTR_HZ 16000 /* SRTR clock frequency */ - -/* bitmasks for SIO_IR, SIO_IEC and SIO_IES */ -#define SIO_IR_SA_TX_MT 0x00000001 /* Serial port A TX empty */ -#define SIO_IR_SA_RX_FULL 0x00000002 /* port A RX buf full */ -#define SIO_IR_SA_RX_HIGH 0x00000004 /* port A RX hiwat */ -#define SIO_IR_SA_RX_TIMER 0x00000008 /* port A RX timeout */ -#define SIO_IR_SA_DELTA_DCD 0x00000010 /* port A delta DCD */ -#define SIO_IR_SA_DELTA_CTS 0x00000020 /* port A delta CTS */ -#define SIO_IR_SA_INT 0x00000040 /* port A pass-thru intr */ -#define SIO_IR_SA_TX_EXPLICIT 0x00000080 /* port A explicit TX thru */ -#define SIO_IR_SA_MEMERR 0x00000100 /* port A PCI error */ -#define SIO_IR_SB_TX_MT 0x00000200 -#define SIO_IR_SB_RX_FULL 0x00000400 -#define SIO_IR_SB_RX_HIGH 0x00000800 -#define SIO_IR_SB_RX_TIMER 0x00001000 -#define SIO_IR_SB_DELTA_DCD 0x00002000 -#define SIO_IR_SB_DELTA_CTS 0x00004000 -#define SIO_IR_SB_INT 0x00008000 -#define SIO_IR_SB_TX_EXPLICIT 0x00010000 -#define SIO_IR_SB_MEMERR 0x00020000 -#define SIO_IR_PP_INT 0x00040000 /* P port pass-thru intr */ -#define SIO_IR_PP_INTA 0x00080000 /* PP context A thru */ -#define SIO_IR_PP_INTB 0x00100000 /* PP context B thru */ -#define SIO_IR_PP_MEMERR 0x00200000 /* PP PCI error */ -#define SIO_IR_KBD_INT 0x00400000 /* kbd/mouse intr */ -#define SIO_IR_RT_INT 0x08000000 /* RT output pulse */ -#define SIO_IR_GEN_INT1 0x10000000 /* RT input pulse */ -#define SIO_IR_GEN_INT_SHIFT 28 - -/* per device interrupt masks */ -#define SIO_IR_SA (SIO_IR_SA_TX_MT | \ - SIO_IR_SA_RX_FULL | \ - SIO_IR_SA_RX_HIGH | \ - SIO_IR_SA_RX_TIMER | \ - SIO_IR_SA_DELTA_DCD | \ - SIO_IR_SA_DELTA_CTS | \ - SIO_IR_SA_INT | \ - SIO_IR_SA_TX_EXPLICIT | \ - SIO_IR_SA_MEMERR) - -#define SIO_IR_SB (SIO_IR_SB_TX_MT | \ - SIO_IR_SB_RX_FULL | \ - SIO_IR_SB_RX_HIGH | \ - SIO_IR_SB_RX_TIMER | \ - SIO_IR_SB_DELTA_DCD | \ - SIO_IR_SB_DELTA_CTS | \ - SIO_IR_SB_INT | \ - SIO_IR_SB_TX_EXPLICIT | \ - SIO_IR_SB_MEMERR) - -#define SIO_IR_PP (SIO_IR_PP_INT | SIO_IR_PP_INTA | \ - SIO_IR_PP_INTB | SIO_IR_PP_MEMERR) -#define SIO_IR_RT (SIO_IR_RT_INT | SIO_IR_GEN_INT1) - -/* bitmasks for SIO_CR */ -#define SIO_CR_CMD_PULSE_SHIFT 15 -#define SIO_CR_SER_A_BASE_SHIFT 1 -#define SIO_CR_SER_B_BASE_SHIFT 8 -#define SIO_CR_ARB_DIAG 0x00380000 /* cur !enet PCI requet (ro) */ -#define SIO_CR_ARB_DIAG_TXA 0x00000000 -#define SIO_CR_ARB_DIAG_RXA 0x00080000 -#define SIO_CR_ARB_DIAG_TXB 0x00100000 -#define SIO_CR_ARB_DIAG_RXB 0x00180000 -#define SIO_CR_ARB_DIAG_PP 0x00200000 -#define SIO_CR_ARB_DIAG_IDLE 0x00400000 /* 0 -> active request (ro) */ - -/* defs for some of the generic I/O pins */ -#define GPCR_PHY_RESET 0x20 /* pin is output to PHY reset */ -#define GPCR_UARTB_MODESEL 0x40 /* pin is output to port B mode sel */ -#define GPCR_UARTA_MODESEL 0x80 /* pin is output to port A mode sel */ - -#define GPPR_PHY_RESET_PIN 5 /* GIO pin controlling phy reset */ -#define GPPR_UARTB_MODESEL_PIN 6 /* GIO pin cntrling uartb modeselect */ -#define GPPR_UARTA_MODESEL_PIN 7 /* GIO pin cntrling uarta modeselect */ - -#endif /* IA64_SN_IOC3_H */ diff --git a/arch/ia64/include/asm/sn/klconfig.h b/arch/ia64/include/asm/sn/klconfig.h deleted file mode 100644 index bcbf209d63be6e123b0748106907938cd9034c5f..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/klconfig.h +++ /dev/null @@ -1,246 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Derived from IRIX . - * - * Copyright (C) 1992-1997,1999,2001-2004 Silicon Graphics, Inc. All Rights Reserved. - * Copyright (C) 1999 by Ralf Baechle - */ -#ifndef _ASM_IA64_SN_KLCONFIG_H -#define _ASM_IA64_SN_KLCONFIG_H - -/* - * The KLCONFIG structures store info about the various BOARDs found - * during Hardware Discovery. In addition, it stores info about the - * components found on the BOARDs. - */ - -typedef s32 klconf_off_t; - - -/* Functions/macros needed to use this structure */ - -typedef struct kl_config_hdr { - char pad[20]; - klconf_off_t ch_board_info; /* the link list of boards */ - char pad0[88]; -} kl_config_hdr_t; - - -#define NODE_OFFSET_TO_LBOARD(nasid,off) (lboard_t*)(GLOBAL_CAC_ADDR((nasid), (off))) - -/* - * The KLCONFIG area is organized as a LINKED LIST of BOARDs. A BOARD - * can be either 'LOCAL' or 'REMOTE'. LOCAL means it is attached to - * the LOCAL/current NODE. REMOTE means it is attached to a different - * node.(TBD - Need a way to treat ROUTER boards.) - * - * There are 2 different structures to represent these boards - - * lboard - Local board, rboard - remote board. These 2 structures - * can be arbitrarily mixed in the LINKED LIST of BOARDs. (Refer - * Figure below). The first byte of the rboard or lboard structure - * is used to find out its type - no unions are used. - * If it is a lboard, then the config info of this board will be found - * on the local node. (LOCAL NODE BASE + offset value gives pointer to - * the structure. - * If it is a rboard, the local structure contains the node number - * and the offset of the beginning of the LINKED LIST on the remote node. - * The details of the hardware on a remote node can be built locally, - * if required, by reading the LINKED LIST on the remote node and - * ignoring all the rboards on that node. - * - * The local node uses the REMOTE NODE NUMBER + OFFSET to point to the - * First board info on the remote node. The remote node list is - * traversed as the local list, using the REMOTE BASE ADDRESS and not - * the local base address and ignoring all rboard values. - * - * - KLCONFIG - - +------------+ +------------+ +------------+ +------------+ - | lboard | +-->| lboard | +-->| rboard | +-->| lboard | - +------------+ | +------------+ | +------------+ | +------------+ - | board info | | | board info | | |errinfo,bptr| | | board info | - +------------+ | +------------+ | +------------+ | +------------+ - | offset |--+ | offset |--+ | offset |--+ |offset=NULL | - +------------+ +------------+ +------------+ +------------+ - - - +------------+ - | board info | - +------------+ +--------------------------------+ - | compt 1 |------>| type, rev, diaginfo, size ... | (CPU) - +------------+ +--------------------------------+ - | compt 2 |--+ - +------------+ | +--------------------------------+ - | ... | +--->| type, rev, diaginfo, size ... | (MEM_BANK) - +------------+ +--------------------------------+ - | errinfo |--+ - +------------+ | +--------------------------------+ - +--->|r/l brd errinfo,compt err flags | - +--------------------------------+ - - * - * Each BOARD consists of COMPONENTs and the BOARD structure has - * pointers (offsets) to its COMPONENT structure. - * The COMPONENT structure has version info, size and speed info, revision, - * error info and the NIC info. This structure can accommodate any - * BOARD with arbitrary COMPONENT composition. - * - * The ERRORINFO part of each BOARD has error information - * that describes errors about the BOARD itself. It also has flags to - * indicate the COMPONENT(s) on the board that have errors. The error - * information specific to the COMPONENT is present in the respective - * COMPONENT structure. - * - * The ERRORINFO structure is also treated like a COMPONENT, ie. the - * BOARD has pointers(offset) to the ERRORINFO structure. The rboard - * structure also has a pointer to the ERRORINFO structure. This is - * the place to store ERRORINFO about a REMOTE NODE, if the HUB on - * that NODE is not working or if the REMOTE MEMORY is BAD. In cases where - * only the CPU of the REMOTE NODE is disabled, the ERRORINFO pointer can - * be a NODE NUMBER, REMOTE OFFSET combination, pointing to error info - * which is present on the REMOTE NODE.(TBD) - * REMOTE ERRINFO can be stored on any of the nearest nodes - * or on all the nearest nodes.(TBD) - * Like BOARD structures, REMOTE ERRINFO structures can be built locally - * using the rboard errinfo pointer. - * - * In order to get useful information from this Data organization, a set of - * interface routines are provided (TBD). The important thing to remember while - * manipulating the structures, is that, the NODE number information should - * be used. If the NODE is non-zero (remote) then each offset should - * be added to the REMOTE BASE ADDR else it should be added to the LOCAL BASE ADDR. - * This includes offsets for BOARDS, COMPONENTS and ERRORINFO. - * - * Note that these structures do not provide much info about connectivity. - * That info will be part of HWGRAPH, which is an extension of the cfg_t - * data structure. (ref IP27prom/cfg.h) It has to be extended to include - * the IO part of the Network(TBD). - * - * The data structures below define the above concepts. - */ - - -/* - * BOARD classes - */ - -#define KLCLASS_MASK 0xf0 -#define KLCLASS_NONE 0x00 -#define KLCLASS_NODE 0x10 /* CPU, Memory and HUB board */ -#define KLCLASS_CPU KLCLASS_NODE -#define KLCLASS_IO 0x20 /* BaseIO, 4 ch SCSI, ethernet, FDDI - and the non-graphics widget boards */ -#define KLCLASS_ROUTER 0x30 /* Router board */ -#define KLCLASS_MIDPLANE 0x40 /* We need to treat this as a board - so that we can record error info */ -#define KLCLASS_IOBRICK 0x70 /* IP35 iobrick */ -#define KLCLASS_MAX 8 /* Bump this if a new CLASS is added */ - -#define KLCLASS(_x) ((_x) & KLCLASS_MASK) - - -/* - * board types - */ - -#define KLTYPE_MASK 0x0f -#define KLTYPE(_x) ((_x) & KLTYPE_MASK) - -#define KLTYPE_SNIA (KLCLASS_CPU | 0x1) -#define KLTYPE_TIO (KLCLASS_CPU | 0x2) - -#define KLTYPE_ROUTER (KLCLASS_ROUTER | 0x1) -#define KLTYPE_META_ROUTER (KLCLASS_ROUTER | 0x3) -#define KLTYPE_REPEATER_ROUTER (KLCLASS_ROUTER | 0x4) - -#define KLTYPE_IOBRICK_XBOW (KLCLASS_MIDPLANE | 0x2) - -#define KLTYPE_IOBRICK (KLCLASS_IOBRICK | 0x0) -#define KLTYPE_NBRICK (KLCLASS_IOBRICK | 0x4) -#define KLTYPE_PXBRICK (KLCLASS_IOBRICK | 0x6) -#define KLTYPE_IXBRICK (KLCLASS_IOBRICK | 0x7) -#define KLTYPE_CGBRICK (KLCLASS_IOBRICK | 0x8) -#define KLTYPE_OPUSBRICK (KLCLASS_IOBRICK | 0x9) -#define KLTYPE_SABRICK (KLCLASS_IOBRICK | 0xa) -#define KLTYPE_IABRICK (KLCLASS_IOBRICK | 0xb) -#define KLTYPE_PABRICK (KLCLASS_IOBRICK | 0xc) -#define KLTYPE_GABRICK (KLCLASS_IOBRICK | 0xd) - - -/* - * board structures - */ - -#define MAX_COMPTS_PER_BRD 24 - -typedef struct lboard_s { - klconf_off_t brd_next_any; /* Next BOARD */ - unsigned char struct_type; /* type of structure, local or remote */ - unsigned char brd_type; /* type+class */ - unsigned char brd_sversion; /* version of this structure */ - unsigned char brd_brevision; /* board revision */ - unsigned char brd_promver; /* board prom version, if any */ - unsigned char brd_flags; /* Enabled, Disabled etc */ - unsigned char brd_slot; /* slot number */ - unsigned short brd_debugsw; /* Debug switches */ - geoid_t brd_geoid; /* geo id */ - partid_t brd_partition; /* Partition number */ - unsigned short brd_diagval; /* diagnostic value */ - unsigned short brd_diagparm; /* diagnostic parameter */ - unsigned char brd_inventory; /* inventory history */ - unsigned char brd_numcompts; /* Number of components */ - nic_t brd_nic; /* Number in CAN */ - nasid_t brd_nasid; /* passed parameter */ - klconf_off_t brd_compts[MAX_COMPTS_PER_BRD]; /* pointers to COMPONENTS */ - klconf_off_t brd_errinfo; /* Board's error information */ - struct lboard_s *brd_parent; /* Logical parent for this brd */ - char pad0[4]; - unsigned char brd_confidence; /* confidence that the board is bad */ - nasid_t brd_owner; /* who owns this board */ - unsigned char brd_nic_flags; /* To handle 8 more NICs */ - char pad1[24]; /* future expansion */ - char brd_name[32]; - nasid_t brd_next_same_host; /* host of next brd w/same nasid */ - klconf_off_t brd_next_same; /* Next BOARD with same nasid */ -} lboard_t; - -/* - * Generic info structure. This stores common info about a - * component. - */ - -typedef struct klinfo_s { /* Generic info */ - unsigned char struct_type; /* type of this structure */ - unsigned char struct_version; /* version of this structure */ - unsigned char flags; /* Enabled, disabled etc */ - unsigned char revision; /* component revision */ - unsigned short diagval; /* result of diagnostics */ - unsigned short diagparm; /* diagnostic parameter */ - unsigned char inventory; /* previous inventory status */ - unsigned short partid; /* widget part number */ - nic_t nic; /* MUst be aligned properly */ - unsigned char physid; /* physical id of component */ - unsigned int virtid; /* virtual id as seen by system */ - unsigned char widid; /* Widget id - if applicable */ - nasid_t nasid; /* node number - from parent */ - char pad1; /* pad out structure. */ - char pad2; /* pad out structure. */ - void *data; - klconf_off_t errinfo; /* component specific errors */ - unsigned short pad3; /* pci fields have moved over to */ - unsigned short pad4; /* klbri_t */ -} klinfo_t ; - - -static inline lboard_t *find_lboard_next(lboard_t * brd) -{ - if (brd && brd->brd_next_any) - return NODE_OFFSET_TO_LBOARD(NASID_GET(brd), brd->brd_next_any); - return NULL; -} - -#endif /* _ASM_IA64_SN_KLCONFIG_H */ diff --git a/arch/ia64/include/asm/sn/l1.h b/arch/ia64/include/asm/sn/l1.h deleted file mode 100644 index 344bf44bb3569a785e9c9e5e8d3fda21ef152268..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/l1.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992-1997,2000-2004 Silicon Graphics, Inc. All Rights Reserved. - */ - -#ifndef _ASM_IA64_SN_L1_H -#define _ASM_IA64_SN_L1_H - -/* brick type response codes */ -#define L1_BRICKTYPE_PX 0x23 /* # */ -#define L1_BRICKTYPE_PE 0x25 /* % */ -#define L1_BRICKTYPE_N_p0 0x26 /* & */ -#define L1_BRICKTYPE_IP45 0x34 /* 4 */ -#define L1_BRICKTYPE_IP41 0x35 /* 5 */ -#define L1_BRICKTYPE_TWISTER 0x36 /* 6 */ /* IP53 & ROUTER */ -#define L1_BRICKTYPE_IX 0x3d /* = */ -#define L1_BRICKTYPE_IP34 0x61 /* a */ -#define L1_BRICKTYPE_GA 0x62 /* b */ -#define L1_BRICKTYPE_C 0x63 /* c */ -#define L1_BRICKTYPE_OPUS_TIO 0x66 /* f */ -#define L1_BRICKTYPE_I 0x69 /* i */ -#define L1_BRICKTYPE_N 0x6e /* n */ -#define L1_BRICKTYPE_OPUS 0x6f /* o */ -#define L1_BRICKTYPE_P 0x70 /* p */ -#define L1_BRICKTYPE_R 0x72 /* r */ -#define L1_BRICKTYPE_CHI_CG 0x76 /* v */ -#define L1_BRICKTYPE_X 0x78 /* x */ -#define L1_BRICKTYPE_X2 0x79 /* y */ -#define L1_BRICKTYPE_SA 0x5e /* ^ */ -#define L1_BRICKTYPE_PA 0x6a /* j */ -#define L1_BRICKTYPE_IA 0x6b /* k */ -#define L1_BRICKTYPE_ATHENA 0x2b /* + */ -#define L1_BRICKTYPE_DAYTONA 0x7a /* z */ -#define L1_BRICKTYPE_1932 0x2c /* . */ -#define L1_BRICKTYPE_191010 0x2e /* , */ - -/* board type response codes */ -#define L1_BOARDTYPE_IP69 0x0100 /* CA */ -#define L1_BOARDTYPE_IP63 0x0200 /* CB */ -#define L1_BOARDTYPE_BASEIO 0x0300 /* IB */ -#define L1_BOARDTYPE_PCIE2SLOT 0x0400 /* IC */ -#define L1_BOARDTYPE_PCIX3SLOT 0x0500 /* ID */ -#define L1_BOARDTYPE_PCIXPCIE4SLOT 0x0600 /* IE */ -#define L1_BOARDTYPE_ABACUS 0x0700 /* AB */ -#define L1_BOARDTYPE_DAYTONA 0x0800 /* AD */ -#define L1_BOARDTYPE_INVAL (-1) /* invalid brick type */ - -#endif /* _ASM_IA64_SN_L1_H */ diff --git a/arch/ia64/include/asm/sn/leds.h b/arch/ia64/include/asm/sn/leds.h deleted file mode 100644 index 66cf8c4d92c9a1bfb83b2657cd8f100aa64df2a9..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/leds.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_LEDS_H -#define _ASM_IA64_SN_LEDS_H - -#include -#include -#include - -#define LED0 (LOCAL_MMR_ADDR(SH_REAL_JUNK_BUS_LED0)) -#define LED_CPU_SHIFT 16 - -#define LED_CPU_HEARTBEAT 0x01 -#define LED_CPU_ACTIVITY 0x02 -#define LED_ALWAYS_SET 0x00 - -/* - * Basic macros for flashing the LEDS on an SGI SN. - */ - -static __inline__ void -set_led_bits(u8 value, u8 mask) -{ - pda->led_state = (pda->led_state & ~mask) | (value & mask); - *pda->led_address = (short) pda->led_state; -} - -#endif /* _ASM_IA64_SN_LEDS_H */ - diff --git a/arch/ia64/include/asm/sn/module.h b/arch/ia64/include/asm/sn/module.h deleted file mode 100644 index 734e980ece2fb43208c168d5ef1a1519a46e4548..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/module.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_MODULE_H -#define _ASM_IA64_SN_MODULE_H - -/* parameter for format_module_id() */ -#define MODULE_FORMAT_BRIEF 1 -#define MODULE_FORMAT_LONG 2 -#define MODULE_FORMAT_LCD 3 - -/* - * Module id format - * - * 31-16 Rack ID (encoded class, group, number - 16-bit unsigned int) - * 15-8 Brick type (8-bit ascii character) - * 7-0 Bay (brick position in rack (0-63) - 8-bit unsigned int) - * - */ - -/* - * Macros for getting the brick type - */ -#define MODULE_BTYPE_MASK 0xff00 -#define MODULE_BTYPE_SHFT 8 -#define MODULE_GET_BTYPE(_m) (((_m) & MODULE_BTYPE_MASK) >> MODULE_BTYPE_SHFT) -#define MODULE_BT_TO_CHAR(_b) ((char)(_b)) -#define MODULE_GET_BTCHAR(_m) (MODULE_BT_TO_CHAR(MODULE_GET_BTYPE(_m))) - -/* - * Macros for getting the rack ID. - */ -#define MODULE_RACK_MASK 0xffff0000 -#define MODULE_RACK_SHFT 16 -#define MODULE_GET_RACK(_m) (((_m) & MODULE_RACK_MASK) >> MODULE_RACK_SHFT) - -/* - * Macros for getting the brick position - */ -#define MODULE_BPOS_MASK 0x00ff -#define MODULE_BPOS_SHFT 0 -#define MODULE_GET_BPOS(_m) (((_m) & MODULE_BPOS_MASK) >> MODULE_BPOS_SHFT) - -/* - * Macros for encoding and decoding rack IDs - * A rack number consists of three parts: - * class (0==CPU/mixed, 1==I/O), group, number - * - * Rack number is stored just as it is displayed on the screen: - * a 3-decimal-digit number. - */ -#define RACK_CLASS_DVDR 100 -#define RACK_GROUP_DVDR 10 -#define RACK_NUM_DVDR 1 - -#define RACK_CREATE_RACKID(_c, _g, _n) ((_c) * RACK_CLASS_DVDR + \ - (_g) * RACK_GROUP_DVDR + (_n) * RACK_NUM_DVDR) - -#define RACK_GET_CLASS(_r) ((_r) / RACK_CLASS_DVDR) -#define RACK_GET_GROUP(_r) (((_r) - RACK_GET_CLASS(_r) * \ - RACK_CLASS_DVDR) / RACK_GROUP_DVDR) -#define RACK_GET_NUM(_r) (((_r) - RACK_GET_CLASS(_r) * \ - RACK_CLASS_DVDR - RACK_GET_GROUP(_r) * \ - RACK_GROUP_DVDR) / RACK_NUM_DVDR) - -/* - * Macros for encoding and decoding rack IDs - * A rack number consists of three parts: - * class 1 bit, 0==CPU/mixed, 1==I/O - * group 2 bits for CPU/mixed, 3 bits for I/O - * number 3 bits for CPU/mixed, 2 bits for I/O (1 based) - */ -#define RACK_GROUP_BITS(_r) (RACK_GET_CLASS(_r) ? 3 : 2) -#define RACK_NUM_BITS(_r) (RACK_GET_CLASS(_r) ? 2 : 3) - -#define RACK_CLASS_MASK(_r) 0x20 -#define RACK_CLASS_SHFT(_r) 5 -#define RACK_ADD_CLASS(_r, _c) \ - ((_r) |= (_c) << RACK_CLASS_SHFT(_r) & RACK_CLASS_MASK(_r)) - -#define RACK_GROUP_SHFT(_r) RACK_NUM_BITS(_r) -#define RACK_GROUP_MASK(_r) \ - ( (((unsigned)1< -#include -#include -#include - -/* - * NUMA Node-Specific Data structures are defined in this file. - * In particular, this is the location of the node PDA. - * A pointer to the right node PDA is saved in each CPU PDA. - */ - -/* - * Node-specific data structure. - * - * One of these structures is allocated on each node of a NUMA system. - * - * This structure provides a convenient way of keeping together - * all per-node data structures. - */ -struct phys_cpuid { - short nasid; - char subnode; - char slice; -}; - -struct nodepda_s { - void *pdinfo; /* Platform-dependent per-node info */ - - /* - * The BTEs on this node are shared by the local cpus - */ - struct bteinfo_s bte_if[MAX_BTES_PER_NODE]; /* Virtual Interface */ - struct timer_list bte_recovery_timer; - spinlock_t bte_recovery_lock; - - /* - * Array of pointers to the nodepdas for each node. - */ - struct nodepda_s *pernode_pdaindr[MAX_COMPACT_NODES]; - - /* - * Array of physical cpu identifiers. Indexed by cpuid. - */ - struct phys_cpuid phys_cpuid[NR_CPUS]; - spinlock_t ptc_lock ____cacheline_aligned_in_smp; -}; - -typedef struct nodepda_s nodepda_t; - -/* - * Access Functions for node PDA. - * Since there is one nodepda for each node, we need a convenient mechanism - * to access these nodepdas without cluttering code with #ifdefs. - * The next set of definitions provides this. - * Routines are expected to use - * - * sn_nodepda - to access node PDA for the node on which code is running - * NODEPDA(cnodeid) - to access node PDA for cnodeid - */ - -DECLARE_PER_CPU(struct nodepda_s *, __sn_nodepda); -#define sn_nodepda __this_cpu_read(__sn_nodepda) -#define NODEPDA(cnodeid) (sn_nodepda->pernode_pdaindr[cnodeid]) - -/* - * Check if given a compact node id the corresponding node has all the - * cpus disabled. - */ -#define is_headless_node(cnodeid) (nr_cpus_node(cnodeid) == 0) - -#endif /* _ASM_IA64_SN_NODEPDA_H */ diff --git a/arch/ia64/include/asm/sn/pcibr_provider.h b/arch/ia64/include/asm/sn/pcibr_provider.h deleted file mode 100644 index da205b7cdaacf0ea77832bb957751ae17b6520e5..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/pcibr_provider.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992-1997,2000-2006 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_PCI_PCIBR_PROVIDER_H -#define _ASM_IA64_SN_PCI_PCIBR_PROVIDER_H - -#include -#include - -/* Workarounds */ -#define PV907516 (1 << 1) /* TIOCP: Don't write the write buffer flush reg */ - -#define BUSTYPE_MASK 0x1 - -/* Macros given a pcibus structure */ -#define IS_PCIX(ps) ((ps)->pbi_bridge_mode & BUSTYPE_MASK) -#define IS_PCI_BRIDGE_ASIC(asic) (asic == PCIIO_ASIC_TYPE_PIC || \ - asic == PCIIO_ASIC_TYPE_TIOCP) -#define IS_PIC_SOFT(ps) (ps->pbi_bridge_type == PCIBR_BRIDGETYPE_PIC) -#define IS_TIOCP_SOFT(ps) (ps->pbi_bridge_type == PCIBR_BRIDGETYPE_TIOCP) - - -/* - * The different PCI Bridge types supported on the SGI Altix platforms - */ -#define PCIBR_BRIDGETYPE_UNKNOWN -1 -#define PCIBR_BRIDGETYPE_PIC 2 -#define PCIBR_BRIDGETYPE_TIOCP 3 - -/* - * Bridge 64bit Direct Map Attributes - */ -#define PCI64_ATTR_PREF (1ull << 59) -#define PCI64_ATTR_PREC (1ull << 58) -#define PCI64_ATTR_VIRTUAL (1ull << 57) -#define PCI64_ATTR_BAR (1ull << 56) -#define PCI64_ATTR_SWAP (1ull << 55) -#define PCI64_ATTR_VIRTUAL1 (1ull << 54) - -#define PCI32_LOCAL_BASE 0 -#define PCI32_MAPPED_BASE 0x40000000 -#define PCI32_DIRECT_BASE 0x80000000 - -#define IS_PCI32_MAPPED(x) ((u64)(x) < PCI32_DIRECT_BASE && \ - (u64)(x) >= PCI32_MAPPED_BASE) -#define IS_PCI32_DIRECT(x) ((u64)(x) >= PCI32_MAPPED_BASE) - - -/* - * Bridge PMU Address Transaltion Entry Attibutes - */ -#define PCI32_ATE_V (0x1 << 0) -#define PCI32_ATE_CO (0x1 << 1) /* PIC ASIC ONLY */ -#define PCI32_ATE_PIO (0x1 << 1) /* TIOCP ASIC ONLY */ -#define PCI32_ATE_MSI (0x1 << 2) -#define PCI32_ATE_PREF (0x1 << 3) -#define PCI32_ATE_BAR (0x1 << 4) -#define PCI32_ATE_ADDR_SHFT 12 - -#define MINIMAL_ATES_REQUIRED(addr, size) \ - (IOPG(IOPGOFF(addr) + (size) - 1) == IOPG((size) - 1)) - -#define MINIMAL_ATE_FLAG(addr, size) \ - (MINIMAL_ATES_REQUIRED((u64)addr, size) ? 1 : 0) - -/* bit 29 of the pci address is the SWAP bit */ -#define ATE_SWAPSHIFT 29 -#define ATE_SWAP_ON(x) ((x) |= (1 << ATE_SWAPSHIFT)) -#define ATE_SWAP_OFF(x) ((x) &= ~(1 << ATE_SWAPSHIFT)) - -/* - * I/O page size - */ -#if PAGE_SIZE < 16384 -#define IOPFNSHIFT 12 /* 4K per mapped page */ -#else -#define IOPFNSHIFT 14 /* 16K per mapped page */ -#endif - -#define IOPGSIZE (1 << IOPFNSHIFT) -#define IOPG(x) ((x) >> IOPFNSHIFT) -#define IOPGOFF(x) ((x) & (IOPGSIZE-1)) - -#define PCIBR_DEV_SWAP_DIR (1ull << 19) -#define PCIBR_CTRL_PAGE_SIZE (0x1 << 21) - -/* - * PMU resources. - */ -struct ate_resource{ - u64 *ate; - u64 num_ate; - u64 lowest_free_index; -}; - -struct pcibus_info { - struct pcibus_bussoft pbi_buscommon; /* common header */ - u32 pbi_moduleid; - short pbi_bridge_type; - short pbi_bridge_mode; - - struct ate_resource pbi_int_ate_resource; - u64 pbi_int_ate_size; - - u64 pbi_dir_xbase; - char pbi_hub_xid; - - u64 pbi_devreg[8]; - - u32 pbi_valid_devices; - u32 pbi_enabled_devices; - - spinlock_t pbi_lock; -}; - -extern int pcibr_init_provider(void); -extern void *pcibr_bus_fixup(struct pcibus_bussoft *, struct pci_controller *); -extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t, int type); -extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t, int type); -extern void pcibr_dma_unmap(struct pci_dev *, dma_addr_t, int); - -/* - * prototypes for the bridge asic register access routines in pcibr_reg.c - */ -extern void pcireg_control_bit_clr(struct pcibus_info *, u64); -extern void pcireg_control_bit_set(struct pcibus_info *, u64); -extern u64 pcireg_tflush_get(struct pcibus_info *); -extern u64 pcireg_intr_status_get(struct pcibus_info *); -extern void pcireg_intr_enable_bit_clr(struct pcibus_info *, u64); -extern void pcireg_intr_enable_bit_set(struct pcibus_info *, u64); -extern void pcireg_intr_addr_addr_set(struct pcibus_info *, int, u64); -extern void pcireg_force_intr_set(struct pcibus_info *, int); -extern u64 pcireg_wrb_flush_get(struct pcibus_info *, int); -extern void pcireg_int_ate_set(struct pcibus_info *, int, u64); -extern u64 __iomem * pcireg_int_ate_addr(struct pcibus_info *, int); -extern void pcibr_force_interrupt(struct sn_irq_info *sn_irq_info); -extern void pcibr_change_devices_irq(struct sn_irq_info *sn_irq_info); -extern int pcibr_ate_alloc(struct pcibus_info *, int); -extern void pcibr_ate_free(struct pcibus_info *, int); -extern void ate_write(struct pcibus_info *, int, int, u64); -extern int sal_pcibr_slot_enable(struct pcibus_info *soft, int device, - void *resp, char **ssdt); -extern int sal_pcibr_slot_disable(struct pcibus_info *soft, int device, - int action, void *resp); -extern u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus); -#endif diff --git a/arch/ia64/include/asm/sn/pcibus_provider_defs.h b/arch/ia64/include/asm/sn/pcibus_provider_defs.h deleted file mode 100644 index 8f7c83d0f6d3937e8c9101dacdc0422d7e523cda..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/pcibus_provider_defs.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H -#define _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H - -/* - * SN pci asic types. Do not ever renumber these or reuse values. The - * values must agree with what prom thinks they are. - */ - -#define PCIIO_ASIC_TYPE_UNKNOWN 0 -#define PCIIO_ASIC_TYPE_PPB 1 -#define PCIIO_ASIC_TYPE_PIC 2 -#define PCIIO_ASIC_TYPE_TIOCP 3 -#define PCIIO_ASIC_TYPE_TIOCA 4 -#define PCIIO_ASIC_TYPE_TIOCE 5 - -#define PCIIO_ASIC_MAX_TYPES 6 - -/* - * Common pciio bus provider data. There should be one of these as the - * first field in any pciio based provider soft structure (e.g. pcibr_soft - * tioca_soft, etc). - */ - -struct pcibus_bussoft { - u32 bs_asic_type; /* chipset type */ - u32 bs_xid; /* xwidget id */ - u32 bs_persist_busnum; /* Persistent Bus Number */ - u32 bs_persist_segment; /* Segment Number */ - u64 bs_legacy_io; /* legacy io pio addr */ - u64 bs_legacy_mem; /* legacy mem pio addr */ - u64 bs_base; /* widget base */ - struct xwidget_info *bs_xwidget_info; -}; - -struct pci_controller; -/* - * SN pci bus indirection - */ - -struct sn_pcibus_provider { - dma_addr_t (*dma_map)(struct pci_dev *, unsigned long, size_t, int flags); - dma_addr_t (*dma_map_consistent)(struct pci_dev *, unsigned long, size_t, int flags); - void (*dma_unmap)(struct pci_dev *, dma_addr_t, int); - void * (*bus_fixup)(struct pcibus_bussoft *, struct pci_controller *); - void (*force_interrupt)(struct sn_irq_info *); - void (*target_interrupt)(struct sn_irq_info *); -}; - -/* - * Flags used by the map interfaces - * bits 3:0 specifies format of passed in address - * bit 4 specifies that address is to be used for MSI - */ - -#define SN_DMA_ADDRTYPE(x) ((x) & 0xf) -#define SN_DMA_ADDR_PHYS 1 /* address is an xio address. */ -#define SN_DMA_ADDR_XIO 2 /* address is phys memory */ -#define SN_DMA_MSI 0x10 /* Bus address is to be used for MSI */ - -extern struct sn_pcibus_provider *sn_pci_provider[]; -#endif /* _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H */ diff --git a/arch/ia64/include/asm/sn/pcidev.h b/arch/ia64/include/asm/sn/pcidev.h deleted file mode 100644 index 1c2382cea807b5431d638b23451a1994bad7e50e..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/pcidev.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2006 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_PCI_PCIDEV_H -#define _ASM_IA64_SN_PCI_PCIDEV_H - -#include - -/* - * In ia64, pci_dev->sysdata must be a *pci_controller. To provide access to - * the pcidev_info structs for all devices under a controller, we keep a - * list of pcidev_info under pci_controller->platform_data. - */ -struct sn_platform_data { - void *provider_soft; - struct list_head pcidev_info; -}; - -#define SN_PLATFORM_DATA(busdev) \ - ((struct sn_platform_data *)(PCI_CONTROLLER(busdev)->platform_data)) - -#define SN_PCIDEV_INFO(dev) sn_pcidev_info_get(dev) - -/* - * Given a pci_bus, return the sn pcibus_bussoft struct. Note that - * this only works for root busses, not for busses represented by PPB's. - */ - -#define SN_PCIBUS_BUSSOFT(pci_bus) \ - ((struct pcibus_bussoft *)(SN_PLATFORM_DATA(pci_bus)->provider_soft)) - -#define SN_PCIBUS_BUSSOFT_INFO(pci_bus) \ - ((struct pcibus_info *)(SN_PLATFORM_DATA(pci_bus)->provider_soft)) -/* - * Given a struct pci_dev, return the sn pcibus_bussoft struct. Note - * that this is not equivalent to SN_PCIBUS_BUSSOFT(pci_dev->bus) due - * due to possible PPB's in the path. - */ - -#define SN_PCIDEV_BUSSOFT(pci_dev) \ - (SN_PCIDEV_INFO(pci_dev)->pdi_host_pcidev_info->pdi_pcibus_info) - -#define SN_PCIDEV_BUSPROVIDER(pci_dev) \ - (SN_PCIDEV_INFO(pci_dev)->pdi_provider) - -#define PCIIO_BUS_NONE 255 /* bus 255 reserved */ -#define PCIIO_SLOT_NONE 255 -#define PCIIO_FUNC_NONE 255 -#define PCIIO_VENDOR_ID_NONE (-1) - -struct pcidev_info { - u64 pdi_pio_mapped_addr[7]; /* 6 BARs PLUS 1 ROM */ - u64 pdi_slot_host_handle; /* Bus and devfn Host pci_dev */ - - struct pcibus_bussoft *pdi_pcibus_info; /* Kernel common bus soft */ - struct pcidev_info *pdi_host_pcidev_info; /* Kernel Host pci_dev */ - struct pci_dev *pdi_linux_pcidev; /* Kernel pci_dev */ - - struct sn_irq_info *pdi_sn_irq_info; - struct sn_pcibus_provider *pdi_provider; /* sn pci ops */ - struct pci_dev *host_pci_dev; /* host bus link */ - struct list_head pdi_list; /* List of pcidev_info */ -}; - -extern void sn_irq_fixup(struct pci_dev *pci_dev, - struct sn_irq_info *sn_irq_info); -extern void sn_irq_unfixup(struct pci_dev *pci_dev); -extern struct pcidev_info * sn_pcidev_info_get(struct pci_dev *); -extern void sn_bus_fixup(struct pci_bus *); -extern void sn_acpi_bus_fixup(struct pci_bus *); -extern void sn_common_bus_fixup(struct pci_bus *, struct pcibus_bussoft *); -extern void sn_bus_store_sysdata(struct pci_dev *dev); -extern void sn_bus_free_sysdata(void); -extern void sn_generate_path(struct pci_bus *pci_bus, char *address); -extern void sn_io_slot_fixup(struct pci_dev *); -extern void sn_acpi_slot_fixup(struct pci_dev *); -extern void sn_pci_fixup_slot(struct pci_dev *dev, struct pcidev_info *, - struct sn_irq_info *); -extern void sn_pci_unfixup_slot(struct pci_dev *dev); -extern void sn_irq_lh_init(void); -#endif /* _ASM_IA64_SN_PCI_PCIDEV_H */ diff --git a/arch/ia64/include/asm/sn/pda.h b/arch/ia64/include/asm/sn/pda.h deleted file mode 100644 index 22ae358c8d16dd7d97d245b103e49f31d27c414e..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/pda.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_PDA_H -#define _ASM_IA64_SN_PDA_H - -#include -#include - - -/* - * CPU-specific data structure. - * - * One of these structures is allocated for each cpu of a NUMA system. - * - * This structure provides a convenient way of keeping together - * all SN per-cpu data structures. - */ - -typedef struct pda_s { - - /* - * Support for SN LEDs - */ - volatile short *led_address; - u8 led_state; - u8 hb_state; /* supports blinking heartbeat leds */ - unsigned int hb_count; - - unsigned int idle_flag; - - volatile unsigned long *bedrock_rev_id; - volatile unsigned long *pio_write_status_addr; - unsigned long pio_write_status_val; - volatile unsigned long *pio_shub_war_cam_addr; - - unsigned long sn_in_service_ivecs[4]; - int sn_lb_int_war_ticks; - int sn_last_irq; - int sn_first_irq; -} pda_t; - - -#define CACHE_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) - -/* - * PDA - * Per-cpu private data area for each cpu. The PDA is located immediately after - * the IA64 cpu_data area. A full page is allocated for the cp_data area for each - * cpu but only a small amout of the page is actually used. We put the SNIA PDA - * in the same page as the cpu_data area. Note that there is a check in the setup - * code to verify that we don't overflow the page. - * - * Seems like we should should cache-line align the pda so that any changes in the - * size of the cpu_data area don't change cache layout. Should we align to 32, 64, 128 - * or 512 boundary. Each has merits. For now, pick 128 but should be revisited later. - */ -DECLARE_PER_CPU(struct pda_s, pda_percpu); - -#define pda (&__ia64_per_cpu_var(pda_percpu)) - -#define pdacpu(cpu) (&per_cpu(pda_percpu, cpu)) - -#endif /* _ASM_IA64_SN_PDA_H */ diff --git a/arch/ia64/include/asm/sn/pic.h b/arch/ia64/include/asm/sn/pic.h deleted file mode 100644 index 5f9da5fd6e56094094171d7506373adde1659ecc..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/pic.h +++ /dev/null @@ -1,261 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_PCI_PIC_H -#define _ASM_IA64_SN_PCI_PIC_H - -/* - * PIC AS DEVICE ZERO - * ------------------ - * - * PIC handles PCI/X busses. PCI/X requires that the 'bridge' (i.e. PIC) - * be designated as 'device 0'. That is a departure from earlier SGI - * PCI bridges. Because of that we use config space 1 to access the - * config space of the first actual PCI device on the bus. - * Here's what the PIC manual says: - * - * The current PCI-X bus specification now defines that the parent - * hosts bus bridge (PIC for example) must be device 0 on bus 0. PIC - * reduced the total number of devices from 8 to 4 and removed the - * device registers and windows, now only supporting devices 0,1,2, and - * 3. PIC did leave all 8 configuration space windows. The reason was - * there was nothing to gain by removing them. Here in lies the problem. - * The device numbering we do using 0 through 3 is unrelated to the device - * numbering which PCI-X requires in configuration space. In the past we - * correlated Configs pace and our device space 0 <-> 0, 1 <-> 1, etc. - * PCI-X requires we start a 1, not 0 and currently the PX brick - * does associate our: - * - * device 0 with configuration space window 1, - * device 1 with configuration space window 2, - * device 2 with configuration space window 3, - * device 3 with configuration space window 4. - * - * The net effect is that all config space access are off-by-one with - * relation to other per-slot accesses on the PIC. - * Here is a table that shows some of that: - * - * Internal Slot# - * | - * | 0 1 2 3 - * ----------|--------------------------------------- - * config | 0x21000 0x22000 0x23000 0x24000 - * | - * even rrb | 0[0] n/a 1[0] n/a [] == implied even/odd - * | - * odd rrb | n/a 0[1] n/a 1[1] - * | - * int dev | 00 01 10 11 - * | - * ext slot# | 1 2 3 4 - * ----------|--------------------------------------- - */ - -#define PIC_ATE_TARGETID_SHFT 8 -#define PIC_HOST_INTR_ADDR 0x0000FFFFFFFFFFFFUL -#define PIC_PCI64_ATTR_TARG_SHFT 60 - - -/***************************************************************************** - *********************** PIC MMR structure mapping *************************** - *****************************************************************************/ - -/* NOTE: PIC WAR. PV#854697. PIC does not allow writes just to [31:0] - * of a 64-bit register. When writing PIC registers, always write the - * entire 64 bits. - */ - -struct pic { - - /* 0x000000-0x00FFFF -- Local Registers */ - - /* 0x000000-0x000057 -- Standard Widget Configuration */ - u64 p_wid_id; /* 0x000000 */ - u64 p_wid_stat; /* 0x000008 */ - u64 p_wid_err_upper; /* 0x000010 */ - u64 p_wid_err_lower; /* 0x000018 */ - #define p_wid_err p_wid_err_lower - u64 p_wid_control; /* 0x000020 */ - u64 p_wid_req_timeout; /* 0x000028 */ - u64 p_wid_int_upper; /* 0x000030 */ - u64 p_wid_int_lower; /* 0x000038 */ - #define p_wid_int p_wid_int_lower - u64 p_wid_err_cmdword; /* 0x000040 */ - u64 p_wid_llp; /* 0x000048 */ - u64 p_wid_tflush; /* 0x000050 */ - - /* 0x000058-0x00007F -- Bridge-specific Widget Configuration */ - u64 p_wid_aux_err; /* 0x000058 */ - u64 p_wid_resp_upper; /* 0x000060 */ - u64 p_wid_resp_lower; /* 0x000068 */ - #define p_wid_resp p_wid_resp_lower - u64 p_wid_tst_pin_ctrl; /* 0x000070 */ - u64 p_wid_addr_lkerr; /* 0x000078 */ - - /* 0x000080-0x00008F -- PMU & MAP */ - u64 p_dir_map; /* 0x000080 */ - u64 _pad_000088; /* 0x000088 */ - - /* 0x000090-0x00009F -- SSRAM */ - u64 p_map_fault; /* 0x000090 */ - u64 _pad_000098; /* 0x000098 */ - - /* 0x0000A0-0x0000AF -- Arbitration */ - u64 p_arb; /* 0x0000A0 */ - u64 _pad_0000A8; /* 0x0000A8 */ - - /* 0x0000B0-0x0000BF -- Number In A Can or ATE Parity Error */ - u64 p_ate_parity_err; /* 0x0000B0 */ - u64 _pad_0000B8; /* 0x0000B8 */ - - /* 0x0000C0-0x0000FF -- PCI/GIO */ - u64 p_bus_timeout; /* 0x0000C0 */ - u64 p_pci_cfg; /* 0x0000C8 */ - u64 p_pci_err_upper; /* 0x0000D0 */ - u64 p_pci_err_lower; /* 0x0000D8 */ - #define p_pci_err p_pci_err_lower - u64 _pad_0000E0[4]; /* 0x0000{E0..F8} */ - - /* 0x000100-0x0001FF -- Interrupt */ - u64 p_int_status; /* 0x000100 */ - u64 p_int_enable; /* 0x000108 */ - u64 p_int_rst_stat; /* 0x000110 */ - u64 p_int_mode; /* 0x000118 */ - u64 p_int_device; /* 0x000120 */ - u64 p_int_host_err; /* 0x000128 */ - u64 p_int_addr[8]; /* 0x0001{30,,,68} */ - u64 p_err_int_view; /* 0x000170 */ - u64 p_mult_int; /* 0x000178 */ - u64 p_force_always[8]; /* 0x0001{80,,,B8} */ - u64 p_force_pin[8]; /* 0x0001{C0,,,F8} */ - - /* 0x000200-0x000298 -- Device */ - u64 p_device[4]; /* 0x0002{00,,,18} */ - u64 _pad_000220[4]; /* 0x0002{20,,,38} */ - u64 p_wr_req_buf[4]; /* 0x0002{40,,,58} */ - u64 _pad_000260[4]; /* 0x0002{60,,,78} */ - u64 p_rrb_map[2]; /* 0x0002{80,,,88} */ - #define p_even_resp p_rrb_map[0] /* 0x000280 */ - #define p_odd_resp p_rrb_map[1] /* 0x000288 */ - u64 p_resp_status; /* 0x000290 */ - u64 p_resp_clear; /* 0x000298 */ - - u64 _pad_0002A0[12]; /* 0x0002{A0..F8} */ - - /* 0x000300-0x0003F8 -- Buffer Address Match Registers */ - struct { - u64 upper; /* 0x0003{00,,,F0} */ - u64 lower; /* 0x0003{08,,,F8} */ - } p_buf_addr_match[16]; - - /* 0x000400-0x0005FF -- Performance Monitor Registers (even only) */ - struct { - u64 flush_w_touch; /* 0x000{400,,,5C0} */ - u64 flush_wo_touch; /* 0x000{408,,,5C8} */ - u64 inflight; /* 0x000{410,,,5D0} */ - u64 prefetch; /* 0x000{418,,,5D8} */ - u64 total_pci_retry; /* 0x000{420,,,5E0} */ - u64 max_pci_retry; /* 0x000{428,,,5E8} */ - u64 max_latency; /* 0x000{430,,,5F0} */ - u64 clear_all; /* 0x000{438,,,5F8} */ - } p_buf_count[8]; - - - /* 0x000600-0x0009FF -- PCI/X registers */ - u64 p_pcix_bus_err_addr; /* 0x000600 */ - u64 p_pcix_bus_err_attr; /* 0x000608 */ - u64 p_pcix_bus_err_data; /* 0x000610 */ - u64 p_pcix_pio_split_addr; /* 0x000618 */ - u64 p_pcix_pio_split_attr; /* 0x000620 */ - u64 p_pcix_dma_req_err_attr; /* 0x000628 */ - u64 p_pcix_dma_req_err_addr; /* 0x000630 */ - u64 p_pcix_timeout; /* 0x000638 */ - - u64 _pad_000640[120]; /* 0x000{640,,,9F8} */ - - /* 0x000A00-0x000BFF -- PCI/X Read&Write Buffer */ - struct { - u64 p_buf_addr; /* 0x000{A00,,,AF0} */ - u64 p_buf_attr; /* 0X000{A08,,,AF8} */ - } p_pcix_read_buf_64[16]; - - struct { - u64 p_buf_addr; /* 0x000{B00,,,BE0} */ - u64 p_buf_attr; /* 0x000{B08,,,BE8} */ - u64 p_buf_valid; /* 0x000{B10,,,BF0} */ - u64 __pad1; /* 0x000{B18,,,BF8} */ - } p_pcix_write_buf_64[8]; - - /* End of Local Registers -- Start of Address Map space */ - - char _pad_000c00[0x010000 - 0x000c00]; - - /* 0x010000-0x011fff -- Internal ATE RAM (Auto Parity Generation) */ - u64 p_int_ate_ram[1024]; /* 0x010000-0x011fff */ - - /* 0x012000-0x013fff -- Internal ATE RAM (Manual Parity Generation) */ - u64 p_int_ate_ram_mp[1024]; /* 0x012000-0x013fff */ - - char _pad_014000[0x18000 - 0x014000]; - - /* 0x18000-0x197F8 -- PIC Write Request Ram */ - u64 p_wr_req_lower[256]; /* 0x18000 - 0x187F8 */ - u64 p_wr_req_upper[256]; /* 0x18800 - 0x18FF8 */ - u64 p_wr_req_parity[256]; /* 0x19000 - 0x197F8 */ - - char _pad_019800[0x20000 - 0x019800]; - - /* 0x020000-0x027FFF -- PCI Device Configuration Spaces */ - union { - u8 c[0x1000 / 1]; /* 0x02{0000,,,7FFF} */ - u16 s[0x1000 / 2]; /* 0x02{0000,,,7FFF} */ - u32 l[0x1000 / 4]; /* 0x02{0000,,,7FFF} */ - u64 d[0x1000 / 8]; /* 0x02{0000,,,7FFF} */ - union { - u8 c[0x100 / 1]; - u16 s[0x100 / 2]; - u32 l[0x100 / 4]; - u64 d[0x100 / 8]; - } f[8]; - } p_type0_cfg_dev[8]; /* 0x02{0000,,,7FFF} */ - - /* 0x028000-0x028FFF -- PCI Type 1 Configuration Space */ - union { - u8 c[0x1000 / 1]; /* 0x028000-0x029000 */ - u16 s[0x1000 / 2]; /* 0x028000-0x029000 */ - u32 l[0x1000 / 4]; /* 0x028000-0x029000 */ - u64 d[0x1000 / 8]; /* 0x028000-0x029000 */ - union { - u8 c[0x100 / 1]; - u16 s[0x100 / 2]; - u32 l[0x100 / 4]; - u64 d[0x100 / 8]; - } f[8]; - } p_type1_cfg; /* 0x028000-0x029000 */ - - char _pad_029000[0x030000-0x029000]; - - /* 0x030000-0x030007 -- PCI Interrupt Acknowledge Cycle */ - union { - u8 c[8 / 1]; - u16 s[8 / 2]; - u32 l[8 / 4]; - u64 d[8 / 8]; - } p_pci_iack; /* 0x030000-0x030007 */ - - char _pad_030007[0x040000-0x030008]; - - /* 0x040000-0x030007 -- PCIX Special Cycle */ - union { - u8 c[8 / 1]; - u16 s[8 / 2]; - u32 l[8 / 4]; - u64 d[8 / 8]; - } p_pcix_cycle; /* 0x040000-0x040007 */ -}; - -#endif /* _ASM_IA64_SN_PCI_PIC_H */ diff --git a/arch/ia64/include/asm/sn/rw_mmr.h b/arch/ia64/include/asm/sn/rw_mmr.h deleted file mode 100644 index 2d78f4c5a45e216a3218616c4287625ae37eef73..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/rw_mmr.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2002-2006 Silicon Graphics, Inc. All Rights Reserved. - */ -#ifndef _ASM_IA64_SN_RW_MMR_H -#define _ASM_IA64_SN_RW_MMR_H - - -/* - * This file that access MMRs via uncached physical addresses. - * pio_phys_read_mmr - read an MMR - * pio_phys_write_mmr - write an MMR - * pio_atomic_phys_write_mmrs - atomically write 1 or 2 MMRs with psr.ic=0 - * Second MMR will be skipped if address is NULL - * - * Addresses passed to these routines should be uncached physical addresses - * ie., 0x80000.... - */ - - -extern long pio_phys_read_mmr(volatile long *mmr); -extern void pio_phys_write_mmr(volatile long *mmr, long val); -extern void pio_atomic_phys_write_mmrs(volatile long *mmr1, long val1, volatile long *mmr2, long val2); - -#endif /* _ASM_IA64_SN_RW_MMR_H */ diff --git a/arch/ia64/include/asm/sn/shub_mmr.h b/arch/ia64/include/asm/sn/shub_mmr.h deleted file mode 100644 index a84d870f42945148773c864163e58a1a95c20587..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/shub_mmr.h +++ /dev/null @@ -1,502 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2001-2005 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_SHUB_MMR_H -#define _ASM_IA64_SN_SHUB_MMR_H - -/* ==================================================================== */ -/* Register "SH_IPI_INT" */ -/* SHub Inter-Processor Interrupt Registers */ -/* ==================================================================== */ -#define SH1_IPI_INT __IA64_UL_CONST(0x0000000110000380) -#define SH2_IPI_INT __IA64_UL_CONST(0x0000000010000380) - -/* SH_IPI_INT_TYPE */ -/* Description: Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT */ -#define SH_IPI_INT_TYPE_SHFT 0 -#define SH_IPI_INT_TYPE_MASK __IA64_UL_CONST(0x0000000000000007) - -/* SH_IPI_INT_AGT */ -/* Description: Agent, must be 0 for SHub */ -#define SH_IPI_INT_AGT_SHFT 3 -#define SH_IPI_INT_AGT_MASK __IA64_UL_CONST(0x0000000000000008) - -/* SH_IPI_INT_PID */ -/* Description: Processor ID, same setting as on targeted McKinley */ -#define SH_IPI_INT_PID_SHFT 4 -#define SH_IPI_INT_PID_MASK __IA64_UL_CONST(0x00000000000ffff0) - -/* SH_IPI_INT_BASE */ -/* Description: Optional interrupt vector area, 2MB aligned */ -#define SH_IPI_INT_BASE_SHFT 21 -#define SH_IPI_INT_BASE_MASK __IA64_UL_CONST(0x0003ffffffe00000) - -/* SH_IPI_INT_IDX */ -/* Description: Targeted McKinley interrupt vector */ -#define SH_IPI_INT_IDX_SHFT 52 -#define SH_IPI_INT_IDX_MASK __IA64_UL_CONST(0x0ff0000000000000) - -/* SH_IPI_INT_SEND */ -/* Description: Send Interrupt Message to PI, This generates a puls */ -#define SH_IPI_INT_SEND_SHFT 63 -#define SH_IPI_INT_SEND_MASK __IA64_UL_CONST(0x8000000000000000) - -/* ==================================================================== */ -/* Register "SH_EVENT_OCCURRED" */ -/* SHub Interrupt Event Occurred */ -/* ==================================================================== */ -#define SH1_EVENT_OCCURRED __IA64_UL_CONST(0x0000000110010000) -#define SH1_EVENT_OCCURRED_ALIAS __IA64_UL_CONST(0x0000000110010008) -#define SH2_EVENT_OCCURRED __IA64_UL_CONST(0x0000000010010000) -#define SH2_EVENT_OCCURRED_ALIAS __IA64_UL_CONST(0x0000000010010008) - -/* ==================================================================== */ -/* Register "SH_PI_CAM_CONTROL" */ -/* CRB CAM MMR Access Control */ -/* ==================================================================== */ -#define SH1_PI_CAM_CONTROL __IA64_UL_CONST(0x0000000120050300) - -/* ==================================================================== */ -/* Register "SH_SHUB_ID" */ -/* SHub ID Number */ -/* ==================================================================== */ -#define SH1_SHUB_ID __IA64_UL_CONST(0x0000000110060580) -#define SH1_SHUB_ID_REVISION_SHFT 28 -#define SH1_SHUB_ID_REVISION_MASK __IA64_UL_CONST(0x00000000f0000000) - -/* ==================================================================== */ -/* Register "SH_RTC" */ -/* Real-time Clock */ -/* ==================================================================== */ -#define SH1_RTC __IA64_UL_CONST(0x00000001101c0000) -#define SH2_RTC __IA64_UL_CONST(0x00000002101c0000) -#define SH_RTC_MASK __IA64_UL_CONST(0x007fffffffffffff) - -/* ==================================================================== */ -/* Register "SH_PIO_WRITE_STATUS_0|1" */ -/* PIO Write Status for CPU 0 & 1 */ -/* ==================================================================== */ -#define SH1_PIO_WRITE_STATUS_0 __IA64_UL_CONST(0x0000000120070200) -#define SH1_PIO_WRITE_STATUS_1 __IA64_UL_CONST(0x0000000120070280) -#define SH2_PIO_WRITE_STATUS_0 __IA64_UL_CONST(0x0000000020070200) -#define SH2_PIO_WRITE_STATUS_1 __IA64_UL_CONST(0x0000000020070280) -#define SH2_PIO_WRITE_STATUS_2 __IA64_UL_CONST(0x0000000020070300) -#define SH2_PIO_WRITE_STATUS_3 __IA64_UL_CONST(0x0000000020070380) - -/* SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK */ -/* Description: Deadlock response detected */ -#define SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT 1 -#define SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK \ - __IA64_UL_CONST(0x0000000000000002) - -/* SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT */ -/* Description: Count of currently pending PIO writes */ -#define SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_SHFT 56 -#define SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK \ - __IA64_UL_CONST(0x3f00000000000000) - -/* ==================================================================== */ -/* Register "SH_PIO_WRITE_STATUS_0_ALIAS" */ -/* ==================================================================== */ -#define SH1_PIO_WRITE_STATUS_0_ALIAS __IA64_UL_CONST(0x0000000120070208) -#define SH2_PIO_WRITE_STATUS_0_ALIAS __IA64_UL_CONST(0x0000000020070208) - -/* ==================================================================== */ -/* Register "SH_EVENT_OCCURRED" */ -/* SHub Interrupt Event Occurred */ -/* ==================================================================== */ -/* SH_EVENT_OCCURRED_UART_INT */ -/* Description: Pending Junk Bus UART Interrupt */ -#define SH_EVENT_OCCURRED_UART_INT_SHFT 20 -#define SH_EVENT_OCCURRED_UART_INT_MASK __IA64_UL_CONST(0x0000000000100000) - -/* SH_EVENT_OCCURRED_IPI_INT */ -/* Description: Pending IPI Interrupt */ -#define SH_EVENT_OCCURRED_IPI_INT_SHFT 28 -#define SH_EVENT_OCCURRED_IPI_INT_MASK __IA64_UL_CONST(0x0000000010000000) - -/* SH_EVENT_OCCURRED_II_INT0 */ -/* Description: Pending II 0 Interrupt */ -#define SH_EVENT_OCCURRED_II_INT0_SHFT 29 -#define SH_EVENT_OCCURRED_II_INT0_MASK __IA64_UL_CONST(0x0000000020000000) - -/* SH_EVENT_OCCURRED_II_INT1 */ -/* Description: Pending II 1 Interrupt */ -#define SH_EVENT_OCCURRED_II_INT1_SHFT 30 -#define SH_EVENT_OCCURRED_II_INT1_MASK __IA64_UL_CONST(0x0000000040000000) - -/* SH2_EVENT_OCCURRED_EXTIO_INT2 */ -/* Description: Pending SHUB 2 EXT IO INT2 */ -#define SH2_EVENT_OCCURRED_EXTIO_INT2_SHFT 33 -#define SH2_EVENT_OCCURRED_EXTIO_INT2_MASK __IA64_UL_CONST(0x0000000200000000) - -/* SH2_EVENT_OCCURRED_EXTIO_INT3 */ -/* Description: Pending SHUB 2 EXT IO INT3 */ -#define SH2_EVENT_OCCURRED_EXTIO_INT3_SHFT 34 -#define SH2_EVENT_OCCURRED_EXTIO_INT3_MASK __IA64_UL_CONST(0x0000000400000000) - -#define SH_ALL_INT_MASK \ - (SH_EVENT_OCCURRED_UART_INT_MASK | SH_EVENT_OCCURRED_IPI_INT_MASK | \ - SH_EVENT_OCCURRED_II_INT0_MASK | SH_EVENT_OCCURRED_II_INT1_MASK | \ - SH_EVENT_OCCURRED_II_INT1_MASK | SH2_EVENT_OCCURRED_EXTIO_INT2_MASK | \ - SH2_EVENT_OCCURRED_EXTIO_INT3_MASK) - - -/* ==================================================================== */ -/* LEDS */ -/* ==================================================================== */ -#define SH1_REAL_JUNK_BUS_LED0 0x7fed00000UL -#define SH1_REAL_JUNK_BUS_LED1 0x7fed10000UL -#define SH1_REAL_JUNK_BUS_LED2 0x7fed20000UL -#define SH1_REAL_JUNK_BUS_LED3 0x7fed30000UL - -#define SH2_REAL_JUNK_BUS_LED0 0xf0000000UL -#define SH2_REAL_JUNK_BUS_LED1 0xf0010000UL -#define SH2_REAL_JUNK_BUS_LED2 0xf0020000UL -#define SH2_REAL_JUNK_BUS_LED3 0xf0030000UL - -/* ==================================================================== */ -/* Register "SH1_PTC_0" */ -/* Puge Translation Cache Message Configuration Information */ -/* ==================================================================== */ -#define SH1_PTC_0 __IA64_UL_CONST(0x00000001101a0000) - -/* SH1_PTC_0_A */ -/* Description: Type */ -#define SH1_PTC_0_A_SHFT 0 - -/* SH1_PTC_0_PS */ -/* Description: Page Size */ -#define SH1_PTC_0_PS_SHFT 2 - -/* SH1_PTC_0_RID */ -/* Description: Region ID */ -#define SH1_PTC_0_RID_SHFT 8 - -/* SH1_PTC_0_START */ -/* Description: Start */ -#define SH1_PTC_0_START_SHFT 63 - -/* ==================================================================== */ -/* Register "SH1_PTC_1" */ -/* Puge Translation Cache Message Configuration Information */ -/* ==================================================================== */ -#define SH1_PTC_1 __IA64_UL_CONST(0x00000001101a0080) - -/* SH1_PTC_1_START */ -/* Description: PTC_1 Start */ -#define SH1_PTC_1_START_SHFT 63 - -/* ==================================================================== */ -/* Register "SH2_PTC" */ -/* Puge Translation Cache Message Configuration Information */ -/* ==================================================================== */ -#define SH2_PTC __IA64_UL_CONST(0x0000000170000000) - -/* SH2_PTC_A */ -/* Description: Type */ -#define SH2_PTC_A_SHFT 0 - -/* SH2_PTC_PS */ -/* Description: Page Size */ -#define SH2_PTC_PS_SHFT 2 - -/* SH2_PTC_RID */ -/* Description: Region ID */ -#define SH2_PTC_RID_SHFT 4 - -/* SH2_PTC_START */ -/* Description: Start */ -#define SH2_PTC_START_SHFT 63 - -/* SH2_PTC_ADDR_RID */ -/* Description: Region ID */ -#define SH2_PTC_ADDR_SHFT 4 -#define SH2_PTC_ADDR_MASK __IA64_UL_CONST(0x1ffffffffffff000) - -/* ==================================================================== */ -/* Register "SH_RTC1_INT_CONFIG" */ -/* SHub RTC 1 Interrupt Config Registers */ -/* ==================================================================== */ - -#define SH1_RTC1_INT_CONFIG __IA64_UL_CONST(0x0000000110001480) -#define SH2_RTC1_INT_CONFIG __IA64_UL_CONST(0x0000000010001480) -#define SH_RTC1_INT_CONFIG_MASK __IA64_UL_CONST(0x0ff3ffffffefffff) -#define SH_RTC1_INT_CONFIG_INIT __IA64_UL_CONST(0x0000000000000000) - -/* SH_RTC1_INT_CONFIG_TYPE */ -/* Description: Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT */ -#define SH_RTC1_INT_CONFIG_TYPE_SHFT 0 -#define SH_RTC1_INT_CONFIG_TYPE_MASK __IA64_UL_CONST(0x0000000000000007) - -/* SH_RTC1_INT_CONFIG_AGT */ -/* Description: Agent, must be 0 for SHub */ -#define SH_RTC1_INT_CONFIG_AGT_SHFT 3 -#define SH_RTC1_INT_CONFIG_AGT_MASK __IA64_UL_CONST(0x0000000000000008) - -/* SH_RTC1_INT_CONFIG_PID */ -/* Description: Processor ID, same setting as on targeted McKinley */ -#define SH_RTC1_INT_CONFIG_PID_SHFT 4 -#define SH_RTC1_INT_CONFIG_PID_MASK __IA64_UL_CONST(0x00000000000ffff0) - -/* SH_RTC1_INT_CONFIG_BASE */ -/* Description: Optional interrupt vector area, 2MB aligned */ -#define SH_RTC1_INT_CONFIG_BASE_SHFT 21 -#define SH_RTC1_INT_CONFIG_BASE_MASK __IA64_UL_CONST(0x0003ffffffe00000) - -/* SH_RTC1_INT_CONFIG_IDX */ -/* Description: Targeted McKinley interrupt vector */ -#define SH_RTC1_INT_CONFIG_IDX_SHFT 52 -#define SH_RTC1_INT_CONFIG_IDX_MASK __IA64_UL_CONST(0x0ff0000000000000) - -/* ==================================================================== */ -/* Register "SH_RTC1_INT_ENABLE" */ -/* SHub RTC 1 Interrupt Enable Registers */ -/* ==================================================================== */ - -#define SH1_RTC1_INT_ENABLE __IA64_UL_CONST(0x0000000110001500) -#define SH2_RTC1_INT_ENABLE __IA64_UL_CONST(0x0000000010001500) -#define SH_RTC1_INT_ENABLE_MASK __IA64_UL_CONST(0x0000000000000001) -#define SH_RTC1_INT_ENABLE_INIT __IA64_UL_CONST(0x0000000000000000) - -/* SH_RTC1_INT_ENABLE_RTC1_ENABLE */ -/* Description: Enable RTC 1 Interrupt */ -#define SH_RTC1_INT_ENABLE_RTC1_ENABLE_SHFT 0 -#define SH_RTC1_INT_ENABLE_RTC1_ENABLE_MASK \ - __IA64_UL_CONST(0x0000000000000001) - -/* ==================================================================== */ -/* Register "SH_RTC2_INT_CONFIG" */ -/* SHub RTC 2 Interrupt Config Registers */ -/* ==================================================================== */ - -#define SH1_RTC2_INT_CONFIG __IA64_UL_CONST(0x0000000110001580) -#define SH2_RTC2_INT_CONFIG __IA64_UL_CONST(0x0000000010001580) -#define SH_RTC2_INT_CONFIG_MASK __IA64_UL_CONST(0x0ff3ffffffefffff) -#define SH_RTC2_INT_CONFIG_INIT __IA64_UL_CONST(0x0000000000000000) - -/* SH_RTC2_INT_CONFIG_TYPE */ -/* Description: Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT */ -#define SH_RTC2_INT_CONFIG_TYPE_SHFT 0 -#define SH_RTC2_INT_CONFIG_TYPE_MASK __IA64_UL_CONST(0x0000000000000007) - -/* SH_RTC2_INT_CONFIG_AGT */ -/* Description: Agent, must be 0 for SHub */ -#define SH_RTC2_INT_CONFIG_AGT_SHFT 3 -#define SH_RTC2_INT_CONFIG_AGT_MASK __IA64_UL_CONST(0x0000000000000008) - -/* SH_RTC2_INT_CONFIG_PID */ -/* Description: Processor ID, same setting as on targeted McKinley */ -#define SH_RTC2_INT_CONFIG_PID_SHFT 4 -#define SH_RTC2_INT_CONFIG_PID_MASK __IA64_UL_CONST(0x00000000000ffff0) - -/* SH_RTC2_INT_CONFIG_BASE */ -/* Description: Optional interrupt vector area, 2MB aligned */ -#define SH_RTC2_INT_CONFIG_BASE_SHFT 21 -#define SH_RTC2_INT_CONFIG_BASE_MASK __IA64_UL_CONST(0x0003ffffffe00000) - -/* SH_RTC2_INT_CONFIG_IDX */ -/* Description: Targeted McKinley interrupt vector */ -#define SH_RTC2_INT_CONFIG_IDX_SHFT 52 -#define SH_RTC2_INT_CONFIG_IDX_MASK __IA64_UL_CONST(0x0ff0000000000000) - -/* ==================================================================== */ -/* Register "SH_RTC2_INT_ENABLE" */ -/* SHub RTC 2 Interrupt Enable Registers */ -/* ==================================================================== */ - -#define SH1_RTC2_INT_ENABLE __IA64_UL_CONST(0x0000000110001600) -#define SH2_RTC2_INT_ENABLE __IA64_UL_CONST(0x0000000010001600) -#define SH_RTC2_INT_ENABLE_MASK __IA64_UL_CONST(0x0000000000000001) -#define SH_RTC2_INT_ENABLE_INIT __IA64_UL_CONST(0x0000000000000000) - -/* SH_RTC2_INT_ENABLE_RTC2_ENABLE */ -/* Description: Enable RTC 2 Interrupt */ -#define SH_RTC2_INT_ENABLE_RTC2_ENABLE_SHFT 0 -#define SH_RTC2_INT_ENABLE_RTC2_ENABLE_MASK \ - __IA64_UL_CONST(0x0000000000000001) - -/* ==================================================================== */ -/* Register "SH_RTC3_INT_CONFIG" */ -/* SHub RTC 3 Interrupt Config Registers */ -/* ==================================================================== */ - -#define SH1_RTC3_INT_CONFIG __IA64_UL_CONST(0x0000000110001680) -#define SH2_RTC3_INT_CONFIG __IA64_UL_CONST(0x0000000010001680) -#define SH_RTC3_INT_CONFIG_MASK __IA64_UL_CONST(0x0ff3ffffffefffff) -#define SH_RTC3_INT_CONFIG_INIT __IA64_UL_CONST(0x0000000000000000) - -/* SH_RTC3_INT_CONFIG_TYPE */ -/* Description: Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT */ -#define SH_RTC3_INT_CONFIG_TYPE_SHFT 0 -#define SH_RTC3_INT_CONFIG_TYPE_MASK __IA64_UL_CONST(0x0000000000000007) - -/* SH_RTC3_INT_CONFIG_AGT */ -/* Description: Agent, must be 0 for SHub */ -#define SH_RTC3_INT_CONFIG_AGT_SHFT 3 -#define SH_RTC3_INT_CONFIG_AGT_MASK __IA64_UL_CONST(0x0000000000000008) - -/* SH_RTC3_INT_CONFIG_PID */ -/* Description: Processor ID, same setting as on targeted McKinley */ -#define SH_RTC3_INT_CONFIG_PID_SHFT 4 -#define SH_RTC3_INT_CONFIG_PID_MASK __IA64_UL_CONST(0x00000000000ffff0) - -/* SH_RTC3_INT_CONFIG_BASE */ -/* Description: Optional interrupt vector area, 2MB aligned */ -#define SH_RTC3_INT_CONFIG_BASE_SHFT 21 -#define SH_RTC3_INT_CONFIG_BASE_MASK __IA64_UL_CONST(0x0003ffffffe00000) - -/* SH_RTC3_INT_CONFIG_IDX */ -/* Description: Targeted McKinley interrupt vector */ -#define SH_RTC3_INT_CONFIG_IDX_SHFT 52 -#define SH_RTC3_INT_CONFIG_IDX_MASK __IA64_UL_CONST(0x0ff0000000000000) - -/* ==================================================================== */ -/* Register "SH_RTC3_INT_ENABLE" */ -/* SHub RTC 3 Interrupt Enable Registers */ -/* ==================================================================== */ - -#define SH1_RTC3_INT_ENABLE __IA64_UL_CONST(0x0000000110001700) -#define SH2_RTC3_INT_ENABLE __IA64_UL_CONST(0x0000000010001700) -#define SH_RTC3_INT_ENABLE_MASK __IA64_UL_CONST(0x0000000000000001) -#define SH_RTC3_INT_ENABLE_INIT __IA64_UL_CONST(0x0000000000000000) - -/* SH_RTC3_INT_ENABLE_RTC3_ENABLE */ -/* Description: Enable RTC 3 Interrupt */ -#define SH_RTC3_INT_ENABLE_RTC3_ENABLE_SHFT 0 -#define SH_RTC3_INT_ENABLE_RTC3_ENABLE_MASK \ - __IA64_UL_CONST(0x0000000000000001) - -/* SH_EVENT_OCCURRED_RTC1_INT */ -/* Description: Pending RTC 1 Interrupt */ -#define SH_EVENT_OCCURRED_RTC1_INT_SHFT 24 -#define SH_EVENT_OCCURRED_RTC1_INT_MASK __IA64_UL_CONST(0x0000000001000000) - -/* SH_EVENT_OCCURRED_RTC2_INT */ -/* Description: Pending RTC 2 Interrupt */ -#define SH_EVENT_OCCURRED_RTC2_INT_SHFT 25 -#define SH_EVENT_OCCURRED_RTC2_INT_MASK __IA64_UL_CONST(0x0000000002000000) - -/* SH_EVENT_OCCURRED_RTC3_INT */ -/* Description: Pending RTC 3 Interrupt */ -#define SH_EVENT_OCCURRED_RTC3_INT_SHFT 26 -#define SH_EVENT_OCCURRED_RTC3_INT_MASK __IA64_UL_CONST(0x0000000004000000) - -/* ==================================================================== */ -/* Register "SH_IPI_ACCESS" */ -/* CPU interrupt Access Permission Bits */ -/* ==================================================================== */ - -#define SH1_IPI_ACCESS __IA64_UL_CONST(0x0000000110060480) -#define SH2_IPI_ACCESS0 __IA64_UL_CONST(0x0000000010060c00) -#define SH2_IPI_ACCESS1 __IA64_UL_CONST(0x0000000010060c80) -#define SH2_IPI_ACCESS2 __IA64_UL_CONST(0x0000000010060d00) -#define SH2_IPI_ACCESS3 __IA64_UL_CONST(0x0000000010060d80) - -/* ==================================================================== */ -/* Register "SH_INT_CMPB" */ -/* RTC Compare Value for Processor B */ -/* ==================================================================== */ - -#define SH1_INT_CMPB __IA64_UL_CONST(0x00000001101b0080) -#define SH2_INT_CMPB __IA64_UL_CONST(0x00000000101b0080) -#define SH_INT_CMPB_MASK __IA64_UL_CONST(0x007fffffffffffff) -#define SH_INT_CMPB_INIT __IA64_UL_CONST(0x0000000000000000) - -/* SH_INT_CMPB_REAL_TIME_CMPB */ -/* Description: Real Time Clock Compare */ -#define SH_INT_CMPB_REAL_TIME_CMPB_SHFT 0 -#define SH_INT_CMPB_REAL_TIME_CMPB_MASK __IA64_UL_CONST(0x007fffffffffffff) - -/* ==================================================================== */ -/* Register "SH_INT_CMPC" */ -/* RTC Compare Value for Processor C */ -/* ==================================================================== */ - -#define SH1_INT_CMPC __IA64_UL_CONST(0x00000001101b0100) -#define SH2_INT_CMPC __IA64_UL_CONST(0x00000000101b0100) -#define SH_INT_CMPC_MASK __IA64_UL_CONST(0x007fffffffffffff) -#define SH_INT_CMPC_INIT __IA64_UL_CONST(0x0000000000000000) - -/* SH_INT_CMPC_REAL_TIME_CMPC */ -/* Description: Real Time Clock Compare */ -#define SH_INT_CMPC_REAL_TIME_CMPC_SHFT 0 -#define SH_INT_CMPC_REAL_TIME_CMPC_MASK __IA64_UL_CONST(0x007fffffffffffff) - -/* ==================================================================== */ -/* Register "SH_INT_CMPD" */ -/* RTC Compare Value for Processor D */ -/* ==================================================================== */ - -#define SH1_INT_CMPD __IA64_UL_CONST(0x00000001101b0180) -#define SH2_INT_CMPD __IA64_UL_CONST(0x00000000101b0180) -#define SH_INT_CMPD_MASK __IA64_UL_CONST(0x007fffffffffffff) -#define SH_INT_CMPD_INIT __IA64_UL_CONST(0x0000000000000000) - -/* SH_INT_CMPD_REAL_TIME_CMPD */ -/* Description: Real Time Clock Compare */ -#define SH_INT_CMPD_REAL_TIME_CMPD_SHFT 0 -#define SH_INT_CMPD_REAL_TIME_CMPD_MASK __IA64_UL_CONST(0x007fffffffffffff) - -/* ==================================================================== */ -/* Register "SH_MD_DQLP_MMR_DIR_PRIVEC0" */ -/* privilege vector for acc=0 */ -/* ==================================================================== */ -#define SH1_MD_DQLP_MMR_DIR_PRIVEC0 __IA64_UL_CONST(0x0000000100030300) - -/* ==================================================================== */ -/* Register "SH_MD_DQRP_MMR_DIR_PRIVEC0" */ -/* privilege vector for acc=0 */ -/* ==================================================================== */ -#define SH1_MD_DQRP_MMR_DIR_PRIVEC0 __IA64_UL_CONST(0x0000000100050300) - -/* ==================================================================== */ -/* Some MMRs are functionally identical (or close enough) on both SHUB1 */ -/* and SHUB2 that it makes sense to define a geberic name for the MMR. */ -/* It is acceptable to use (for example) SH_IPI_INT to reference the */ -/* the IPI MMR. The value of SH_IPI_INT is determined at runtime based */ -/* on the type of the SHUB. Do not use these #defines in performance */ -/* critical code or loops - there is a small performance penalty. */ -/* ==================================================================== */ -#define shubmmr(a,b) (is_shub2() ? a##2_##b : a##1_##b) - -#define SH_REAL_JUNK_BUS_LED0 shubmmr(SH, REAL_JUNK_BUS_LED0) -#define SH_IPI_INT shubmmr(SH, IPI_INT) -#define SH_EVENT_OCCURRED shubmmr(SH, EVENT_OCCURRED) -#define SH_EVENT_OCCURRED_ALIAS shubmmr(SH, EVENT_OCCURRED_ALIAS) -#define SH_RTC shubmmr(SH, RTC) -#define SH_RTC1_INT_CONFIG shubmmr(SH, RTC1_INT_CONFIG) -#define SH_RTC1_INT_ENABLE shubmmr(SH, RTC1_INT_ENABLE) -#define SH_RTC2_INT_CONFIG shubmmr(SH, RTC2_INT_CONFIG) -#define SH_RTC2_INT_ENABLE shubmmr(SH, RTC2_INT_ENABLE) -#define SH_RTC3_INT_CONFIG shubmmr(SH, RTC3_INT_CONFIG) -#define SH_RTC3_INT_ENABLE shubmmr(SH, RTC3_INT_ENABLE) -#define SH_INT_CMPB shubmmr(SH, INT_CMPB) -#define SH_INT_CMPC shubmmr(SH, INT_CMPC) -#define SH_INT_CMPD shubmmr(SH, INT_CMPD) - -/* ========================================================================== */ -/* Register "SH2_BT_ENG_CSR_0" */ -/* Engine 0 Control and Status Register */ -/* ========================================================================== */ - -#define SH2_BT_ENG_CSR_0 __IA64_UL_CONST(0x0000000030040000) -#define SH2_BT_ENG_SRC_ADDR_0 __IA64_UL_CONST(0x0000000030040080) -#define SH2_BT_ENG_DEST_ADDR_0 __IA64_UL_CONST(0x0000000030040100) -#define SH2_BT_ENG_NOTIF_ADDR_0 __IA64_UL_CONST(0x0000000030040180) - -/* ========================================================================== */ -/* BTE interfaces 1-3 */ -/* ========================================================================== */ - -#define SH2_BT_ENG_CSR_1 __IA64_UL_CONST(0x0000000030050000) -#define SH2_BT_ENG_CSR_2 __IA64_UL_CONST(0x0000000030060000) -#define SH2_BT_ENG_CSR_3 __IA64_UL_CONST(0x0000000030070000) - -#endif /* _ASM_IA64_SN_SHUB_MMR_H */ diff --git a/arch/ia64/include/asm/sn/shubio.h b/arch/ia64/include/asm/sn/shubio.h deleted file mode 100644 index 8a1ec139f977cd9c5237d0a897158ed215659d20..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/shubio.h +++ /dev/null @@ -1,3358 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_SHUBIO_H -#define _ASM_IA64_SN_SHUBIO_H - -#define HUB_WIDGET_ID_MAX 0xf -#define IIO_NUM_ITTES 7 -#define HUB_NUM_BIG_WINDOW (IIO_NUM_ITTES - 1) - -#define IIO_WID 0x00400000 /* Crosstalk Widget Identification */ - /* This register is also accessible from - * Crosstalk at address 0x0. */ -#define IIO_WSTAT 0x00400008 /* Crosstalk Widget Status */ -#define IIO_WCR 0x00400020 /* Crosstalk Widget Control Register */ -#define IIO_ILAPR 0x00400100 /* IO Local Access Protection Register */ -#define IIO_ILAPO 0x00400108 /* IO Local Access Protection Override */ -#define IIO_IOWA 0x00400110 /* IO Outbound Widget Access */ -#define IIO_IIWA 0x00400118 /* IO Inbound Widget Access */ -#define IIO_IIDEM 0x00400120 /* IO Inbound Device Error Mask */ -#define IIO_ILCSR 0x00400128 /* IO LLP Control and Status Register */ -#define IIO_ILLR 0x00400130 /* IO LLP Log Register */ -#define IIO_IIDSR 0x00400138 /* IO Interrupt Destination */ - -#define IIO_IGFX0 0x00400140 /* IO Graphics Node-Widget Map 0 */ -#define IIO_IGFX1 0x00400148 /* IO Graphics Node-Widget Map 1 */ - -#define IIO_ISCR0 0x00400150 /* IO Scratch Register 0 */ -#define IIO_ISCR1 0x00400158 /* IO Scratch Register 1 */ - -#define IIO_ITTE1 0x00400160 /* IO Translation Table Entry 1 */ -#define IIO_ITTE2 0x00400168 /* IO Translation Table Entry 2 */ -#define IIO_ITTE3 0x00400170 /* IO Translation Table Entry 3 */ -#define IIO_ITTE4 0x00400178 /* IO Translation Table Entry 4 */ -#define IIO_ITTE5 0x00400180 /* IO Translation Table Entry 5 */ -#define IIO_ITTE6 0x00400188 /* IO Translation Table Entry 6 */ -#define IIO_ITTE7 0x00400190 /* IO Translation Table Entry 7 */ - -#define IIO_IPRB0 0x00400198 /* IO PRB Entry 0 */ -#define IIO_IPRB8 0x004001A0 /* IO PRB Entry 8 */ -#define IIO_IPRB9 0x004001A8 /* IO PRB Entry 9 */ -#define IIO_IPRBA 0x004001B0 /* IO PRB Entry A */ -#define IIO_IPRBB 0x004001B8 /* IO PRB Entry B */ -#define IIO_IPRBC 0x004001C0 /* IO PRB Entry C */ -#define IIO_IPRBD 0x004001C8 /* IO PRB Entry D */ -#define IIO_IPRBE 0x004001D0 /* IO PRB Entry E */ -#define IIO_IPRBF 0x004001D8 /* IO PRB Entry F */ - -#define IIO_IXCC 0x004001E0 /* IO Crosstalk Credit Count Timeout */ -#define IIO_IMEM 0x004001E8 /* IO Miscellaneous Error Mask */ -#define IIO_IXTT 0x004001F0 /* IO Crosstalk Timeout Threshold */ -#define IIO_IECLR 0x004001F8 /* IO Error Clear Register */ -#define IIO_IBCR 0x00400200 /* IO BTE Control Register */ - -#define IIO_IXSM 0x00400208 /* IO Crosstalk Spurious Message */ -#define IIO_IXSS 0x00400210 /* IO Crosstalk Spurious Sideband */ - -#define IIO_ILCT 0x00400218 /* IO LLP Channel Test */ - -#define IIO_IIEPH1 0x00400220 /* IO Incoming Error Packet Header, Part 1 */ -#define IIO_IIEPH2 0x00400228 /* IO Incoming Error Packet Header, Part 2 */ - -#define IIO_ISLAPR 0x00400230 /* IO SXB Local Access Protection Regster */ -#define IIO_ISLAPO 0x00400238 /* IO SXB Local Access Protection Override */ - -#define IIO_IWI 0x00400240 /* IO Wrapper Interrupt Register */ -#define IIO_IWEL 0x00400248 /* IO Wrapper Error Log Register */ -#define IIO_IWC 0x00400250 /* IO Wrapper Control Register */ -#define IIO_IWS 0x00400258 /* IO Wrapper Status Register */ -#define IIO_IWEIM 0x00400260 /* IO Wrapper Error Interrupt Masking Register */ - -#define IIO_IPCA 0x00400300 /* IO PRB Counter Adjust */ - -#define IIO_IPRTE0_A 0x00400308 /* IO PIO Read Address Table Entry 0, Part A */ -#define IIO_IPRTE1_A 0x00400310 /* IO PIO Read Address Table Entry 1, Part A */ -#define IIO_IPRTE2_A 0x00400318 /* IO PIO Read Address Table Entry 2, Part A */ -#define IIO_IPRTE3_A 0x00400320 /* IO PIO Read Address Table Entry 3, Part A */ -#define IIO_IPRTE4_A 0x00400328 /* IO PIO Read Address Table Entry 4, Part A */ -#define IIO_IPRTE5_A 0x00400330 /* IO PIO Read Address Table Entry 5, Part A */ -#define IIO_IPRTE6_A 0x00400338 /* IO PIO Read Address Table Entry 6, Part A */ -#define IIO_IPRTE7_A 0x00400340 /* IO PIO Read Address Table Entry 7, Part A */ - -#define IIO_IPRTE0_B 0x00400348 /* IO PIO Read Address Table Entry 0, Part B */ -#define IIO_IPRTE1_B 0x00400350 /* IO PIO Read Address Table Entry 1, Part B */ -#define IIO_IPRTE2_B 0x00400358 /* IO PIO Read Address Table Entry 2, Part B */ -#define IIO_IPRTE3_B 0x00400360 /* IO PIO Read Address Table Entry 3, Part B */ -#define IIO_IPRTE4_B 0x00400368 /* IO PIO Read Address Table Entry 4, Part B */ -#define IIO_IPRTE5_B 0x00400370 /* IO PIO Read Address Table Entry 5, Part B */ -#define IIO_IPRTE6_B 0x00400378 /* IO PIO Read Address Table Entry 6, Part B */ -#define IIO_IPRTE7_B 0x00400380 /* IO PIO Read Address Table Entry 7, Part B */ - -#define IIO_IPDR 0x00400388 /* IO PIO Deallocation Register */ -#define IIO_ICDR 0x00400390 /* IO CRB Entry Deallocation Register */ -#define IIO_IFDR 0x00400398 /* IO IOQ FIFO Depth Register */ -#define IIO_IIAP 0x004003A0 /* IO IIQ Arbitration Parameters */ -#define IIO_ICMR 0x004003A8 /* IO CRB Management Register */ -#define IIO_ICCR 0x004003B0 /* IO CRB Control Register */ -#define IIO_ICTO 0x004003B8 /* IO CRB Timeout */ -#define IIO_ICTP 0x004003C0 /* IO CRB Timeout Prescalar */ - -#define IIO_ICRB0_A 0x00400400 /* IO CRB Entry 0_A */ -#define IIO_ICRB0_B 0x00400408 /* IO CRB Entry 0_B */ -#define IIO_ICRB0_C 0x00400410 /* IO CRB Entry 0_C */ -#define IIO_ICRB0_D 0x00400418 /* IO CRB Entry 0_D */ -#define IIO_ICRB0_E 0x00400420 /* IO CRB Entry 0_E */ - -#define IIO_ICRB1_A 0x00400430 /* IO CRB Entry 1_A */ -#define IIO_ICRB1_B 0x00400438 /* IO CRB Entry 1_B */ -#define IIO_ICRB1_C 0x00400440 /* IO CRB Entry 1_C */ -#define IIO_ICRB1_D 0x00400448 /* IO CRB Entry 1_D */ -#define IIO_ICRB1_E 0x00400450 /* IO CRB Entry 1_E */ - -#define IIO_ICRB2_A 0x00400460 /* IO CRB Entry 2_A */ -#define IIO_ICRB2_B 0x00400468 /* IO CRB Entry 2_B */ -#define IIO_ICRB2_C 0x00400470 /* IO CRB Entry 2_C */ -#define IIO_ICRB2_D 0x00400478 /* IO CRB Entry 2_D */ -#define IIO_ICRB2_E 0x00400480 /* IO CRB Entry 2_E */ - -#define IIO_ICRB3_A 0x00400490 /* IO CRB Entry 3_A */ -#define IIO_ICRB3_B 0x00400498 /* IO CRB Entry 3_B */ -#define IIO_ICRB3_C 0x004004a0 /* IO CRB Entry 3_C */ -#define IIO_ICRB3_D 0x004004a8 /* IO CRB Entry 3_D */ -#define IIO_ICRB3_E 0x004004b0 /* IO CRB Entry 3_E */ - -#define IIO_ICRB4_A 0x004004c0 /* IO CRB Entry 4_A */ -#define IIO_ICRB4_B 0x004004c8 /* IO CRB Entry 4_B */ -#define IIO_ICRB4_C 0x004004d0 /* IO CRB Entry 4_C */ -#define IIO_ICRB4_D 0x004004d8 /* IO CRB Entry 4_D */ -#define IIO_ICRB4_E 0x004004e0 /* IO CRB Entry 4_E */ - -#define IIO_ICRB5_A 0x004004f0 /* IO CRB Entry 5_A */ -#define IIO_ICRB5_B 0x004004f8 /* IO CRB Entry 5_B */ -#define IIO_ICRB5_C 0x00400500 /* IO CRB Entry 5_C */ -#define IIO_ICRB5_D 0x00400508 /* IO CRB Entry 5_D */ -#define IIO_ICRB5_E 0x00400510 /* IO CRB Entry 5_E */ - -#define IIO_ICRB6_A 0x00400520 /* IO CRB Entry 6_A */ -#define IIO_ICRB6_B 0x00400528 /* IO CRB Entry 6_B */ -#define IIO_ICRB6_C 0x00400530 /* IO CRB Entry 6_C */ -#define IIO_ICRB6_D 0x00400538 /* IO CRB Entry 6_D */ -#define IIO_ICRB6_E 0x00400540 /* IO CRB Entry 6_E */ - -#define IIO_ICRB7_A 0x00400550 /* IO CRB Entry 7_A */ -#define IIO_ICRB7_B 0x00400558 /* IO CRB Entry 7_B */ -#define IIO_ICRB7_C 0x00400560 /* IO CRB Entry 7_C */ -#define IIO_ICRB7_D 0x00400568 /* IO CRB Entry 7_D */ -#define IIO_ICRB7_E 0x00400570 /* IO CRB Entry 7_E */ - -#define IIO_ICRB8_A 0x00400580 /* IO CRB Entry 8_A */ -#define IIO_ICRB8_B 0x00400588 /* IO CRB Entry 8_B */ -#define IIO_ICRB8_C 0x00400590 /* IO CRB Entry 8_C */ -#define IIO_ICRB8_D 0x00400598 /* IO CRB Entry 8_D */ -#define IIO_ICRB8_E 0x004005a0 /* IO CRB Entry 8_E */ - -#define IIO_ICRB9_A 0x004005b0 /* IO CRB Entry 9_A */ -#define IIO_ICRB9_B 0x004005b8 /* IO CRB Entry 9_B */ -#define IIO_ICRB9_C 0x004005c0 /* IO CRB Entry 9_C */ -#define IIO_ICRB9_D 0x004005c8 /* IO CRB Entry 9_D */ -#define IIO_ICRB9_E 0x004005d0 /* IO CRB Entry 9_E */ - -#define IIO_ICRBA_A 0x004005e0 /* IO CRB Entry A_A */ -#define IIO_ICRBA_B 0x004005e8 /* IO CRB Entry A_B */ -#define IIO_ICRBA_C 0x004005f0 /* IO CRB Entry A_C */ -#define IIO_ICRBA_D 0x004005f8 /* IO CRB Entry A_D */ -#define IIO_ICRBA_E 0x00400600 /* IO CRB Entry A_E */ - -#define IIO_ICRBB_A 0x00400610 /* IO CRB Entry B_A */ -#define IIO_ICRBB_B 0x00400618 /* IO CRB Entry B_B */ -#define IIO_ICRBB_C 0x00400620 /* IO CRB Entry B_C */ -#define IIO_ICRBB_D 0x00400628 /* IO CRB Entry B_D */ -#define IIO_ICRBB_E 0x00400630 /* IO CRB Entry B_E */ - -#define IIO_ICRBC_A 0x00400640 /* IO CRB Entry C_A */ -#define IIO_ICRBC_B 0x00400648 /* IO CRB Entry C_B */ -#define IIO_ICRBC_C 0x00400650 /* IO CRB Entry C_C */ -#define IIO_ICRBC_D 0x00400658 /* IO CRB Entry C_D */ -#define IIO_ICRBC_E 0x00400660 /* IO CRB Entry C_E */ - -#define IIO_ICRBD_A 0x00400670 /* IO CRB Entry D_A */ -#define IIO_ICRBD_B 0x00400678 /* IO CRB Entry D_B */ -#define IIO_ICRBD_C 0x00400680 /* IO CRB Entry D_C */ -#define IIO_ICRBD_D 0x00400688 /* IO CRB Entry D_D */ -#define IIO_ICRBD_E 0x00400690 /* IO CRB Entry D_E */ - -#define IIO_ICRBE_A 0x004006a0 /* IO CRB Entry E_A */ -#define IIO_ICRBE_B 0x004006a8 /* IO CRB Entry E_B */ -#define IIO_ICRBE_C 0x004006b0 /* IO CRB Entry E_C */ -#define IIO_ICRBE_D 0x004006b8 /* IO CRB Entry E_D */ -#define IIO_ICRBE_E 0x004006c0 /* IO CRB Entry E_E */ - -#define IIO_ICSML 0x00400700 /* IO CRB Spurious Message Low */ -#define IIO_ICSMM 0x00400708 /* IO CRB Spurious Message Middle */ -#define IIO_ICSMH 0x00400710 /* IO CRB Spurious Message High */ - -#define IIO_IDBSS 0x00400718 /* IO Debug Submenu Select */ - -#define IIO_IBLS0 0x00410000 /* IO BTE Length Status 0 */ -#define IIO_IBSA0 0x00410008 /* IO BTE Source Address 0 */ -#define IIO_IBDA0 0x00410010 /* IO BTE Destination Address 0 */ -#define IIO_IBCT0 0x00410018 /* IO BTE Control Terminate 0 */ -#define IIO_IBNA0 0x00410020 /* IO BTE Notification Address 0 */ -#define IIO_IBIA0 0x00410028 /* IO BTE Interrupt Address 0 */ -#define IIO_IBLS1 0x00420000 /* IO BTE Length Status 1 */ -#define IIO_IBSA1 0x00420008 /* IO BTE Source Address 1 */ -#define IIO_IBDA1 0x00420010 /* IO BTE Destination Address 1 */ -#define IIO_IBCT1 0x00420018 /* IO BTE Control Terminate 1 */ -#define IIO_IBNA1 0x00420020 /* IO BTE Notification Address 1 */ -#define IIO_IBIA1 0x00420028 /* IO BTE Interrupt Address 1 */ - -#define IIO_IPCR 0x00430000 /* IO Performance Control */ -#define IIO_IPPR 0x00430008 /* IO Performance Profiling */ - -/************************************************************************ - * * - * Description: This register echoes some information from the * - * LB_REV_ID register. It is available through Crosstalk as described * - * above. The REV_NUM and MFG_NUM fields receive their values from * - * the REVISION and MANUFACTURER fields in the LB_REV_ID register. * - * The PART_NUM field's value is the Crosstalk device ID number that * - * Steve Miller assigned to the SHub chip. * - * * - ************************************************************************/ - -typedef union ii_wid_u { - u64 ii_wid_regval; - struct { - u64 w_rsvd_1:1; - u64 w_mfg_num:11; - u64 w_part_num:16; - u64 w_rev_num:4; - u64 w_rsvd:32; - } ii_wid_fld_s; -} ii_wid_u_t; - -/************************************************************************ - * * - * The fields in this register are set upon detection of an error * - * and cleared by various mechanisms, as explained in the * - * description. * - * * - ************************************************************************/ - -typedef union ii_wstat_u { - u64 ii_wstat_regval; - struct { - u64 w_pending:4; - u64 w_xt_crd_to:1; - u64 w_xt_tail_to:1; - u64 w_rsvd_3:3; - u64 w_tx_mx_rty:1; - u64 w_rsvd_2:6; - u64 w_llp_tx_cnt:8; - u64 w_rsvd_1:8; - u64 w_crazy:1; - u64 w_rsvd:31; - } ii_wstat_fld_s; -} ii_wstat_u_t; - -/************************************************************************ - * * - * Description: This is a read-write enabled register. It controls * - * various aspects of the Crosstalk flow control. * - * * - ************************************************************************/ - -typedef union ii_wcr_u { - u64 ii_wcr_regval; - struct { - u64 w_wid:4; - u64 w_tag:1; - u64 w_rsvd_1:8; - u64 w_dst_crd:3; - u64 w_f_bad_pkt:1; - u64 w_dir_con:1; - u64 w_e_thresh:5; - u64 w_rsvd:41; - } ii_wcr_fld_s; -} ii_wcr_u_t; - -/************************************************************************ - * * - * Description: This register's value is a bit vector that guards * - * access to local registers within the II as well as to external * - * Crosstalk widgets. Each bit in the register corresponds to a * - * particular region in the system; a region consists of one, two or * - * four nodes (depending on the value of the REGION_SIZE field in the * - * LB_REV_ID register, which is documented in Section 8.3.1.1). The * - * protection provided by this register applies to PIO read * - * operations as well as PIO write operations. The II will perform a * - * PIO read or write request only if the bit for the requestor's * - * region is set; otherwise, the II will not perform the requested * - * operation and will return an error response. When a PIO read or * - * write request targets an external Crosstalk widget, then not only * - * must the bit for the requestor's region be set in the ILAPR, but * - * also the target widget's bit in the IOWA register must be set in * - * order for the II to perform the requested operation; otherwise, * - * the II will return an error response. Hence, the protection * - * provided by the IOWA register supplements the protection provided * - * by the ILAPR for requests that target external Crosstalk widgets. * - * This register itself can be accessed only by the nodes whose * - * region ID bits are enabled in this same register. It can also be * - * accessed through the IAlias space by the local processors. * - * The reset value of this register allows access by all nodes. * - * * - ************************************************************************/ - -typedef union ii_ilapr_u { - u64 ii_ilapr_regval; - struct { - u64 i_region:64; - } ii_ilapr_fld_s; -} ii_ilapr_u_t; - -/************************************************************************ - * * - * Description: A write to this register of the 64-bit value * - * "SGIrules" in ASCII, will cause the bit in the ILAPR register * - * corresponding to the region of the requestor to be set (allow * - * access). A write of any other value will be ignored. Access * - * protection for this register is "SGIrules". * - * This register can also be accessed through the IAlias space. * - * However, this access will not change the access permissions in the * - * ILAPR. * - * * - ************************************************************************/ - -typedef union ii_ilapo_u { - u64 ii_ilapo_regval; - struct { - u64 i_io_ovrride:64; - } ii_ilapo_fld_s; -} ii_ilapo_u_t; - -/************************************************************************ - * * - * This register qualifies all the PIO and Graphics writes launched * - * from the SHUB towards a widget. * - * * - ************************************************************************/ - -typedef union ii_iowa_u { - u64 ii_iowa_regval; - struct { - u64 i_w0_oac:1; - u64 i_rsvd_1:7; - u64 i_wx_oac:8; - u64 i_rsvd:48; - } ii_iowa_fld_s; -} ii_iowa_u_t; - -/************************************************************************ - * * - * Description: This register qualifies all the requests launched * - * from a widget towards the Shub. This register is intended to be * - * used by software in case of misbehaving widgets. * - * * - * * - ************************************************************************/ - -typedef union ii_iiwa_u { - u64 ii_iiwa_regval; - struct { - u64 i_w0_iac:1; - u64 i_rsvd_1:7; - u64 i_wx_iac:8; - u64 i_rsvd:48; - } ii_iiwa_fld_s; -} ii_iiwa_u_t; - -/************************************************************************ - * * - * Description: This register qualifies all the operations launched * - * from a widget towards the SHub. It allows individual access * - * control for up to 8 devices per widget. A device refers to * - * individual DMA master hosted by a widget. * - * The bits in each field of this register are cleared by the Shub * - * upon detection of an error which requires the device to be * - * disabled. These fields assume that 0=TNUM=7 (i.e., Bridge-centric * - * Crosstalk). Whether or not a device has access rights to this * - * Shub is determined by an AND of the device enable bit in the * - * appropriate field of this register and the corresponding bit in * - * the Wx_IAC field (for the widget which this device belongs to). * - * The bits in this field are set by writing a 1 to them. Incoming * - * replies from Crosstalk are not subject to this access control * - * mechanism. * - * * - ************************************************************************/ - -typedef union ii_iidem_u { - u64 ii_iidem_regval; - struct { - u64 i_w8_dxs:8; - u64 i_w9_dxs:8; - u64 i_wa_dxs:8; - u64 i_wb_dxs:8; - u64 i_wc_dxs:8; - u64 i_wd_dxs:8; - u64 i_we_dxs:8; - u64 i_wf_dxs:8; - } ii_iidem_fld_s; -} ii_iidem_u_t; - -/************************************************************************ - * * - * This register contains the various programmable fields necessary * - * for controlling and observing the LLP signals. * - * * - ************************************************************************/ - -typedef union ii_ilcsr_u { - u64 ii_ilcsr_regval; - struct { - u64 i_nullto:6; - u64 i_rsvd_4:2; - u64 i_wrmrst:1; - u64 i_rsvd_3:1; - u64 i_llp_en:1; - u64 i_bm8:1; - u64 i_llp_stat:2; - u64 i_remote_power:1; - u64 i_rsvd_2:1; - u64 i_maxrtry:10; - u64 i_d_avail_sel:2; - u64 i_rsvd_1:4; - u64 i_maxbrst:10; - u64 i_rsvd:22; - - } ii_ilcsr_fld_s; -} ii_ilcsr_u_t; - -/************************************************************************ - * * - * This is simply a status registers that monitors the LLP error * - * rate. * - * * - ************************************************************************/ - -typedef union ii_illr_u { - u64 ii_illr_regval; - struct { - u64 i_sn_cnt:16; - u64 i_cb_cnt:16; - u64 i_rsvd:32; - } ii_illr_fld_s; -} ii_illr_u_t; - -/************************************************************************ - * * - * Description: All II-detected non-BTE error interrupts are * - * specified via this register. * - * NOTE: The PI interrupt register address is hardcoded in the II. If * - * PI_ID==0, then the II sends an interrupt request (Duplonet PWRI * - * packet) to address offset 0x0180_0090 within the local register * - * address space of PI0 on the node specified by the NODE field. If * - * PI_ID==1, then the II sends the interrupt request to address * - * offset 0x01A0_0090 within the local register address space of PI1 * - * on the node specified by the NODE field. * - * * - ************************************************************************/ - -typedef union ii_iidsr_u { - u64 ii_iidsr_regval; - struct { - u64 i_level:8; - u64 i_pi_id:1; - u64 i_node:11; - u64 i_rsvd_3:4; - u64 i_enable:1; - u64 i_rsvd_2:3; - u64 i_int_sent:2; - u64 i_rsvd_1:2; - u64 i_pi0_forward_int:1; - u64 i_pi1_forward_int:1; - u64 i_rsvd:30; - } ii_iidsr_fld_s; -} ii_iidsr_u_t; - -/************************************************************************ - * * - * There are two instances of this register. This register is used * - * for matching up the incoming responses from the graphics widget to * - * the processor that initiated the graphics operation. The * - * write-responses are converted to graphics credits and returned to * - * the processor so that the processor interface can manage the flow * - * control. * - * * - ************************************************************************/ - -typedef union ii_igfx0_u { - u64 ii_igfx0_regval; - struct { - u64 i_w_num:4; - u64 i_pi_id:1; - u64 i_n_num:12; - u64 i_p_num:1; - u64 i_rsvd:46; - } ii_igfx0_fld_s; -} ii_igfx0_u_t; - -/************************************************************************ - * * - * There are two instances of this register. This register is used * - * for matching up the incoming responses from the graphics widget to * - * the processor that initiated the graphics operation. The * - * write-responses are converted to graphics credits and returned to * - * the processor so that the processor interface can manage the flow * - * control. * - * * - ************************************************************************/ - -typedef union ii_igfx1_u { - u64 ii_igfx1_regval; - struct { - u64 i_w_num:4; - u64 i_pi_id:1; - u64 i_n_num:12; - u64 i_p_num:1; - u64 i_rsvd:46; - } ii_igfx1_fld_s; -} ii_igfx1_u_t; - -/************************************************************************ - * * - * There are two instances of this registers. These registers are * - * used as scratch registers for software use. * - * * - ************************************************************************/ - -typedef union ii_iscr0_u { - u64 ii_iscr0_regval; - struct { - u64 i_scratch:64; - } ii_iscr0_fld_s; -} ii_iscr0_u_t; - -/************************************************************************ - * * - * There are two instances of this registers. These registers are * - * used as scratch registers for software use. * - * * - ************************************************************************/ - -typedef union ii_iscr1_u { - u64 ii_iscr1_regval; - struct { - u64 i_scratch:64; - } ii_iscr1_fld_s; -} ii_iscr1_u_t; - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Shub Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the SHub is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Shub is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - -typedef union ii_itte1_u { - u64 ii_itte1_regval; - struct { - u64 i_offset:5; - u64 i_rsvd_1:3; - u64 i_w_num:4; - u64 i_iosp:1; - u64 i_rsvd:51; - } ii_itte1_fld_s; -} ii_itte1_u_t; - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Shub Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Shub is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Shub is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - -typedef union ii_itte2_u { - u64 ii_itte2_regval; - struct { - u64 i_offset:5; - u64 i_rsvd_1:3; - u64 i_w_num:4; - u64 i_iosp:1; - u64 i_rsvd:51; - } ii_itte2_fld_s; -} ii_itte2_u_t; - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Shub Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Shub is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the SHub is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - -typedef union ii_itte3_u { - u64 ii_itte3_regval; - struct { - u64 i_offset:5; - u64 i_rsvd_1:3; - u64 i_w_num:4; - u64 i_iosp:1; - u64 i_rsvd:51; - } ii_itte3_fld_s; -} ii_itte3_u_t; - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a SHub Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the SHub is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the SHub is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - -typedef union ii_itte4_u { - u64 ii_itte4_regval; - struct { - u64 i_offset:5; - u64 i_rsvd_1:3; - u64 i_w_num:4; - u64 i_iosp:1; - u64 i_rsvd:51; - } ii_itte4_fld_s; -} ii_itte4_u_t; - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a SHub Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Shub is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Shub is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - -typedef union ii_itte5_u { - u64 ii_itte5_regval; - struct { - u64 i_offset:5; - u64 i_rsvd_1:3; - u64 i_w_num:4; - u64 i_iosp:1; - u64 i_rsvd:51; - } ii_itte5_fld_s; -} ii_itte5_u_t; - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Shub Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Shub is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Shub is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - -typedef union ii_itte6_u { - u64 ii_itte6_regval; - struct { - u64 i_offset:5; - u64 i_rsvd_1:3; - u64 i_w_num:4; - u64 i_iosp:1; - u64 i_rsvd:51; - } ii_itte6_fld_s; -} ii_itte6_u_t; - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Shub Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Shub is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the SHub is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - -typedef union ii_itte7_u { - u64 ii_itte7_regval; - struct { - u64 i_offset:5; - u64 i_rsvd_1:3; - u64 i_w_num:4; - u64 i_iosp:1; - u64 i_rsvd:51; - } ii_itte7_fld_s; -} ii_itte7_u_t; - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of SHub and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - -typedef union ii_iprb0_u { - u64 ii_iprb0_regval; - struct { - u64 i_c:8; - u64 i_na:14; - u64 i_rsvd_2:2; - u64 i_nb:14; - u64 i_rsvd_1:2; - u64 i_m:2; - u64 i_f:1; - u64 i_of_cnt:5; - u64 i_error:1; - u64 i_rd_to:1; - u64 i_spur_wr:1; - u64 i_spur_rd:1; - u64 i_rsvd:11; - u64 i_mult_err:1; - } ii_iprb0_fld_s; -} ii_iprb0_u_t; - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of SHub and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - -typedef union ii_iprb8_u { - u64 ii_iprb8_regval; - struct { - u64 i_c:8; - u64 i_na:14; - u64 i_rsvd_2:2; - u64 i_nb:14; - u64 i_rsvd_1:2; - u64 i_m:2; - u64 i_f:1; - u64 i_of_cnt:5; - u64 i_error:1; - u64 i_rd_to:1; - u64 i_spur_wr:1; - u64 i_spur_rd:1; - u64 i_rsvd:11; - u64 i_mult_err:1; - } ii_iprb8_fld_s; -} ii_iprb8_u_t; - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of SHub and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - -typedef union ii_iprb9_u { - u64 ii_iprb9_regval; - struct { - u64 i_c:8; - u64 i_na:14; - u64 i_rsvd_2:2; - u64 i_nb:14; - u64 i_rsvd_1:2; - u64 i_m:2; - u64 i_f:1; - u64 i_of_cnt:5; - u64 i_error:1; - u64 i_rd_to:1; - u64 i_spur_wr:1; - u64 i_spur_rd:1; - u64 i_rsvd:11; - u64 i_mult_err:1; - } ii_iprb9_fld_s; -} ii_iprb9_u_t; - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of SHub and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * * - * * - ************************************************************************/ - -typedef union ii_iprba_u { - u64 ii_iprba_regval; - struct { - u64 i_c:8; - u64 i_na:14; - u64 i_rsvd_2:2; - u64 i_nb:14; - u64 i_rsvd_1:2; - u64 i_m:2; - u64 i_f:1; - u64 i_of_cnt:5; - u64 i_error:1; - u64 i_rd_to:1; - u64 i_spur_wr:1; - u64 i_spur_rd:1; - u64 i_rsvd:11; - u64 i_mult_err:1; - } ii_iprba_fld_s; -} ii_iprba_u_t; - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of SHub and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - -typedef union ii_iprbb_u { - u64 ii_iprbb_regval; - struct { - u64 i_c:8; - u64 i_na:14; - u64 i_rsvd_2:2; - u64 i_nb:14; - u64 i_rsvd_1:2; - u64 i_m:2; - u64 i_f:1; - u64 i_of_cnt:5; - u64 i_error:1; - u64 i_rd_to:1; - u64 i_spur_wr:1; - u64 i_spur_rd:1; - u64 i_rsvd:11; - u64 i_mult_err:1; - } ii_iprbb_fld_s; -} ii_iprbb_u_t; - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of SHub and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - -typedef union ii_iprbc_u { - u64 ii_iprbc_regval; - struct { - u64 i_c:8; - u64 i_na:14; - u64 i_rsvd_2:2; - u64 i_nb:14; - u64 i_rsvd_1:2; - u64 i_m:2; - u64 i_f:1; - u64 i_of_cnt:5; - u64 i_error:1; - u64 i_rd_to:1; - u64 i_spur_wr:1; - u64 i_spur_rd:1; - u64 i_rsvd:11; - u64 i_mult_err:1; - } ii_iprbc_fld_s; -} ii_iprbc_u_t; - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of SHub and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - -typedef union ii_iprbd_u { - u64 ii_iprbd_regval; - struct { - u64 i_c:8; - u64 i_na:14; - u64 i_rsvd_2:2; - u64 i_nb:14; - u64 i_rsvd_1:2; - u64 i_m:2; - u64 i_f:1; - u64 i_of_cnt:5; - u64 i_error:1; - u64 i_rd_to:1; - u64 i_spur_wr:1; - u64 i_spur_rd:1; - u64 i_rsvd:11; - u64 i_mult_err:1; - } ii_iprbd_fld_s; -} ii_iprbd_u_t; - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of SHub and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - -typedef union ii_iprbe_u { - u64 ii_iprbe_regval; - struct { - u64 i_c:8; - u64 i_na:14; - u64 i_rsvd_2:2; - u64 i_nb:14; - u64 i_rsvd_1:2; - u64 i_m:2; - u64 i_f:1; - u64 i_of_cnt:5; - u64 i_error:1; - u64 i_rd_to:1; - u64 i_spur_wr:1; - u64 i_spur_rd:1; - u64 i_rsvd:11; - u64 i_mult_err:1; - } ii_iprbe_fld_s; -} ii_iprbe_u_t; - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Shub and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - -typedef union ii_iprbf_u { - u64 ii_iprbf_regval; - struct { - u64 i_c:8; - u64 i_na:14; - u64 i_rsvd_2:2; - u64 i_nb:14; - u64 i_rsvd_1:2; - u64 i_m:2; - u64 i_f:1; - u64 i_of_cnt:5; - u64 i_error:1; - u64 i_rd_to:1; - u64 i_spur_wr:1; - u64 i_spur_rd:1; - u64 i_rsvd:11; - u64 i_mult_err:1; - } ii_iprbe_fld_s; -} ii_iprbf_u_t; - -/************************************************************************ - * * - * This register specifies the timeout value to use for monitoring * - * Crosstalk credits which are used outbound to Crosstalk. An * - * internal counter called the Crosstalk Credit Timeout Counter * - * increments every 128 II clocks. The counter starts counting * - * anytime the credit count drops below a threshold, and resets to * - * zero (stops counting) anytime the credit count is at or above the * - * threshold. The threshold is 1 credit in direct connect mode and 2 * - * in Crossbow connect mode. When the internal Crosstalk Credit * - * Timeout Counter reaches the value programmed in this register, a * - * Crosstalk Credit Timeout has occurred. The internal counter is not * - * readable from software, and stops counting at its maximum value, * - * so it cannot cause more than one interrupt. * - * * - ************************************************************************/ - -typedef union ii_ixcc_u { - u64 ii_ixcc_regval; - struct { - u64 i_time_out:26; - u64 i_rsvd:38; - } ii_ixcc_fld_s; -} ii_ixcc_u_t; - -/************************************************************************ - * * - * Description: This register qualifies all the PIO and DMA * - * operations launched from widget 0 towards the SHub. In * - * addition, it also qualifies accesses by the BTE streams. * - * The bits in each field of this register are cleared by the SHub * - * upon detection of an error which requires widget 0 or the BTE * - * streams to be terminated. Whether or not widget x has access * - * rights to this SHub is determined by an AND of the device * - * enable bit in the appropriate field of this register and bit 0 in * - * the Wx_IAC field. The bits in this field are set by writing a 1 to * - * them. Incoming replies from Crosstalk are not subject to this * - * access control mechanism. * - * * - ************************************************************************/ - -typedef union ii_imem_u { - u64 ii_imem_regval; - struct { - u64 i_w0_esd:1; - u64 i_rsvd_3:3; - u64 i_b0_esd:1; - u64 i_rsvd_2:3; - u64 i_b1_esd:1; - u64 i_rsvd_1:3; - u64 i_clr_precise:1; - u64 i_rsvd:51; - } ii_imem_fld_s; -} ii_imem_u_t; - -/************************************************************************ - * * - * Description: This register specifies the timeout value to use for * - * monitoring Crosstalk tail flits coming into the Shub in the * - * TAIL_TO field. An internal counter associated with this register * - * is incremented every 128 II internal clocks (7 bits). The counter * - * starts counting anytime a header micropacket is received and stops * - * counting (and resets to zero) any time a micropacket with a Tail * - * bit is received. Once the counter reaches the threshold value * - * programmed in this register, it generates an interrupt to the * - * processor that is programmed into the IIDSR. The counter saturates * - * (does not roll over) at its maximum value, so it cannot cause * - * another interrupt until after it is cleared. * - * The register also contains the Read Response Timeout values. The * - * Prescalar is 23 bits, and counts II clocks. An internal counter * - * increments on every II clock and when it reaches the value in the * - * Prescalar field, all IPRTE registers with their valid bits set * - * have their Read Response timers bumped. Whenever any of them match * - * the value in the RRSP_TO field, a Read Response Timeout has * - * occurred, and error handling occurs as described in the Error * - * Handling section of this document. * - * * - ************************************************************************/ - -typedef union ii_ixtt_u { - u64 ii_ixtt_regval; - struct { - u64 i_tail_to:26; - u64 i_rsvd_1:6; - u64 i_rrsp_ps:23; - u64 i_rrsp_to:5; - u64 i_rsvd:4; - } ii_ixtt_fld_s; -} ii_ixtt_u_t; - -/************************************************************************ - * * - * Writing a 1 to the fields of this register clears the appropriate * - * error bits in other areas of SHub. Note that when the * - * E_PRB_x bits are used to clear error bits in PRB registers, * - * SPUR_RD and SPUR_WR may persist, because they require additional * - * action to clear them. See the IPRBx and IXSS Register * - * specifications. * - * * - ************************************************************************/ - -typedef union ii_ieclr_u { - u64 ii_ieclr_regval; - struct { - u64 i_e_prb_0:1; - u64 i_rsvd:7; - u64 i_e_prb_8:1; - u64 i_e_prb_9:1; - u64 i_e_prb_a:1; - u64 i_e_prb_b:1; - u64 i_e_prb_c:1; - u64 i_e_prb_d:1; - u64 i_e_prb_e:1; - u64 i_e_prb_f:1; - u64 i_e_crazy:1; - u64 i_e_bte_0:1; - u64 i_e_bte_1:1; - u64 i_reserved_1:10; - u64 i_spur_rd_hdr:1; - u64 i_cam_intr_to:1; - u64 i_cam_overflow:1; - u64 i_cam_read_miss:1; - u64 i_ioq_rep_underflow:1; - u64 i_ioq_req_underflow:1; - u64 i_ioq_rep_overflow:1; - u64 i_ioq_req_overflow:1; - u64 i_iiq_rep_overflow:1; - u64 i_iiq_req_overflow:1; - u64 i_ii_xn_rep_cred_overflow:1; - u64 i_ii_xn_req_cred_overflow:1; - u64 i_ii_xn_invalid_cmd:1; - u64 i_xn_ii_invalid_cmd:1; - u64 i_reserved_2:21; - } ii_ieclr_fld_s; -} ii_ieclr_u_t; - -/************************************************************************ - * * - * This register controls both BTEs. SOFT_RESET is intended for * - * recovery after an error. COUNT controls the total number of CRBs * - * that both BTEs (combined) can use, which affects total BTE * - * bandwidth. * - * * - ************************************************************************/ - -typedef union ii_ibcr_u { - u64 ii_ibcr_regval; - struct { - u64 i_count:4; - u64 i_rsvd_1:4; - u64 i_soft_reset:1; - u64 i_rsvd:55; - } ii_ibcr_fld_s; -} ii_ibcr_u_t; - -/************************************************************************ - * * - * This register contains the header of a spurious read response * - * received from Crosstalk. A spurious read response is defined as a * - * read response received by II from a widget for which (1) the SIDN * - * has a value between 1 and 7, inclusive (II never sends requests to * - * these widgets (2) there is no valid IPRTE register which * - * corresponds to the TNUM, or (3) the widget indicated in SIDN is * - * not the same as the widget recorded in the IPRTE register * - * referenced by the TNUM. If this condition is true, and if the * - * IXSS[VALID] bit is clear, then the header of the spurious read * - * response is capture in IXSM and IXSS, and IXSS[VALID] is set. The * - * errant header is thereby captured, and no further spurious read * - * respones are captured until IXSS[VALID] is cleared by setting the * - * appropriate bit in IECLR. Every time a spurious read response is * - * detected, the SPUR_RD bit of the PRB corresponding to the incoming * - * message's SIDN field is set. This always happens, regardless of * - * whether a header is captured. The programmer should check * - * IXSM[SIDN] to determine which widget sent the spurious response, * - * because there may be more than one SPUR_RD bit set in the PRB * - * registers. The widget indicated by IXSM[SIDN] was the first * - * spurious read response to be received since the last time * - * IXSS[VALID] was clear. The SPUR_RD bit of the corresponding PRB * - * will be set. Any SPUR_RD bits in any other PRB registers indicate * - * spurious messages from other widets which were detected after the * - * header was captured.. * - * * - ************************************************************************/ - -typedef union ii_ixsm_u { - u64 ii_ixsm_regval; - struct { - u64 i_byte_en:32; - u64 i_reserved:1; - u64 i_tag:3; - u64 i_alt_pactyp:4; - u64 i_bo:1; - u64 i_error:1; - u64 i_vbpm:1; - u64 i_gbr:1; - u64 i_ds:2; - u64 i_ct:1; - u64 i_tnum:5; - u64 i_pactyp:4; - u64 i_sidn:4; - u64 i_didn:4; - } ii_ixsm_fld_s; -} ii_ixsm_u_t; - -/************************************************************************ - * * - * This register contains the sideband bits of a spurious read * - * response received from Crosstalk. * - * * - ************************************************************************/ - -typedef union ii_ixss_u { - u64 ii_ixss_regval; - struct { - u64 i_sideband:8; - u64 i_rsvd:55; - u64 i_valid:1; - } ii_ixss_fld_s; -} ii_ixss_u_t; - -/************************************************************************ - * * - * This register enables software to access the II LLP's test port. * - * Refer to the LLP 2.5 documentation for an explanation of the test * - * port. Software can write to this register to program the values * - * for the control fields (TestErrCapture, TestClear, TestFlit, * - * TestMask and TestSeed). Similarly, software can read from this * - * register to obtain the values of the test port's status outputs * - * (TestCBerr, TestValid and TestData). * - * * - ************************************************************************/ - -typedef union ii_ilct_u { - u64 ii_ilct_regval; - struct { - u64 i_test_seed:20; - u64 i_test_mask:8; - u64 i_test_data:20; - u64 i_test_valid:1; - u64 i_test_cberr:1; - u64 i_test_flit:3; - u64 i_test_clear:1; - u64 i_test_err_capture:1; - u64 i_rsvd:9; - } ii_ilct_fld_s; -} ii_ilct_u_t; - -/************************************************************************ - * * - * If the II detects an illegal incoming Duplonet packet (request or * - * reply) when VALID==0 in the IIEPH1 register, then it saves the * - * contents of the packet's header flit in the IIEPH1 and IIEPH2 * - * registers, sets the VALID bit in IIEPH1, clears the OVERRUN bit, * - * and assigns a value to the ERR_TYPE field which indicates the * - * specific nature of the error. The II recognizes four different * - * types of errors: short request packets (ERR_TYPE==2), short reply * - * packets (ERR_TYPE==3), long request packets (ERR_TYPE==4) and long * - * reply packets (ERR_TYPE==5). The encodings for these types of * - * errors were chosen to be consistent with the same types of errors * - * indicated by the ERR_TYPE field in the LB_ERROR_HDR1 register (in * - * the LB unit). If the II detects an illegal incoming Duplonet * - * packet when VALID==1 in the IIEPH1 register, then it merely sets * - * the OVERRUN bit to indicate that a subsequent error has happened, * - * and does nothing further. * - * * - ************************************************************************/ - -typedef union ii_iieph1_u { - u64 ii_iieph1_regval; - struct { - u64 i_command:7; - u64 i_rsvd_5:1; - u64 i_suppl:14; - u64 i_rsvd_4:1; - u64 i_source:14; - u64 i_rsvd_3:1; - u64 i_err_type:4; - u64 i_rsvd_2:4; - u64 i_overrun:1; - u64 i_rsvd_1:3; - u64 i_valid:1; - u64 i_rsvd:13; - } ii_iieph1_fld_s; -} ii_iieph1_u_t; - -/************************************************************************ - * * - * This register holds the Address field from the header flit of an * - * incoming erroneous Duplonet packet, along with the tail bit which * - * accompanied this header flit. This register is essentially an * - * extension of IIEPH1. Two registers were necessary because the 64 * - * bits available in only a single register were insufficient to * - * capture the entire header flit of an erroneous packet. * - * * - ************************************************************************/ - -typedef union ii_iieph2_u { - u64 ii_iieph2_regval; - struct { - u64 i_rsvd_0:3; - u64 i_address:47; - u64 i_rsvd_1:10; - u64 i_tail:1; - u64 i_rsvd:3; - } ii_iieph2_fld_s; -} ii_iieph2_u_t; - -/******************************/ - -/************************************************************************ - * * - * This register's value is a bit vector that guards access from SXBs * - * to local registers within the II as well as to external Crosstalk * - * widgets * - * * - ************************************************************************/ - -typedef union ii_islapr_u { - u64 ii_islapr_regval; - struct { - u64 i_region:64; - } ii_islapr_fld_s; -} ii_islapr_u_t; - -/************************************************************************ - * * - * A write to this register of the 56-bit value "Pup+Bun" will cause * - * the bit in the ISLAPR register corresponding to the region of the * - * requestor to be set (access allowed). ( - * * - ************************************************************************/ - -typedef union ii_islapo_u { - u64 ii_islapo_regval; - struct { - u64 i_io_sbx_ovrride:56; - u64 i_rsvd:8; - } ii_islapo_fld_s; -} ii_islapo_u_t; - -/************************************************************************ - * * - * Determines how long the wrapper will wait aftr an interrupt is * - * initially issued from the II before it times out the outstanding * - * interrupt and drops it from the interrupt queue. * - * * - ************************************************************************/ - -typedef union ii_iwi_u { - u64 ii_iwi_regval; - struct { - u64 i_prescale:24; - u64 i_rsvd:8; - u64 i_timeout:8; - u64 i_rsvd1:8; - u64 i_intrpt_retry_period:8; - u64 i_rsvd2:8; - } ii_iwi_fld_s; -} ii_iwi_u_t; - -/************************************************************************ - * * - * Log errors which have occurred in the II wrapper. The errors are * - * cleared by writing to the IECLR register. * - * * - ************************************************************************/ - -typedef union ii_iwel_u { - u64 ii_iwel_regval; - struct { - u64 i_intr_timed_out:1; - u64 i_rsvd:7; - u64 i_cam_overflow:1; - u64 i_cam_read_miss:1; - u64 i_rsvd1:2; - u64 i_ioq_rep_underflow:1; - u64 i_ioq_req_underflow:1; - u64 i_ioq_rep_overflow:1; - u64 i_ioq_req_overflow:1; - u64 i_iiq_rep_overflow:1; - u64 i_iiq_req_overflow:1; - u64 i_rsvd2:6; - u64 i_ii_xn_rep_cred_over_under:1; - u64 i_ii_xn_req_cred_over_under:1; - u64 i_rsvd3:6; - u64 i_ii_xn_invalid_cmd:1; - u64 i_xn_ii_invalid_cmd:1; - u64 i_rsvd4:30; - } ii_iwel_fld_s; -} ii_iwel_u_t; - -/************************************************************************ - * * - * Controls the II wrapper. * - * * - ************************************************************************/ - -typedef union ii_iwc_u { - u64 ii_iwc_regval; - struct { - u64 i_dma_byte_swap:1; - u64 i_rsvd:3; - u64 i_cam_read_lines_reset:1; - u64 i_rsvd1:3; - u64 i_ii_xn_cred_over_under_log:1; - u64 i_rsvd2:19; - u64 i_xn_rep_iq_depth:5; - u64 i_rsvd3:3; - u64 i_xn_req_iq_depth:5; - u64 i_rsvd4:3; - u64 i_iiq_depth:6; - u64 i_rsvd5:12; - u64 i_force_rep_cred:1; - u64 i_force_req_cred:1; - } ii_iwc_fld_s; -} ii_iwc_u_t; - -/************************************************************************ - * * - * Status in the II wrapper. * - * * - ************************************************************************/ - -typedef union ii_iws_u { - u64 ii_iws_regval; - struct { - u64 i_xn_rep_iq_credits:5; - u64 i_rsvd:3; - u64 i_xn_req_iq_credits:5; - u64 i_rsvd1:51; - } ii_iws_fld_s; -} ii_iws_u_t; - -/************************************************************************ - * * - * Masks errors in the IWEL register. * - * * - ************************************************************************/ - -typedef union ii_iweim_u { - u64 ii_iweim_regval; - struct { - u64 i_intr_timed_out:1; - u64 i_rsvd:7; - u64 i_cam_overflow:1; - u64 i_cam_read_miss:1; - u64 i_rsvd1:2; - u64 i_ioq_rep_underflow:1; - u64 i_ioq_req_underflow:1; - u64 i_ioq_rep_overflow:1; - u64 i_ioq_req_overflow:1; - u64 i_iiq_rep_overflow:1; - u64 i_iiq_req_overflow:1; - u64 i_rsvd2:6; - u64 i_ii_xn_rep_cred_overflow:1; - u64 i_ii_xn_req_cred_overflow:1; - u64 i_rsvd3:6; - u64 i_ii_xn_invalid_cmd:1; - u64 i_xn_ii_invalid_cmd:1; - u64 i_rsvd4:30; - } ii_iweim_fld_s; -} ii_iweim_u_t; - -/************************************************************************ - * * - * A write to this register causes a particular field in the * - * corresponding widget's PRB entry to be adjusted up or down by 1. * - * This counter should be used when recovering from error and reset * - * conditions. Note that software would be capable of causing * - * inadvertent overflow or underflow of these counters. * - * * - ************************************************************************/ - -typedef union ii_ipca_u { - u64 ii_ipca_regval; - struct { - u64 i_wid:4; - u64 i_adjust:1; - u64 i_rsvd_1:3; - u64 i_field:2; - u64 i_rsvd:54; - } ii_ipca_fld_s; -} ii_ipca_u_t; - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - -typedef union ii_iprte0a_u { - u64 ii_iprte0a_regval; - struct { - u64 i_rsvd_1:54; - u64 i_widget:4; - u64 i_to_cnt:5; - u64 i_vld:1; - } ii_iprte0a_fld_s; -} ii_iprte0a_u_t; - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - -typedef union ii_iprte1a_u { - u64 ii_iprte1a_regval; - struct { - u64 i_rsvd_1:54; - u64 i_widget:4; - u64 i_to_cnt:5; - u64 i_vld:1; - } ii_iprte1a_fld_s; -} ii_iprte1a_u_t; - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - -typedef union ii_iprte2a_u { - u64 ii_iprte2a_regval; - struct { - u64 i_rsvd_1:54; - u64 i_widget:4; - u64 i_to_cnt:5; - u64 i_vld:1; - } ii_iprte2a_fld_s; -} ii_iprte2a_u_t; - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - -typedef union ii_iprte3a_u { - u64 ii_iprte3a_regval; - struct { - u64 i_rsvd_1:54; - u64 i_widget:4; - u64 i_to_cnt:5; - u64 i_vld:1; - } ii_iprte3a_fld_s; -} ii_iprte3a_u_t; - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - -typedef union ii_iprte4a_u { - u64 ii_iprte4a_regval; - struct { - u64 i_rsvd_1:54; - u64 i_widget:4; - u64 i_to_cnt:5; - u64 i_vld:1; - } ii_iprte4a_fld_s; -} ii_iprte4a_u_t; - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - -typedef union ii_iprte5a_u { - u64 ii_iprte5a_regval; - struct { - u64 i_rsvd_1:54; - u64 i_widget:4; - u64 i_to_cnt:5; - u64 i_vld:1; - } ii_iprte5a_fld_s; -} ii_iprte5a_u_t; - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - -typedef union ii_iprte6a_u { - u64 ii_iprte6a_regval; - struct { - u64 i_rsvd_1:54; - u64 i_widget:4; - u64 i_to_cnt:5; - u64 i_vld:1; - } ii_iprte6a_fld_s; -} ii_iprte6a_u_t; - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - -typedef union ii_iprte7a_u { - u64 ii_iprte7a_regval; - struct { - u64 i_rsvd_1:54; - u64 i_widget:4; - u64 i_to_cnt:5; - u64 i_vld:1; - } ii_iprtea7_fld_s; -} ii_iprte7a_u_t; - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - -typedef union ii_iprte0b_u { - u64 ii_iprte0b_regval; - struct { - u64 i_rsvd_1:3; - u64 i_address:47; - u64 i_init:3; - u64 i_source:11; - } ii_iprte0b_fld_s; -} ii_iprte0b_u_t; - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - -typedef union ii_iprte1b_u { - u64 ii_iprte1b_regval; - struct { - u64 i_rsvd_1:3; - u64 i_address:47; - u64 i_init:3; - u64 i_source:11; - } ii_iprte1b_fld_s; -} ii_iprte1b_u_t; - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - -typedef union ii_iprte2b_u { - u64 ii_iprte2b_regval; - struct { - u64 i_rsvd_1:3; - u64 i_address:47; - u64 i_init:3; - u64 i_source:11; - } ii_iprte2b_fld_s; -} ii_iprte2b_u_t; - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - -typedef union ii_iprte3b_u { - u64 ii_iprte3b_regval; - struct { - u64 i_rsvd_1:3; - u64 i_address:47; - u64 i_init:3; - u64 i_source:11; - } ii_iprte3b_fld_s; -} ii_iprte3b_u_t; - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - -typedef union ii_iprte4b_u { - u64 ii_iprte4b_regval; - struct { - u64 i_rsvd_1:3; - u64 i_address:47; - u64 i_init:3; - u64 i_source:11; - } ii_iprte4b_fld_s; -} ii_iprte4b_u_t; - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - -typedef union ii_iprte5b_u { - u64 ii_iprte5b_regval; - struct { - u64 i_rsvd_1:3; - u64 i_address:47; - u64 i_init:3; - u64 i_source:11; - } ii_iprte5b_fld_s; -} ii_iprte5b_u_t; - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - -typedef union ii_iprte6b_u { - u64 ii_iprte6b_regval; - struct { - u64 i_rsvd_1:3; - u64 i_address:47; - u64 i_init:3; - u64 i_source:11; - - } ii_iprte6b_fld_s; -} ii_iprte6b_u_t; - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - -typedef union ii_iprte7b_u { - u64 ii_iprte7b_regval; - struct { - u64 i_rsvd_1:3; - u64 i_address:47; - u64 i_init:3; - u64 i_source:11; - } ii_iprte7b_fld_s; -} ii_iprte7b_u_t; - -/************************************************************************ - * * - * Description: SHub II contains a feature which did not exist in * - * the Hub which automatically cleans up after a Read Response * - * timeout, including deallocation of the IPRTE and recovery of IBuf * - * space. The inclusion of this register in SHub is for backward * - * compatibility * - * A write to this register causes an entry from the table of * - * outstanding PIO Read Requests to be freed and returned to the * - * stack of free entries. This register is used in handling the * - * timeout errors that result in a PIO Reply never returning from * - * Crosstalk. * - * Note that this register does not affect the contents of the IPRTE * - * registers. The Valid bits in those registers have to be * - * specifically turned off by software. * - * * - ************************************************************************/ - -typedef union ii_ipdr_u { - u64 ii_ipdr_regval; - struct { - u64 i_te:3; - u64 i_rsvd_1:1; - u64 i_pnd:1; - u64 i_init_rpcnt:1; - u64 i_rsvd:58; - } ii_ipdr_fld_s; -} ii_ipdr_u_t; - -/************************************************************************ - * * - * A write to this register causes a CRB entry to be returned to the * - * queue of free CRBs. The entry should have previously been cleared * - * (mark bit) via backdoor access to the pertinent CRB entry. This * - * register is used in the last step of handling the errors that are * - * captured and marked in CRB entries. Briefly: 1) first error for * - * DMA write from a particular device, and first error for a * - * particular BTE stream, lead to a marked CRB entry, and processor * - * interrupt, 2) software reads the error information captured in the * - * CRB entry, and presumably takes some corrective action, 3) * - * software clears the mark bit, and finally 4) software writes to * - * the ICDR register to return the CRB entry to the list of free CRB * - * entries. * - * * - ************************************************************************/ - -typedef union ii_icdr_u { - u64 ii_icdr_regval; - struct { - u64 i_crb_num:4; - u64 i_pnd:1; - u64 i_rsvd:59; - } ii_icdr_fld_s; -} ii_icdr_u_t; - -/************************************************************************ - * * - * This register provides debug access to two FIFOs inside of II. * - * Both IOQ_MAX* fields of this register contain the instantaneous * - * depth (in units of the number of available entries) of the * - * associated IOQ FIFO. A read of this register will return the * - * number of free entries on each FIFO at the time of the read. So * - * when a FIFO is idle, the associated field contains the maximum * - * depth of the FIFO. This register is writable for debug reasons * - * and is intended to be written with the maximum desired FIFO depth * - * while the FIFO is idle. Software must assure that II is idle when * - * this register is written. If there are any active entries in any * - * of these FIFOs when this register is written, the results are * - * undefined. * - * * - ************************************************************************/ - -typedef union ii_ifdr_u { - u64 ii_ifdr_regval; - struct { - u64 i_ioq_max_rq:7; - u64 i_set_ioq_rq:1; - u64 i_ioq_max_rp:7; - u64 i_set_ioq_rp:1; - u64 i_rsvd:48; - } ii_ifdr_fld_s; -} ii_ifdr_u_t; - -/************************************************************************ - * * - * This register allows the II to become sluggish in removing * - * messages from its inbound queue (IIQ). This will cause messages to * - * back up in either virtual channel. Disabling the "molasses" mode * - * subsequently allows the II to be tested under stress. In the * - * sluggish ("Molasses") mode, the localized effects of congestion * - * can be observed. * - * * - ************************************************************************/ - -typedef union ii_iiap_u { - u64 ii_iiap_regval; - struct { - u64 i_rq_mls:6; - u64 i_rsvd_1:2; - u64 i_rp_mls:6; - u64 i_rsvd:50; - } ii_iiap_fld_s; -} ii_iiap_u_t; - -/************************************************************************ - * * - * This register allows several parameters of CRB operation to be * - * set. Note that writing to this register can have catastrophic side * - * effects, if the CRB is not quiescent, i.e. if the CRB is * - * processing protocol messages when the write occurs. * - * * - ************************************************************************/ - -typedef union ii_icmr_u { - u64 ii_icmr_regval; - struct { - u64 i_sp_msg:1; - u64 i_rd_hdr:1; - u64 i_rsvd_4:2; - u64 i_c_cnt:4; - u64 i_rsvd_3:4; - u64 i_clr_rqpd:1; - u64 i_clr_rppd:1; - u64 i_rsvd_2:2; - u64 i_fc_cnt:4; - u64 i_crb_vld:15; - u64 i_crb_mark:15; - u64 i_rsvd_1:2; - u64 i_precise:1; - u64 i_rsvd:11; - } ii_icmr_fld_s; -} ii_icmr_u_t; - -/************************************************************************ - * * - * This register allows control of the table portion of the CRB * - * logic via software. Control operations from this register have * - * priority over all incoming Crosstalk or BTE requests. * - * * - ************************************************************************/ - -typedef union ii_iccr_u { - u64 ii_iccr_regval; - struct { - u64 i_crb_num:4; - u64 i_rsvd_1:4; - u64 i_cmd:8; - u64 i_pending:1; - u64 i_rsvd:47; - } ii_iccr_fld_s; -} ii_iccr_u_t; - -/************************************************************************ - * * - * This register allows the maximum timeout value to be programmed. * - * * - ************************************************************************/ - -typedef union ii_icto_u { - u64 ii_icto_regval; - struct { - u64 i_timeout:8; - u64 i_rsvd:56; - } ii_icto_fld_s; -} ii_icto_u_t; - -/************************************************************************ - * * - * This register allows the timeout prescalar to be programmed. An * - * internal counter is associated with this register. When the * - * internal counter reaches the value of the PRESCALE field, the * - * timer registers in all valid CRBs are incremented (CRBx_D[TIMEOUT] * - * field). The internal counter resets to zero, and then continues * - * counting. * - * * - ************************************************************************/ - -typedef union ii_ictp_u { - u64 ii_ictp_regval; - struct { - u64 i_prescale:24; - u64 i_rsvd:40; - } ii_ictp_fld_s; -} ii_ictp_u_t; - -/************************************************************************ - * * - * Description: There are 15 CRB Entries (ICRB0 to ICRBE) that are * - * used for Crosstalk operations (both cacheline and partial * - * operations) or BTE/IO. Because the CRB entries are very wide, five * - * registers (_A to _E) are required to read and write each entry. * - * The CRB Entry registers can be conceptualized as rows and columns * - * (illustrated in the table above). Each row contains the 4 * - * registers required for a single CRB Entry. The first doubleword * - * (column) for each entry is labeled A, and the second doubleword * - * (higher address) is labeled B, the third doubleword is labeled C, * - * the fourth doubleword is labeled D and the fifth doubleword is * - * labeled E. All CRB entries have their addresses on a quarter * - * cacheline aligned boundary. * - * Upon reset, only the following fields are initialized: valid * - * (VLD), priority count, timeout, timeout valid, and context valid. * - * All other bits should be cleared by software before use (after * - * recovering any potential error state from before the reset). * - * The following four tables summarize the format for the four * - * registers that are used for each ICRB# Entry. * - * * - ************************************************************************/ - -typedef union ii_icrb0_a_u { - u64 ii_icrb0_a_regval; - struct { - u64 ia_iow:1; - u64 ia_vld:1; - u64 ia_addr:47; - u64 ia_tnum:5; - u64 ia_sidn:4; - u64 ia_rsvd:6; - } ii_icrb0_a_fld_s; -} ii_icrb0_a_u_t; - -/************************************************************************ - * * - * Description: There are 15 CRB Entries (ICRB0 to ICRBE) that are * - * used for Crosstalk operations (both cacheline and partial * - * operations) or BTE/IO. Because the CRB entries are very wide, five * - * registers (_A to _E) are required to read and write each entry. * - * * - ************************************************************************/ - -typedef union ii_icrb0_b_u { - u64 ii_icrb0_b_regval; - struct { - u64 ib_xt_err:1; - u64 ib_mark:1; - u64 ib_ln_uce:1; - u64 ib_errcode:3; - u64 ib_error:1; - u64 ib_stall__bte_1:1; - u64 ib_stall__bte_0:1; - u64 ib_stall__intr:1; - u64 ib_stall_ib:1; - u64 ib_intvn:1; - u64 ib_wb:1; - u64 ib_hold:1; - u64 ib_ack:1; - u64 ib_resp:1; - u64 ib_ack_cnt:11; - u64 ib_rsvd:7; - u64 ib_exc:5; - u64 ib_init:3; - u64 ib_imsg:8; - u64 ib_imsgtype:2; - u64 ib_use_old:1; - u64 ib_rsvd_1:11; - } ii_icrb0_b_fld_s; -} ii_icrb0_b_u_t; - -/************************************************************************ - * * - * Description: There are 15 CRB Entries (ICRB0 to ICRBE) that are * - * used for Crosstalk operations (both cacheline and partial * - * operations) or BTE/IO. Because the CRB entries are very wide, five * - * registers (_A to _E) are required to read and write each entry. * - * * - ************************************************************************/ - -typedef union ii_icrb0_c_u { - u64 ii_icrb0_c_regval; - struct { - u64 ic_source:15; - u64 ic_size:2; - u64 ic_ct:1; - u64 ic_bte_num:1; - u64 ic_gbr:1; - u64 ic_resprqd:1; - u64 ic_bo:1; - u64 ic_suppl:15; - u64 ic_rsvd:27; - } ii_icrb0_c_fld_s; -} ii_icrb0_c_u_t; - -/************************************************************************ - * * - * Description: There are 15 CRB Entries (ICRB0 to ICRBE) that are * - * used for Crosstalk operations (both cacheline and partial * - * operations) or BTE/IO. Because the CRB entries are very wide, five * - * registers (_A to _E) are required to read and write each entry. * - * * - ************************************************************************/ - -typedef union ii_icrb0_d_u { - u64 ii_icrb0_d_regval; - struct { - u64 id_pa_be:43; - u64 id_bte_op:1; - u64 id_pr_psc:4; - u64 id_pr_cnt:4; - u64 id_sleep:1; - u64 id_rsvd:11; - } ii_icrb0_d_fld_s; -} ii_icrb0_d_u_t; - -/************************************************************************ - * * - * Description: There are 15 CRB Entries (ICRB0 to ICRBE) that are * - * used for Crosstalk operations (both cacheline and partial * - * operations) or BTE/IO. Because the CRB entries are very wide, five * - * registers (_A to _E) are required to read and write each entry. * - * * - ************************************************************************/ - -typedef union ii_icrb0_e_u { - u64 ii_icrb0_e_regval; - struct { - u64 ie_timeout:8; - u64 ie_context:15; - u64 ie_rsvd:1; - u64 ie_tvld:1; - u64 ie_cvld:1; - u64 ie_rsvd_0:38; - } ii_icrb0_e_fld_s; -} ii_icrb0_e_u_t; - -/************************************************************************ - * * - * This register contains the lower 64 bits of the header of the * - * spurious message captured by II. Valid when the SP_MSG bit in ICMR * - * register is set. * - * * - ************************************************************************/ - -typedef union ii_icsml_u { - u64 ii_icsml_regval; - struct { - u64 i_tt_addr:47; - u64 i_newsuppl_ex:14; - u64 i_reserved:2; - u64 i_overflow:1; - } ii_icsml_fld_s; -} ii_icsml_u_t; - -/************************************************************************ - * * - * This register contains the middle 64 bits of the header of the * - * spurious message captured by II. Valid when the SP_MSG bit in ICMR * - * register is set. * - * * - ************************************************************************/ - -typedef union ii_icsmm_u { - u64 ii_icsmm_regval; - struct { - u64 i_tt_ack_cnt:11; - u64 i_reserved:53; - } ii_icsmm_fld_s; -} ii_icsmm_u_t; - -/************************************************************************ - * * - * This register contains the microscopic state, all the inputs to * - * the protocol table, captured with the spurious message. Valid when * - * the SP_MSG bit in the ICMR register is set. * - * * - ************************************************************************/ - -typedef union ii_icsmh_u { - u64 ii_icsmh_regval; - struct { - u64 i_tt_vld:1; - u64 i_xerr:1; - u64 i_ft_cwact_o:1; - u64 i_ft_wact_o:1; - u64 i_ft_active_o:1; - u64 i_sync:1; - u64 i_mnusg:1; - u64 i_mnusz:1; - u64 i_plusz:1; - u64 i_plusg:1; - u64 i_tt_exc:5; - u64 i_tt_wb:1; - u64 i_tt_hold:1; - u64 i_tt_ack:1; - u64 i_tt_resp:1; - u64 i_tt_intvn:1; - u64 i_g_stall_bte1:1; - u64 i_g_stall_bte0:1; - u64 i_g_stall_il:1; - u64 i_g_stall_ib:1; - u64 i_tt_imsg:8; - u64 i_tt_imsgtype:2; - u64 i_tt_use_old:1; - u64 i_tt_respreqd:1; - u64 i_tt_bte_num:1; - u64 i_cbn:1; - u64 i_match:1; - u64 i_rpcnt_lt_34:1; - u64 i_rpcnt_ge_34:1; - u64 i_rpcnt_lt_18:1; - u64 i_rpcnt_ge_18:1; - u64 i_rpcnt_lt_2:1; - u64 i_rpcnt_ge_2:1; - u64 i_rqcnt_lt_18:1; - u64 i_rqcnt_ge_18:1; - u64 i_rqcnt_lt_2:1; - u64 i_rqcnt_ge_2:1; - u64 i_tt_device:7; - u64 i_tt_init:3; - u64 i_reserved:5; - } ii_icsmh_fld_s; -} ii_icsmh_u_t; - -/************************************************************************ - * * - * The Shub DEBUG unit provides a 3-bit selection signal to the * - * II core and a 3-bit selection signal to the fsbclk domain in the II * - * wrapper. * - * * - ************************************************************************/ - -typedef union ii_idbss_u { - u64 ii_idbss_regval; - struct { - u64 i_iioclk_core_submenu:3; - u64 i_rsvd:5; - u64 i_fsbclk_wrapper_submenu:3; - u64 i_rsvd_1:5; - u64 i_iioclk_menu:5; - u64 i_rsvd_2:43; - } ii_idbss_fld_s; -} ii_idbss_u_t; - -/************************************************************************ - * * - * Description: This register is used to set up the length for a * - * transfer and then to monitor the progress of that transfer. This * - * register needs to be initialized before a transfer is started. A * - * legitimate write to this register will set the Busy bit, clear the * - * Error bit, and initialize the length to the value desired. * - * While the transfer is in progress, hardware will decrement the * - * length field with each successful block that is copied. Once the * - * transfer completes, hardware will clear the Busy bit. The length * - * field will also contain the number of cache lines left to be * - * transferred. * - * * - ************************************************************************/ - -typedef union ii_ibls0_u { - u64 ii_ibls0_regval; - struct { - u64 i_length:16; - u64 i_error:1; - u64 i_rsvd_1:3; - u64 i_busy:1; - u64 i_rsvd:43; - } ii_ibls0_fld_s; -} ii_ibls0_u_t; - -/************************************************************************ - * * - * This register should be loaded before a transfer is started. The * - * address to be loaded in bits 39:0 is the 40-bit TRex+ physical * - * address as described in Section 1.3, Figure2 and Figure3. Since * - * the bottom 7 bits of the address are always taken to be zero, BTE * - * transfers are always cacheline-aligned. * - * * - ************************************************************************/ - -typedef union ii_ibsa0_u { - u64 ii_ibsa0_regval; - struct { - u64 i_rsvd_1:7; - u64 i_addr:42; - u64 i_rsvd:15; - } ii_ibsa0_fld_s; -} ii_ibsa0_u_t; - -/************************************************************************ - * * - * This register should be loaded before a transfer is started. The * - * address to be loaded in bits 39:0 is the 40-bit TRex+ physical * - * address as described in Section 1.3, Figure2 and Figure3. Since * - * the bottom 7 bits of the address are always taken to be zero, BTE * - * transfers are always cacheline-aligned. * - * * - ************************************************************************/ - -typedef union ii_ibda0_u { - u64 ii_ibda0_regval; - struct { - u64 i_rsvd_1:7; - u64 i_addr:42; - u64 i_rsvd:15; - } ii_ibda0_fld_s; -} ii_ibda0_u_t; - -/************************************************************************ - * * - * Writing to this register sets up the attributes of the transfer * - * and initiates the transfer operation. Reading this register has * - * the side effect of terminating any transfer in progress. Note: * - * stopping a transfer midstream could have an adverse impact on the * - * other BTE. If a BTE stream has to be stopped (due to error * - * handling for example), both BTE streams should be stopped and * - * their transfers discarded. * - * * - ************************************************************************/ - -typedef union ii_ibct0_u { - u64 ii_ibct0_regval; - struct { - u64 i_zerofill:1; - u64 i_rsvd_2:3; - u64 i_notify:1; - u64 i_rsvd_1:3; - u64 i_poison:1; - u64 i_rsvd:55; - } ii_ibct0_fld_s; -} ii_ibct0_u_t; - -/************************************************************************ - * * - * This register contains the address to which the WINV is sent. * - * This address has to be cache line aligned. * - * * - ************************************************************************/ - -typedef union ii_ibna0_u { - u64 ii_ibna0_regval; - struct { - u64 i_rsvd_1:7; - u64 i_addr:42; - u64 i_rsvd:15; - } ii_ibna0_fld_s; -} ii_ibna0_u_t; - -/************************************************************************ - * * - * This register contains the programmable level as well as the node * - * ID and PI unit of the processor to which the interrupt will be * - * sent. * - * * - ************************************************************************/ - -typedef union ii_ibia0_u { - u64 ii_ibia0_regval; - struct { - u64 i_rsvd_2:1; - u64 i_node_id:11; - u64 i_rsvd_1:4; - u64 i_level:7; - u64 i_rsvd:41; - } ii_ibia0_fld_s; -} ii_ibia0_u_t; - -/************************************************************************ - * * - * Description: This register is used to set up the length for a * - * transfer and then to monitor the progress of that transfer. This * - * register needs to be initialized before a transfer is started. A * - * legitimate write to this register will set the Busy bit, clear the * - * Error bit, and initialize the length to the value desired. * - * While the transfer is in progress, hardware will decrement the * - * length field with each successful block that is copied. Once the * - * transfer completes, hardware will clear the Busy bit. The length * - * field will also contain the number of cache lines left to be * - * transferred. * - * * - ************************************************************************/ - -typedef union ii_ibls1_u { - u64 ii_ibls1_regval; - struct { - u64 i_length:16; - u64 i_error:1; - u64 i_rsvd_1:3; - u64 i_busy:1; - u64 i_rsvd:43; - } ii_ibls1_fld_s; -} ii_ibls1_u_t; - -/************************************************************************ - * * - * This register should be loaded before a transfer is started. The * - * address to be loaded in bits 39:0 is the 40-bit TRex+ physical * - * address as described in Section 1.3, Figure2 and Figure3. Since * - * the bottom 7 bits of the address are always taken to be zero, BTE * - * transfers are always cacheline-aligned. * - * * - ************************************************************************/ - -typedef union ii_ibsa1_u { - u64 ii_ibsa1_regval; - struct { - u64 i_rsvd_1:7; - u64 i_addr:33; - u64 i_rsvd:24; - } ii_ibsa1_fld_s; -} ii_ibsa1_u_t; - -/************************************************************************ - * * - * This register should be loaded before a transfer is started. The * - * address to be loaded in bits 39:0 is the 40-bit TRex+ physical * - * address as described in Section 1.3, Figure2 and Figure3. Since * - * the bottom 7 bits of the address are always taken to be zero, BTE * - * transfers are always cacheline-aligned. * - * * - ************************************************************************/ - -typedef union ii_ibda1_u { - u64 ii_ibda1_regval; - struct { - u64 i_rsvd_1:7; - u64 i_addr:33; - u64 i_rsvd:24; - } ii_ibda1_fld_s; -} ii_ibda1_u_t; - -/************************************************************************ - * * - * Writing to this register sets up the attributes of the transfer * - * and initiates the transfer operation. Reading this register has * - * the side effect of terminating any transfer in progress. Note: * - * stopping a transfer midstream could have an adverse impact on the * - * other BTE. If a BTE stream has to be stopped (due to error * - * handling for example), both BTE streams should be stopped and * - * their transfers discarded. * - * * - ************************************************************************/ - -typedef union ii_ibct1_u { - u64 ii_ibct1_regval; - struct { - u64 i_zerofill:1; - u64 i_rsvd_2:3; - u64 i_notify:1; - u64 i_rsvd_1:3; - u64 i_poison:1; - u64 i_rsvd:55; - } ii_ibct1_fld_s; -} ii_ibct1_u_t; - -/************************************************************************ - * * - * This register contains the address to which the WINV is sent. * - * This address has to be cache line aligned. * - * * - ************************************************************************/ - -typedef union ii_ibna1_u { - u64 ii_ibna1_regval; - struct { - u64 i_rsvd_1:7; - u64 i_addr:33; - u64 i_rsvd:24; - } ii_ibna1_fld_s; -} ii_ibna1_u_t; - -/************************************************************************ - * * - * This register contains the programmable level as well as the node * - * ID and PI unit of the processor to which the interrupt will be * - * sent. * - * * - ************************************************************************/ - -typedef union ii_ibia1_u { - u64 ii_ibia1_regval; - struct { - u64 i_pi_id:1; - u64 i_node_id:8; - u64 i_rsvd_1:7; - u64 i_level:7; - u64 i_rsvd:41; - } ii_ibia1_fld_s; -} ii_ibia1_u_t; - -/************************************************************************ - * * - * This register defines the resources that feed information into * - * the two performance counters located in the IO Performance * - * Profiling Register. There are 17 different quantities that can be * - * measured. Given these 17 different options, the two performance * - * counters have 15 of them in common; menu selections 0 through 0xE * - * are identical for each performance counter. As for the other two * - * options, one is available from one performance counter and the * - * other is available from the other performance counter. Hence, the * - * II supports all 17*16=272 possible combinations of quantities to * - * measure. * - * * - ************************************************************************/ - -typedef union ii_ipcr_u { - u64 ii_ipcr_regval; - struct { - u64 i_ippr0_c:4; - u64 i_ippr1_c:4; - u64 i_icct:8; - u64 i_rsvd:48; - } ii_ipcr_fld_s; -} ii_ipcr_u_t; - -/************************************************************************ - * * - * * - * * - ************************************************************************/ - -typedef union ii_ippr_u { - u64 ii_ippr_regval; - struct { - u64 i_ippr0:32; - u64 i_ippr1:32; - } ii_ippr_fld_s; -} ii_ippr_u_t; - -/************************************************************************ - * * - * The following defines which were not formed into structures are * - * probably identical to another register, and the name of the * - * register is provided against each of these registers. This * - * information needs to be checked carefully * - * * - * IIO_ICRB1_A IIO_ICRB0_A * - * IIO_ICRB1_B IIO_ICRB0_B * - * IIO_ICRB1_C IIO_ICRB0_C * - * IIO_ICRB1_D IIO_ICRB0_D * - * IIO_ICRB1_E IIO_ICRB0_E * - * IIO_ICRB2_A IIO_ICRB0_A * - * IIO_ICRB2_B IIO_ICRB0_B * - * IIO_ICRB2_C IIO_ICRB0_C * - * IIO_ICRB2_D IIO_ICRB0_D * - * IIO_ICRB2_E IIO_ICRB0_E * - * IIO_ICRB3_A IIO_ICRB0_A * - * IIO_ICRB3_B IIO_ICRB0_B * - * IIO_ICRB3_C IIO_ICRB0_C * - * IIO_ICRB3_D IIO_ICRB0_D * - * IIO_ICRB3_E IIO_ICRB0_E * - * IIO_ICRB4_A IIO_ICRB0_A * - * IIO_ICRB4_B IIO_ICRB0_B * - * IIO_ICRB4_C IIO_ICRB0_C * - * IIO_ICRB4_D IIO_ICRB0_D * - * IIO_ICRB4_E IIO_ICRB0_E * - * IIO_ICRB5_A IIO_ICRB0_A * - * IIO_ICRB5_B IIO_ICRB0_B * - * IIO_ICRB5_C IIO_ICRB0_C * - * IIO_ICRB5_D IIO_ICRB0_D * - * IIO_ICRB5_E IIO_ICRB0_E * - * IIO_ICRB6_A IIO_ICRB0_A * - * IIO_ICRB6_B IIO_ICRB0_B * - * IIO_ICRB6_C IIO_ICRB0_C * - * IIO_ICRB6_D IIO_ICRB0_D * - * IIO_ICRB6_E IIO_ICRB0_E * - * IIO_ICRB7_A IIO_ICRB0_A * - * IIO_ICRB7_B IIO_ICRB0_B * - * IIO_ICRB7_C IIO_ICRB0_C * - * IIO_ICRB7_D IIO_ICRB0_D * - * IIO_ICRB7_E IIO_ICRB0_E * - * IIO_ICRB8_A IIO_ICRB0_A * - * IIO_ICRB8_B IIO_ICRB0_B * - * IIO_ICRB8_C IIO_ICRB0_C * - * IIO_ICRB8_D IIO_ICRB0_D * - * IIO_ICRB8_E IIO_ICRB0_E * - * IIO_ICRB9_A IIO_ICRB0_A * - * IIO_ICRB9_B IIO_ICRB0_B * - * IIO_ICRB9_C IIO_ICRB0_C * - * IIO_ICRB9_D IIO_ICRB0_D * - * IIO_ICRB9_E IIO_ICRB0_E * - * IIO_ICRBA_A IIO_ICRB0_A * - * IIO_ICRBA_B IIO_ICRB0_B * - * IIO_ICRBA_C IIO_ICRB0_C * - * IIO_ICRBA_D IIO_ICRB0_D * - * IIO_ICRBA_E IIO_ICRB0_E * - * IIO_ICRBB_A IIO_ICRB0_A * - * IIO_ICRBB_B IIO_ICRB0_B * - * IIO_ICRBB_C IIO_ICRB0_C * - * IIO_ICRBB_D IIO_ICRB0_D * - * IIO_ICRBB_E IIO_ICRB0_E * - * IIO_ICRBC_A IIO_ICRB0_A * - * IIO_ICRBC_B IIO_ICRB0_B * - * IIO_ICRBC_C IIO_ICRB0_C * - * IIO_ICRBC_D IIO_ICRB0_D * - * IIO_ICRBC_E IIO_ICRB0_E * - * IIO_ICRBD_A IIO_ICRB0_A * - * IIO_ICRBD_B IIO_ICRB0_B * - * IIO_ICRBD_C IIO_ICRB0_C * - * IIO_ICRBD_D IIO_ICRB0_D * - * IIO_ICRBD_E IIO_ICRB0_E * - * IIO_ICRBE_A IIO_ICRB0_A * - * IIO_ICRBE_B IIO_ICRB0_B * - * IIO_ICRBE_C IIO_ICRB0_C * - * IIO_ICRBE_D IIO_ICRB0_D * - * IIO_ICRBE_E IIO_ICRB0_E * - * * - ************************************************************************/ - -/* - * Slightly friendlier names for some common registers. - */ -#define IIO_WIDGET IIO_WID /* Widget identification */ -#define IIO_WIDGET_STAT IIO_WSTAT /* Widget status register */ -#define IIO_WIDGET_CTRL IIO_WCR /* Widget control register */ -#define IIO_PROTECT IIO_ILAPR /* IO interface protection */ -#define IIO_PROTECT_OVRRD IIO_ILAPO /* IO protect override */ -#define IIO_OUTWIDGET_ACCESS IIO_IOWA /* Outbound widget access */ -#define IIO_INWIDGET_ACCESS IIO_IIWA /* Inbound widget access */ -#define IIO_INDEV_ERR_MASK IIO_IIDEM /* Inbound device error mask */ -#define IIO_LLP_CSR IIO_ILCSR /* LLP control and status */ -#define IIO_LLP_LOG IIO_ILLR /* LLP log */ -#define IIO_XTALKCC_TOUT IIO_IXCC /* Xtalk credit count timeout */ -#define IIO_XTALKTT_TOUT IIO_IXTT /* Xtalk tail timeout */ -#define IIO_IO_ERR_CLR IIO_IECLR /* IO error clear */ -#define IIO_IGFX_0 IIO_IGFX0 -#define IIO_IGFX_1 IIO_IGFX1 -#define IIO_IBCT_0 IIO_IBCT0 -#define IIO_IBCT_1 IIO_IBCT1 -#define IIO_IBLS_0 IIO_IBLS0 -#define IIO_IBLS_1 IIO_IBLS1 -#define IIO_IBSA_0 IIO_IBSA0 -#define IIO_IBSA_1 IIO_IBSA1 -#define IIO_IBDA_0 IIO_IBDA0 -#define IIO_IBDA_1 IIO_IBDA1 -#define IIO_IBNA_0 IIO_IBNA0 -#define IIO_IBNA_1 IIO_IBNA1 -#define IIO_IBIA_0 IIO_IBIA0 -#define IIO_IBIA_1 IIO_IBIA1 -#define IIO_IOPRB_0 IIO_IPRB0 - -#define IIO_PRTE_A(_x) (IIO_IPRTE0_A + (8 * (_x))) -#define IIO_PRTE_B(_x) (IIO_IPRTE0_B + (8 * (_x))) -#define IIO_NUM_PRTES 8 /* Total number of PRB table entries */ -#define IIO_WIDPRTE_A(x) IIO_PRTE_A(((x) - 8)) /* widget ID to its PRTE num */ -#define IIO_WIDPRTE_B(x) IIO_PRTE_B(((x) - 8)) /* widget ID to its PRTE num */ - -#define IIO_NUM_IPRBS 9 - -#define IIO_LLP_CSR_IS_UP 0x00002000 -#define IIO_LLP_CSR_LLP_STAT_MASK 0x00003000 -#define IIO_LLP_CSR_LLP_STAT_SHFT 12 - -#define IIO_LLP_CB_MAX 0xffff /* in ILLR CB_CNT, Max Check Bit errors */ -#define IIO_LLP_SN_MAX 0xffff /* in ILLR SN_CNT, Max Sequence Number errors */ - -/* key to IIO_PROTECT_OVRRD */ -#define IIO_PROTECT_OVRRD_KEY 0x53474972756c6573ull /* "SGIrules" */ - -/* BTE register names */ -#define IIO_BTE_STAT_0 IIO_IBLS_0 /* Also BTE length/status 0 */ -#define IIO_BTE_SRC_0 IIO_IBSA_0 /* Also BTE source address 0 */ -#define IIO_BTE_DEST_0 IIO_IBDA_0 /* Also BTE dest. address 0 */ -#define IIO_BTE_CTRL_0 IIO_IBCT_0 /* Also BTE control/terminate 0 */ -#define IIO_BTE_NOTIFY_0 IIO_IBNA_0 /* Also BTE notification 0 */ -#define IIO_BTE_INT_0 IIO_IBIA_0 /* Also BTE interrupt 0 */ -#define IIO_BTE_OFF_0 0 /* Base offset from BTE 0 regs. */ -#define IIO_BTE_OFF_1 (IIO_IBLS_1 - IIO_IBLS_0) /* Offset from base to BTE 1 */ - -/* BTE register offsets from base */ -#define BTEOFF_STAT 0 -#define BTEOFF_SRC (IIO_BTE_SRC_0 - IIO_BTE_STAT_0) -#define BTEOFF_DEST (IIO_BTE_DEST_0 - IIO_BTE_STAT_0) -#define BTEOFF_CTRL (IIO_BTE_CTRL_0 - IIO_BTE_STAT_0) -#define BTEOFF_NOTIFY (IIO_BTE_NOTIFY_0 - IIO_BTE_STAT_0) -#define BTEOFF_INT (IIO_BTE_INT_0 - IIO_BTE_STAT_0) - -/* names used in shub diags */ -#define IIO_BASE_BTE0 IIO_IBLS_0 -#define IIO_BASE_BTE1 IIO_IBLS_1 - -/* - * Macro which takes the widget number, and returns the - * IO PRB address of that widget. - * value _x is expected to be a widget number in the range - * 0, 8 - 0xF - */ -#define IIO_IOPRB(_x) (IIO_IOPRB_0 + ( ( (_x) < HUB_WIDGET_ID_MIN ? \ - (_x) : \ - (_x) - (HUB_WIDGET_ID_MIN-1)) << 3) ) - -/* GFX Flow Control Node/Widget Register */ -#define IIO_IGFX_W_NUM_BITS 4 /* size of widget num field */ -#define IIO_IGFX_W_NUM_MASK ((1<> IIO_WSTAT_TXRETRY_SHFT) & \ - IIO_WSTAT_TXRETRY_MASK) - -/* Number of II perf. counters we can multiplex at once */ - -#define IO_PERF_SETS 32 - -/* Bit for the widget in inbound access register */ -#define IIO_IIWA_WIDGET(_w) ((u64)(1ULL << _w)) -/* Bit for the widget in outbound access register */ -#define IIO_IOWA_WIDGET(_w) ((u64)(1ULL << _w)) - -/* NOTE: The following define assumes that we are going to get - * widget numbers from 8 thru F and the device numbers within - * widget from 0 thru 7. - */ -#define IIO_IIDEM_WIDGETDEV_MASK(w, d) ((u64)(1ULL << (8 * ((w) - 8) + (d)))) - -/* IO Interrupt Destination Register */ -#define IIO_IIDSR_SENT_SHIFT 28 -#define IIO_IIDSR_SENT_MASK 0x30000000 -#define IIO_IIDSR_ENB_SHIFT 24 -#define IIO_IIDSR_ENB_MASK 0x01000000 -#define IIO_IIDSR_NODE_SHIFT 9 -#define IIO_IIDSR_NODE_MASK 0x000ff700 -#define IIO_IIDSR_PI_ID_SHIFT 8 -#define IIO_IIDSR_PI_ID_MASK 0x00000100 -#define IIO_IIDSR_LVL_SHIFT 0 -#define IIO_IIDSR_LVL_MASK 0x000000ff - -/* Xtalk timeout threshold register (IIO_IXTT) */ -#define IXTT_RRSP_TO_SHFT 55 /* read response timeout */ -#define IXTT_RRSP_TO_MASK (0x1FULL << IXTT_RRSP_TO_SHFT) -#define IXTT_RRSP_PS_SHFT 32 /* read responsed TO prescalar */ -#define IXTT_RRSP_PS_MASK (0x7FFFFFULL << IXTT_RRSP_PS_SHFT) -#define IXTT_TAIL_TO_SHFT 0 /* tail timeout counter threshold */ -#define IXTT_TAIL_TO_MASK (0x3FFFFFFULL << IXTT_TAIL_TO_SHFT) - -/* - * The IO LLP control status register and widget control register - */ - -typedef union hubii_wcr_u { - u64 wcr_reg_value; - struct { - u64 wcr_widget_id:4, /* LLP crossbar credit */ - wcr_tag_mode:1, /* Tag mode */ - wcr_rsvd1:8, /* Reserved */ - wcr_xbar_crd:3, /* LLP crossbar credit */ - wcr_f_bad_pkt:1, /* Force bad llp pkt enable */ - wcr_dir_con:1, /* widget direct connect */ - wcr_e_thresh:5, /* elasticity threshold */ - wcr_rsvd:41; /* unused */ - } wcr_fields_s; -} hubii_wcr_t; - -#define iwcr_dir_con wcr_fields_s.wcr_dir_con - -/* The structures below are defined to extract and modify the ii -performance registers */ - -/* io_perf_sel allows the caller to specify what tests will be - performed */ - -typedef union io_perf_sel { - u64 perf_sel_reg; - struct { - u64 perf_ippr0:4, perf_ippr1:4, perf_icct:8, perf_rsvd:48; - } perf_sel_bits; -} io_perf_sel_t; - -/* io_perf_cnt is to extract the count from the shub registers. Due to - hardware problems there is only one counter, not two. */ - -typedef union io_perf_cnt { - u64 perf_cnt; - struct { - u64 perf_cnt:20, perf_rsvd2:12, perf_rsvd1:32; - } perf_cnt_bits; - -} io_perf_cnt_t; - -typedef union iprte_a { - u64 entry; - struct { - u64 i_rsvd_1:3; - u64 i_addr:38; - u64 i_init:3; - u64 i_source:8; - u64 i_rsvd:2; - u64 i_widget:4; - u64 i_to_cnt:5; - u64 i_vld:1; - } iprte_fields; -} iprte_a_t; - -#endif /* _ASM_IA64_SN_SHUBIO_H */ diff --git a/arch/ia64/include/asm/sn/simulator.h b/arch/ia64/include/asm/sn/simulator.h deleted file mode 100644 index c2611f6cfe3336b393c7f2d99c839b294c326c78..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/simulator.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_SIMULATOR_H -#define _ASM_IA64_SN_SIMULATOR_H - -#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) || defined(CONFIG_IA64_SGI_UV) -#define SNMAGIC 0xaeeeeeee8badbeefL -#define IS_MEDUSA() ({long sn; asm("mov %0=cpuid[%1]" : "=r"(sn) : "r"(2)); sn == SNMAGIC;}) - -#define SIMULATOR_SLEEP() asm("nop.i 0x8beef") -#define IS_RUNNING_ON_SIMULATOR() (sn_prom_type) -#define IS_RUNNING_ON_FAKE_PROM() (sn_prom_type == 2) -extern int sn_prom_type; /* 0=hardware, 1=medusa/realprom, 2=medusa/fakeprom */ -#else -#define IS_MEDUSA() 0 -#define SIMULATOR_SLEEP() -#define IS_RUNNING_ON_SIMULATOR() 0 -#endif - -#endif /* _ASM_IA64_SN_SIMULATOR_H */ diff --git a/arch/ia64/include/asm/sn/sn2/sn_hwperf.h b/arch/ia64/include/asm/sn/sn2/sn_hwperf.h deleted file mode 100644 index e61ebac38cdd57b32a7529c0ac81e4bcfecfb573..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/sn2/sn_hwperf.h +++ /dev/null @@ -1,242 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved. - * - * Data types used by the SN_SAL_HWPERF_OP SAL call for monitoring - * SGI Altix node and router hardware - * - * Mark Goodwin Mon Aug 30 12:23:46 EST 2004 - */ - -#ifndef SN_HWPERF_H -#define SN_HWPERF_H - -/* - * object structure. SN_HWPERF_ENUM_OBJECTS and SN_HWPERF_GET_CPU_INFO - * return an array of these. Do not change this without also - * changing the corresponding SAL code. - */ -#define SN_HWPERF_MAXSTRING 128 -struct sn_hwperf_object_info { - u32 id; - union { - struct { - u64 this_part:1; - u64 is_shared:1; - } fields; - struct { - u64 flags; - u64 reserved; - } b; - } f; - char name[SN_HWPERF_MAXSTRING]; - char location[SN_HWPERF_MAXSTRING]; - u32 ports; -}; - -#define sn_hwp_this_part f.fields.this_part -#define sn_hwp_is_shared f.fields.is_shared -#define sn_hwp_flags f.b.flags - -/* macros for object classification */ -#define SN_HWPERF_IS_NODE(x) ((x) && strstr((x)->name, "SHub")) -#define SN_HWPERF_IS_NODE_SHUB2(x) ((x) && strstr((x)->name, "SHub 2.")) -#define SN_HWPERF_IS_IONODE(x) ((x) && strstr((x)->name, "TIO")) -#define SN_HWPERF_IS_NL3ROUTER(x) ((x) && strstr((x)->name, "NL3Router")) -#define SN_HWPERF_IS_NL4ROUTER(x) ((x) && strstr((x)->name, "NL4Router")) -#define SN_HWPERF_IS_OLDROUTER(x) ((x) && strstr((x)->name, "Router")) -#define SN_HWPERF_IS_ROUTER(x) (SN_HWPERF_IS_NL3ROUTER(x) || \ - SN_HWPERF_IS_NL4ROUTER(x) || \ - SN_HWPERF_IS_OLDROUTER(x)) -#define SN_HWPERF_FOREIGN(x) ((x) && !(x)->sn_hwp_this_part && !(x)->sn_hwp_is_shared) -#define SN_HWPERF_SAME_OBJTYPE(x,y) ((SN_HWPERF_IS_NODE(x) && SN_HWPERF_IS_NODE(y)) ||\ - (SN_HWPERF_IS_IONODE(x) && SN_HWPERF_IS_IONODE(y)) ||\ - (SN_HWPERF_IS_ROUTER(x) && SN_HWPERF_IS_ROUTER(y))) - -/* numa port structure, SN_HWPERF_ENUM_PORTS returns an array of these */ -struct sn_hwperf_port_info { - u32 port; - u32 conn_id; - u32 conn_port; -}; - -/* for HWPERF_{GET,SET}_MMRS */ -struct sn_hwperf_data { - u64 addr; - u64 data; -}; - -/* user ioctl() argument, see below */ -struct sn_hwperf_ioctl_args { - u64 arg; /* argument, usually an object id */ - u64 sz; /* size of transfer */ - void *ptr; /* pointer to source/target */ - u32 v0; /* second return value */ -}; - -/* - * For SN_HWPERF_{GET,SET}_MMRS and SN_HWPERF_OBJECT_DISTANCE, - * sn_hwperf_ioctl_args.arg can be used to specify a CPU on which - * to call SAL, and whether to use an interprocessor interrupt - * or task migration in order to do so. If the CPU specified is - * SN_HWPERF_ARG_ANY_CPU, then the current CPU will be used. - */ -#define SN_HWPERF_ARG_ANY_CPU 0x7fffffffUL -#define SN_HWPERF_ARG_CPU_MASK 0x7fffffff00000000ULL -#define SN_HWPERF_ARG_USE_IPI_MASK 0x8000000000000000ULL -#define SN_HWPERF_ARG_OBJID_MASK 0x00000000ffffffffULL - -/* - * ioctl requests on the "sn_hwperf" misc device that call SAL. - */ -#define SN_HWPERF_OP_MEM_COPYIN 0x1000 -#define SN_HWPERF_OP_MEM_COPYOUT 0x2000 -#define SN_HWPERF_OP_MASK 0x0fff - -/* - * Determine mem requirement. - * arg don't care - * sz 8 - * p pointer to u64 integer - */ -#define SN_HWPERF_GET_HEAPSIZE 1 - -/* - * Install mem for SAL drvr - * arg don't care - * sz sizeof buffer pointed to by p - * p pointer to buffer for scratch area - */ -#define SN_HWPERF_INSTALL_HEAP 2 - -/* - * Determine number of objects - * arg don't care - * sz 8 - * p pointer to u64 integer - */ -#define SN_HWPERF_OBJECT_COUNT (10|SN_HWPERF_OP_MEM_COPYOUT) - -/* - * Determine object "distance", relative to a cpu. This operation can - * execute on a designated logical cpu number, using either an IPI or - * via task migration. If the cpu number is SN_HWPERF_ANY_CPU, then - * the current CPU is used. See the SN_HWPERF_ARG_* macros above. - * - * arg bitmap of IPI flag, cpu number and object id - * sz 8 - * p pointer to u64 integer - */ -#define SN_HWPERF_OBJECT_DISTANCE (11|SN_HWPERF_OP_MEM_COPYOUT) - -/* - * Enumerate objects. Special case if sz == 8, returns the required - * buffer size. - * arg don't care - * sz sizeof buffer pointed to by p - * p pointer to array of struct sn_hwperf_object_info - */ -#define SN_HWPERF_ENUM_OBJECTS (12|SN_HWPERF_OP_MEM_COPYOUT) - -/* - * Enumerate NumaLink ports for an object. Special case if sz == 8, - * returns the required buffer size. - * arg object id - * sz sizeof buffer pointed to by p - * p pointer to array of struct sn_hwperf_port_info - */ -#define SN_HWPERF_ENUM_PORTS (13|SN_HWPERF_OP_MEM_COPYOUT) - -/* - * SET/GET memory mapped registers. These operations can execute - * on a designated logical cpu number, using either an IPI or via - * task migration. If the cpu number is SN_HWPERF_ANY_CPU, then - * the current CPU is used. See the SN_HWPERF_ARG_* macros above. - * - * arg bitmap of ipi flag, cpu number and object id - * sz sizeof buffer pointed to by p - * p pointer to array of struct sn_hwperf_data - */ -#define SN_HWPERF_SET_MMRS (14|SN_HWPERF_OP_MEM_COPYIN) -#define SN_HWPERF_GET_MMRS (15|SN_HWPERF_OP_MEM_COPYOUT| \ - SN_HWPERF_OP_MEM_COPYIN) -/* - * Lock a shared object - * arg object id - * sz don't care - * p don't care - */ -#define SN_HWPERF_ACQUIRE 16 - -/* - * Unlock a shared object - * arg object id - * sz don't care - * p don't care - */ -#define SN_HWPERF_RELEASE 17 - -/* - * Break a lock on a shared object - * arg object id - * sz don't care - * p don't care - */ -#define SN_HWPERF_FORCE_RELEASE 18 - -/* - * ioctl requests on "sn_hwperf" that do not call SAL - */ - -/* - * get cpu info as an array of hwperf_object_info_t. - * id is logical CPU number, name is description, location - * is geoid (e.g. 001c04#1c). Special case if sz == 8, - * returns the required buffer size. - * - * arg don't care - * sz sizeof buffer pointed to by p - * p pointer to array of struct sn_hwperf_object_info - */ -#define SN_HWPERF_GET_CPU_INFO (100|SN_HWPERF_OP_MEM_COPYOUT) - -/* - * Given an object id, return it's node number (aka cnode). - * arg object id - * sz 8 - * p pointer to u64 integer - */ -#define SN_HWPERF_GET_OBJ_NODE (101|SN_HWPERF_OP_MEM_COPYOUT) - -/* - * Given a node number (cnode), return it's nasid. - * arg ordinal node number (aka cnodeid) - * sz 8 - * p pointer to u64 integer - */ -#define SN_HWPERF_GET_NODE_NASID (102|SN_HWPERF_OP_MEM_COPYOUT) - -/* - * Given a node id, determine the id of the nearest node with CPUs - * and the id of the nearest node that has memory. The argument - * node would normally be a "headless" node, e.g. an "IO node". - * Return 0 on success. - */ -extern int sn_hwperf_get_nearest_node(cnodeid_t node, - cnodeid_t *near_mem, cnodeid_t *near_cpu); - -/* return codes */ -#define SN_HWPERF_OP_OK 0 -#define SN_HWPERF_OP_NOMEM 1 -#define SN_HWPERF_OP_NO_PERM 2 -#define SN_HWPERF_OP_IO_ERROR 3 -#define SN_HWPERF_OP_BUSY 4 -#define SN_HWPERF_OP_RECONFIGURE 253 -#define SN_HWPERF_OP_INVAL 254 - -int sn_topology_open(struct inode *inode, struct file *file); -int sn_topology_release(struct inode *inode, struct file *file); -#endif /* SN_HWPERF_H */ diff --git a/arch/ia64/include/asm/sn/sn_cpuid.h b/arch/ia64/include/asm/sn/sn_cpuid.h deleted file mode 100644 index a676dd9ace3eb2dceba652dea92761ea56d93842..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/sn_cpuid.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved. - */ - - -#ifndef _ASM_IA64_SN_SN_CPUID_H -#define _ASM_IA64_SN_SN_CPUID_H - -#include -#include -#include -#include - - -/* - * Functions for converting between cpuids, nodeids and NASIDs. - * - * These are for SGI platforms only. - * - */ - - - - -/* - * Definitions of terms (these definitions are for IA64 ONLY. Other architectures - * use cpuid/cpunum quite defferently): - * - * CPUID - a number in range of 0..NR_CPUS-1 that uniquely identifies - * the cpu. The value cpuid has no significance on IA64 other than - * the boot cpu is 0. - * smp_processor_id() returns the cpuid of the current cpu. - * - * CPU_PHYSICAL_ID (also known as HARD_PROCESSOR_ID) - * This is the same as 31:24 of the processor LID register - * hard_smp_processor_id()- cpu_physical_id of current processor - * cpu_physical_id(cpuid) - convert a to a - * cpu_logical_id(phy_id) - convert a to a - * * not real efficient - don't use in perf critical code - * - * SLICE - a number in the range of 0 - 3 (typically) that represents the - * cpu number on a brick. - * - * SUBNODE - (almost obsolete) the number of the FSB that a cpu is - * connected to. This is also the same as the PI number. Usually 0 or 1. - * - * NOTE!!!: the value of the bits in the cpu physical id (SAPICid or LID) of a cpu has no - * significance. The SAPIC id (LID) is a 16-bit cookie that has meaning only to the PROM. - * - * - * The macros convert between cpu physical ids & slice/nasid/cnodeid. - * These terms are described below: - * - * - * Brick - * ----- ----- ----- ----- CPU - * | 0 | | 1 | | 0 | | 1 | SLICE - * ----- ----- ----- ----- - * | | | | - * | | | | - * 0 | | 2 0 | | 2 FSB SLOT - * ------- ------- - * | | - * | | - * | | - * ------------ ------------- - * | | | | - * | SHUB | | SHUB | NASID (0..MAX_NASIDS) - * | |----- | | CNODEID (0..num_compact_nodes-1) - * | | | | - * | | | | - * ------------ ------------- - * | | - * - * - */ - -#define get_node_number(addr) NASID_GET(addr) - -/* - * NOTE: on non-MP systems, only cpuid 0 exists - */ - -extern short physical_node_map[]; /* indexed by nasid to get cnode */ - -/* - * Macros for retrieving info about current cpu - */ -#define get_nasid() (sn_nodepda->phys_cpuid[smp_processor_id()].nasid) -#define get_subnode() (sn_nodepda->phys_cpuid[smp_processor_id()].subnode) -#define get_slice() (sn_nodepda->phys_cpuid[smp_processor_id()].slice) -#define get_cnode() (sn_nodepda->phys_cpuid[smp_processor_id()].cnode) -#define get_sapicid() ((ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff) - -/* - * Macros for retrieving info about an arbitrary cpu - * cpuid - logical cpu id - */ -#define cpuid_to_nasid(cpuid) (sn_nodepda->phys_cpuid[cpuid].nasid) -#define cpuid_to_subnode(cpuid) (sn_nodepda->phys_cpuid[cpuid].subnode) -#define cpuid_to_slice(cpuid) (sn_nodepda->phys_cpuid[cpuid].slice) - - -/* - * Dont use the following in performance critical code. They require scans - * of potentially large tables. - */ -extern int nasid_slice_to_cpuid(int, int); - -/* - * cnodeid_to_nasid - convert a cnodeid to a NASID - */ -#define cnodeid_to_nasid(cnodeid) (sn_cnodeid_to_nasid[cnodeid]) - -/* - * nasid_to_cnodeid - convert a NASID to a cnodeid - */ -#define nasid_to_cnodeid(nasid) (physical_node_map[nasid]) - -/* - * partition_coherence_id - get the coherence ID of the current partition - */ -extern u8 sn_coherency_id; -#define partition_coherence_id() (sn_coherency_id) - -#endif /* _ASM_IA64_SN_SN_CPUID_H */ - diff --git a/arch/ia64/include/asm/sn/sn_feature_sets.h b/arch/ia64/include/asm/sn/sn_feature_sets.h deleted file mode 100644 index 8e83ac117aceb73863d0e0315a26ee938eed6151..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/sn_feature_sets.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _ASM_IA64_SN_FEATURE_SETS_H -#define _ASM_IA64_SN_FEATURE_SETS_H - -/* - * SN PROM Features - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2005-2006 Silicon Graphics, Inc. All rights reserved. - */ - - -/* --------------------- PROM Features -----------------------------*/ -extern int sn_prom_feature_available(int id); - -#define MAX_PROM_FEATURE_SETS 2 - -/* - * The following defines features that may or may not be supported by the - * current PROM. The OS uses sn_prom_feature_available(feature) to test for - * the presence of a PROM feature. Down rev (old) PROMs will always test - * "false" for new features. - * - * Use: - * if (sn_prom_feature_available(PRF_XXX)) - * ... - */ - -#define PRF_PAL_CACHE_FLUSH_SAFE 0 -#define PRF_DEVICE_FLUSH_LIST 1 -#define PRF_HOTPLUG_SUPPORT 2 -#define PRF_CPU_DISABLE_SUPPORT 3 - -/* --------------------- OS Features -------------------------------*/ - -/* - * The following defines OS features that are optionally present in - * the operating system. - * During boot, PROM is notified of these features via a series of calls: - * - * ia64_sn_set_os_feature(feature1); - * - * Once enabled, a feature cannot be disabled. - * - * By default, features are disabled unless explicitly enabled. - * - * These defines must be kept in sync with the corresponding - * PROM definitions in feature_sets.h. - */ -#define OSF_MCA_SLV_TO_OS_INIT_SLV 0 -#define OSF_FEAT_LOG_SBES 1 -#define OSF_ACPI_ENABLE 2 -#define OSF_PCISEGMENT_ENABLE 3 - - -#endif /* _ASM_IA64_SN_FEATURE_SETS_H */ diff --git a/arch/ia64/include/asm/sn/sn_sal.h b/arch/ia64/include/asm/sn/sn_sal.h index 1f5ff470a5a18336dabfd257a94cbf5576ad4055..d437aa43343b348909f93b32b5e56565c4fce43a 100644 --- a/arch/ia64/include/asm/sn/sn_sal.h +++ b/arch/ia64/include/asm/sn/sn_sal.h @@ -11,139 +11,16 @@ * Copyright (c) 2000-2006 Silicon Graphics, Inc. All rights reserved. */ - +#include #include -#include -#include -#include -#include -#include // SGI Specific Calls -#define SN_SAL_POD_MODE 0x02000001 -#define SN_SAL_SYSTEM_RESET 0x02000002 -#define SN_SAL_PROBE 0x02000003 -#define SN_SAL_GET_MASTER_NASID 0x02000004 -#define SN_SAL_GET_KLCONFIG_ADDR 0x02000005 -#define SN_SAL_LOG_CE 0x02000006 -#define SN_SAL_REGISTER_CE 0x02000007 #define SN_SAL_GET_PARTITION_ADDR 0x02000009 -#define SN_SAL_XP_ADDR_REGION 0x0200000f -#define SN_SAL_NO_FAULT_ZONE_VIRTUAL 0x02000010 -#define SN_SAL_NO_FAULT_ZONE_PHYSICAL 0x02000011 -#define SN_SAL_PRINT_ERROR 0x02000012 -#define SN_SAL_REGISTER_PMI_HANDLER 0x02000014 -#define SN_SAL_SET_ERROR_HANDLING_FEATURES 0x0200001a // reentrant -#define SN_SAL_GET_FIT_COMPT 0x0200001b // reentrant -#define SN_SAL_GET_SAPIC_INFO 0x0200001d -#define SN_SAL_GET_SN_INFO 0x0200001e -#define SN_SAL_CONSOLE_PUTC 0x02000021 -#define SN_SAL_CONSOLE_GETC 0x02000022 -#define SN_SAL_CONSOLE_PUTS 0x02000023 -#define SN_SAL_CONSOLE_GETS 0x02000024 -#define SN_SAL_CONSOLE_GETS_TIMEOUT 0x02000025 -#define SN_SAL_CONSOLE_POLL 0x02000026 -#define SN_SAL_CONSOLE_INTR 0x02000027 -#define SN_SAL_CONSOLE_PUTB 0x02000028 -#define SN_SAL_CONSOLE_XMIT_CHARS 0x0200002a -#define SN_SAL_CONSOLE_READC 0x0200002b -#define SN_SAL_SYSCTL_OP 0x02000030 -#define SN_SAL_SYSCTL_MODID_GET 0x02000031 -#define SN_SAL_SYSCTL_GET 0x02000032 -#define SN_SAL_SYSCTL_IOBRICK_MODULE_GET 0x02000033 -#define SN_SAL_SYSCTL_IO_PORTSPEED_GET 0x02000035 -#define SN_SAL_SYSCTL_SLAB_GET 0x02000036 -#define SN_SAL_BUS_CONFIG 0x02000037 -#define SN_SAL_SYS_SERIAL_GET 0x02000038 -#define SN_SAL_PARTITION_SERIAL_GET 0x02000039 -#define SN_SAL_SYSCTL_PARTITION_GET 0x0200003a -#define SN_SAL_SYSTEM_POWER_DOWN 0x0200003b -#define SN_SAL_GET_MASTER_BASEIO_NASID 0x0200003c -#define SN_SAL_COHERENCE 0x0200003d #define SN_SAL_MEMPROTECT 0x0200003e -#define SN_SAL_SYSCTL_FRU_CAPTURE 0x0200003f - -#define SN_SAL_SYSCTL_IOBRICK_PCI_OP 0x02000042 // reentrant -#define SN_SAL_IROUTER_OP 0x02000043 -#define SN_SAL_SYSCTL_EVENT 0x02000044 -#define SN_SAL_IOIF_INTERRUPT 0x0200004a -#define SN_SAL_HWPERF_OP 0x02000050 // lock -#define SN_SAL_IOIF_ERROR_INTERRUPT 0x02000051 -#define SN_SAL_IOIF_PCI_SAFE 0x02000052 -#define SN_SAL_IOIF_SLOT_ENABLE 0x02000053 -#define SN_SAL_IOIF_SLOT_DISABLE 0x02000054 -#define SN_SAL_IOIF_GET_HUBDEV_INFO 0x02000055 -#define SN_SAL_IOIF_GET_PCIBUS_INFO 0x02000056 -#define SN_SAL_IOIF_GET_PCIDEV_INFO 0x02000057 -#define SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST 0x02000058 // deprecated -#define SN_SAL_IOIF_GET_DEVICE_DMAFLUSH_LIST 0x0200005a - -#define SN_SAL_IOIF_INIT 0x0200005f -#define SN_SAL_HUB_ERROR_INTERRUPT 0x02000060 -#define SN_SAL_BTE_RECOVER 0x02000061 -#define SN_SAL_RESERVED_DO_NOT_USE 0x02000062 -#define SN_SAL_IOIF_GET_PCI_TOPOLOGY 0x02000064 - -#define SN_SAL_GET_PROM_FEATURE_SET 0x02000065 -#define SN_SAL_SET_OS_FEATURE_SET 0x02000066 -#define SN_SAL_INJECT_ERROR 0x02000067 -#define SN_SAL_SET_CPU_NUMBER 0x02000068 -#define SN_SAL_KERNEL_LAUNCH_EVENT 0x02000069 #define SN_SAL_WATCHLIST_ALLOC 0x02000070 #define SN_SAL_WATCHLIST_FREE 0x02000071 -/* - * Service-specific constants - */ - -/* Console interrupt manipulation */ - /* action codes */ -#define SAL_CONSOLE_INTR_OFF 0 /* turn the interrupt off */ -#define SAL_CONSOLE_INTR_ON 1 /* turn the interrupt on */ -#define SAL_CONSOLE_INTR_STATUS 2 /* retrieve the interrupt status */ - /* interrupt specification & status return codes */ -#define SAL_CONSOLE_INTR_XMIT 1 /* output interrupt */ -#define SAL_CONSOLE_INTR_RECV 2 /* input interrupt */ - -/* interrupt handling */ -#define SAL_INTR_ALLOC 1 -#define SAL_INTR_FREE 2 -#define SAL_INTR_REDIRECT 3 - -/* - * operations available on the generic SN_SAL_SYSCTL_OP - * runtime service - */ -#define SAL_SYSCTL_OP_IOBOARD 0x0001 /* retrieve board type */ -#define SAL_SYSCTL_OP_TIO_JLCK_RST 0x0002 /* issue TIO clock reset */ - -/* - * IRouter (i.e. generalized system controller) operations - */ -#define SAL_IROUTER_OPEN 0 /* open a subchannel */ -#define SAL_IROUTER_CLOSE 1 /* close a subchannel */ -#define SAL_IROUTER_SEND 2 /* send part of an IRouter packet */ -#define SAL_IROUTER_RECV 3 /* receive part of an IRouter packet */ -#define SAL_IROUTER_INTR_STATUS 4 /* check the interrupt status for - * an open subchannel - */ -#define SAL_IROUTER_INTR_ON 5 /* enable an interrupt */ -#define SAL_IROUTER_INTR_OFF 6 /* disable an interrupt */ -#define SAL_IROUTER_INIT 7 /* initialize IRouter driver */ - -/* IRouter interrupt mask bits */ -#define SAL_IROUTER_INTR_XMIT SAL_CONSOLE_INTR_XMIT -#define SAL_IROUTER_INTR_RECV SAL_CONSOLE_INTR_RECV - -/* - * Error Handling Features - */ -#define SAL_ERR_FEAT_MCA_SLV_TO_OS_INIT_SLV 0x1 // obsolete -#define SAL_ERR_FEAT_LOG_SBES 0x2 // obsolete -#define SAL_ERR_FEAT_MFR_OVERRIDE 0x4 -#define SAL_ERR_FEAT_SBE_THRESHOLD 0xffff0000 - /* * SAL Error Codes */ @@ -153,458 +30,6 @@ #define SALRET_INVALID_ARG (-2) #define SALRET_ERROR (-3) -#define SN_SAL_FAKE_PROM 0x02009999 - -/** - * sn_sal_revision - get the SGI SAL revision number - * - * The SGI PROM stores its version in the sal_[ab]_rev_(major|minor). - * This routine simply extracts the major and minor values and - * presents them in a u32 format. - * - * For example, version 4.05 would be represented at 0x0405. - */ -static inline u32 -sn_sal_rev(void) -{ - struct ia64_sal_systab *systab = __va(efi.sal_systab); - - return (u32)(systab->sal_b_rev_major << 8 | systab->sal_b_rev_minor); -} - -/* - * Returns the master console nasid, if the call fails, return an illegal - * value. - */ -static inline u64 -ia64_sn_get_console_nasid(void) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL(ret_stuff, SN_SAL_GET_MASTER_NASID, 0, 0, 0, 0, 0, 0, 0); - - if (ret_stuff.status < 0) - return ret_stuff.status; - - /* Master console nasid is in 'v0' */ - return ret_stuff.v0; -} - -/* - * Returns the master baseio nasid, if the call fails, return an illegal - * value. - */ -static inline u64 -ia64_sn_get_master_baseio_nasid(void) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL(ret_stuff, SN_SAL_GET_MASTER_BASEIO_NASID, 0, 0, 0, 0, 0, 0, 0); - - if (ret_stuff.status < 0) - return ret_stuff.status; - - /* Master baseio nasid is in 'v0' */ - return ret_stuff.v0; -} - -static inline void * -ia64_sn_get_klconfig_addr(nasid_t nasid) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL(ret_stuff, SN_SAL_GET_KLCONFIG_ADDR, (u64)nasid, 0, 0, 0, 0, 0, 0); - return ret_stuff.v0 ? __va(ret_stuff.v0) : NULL; -} - -/* - * Returns the next console character. - */ -static inline u64 -ia64_sn_console_getc(int *ch) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_GETC, 0, 0, 0, 0, 0, 0, 0); - - /* character is in 'v0' */ - *ch = (int)ret_stuff.v0; - - return ret_stuff.status; -} - -/* - * Read a character from the SAL console device, after a previous interrupt - * or poll operation has given us to know that a character is available - * to be read. - */ -static inline u64 -ia64_sn_console_readc(void) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_READC, 0, 0, 0, 0, 0, 0, 0); - - /* character is in 'v0' */ - return ret_stuff.v0; -} - -/* - * Sends the given character to the console. - */ -static inline u64 -ia64_sn_console_putc(char ch) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_PUTC, (u64)ch, 0, 0, 0, 0, 0, 0); - - return ret_stuff.status; -} - -/* - * Sends the given buffer to the console. - */ -static inline u64 -ia64_sn_console_putb(const char *buf, int len) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_PUTB, (u64)buf, (u64)len, 0, 0, 0, 0, 0); - - if ( ret_stuff.status == 0 ) { - return ret_stuff.v0; - } - return (u64)0; -} - -/* - * Print a platform error record - */ -static inline u64 -ia64_sn_plat_specific_err_print(int (*hook)(const char*, ...), char *rec) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL_REENTRANT(ret_stuff, SN_SAL_PRINT_ERROR, (u64)hook, (u64)rec, 0, 0, 0, 0, 0); - - return ret_stuff.status; -} - -/* - * Check for Platform errors - */ -static inline u64 -ia64_sn_plat_cpei_handler(void) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL_NOLOCK(ret_stuff, SN_SAL_LOG_CE, 0, 0, 0, 0, 0, 0, 0); - - return ret_stuff.status; -} - -/* - * Set Error Handling Features (Obsolete) - */ -static inline u64 -ia64_sn_plat_set_error_handling_features(void) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL_REENTRANT(ret_stuff, SN_SAL_SET_ERROR_HANDLING_FEATURES, - SAL_ERR_FEAT_LOG_SBES, - 0, 0, 0, 0, 0, 0); - - return ret_stuff.status; -} - -/* - * Checks for console input. - */ -static inline u64 -ia64_sn_console_check(int *result) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_POLL, 0, 0, 0, 0, 0, 0, 0); - - /* result is in 'v0' */ - *result = (int)ret_stuff.v0; - - return ret_stuff.status; -} - -/* - * Checks console interrupt status - */ -static inline u64 -ia64_sn_console_intr_status(void) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_INTR, - 0, SAL_CONSOLE_INTR_STATUS, - 0, 0, 0, 0, 0); - - if (ret_stuff.status == 0) { - return ret_stuff.v0; - } - - return 0; -} - -/* - * Enable an interrupt on the SAL console device. - */ -static inline void -ia64_sn_console_intr_enable(u64 intr) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_INTR, - intr, SAL_CONSOLE_INTR_ON, - 0, 0, 0, 0, 0); -} - -/* - * Disable an interrupt on the SAL console device. - */ -static inline void -ia64_sn_console_intr_disable(u64 intr) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_INTR, - intr, SAL_CONSOLE_INTR_OFF, - 0, 0, 0, 0, 0); -} - -/* - * Sends a character buffer to the console asynchronously. - */ -static inline u64 -ia64_sn_console_xmit_chars(char *buf, int len) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_XMIT_CHARS, - (u64)buf, (u64)len, - 0, 0, 0, 0, 0); - - if (ret_stuff.status == 0) { - return ret_stuff.v0; - } - - return 0; -} - -/* - * Returns the iobrick module Id - */ -static inline u64 -ia64_sn_sysctl_iobrick_module_get(nasid_t nasid, int *result) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL_NOLOCK(ret_stuff, SN_SAL_SYSCTL_IOBRICK_MODULE_GET, nasid, 0, 0, 0, 0, 0, 0); - - /* result is in 'v0' */ - *result = (int)ret_stuff.v0; - - return ret_stuff.status; -} - -/** - * ia64_sn_pod_mode - call the SN_SAL_POD_MODE function - * - * SN_SAL_POD_MODE actually takes an argument, but it's always - * 0 when we call it from the kernel, so we don't have to expose - * it to the caller. - */ -static inline u64 -ia64_sn_pod_mode(void) -{ - struct ia64_sal_retval isrv; - SAL_CALL_REENTRANT(isrv, SN_SAL_POD_MODE, 0, 0, 0, 0, 0, 0, 0); - if (isrv.status) - return 0; - return isrv.v0; -} - -/** - * ia64_sn_probe_mem - read from memory safely - * @addr: address to probe - * @size: number bytes to read (1,2,4,8) - * @data_ptr: address to store value read by probe (-1 returned if probe fails) - * - * Call into the SAL to do a memory read. If the read generates a machine - * check, this routine will recover gracefully and return -1 to the caller. - * @addr is usually a kernel virtual address in uncached space (i.e. the - * address starts with 0xc), but if called in physical mode, @addr should - * be a physical address. - * - * Return values: - * 0 - probe successful - * 1 - probe failed (generated MCA) - * 2 - Bad arg - * <0 - PAL error - */ -static inline u64 -ia64_sn_probe_mem(long addr, long size, void *data_ptr) -{ - struct ia64_sal_retval isrv; - - SAL_CALL(isrv, SN_SAL_PROBE, addr, size, 0, 0, 0, 0, 0); - - if (data_ptr) { - switch (size) { - case 1: - *((u8*)data_ptr) = (u8)isrv.v0; - break; - case 2: - *((u16*)data_ptr) = (u16)isrv.v0; - break; - case 4: - *((u32*)data_ptr) = (u32)isrv.v0; - break; - case 8: - *((u64*)data_ptr) = (u64)isrv.v0; - break; - default: - isrv.status = 2; - } - } - return isrv.status; -} - -/* - * Retrieve the system serial number as an ASCII string. - */ -static inline u64 -ia64_sn_sys_serial_get(char *buf) -{ - struct ia64_sal_retval ret_stuff; - SAL_CALL_NOLOCK(ret_stuff, SN_SAL_SYS_SERIAL_GET, buf, 0, 0, 0, 0, 0, 0); - return ret_stuff.status; -} - -extern char sn_system_serial_number_string[]; -extern u64 sn_partition_serial_number; - -static inline char * -sn_system_serial_number(void) { - if (sn_system_serial_number_string[0]) { - return(sn_system_serial_number_string); - } else { - ia64_sn_sys_serial_get(sn_system_serial_number_string); - return(sn_system_serial_number_string); - } -} - - -/* - * Returns a unique id number for this system and partition (suitable for - * use with license managers), based in part on the system serial number. - */ -static inline u64 -ia64_sn_partition_serial_get(void) -{ - struct ia64_sal_retval ret_stuff; - ia64_sal_oemcall_reentrant(&ret_stuff, SN_SAL_PARTITION_SERIAL_GET, 0, - 0, 0, 0, 0, 0, 0); - if (ret_stuff.status != 0) - return 0; - return ret_stuff.v0; -} - -static inline u64 -sn_partition_serial_number_val(void) { - if (unlikely(sn_partition_serial_number == 0)) { - sn_partition_serial_number = ia64_sn_partition_serial_get(); - } - return sn_partition_serial_number; -} - -/* - * Returns the partition id of the nasid passed in as an argument, - * or INVALID_PARTID if the partition id cannot be retrieved. - */ -static inline partid_t -ia64_sn_sysctl_partition_get(nasid_t nasid) -{ - struct ia64_sal_retval ret_stuff; - SAL_CALL(ret_stuff, SN_SAL_SYSCTL_PARTITION_GET, nasid, - 0, 0, 0, 0, 0, 0); - if (ret_stuff.status != 0) - return -1; - return ((partid_t)ret_stuff.v0); -} - /* * Returns the physical address of the partition's reserved page through * an iterative number of calls. @@ -633,96 +58,6 @@ sn_partition_reserved_page_pa(u64 buf, u64 *cookie, u64 *addr, u64 *len) return rv.status; } -/* - * Register or unregister a physical address range being referenced across - * a partition boundary for which certain SAL errors should be scanned for, - * cleaned up and ignored. This is of value for kernel partitioning code only. - * Values for the operation argument: - * 1 = register this address range with SAL - * 0 = unregister this address range with SAL - * - * SAL maintains a reference count on an address range in case it is registered - * multiple times. - * - * On success, returns the reference count of the address range after the SAL - * call has performed the current registration/unregistration. Returns a - * negative value if an error occurred. - */ -static inline int -sn_register_xp_addr_region(u64 paddr, u64 len, int operation) -{ - struct ia64_sal_retval ret_stuff; - ia64_sal_oemcall(&ret_stuff, SN_SAL_XP_ADDR_REGION, paddr, len, - (u64)operation, 0, 0, 0, 0); - return ret_stuff.status; -} - -/* - * Register or unregister an instruction range for which SAL errors should - * be ignored. If an error occurs while in the registered range, SAL jumps - * to return_addr after ignoring the error. Values for the operation argument: - * 1 = register this instruction range with SAL - * 0 = unregister this instruction range with SAL - * - * Returns 0 on success, or a negative value if an error occurred. - */ -static inline int -sn_register_nofault_code(u64 start_addr, u64 end_addr, u64 return_addr, - int virtual, int operation) -{ - struct ia64_sal_retval ret_stuff; - u64 call; - if (virtual) { - call = SN_SAL_NO_FAULT_ZONE_VIRTUAL; - } else { - call = SN_SAL_NO_FAULT_ZONE_PHYSICAL; - } - ia64_sal_oemcall(&ret_stuff, call, start_addr, end_addr, return_addr, - (u64)1, 0, 0, 0); - return ret_stuff.status; -} - -/* - * Register or unregister a function to handle a PMI received by a CPU. - * Before calling the registered handler, SAL sets r1 to the value that - * was passed in as the global_pointer. - * - * If the handler pointer is NULL, then the currently registered handler - * will be unregistered. - * - * Returns 0 on success, or a negative value if an error occurred. - */ -static inline int -sn_register_pmi_handler(u64 handler, u64 global_pointer) -{ - struct ia64_sal_retval ret_stuff; - ia64_sal_oemcall(&ret_stuff, SN_SAL_REGISTER_PMI_HANDLER, handler, - global_pointer, 0, 0, 0, 0, 0); - return ret_stuff.status; -} - -/* - * Change or query the coherence domain for this partition. Each cpu-based - * nasid is represented by a bit in an array of 64-bit words: - * 0 = not in this partition's coherency domain - * 1 = in this partition's coherency domain - * - * It is not possible for the local system's nasids to be removed from - * the coherency domain. Purpose of the domain arguments: - * new_domain = set the coherence domain to the given nasids - * old_domain = return the current coherence domain - * - * Returns 0 on success, or a negative value if an error occurred. - */ -static inline int -sn_change_coherence(u64 *new_domain, u64 *old_domain) -{ - struct ia64_sal_retval ret_stuff; - ia64_sal_oemcall_nolock(&ret_stuff, SN_SAL_COHERENCE, (u64)new_domain, - (u64)old_domain, 0, 0, 0, 0, 0); - return ret_stuff.status; -} - /* * Change memory access protections for a physical address range. * nasid_array is not used on Altix, but may be in future architectures. @@ -744,450 +79,6 @@ sn_change_memprotect(u64 paddr, u64 len, u64 perms, u64 *nasid_array) #define SN_MEMPROT_ACCESS_CLASS_6 0x084080 #define SN_MEMPROT_ACCESS_CLASS_7 0x021080 -/* - * Turns off system power. - */ -static inline void -ia64_sn_power_down(void) -{ - struct ia64_sal_retval ret_stuff; - SAL_CALL(ret_stuff, SN_SAL_SYSTEM_POWER_DOWN, 0, 0, 0, 0, 0, 0, 0); - while(1) - cpu_relax(); - /* never returns */ -} - -/** - * ia64_sn_fru_capture - tell the system controller to capture hw state - * - * This routine will call the SAL which will tell the system controller(s) - * to capture hw mmr information from each SHub in the system. - */ -static inline u64 -ia64_sn_fru_capture(void) -{ - struct ia64_sal_retval isrv; - SAL_CALL(isrv, SN_SAL_SYSCTL_FRU_CAPTURE, 0, 0, 0, 0, 0, 0, 0); - if (isrv.status) - return 0; - return isrv.v0; -} - -/* - * Performs an operation on a PCI bus or slot -- power up, power down - * or reset. - */ -static inline u64 -ia64_sn_sysctl_iobrick_pci_op(nasid_t n, u64 connection_type, - u64 bus, char slot, - u64 action) -{ - struct ia64_sal_retval rv = {0, 0, 0, 0}; - - SAL_CALL_NOLOCK(rv, SN_SAL_SYSCTL_IOBRICK_PCI_OP, connection_type, n, action, - bus, (u64) slot, 0, 0); - if (rv.status) - return rv.v0; - return 0; -} - - -/* - * Open a subchannel for sending arbitrary data to the system - * controller network via the system controller device associated with - * 'nasid'. Return the subchannel number or a negative error code. - */ -static inline int -ia64_sn_irtr_open(nasid_t nasid) -{ - struct ia64_sal_retval rv; - SAL_CALL_REENTRANT(rv, SN_SAL_IROUTER_OP, SAL_IROUTER_OPEN, nasid, - 0, 0, 0, 0, 0); - return (int) rv.v0; -} - -/* - * Close system controller subchannel 'subch' previously opened on 'nasid'. - */ -static inline int -ia64_sn_irtr_close(nasid_t nasid, int subch) -{ - struct ia64_sal_retval rv; - SAL_CALL_REENTRANT(rv, SN_SAL_IROUTER_OP, SAL_IROUTER_CLOSE, - (u64) nasid, (u64) subch, 0, 0, 0, 0); - return (int) rv.status; -} - -/* - * Read data from system controller associated with 'nasid' on - * subchannel 'subch'. The buffer to be filled is pointed to by - * 'buf', and its capacity is in the integer pointed to by 'len'. The - * referent of 'len' is set to the number of bytes read by the SAL - * call. The return value is either SALRET_OK (for bytes read) or - * SALRET_ERROR (for error or "no data available"). - */ -static inline int -ia64_sn_irtr_recv(nasid_t nasid, int subch, char *buf, int *len) -{ - struct ia64_sal_retval rv; - SAL_CALL_REENTRANT(rv, SN_SAL_IROUTER_OP, SAL_IROUTER_RECV, - (u64) nasid, (u64) subch, (u64) buf, (u64) len, - 0, 0); - return (int) rv.status; -} - -/* - * Write data to the system controller network via the system - * controller associated with 'nasid' on suchannel 'subch'. The - * buffer to be written out is pointed to by 'buf', and 'len' is the - * number of bytes to be written. The return value is either the - * number of bytes written (which could be zero) or a negative error - * code. - */ -static inline int -ia64_sn_irtr_send(nasid_t nasid, int subch, char *buf, int len) -{ - struct ia64_sal_retval rv; - SAL_CALL_REENTRANT(rv, SN_SAL_IROUTER_OP, SAL_IROUTER_SEND, - (u64) nasid, (u64) subch, (u64) buf, (u64) len, - 0, 0); - return (int) rv.v0; -} - -/* - * Check whether any interrupts are pending for the system controller - * associated with 'nasid' and its subchannel 'subch'. The return - * value is a mask of pending interrupts (SAL_IROUTER_INTR_XMIT and/or - * SAL_IROUTER_INTR_RECV). - */ -static inline int -ia64_sn_irtr_intr(nasid_t nasid, int subch) -{ - struct ia64_sal_retval rv; - SAL_CALL_REENTRANT(rv, SN_SAL_IROUTER_OP, SAL_IROUTER_INTR_STATUS, - (u64) nasid, (u64) subch, 0, 0, 0, 0); - return (int) rv.v0; -} - -/* - * Enable the interrupt indicated by the intr parameter (either - * SAL_IROUTER_INTR_XMIT or SAL_IROUTER_INTR_RECV). - */ -static inline int -ia64_sn_irtr_intr_enable(nasid_t nasid, int subch, u64 intr) -{ - struct ia64_sal_retval rv; - SAL_CALL_REENTRANT(rv, SN_SAL_IROUTER_OP, SAL_IROUTER_INTR_ON, - (u64) nasid, (u64) subch, intr, 0, 0, 0); - return (int) rv.v0; -} - -/* - * Disable the interrupt indicated by the intr parameter (either - * SAL_IROUTER_INTR_XMIT or SAL_IROUTER_INTR_RECV). - */ -static inline int -ia64_sn_irtr_intr_disable(nasid_t nasid, int subch, u64 intr) -{ - struct ia64_sal_retval rv; - SAL_CALL_REENTRANT(rv, SN_SAL_IROUTER_OP, SAL_IROUTER_INTR_OFF, - (u64) nasid, (u64) subch, intr, 0, 0, 0); - return (int) rv.v0; -} - -/* - * Set up a node as the point of contact for system controller - * environmental event delivery. - */ -static inline int -ia64_sn_sysctl_event_init(nasid_t nasid) -{ - struct ia64_sal_retval rv; - SAL_CALL_REENTRANT(rv, SN_SAL_SYSCTL_EVENT, (u64) nasid, - 0, 0, 0, 0, 0, 0); - return (int) rv.v0; -} - -/* - * Ask the system controller on the specified nasid to reset - * the CX corelet clock. Only valid on TIO nodes. - */ -static inline int -ia64_sn_sysctl_tio_clock_reset(nasid_t nasid) -{ - struct ia64_sal_retval rv; - SAL_CALL_REENTRANT(rv, SN_SAL_SYSCTL_OP, SAL_SYSCTL_OP_TIO_JLCK_RST, - nasid, 0, 0, 0, 0, 0); - if (rv.status != 0) - return (int)rv.status; - if (rv.v0 != 0) - return (int)rv.v0; - - return 0; -} - -/* - * Get the associated ioboard type for a given nasid. - */ -static inline long -ia64_sn_sysctl_ioboard_get(nasid_t nasid, u16 *ioboard) -{ - struct ia64_sal_retval isrv; - SAL_CALL_REENTRANT(isrv, SN_SAL_SYSCTL_OP, SAL_SYSCTL_OP_IOBOARD, - nasid, 0, 0, 0, 0, 0); - if (isrv.v0 != 0) { - *ioboard = isrv.v0; - return isrv.status; - } - if (isrv.v1 != 0) { - *ioboard = isrv.v1; - return isrv.status; - } - - return isrv.status; -} - -/** - * ia64_sn_get_fit_compt - read a FIT entry from the PROM header - * @nasid: NASID of node to read - * @index: FIT entry index to be retrieved (0..n) - * @fitentry: 16 byte buffer where FIT entry will be stored. - * @banbuf: optional buffer for retrieving banner - * @banlen: length of banner buffer - * - * Access to the physical PROM chips needs to be serialized since reads and - * writes can't occur at the same time, so we need to call into the SAL when - * we want to look at the FIT entries on the chips. - * - * Returns: - * %SALRET_OK if ok - * %SALRET_INVALID_ARG if index too big - * %SALRET_NOT_IMPLEMENTED if running on older PROM - * ??? if nasid invalid OR banner buffer not large enough - */ -static inline int -ia64_sn_get_fit_compt(u64 nasid, u64 index, void *fitentry, void *banbuf, - u64 banlen) -{ - struct ia64_sal_retval rv; - SAL_CALL_NOLOCK(rv, SN_SAL_GET_FIT_COMPT, nasid, index, fitentry, - banbuf, banlen, 0, 0); - return (int) rv.status; -} - -/* - * Initialize the SAL components of the system controller - * communication driver; specifically pass in a sizable buffer that - * can be used for allocation of subchannel queues as new subchannels - * are opened. "buf" points to the buffer, and "len" specifies its - * length. - */ -static inline int -ia64_sn_irtr_init(nasid_t nasid, void *buf, int len) -{ - struct ia64_sal_retval rv; - SAL_CALL_REENTRANT(rv, SN_SAL_IROUTER_OP, SAL_IROUTER_INIT, - (u64) nasid, (u64) buf, (u64) len, 0, 0, 0); - return (int) rv.status; -} - -/* - * Returns the nasid, subnode & slice corresponding to a SAPIC ID - * - * In: - * arg0 - SN_SAL_GET_SAPIC_INFO - * arg1 - sapicid (lid >> 16) - * Out: - * v0 - nasid - * v1 - subnode - * v2 - slice - */ -static inline u64 -ia64_sn_get_sapic_info(int sapicid, int *nasid, int *subnode, int *slice) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL_NOLOCK(ret_stuff, SN_SAL_GET_SAPIC_INFO, sapicid, 0, 0, 0, 0, 0, 0); - -/***** BEGIN HACK - temp til old proms no longer supported ********/ - if (ret_stuff.status == SALRET_NOT_IMPLEMENTED) { - if (nasid) *nasid = sapicid & 0xfff; - if (subnode) *subnode = (sapicid >> 13) & 1; - if (slice) *slice = (sapicid >> 12) & 3; - return 0; - } -/***** END HACK *******/ - - if (ret_stuff.status < 0) - return ret_stuff.status; - - if (nasid) *nasid = (int) ret_stuff.v0; - if (subnode) *subnode = (int) ret_stuff.v1; - if (slice) *slice = (int) ret_stuff.v2; - return 0; -} - -/* - * Returns information about the HUB/SHUB. - * In: - * arg0 - SN_SAL_GET_SN_INFO - * arg1 - 0 (other values reserved for future use) - * Out: - * v0 - * [7:0] - shub type (0=shub1, 1=shub2) - * [15:8] - Log2 max number of nodes in entire system (includes - * C-bricks, I-bricks, etc) - * [23:16] - Log2 of nodes per sharing domain - * [31:24] - partition ID - * [39:32] - coherency_id - * [47:40] - regionsize - * v1 - * [15:0] - nasid mask (ex., 0x7ff for 11 bit nasid) - * [23:15] - bit position of low nasid bit - */ -static inline u64 -ia64_sn_get_sn_info(int fc, u8 *shubtype, u16 *nasid_bitmask, u8 *nasid_shift, - u8 *systemsize, u8 *sharing_domain_size, u8 *partid, u8 *coher, u8 *reg) -{ - struct ia64_sal_retval ret_stuff; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - ret_stuff.v1 = 0; - ret_stuff.v2 = 0; - SAL_CALL_NOLOCK(ret_stuff, SN_SAL_GET_SN_INFO, fc, 0, 0, 0, 0, 0, 0); - -/***** BEGIN HACK - temp til old proms no longer supported ********/ - if (ret_stuff.status == SALRET_NOT_IMPLEMENTED) { - int nasid = get_sapicid() & 0xfff; -#define SH_SHUB_ID_NODES_PER_BIT_MASK 0x001f000000000000UL -#define SH_SHUB_ID_NODES_PER_BIT_SHFT 48 - if (shubtype) *shubtype = 0; - if (nasid_bitmask) *nasid_bitmask = 0x7ff; - if (nasid_shift) *nasid_shift = 38; - if (systemsize) *systemsize = 10; - if (sharing_domain_size) *sharing_domain_size = 8; - if (partid) *partid = ia64_sn_sysctl_partition_get(nasid); - if (coher) *coher = nasid >> 9; - if (reg) *reg = (HUB_L((u64 *) LOCAL_MMR_ADDR(SH1_SHUB_ID)) & SH_SHUB_ID_NODES_PER_BIT_MASK) >> - SH_SHUB_ID_NODES_PER_BIT_SHFT; - return 0; - } -/***** END HACK *******/ - - if (ret_stuff.status < 0) - return ret_stuff.status; - - if (shubtype) *shubtype = ret_stuff.v0 & 0xff; - if (systemsize) *systemsize = (ret_stuff.v0 >> 8) & 0xff; - if (sharing_domain_size) *sharing_domain_size = (ret_stuff.v0 >> 16) & 0xff; - if (partid) *partid = (ret_stuff.v0 >> 24) & 0xff; - if (coher) *coher = (ret_stuff.v0 >> 32) & 0xff; - if (reg) *reg = (ret_stuff.v0 >> 40) & 0xff; - if (nasid_bitmask) *nasid_bitmask = (ret_stuff.v1 & 0xffff); - if (nasid_shift) *nasid_shift = (ret_stuff.v1 >> 16) & 0xff; - return 0; -} - -/* - * This is the access point to the Altix PROM hardware performance - * and status monitoring interface. For info on using this, see - * arch/ia64/include/asm/sn/sn2/sn_hwperf.h - */ -static inline int -ia64_sn_hwperf_op(nasid_t nasid, u64 opcode, u64 a0, u64 a1, u64 a2, - u64 a3, u64 a4, int *v0) -{ - struct ia64_sal_retval rv; - SAL_CALL_NOLOCK(rv, SN_SAL_HWPERF_OP, (u64)nasid, - opcode, a0, a1, a2, a3, a4); - if (v0) - *v0 = (int) rv.v0; - return (int) rv.status; -} - -static inline int -ia64_sn_ioif_get_pci_topology(u64 buf, u64 len) -{ - struct ia64_sal_retval rv; - SAL_CALL_NOLOCK(rv, SN_SAL_IOIF_GET_PCI_TOPOLOGY, buf, len, 0, 0, 0, 0, 0); - return (int) rv.status; -} - -/* - * BTE error recovery is implemented in SAL - */ -static inline int -ia64_sn_bte_recovery(nasid_t nasid) -{ - struct ia64_sal_retval rv; - - rv.status = 0; - SAL_CALL_NOLOCK(rv, SN_SAL_BTE_RECOVER, (u64)nasid, 0, 0, 0, 0, 0, 0); - if (rv.status == SALRET_NOT_IMPLEMENTED) - return 0; - return (int) rv.status; -} - -static inline int -ia64_sn_is_fake_prom(void) -{ - struct ia64_sal_retval rv; - SAL_CALL_NOLOCK(rv, SN_SAL_FAKE_PROM, 0, 0, 0, 0, 0, 0, 0); - return (rv.status == 0); -} - -static inline int -ia64_sn_get_prom_feature_set(int set, unsigned long *feature_set) -{ - struct ia64_sal_retval rv; - - SAL_CALL_NOLOCK(rv, SN_SAL_GET_PROM_FEATURE_SET, set, 0, 0, 0, 0, 0, 0); - if (rv.status != 0) - return rv.status; - *feature_set = rv.v0; - return 0; -} - -static inline int -ia64_sn_set_os_feature(int feature) -{ - struct ia64_sal_retval rv; - - SAL_CALL_NOLOCK(rv, SN_SAL_SET_OS_FEATURE_SET, feature, 0, 0, 0, 0, 0, 0); - return rv.status; -} - -static inline int -sn_inject_error(u64 paddr, u64 *data, u64 *ecc) -{ - struct ia64_sal_retval ret_stuff; - - ia64_sal_oemcall_nolock(&ret_stuff, SN_SAL_INJECT_ERROR, paddr, (u64)data, - (u64)ecc, 0, 0, 0, 0); - return ret_stuff.status; -} - -static inline int -ia64_sn_set_cpu_number(int cpu) -{ - struct ia64_sal_retval rv; - - SAL_CALL_NOLOCK(rv, SN_SAL_SET_CPU_NUMBER, cpu, 0, 0, 0, 0, 0, 0); - return rv.status; -} -static inline int -ia64_sn_kernel_launch_event(void) -{ - struct ia64_sal_retval rv; - SAL_CALL_NOLOCK(rv, SN_SAL_KERNEL_LAUNCH_EVENT, 0, 0, 0, 0, 0, 0, 0); - return rv.status; -} - union sn_watchlist_u { u64 val; struct { diff --git a/arch/ia64/include/asm/sn/tioca.h b/arch/ia64/include/asm/sn/tioca.h deleted file mode 100644 index 666222d7f0f6b81215c9ffd886e965bfe65e265c..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/tioca.h +++ /dev/null @@ -1,596 +0,0 @@ -#ifndef _ASM_IA64_SN_TIO_TIOCA_H -#define _ASM_IA64_SN_TIO_TIOCA_H - -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2003-2005 Silicon Graphics, Inc. All rights reserved. - */ - - -#define TIOCA_PART_NUM 0xE020 -#define TIOCA_MFGR_NUM 0x24 -#define TIOCA_REV_A 0x1 - -/* - * Register layout for TIO:CA. See below for bitmasks for each register. - */ - -struct tioca { - u64 ca_id; /* 0x000000 */ - u64 ca_control1; /* 0x000008 */ - u64 ca_control2; /* 0x000010 */ - u64 ca_status1; /* 0x000018 */ - u64 ca_status2; /* 0x000020 */ - u64 ca_gart_aperature; /* 0x000028 */ - u64 ca_gfx_detach; /* 0x000030 */ - u64 ca_inta_dest_addr; /* 0x000038 */ - u64 ca_intb_dest_addr; /* 0x000040 */ - u64 ca_err_int_dest_addr; /* 0x000048 */ - u64 ca_int_status; /* 0x000050 */ - u64 ca_int_status_alias; /* 0x000058 */ - u64 ca_mult_error; /* 0x000060 */ - u64 ca_mult_error_alias; /* 0x000068 */ - u64 ca_first_error; /* 0x000070 */ - u64 ca_int_mask; /* 0x000078 */ - u64 ca_crm_pkterr_type; /* 0x000080 */ - u64 ca_crm_pkterr_type_alias; /* 0x000088 */ - u64 ca_crm_ct_error_detail_1; /* 0x000090 */ - u64 ca_crm_ct_error_detail_2; /* 0x000098 */ - u64 ca_crm_tnumto; /* 0x0000A0 */ - u64 ca_gart_err; /* 0x0000A8 */ - u64 ca_pcierr_type; /* 0x0000B0 */ - u64 ca_pcierr_addr; /* 0x0000B8 */ - - u64 ca_pad_0000C0[3]; /* 0x0000{C0..D0} */ - - u64 ca_pci_rd_buf_flush; /* 0x0000D8 */ - u64 ca_pci_dma_addr_extn; /* 0x0000E0 */ - u64 ca_agp_dma_addr_extn; /* 0x0000E8 */ - u64 ca_force_inta; /* 0x0000F0 */ - u64 ca_force_intb; /* 0x0000F8 */ - u64 ca_debug_vector_sel; /* 0x000100 */ - u64 ca_debug_mux_core_sel; /* 0x000108 */ - u64 ca_debug_mux_pci_sel; /* 0x000110 */ - u64 ca_debug_domain_sel; /* 0x000118 */ - - u64 ca_pad_000120[28]; /* 0x0001{20..F8} */ - - u64 ca_gart_ptr_table; /* 0x200 */ - u64 ca_gart_tlb_addr[8]; /* 0x2{08..40} */ -}; - -/* - * Mask/shift definitions for TIO:CA registers. The convention here is - * to mainly use the names as they appear in the "TIO AEGIS Programmers' - * Reference" with a CA_ prefix added. Some exceptions were made to fix - * duplicate field names or to generalize fields that are common to - * different registers (ca_debug_mux_core_sel and ca_debug_mux_pci_sel for - * example). - * - * Fields consisting of a single bit have a single #define have a single - * macro declaration to mask the bit. Fields consisting of multiple bits - * have two declarations: one to mask the proper bits in a register, and - * a second with the suffix "_SHFT" to identify how far the mask needs to - * be shifted right to get its base value. - */ - -/* ==== ca_control1 */ -#define CA_SYS_BIG_END (1ull << 0) -#define CA_DMA_AGP_SWAP (1ull << 1) -#define CA_DMA_PCI_SWAP (1ull << 2) -#define CA_PIO_IO_SWAP (1ull << 3) -#define CA_PIO_MEM_SWAP (1ull << 4) -#define CA_GFX_WR_SWAP (1ull << 5) -#define CA_AGP_FW_ENABLE (1ull << 6) -#define CA_AGP_CAL_CYCLE (0x7ull << 7) -#define CA_AGP_CAL_CYCLE_SHFT 7 -#define CA_AGP_CAL_PRSCL_BYP (1ull << 10) -#define CA_AGP_INIT_CAL_ENB (1ull << 11) -#define CA_INJ_ADDR_PERR (1ull << 12) -#define CA_INJ_DATA_PERR (1ull << 13) - /* bits 15:14 unused */ -#define CA_PCIM_IO_NBE_AD (0x7ull << 16) -#define CA_PCIM_IO_NBE_AD_SHFT 16 -#define CA_PCIM_FAST_BTB_ENB (1ull << 19) - /* bits 23:20 unused */ -#define CA_PIO_ADDR_OFFSET (0xffull << 24) -#define CA_PIO_ADDR_OFFSET_SHFT 24 - /* bits 35:32 unused */ -#define CA_AGPDMA_OP_COMBDELAY (0x1full << 36) -#define CA_AGPDMA_OP_COMBDELAY_SHFT 36 - /* bit 41 unused */ -#define CA_AGPDMA_OP_ENB_COMBDELAY (1ull << 42) -#define CA_PCI_INT_LPCNT (0xffull << 44) -#define CA_PCI_INT_LPCNT_SHFT 44 - /* bits 63:52 unused */ - -/* ==== ca_control2 */ -#define CA_AGP_LATENCY_TO (0xffull << 0) -#define CA_AGP_LATENCY_TO_SHFT 0 -#define CA_PCI_LATENCY_TO (0xffull << 8) -#define CA_PCI_LATENCY_TO_SHFT 8 -#define CA_PCI_MAX_RETRY (0x3ffull << 16) -#define CA_PCI_MAX_RETRY_SHFT 16 - /* bits 27:26 unused */ -#define CA_RT_INT_EN (0x3ull << 28) -#define CA_RT_INT_EN_SHFT 28 -#define CA_MSI_INT_ENB (1ull << 30) -#define CA_PCI_ARB_ERR_ENB (1ull << 31) -#define CA_GART_MEM_PARAM (0x3ull << 32) -#define CA_GART_MEM_PARAM_SHFT 32 -#define CA_GART_RD_PREFETCH_ENB (1ull << 34) -#define CA_GART_WR_PREFETCH_ENB (1ull << 35) -#define CA_GART_FLUSH_TLB (1ull << 36) - /* bits 39:37 unused */ -#define CA_CRM_TNUMTO_PERIOD (0x1fffull << 40) -#define CA_CRM_TNUMTO_PERIOD_SHFT 40 - /* bits 55:53 unused */ -#define CA_CRM_TNUMTO_ENB (1ull << 56) -#define CA_CRM_PRESCALER_BYP (1ull << 57) - /* bits 59:58 unused */ -#define CA_CRM_MAX_CREDIT (0x7ull << 60) -#define CA_CRM_MAX_CREDIT_SHFT 60 - /* bit 63 unused */ - -/* ==== ca_status1 */ -#define CA_CORELET_ID (0x3ull << 0) -#define CA_CORELET_ID_SHFT 0 -#define CA_INTA_N (1ull << 2) -#define CA_INTB_N (1ull << 3) -#define CA_CRM_CREDIT_AVAIL (0x7ull << 4) -#define CA_CRM_CREDIT_AVAIL_SHFT 4 - /* bit 7 unused */ -#define CA_CRM_SPACE_AVAIL (0x7full << 8) -#define CA_CRM_SPACE_AVAIL_SHFT 8 - /* bit 15 unused */ -#define CA_GART_TLB_VAL (0xffull << 16) -#define CA_GART_TLB_VAL_SHFT 16 - /* bits 63:24 unused */ - -/* ==== ca_status2 */ -#define CA_GFX_CREDIT_AVAIL (0xffull << 0) -#define CA_GFX_CREDIT_AVAIL_SHFT 0 -#define CA_GFX_OPQ_AVAIL (0xffull << 8) -#define CA_GFX_OPQ_AVAIL_SHFT 8 -#define CA_GFX_WRBUFF_AVAIL (0xffull << 16) -#define CA_GFX_WRBUFF_AVAIL_SHFT 16 -#define CA_ADMA_OPQ_AVAIL (0xffull << 24) -#define CA_ADMA_OPQ_AVAIL_SHFT 24 -#define CA_ADMA_WRBUFF_AVAIL (0xffull << 32) -#define CA_ADMA_WRBUFF_AVAIL_SHFT 32 -#define CA_ADMA_RDBUFF_AVAIL (0x7full << 40) -#define CA_ADMA_RDBUFF_AVAIL_SHFT 40 -#define CA_PCI_PIO_OP_STAT (1ull << 47) -#define CA_PDMA_OPQ_AVAIL (0xfull << 48) -#define CA_PDMA_OPQ_AVAIL_SHFT 48 -#define CA_PDMA_WRBUFF_AVAIL (0xfull << 52) -#define CA_PDMA_WRBUFF_AVAIL_SHFT 52 -#define CA_PDMA_RDBUFF_AVAIL (0x3ull << 56) -#define CA_PDMA_RDBUFF_AVAIL_SHFT 56 - /* bits 63:58 unused */ - -/* ==== ca_gart_aperature */ -#define CA_GART_AP_ENB_AGP (1ull << 0) -#define CA_GART_PAGE_SIZE (1ull << 1) -#define CA_GART_AP_ENB_PCI (1ull << 2) - /* bits 11:3 unused */ -#define CA_GART_AP_SIZE (0x3ffull << 12) -#define CA_GART_AP_SIZE_SHFT 12 -#define CA_GART_AP_BASE (0x3ffffffffffull << 22) -#define CA_GART_AP_BASE_SHFT 22 - -/* ==== ca_inta_dest_addr - ==== ca_intb_dest_addr - ==== ca_err_int_dest_addr */ - /* bits 2:0 unused */ -#define CA_INT_DEST_ADDR (0x7ffffffffffffull << 3) -#define CA_INT_DEST_ADDR_SHFT 3 - /* bits 55:54 unused */ -#define CA_INT_DEST_VECT (0xffull << 56) -#define CA_INT_DEST_VECT_SHFT 56 - -/* ==== ca_int_status */ -/* ==== ca_int_status_alias */ -/* ==== ca_mult_error */ -/* ==== ca_mult_error_alias */ -/* ==== ca_first_error */ -/* ==== ca_int_mask */ -#define CA_PCI_ERR (1ull << 0) - /* bits 3:1 unused */ -#define CA_GART_FETCH_ERR (1ull << 4) -#define CA_GFX_WR_OVFLW (1ull << 5) -#define CA_PIO_REQ_OVFLW (1ull << 6) -#define CA_CRM_PKTERR (1ull << 7) -#define CA_CRM_DVERR (1ull << 8) -#define CA_TNUMTO (1ull << 9) -#define CA_CXM_RSP_CRED_OVFLW (1ull << 10) -#define CA_CXM_REQ_CRED_OVFLW (1ull << 11) -#define CA_PIO_INVALID_ADDR (1ull << 12) -#define CA_PCI_ARB_TO (1ull << 13) -#define CA_AGP_REQ_OFLOW (1ull << 14) -#define CA_SBA_TYPE1_ERR (1ull << 15) - /* bit 16 unused */ -#define CA_INTA (1ull << 17) -#define CA_INTB (1ull << 18) -#define CA_MULT_INTA (1ull << 19) -#define CA_MULT_INTB (1ull << 20) -#define CA_GFX_CREDIT_OVFLW (1ull << 21) - /* bits 63:22 unused */ - -/* ==== ca_crm_pkterr_type */ -/* ==== ca_crm_pkterr_type_alias */ -#define CA_CRM_PKTERR_SBERR_HDR (1ull << 0) -#define CA_CRM_PKTERR_DIDN (1ull << 1) -#define CA_CRM_PKTERR_PACTYPE (1ull << 2) -#define CA_CRM_PKTERR_INV_TNUM (1ull << 3) -#define CA_CRM_PKTERR_ADDR_RNG (1ull << 4) -#define CA_CRM_PKTERR_ADDR_ALGN (1ull << 5) -#define CA_CRM_PKTERR_HDR_PARAM (1ull << 6) -#define CA_CRM_PKTERR_CW_ERR (1ull << 7) -#define CA_CRM_PKTERR_SBERR_NH (1ull << 8) -#define CA_CRM_PKTERR_EARLY_TERM (1ull << 9) -#define CA_CRM_PKTERR_EARLY_TAIL (1ull << 10) -#define CA_CRM_PKTERR_MSSNG_TAIL (1ull << 11) -#define CA_CRM_PKTERR_MSSNG_HDR (1ull << 12) - /* bits 15:13 unused */ -#define CA_FIRST_CRM_PKTERR_SBERR_HDR (1ull << 16) -#define CA_FIRST_CRM_PKTERR_DIDN (1ull << 17) -#define CA_FIRST_CRM_PKTERR_PACTYPE (1ull << 18) -#define CA_FIRST_CRM_PKTERR_INV_TNUM (1ull << 19) -#define CA_FIRST_CRM_PKTERR_ADDR_RNG (1ull << 20) -#define CA_FIRST_CRM_PKTERR_ADDR_ALGN (1ull << 21) -#define CA_FIRST_CRM_PKTERR_HDR_PARAM (1ull << 22) -#define CA_FIRST_CRM_PKTERR_CW_ERR (1ull << 23) -#define CA_FIRST_CRM_PKTERR_SBERR_NH (1ull << 24) -#define CA_FIRST_CRM_PKTERR_EARLY_TERM (1ull << 25) -#define CA_FIRST_CRM_PKTERR_EARLY_TAIL (1ull << 26) -#define CA_FIRST_CRM_PKTERR_MSSNG_TAIL (1ull << 27) -#define CA_FIRST_CRM_PKTERR_MSSNG_HDR (1ull << 28) - /* bits 63:29 unused */ - -/* ==== ca_crm_ct_error_detail_1 */ -#define CA_PKT_TYPE (0xfull << 0) -#define CA_PKT_TYPE_SHFT 0 -#define CA_SRC_ID (0x3ull << 4) -#define CA_SRC_ID_SHFT 4 -#define CA_DATA_SZ (0x3ull << 6) -#define CA_DATA_SZ_SHFT 6 -#define CA_TNUM (0xffull << 8) -#define CA_TNUM_SHFT 8 -#define CA_DW_DATA_EN (0xffull << 16) -#define CA_DW_DATA_EN_SHFT 16 -#define CA_GFX_CRED (0xffull << 24) -#define CA_GFX_CRED_SHFT 24 -#define CA_MEM_RD_PARAM (0x3ull << 32) -#define CA_MEM_RD_PARAM_SHFT 32 -#define CA_PIO_OP (1ull << 34) -#define CA_CW_ERR (1ull << 35) - /* bits 62:36 unused */ -#define CA_VALID (1ull << 63) - -/* ==== ca_crm_ct_error_detail_2 */ - /* bits 2:0 unused */ -#define CA_PKT_ADDR (0x1fffffffffffffull << 3) -#define CA_PKT_ADDR_SHFT 3 - /* bits 63:56 unused */ - -/* ==== ca_crm_tnumto */ -#define CA_CRM_TNUMTO_VAL (0xffull << 0) -#define CA_CRM_TNUMTO_VAL_SHFT 0 -#define CA_CRM_TNUMTO_WR (1ull << 8) - /* bits 63:9 unused */ - -/* ==== ca_gart_err */ -#define CA_GART_ERR_SOURCE (0x3ull << 0) -#define CA_GART_ERR_SOURCE_SHFT 0 - /* bits 3:2 unused */ -#define CA_GART_ERR_ADDR (0xfffffffffull << 4) -#define CA_GART_ERR_ADDR_SHFT 4 - /* bits 63:40 unused */ - -/* ==== ca_pcierr_type */ -#define CA_PCIERR_DATA (0xffffffffull << 0) -#define CA_PCIERR_DATA_SHFT 0 -#define CA_PCIERR_ENB (0xfull << 32) -#define CA_PCIERR_ENB_SHFT 32 -#define CA_PCIERR_CMD (0xfull << 36) -#define CA_PCIERR_CMD_SHFT 36 -#define CA_PCIERR_A64 (1ull << 40) -#define CA_PCIERR_SLV_SERR (1ull << 41) -#define CA_PCIERR_SLV_WR_PERR (1ull << 42) -#define CA_PCIERR_SLV_RD_PERR (1ull << 43) -#define CA_PCIERR_MST_SERR (1ull << 44) -#define CA_PCIERR_MST_WR_PERR (1ull << 45) -#define CA_PCIERR_MST_RD_PERR (1ull << 46) -#define CA_PCIERR_MST_MABT (1ull << 47) -#define CA_PCIERR_MST_TABT (1ull << 48) -#define CA_PCIERR_MST_RETRY_TOUT (1ull << 49) - -#define CA_PCIERR_TYPES \ - (CA_PCIERR_A64|CA_PCIERR_SLV_SERR| \ - CA_PCIERR_SLV_WR_PERR|CA_PCIERR_SLV_RD_PERR| \ - CA_PCIERR_MST_SERR|CA_PCIERR_MST_WR_PERR|CA_PCIERR_MST_RD_PERR| \ - CA_PCIERR_MST_MABT|CA_PCIERR_MST_TABT|CA_PCIERR_MST_RETRY_TOUT) - - /* bits 63:50 unused */ - -/* ==== ca_pci_dma_addr_extn */ -#define CA_UPPER_NODE_OFFSET (0x3full << 0) -#define CA_UPPER_NODE_OFFSET_SHFT 0 - /* bits 7:6 unused */ -#define CA_CHIPLET_ID (0x3ull << 8) -#define CA_CHIPLET_ID_SHFT 8 - /* bits 11:10 unused */ -#define CA_PCI_DMA_NODE_ID (0xffffull << 12) -#define CA_PCI_DMA_NODE_ID_SHFT 12 - /* bits 27:26 unused */ -#define CA_PCI_DMA_PIO_MEM_TYPE (1ull << 28) - /* bits 63:29 unused */ - - -/* ==== ca_agp_dma_addr_extn */ - /* bits 19:0 unused */ -#define CA_AGP_DMA_NODE_ID (0xffffull << 20) -#define CA_AGP_DMA_NODE_ID_SHFT 20 - /* bits 27:26 unused */ -#define CA_AGP_DMA_PIO_MEM_TYPE (1ull << 28) - /* bits 63:29 unused */ - -/* ==== ca_debug_vector_sel */ -#define CA_DEBUG_MN_VSEL (0xfull << 0) -#define CA_DEBUG_MN_VSEL_SHFT 0 -#define CA_DEBUG_PP_VSEL (0xfull << 4) -#define CA_DEBUG_PP_VSEL_SHFT 4 -#define CA_DEBUG_GW_VSEL (0xfull << 8) -#define CA_DEBUG_GW_VSEL_SHFT 8 -#define CA_DEBUG_GT_VSEL (0xfull << 12) -#define CA_DEBUG_GT_VSEL_SHFT 12 -#define CA_DEBUG_PD_VSEL (0xfull << 16) -#define CA_DEBUG_PD_VSEL_SHFT 16 -#define CA_DEBUG_AD_VSEL (0xfull << 20) -#define CA_DEBUG_AD_VSEL_SHFT 20 -#define CA_DEBUG_CX_VSEL (0xfull << 24) -#define CA_DEBUG_CX_VSEL_SHFT 24 -#define CA_DEBUG_CR_VSEL (0xfull << 28) -#define CA_DEBUG_CR_VSEL_SHFT 28 -#define CA_DEBUG_BA_VSEL (0xfull << 32) -#define CA_DEBUG_BA_VSEL_SHFT 32 -#define CA_DEBUG_PE_VSEL (0xfull << 36) -#define CA_DEBUG_PE_VSEL_SHFT 36 -#define CA_DEBUG_BO_VSEL (0xfull << 40) -#define CA_DEBUG_BO_VSEL_SHFT 40 -#define CA_DEBUG_BI_VSEL (0xfull << 44) -#define CA_DEBUG_BI_VSEL_SHFT 44 -#define CA_DEBUG_AS_VSEL (0xfull << 48) -#define CA_DEBUG_AS_VSEL_SHFT 48 -#define CA_DEBUG_PS_VSEL (0xfull << 52) -#define CA_DEBUG_PS_VSEL_SHFT 52 -#define CA_DEBUG_PM_VSEL (0xfull << 56) -#define CA_DEBUG_PM_VSEL_SHFT 56 - /* bits 63:60 unused */ - -/* ==== ca_debug_mux_core_sel */ -/* ==== ca_debug_mux_pci_sel */ -#define CA_DEBUG_MSEL0 (0x7ull << 0) -#define CA_DEBUG_MSEL0_SHFT 0 - /* bit 3 unused */ -#define CA_DEBUG_NSEL0 (0x7ull << 4) -#define CA_DEBUG_NSEL0_SHFT 4 - /* bit 7 unused */ -#define CA_DEBUG_MSEL1 (0x7ull << 8) -#define CA_DEBUG_MSEL1_SHFT 8 - /* bit 11 unused */ -#define CA_DEBUG_NSEL1 (0x7ull << 12) -#define CA_DEBUG_NSEL1_SHFT 12 - /* bit 15 unused */ -#define CA_DEBUG_MSEL2 (0x7ull << 16) -#define CA_DEBUG_MSEL2_SHFT 16 - /* bit 19 unused */ -#define CA_DEBUG_NSEL2 (0x7ull << 20) -#define CA_DEBUG_NSEL2_SHFT 20 - /* bit 23 unused */ -#define CA_DEBUG_MSEL3 (0x7ull << 24) -#define CA_DEBUG_MSEL3_SHFT 24 - /* bit 27 unused */ -#define CA_DEBUG_NSEL3 (0x7ull << 28) -#define CA_DEBUG_NSEL3_SHFT 28 - /* bit 31 unused */ -#define CA_DEBUG_MSEL4 (0x7ull << 32) -#define CA_DEBUG_MSEL4_SHFT 32 - /* bit 35 unused */ -#define CA_DEBUG_NSEL4 (0x7ull << 36) -#define CA_DEBUG_NSEL4_SHFT 36 - /* bit 39 unused */ -#define CA_DEBUG_MSEL5 (0x7ull << 40) -#define CA_DEBUG_MSEL5_SHFT 40 - /* bit 43 unused */ -#define CA_DEBUG_NSEL5 (0x7ull << 44) -#define CA_DEBUG_NSEL5_SHFT 44 - /* bit 47 unused */ -#define CA_DEBUG_MSEL6 (0x7ull << 48) -#define CA_DEBUG_MSEL6_SHFT 48 - /* bit 51 unused */ -#define CA_DEBUG_NSEL6 (0x7ull << 52) -#define CA_DEBUG_NSEL6_SHFT 52 - /* bit 55 unused */ -#define CA_DEBUG_MSEL7 (0x7ull << 56) -#define CA_DEBUG_MSEL7_SHFT 56 - /* bit 59 unused */ -#define CA_DEBUG_NSEL7 (0x7ull << 60) -#define CA_DEBUG_NSEL7_SHFT 60 - /* bit 63 unused */ - - -/* ==== ca_debug_domain_sel */ -#define CA_DEBUG_DOMAIN_L (1ull << 0) -#define CA_DEBUG_DOMAIN_H (1ull << 1) - /* bits 63:2 unused */ - -/* ==== ca_gart_ptr_table */ -#define CA_GART_PTR_VAL (1ull << 0) - /* bits 11:1 unused */ -#define CA_GART_PTR_ADDR (0xfffffffffffull << 12) -#define CA_GART_PTR_ADDR_SHFT 12 - /* bits 63:56 unused */ - -/* ==== ca_gart_tlb_addr[0-7] */ -#define CA_GART_TLB_ADDR (0xffffffffffffffull << 0) -#define CA_GART_TLB_ADDR_SHFT 0 - /* bits 62:56 unused */ -#define CA_GART_TLB_ENTRY_VAL (1ull << 63) - -/* - * PIO address space ranges for TIO:CA - */ - -/* CA internal registers */ -#define CA_PIO_ADMIN 0x00000000 -#define CA_PIO_ADMIN_LEN 0x00010000 - -/* GFX Write Buffer - Diagnostics */ -#define CA_PIO_GFX 0x00010000 -#define CA_PIO_GFX_LEN 0x00010000 - -/* AGP DMA Write Buffer - Diagnostics */ -#define CA_PIO_AGP_DMAWRITE 0x00020000 -#define CA_PIO_AGP_DMAWRITE_LEN 0x00010000 - -/* AGP DMA READ Buffer - Diagnostics */ -#define CA_PIO_AGP_DMAREAD 0x00030000 -#define CA_PIO_AGP_DMAREAD_LEN 0x00010000 - -/* PCI Config Type 0 */ -#define CA_PIO_PCI_TYPE0_CONFIG 0x01000000 -#define CA_PIO_PCI_TYPE0_CONFIG_LEN 0x01000000 - -/* PCI Config Type 1 */ -#define CA_PIO_PCI_TYPE1_CONFIG 0x02000000 -#define CA_PIO_PCI_TYPE1_CONFIG_LEN 0x01000000 - -/* PCI I/O Cycles - mapped to PCI Address 0x00000000-0x04ffffff */ -#define CA_PIO_PCI_IO 0x03000000 -#define CA_PIO_PCI_IO_LEN 0x05000000 - -/* PCI MEM Cycles - mapped to PCI with CA_PIO_ADDR_OFFSET of ca_control1 */ -/* use Fast Write if enabled and coretalk packet type is a GFX request */ -#define CA_PIO_PCI_MEM_OFFSET 0x08000000 -#define CA_PIO_PCI_MEM_OFFSET_LEN 0x08000000 - -/* PCI MEM Cycles - mapped to PCI Address 0x00000000-0xbfffffff */ -/* use Fast Write if enabled and coretalk packet type is a GFX request */ -#define CA_PIO_PCI_MEM 0x40000000 -#define CA_PIO_PCI_MEM_LEN 0xc0000000 - -/* - * DMA space - * - * The CA aperature (ie. bus address range) mapped by the GART is segmented into - * two parts. The lower portion of the aperature is used for mapping 32 bit - * PCI addresses which are managed by the dma interfaces in this file. The - * upper poprtion of the aperature is used for mapping 48 bit AGP addresses. - * The AGP portion of the aperature is managed by the agpgart_be.c driver - * in drivers/linux/agp. There are ca-specific hooks in that driver to - * manipulate the gart, but management of the AGP portion of the aperature - * is the responsibility of that driver. - * - * CA allows three main types of DMA mapping: - * - * PCI 64-bit Managed by this driver - * PCI 32-bit Managed by this driver - * AGP 48-bit Managed by hooks in the /dev/agpgart driver - * - * All of the above can optionally be remapped through the GART. The following - * table lists the combinations of addressing types and GART remapping that - * is currently supported by the driver (h/w supports all, s/w limits this): - * - * PCI64 PCI32 AGP48 - * GART no yes yes - * Direct yes yes no - * - * GART remapping of PCI64 is not done because there is no need to. The - * 64 bit PCI address holds all of the information necessary to target any - * memory in the system. - * - * AGP48 is always mapped through the GART. Management of the AGP48 portion - * of the aperature is the responsibility of code in the agpgart_be driver. - * - * The non-64 bit bus address space will currently be partitioned like this: - * - * 0xffff_ffff_ffff +-------- - * | AGP48 direct - * | Space managed by this driver - * CA_AGP_DIRECT_BASE +-------- - * | AGP GART mapped (gfx aperature) - * | Space managed by /dev/agpgart driver - * | This range is exposed to the agpgart - * | driver as the "graphics aperature" - * CA_AGP_MAPPED_BASE +----- - * | PCI GART mapped - * | Space managed by this driver - * CA_PCI32_MAPPED_BASE +---- - * | PCI32 direct - * | Space managed by this driver - * 0xC000_0000 +-------- - * (CA_PCI32_DIRECT_BASE) - * - * The bus address range CA_PCI32_MAPPED_BASE through CA_AGP_DIRECT_BASE - * is what we call the CA aperature. Addresses falling in this range will - * be remapped using the GART. - * - * The bus address range CA_AGP_MAPPED_BASE through CA_AGP_DIRECT_BASE - * is what we call the graphics aperature. This is a subset of the CA - * aperature and is under the control of the agpgart_be driver. - * - * CA_PCI32_MAPPED_BASE, CA_AGP_MAPPED_BASE, and CA_AGP_DIRECT_BASE are - * somewhat arbitrary values. The known constraints on choosing these is: - * - * 1) CA_AGP_DIRECT_BASE-CA_PCI32_MAPPED_BASE+1 (the CA aperature size) - * must be one of the values supported by the ca_gart_aperature register. - * Currently valid values are: 4MB through 4096MB in powers of 2 increments - * - * 2) CA_AGP_DIRECT_BASE-CA_AGP_MAPPED_BASE+1 (the gfx aperature size) - * must be in MB units since that's what the agpgart driver assumes. - */ - -/* - * Define Bus DMA ranges. These are configurable (see constraints above) - * and will probably need tuning based on experience. - */ - - -/* - * 11/24/03 - * CA has an addressing glitch w.r.t. PCI direct 32 bit DMA that makes it - * generally unusable. The problem is that for PCI direct 32 - * DMA's, all 32 bits of the bus address are used to form the lower 32 bits - * of the coretalk address, and coretalk bits 38:32 come from a register. - * Since only PCI bus addresses 0xC0000000-0xFFFFFFFF (1GB) are available - * for DMA (the rest is allocated to PIO), host node addresses need to be - * such that their lower 32 bits fall in the 0xC0000000-0xffffffff range - * as well. So there can be no PCI32 direct DMA below 3GB!! For this - * reason we set the CA_PCI32_DIRECT_SIZE to 0 which essentially makes - * tioca_dma_direct32() a noop but preserves the code flow should this issue - * be fixed in a respin. - * - * For now, all PCI32 DMA's must be mapped through the GART. - */ - -#define CA_PCI32_DIRECT_BASE 0xC0000000UL /* BASE not configurable */ -#define CA_PCI32_DIRECT_SIZE 0x00000000UL /* 0 MB */ - -#define CA_PCI32_MAPPED_BASE 0xC0000000UL -#define CA_PCI32_MAPPED_SIZE 0x40000000UL /* 2GB */ - -#define CA_AGP_MAPPED_BASE 0x80000000UL -#define CA_AGP_MAPPED_SIZE 0x40000000UL /* 2GB */ - -#define CA_AGP_DIRECT_BASE 0x40000000UL /* 2GB */ -#define CA_AGP_DIRECT_SIZE 0x40000000UL - -#define CA_APERATURE_BASE (CA_AGP_MAPPED_BASE) -#define CA_APERATURE_SIZE (CA_AGP_MAPPED_SIZE+CA_PCI32_MAPPED_SIZE) - -#endif /* _ASM_IA64_SN_TIO_TIOCA_H */ diff --git a/arch/ia64/include/asm/sn/tioca_provider.h b/arch/ia64/include/asm/sn/tioca_provider.h deleted file mode 100644 index 9a820ac61be338347f23d5d939e009bce8d52a7d..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/tioca_provider.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2003-2005 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_TIO_CA_AGP_PROVIDER_H -#define _ASM_IA64_SN_TIO_CA_AGP_PROVIDER_H - -#include - -/* - * WAR enables - * Defines for individual WARs. Each is a bitmask of applicable - * part revision numbers. (1 << 1) == rev A, (1 << 2) == rev B, - * (3 << 1) == (rev A or rev B), etc - */ - -#define TIOCA_WAR_ENABLED(pv, tioca_common) \ - ((1 << tioca_common->ca_rev) & pv) - - /* TIO:ICE:FRZ:Freezer loses a PIO data ucred on PIO RD RSP with CW error */ -#define PV907908 (1 << 1) - /* ATI config space problems after BIOS execution starts */ -#define PV908234 (1 << 1) - /* CA:AGPDMA write request data mismatch with ABC1CL merge */ -#define PV895469 (1 << 1) - /* TIO:CA TLB invalidate of written GART entries possibly not occurring in CA*/ -#define PV910244 (1 << 1) - -struct tioca_dmamap{ - struct list_head cad_list; /* headed by ca_list */ - - dma_addr_t cad_dma_addr; /* Linux dma handle */ - uint cad_gart_entry; /* start entry in ca_gart_pagemap */ - uint cad_gart_size; /* #entries for this map */ -}; - -/* - * Kernel only fields. Prom may look at this stuff for debugging only. - * Access this structure through the ca_kernel_private ptr. - */ - -struct tioca_common ; - -struct tioca_kernel { - struct tioca_common *ca_common; /* tioca this belongs to */ - struct list_head ca_list; /* list of all ca's */ - struct list_head ca_dmamaps; - spinlock_t ca_lock; /* Kernel lock */ - cnodeid_t ca_closest_node; - struct list_head *ca_devices; /* bus->devices */ - - /* - * General GART stuff - */ - u64 ca_ap_size; /* size of aperature in bytes */ - u32 ca_gart_entries; /* # u64 entries in gart */ - u32 ca_ap_pagesize; /* aperature page size in bytes */ - u64 ca_ap_bus_base; /* bus address of CA aperature */ - u64 ca_gart_size; /* gart size in bytes */ - u64 *ca_gart; /* gart table vaddr */ - u64 ca_gart_coretalk_addr; /* gart coretalk addr */ - u8 ca_gart_iscoherent; /* used in tioca_tlbflush */ - - /* PCI GART convenience values */ - u64 ca_pciap_base; /* pci aperature bus base address */ - u64 ca_pciap_size; /* pci aperature size (bytes) */ - u64 ca_pcigart_base; /* gfx GART bus base address */ - u64 *ca_pcigart; /* gfx GART vm address */ - u32 ca_pcigart_entries; - u32 ca_pcigart_start; /* PCI start index in ca_gart */ - void *ca_pcigart_pagemap; - - /* AGP GART convenience values */ - u64 ca_gfxap_base; /* gfx aperature bus base address */ - u64 ca_gfxap_size; /* gfx aperature size (bytes) */ - u64 ca_gfxgart_base; /* gfx GART bus base address */ - u64 *ca_gfxgart; /* gfx GART vm address */ - u32 ca_gfxgart_entries; - u32 ca_gfxgart_start; /* agpgart start index in ca_gart */ -}; - -/* - * Common tioca info shared between kernel and prom - * - * DO NOT CHANGE THIS STRUCT WITHOUT MAKING CORRESPONDING CHANGES - * TO THE PROM VERSION. - */ - -struct tioca_common { - struct pcibus_bussoft ca_common; /* common pciio header */ - - u32 ca_rev; - u32 ca_closest_nasid; - - u64 ca_prom_private; - u64 ca_kernel_private; -}; - -/** - * tioca_paddr_to_gart - Convert an SGI coretalk address to a CA GART entry - * @paddr: page address to convert - * - * Convert a system [coretalk] address to a GART entry. GART entries are - * formed using the following: - * - * data = ( (1<<63) | ( (REMAP_NODE_ID << 40) | (MD_CHIPLET_ID << 38) | - * (REMAP_SYS_ADDR) ) >> 12 ) - * - * DATA written to 1 GART TABLE Entry in system memory is remapped system - * addr for 1 page - * - * The data is for coretalk address format right shifted 12 bits with a - * valid bit. - * - * GART_TABLE_ENTRY [ 25:0 ] -- REMAP_SYS_ADDRESS[37:12]. - * GART_TABLE_ENTRY [ 27:26 ] -- SHUB MD chiplet id. - * GART_TABLE_ENTRY [ 41:28 ] -- REMAP_NODE_ID. - * GART_TABLE_ENTRY [ 63 ] -- Valid Bit - */ -static inline u64 -tioca_paddr_to_gart(unsigned long paddr) -{ - /* - * We are assuming right now that paddr already has the correct - * format since the address from xtalk_dmaXXX should already have - * NODE_ID, CHIPLET_ID, and SYS_ADDR in the correct locations. - */ - - return ((paddr) >> 12) | (1UL << 63); -} - -/** - * tioca_physpage_to_gart - Map a host physical page for SGI CA based DMA - * @page_addr: system page address to map - */ - -static inline unsigned long -tioca_physpage_to_gart(u64 page_addr) -{ - u64 coretalk_addr; - - coretalk_addr = PHYS_TO_TIODMA(page_addr); - if (!coretalk_addr) { - return 0; - } - - return tioca_paddr_to_gart(coretalk_addr); -} - -/** - * tioca_tlbflush - invalidate cached SGI CA GART TLB entries - * @tioca_kernel: CA context - * - * Invalidate tlb entries for a given CA GART. Main complexity is to account - * for revA bug. - */ -static inline void -tioca_tlbflush(struct tioca_kernel *tioca_kernel) -{ - volatile u64 tmp; - volatile struct tioca __iomem *ca_base; - struct tioca_common *tioca_common; - - tioca_common = tioca_kernel->ca_common; - ca_base = (struct tioca __iomem *)tioca_common->ca_common.bs_base; - - /* - * Explicit flushes not needed if GART is in cached mode - */ - if (tioca_kernel->ca_gart_iscoherent) { - if (TIOCA_WAR_ENABLED(PV910244, tioca_common)) { - /* - * PV910244: RevA CA needs explicit flushes. - * Need to put GART into uncached mode before - * flushing otherwise the explicit flush is ignored. - * - * Alternate WAR would be to leave GART cached and - * touch every CL aligned GART entry. - */ - - __sn_clrq_relaxed(&ca_base->ca_control2, CA_GART_MEM_PARAM); - __sn_setq_relaxed(&ca_base->ca_control2, CA_GART_FLUSH_TLB); - __sn_setq_relaxed(&ca_base->ca_control2, - (0x2ull << CA_GART_MEM_PARAM_SHFT)); - tmp = __sn_readq_relaxed(&ca_base->ca_control2); - } - - return; - } - - /* - * Gart in uncached mode ... need an explicit flush. - */ - - __sn_setq_relaxed(&ca_base->ca_control2, CA_GART_FLUSH_TLB); - tmp = __sn_readq_relaxed(&ca_base->ca_control2); -} - -extern u32 tioca_gart_found; -extern struct list_head tioca_list; -extern int tioca_init_provider(void); -extern void tioca_fastwrite_enable(struct tioca_kernel *tioca_kern); -#endif /* _ASM_IA64_SN_TIO_CA_AGP_PROVIDER_H */ diff --git a/arch/ia64/include/asm/sn/tioce.h b/arch/ia64/include/asm/sn/tioce.h deleted file mode 100644 index 6eae8ada90f00f308fbb8e5c2e12721d795e1c31..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/tioce.h +++ /dev/null @@ -1,760 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2003-2005 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef __ASM_IA64_SN_TIOCE_H__ -#define __ASM_IA64_SN_TIOCE_H__ - -/* CE ASIC part & mfgr information */ -#define TIOCE_PART_NUM 0xCE00 -#define TIOCE_SRC_ID 0x01 -#define TIOCE_REV_A 0x1 - -/* CE Virtual PPB Vendor/Device IDs */ -#define CE_VIRT_PPB_VENDOR_ID 0x10a9 -#define CE_VIRT_PPB_DEVICE_ID 0x4002 - -/* CE Host Bridge Vendor/Device IDs */ -#define CE_HOST_BRIDGE_VENDOR_ID 0x10a9 -#define CE_HOST_BRIDGE_DEVICE_ID 0x4001 - - -#define TIOCE_NUM_M40_ATES 4096 -#define TIOCE_NUM_M3240_ATES 2048 -#define TIOCE_NUM_PORTS 2 - -/* - * Register layout for TIOCE. MMR offsets are shown at the far right of the - * structure definition. - */ -typedef volatile struct tioce { - /* - * ADMIN : Administration Registers - */ - u64 ce_adm_id; /* 0x000000 */ - u64 ce_pad_000008; /* 0x000008 */ - u64 ce_adm_dyn_credit_status; /* 0x000010 */ - u64 ce_adm_last_credit_status; /* 0x000018 */ - u64 ce_adm_credit_limit; /* 0x000020 */ - u64 ce_adm_force_credit; /* 0x000028 */ - u64 ce_adm_control; /* 0x000030 */ - u64 ce_adm_mmr_chn_timeout; /* 0x000038 */ - u64 ce_adm_ssp_ure_timeout; /* 0x000040 */ - u64 ce_adm_ssp_dre_timeout; /* 0x000048 */ - u64 ce_adm_ssp_debug_sel; /* 0x000050 */ - u64 ce_adm_int_status; /* 0x000058 */ - u64 ce_adm_int_status_alias; /* 0x000060 */ - u64 ce_adm_int_mask; /* 0x000068 */ - u64 ce_adm_int_pending; /* 0x000070 */ - u64 ce_adm_force_int; /* 0x000078 */ - u64 ce_adm_ure_ups_buf_barrier_flush; /* 0x000080 */ - u64 ce_adm_int_dest[15]; /* 0x000088 -- 0x0000F8 */ - u64 ce_adm_error_summary; /* 0x000100 */ - u64 ce_adm_error_summary_alias; /* 0x000108 */ - u64 ce_adm_error_mask; /* 0x000110 */ - u64 ce_adm_first_error; /* 0x000118 */ - u64 ce_adm_error_overflow; /* 0x000120 */ - u64 ce_adm_error_overflow_alias; /* 0x000128 */ - u64 ce_pad_000130[2]; /* 0x000130 -- 0x000138 */ - u64 ce_adm_tnum_error; /* 0x000140 */ - u64 ce_adm_mmr_err_detail; /* 0x000148 */ - u64 ce_adm_msg_sram_perr_detail; /* 0x000150 */ - u64 ce_adm_bap_sram_perr_detail; /* 0x000158 */ - u64 ce_adm_ce_sram_perr_detail; /* 0x000160 */ - u64 ce_adm_ce_credit_oflow_detail; /* 0x000168 */ - u64 ce_adm_tx_link_idle_max_timer; /* 0x000170 */ - u64 ce_adm_pcie_debug_sel; /* 0x000178 */ - u64 ce_pad_000180[16]; /* 0x000180 -- 0x0001F8 */ - - u64 ce_adm_pcie_debug_sel_top; /* 0x000200 */ - u64 ce_adm_pcie_debug_lat_sel_lo_top; /* 0x000208 */ - u64 ce_adm_pcie_debug_lat_sel_hi_top; /* 0x000210 */ - u64 ce_adm_pcie_debug_trig_sel_top; /* 0x000218 */ - u64 ce_adm_pcie_debug_trig_lat_sel_lo_top; /* 0x000220 */ - u64 ce_adm_pcie_debug_trig_lat_sel_hi_top; /* 0x000228 */ - u64 ce_adm_pcie_trig_compare_top; /* 0x000230 */ - u64 ce_adm_pcie_trig_compare_en_top; /* 0x000238 */ - u64 ce_adm_ssp_debug_sel_top; /* 0x000240 */ - u64 ce_adm_ssp_debug_lat_sel_lo_top; /* 0x000248 */ - u64 ce_adm_ssp_debug_lat_sel_hi_top; /* 0x000250 */ - u64 ce_adm_ssp_debug_trig_sel_top; /* 0x000258 */ - u64 ce_adm_ssp_debug_trig_lat_sel_lo_top; /* 0x000260 */ - u64 ce_adm_ssp_debug_trig_lat_sel_hi_top; /* 0x000268 */ - u64 ce_adm_ssp_trig_compare_top; /* 0x000270 */ - u64 ce_adm_ssp_trig_compare_en_top; /* 0x000278 */ - u64 ce_pad_000280[48]; /* 0x000280 -- 0x0003F8 */ - - u64 ce_adm_bap_ctrl; /* 0x000400 */ - u64 ce_pad_000408[127]; /* 0x000408 -- 0x0007F8 */ - - u64 ce_msg_buf_data63_0[35]; /* 0x000800 -- 0x000918 */ - u64 ce_pad_000920[29]; /* 0x000920 -- 0x0009F8 */ - - u64 ce_msg_buf_data127_64[35]; /* 0x000A00 -- 0x000B18 */ - u64 ce_pad_000B20[29]; /* 0x000B20 -- 0x000BF8 */ - - u64 ce_msg_buf_parity[35]; /* 0x000C00 -- 0x000D18 */ - u64 ce_pad_000D20[29]; /* 0x000D20 -- 0x000DF8 */ - - u64 ce_pad_000E00[576]; /* 0x000E00 -- 0x001FF8 */ - - /* - * LSI : LSI's PCI Express Link Registers (Link#1 and Link#2) - * Link#1 MMRs at start at 0x002000, Link#2 MMRs at 0x003000 - * NOTE: the comment offsets at far right: let 'z' = {2 or 3} - */ - #define ce_lsi(link_num) ce_lsi[link_num-1] - struct ce_lsi_reg { - u64 ce_lsi_lpu_id; /* 0x00z000 */ - u64 ce_lsi_rst; /* 0x00z008 */ - u64 ce_lsi_dbg_stat; /* 0x00z010 */ - u64 ce_lsi_dbg_cfg; /* 0x00z018 */ - u64 ce_lsi_ltssm_ctrl; /* 0x00z020 */ - u64 ce_lsi_lk_stat; /* 0x00z028 */ - u64 ce_pad_00z030[2]; /* 0x00z030 -- 0x00z038 */ - u64 ce_lsi_int_and_stat; /* 0x00z040 */ - u64 ce_lsi_int_mask; /* 0x00z048 */ - u64 ce_pad_00z050[22]; /* 0x00z050 -- 0x00z0F8 */ - u64 ce_lsi_lk_perf_cnt_sel; /* 0x00z100 */ - u64 ce_pad_00z108; /* 0x00z108 */ - u64 ce_lsi_lk_perf_cnt_ctrl; /* 0x00z110 */ - u64 ce_pad_00z118; /* 0x00z118 */ - u64 ce_lsi_lk_perf_cnt1; /* 0x00z120 */ - u64 ce_lsi_lk_perf_cnt1_test; /* 0x00z128 */ - u64 ce_lsi_lk_perf_cnt2; /* 0x00z130 */ - u64 ce_lsi_lk_perf_cnt2_test; /* 0x00z138 */ - u64 ce_pad_00z140[24]; /* 0x00z140 -- 0x00z1F8 */ - u64 ce_lsi_lk_lyr_cfg; /* 0x00z200 */ - u64 ce_lsi_lk_lyr_status; /* 0x00z208 */ - u64 ce_lsi_lk_lyr_int_stat; /* 0x00z210 */ - u64 ce_lsi_lk_ly_int_stat_test; /* 0x00z218 */ - u64 ce_lsi_lk_ly_int_stat_mask; /* 0x00z220 */ - u64 ce_pad_00z228[3]; /* 0x00z228 -- 0x00z238 */ - u64 ce_lsi_fc_upd_ctl; /* 0x00z240 */ - u64 ce_pad_00z248[3]; /* 0x00z248 -- 0x00z258 */ - u64 ce_lsi_flw_ctl_upd_to_timer; /* 0x00z260 */ - u64 ce_lsi_flw_ctl_upd_timer0; /* 0x00z268 */ - u64 ce_lsi_flw_ctl_upd_timer1; /* 0x00z270 */ - u64 ce_pad_00z278[49]; /* 0x00z278 -- 0x00z3F8 */ - u64 ce_lsi_freq_nak_lat_thrsh; /* 0x00z400 */ - u64 ce_lsi_ack_nak_lat_tmr; /* 0x00z408 */ - u64 ce_lsi_rply_tmr_thr; /* 0x00z410 */ - u64 ce_lsi_rply_tmr; /* 0x00z418 */ - u64 ce_lsi_rply_num_stat; /* 0x00z420 */ - u64 ce_lsi_rty_buf_max_addr; /* 0x00z428 */ - u64 ce_lsi_rty_fifo_ptr; /* 0x00z430 */ - u64 ce_lsi_rty_fifo_rd_wr_ptr; /* 0x00z438 */ - u64 ce_lsi_rty_fifo_cred; /* 0x00z440 */ - u64 ce_lsi_seq_cnt; /* 0x00z448 */ - u64 ce_lsi_ack_sent_seq_num; /* 0x00z450 */ - u64 ce_lsi_seq_cnt_fifo_max_addr; /* 0x00z458 */ - u64 ce_lsi_seq_cnt_fifo_ptr; /* 0x00z460 */ - u64 ce_lsi_seq_cnt_rd_wr_ptr; /* 0x00z468 */ - u64 ce_lsi_tx_lk_ts_ctl; /* 0x00z470 */ - u64 ce_pad_00z478; /* 0x00z478 */ - u64 ce_lsi_mem_addr_ctl; /* 0x00z480 */ - u64 ce_lsi_mem_d_ld0; /* 0x00z488 */ - u64 ce_lsi_mem_d_ld1; /* 0x00z490 */ - u64 ce_lsi_mem_d_ld2; /* 0x00z498 */ - u64 ce_lsi_mem_d_ld3; /* 0x00z4A0 */ - u64 ce_lsi_mem_d_ld4; /* 0x00z4A8 */ - u64 ce_pad_00z4B0[2]; /* 0x00z4B0 -- 0x00z4B8 */ - u64 ce_lsi_rty_d_cnt; /* 0x00z4C0 */ - u64 ce_lsi_seq_buf_cnt; /* 0x00z4C8 */ - u64 ce_lsi_seq_buf_bt_d; /* 0x00z4D0 */ - u64 ce_pad_00z4D8; /* 0x00z4D8 */ - u64 ce_lsi_ack_lat_thr; /* 0x00z4E0 */ - u64 ce_pad_00z4E8[3]; /* 0x00z4E8 -- 0x00z4F8 */ - u64 ce_lsi_nxt_rcv_seq_1_cntr; /* 0x00z500 */ - u64 ce_lsi_unsp_dllp_rcvd; /* 0x00z508 */ - u64 ce_lsi_rcv_lk_ts_ctl; /* 0x00z510 */ - u64 ce_pad_00z518[29]; /* 0x00z518 -- 0x00z5F8 */ - u64 ce_lsi_phy_lyr_cfg; /* 0x00z600 */ - u64 ce_pad_00z608; /* 0x00z608 */ - u64 ce_lsi_phy_lyr_int_stat; /* 0x00z610 */ - u64 ce_lsi_phy_lyr_int_stat_test; /* 0x00z618 */ - u64 ce_lsi_phy_lyr_int_mask; /* 0x00z620 */ - u64 ce_pad_00z628[11]; /* 0x00z628 -- 0x00z678 */ - u64 ce_lsi_rcv_phy_cfg; /* 0x00z680 */ - u64 ce_lsi_rcv_phy_stat1; /* 0x00z688 */ - u64 ce_lsi_rcv_phy_stat2; /* 0x00z690 */ - u64 ce_lsi_rcv_phy_stat3; /* 0x00z698 */ - u64 ce_lsi_rcv_phy_int_stat; /* 0x00z6A0 */ - u64 ce_lsi_rcv_phy_int_stat_test; /* 0x00z6A8 */ - u64 ce_lsi_rcv_phy_int_mask; /* 0x00z6B0 */ - u64 ce_pad_00z6B8[9]; /* 0x00z6B8 -- 0x00z6F8 */ - u64 ce_lsi_tx_phy_cfg; /* 0x00z700 */ - u64 ce_lsi_tx_phy_stat; /* 0x00z708 */ - u64 ce_lsi_tx_phy_int_stat; /* 0x00z710 */ - u64 ce_lsi_tx_phy_int_stat_test; /* 0x00z718 */ - u64 ce_lsi_tx_phy_int_mask; /* 0x00z720 */ - u64 ce_lsi_tx_phy_stat2; /* 0x00z728 */ - u64 ce_pad_00z730[10]; /* 0x00z730 -- 0x00z77F */ - u64 ce_lsi_ltssm_cfg1; /* 0x00z780 */ - u64 ce_lsi_ltssm_cfg2; /* 0x00z788 */ - u64 ce_lsi_ltssm_cfg3; /* 0x00z790 */ - u64 ce_lsi_ltssm_cfg4; /* 0x00z798 */ - u64 ce_lsi_ltssm_cfg5; /* 0x00z7A0 */ - u64 ce_lsi_ltssm_stat1; /* 0x00z7A8 */ - u64 ce_lsi_ltssm_stat2; /* 0x00z7B0 */ - u64 ce_lsi_ltssm_int_stat; /* 0x00z7B8 */ - u64 ce_lsi_ltssm_int_stat_test; /* 0x00z7C0 */ - u64 ce_lsi_ltssm_int_mask; /* 0x00z7C8 */ - u64 ce_lsi_ltssm_stat_wr_en; /* 0x00z7D0 */ - u64 ce_pad_00z7D8[5]; /* 0x00z7D8 -- 0x00z7F8 */ - u64 ce_lsi_gb_cfg1; /* 0x00z800 */ - u64 ce_lsi_gb_cfg2; /* 0x00z808 */ - u64 ce_lsi_gb_cfg3; /* 0x00z810 */ - u64 ce_lsi_gb_cfg4; /* 0x00z818 */ - u64 ce_lsi_gb_stat; /* 0x00z820 */ - u64 ce_lsi_gb_int_stat; /* 0x00z828 */ - u64 ce_lsi_gb_int_stat_test; /* 0x00z830 */ - u64 ce_lsi_gb_int_mask; /* 0x00z838 */ - u64 ce_lsi_gb_pwr_dn1; /* 0x00z840 */ - u64 ce_lsi_gb_pwr_dn2; /* 0x00z848 */ - u64 ce_pad_00z850[246]; /* 0x00z850 -- 0x00zFF8 */ - } ce_lsi[2]; - - u64 ce_pad_004000[10]; /* 0x004000 -- 0x004048 */ - - /* - * CRM: Coretalk Receive Module Registers - */ - u64 ce_crm_debug_mux; /* 0x004050 */ - u64 ce_pad_004058; /* 0x004058 */ - u64 ce_crm_ssp_err_cmd_wrd; /* 0x004060 */ - u64 ce_crm_ssp_err_addr; /* 0x004068 */ - u64 ce_crm_ssp_err_syn; /* 0x004070 */ - - u64 ce_pad_004078[499]; /* 0x004078 -- 0x005008 */ - - /* - * CXM: Coretalk Xmit Module Registers - */ - u64 ce_cxm_dyn_credit_status; /* 0x005010 */ - u64 ce_cxm_last_credit_status; /* 0x005018 */ - u64 ce_cxm_credit_limit; /* 0x005020 */ - u64 ce_cxm_force_credit; /* 0x005028 */ - u64 ce_cxm_disable_bypass; /* 0x005030 */ - u64 ce_pad_005038[3]; /* 0x005038 -- 0x005048 */ - u64 ce_cxm_debug_mux; /* 0x005050 */ - - u64 ce_pad_005058[501]; /* 0x005058 -- 0x005FF8 */ - - /* - * DTL: Downstream Transaction Layer Regs (Link#1 and Link#2) - * DTL: Link#1 MMRs at start at 0x006000, Link#2 MMRs at 0x008000 - * DTL: the comment offsets at far right: let 'y' = {6 or 8} - * - * UTL: Downstream Transaction Layer Regs (Link#1 and Link#2) - * UTL: Link#1 MMRs at start at 0x007000, Link#2 MMRs at 0x009000 - * UTL: the comment offsets at far right: let 'z' = {7 or 9} - */ - #define ce_dtl(link_num) ce_dtl_utl[link_num-1] - #define ce_utl(link_num) ce_dtl_utl[link_num-1] - struct ce_dtl_utl_reg { - /* DTL */ - u64 ce_dtl_dtdr_credit_limit; /* 0x00y000 */ - u64 ce_dtl_dtdr_credit_force; /* 0x00y008 */ - u64 ce_dtl_dyn_credit_status; /* 0x00y010 */ - u64 ce_dtl_dtl_last_credit_stat; /* 0x00y018 */ - u64 ce_dtl_dtl_ctrl; /* 0x00y020 */ - u64 ce_pad_00y028[5]; /* 0x00y028 -- 0x00y048 */ - u64 ce_dtl_debug_sel; /* 0x00y050 */ - u64 ce_pad_00y058[501]; /* 0x00y058 -- 0x00yFF8 */ - - /* UTL */ - u64 ce_utl_utl_ctrl; /* 0x00z000 */ - u64 ce_utl_debug_sel; /* 0x00z008 */ - u64 ce_pad_00z010[510]; /* 0x00z010 -- 0x00zFF8 */ - } ce_dtl_utl[2]; - - u64 ce_pad_00A000[514]; /* 0x00A000 -- 0x00B008 */ - - /* - * URE: Upstream Request Engine - */ - u64 ce_ure_dyn_credit_status; /* 0x00B010 */ - u64 ce_ure_last_credit_status; /* 0x00B018 */ - u64 ce_ure_credit_limit; /* 0x00B020 */ - u64 ce_pad_00B028; /* 0x00B028 */ - u64 ce_ure_control; /* 0x00B030 */ - u64 ce_ure_status; /* 0x00B038 */ - u64 ce_pad_00B040[2]; /* 0x00B040 -- 0x00B048 */ - u64 ce_ure_debug_sel; /* 0x00B050 */ - u64 ce_ure_pcie_debug_sel; /* 0x00B058 */ - u64 ce_ure_ssp_err_cmd_wrd; /* 0x00B060 */ - u64 ce_ure_ssp_err_addr; /* 0x00B068 */ - u64 ce_ure_page_map; /* 0x00B070 */ - u64 ce_ure_dir_map[TIOCE_NUM_PORTS]; /* 0x00B078 */ - u64 ce_ure_pipe_sel1; /* 0x00B088 */ - u64 ce_ure_pipe_mask1; /* 0x00B090 */ - u64 ce_ure_pipe_sel2; /* 0x00B098 */ - u64 ce_ure_pipe_mask2; /* 0x00B0A0 */ - u64 ce_ure_pcie1_credits_sent; /* 0x00B0A8 */ - u64 ce_ure_pcie1_credits_used; /* 0x00B0B0 */ - u64 ce_ure_pcie1_credit_limit; /* 0x00B0B8 */ - u64 ce_ure_pcie2_credits_sent; /* 0x00B0C0 */ - u64 ce_ure_pcie2_credits_used; /* 0x00B0C8 */ - u64 ce_ure_pcie2_credit_limit; /* 0x00B0D0 */ - u64 ce_ure_pcie_force_credit; /* 0x00B0D8 */ - u64 ce_ure_rd_tnum_val; /* 0x00B0E0 */ - u64 ce_ure_rd_tnum_rsp_rcvd; /* 0x00B0E8 */ - u64 ce_ure_rd_tnum_esent_timer; /* 0x00B0F0 */ - u64 ce_ure_rd_tnum_error; /* 0x00B0F8 */ - u64 ce_ure_rd_tnum_first_cl; /* 0x00B100 */ - u64 ce_ure_rd_tnum_link_buf; /* 0x00B108 */ - u64 ce_ure_wr_tnum_val; /* 0x00B110 */ - u64 ce_ure_sram_err_addr0; /* 0x00B118 */ - u64 ce_ure_sram_err_addr1; /* 0x00B120 */ - u64 ce_ure_sram_err_addr2; /* 0x00B128 */ - u64 ce_ure_sram_rd_addr0; /* 0x00B130 */ - u64 ce_ure_sram_rd_addr1; /* 0x00B138 */ - u64 ce_ure_sram_rd_addr2; /* 0x00B140 */ - u64 ce_ure_sram_wr_addr0; /* 0x00B148 */ - u64 ce_ure_sram_wr_addr1; /* 0x00B150 */ - u64 ce_ure_sram_wr_addr2; /* 0x00B158 */ - u64 ce_ure_buf_flush10; /* 0x00B160 */ - u64 ce_ure_buf_flush11; /* 0x00B168 */ - u64 ce_ure_buf_flush12; /* 0x00B170 */ - u64 ce_ure_buf_flush13; /* 0x00B178 */ - u64 ce_ure_buf_flush20; /* 0x00B180 */ - u64 ce_ure_buf_flush21; /* 0x00B188 */ - u64 ce_ure_buf_flush22; /* 0x00B190 */ - u64 ce_ure_buf_flush23; /* 0x00B198 */ - u64 ce_ure_pcie_control1; /* 0x00B1A0 */ - u64 ce_ure_pcie_control2; /* 0x00B1A8 */ - - u64 ce_pad_00B1B0[458]; /* 0x00B1B0 -- 0x00BFF8 */ - - /* Upstream Data Buffer, Port1 */ - struct ce_ure_maint_ups_dat1_data { - u64 data63_0[512]; /* 0x00C000 -- 0x00CFF8 */ - u64 data127_64[512]; /* 0x00D000 -- 0x00DFF8 */ - u64 parity[512]; /* 0x00E000 -- 0x00EFF8 */ - } ce_ure_maint_ups_dat1; - - /* Upstream Header Buffer, Port1 */ - struct ce_ure_maint_ups_hdr1_data { - u64 data63_0[512]; /* 0x00F000 -- 0x00FFF8 */ - u64 data127_64[512]; /* 0x010000 -- 0x010FF8 */ - u64 parity[512]; /* 0x011000 -- 0x011FF8 */ - } ce_ure_maint_ups_hdr1; - - /* Upstream Data Buffer, Port2 */ - struct ce_ure_maint_ups_dat2_data { - u64 data63_0[512]; /* 0x012000 -- 0x012FF8 */ - u64 data127_64[512]; /* 0x013000 -- 0x013FF8 */ - u64 parity[512]; /* 0x014000 -- 0x014FF8 */ - } ce_ure_maint_ups_dat2; - - /* Upstream Header Buffer, Port2 */ - struct ce_ure_maint_ups_hdr2_data { - u64 data63_0[512]; /* 0x015000 -- 0x015FF8 */ - u64 data127_64[512]; /* 0x016000 -- 0x016FF8 */ - u64 parity[512]; /* 0x017000 -- 0x017FF8 */ - } ce_ure_maint_ups_hdr2; - - /* Downstream Data Buffer */ - struct ce_ure_maint_dns_dat_data { - u64 data63_0[512]; /* 0x018000 -- 0x018FF8 */ - u64 data127_64[512]; /* 0x019000 -- 0x019FF8 */ - u64 parity[512]; /* 0x01A000 -- 0x01AFF8 */ - } ce_ure_maint_dns_dat; - - /* Downstream Header Buffer */ - struct ce_ure_maint_dns_hdr_data { - u64 data31_0[64]; /* 0x01B000 -- 0x01B1F8 */ - u64 data95_32[64]; /* 0x01B200 -- 0x01B3F8 */ - u64 parity[64]; /* 0x01B400 -- 0x01B5F8 */ - } ce_ure_maint_dns_hdr; - - /* RCI Buffer Data */ - struct ce_ure_maint_rci_data { - u64 data41_0[64]; /* 0x01B600 -- 0x01B7F8 */ - u64 data69_42[64]; /* 0x01B800 -- 0x01B9F8 */ - } ce_ure_maint_rci; - - /* Response Queue */ - u64 ce_ure_maint_rspq[64]; /* 0x01BA00 -- 0x01BBF8 */ - - u64 ce_pad_01C000[4224]; /* 0x01BC00 -- 0x023FF8 */ - - /* Admin Build-a-Packet Buffer */ - struct ce_adm_maint_bap_buf_data { - u64 data63_0[258]; /* 0x024000 -- 0x024808 */ - u64 data127_64[258]; /* 0x024810 -- 0x025018 */ - u64 parity[258]; /* 0x025020 -- 0x025828 */ - } ce_adm_maint_bap_buf; - - u64 ce_pad_025830[5370]; /* 0x025830 -- 0x02FFF8 */ - - /* URE: 40bit PMU ATE Buffer */ /* 0x030000 -- 0x037FF8 */ - u64 ce_ure_ate40[TIOCE_NUM_M40_ATES]; - - /* URE: 32/40bit PMU ATE Buffer */ /* 0x038000 -- 0x03BFF8 */ - u64 ce_ure_ate3240[TIOCE_NUM_M3240_ATES]; - - u64 ce_pad_03C000[2050]; /* 0x03C000 -- 0x040008 */ - - /* - * DRE: Down Stream Request Engine - */ - u64 ce_dre_dyn_credit_status1; /* 0x040010 */ - u64 ce_dre_dyn_credit_status2; /* 0x040018 */ - u64 ce_dre_last_credit_status1; /* 0x040020 */ - u64 ce_dre_last_credit_status2; /* 0x040028 */ - u64 ce_dre_credit_limit1; /* 0x040030 */ - u64 ce_dre_credit_limit2; /* 0x040038 */ - u64 ce_dre_force_credit1; /* 0x040040 */ - u64 ce_dre_force_credit2; /* 0x040048 */ - u64 ce_dre_debug_mux1; /* 0x040050 */ - u64 ce_dre_debug_mux2; /* 0x040058 */ - u64 ce_dre_ssp_err_cmd_wrd; /* 0x040060 */ - u64 ce_dre_ssp_err_addr; /* 0x040068 */ - u64 ce_dre_comp_err_cmd_wrd; /* 0x040070 */ - u64 ce_dre_comp_err_addr; /* 0x040078 */ - u64 ce_dre_req_status; /* 0x040080 */ - u64 ce_dre_config1; /* 0x040088 */ - u64 ce_dre_config2; /* 0x040090 */ - u64 ce_dre_config_req_status; /* 0x040098 */ - u64 ce_pad_0400A0[12]; /* 0x0400A0 -- 0x0400F8 */ - u64 ce_dre_dyn_fifo; /* 0x040100 */ - u64 ce_pad_040108[3]; /* 0x040108 -- 0x040118 */ - u64 ce_dre_last_fifo; /* 0x040120 */ - - u64 ce_pad_040128[27]; /* 0x040128 -- 0x0401F8 */ - - /* DRE Downstream Head Queue */ - struct ce_dre_maint_ds_head_queue { - u64 data63_0[32]; /* 0x040200 -- 0x0402F8 */ - u64 data127_64[32]; /* 0x040300 -- 0x0403F8 */ - u64 parity[32]; /* 0x040400 -- 0x0404F8 */ - } ce_dre_maint_ds_head_q; - - u64 ce_pad_040500[352]; /* 0x040500 -- 0x040FF8 */ - - /* DRE Downstream Data Queue */ - struct ce_dre_maint_ds_data_queue { - u64 data63_0[256]; /* 0x041000 -- 0x0417F8 */ - u64 ce_pad_041800[256]; /* 0x041800 -- 0x041FF8 */ - u64 data127_64[256]; /* 0x042000 -- 0x0427F8 */ - u64 ce_pad_042800[256]; /* 0x042800 -- 0x042FF8 */ - u64 parity[256]; /* 0x043000 -- 0x0437F8 */ - u64 ce_pad_043800[256]; /* 0x043800 -- 0x043FF8 */ - } ce_dre_maint_ds_data_q; - - /* DRE URE Upstream Response Queue */ - struct ce_dre_maint_ure_us_rsp_queue { - u64 data63_0[8]; /* 0x044000 -- 0x044038 */ - u64 ce_pad_044040[24]; /* 0x044040 -- 0x0440F8 */ - u64 data127_64[8]; /* 0x044100 -- 0x044138 */ - u64 ce_pad_044140[24]; /* 0x044140 -- 0x0441F8 */ - u64 parity[8]; /* 0x044200 -- 0x044238 */ - u64 ce_pad_044240[24]; /* 0x044240 -- 0x0442F8 */ - } ce_dre_maint_ure_us_rsp_q; - - u64 ce_dre_maint_us_wrt_rsp[32];/* 0x044300 -- 0x0443F8 */ - - u64 ce_end_of_struct; /* 0x044400 */ -} tioce_t; - -/* ce_lsiX_gb_cfg1 register bit masks & shifts */ -#define CE_LSI_GB_CFG1_RXL0S_THS_SHFT 0 -#define CE_LSI_GB_CFG1_RXL0S_THS_MASK (0xffULL << 0) -#define CE_LSI_GB_CFG1_RXL0S_SMP_SHFT 8 -#define CE_LSI_GB_CFG1_RXL0S_SMP_MASK (0xfULL << 8) -#define CE_LSI_GB_CFG1_RXL0S_ADJ_SHFT 12 -#define CE_LSI_GB_CFG1_RXL0S_ADJ_MASK (0x7ULL << 12) -#define CE_LSI_GB_CFG1_RXL0S_FLT_SHFT 15 -#define CE_LSI_GB_CFG1_RXL0S_FLT_MASK (0x1ULL << 15) -#define CE_LSI_GB_CFG1_LPBK_SEL_SHFT 16 -#define CE_LSI_GB_CFG1_LPBK_SEL_MASK (0x3ULL << 16) -#define CE_LSI_GB_CFG1_LPBK_EN_SHFT 18 -#define CE_LSI_GB_CFG1_LPBK_EN_MASK (0x1ULL << 18) -#define CE_LSI_GB_CFG1_RVRS_LB_SHFT 19 -#define CE_LSI_GB_CFG1_RVRS_LB_MASK (0x1ULL << 19) -#define CE_LSI_GB_CFG1_RVRS_CLK_SHFT 20 -#define CE_LSI_GB_CFG1_RVRS_CLK_MASK (0x3ULL << 20) -#define CE_LSI_GB_CFG1_SLF_TS_SHFT 24 -#define CE_LSI_GB_CFG1_SLF_TS_MASK (0xfULL << 24) - -/* ce_adm_int_mask/ce_adm_int_status register bit defines */ -#define CE_ADM_INT_CE_ERROR_SHFT 0 -#define CE_ADM_INT_LSI1_IP_ERROR_SHFT 1 -#define CE_ADM_INT_LSI2_IP_ERROR_SHFT 2 -#define CE_ADM_INT_PCIE_ERROR_SHFT 3 -#define CE_ADM_INT_PORT1_HOTPLUG_EVENT_SHFT 4 -#define CE_ADM_INT_PORT2_HOTPLUG_EVENT_SHFT 5 -#define CE_ADM_INT_PCIE_PORT1_DEV_A_SHFT 6 -#define CE_ADM_INT_PCIE_PORT1_DEV_B_SHFT 7 -#define CE_ADM_INT_PCIE_PORT1_DEV_C_SHFT 8 -#define CE_ADM_INT_PCIE_PORT1_DEV_D_SHFT 9 -#define CE_ADM_INT_PCIE_PORT2_DEV_A_SHFT 10 -#define CE_ADM_INT_PCIE_PORT2_DEV_B_SHFT 11 -#define CE_ADM_INT_PCIE_PORT2_DEV_C_SHFT 12 -#define CE_ADM_INT_PCIE_PORT2_DEV_D_SHFT 13 -#define CE_ADM_INT_PCIE_MSG_SHFT 14 /*see int_dest_14*/ -#define CE_ADM_INT_PCIE_MSG_SLOT_0_SHFT 14 -#define CE_ADM_INT_PCIE_MSG_SLOT_1_SHFT 15 -#define CE_ADM_INT_PCIE_MSG_SLOT_2_SHFT 16 -#define CE_ADM_INT_PCIE_MSG_SLOT_3_SHFT 17 -#define CE_ADM_INT_PORT1_PM_PME_MSG_SHFT 22 -#define CE_ADM_INT_PORT2_PM_PME_MSG_SHFT 23 - -/* ce_adm_force_int register bit defines */ -#define CE_ADM_FORCE_INT_PCIE_PORT1_DEV_A_SHFT 0 -#define CE_ADM_FORCE_INT_PCIE_PORT1_DEV_B_SHFT 1 -#define CE_ADM_FORCE_INT_PCIE_PORT1_DEV_C_SHFT 2 -#define CE_ADM_FORCE_INT_PCIE_PORT1_DEV_D_SHFT 3 -#define CE_ADM_FORCE_INT_PCIE_PORT2_DEV_A_SHFT 4 -#define CE_ADM_FORCE_INT_PCIE_PORT2_DEV_B_SHFT 5 -#define CE_ADM_FORCE_INT_PCIE_PORT2_DEV_C_SHFT 6 -#define CE_ADM_FORCE_INT_PCIE_PORT2_DEV_D_SHFT 7 -#define CE_ADM_FORCE_INT_ALWAYS_SHFT 8 - -/* ce_adm_int_dest register bit masks & shifts */ -#define INTR_VECTOR_SHFT 56 - -/* ce_adm_error_mask and ce_adm_error_summary register bit masks */ -#define CE_ADM_ERR_CRM_SSP_REQ_INVALID (0x1ULL << 0) -#define CE_ADM_ERR_SSP_REQ_HEADER (0x1ULL << 1) -#define CE_ADM_ERR_SSP_RSP_HEADER (0x1ULL << 2) -#define CE_ADM_ERR_SSP_PROTOCOL_ERROR (0x1ULL << 3) -#define CE_ADM_ERR_SSP_SBE (0x1ULL << 4) -#define CE_ADM_ERR_SSP_MBE (0x1ULL << 5) -#define CE_ADM_ERR_CXM_CREDIT_OFLOW (0x1ULL << 6) -#define CE_ADM_ERR_DRE_SSP_REQ_INVAL (0x1ULL << 7) -#define CE_ADM_ERR_SSP_REQ_LONG (0x1ULL << 8) -#define CE_ADM_ERR_SSP_REQ_OFLOW (0x1ULL << 9) -#define CE_ADM_ERR_SSP_REQ_SHORT (0x1ULL << 10) -#define CE_ADM_ERR_SSP_REQ_SIDEBAND (0x1ULL << 11) -#define CE_ADM_ERR_SSP_REQ_ADDR_ERR (0x1ULL << 12) -#define CE_ADM_ERR_SSP_REQ_BAD_BE (0x1ULL << 13) -#define CE_ADM_ERR_PCIE_COMPL_TIMEOUT (0x1ULL << 14) -#define CE_ADM_ERR_PCIE_UNEXP_COMPL (0x1ULL << 15) -#define CE_ADM_ERR_PCIE_ERR_COMPL (0x1ULL << 16) -#define CE_ADM_ERR_DRE_CREDIT_OFLOW (0x1ULL << 17) -#define CE_ADM_ERR_DRE_SRAM_PE (0x1ULL << 18) -#define CE_ADM_ERR_SSP_RSP_INVALID (0x1ULL << 19) -#define CE_ADM_ERR_SSP_RSP_LONG (0x1ULL << 20) -#define CE_ADM_ERR_SSP_RSP_SHORT (0x1ULL << 21) -#define CE_ADM_ERR_SSP_RSP_SIDEBAND (0x1ULL << 22) -#define CE_ADM_ERR_URE_SSP_RSP_UNEXP (0x1ULL << 23) -#define CE_ADM_ERR_URE_SSP_WR_REQ_TIMEOUT (0x1ULL << 24) -#define CE_ADM_ERR_URE_SSP_RD_REQ_TIMEOUT (0x1ULL << 25) -#define CE_ADM_ERR_URE_ATE3240_PAGE_FAULT (0x1ULL << 26) -#define CE_ADM_ERR_URE_ATE40_PAGE_FAULT (0x1ULL << 27) -#define CE_ADM_ERR_URE_CREDIT_OFLOW (0x1ULL << 28) -#define CE_ADM_ERR_URE_SRAM_PE (0x1ULL << 29) -#define CE_ADM_ERR_ADM_SSP_RSP_UNEXP (0x1ULL << 30) -#define CE_ADM_ERR_ADM_SSP_REQ_TIMEOUT (0x1ULL << 31) -#define CE_ADM_ERR_MMR_ACCESS_ERROR (0x1ULL << 32) -#define CE_ADM_ERR_MMR_ADDR_ERROR (0x1ULL << 33) -#define CE_ADM_ERR_ADM_CREDIT_OFLOW (0x1ULL << 34) -#define CE_ADM_ERR_ADM_SRAM_PE (0x1ULL << 35) -#define CE_ADM_ERR_DTL1_MIN_PDATA_CREDIT_ERR (0x1ULL << 36) -#define CE_ADM_ERR_DTL1_INF_COMPL_CRED_UPDT_ERR (0x1ULL << 37) -#define CE_ADM_ERR_DTL1_INF_POSTED_CRED_UPDT_ERR (0x1ULL << 38) -#define CE_ADM_ERR_DTL1_INF_NPOSTED_CRED_UPDT_ERR (0x1ULL << 39) -#define CE_ADM_ERR_DTL1_COMP_HD_CRED_MAX_ERR (0x1ULL << 40) -#define CE_ADM_ERR_DTL1_COMP_D_CRED_MAX_ERR (0x1ULL << 41) -#define CE_ADM_ERR_DTL1_NPOSTED_HD_CRED_MAX_ERR (0x1ULL << 42) -#define CE_ADM_ERR_DTL1_NPOSTED_D_CRED_MAX_ERR (0x1ULL << 43) -#define CE_ADM_ERR_DTL1_POSTED_HD_CRED_MAX_ERR (0x1ULL << 44) -#define CE_ADM_ERR_DTL1_POSTED_D_CRED_MAX_ERR (0x1ULL << 45) -#define CE_ADM_ERR_DTL2_MIN_PDATA_CREDIT_ERR (0x1ULL << 46) -#define CE_ADM_ERR_DTL2_INF_COMPL_CRED_UPDT_ERR (0x1ULL << 47) -#define CE_ADM_ERR_DTL2_INF_POSTED_CRED_UPDT_ERR (0x1ULL << 48) -#define CE_ADM_ERR_DTL2_INF_NPOSTED_CRED_UPDT_ERR (0x1ULL << 49) -#define CE_ADM_ERR_DTL2_COMP_HD_CRED_MAX_ERR (0x1ULL << 50) -#define CE_ADM_ERR_DTL2_COMP_D_CRED_MAX_ERR (0x1ULL << 51) -#define CE_ADM_ERR_DTL2_NPOSTED_HD_CRED_MAX_ERR (0x1ULL << 52) -#define CE_ADM_ERR_DTL2_NPOSTED_D_CRED_MAX_ERR (0x1ULL << 53) -#define CE_ADM_ERR_DTL2_POSTED_HD_CRED_MAX_ERR (0x1ULL << 54) -#define CE_ADM_ERR_DTL2_POSTED_D_CRED_MAX_ERR (0x1ULL << 55) -#define CE_ADM_ERR_PORT1_PCIE_COR_ERR (0x1ULL << 56) -#define CE_ADM_ERR_PORT1_PCIE_NFAT_ERR (0x1ULL << 57) -#define CE_ADM_ERR_PORT1_PCIE_FAT_ERR (0x1ULL << 58) -#define CE_ADM_ERR_PORT2_PCIE_COR_ERR (0x1ULL << 59) -#define CE_ADM_ERR_PORT2_PCIE_NFAT_ERR (0x1ULL << 60) -#define CE_ADM_ERR_PORT2_PCIE_FAT_ERR (0x1ULL << 61) - -/* ce_adm_ure_ups_buf_barrier_flush register bit masks and shifts */ -#define FLUSH_SEL_PORT1_PIPE0_SHFT 0 -#define FLUSH_SEL_PORT1_PIPE1_SHFT 4 -#define FLUSH_SEL_PORT1_PIPE2_SHFT 8 -#define FLUSH_SEL_PORT1_PIPE3_SHFT 12 -#define FLUSH_SEL_PORT2_PIPE0_SHFT 16 -#define FLUSH_SEL_PORT2_PIPE1_SHFT 20 -#define FLUSH_SEL_PORT2_PIPE2_SHFT 24 -#define FLUSH_SEL_PORT2_PIPE3_SHFT 28 - -/* ce_dre_config1 register bit masks and shifts */ -#define CE_DRE_RO_ENABLE (0x1ULL << 0) -#define CE_DRE_DYN_RO_ENABLE (0x1ULL << 1) -#define CE_DRE_SUP_CONFIG_COMP_ERROR (0x1ULL << 2) -#define CE_DRE_SUP_IO_COMP_ERROR (0x1ULL << 3) -#define CE_DRE_ADDR_MODE_SHFT 4 - -/* ce_dre_config_req_status register bit masks */ -#define CE_DRE_LAST_CONFIG_COMPLETION (0x7ULL << 0) -#define CE_DRE_DOWNSTREAM_CONFIG_ERROR (0x1ULL << 3) -#define CE_DRE_CONFIG_COMPLETION_VALID (0x1ULL << 4) -#define CE_DRE_CONFIG_REQUEST_ACTIVE (0x1ULL << 5) - -/* ce_ure_control register bit masks & shifts */ -#define CE_URE_RD_MRG_ENABLE (0x1ULL << 0) -#define CE_URE_WRT_MRG_ENABLE1 (0x1ULL << 4) -#define CE_URE_WRT_MRG_ENABLE2 (0x1ULL << 5) -#define CE_URE_WRT_MRG_TIMER_SHFT 12 -#define CE_URE_WRT_MRG_TIMER_MASK (0x7FFULL << CE_URE_WRT_MRG_TIMER_SHFT) -#define CE_URE_WRT_MRG_TIMER(x) (((u64)(x) << \ - CE_URE_WRT_MRG_TIMER_SHFT) & \ - CE_URE_WRT_MRG_TIMER_MASK) -#define CE_URE_RSPQ_BYPASS_DISABLE (0x1ULL << 24) -#define CE_URE_UPS_DAT1_PAR_DISABLE (0x1ULL << 32) -#define CE_URE_UPS_HDR1_PAR_DISABLE (0x1ULL << 33) -#define CE_URE_UPS_DAT2_PAR_DISABLE (0x1ULL << 34) -#define CE_URE_UPS_HDR2_PAR_DISABLE (0x1ULL << 35) -#define CE_URE_ATE_PAR_DISABLE (0x1ULL << 36) -#define CE_URE_RCI_PAR_DISABLE (0x1ULL << 37) -#define CE_URE_RSPQ_PAR_DISABLE (0x1ULL << 38) -#define CE_URE_DNS_DAT_PAR_DISABLE (0x1ULL << 39) -#define CE_URE_DNS_HDR_PAR_DISABLE (0x1ULL << 40) -#define CE_URE_MALFORM_DISABLE (0x1ULL << 44) -#define CE_URE_UNSUP_DISABLE (0x1ULL << 45) - -/* ce_ure_page_map register bit masks & shifts */ -#define CE_URE_ATE3240_ENABLE (0x1ULL << 0) -#define CE_URE_ATE40_ENABLE (0x1ULL << 1) -#define CE_URE_PAGESIZE_SHFT 4 -#define CE_URE_PAGESIZE_MASK (0x7ULL << CE_URE_PAGESIZE_SHFT) -#define CE_URE_4K_PAGESIZE (0x0ULL << CE_URE_PAGESIZE_SHFT) -#define CE_URE_16K_PAGESIZE (0x1ULL << CE_URE_PAGESIZE_SHFT) -#define CE_URE_64K_PAGESIZE (0x2ULL << CE_URE_PAGESIZE_SHFT) -#define CE_URE_128K_PAGESIZE (0x3ULL << CE_URE_PAGESIZE_SHFT) -#define CE_URE_256K_PAGESIZE (0x4ULL << CE_URE_PAGESIZE_SHFT) - -/* ce_ure_pipe_sel register bit masks & shifts */ -#define PKT_TRAFIC_SHRT 16 -#define BUS_SRC_ID_SHFT 8 -#define DEV_SRC_ID_SHFT 3 -#define FNC_SRC_ID_SHFT 0 -#define CE_URE_TC_MASK (0x07ULL << PKT_TRAFIC_SHRT) -#define CE_URE_BUS_MASK (0xFFULL << BUS_SRC_ID_SHFT) -#define CE_URE_DEV_MASK (0x1FULL << DEV_SRC_ID_SHFT) -#define CE_URE_FNC_MASK (0x07ULL << FNC_SRC_ID_SHFT) -#define CE_URE_PIPE_BUS(b) (((u64)(b) << BUS_SRC_ID_SHFT) & \ - CE_URE_BUS_MASK) -#define CE_URE_PIPE_DEV(d) (((u64)(d) << DEV_SRC_ID_SHFT) & \ - CE_URE_DEV_MASK) -#define CE_URE_PIPE_FNC(f) (((u64)(f) << FNC_SRC_ID_SHFT) & \ - CE_URE_FNC_MASK) - -#define CE_URE_SEL1_SHFT 0 -#define CE_URE_SEL2_SHFT 20 -#define CE_URE_SEL3_SHFT 40 -#define CE_URE_SEL1_MASK (0x7FFFFULL << CE_URE_SEL1_SHFT) -#define CE_URE_SEL2_MASK (0x7FFFFULL << CE_URE_SEL2_SHFT) -#define CE_URE_SEL3_MASK (0x7FFFFULL << CE_URE_SEL3_SHFT) - - -/* ce_ure_pipe_mask register bit masks & shifts */ -#define CE_URE_MASK1_SHFT 0 -#define CE_URE_MASK2_SHFT 20 -#define CE_URE_MASK3_SHFT 40 -#define CE_URE_MASK1_MASK (0x7FFFFULL << CE_URE_MASK1_SHFT) -#define CE_URE_MASK2_MASK (0x7FFFFULL << CE_URE_MASK2_SHFT) -#define CE_URE_MASK3_MASK (0x7FFFFULL << CE_URE_MASK3_SHFT) - - -/* ce_ure_pcie_control1 register bit masks & shifts */ -#define CE_URE_SI (0x1ULL << 0) -#define CE_URE_ELAL_SHFT 4 -#define CE_URE_ELAL_MASK (0x7ULL << CE_URE_ELAL_SHFT) -#define CE_URE_ELAL_SET(n) (((u64)(n) << CE_URE_ELAL_SHFT) & \ - CE_URE_ELAL_MASK) -#define CE_URE_ELAL1_SHFT 8 -#define CE_URE_ELAL1_MASK (0x7ULL << CE_URE_ELAL1_SHFT) -#define CE_URE_ELAL1_SET(n) (((u64)(n) << CE_URE_ELAL1_SHFT) & \ - CE_URE_ELAL1_MASK) -#define CE_URE_SCC (0x1ULL << 12) -#define CE_URE_PN1_SHFT 16 -#define CE_URE_PN1_MASK (0xFFULL << CE_URE_PN1_SHFT) -#define CE_URE_PN2_SHFT 24 -#define CE_URE_PN2_MASK (0xFFULL << CE_URE_PN2_SHFT) -#define CE_URE_PN1_SET(n) (((u64)(n) << CE_URE_PN1_SHFT) & \ - CE_URE_PN1_MASK) -#define CE_URE_PN2_SET(n) (((u64)(n) << CE_URE_PN2_SHFT) & \ - CE_URE_PN2_MASK) - -/* ce_ure_pcie_control2 register bit masks & shifts */ -#define CE_URE_ABP (0x1ULL << 0) -#define CE_URE_PCP (0x1ULL << 1) -#define CE_URE_MSP (0x1ULL << 2) -#define CE_URE_AIP (0x1ULL << 3) -#define CE_URE_PIP (0x1ULL << 4) -#define CE_URE_HPS (0x1ULL << 5) -#define CE_URE_HPC (0x1ULL << 6) -#define CE_URE_SPLV_SHFT 7 -#define CE_URE_SPLV_MASK (0xFFULL << CE_URE_SPLV_SHFT) -#define CE_URE_SPLV_SET(n) (((u64)(n) << CE_URE_SPLV_SHFT) & \ - CE_URE_SPLV_MASK) -#define CE_URE_SPLS_SHFT 15 -#define CE_URE_SPLS_MASK (0x3ULL << CE_URE_SPLS_SHFT) -#define CE_URE_SPLS_SET(n) (((u64)(n) << CE_URE_SPLS_SHFT) & \ - CE_URE_SPLS_MASK) -#define CE_URE_PSN1_SHFT 19 -#define CE_URE_PSN1_MASK (0x1FFFULL << CE_URE_PSN1_SHFT) -#define CE_URE_PSN2_SHFT 32 -#define CE_URE_PSN2_MASK (0x1FFFULL << CE_URE_PSN2_SHFT) -#define CE_URE_PSN1_SET(n) (((u64)(n) << CE_URE_PSN1_SHFT) & \ - CE_URE_PSN1_MASK) -#define CE_URE_PSN2_SET(n) (((u64)(n) << CE_URE_PSN2_SHFT) & \ - CE_URE_PSN2_MASK) - -/* - * PIO address space ranges for CE - */ - -/* Local CE Registers Space */ -#define CE_PIO_MMR 0x00000000 -#define CE_PIO_MMR_LEN 0x04000000 - -/* PCI Compatible Config Space */ -#define CE_PIO_CONFIG_SPACE 0x04000000 -#define CE_PIO_CONFIG_SPACE_LEN 0x04000000 - -/* PCI I/O Space Alias */ -#define CE_PIO_IO_SPACE_ALIAS 0x08000000 -#define CE_PIO_IO_SPACE_ALIAS_LEN 0x08000000 - -/* PCI Enhanced Config Space */ -#define CE_PIO_E_CONFIG_SPACE 0x10000000 -#define CE_PIO_E_CONFIG_SPACE_LEN 0x10000000 - -/* PCI I/O Space */ -#define CE_PIO_IO_SPACE 0x100000000 -#define CE_PIO_IO_SPACE_LEN 0x100000000 - -/* PCI MEM Space */ -#define CE_PIO_MEM_SPACE 0x200000000 -#define CE_PIO_MEM_SPACE_LEN TIO_HWIN_SIZE - - -/* - * CE PCI Enhanced Config Space shifts & masks - */ -#define CE_E_CONFIG_BUS_SHFT 20 -#define CE_E_CONFIG_BUS_MASK (0xFF << CE_E_CONFIG_BUS_SHFT) -#define CE_E_CONFIG_DEVICE_SHFT 15 -#define CE_E_CONFIG_DEVICE_MASK (0x1F << CE_E_CONFIG_DEVICE_SHFT) -#define CE_E_CONFIG_FUNC_SHFT 12 -#define CE_E_CONFIG_FUNC_MASK (0x7 << CE_E_CONFIG_FUNC_SHFT) - -#endif /* __ASM_IA64_SN_TIOCE_H__ */ diff --git a/arch/ia64/include/asm/sn/tioce_provider.h b/arch/ia64/include/asm/sn/tioce_provider.h deleted file mode 100644 index 32c32f30b0998b1f22877ff23a8784c253313fe0..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/tioce_provider.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2003-2005 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_CE_PROVIDER_H -#define _ASM_IA64_SN_CE_PROVIDER_H - -#include -#include - -/* - * Common TIOCE structure shared between the prom and kernel - * - * DO NOT CHANGE THIS STRUCT WITHOUT MAKING CORRESPONDING CHANGES TO THE - * PROM VERSION. - */ -struct tioce_common { - struct pcibus_bussoft ce_pcibus; /* common pciio header */ - - u32 ce_rev; - u64 ce_kernel_private; - u64 ce_prom_private; -}; - -struct tioce_kernel { - struct tioce_common *ce_common; - spinlock_t ce_lock; - struct list_head ce_dmamap_list; - - u64 ce_ate40_shadow[TIOCE_NUM_M40_ATES]; - u64 ce_ate3240_shadow[TIOCE_NUM_M3240_ATES]; - u32 ce_ate3240_pagesize; - - u8 ce_port1_secondary; - - /* per-port resources */ - struct { - int dirmap_refcnt; - u64 dirmap_shadow; - } ce_port[TIOCE_NUM_PORTS]; -}; - -struct tioce_dmamap { - struct list_head ce_dmamap_list; /* headed by tioce_kernel */ - u32 refcnt; - - u64 nbytes; /* # bytes mapped */ - - u64 ct_start; /* coretalk start address */ - u64 pci_start; /* bus start address */ - - u64 __iomem *ate_hw;/* hw ptr of first ate in map */ - u64 *ate_shadow; /* shadow ptr of firat ate */ - u16 ate_count; /* # ate's in the map */ -}; - -extern int tioce_init_provider(void); - -#endif /* __ASM_IA64_SN_CE_PROVIDER_H */ diff --git a/arch/ia64/include/asm/sn/tiocp.h b/arch/ia64/include/asm/sn/tiocp.h deleted file mode 100644 index e8ad0bb5b6c51c27850633b8ec093b976f61f27b..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/tiocp.h +++ /dev/null @@ -1,257 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2003-2005 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_PCI_TIOCP_H -#define _ASM_IA64_SN_PCI_TIOCP_H - -#define TIOCP_HOST_INTR_ADDR 0x003FFFFFFFFFFFFFUL -#define TIOCP_PCI64_CMDTYPE_MEM (0x1ull << 60) -#define TIOCP_PCI64_CMDTYPE_MSI (0x3ull << 60) - - -/***************************************************************************** - *********************** TIOCP MMR structure mapping *************************** - *****************************************************************************/ - -struct tiocp{ - - /* 0x000000-0x00FFFF -- Local Registers */ - - /* 0x000000-0x000057 -- (Legacy Widget Space) Configuration */ - u64 cp_id; /* 0x000000 */ - u64 cp_stat; /* 0x000008 */ - u64 cp_err_upper; /* 0x000010 */ - u64 cp_err_lower; /* 0x000018 */ - #define cp_err cp_err_lower - u64 cp_control; /* 0x000020 */ - u64 cp_req_timeout; /* 0x000028 */ - u64 cp_intr_upper; /* 0x000030 */ - u64 cp_intr_lower; /* 0x000038 */ - #define cp_intr cp_intr_lower - u64 cp_err_cmdword; /* 0x000040 */ - u64 _pad_000048; /* 0x000048 */ - u64 cp_tflush; /* 0x000050 */ - - /* 0x000058-0x00007F -- Bridge-specific Configuration */ - u64 cp_aux_err; /* 0x000058 */ - u64 cp_resp_upper; /* 0x000060 */ - u64 cp_resp_lower; /* 0x000068 */ - #define cp_resp cp_resp_lower - u64 cp_tst_pin_ctrl; /* 0x000070 */ - u64 cp_addr_lkerr; /* 0x000078 */ - - /* 0x000080-0x00008F -- PMU & MAP */ - u64 cp_dir_map; /* 0x000080 */ - u64 _pad_000088; /* 0x000088 */ - - /* 0x000090-0x00009F -- SSRAM */ - u64 cp_map_fault; /* 0x000090 */ - u64 _pad_000098; /* 0x000098 */ - - /* 0x0000A0-0x0000AF -- Arbitration */ - u64 cp_arb; /* 0x0000A0 */ - u64 _pad_0000A8; /* 0x0000A8 */ - - /* 0x0000B0-0x0000BF -- Number In A Can or ATE Parity Error */ - u64 cp_ate_parity_err; /* 0x0000B0 */ - u64 _pad_0000B8; /* 0x0000B8 */ - - /* 0x0000C0-0x0000FF -- PCI/GIO */ - u64 cp_bus_timeout; /* 0x0000C0 */ - u64 cp_pci_cfg; /* 0x0000C8 */ - u64 cp_pci_err_upper; /* 0x0000D0 */ - u64 cp_pci_err_lower; /* 0x0000D8 */ - #define cp_pci_err cp_pci_err_lower - u64 _pad_0000E0[4]; /* 0x0000{E0..F8} */ - - /* 0x000100-0x0001FF -- Interrupt */ - u64 cp_int_status; /* 0x000100 */ - u64 cp_int_enable; /* 0x000108 */ - u64 cp_int_rst_stat; /* 0x000110 */ - u64 cp_int_mode; /* 0x000118 */ - u64 cp_int_device; /* 0x000120 */ - u64 cp_int_host_err; /* 0x000128 */ - u64 cp_int_addr[8]; /* 0x0001{30,,,68} */ - u64 cp_err_int_view; /* 0x000170 */ - u64 cp_mult_int; /* 0x000178 */ - u64 cp_force_always[8]; /* 0x0001{80,,,B8} */ - u64 cp_force_pin[8]; /* 0x0001{C0,,,F8} */ - - /* 0x000200-0x000298 -- Device */ - u64 cp_device[4]; /* 0x0002{00,,,18} */ - u64 _pad_000220[4]; /* 0x0002{20,,,38} */ - u64 cp_wr_req_buf[4]; /* 0x0002{40,,,58} */ - u64 _pad_000260[4]; /* 0x0002{60,,,78} */ - u64 cp_rrb_map[2]; /* 0x0002{80,,,88} */ - #define cp_even_resp cp_rrb_map[0] /* 0x000280 */ - #define cp_odd_resp cp_rrb_map[1] /* 0x000288 */ - u64 cp_resp_status; /* 0x000290 */ - u64 cp_resp_clear; /* 0x000298 */ - - u64 _pad_0002A0[12]; /* 0x0002{A0..F8} */ - - /* 0x000300-0x0003F8 -- Buffer Address Match Registers */ - struct { - u64 upper; /* 0x0003{00,,,F0} */ - u64 lower; /* 0x0003{08,,,F8} */ - } cp_buf_addr_match[16]; - - /* 0x000400-0x0005FF -- Performance Monitor Registers (even only) */ - struct { - u64 flush_w_touch; /* 0x000{400,,,5C0} */ - u64 flush_wo_touch; /* 0x000{408,,,5C8} */ - u64 inflight; /* 0x000{410,,,5D0} */ - u64 prefetch; /* 0x000{418,,,5D8} */ - u64 total_pci_retry; /* 0x000{420,,,5E0} */ - u64 max_pci_retry; /* 0x000{428,,,5E8} */ - u64 max_latency; /* 0x000{430,,,5F0} */ - u64 clear_all; /* 0x000{438,,,5F8} */ - } cp_buf_count[8]; - - - /* 0x000600-0x0009FF -- PCI/X registers */ - u64 cp_pcix_bus_err_addr; /* 0x000600 */ - u64 cp_pcix_bus_err_attr; /* 0x000608 */ - u64 cp_pcix_bus_err_data; /* 0x000610 */ - u64 cp_pcix_pio_split_addr; /* 0x000618 */ - u64 cp_pcix_pio_split_attr; /* 0x000620 */ - u64 cp_pcix_dma_req_err_attr; /* 0x000628 */ - u64 cp_pcix_dma_req_err_addr; /* 0x000630 */ - u64 cp_pcix_timeout; /* 0x000638 */ - - u64 _pad_000640[24]; /* 0x000{640,,,6F8} */ - - /* 0x000700-0x000737 -- Debug Registers */ - u64 cp_ct_debug_ctl; /* 0x000700 */ - u64 cp_br_debug_ctl; /* 0x000708 */ - u64 cp_mux3_debug_ctl; /* 0x000710 */ - u64 cp_mux4_debug_ctl; /* 0x000718 */ - u64 cp_mux5_debug_ctl; /* 0x000720 */ - u64 cp_mux6_debug_ctl; /* 0x000728 */ - u64 cp_mux7_debug_ctl; /* 0x000730 */ - - u64 _pad_000738[89]; /* 0x000{738,,,9F8} */ - - /* 0x000A00-0x000BFF -- PCI/X Read&Write Buffer */ - struct { - u64 cp_buf_addr; /* 0x000{A00,,,AF0} */ - u64 cp_buf_attr; /* 0X000{A08,,,AF8} */ - } cp_pcix_read_buf_64[16]; - - struct { - u64 cp_buf_addr; /* 0x000{B00,,,BE0} */ - u64 cp_buf_attr; /* 0x000{B08,,,BE8} */ - u64 cp_buf_valid; /* 0x000{B10,,,BF0} */ - u64 __pad1; /* 0x000{B18,,,BF8} */ - } cp_pcix_write_buf_64[8]; - - /* End of Local Registers -- Start of Address Map space */ - - char _pad_000c00[0x010000 - 0x000c00]; - - /* 0x010000-0x011FF8 -- Internal ATE RAM (Auto Parity Generation) */ - u64 cp_int_ate_ram[1024]; /* 0x010000-0x011FF8 */ - - char _pad_012000[0x14000 - 0x012000]; - - /* 0x014000-0x015FF8 -- Internal ATE RAM (Manual Parity Generation) */ - u64 cp_int_ate_ram_mp[1024]; /* 0x014000-0x015FF8 */ - - char _pad_016000[0x18000 - 0x016000]; - - /* 0x18000-0x197F8 -- TIOCP Write Request Ram */ - u64 cp_wr_req_lower[256]; /* 0x18000 - 0x187F8 */ - u64 cp_wr_req_upper[256]; /* 0x18800 - 0x18FF8 */ - u64 cp_wr_req_parity[256]; /* 0x19000 - 0x197F8 */ - - char _pad_019800[0x1C000 - 0x019800]; - - /* 0x1C000-0x1EFF8 -- TIOCP Read Response Ram */ - u64 cp_rd_resp_lower[512]; /* 0x1C000 - 0x1CFF8 */ - u64 cp_rd_resp_upper[512]; /* 0x1D000 - 0x1DFF8 */ - u64 cp_rd_resp_parity[512]; /* 0x1E000 - 0x1EFF8 */ - - char _pad_01F000[0x20000 - 0x01F000]; - - /* 0x020000-0x021FFF -- Host Device (CP) Configuration Space (not used) */ - char _pad_020000[0x021000 - 0x20000]; - - /* 0x021000-0x027FFF -- PCI Device Configuration Spaces */ - union { - u8 c[0x1000 / 1]; /* 0x02{0000,,,7FFF} */ - u16 s[0x1000 / 2]; /* 0x02{0000,,,7FFF} */ - u32 l[0x1000 / 4]; /* 0x02{0000,,,7FFF} */ - u64 d[0x1000 / 8]; /* 0x02{0000,,,7FFF} */ - union { - u8 c[0x100 / 1]; - u16 s[0x100 / 2]; - u32 l[0x100 / 4]; - u64 d[0x100 / 8]; - } f[8]; - } cp_type0_cfg_dev[7]; /* 0x02{1000,,,7FFF} */ - - /* 0x028000-0x028FFF -- PCI Type 1 Configuration Space */ - union { - u8 c[0x1000 / 1]; /* 0x028000-0x029000 */ - u16 s[0x1000 / 2]; /* 0x028000-0x029000 */ - u32 l[0x1000 / 4]; /* 0x028000-0x029000 */ - u64 d[0x1000 / 8]; /* 0x028000-0x029000 */ - union { - u8 c[0x100 / 1]; - u16 s[0x100 / 2]; - u32 l[0x100 / 4]; - u64 d[0x100 / 8]; - } f[8]; - } cp_type1_cfg; /* 0x028000-0x029000 */ - - char _pad_029000[0x030000-0x029000]; - - /* 0x030000-0x030007 -- PCI Interrupt Acknowledge Cycle */ - union { - u8 c[8 / 1]; - u16 s[8 / 2]; - u32 l[8 / 4]; - u64 d[8 / 8]; - } cp_pci_iack; /* 0x030000-0x030007 */ - - char _pad_030007[0x040000-0x030008]; - - /* 0x040000-0x040007 -- PCIX Special Cycle */ - union { - u8 c[8 / 1]; - u16 s[8 / 2]; - u32 l[8 / 4]; - u64 d[8 / 8]; - } cp_pcix_cycle; /* 0x040000-0x040007 */ - - char _pad_040007[0x200000-0x040008]; - - /* 0x200000-0x7FFFFF -- PCI/GIO Device Spaces */ - union { - u8 c[0x100000 / 1]; - u16 s[0x100000 / 2]; - u32 l[0x100000 / 4]; - u64 d[0x100000 / 8]; - } cp_devio_raw[6]; /* 0x200000-0x7FFFFF */ - - #define cp_devio(n) cp_devio_raw[((n)<2)?(n*2):(n+2)] - - char _pad_800000[0xA00000-0x800000]; - - /* 0xA00000-0xBFFFFF -- PCI/GIO Device Spaces w/flush */ - union { - u8 c[0x100000 / 1]; - u16 s[0x100000 / 2]; - u32 l[0x100000 / 4]; - u64 d[0x100000 / 8]; - } cp_devio_raw_flush[6]; /* 0xA00000-0xBFFFFF */ - - #define cp_devio_flush(n) cp_devio_raw_flush[((n)<2)?(n*2):(n+2)] - -}; - -#endif /* _ASM_IA64_SN_PCI_TIOCP_H */ diff --git a/arch/ia64/include/asm/sn/tiocx.h b/arch/ia64/include/asm/sn/tiocx.h deleted file mode 100644 index d29728492f36ccf39ec7c50ba19f223ca510ca0a..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/tiocx.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_TIO_TIOCX_H -#define _ASM_IA64_SN_TIO_TIOCX_H - -#ifdef __KERNEL__ - -struct cx_id_s { - unsigned int part_num; - unsigned int mfg_num; - int nasid; -}; - -struct cx_dev { - struct cx_id_s cx_id; - int bt; /* board/blade type */ - void *soft; /* driver specific */ - struct hubdev_info *hubdev; - struct device dev; - struct cx_drv *driver; -}; - -struct cx_device_id { - unsigned int part_num; - unsigned int mfg_num; -}; - -struct cx_drv { - char *name; - const struct cx_device_id *id_table; - struct device_driver driver; - int (*probe) (struct cx_dev * dev, const struct cx_device_id * id); - int (*remove) (struct cx_dev * dev); -}; - -/* create DMA address by stripping AS bits */ -#define TIOCX_DMA_ADDR(a) (u64)((u64)(a) & 0xffffcfffffffffUL) - -#define TIOCX_TO_TIOCX_DMA_ADDR(a) (u64)(((u64)(a) & 0xfffffffff) | \ - ((((u64)(a)) & 0xffffc000000000UL) <<2)) - -#define TIO_CE_ASIC_PARTNUM 0xce00 -#define TIOCX_CORELET 3 - -/* These are taken from tio_mmr_as.h */ -#define TIO_ICE_FRZ_CFG TIO_MMR_ADDR_MOD(0x00000000b0008100UL) -#define TIO_ICE_PMI_TX_CFG TIO_MMR_ADDR_MOD(0x00000000b000b100UL) -#define TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3 TIO_MMR_ADDR_MOD(0x00000000b000be18UL) -#define TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3_CREDIT_CNT_MASK 0x000000000000000fUL - -#define to_cx_dev(n) container_of(n, struct cx_dev, dev) -#define to_cx_driver(drv) container_of(drv, struct cx_drv, driver) - -extern struct sn_irq_info *tiocx_irq_alloc(nasid_t, int, int, nasid_t, int); -extern void tiocx_irq_free(struct sn_irq_info *); -extern int cx_device_unregister(struct cx_dev *); -extern int cx_device_register(nasid_t, int, int, struct hubdev_info *, int); -extern int cx_driver_unregister(struct cx_drv *); -extern int cx_driver_register(struct cx_drv *); -extern u64 tiocx_dma_addr(u64 addr); -extern u64 tiocx_swin_base(int nasid); -extern void tiocx_mmr_store(int nasid, u64 offset, u64 value); -extern u64 tiocx_mmr_load(int nasid, u64 offset); - -#endif // __KERNEL__ -#endif // _ASM_IA64_SN_TIO_TIOCX__ diff --git a/arch/ia64/include/asm/sn/types.h b/arch/ia64/include/asm/sn/types.h deleted file mode 100644 index 8e04ee211e59d5f7081ed7082a681b7838e51d4a..0000000000000000000000000000000000000000 --- a/arch/ia64/include/asm/sn/types.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. - * Copyright (C) 1999 by Ralf Baechle - */ -#ifndef _ASM_IA64_SN_TYPES_H -#define _ASM_IA64_SN_TYPES_H - -#include - -typedef unsigned long cpuid_t; -typedef signed short nasid_t; /* node id in numa-as-id space */ -typedef signed char partid_t; /* partition ID type */ -typedef unsigned int moduleid_t; /* user-visible module number type */ -typedef unsigned int cmoduleid_t; /* kernel compact module id type */ -typedef unsigned char slotid_t; /* slot (blade) within module */ -typedef unsigned char slabid_t; /* slab (asic) within slot */ -typedef u64 nic_t; -typedef unsigned long iopaddr_t; -typedef unsigned long paddr_t; -typedef short cnodeid_t; - -#endif /* _ASM_IA64_SN_TYPES_H */ diff --git a/arch/ia64/include/asm/switch_to.h b/arch/ia64/include/asm/switch_to.h index b10f31ec522c4d3867485a76175308306a011a8b..9011e90a6b97c1c951082c649695bb436d02f678 100644 --- a/arch/ia64/include/asm/switch_to.h +++ b/arch/ia64/include/asm/switch_to.h @@ -69,7 +69,6 @@ extern void ia64_load_extra (struct task_struct *task); if (unlikely((current->thread.flags & IA64_THREAD_MIGRATION) && \ (task_cpu(current) != \ task_thread_info(current)->last_cpu))) { \ - platform_migrate(current); \ task_thread_info(current)->last_cpu = task_cpu(current); \ } \ } while (0) diff --git a/arch/ia64/include/asm/tlb.h b/arch/ia64/include/asm/tlb.h index 86ec034ba49917bcc2b71b8425ffdafd82ed1cae..f1f257d632b3722d767566680fc63320a4150359 100644 --- a/arch/ia64/include/asm/tlb.h +++ b/arch/ia64/include/asm/tlb.h @@ -45,7 +45,6 @@ #include #include #include -#include #include diff --git a/arch/ia64/include/asm/uv/uv.h b/arch/ia64/include/asm/uv/uv.h index 71df93ee3bc024ef3beccb35e4b231b4844cd27a..48d4526bf4cd5af35a3ded26dc87ef6d9f0d1687 100644 --- a/arch/ia64/include/asm/uv/uv.h +++ b/arch/ia64/include/asm/uv/uv.h @@ -2,12 +2,29 @@ #ifndef _ASM_IA64_UV_UV_H #define _ASM_IA64_UV_UV_H -#include +#ifdef CONFIG_IA64_SGI_UV +extern bool ia64_is_uv; static inline int is_uv_system(void) { - /* temporary support for running on hardware simulator */ - return IS_MEDUSA() || ia64_platform_is("uv"); + return ia64_is_uv; } +void __init uv_probe_system_type(void); +void __init uv_setup(char **cmdline_p); +#else /* CONFIG_IA64_SGI_UV */ +static inline int is_uv_system(void) +{ + return false; +} + +static inline void __init uv_probe_system_type(void) +{ +} + +static inline void __init uv_setup(char **cmdline_p) +{ +} +#endif /* CONFIG_IA64_SGI_UV */ + #endif /* _ASM_IA64_UV_UV_H */ diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile index 4ba05140b249ba10afe8b0f7655d5deff3748b38..1a8df6669eee658c69f27051a6141fd2c8014a1c 100644 --- a/arch/ia64/kernel/Makefile +++ b/arch/ia64/kernel/Makefile @@ -10,15 +10,14 @@ endif extra-y := head.o vmlinux.lds obj-y := entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \ - irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \ + irq_lsapic.o ivt.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \ salinfo.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \ - unwind.o mca.o mca_asm.o topology.o dma-mapping.o + unwind.o mca.o mca_asm.o topology.o dma-mapping.o iosapic.o acpi.o \ + acpi-ext.o -obj-$(CONFIG_ACPI) += acpi.o acpi-ext.o obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o obj-$(CONFIG_IA64_PALINFO) += palinfo.o -obj-$(CONFIG_IOSAPIC) += iosapic.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_SMP) += smp.o smpboot.o obj-$(CONFIG_NUMA) += numa.o @@ -31,7 +30,7 @@ obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o obj-$(CONFIG_AUDIT) += audit.o -obj-$(CONFIG_PCI_MSI) += msi_ia64.o +obj-y += msi_ia64.o mca_recovery-y += mca_drv.o mca_drv_asm.o obj-$(CONFIG_IA64_MC_ERR_INJECT)+= err_inject.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index c597ab5275b8ef268f50dfbe20e7f4bdeff75317..70d1587ddcd4676030bc3ce8d5cf51cc01a2cc71 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -45,77 +44,6 @@ unsigned int acpi_cpei_phys_cpuid; unsigned long acpi_wakeup_address = 0; -#ifdef CONFIG_IA64_GENERIC -static unsigned long __init acpi_find_rsdp(void) -{ - unsigned long rsdp_phys = 0; - - if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) - rsdp_phys = efi.acpi20; - else if (efi.acpi != EFI_INVALID_TABLE_ADDR) - printk(KERN_WARNING PREFIX - "v1.0/r0.71 tables no longer supported\n"); - return rsdp_phys; -} - -const char __init * -acpi_get_sysname(void) -{ - unsigned long rsdp_phys; - struct acpi_table_rsdp *rsdp; - struct acpi_table_xsdt *xsdt; - struct acpi_table_header *hdr; -#ifdef CONFIG_INTEL_IOMMU - u64 i, nentries; -#endif - - rsdp_phys = acpi_find_rsdp(); - if (!rsdp_phys) { - printk(KERN_ERR - "ACPI 2.0 RSDP not found, default to \"dig\"\n"); - return "dig"; - } - - rsdp = (struct acpi_table_rsdp *)__va(rsdp_phys); - if (strncmp(rsdp->signature, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)) { - printk(KERN_ERR - "ACPI 2.0 RSDP signature incorrect, default to \"dig\"\n"); - return "dig"; - } - - xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_physical_address); - hdr = &xsdt->header; - if (strncmp(hdr->signature, ACPI_SIG_XSDT, sizeof(ACPI_SIG_XSDT) - 1)) { - printk(KERN_ERR - "ACPI 2.0 XSDT signature incorrect, default to \"dig\"\n"); - return "dig"; - } - - if (!strcmp(hdr->oem_id, "HP")) { - return "hpzx1"; - } else if (!strcmp(hdr->oem_id, "SGI")) { - if (!strcmp(hdr->oem_table_id + 4, "UV")) - return "uv"; - else - return "sn2"; - } - -#ifdef CONFIG_INTEL_IOMMU - /* Look for Intel IOMMU */ - nentries = (hdr->length - sizeof(*hdr)) / - sizeof(xsdt->table_offset_entry[0]); - for (i = 0; i < nentries; i++) { - hdr = __va(xsdt->table_offset_entry[i]); - if (strncmp(hdr->signature, ACPI_SIG_DMAR, - sizeof(ACPI_SIG_DMAR) - 1) == 0) - return "dig_vtd"; - } -#endif - - return "dig"; -} -#endif /* CONFIG_IA64_GENERIC */ - #define ACPI_MAX_PLATFORM_INTERRUPTS 256 /* Array to record platform interrupt vectors for generic interrupt routing. */ @@ -407,7 +335,7 @@ get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa) int pxm; pxm = pa->proximity_domain_lo; - if (ia64_platform_is("sn2") || acpi_srat_revision >= 2) + if (acpi_srat_revision >= 2) pxm += pa->proximity_domain_hi[0] << 8; return pxm; } @@ -418,7 +346,7 @@ get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma) int pxm; pxm = ma->proximity_domain; - if (!ia64_platform_is("sn2") && acpi_srat_revision <= 1) + if (acpi_srat_revision <= 1) pxm &= 0xff; return pxm; @@ -710,9 +638,8 @@ int __init acpi_boot_init(void) if (acpi_table_parse_madt (ACPI_MADT_TYPE_IO_SAPIC, acpi_parse_iosapic, NR_IOSAPICS) < 1) { - if (!ia64_platform_is("sn2")) - printk(KERN_ERR PREFIX - "Error parsing MADT - no IOSAPIC entries\n"); + printk(KERN_ERR PREFIX + "Error parsing MADT - no IOSAPIC entries\n"); } /* System-Level Interrupt Routing */ diff --git a/arch/ia64/kernel/dma-mapping.c b/arch/ia64/kernel/dma-mapping.c index ad7d9963de34f1f970c000fd82639b49fffbe11e..4a3262795890443625712445b0a797d21b35f438 100644 --- a/arch/ia64/kernel/dma-mapping.c +++ b/arch/ia64/kernel/dma-mapping.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 #include -#include #include /* Set this to 1 if there is a HW IOMMU in the system */ @@ -9,13 +8,6 @@ int iommu_detected __read_mostly; const struct dma_map_ops *dma_ops; EXPORT_SYMBOL(dma_ops); -const struct dma_map_ops *dma_get_ops(struct device *dev) -{ - return dma_ops; -} -EXPORT_SYMBOL(dma_get_ops); - -#ifdef CONFIG_SWIOTLB void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs) { @@ -33,9 +25,3 @@ long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr, { return page_to_pfn(virt_to_page(cpu_addr)); } - -void __init swiotlb_dma_init(void) -{ - swiotlb_init(1); -} -#endif diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index 3795d18276c43e9dba11098260651732018690ea..0a34dcc435c6167add04c1a8fc0356fad8c0afa1 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -47,8 +47,11 @@ static __initdata unsigned long palo_phys; +unsigned long sal_systab_phys = EFI_INVALID_TABLE_ADDR; + static __initdata efi_config_table_type_t arch_tables[] = { {PROCESSOR_ABSTRACTION_LAYER_OVERWRITE_GUID, "PALO", &palo_phys}, + {SAL_SYSTEM_TABLE_GUID, "SALsystab", &sal_systab_phys}, {NULL_GUID, NULL, 0}, }; diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index fe6e4946672e5ac21aadba499614d14a37e5ebdf..fad4db20ce65f66dffe926801c146e45d84259f9 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -67,10 +67,7 @@ * used as architecture-independent interrupt handling mechanism in Linux. * As an IRQ is a number, we have to have * IA-64 interrupt vector number <-> IRQ number mapping. On smaller - * systems, we use one-to-one mapping between IA-64 vector and IRQ. A - * platform can implement platform_irq_to_vector(irq) and - * platform_local_vector_to_irq(vector) APIs to differentiate the mapping. - * Please see also arch/ia64/include/asm/hw_irq.h for those APIs. + * systems, we use one-to-one mapping between IA-64 vector and IRQ. * * To sum up, there are three levels of mappings involved: * @@ -96,7 +93,6 @@ #include #include #include -#include #include #include @@ -646,10 +642,8 @@ get_target_cpu (unsigned int gsi, int irq) if (!cpu_online(smp_processor_id())) return cpu_physical_id(smp_processor_id()); -#ifdef CONFIG_ACPI if (cpe_vector > 0 && irq_to_vector(irq) == IA64_CPEP_VECTOR) return get_cpei_target_cpu(); -#endif #ifdef CONFIG_NUMA { diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index 8ed81b252694a008c130632412816761f98a357c..0a8e5e585edc5d9702a53b8aa77701237b9af6b7 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c @@ -35,18 +35,6 @@ void ack_bad_irq(unsigned int irq) printk(KERN_ERR "Unexpected irq vector 0x%x on CPU %u!\n", irq, smp_processor_id()); } -#ifdef CONFIG_IA64_GENERIC -ia64_vector __ia64_irq_to_vector(int irq) -{ - return irq_cfg[irq].vector; -} - -unsigned int __ia64_local_vector_to_irq (ia64_vector vec) -{ - return __this_cpu_read(vector_irq[vec]); -} -#endif - /* * Interrupt statistics: */ @@ -73,17 +61,6 @@ void set_irq_affinity_info (unsigned int irq, int hwid, int redir) irq_redir[irq] = (char) (redir & 0xff); } } - -bool is_affinity_mask_valid(const struct cpumask *cpumask) -{ - if (ia64_platform_is("sn2")) { - /* Only allow one CPU to be specified in the smp_affinity mask */ - if (cpumask_weight(cpumask) != 1) - return false; - } - return true; -} - #endif /* CONFIG_SMP */ int __init arch_early_irq_init(void) diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index ab87d6c25b152984c354134e56373661daa9d87b..f1020847813177673fbe0f5ddc92db1e43747ded 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include @@ -53,7 +52,6 @@ #define IRQ_USED (1) #define IRQ_RSVD (2) -/* These can be overridden in platform_irq_init */ int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR; int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR; @@ -250,7 +248,7 @@ void __setup_vector_irq(int cpu) } } -#if defined(CONFIG_SMP) && (defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_DIG)) +#ifdef CONFIG_SMP static enum vector_domain_type { VECTOR_DOMAIN_NONE, @@ -314,7 +312,7 @@ void irq_complete_move(unsigned irq) cpumask_and(&cleanup_mask, &cfg->old_domain, cpu_online_mask); cfg->move_cleanup_count = cpumask_weight(&cleanup_mask); for_each_cpu(i, &cleanup_mask) - platform_send_ipi(i, IA64_IRQ_MOVE_VECTOR, IA64_IPI_DM_INT, 0); + ia64_send_ipi(i, IA64_IRQ_MOVE_VECTOR, IA64_IPI_DM_INT, 0); cfg->move_in_progress = 0; } @@ -634,21 +632,16 @@ ia64_native_register_ipi(void) void __init init_IRQ (void) { -#ifdef CONFIG_ACPI acpi_boot_init(); -#endif ia64_register_ipi(); register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL); #ifdef CONFIG_SMP -#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_DIG) if (vector_domain_type != VECTOR_DOMAIN_NONE) register_percpu_irq(IA64_IRQ_MOVE_VECTOR, &irq_move_irqaction); #endif -#endif #ifdef CONFIG_PERFMON pfm_init_percpu(); #endif - platform_irq_init(); } void diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 5de801a2c0f03e9d9de098677b4ed07f25ae1114..b8356edbde659077cb0f56fd495c69d6874eae5b 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c @@ -979,32 +979,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, return ret; } -struct param_bsp_cfm { - unsigned long ip; - unsigned long *bsp; - unsigned long cfm; -}; - -static void ia64_get_bsp_cfm(struct unw_frame_info *info, void *arg) -{ - unsigned long ip; - struct param_bsp_cfm *lp = arg; - - do { - unw_get_ip(info, &ip); - if (ip == 0) - break; - if (ip == lp->ip) { - unw_get_bsp(info, (unsigned long*)&lp->bsp); - unw_get_cfm(info, (unsigned long*)&lp->cfm); - return; - } - } while (unw_unwind(info) >= 0); - lp->bsp = NULL; - lp->cfm = 0; - return; -} - unsigned long arch_deref_entry_point(void *entry) { return ((struct fnptr *)entry)->ip; diff --git a/arch/ia64/kernel/machine_kexec.c b/arch/ia64/kernel/machine_kexec.c index 3b1dd5496d08e5100f0bfb1b001ae5abd0389f34..efc9b568401c898047170f6f3875e55f6bca489b 100644 --- a/arch/ia64/kernel/machine_kexec.c +++ b/arch/ia64/kernel/machine_kexec.c @@ -127,7 +127,6 @@ static void ia64_machine_kexec(struct unw_frame_info *info, void *arg) ia64_srlz_d(); while (ia64_get_ivr() != IA64_SPURIOUS_INT_VECTOR) ia64_eoi(); - platform_kernel_launch_event(); rnk = (relocate_new_kernel_t)&code_addr; (*rnk)(image->head, image->start, ia64_boot_param, GRANULEROUNDDOWN((unsigned long) pal_addr)); diff --git a/arch/ia64/kernel/machvec.c b/arch/ia64/kernel/machvec.c deleted file mode 100644 index ebd82535f51b7dc29af27a89258a0b683b472475..0000000000000000000000000000000000000000 --- a/arch/ia64/kernel/machvec.c +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include - -#ifdef CONFIG_IA64_GENERIC - -#include -#include - -#include - -struct ia64_machine_vector ia64_mv = { - .mmiowb = ___ia64_mmiowb -}; -EXPORT_SYMBOL(ia64_mv); - -static struct ia64_machine_vector * __init -lookup_machvec (const char *name) -{ - extern struct ia64_machine_vector machvec_start[]; - extern struct ia64_machine_vector machvec_end[]; - struct ia64_machine_vector *mv; - - for (mv = machvec_start; mv < machvec_end; ++mv) - if (strcmp (mv->name, name) == 0) - return mv; - - return 0; -} - -void __init -machvec_init (const char *name) -{ - struct ia64_machine_vector *mv; - - if (!name) - name = acpi_get_sysname(); - mv = lookup_machvec(name); - if (!mv) - panic("generic kernel failed to find machine vector for" - " platform %s!", name); - - ia64_mv = *mv; - printk(KERN_INFO "booting generic kernel on platform %s\n", name); -} - -void __init -machvec_init_from_cmdline(const char *cmdline) -{ - char str[64]; - const char *start; - char *end; - - if (! (start = strstr(cmdline, "machvec=")) ) - return machvec_init(NULL); - - strlcpy(str, start + strlen("machvec="), sizeof(str)); - if ( (end = strchr(str, ' ')) ) - *end = '\0'; - - return machvec_init(str); -} - -#endif /* CONFIG_IA64_GENERIC */ - -void -machvec_setup (char **arg) -{ -} -EXPORT_SYMBOL(machvec_setup); - -void -machvec_timer_interrupt (int irq, void *dev_id) -{ -} -EXPORT_SYMBOL(machvec_timer_interrupt); diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 79190d877fa700c87d7b6c92eb47f5ac72c09ad4..bf2cb9294795cd097cc56424f750c36892a48eb0 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -91,7 +91,6 @@ #include #include -#include #include #include #include @@ -149,9 +148,7 @@ static ia64_mc_info_t ia64_mc_info; #define CPE_HISTORY_LENGTH 5 #define CMC_HISTORY_LENGTH 5 -#ifdef CONFIG_ACPI static struct timer_list cpe_poll_timer; -#endif static struct timer_list cmc_poll_timer; /* * This variable tells whether we are currently in polling mode. @@ -532,8 +529,6 @@ int mca_recover_range(unsigned long addr) } EXPORT_SYMBOL_GPL(mca_recover_range); -#ifdef CONFIG_ACPI - int cpe_vector = -1; int ia64_cpe_irq = -1; @@ -595,9 +590,6 @@ ia64_mca_cpe_int_handler (int cpe_irq, void *arg) return IRQ_HANDLED; } -#endif /* CONFIG_ACPI */ - -#ifdef CONFIG_ACPI /* * ia64_mca_register_cpev * @@ -625,7 +617,6 @@ ia64_mca_register_cpev (int cpev) IA64_MCA_DEBUG("%s: corrected platform error " "vector %#x registered\n", __func__, cpev); } -#endif /* CONFIG_ACPI */ /* * ia64_mca_cmc_vector_setup @@ -744,7 +735,7 @@ ia64_mca_cmc_vector_enable_keventd(struct work_struct *unused) static void ia64_mca_wakeup(int cpu) { - platform_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0); + ia64_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0); } /* @@ -1490,7 +1481,7 @@ ia64_mca_cmc_int_caller(int cmc_irq, void *arg) cpuid = cpumask_next(cpuid+1, cpu_online_mask); if (cpuid < nr_cpu_ids) { - platform_send_ipi(cpuid, IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0); + ia64_send_ipi(cpuid, IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0); } else { /* If no log record, switch out of polling mode */ if (start_count == IA64_LOG_COUNT(SAL_INFO_TYPE_CMC)) { @@ -1523,7 +1514,7 @@ static void ia64_mca_cmc_poll (struct timer_list *unused) { /* Trigger a CMC interrupt cascade */ - platform_send_ipi(cpumask_first(cpu_online_mask), IA64_CMCP_VECTOR, + ia64_send_ipi(cpumask_first(cpu_online_mask), IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0); } @@ -1540,8 +1531,6 @@ ia64_mca_cmc_poll (struct timer_list *unused) * Outputs * handled */ -#ifdef CONFIG_ACPI - static irqreturn_t ia64_mca_cpe_int_caller(int cpe_irq, void *arg) { @@ -1560,7 +1549,7 @@ ia64_mca_cpe_int_caller(int cpe_irq, void *arg) cpuid = cpumask_next(cpuid+1, cpu_online_mask); if (cpuid < NR_CPUS) { - platform_send_ipi(cpuid, IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0); + ia64_send_ipi(cpuid, IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0); } else { /* * If a log was recorded, increase our polling frequency, @@ -1600,12 +1589,10 @@ static void ia64_mca_cpe_poll (struct timer_list *unused) { /* Trigger a CPE interrupt cascade */ - platform_send_ipi(cpumask_first(cpu_online_mask), IA64_CPEP_VECTOR, + ia64_send_ipi(cpumask_first(cpu_online_mask), IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0); } -#endif /* CONFIG_ACPI */ - static int default_monarch_init_process(struct notifier_block *self, unsigned long val, void *data) { @@ -1799,7 +1786,6 @@ static struct irqaction mca_wkup_irqaction = { .name = "mca_wkup" }; -#ifdef CONFIG_ACPI static struct irqaction mca_cpe_irqaction = { .handler = ia64_mca_cpe_int_handler, .name = "cpe_hndlr" @@ -1809,7 +1795,6 @@ static struct irqaction mca_cpep_irqaction = { .handler = ia64_mca_cpe_int_caller, .name = "cpe_poll" }; -#endif /* CONFIG_ACPI */ /* Minimal format of the MCA/INIT stacks. The pseudo processes that run on * these stacks can never sleep, they cannot return from the kernel to user @@ -2081,10 +2066,8 @@ void __init ia64_mca_irq_init(void) /* Setup the MCA wakeup interrupt vector */ register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction); -#ifdef CONFIG_ACPI /* Setup the CPEI/P handler */ register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction); -#endif } /* @@ -2112,7 +2095,6 @@ ia64_mca_late_init(void) ia64_mca_cpu_online, NULL); IA64_MCA_DEBUG("%s: CMCI/P setup and enabled.\n", __func__); -#ifdef CONFIG_ACPI /* Setup the CPEI/P vector and handler */ cpe_vector = acpi_request_vector(ACPI_INTERRUPT_CPEI); timer_setup(&cpe_poll_timer, ia64_mca_cpe_poll, 0); @@ -2143,7 +2125,6 @@ ia64_mca_late_init(void) IA64_MCA_DEBUG("%s: CPEP setup and enabled.\n", __func__); } } -#endif return 0; } diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c index cd7972ede1d6f9b80f5a1e9b2e1c8296062a3422..4d0ab323dee8c7d65cb0db3a1adb1b186970cda6 100644 --- a/arch/ia64/kernel/mca_drv.c +++ b/arch/ia64/kernel/mca_drv.c @@ -26,7 +26,6 @@ #include #include -#include #include #include #include diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c index 326448f9df16068392e49af096afd1c8b2713131..1a42ba885188a5c8e865bb28108c685ed1a37515 100644 --- a/arch/ia64/kernel/module.c +++ b/arch/ia64/kernel/module.c @@ -914,10 +914,14 @@ module_finalize (const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mo void module_arch_cleanup (struct module *mod) { - if (mod->arch.init_unw_table) + if (mod->arch.init_unw_table) { unw_remove_unwind_table(mod->arch.init_unw_table); - if (mod->arch.core_unw_table) + mod->arch.init_unw_table = NULL; + } + if (mod->arch.core_unw_table) { unw_remove_unwind_table(mod->arch.core_unw_table); + mod->arch.core_unw_table = NULL; + } } void *dereference_module_function_descriptor(struct module *mod, void *ptr) diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c index 519d9432f407e264ca178749f1eaa4549add119a..df5c28f252e3d7d0868b1bb8f4eeaa338af1d8be 100644 --- a/arch/ia64/kernel/msi_ia64.c +++ b/arch/ia64/kernel/msi_ia64.c @@ -43,7 +43,7 @@ static int ia64_set_msi_irq_affinity(struct irq_data *idata, } #endif /* CONFIG_SMP */ -int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) +int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) { struct msi_msg msg; unsigned long dest_phys_id; @@ -77,7 +77,7 @@ int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) return 0; } -void ia64_teardown_msi_irq(unsigned int irq) +void arch_teardown_msi_irq(unsigned int irq) { destroy_irq(irq); } @@ -111,23 +111,6 @@ static struct irq_chip ia64_msi_chip = { .irq_retrigger = ia64_msi_retrigger_irq, }; - -int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) -{ - if (platform_setup_msi_irq) - return platform_setup_msi_irq(pdev, desc); - - return ia64_setup_msi_irq(pdev, desc); -} - -void arch_teardown_msi_irq(unsigned int irq) -{ - if (platform_teardown_msi_irq) - return platform_teardown_msi_irq(irq); - - return ia64_teardown_msi_irq(irq); -} - #ifdef CONFIG_INTEL_IOMMU #ifdef CONFIG_SMP static int dmar_msi_set_affinity(struct irq_data *data, diff --git a/arch/ia64/kernel/pci-dma.c b/arch/ia64/kernel/pci-dma.c index fe988c49f01ce6ae844355731ddc50f01fef3df1..c90221733c6b91e031f0ac00758f5bbaf4cbf87a 100644 --- a/arch/ia64/kernel/pci-dma.c +++ b/arch/ia64/kernel/pci-dma.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -22,8 +21,6 @@ int force_iommu __read_mostly = 1; int force_iommu __read_mostly; #endif -int iommu_pass_through; - static int __init pci_iommu_init(void) { if (iommu_detected) @@ -34,24 +31,3 @@ static int __init pci_iommu_init(void) /* Must execute after PCI subsystem */ fs_initcall(pci_iommu_init); - -void __init pci_iommu_alloc(void) -{ - /* - * The order of these functions is important for - * fall-back/fail-over reasons - */ - detect_intel_iommu(); - -#ifdef CONFIG_SWIOTLB - if (!iommu_detected) { -#ifdef CONFIG_IA64_GENERIC - printk(KERN_INFO "PCI-DMA: Re-initialize machine vector.\n"); - machvec_init("dig"); - swiotlb_dma_init(); -#else - panic("Unable to find Intel IOMMU"); -#endif /* CONFIG_IA64_GENERIC */ - } -#endif /* CONFIG_SWIOTLB */ -} diff --git a/arch/ia64/kernel/sal.c b/arch/ia64/kernel/sal.c index 9b2331ac10cebf5a2b278a73886d397b0225f0e8..c455ece977add824b51adc10e904807bbab4d2b8 100644 --- a/arch/ia64/kernel/sal.c +++ b/arch/ia64/kernel/sal.c @@ -110,13 +110,6 @@ check_versions (struct ia64_sal_systab *systab) sal_revision = SAL_VERSION_CODE(2, 8); sal_version = SAL_VERSION_CODE(0, 0); } - - if (ia64_platform_is("sn2") && (sal_revision == SAL_VERSION_CODE(2, 9))) - /* - * SGI Altix has hard-coded version 2.9 in their prom - * but they actually implement 3.2, so let's fix it here. - */ - sal_revision = SAL_VERSION_CODE(3, 2); } static void __init @@ -256,7 +249,7 @@ check_sal_cache_flush (void) * Send ourselves a timer interrupt, wait until it's reported, and see * if SAL_CACHE_FLUSH drops it. */ - platform_send_ipi(cpu, IA64_TIMER_VECTOR, IA64_IPI_DM_INT, 0); + ia64_send_ipi(cpu, IA64_TIMER_VECTOR, IA64_IPI_DM_INT, 0); while (!ia64_get_irr(IA64_TIMER_VECTOR)) cpu_relax(); diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index c9cfa760cd57bfc4c00ce275708e6723422d9769..8eb276aac5cec38df3b7eff06f1802316fdc49eb 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -50,7 +52,6 @@ #include #include -#include #include #include #include @@ -63,12 +64,14 @@ #include #include #include -#include +#include #if defined(CONFIG_SMP) && (IA64_CPU_SIZE > PAGE_SIZE) # error "struct cpuinfo_ia64 too big!" #endif +char ia64_platform_name[64]; + #ifdef CONFIG_SMP unsigned long __per_cpu_offset[NR_CPUS]; EXPORT_SYMBOL(__per_cpu_offset); @@ -260,11 +263,11 @@ __initcall(register_memory); * in kdump case. See the comment in sba_init() in sba_iommu.c. * * So, the only machvec that really supports loading the kdump kernel - * over 4 GB is "sn2". + * over 4 GB is "uv". */ static int __init check_crashkernel_memory(unsigned long pbase, size_t size) { - if (ia64_platform_is("sn2") || ia64_platform_is("uv")) + if (is_uv_system()) return 1; else return pbase < (1UL << 32); @@ -461,23 +464,44 @@ io_port_init (void) static inline int __init early_console_setup (char *cmdline) { - int earlycons = 0; - -#ifdef CONFIG_SERIAL_SGI_L1_CONSOLE - { - extern int sn_serial_console_early_setup(void); - if (!sn_serial_console_early_setup()) - earlycons++; - } -#endif #ifdef CONFIG_EFI_PCDP if (!efi_setup_pcdp_console(cmdline)) - earlycons++; + return 0; #endif - if (!simcons_register()) - earlycons++; + return -1; +} + +static void __init +screen_info_setup(void) +{ + unsigned int orig_x, orig_y, num_cols, num_rows, font_height; + + memset(&screen_info, 0, sizeof(screen_info)); + + if (!ia64_boot_param->console_info.num_rows || + !ia64_boot_param->console_info.num_cols) { + printk(KERN_WARNING "invalid screen-info, guessing 80x25\n"); + orig_x = 0; + orig_y = 0; + num_cols = 80; + num_rows = 25; + font_height = 16; + } else { + orig_x = ia64_boot_param->console_info.orig_x; + orig_y = ia64_boot_param->console_info.orig_y; + num_cols = ia64_boot_param->console_info.num_cols; + num_rows = ia64_boot_param->console_info.num_rows; + font_height = 400 / num_rows; + } - return (earlycons) ? 0 : -1; + screen_info.orig_x = orig_x; + screen_info.orig_y = orig_y; + screen_info.orig_video_cols = num_cols; + screen_info.orig_video_lines = num_rows; + screen_info.orig_video_points = font_height; + screen_info.orig_video_mode = 3; /* XXX fake */ + screen_info.orig_video_isVGA = 1; /* XXX fake */ + screen_info.orig_video_ega_bx = 3; /* XXX fake */ } static inline void @@ -536,35 +560,25 @@ setup_arch (char **cmdline_p) efi_init(); io_port_init(); -#ifdef CONFIG_IA64_GENERIC - /* machvec needs to be parsed from the command line - * before parse_early_param() is called to ensure - * that ia64_mv is initialised before any command line - * settings may cause console setup to occur - */ - machvec_init_from_cmdline(*cmdline_p); -#endif - + uv_probe_system_type(); parse_early_param(); if (early_console_setup(*cmdline_p) == 0) mark_bsp_online(); -#ifdef CONFIG_ACPI /* Initialize the ACPI boot-time table parser */ acpi_table_init(); early_acpi_boot_init(); -# ifdef CONFIG_ACPI_NUMA +#ifdef CONFIG_ACPI_NUMA acpi_numa_init(); acpi_numa_fixup(); -# ifdef CONFIG_ACPI_HOTPLUG_CPU +#ifdef CONFIG_ACPI_HOTPLUG_CPU prefill_possible_map(); -# endif +#endif per_cpu_scan_finalize((cpumask_weight(&early_cpu_possible_map) == 0 ? 32 : cpumask_weight(&early_cpu_possible_map)), additional_cpus > 0 ? additional_cpus : 0); -# endif -#endif /* CONFIG_APCI_BOOT */ +#endif /* CONFIG_ACPI_NUMA */ #ifdef CONFIG_SMP smp_build_cpu_map(); @@ -572,7 +586,7 @@ setup_arch (char **cmdline_p) find_memory(); /* process SAL system table: */ - ia64_sal_init(__va(efi.sal_systab)); + ia64_sal_init(__va(sal_systab_phys)); #ifdef CONFIG_ITANIUM ia64_patch_rse((u64) __start___rse_patchlist, (u64) __end___rse_patchlist); @@ -614,10 +628,21 @@ setup_arch (char **cmdline_p) if (!nomca) ia64_mca_init(); - platform_setup(cmdline_p); -#ifndef CONFIG_IA64_HP_SIM - check_sal_cache_flush(); + /* + * Default to /dev/sda2. This assumes that the EFI partition + * is physical disk 1 partition 1 and the Linux root disk is + * physical disk 1 partition 2. + */ + ROOT_DEV = Root_SDA2; /* default to second partition on first drive */ + + if (is_uv_system()) + uv_setup(cmdline_p); +#ifdef CONFIG_SMP + else + init_smp_config(); #endif + + screen_info_setup(); paging_init(); clear_sched_clock_stable(); @@ -1046,7 +1071,6 @@ cpu_init (void) ia64_patch_phys_stack_reg(num_phys_stacked*8 + 8); max_num_phys_stacked = num_phys_stacked; } - platform_cpu_init(); } void __init diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index e5044aed9452007435e695645f051cd8c137b3a1..d07ed65c9c6e95481f5f8aa2cb4119a43875d960 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -363,19 +363,19 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall) if (unlikely(restart)) { switch (errno) { - case ERESTART_RESTARTBLOCK: - case ERESTARTNOHAND: + case ERESTART_RESTARTBLOCK: + case ERESTARTNOHAND: scr->pt.r8 = EINTR; /* note: scr->pt.r10 is already -1 */ break; - - case ERESTARTSYS: + case ERESTARTSYS: if ((ksig.ka.sa.sa_flags & SA_RESTART) == 0) { scr->pt.r8 = EINTR; /* note: scr->pt.r10 is already -1 */ break; } - case ERESTARTNOINTR: + /*FALLTHRU*/ + case ERESTARTNOINTR: ia64_decrement_ip(&scr->pt); restart = 0; /* don't restart twice if handle_signal() fails... */ } diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c index 133b63355814b45bcbce6d4cf45d2b8dbb192bd8..de35c54f033dff1c4c6ebc43dd66d021ee9de2f5 100644 --- a/arch/ia64/kernel/smp.c +++ b/arch/ia64/kernel/smp.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -146,7 +145,7 @@ static inline void send_IPI_single (int dest_cpu, int op) { set_bit(op, &per_cpu(ipi_operation, dest_cpu)); - platform_send_ipi(dest_cpu, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0); + ia64_send_ipi(dest_cpu, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0); } /* @@ -213,7 +212,7 @@ kdump_smp_send_init(void) for_each_online_cpu(cpu) { if (cpu != self_cpu) { if(kdump_status[cpu] == 0) - platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0); + ia64_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0); } } } @@ -224,7 +223,7 @@ kdump_smp_send_init(void) void smp_send_reschedule (int cpu) { - platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0); + ia64_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0); } EXPORT_SYMBOL_GPL(smp_send_reschedule); @@ -234,7 +233,7 @@ EXPORT_SYMBOL_GPL(smp_send_reschedule); static void smp_send_local_flush_tlb (int cpu) { - platform_send_ipi(cpu, IA64_IPI_LOCAL_TLB_FLUSH, IA64_IPI_DM_INT, 0); + ia64_send_ipi(cpu, IA64_IPI_LOCAL_TLB_FLUSH, IA64_IPI_DM_INT, 0); } void diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index d0474a0c67db5050704eb614fb4995cd0b54643f..6501d9a9a21b328e148565107c82a999e90f2ce8 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -57,7 +56,6 @@ #include #include #include -#include #define SMP_DEBUG 0 @@ -468,7 +466,7 @@ do_boot_cpu (int sapicid, int cpu, struct task_struct *idle) Dprintk("Sending wakeup vector %lu to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid); set_brendez_area(cpu); - platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0); + ia64_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0); /* * Wait 10s total for the AP to start @@ -658,11 +656,6 @@ int __cpu_disable(void) return (-EBUSY); } - if (ia64_platform_is("sn2")) { - if (!sn_cpu_disable_allowed(cpu)) - return -EBUSY; - } - set_cpu_online(cpu, false); if (migrate_platform_irqs(cpu)) { diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c index 9ebe1d633abca861776d486d4c9fbac9e2e113b3..e14db25146c222cdc8aef027f691fef6a73ac9cf 100644 --- a/arch/ia64/kernel/sys_ia64.c +++ b/arch/ia64/kernel/sys_ia64.c @@ -166,21 +166,3 @@ ia64_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, u force_successful_syscall_return(); return addr; } - -#ifndef CONFIG_PCI - -asmlinkage long -sys_pciconfig_read (unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len, - void *buf) -{ - return -ENOSYS; -} - -asmlinkage long -sys_pciconfig_write (unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len, - void *buf) -{ - return -ENOSYS; -} - -#endif /* CONFIG_PCI */ diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index 4ecd81b0e8ecb79d800251c1c1e55891d2e750e3..1e95d32c88772ba4dd96adeb8813985eccc0de65 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -167,8 +166,6 @@ timer_interrupt (int irq, void *dev_id) return IRQ_HANDLED; } - platform_timer_interrupt(irq, dev_id); - new_itm = local_cpu_data->itm_next; if (!time_after(ia64_get_itc(), new_itm)) diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c index e311ee13e61d01536e79c431b2a830db93230a06..09fc385c2acd2ce0bc7fae3a9ffe05c1f1441427 100644 --- a/arch/ia64/kernel/topology.c +++ b/arch/ia64/kernel/topology.c @@ -42,7 +42,6 @@ EXPORT_SYMBOL_GPL(arch_fix_phys_package_id); #ifdef CONFIG_HOTPLUG_CPU int __ref arch_register_cpu(int num) { -#ifdef CONFIG_ACPI /* * If CPEI can be re-targeted or if this is not * CPEI target, then it is hotpluggable @@ -50,7 +49,6 @@ int __ref arch_register_cpu(int num) if (can_cpei_retarget() || !is_cpu_cpei_target(num)) sysfs_cpus[num].cpu.hotpluggable = 1; map_cpu_to_node(num, node_cpuid[num].nid); -#endif return register_cpu(&sysfs_cpus[num].cpu, num); } EXPORT_SYMBOL(arch_register_cpu); @@ -58,9 +56,7 @@ EXPORT_SYMBOL(arch_register_cpu); void __ref arch_unregister_cpu(int num) { unregister_cpu(&sysfs_cpus[num].cpu); -#ifdef CONFIG_ACPI unmap_cpu_from_node(num, cpu_to_node(num)); -#endif } EXPORT_SYMBOL(arch_unregister_cpu); #else diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c index eb7d5df59fa32c3c804ac796c77cb6d59c4f498a..2d4e65ba5c3e9025bb0ccad498a0ee5f6624bccc 100644 --- a/arch/ia64/kernel/unaligned.c +++ b/arch/ia64/kernel/unaligned.c @@ -1431,7 +1431,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs) if (u.insn.x) /* oops, really a semaphore op (cmpxchg, etc) */ goto failure; - /* no break */ + /*FALLTHRU*/ case LDS_IMM_OP: case LDSA_IMM_OP: case LDFS_OP: @@ -1459,7 +1459,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs) if (u.insn.x) /* oops, really a semaphore op (cmpxchg, etc) */ goto failure; - /* no break */ + /*FALLTHRU*/ case LD_IMM_OP: case LDA_IMM_OP: case LDBIAS_IMM_OP: @@ -1475,7 +1475,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs) if (u.insn.x) /* oops, really a semaphore op (cmpxchg, etc) */ goto failure; - /* no break */ + /*FALLTHRU*/ case ST_IMM_OP: case STREL_IMM_OP: ret = emulate_store_int(ifa, u.insn, regs); diff --git a/arch/ia64/kernel/uncached.c b/arch/ia64/kernel/uncached.c index 16c6d377c502daf6fb7aa7b6d9143fa5cfd4d4b9..3776ef2251253a21afa269a5b4e83d890de4920c 100644 --- a/arch/ia64/kernel/uncached.c +++ b/arch/ia64/kernel/uncached.c @@ -24,7 +24,6 @@ #include #include #include -#include extern void __init efi_memmap_walk_uc(efi_freemem_callback_t, void *); @@ -129,10 +128,7 @@ static int uncached_add_chunk(struct uncached_pool *uc_pool, int nid) preempt_disable(); - if (ia64_platform_is("sn2")) - sn_flush_all_caches(uc_addr, IA64_GRANULE_SIZE); - else - flush_icache_range(uc_addr, uc_addr + IA64_GRANULE_SIZE); + flush_icache_range(uc_addr, uc_addr + IA64_GRANULE_SIZE); /* flush the just introduced uncached translation from the TLB */ local_flush_tlb_all(); diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index 0da58cf8e2138a99dfc44e427561c359e8f72d5b..d9d4e21107cdbe8cee21c863ff0e7f585eaa171a 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -141,16 +141,6 @@ SECTIONS { __end___mckinley_e9_bundles = .; } -#if defined(CONFIG_IA64_GENERIC) - /* Machine Vector */ - . = ALIGN(16); - .machvec : AT(ADDR(.machvec) - LOAD_OFFSET) { - machvec_start = .; - *(.machvec) - machvec_end = .; - } -#endif - #ifdef CONFIG_SMP . = ALIGN(PERCPU_PAGE_SIZE); __cpu0_per_cpu = .; diff --git a/arch/ia64/lib/io.c b/arch/ia64/lib/io.c index d107eaf3790ddcf634f7a487253befbc6a21d0fe..c3e02462ed1694b809a0d59650396ae72f58adb7 100644 --- a/arch/ia64/lib/io.c +++ b/arch/ia64/lib/io.c @@ -49,117 +49,3 @@ void memset_io(volatile void __iomem *dst, int c, long count) } } EXPORT_SYMBOL(memset_io); - -#ifdef CONFIG_IA64_GENERIC - -#undef __ia64_inb -#undef __ia64_inw -#undef __ia64_inl -#undef __ia64_outb -#undef __ia64_outw -#undef __ia64_outl -#undef __ia64_readb -#undef __ia64_readw -#undef __ia64_readl -#undef __ia64_readq -#undef __ia64_readb_relaxed -#undef __ia64_readw_relaxed -#undef __ia64_readl_relaxed -#undef __ia64_readq_relaxed -#undef __ia64_writeb -#undef __ia64_writew -#undef __ia64_writel -#undef __ia64_writeq -#undef __ia64_mmiowb - -unsigned int -__ia64_inb (unsigned long port) -{ - return ___ia64_inb(port); -} - -unsigned int -__ia64_inw (unsigned long port) -{ - return ___ia64_inw(port); -} - -unsigned int -__ia64_inl (unsigned long port) -{ - return ___ia64_inl(port); -} - -void -__ia64_outb (unsigned char val, unsigned long port) -{ - ___ia64_outb(val, port); -} - -void -__ia64_outw (unsigned short val, unsigned long port) -{ - ___ia64_outw(val, port); -} - -void -__ia64_outl (unsigned int val, unsigned long port) -{ - ___ia64_outl(val, port); -} - -unsigned char -__ia64_readb (void __iomem *addr) -{ - return ___ia64_readb (addr); -} - -unsigned short -__ia64_readw (void __iomem *addr) -{ - return ___ia64_readw (addr); -} - -unsigned int -__ia64_readl (void __iomem *addr) -{ - return ___ia64_readl (addr); -} - -unsigned long -__ia64_readq (void __iomem *addr) -{ - return ___ia64_readq (addr); -} - -unsigned char -__ia64_readb_relaxed (void __iomem *addr) -{ - return ___ia64_readb (addr); -} - -unsigned short -__ia64_readw_relaxed (void __iomem *addr) -{ - return ___ia64_readw (addr); -} - -unsigned int -__ia64_readl_relaxed (void __iomem *addr) -{ - return ___ia64_readl (addr); -} - -unsigned long -__ia64_readq_relaxed (void __iomem *addr) -{ - return ___ia64_readq (addr); -} - -void -__ia64_mmiowb(void) -{ - ___ia64_mmiowb(); -} - -#endif /* CONFIG_IA64_GENERIC */ diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c index d29fb6b9fa331030fbdad1247d09cb7e77b2317c..db09a693f0941dba95f02da4aeff80792464372f 100644 --- a/arch/ia64/mm/contig.c +++ b/arch/ia64/mm/contig.c @@ -134,10 +134,7 @@ setup_per_cpu_areas(void) ai->atom_size = PAGE_SIZE; ai->alloc_size = PERCPU_PAGE_SIZE; - rc = pcpu_setup_first_chunk(ai, __per_cpu_start + __per_cpu_offset[0]); - if (rc) - panic("failed to setup percpu area (err=%d)", rc); - + pcpu_setup_first_chunk(ai, __per_cpu_start + __per_cpu_offset[0]); pcpu_free_alloc_info(ai); } #else diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index 05490dd073e6c3f44cc69f77a305da83e7abc818..219fc640414bfe819260540ec5f401eb9d5ad099 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c @@ -245,10 +245,7 @@ void __init setup_per_cpu_areas(void) gi->cpu_map = &cpu_map[unit]; } - rc = pcpu_setup_first_chunk(ai, base); - if (rc) - panic("failed to setup percpu area (err=%d)", rc); - + pcpu_setup_first_chunk(ai, base); pcpu_free_alloc_info(ai); } #endif @@ -396,8 +393,7 @@ static void __meminit scatter_node_data(void) * * Each node's per-node area has a copy of the global pg_data_t list, so * we copy that to each node here, as well as setting the per-cpu pointer - * to the local node data structure. The active_cpus field of the per-node - * structure gets setup by the platform_cpu_init() function later. + * to the local node data structure. */ static void __init initialize_pernode_data(void) { diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index aae75fd7b810309edf5f3960b0dd0d163e39b9c6..678b98a09c854c78cb2ac3e69a7a2f9261e2a890 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -23,10 +24,10 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -67,7 +68,6 @@ __ia64_sync_icache_dcache (pte_t pte) set_bit(PG_arch_1, &page->flags); /* mark page as clean */ } -#ifdef CONFIG_SWIOTLB /* * Since DMA is i-cache coherent, any (complete) pages that were written via * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to @@ -82,7 +82,6 @@ void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr, set_bit(PG_arch_1, &pfn_to_page(pfn)->flags); } while (++pfn <= PHYS_PFN(paddr + size - 1)); } -#endif inline void ia64_set_rbs_bot (void) @@ -632,13 +631,17 @@ mem_init (void) BUG_ON(PTRS_PER_PMD * sizeof(pmd_t) != PAGE_SIZE); BUG_ON(PTRS_PER_PTE * sizeof(pte_t) != PAGE_SIZE); -#ifdef CONFIG_PCI /* - * This needs to be called _after_ the command line has been parsed but _before_ - * any drivers that may need the PCI DMA interface are initialized or bootmem has - * been freed. + * This needs to be called _after_ the command line has been parsed but + * _before_ any drivers that may need the PCI DMA interface are + * initialized or bootmem has been freed. */ - platform_dma_init(); +#ifdef CONFIG_INTEL_IOMMU + detect_intel_iommu(); + if (!iommu_detected) +#endif +#ifdef CONFIG_SWIOTLB + swiotlb_init(1); #endif #ifdef CONFIG_FLATMEM diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c index 0714df1b78547d234d2f1bfaf590ea74063e9ef7..72cc568bc841115885ec3d4a062aeef7a110c7a6 100644 --- a/arch/ia64/mm/tlb.c +++ b/arch/ia64/mm/tlb.c @@ -245,7 +245,8 @@ setup_ptcg_sem(int max_purges, int nptcg_from) spinaphore_init(&ptcg_sem, max_purges); } -void +#ifdef CONFIG_SMP +static void ia64_global_tlb_purge (struct mm_struct *mm, unsigned long start, unsigned long end, unsigned long nbits) { @@ -282,6 +283,7 @@ ia64_global_tlb_purge (struct mm_struct *mm, unsigned long start, activate_context(active_mm); } } +#endif /* CONFIG_SMP */ void local_flush_tlb_all (void) @@ -332,7 +334,7 @@ __flush_tlb_range (struct vm_area_struct *vma, unsigned long start, preempt_disable(); #ifdef CONFIG_SMP if (mm != current->active_mm || cpumask_weight(mm_cpumask(mm)) != 1) { - platform_global_tlb_purge(mm, start, end, nbits); + ia64_global_tlb_purge(mm, start, end, nbits); preempt_enable(); return; } diff --git a/arch/ia64/pci/fixup.c b/arch/ia64/pci/fixup.c index e1fa45b2148c12045f8f2a950ba39e2193b958f9..acb55a41260dd0ab9ade073d28732dee0ee822f6 100644 --- a/arch/ia64/pci/fixup.c +++ b/arch/ia64/pci/fixup.c @@ -8,8 +8,7 @@ #include #include #include - -#include +#include /* * Fixup to mark boot BIOS video selected by BIOS before it changes @@ -35,8 +34,7 @@ static void pci_fixup_video(struct pci_dev *pdev) u16 config; struct resource *res; - if ((strcmp(ia64_platform_name, "dig") != 0) - && (strcmp(ia64_platform_name, "hpzx1") != 0)) + if (is_uv_system()) return; /* Maybe, this machine supports legacy memory map. */ diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 165e561dc81a9373b8a7a3deff80a714070270c8..211757e34198a35267160298d6e0b923f5e8d5a0 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -372,7 +371,6 @@ void pcibios_fixup_bus(struct pci_bus *b) } list_for_each_entry(dev, &b->devices, bus_list) pcibios_fixup_device_resources(dev); - platform_pci_fixup_bus(b); } void pcibios_add_bus(struct pci_bus *bus) @@ -413,7 +411,7 @@ pcibios_disable_device (struct pci_dev *dev) } /** - * ia64_pci_get_legacy_mem - generic legacy mem routine + * pci_get_legacy_mem - generic legacy mem routine * @bus: bus to get legacy memory base address for * * Find the base of legacy memory for @bus. This is typically the first @@ -424,7 +422,7 @@ pcibios_disable_device (struct pci_dev *dev) * This is the ia64 generic version of this routine. Other platforms * are free to override it with a machine vector. */ -char *ia64_pci_get_legacy_mem(struct pci_bus *bus) +char *pci_get_legacy_mem(struct pci_bus *bus) { return (char *)__IA64_UNCACHED_OFFSET; } @@ -473,7 +471,7 @@ pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma, } /** - * ia64_pci_legacy_read - read from legacy I/O space + * pci_legacy_read - read from legacy I/O space * @bus: bus to read * @port: legacy port value * @val: caller allocated storage for returned value @@ -485,7 +483,7 @@ pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma, * overridden by the platform. This is necessary on platforms that don't * support legacy I/O routing or that hard fail on legacy I/O timeouts. */ -int ia64_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size) +int pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size) { int ret = size; @@ -508,7 +506,7 @@ int ia64_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size) } /** - * ia64_pci_legacy_write - perform a legacy I/O write + * pci_legacy_write - perform a legacy I/O write * @bus: bus pointer * @port: port to write * @val: value to write @@ -516,7 +514,7 @@ int ia64_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size) * * Simply writes @size bytes of @val to @port. */ -int ia64_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size) +int pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size) { int ret = size; diff --git a/arch/ia64/sn/Makefile b/arch/ia64/sn/Makefile deleted file mode 100644 index 79a7df02e8120f0302151a579fa499b09cf3d785..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# arch/ia64/sn/Makefile -# -# This file is subject to the terms and conditions of the GNU General Public -# License. See the file "COPYING" in the main directory of this archive -# for more details. -# -# Copyright (C) 2004 Silicon Graphics, Inc. All Rights Reserved. -# -# Makefile for the sn ia64 subplatform -# - -obj-y += kernel/ pci/ diff --git a/arch/ia64/sn/include/ioerror.h b/arch/ia64/sn/include/ioerror.h deleted file mode 100644 index e68f2b0789a76e347256e0d81eaed4727ec709d0..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/include/ioerror.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_IOERROR_H -#define _ASM_IA64_SN_IOERROR_H - -/* - * IO error structure. - * - * This structure would expand to hold the information retrieved from - * all IO related error registers. - * - * This structure is defined to hold all system specific - * information related to a single error. - * - * This serves a couple of purpose. - * - Error handling often involves translating one form of address to other - * form. So, instead of having different data structures at each level, - * we have a single structure, and the appropriate fields get filled in - * at each layer. - * - This provides a way to dump all error related information in any layer - * of erorr handling (debugging aid). - * - * A second possibility is to allow each layer to define its own error - * data structure, and fill in the proper fields. This has the advantage - * of isolating the layers. - * A big concern is the potential stack usage (and overflow), if each layer - * defines these structures on stack (assuming we don't want to do kmalloc. - * - * Any layer wishing to pass extra information to a layer next to it in - * error handling hierarchy, can do so as a separate parameter. - */ - -typedef struct io_error_s { - /* Bit fields indicating which structure fields are valid */ - union { - struct { - unsigned ievb_errortype:1; - unsigned ievb_widgetnum:1; - unsigned ievb_widgetdev:1; - unsigned ievb_srccpu:1; - unsigned ievb_srcnode:1; - unsigned ievb_errnode:1; - unsigned ievb_sysioaddr:1; - unsigned ievb_xtalkaddr:1; - unsigned ievb_busspace:1; - unsigned ievb_busaddr:1; - unsigned ievb_vaddr:1; - unsigned ievb_memaddr:1; - unsigned ievb_epc:1; - unsigned ievb_ef:1; - unsigned ievb_tnum:1; - } iev_b; - unsigned iev_a; - } ie_v; - - short ie_errortype; /* error type: extra info about error */ - short ie_widgetnum; /* Widget number that's in error */ - short ie_widgetdev; /* Device within widget in error */ - cpuid_t ie_srccpu; /* CPU on srcnode generating error */ - cnodeid_t ie_srcnode; /* Node which caused the error */ - cnodeid_t ie_errnode; /* Node where error was noticed */ - iopaddr_t ie_sysioaddr; /* Sys specific IO address */ - iopaddr_t ie_xtalkaddr; /* Xtalk (48bit) addr of Error */ - iopaddr_t ie_busspace; /* Bus specific address space */ - iopaddr_t ie_busaddr; /* Bus specific address */ - caddr_t ie_vaddr; /* Virtual address of error */ - iopaddr_t ie_memaddr; /* Physical memory address */ - caddr_t ie_epc; /* pc when error reported */ - caddr_t ie_ef; /* eframe when error reported */ - short ie_tnum; /* Xtalk TNUM field */ -} ioerror_t; - -#define IOERROR_INIT(e) do { (e)->ie_v.iev_a = 0; } while (0) -#define IOERROR_SETVALUE(e,f,v) do { (e)->ie_ ## f = (v); (e)->ie_v.iev_b.ievb_ ## f = 1; } while (0) - -#endif /* _ASM_IA64_SN_IOERROR_H */ diff --git a/arch/ia64/sn/include/tio.h b/arch/ia64/sn/include/tio.h deleted file mode 100644 index 6b2e7b75eb19136cee3f7f5943667c55ee75da90..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/include/tio.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_TIO_H -#define _ASM_IA64_SN_TIO_H - -#define TIO_MMR_ADDR_MOD - -#define TIO_NODE_ID TIO_MMR_ADDR_MOD(0x0000000090060e80) - -#define TIO_ITTE_BASE 0xb0008800 /* base of translation table entries */ -#define TIO_ITTE(bigwin) (TIO_ITTE_BASE + 8*(bigwin)) - -#define TIO_ITTE_OFFSET_BITS 8 /* size of offset field */ -#define TIO_ITTE_OFFSET_MASK ((1<> TIO_ITTE_WIDGET_SHIFT) & TIO_ITTE_WIDGET_MASK) -#define TIO_ITTE_VALID(itte) \ - (((itte) >> TIO_ITTE_VALID_SHIFT) & TIO_ITTE_VALID_MASK) - -#define TIO_ITTE_PUT(nasid, bigwin, widget, addr, valid) \ - REMOTE_HUB_S((nasid), TIO_ITTE(bigwin), \ - (((((addr) >> TIO_BWIN_SIZE_BITS) & \ - TIO_ITTE_OFFSET_MASK) << TIO_ITTE_OFFSET_SHIFT) | \ - (((widget) & TIO_ITTE_WIDGET_MASK) << TIO_ITTE_WIDGET_SHIFT)) | \ - (( (valid) & TIO_ITTE_VALID_MASK) << TIO_ITTE_VALID_SHIFT)) - -#endif /* _ASM_IA64_SN_TIO_H */ diff --git a/arch/ia64/sn/include/xtalk/hubdev.h b/arch/ia64/sn/include/xtalk/hubdev.h deleted file mode 100644 index 8182583c762c6a4928857373041cb900779044d0..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/include/xtalk/hubdev.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_XTALK_HUBDEV_H -#define _ASM_IA64_SN_XTALK_HUBDEV_H - -#include "xtalk/xwidgetdev.h" - -#define HUB_WIDGET_ID_MAX 0xf -#define DEV_PER_WIDGET (2*2*8) -#define IIO_ITTE_WIDGET_BITS 4 /* size of widget field */ -#define IIO_ITTE_WIDGET_MASK ((1<> IIO_ITTE_WIDGET_SHIFT) & IIO_ITTE_WIDGET_MASK) - -/* - * Use the top big window as a surrogate for the first small window - */ -#define SWIN0_BIGWIN HUB_NUM_BIG_WINDOW -#define IIO_NUM_ITTES 7 -#define HUB_NUM_BIG_WINDOW (IIO_NUM_ITTES - 1) - -/* This struct is shared between the PROM and the kernel. - * Changes to this struct will require corresponding changes to the kernel. - */ -struct sn_flush_device_common { - int sfdl_bus; - int sfdl_slot; - int sfdl_pin; - struct common_bar_list { - unsigned long start; - unsigned long end; - } sfdl_bar_list[6]; - unsigned long sfdl_force_int_addr; - unsigned long sfdl_flush_value; - volatile unsigned long *sfdl_flush_addr; - u32 sfdl_persistent_busnum; - u32 sfdl_persistent_segment; - struct pcibus_info *sfdl_pcibus_info; -}; - -/* This struct is kernel only and is not used by the PROM */ -struct sn_flush_device_kernel { - spinlock_t sfdl_flush_lock; - struct sn_flush_device_common *common; -}; - -/* 01/16/06 This struct is the old PROM/kernel struct and needs to be included - * for older official PROMs to function on the new kernel base. This struct - * will be removed when the next official PROM release occurs. */ - -struct sn_flush_device_war { - struct sn_flush_device_common common; - u32 filler; /* older PROMs expect the default size of a spinlock_t */ -}; - -/* - * **widget_p - Used as an array[wid_num][device] of sn_flush_device_kernel. - */ -struct sn_flush_nasid_entry { - struct sn_flush_device_kernel **widget_p; // Used as an array of wid_num - u64 iio_itte[8]; -}; - -struct hubdev_info { - geoid_t hdi_geoid; - short hdi_nasid; - short hdi_peer_nasid; /* Dual Porting Peer */ - - struct sn_flush_nasid_entry hdi_flush_nasid_list; - struct xwidget_info hdi_xwidget_info[HUB_WIDGET_ID_MAX + 1]; - - - void *hdi_nodepda; - void *hdi_node_vertex; - u32 max_segment_number; - u32 max_pcibus_number; -}; - -extern void hubdev_init_node(nodepda_t *, cnodeid_t); -extern void hub_error_init(struct hubdev_info *); -extern void ice_error_init(struct hubdev_info *); - - -#endif /* _ASM_IA64_SN_XTALK_HUBDEV_H */ diff --git a/arch/ia64/sn/include/xtalk/xbow.h b/arch/ia64/sn/include/xtalk/xbow.h deleted file mode 100644 index 90f37a4133d0a2691ae56dd2a3ef36a68d527994..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/include/xtalk/xbow.h +++ /dev/null @@ -1,301 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992-1997,2000-2006 Silicon Graphics, Inc. All Rights - * Reserved. - */ -#ifndef _ASM_IA64_SN_XTALK_XBOW_H -#define _ASM_IA64_SN_XTALK_XBOW_H - -#define XBOW_PORT_8 0x8 -#define XBOW_PORT_C 0xc -#define XBOW_PORT_F 0xf - -#define MAX_XBOW_PORTS 8 /* number of ports on xbow chip */ -#define BASE_XBOW_PORT XBOW_PORT_8 /* Lowest external port */ - -#define XBOW_CREDIT 4 - -#define MAX_XBOW_NAME 16 - -/* Register set for each xbow link */ -typedef volatile struct xb_linkregs_s { -/* - * we access these through synergy unswizzled space, so the address - * gets twiddled (i.e. references to 0x4 actually go to 0x0 and vv.) - * That's why we put the register first and filler second. - */ - u32 link_ibf; - u32 filler0; /* filler for proper alignment */ - u32 link_control; - u32 filler1; - u32 link_status; - u32 filler2; - u32 link_arb_upper; - u32 filler3; - u32 link_arb_lower; - u32 filler4; - u32 link_status_clr; - u32 filler5; - u32 link_reset; - u32 filler6; - u32 link_aux_status; - u32 filler7; -} xb_linkregs_t; - -typedef volatile struct xbow_s { - /* standard widget configuration 0x000000-0x000057 */ - struct widget_cfg xb_widget; /* 0x000000 */ - - /* helper fieldnames for accessing bridge widget */ - -#define xb_wid_id xb_widget.w_id -#define xb_wid_stat xb_widget.w_status -#define xb_wid_err_upper xb_widget.w_err_upper_addr -#define xb_wid_err_lower xb_widget.w_err_lower_addr -#define xb_wid_control xb_widget.w_control -#define xb_wid_req_timeout xb_widget.w_req_timeout -#define xb_wid_int_upper xb_widget.w_intdest_upper_addr -#define xb_wid_int_lower xb_widget.w_intdest_lower_addr -#define xb_wid_err_cmdword xb_widget.w_err_cmd_word -#define xb_wid_llp xb_widget.w_llp_cfg -#define xb_wid_stat_clr xb_widget.w_tflush - -/* - * we access these through synergy unswizzled space, so the address - * gets twiddled (i.e. references to 0x4 actually go to 0x0 and vv.) - * That's why we put the register first and filler second. - */ - /* xbow-specific widget configuration 0x000058-0x0000FF */ - u32 xb_wid_arb_reload; /* 0x00005C */ - u32 _pad_000058; - u32 xb_perf_ctr_a; /* 0x000064 */ - u32 _pad_000060; - u32 xb_perf_ctr_b; /* 0x00006c */ - u32 _pad_000068; - u32 xb_nic; /* 0x000074 */ - u32 _pad_000070; - - /* Xbridge only */ - u32 xb_w0_rst_fnc; /* 0x00007C */ - u32 _pad_000078; - u32 xb_l8_rst_fnc; /* 0x000084 */ - u32 _pad_000080; - u32 xb_l9_rst_fnc; /* 0x00008c */ - u32 _pad_000088; - u32 xb_la_rst_fnc; /* 0x000094 */ - u32 _pad_000090; - u32 xb_lb_rst_fnc; /* 0x00009c */ - u32 _pad_000098; - u32 xb_lc_rst_fnc; /* 0x0000a4 */ - u32 _pad_0000a0; - u32 xb_ld_rst_fnc; /* 0x0000ac */ - u32 _pad_0000a8; - u32 xb_le_rst_fnc; /* 0x0000b4 */ - u32 _pad_0000b0; - u32 xb_lf_rst_fnc; /* 0x0000bc */ - u32 _pad_0000b8; - u32 xb_lock; /* 0x0000c4 */ - u32 _pad_0000c0; - u32 xb_lock_clr; /* 0x0000cc */ - u32 _pad_0000c8; - /* end of Xbridge only */ - u32 _pad_0000d0[12]; - - /* Link Specific Registers, port 8..15 0x000100-0x000300 */ - xb_linkregs_t xb_link_raw[MAX_XBOW_PORTS]; -} xbow_t; - -#define xb_link(p) xb_link_raw[(p) & (MAX_XBOW_PORTS - 1)] - -#define XB_FLAGS_EXISTS 0x1 /* device exists */ -#define XB_FLAGS_MASTER 0x2 -#define XB_FLAGS_SLAVE 0x0 -#define XB_FLAGS_GBR 0x4 -#define XB_FLAGS_16BIT 0x8 -#define XB_FLAGS_8BIT 0x0 - -/* is widget port number valid? (based on version 7.0 of xbow spec) */ -#define XBOW_WIDGET_IS_VALID(wid) ((wid) >= XBOW_PORT_8 && (wid) <= XBOW_PORT_F) - -/* whether to use upper or lower arbitration register, given source widget id */ -#define XBOW_ARB_IS_UPPER(wid) ((wid) >= XBOW_PORT_8 && (wid) <= XBOW_PORT_B) -#define XBOW_ARB_IS_LOWER(wid) ((wid) >= XBOW_PORT_C && (wid) <= XBOW_PORT_F) - -/* offset of arbitration register, given source widget id */ -#define XBOW_ARB_OFF(wid) (XBOW_ARB_IS_UPPER(wid) ? 0x1c : 0x24) - -#define XBOW_WID_ID WIDGET_ID -#define XBOW_WID_STAT WIDGET_STATUS -#define XBOW_WID_ERR_UPPER WIDGET_ERR_UPPER_ADDR -#define XBOW_WID_ERR_LOWER WIDGET_ERR_LOWER_ADDR -#define XBOW_WID_CONTROL WIDGET_CONTROL -#define XBOW_WID_REQ_TO WIDGET_REQ_TIMEOUT -#define XBOW_WID_INT_UPPER WIDGET_INTDEST_UPPER_ADDR -#define XBOW_WID_INT_LOWER WIDGET_INTDEST_LOWER_ADDR -#define XBOW_WID_ERR_CMDWORD WIDGET_ERR_CMD_WORD -#define XBOW_WID_LLP WIDGET_LLP_CFG -#define XBOW_WID_STAT_CLR WIDGET_TFLUSH -#define XBOW_WID_ARB_RELOAD 0x5c -#define XBOW_WID_PERF_CTR_A 0x64 -#define XBOW_WID_PERF_CTR_B 0x6c -#define XBOW_WID_NIC 0x74 - -/* Xbridge only */ -#define XBOW_W0_RST_FNC 0x00007C -#define XBOW_L8_RST_FNC 0x000084 -#define XBOW_L9_RST_FNC 0x00008c -#define XBOW_LA_RST_FNC 0x000094 -#define XBOW_LB_RST_FNC 0x00009c -#define XBOW_LC_RST_FNC 0x0000a4 -#define XBOW_LD_RST_FNC 0x0000ac -#define XBOW_LE_RST_FNC 0x0000b4 -#define XBOW_LF_RST_FNC 0x0000bc -#define XBOW_RESET_FENCE(x) ((x) > 7 && (x) < 16) ? \ - (XBOW_W0_RST_FNC + ((x) - 7) * 8) : \ - ((x) == 0) ? XBOW_W0_RST_FNC : 0 -#define XBOW_LOCK 0x0000c4 -#define XBOW_LOCK_CLR 0x0000cc -/* End of Xbridge only */ - -/* used only in ide, but defined here within the reserved portion */ -/* of the widget0 address space (before 0xf4) */ -#define XBOW_WID_UNDEF 0xe4 - -/* xbow link register set base, legal value for x is 0x8..0xf */ -#define XB_LINK_BASE 0x100 -#define XB_LINK_OFFSET 0x40 -#define XB_LINK_REG_BASE(x) (XB_LINK_BASE + ((x) & (MAX_XBOW_PORTS - 1)) * XB_LINK_OFFSET) - -#define XB_LINK_IBUF_FLUSH(x) (XB_LINK_REG_BASE(x) + 0x4) -#define XB_LINK_CTRL(x) (XB_LINK_REG_BASE(x) + 0xc) -#define XB_LINK_STATUS(x) (XB_LINK_REG_BASE(x) + 0x14) -#define XB_LINK_ARB_UPPER(x) (XB_LINK_REG_BASE(x) + 0x1c) -#define XB_LINK_ARB_LOWER(x) (XB_LINK_REG_BASE(x) + 0x24) -#define XB_LINK_STATUS_CLR(x) (XB_LINK_REG_BASE(x) + 0x2c) -#define XB_LINK_RESET(x) (XB_LINK_REG_BASE(x) + 0x34) -#define XB_LINK_AUX_STATUS(x) (XB_LINK_REG_BASE(x) + 0x3c) - -/* link_control(x) */ -#define XB_CTRL_LINKALIVE_IE 0x80000000 /* link comes alive */ -/* reserved: 0x40000000 */ -#define XB_CTRL_PERF_CTR_MODE_MSK 0x30000000 /* perf counter mode */ -#define XB_CTRL_IBUF_LEVEL_MSK 0x0e000000 /* input packet buffer - level */ -#define XB_CTRL_8BIT_MODE 0x01000000 /* force link into 8 - bit mode */ -#define XB_CTRL_BAD_LLP_PKT 0x00800000 /* force bad LLP - packet */ -#define XB_CTRL_WIDGET_CR_MSK 0x007c0000 /* LLP widget credit - mask */ -#define XB_CTRL_WIDGET_CR_SHFT 18 /* LLP widget credit - shift */ -#define XB_CTRL_ILLEGAL_DST_IE 0x00020000 /* illegal destination - */ -#define XB_CTRL_OALLOC_IBUF_IE 0x00010000 /* overallocated input - buffer */ -/* reserved: 0x0000fe00 */ -#define XB_CTRL_BNDWDTH_ALLOC_IE 0x00000100 /* bandwidth alloc */ -#define XB_CTRL_RCV_CNT_OFLOW_IE 0x00000080 /* rcv retry overflow */ -#define XB_CTRL_XMT_CNT_OFLOW_IE 0x00000040 /* xmt retry overflow */ -#define XB_CTRL_XMT_MAX_RTRY_IE 0x00000020 /* max transmit retry */ -#define XB_CTRL_RCV_IE 0x00000010 /* receive */ -#define XB_CTRL_XMT_RTRY_IE 0x00000008 /* transmit retry */ -/* reserved: 0x00000004 */ -#define XB_CTRL_MAXREQ_TOUT_IE 0x00000002 /* maximum request - timeout */ -#define XB_CTRL_SRC_TOUT_IE 0x00000001 /* source timeout */ - -/* link_status(x) */ -#define XB_STAT_LINKALIVE XB_CTRL_LINKALIVE_IE -/* reserved: 0x7ff80000 */ -#define XB_STAT_MULTI_ERR 0x00040000 /* multi error */ -#define XB_STAT_ILLEGAL_DST_ERR XB_CTRL_ILLEGAL_DST_IE -#define XB_STAT_OALLOC_IBUF_ERR XB_CTRL_OALLOC_IBUF_IE -#define XB_STAT_BNDWDTH_ALLOC_ID_MSK 0x0000ff00 /* port bitmask */ -#define XB_STAT_RCV_CNT_OFLOW_ERR XB_CTRL_RCV_CNT_OFLOW_IE -#define XB_STAT_XMT_CNT_OFLOW_ERR XB_CTRL_XMT_CNT_OFLOW_IE -#define XB_STAT_XMT_MAX_RTRY_ERR XB_CTRL_XMT_MAX_RTRY_IE -#define XB_STAT_RCV_ERR XB_CTRL_RCV_IE -#define XB_STAT_XMT_RTRY_ERR XB_CTRL_XMT_RTRY_IE -/* reserved: 0x00000004 */ -#define XB_STAT_MAXREQ_TOUT_ERR XB_CTRL_MAXREQ_TOUT_IE -#define XB_STAT_SRC_TOUT_ERR XB_CTRL_SRC_TOUT_IE - -/* link_aux_status(x) */ -#define XB_AUX_STAT_RCV_CNT 0xff000000 -#define XB_AUX_STAT_XMT_CNT 0x00ff0000 -#define XB_AUX_STAT_TOUT_DST 0x0000ff00 -#define XB_AUX_LINKFAIL_RST_BAD 0x00000040 -#define XB_AUX_STAT_PRESENT 0x00000020 -#define XB_AUX_STAT_PORT_WIDTH 0x00000010 -/* reserved: 0x0000000f */ - -/* - * link_arb_upper/link_arb_lower(x), (reg) should be the link_arb_upper - * register if (x) is 0x8..0xb, link_arb_lower if (x) is 0xc..0xf - */ -#define XB_ARB_GBR_MSK 0x1f -#define XB_ARB_RR_MSK 0x7 -#define XB_ARB_GBR_SHFT(x) (((x) & 0x3) * 8) -#define XB_ARB_RR_SHFT(x) (((x) & 0x3) * 8 + 5) -#define XB_ARB_GBR_CNT(reg,x) ((reg) >> XB_ARB_GBR_SHFT(x) & XB_ARB_GBR_MSK) -#define XB_ARB_RR_CNT(reg,x) ((reg) >> XB_ARB_RR_SHFT(x) & XB_ARB_RR_MSK) - -/* XBOW_WID_STAT */ -#define XB_WID_STAT_LINK_INTR_SHFT (24) -#define XB_WID_STAT_LINK_INTR_MASK (0xFF << XB_WID_STAT_LINK_INTR_SHFT) -#define XB_WID_STAT_LINK_INTR(x) \ - (0x1 << (((x)&7) + XB_WID_STAT_LINK_INTR_SHFT)) -#define XB_WID_STAT_WIDGET0_INTR 0x00800000 -#define XB_WID_STAT_SRCID_MASK 0x000003c0 /* Xbridge only */ -#define XB_WID_STAT_REG_ACC_ERR 0x00000020 -#define XB_WID_STAT_RECV_TOUT 0x00000010 /* Xbridge only */ -#define XB_WID_STAT_ARB_TOUT 0x00000008 /* Xbridge only */ -#define XB_WID_STAT_XTALK_ERR 0x00000004 -#define XB_WID_STAT_DST_TOUT 0x00000002 /* Xbridge only */ -#define XB_WID_STAT_MULTI_ERR 0x00000001 - -#define XB_WID_STAT_SRCID_SHFT 6 - -/* XBOW_WID_CONTROL */ -#define XB_WID_CTRL_REG_ACC_IE XB_WID_STAT_REG_ACC_ERR -#define XB_WID_CTRL_RECV_TOUT XB_WID_STAT_RECV_TOUT -#define XB_WID_CTRL_ARB_TOUT XB_WID_STAT_ARB_TOUT -#define XB_WID_CTRL_XTALK_IE XB_WID_STAT_XTALK_ERR - -/* XBOW_WID_INT_UPPER */ -/* defined in xwidget.h for WIDGET_INTDEST_UPPER_ADDR */ - -/* XBOW WIDGET part number, in the ID register */ -#define XBOW_WIDGET_PART_NUM 0x0 /* crossbow */ -#define XXBOW_WIDGET_PART_NUM 0xd000 /* Xbridge */ -#define XBOW_WIDGET_MFGR_NUM 0x0 -#define XXBOW_WIDGET_MFGR_NUM 0x0 -#define PXBOW_WIDGET_PART_NUM 0xd100 /* PIC */ - -#define XBOW_REV_1_0 0x1 /* xbow rev 1.0 is "1" */ -#define XBOW_REV_1_1 0x2 /* xbow rev 1.1 is "2" */ -#define XBOW_REV_1_2 0x3 /* xbow rev 1.2 is "3" */ -#define XBOW_REV_1_3 0x4 /* xbow rev 1.3 is "4" */ -#define XBOW_REV_2_0 0x5 /* xbow rev 2.0 is "5" */ - -#define XXBOW_PART_REV_1_0 (XXBOW_WIDGET_PART_NUM << 4 | 0x1 ) -#define XXBOW_PART_REV_2_0 (XXBOW_WIDGET_PART_NUM << 4 | 0x2 ) - -/* XBOW_WID_ARB_RELOAD */ -#define XBOW_WID_ARB_RELOAD_INT 0x3f /* GBR reload interval */ - -#define IS_XBRIDGE_XBOW(wid) \ - (XWIDGET_PART_NUM(wid) == XXBOW_WIDGET_PART_NUM && \ - XWIDGET_MFG_NUM(wid) == XXBOW_WIDGET_MFGR_NUM) - -#define IS_PIC_XBOW(wid) \ - (XWIDGET_PART_NUM(wid) == PXBOW_WIDGET_PART_NUM && \ - XWIDGET_MFG_NUM(wid) == XXBOW_WIDGET_MFGR_NUM) - -#define XBOW_WAR_ENABLED(pv, widid) ((1 << XWIDGET_REV_NUM(widid)) & pv) - -#endif /* _ASM_IA64_SN_XTALK_XBOW_H */ diff --git a/arch/ia64/sn/include/xtalk/xwidgetdev.h b/arch/ia64/sn/include/xtalk/xwidgetdev.h deleted file mode 100644 index 2800eda0fd686fdaf467fa1a04c2cef94a6f2748..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/include/xtalk/xwidgetdev.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. - */ -#ifndef _ASM_IA64_SN_XTALK_XWIDGET_H -#define _ASM_IA64_SN_XTALK_XWIDGET_H - -/* WIDGET_ID */ -#define WIDGET_REV_NUM 0xf0000000 -#define WIDGET_PART_NUM 0x0ffff000 -#define WIDGET_MFG_NUM 0x00000ffe -#define WIDGET_REV_NUM_SHFT 28 -#define WIDGET_PART_NUM_SHFT 12 -#define WIDGET_MFG_NUM_SHFT 1 - -#define XWIDGET_PART_NUM(widgetid) (((widgetid) & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT) -#define XWIDGET_REV_NUM(widgetid) (((widgetid) & WIDGET_REV_NUM) >> WIDGET_REV_NUM_SHFT) -#define XWIDGET_MFG_NUM(widgetid) (((widgetid) & WIDGET_MFG_NUM) >> WIDGET_MFG_NUM_SHFT) -#define XWIDGET_PART_REV_NUM(widgetid) ((XWIDGET_PART_NUM(widgetid) << 4) | \ - XWIDGET_REV_NUM(widgetid)) -#define XWIDGET_PART_REV_NUM_REV(partrev) (partrev & 0xf) - -/* widget configuration registers */ -struct widget_cfg{ - u32 w_id; /* 0x04 */ - u32 w_pad_0; /* 0x00 */ - u32 w_status; /* 0x0c */ - u32 w_pad_1; /* 0x08 */ - u32 w_err_upper_addr; /* 0x14 */ - u32 w_pad_2; /* 0x10 */ - u32 w_err_lower_addr; /* 0x1c */ - u32 w_pad_3; /* 0x18 */ - u32 w_control; /* 0x24 */ - u32 w_pad_4; /* 0x20 */ - u32 w_req_timeout; /* 0x2c */ - u32 w_pad_5; /* 0x28 */ - u32 w_intdest_upper_addr; /* 0x34 */ - u32 w_pad_6; /* 0x30 */ - u32 w_intdest_lower_addr; /* 0x3c */ - u32 w_pad_7; /* 0x38 */ - u32 w_err_cmd_word; /* 0x44 */ - u32 w_pad_8; /* 0x40 */ - u32 w_llp_cfg; /* 0x4c */ - u32 w_pad_9; /* 0x48 */ - u32 w_tflush; /* 0x54 */ - u32 w_pad_10; /* 0x50 */ -}; - -/* - * Crosstalk Widget Hardware Identification, as defined in the Crosstalk spec. - */ -struct xwidget_hwid{ - int mfg_num; - int rev_num; - int part_num; -}; - -struct xwidget_info{ - - struct xwidget_hwid xwi_hwid; /* Widget Identification */ - char xwi_masterxid; /* Hub's Widget Port Number */ - void *xwi_hubinfo; /* Hub's provider private info */ - u64 *xwi_hub_provider; /* prom provider functions */ - void *xwi_vertex; -}; - -#endif /* _ASM_IA64_SN_XTALK_XWIDGET_H */ diff --git a/arch/ia64/sn/kernel/Makefile b/arch/ia64/sn/kernel/Makefile deleted file mode 100644 index 9c349dd232650a19f76de0420461cb0e32b4ade1..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# arch/ia64/sn/kernel/Makefile -# -# This file is subject to the terms and conditions of the GNU General Public -# License. See the file "COPYING" in the main directory of this archive -# for more details. -# -# Copyright (C) 1999,2001-2006,2008 Silicon Graphics, Inc. All Rights Reserved. -# - -ccflags-y := -I $(srctree)/arch/ia64/sn/include - -obj-y += setup.o bte.o bte_error.o irq.o mca.o idle.o \ - huberror.o io_acpi_init.o io_common.o \ - io_init.o iomv.o klconflib.o pio_phys.o \ - sn2/ -obj-$(CONFIG_IA64_GENERIC) += machvec.o -obj-$(CONFIG_SGI_TIOCX) += tiocx.o -obj-$(CONFIG_PCI_MSI) += msi_sn.o diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c deleted file mode 100644 index 9900e6d4add60d6e3731401ec087da87b1f4be1a..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/bte.c +++ /dev/null @@ -1,475 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2000-2007 Silicon Graphics, Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#ifndef L1_CACHE_MASK -#define L1_CACHE_MASK (L1_CACHE_BYTES - 1) -#endif - -/* two interfaces on two btes */ -#define MAX_INTERFACES_TO_TRY 4 -#define MAX_NODES_TO_TRY 2 - -static struct bteinfo_s *bte_if_on_node(nasid_t nasid, int interface) -{ - nodepda_t *tmp_nodepda; - - if (nasid_to_cnodeid(nasid) == -1) - return (struct bteinfo_s *)NULL; - - tmp_nodepda = NODEPDA(nasid_to_cnodeid(nasid)); - return &tmp_nodepda->bte_if[interface]; - -} - -static inline void bte_start_transfer(struct bteinfo_s *bte, u64 len, u64 mode) -{ - if (is_shub2()) { - BTE_CTRL_STORE(bte, (IBLS_BUSY | ((len) | (mode) << 24))); - } else { - BTE_LNSTAT_STORE(bte, len); - BTE_CTRL_STORE(bte, mode); - } -} - -/************************************************************************ - * Block Transfer Engine copy related functions. - * - ***********************************************************************/ - -/* - * bte_copy(src, dest, len, mode, notification) - * - * Use the block transfer engine to move kernel memory from src to dest - * using the assigned mode. - * - * Parameters: - * src - physical address of the transfer source. - * dest - physical address of the transfer destination. - * len - number of bytes to transfer from source to dest. - * mode - hardware defined. See reference information - * for IBCT0/1 in the SHUB Programmers Reference - * notification - kernel virtual address of the notification cache - * line. If NULL, the default is used and - * the bte_copy is synchronous. - * - * NOTE: This function requires src, dest, and len to - * be cacheline aligned. - */ -bte_result_t bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification) -{ - u64 transfer_size; - u64 transfer_stat; - u64 notif_phys_addr; - struct bteinfo_s *bte; - bte_result_t bte_status; - unsigned long irq_flags; - unsigned long itc_end = 0; - int nasid_to_try[MAX_NODES_TO_TRY]; - int my_nasid = cpuid_to_nasid(raw_smp_processor_id()); - int bte_if_index, nasid_index; - int bte_first, btes_per_node = BTES_PER_NODE; - - BTE_PRINTK(("bte_copy(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%p)\n", - src, dest, len, mode, notification)); - - if (len == 0) { - return BTE_SUCCESS; - } - - BUG_ON(len & L1_CACHE_MASK); - BUG_ON(src & L1_CACHE_MASK); - BUG_ON(dest & L1_CACHE_MASK); - BUG_ON(len > BTE_MAX_XFER); - - /* - * Start with interface corresponding to cpu number - */ - bte_first = raw_smp_processor_id() % btes_per_node; - - if (mode & BTE_USE_DEST) { - /* try remote then local */ - nasid_to_try[0] = NASID_GET(dest); - if (mode & BTE_USE_ANY) { - nasid_to_try[1] = my_nasid; - } else { - nasid_to_try[1] = 0; - } - } else { - /* try local then remote */ - nasid_to_try[0] = my_nasid; - if (mode & BTE_USE_ANY) { - nasid_to_try[1] = NASID_GET(dest); - } else { - nasid_to_try[1] = 0; - } - } - -retry_bteop: - do { - local_irq_save(irq_flags); - - bte_if_index = bte_first; - nasid_index = 0; - - /* Attempt to lock one of the BTE interfaces. */ - while (nasid_index < MAX_NODES_TO_TRY) { - bte = bte_if_on_node(nasid_to_try[nasid_index],bte_if_index); - - if (bte == NULL) { - nasid_index++; - continue; - } - - if (spin_trylock(&bte->spinlock)) { - if (!(*bte->most_rcnt_na & BTE_WORD_AVAILABLE) || - (BTE_LNSTAT_LOAD(bte) & BTE_ACTIVE)) { - /* Got the lock but BTE still busy */ - spin_unlock(&bte->spinlock); - } else { - /* we got the lock and it's not busy */ - break; - } - } - - bte_if_index = (bte_if_index + 1) % btes_per_node; /* Next interface */ - if (bte_if_index == bte_first) { - /* - * We've tried all interfaces on this node - */ - nasid_index++; - } - - bte = NULL; - } - - if (bte != NULL) { - break; - } - - local_irq_restore(irq_flags); - - if (!(mode & BTE_WACQUIRE)) { - return BTEFAIL_NOTAVAIL; - } - } while (1); - - if (notification == NULL) { - /* User does not want to be notified. */ - bte->most_rcnt_na = &bte->notify; - } else { - bte->most_rcnt_na = notification; - } - - /* Calculate the number of cache lines to transfer. */ - transfer_size = ((len >> L1_CACHE_SHIFT) & BTE_LEN_MASK); - - /* Initialize the notification to a known value. */ - *bte->most_rcnt_na = BTE_WORD_BUSY; - notif_phys_addr = (u64)bte->most_rcnt_na; - - /* Set the source and destination registers */ - BTE_PRINTKV(("IBSA = 0x%lx)\n", src)); - BTE_SRC_STORE(bte, src); - BTE_PRINTKV(("IBDA = 0x%lx)\n", dest)); - BTE_DEST_STORE(bte, dest); - - /* Set the notification register */ - BTE_PRINTKV(("IBNA = 0x%lx)\n", notif_phys_addr)); - BTE_NOTIF_STORE(bte, notif_phys_addr); - - /* Initiate the transfer */ - BTE_PRINTK(("IBCT = 0x%lx)\n", BTE_VALID_MODE(mode))); - bte_start_transfer(bte, transfer_size, BTE_VALID_MODE(mode)); - - itc_end = ia64_get_itc() + (40000000 * local_cpu_data->cyc_per_usec); - - spin_unlock_irqrestore(&bte->spinlock, irq_flags); - - if (notification != NULL) { - return BTE_SUCCESS; - } - - while ((transfer_stat = *bte->most_rcnt_na) == BTE_WORD_BUSY) { - cpu_relax(); - if (ia64_get_itc() > itc_end) { - BTE_PRINTK(("BTE timeout nasid 0x%x bte%d IBLS = 0x%lx na 0x%lx\n", - NASID_GET(bte->bte_base_addr), bte->bte_num, - BTE_LNSTAT_LOAD(bte), *bte->most_rcnt_na) ); - bte->bte_error_count++; - bte->bh_error = IBLS_ERROR; - bte_error_handler(NODEPDA(bte->bte_cnode)); - *bte->most_rcnt_na = BTE_WORD_AVAILABLE; - goto retry_bteop; - } - } - - BTE_PRINTKV((" Delay Done. IBLS = 0x%lx, most_rcnt_na = 0x%lx\n", - BTE_LNSTAT_LOAD(bte), *bte->most_rcnt_na)); - - if (transfer_stat & IBLS_ERROR) { - bte_status = BTE_GET_ERROR_STATUS(transfer_stat); - } else { - bte_status = BTE_SUCCESS; - } - *bte->most_rcnt_na = BTE_WORD_AVAILABLE; - - BTE_PRINTK(("Returning status is 0x%lx and most_rcnt_na is 0x%lx\n", - BTE_LNSTAT_LOAD(bte), *bte->most_rcnt_na)); - - return bte_status; -} - -EXPORT_SYMBOL(bte_copy); - -/* - * bte_unaligned_copy(src, dest, len, mode) - * - * use the block transfer engine to move kernel - * memory from src to dest using the assigned mode. - * - * Parameters: - * src - physical address of the transfer source. - * dest - physical address of the transfer destination. - * len - number of bytes to transfer from source to dest. - * mode - hardware defined. See reference information - * for IBCT0/1 in the SGI documentation. - * - * NOTE: If the source, dest, and len are all cache line aligned, - * then it would be _FAR_ preferable to use bte_copy instead. - */ -bte_result_t bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode) -{ - int destFirstCacheOffset; - u64 headBteSource; - u64 headBteLen; - u64 headBcopySrcOffset; - u64 headBcopyDest; - u64 headBcopyLen; - u64 footBteSource; - u64 footBteLen; - u64 footBcopyDest; - u64 footBcopyLen; - bte_result_t rv; - char *bteBlock, *bteBlock_unaligned; - - if (len == 0) { - return BTE_SUCCESS; - } - - /* temporary buffer used during unaligned transfers */ - bteBlock_unaligned = kmalloc(len + 3 * L1_CACHE_BYTES, GFP_KERNEL); - if (bteBlock_unaligned == NULL) { - return BTEFAIL_NOTAVAIL; - } - bteBlock = (char *)L1_CACHE_ALIGN((u64) bteBlock_unaligned); - - headBcopySrcOffset = src & L1_CACHE_MASK; - destFirstCacheOffset = dest & L1_CACHE_MASK; - - /* - * At this point, the transfer is broken into - * (up to) three sections. The first section is - * from the start address to the first physical - * cache line, the second is from the first physical - * cache line to the last complete cache line, - * and the third is from the last cache line to the - * end of the buffer. The first and third sections - * are handled by bte copying into a temporary buffer - * and then bcopy'ing the necessary section into the - * final location. The middle section is handled with - * a standard bte copy. - * - * One nasty exception to the above rule is when the - * source and destination are not symmetrically - * mis-aligned. If the source offset from the first - * cache line is different from the destination offset, - * we make the first section be the entire transfer - * and the bcopy the entire block into place. - */ - if (headBcopySrcOffset == destFirstCacheOffset) { - - /* - * Both the source and destination are the same - * distance from a cache line boundary so we can - * use the bte to transfer the bulk of the - * data. - */ - headBteSource = src & ~L1_CACHE_MASK; - headBcopyDest = dest; - if (headBcopySrcOffset) { - headBcopyLen = - (len > - (L1_CACHE_BYTES - - headBcopySrcOffset) ? L1_CACHE_BYTES - - headBcopySrcOffset : len); - headBteLen = L1_CACHE_BYTES; - } else { - headBcopyLen = 0; - headBteLen = 0; - } - - if (len > headBcopyLen) { - footBcopyLen = (len - headBcopyLen) & L1_CACHE_MASK; - footBteLen = L1_CACHE_BYTES; - - footBteSource = src + len - footBcopyLen; - footBcopyDest = dest + len - footBcopyLen; - - if (footBcopyDest == (headBcopyDest + headBcopyLen)) { - /* - * We have two contiguous bcopy - * blocks. Merge them. - */ - headBcopyLen += footBcopyLen; - headBteLen += footBteLen; - } else if (footBcopyLen > 0) { - rv = bte_copy(footBteSource, - ia64_tpa((unsigned long)bteBlock), - footBteLen, mode, NULL); - if (rv != BTE_SUCCESS) { - kfree(bteBlock_unaligned); - return rv; - } - - memcpy(__va(footBcopyDest), - (char *)bteBlock, footBcopyLen); - } - } else { - footBcopyLen = 0; - footBteLen = 0; - } - - if (len > (headBcopyLen + footBcopyLen)) { - /* now transfer the middle. */ - rv = bte_copy((src + headBcopyLen), - (dest + - headBcopyLen), - (len - headBcopyLen - - footBcopyLen), mode, NULL); - if (rv != BTE_SUCCESS) { - kfree(bteBlock_unaligned); - return rv; - } - - } - } else { - - /* - * The transfer is not symmetric, we will - * allocate a buffer large enough for all the - * data, bte_copy into that buffer and then - * bcopy to the destination. - */ - - headBcopySrcOffset = src & L1_CACHE_MASK; - headBcopyDest = dest; - headBcopyLen = len; - - headBteSource = src - headBcopySrcOffset; - /* Add the leading and trailing bytes from source */ - headBteLen = L1_CACHE_ALIGN(len + headBcopySrcOffset); - } - - if (headBcopyLen > 0) { - rv = bte_copy(headBteSource, - ia64_tpa((unsigned long)bteBlock), headBteLen, - mode, NULL); - if (rv != BTE_SUCCESS) { - kfree(bteBlock_unaligned); - return rv; - } - - memcpy(__va(headBcopyDest), ((char *)bteBlock + - headBcopySrcOffset), headBcopyLen); - } - kfree(bteBlock_unaligned); - return BTE_SUCCESS; -} - -EXPORT_SYMBOL(bte_unaligned_copy); - -/************************************************************************ - * Block Transfer Engine initialization functions. - * - ***********************************************************************/ -static void bte_recovery_timeout(struct timer_list *t) -{ - struct nodepda_s *nodepda = from_timer(nodepda, t, bte_recovery_timer); - - bte_error_handler(nodepda); -} - -/* - * bte_init_node(nodepda, cnode) - * - * Initialize the nodepda structure with BTE base addresses and - * spinlocks. - */ -void bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode) -{ - int i; - - /* - * Indicate that all the block transfer engines on this node - * are available. - */ - - /* - * Allocate one bte_recover_t structure per node. It holds - * the recovery lock for node. All the bte interface structures - * will point at this one bte_recover structure to get the lock. - */ - spin_lock_init(&mynodepda->bte_recovery_lock); - timer_setup(&mynodepda->bte_recovery_timer, bte_recovery_timeout, 0); - - for (i = 0; i < BTES_PER_NODE; i++) { - u64 *base_addr; - - /* Which link status register should we use? */ - base_addr = (u64 *) - REMOTE_HUB_ADDR(cnodeid_to_nasid(cnode), BTE_BASE_ADDR(i)); - mynodepda->bte_if[i].bte_base_addr = base_addr; - mynodepda->bte_if[i].bte_source_addr = BTE_SOURCE_ADDR(base_addr); - mynodepda->bte_if[i].bte_destination_addr = BTE_DEST_ADDR(base_addr); - mynodepda->bte_if[i].bte_control_addr = BTE_CTRL_ADDR(base_addr); - mynodepda->bte_if[i].bte_notify_addr = BTE_NOTIF_ADDR(base_addr); - - /* - * Initialize the notification and spinlock - * so the first transfer can occur. - */ - mynodepda->bte_if[i].most_rcnt_na = - &(mynodepda->bte_if[i].notify); - mynodepda->bte_if[i].notify = BTE_WORD_AVAILABLE; - spin_lock_init(&mynodepda->bte_if[i].spinlock); - - mynodepda->bte_if[i].bte_cnode = cnode; - mynodepda->bte_if[i].bte_error_count = 0; - mynodepda->bte_if[i].bte_num = i; - mynodepda->bte_if[i].cleanup_active = 0; - mynodepda->bte_if[i].bh_error = 0; - } - -} diff --git a/arch/ia64/sn/kernel/bte_error.c b/arch/ia64/sn/kernel/bte_error.c deleted file mode 100644 index d92786c09b344d05ff048979d24597787cae4e57..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/bte_error.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2000-2007 Silicon Graphics, Inc. All Rights Reserved. - */ - -#include -#include -#include "ioerror.h" -#include -#include -#include -#include "xtalk/xwidgetdev.h" -#include "xtalk/hubdev.h" -#include -#include - -/* - * Bte error handling is done in two parts. The first captures - * any crb related errors. Since there can be multiple crbs per - * interface and multiple interfaces active, we need to wait until - * all active crbs are completed. This is the first job of the - * second part error handler. When all bte related CRBs are cleanly - * completed, it resets the interfaces and gets them ready for new - * transfers to be queued. - */ - -/* - * Wait until all BTE related CRBs are completed - * and then reset the interfaces. - */ -static int shub1_bte_error_handler(struct nodepda_s *err_nodepda) -{ - struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer; - nasid_t nasid; - int i; - int valid_crbs; - ii_imem_u_t imem; /* II IMEM Register */ - ii_icrb0_d_u_t icrbd; /* II CRB Register D */ - ii_ibcr_u_t ibcr; - ii_icmr_u_t icmr; - ii_ieclr_u_t ieclr; - - BTE_PRINTK(("shub1_bte_error_handler(%p) - %d\n", err_nodepda, - smp_processor_id())); - - if ((err_nodepda->bte_if[0].bh_error == BTE_SUCCESS) && - (err_nodepda->bte_if[1].bh_error == BTE_SUCCESS)) { - BTE_PRINTK(("eh:%p:%d Nothing to do.\n", err_nodepda, - smp_processor_id())); - return 1; - } - - /* Determine information about our hub */ - nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode); - - /* - * A BTE transfer can use multiple CRBs. We need to make sure - * that all the BTE CRBs are complete (or timed out) before - * attempting to clean up the error. Resetting the BTE while - * there are still BTE CRBs active will hang the BTE. - * We should look at all the CRBs to see if they are allocated - * to the BTE and see if they are still active. When none - * are active, we can continue with the cleanup. - * - * We also want to make sure that the local NI port is up. - * When a router resets the NI port can go down, while it - * goes through the LLP handshake, but then comes back up. - */ - icmr.ii_icmr_regval = REMOTE_HUB_L(nasid, IIO_ICMR); - if (icmr.ii_icmr_fld_s.i_crb_mark != 0) { - /* - * There are errors which still need to be cleaned up by - * hubiio_crb_error_handler - */ - mod_timer(recovery_timer, jiffies + (HZ * 5)); - BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda, - smp_processor_id())); - return 1; - } - if (icmr.ii_icmr_fld_s.i_crb_vld != 0) { - - valid_crbs = icmr.ii_icmr_fld_s.i_crb_vld; - - for (i = 0; i < IIO_NUM_CRBS; i++) { - if (!((1 << i) & valid_crbs)) { - /* This crb was not marked as valid, ignore */ - continue; - } - icrbd.ii_icrb0_d_regval = - REMOTE_HUB_L(nasid, IIO_ICRB_D(i)); - if (icrbd.d_bteop) { - mod_timer(recovery_timer, jiffies + (HZ * 5)); - BTE_PRINTK(("eh:%p:%d Valid %d, Giving up\n", - err_nodepda, smp_processor_id(), - i)); - return 1; - } - } - } - - BTE_PRINTK(("eh:%p:%d Cleaning up\n", err_nodepda, smp_processor_id())); - /* Re-enable both bte interfaces */ - imem.ii_imem_regval = REMOTE_HUB_L(nasid, IIO_IMEM); - imem.ii_imem_fld_s.i_b0_esd = imem.ii_imem_fld_s.i_b1_esd = 1; - REMOTE_HUB_S(nasid, IIO_IMEM, imem.ii_imem_regval); - - /* Clear BTE0/1 error bits */ - ieclr.ii_ieclr_regval = 0; - if (err_nodepda->bte_if[0].bh_error != BTE_SUCCESS) - ieclr.ii_ieclr_fld_s.i_e_bte_0 = 1; - if (err_nodepda->bte_if[1].bh_error != BTE_SUCCESS) - ieclr.ii_ieclr_fld_s.i_e_bte_1 = 1; - REMOTE_HUB_S(nasid, IIO_IECLR, ieclr.ii_ieclr_regval); - - /* Reinitialize both BTE state machines. */ - ibcr.ii_ibcr_regval = REMOTE_HUB_L(nasid, IIO_IBCR); - ibcr.ii_ibcr_fld_s.i_soft_reset = 1; - REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval); - - del_timer(recovery_timer); - return 0; -} - -/* - * Wait until all BTE related CRBs are completed - * and then reset the interfaces. - */ -static int shub2_bte_error_handler(struct nodepda_s *err_nodepda) -{ - struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer; - struct bteinfo_s *bte; - nasid_t nasid; - u64 status; - int i; - - nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode); - - /* - * Verify that all the BTEs are complete - */ - for (i = 0; i < BTES_PER_NODE; i++) { - bte = &err_nodepda->bte_if[i]; - status = BTE_LNSTAT_LOAD(bte); - if (status & IBLS_ERROR) { - bte->bh_error = BTE_SHUB2_ERROR(status); - continue; - } - if (!(status & IBLS_BUSY)) - continue; - mod_timer(recovery_timer, jiffies + (HZ * 5)); - BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda, - smp_processor_id())); - return 1; - } - if (ia64_sn_bte_recovery(nasid)) - panic("bte_error_handler(): Fatal BTE Error"); - - del_timer(recovery_timer); - return 0; -} - -/* - * Wait until all BTE related CRBs are completed - * and then reset the interfaces. - */ -void bte_error_handler(struct nodepda_s *err_nodepda) -{ - spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock; - int i; - unsigned long irq_flags; - volatile u64 *notify; - bte_result_t bh_error; - - BTE_PRINTK(("bte_error_handler(%p) - %d\n", err_nodepda, - smp_processor_id())); - - spin_lock_irqsave(recovery_lock, irq_flags); - - /* - * Lock all interfaces on this node to prevent new transfers - * from being queued. - */ - for (i = 0; i < BTES_PER_NODE; i++) { - if (err_nodepda->bte_if[i].cleanup_active) { - continue; - } - spin_lock(&err_nodepda->bte_if[i].spinlock); - BTE_PRINTK(("eh:%p:%d locked %d\n", err_nodepda, - smp_processor_id(), i)); - err_nodepda->bte_if[i].cleanup_active = 1; - } - - if (is_shub1()) { - if (shub1_bte_error_handler(err_nodepda)) { - spin_unlock_irqrestore(recovery_lock, irq_flags); - return; - } - } else { - if (shub2_bte_error_handler(err_nodepda)) { - spin_unlock_irqrestore(recovery_lock, irq_flags); - return; - } - } - - for (i = 0; i < BTES_PER_NODE; i++) { - bh_error = err_nodepda->bte_if[i].bh_error; - if (bh_error != BTE_SUCCESS) { - /* There is an error which needs to be notified */ - notify = err_nodepda->bte_if[i].most_rcnt_na; - BTE_PRINTK(("cnode %d bte %d error=0x%lx\n", - err_nodepda->bte_if[i].bte_cnode, - err_nodepda->bte_if[i].bte_num, - IBLS_ERROR | (u64) bh_error)); - *notify = IBLS_ERROR | bh_error; - err_nodepda->bte_if[i].bh_error = BTE_SUCCESS; - } - - err_nodepda->bte_if[i].cleanup_active = 0; - BTE_PRINTK(("eh:%p:%d Unlocked %d\n", err_nodepda, - smp_processor_id(), i)); - spin_unlock(&err_nodepda->bte_if[i].spinlock); - } - - spin_unlock_irqrestore(recovery_lock, irq_flags); -} - -/* - * First part error handler. This is called whenever any error CRB interrupt - * is generated by the II. - */ -void -bte_crb_error_handler(cnodeid_t cnode, int btenum, - int crbnum, ioerror_t * ioe, int bteop) -{ - struct bteinfo_s *bte; - - - bte = &(NODEPDA(cnode)->bte_if[btenum]); - - /* - * The caller has already figured out the error type, we save that - * in the bte handle structure for the thread exercising the - * interface to consume. - */ - bte->bh_error = ioe->ie_errortype + BTEFAIL_OFFSET; - bte->bte_error_count++; - - BTE_PRINTK(("Got an error on cnode %d bte %d: HW error type 0x%x\n", - bte->bte_cnode, bte->bte_num, ioe->ie_errortype)); - bte_error_handler(NODEPDA(cnode)); -} - diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c deleted file mode 100644 index 97fa56dddf50ab23c22d94e74cd6b7ce9fb151c0..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/huberror.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000,2002-2007 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include "ioerror.h" -#include -#include -#include -#include "xtalk/xwidgetdev.h" -#include "xtalk/hubdev.h" -#include - -void hubiio_crb_error_handler(struct hubdev_info *hubdev_info); -extern void bte_crb_error_handler(cnodeid_t, int, int, ioerror_t *, - int); -static irqreturn_t hub_eint_handler(int irq, void *arg) -{ - struct hubdev_info *hubdev_info; - struct ia64_sal_retval ret_stuff; - nasid_t nasid; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - hubdev_info = (struct hubdev_info *)arg; - nasid = hubdev_info->hdi_nasid; - - if (is_shub1()) { - SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT, - (u64) nasid, 0, 0, 0, 0, 0, 0); - - if ((int)ret_stuff.v0) - panic("%s: Fatal %s Error", __func__, - ((nasid & 1) ? "TIO" : "HUBII")); - - if (!(nasid & 1)) /* Not a TIO, handle CRB errors */ - (void)hubiio_crb_error_handler(hubdev_info); - } else - if (nasid & 1) { /* TIO errors */ - SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT, - (u64) nasid, 0, 0, 0, 0, 0, 0); - - if ((int)ret_stuff.v0) - panic("%s: Fatal TIO Error", __func__); - } else - bte_error_handler(NODEPDA(nasid_to_cnodeid(nasid))); - - return IRQ_HANDLED; -} - -/* - * Free the hub CRB "crbnum" which encountered an error. - * Assumption is, error handling was successfully done, - * and we now want to return the CRB back to Hub for normal usage. - * - * In order to free the CRB, all that's needed is to de-allocate it - * - * Assumption: - * No other processor is mucking around with the hub control register. - * So, upper layer has to single thread this. - */ -void hubiio_crb_free(struct hubdev_info *hubdev_info, int crbnum) -{ - ii_icrb0_b_u_t icrbb; - - /* - * The hardware does NOT clear the mark bit, so it must get cleared - * here to be sure the error is not processed twice. - */ - icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(hubdev_info->hdi_nasid, - IIO_ICRB_B(crbnum)); - icrbb.b_mark = 0; - REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICRB_B(crbnum), - icrbb.ii_icrb0_b_regval); - /* - * Deallocate the register wait till hub indicates it's done. - */ - REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICDR, (IIO_ICDR_PND | crbnum)); - while (REMOTE_HUB_L(hubdev_info->hdi_nasid, IIO_ICDR) & IIO_ICDR_PND) - cpu_relax(); - -} - -/* - * hubiio_crb_error_handler - * - * This routine gets invoked when a hub gets an error - * interrupt. So, the routine is running in interrupt context - * at error interrupt level. - * Action: - * It's responsible for identifying ALL the CRBs that are marked - * with error, and process them. - * - * If you find the CRB that's marked with error, map this to the - * reason it caused error, and invoke appropriate error handler. - * - * XXX Be aware of the information in the context register. - * - * NOTE: - * Use REMOTE_HUB_* macro instead of LOCAL_HUB_* so that the interrupt - * handler can be run on any node. (not necessarily the node - * corresponding to the hub that encountered error). - */ - -void hubiio_crb_error_handler(struct hubdev_info *hubdev_info) -{ - nasid_t nasid; - ii_icrb0_a_u_t icrba; /* II CRB Register A */ - ii_icrb0_b_u_t icrbb; /* II CRB Register B */ - ii_icrb0_c_u_t icrbc; /* II CRB Register C */ - ii_icrb0_d_u_t icrbd; /* II CRB Register D */ - ii_icrb0_e_u_t icrbe; /* II CRB Register D */ - int i; - int num_errors = 0; /* Num of errors handled */ - ioerror_t ioerror; - - nasid = hubdev_info->hdi_nasid; - - /* - * XXX - Add locking for any recovery actions - */ - /* - * Scan through all CRBs in the Hub, and handle the errors - * in any of the CRBs marked. - */ - for (i = 0; i < IIO_NUM_CRBS; i++) { - /* Check this crb entry to see if it is in error. */ - icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i)); - - if (icrbb.b_mark == 0) { - continue; - } - - icrba.ii_icrb0_a_regval = REMOTE_HUB_L(nasid, IIO_ICRB_A(i)); - - IOERROR_INIT(&ioerror); - - /* read other CRB error registers. */ - icrbc.ii_icrb0_c_regval = REMOTE_HUB_L(nasid, IIO_ICRB_C(i)); - icrbd.ii_icrb0_d_regval = REMOTE_HUB_L(nasid, IIO_ICRB_D(i)); - icrbe.ii_icrb0_e_regval = REMOTE_HUB_L(nasid, IIO_ICRB_E(i)); - - IOERROR_SETVALUE(&ioerror, errortype, icrbb.b_ecode); - - /* Check if this error is due to BTE operation, - * and handle it separately. - */ - if (icrbd.d_bteop || - ((icrbb.b_initiator == IIO_ICRB_INIT_BTE0 || - icrbb.b_initiator == IIO_ICRB_INIT_BTE1) && - (icrbb.b_imsgtype == IIO_ICRB_IMSGT_BTE || - icrbb.b_imsgtype == IIO_ICRB_IMSGT_SN1NET))) { - - int bte_num; - - if (icrbd.d_bteop) - bte_num = icrbc.c_btenum; - else /* b_initiator bit 2 gives BTE number */ - bte_num = (icrbb.b_initiator & 0x4) >> 2; - - hubiio_crb_free(hubdev_info, i); - - bte_crb_error_handler(nasid_to_cnodeid(nasid), bte_num, - i, &ioerror, icrbd.d_bteop); - num_errors++; - continue; - } - } -} - -/* - * Function : hub_error_init - * Purpose : initialize the error handling requirements for a given hub. - * Parameters : cnode, the compact nodeid. - * Assumptions : Called only once per hub, either by a local cpu. Or by a - * remote cpu, when this hub is headless.(cpuless) - * Returns : None - */ -void hub_error_init(struct hubdev_info *hubdev_info) -{ - - if (request_irq(SGI_II_ERROR, hub_eint_handler, IRQF_SHARED, - "SN_hub_error", hubdev_info)) { - printk(KERN_ERR "hub_error_init: Failed to request_irq for 0x%p\n", - hubdev_info); - return; - } - irq_set_handler(SGI_II_ERROR, handle_level_irq); - sn_set_err_irq_affinity(SGI_II_ERROR); -} - - -/* - * Function : ice_error_init - * Purpose : initialize the error handling requirements for a given tio. - * Parameters : cnode, the compact nodeid. - * Assumptions : Called only once per tio. - * Returns : None - */ -void ice_error_init(struct hubdev_info *hubdev_info) -{ - - if (request_irq - (SGI_TIO_ERROR, (void *)hub_eint_handler, IRQF_SHARED, "SN_TIO_error", - (void *)hubdev_info)) { - printk("ice_error_init: request_irq() error hubdev_info 0x%p\n", - hubdev_info); - return; - } - irq_set_handler(SGI_TIO_ERROR, handle_level_irq); - sn_set_err_irq_affinity(SGI_TIO_ERROR); -} - diff --git a/arch/ia64/sn/kernel/idle.c b/arch/ia64/sn/kernel/idle.c deleted file mode 100644 index 49d178f022b581def0c7d023fa20bfdd6e613994..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/idle.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2001-2004 Silicon Graphics, Inc. All rights reserved. - */ - -#include - -void snidle(int state) -{ - if (state) { - if (pda->idle_flag == 0) { - /* - * Turn the activity LED off. - */ - set_led_bits(0, LED_CPU_ACTIVITY); - } - - pda->idle_flag = 1; - } else { - /* - * Turn the activity LED on. - */ - set_led_bits(LED_CPU_ACTIVITY, LED_CPU_ACTIVITY); - - pda->idle_flag = 0; - } -} diff --git a/arch/ia64/sn/kernel/io_acpi_init.c b/arch/ia64/sn/kernel/io_acpi_init.c deleted file mode 100644 index c31fe637b0b43bdef72a25a175083f3ab703465e..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/io_acpi_init.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2006 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include "xtalk/hubdev.h" -#include -#include -#include - - -/* - * The code in this file will only be executed when running with - * a PROM that has ACPI IO support. (i.e., SN_ACPI_BASE_SUPPORT() == 1) - */ - - -/* - * This value must match the UUID the PROM uses - * (io/acpi/defblk.c) when building a vendor descriptor. - */ -struct acpi_vendor_uuid sn_uuid = { - .subtype = 0, - .data = { 0x2c, 0xc6, 0xa6, 0xfe, 0x9c, 0x44, 0xda, 0x11, - 0xa2, 0x7c, 0x08, 0x00, 0x69, 0x13, 0xea, 0x51 }, -}; - -struct sn_pcidev_match { - u8 bus; - unsigned int devfn; - acpi_handle handle; -}; - -/* - * Perform the early IO init in PROM. - */ -static long -sal_ioif_init(u64 *result) -{ - struct ia64_sal_retval isrv = {0,0,0,0}; - - SAL_CALL_NOLOCK(isrv, - SN_SAL_IOIF_INIT, 0, 0, 0, 0, 0, 0, 0); - *result = isrv.v0; - return isrv.status; -} - -/* - * sn_acpi_hubdev_init() - This function is called by acpi_ns_get_device_callback() - * for all SGIHUB and SGITIO acpi devices defined in the - * DSDT. It obtains the hubdev_info pointer from the - * ACPI vendor resource, which the PROM setup, and sets up the - * hubdev_info in the pda. - */ - -static acpi_status __init -sn_acpi_hubdev_init(acpi_handle handle, u32 depth, void *context, void **ret) -{ - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - u64 addr; - struct hubdev_info *hubdev; - struct hubdev_info *hubdev_ptr; - int i; - u64 nasid; - struct acpi_resource *resource; - acpi_status status; - struct acpi_resource_vendor_typed *vendor; - extern void sn_common_hubdev_init(struct hubdev_info *); - - status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS, - &sn_uuid, &buffer); - if (ACPI_FAILURE(status)) { - acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); - printk(KERN_ERR - "sn_acpi_hubdev_init: acpi_get_vendor_resource() " - "(0x%x) failed for: %s\n", status, - (char *)name_buffer.pointer); - kfree(name_buffer.pointer); - return AE_OK; /* Continue walking namespace */ - } - - resource = buffer.pointer; - vendor = &resource->data.vendor_typed; - if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) != - sizeof(struct hubdev_info *)) { - acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); - printk(KERN_ERR - "sn_acpi_hubdev_init: Invalid vendor data length: " - "%d for: %s\n", - vendor->byte_length, (char *)name_buffer.pointer); - kfree(name_buffer.pointer); - goto exit; - } - - memcpy(&addr, vendor->byte_data, sizeof(struct hubdev_info *)); - hubdev_ptr = __va((struct hubdev_info *) addr); - - nasid = hubdev_ptr->hdi_nasid; - i = nasid_to_cnodeid(nasid); - hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo); - *hubdev = *hubdev_ptr; - sn_common_hubdev_init(hubdev); - -exit: - kfree(buffer.pointer); - return AE_OK; /* Continue walking namespace */ -} - -/* - * sn_get_bussoft_ptr() - The pcibus_bussoft pointer is found in - * the ACPI Vendor resource for this bus. - */ -static struct pcibus_bussoft * -sn_get_bussoft_ptr(struct pci_bus *bus) -{ - u64 addr; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - acpi_handle handle; - struct pcibus_bussoft *prom_bussoft_ptr; - struct acpi_resource *resource; - acpi_status status; - struct acpi_resource_vendor_typed *vendor; - - - handle = acpi_device_handle(PCI_CONTROLLER(bus)->companion); - status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS, - &sn_uuid, &buffer); - if (ACPI_FAILURE(status)) { - acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); - printk(KERN_ERR "%s: " - "acpi_get_vendor_resource() failed (0x%x) for: %s\n", - __func__, status, (char *)name_buffer.pointer); - kfree(name_buffer.pointer); - return NULL; - } - resource = buffer.pointer; - vendor = &resource->data.vendor_typed; - - if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) != - sizeof(struct pcibus_bussoft *)) { - printk(KERN_ERR - "%s: Invalid vendor data length %d\n", - __func__, vendor->byte_length); - kfree(buffer.pointer); - return NULL; - } - memcpy(&addr, vendor->byte_data, sizeof(struct pcibus_bussoft *)); - prom_bussoft_ptr = __va((struct pcibus_bussoft *) addr); - kfree(buffer.pointer); - - return prom_bussoft_ptr; -} - -/* - * sn_extract_device_info - Extract the pcidev_info and the sn_irq_info - * pointers from the vendor resource using the - * provided acpi handle, and copy the structures - * into the argument buffers. - */ -static int -sn_extract_device_info(acpi_handle handle, struct pcidev_info **pcidev_info, - struct sn_irq_info **sn_irq_info) -{ - u64 addr; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct sn_irq_info *irq_info, *irq_info_prom; - struct pcidev_info *pcidev_ptr, *pcidev_prom_ptr; - struct acpi_resource *resource; - int ret = 0; - acpi_status status; - struct acpi_resource_vendor_typed *vendor; - - /* - * The pointer to this device's pcidev_info structure in - * the PROM, is in the vendor resource. - */ - status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS, - &sn_uuid, &buffer); - if (ACPI_FAILURE(status)) { - acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); - printk(KERN_ERR - "%s: acpi_get_vendor_resource() failed (0x%x) for: %s\n", - __func__, status, (char *)name_buffer.pointer); - kfree(name_buffer.pointer); - return 1; - } - - resource = buffer.pointer; - vendor = &resource->data.vendor_typed; - if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) != - sizeof(struct pci_devdev_info *)) { - acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); - printk(KERN_ERR - "%s: Invalid vendor data length: %d for: %s\n", - __func__, vendor->byte_length, - (char *)name_buffer.pointer); - kfree(name_buffer.pointer); - ret = 1; - goto exit; - } - - pcidev_ptr = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL); - if (!pcidev_ptr) - panic("%s: Unable to alloc memory for pcidev_info", __func__); - - memcpy(&addr, vendor->byte_data, sizeof(struct pcidev_info *)); - pcidev_prom_ptr = __va(addr); - memcpy(pcidev_ptr, pcidev_prom_ptr, sizeof(struct pcidev_info)); - - /* Get the IRQ info */ - irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); - if (!irq_info) - panic("%s: Unable to alloc memory for sn_irq_info", __func__); - - if (pcidev_ptr->pdi_sn_irq_info) { - irq_info_prom = __va(pcidev_ptr->pdi_sn_irq_info); - memcpy(irq_info, irq_info_prom, sizeof(struct sn_irq_info)); - } - - *pcidev_info = pcidev_ptr; - *sn_irq_info = irq_info; - -exit: - kfree(buffer.pointer); - return ret; -} - -static unsigned int -get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle) -{ - unsigned long long adr; - acpi_handle child; - unsigned int devfn; - int function; - acpi_handle parent; - int slot; - acpi_status status; - struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - - acpi_get_name(device_handle, ACPI_FULL_PATHNAME, &name_buffer); - - /* - * Do an upward search to find the root bus device, and - * obtain the host devfn from the previous child device. - */ - child = device_handle; - while (child) { - status = acpi_get_parent(child, &parent); - if (ACPI_FAILURE(status)) { - printk(KERN_ERR "%s: acpi_get_parent() failed " - "(0x%x) for: %s\n", __func__, status, - (char *)name_buffer.pointer); - panic("%s: Unable to find host devfn\n", __func__); - } - if (parent == rootbus_handle) - break; - child = parent; - } - if (!child) { - printk(KERN_ERR "%s: Unable to find root bus for: %s\n", - __func__, (char *)name_buffer.pointer); - BUG(); - } - - status = acpi_evaluate_integer(child, METHOD_NAME__ADR, NULL, &adr); - if (ACPI_FAILURE(status)) { - printk(KERN_ERR "%s: Unable to get _ADR (0x%x) for: %s\n", - __func__, status, (char *)name_buffer.pointer); - panic("%s: Unable to find host devfn\n", __func__); - } - - kfree(name_buffer.pointer); - - slot = (adr >> 16) & 0xffff; - function = adr & 0xffff; - devfn = PCI_DEVFN(slot, function); - return devfn; -} - -/* - * find_matching_device - Callback routine to find the ACPI device - * that matches up with our pci_dev device. - * Matching is done on bus number and devfn. - * To find the bus number for a particular - * ACPI device, we must look at the _BBN method - * of its parent. - */ -static acpi_status -find_matching_device(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - unsigned long long bbn = -1; - unsigned long long adr; - acpi_handle parent = NULL; - acpi_status status; - unsigned int devfn; - int function; - int slot; - struct sn_pcidev_match *info = context; - struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, - &adr); - if (ACPI_SUCCESS(status)) { - status = acpi_get_parent(handle, &parent); - if (ACPI_FAILURE(status)) { - acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); - printk(KERN_ERR - "%s: acpi_get_parent() failed (0x%x) for: %s\n", - __func__, status, (char *)name_buffer.pointer); - kfree(name_buffer.pointer); - return AE_OK; - } - status = acpi_evaluate_integer(parent, METHOD_NAME__BBN, - NULL, &bbn); - if (ACPI_FAILURE(status)) { - acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); - printk(KERN_ERR - "%s: Failed to find _BBN in parent of: %s\n", - __func__, (char *)name_buffer.pointer); - kfree(name_buffer.pointer); - return AE_OK; - } - - slot = (adr >> 16) & 0xffff; - function = adr & 0xffff; - devfn = PCI_DEVFN(slot, function); - if ((info->devfn == devfn) && (info->bus == bbn)) { - /* We have a match! */ - info->handle = handle; - return 1; - } - } - return AE_OK; -} - -/* - * sn_acpi_get_pcidev_info - Search ACPI namespace for the acpi - * device matching the specified pci_dev, - * and return the pcidev info and irq info. - */ -int -sn_acpi_get_pcidev_info(struct pci_dev *dev, struct pcidev_info **pcidev_info, - struct sn_irq_info **sn_irq_info) -{ - unsigned int host_devfn; - struct sn_pcidev_match pcidev_match; - acpi_handle rootbus_handle; - unsigned long long segment; - acpi_status status; - struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - - rootbus_handle = acpi_device_handle(PCI_CONTROLLER(dev)->companion); - status = acpi_evaluate_integer(rootbus_handle, METHOD_NAME__SEG, NULL, - &segment); - if (ACPI_SUCCESS(status)) { - if (segment != pci_domain_nr(dev)) { - acpi_get_name(rootbus_handle, ACPI_FULL_PATHNAME, - &name_buffer); - printk(KERN_ERR - "%s: Segment number mismatch, 0x%llx vs 0x%x for: %s\n", - __func__, segment, pci_domain_nr(dev), - (char *)name_buffer.pointer); - kfree(name_buffer.pointer); - return 1; - } - } else { - acpi_get_name(rootbus_handle, ACPI_FULL_PATHNAME, &name_buffer); - printk(KERN_ERR "%s: Unable to get __SEG from: %s\n", - __func__, (char *)name_buffer.pointer); - kfree(name_buffer.pointer); - return 1; - } - - /* - * We want to search all devices in this segment/domain - * of the ACPI namespace for the matching ACPI device, - * which holds the pcidev_info pointer in its vendor resource. - */ - pcidev_match.bus = dev->bus->number; - pcidev_match.devfn = dev->devfn; - pcidev_match.handle = NULL; - - acpi_walk_namespace(ACPI_TYPE_DEVICE, rootbus_handle, ACPI_UINT32_MAX, - find_matching_device, NULL, &pcidev_match, NULL); - - if (!pcidev_match.handle) { - printk(KERN_ERR - "%s: Could not find matching ACPI device for %s.\n", - __func__, pci_name(dev)); - return 1; - } - - if (sn_extract_device_info(pcidev_match.handle, pcidev_info, sn_irq_info)) - return 1; - - /* Build up the pcidev_info.pdi_slot_host_handle */ - host_devfn = get_host_devfn(pcidev_match.handle, rootbus_handle); - (*pcidev_info)->pdi_slot_host_handle = - ((unsigned long) pci_domain_nr(dev) << 40) | - /* bus == 0 */ - host_devfn; - return 0; -} - -/* - * sn_acpi_slot_fixup - Obtain the pcidev_info and sn_irq_info. - * Perform any SN specific slot fixup. - * At present there does not appear to be - * any generic way to handle a ROM image - * that has been shadowed by the PROM, so - * we pass a pointer to it within the - * pcidev_info structure. - */ - -void -sn_acpi_slot_fixup(struct pci_dev *dev) -{ - struct pcidev_info *pcidev_info = NULL; - struct sn_irq_info *sn_irq_info = NULL; - struct resource *res; - size_t size; - - if (sn_acpi_get_pcidev_info(dev, &pcidev_info, &sn_irq_info)) { - panic("%s: Failure obtaining pcidev_info for %s\n", - __func__, pci_name(dev)); - } - - if (pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]) { - /* - * A valid ROM image exists and has been shadowed by the - * PROM. Setup the pci_dev ROM resource with the address - * of the shadowed copy, and the actual length of the ROM image. - */ - size = pci_resource_len(dev, PCI_ROM_RESOURCE); - - res = &dev->resource[PCI_ROM_RESOURCE]; - - pci_disable_rom(dev); - if (res->parent) - release_resource(res); - - res->start = pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]; - res->end = res->start + size - 1; - res->flags = IORESOURCE_MEM | IORESOURCE_ROM_SHADOW | - IORESOURCE_PCI_FIXED; - } - sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info); -} -EXPORT_SYMBOL(sn_acpi_slot_fixup); - - -/* - * sn_acpi_bus_fixup - Perform SN specific setup of software structs - * (pcibus_bussoft, pcidev_info) and hardware - * registers, for the specified bus and devices under it. - */ -void -sn_acpi_bus_fixup(struct pci_bus *bus) -{ - struct pci_dev *pci_dev = NULL; - struct pcibus_bussoft *prom_bussoft_ptr; - - if (!bus->parent) { /* If root bus */ - prom_bussoft_ptr = sn_get_bussoft_ptr(bus); - if (prom_bussoft_ptr == NULL) { - printk(KERN_ERR - "%s: 0x%04x:0x%02x Unable to " - "obtain prom_bussoft_ptr\n", - __func__, pci_domain_nr(bus), bus->number); - return; - } - sn_common_bus_fixup(bus, prom_bussoft_ptr); - } - list_for_each_entry(pci_dev, &bus->devices, bus_list) { - sn_acpi_slot_fixup(pci_dev); - } -} - -/* - * sn_io_acpi_init - PROM has ACPI support for IO, defining at a minimum the - * nodes and root buses in the DSDT. As a result, bus scanning - * will be initiated by the Linux ACPI code. - */ - -void __init -sn_io_acpi_init(void) -{ - u64 result; - long status; - - /* SN Altix does not follow the IOSAPIC IRQ routing model */ - acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM; - - /* Setup hubdev_info for all SGIHUB/SGITIO devices */ - acpi_get_devices("SGIHUB", sn_acpi_hubdev_init, NULL, NULL); - acpi_get_devices("SGITIO", sn_acpi_hubdev_init, NULL, NULL); - - status = sal_ioif_init(&result); - if (status || result) - panic("sal_ioif_init failed: [%lx] %s\n", - status, ia64_sal_strerror(status)); -} diff --git a/arch/ia64/sn/kernel/io_common.c b/arch/ia64/sn/kernel/io_common.c deleted file mode 100644 index d46847323ef6a64ee02c0f4aca2ed494e1c534c9..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/io_common.c +++ /dev/null @@ -1,561 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2006 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "xtalk/hubdev.h" -#include "xtalk/xwidgetdev.h" -#include -#include -#include - -extern void sn_init_cpei_timer(void); -extern void register_sn_procfs(void); -extern void sn_io_acpi_init(void); -extern void sn_io_init(void); - - -static struct list_head sn_sysdata_list; - -/* sysdata list struct */ -struct sysdata_el { - struct list_head entry; - void *sysdata; -}; - -int sn_ioif_inited; /* SN I/O infrastructure initialized? */ - -int sn_acpi_rev; /* SN ACPI revision */ -EXPORT_SYMBOL_GPL(sn_acpi_rev); - -struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES]; /* indexed by asic type */ - -/* - * Hooks and struct for unsupported pci providers - */ - -static dma_addr_t -sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size, int type) -{ - return 0; -} - -static void -sn_default_pci_unmap(struct pci_dev *pdev, dma_addr_t addr, int direction) -{ - return; -} - -static void * -sn_default_pci_bus_fixup(struct pcibus_bussoft *soft, struct pci_controller *controller) -{ - return NULL; -} - -static struct sn_pcibus_provider sn_pci_default_provider = { - .dma_map = sn_default_pci_map, - .dma_map_consistent = sn_default_pci_map, - .dma_unmap = sn_default_pci_unmap, - .bus_fixup = sn_default_pci_bus_fixup, -}; - -/* - * Retrieve the DMA Flush List given nasid, widget, and device. - * This list is needed to implement the WAR - Flush DMA data on PIO Reads. - */ -static inline u64 -sal_get_device_dmaflush_list(u64 nasid, u64 widget_num, u64 device_num, - u64 address) -{ - struct ia64_sal_retval ret_stuff; - ret_stuff.status = 0; - ret_stuff.v0 = 0; - - SAL_CALL_NOLOCK(ret_stuff, - (u64) SN_SAL_IOIF_GET_DEVICE_DMAFLUSH_LIST, - (u64) nasid, (u64) widget_num, - (u64) device_num, (u64) address, 0, 0, 0); - return ret_stuff.status; -} - -/* - * sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified - * device. - */ -inline struct pcidev_info * -sn_pcidev_info_get(struct pci_dev *dev) -{ - struct pcidev_info *pcidev; - - list_for_each_entry(pcidev, - &(SN_PLATFORM_DATA(dev)->pcidev_info), pdi_list) { - if (pcidev->pdi_linux_pcidev == dev) - return pcidev; - } - return NULL; -} - -/* Older PROM flush WAR - * - * 01/16/06 -- This war will be in place until a new official PROM is released. - * Additionally note that the struct sn_flush_device_war also has to be - * removed from arch/ia64/sn/include/xtalk/hubdev.h - */ - -static s64 sn_device_fixup_war(u64 nasid, u64 widget, int device, - struct sn_flush_device_common *common) -{ - struct sn_flush_device_war *war_list; - struct sn_flush_device_war *dev_entry; - struct ia64_sal_retval isrv = {0,0,0,0}; - - printk_once(KERN_WARNING - "PROM version < 4.50 -- implementing old PROM flush WAR\n"); - - war_list = kcalloc(DEV_PER_WIDGET, sizeof(*war_list), GFP_KERNEL); - BUG_ON(!war_list); - - SAL_CALL_NOLOCK(isrv, SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST, - nasid, widget, __pa(war_list), 0, 0, 0 ,0); - if (isrv.status) - panic("sn_device_fixup_war failed: %s\n", - ia64_sal_strerror(isrv.status)); - - dev_entry = war_list + device; - memcpy(common,dev_entry, sizeof(*common)); - kfree(war_list); - - return isrv.status; -} - -/* - * sn_common_hubdev_init() - This routine is called to initialize the HUB data - * structure for each node in the system. - */ -void __init -sn_common_hubdev_init(struct hubdev_info *hubdev) -{ - - struct sn_flush_device_kernel *sn_flush_device_kernel; - struct sn_flush_device_kernel *dev_entry; - s64 status; - int widget, device, size; - - /* Attach the error interrupt handlers */ - if (hubdev->hdi_nasid & 1) /* If TIO */ - ice_error_init(hubdev); - else - hub_error_init(hubdev); - - for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) - hubdev->hdi_xwidget_info[widget].xwi_hubinfo = hubdev; - - if (!hubdev->hdi_flush_nasid_list.widget_p) - return; - - size = (HUB_WIDGET_ID_MAX + 1) * - sizeof(struct sn_flush_device_kernel *); - hubdev->hdi_flush_nasid_list.widget_p = - kzalloc(size, GFP_KERNEL); - BUG_ON(!hubdev->hdi_flush_nasid_list.widget_p); - - for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) { - size = DEV_PER_WIDGET * - sizeof(struct sn_flush_device_kernel); - sn_flush_device_kernel = kzalloc(size, GFP_KERNEL); - BUG_ON(!sn_flush_device_kernel); - - dev_entry = sn_flush_device_kernel; - for (device = 0; device < DEV_PER_WIDGET; - device++, dev_entry++) { - size = sizeof(struct sn_flush_device_common); - dev_entry->common = kzalloc(size, GFP_KERNEL); - BUG_ON(!dev_entry->common); - if (sn_prom_feature_available(PRF_DEVICE_FLUSH_LIST)) - status = sal_get_device_dmaflush_list( - hubdev->hdi_nasid, widget, device, - (u64)(dev_entry->common)); - else - status = sn_device_fixup_war(hubdev->hdi_nasid, - widget, device, - dev_entry->common); - if (status != SALRET_OK) - panic("SAL call failed: %s\n", - ia64_sal_strerror(status)); - - spin_lock_init(&dev_entry->sfdl_flush_lock); - } - - if (sn_flush_device_kernel) - hubdev->hdi_flush_nasid_list.widget_p[widget] = - sn_flush_device_kernel; - } -} - -void sn_pci_unfixup_slot(struct pci_dev *dev) -{ - struct pci_dev *host_pci_dev = SN_PCIDEV_INFO(dev)->host_pci_dev; - - sn_irq_unfixup(dev); - pci_dev_put(host_pci_dev); - pci_dev_put(dev); -} - -/* - * sn_pci_fixup_slot() - */ -void sn_pci_fixup_slot(struct pci_dev *dev, struct pcidev_info *pcidev_info, - struct sn_irq_info *sn_irq_info) -{ - int segment = pci_domain_nr(dev->bus); - struct pcibus_bussoft *bs; - struct pci_dev *host_pci_dev; - unsigned int bus_no, devfn; - - pci_dev_get(dev); /* for the sysdata pointer */ - - /* Add pcidev_info to list in pci_controller.platform_data */ - list_add_tail(&pcidev_info->pdi_list, - &(SN_PLATFORM_DATA(dev->bus)->pcidev_info)); - /* - * Using the PROMs values for the PCI host bus, get the Linux - * PCI host_pci_dev struct and set up host bus linkages - */ - - bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff; - devfn = pcidev_info->pdi_slot_host_handle & 0xffffffff; - host_pci_dev = pci_get_domain_bus_and_slot(segment, bus_no, devfn); - - pcidev_info->host_pci_dev = host_pci_dev; - pcidev_info->pdi_linux_pcidev = dev; - pcidev_info->pdi_host_pcidev_info = SN_PCIDEV_INFO(host_pci_dev); - bs = SN_PCIBUS_BUSSOFT(dev->bus); - pcidev_info->pdi_pcibus_info = bs; - - if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) { - SN_PCIDEV_BUSPROVIDER(dev) = sn_pci_provider[bs->bs_asic_type]; - } else { - SN_PCIDEV_BUSPROVIDER(dev) = &sn_pci_default_provider; - } - - /* Only set up IRQ stuff if this device has a host bus context */ - if (bs && sn_irq_info->irq_irq) { - pcidev_info->pdi_sn_irq_info = sn_irq_info; - dev->irq = pcidev_info->pdi_sn_irq_info->irq_irq; - sn_irq_fixup(dev, sn_irq_info); - } else { - pcidev_info->pdi_sn_irq_info = NULL; - kfree(sn_irq_info); - } -} - -/* - * sn_common_bus_fixup - Perform platform specific bus fixup. - * Execute the ASIC specific fixup routine - * for this bus. - */ -void -sn_common_bus_fixup(struct pci_bus *bus, - struct pcibus_bussoft *prom_bussoft_ptr) -{ - int cnode; - struct pci_controller *controller; - struct hubdev_info *hubdev_info; - int nasid; - void *provider_soft; - struct sn_pcibus_provider *provider; - struct sn_platform_data *sn_platform_data; - - controller = PCI_CONTROLLER(bus); - /* - * Per-provider fixup. Copies the bus soft structure from prom - * to local area and links SN_PCIBUS_BUSSOFT(). - */ - - if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) { - printk(KERN_WARNING "sn_common_bus_fixup: Unsupported asic type, %d", - prom_bussoft_ptr->bs_asic_type); - return; - } - - if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB) - return; /* no further fixup necessary */ - - provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type]; - if (provider == NULL) - panic("sn_common_bus_fixup: No provider registered for this asic type, %d", - prom_bussoft_ptr->bs_asic_type); - - if (provider->bus_fixup) - provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr, - controller); - else - provider_soft = NULL; - - /* - * Generic bus fixup goes here. Don't reference prom_bussoft_ptr - * after this point. - */ - controller->platform_data = kzalloc(sizeof(struct sn_platform_data), - GFP_KERNEL); - BUG_ON(controller->platform_data == NULL); - sn_platform_data = - (struct sn_platform_data *) controller->platform_data; - sn_platform_data->provider_soft = provider_soft; - INIT_LIST_HEAD(&((struct sn_platform_data *) - controller->platform_data)->pcidev_info); - nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base); - cnode = nasid_to_cnodeid(nasid); - hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); - SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info = - &(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]); - - /* - * If the node information we obtained during the fixup phase is - * invalid then set controller->node to -1 (undetermined) - */ - if (controller->node >= num_online_nodes()) { - struct pcibus_bussoft *b = SN_PCIBUS_BUSSOFT(bus); - - printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%u " - "L_IO=%llx L_MEM=%llx BASE=%llx\n", - b->bs_asic_type, b->bs_xid, b->bs_persist_busnum, - b->bs_legacy_io, b->bs_legacy_mem, b->bs_base); - printk(KERN_WARNING "on node %d but only %d nodes online." - "Association set to undetermined.\n", - controller->node, num_online_nodes()); - controller->node = -1; - } -} - -void sn_bus_store_sysdata(struct pci_dev *dev) -{ - struct sysdata_el *element; - - element = kzalloc(sizeof(struct sysdata_el), GFP_KERNEL); - if (!element) { - dev_dbg(&dev->dev, "%s: out of memory!\n", __func__); - return; - } - element->sysdata = SN_PCIDEV_INFO(dev); - list_add(&element->entry, &sn_sysdata_list); -} - -void sn_bus_free_sysdata(void) -{ - struct sysdata_el *element; - struct list_head *list, *safe; - - list_for_each_safe(list, safe, &sn_sysdata_list) { - element = list_entry(list, struct sysdata_el, entry); - list_del(&element->entry); - list_del(&(((struct pcidev_info *) - (element->sysdata))->pdi_list)); - kfree(element->sysdata); - kfree(element); - } - return; -} - -/* - * hubdev_init_node() - Creates the HUB data structure and link them to it's - * own NODE specific data area. - */ -void __init hubdev_init_node(nodepda_t * npda, cnodeid_t node) -{ - struct hubdev_info *hubdev_info; - int size; - - size = sizeof(struct hubdev_info); - - if (node >= num_online_nodes()) /* Headless/memless IO nodes */ - node = 0; - - hubdev_info = (struct hubdev_info *)memblock_alloc_node(size, - SMP_CACHE_BYTES, - node); - if (!hubdev_info) - panic("%s: Failed to allocate %d bytes align=0x%x nid=%d\n", - __func__, size, SMP_CACHE_BYTES, node); - - npda->pdinfo = (void *)hubdev_info; -} - -geoid_t -cnodeid_get_geoid(cnodeid_t cnode) -{ - struct hubdev_info *hubdev; - - hubdev = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); - return hubdev->hdi_geoid; -} - -void sn_generate_path(struct pci_bus *pci_bus, char *address) -{ - nasid_t nasid; - cnodeid_t cnode; - geoid_t geoid; - moduleid_t moduleid; - u16 bricktype; - - nasid = NASID_GET(SN_PCIBUS_BUSSOFT(pci_bus)->bs_base); - cnode = nasid_to_cnodeid(nasid); - geoid = cnodeid_get_geoid(cnode); - moduleid = geo_module(geoid); - - sprintf(address, "module_%c%c%c%c%.2d", - '0'+RACK_GET_CLASS(MODULE_GET_RACK(moduleid)), - '0'+RACK_GET_GROUP(MODULE_GET_RACK(moduleid)), - '0'+RACK_GET_NUM(MODULE_GET_RACK(moduleid)), - MODULE_GET_BTCHAR(moduleid), MODULE_GET_BPOS(moduleid)); - - /* Tollhouse requires slot id to be displayed */ - bricktype = MODULE_GET_BTYPE(moduleid); - if ((bricktype == L1_BRICKTYPE_191010) || - (bricktype == L1_BRICKTYPE_1932)) - sprintf(address + strlen(address), "^%d", - geo_slot(geoid)); -} - -void sn_pci_fixup_bus(struct pci_bus *bus) -{ - - if (SN_ACPI_BASE_SUPPORT()) - sn_acpi_bus_fixup(bus); - else - sn_bus_fixup(bus); -} - -/* - * sn_io_early_init - Perform early IO (and some non-IO) initialization. - * In particular, setup the sn_pci_provider[] array. - * This needs to be done prior to any bus scanning - * (acpi_scan_init()) in the ACPI case, as the SN - * bus fixup code will reference the array. - */ -static int __init -sn_io_early_init(void) -{ - int i; - - if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM()) - return 0; - - /* we set the acpi revision to that of the DSDT table OEM rev. */ - { - struct acpi_table_header *header = NULL; - - acpi_get_table(ACPI_SIG_DSDT, 1, &header); - BUG_ON(header == NULL); - sn_acpi_rev = header->oem_revision; - } - - /* - * prime sn_pci_provider[]. Individual provider init routines will - * override their respective default entries. - */ - - for (i = 0; i < PCIIO_ASIC_MAX_TYPES; i++) - sn_pci_provider[i] = &sn_pci_default_provider; - - pcibr_init_provider(); - tioca_init_provider(); - tioce_init_provider(); - - sn_irq_lh_init(); - INIT_LIST_HEAD(&sn_sysdata_list); - sn_init_cpei_timer(); - -#ifdef CONFIG_PROC_FS - register_sn_procfs(); -#endif - - { - struct acpi_table_header *header; - (void)acpi_get_table(ACPI_SIG_DSDT, 1, &header); - printk(KERN_INFO "ACPI DSDT OEM Rev 0x%x\n", - header->oem_revision); - } - if (SN_ACPI_BASE_SUPPORT()) - sn_io_acpi_init(); - else - sn_io_init(); - return 0; -} - -arch_initcall(sn_io_early_init); - -/* - * sn_io_late_init() - Perform any final platform specific IO initialization. - */ - -int __init -sn_io_late_init(void) -{ - struct pci_bus *bus; - struct pcibus_bussoft *bussoft; - cnodeid_t cnode; - nasid_t nasid; - cnodeid_t near_cnode; - - if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM()) - return 0; - - /* - * Setup closest node in pci_controller->node for - * PIC, TIOCP, TIOCE (TIOCA does it during bus fixup using - * info from the PROM). - */ - bus = NULL; - while ((bus = pci_find_next_bus(bus)) != NULL) { - bussoft = SN_PCIBUS_BUSSOFT(bus); - nasid = NASID_GET(bussoft->bs_base); - cnode = nasid_to_cnodeid(nasid); - if ((bussoft->bs_asic_type == PCIIO_ASIC_TYPE_TIOCP) || - (bussoft->bs_asic_type == PCIIO_ASIC_TYPE_TIOCE) || - (bussoft->bs_asic_type == PCIIO_ASIC_TYPE_PIC)) { - /* PCI Bridge: find nearest node with CPUs */ - int e = sn_hwperf_get_nearest_node(cnode, NULL, - &near_cnode); - if (e < 0) { - near_cnode = (cnodeid_t)-1; /* use any node */ - printk(KERN_WARNING "sn_io_late_init: failed " - "to find near node with CPUs for " - "node %d, err=%d\n", cnode, e); - } - PCI_CONTROLLER(bus)->node = near_cnode; - } - } - - sn_ioif_inited = 1; /* SN I/O infrastructure now initialized */ - - return 0; -} - -fs_initcall(sn_io_late_init); - -EXPORT_SYMBOL(sn_pci_unfixup_slot); -EXPORT_SYMBOL(sn_bus_store_sysdata); -EXPORT_SYMBOL(sn_bus_free_sysdata); -EXPORT_SYMBOL(sn_generate_path); - diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c deleted file mode 100644 index d63809a6adfadbd87e4b3ad0cbf658de05d3bf45..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/io_init.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2006 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "xtalk/hubdev.h" - -/* - * The code in this file will only be executed when running with - * a PROM that does _not_ have base ACPI IO support. - * (i.e., SN_ACPI_BASE_SUPPORT() == 0) - */ - -static int max_segment_number; /* Default highest segment number */ -static int max_pcibus_number = 255; /* Default highest pci bus number */ - - -/* - * Retrieve the hub device info structure for the given nasid. - */ -static inline u64 sal_get_hubdev_info(u64 handle, u64 address) -{ - struct ia64_sal_retval ret_stuff; - ret_stuff.status = 0; - ret_stuff.v0 = 0; - - SAL_CALL_NOLOCK(ret_stuff, - (u64) SN_SAL_IOIF_GET_HUBDEV_INFO, - (u64) handle, (u64) address, 0, 0, 0, 0, 0); - return ret_stuff.v0; -} - -/* - * Retrieve the pci bus information given the bus number. - */ -static inline u64 sal_get_pcibus_info(u64 segment, u64 busnum, u64 address) -{ - struct ia64_sal_retval ret_stuff; - ret_stuff.status = 0; - ret_stuff.v0 = 0; - - SAL_CALL_NOLOCK(ret_stuff, - (u64) SN_SAL_IOIF_GET_PCIBUS_INFO, - (u64) segment, (u64) busnum, (u64) address, 0, 0, 0, 0); - return ret_stuff.v0; -} - -/* - * Retrieve the pci device information given the bus and device|function number. - */ -static inline u64 -sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, - u64 sn_irq_info) -{ - struct ia64_sal_retval ret_stuff; - ret_stuff.status = 0; - ret_stuff.v0 = 0; - - SAL_CALL_NOLOCK(ret_stuff, - (u64) SN_SAL_IOIF_GET_PCIDEV_INFO, - (u64) segment, (u64) bus_number, (u64) devfn, - (u64) pci_dev, - sn_irq_info, 0, 0); - return ret_stuff.v0; -} - - -/* - * sn_fixup_ionodes() - This routine initializes the HUB data structure for - * each node in the system. This function is only - * executed when running with a non-ACPI capable PROM. - */ -static void __init sn_fixup_ionodes(void) -{ - - struct hubdev_info *hubdev; - u64 status; - u64 nasid; - int i; - extern void sn_common_hubdev_init(struct hubdev_info *); - - /* - * Get SGI Specific HUB chipset information. - * Inform Prom that this kernel can support domain bus numbering. - */ - for (i = 0; i < num_cnodes; i++) { - hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo); - nasid = cnodeid_to_nasid(i); - hubdev->max_segment_number = 0xffffffff; - hubdev->max_pcibus_number = 0xff; - status = sal_get_hubdev_info(nasid, (u64) __pa(hubdev)); - if (status) - continue; - - /* Save the largest Domain and pcibus numbers found. */ - if (hubdev->max_segment_number) { - /* - * Dealing with a Prom that supports segments. - */ - max_segment_number = hubdev->max_segment_number; - max_pcibus_number = hubdev->max_pcibus_number; - } - sn_common_hubdev_init(hubdev); - } -} - -/* - * sn_pci_legacy_window_fixup - Setup PCI resources for - * legacy IO and MEM space. This needs to - * be done here, as the PROM does not have - * ACPI support defining the root buses - * and their resources (_CRS), - */ -static void -sn_legacy_pci_window_fixup(struct resource *res, - u64 legacy_io, u64 legacy_mem) -{ - res[0].name = "legacy_io"; - res[0].flags = IORESOURCE_IO; - res[0].start = legacy_io; - res[0].end = res[0].start + 0xffff; - res[0].parent = &ioport_resource; - res[1].name = "legacy_mem"; - res[1].flags = IORESOURCE_MEM; - res[1].start = legacy_mem; - res[1].end = res[1].start + (1024 * 1024) - 1; - res[1].parent = &iomem_resource; -} - -/* - * sn_io_slot_fixup() - We are not running with an ACPI capable PROM, - * and need to convert the pci_dev->resource - * 'start' and 'end' addresses to mapped addresses, - * and setup the pci_controller->window array entries. - */ -void -sn_io_slot_fixup(struct pci_dev *dev) -{ - int idx; - struct resource *res; - unsigned long size; - struct pcidev_info *pcidev_info; - struct sn_irq_info *sn_irq_info; - int status; - - pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL); - if (!pcidev_info) - panic("%s: Unable to alloc memory for pcidev_info", __func__); - - sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); - if (!sn_irq_info) - panic("%s: Unable to alloc memory for sn_irq_info", __func__); - - /* Call to retrieve pci device information needed by kernel. */ - status = sal_get_pcidev_info((u64) pci_domain_nr(dev), - (u64) dev->bus->number, - dev->devfn, - (u64) __pa(pcidev_info), - (u64) __pa(sn_irq_info)); - - BUG_ON(status); /* Cannot get platform pci device information */ - - - /* Copy over PIO Mapped Addresses */ - for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) { - if (!pcidev_info->pdi_pio_mapped_addr[idx]) - continue; - - res = &dev->resource[idx]; - - size = res->end - res->start; - if (size == 0) - continue; - - res->start = pcidev_info->pdi_pio_mapped_addr[idx]; - res->end = res->start + size; - - /* - * if it's already in the device structure, remove it before - * inserting - */ - if (res->parent && res->parent->child) - release_resource(res); - - if (res->flags & IORESOURCE_IO) - insert_resource(&ioport_resource, res); - else - insert_resource(&iomem_resource, res); - /* - * If ROM, mark as shadowed in PROM. - */ - if (idx == PCI_ROM_RESOURCE) { - pci_disable_rom(dev); - res->flags = IORESOURCE_MEM | IORESOURCE_ROM_SHADOW | - IORESOURCE_PCI_FIXED; - } - } - - sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info); -} -EXPORT_SYMBOL(sn_io_slot_fixup); - -/* - * sn_pci_controller_fixup() - This routine sets up a bus's resources - * consistent with the Linux PCI abstraction layer. - */ -static void __init -sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) -{ - s64 status = 0; - struct pci_controller *controller; - struct pcibus_bussoft *prom_bussoft_ptr; - struct resource *res; - LIST_HEAD(resources); - - status = sal_get_pcibus_info((u64) segment, (u64) busnum, - (u64) ia64_tpa(&prom_bussoft_ptr)); - if (status > 0) - return; /*bus # does not exist */ - prom_bussoft_ptr = __va(prom_bussoft_ptr); - - controller = kzalloc(sizeof(*controller), GFP_KERNEL); - BUG_ON(!controller); - controller->segment = segment; - - res = kcalloc(2, sizeof(struct resource), GFP_KERNEL); - BUG_ON(!res); - - /* - * Temporarily save the prom_bussoft_ptr for use by sn_bus_fixup(). - * (platform_data will be overwritten later in sn_common_bus_fixup()) - */ - controller->platform_data = prom_bussoft_ptr; - - sn_legacy_pci_window_fixup(res, - prom_bussoft_ptr->bs_legacy_io, - prom_bussoft_ptr->bs_legacy_mem); - pci_add_resource_offset(&resources, &res[0], - prom_bussoft_ptr->bs_legacy_io); - pci_add_resource_offset(&resources, &res[1], - prom_bussoft_ptr->bs_legacy_mem); - - bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, controller, - &resources); - if (bus == NULL) { - kfree(res); - kfree(controller); - return; - } - pci_bus_add_devices(bus); -} - -/* - * sn_bus_fixup - */ -void -sn_bus_fixup(struct pci_bus *bus) -{ - struct pci_dev *pci_dev = NULL; - struct pcibus_bussoft *prom_bussoft_ptr; - - if (!bus->parent) { /* If root bus */ - prom_bussoft_ptr = PCI_CONTROLLER(bus)->platform_data; - if (prom_bussoft_ptr == NULL) { - printk(KERN_ERR - "sn_bus_fixup: 0x%04x:0x%02x Unable to " - "obtain prom_bussoft_ptr\n", - pci_domain_nr(bus), bus->number); - return; - } - sn_common_bus_fixup(bus, prom_bussoft_ptr); - } - list_for_each_entry(pci_dev, &bus->devices, bus_list) { - sn_io_slot_fixup(pci_dev); - } - -} - -/* - * sn_io_init - PROM does not have ACPI support to define nodes or root buses, - * so we need to do things the hard way, including initiating the - * bus scanning ourselves. - */ - -void __init sn_io_init(void) -{ - int i, j; - - sn_fixup_ionodes(); - - /* busses are not known yet ... */ - for (i = 0; i <= max_segment_number; i++) - for (j = 0; j <= max_pcibus_number; j++) - sn_pci_controller_fixup(i, j, NULL); -} diff --git a/arch/ia64/sn/kernel/iomv.c b/arch/ia64/sn/kernel/iomv.c deleted file mode 100644 index 2b22a71663c10e3469a00d429e147baac5538740..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/iomv.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2003, 2006 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define IS_LEGACY_VGA_IOPORT(p) \ - (((p) >= 0x3b0 && (p) <= 0x3bb) || ((p) >= 0x3c0 && (p) <= 0x3df)) - -/** - * sn_io_addr - convert an in/out port to an i/o address - * @port: port to convert - * - * Legacy in/out instructions are converted to ld/st instructions - * on IA64. This routine will convert a port number into a valid - * SN i/o address. Used by sn_in*() and sn_out*(). - */ - -void *sn_io_addr(unsigned long port) -{ - if (!IS_RUNNING_ON_SIMULATOR()) { - if (IS_LEGACY_VGA_IOPORT(port)) - return (__ia64_mk_io_addr(port)); - /* On sn2, legacy I/O ports don't point at anything */ - if (port < (64 * 1024)) - return NULL; - if (SN_ACPI_BASE_SUPPORT()) - return (__ia64_mk_io_addr(port)); - else - return ((void *)(port | __IA64_UNCACHED_OFFSET)); - } else { - /* but the simulator uses them... */ - unsigned long addr; - - /* - * word align port, but need more than 10 bits - * for accessing registers in bedrock local block - * (so we don't do port&0xfff) - */ - addr = (is_shub2() ? 0xc00000028c000000UL : 0xc0000087cc000000UL) | ((port >> 2) << 12); - if ((port >= 0x1f0 && port <= 0x1f7) || port == 0x3f6 || port == 0x3f7) - addr |= port; - return (void *)addr; - } -} - -EXPORT_SYMBOL(sn_io_addr); - -/** - * __sn_mmiowb - I/O space memory barrier - * - * See arch/ia64/include/asm/io.h and Documentation/driver-api/device-io.rst - * for details. - * - * On SN2, we wait for the PIO_WRITE_STATUS SHub register to clear. - * See PV 871084 for details about the WAR about zero value. - * - */ -void __sn_mmiowb(void) -{ - volatile unsigned long *adr = pda->pio_write_status_addr; - unsigned long val = pda->pio_write_status_val; - - while ((*adr & SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK) != val) - cpu_relax(); -} - -EXPORT_SYMBOL(__sn_mmiowb); diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c deleted file mode 100644 index d9b576df4f826c0c672d6a5d9164272f6aafa131..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/irq.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Platform dependent support for SGI SN - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2000-2008 Silicon Graphics, Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void register_intr_pda(struct sn_irq_info *sn_irq_info); -static void unregister_intr_pda(struct sn_irq_info *sn_irq_info); - -extern int sn_ioif_inited; -struct list_head **sn_irq_lh; -static DEFINE_SPINLOCK(sn_irq_info_lock); /* non-IRQ lock */ - -u64 sn_intr_alloc(nasid_t local_nasid, int local_widget, - struct sn_irq_info *sn_irq_info, - int req_irq, nasid_t req_nasid, - int req_slice) -{ - struct ia64_sal_retval ret_stuff; - ret_stuff.status = 0; - ret_stuff.v0 = 0; - - SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT, - (u64) SAL_INTR_ALLOC, (u64) local_nasid, - (u64) local_widget, __pa(sn_irq_info), (u64) req_irq, - (u64) req_nasid, (u64) req_slice); - - return ret_stuff.status; -} - -void sn_intr_free(nasid_t local_nasid, int local_widget, - struct sn_irq_info *sn_irq_info) -{ - struct ia64_sal_retval ret_stuff; - ret_stuff.status = 0; - ret_stuff.v0 = 0; - - SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT, - (u64) SAL_INTR_FREE, (u64) local_nasid, - (u64) local_widget, (u64) sn_irq_info->irq_irq, - (u64) sn_irq_info->irq_cookie, 0, 0); -} - -u64 sn_intr_redirect(nasid_t local_nasid, int local_widget, - struct sn_irq_info *sn_irq_info, - nasid_t req_nasid, int req_slice) -{ - struct ia64_sal_retval ret_stuff; - ret_stuff.status = 0; - ret_stuff.v0 = 0; - - SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT, - (u64) SAL_INTR_REDIRECT, (u64) local_nasid, - (u64) local_widget, __pa(sn_irq_info), - (u64) req_nasid, (u64) req_slice, 0); - - return ret_stuff.status; -} - -static unsigned int sn_startup_irq(struct irq_data *data) -{ - return 0; -} - -static void sn_shutdown_irq(struct irq_data *data) -{ -} - -extern void ia64_mca_register_cpev(int); - -static void sn_disable_irq(struct irq_data *data) -{ - if (data->irq == local_vector_to_irq(IA64_CPE_VECTOR)) - ia64_mca_register_cpev(0); -} - -static void sn_enable_irq(struct irq_data *data) -{ - if (data->irq == local_vector_to_irq(IA64_CPE_VECTOR)) - ia64_mca_register_cpev(data->irq); -} - -static void sn_ack_irq(struct irq_data *data) -{ - u64 event_occurred, mask; - unsigned int irq = data->irq & 0xff; - - event_occurred = HUB_L((u64*)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED)); - mask = event_occurred & SH_ALL_INT_MASK; - HUB_S((u64*)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS), mask); - __set_bit(irq, (volatile void *)pda->sn_in_service_ivecs); - - irq_move_irq(data); -} - -struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info, - nasid_t nasid, int slice) -{ - int vector; - int cpuid; -#ifdef CONFIG_SMP - int cpuphys; -#endif - int64_t bridge; - int local_widget, status; - nasid_t local_nasid; - struct sn_irq_info *new_irq_info; - struct sn_pcibus_provider *pci_provider; - - bridge = (u64) sn_irq_info->irq_bridge; - if (!bridge) { - return NULL; /* irq is not a device interrupt */ - } - - local_nasid = NASID_GET(bridge); - - if (local_nasid & 1) - local_widget = TIO_SWIN_WIDGETNUM(bridge); - else - local_widget = SWIN_WIDGETNUM(bridge); - vector = sn_irq_info->irq_irq; - - /* Make use of SAL_INTR_REDIRECT if PROM supports it */ - status = sn_intr_redirect(local_nasid, local_widget, sn_irq_info, nasid, slice); - if (!status) { - new_irq_info = sn_irq_info; - goto finish_up; - } - - /* - * PROM does not support SAL_INTR_REDIRECT, or it failed. - * Revert to old method. - */ - new_irq_info = kmemdup(sn_irq_info, sizeof(struct sn_irq_info), - GFP_ATOMIC); - if (new_irq_info == NULL) - return NULL; - - /* Free the old PROM new_irq_info structure */ - sn_intr_free(local_nasid, local_widget, new_irq_info); - unregister_intr_pda(new_irq_info); - - /* allocate a new PROM new_irq_info struct */ - status = sn_intr_alloc(local_nasid, local_widget, - new_irq_info, vector, - nasid, slice); - - /* SAL call failed */ - if (status) { - kfree(new_irq_info); - return NULL; - } - - register_intr_pda(new_irq_info); - spin_lock(&sn_irq_info_lock); - list_replace_rcu(&sn_irq_info->list, &new_irq_info->list); - spin_unlock(&sn_irq_info_lock); - kfree_rcu(sn_irq_info, rcu); - - -finish_up: - /* Update kernels new_irq_info with new target info */ - cpuid = nasid_slice_to_cpuid(new_irq_info->irq_nasid, - new_irq_info->irq_slice); - new_irq_info->irq_cpuid = cpuid; - - pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type]; - - /* - * If this represents a line interrupt, target it. If it's - * an msi (irq_int_bit < 0), it's already targeted. - */ - if (new_irq_info->irq_int_bit >= 0 && - pci_provider && pci_provider->target_interrupt) - (pci_provider->target_interrupt)(new_irq_info); - -#ifdef CONFIG_SMP - cpuphys = cpu_physical_id(cpuid); - set_irq_affinity_info((vector & 0xff), cpuphys, 0); -#endif - - return new_irq_info; -} - -static int sn_set_affinity_irq(struct irq_data *data, - const struct cpumask *mask, bool force) -{ - struct sn_irq_info *sn_irq_info, *sn_irq_info_safe; - unsigned int irq = data->irq; - nasid_t nasid; - int slice; - - nasid = cpuid_to_nasid(cpumask_first_and(mask, cpu_online_mask)); - slice = cpuid_to_slice(cpumask_first_and(mask, cpu_online_mask)); - - list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe, - sn_irq_lh[irq], list) - (void)sn_retarget_vector(sn_irq_info, nasid, slice); - - return 0; -} - -#ifdef CONFIG_SMP -void sn_set_err_irq_affinity(unsigned int irq) -{ - /* - * On systems which support CPU disabling (SHub2), all error interrupts - * are targeted at the boot CPU. - */ - if (is_shub2() && sn_prom_feature_available(PRF_CPU_DISABLE_SUPPORT)) - set_irq_affinity_info(irq, cpu_physical_id(0), 0); -} -#else -void sn_set_err_irq_affinity(unsigned int irq) { } -#endif - -static void -sn_mask_irq(struct irq_data *data) -{ -} - -static void -sn_unmask_irq(struct irq_data *data) -{ -} - -struct irq_chip irq_type_sn = { - .name = "SN hub", - .irq_startup = sn_startup_irq, - .irq_shutdown = sn_shutdown_irq, - .irq_enable = sn_enable_irq, - .irq_disable = sn_disable_irq, - .irq_ack = sn_ack_irq, - .irq_mask = sn_mask_irq, - .irq_unmask = sn_unmask_irq, - .irq_set_affinity = sn_set_affinity_irq -}; - -ia64_vector sn_irq_to_vector(int irq) -{ - if (irq >= IA64_NUM_VECTORS) - return 0; - return (ia64_vector)irq; -} - -unsigned int sn_local_vector_to_irq(u8 vector) -{ - return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector)); -} - -void sn_irq_init(void) -{ - int i; - - ia64_first_device_vector = IA64_SN2_FIRST_DEVICE_VECTOR; - ia64_last_device_vector = IA64_SN2_LAST_DEVICE_VECTOR; - - for (i = 0; i < NR_IRQS; i++) { - if (irq_get_chip(i) == &no_irq_chip) - irq_set_chip(i, &irq_type_sn); - } -} - -static void register_intr_pda(struct sn_irq_info *sn_irq_info) -{ - int irq = sn_irq_info->irq_irq; - int cpu = sn_irq_info->irq_cpuid; - - if (pdacpu(cpu)->sn_last_irq < irq) { - pdacpu(cpu)->sn_last_irq = irq; - } - - if (pdacpu(cpu)->sn_first_irq == 0 || pdacpu(cpu)->sn_first_irq > irq) - pdacpu(cpu)->sn_first_irq = irq; -} - -static void unregister_intr_pda(struct sn_irq_info *sn_irq_info) -{ - int irq = sn_irq_info->irq_irq; - int cpu = sn_irq_info->irq_cpuid; - struct sn_irq_info *tmp_irq_info; - int i, foundmatch; - - rcu_read_lock(); - if (pdacpu(cpu)->sn_last_irq == irq) { - foundmatch = 0; - for (i = pdacpu(cpu)->sn_last_irq - 1; - i && !foundmatch; i--) { - list_for_each_entry_rcu(tmp_irq_info, - sn_irq_lh[i], - list) { - if (tmp_irq_info->irq_cpuid == cpu) { - foundmatch = 1; - break; - } - } - } - pdacpu(cpu)->sn_last_irq = i; - } - - if (pdacpu(cpu)->sn_first_irq == irq) { - foundmatch = 0; - for (i = pdacpu(cpu)->sn_first_irq + 1; - i < NR_IRQS && !foundmatch; i++) { - list_for_each_entry_rcu(tmp_irq_info, - sn_irq_lh[i], - list) { - if (tmp_irq_info->irq_cpuid == cpu) { - foundmatch = 1; - break; - } - } - } - pdacpu(cpu)->sn_first_irq = ((i == NR_IRQS) ? 0 : i); - } - rcu_read_unlock(); -} - -void sn_irq_fixup(struct pci_dev *pci_dev, struct sn_irq_info *sn_irq_info) -{ - nasid_t nasid = sn_irq_info->irq_nasid; - int slice = sn_irq_info->irq_slice; - int cpu = nasid_slice_to_cpuid(nasid, slice); -#ifdef CONFIG_SMP - int cpuphys; -#endif - - pci_dev_get(pci_dev); - sn_irq_info->irq_cpuid = cpu; - sn_irq_info->irq_pciioinfo = SN_PCIDEV_INFO(pci_dev); - - /* link it into the sn_irq[irq] list */ - spin_lock(&sn_irq_info_lock); - list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]); - reserve_irq_vector(sn_irq_info->irq_irq); - if (sn_irq_info->irq_int_bit != -1) - irq_set_handler(sn_irq_info->irq_irq, handle_level_irq); - spin_unlock(&sn_irq_info_lock); - - register_intr_pda(sn_irq_info); -#ifdef CONFIG_SMP - cpuphys = cpu_physical_id(cpu); - set_irq_affinity_info(sn_irq_info->irq_irq, cpuphys, 0); - /* - * Affinity was set by the PROM, prevent it from - * being reset by the request_irq() path. - */ - irqd_mark_affinity_was_set(irq_get_irq_data(sn_irq_info->irq_irq)); -#endif -} - -void sn_irq_unfixup(struct pci_dev *pci_dev) -{ - struct sn_irq_info *sn_irq_info; - - /* Only cleanup IRQ stuff if this device has a host bus context */ - if (!SN_PCIDEV_BUSSOFT(pci_dev)) - return; - - sn_irq_info = SN_PCIDEV_INFO(pci_dev)->pdi_sn_irq_info; - if (!sn_irq_info) - return; - if (!sn_irq_info->irq_irq) { - kfree(sn_irq_info); - return; - } - - unregister_intr_pda(sn_irq_info); - spin_lock(&sn_irq_info_lock); - list_del_rcu(&sn_irq_info->list); - spin_unlock(&sn_irq_info_lock); - if (list_empty(sn_irq_lh[sn_irq_info->irq_irq])) - free_irq_vector(sn_irq_info->irq_irq); - kfree_rcu(sn_irq_info, rcu); - pci_dev_put(pci_dev); - -} - -static inline void -sn_call_force_intr_provider(struct sn_irq_info *sn_irq_info) -{ - struct sn_pcibus_provider *pci_provider; - - pci_provider = sn_pci_provider[sn_irq_info->irq_bridge_type]; - - /* Don't force an interrupt if the irq has been disabled */ - if (!irqd_irq_disabled(irq_get_irq_data(sn_irq_info->irq_irq)) && - pci_provider && pci_provider->force_interrupt) - (*pci_provider->force_interrupt)(sn_irq_info); -} - -/* - * Check for lost interrupts. If the PIC int_status reg. says that - * an interrupt has been sent, but not handled, and the interrupt - * is not pending in either the cpu irr regs or in the soft irr regs, - * and the interrupt is not in service, then the interrupt may have - * been lost. Force an interrupt on that pin. It is possible that - * the interrupt is in flight, so we may generate a spurious interrupt, - * but we should never miss a real lost interrupt. - */ -static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info) -{ - u64 regval; - struct pcidev_info *pcidev_info; - struct pcibus_info *pcibus_info; - - /* - * Bridge types attached to TIO (anything but PIC) do not need this WAR - * since they do not target Shub II interrupt registers. If that - * ever changes, this check needs to accommodate. - */ - if (sn_irq_info->irq_bridge_type != PCIIO_ASIC_TYPE_PIC) - return; - - pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; - if (!pcidev_info) - return; - - pcibus_info = - (struct pcibus_info *)pcidev_info->pdi_host_pcidev_info-> - pdi_pcibus_info; - regval = pcireg_intr_status_get(pcibus_info); - - if (!ia64_get_irr(irq_to_vector(irq))) { - if (!test_bit(irq, pda->sn_in_service_ivecs)) { - regval &= 0xff; - if (sn_irq_info->irq_int_bit & regval & - sn_irq_info->irq_last_intr) { - regval &= ~(sn_irq_info->irq_int_bit & regval); - sn_call_force_intr_provider(sn_irq_info); - } - } - } - sn_irq_info->irq_last_intr = regval; -} - -void sn_lb_int_war_check(void) -{ - struct sn_irq_info *sn_irq_info; - int i; - - if (!sn_ioif_inited || pda->sn_first_irq == 0) - return; - - rcu_read_lock(); - for (i = pda->sn_first_irq; i <= pda->sn_last_irq; i++) { - list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[i], list) { - sn_check_intr(i, sn_irq_info); - } - } - rcu_read_unlock(); -} - -void __init sn_irq_lh_init(void) -{ - int i; - - sn_irq_lh = kmalloc_array(NR_IRQS, sizeof(struct list_head *), - GFP_KERNEL); - if (!sn_irq_lh) - panic("SN PCI INIT: Failed to allocate memory for PCI init\n"); - - for (i = 0; i < NR_IRQS; i++) { - sn_irq_lh[i] = kmalloc(sizeof(struct list_head), GFP_KERNEL); - if (!sn_irq_lh[i]) - panic("SN PCI INIT: Failed IRQ memory allocation\n"); - - INIT_LIST_HEAD(sn_irq_lh[i]); - } -} diff --git a/arch/ia64/sn/kernel/klconflib.c b/arch/ia64/sn/kernel/klconflib.c deleted file mode 100644 index 87682b48ef836f7c21bf667a232bc8b8fd544985..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/klconflib.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include - -char brick_types[MAX_BRICK_TYPES + 1] = "cri.xdpn%#=vo^kjbf890123456789..."; -/* - * Format a module id for printing. - * - * There are three possible formats: - * - * MODULE_FORMAT_BRIEF is the brief 6-character format, including - * the actual brick-type as recorded in the - * moduleid_t, eg. 002c15 for a C-brick, or - * 101#17 for a PX-brick. - * - * MODULE_FORMAT_LONG is the hwgraph format, eg. rack/002/bay/15 - * of rack/101/bay/17 (note that the brick - * type does not appear in this format). - * - * MODULE_FORMAT_LCD is like MODULE_FORMAT_BRIEF, except that it - * ensures that the module id provided appears - * exactly as it would on the LCD display of - * the corresponding brick, eg. still 002c15 - * for a C-brick, but 101p17 for a PX-brick. - * - * maule (9/13/04): Removed top-level check for (fmt == MODULE_FORMAT_LCD) - * making MODULE_FORMAT_LCD equivalent to MODULE_FORMAT_BRIEF. It was - * decided that all callers should assume the returned string should be what - * is displayed on the brick L1 LCD. - */ -void -format_module_id(char *buffer, moduleid_t m, int fmt) -{ - int rack, position; - unsigned char brickchar; - - rack = MODULE_GET_RACK(m); - brickchar = MODULE_GET_BTCHAR(m); - - /* Be sure we use the same brick type character as displayed - * on the brick's LCD - */ - switch (brickchar) - { - case L1_BRICKTYPE_GA: - case L1_BRICKTYPE_OPUS_TIO: - brickchar = L1_BRICKTYPE_C; - break; - - case L1_BRICKTYPE_PX: - case L1_BRICKTYPE_PE: - case L1_BRICKTYPE_PA: - case L1_BRICKTYPE_SA: /* we can move this to the "I's" later - * if that makes more sense - */ - brickchar = L1_BRICKTYPE_P; - break; - - case L1_BRICKTYPE_IX: - case L1_BRICKTYPE_IA: - - brickchar = L1_BRICKTYPE_I; - break; - } - - position = MODULE_GET_BPOS(m); - - if ((fmt == MODULE_FORMAT_BRIEF) || (fmt == MODULE_FORMAT_LCD)) { - /* Brief module number format, eg. 002c15 */ - - /* Decompress the rack number */ - *buffer++ = '0' + RACK_GET_CLASS(rack); - *buffer++ = '0' + RACK_GET_GROUP(rack); - *buffer++ = '0' + RACK_GET_NUM(rack); - - /* Add the brick type */ - *buffer++ = brickchar; - } - else if (fmt == MODULE_FORMAT_LONG) { - /* Fuller hwgraph format, eg. rack/002/bay/15 */ - - strcpy(buffer, "rack" "/"); buffer += strlen(buffer); - - *buffer++ = '0' + RACK_GET_CLASS(rack); - *buffer++ = '0' + RACK_GET_GROUP(rack); - *buffer++ = '0' + RACK_GET_NUM(rack); - - strcpy(buffer, "/" "bay" "/"); buffer += strlen(buffer); - } - - /* Add the bay position, using at least two digits */ - if (position < 10) - *buffer++ = '0'; - sprintf(buffer, "%d", position); -} diff --git a/arch/ia64/sn/kernel/machvec.c b/arch/ia64/sn/kernel/machvec.c deleted file mode 100644 index 02bb9155840cc730e4c252242588935bb3da7685..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/machvec.c +++ /dev/null @@ -1,11 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. - */ - -#define MACHVEC_PLATFORM_NAME sn2 -#define MACHVEC_PLATFORM_HEADER -#include diff --git a/arch/ia64/sn/kernel/mca.c b/arch/ia64/sn/kernel/mca.c deleted file mode 100644 index bc3bd930c74cf9003acb60f53c43f19390d61ce0..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/mca.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Interval for calling SAL to poll for errors that do NOT cause error - * interrupts. SAL will raise a CPEI if any errors are present that - * need to be logged. - */ -#define CPEI_INTERVAL (5*HZ) - -struct timer_list sn_cpei_timer; -void sn_init_cpei_timer(void); - -/* Printing oemdata from mca uses data that is not passed through SAL, it is - * global. Only one user at a time. - */ -static DEFINE_MUTEX(sn_oemdata_mutex); -static u8 **sn_oemdata; -static u64 *sn_oemdata_size, sn_oemdata_bufsize; - -/* - * print_hook - * - * This function is the callback routine that SAL calls to log error - * info for platform errors. buf is appended to sn_oemdata, resizing as - * required. - * Note: this is a SAL to OS callback, running under the same rules as the SAL - * code. SAL calls are run with preempt disabled so this routine must not - * sleep. vmalloc can sleep so print_hook cannot resize the output buffer - * itself, instead it must set the required size and return to let the caller - * resize the buffer then redrive the SAL call. - */ -static int print_hook(const char *fmt, ...) -{ - char buf[400]; - int len; - va_list args; - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - len = strlen(buf); - if (*sn_oemdata_size + len <= sn_oemdata_bufsize) - memcpy(*sn_oemdata + *sn_oemdata_size, buf, len); - *sn_oemdata_size += len; - return 0; -} - -static void sn_cpei_handler(int irq, void *devid, struct pt_regs *regs) -{ - /* - * this function's sole purpose is to call SAL when we receive - * a CE interrupt from SHUB or when the timer routine decides - * we need to call SAL to check for CEs. - */ - - /* CALL SAL_LOG_CE */ - - ia64_sn_plat_cpei_handler(); -} - -static void sn_cpei_timer_handler(struct timer_list *unused) -{ - sn_cpei_handler(-1, NULL, NULL); - mod_timer(&sn_cpei_timer, jiffies + CPEI_INTERVAL); -} - -void sn_init_cpei_timer(void) -{ - timer_setup(&sn_cpei_timer, sn_cpei_timer_handler, 0); - sn_cpei_timer.expires = jiffies + CPEI_INTERVAL; - add_timer(&sn_cpei_timer); -} - -static int -sn_platform_plat_specific_err_print(const u8 * sect_header, u8 ** oemdata, - u64 * oemdata_size) -{ - mutex_lock(&sn_oemdata_mutex); - sn_oemdata = oemdata; - sn_oemdata_size = oemdata_size; - sn_oemdata_bufsize = 0; - *sn_oemdata_size = PAGE_SIZE; /* first guess at how much data will be generated */ - while (*sn_oemdata_size > sn_oemdata_bufsize) { - u8 *newbuf = vmalloc(*sn_oemdata_size); - if (!newbuf) { - mutex_unlock(&sn_oemdata_mutex); - printk(KERN_ERR "%s: unable to extend sn_oemdata\n", - __func__); - return 1; - } - vfree(*sn_oemdata); - *sn_oemdata = newbuf; - sn_oemdata_bufsize = *sn_oemdata_size; - *sn_oemdata_size = 0; - ia64_sn_plat_specific_err_print(print_hook, (char *)sect_header); - } - mutex_unlock(&sn_oemdata_mutex); - return 0; -} - -/* Callback when userspace salinfo wants to decode oem data via the platform - * kernel and/or prom. - */ -int sn_salinfo_platform_oemdata(const u8 *sect_header, u8 **oemdata, u64 *oemdata_size) -{ - efi_guid_t guid = *(efi_guid_t *)sect_header; - int valid = 0; - *oemdata_size = 0; - vfree(*oemdata); - *oemdata = NULL; - if (efi_guidcmp(guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID) == 0) { - sal_log_plat_specific_err_info_t *psei = (sal_log_plat_specific_err_info_t *)sect_header; - valid = psei->valid.oem_data; - } else if (efi_guidcmp(guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID) == 0) { - sal_log_mem_dev_err_info_t *mdei = (sal_log_mem_dev_err_info_t *)sect_header; - valid = mdei->valid.oem_data; - } - if (valid) - return sn_platform_plat_specific_err_print(sect_header, oemdata, oemdata_size); - else - return 0; -} - -static int __init sn_salinfo_init(void) -{ - if (ia64_platform_is("sn2")) - salinfo_platform_oemdata = &sn_salinfo_platform_oemdata; - return 0; -} -device_initcall(sn_salinfo_init); diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c deleted file mode 100644 index fb25065b22c626d8af13b29f29a3a8b3248b96bf..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/msi_sn.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -struct sn_msi_info { - u64 pci_addr; - struct sn_irq_info *sn_irq_info; -}; - -static struct sn_msi_info sn_msi_info[NR_IRQS]; - -static struct irq_chip sn_msi_chip; - -void sn_teardown_msi_irq(unsigned int irq) -{ - nasid_t nasid; - int widget; - struct pci_dev *pdev; - struct pcidev_info *sn_pdev; - struct sn_irq_info *sn_irq_info; - struct pcibus_bussoft *bussoft; - struct sn_pcibus_provider *provider; - - sn_irq_info = sn_msi_info[irq].sn_irq_info; - if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) - return; - - sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; - pdev = sn_pdev->pdi_linux_pcidev; - provider = SN_PCIDEV_BUSPROVIDER(pdev); - - (*provider->dma_unmap)(pdev, - sn_msi_info[irq].pci_addr, - PCI_DMA_FROMDEVICE); - sn_msi_info[irq].pci_addr = 0; - - bussoft = SN_PCIDEV_BUSSOFT(pdev); - nasid = NASID_GET(bussoft->bs_base); - widget = (nasid & 1) ? - TIO_SWIN_WIDGETNUM(bussoft->bs_base) : - SWIN_WIDGETNUM(bussoft->bs_base); - - sn_intr_free(nasid, widget, sn_irq_info); - sn_msi_info[irq].sn_irq_info = NULL; - - destroy_irq(irq); -} - -int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry) -{ - struct msi_msg msg; - int widget; - int status; - nasid_t nasid; - u64 bus_addr; - struct sn_irq_info *sn_irq_info; - struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev); - struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); - int irq; - - if (!entry->msi_attrib.is_64) - return -EINVAL; - - if (bussoft == NULL) - return -EINVAL; - - if (provider == NULL || provider->dma_map_consistent == NULL) - return -EINVAL; - - irq = create_irq(); - if (irq < 0) - return irq; - - /* - * Set up the vector plumbing. Let the prom (via sn_intr_alloc) - * decide which cpu to direct this msi at by default. - */ - - nasid = NASID_GET(bussoft->bs_base); - widget = (nasid & 1) ? - TIO_SWIN_WIDGETNUM(bussoft->bs_base) : - SWIN_WIDGETNUM(bussoft->bs_base); - - sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); - if (! sn_irq_info) { - destroy_irq(irq); - return -ENOMEM; - } - - status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1); - if (status) { - kfree(sn_irq_info); - destroy_irq(irq); - return -ENOMEM; - } - - sn_irq_info->irq_int_bit = -1; /* mark this as an MSI irq */ - sn_irq_fixup(pdev, sn_irq_info); - - /* Prom probably should fill these in, but doesn't ... */ - sn_irq_info->irq_bridge_type = bussoft->bs_asic_type; - sn_irq_info->irq_bridge = (void *)bussoft->bs_base; - - /* - * Map the xio address into bus space - */ - bus_addr = (*provider->dma_map_consistent)(pdev, - sn_irq_info->irq_xtalkaddr, - sizeof(sn_irq_info->irq_xtalkaddr), - SN_DMA_MSI|SN_DMA_ADDR_XIO); - if (! bus_addr) { - sn_intr_free(nasid, widget, sn_irq_info); - kfree(sn_irq_info); - destroy_irq(irq); - return -ENOMEM; - } - - sn_msi_info[irq].sn_irq_info = sn_irq_info; - sn_msi_info[irq].pci_addr = bus_addr; - - msg.address_hi = (u32)(bus_addr >> 32); - msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff); - - /* - * In the SN platform, bit 16 is a "send vector" bit which - * must be present in order to move the vector through the system. - */ - msg.data = 0x100 + irq; - - irq_set_msi_desc(irq, entry); - pci_write_msi_msg(irq, &msg); - irq_set_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq); - - return 0; -} - -#ifdef CONFIG_SMP -static int sn_set_msi_irq_affinity(struct irq_data *data, - const struct cpumask *cpu_mask, bool force) -{ - struct msi_msg msg; - int slice; - nasid_t nasid; - u64 bus_addr; - struct pci_dev *pdev; - struct pcidev_info *sn_pdev; - struct sn_irq_info *sn_irq_info; - struct sn_irq_info *new_irq_info; - struct sn_pcibus_provider *provider; - unsigned int cpu, irq = data->irq; - - cpu = cpumask_first_and(cpu_mask, cpu_online_mask); - sn_irq_info = sn_msi_info[irq].sn_irq_info; - if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) - return -1; - - /* - * Release XIO resources for the old MSI PCI address - */ - - __get_cached_msi_msg(irq_data_get_msi_desc(data), &msg); - sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; - pdev = sn_pdev->pdi_linux_pcidev; - provider = SN_PCIDEV_BUSPROVIDER(pdev); - - bus_addr = (u64)(msg.address_hi) << 32 | (u64)(msg.address_lo); - (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE); - sn_msi_info[irq].pci_addr = 0; - - nasid = cpuid_to_nasid(cpu); - slice = cpuid_to_slice(cpu); - - new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice); - sn_msi_info[irq].sn_irq_info = new_irq_info; - if (new_irq_info == NULL) - return -1; - - /* - * Map the xio address into bus space - */ - - bus_addr = (*provider->dma_map_consistent)(pdev, - new_irq_info->irq_xtalkaddr, - sizeof(new_irq_info->irq_xtalkaddr), - SN_DMA_MSI|SN_DMA_ADDR_XIO); - - sn_msi_info[irq].pci_addr = bus_addr; - msg.address_hi = (u32)(bus_addr >> 32); - msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff); - - pci_write_msi_msg(irq, &msg); - cpumask_copy(irq_data_get_affinity_mask(data), cpu_mask); - - return 0; -} -#endif /* CONFIG_SMP */ - -static void sn_ack_msi_irq(struct irq_data *data) -{ - irq_move_irq(data); - ia64_eoi(); -} - -static int sn_msi_retrigger_irq(struct irq_data *data) -{ - unsigned int vector = data->irq; - ia64_resend_irq(vector); - - return 1; -} - -static struct irq_chip sn_msi_chip = { - .name = "PCI-MSI", - .irq_mask = pci_msi_mask_irq, - .irq_unmask = pci_msi_unmask_irq, - .irq_ack = sn_ack_msi_irq, -#ifdef CONFIG_SMP - .irq_set_affinity = sn_set_msi_irq_affinity, -#endif - .irq_retrigger = sn_msi_retrigger_irq, -}; diff --git a/arch/ia64/sn/kernel/pio_phys.S b/arch/ia64/sn/kernel/pio_phys.S deleted file mode 100644 index 3c7d48d6ecb81de85544a0001278e76a11da66c2..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/pio_phys.S +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved. - * - * This file contains macros used to access MMR registers via - * uncached physical addresses. - * pio_phys_read_mmr - read an MMR - * pio_phys_write_mmr - write an MMR - * pio_atomic_phys_write_mmrs - atomically write 1 or 2 MMRs with psr.ic=0 - * Second MMR will be skipped if address is NULL - * - * Addresses passed to these routines should be uncached physical addresses - * ie., 0x80000.... - */ - - - -#include -#include - -GLOBAL_ENTRY(pio_phys_read_mmr) - .prologue - .regstk 1,0,0,0 - .body - mov r2=psr - rsm psr.i | psr.dt - ;; - srlz.d - ld8.acq r8=[r32] - ;; - mov psr.l=r2;; - srlz.d - br.ret.sptk.many rp -END(pio_phys_read_mmr) - -GLOBAL_ENTRY(pio_phys_write_mmr) - .prologue - .regstk 2,0,0,0 - .body - mov r2=psr - rsm psr.i | psr.dt - ;; - srlz.d - st8.rel [r32]=r33 - ;; - mov psr.l=r2;; - srlz.d - br.ret.sptk.many rp -END(pio_phys_write_mmr) - -GLOBAL_ENTRY(pio_atomic_phys_write_mmrs) - .prologue - .regstk 4,0,0,0 - .body - mov r2=psr - cmp.ne p9,p0=r34,r0; - rsm psr.i | psr.dt | psr.ic - ;; - srlz.d - st8.rel [r32]=r33 -(p9) st8.rel [r34]=r35 - ;; - mov psr.l=r2;; - srlz.d - br.ret.sptk.many rp -END(pio_atomic_phys_write_mmrs) - - diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c deleted file mode 100644 index e6a5049ef5031bcc702a4ba5a937618033221409..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/setup.c +++ /dev/null @@ -1,786 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1999,2001-2006 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "xtalk/xwidgetdev.h" -#include "xtalk/hubdev.h" -#include - - -DEFINE_PER_CPU(struct pda_s, pda_percpu); - -#define MAX_PHYS_MEMORY (1UL << IA64_MAX_PHYS_BITS) /* Max physical address supported */ - -extern void bte_init_node(nodepda_t *, cnodeid_t); - -extern void sn_timer_init(void); -extern unsigned long last_time_offset; -extern void (*ia64_mark_idle) (int); -extern void snidle(int); - -unsigned long sn_rtc_cycles_per_second; -EXPORT_SYMBOL(sn_rtc_cycles_per_second); - -DEFINE_PER_CPU(struct sn_hub_info_s, __sn_hub_info); -EXPORT_PER_CPU_SYMBOL(__sn_hub_info); - -DEFINE_PER_CPU(short, __sn_cnodeid_to_nasid[MAX_COMPACT_NODES]); -EXPORT_PER_CPU_SYMBOL(__sn_cnodeid_to_nasid); - -DEFINE_PER_CPU(struct nodepda_s *, __sn_nodepda); -EXPORT_PER_CPU_SYMBOL(__sn_nodepda); - -char sn_system_serial_number_string[128]; -EXPORT_SYMBOL(sn_system_serial_number_string); -u64 sn_partition_serial_number; -EXPORT_SYMBOL(sn_partition_serial_number); -u8 sn_partition_id; -EXPORT_SYMBOL(sn_partition_id); -u8 sn_system_size; -EXPORT_SYMBOL(sn_system_size); -u8 sn_sharing_domain_size; -EXPORT_SYMBOL(sn_sharing_domain_size); -u8 sn_coherency_id; -EXPORT_SYMBOL(sn_coherency_id); -u8 sn_region_size; -EXPORT_SYMBOL(sn_region_size); -int sn_prom_type; /* 0=hardware, 1=medusa/realprom, 2=medusa/fakeprom */ - -short physical_node_map[MAX_NUMALINK_NODES]; -static unsigned long sn_prom_features[MAX_PROM_FEATURE_SETS]; - -EXPORT_SYMBOL(physical_node_map); - -int num_cnodes; - -static void sn_init_pdas(char **); -static void build_cnode_tables(void); - -static nodepda_t *nodepdaindr[MAX_COMPACT_NODES]; - -/* - * The format of "screen_info" is strange, and due to early i386-setup - * code. This is just enough to make the console code think we're on a - * VGA color display. - */ -struct screen_info sn_screen_info = { - .orig_x = 0, - .orig_y = 0, - .orig_video_mode = 3, - .orig_video_cols = 80, - .orig_video_ega_bx = 3, - .orig_video_lines = 25, - .orig_video_isVGA = 1, - .orig_video_points = 16 -}; - -/* - * This routine can only be used during init, since - * smp_boot_data is an init data structure. - * We have to use smp_boot_data.cpu_phys_id to find - * the physical id of the processor because the normal - * cpu_physical_id() relies on data structures that - * may not be initialized yet. - */ - -static int __init pxm_to_nasid(int pxm) -{ - int i; - int nid; - - nid = pxm_to_node(pxm); - for (i = 0; i < num_node_memblks; i++) { - if (node_memblk[i].nid == nid) { - return NASID_GET(node_memblk[i].start_paddr); - } - } - return -1; -} - -/** - * early_sn_setup - early setup routine for SN platforms - * - * Sets up an initial console to aid debugging. Intended primarily - * for bringup. See start_kernel() in init/main.c. - */ - -void __init early_sn_setup(void) -{ - efi_system_table_t *efi_systab; - efi_config_table_t *config_tables; - struct ia64_sal_systab *sal_systab; - struct ia64_sal_desc_entry_point *ep; - char *p; - int i, j; - - /* - * Parse enough of the SAL tables to locate the SAL entry point. Since, console - * IO on SN2 is done via SAL calls, early_printk won't work without this. - * - * This code duplicates some of the ACPI table parsing that is in efi.c & sal.c. - * Any changes to those file may have to be made here as well. - */ - efi_systab = (efi_system_table_t *) __va(ia64_boot_param->efi_systab); - config_tables = __va(efi_systab->tables); - for (i = 0; i < efi_systab->nr_tables; i++) { - if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == - 0) { - sal_systab = __va(config_tables[i].table); - p = (char *)(sal_systab + 1); - for (j = 0; j < sal_systab->entry_count; j++) { - if (*p == SAL_DESC_ENTRY_POINT) { - ep = (struct ia64_sal_desc_entry_point - *)p; - ia64_sal_handler_init(__va - (ep->sal_proc), - __va(ep->gp)); - return; - } - p += SAL_DESC_SIZE(*p); - } - } - } - /* Uh-oh, SAL not available?? */ - printk(KERN_ERR "failed to find SAL entry point\n"); -} - -extern int platform_intr_list[]; -static int shub_1_1_found; - -/* - * sn_check_for_wars - * - * Set flag for enabling shub specific wars - */ - -static inline int is_shub_1_1(int nasid) -{ - unsigned long id; - int rev; - - if (is_shub2()) - return 0; - id = REMOTE_HUB_L(nasid, SH1_SHUB_ID); - rev = (id & SH1_SHUB_ID_REVISION_MASK) >> SH1_SHUB_ID_REVISION_SHFT; - return rev <= 2; -} - -static void sn_check_for_wars(void) -{ - int cnode; - - if (is_shub2()) { - /* none yet */ - } else { - for_each_online_node(cnode) { - if (is_shub_1_1(cnodeid_to_nasid(cnode))) - shub_1_1_found = 1; - } - } -} - -/* - * Scan the EFI PCDP table (if it exists) for an acceptable VGA console - * output device. If one exists, pick it and set sn_legacy_{io,mem} to - * reflect the bus offsets needed to address it. - * - * Since pcdp support in SN is not supported in the 2.4 kernel (or at least - * the one lbs is based on) just declare the needed structs here. - * - * Reference spec http://www.dig64.org/specifications/DIG64_PCDPv20.pdf - * - * Returns 0 if no acceptable vga is found, !0 otherwise. - * - * Note: This stuff is duped here because Altix requires the PCDP to - * locate a usable VGA device due to lack of proper ACPI support. Structures - * could be used from drivers/firmware/pcdp.h, but it was decided that moving - * this file to a more public location just for Altix use was undesirable. - */ - -struct hcdp_uart_desc { - u8 pad[45]; -}; - -struct pcdp { - u8 signature[4]; /* should be 'HCDP' */ - u32 length; - u8 rev; /* should be >=3 for pcdp, <3 for hcdp */ - u8 sum; - u8 oem_id[6]; - u64 oem_tableid; - u32 oem_rev; - u32 creator_id; - u32 creator_rev; - u32 num_type0; - struct hcdp_uart_desc uart[0]; /* num_type0 of these */ - /* pcdp descriptors follow */ -} __attribute__((packed)); - -struct pcdp_device_desc { - u8 type; - u8 primary; - u16 length; - u16 index; - /* interconnect specific structure follows */ - /* device specific structure follows that */ -} __attribute__((packed)); - -struct pcdp_interface_pci { - u8 type; /* 1 == pci */ - u8 reserved; - u16 length; - u8 segment; - u8 bus; - u8 dev; - u8 fun; - u16 devid; - u16 vendid; - u32 acpi_interrupt; - u64 mmio_tra; - u64 ioport_tra; - u8 flags; - u8 translation; -} __attribute__((packed)); - -struct pcdp_vga_device { - u8 num_eas_desc; - /* ACPI Extended Address Space Desc follows */ -} __attribute__((packed)); - -/* from pcdp_device_desc.primary */ -#define PCDP_PRIMARY_CONSOLE 0x01 - -/* from pcdp_device_desc.type */ -#define PCDP_CONSOLE_INOUT 0x0 -#define PCDP_CONSOLE_DEBUG 0x1 -#define PCDP_CONSOLE_OUT 0x2 -#define PCDP_CONSOLE_IN 0x3 -#define PCDP_CONSOLE_TYPE_VGA 0x8 - -#define PCDP_CONSOLE_VGA (PCDP_CONSOLE_TYPE_VGA | PCDP_CONSOLE_OUT) - -/* from pcdp_interface_pci.type */ -#define PCDP_IF_PCI 1 - -/* from pcdp_interface_pci.translation */ -#define PCDP_PCI_TRANS_IOPORT 0x02 -#define PCDP_PCI_TRANS_MMIO 0x01 - -#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) -static void -sn_scan_pcdp(void) -{ - u8 *bp; - struct pcdp *pcdp; - struct pcdp_device_desc device; - struct pcdp_interface_pci if_pci; - extern struct efi efi; - - if (efi.hcdp == EFI_INVALID_TABLE_ADDR) - return; /* no hcdp/pcdp table */ - - pcdp = __va(efi.hcdp); - - if (pcdp->rev < 3) - return; /* only support PCDP (rev >= 3) */ - - for (bp = (u8 *)&pcdp->uart[pcdp->num_type0]; - bp < (u8 *)pcdp + pcdp->length; - bp += device.length) { - memcpy(&device, bp, sizeof(device)); - if (! (device.primary & PCDP_PRIMARY_CONSOLE)) - continue; /* not primary console */ - - if (device.type != PCDP_CONSOLE_VGA) - continue; /* not VGA descriptor */ - - memcpy(&if_pci, bp+sizeof(device), sizeof(if_pci)); - if (if_pci.type != PCDP_IF_PCI) - continue; /* not PCI interconnect */ - - if (if_pci.translation & PCDP_PCI_TRANS_IOPORT) - vga_console_iobase = if_pci.ioport_tra; - - if (if_pci.translation & PCDP_PCI_TRANS_MMIO) - vga_console_membase = - if_pci.mmio_tra | __IA64_UNCACHED_OFFSET; - - break; /* once we find the primary, we're done */ - } -} -#endif - -static unsigned long sn2_rtc_initial; - -/** - * sn_setup - SN platform setup routine - * @cmdline_p: kernel command line - * - * Handles platform setup for SN machines. This includes determining - * the RTC frequency (via a SAL call), initializing secondary CPUs, and - * setting up per-node data areas. The console is also initialized here. - */ -void __init sn_setup(char **cmdline_p) -{ - long status, ticks_per_sec, drift; - u32 version = sn_sal_rev(); - extern void sn_cpu_init(void); - - sn2_rtc_initial = rtc_time(); - ia64_sn_plat_set_error_handling_features(); // obsolete - ia64_sn_set_os_feature(OSF_MCA_SLV_TO_OS_INIT_SLV); - ia64_sn_set_os_feature(OSF_FEAT_LOG_SBES); - /* - * Note: The calls to notify the PROM of ACPI and PCI Segment - * support must be done prior to acpi_load_tables(), as - * an ACPI capable PROM will rebuild the DSDT as result - * of the call. - */ - ia64_sn_set_os_feature(OSF_PCISEGMENT_ENABLE); - ia64_sn_set_os_feature(OSF_ACPI_ENABLE); - - /* Load the new DSDT and SSDT tables into the global table list. */ - acpi_table_init(); - -#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) - /* - * Handle SN vga console. - * - * SN systems do not have enough ACPI table information - * being passed from prom to identify VGA adapters and the legacy - * addresses to access them. Until that is done, SN systems rely - * on the PCDP table to identify the primary VGA console if one - * exists. - * - * However, kernel PCDP support is optional, and even if it is built - * into the kernel, it will not be used if the boot cmdline contains - * console= directives. - * - * So, to work around this mess, we duplicate some of the PCDP code - * here so that the primary VGA console (as defined by PCDP) will - * work on SN systems even if a different console (e.g. serial) is - * selected on the boot line (or CONFIG_EFI_PCDP is off). - */ - - if (! vga_console_membase) - sn_scan_pcdp(); - - /* - * Setup legacy IO space. - * vga_console_iobase maps to PCI IO Space address 0 on the - * bus containing the VGA console. - */ - if (vga_console_iobase) { - io_space[0].mmio_base = - (unsigned long) ioremap(vga_console_iobase, 0); - io_space[0].sparse = 0; - } - - if (vga_console_membase) { - /* usable vga ... make tty0 the preferred default console */ - if (!strstr(*cmdline_p, "console=")) - add_preferred_console("tty", 0, NULL); - } else { - printk(KERN_DEBUG "SGI: Disabling VGA console\n"); - if (!strstr(*cmdline_p, "console=")) - add_preferred_console("ttySG", 0, NULL); -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#else - conswitchp = NULL; -#endif /* CONFIG_DUMMY_CONSOLE */ - } -#endif /* def(CONFIG_VT) && def(CONFIG_VGA_CONSOLE) */ - - MAX_DMA_ADDRESS = PAGE_OFFSET + MAX_PHYS_MEMORY; - - /* - * Build the tables for managing cnodes. - */ - build_cnode_tables(); - - status = - ia64_sal_freq_base(SAL_FREQ_BASE_REALTIME_CLOCK, &ticks_per_sec, - &drift); - if (status != 0 || ticks_per_sec < 100000) { - printk(KERN_WARNING - "unable to determine platform RTC clock frequency, guessing.\n"); - /* PROM gives wrong value for clock freq. so guess */ - sn_rtc_cycles_per_second = 1000000000000UL / 30000UL; - } else - sn_rtc_cycles_per_second = ticks_per_sec; - - platform_intr_list[ACPI_INTERRUPT_CPEI] = IA64_CPE_VECTOR; - - printk("SGI SAL version %x.%02x\n", version >> 8, version & 0x00FF); - - /* - * we set the default root device to /dev/hda - * to make simulation easy - */ - ROOT_DEV = Root_HDA1; - - /* - * Create the PDAs and NODEPDAs for all the cpus. - */ - sn_init_pdas(cmdline_p); - - ia64_mark_idle = &snidle; - - /* - * For the bootcpu, we do this here. All other cpus will make the - * call as part of cpu_init in slave cpu initialization. - */ - sn_cpu_init(); - -#ifdef CONFIG_SMP - init_smp_config(); -#endif - screen_info = sn_screen_info; - - sn_timer_init(); - - /* - * set pm_power_off to a SAL call to allow - * sn machines to power off. The SAL call can be replaced - * by an ACPI interface call when ACPI is fully implemented - * for sn. - */ - pm_power_off = ia64_sn_power_down; - current->thread.flags |= IA64_THREAD_MIGRATION; -} - -/** - * sn_init_pdas - setup node data areas - * - * One time setup for Node Data Area. Called by sn_setup(). - */ -static void __init sn_init_pdas(char **cmdline_p) -{ - cnodeid_t cnode; - - /* - * Allocate & initialize the nodepda for each node. - */ - for_each_online_node(cnode) { - nodepdaindr[cnode] = - memblock_alloc_node(sizeof(nodepda_t), SMP_CACHE_BYTES, - cnode); - if (!nodepdaindr[cnode]) - panic("%s: Failed to allocate %lu bytes align=0x%x nid=%d\n", - __func__, sizeof(nodepda_t), SMP_CACHE_BYTES, - cnode); - memset(nodepdaindr[cnode]->phys_cpuid, -1, - sizeof(nodepdaindr[cnode]->phys_cpuid)); - spin_lock_init(&nodepdaindr[cnode]->ptc_lock); - } - - /* - * Allocate & initialize nodepda for TIOs. For now, put them on node 0. - */ - for (cnode = num_online_nodes(); cnode < num_cnodes; cnode++) { - nodepdaindr[cnode] = - memblock_alloc_node(sizeof(nodepda_t), SMP_CACHE_BYTES, 0); - if (!nodepdaindr[cnode]) - panic("%s: Failed to allocate %lu bytes align=0x%x nid=%d\n", - __func__, sizeof(nodepda_t), SMP_CACHE_BYTES, - cnode); - } - - - /* - * Now copy the array of nodepda pointers to each nodepda. - */ - for (cnode = 0; cnode < num_cnodes; cnode++) - memcpy(nodepdaindr[cnode]->pernode_pdaindr, nodepdaindr, - sizeof(nodepdaindr)); - - /* - * Set up IO related platform-dependent nodepda fields. - * The following routine actually sets up the hubinfo struct - * in nodepda. - */ - for_each_online_node(cnode) { - bte_init_node(nodepdaindr[cnode], cnode); - } - - /* - * Initialize the per node hubdev. This includes IO Nodes and - * headless/memless nodes. - */ - for (cnode = 0; cnode < num_cnodes; cnode++) { - hubdev_init_node(nodepdaindr[cnode], cnode); - } -} - -/** - * sn_cpu_init - initialize per-cpu data areas - * @cpuid: cpuid of the caller - * - * Called during cpu initialization on each cpu as it starts. - * Currently, initializes the per-cpu data area for SNIA. - * Also sets up a few fields in the nodepda. Also known as - * platform_cpu_init() by the ia64 machvec code. - */ -void sn_cpu_init(void) -{ - int cpuid; - int cpuphyid; - int nasid; - int subnode; - int slice; - int cnode; - int i; - static int wars_have_been_checked, set_cpu0_number; - - cpuid = smp_processor_id(); - if (cpuid == 0 && IS_MEDUSA()) { - if (ia64_sn_is_fake_prom()) - sn_prom_type = 2; - else - sn_prom_type = 1; - printk(KERN_INFO "Running on medusa with %s PROM\n", - (sn_prom_type == 1) ? "real" : "fake"); - } - - memset(pda, 0, sizeof(*pda)); - if (ia64_sn_get_sn_info(0, &sn_hub_info->shub2, - &sn_hub_info->nasid_bitmask, - &sn_hub_info->nasid_shift, - &sn_system_size, &sn_sharing_domain_size, - &sn_partition_id, &sn_coherency_id, - &sn_region_size)) - BUG(); - sn_hub_info->as_shift = sn_hub_info->nasid_shift - 2; - - /* - * Don't check status. The SAL call is not supported on all PROMs - * but a failure is harmless. - * Architecturally, cpu_init is always called twice on cpu 0. We - * should set cpu_number on cpu 0 once. - */ - if (cpuid == 0) { - if (!set_cpu0_number) { - (void) ia64_sn_set_cpu_number(cpuid); - set_cpu0_number = 1; - } - } else - (void) ia64_sn_set_cpu_number(cpuid); - - /* - * The boot cpu makes this call again after platform initialization is - * complete. - */ - if (nodepdaindr[0] == NULL) - return; - - for (i = 0; i < MAX_PROM_FEATURE_SETS; i++) - if (ia64_sn_get_prom_feature_set(i, &sn_prom_features[i]) != 0) - break; - - cpuphyid = get_sapicid(); - - if (ia64_sn_get_sapic_info(cpuphyid, &nasid, &subnode, &slice)) - BUG(); - - for (i=0; i < MAX_NUMNODES; i++) { - if (nodepdaindr[i]) { - nodepdaindr[i]->phys_cpuid[cpuid].nasid = nasid; - nodepdaindr[i]->phys_cpuid[cpuid].slice = slice; - nodepdaindr[i]->phys_cpuid[cpuid].subnode = subnode; - } - } - - cnode = nasid_to_cnodeid(nasid); - - __this_cpu_write(__sn_nodepda, nodepdaindr[cnode]); - - pda->led_address = - (typeof(pda->led_address)) (LED0 + (slice << LED_CPU_SHIFT)); - pda->led_state = LED_ALWAYS_SET; - pda->hb_count = HZ / 2; - pda->hb_state = 0; - pda->idle_flag = 0; - - if (cpuid != 0) { - /* copy cpu 0's sn_cnodeid_to_nasid table to this cpu's */ - memcpy(sn_cnodeid_to_nasid, - (&per_cpu(__sn_cnodeid_to_nasid, 0)), - sizeof(__ia64_per_cpu_var(__sn_cnodeid_to_nasid))); - } - - /* - * Check for WARs. - * Only needs to be done once, on BSP. - * Has to be done after loop above, because it uses this cpu's - * sn_cnodeid_to_nasid table which was just initialized if this - * isn't cpu 0. - * Has to be done before assignment below. - */ - if (!wars_have_been_checked) { - sn_check_for_wars(); - wars_have_been_checked = 1; - } - sn_hub_info->shub_1_1_found = shub_1_1_found; - - /* - * Set up addresses of PIO/MEM write status registers. - */ - { - u64 pio1[] = {SH1_PIO_WRITE_STATUS_0, 0, SH1_PIO_WRITE_STATUS_1, 0}; - u64 pio2[] = {SH2_PIO_WRITE_STATUS_0, SH2_PIO_WRITE_STATUS_2, - SH2_PIO_WRITE_STATUS_1, SH2_PIO_WRITE_STATUS_3}; - u64 *pio; - pio = is_shub1() ? pio1 : pio2; - pda->pio_write_status_addr = - (volatile unsigned long *)GLOBAL_MMR_ADDR(nasid, pio[slice]); - pda->pio_write_status_val = is_shub1() ? SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK : 0; - } - - /* - * WAR addresses for SHUB 1.x. - */ - if (local_node_data->active_cpu_count++ == 0 && is_shub1()) { - int buddy_nasid; - buddy_nasid = - cnodeid_to_nasid(numa_node_id() == - num_online_nodes() - 1 ? 0 : numa_node_id() + 1); - pda->pio_shub_war_cam_addr = - (volatile unsigned long *)GLOBAL_MMR_ADDR(nasid, - SH1_PI_CAM_CONTROL); - } -} - -/* - * Build tables for converting between NASIDs and cnodes. - */ -static inline int __init board_needs_cnode(int type) -{ - return (type == KLTYPE_SNIA || type == KLTYPE_TIO); -} - -void __init build_cnode_tables(void) -{ - int nasid; - int node; - lboard_t *brd; - - memset(physical_node_map, -1, sizeof(physical_node_map)); - memset(sn_cnodeid_to_nasid, -1, - sizeof(__ia64_per_cpu_var(__sn_cnodeid_to_nasid))); - - /* - * First populate the tables with C/M bricks. This ensures that - * cnode == node for all C & M bricks. - */ - for_each_online_node(node) { - nasid = pxm_to_nasid(node_to_pxm(node)); - sn_cnodeid_to_nasid[node] = nasid; - physical_node_map[nasid] = node; - } - - /* - * num_cnodes is total number of C/M/TIO bricks. Because of the 256 node - * limit on the number of nodes, we can't use the generic node numbers - * for this. Note that num_cnodes is incremented below as TIOs or - * headless/memoryless nodes are discovered. - */ - num_cnodes = num_online_nodes(); - - /* fakeprom does not support klgraph */ - if (IS_RUNNING_ON_FAKE_PROM()) - return; - - /* Find TIOs & headless/memoryless nodes and add them to the tables */ - for_each_online_node(node) { - kl_config_hdr_t *klgraph_header; - nasid = cnodeid_to_nasid(node); - klgraph_header = ia64_sn_get_klconfig_addr(nasid); - BUG_ON(klgraph_header == NULL); - brd = NODE_OFFSET_TO_LBOARD(nasid, klgraph_header->ch_board_info); - while (brd) { - if (board_needs_cnode(brd->brd_type) && physical_node_map[brd->brd_nasid] < 0) { - sn_cnodeid_to_nasid[num_cnodes] = brd->brd_nasid; - physical_node_map[brd->brd_nasid] = num_cnodes++; - } - brd = find_lboard_next(brd); - } - } -} - -int -nasid_slice_to_cpuid(int nasid, int slice) -{ - long cpu; - - for (cpu = 0; cpu < nr_cpu_ids; cpu++) - if (cpuid_to_nasid(cpu) == nasid && - cpuid_to_slice(cpu) == slice) - return cpu; - - return -1; -} - -int sn_prom_feature_available(int id) -{ - if (id >= BITS_PER_LONG * MAX_PROM_FEATURE_SETS) - return 0; - return test_bit(id, sn_prom_features); -} - -void -sn_kernel_launch_event(void) -{ - /* ignore status until we understand possible failure, if any*/ - if (ia64_sn_kernel_launch_event()) - printk(KERN_ERR "KEXEC is not supported in this PROM, Please update the PROM.\n"); -} -EXPORT_SYMBOL(sn_prom_feature_available); - diff --git a/arch/ia64/sn/kernel/sn2/Makefile b/arch/ia64/sn/kernel/sn2/Makefile deleted file mode 100644 index 170bde4549da8f6191726c099fe7c88483377f31..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/sn2/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# arch/ia64/sn/kernel/sn2/Makefile -# -# This file is subject to the terms and conditions of the GNU General Public -# License. See the file "COPYING" in the main directory of this archive -# for more details. -# -# Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved. -# -# sn2 specific kernel files -# - -obj-y += cache.o io.o ptc_deadlock.o sn2_smp.o sn_proc_fs.o \ - prominfo_proc.o timer.o timer_interrupt.o sn_hwperf.o diff --git a/arch/ia64/sn/kernel/sn2/cache.c b/arch/ia64/sn/kernel/sn2/cache.c deleted file mode 100644 index 2862cb33026d16dd8bbc46a2d54cb793314acf96..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/sn2/cache.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001-2003, 2006 Silicon Graphics, Inc. All rights reserved. - * - */ -#include -#include -#include - -/** - * sn_flush_all_caches - flush a range of address from all caches (incl. L4) - * @flush_addr: identity mapped region 7 address to start flushing - * @bytes: number of bytes to flush - * - * Flush a range of addresses from all caches including L4. - * All addresses fully or partially contained within - * @flush_addr to @flush_addr + @bytes are flushed - * from all caches. - */ -void -sn_flush_all_caches(long flush_addr, long bytes) -{ - unsigned long addr = flush_addr; - - /* SHub1 requires a cached address */ - if (is_shub1() && (addr & RGN_BITS) == RGN_BASE(RGN_UNCACHED)) - addr = (addr - RGN_BASE(RGN_UNCACHED)) + RGN_BASE(RGN_KERNEL); - - flush_icache_range(addr, addr + bytes); - /* - * The last call may have returned before the caches - * were actually flushed, so we call it again to make - * sure. - */ - flush_icache_range(addr, addr + bytes); - mb(); -} -EXPORT_SYMBOL(sn_flush_all_caches); diff --git a/arch/ia64/sn/kernel/sn2/io.c b/arch/ia64/sn/kernel/sn2/io.c deleted file mode 100644 index a12c0586de38257c4f0a4bc8c792d8e90db65ab5..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/sn2/io.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2003 Silicon Graphics, Inc. All rights reserved. - * - * The generic kernel requires function pointers to these routines, so - * we wrap the inlines from asm/ia64/sn/sn2/io.h here. - */ - -#include - -#ifdef CONFIG_IA64_GENERIC - -#undef __sn_inb -#undef __sn_inw -#undef __sn_inl -#undef __sn_outb -#undef __sn_outw -#undef __sn_outl -#undef __sn_readb -#undef __sn_readw -#undef __sn_readl -#undef __sn_readq -#undef __sn_readb_relaxed -#undef __sn_readw_relaxed -#undef __sn_readl_relaxed -#undef __sn_readq_relaxed - -unsigned int __sn_inb(unsigned long port) -{ - return ___sn_inb(port); -} - -unsigned int __sn_inw(unsigned long port) -{ - return ___sn_inw(port); -} - -unsigned int __sn_inl(unsigned long port) -{ - return ___sn_inl(port); -} - -void __sn_outb(unsigned char val, unsigned long port) -{ - ___sn_outb(val, port); -} - -void __sn_outw(unsigned short val, unsigned long port) -{ - ___sn_outw(val, port); -} - -void __sn_outl(unsigned int val, unsigned long port) -{ - ___sn_outl(val, port); -} - -unsigned char __sn_readb(void __iomem *addr) -{ - return ___sn_readb(addr); -} - -unsigned short __sn_readw(void __iomem *addr) -{ - return ___sn_readw(addr); -} - -unsigned int __sn_readl(void __iomem *addr) -{ - return ___sn_readl(addr); -} - -unsigned long __sn_readq(void __iomem *addr) -{ - return ___sn_readq(addr); -} - -unsigned char __sn_readb_relaxed(void __iomem *addr) -{ - return ___sn_readb_relaxed(addr); -} - -unsigned short __sn_readw_relaxed(void __iomem *addr) -{ - return ___sn_readw_relaxed(addr); -} - -unsigned int __sn_readl_relaxed(void __iomem *addr) -{ - return ___sn_readl_relaxed(addr); -} - -unsigned long __sn_readq_relaxed(void __iomem *addr) -{ - return ___sn_readq_relaxed(addr); -} - -#endif diff --git a/arch/ia64/sn/kernel/sn2/prominfo_proc.c b/arch/ia64/sn/kernel/sn2/prominfo_proc.c deleted file mode 100644 index e15457bf21acb7820ece4fee36f0fa4726fcb2d7..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/sn2/prominfo_proc.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1999,2001-2004, 2006 Silicon Graphics, Inc. All Rights Reserved. - * - * Module to export the system's Firmware Interface Tables, including - * PROM revision numbers and banners, in /proc - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("PROM version reporting for /proc"); -MODULE_AUTHOR("Chad Talbott"); -MODULE_LICENSE("GPL"); - -/* Standard Intel FIT entry types */ -#define FIT_ENTRY_FIT_HEADER 0x00 /* FIT header entry */ -#define FIT_ENTRY_PAL_B 0x01 /* PAL_B entry */ -/* Entries 0x02 through 0x0D reserved by Intel */ -#define FIT_ENTRY_PAL_A_PROC 0x0E /* Processor-specific PAL_A entry */ -#define FIT_ENTRY_PAL_A 0x0F /* PAL_A entry, same as... */ -#define FIT_ENTRY_PAL_A_GEN 0x0F /* ...Generic PAL_A entry */ -#define FIT_ENTRY_UNUSED 0x7F /* Unused (reserved by Intel?) */ -/* OEM-defined entries range from 0x10 to 0x7E. */ -#define FIT_ENTRY_SAL_A 0x10 /* SAL_A entry */ -#define FIT_ENTRY_SAL_B 0x11 /* SAL_B entry */ -#define FIT_ENTRY_SALRUNTIME 0x12 /* SAL runtime entry */ -#define FIT_ENTRY_EFI 0x1F /* EFI entry */ -#define FIT_ENTRY_FPSWA 0x20 /* embedded fpswa entry */ -#define FIT_ENTRY_VMLINUX 0x21 /* embedded vmlinux entry */ - -#define FIT_MAJOR_SHIFT (32 + 8) -#define FIT_MAJOR_MASK ((1 << 8) - 1) -#define FIT_MINOR_SHIFT 32 -#define FIT_MINOR_MASK ((1 << 8) - 1) - -#define FIT_MAJOR(q) \ - ((unsigned) ((q) >> FIT_MAJOR_SHIFT) & FIT_MAJOR_MASK) -#define FIT_MINOR(q) \ - ((unsigned) ((q) >> FIT_MINOR_SHIFT) & FIT_MINOR_MASK) - -#define FIT_TYPE_SHIFT (32 + 16) -#define FIT_TYPE_MASK ((1 << 7) - 1) - -#define FIT_TYPE(q) \ - ((unsigned) ((q) >> FIT_TYPE_SHIFT) & FIT_TYPE_MASK) - -struct fit_type_map_t { - unsigned char type; - const char *name; -}; - -static const struct fit_type_map_t fit_entry_types[] = { - {FIT_ENTRY_FIT_HEADER, "FIT Header"}, - {FIT_ENTRY_PAL_A_GEN, "Generic PAL_A"}, - {FIT_ENTRY_PAL_A_PROC, "Processor-specific PAL_A"}, - {FIT_ENTRY_PAL_A, "PAL_A"}, - {FIT_ENTRY_PAL_B, "PAL_B"}, - {FIT_ENTRY_SAL_A, "SAL_A"}, - {FIT_ENTRY_SAL_B, "SAL_B"}, - {FIT_ENTRY_SALRUNTIME, "SAL runtime"}, - {FIT_ENTRY_EFI, "EFI"}, - {FIT_ENTRY_VMLINUX, "Embedded Linux"}, - {FIT_ENTRY_FPSWA, "Embedded FPSWA"}, - {FIT_ENTRY_UNUSED, "Unused"}, - {0xff, "Error"}, -}; - -static const char *fit_type_name(unsigned char type) -{ - struct fit_type_map_t const *mapp; - - for (mapp = fit_entry_types; mapp->type != 0xff; mapp++) - if (type == mapp->type) - return mapp->name; - - if ((type > FIT_ENTRY_PAL_A) && (type < FIT_ENTRY_UNUSED)) - return "OEM type"; - if ((type > FIT_ENTRY_PAL_B) && (type < FIT_ENTRY_PAL_A)) - return "Reserved"; - - return "Unknown type"; -} - -static int -get_fit_entry(unsigned long nasid, int index, unsigned long *fentry, - char *banner, int banlen) -{ - return ia64_sn_get_fit_compt(nasid, index, fentry, banner, banlen); -} - - -/* - * These two routines display the FIT table for each node. - */ -static void dump_fit_entry(struct seq_file *m, unsigned long *fentry) -{ - unsigned type; - - type = FIT_TYPE(fentry[1]); - seq_printf(m, "%02x %-25s %x.%02x %016lx %u\n", - type, - fit_type_name(type), - FIT_MAJOR(fentry[1]), FIT_MINOR(fentry[1]), - fentry[0], - /* mult by sixteen to get size in bytes */ - (unsigned)(fentry[1] & 0xffffff) * 16); -} - - -/* - * We assume that the fit table will be small enough that we can print - * the whole thing into one page. (This is true for our default 16kB - * pages -- each entry is about 60 chars wide when printed.) I read - * somewhere that the maximum size of the FIT is 128 entries, so we're - * OK except for 4kB pages (and no one is going to do that on SN - * anyway). - */ -static int proc_fit_show(struct seq_file *m, void *v) -{ - unsigned long nasid = (unsigned long)m->private; - unsigned long fentry[2]; - int index; - - for (index=0;;index++) { - BUG_ON(index * 60 > PAGE_SIZE); - if (get_fit_entry(nasid, index, fentry, NULL, 0)) - break; - dump_fit_entry(m, fentry); - } - return 0; -} - -static int proc_version_show(struct seq_file *m, void *v) -{ - unsigned long nasid = (unsigned long)m->private; - unsigned long fentry[2]; - char banner[128]; - int index; - - for (index = 0; ; index++) { - if (get_fit_entry(nasid, index, fentry, banner, - sizeof(banner))) - return 0; - if (FIT_TYPE(fentry[1]) == FIT_ENTRY_SAL_A) - break; - } - - seq_printf(m, "%x.%02x\n", FIT_MAJOR(fentry[1]), FIT_MINOR(fentry[1])); - - if (banner[0]) - seq_printf(m, "%s\n", banner); - return 0; -} - -/* module entry points */ -int __init prominfo_init(void); -void __exit prominfo_exit(void); - -module_init(prominfo_init); -module_exit(prominfo_exit); - -#define NODE_NAME_LEN 11 - -int __init prominfo_init(void) -{ - struct proc_dir_entry *sgi_prominfo_entry; - cnodeid_t cnodeid; - - if (!ia64_platform_is("sn2")) - return 0; - - sgi_prominfo_entry = proc_mkdir("sgi_prominfo", NULL); - if (!sgi_prominfo_entry) - return -ENOMEM; - - for_each_online_node(cnodeid) { - struct proc_dir_entry *dir; - unsigned long nasid; - char name[NODE_NAME_LEN]; - - sprintf(name, "node%d", cnodeid); - dir = proc_mkdir(name, sgi_prominfo_entry); - if (!dir) - continue; - nasid = cnodeid_to_nasid(cnodeid); - proc_create_single_data("fit", 0, dir, proc_fit_show, - (void *)nasid); - proc_create_single_data("version", 0, dir, proc_version_show, - (void *)nasid); - } - return 0; -} - -void __exit prominfo_exit(void) -{ - remove_proc_subtree("sgi_prominfo", NULL); -} diff --git a/arch/ia64/sn/kernel/sn2/ptc_deadlock.S b/arch/ia64/sn/kernel/sn2/ptc_deadlock.S deleted file mode 100644 index bebbcc4f8dd408df200a3a7f330a78a04a6cc26a..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/sn2/ptc_deadlock.S +++ /dev/null @@ -1,92 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include - -#define DEADLOCKBIT SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT -#define WRITECOUNTMASK SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK -#define ALIAS_OFFSET 8 - - - .global sn2_ptc_deadlock_recovery_core - .proc sn2_ptc_deadlock_recovery_core - -sn2_ptc_deadlock_recovery_core: - .regstk 6,0,0,0 - - ptc0 = in0 - data0 = in1 - ptc1 = in2 - data1 = in3 - piowc = in4 - zeroval = in5 - piowcphy = r30 - psrsave = r2 - scr1 = r16 - scr2 = r17 - mask = r18 - - - extr.u piowcphy=piowc,0,61;; // Convert piowc to uncached physical address - dep piowcphy=-1,piowcphy,63,1 - movl mask=WRITECOUNTMASK - mov r8=r0 - -1: - cmp.ne p8,p9=r0,ptc1 // Test for shub type (ptc1 non-null on shub1) - // p8 = 1 if shub1, p9 = 1 if shub2 - - add scr2=ALIAS_OFFSET,piowc // Address of WRITE_STATUS alias register - mov scr1=7;; // Clear DEADLOCK, WRITE_ERROR, MULTI_WRITE_ERROR -(p8) st8.rel [scr2]=scr1;; -(p9) ld8.acq scr1=[scr2];; - -5: ld8.acq scr1=[piowc];; // Wait for PIOs to complete. - hint @pause - and scr2=scr1,mask;; // mask of writecount bits - cmp.ne p6,p0=zeroval,scr2 -(p6) br.cond.sptk 5b - - - - ////////////// BEGIN PHYSICAL MODE //////////////////// - mov psrsave=psr // Disable IC (no PMIs) - rsm psr.i | psr.dt | psr.ic;; - srlz.i;; - - st8.rel [ptc0]=data0 // Write PTC0 & wait for completion. - -5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete. - hint @pause - and scr2=scr1,mask;; // mask of writecount bits - cmp.ne p6,p0=zeroval,scr2 -(p6) br.cond.sptk 5b;; - - tbit.nz p8,p7=scr1,DEADLOCKBIT;;// Test for DEADLOCK -(p7) cmp.ne p7,p0=r0,ptc1;; // Test for non-null ptc1 - -(p7) st8.rel [ptc1]=data1;; // Now write PTC1. - -5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete. - hint @pause - and scr2=scr1,mask;; // mask of writecount bits - cmp.ne p6,p0=zeroval,scr2 -(p6) br.cond.sptk 5b - - tbit.nz p8,p0=scr1,DEADLOCKBIT;;// Test for DEADLOCK - - mov psr.l=psrsave;; // Reenable IC - srlz.i;; - ////////////// END PHYSICAL MODE //////////////////// - -(p8) add r8=1,r8 -(p8) br.cond.spnt 1b;; // Repeat if DEADLOCK occurred. - - br.ret.sptk rp - .endp sn2_ptc_deadlock_recovery_core diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c deleted file mode 100644 index b510f4f17fd4679abf2e0de1fd5191f6f56d5a8f..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/sn2/sn2_smp.c +++ /dev/null @@ -1,577 +0,0 @@ -/* - * SN2 Platform specific SMP Support - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2006 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -DEFINE_PER_CPU(struct ptc_stats, ptcstats); -DECLARE_PER_CPU(struct ptc_stats, ptcstats); - -static __cacheline_aligned DEFINE_SPINLOCK(sn2_global_ptc_lock); - -/* 0 = old algorithm (no IPI flushes), 1 = ipi deadlock flush, 2 = ipi instead of SHUB ptc, >2 = always ipi */ -static int sn2_flush_opt = 0; - -extern unsigned long -sn2_ptc_deadlock_recovery_core(volatile unsigned long *, unsigned long, - volatile unsigned long *, unsigned long, - volatile unsigned long *, unsigned long); -void -sn2_ptc_deadlock_recovery(nodemask_t, short, short, int, - volatile unsigned long *, unsigned long, - volatile unsigned long *, unsigned long); - -/* - * Note: some is the following is captured here to make degugging easier - * (the macros make more sense if you see the debug patch - not posted) - */ -#define sn2_ptctest 0 -#define local_node_uses_ptc_ga(sh1) ((sh1) ? 1 : 0) -#define max_active_pio(sh1) ((sh1) ? 32 : 7) -#define reset_max_active_on_deadlock() 1 -#define PTC_LOCK(sh1) ((sh1) ? &sn2_global_ptc_lock : &sn_nodepda->ptc_lock) - -struct ptc_stats { - unsigned long ptc_l; - unsigned long change_rid; - unsigned long shub_ptc_flushes; - unsigned long nodes_flushed; - unsigned long deadlocks; - unsigned long deadlocks2; - unsigned long lock_itc_clocks; - unsigned long shub_itc_clocks; - unsigned long shub_itc_clocks_max; - unsigned long shub_ptc_flushes_not_my_mm; - unsigned long shub_ipi_flushes; - unsigned long shub_ipi_flushes_itc_clocks; -}; - -#define sn2_ptctest 0 - -static inline unsigned long wait_piowc(void) -{ - volatile unsigned long *piows; - unsigned long zeroval, ws; - - piows = pda->pio_write_status_addr; - zeroval = pda->pio_write_status_val; - do { - cpu_relax(); - } while (((ws = *piows) & SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK) != zeroval); - return (ws & SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK) != 0; -} - -/** - * sn_migrate - SN-specific task migration actions - * @task: Task being migrated to new CPU - * - * SN2 PIO writes from separate CPUs are not guaranteed to arrive in order. - * Context switching user threads which have memory-mapped MMIO may cause - * PIOs to issue from separate CPUs, thus the PIO writes must be drained - * from the previous CPU's Shub before execution resumes on the new CPU. - */ -void sn_migrate(struct task_struct *task) -{ - pda_t *last_pda = pdacpu(task_thread_info(task)->last_cpu); - volatile unsigned long *adr = last_pda->pio_write_status_addr; - unsigned long val = last_pda->pio_write_status_val; - - /* Drain PIO writes from old CPU's Shub */ - while (unlikely((*adr & SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK) - != val)) - cpu_relax(); -} - -static void -sn2_ipi_flush_all_tlb(struct mm_struct *mm) -{ - unsigned long itc; - - itc = ia64_get_itc(); - smp_flush_tlb_cpumask(*mm_cpumask(mm)); - itc = ia64_get_itc() - itc; - __this_cpu_add(ptcstats.shub_ipi_flushes_itc_clocks, itc); - __this_cpu_inc(ptcstats.shub_ipi_flushes); -} - -/** - * sn2_global_tlb_purge - globally purge translation cache of virtual address range - * @mm: mm_struct containing virtual address range - * @start: start of virtual address range - * @end: end of virtual address range - * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) - * - * Purges the translation caches of all processors of the given virtual address - * range. - * - * Note: - * - cpu_vm_mask is a bit mask that indicates which cpus have loaded the context. - * - cpu_vm_mask is converted into a nodemask of the nodes containing the - * cpus in cpu_vm_mask. - * - if only one bit is set in cpu_vm_mask & it is the current cpu & the - * process is purging its own virtual address range, then only the - * local TLB needs to be flushed. This flushing can be done using - * ptc.l. This is the common case & avoids the global spinlock. - * - if multiple cpus have loaded the context, then flushing has to be - * done with ptc.g/MMRs under protection of the global ptc_lock. - */ - -void -sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start, - unsigned long end, unsigned long nbits) -{ - int i, ibegin, shub1, cnode, mynasid, cpu, lcpu = 0, nasid; - int mymm = (mm == current->active_mm && mm == current->mm); - int use_cpu_ptcga; - volatile unsigned long *ptc0, *ptc1; - unsigned long itc, itc2, flags, data0 = 0, data1 = 0, rr_value, old_rr = 0; - short nix; - nodemask_t nodes_flushed; - int active, max_active, deadlock, flush_opt = sn2_flush_opt; - - if (flush_opt > 2) { - sn2_ipi_flush_all_tlb(mm); - return; - } - - nodes_clear(nodes_flushed); - i = 0; - - for_each_cpu(cpu, mm_cpumask(mm)) { - cnode = cpu_to_node(cpu); - node_set(cnode, nodes_flushed); - lcpu = cpu; - i++; - } - - if (i == 0) - return; - - preempt_disable(); - - if (likely(i == 1 && lcpu == smp_processor_id() && mymm)) { - do { - ia64_ptcl(start, nbits << 2); - start += (1UL << nbits); - } while (start < end); - ia64_srlz_i(); - __this_cpu_inc(ptcstats.ptc_l); - preempt_enable(); - return; - } - - if (atomic_read(&mm->mm_users) == 1 && mymm) { - flush_tlb_mm(mm); - __this_cpu_inc(ptcstats.change_rid); - preempt_enable(); - return; - } - - if (flush_opt == 2) { - sn2_ipi_flush_all_tlb(mm); - preempt_enable(); - return; - } - - itc = ia64_get_itc(); - nix = nodes_weight(nodes_flushed); - - rr_value = (mm->context << 3) | REGION_NUMBER(start); - - shub1 = is_shub1(); - if (shub1) { - data0 = (1UL << SH1_PTC_0_A_SHFT) | - (nbits << SH1_PTC_0_PS_SHFT) | - (rr_value << SH1_PTC_0_RID_SHFT) | - (1UL << SH1_PTC_0_START_SHFT); - ptc0 = (long *)GLOBAL_MMR_PHYS_ADDR(0, SH1_PTC_0); - ptc1 = (long *)GLOBAL_MMR_PHYS_ADDR(0, SH1_PTC_1); - } else { - data0 = (1UL << SH2_PTC_A_SHFT) | - (nbits << SH2_PTC_PS_SHFT) | - (1UL << SH2_PTC_START_SHFT); - ptc0 = (long *)GLOBAL_MMR_PHYS_ADDR(0, SH2_PTC + - (rr_value << SH2_PTC_RID_SHFT)); - ptc1 = NULL; - } - - - mynasid = get_nasid(); - use_cpu_ptcga = local_node_uses_ptc_ga(shub1); - max_active = max_active_pio(shub1); - - itc = ia64_get_itc(); - spin_lock_irqsave(PTC_LOCK(shub1), flags); - itc2 = ia64_get_itc(); - - __this_cpu_add(ptcstats.lock_itc_clocks, itc2 - itc); - __this_cpu_inc(ptcstats.shub_ptc_flushes); - __this_cpu_add(ptcstats.nodes_flushed, nix); - if (!mymm) - __this_cpu_inc(ptcstats.shub_ptc_flushes_not_my_mm); - - if (use_cpu_ptcga && !mymm) { - old_rr = ia64_get_rr(start); - ia64_set_rr(start, (old_rr & 0xff) | (rr_value << 8)); - ia64_srlz_d(); - } - - wait_piowc(); - do { - if (shub1) - data1 = start | (1UL << SH1_PTC_1_START_SHFT); - else - data0 = (data0 & ~SH2_PTC_ADDR_MASK) | (start & SH2_PTC_ADDR_MASK); - deadlock = 0; - active = 0; - ibegin = 0; - i = 0; - for_each_node_mask(cnode, nodes_flushed) { - nasid = cnodeid_to_nasid(cnode); - if (use_cpu_ptcga && unlikely(nasid == mynasid)) { - ia64_ptcga(start, nbits << 2); - ia64_srlz_i(); - } else { - ptc0 = CHANGE_NASID(nasid, ptc0); - if (ptc1) - ptc1 = CHANGE_NASID(nasid, ptc1); - pio_atomic_phys_write_mmrs(ptc0, data0, ptc1, data1); - active++; - } - if (active >= max_active || i == (nix - 1)) { - if ((deadlock = wait_piowc())) { - if (flush_opt == 1) - goto done; - sn2_ptc_deadlock_recovery(nodes_flushed, ibegin, i, mynasid, ptc0, data0, ptc1, data1); - if (reset_max_active_on_deadlock()) - max_active = 1; - } - active = 0; - ibegin = i + 1; - } - i++; - } - start += (1UL << nbits); - } while (start < end); - -done: - itc2 = ia64_get_itc() - itc2; - __this_cpu_add(ptcstats.shub_itc_clocks, itc2); - if (itc2 > __this_cpu_read(ptcstats.shub_itc_clocks_max)) - __this_cpu_write(ptcstats.shub_itc_clocks_max, itc2); - - if (old_rr) { - ia64_set_rr(start, old_rr); - ia64_srlz_d(); - } - - spin_unlock_irqrestore(PTC_LOCK(shub1), flags); - - if (flush_opt == 1 && deadlock) { - __this_cpu_inc(ptcstats.deadlocks); - sn2_ipi_flush_all_tlb(mm); - } - - preempt_enable(); -} - -/* - * sn2_ptc_deadlock_recovery - * - * Recover from PTC deadlocks conditions. Recovery requires stepping thru each - * TLB flush transaction. The recovery sequence is somewhat tricky & is - * coded in assembly language. - */ - -void -sn2_ptc_deadlock_recovery(nodemask_t nodes, short ib, short ie, int mynasid, - volatile unsigned long *ptc0, unsigned long data0, - volatile unsigned long *ptc1, unsigned long data1) -{ - short nasid, i; - int cnode; - unsigned long *piows, zeroval, n; - - __this_cpu_inc(ptcstats.deadlocks); - - piows = (unsigned long *) pda->pio_write_status_addr; - zeroval = pda->pio_write_status_val; - - i = 0; - for_each_node_mask(cnode, nodes) { - if (i < ib) - goto next; - - if (i > ie) - break; - - nasid = cnodeid_to_nasid(cnode); - if (local_node_uses_ptc_ga(is_shub1()) && nasid == mynasid) - goto next; - - ptc0 = CHANGE_NASID(nasid, ptc0); - if (ptc1) - ptc1 = CHANGE_NASID(nasid, ptc1); - - n = sn2_ptc_deadlock_recovery_core(ptc0, data0, ptc1, data1, piows, zeroval); - __this_cpu_add(ptcstats.deadlocks2, n); -next: - i++; - } - -} - -/** - * sn_send_IPI_phys - send an IPI to a Nasid and slice - * @nasid: nasid to receive the interrupt (may be outside partition) - * @physid: physical cpuid to receive the interrupt. - * @vector: command to send - * @delivery_mode: delivery mechanism - * - * Sends an IPI (interprocessor interrupt) to the processor specified by - * @physid - * - * @delivery_mode can be one of the following - * - * %IA64_IPI_DM_INT - pend an interrupt - * %IA64_IPI_DM_PMI - pend a PMI - * %IA64_IPI_DM_NMI - pend an NMI - * %IA64_IPI_DM_INIT - pend an INIT interrupt - */ -void sn_send_IPI_phys(int nasid, long physid, int vector, int delivery_mode) -{ - long val; - unsigned long flags = 0; - volatile long *p; - - p = (long *)GLOBAL_MMR_PHYS_ADDR(nasid, SH_IPI_INT); - val = (1UL << SH_IPI_INT_SEND_SHFT) | - (physid << SH_IPI_INT_PID_SHFT) | - ((long)delivery_mode << SH_IPI_INT_TYPE_SHFT) | - ((long)vector << SH_IPI_INT_IDX_SHFT) | - (0x000feeUL << SH_IPI_INT_BASE_SHFT); - - mb(); - if (enable_shub_wars_1_1()) { - spin_lock_irqsave(&sn2_global_ptc_lock, flags); - } - pio_phys_write_mmr(p, val); - if (enable_shub_wars_1_1()) { - wait_piowc(); - spin_unlock_irqrestore(&sn2_global_ptc_lock, flags); - } - -} - -EXPORT_SYMBOL(sn_send_IPI_phys); - -/** - * sn2_send_IPI - send an IPI to a processor - * @cpuid: target of the IPI - * @vector: command to send - * @delivery_mode: delivery mechanism - * @redirect: redirect the IPI? - * - * Sends an IPI (InterProcessor Interrupt) to the processor specified by - * @cpuid. @vector specifies the command to send, while @delivery_mode can - * be one of the following - * - * %IA64_IPI_DM_INT - pend an interrupt - * %IA64_IPI_DM_PMI - pend a PMI - * %IA64_IPI_DM_NMI - pend an NMI - * %IA64_IPI_DM_INIT - pend an INIT interrupt - */ -void sn2_send_IPI(int cpuid, int vector, int delivery_mode, int redirect) -{ - long physid; - int nasid; - - physid = cpu_physical_id(cpuid); - nasid = cpuid_to_nasid(cpuid); - - /* the following is used only when starting cpus at boot time */ - if (unlikely(nasid == -1)) - ia64_sn_get_sapic_info(physid, &nasid, NULL, NULL); - - sn_send_IPI_phys(nasid, physid, vector, delivery_mode); -} - -#ifdef CONFIG_HOTPLUG_CPU -/** - * sn_cpu_disable_allowed - Determine if a CPU can be disabled. - * @cpu - CPU that is requested to be disabled. - * - * CPU disable is only allowed on SHub2 systems running with a PROM - * that supports CPU disable. It is not permitted to disable the boot processor. - */ -bool sn_cpu_disable_allowed(int cpu) -{ - if (is_shub2() && sn_prom_feature_available(PRF_CPU_DISABLE_SUPPORT)) { - if (cpu != 0) - return true; - else - printk(KERN_WARNING - "Disabling the boot processor is not allowed.\n"); - - } else - printk(KERN_WARNING - "CPU disable is not supported on this system.\n"); - - return false; -} -#endif /* CONFIG_HOTPLUG_CPU */ - -#ifdef CONFIG_PROC_FS - -#define PTC_BASENAME "sgi_sn/ptc_statistics" - -static void *sn2_ptc_seq_start(struct seq_file *file, loff_t * offset) -{ - if (*offset < nr_cpu_ids) - return offset; - return NULL; -} - -static void *sn2_ptc_seq_next(struct seq_file *file, void *data, loff_t * offset) -{ - (*offset)++; - if (*offset < nr_cpu_ids) - return offset; - return NULL; -} - -static void sn2_ptc_seq_stop(struct seq_file *file, void *data) -{ -} - -static int sn2_ptc_seq_show(struct seq_file *file, void *data) -{ - struct ptc_stats *stat; - int cpu; - - cpu = *(loff_t *) data; - - if (!cpu) { - seq_printf(file, - "# cpu ptc_l newrid ptc_flushes nodes_flushed deadlocks lock_nsec shub_nsec shub_nsec_max not_my_mm deadlock2 ipi_fluches ipi_nsec\n"); - seq_printf(file, "# ptctest %d, flushopt %d\n", sn2_ptctest, sn2_flush_opt); - } - - if (cpu < nr_cpu_ids && cpu_online(cpu)) { - stat = &per_cpu(ptcstats, cpu); - seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n", cpu, stat->ptc_l, - stat->change_rid, stat->shub_ptc_flushes, stat->nodes_flushed, - stat->deadlocks, - 1000 * stat->lock_itc_clocks / per_cpu(ia64_cpu_info, cpu).cyc_per_usec, - 1000 * stat->shub_itc_clocks / per_cpu(ia64_cpu_info, cpu).cyc_per_usec, - 1000 * stat->shub_itc_clocks_max / per_cpu(ia64_cpu_info, cpu).cyc_per_usec, - stat->shub_ptc_flushes_not_my_mm, - stat->deadlocks2, - stat->shub_ipi_flushes, - 1000 * stat->shub_ipi_flushes_itc_clocks / per_cpu(ia64_cpu_info, cpu).cyc_per_usec); - } - return 0; -} - -static ssize_t sn2_ptc_proc_write(struct file *file, const char __user *user, size_t count, loff_t *data) -{ - int cpu; - char optstr[64]; - - if (count == 0 || count > sizeof(optstr)) - return -EINVAL; - if (copy_from_user(optstr, user, count)) - return -EFAULT; - optstr[count - 1] = '\0'; - sn2_flush_opt = simple_strtoul(optstr, NULL, 0); - - for_each_online_cpu(cpu) - memset(&per_cpu(ptcstats, cpu), 0, sizeof(struct ptc_stats)); - - return count; -} - -static const struct seq_operations sn2_ptc_seq_ops = { - .start = sn2_ptc_seq_start, - .next = sn2_ptc_seq_next, - .stop = sn2_ptc_seq_stop, - .show = sn2_ptc_seq_show -}; - -static int sn2_ptc_proc_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &sn2_ptc_seq_ops); -} - -static const struct file_operations proc_sn2_ptc_operations = { - .open = sn2_ptc_proc_open, - .read = seq_read, - .write = sn2_ptc_proc_write, - .llseek = seq_lseek, - .release = seq_release, -}; - -static struct proc_dir_entry *proc_sn2_ptc; - -static int __init sn2_ptc_init(void) -{ - if (!ia64_platform_is("sn2")) - return 0; - - proc_sn2_ptc = proc_create(PTC_BASENAME, 0444, - NULL, &proc_sn2_ptc_operations); - if (!proc_sn2_ptc) { - printk(KERN_ERR "unable to create %s proc entry", PTC_BASENAME); - return -EINVAL; - } - spin_lock_init(&sn2_global_ptc_lock); - return 0; -} - -static void __exit sn2_ptc_exit(void) -{ - remove_proc_entry(PTC_BASENAME, NULL); -} - -module_init(sn2_ptc_init); -module_exit(sn2_ptc_exit); -#endif /* CONFIG_PROC_FS */ - diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c deleted file mode 100644 index 55febd65911a7165b59f71b9e60a0062a137d84f..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c +++ /dev/null @@ -1,1004 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2004-2006 Silicon Graphics, Inc. All rights reserved. - * - * SGI Altix topology and hardware performance monitoring API. - * Mark Goodwin . - * - * Creates /proc/sgi_sn/sn_topology (read-only) to export - * info about Altix nodes, routers, CPUs and NumaLink - * interconnection/topology. - * - * Also creates a dynamic misc device named "sn_hwperf" - * that supports an ioctl interface to call down into SAL - * to discover hw objects, topology and to read/write - * memory mapped registers, e.g. for performance monitoring. - * The "sn_hwperf" device is registered only after the procfs - * file is first opened, i.e. only if/when it's needed. - * - * This API is used by SGI Performance Co-Pilot and other - * tools, see http://oss.sgi.com/projects/pcp - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void *sn_hwperf_salheap = NULL; -static int sn_hwperf_obj_cnt = 0; -static nasid_t sn_hwperf_master_nasid = INVALID_NASID; -static int sn_hwperf_init(void); -static DEFINE_MUTEX(sn_hwperf_init_mutex); - -#define cnode_possible(n) ((n) < num_cnodes) - -static int sn_hwperf_enum_objects(int *nobj, struct sn_hwperf_object_info **ret) -{ - int e; - u64 sz; - struct sn_hwperf_object_info *objbuf = NULL; - - if ((e = sn_hwperf_init()) < 0) { - printk(KERN_ERR "sn_hwperf_init failed: err %d\n", e); - goto out; - } - - sz = sn_hwperf_obj_cnt * sizeof(struct sn_hwperf_object_info); - objbuf = vmalloc(sz); - if (objbuf == NULL) { - printk("sn_hwperf_enum_objects: vmalloc(%d) failed\n", (int)sz); - e = -ENOMEM; - goto out; - } - - e = ia64_sn_hwperf_op(sn_hwperf_master_nasid, SN_HWPERF_ENUM_OBJECTS, - 0, sz, (u64) objbuf, 0, 0, NULL); - if (e != SN_HWPERF_OP_OK) { - e = -EINVAL; - vfree(objbuf); - } - -out: - *nobj = sn_hwperf_obj_cnt; - *ret = objbuf; - return e; -} - -static int sn_hwperf_location_to_bpos(char *location, - int *rack, int *bay, int *slot, int *slab) -{ - char type; - - /* first scan for an old style geoid string */ - if (sscanf(location, "%03d%c%02d#%d", - rack, &type, bay, slab) == 4) - *slot = 0; - else /* scan for a new bladed geoid string */ - if (sscanf(location, "%03d%c%02d^%02d#%d", - rack, &type, bay, slot, slab) != 5) - return -1; - /* success */ - return 0; -} - -static int sn_hwperf_geoid_to_cnode(char *location) -{ - int cnode; - geoid_t geoid; - moduleid_t module_id; - int rack, bay, slot, slab; - int this_rack, this_bay, this_slot, this_slab; - - if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab)) - return -1; - - /* - * FIXME: replace with cleaner for_each_XXX macro which addresses - * both compute and IO nodes once ACPI3.0 is available. - */ - for (cnode = 0; cnode < num_cnodes; cnode++) { - geoid = cnodeid_get_geoid(cnode); - module_id = geo_module(geoid); - this_rack = MODULE_GET_RACK(module_id); - this_bay = MODULE_GET_BPOS(module_id); - this_slot = geo_slot(geoid); - this_slab = geo_slab(geoid); - if (rack == this_rack && bay == this_bay && - slot == this_slot && slab == this_slab) { - break; - } - } - - return cnode_possible(cnode) ? cnode : -1; -} - -static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj) -{ - if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj)) - BUG(); - if (SN_HWPERF_FOREIGN(obj)) - return -1; - return sn_hwperf_geoid_to_cnode(obj->location); -} - -static int sn_hwperf_generic_ordinal(struct sn_hwperf_object_info *obj, - struct sn_hwperf_object_info *objs) -{ - int ordinal; - struct sn_hwperf_object_info *p; - - for (ordinal=0, p=objs; p != obj; p++) { - if (SN_HWPERF_FOREIGN(p)) - continue; - if (SN_HWPERF_SAME_OBJTYPE(p, obj)) - ordinal++; - } - - return ordinal; -} - -static const char *slabname_node = "node"; /* SHub asic */ -static const char *slabname_ionode = "ionode"; /* TIO asic */ -static const char *slabname_router = "router"; /* NL3R or NL4R */ -static const char *slabname_other = "other"; /* unknown asic */ - -static const char *sn_hwperf_get_slabname(struct sn_hwperf_object_info *obj, - struct sn_hwperf_object_info *objs, int *ordinal) -{ - int isnode; - const char *slabname = slabname_other; - - if ((isnode = SN_HWPERF_IS_NODE(obj)) || SN_HWPERF_IS_IONODE(obj)) { - slabname = isnode ? slabname_node : slabname_ionode; - *ordinal = sn_hwperf_obj_to_cnode(obj); - } - else { - *ordinal = sn_hwperf_generic_ordinal(obj, objs); - if (SN_HWPERF_IS_ROUTER(obj)) - slabname = slabname_router; - } - - return slabname; -} - -static void print_pci_topology(struct seq_file *s) -{ - char *p; - size_t sz; - int e; - - for (sz = PAGE_SIZE; sz < 16 * PAGE_SIZE; sz += PAGE_SIZE) { - if (!(p = kmalloc(sz, GFP_KERNEL))) - break; - e = ia64_sn_ioif_get_pci_topology(__pa(p), sz); - if (e == SALRET_OK) - seq_puts(s, p); - kfree(p); - if (e == SALRET_OK || e == SALRET_NOT_IMPLEMENTED) - break; - } -} - -static inline int sn_hwperf_has_cpus(cnodeid_t node) -{ - return node < MAX_NUMNODES && node_online(node) && nr_cpus_node(node); -} - -static inline int sn_hwperf_has_mem(cnodeid_t node) -{ - return node < MAX_NUMNODES && node_online(node) && NODE_DATA(node)->node_present_pages; -} - -static struct sn_hwperf_object_info * -sn_hwperf_findobj_id(struct sn_hwperf_object_info *objbuf, - int nobj, int id) -{ - int i; - struct sn_hwperf_object_info *p = objbuf; - - for (i=0; i < nobj; i++, p++) { - if (p->id == id) - return p; - } - - return NULL; - -} - -static int sn_hwperf_get_nearest_node_objdata(struct sn_hwperf_object_info *objbuf, - int nobj, cnodeid_t node, cnodeid_t *near_mem_node, cnodeid_t *near_cpu_node) -{ - int e; - struct sn_hwperf_object_info *nodeobj = NULL; - struct sn_hwperf_object_info *op; - struct sn_hwperf_object_info *dest; - struct sn_hwperf_object_info *router; - struct sn_hwperf_port_info ptdata[16]; - int sz, i, j; - cnodeid_t c; - int found_mem = 0; - int found_cpu = 0; - - if (!cnode_possible(node)) - return -EINVAL; - - if (sn_hwperf_has_cpus(node)) { - if (near_cpu_node) - *near_cpu_node = node; - found_cpu++; - } - - if (sn_hwperf_has_mem(node)) { - if (near_mem_node) - *near_mem_node = node; - found_mem++; - } - - if (found_cpu && found_mem) - return 0; /* trivially successful */ - - /* find the argument node object */ - for (i=0, op=objbuf; i < nobj; i++, op++) { - if (!SN_HWPERF_IS_NODE(op) && !SN_HWPERF_IS_IONODE(op)) - continue; - if (node == sn_hwperf_obj_to_cnode(op)) { - nodeobj = op; - break; - } - } - if (!nodeobj) { - e = -ENOENT; - goto err; - } - - /* get it's interconnect topology */ - sz = op->ports * sizeof(struct sn_hwperf_port_info); - BUG_ON(sz > sizeof(ptdata)); - e = ia64_sn_hwperf_op(sn_hwperf_master_nasid, - SN_HWPERF_ENUM_PORTS, nodeobj->id, sz, - (u64)&ptdata, 0, 0, NULL); - if (e != SN_HWPERF_OP_OK) { - e = -EINVAL; - goto err; - } - - /* find nearest node with cpus and nearest memory */ - for (router=NULL, j=0; j < op->ports; j++) { - dest = sn_hwperf_findobj_id(objbuf, nobj, ptdata[j].conn_id); - if (dest && SN_HWPERF_IS_ROUTER(dest)) - router = dest; - if (!dest || SN_HWPERF_FOREIGN(dest) || - !SN_HWPERF_IS_NODE(dest) || SN_HWPERF_IS_IONODE(dest)) { - continue; - } - c = sn_hwperf_obj_to_cnode(dest); - if (!found_cpu && sn_hwperf_has_cpus(c)) { - if (near_cpu_node) - *near_cpu_node = c; - found_cpu++; - } - if (!found_mem && sn_hwperf_has_mem(c)) { - if (near_mem_node) - *near_mem_node = c; - found_mem++; - } - } - - if (router && (!found_cpu || !found_mem)) { - /* search for a node connected to the same router */ - sz = router->ports * sizeof(struct sn_hwperf_port_info); - BUG_ON(sz > sizeof(ptdata)); - e = ia64_sn_hwperf_op(sn_hwperf_master_nasid, - SN_HWPERF_ENUM_PORTS, router->id, sz, - (u64)&ptdata, 0, 0, NULL); - if (e != SN_HWPERF_OP_OK) { - e = -EINVAL; - goto err; - } - for (j=0; j < router->ports; j++) { - dest = sn_hwperf_findobj_id(objbuf, nobj, - ptdata[j].conn_id); - if (!dest || dest->id == node || - SN_HWPERF_FOREIGN(dest) || - !SN_HWPERF_IS_NODE(dest) || - SN_HWPERF_IS_IONODE(dest)) { - continue; - } - c = sn_hwperf_obj_to_cnode(dest); - if (!found_cpu && sn_hwperf_has_cpus(c)) { - if (near_cpu_node) - *near_cpu_node = c; - found_cpu++; - } - if (!found_mem && sn_hwperf_has_mem(c)) { - if (near_mem_node) - *near_mem_node = c; - found_mem++; - } - if (found_cpu && found_mem) - break; - } - } - - if (!found_cpu || !found_mem) { - /* resort to _any_ node with CPUs and memory */ - for (i=0, op=objbuf; i < nobj; i++, op++) { - if (SN_HWPERF_FOREIGN(op) || - SN_HWPERF_IS_IONODE(op) || - !SN_HWPERF_IS_NODE(op)) { - continue; - } - c = sn_hwperf_obj_to_cnode(op); - if (!found_cpu && sn_hwperf_has_cpus(c)) { - if (near_cpu_node) - *near_cpu_node = c; - found_cpu++; - } - if (!found_mem && sn_hwperf_has_mem(c)) { - if (near_mem_node) - *near_mem_node = c; - found_mem++; - } - if (found_cpu && found_mem) - break; - } - } - - if (!found_cpu || !found_mem) - e = -ENODATA; - -err: - return e; -} - - -static int sn_topology_show(struct seq_file *s, void *d) -{ - int sz; - int pt; - int e = 0; - int i; - int j; - const char *slabname; - int ordinal; - char slice; - struct cpuinfo_ia64 *c; - struct sn_hwperf_port_info *ptdata; - struct sn_hwperf_object_info *p; - struct sn_hwperf_object_info *obj = d; /* this object */ - struct sn_hwperf_object_info *objs = s->private; /* all objects */ - u8 shubtype; - u8 system_size; - u8 sharing_size; - u8 partid; - u8 coher; - u8 nasid_shift; - u8 region_size; - u16 nasid_mask; - int nasid_msb; - - if (obj == objs) { - seq_printf(s, "# sn_topology version 2\n"); - seq_printf(s, "# objtype ordinal location partition" - " [attribute value [, ...]]\n"); - - if (ia64_sn_get_sn_info(0, - &shubtype, &nasid_mask, &nasid_shift, &system_size, - &sharing_size, &partid, &coher, ®ion_size)) - BUG(); - for (nasid_msb=63; nasid_msb > 0; nasid_msb--) { - if (((u64)nasid_mask << nasid_shift) & (1ULL << nasid_msb)) - break; - } - seq_printf(s, "partition %u %s local " - "shubtype %s, " - "nasid_mask 0x%016llx, " - "nasid_bits %d:%d, " - "system_size %d, " - "sharing_size %d, " - "coherency_domain %d, " - "region_size %d\n", - - partid, utsname()->nodename, - shubtype ? "shub2" : "shub1", - (u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift, - system_size, sharing_size, coher, region_size); - - print_pci_topology(s); - } - - if (SN_HWPERF_FOREIGN(obj)) { - /* private in another partition: not interesting */ - return 0; - } - - for (i = 0; i < SN_HWPERF_MAXSTRING && obj->name[i]; i++) { - if (obj->name[i] == ' ') - obj->name[i] = '_'; - } - - slabname = sn_hwperf_get_slabname(obj, objs, &ordinal); - seq_printf(s, "%s %d %s %s asic %s", slabname, ordinal, obj->location, - obj->sn_hwp_this_part ? "local" : "shared", obj->name); - - if (ordinal < 0 || (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj))) - seq_putc(s, '\n'); - else { - cnodeid_t near_mem = -1; - cnodeid_t near_cpu = -1; - - seq_printf(s, ", nasid 0x%x", cnodeid_to_nasid(ordinal)); - - if (sn_hwperf_get_nearest_node_objdata(objs, sn_hwperf_obj_cnt, - ordinal, &near_mem, &near_cpu) == 0) { - seq_printf(s, ", near_mem_nodeid %d, near_cpu_nodeid %d", - near_mem, near_cpu); - } - - if (!SN_HWPERF_IS_IONODE(obj)) { - for_each_online_node(i) { - seq_printf(s, i ? ":%d" : ", dist %d", - node_distance(ordinal, i)); - } - } - - seq_putc(s, '\n'); - - /* - * CPUs on this node, if any - */ - if (!SN_HWPERF_IS_IONODE(obj)) { - for_each_cpu_and(i, cpu_online_mask, - cpumask_of_node(ordinal)) { - slice = 'a' + cpuid_to_slice(i); - c = cpu_data(i); - seq_printf(s, "cpu %d %s%c local" - " freq %luMHz, arch ia64", - i, obj->location, slice, - c->proc_freq / 1000000); - for_each_online_cpu(j) { - seq_printf(s, j ? ":%d" : ", dist %d", - node_distance( - cpu_to_node(i), - cpu_to_node(j))); - } - seq_putc(s, '\n'); - } - } - } - - if (obj->ports) { - /* - * numalink ports - */ - sz = obj->ports * sizeof(struct sn_hwperf_port_info); - if ((ptdata = kmalloc(sz, GFP_KERNEL)) == NULL) - return -ENOMEM; - e = ia64_sn_hwperf_op(sn_hwperf_master_nasid, - SN_HWPERF_ENUM_PORTS, obj->id, sz, - (u64) ptdata, 0, 0, NULL); - if (e != SN_HWPERF_OP_OK) - return -EINVAL; - for (ordinal=0, p=objs; p != obj; p++) { - if (!SN_HWPERF_FOREIGN(p)) - ordinal += p->ports; - } - for (pt = 0; pt < obj->ports; pt++) { - for (p = objs, i = 0; i < sn_hwperf_obj_cnt; i++, p++) { - if (ptdata[pt].conn_id == p->id) { - break; - } - } - seq_printf(s, "numalink %d %s-%d", - ordinal+pt, obj->location, ptdata[pt].port); - - if (i >= sn_hwperf_obj_cnt) { - /* no connection */ - seq_puts(s, " local endpoint disconnected" - ", protocol unknown\n"); - continue; - } - - if (obj->sn_hwp_this_part && p->sn_hwp_this_part) - /* both ends local to this partition */ - seq_puts(s, " local"); - else if (SN_HWPERF_FOREIGN(p)) - /* both ends of the link in foreign partition */ - seq_puts(s, " foreign"); - else - /* link straddles a partition */ - seq_puts(s, " shared"); - - /* - * Unlikely, but strictly should query the LLP config - * registers because an NL4R can be configured to run - * NL3 protocol, even when not talking to an NL3 router. - * Ditto for node-node. - */ - seq_printf(s, " endpoint %s-%d, protocol %s\n", - p->location, ptdata[pt].conn_port, - (SN_HWPERF_IS_NL3ROUTER(obj) || - SN_HWPERF_IS_NL3ROUTER(p)) ? "LLP3" : "LLP4"); - } - kfree(ptdata); - } - - return 0; -} - -static void *sn_topology_start(struct seq_file *s, loff_t * pos) -{ - struct sn_hwperf_object_info *objs = s->private; - - if (*pos < sn_hwperf_obj_cnt) - return (void *)(objs + *pos); - - return NULL; -} - -static void *sn_topology_next(struct seq_file *s, void *v, loff_t * pos) -{ - ++*pos; - return sn_topology_start(s, pos); -} - -static void sn_topology_stop(struct seq_file *m, void *v) -{ - return; -} - -/* - * /proc/sgi_sn/sn_topology, read-only using seq_file - */ -static const struct seq_operations sn_topology_seq_ops = { - .start = sn_topology_start, - .next = sn_topology_next, - .stop = sn_topology_stop, - .show = sn_topology_show -}; - -struct sn_hwperf_op_info { - u64 op; - struct sn_hwperf_ioctl_args *a; - void *p; - int *v0; - int ret; -}; - -static void sn_hwperf_call_sal(void *info) -{ - struct sn_hwperf_op_info *op_info = info; - int r; - - r = ia64_sn_hwperf_op(sn_hwperf_master_nasid, op_info->op, - op_info->a->arg, op_info->a->sz, - (u64) op_info->p, 0, 0, op_info->v0); - op_info->ret = r; -} - -static long sn_hwperf_call_sal_work(void *info) -{ - sn_hwperf_call_sal(info); - return 0; -} - -static int sn_hwperf_op_cpu(struct sn_hwperf_op_info *op_info) -{ - u32 cpu; - u32 use_ipi; - int r = 0; - - cpu = (op_info->a->arg & SN_HWPERF_ARG_CPU_MASK) >> 32; - use_ipi = op_info->a->arg & SN_HWPERF_ARG_USE_IPI_MASK; - op_info->a->arg &= SN_HWPERF_ARG_OBJID_MASK; - - if (cpu != SN_HWPERF_ARG_ANY_CPU) { - if (cpu >= nr_cpu_ids || !cpu_online(cpu)) { - r = -EINVAL; - goto out; - } - } - - if (cpu == SN_HWPERF_ARG_ANY_CPU) { - /* don't care which cpu */ - sn_hwperf_call_sal(op_info); - } else if (cpu == get_cpu()) { - /* already on correct cpu */ - sn_hwperf_call_sal(op_info); - put_cpu(); - } else { - put_cpu(); - if (use_ipi) { - /* use an interprocessor interrupt to call SAL */ - smp_call_function_single(cpu, sn_hwperf_call_sal, - op_info, 1); - } else { - /* Call on the target CPU */ - work_on_cpu_safe(cpu, sn_hwperf_call_sal_work, op_info); - } - } - r = op_info->ret; - -out: - return r; -} - -/* map SAL hwperf error code to system error code */ -static int sn_hwperf_map_err(int hwperf_err) -{ - int e; - - switch(hwperf_err) { - case SN_HWPERF_OP_OK: - e = 0; - break; - - case SN_HWPERF_OP_NOMEM: - e = -ENOMEM; - break; - - case SN_HWPERF_OP_NO_PERM: - e = -EPERM; - break; - - case SN_HWPERF_OP_IO_ERROR: - e = -EIO; - break; - - case SN_HWPERF_OP_BUSY: - e = -EBUSY; - break; - - case SN_HWPERF_OP_RECONFIGURE: - e = -EAGAIN; - break; - - case SN_HWPERF_OP_INVAL: - default: - e = -EINVAL; - break; - } - - return e; -} - -/* - * ioctl for "sn_hwperf" misc device - */ -static long sn_hwperf_ioctl(struct file *fp, u32 op, unsigned long arg) -{ - struct sn_hwperf_ioctl_args a; - struct cpuinfo_ia64 *cdata; - struct sn_hwperf_object_info *objs; - struct sn_hwperf_object_info *cpuobj; - struct sn_hwperf_op_info op_info; - void *p = NULL; - int nobj; - char slice; - int node; - int r; - int v0; - int i; - int j; - - /* only user requests are allowed here */ - if ((op & SN_HWPERF_OP_MASK) < 10) { - r = -EINVAL; - goto error; - } - r = copy_from_user(&a, (const void __user *)arg, - sizeof(struct sn_hwperf_ioctl_args)); - if (r != 0) { - r = -EFAULT; - goto error; - } - - /* - * Allocate memory to hold a kernel copy of the user buffer. The - * buffer contents are either copied in or out (or both) of user - * space depending on the flags encoded in the requested operation. - */ - if (a.ptr) { - p = vmalloc(a.sz); - if (!p) { - r = -ENOMEM; - goto error; - } - } - - if (op & SN_HWPERF_OP_MEM_COPYIN) { - r = copy_from_user(p, (const void __user *)a.ptr, a.sz); - if (r != 0) { - r = -EFAULT; - goto error; - } - } - - switch (op) { - case SN_HWPERF_GET_CPU_INFO: - if (a.sz == sizeof(u64)) { - /* special case to get size needed */ - *(u64 *) p = (u64) num_online_cpus() * - sizeof(struct sn_hwperf_object_info); - } else - if (a.sz < num_online_cpus() * sizeof(struct sn_hwperf_object_info)) { - r = -ENOMEM; - goto error; - } else - if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) { - int cpuobj_index = 0; - - memset(p, 0, a.sz); - for (i = 0; i < nobj; i++) { - if (!SN_HWPERF_IS_NODE(objs + i)) - continue; - node = sn_hwperf_obj_to_cnode(objs + i); - for_each_online_cpu(j) { - if (node != cpu_to_node(j)) - continue; - cpuobj = (struct sn_hwperf_object_info *) p + cpuobj_index++; - slice = 'a' + cpuid_to_slice(j); - cdata = cpu_data(j); - cpuobj->id = j; - snprintf(cpuobj->name, - sizeof(cpuobj->name), - "CPU %luMHz %s", - cdata->proc_freq / 1000000, - cdata->vendor); - snprintf(cpuobj->location, - sizeof(cpuobj->location), - "%s%c", objs[i].location, - slice); - } - } - - vfree(objs); - } - break; - - case SN_HWPERF_GET_NODE_NASID: - if (a.sz != sizeof(u64) || - (node = a.arg) < 0 || !cnode_possible(node)) { - r = -EINVAL; - goto error; - } - *(u64 *)p = (u64)cnodeid_to_nasid(node); - break; - - case SN_HWPERF_GET_OBJ_NODE: - i = a.arg; - if (a.sz != sizeof(u64) || i < 0) { - r = -EINVAL; - goto error; - } - if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) { - if (i >= nobj) { - r = -EINVAL; - vfree(objs); - goto error; - } - if (objs[i].id != a.arg) { - for (i = 0; i < nobj; i++) { - if (objs[i].id == a.arg) - break; - } - } - if (i == nobj) { - r = -EINVAL; - vfree(objs); - goto error; - } - - if (!SN_HWPERF_IS_NODE(objs + i) && - !SN_HWPERF_IS_IONODE(objs + i)) { - r = -ENOENT; - vfree(objs); - goto error; - } - - *(u64 *)p = (u64)sn_hwperf_obj_to_cnode(objs + i); - vfree(objs); - } - break; - - case SN_HWPERF_GET_MMRS: - case SN_HWPERF_SET_MMRS: - case SN_HWPERF_OBJECT_DISTANCE: - op_info.p = p; - op_info.a = &a; - op_info.v0 = &v0; - op_info.op = op; - r = sn_hwperf_op_cpu(&op_info); - if (r) { - r = sn_hwperf_map_err(r); - a.v0 = v0; - goto error; - } - break; - - default: - /* all other ops are a direct SAL call */ - r = ia64_sn_hwperf_op(sn_hwperf_master_nasid, op, - a.arg, a.sz, (u64) p, 0, 0, &v0); - if (r) { - r = sn_hwperf_map_err(r); - goto error; - } - a.v0 = v0; - break; - } - - if (op & SN_HWPERF_OP_MEM_COPYOUT) { - r = copy_to_user((void __user *)a.ptr, p, a.sz); - if (r != 0) { - r = -EFAULT; - goto error; - } - } - -error: - vfree(p); - - return r; -} - -static const struct file_operations sn_hwperf_fops = { - .unlocked_ioctl = sn_hwperf_ioctl, - .llseek = noop_llseek, -}; - -static struct miscdevice sn_hwperf_dev = { - MISC_DYNAMIC_MINOR, - "sn_hwperf", - &sn_hwperf_fops -}; - -static int sn_hwperf_init(void) -{ - u64 v; - int salr; - int e = 0; - - /* single threaded, once-only initialization */ - mutex_lock(&sn_hwperf_init_mutex); - - if (sn_hwperf_salheap) { - mutex_unlock(&sn_hwperf_init_mutex); - return e; - } - - /* - * The PROM code needs a fixed reference node. For convenience the - * same node as the console I/O is used. - */ - sn_hwperf_master_nasid = (nasid_t) ia64_sn_get_console_nasid(); - - /* - * Request the needed size and install the PROM scratch area. - * The PROM keeps various tracking bits in this memory area. - */ - salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid, - (u64) SN_HWPERF_GET_HEAPSIZE, 0, - (u64) sizeof(u64), (u64) &v, 0, 0, NULL); - if (salr != SN_HWPERF_OP_OK) { - e = -EINVAL; - goto out; - } - - if ((sn_hwperf_salheap = vmalloc(v)) == NULL) { - e = -ENOMEM; - goto out; - } - salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid, - SN_HWPERF_INSTALL_HEAP, 0, v, - (u64) sn_hwperf_salheap, 0, 0, NULL); - if (salr != SN_HWPERF_OP_OK) { - e = -EINVAL; - goto out; - } - - salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid, - SN_HWPERF_OBJECT_COUNT, 0, - sizeof(u64), (u64) &v, 0, 0, NULL); - if (salr != SN_HWPERF_OP_OK) { - e = -EINVAL; - goto out; - } - sn_hwperf_obj_cnt = (int)v; - -out: - if (e < 0 && sn_hwperf_salheap) { - vfree(sn_hwperf_salheap); - sn_hwperf_salheap = NULL; - sn_hwperf_obj_cnt = 0; - } - mutex_unlock(&sn_hwperf_init_mutex); - return e; -} - -int sn_topology_open(struct inode *inode, struct file *file) -{ - int e; - struct seq_file *seq; - struct sn_hwperf_object_info *objbuf; - int nobj; - - if ((e = sn_hwperf_enum_objects(&nobj, &objbuf)) == 0) { - e = seq_open(file, &sn_topology_seq_ops); - seq = file->private_data; - seq->private = objbuf; - } - - return e; -} - -int sn_topology_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq = file->private_data; - - vfree(seq->private); - return seq_release(inode, file); -} - -int sn_hwperf_get_nearest_node(cnodeid_t node, - cnodeid_t *near_mem_node, cnodeid_t *near_cpu_node) -{ - int e; - int nobj; - struct sn_hwperf_object_info *objbuf; - - if ((e = sn_hwperf_enum_objects(&nobj, &objbuf)) == 0) { - e = sn_hwperf_get_nearest_node_objdata(objbuf, nobj, - node, near_mem_node, near_cpu_node); - vfree(objbuf); - } - - return e; -} - -static int sn_hwperf_misc_register_init(void) -{ - int e; - - if (!ia64_platform_is("sn2")) - return 0; - - sn_hwperf_init(); - - /* - * Register a dynamic misc device for hwperf ioctls. Platforms - * supporting hotplug will create /dev/sn_hwperf, else user - * can to look up the minor number in /proc/misc. - */ - if ((e = misc_register(&sn_hwperf_dev)) != 0) { - printk(KERN_ERR "sn_hwperf_misc_register_init: failed to " - "register misc device for \"%s\"\n", sn_hwperf_dev.name); - } - - return e; -} - -device_initcall(sn_hwperf_misc_register_init); /* after misc_init() */ -EXPORT_SYMBOL(sn_hwperf_get_nearest_node); diff --git a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c deleted file mode 100644 index c2a4d84297b0efae7db16280442c9409f27310d6..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved. - */ - -#ifdef CONFIG_PROC_FS -#include -#include -#include -#include - -static int partition_id_show(struct seq_file *s, void *p) -{ - seq_printf(s, "%d\n", sn_partition_id); - return 0; -} - -static int system_serial_number_show(struct seq_file *s, void *p) -{ - seq_printf(s, "%s\n", sn_system_serial_number()); - return 0; -} - -static int licenseID_show(struct seq_file *s, void *p) -{ - seq_printf(s, "0x%llx\n", sn_partition_serial_number_val()); - return 0; -} - -static int coherence_id_show(struct seq_file *s, void *p) -{ - seq_printf(s, "%d\n", partition_coherence_id()); - - return 0; -} - -/* /proc/sgi_sn/sn_topology uses seq_file, see sn_hwperf.c */ -extern int sn_topology_open(struct inode *, struct file *); -extern int sn_topology_release(struct inode *, struct file *); - -static const struct file_operations proc_sn_topo_fops = { - .open = sn_topology_open, - .read = seq_read, - .llseek = seq_lseek, - .release = sn_topology_release, -}; - -void register_sn_procfs(void) -{ - static struct proc_dir_entry *sgi_proc_dir = NULL; - - BUG_ON(sgi_proc_dir != NULL); - if (!(sgi_proc_dir = proc_mkdir("sgi_sn", NULL))) - return; - - proc_create_single("partition_id", 0444, sgi_proc_dir, - partition_id_show); - proc_create_single("system_serial_number", 0444, sgi_proc_dir, - system_serial_number_show); - proc_create_single("licenseID", 0444, sgi_proc_dir, licenseID_show); - proc_create_single("coherence_id", 0444, sgi_proc_dir, - coherence_id_show); - proc_create("sn_topology", 0444, sgi_proc_dir, &proc_sn_topo_fops); -} - -#endif /* CONFIG_PROC_FS */ diff --git a/arch/ia64/sn/kernel/sn2/timer.c b/arch/ia64/sn/kernel/sn2/timer.c deleted file mode 100644 index 3009d9d86f2973a65f31102901cd1d5da3d873ed..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/sn2/timer.c +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * linux/arch/ia64/sn/kernel/sn2/timer.c - * - * Copyright (C) 2003 Silicon Graphics, Inc. - * Copyright (C) 2003 Hewlett-Packard Co - * David Mosberger : updated for new timer-interpolation infrastructure - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -extern unsigned long sn_rtc_cycles_per_second; - -static u64 read_sn2(struct clocksource *cs) -{ - return (u64)readq(RTC_COUNTER_ADDR); -} - -static struct clocksource clocksource_sn2 = { - .name = "sn2_rtc", - .rating = 450, - .read = read_sn2, - .mask = (1LL << 55) - 1, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -/* - * sn udelay uses the RTC instead of the ITC because the ITC is not - * synchronized across all CPUs, and the thread may migrate to another CPU - * if preemption is enabled. - */ -static void -ia64_sn_udelay (unsigned long usecs) -{ - unsigned long start = rtc_time(); - unsigned long end = start + - usecs * sn_rtc_cycles_per_second / 1000000; - - while (time_before((unsigned long)rtc_time(), end)) - cpu_relax(); -} - -void __init sn_timer_init(void) -{ - clocksource_sn2.archdata.fsys_mmio = RTC_COUNTER_ADDR; - clocksource_register_hz(&clocksource_sn2, sn_rtc_cycles_per_second); - - ia64_udelay = &ia64_sn_udelay; -} diff --git a/arch/ia64/sn/kernel/sn2/timer_interrupt.c b/arch/ia64/sn/kernel/sn2/timer_interrupt.c deleted file mode 100644 index 103d6ea8e94b55bb4b7341bf2b43278bee8f0d75..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/sn2/timer_interrupt.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * - * Copyright (c) 2005, 2006 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include -#include -#include - -extern void sn_lb_int_war_check(void); -extern irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs); - -#define SN_LB_INT_WAR_INTERVAL 100 - -void sn_timer_interrupt(int irq, void *dev_id) -{ - /* LED blinking */ - if (!pda->hb_count--) { - pda->hb_count = HZ / 2; - set_led_bits(pda->hb_state ^= - LED_CPU_HEARTBEAT, LED_CPU_HEARTBEAT); - } - - if (is_shub1()) { - if (enable_shub_wars_1_1()) { - /* Bugfix code for SHUB 1.1 */ - if (pda->pio_shub_war_cam_addr) - *pda->pio_shub_war_cam_addr = 0x8000000000000010UL; - } - if (pda->sn_lb_int_war_ticks == 0) - sn_lb_int_war_check(); - pda->sn_lb_int_war_ticks++; - if (pda->sn_lb_int_war_ticks >= SN_LB_INT_WAR_INTERVAL) - pda->sn_lb_int_war_ticks = 0; - } -} diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c deleted file mode 100644 index 32d0380eb72e9d8f0e8907185db1bc70f409e3a6..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/kernel/tiocx.c +++ /dev/null @@ -1,569 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "tio.h" -#include "xtalk/xwidgetdev.h" -#include "xtalk/hubdev.h" - -#define CX_DEV_NONE 0 -#define DEVICE_NAME "tiocx" -#define WIDGET_ID 0 -#define TIOCX_DEBUG 0 - -#if TIOCX_DEBUG -#define DBG(fmt...) printk(KERN_ALERT fmt) -#else -#define DBG(fmt...) -#endif - -struct device_attribute dev_attr_cxdev_control; - -/** - * tiocx_match - Try to match driver id list with device. - * @dev: device pointer - * @drv: driver pointer - * - * Returns 1 if match, 0 otherwise. - */ -static int tiocx_match(struct device *dev, struct device_driver *drv) -{ - struct cx_dev *cx_dev = to_cx_dev(dev); - struct cx_drv *cx_drv = to_cx_driver(drv); - const struct cx_device_id *ids = cx_drv->id_table; - - if (!ids) - return 0; - - while (ids->part_num) { - if (ids->part_num == cx_dev->cx_id.part_num) - return 1; - ids++; - } - return 0; - -} - -static int tiocx_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - return -ENODEV; -} - -static void tiocx_bus_release(struct device *dev) -{ - kfree(to_cx_dev(dev)); -} - -/** - * cx_device_match - Find cx_device in the id table. - * @ids: id table from driver - * @cx_device: part/mfg id for the device - * - */ -static const struct cx_device_id *cx_device_match(const struct cx_device_id - *ids, - struct cx_dev *cx_device) -{ - /* - * NOTES: We may want to check for CX_ANY_ID too. - * Do we want to match against nasid too? - * CX_DEV_NONE == 0, if the driver tries to register for - * part/mfg == 0 we should return no-match (NULL) here. - */ - while (ids->part_num && ids->mfg_num) { - if (ids->part_num == cx_device->cx_id.part_num && - ids->mfg_num == cx_device->cx_id.mfg_num) - return ids; - ids++; - } - - return NULL; -} - -/** - * cx_device_probe - Look for matching device. - * Call driver probe routine if found. - * @cx_driver: driver table (cx_drv struct) from driver - * @cx_device: part/mfg id for the device - */ -static int cx_device_probe(struct device *dev) -{ - const struct cx_device_id *id; - struct cx_drv *cx_drv = to_cx_driver(dev->driver); - struct cx_dev *cx_dev = to_cx_dev(dev); - int error = 0; - - if (!cx_dev->driver && cx_drv->probe) { - id = cx_device_match(cx_drv->id_table, cx_dev); - if (id) { - if ((error = cx_drv->probe(cx_dev, id)) < 0) - return error; - else - cx_dev->driver = cx_drv; - } - } - - return error; -} - -/** - * cx_driver_remove - Remove driver from device struct. - * @dev: device - */ -static int cx_driver_remove(struct device *dev) -{ - struct cx_dev *cx_dev = to_cx_dev(dev); - struct cx_drv *cx_drv = cx_dev->driver; - if (cx_drv->remove) - cx_drv->remove(cx_dev); - cx_dev->driver = NULL; - return 0; -} - -struct bus_type tiocx_bus_type = { - .name = "tiocx", - .match = tiocx_match, - .uevent = tiocx_uevent, - .probe = cx_device_probe, - .remove = cx_driver_remove, -}; - -/** - * cx_driver_register - Register the driver. - * @cx_driver: driver table (cx_drv struct) from driver - * - * Called from the driver init routine to register a driver. - * The cx_drv struct contains the driver name, a pointer to - * a table of part/mfg numbers and a pointer to the driver's - * probe/attach routine. - */ -int cx_driver_register(struct cx_drv *cx_driver) -{ - cx_driver->driver.name = cx_driver->name; - cx_driver->driver.bus = &tiocx_bus_type; - - return driver_register(&cx_driver->driver); -} - -/** - * cx_driver_unregister - Unregister the driver. - * @cx_driver: driver table (cx_drv struct) from driver - */ -int cx_driver_unregister(struct cx_drv *cx_driver) -{ - driver_unregister(&cx_driver->driver); - return 0; -} - -/** - * cx_device_register - Register a device. - * @nasid: device's nasid - * @part_num: device's part number - * @mfg_num: device's manufacturer number - * @hubdev: hub info associated with this device - * @bt: board type of the device - * - */ -int -cx_device_register(nasid_t nasid, int part_num, int mfg_num, - struct hubdev_info *hubdev, int bt) -{ - struct cx_dev *cx_dev; - int r; - - cx_dev = kzalloc(sizeof(struct cx_dev), GFP_KERNEL); - DBG("cx_dev= 0x%p\n", cx_dev); - if (cx_dev == NULL) - return -ENOMEM; - - cx_dev->cx_id.part_num = part_num; - cx_dev->cx_id.mfg_num = mfg_num; - cx_dev->cx_id.nasid = nasid; - cx_dev->hubdev = hubdev; - cx_dev->bt = bt; - - cx_dev->dev.parent = NULL; - cx_dev->dev.bus = &tiocx_bus_type; - cx_dev->dev.release = tiocx_bus_release; - dev_set_name(&cx_dev->dev, "%d", cx_dev->cx_id.nasid); - r = device_register(&cx_dev->dev); - if (r) { - kfree(cx_dev); - return r; - } - get_device(&cx_dev->dev); - - device_create_file(&cx_dev->dev, &dev_attr_cxdev_control); - - return 0; -} - -/** - * cx_device_unregister - Unregister a device. - * @cx_dev: part/mfg id for the device - */ -int cx_device_unregister(struct cx_dev *cx_dev) -{ - put_device(&cx_dev->dev); - device_unregister(&cx_dev->dev); - return 0; -} - -/** - * cx_device_reload - Reload the device. - * @nasid: device's nasid - * @part_num: device's part number - * @mfg_num: device's manufacturer number - * - * Remove the device associated with 'nasid' from device list and then - * call device-register with the given part/mfg numbers. - */ -static int cx_device_reload(struct cx_dev *cx_dev) -{ - cx_device_unregister(cx_dev); - return cx_device_register(cx_dev->cx_id.nasid, cx_dev->cx_id.part_num, - cx_dev->cx_id.mfg_num, cx_dev->hubdev, - cx_dev->bt); -} - -static inline u64 tiocx_intr_alloc(nasid_t nasid, int widget, - u64 sn_irq_info, - int req_irq, nasid_t req_nasid, - int req_slice) -{ - struct ia64_sal_retval rv; - rv.status = 0; - rv.v0 = 0; - - ia64_sal_oemcall_nolock(&rv, SN_SAL_IOIF_INTERRUPT, - SAL_INTR_ALLOC, nasid, - widget, sn_irq_info, req_irq, - req_nasid, req_slice); - return rv.status; -} - -static inline void tiocx_intr_free(nasid_t nasid, int widget, - struct sn_irq_info *sn_irq_info) -{ - struct ia64_sal_retval rv; - rv.status = 0; - rv.v0 = 0; - - ia64_sal_oemcall_nolock(&rv, SN_SAL_IOIF_INTERRUPT, - SAL_INTR_FREE, nasid, - widget, sn_irq_info->irq_irq, - sn_irq_info->irq_cookie, 0, 0); -} - -struct sn_irq_info *tiocx_irq_alloc(nasid_t nasid, int widget, int irq, - nasid_t req_nasid, int slice) -{ - struct sn_irq_info *sn_irq_info; - int status; - int sn_irq_size = sizeof(struct sn_irq_info); - - if ((nasid & 1) == 0) - return NULL; - - sn_irq_info = kzalloc(sn_irq_size, GFP_KERNEL); - if (sn_irq_info == NULL) - return NULL; - - status = tiocx_intr_alloc(nasid, widget, __pa(sn_irq_info), irq, - req_nasid, slice); - if (status) { - kfree(sn_irq_info); - return NULL; - } else { - return sn_irq_info; - } -} - -void tiocx_irq_free(struct sn_irq_info *sn_irq_info) -{ - u64 bridge = (u64) sn_irq_info->irq_bridge; - nasid_t nasid = NASID_GET(bridge); - int widget; - - if (nasid & 1) { - widget = TIO_SWIN_WIDGETNUM(bridge); - tiocx_intr_free(nasid, widget, sn_irq_info); - kfree(sn_irq_info); - } -} - -u64 tiocx_dma_addr(u64 addr) -{ - return PHYS_TO_TIODMA(addr); -} - -u64 tiocx_swin_base(int nasid) -{ - return TIO_SWIN_BASE(nasid, TIOCX_CORELET); -} - -EXPORT_SYMBOL(cx_driver_register); -EXPORT_SYMBOL(cx_driver_unregister); -EXPORT_SYMBOL(cx_device_register); -EXPORT_SYMBOL(cx_device_unregister); -EXPORT_SYMBOL(tiocx_irq_alloc); -EXPORT_SYMBOL(tiocx_irq_free); -EXPORT_SYMBOL(tiocx_bus_type); -EXPORT_SYMBOL(tiocx_dma_addr); -EXPORT_SYMBOL(tiocx_swin_base); - -static void tio_conveyor_set(nasid_t nasid, int enable_flag) -{ - u64 ice_frz; - u64 disable_cb = (1ull << 61); - - if (!(nasid & 1)) - return; - - ice_frz = REMOTE_HUB_L(nasid, TIO_ICE_FRZ_CFG); - if (enable_flag) { - if (!(ice_frz & disable_cb)) /* already enabled */ - return; - ice_frz &= ~disable_cb; - } else { - if (ice_frz & disable_cb) /* already disabled */ - return; - ice_frz |= disable_cb; - } - DBG(KERN_ALERT "TIO_ICE_FRZ_CFG= 0x%lx\n", ice_frz); - REMOTE_HUB_S(nasid, TIO_ICE_FRZ_CFG, ice_frz); -} - -#define tio_conveyor_enable(nasid) tio_conveyor_set(nasid, 1) -#define tio_conveyor_disable(nasid) tio_conveyor_set(nasid, 0) - -static void tio_corelet_reset(nasid_t nasid, int corelet) -{ - if (!(nasid & 1)) - return; - - REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 1 << corelet); - udelay(2000); - REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 0); - udelay(2000); -} - -static int is_fpga_tio(int nasid, int *bt) -{ - u16 uninitialized_var(ioboard_type); /* GCC be quiet */ - long rc; - - rc = ia64_sn_sysctl_ioboard_get(nasid, &ioboard_type); - if (rc) { - printk(KERN_WARNING "ia64_sn_sysctl_ioboard_get failed: %ld\n", - rc); - return 0; - } - - switch (ioboard_type) { - case L1_BRICKTYPE_SA: - case L1_BRICKTYPE_ATHENA: - case L1_BOARDTYPE_DAYTONA: - *bt = ioboard_type; - return 1; - } - - return 0; -} - -static int bitstream_loaded(nasid_t nasid) -{ - u64 cx_credits; - - cx_credits = REMOTE_HUB_L(nasid, TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3); - cx_credits &= TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3_CREDIT_CNT_MASK; - DBG("cx_credits= 0x%lx\n", cx_credits); - - return (cx_credits == 0xf) ? 1 : 0; -} - -static int tiocx_reload(struct cx_dev *cx_dev) -{ - int part_num = CX_DEV_NONE; - int mfg_num = CX_DEV_NONE; - nasid_t nasid = cx_dev->cx_id.nasid; - - if (bitstream_loaded(nasid)) { - u64 cx_id; - int rv; - - rv = ia64_sn_sysctl_tio_clock_reset(nasid); - if (rv) { - printk(KERN_ALERT "CX port JTAG reset failed.\n"); - } else { - cx_id = *(volatile u64 *) - (TIO_SWIN_BASE(nasid, TIOCX_CORELET) + - WIDGET_ID); - part_num = XWIDGET_PART_NUM(cx_id); - mfg_num = XWIDGET_MFG_NUM(cx_id); - DBG("part= 0x%x, mfg= 0x%x\n", part_num, mfg_num); - /* just ignore it if it's a CE */ - if (part_num == TIO_CE_ASIC_PARTNUM) - return 0; - } - } - - cx_dev->cx_id.part_num = part_num; - cx_dev->cx_id.mfg_num = mfg_num; - - /* - * Delete old device and register the new one. It's ok if - * part_num/mfg_num == CX_DEV_NONE. We want to register - * devices in the table even if a bitstream isn't loaded. - * That allows use to see that a bitstream isn't loaded via - * TIOCX_IOCTL_DEV_LIST. - */ - return cx_device_reload(cx_dev); -} - -static ssize_t show_cxdev_control(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct cx_dev *cx_dev = to_cx_dev(dev); - - return sprintf(buf, "0x%x 0x%x 0x%x 0x%x\n", - cx_dev->cx_id.nasid, - cx_dev->cx_id.part_num, cx_dev->cx_id.mfg_num, - cx_dev->bt); -} - -static ssize_t store_cxdev_control(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - int n; - struct cx_dev *cx_dev = to_cx_dev(dev); - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (count <= 0) - return 0; - - n = simple_strtoul(buf, NULL, 0); - - switch (n) { - case 1: - tio_corelet_reset(cx_dev->cx_id.nasid, TIOCX_CORELET); - tiocx_reload(cx_dev); - break; - case 2: - tiocx_reload(cx_dev); - break; - case 3: - tio_corelet_reset(cx_dev->cx_id.nasid, TIOCX_CORELET); - break; - default: - break; - } - - return count; -} - -DEVICE_ATTR(cxdev_control, 0644, show_cxdev_control, store_cxdev_control); - -static int __init tiocx_init(void) -{ - cnodeid_t cnodeid; - int found_tiocx_device = 0; - int err; - - if (!ia64_platform_is("sn2")) - return 0; - - err = bus_register(&tiocx_bus_type); - if (err) - return err; - - for (cnodeid = 0; cnodeid < num_cnodes; cnodeid++) { - nasid_t nasid; - int bt; - - nasid = cnodeid_to_nasid(cnodeid); - - if ((nasid & 0x1) && is_fpga_tio(nasid, &bt)) { - struct hubdev_info *hubdev; - struct xwidget_info *widgetp; - - DBG("Found TIO at nasid 0x%x\n", nasid); - - hubdev = - (struct hubdev_info *)(NODEPDA(cnodeid)->pdinfo); - - widgetp = &hubdev->hdi_xwidget_info[TIOCX_CORELET]; - - /* The CE hangs off of the CX port but is not an FPGA */ - if (widgetp->xwi_hwid.part_num == TIO_CE_ASIC_PARTNUM) - continue; - - tio_corelet_reset(nasid, TIOCX_CORELET); - tio_conveyor_enable(nasid); - - if (cx_device_register - (nasid, widgetp->xwi_hwid.part_num, - widgetp->xwi_hwid.mfg_num, hubdev, bt) < 0) - return -ENXIO; - else - found_tiocx_device++; - } - } - - /* It's ok if we find zero devices. */ - DBG("found_tiocx_device= %d\n", found_tiocx_device); - - return 0; -} - -static int cx_remove_device(struct device * dev, void * data) -{ - struct cx_dev *cx_dev = to_cx_dev(dev); - device_remove_file(dev, &dev_attr_cxdev_control); - cx_device_unregister(cx_dev); - return 0; -} - -static void __exit tiocx_exit(void) -{ - DBG("tiocx_exit\n"); - - /* - * Unregister devices. - */ - bus_for_each_dev(&tiocx_bus_type, NULL, NULL, cx_remove_device); - bus_unregister(&tiocx_bus_type); -} - -fs_initcall(tiocx_init); -module_exit(tiocx_exit); - -/************************************************************************ - * Module licensing and description - ************************************************************************/ -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Bruce Losure "); -MODULE_DESCRIPTION("TIOCX module"); -MODULE_SUPPORTED_DEVICE(DEVICE_NAME); diff --git a/arch/ia64/sn/pci/Makefile b/arch/ia64/sn/pci/Makefile deleted file mode 100644 index 321576b1b425f8916858c875058326148216fa8f..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/pci/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# This file is subject to the terms and conditions of the GNU General Public -# License. See the file "COPYING" in the main directory of this archive -# for more details. -# -# Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. -# -# Makefile for the sn pci general routines. - -obj-y := pci_dma.o tioca_provider.o tioce_provider.o pcibr/ diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c deleted file mode 100644 index b7d42e4edc1f2072d71e42f14917f4285eea5d56..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/pci/pci_dma.c +++ /dev/null @@ -1,446 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000,2002-2005 Silicon Graphics, Inc. All rights reserved. - * - * Routines for PCI DMA mapping. See Documentation/DMA-API.txt for - * a description of how these routines should be used. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define SG_ENT_VIRT_ADDRESS(sg) (sg_virt((sg))) -#define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG)) - -/** - * sn_dma_supported - test a DMA mask - * @dev: device to test - * @mask: DMA mask to test - * - * Return whether the given PCI device DMA address mask can be supported - * properly. For example, if your device can only drive the low 24-bits - * during PCI bus mastering, then you would pass 0x00ffffff as the mask to - * this function. Of course, SN only supports devices that have 32 or more - * address bits when using the PMU. - */ -static int sn_dma_supported(struct device *dev, u64 mask) -{ - BUG_ON(!dev_is_pci(dev)); - - if (mask < 0x7fffffff) - return 0; - return 1; -} - -/** - * sn_dma_set_mask - set the DMA mask - * @dev: device to set - * @dma_mask: new mask - * - * Set @dev's DMA mask if the hw supports it. - */ -int sn_dma_set_mask(struct device *dev, u64 dma_mask) -{ - BUG_ON(!dev_is_pci(dev)); - - if (!sn_dma_supported(dev, dma_mask)) - return 0; - - *dev->dma_mask = dma_mask; - return 1; -} -EXPORT_SYMBOL(sn_dma_set_mask); - -/** - * sn_dma_alloc_coherent - allocate memory for coherent DMA - * @dev: device to allocate for - * @size: size of the region - * @dma_handle: DMA (bus) address - * @flags: memory allocation flags - * - * dma_alloc_coherent() returns a pointer to a memory region suitable for - * coherent DMA traffic to/from a PCI device. On SN platforms, this means - * that @dma_handle will have the %PCIIO_DMA_CMD flag set. - * - * This interface is usually used for "command" streams (e.g. the command - * queue for a SCSI controller). See Documentation/DMA-API.txt for - * more information. - */ -static void *sn_dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, gfp_t flags, - unsigned long attrs) -{ - void *cpuaddr; - unsigned long phys_addr; - int node; - struct pci_dev *pdev = to_pci_dev(dev); - struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); - - BUG_ON(!dev_is_pci(dev)); - - /* - * Allocate the memory. - */ - node = pcibus_to_node(pdev->bus); - if (likely(node >=0)) { - struct page *p = __alloc_pages_node(node, - flags, get_order(size)); - - if (likely(p)) - cpuaddr = page_address(p); - else - return NULL; - } else - cpuaddr = (void *)__get_free_pages(flags, get_order(size)); - - if (unlikely(!cpuaddr)) - return NULL; - - memset(cpuaddr, 0x0, size); - - /* physical addr. of the memory we just got */ - phys_addr = __pa(cpuaddr); - - /* - * 64 bit address translations should never fail. - * 32 bit translations can fail if there are insufficient mapping - * resources. - */ - - *dma_handle = provider->dma_map_consistent(pdev, phys_addr, size, - SN_DMA_ADDR_PHYS); - if (!*dma_handle) { - printk(KERN_ERR "%s: out of ATEs\n", __func__); - free_pages((unsigned long)cpuaddr, get_order(size)); - return NULL; - } - - return cpuaddr; -} - -/** - * sn_pci_free_coherent - free memory associated with coherent DMAable region - * @dev: device to free for - * @size: size to free - * @cpu_addr: kernel virtual address to free - * @dma_handle: DMA address associated with this region - * - * Frees the memory allocated by dma_alloc_coherent(), potentially unmapping - * any associated IOMMU mappings. - */ -static void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, - dma_addr_t dma_handle, unsigned long attrs) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); - - BUG_ON(!dev_is_pci(dev)); - - provider->dma_unmap(pdev, dma_handle, 0); - free_pages((unsigned long)cpu_addr, get_order(size)); -} - -/** - * sn_dma_map_single_attrs - map a single page for DMA - * @dev: device to map for - * @cpu_addr: kernel virtual address of the region to map - * @size: size of the region - * @direction: DMA direction - * @attrs: optional dma attributes - * - * Map the region pointed to by @cpu_addr for DMA and return the - * DMA address. - * - * We map this to the one step pcibr_dmamap_trans interface rather than - * the two step pcibr_dmamap_alloc/pcibr_dmamap_addr because we have - * no way of saving the dmamap handle from the alloc to later free - * (which is pretty much unacceptable). - * - * mappings with the DMA_ATTR_WRITE_BARRIER get mapped with - * dma_map_consistent() so that writes force a flush of pending DMA. - * (See "SGI Altix Architecture Considerations for Linux Device Drivers", - * Document Number: 007-4763-001) - * - * TODO: simplify our interface; - * figure out how to save dmamap handle so can use two step. - */ -static dma_addr_t sn_dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction dir, - unsigned long attrs) -{ - void *cpu_addr = page_address(page) + offset; - dma_addr_t dma_addr; - unsigned long phys_addr; - struct pci_dev *pdev = to_pci_dev(dev); - struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); - - BUG_ON(!dev_is_pci(dev)); - - phys_addr = __pa(cpu_addr); - if (attrs & DMA_ATTR_WRITE_BARRIER) - dma_addr = provider->dma_map_consistent(pdev, phys_addr, - size, SN_DMA_ADDR_PHYS); - else - dma_addr = provider->dma_map(pdev, phys_addr, size, - SN_DMA_ADDR_PHYS); - - if (!dma_addr) { - printk(KERN_ERR "%s: out of ATEs\n", __func__); - return DMA_MAPPING_ERROR; - } - return dma_addr; -} - -/** - * sn_dma_unmap_single_attrs - unamp a DMA mapped page - * @dev: device to sync - * @dma_addr: DMA address to sync - * @size: size of region - * @direction: DMA direction - * @attrs: optional dma attributes - * - * This routine is supposed to sync the DMA region specified - * by @dma_handle into the coherence domain. On SN, we're always cache - * coherent, so we just need to free any ATEs associated with this mapping. - */ -static void sn_dma_unmap_page(struct device *dev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction dir, - unsigned long attrs) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); - - BUG_ON(!dev_is_pci(dev)); - - provider->dma_unmap(pdev, dma_addr, dir); -} - -/** - * sn_dma_unmap_sg - unmap a DMA scatterlist - * @dev: device to unmap - * @sg: scatterlist to unmap - * @nhwentries: number of scatterlist entries - * @direction: DMA direction - * @attrs: optional dma attributes - * - * Unmap a set of streaming mode DMA translations. - */ -static void sn_dma_unmap_sg(struct device *dev, struct scatterlist *sgl, - int nhwentries, enum dma_data_direction dir, - unsigned long attrs) -{ - int i; - struct pci_dev *pdev = to_pci_dev(dev); - struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); - struct scatterlist *sg; - - BUG_ON(!dev_is_pci(dev)); - - for_each_sg(sgl, sg, nhwentries, i) { - provider->dma_unmap(pdev, sg->dma_address, dir); - sg->dma_address = (dma_addr_t) NULL; - sg->dma_length = 0; - } -} - -/** - * sn_dma_map_sg - map a scatterlist for DMA - * @dev: device to map for - * @sg: scatterlist to map - * @nhwentries: number of entries - * @direction: direction of the DMA transaction - * @attrs: optional dma attributes - * - * mappings with the DMA_ATTR_WRITE_BARRIER get mapped with - * dma_map_consistent() so that writes force a flush of pending DMA. - * (See "SGI Altix Architecture Considerations for Linux Device Drivers", - * Document Number: 007-4763-001) - * - * Maps each entry of @sg for DMA. - */ -static int sn_dma_map_sg(struct device *dev, struct scatterlist *sgl, - int nhwentries, enum dma_data_direction dir, - unsigned long attrs) -{ - unsigned long phys_addr; - struct scatterlist *saved_sg = sgl, *sg; - struct pci_dev *pdev = to_pci_dev(dev); - struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); - int i; - - BUG_ON(!dev_is_pci(dev)); - - /* - * Setup a DMA address for each entry in the scatterlist. - */ - for_each_sg(sgl, sg, nhwentries, i) { - dma_addr_t dma_addr; - phys_addr = SG_ENT_PHYS_ADDRESS(sg); - if (attrs & DMA_ATTR_WRITE_BARRIER) - dma_addr = provider->dma_map_consistent(pdev, - phys_addr, - sg->length, - SN_DMA_ADDR_PHYS); - else - dma_addr = provider->dma_map(pdev, phys_addr, - sg->length, - SN_DMA_ADDR_PHYS); - - sg->dma_address = dma_addr; - if (!sg->dma_address) { - printk(KERN_ERR "%s: out of ATEs\n", __func__); - - /* - * Free any successfully allocated entries. - */ - if (i > 0) - sn_dma_unmap_sg(dev, saved_sg, i, dir, attrs); - return 0; - } - - sg->dma_length = sg->length; - } - - return nhwentries; -} - -static u64 sn_dma_get_required_mask(struct device *dev) -{ - return DMA_BIT_MASK(64); -} - -char *sn_pci_get_legacy_mem(struct pci_bus *bus) -{ - if (!SN_PCIBUS_BUSSOFT(bus)) - return ERR_PTR(-ENODEV); - - return (char *)(SN_PCIBUS_BUSSOFT(bus)->bs_legacy_mem | __IA64_UNCACHED_OFFSET); -} - -int sn_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size) -{ - unsigned long addr; - int ret; - struct ia64_sal_retval isrv; - - /* - * First, try the SN_SAL_IOIF_PCI_SAFE SAL call which can work - * around hw issues at the pci bus level. SGI proms older than - * 4.10 don't implement this. - */ - - SAL_CALL(isrv, SN_SAL_IOIF_PCI_SAFE, - pci_domain_nr(bus), bus->number, - 0, /* io */ - 0, /* read */ - port, size, __pa(val)); - - if (isrv.status == 0) - return size; - - /* - * If the above failed, retry using the SAL_PROBE call which should - * be present in all proms (but which cannot work round PCI chipset - * bugs). This code is retained for compatibility with old - * pre-4.10 proms, and should be removed at some point in the future. - */ - - if (!SN_PCIBUS_BUSSOFT(bus)) - return -ENODEV; - - addr = SN_PCIBUS_BUSSOFT(bus)->bs_legacy_io | __IA64_UNCACHED_OFFSET; - addr += port; - - ret = ia64_sn_probe_mem(addr, (long)size, (void *)val); - - if (ret == 2) - return -EINVAL; - - if (ret == 1) - *val = -1; - - return size; -} - -int sn_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size) -{ - int ret = size; - unsigned long paddr; - unsigned long *addr; - struct ia64_sal_retval isrv; - - /* - * First, try the SN_SAL_IOIF_PCI_SAFE SAL call which can work - * around hw issues at the pci bus level. SGI proms older than - * 4.10 don't implement this. - */ - - SAL_CALL(isrv, SN_SAL_IOIF_PCI_SAFE, - pci_domain_nr(bus), bus->number, - 0, /* io */ - 1, /* write */ - port, size, __pa(&val)); - - if (isrv.status == 0) - return size; - - /* - * If the above failed, retry using the SAL_PROBE call which should - * be present in all proms (but which cannot work round PCI chipset - * bugs). This code is retained for compatibility with old - * pre-4.10 proms, and should be removed at some point in the future. - */ - - if (!SN_PCIBUS_BUSSOFT(bus)) { - ret = -ENODEV; - goto out; - } - - /* Put the phys addr in uncached space */ - paddr = SN_PCIBUS_BUSSOFT(bus)->bs_legacy_io | __IA64_UNCACHED_OFFSET; - paddr += port; - addr = (unsigned long *)paddr; - - switch (size) { - case 1: - *(volatile u8 *)(addr) = (u8)(val); - break; - case 2: - *(volatile u16 *)(addr) = (u16)(val); - break; - case 4: - *(volatile u32 *)(addr) = (u32)(val); - break; - default: - ret = -EINVAL; - break; - } - out: - return ret; -} - -static struct dma_map_ops sn_dma_ops = { - .alloc = sn_dma_alloc_coherent, - .free = sn_dma_free_coherent, - .map_page = sn_dma_map_page, - .unmap_page = sn_dma_unmap_page, - .map_sg = sn_dma_map_sg, - .unmap_sg = sn_dma_unmap_sg, - .dma_supported = sn_dma_supported, - .get_required_mask = sn_dma_get_required_mask, -}; - -void sn_dma_init(void) -{ - dma_ops = &sn_dma_ops; -} diff --git a/arch/ia64/sn/pci/pcibr/Makefile b/arch/ia64/sn/pci/pcibr/Makefile deleted file mode 100644 index 712f6af7c6e0d05c5ba58fc713cd764241617def..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/pci/pcibr/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# -# This file is subject to the terms and conditions of the GNU General Public -# License. See the file "COPYING" in the main directory of this archive -# for more details. -# -# Copyright (C) 2002-2004 Silicon Graphics, Inc. All Rights Reserved. -# -# Makefile for the sn2 io routines. - -ccflags-y := -I $(srctree)/arch/ia64/sn/include - -obj-y += pcibr_dma.o pcibr_reg.o \ - pcibr_ate.o pcibr_provider.o diff --git a/arch/ia64/sn/pci/pcibr/pcibr_ate.c b/arch/ia64/sn/pci/pcibr/pcibr_ate.c deleted file mode 100644 index b67bb4cb73ff7ec35479788c382c718b088409a3..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/pci/pcibr/pcibr_ate.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001-2006 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include - -int pcibr_invalidate_ate; /* by default don't invalidate ATE on free */ - -/* - * mark_ate: Mark the ate as either free or inuse. - */ -static void mark_ate(struct ate_resource *ate_resource, int start, int number, - u64 value) -{ - u64 *ate = ate_resource->ate; - int index; - int length = 0; - - for (index = start; length < number; index++, length++) - ate[index] = value; -} - -/* - * find_free_ate: Find the first free ate index starting from the given - * index for the desired consecutive count. - */ -static int find_free_ate(struct ate_resource *ate_resource, int start, - int count) -{ - u64 *ate = ate_resource->ate; - int index; - int start_free; - - for (index = start; index < ate_resource->num_ate;) { - if (!ate[index]) { - int i; - int free; - free = 0; - start_free = index; /* Found start free ate */ - for (i = start_free; i < ate_resource->num_ate; i++) { - if (!ate[i]) { /* This is free */ - if (++free == count) - return start_free; - } else { - index = i + 1; - break; - } - } - if (i >= ate_resource->num_ate) - return -1; - } else - index++; /* Try next ate */ - } - - return -1; -} - -/* - * free_ate_resource: Free the requested number of ATEs. - */ -static inline void free_ate_resource(struct ate_resource *ate_resource, - int start) -{ - mark_ate(ate_resource, start, ate_resource->ate[start], 0); - if ((ate_resource->lowest_free_index > start) || - (ate_resource->lowest_free_index < 0)) - ate_resource->lowest_free_index = start; -} - -/* - * alloc_ate_resource: Allocate the requested number of ATEs. - */ -static inline int alloc_ate_resource(struct ate_resource *ate_resource, - int ate_needed) -{ - int start_index; - - /* - * Check for ate exhaustion. - */ - if (ate_resource->lowest_free_index < 0) - return -1; - - /* - * Find the required number of free consecutive ates. - */ - start_index = - find_free_ate(ate_resource, ate_resource->lowest_free_index, - ate_needed); - if (start_index >= 0) - mark_ate(ate_resource, start_index, ate_needed, ate_needed); - - ate_resource->lowest_free_index = - find_free_ate(ate_resource, ate_resource->lowest_free_index, 1); - - return start_index; -} - -/* - * Allocate "count" contiguous Bridge Address Translation Entries - * on the specified bridge to be used for PCI to XTALK mappings. - * Indices in rm map range from 1..num_entries. Indices returned - * to caller range from 0..num_entries-1. - * - * Return the start index on success, -1 on failure. - */ -int pcibr_ate_alloc(struct pcibus_info *pcibus_info, int count) -{ - int status; - unsigned long flags; - - spin_lock_irqsave(&pcibus_info->pbi_lock, flags); - status = alloc_ate_resource(&pcibus_info->pbi_int_ate_resource, count); - spin_unlock_irqrestore(&pcibus_info->pbi_lock, flags); - - return status; -} - -/* - * Setup an Address Translation Entry as specified. Use either the Bridge - * internal maps or the external map RAM, as appropriate. - */ -static inline u64 __iomem *pcibr_ate_addr(struct pcibus_info *pcibus_info, - int ate_index) -{ - if (ate_index < pcibus_info->pbi_int_ate_size) { - return pcireg_int_ate_addr(pcibus_info, ate_index); - } - panic("pcibr_ate_addr: invalid ate_index 0x%x", ate_index); -} - -/* - * Update the ate. - */ -inline void -ate_write(struct pcibus_info *pcibus_info, int ate_index, int count, - volatile u64 ate) -{ - while (count-- > 0) { - if (ate_index < pcibus_info->pbi_int_ate_size) { - pcireg_int_ate_set(pcibus_info, ate_index, ate); - } else { - panic("ate_write: invalid ate_index 0x%x", ate_index); - } - ate_index++; - ate += IOPGSIZE; - } - - pcireg_tflush_get(pcibus_info); /* wait until Bridge PIO complete */ -} - -void pcibr_ate_free(struct pcibus_info *pcibus_info, int index) -{ - - volatile u64 ate; - int count; - unsigned long flags; - - if (pcibr_invalidate_ate) { - /* For debugging purposes, clear the valid bit in the ATE */ - ate = *pcibr_ate_addr(pcibus_info, index); - count = pcibus_info->pbi_int_ate_resource.ate[index]; - ate_write(pcibus_info, index, count, (ate & ~PCI32_ATE_V)); - } - - spin_lock_irqsave(&pcibus_info->pbi_lock, flags); - free_ate_resource(&pcibus_info->pbi_int_ate_resource, index); - spin_unlock_irqrestore(&pcibus_info->pbi_lock, flags); -} diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c deleted file mode 100644 index 1e863b277ac967fa29ad0ddf3ae0517ecb281ff7..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c +++ /dev/null @@ -1,413 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001-2005 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "tio.h" -#include "xtalk/xwidgetdev.h" -#include "xtalk/hubdev.h" - -extern int sn_ioif_inited; - -/* ===================================================================== - * DMA MANAGEMENT - * - * The Bridge ASIC provides three methods of doing DMA: via a "direct map" - * register available in 32-bit PCI space (which selects a contiguous 2G - * address space on some other widget), via "direct" addressing via 64-bit - * PCI space (all destination information comes from the PCI address, - * including transfer attributes), and via a "mapped" region that allows - * a bunch of different small mappings to be established with the PMU. - * - * For efficiency, we most prefer to use the 32bit direct mapping facility, - * since it requires no resource allocations. The advantage of using the - * PMU over the 64-bit direct is that single-cycle PCI addressing can be - * used; the advantage of using 64-bit direct over PMU addressing is that - * we do not have to allocate entries in the PMU. - */ - -static dma_addr_t -pcibr_dmamap_ate32(struct pcidev_info *info, - u64 paddr, size_t req_size, u64 flags, int dma_flags) -{ - - struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info; - struct pcibus_info *pcibus_info = (struct pcibus_info *)pcidev_info-> - pdi_pcibus_info; - u8 internal_device = (PCI_SLOT(pcidev_info->pdi_host_pcidev_info-> - pdi_linux_pcidev->devfn)) - 1; - int ate_count; - int ate_index; - u64 ate_flags = flags | PCI32_ATE_V; - u64 ate; - u64 pci_addr; - u64 xio_addr; - u64 offset; - - /* PIC in PCI-X mode does not supports 32bit PageMap mode */ - if (IS_PIC_SOFT(pcibus_info) && IS_PCIX(pcibus_info)) { - return 0; - } - - /* Calculate the number of ATEs needed. */ - if (!(MINIMAL_ATE_FLAG(paddr, req_size))) { - ate_count = IOPG((IOPGSIZE - 1) /* worst case start offset */ - +req_size /* max mapping bytes */ - - 1) + 1; /* round UP */ - } else { /* assume requested target is page aligned */ - ate_count = IOPG(req_size /* max mapping bytes */ - - 1) + 1; /* round UP */ - } - - /* Get the number of ATEs required. */ - ate_index = pcibr_ate_alloc(pcibus_info, ate_count); - if (ate_index < 0) - return 0; - - /* In PCI-X mode, Prefetch not supported */ - if (IS_PCIX(pcibus_info)) - ate_flags &= ~(PCI32_ATE_PREF); - - if (SN_DMA_ADDRTYPE(dma_flags == SN_DMA_ADDR_PHYS)) - xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) : - PHYS_TO_TIODMA(paddr); - else - xio_addr = paddr; - - offset = IOPGOFF(xio_addr); - ate = ate_flags | (xio_addr - offset); - - /* If PIC, put the targetid in the ATE */ - if (IS_PIC_SOFT(pcibus_info)) { - ate |= (pcibus_info->pbi_hub_xid << PIC_ATE_TARGETID_SHFT); - } - - /* - * If we're mapping for MSI, set the MSI bit in the ATE. If it's a - * TIOCP based pci bus, we also need to set the PIO bit in the ATE. - */ - if (dma_flags & SN_DMA_MSI) { - ate |= PCI32_ATE_MSI; - if (IS_TIOCP_SOFT(pcibus_info)) - ate |= PCI32_ATE_PIO; - } - - ate_write(pcibus_info, ate_index, ate_count, ate); - - /* - * Set up the DMA mapped Address. - */ - pci_addr = PCI32_MAPPED_BASE + offset + IOPGSIZE * ate_index; - - /* - * If swap was set in device in pcibr_endian_set() - * we need to turn swapping on. - */ - if (pcibus_info->pbi_devreg[internal_device] & PCIBR_DEV_SWAP_DIR) - ATE_SWAP_ON(pci_addr); - - - return pci_addr; -} - -static dma_addr_t -pcibr_dmatrans_direct64(struct pcidev_info * info, u64 paddr, - u64 dma_attributes, int dma_flags) -{ - struct pcibus_info *pcibus_info = (struct pcibus_info *) - ((info->pdi_host_pcidev_info)->pdi_pcibus_info); - u64 pci_addr; - - /* Translate to Crosstalk View of Physical Address */ - if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS) - pci_addr = IS_PIC_SOFT(pcibus_info) ? - PHYS_TO_DMA(paddr) : - PHYS_TO_TIODMA(paddr); - else - pci_addr = paddr; - pci_addr |= dma_attributes; - - /* Handle Bus mode */ - if (IS_PCIX(pcibus_info)) - pci_addr &= ~PCI64_ATTR_PREF; - - /* Handle Bridge Chipset differences */ - if (IS_PIC_SOFT(pcibus_info)) { - pci_addr |= - ((u64) pcibus_info-> - pbi_hub_xid << PIC_PCI64_ATTR_TARG_SHFT); - } else - pci_addr |= (dma_flags & SN_DMA_MSI) ? - TIOCP_PCI64_CMDTYPE_MSI : - TIOCP_PCI64_CMDTYPE_MEM; - - /* If PCI mode, func zero uses VCHAN0, every other func uses VCHAN1 */ - if (!IS_PCIX(pcibus_info) && PCI_FUNC(info->pdi_linux_pcidev->devfn)) - pci_addr |= PCI64_ATTR_VIRTUAL; - - return pci_addr; -} - -static dma_addr_t -pcibr_dmatrans_direct32(struct pcidev_info * info, - u64 paddr, size_t req_size, u64 flags, int dma_flags) -{ - struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info; - struct pcibus_info *pcibus_info = (struct pcibus_info *)pcidev_info-> - pdi_pcibus_info; - u64 xio_addr; - - u64 xio_base; - u64 offset; - u64 endoff; - - if (IS_PCIX(pcibus_info)) { - return 0; - } - - if (dma_flags & SN_DMA_MSI) - return 0; - - if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS) - xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) : - PHYS_TO_TIODMA(paddr); - else - xio_addr = paddr; - - xio_base = pcibus_info->pbi_dir_xbase; - offset = xio_addr - xio_base; - endoff = req_size + offset; - if ((req_size > (1ULL << 31)) || /* Too Big */ - (xio_addr < xio_base) || /* Out of range for mappings */ - (endoff > (1ULL << 31))) { /* Too Big */ - return 0; - } - - return PCI32_DIRECT_BASE | offset; -} - -/* - * Wrapper routine for freeing DMA maps - * DMA mappings for Direct 64 and 32 do not have any DMA maps. - */ -void -pcibr_dma_unmap(struct pci_dev *hwdev, dma_addr_t dma_handle, int direction) -{ - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); - struct pcibus_info *pcibus_info = - (struct pcibus_info *)pcidev_info->pdi_pcibus_info; - - if (IS_PCI32_MAPPED(dma_handle)) { - int ate_index; - - ate_index = - IOPG((ATE_SWAP_OFF(dma_handle) - PCI32_MAPPED_BASE)); - pcibr_ate_free(pcibus_info, ate_index); - } -} - -/* - * On SN systems there is a race condition between a PIO read response and - * DMA's. In rare cases, the read response may beat the DMA, causing the - * driver to think that data in memory is complete and meaningful. This code - * eliminates that race. This routine is called by the PIO read routines - * after doing the read. For PIC this routine then forces a fake interrupt - * on another line, which is logically associated with the slot that the PIO - * is addressed to. It then spins while watching the memory location that - * the interrupt is targeted to. When the interrupt response arrives, we - * are sure that the DMA has landed in memory and it is safe for the driver - * to proceed. For TIOCP use the Device(x) Write Request Buffer Flush - * Bridge register since it ensures the data has entered the coherence domain, - * unlike the PIC Device(x) Write Request Buffer Flush register. - */ - -void sn_dma_flush(u64 addr) -{ - nasid_t nasid; - int is_tio; - int wid_num; - int i, j; - unsigned long flags; - u64 itte; - struct hubdev_info *hubinfo; - struct sn_flush_device_kernel *p; - struct sn_flush_device_common *common; - struct sn_flush_nasid_entry *flush_nasid_list; - - if (!sn_ioif_inited) - return; - - nasid = NASID_GET(addr); - if (-1 == nasid_to_cnodeid(nasid)) - return; - - hubinfo = (NODEPDA(nasid_to_cnodeid(nasid)))->pdinfo; - - BUG_ON(!hubinfo); - - flush_nasid_list = &hubinfo->hdi_flush_nasid_list; - if (flush_nasid_list->widget_p == NULL) - return; - - is_tio = (nasid & 1); - if (is_tio) { - int itte_index; - - if (TIO_HWIN(addr)) - itte_index = 0; - else if (TIO_BWIN_WINDOWNUM(addr)) - itte_index = TIO_BWIN_WINDOWNUM(addr); - else - itte_index = -1; - - if (itte_index >= 0) { - itte = flush_nasid_list->iio_itte[itte_index]; - if (! TIO_ITTE_VALID(itte)) - return; - wid_num = TIO_ITTE_WIDGET(itte); - } else - wid_num = TIO_SWIN_WIDGETNUM(addr); - } else { - if (BWIN_WINDOWNUM(addr)) { - itte = flush_nasid_list->iio_itte[BWIN_WINDOWNUM(addr)]; - wid_num = IIO_ITTE_WIDGET(itte); - } else - wid_num = SWIN_WIDGETNUM(addr); - } - if (flush_nasid_list->widget_p[wid_num] == NULL) - return; - p = &flush_nasid_list->widget_p[wid_num][0]; - - /* find a matching BAR */ - for (i = 0; i < DEV_PER_WIDGET; i++,p++) { - common = p->common; - for (j = 0; j < PCI_ROM_RESOURCE; j++) { - if (common->sfdl_bar_list[j].start == 0) - break; - if (addr >= common->sfdl_bar_list[j].start - && addr <= common->sfdl_bar_list[j].end) - break; - } - if (j < PCI_ROM_RESOURCE && common->sfdl_bar_list[j].start != 0) - break; - } - - /* if no matching BAR, return without doing anything. */ - if (i == DEV_PER_WIDGET) - return; - - /* - * For TIOCP use the Device(x) Write Request Buffer Flush Bridge - * register since it ensures the data has entered the coherence - * domain, unlike PIC. - */ - if (is_tio) { - /* - * Note: devices behind TIOCE should never be matched in the - * above code, and so the following code is PIC/CP centric. - * If CE ever needs the sn_dma_flush mechanism, we will have - * to account for that here and in tioce_bus_fixup(). - */ - u32 tio_id = HUB_L(TIO_IOSPACE_ADDR(nasid, TIO_NODE_ID)); - u32 revnum = XWIDGET_PART_REV_NUM(tio_id); - - /* TIOCP BRINGUP WAR (PV907516): Don't write buffer flush reg */ - if ((1 << XWIDGET_PART_REV_NUM_REV(revnum)) & PV907516) { - return; - } else { - pcireg_wrb_flush_get(common->sfdl_pcibus_info, - (common->sfdl_slot - 1)); - } - } else { - spin_lock_irqsave(&p->sfdl_flush_lock, flags); - *common->sfdl_flush_addr = 0; - - /* force an interrupt. */ - *(volatile u32 *)(common->sfdl_force_int_addr) = 1; - - /* wait for the interrupt to come back. */ - while (*(common->sfdl_flush_addr) != 0x10f) - cpu_relax(); - - /* okay, everything is synched up. */ - spin_unlock_irqrestore(&p->sfdl_flush_lock, flags); - } - return; -} - -/* - * DMA interfaces. Called from pci_dma.c routines. - */ - -dma_addr_t -pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size, int dma_flags) -{ - dma_addr_t dma_handle; - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); - - /* SN cannot support DMA addresses smaller than 32 bits. */ - if (hwdev->dma_mask < 0x7fffffff) { - return 0; - } - - if (hwdev->dma_mask == ~0UL) { - /* - * Handle the most common case: 64 bit cards. This - * call should always succeed. - */ - - dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr, - PCI64_ATTR_PREF, dma_flags); - } else { - /* Handle 32-63 bit cards via direct mapping */ - dma_handle = pcibr_dmatrans_direct32(pcidev_info, phys_addr, - size, 0, dma_flags); - if (!dma_handle) { - /* - * It is a 32 bit card and we cannot do direct mapping, - * so we use an ATE. - */ - - dma_handle = pcibr_dmamap_ate32(pcidev_info, phys_addr, - size, PCI32_ATE_PREF, - dma_flags); - } - } - - return dma_handle; -} - -dma_addr_t -pcibr_dma_map_consistent(struct pci_dev * hwdev, unsigned long phys_addr, - size_t size, int dma_flags) -{ - dma_addr_t dma_handle; - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); - - if (hwdev->dev.coherent_dma_mask == ~0UL) { - dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr, - PCI64_ATTR_BAR, dma_flags); - } else { - dma_handle = (dma_addr_t) pcibr_dmamap_ate32(pcidev_info, - phys_addr, size, - PCI32_ATE_BAR, dma_flags); - } - - return dma_handle; -} - -EXPORT_SYMBOL(sn_dma_flush); diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c deleted file mode 100644 index 7195df1da121fba60ffe69bba64f937fe812e334..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001-2004, 2006 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "xtalk/xwidgetdev.h" -#include "xtalk/hubdev.h" - -int -sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp, - char **ssdt) -{ - struct ia64_sal_retval ret_stuff; - u64 busnum; - u64 segment; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - - segment = soft->pbi_buscommon.bs_persist_segment; - busnum = soft->pbi_buscommon.bs_persist_busnum; - SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_ENABLE, segment, - busnum, (u64) device, (u64) resp, (u64)ia64_tpa(ssdt), - 0, 0); - - return (int)ret_stuff.v0; -} - -int -sal_pcibr_slot_disable(struct pcibus_info *soft, int device, int action, - void *resp) -{ - struct ia64_sal_retval ret_stuff; - u64 busnum; - u64 segment; - - ret_stuff.status = 0; - ret_stuff.v0 = 0; - - segment = soft->pbi_buscommon.bs_persist_segment; - busnum = soft->pbi_buscommon.bs_persist_busnum; - SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_DISABLE, - segment, busnum, (u64) device, (u64) action, - (u64) resp, 0, 0); - - return (int)ret_stuff.v0; -} - -static int sal_pcibr_error_interrupt(struct pcibus_info *soft) -{ - struct ia64_sal_retval ret_stuff; - u64 busnum; - int segment; - ret_stuff.status = 0; - ret_stuff.v0 = 0; - - segment = soft->pbi_buscommon.bs_persist_segment; - busnum = soft->pbi_buscommon.bs_persist_busnum; - SAL_CALL_NOLOCK(ret_stuff, - (u64) SN_SAL_IOIF_ERROR_INTERRUPT, - (u64) segment, (u64) busnum, 0, 0, 0, 0, 0); - - return (int)ret_stuff.v0; -} - -u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus) -{ - long rc; - u16 uninitialized_var(ioboard); /* GCC be quiet */ - nasid_t nasid = NASID_GET(SN_PCIBUS_BUSSOFT(pci_bus)->bs_base); - - rc = ia64_sn_sysctl_ioboard_get(nasid, &ioboard); - if (rc) { - printk(KERN_WARNING "ia64_sn_sysctl_ioboard_get failed: %ld\n", - rc); - return 0; - } - - return ioboard; -} - -/* - * PCI Bridge Error interrupt handler. Gets invoked whenever a PCI - * bridge sends an error interrupt. - */ -static irqreturn_t -pcibr_error_intr_handler(int irq, void *arg) -{ - struct pcibus_info *soft = arg; - - if (sal_pcibr_error_interrupt(soft) < 0) - panic("pcibr_error_intr_handler(): Fatal Bridge Error"); - - return IRQ_HANDLED; -} - -void * -pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller) -{ - int nasid, cnode, j; - struct hubdev_info *hubdev_info; - struct pcibus_info *soft; - struct sn_flush_device_kernel *sn_flush_device_kernel; - struct sn_flush_device_common *common; - - if (! IS_PCI_BRIDGE_ASIC(prom_bussoft->bs_asic_type)) { - return NULL; - } - - /* - * Allocate kernel bus soft and copy from prom. - */ - - soft = kmemdup(prom_bussoft, sizeof(struct pcibus_info), GFP_KERNEL); - if (!soft) { - return NULL; - } - - soft->pbi_buscommon.bs_base = (unsigned long) - ioremap(REGION_OFFSET(soft->pbi_buscommon.bs_base), - sizeof(struct pic)); - - spin_lock_init(&soft->pbi_lock); - - /* - * register the bridge's error interrupt handler - */ - if (request_irq(SGI_PCIASIC_ERROR, pcibr_error_intr_handler, - IRQF_SHARED, "PCIBR error", (void *)(soft))) { - printk(KERN_WARNING - "pcibr cannot allocate interrupt for error handler\n"); - } - irq_set_handler(SGI_PCIASIC_ERROR, handle_level_irq); - sn_set_err_irq_affinity(SGI_PCIASIC_ERROR); - - /* - * Update the Bridge with the "kernel" pagesize - */ - if (PAGE_SIZE < 16384) { - pcireg_control_bit_clr(soft, PCIBR_CTRL_PAGE_SIZE); - } else { - pcireg_control_bit_set(soft, PCIBR_CTRL_PAGE_SIZE); - } - - nasid = NASID_GET(soft->pbi_buscommon.bs_base); - cnode = nasid_to_cnodeid(nasid); - hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); - - if (hubdev_info->hdi_flush_nasid_list.widget_p) { - sn_flush_device_kernel = hubdev_info->hdi_flush_nasid_list. - widget_p[(int)soft->pbi_buscommon.bs_xid]; - if (sn_flush_device_kernel) { - for (j = 0; j < DEV_PER_WIDGET; - j++, sn_flush_device_kernel++) { - common = sn_flush_device_kernel->common; - if (common->sfdl_slot == -1) - continue; - if ((common->sfdl_persistent_segment == - soft->pbi_buscommon.bs_persist_segment) && - (common->sfdl_persistent_busnum == - soft->pbi_buscommon.bs_persist_busnum)) - common->sfdl_pcibus_info = - soft; - } - } - } - - /* Setup the PMU ATE map */ - soft->pbi_int_ate_resource.lowest_free_index = 0; - soft->pbi_int_ate_resource.ate = - kcalloc(soft->pbi_int_ate_size, sizeof(u64), GFP_KERNEL); - - if (!soft->pbi_int_ate_resource.ate) { - kfree(soft); - return NULL; - } - - return soft; -} - -void pcibr_force_interrupt(struct sn_irq_info *sn_irq_info) -{ - struct pcidev_info *pcidev_info; - struct pcibus_info *pcibus_info; - int bit = sn_irq_info->irq_int_bit; - - if (! sn_irq_info->irq_bridge) - return; - - pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; - if (pcidev_info) { - pcibus_info = - (struct pcibus_info *)pcidev_info->pdi_host_pcidev_info-> - pdi_pcibus_info; - pcireg_force_intr_set(pcibus_info, bit); - } -} - -void pcibr_target_interrupt(struct sn_irq_info *sn_irq_info) -{ - struct pcidev_info *pcidev_info; - struct pcibus_info *pcibus_info; - int bit = sn_irq_info->irq_int_bit; - u64 xtalk_addr = sn_irq_info->irq_xtalkaddr; - - pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; - if (pcidev_info) { - pcibus_info = - (struct pcibus_info *)pcidev_info->pdi_host_pcidev_info-> - pdi_pcibus_info; - - /* Disable the device's IRQ */ - pcireg_intr_enable_bit_clr(pcibus_info, (1 << bit)); - - /* Change the device's IRQ */ - pcireg_intr_addr_addr_set(pcibus_info, bit, xtalk_addr); - - /* Re-enable the device's IRQ */ - pcireg_intr_enable_bit_set(pcibus_info, (1 << bit)); - - pcibr_force_interrupt(sn_irq_info); - } -} - -/* - * Provider entries for PIC/CP - */ - -struct sn_pcibus_provider pcibr_provider = { - .dma_map = pcibr_dma_map, - .dma_map_consistent = pcibr_dma_map_consistent, - .dma_unmap = pcibr_dma_unmap, - .bus_fixup = pcibr_bus_fixup, - .force_interrupt = pcibr_force_interrupt, - .target_interrupt = pcibr_target_interrupt -}; - -int -pcibr_init_provider(void) -{ - sn_pci_provider[PCIIO_ASIC_TYPE_PIC] = &pcibr_provider; - sn_pci_provider[PCIIO_ASIC_TYPE_TIOCP] = &pcibr_provider; - - return 0; -} - -EXPORT_SYMBOL_GPL(sal_pcibr_slot_enable); -EXPORT_SYMBOL_GPL(sal_pcibr_slot_disable); -EXPORT_SYMBOL_GPL(sn_ioboard_to_pci_bus); diff --git a/arch/ia64/sn/pci/pcibr/pcibr_reg.c b/arch/ia64/sn/pci/pcibr/pcibr_reg.c deleted file mode 100644 index 8b8bbd51d43389f8a108d7599d9d98490a8e15f1..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/pci/pcibr/pcibr_reg.c +++ /dev/null @@ -1,285 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -union br_ptr { - struct tiocp tio; - struct pic pic; -}; - -/* - * Control Register Access -- Read/Write 0000_0020 - */ -void pcireg_control_bit_clr(struct pcibus_info *pcibus_info, u64 bits) -{ - union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base; - - if (pcibus_info) { - switch (pcibus_info->pbi_bridge_type) { - case PCIBR_BRIDGETYPE_TIOCP: - __sn_clrq_relaxed(&ptr->tio.cp_control, bits); - break; - case PCIBR_BRIDGETYPE_PIC: - __sn_clrq_relaxed(&ptr->pic.p_wid_control, bits); - break; - default: - panic - ("pcireg_control_bit_clr: unknown bridgetype bridge 0x%p", - ptr); - } - } -} - -void pcireg_control_bit_set(struct pcibus_info *pcibus_info, u64 bits) -{ - union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base; - - if (pcibus_info) { - switch (pcibus_info->pbi_bridge_type) { - case PCIBR_BRIDGETYPE_TIOCP: - __sn_setq_relaxed(&ptr->tio.cp_control, bits); - break; - case PCIBR_BRIDGETYPE_PIC: - __sn_setq_relaxed(&ptr->pic.p_wid_control, bits); - break; - default: - panic - ("pcireg_control_bit_set: unknown bridgetype bridge 0x%p", - ptr); - } - } -} - -/* - * PCI/PCIX Target Flush Register Access -- Read Only 0000_0050 - */ -u64 pcireg_tflush_get(struct pcibus_info *pcibus_info) -{ - union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base; - u64 ret = 0; - - if (pcibus_info) { - switch (pcibus_info->pbi_bridge_type) { - case PCIBR_BRIDGETYPE_TIOCP: - ret = __sn_readq_relaxed(&ptr->tio.cp_tflush); - break; - case PCIBR_BRIDGETYPE_PIC: - ret = __sn_readq_relaxed(&ptr->pic.p_wid_tflush); - break; - default: - panic - ("pcireg_tflush_get: unknown bridgetype bridge 0x%p", - ptr); - } - } - - /* Read of the Target Flush should always return zero */ - if (ret != 0) - panic("pcireg_tflush_get:Target Flush failed\n"); - - return ret; -} - -/* - * Interrupt Status Register Access -- Read Only 0000_0100 - */ -u64 pcireg_intr_status_get(struct pcibus_info * pcibus_info) -{ - union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base; - u64 ret = 0; - - if (pcibus_info) { - switch (pcibus_info->pbi_bridge_type) { - case PCIBR_BRIDGETYPE_TIOCP: - ret = __sn_readq_relaxed(&ptr->tio.cp_int_status); - break; - case PCIBR_BRIDGETYPE_PIC: - ret = __sn_readq_relaxed(&ptr->pic.p_int_status); - break; - default: - panic - ("pcireg_intr_status_get: unknown bridgetype bridge 0x%p", - ptr); - } - } - return ret; -} - -/* - * Interrupt Enable Register Access -- Read/Write 0000_0108 - */ -void pcireg_intr_enable_bit_clr(struct pcibus_info *pcibus_info, u64 bits) -{ - union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base; - - if (pcibus_info) { - switch (pcibus_info->pbi_bridge_type) { - case PCIBR_BRIDGETYPE_TIOCP: - __sn_clrq_relaxed(&ptr->tio.cp_int_enable, bits); - break; - case PCIBR_BRIDGETYPE_PIC: - __sn_clrq_relaxed(&ptr->pic.p_int_enable, bits); - break; - default: - panic - ("pcireg_intr_enable_bit_clr: unknown bridgetype bridge 0x%p", - ptr); - } - } -} - -void pcireg_intr_enable_bit_set(struct pcibus_info *pcibus_info, u64 bits) -{ - union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base; - - if (pcibus_info) { - switch (pcibus_info->pbi_bridge_type) { - case PCIBR_BRIDGETYPE_TIOCP: - __sn_setq_relaxed(&ptr->tio.cp_int_enable, bits); - break; - case PCIBR_BRIDGETYPE_PIC: - __sn_setq_relaxed(&ptr->pic.p_int_enable, bits); - break; - default: - panic - ("pcireg_intr_enable_bit_set: unknown bridgetype bridge 0x%p", - ptr); - } - } -} - -/* - * Intr Host Address Register (int_addr) -- Read/Write 0000_0130 - 0000_0168 - */ -void pcireg_intr_addr_addr_set(struct pcibus_info *pcibus_info, int int_n, - u64 addr) -{ - union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base; - - if (pcibus_info) { - switch (pcibus_info->pbi_bridge_type) { - case PCIBR_BRIDGETYPE_TIOCP: - __sn_clrq_relaxed(&ptr->tio.cp_int_addr[int_n], - TIOCP_HOST_INTR_ADDR); - __sn_setq_relaxed(&ptr->tio.cp_int_addr[int_n], - (addr & TIOCP_HOST_INTR_ADDR)); - break; - case PCIBR_BRIDGETYPE_PIC: - __sn_clrq_relaxed(&ptr->pic.p_int_addr[int_n], - PIC_HOST_INTR_ADDR); - __sn_setq_relaxed(&ptr->pic.p_int_addr[int_n], - (addr & PIC_HOST_INTR_ADDR)); - break; - default: - panic - ("pcireg_intr_addr_addr_get: unknown bridgetype bridge 0x%p", - ptr); - } - } -} - -/* - * Force Interrupt Register Access -- Write Only 0000_01C0 - 0000_01F8 - */ -void pcireg_force_intr_set(struct pcibus_info *pcibus_info, int int_n) -{ - union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base; - - if (pcibus_info) { - switch (pcibus_info->pbi_bridge_type) { - case PCIBR_BRIDGETYPE_TIOCP: - writeq(1, &ptr->tio.cp_force_pin[int_n]); - break; - case PCIBR_BRIDGETYPE_PIC: - writeq(1, &ptr->pic.p_force_pin[int_n]); - break; - default: - panic - ("pcireg_force_intr_set: unknown bridgetype bridge 0x%p", - ptr); - } - } -} - -/* - * Device(x) Write Buffer Flush Reg Access -- Read Only 0000_0240 - 0000_0258 - */ -u64 pcireg_wrb_flush_get(struct pcibus_info *pcibus_info, int device) -{ - union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base; - u64 ret = 0; - - if (pcibus_info) { - switch (pcibus_info->pbi_bridge_type) { - case PCIBR_BRIDGETYPE_TIOCP: - ret = - __sn_readq_relaxed(&ptr->tio.cp_wr_req_buf[device]); - break; - case PCIBR_BRIDGETYPE_PIC: - ret = - __sn_readq_relaxed(&ptr->pic.p_wr_req_buf[device]); - break; - default: - panic("pcireg_wrb_flush_get: unknown bridgetype bridge 0x%p", ptr); - } - - } - /* Read of the Write Buffer Flush should always return zero */ - return ret; -} - -void pcireg_int_ate_set(struct pcibus_info *pcibus_info, int ate_index, - u64 val) -{ - union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base; - - if (pcibus_info) { - switch (pcibus_info->pbi_bridge_type) { - case PCIBR_BRIDGETYPE_TIOCP: - writeq(val, &ptr->tio.cp_int_ate_ram[ate_index]); - break; - case PCIBR_BRIDGETYPE_PIC: - writeq(val, &ptr->pic.p_int_ate_ram[ate_index]); - break; - default: - panic - ("pcireg_int_ate_set: unknown bridgetype bridge 0x%p", - ptr); - } - } -} - -u64 __iomem *pcireg_int_ate_addr(struct pcibus_info *pcibus_info, int ate_index) -{ - union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base; - u64 __iomem *ret = NULL; - - if (pcibus_info) { - switch (pcibus_info->pbi_bridge_type) { - case PCIBR_BRIDGETYPE_TIOCP: - ret = &ptr->tio.cp_int_ate_ram[ate_index]; - break; - case PCIBR_BRIDGETYPE_PIC: - ret = &ptr->pic.p_int_ate_ram[ate_index]; - break; - default: - panic - ("pcireg_int_ate_addr: unknown bridgetype bridge 0x%p", - ptr); - } - } - return ret; -} diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c deleted file mode 100644 index a70b11fd57d6e2cdb8299befa0a86351a98265b5..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/pci/tioca_provider.c +++ /dev/null @@ -1,677 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2003-2005 Silicon Graphics, Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -u32 tioca_gart_found; -EXPORT_SYMBOL(tioca_gart_found); /* used by agp-sgi */ - -LIST_HEAD(tioca_list); -EXPORT_SYMBOL(tioca_list); /* used by agp-sgi */ - -static int tioca_gart_init(struct tioca_kernel *); - -/** - * tioca_gart_init - Initialize SGI TIOCA GART - * @tioca_common: ptr to common prom/kernel struct identifying the - * - * If the indicated tioca has devices present, initialize its associated - * GART MMR's and kernel memory. - */ -static int -tioca_gart_init(struct tioca_kernel *tioca_kern) -{ - u64 ap_reg; - u64 offset; - struct page *tmp; - struct tioca_common *tioca_common; - struct tioca __iomem *ca_base; - - tioca_common = tioca_kern->ca_common; - ca_base = (struct tioca __iomem *)tioca_common->ca_common.bs_base; - - if (list_empty(tioca_kern->ca_devices)) - return 0; - - ap_reg = 0; - - /* - * Validate aperature size - */ - - switch (CA_APERATURE_SIZE >> 20) { - case 4: - ap_reg |= (0x3ff << CA_GART_AP_SIZE_SHFT); /* 4MB */ - break; - case 8: - ap_reg |= (0x3fe << CA_GART_AP_SIZE_SHFT); /* 8MB */ - break; - case 16: - ap_reg |= (0x3fc << CA_GART_AP_SIZE_SHFT); /* 16MB */ - break; - case 32: - ap_reg |= (0x3f8 << CA_GART_AP_SIZE_SHFT); /* 32 MB */ - break; - case 64: - ap_reg |= (0x3f0 << CA_GART_AP_SIZE_SHFT); /* 64 MB */ - break; - case 128: - ap_reg |= (0x3e0 << CA_GART_AP_SIZE_SHFT); /* 128 MB */ - break; - case 256: - ap_reg |= (0x3c0 << CA_GART_AP_SIZE_SHFT); /* 256 MB */ - break; - case 512: - ap_reg |= (0x380 << CA_GART_AP_SIZE_SHFT); /* 512 MB */ - break; - case 1024: - ap_reg |= (0x300 << CA_GART_AP_SIZE_SHFT); /* 1GB */ - break; - case 2048: - ap_reg |= (0x200 << CA_GART_AP_SIZE_SHFT); /* 2GB */ - break; - case 4096: - ap_reg |= (0x000 << CA_GART_AP_SIZE_SHFT); /* 4 GB */ - break; - default: - printk(KERN_ERR "%s: Invalid CA_APERATURE_SIZE " - "0x%lx\n", __func__, (ulong) CA_APERATURE_SIZE); - return -1; - } - - /* - * Set up other aperature parameters - */ - - if (PAGE_SIZE >= 16384) { - tioca_kern->ca_ap_pagesize = 16384; - ap_reg |= CA_GART_PAGE_SIZE; - } else { - tioca_kern->ca_ap_pagesize = 4096; - } - - tioca_kern->ca_ap_size = CA_APERATURE_SIZE; - tioca_kern->ca_ap_bus_base = CA_APERATURE_BASE; - tioca_kern->ca_gart_entries = - tioca_kern->ca_ap_size / tioca_kern->ca_ap_pagesize; - - ap_reg |= (CA_GART_AP_ENB_AGP | CA_GART_AP_ENB_PCI); - ap_reg |= tioca_kern->ca_ap_bus_base; - - /* - * Allocate and set up the GART - */ - - tioca_kern->ca_gart_size = tioca_kern->ca_gart_entries * sizeof(u64); - tmp = - alloc_pages_node(tioca_kern->ca_closest_node, - GFP_KERNEL | __GFP_ZERO, - get_order(tioca_kern->ca_gart_size)); - - if (!tmp) { - printk(KERN_ERR "%s: Could not allocate " - "%llu bytes (order %d) for GART\n", - __func__, - tioca_kern->ca_gart_size, - get_order(tioca_kern->ca_gart_size)); - return -ENOMEM; - } - - tioca_kern->ca_gart = page_address(tmp); - tioca_kern->ca_gart_coretalk_addr = - PHYS_TO_TIODMA(virt_to_phys(tioca_kern->ca_gart)); - - /* - * Compute PCI/AGP convenience fields - */ - - offset = CA_PCI32_MAPPED_BASE - CA_APERATURE_BASE; - tioca_kern->ca_pciap_base = CA_PCI32_MAPPED_BASE; - tioca_kern->ca_pciap_size = CA_PCI32_MAPPED_SIZE; - tioca_kern->ca_pcigart_start = offset / tioca_kern->ca_ap_pagesize; - tioca_kern->ca_pcigart_base = - tioca_kern->ca_gart_coretalk_addr + offset; - tioca_kern->ca_pcigart = - &tioca_kern->ca_gart[tioca_kern->ca_pcigart_start]; - tioca_kern->ca_pcigart_entries = - tioca_kern->ca_pciap_size / tioca_kern->ca_ap_pagesize; - tioca_kern->ca_pcigart_pagemap = - kzalloc(tioca_kern->ca_pcigart_entries / 8, GFP_KERNEL); - if (!tioca_kern->ca_pcigart_pagemap) { - free_pages((unsigned long)tioca_kern->ca_gart, - get_order(tioca_kern->ca_gart_size)); - return -1; - } - - offset = CA_AGP_MAPPED_BASE - CA_APERATURE_BASE; - tioca_kern->ca_gfxap_base = CA_AGP_MAPPED_BASE; - tioca_kern->ca_gfxap_size = CA_AGP_MAPPED_SIZE; - tioca_kern->ca_gfxgart_start = offset / tioca_kern->ca_ap_pagesize; - tioca_kern->ca_gfxgart_base = - tioca_kern->ca_gart_coretalk_addr + offset; - tioca_kern->ca_gfxgart = - &tioca_kern->ca_gart[tioca_kern->ca_gfxgart_start]; - tioca_kern->ca_gfxgart_entries = - tioca_kern->ca_gfxap_size / tioca_kern->ca_ap_pagesize; - - /* - * various control settings: - * use agp op-combining - * use GET semantics to fetch memory - * participate in coherency domain - * DISABLE GART PREFETCHING due to hw bug tracked in SGI PV930029 - */ - - __sn_setq_relaxed(&ca_base->ca_control1, - CA_AGPDMA_OP_ENB_COMBDELAY); /* PV895469 ? */ - __sn_clrq_relaxed(&ca_base->ca_control2, CA_GART_MEM_PARAM); - __sn_setq_relaxed(&ca_base->ca_control2, - (0x2ull << CA_GART_MEM_PARAM_SHFT)); - tioca_kern->ca_gart_iscoherent = 1; - __sn_clrq_relaxed(&ca_base->ca_control2, - (CA_GART_WR_PREFETCH_ENB | CA_GART_RD_PREFETCH_ENB)); - - /* - * Unmask GART fetch error interrupts. Clear residual errors first. - */ - - writeq(CA_GART_FETCH_ERR, &ca_base->ca_int_status_alias); - writeq(CA_GART_FETCH_ERR, &ca_base->ca_mult_error_alias); - __sn_clrq_relaxed(&ca_base->ca_int_mask, CA_GART_FETCH_ERR); - - /* - * Program the aperature and gart registers in TIOCA - */ - - writeq(ap_reg, &ca_base->ca_gart_aperature); - writeq(tioca_kern->ca_gart_coretalk_addr|1, &ca_base->ca_gart_ptr_table); - - return 0; -} - -/** - * tioca_fastwrite_enable - enable AGP FW for a tioca and its functions - * @tioca_kernel: structure representing the CA - * - * Given a CA, scan all attached functions making sure they all support - * FastWrite. If so, enable FastWrite for all functions and the CA itself. - */ - -void -tioca_fastwrite_enable(struct tioca_kernel *tioca_kern) -{ - int cap_ptr; - u32 reg; - struct tioca __iomem *tioca_base; - struct pci_dev *pdev; - struct tioca_common *common; - - common = tioca_kern->ca_common; - - /* - * Scan all vga controllers on this bus making sure they all - * support FW. If not, return. - */ - - list_for_each_entry(pdev, tioca_kern->ca_devices, bus_list) { - if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8)) - continue; - - cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); - if (!cap_ptr) - return; /* no AGP CAP means no FW */ - - pci_read_config_dword(pdev, cap_ptr + PCI_AGP_STATUS, ®); - if (!(reg & PCI_AGP_STATUS_FW)) - return; /* function doesn't support FW */ - } - - /* - * Set fw for all vga fn's - */ - - list_for_each_entry(pdev, tioca_kern->ca_devices, bus_list) { - if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8)) - continue; - - cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); - pci_read_config_dword(pdev, cap_ptr + PCI_AGP_COMMAND, ®); - reg |= PCI_AGP_COMMAND_FW; - pci_write_config_dword(pdev, cap_ptr + PCI_AGP_COMMAND, reg); - } - - /* - * Set ca's fw to match - */ - - tioca_base = (struct tioca __iomem*)common->ca_common.bs_base; - __sn_setq_relaxed(&tioca_base->ca_control1, CA_AGP_FW_ENABLE); -} - -EXPORT_SYMBOL(tioca_fastwrite_enable); /* used by agp-sgi */ - -/** - * tioca_dma_d64 - create a DMA mapping using 64-bit direct mode - * @paddr: system physical address - * - * Map @paddr into 64-bit CA bus space. No device context is necessary. - * Bits 53:0 come from the coretalk address. We just need to mask in the - * following optional bits of the 64-bit pci address: - * - * 63:60 - Coretalk Packet Type - 0x1 for Mem Get/Put (coherent) - * 0x2 for PIO (non-coherent) - * We will always use 0x1 - * 55:55 - Swap bytes Currently unused - */ -static u64 -tioca_dma_d64(unsigned long paddr) -{ - dma_addr_t bus_addr; - - bus_addr = PHYS_TO_TIODMA(paddr); - - BUG_ON(!bus_addr); - BUG_ON(bus_addr >> 54); - - /* Set upper nibble to Cache Coherent Memory op */ - bus_addr |= (1UL << 60); - - return bus_addr; -} - -/** - * tioca_dma_d48 - create a DMA mapping using 48-bit direct mode - * @pdev: linux pci_dev representing the function - * @paddr: system physical address - * - * Map @paddr into 64-bit bus space of the CA associated with @pcidev_info. - * - * The CA agp 48 bit direct address falls out as follows: - * - * When direct mapping AGP addresses, the 48 bit AGP address is - * constructed as follows: - * - * [47:40] - Low 8 bits of the page Node ID extracted from coretalk - * address [47:40]. The upper 8 node bits are fixed - * and come from the xxx register bits [5:0] - * [39:38] - Chiplet ID extracted from coretalk address [39:38] - * [37:00] - node offset extracted from coretalk address [37:00] - * - * Since the node id in general will be non-zero, and the chiplet id - * will always be non-zero, it follows that the device must support - * a dma mask of at least 0xffffffffff (40 bits) to target node 0 - * and in general should be 0xffffffffffff (48 bits) to target nodes - * up to 255. Nodes above 255 need the support of the xxx register, - * and so a given CA can only directly target nodes in the range - * xxx - xxx+255. - */ -static u64 -tioca_dma_d48(struct pci_dev *pdev, u64 paddr) -{ - struct tioca_common *tioca_common; - struct tioca __iomem *ca_base; - u64 ct_addr; - dma_addr_t bus_addr; - u32 node_upper; - u64 agp_dma_extn; - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev); - - tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info; - ca_base = (struct tioca __iomem *)tioca_common->ca_common.bs_base; - - ct_addr = PHYS_TO_TIODMA(paddr); - if (!ct_addr) - return 0; - - bus_addr = (dma_addr_t) (ct_addr & 0xffffffffffffUL); - node_upper = ct_addr >> 48; - - if (node_upper > 64) { - printk(KERN_ERR "%s: coretalk addr 0x%p node id out " - "of range\n", __func__, (void *)ct_addr); - return 0; - } - - agp_dma_extn = __sn_readq_relaxed(&ca_base->ca_agp_dma_addr_extn); - if (node_upper != (agp_dma_extn >> CA_AGP_DMA_NODE_ID_SHFT)) { - printk(KERN_ERR "%s: coretalk upper node (%u) " - "mismatch with ca_agp_dma_addr_extn (%llu)\n", - __func__, - node_upper, (agp_dma_extn >> CA_AGP_DMA_NODE_ID_SHFT)); - return 0; - } - - return bus_addr; -} - -/** - * tioca_dma_mapped - create a DMA mapping using a CA GART - * @pdev: linux pci_dev representing the function - * @paddr: host physical address to map - * @req_size: len (bytes) to map - * - * Map @paddr into CA address space using the GART mechanism. The mapped - * dma_addr_t is guaranteed to be contiguous in CA bus space. - */ -static dma_addr_t -tioca_dma_mapped(struct pci_dev *pdev, unsigned long paddr, size_t req_size) -{ - int ps, ps_shift, entry, entries, mapsize; - u64 xio_addr, end_xio_addr; - struct tioca_common *tioca_common; - struct tioca_kernel *tioca_kern; - dma_addr_t bus_addr = 0; - struct tioca_dmamap *ca_dmamap; - void *map; - unsigned long flags; - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev); - - tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info; - tioca_kern = (struct tioca_kernel *)tioca_common->ca_kernel_private; - - xio_addr = PHYS_TO_TIODMA(paddr); - if (!xio_addr) - return 0; - - spin_lock_irqsave(&tioca_kern->ca_lock, flags); - - /* - * allocate a map struct - */ - - ca_dmamap = kzalloc(sizeof(struct tioca_dmamap), GFP_ATOMIC); - if (!ca_dmamap) - goto map_return; - - /* - * Locate free entries that can hold req_size. Account for - * unaligned start/length when allocating. - */ - - ps = tioca_kern->ca_ap_pagesize; /* will be power of 2 */ - ps_shift = ffs(ps) - 1; - end_xio_addr = xio_addr + req_size - 1; - - entries = (end_xio_addr >> ps_shift) - (xio_addr >> ps_shift) + 1; - - map = tioca_kern->ca_pcigart_pagemap; - mapsize = tioca_kern->ca_pcigart_entries; - - entry = bitmap_find_next_zero_area(map, mapsize, 0, entries, 0); - if (entry >= mapsize) { - kfree(ca_dmamap); - goto map_return; - } - - bitmap_set(map, entry, entries); - - bus_addr = tioca_kern->ca_pciap_base + (entry * ps); - - ca_dmamap->cad_dma_addr = bus_addr; - ca_dmamap->cad_gart_size = entries; - ca_dmamap->cad_gart_entry = entry; - list_add(&ca_dmamap->cad_list, &tioca_kern->ca_dmamaps); - - if (xio_addr % ps) { - tioca_kern->ca_pcigart[entry] = tioca_paddr_to_gart(xio_addr); - bus_addr += xio_addr & (ps - 1); - xio_addr &= ~(ps - 1); - xio_addr += ps; - entry++; - } - - while (xio_addr < end_xio_addr) { - tioca_kern->ca_pcigart[entry] = tioca_paddr_to_gart(xio_addr); - xio_addr += ps; - entry++; - } - - tioca_tlbflush(tioca_kern); - -map_return: - spin_unlock_irqrestore(&tioca_kern->ca_lock, flags); - return bus_addr; -} - -/** - * tioca_dma_unmap - release CA mapping resources - * @pdev: linux pci_dev representing the function - * @bus_addr: bus address returned by an earlier tioca_dma_map - * @dir: mapping direction (unused) - * - * Locate mapping resources associated with @bus_addr and release them. - * For mappings created using the direct modes (64 or 48) there are no - * resources to release. - */ -static void -tioca_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir) -{ - int i, entry; - struct tioca_common *tioca_common; - struct tioca_kernel *tioca_kern; - struct tioca_dmamap *map; - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev); - unsigned long flags; - - tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info; - tioca_kern = (struct tioca_kernel *)tioca_common->ca_kernel_private; - - /* return straight away if this isn't be a mapped address */ - - if (bus_addr < tioca_kern->ca_pciap_base || - bus_addr >= (tioca_kern->ca_pciap_base + tioca_kern->ca_pciap_size)) - return; - - spin_lock_irqsave(&tioca_kern->ca_lock, flags); - - list_for_each_entry(map, &tioca_kern->ca_dmamaps, cad_list) - if (map->cad_dma_addr == bus_addr) - break; - - BUG_ON(map == NULL); - - entry = map->cad_gart_entry; - - for (i = 0; i < map->cad_gart_size; i++, entry++) { - clear_bit(entry, tioca_kern->ca_pcigart_pagemap); - tioca_kern->ca_pcigart[entry] = 0; - } - tioca_tlbflush(tioca_kern); - - list_del(&map->cad_list); - spin_unlock_irqrestore(&tioca_kern->ca_lock, flags); - kfree(map); -} - -/** - * tioca_dma_map - map pages for PCI DMA - * @pdev: linux pci_dev representing the function - * @paddr: host physical address to map - * @byte_count: bytes to map - * - * This is the main wrapper for mapping host physical pages to CA PCI space. - * The mapping mode used is based on the devices dma_mask. As a last resort - * use the GART mapped mode. - */ -static u64 -tioca_dma_map(struct pci_dev *pdev, unsigned long paddr, size_t byte_count, int dma_flags) -{ - u64 mapaddr; - - /* - * Not supported for now ... - */ - if (dma_flags & SN_DMA_MSI) - return 0; - - /* - * If card is 64 or 48 bit addressable, use a direct mapping. 32 - * bit direct is so restrictive w.r.t. where the memory resides that - * we don't use it even though CA has some support. - */ - - if (pdev->dma_mask == ~0UL) - mapaddr = tioca_dma_d64(paddr); - else if (pdev->dma_mask == 0xffffffffffffUL) - mapaddr = tioca_dma_d48(pdev, paddr); - else - mapaddr = 0; - - /* Last resort ... use PCI portion of CA GART */ - - if (mapaddr == 0) - mapaddr = tioca_dma_mapped(pdev, paddr, byte_count); - - return mapaddr; -} - -/** - * tioca_error_intr_handler - SGI TIO CA error interrupt handler - * @irq: unused - * @arg: pointer to tioca_common struct for the given CA - * - * Handle a CA error interrupt. Simply a wrapper around a SAL call which - * defers processing to the SGI prom. - */ -static irqreturn_t -tioca_error_intr_handler(int irq, void *arg) -{ - struct tioca_common *soft = arg; - struct ia64_sal_retval ret_stuff; - u64 segment; - u64 busnum; - ret_stuff.status = 0; - ret_stuff.v0 = 0; - - segment = soft->ca_common.bs_persist_segment; - busnum = soft->ca_common.bs_persist_busnum; - - SAL_CALL_NOLOCK(ret_stuff, - (u64) SN_SAL_IOIF_ERROR_INTERRUPT, - segment, busnum, 0, 0, 0, 0, 0); - - return IRQ_HANDLED; -} - -/** - * tioca_bus_fixup - perform final PCI fixup for a TIO CA bus - * @prom_bussoft: Common prom/kernel struct representing the bus - * - * Replicates the tioca_common pointed to by @prom_bussoft in kernel - * space. Allocates and initializes a kernel-only area for a given CA, - * and sets up an irq for handling CA error interrupts. - * - * On successful setup, returns the kernel version of tioca_common back to - * the caller. - */ -static void * -tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller) -{ - struct tioca_common *tioca_common; - struct tioca_kernel *tioca_kern; - struct pci_bus *bus; - - /* sanity check prom rev */ - - if (is_shub1() && sn_sal_rev() < 0x0406) { - printk - (KERN_ERR "%s: SGI prom rev 4.06 or greater required " - "for tioca support\n", __func__); - return NULL; - } - - /* - * Allocate kernel bus soft and copy from prom. - */ - - tioca_common = kmemdup(prom_bussoft, sizeof(struct tioca_common), - GFP_KERNEL); - if (!tioca_common) - return NULL; - - tioca_common->ca_common.bs_base = (unsigned long) - ioremap(REGION_OFFSET(tioca_common->ca_common.bs_base), - sizeof(struct tioca_common)); - - /* init kernel-private area */ - - tioca_kern = kzalloc(sizeof(struct tioca_kernel), GFP_KERNEL); - if (!tioca_kern) { - kfree(tioca_common); - return NULL; - } - - tioca_kern->ca_common = tioca_common; - spin_lock_init(&tioca_kern->ca_lock); - INIT_LIST_HEAD(&tioca_kern->ca_dmamaps); - tioca_kern->ca_closest_node = - nasid_to_cnodeid(tioca_common->ca_closest_nasid); - tioca_common->ca_kernel_private = (u64) tioca_kern; - - bus = pci_find_bus(tioca_common->ca_common.bs_persist_segment, - tioca_common->ca_common.bs_persist_busnum); - BUG_ON(!bus); - tioca_kern->ca_devices = &bus->devices; - - /* init GART */ - - if (tioca_gart_init(tioca_kern) < 0) { - kfree(tioca_kern); - kfree(tioca_common); - return NULL; - } - - tioca_gart_found++; - list_add(&tioca_kern->ca_list, &tioca_list); - - if (request_irq(SGI_TIOCA_ERROR, - tioca_error_intr_handler, - IRQF_SHARED, "TIOCA error", (void *)tioca_common)) - printk(KERN_WARNING - "%s: Unable to get irq %d. " - "Error interrupts won't be routed for TIOCA bus %d\n", - __func__, SGI_TIOCA_ERROR, - (int)tioca_common->ca_common.bs_persist_busnum); - - irq_set_handler(SGI_TIOCA_ERROR, handle_level_irq); - sn_set_err_irq_affinity(SGI_TIOCA_ERROR); - - /* Setup locality information */ - controller->node = tioca_kern->ca_closest_node; - return tioca_common; -} - -static struct sn_pcibus_provider tioca_pci_interfaces = { - .dma_map = tioca_dma_map, - .dma_map_consistent = tioca_dma_map, - .dma_unmap = tioca_dma_unmap, - .bus_fixup = tioca_bus_fixup, - .force_interrupt = NULL, - .target_interrupt = NULL -}; - -/** - * tioca_init_provider - init SN PCI provider ops for TIO CA - */ -int -tioca_init_provider(void) -{ - sn_pci_provider[PCIIO_ASIC_TYPE_TIOCA] = &tioca_pci_interfaces; - return 0; -} diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c deleted file mode 100644 index 3bd9abc35485ed4cd2c4ba4ffa51b974b4044f4c..0000000000000000000000000000000000000000 --- a/arch/ia64/sn/pci/tioce_provider.c +++ /dev/null @@ -1,1062 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2003-2006 Silicon Graphics, Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * 1/26/2006 - * - * WAR for SGI PV 944642. For revA TIOCE, need to use the following recipe - * (taken from the above PV) before and after accessing tioce internal MMR's - * to avoid tioce lockups. - * - * The recipe as taken from the PV: - * - * if(mmr address < 0x45000) { - * if(mmr address == 0 or 0x80) - * mmr wrt or read address 0xc0 - * else if(mmr address == 0x148 or 0x200) - * mmr wrt or read address 0x28 - * else - * mmr wrt or read address 0x158 - * - * do desired mmr access (rd or wrt) - * - * if(mmr address == 0x100) - * mmr wrt or read address 0x38 - * mmr wrt or read address 0xb050 - * } else - * do desired mmr access - * - * According to hw, we can use reads instead of writes to the above address - * - * Note this WAR can only to be used for accessing internal MMR's in the - * TIOCE Coretalk Address Range 0x0 - 0x07ff_ffff. This includes the - * "Local CE Registers and Memories" and "PCI Compatible Config Space" address - * spaces from table 2-1 of the "CE Programmer's Reference Overview" document. - * - * All registers defined in struct tioce will meet that criteria. - */ - -static inline void -tioce_mmr_war_pre(struct tioce_kernel *kern, void __iomem *mmr_addr) -{ - u64 mmr_base; - u64 mmr_offset; - - if (kern->ce_common->ce_rev != TIOCE_REV_A) - return; - - mmr_base = kern->ce_common->ce_pcibus.bs_base; - mmr_offset = (unsigned long)mmr_addr - mmr_base; - - if (mmr_offset < 0x45000) { - u64 mmr_war_offset; - - if (mmr_offset == 0 || mmr_offset == 0x80) - mmr_war_offset = 0xc0; - else if (mmr_offset == 0x148 || mmr_offset == 0x200) - mmr_war_offset = 0x28; - else - mmr_war_offset = 0x158; - - readq_relaxed((void __iomem *)(mmr_base + mmr_war_offset)); - } -} - -static inline void -tioce_mmr_war_post(struct tioce_kernel *kern, void __iomem *mmr_addr) -{ - u64 mmr_base; - u64 mmr_offset; - - if (kern->ce_common->ce_rev != TIOCE_REV_A) - return; - - mmr_base = kern->ce_common->ce_pcibus.bs_base; - mmr_offset = (unsigned long)mmr_addr - mmr_base; - - if (mmr_offset < 0x45000) { - if (mmr_offset == 0x100) - readq_relaxed((void __iomem *)(mmr_base + 0x38)); - readq_relaxed((void __iomem *)(mmr_base + 0xb050)); - } -} - -/* load mmr contents into a variable */ -#define tioce_mmr_load(kern, mmrp, varp) do {\ - tioce_mmr_war_pre(kern, mmrp); \ - *(varp) = readq_relaxed(mmrp); \ - tioce_mmr_war_post(kern, mmrp); \ -} while (0) - -/* store variable contents into mmr */ -#define tioce_mmr_store(kern, mmrp, varp) do {\ - tioce_mmr_war_pre(kern, mmrp); \ - writeq(*varp, mmrp); \ - tioce_mmr_war_post(kern, mmrp); \ -} while (0) - -/* store immediate value into mmr */ -#define tioce_mmr_storei(kern, mmrp, val) do {\ - tioce_mmr_war_pre(kern, mmrp); \ - writeq(val, mmrp); \ - tioce_mmr_war_post(kern, mmrp); \ -} while (0) - -/* set bits (immediate value) into mmr */ -#define tioce_mmr_seti(kern, mmrp, bits) do {\ - u64 tmp; \ - tioce_mmr_load(kern, mmrp, &tmp); \ - tmp |= (bits); \ - tioce_mmr_store(kern, mmrp, &tmp); \ -} while (0) - -/* clear bits (immediate value) into mmr */ -#define tioce_mmr_clri(kern, mmrp, bits) do { \ - u64 tmp; \ - tioce_mmr_load(kern, mmrp, &tmp); \ - tmp &= ~(bits); \ - tioce_mmr_store(kern, mmrp, &tmp); \ -} while (0) - -/** - * Bus address ranges for the 5 flavors of TIOCE DMA - */ - -#define TIOCE_D64_MIN 0x8000000000000000UL -#define TIOCE_D64_MAX 0xffffffffffffffffUL -#define TIOCE_D64_ADDR(a) ((a) >= TIOCE_D64_MIN) - -#define TIOCE_D32_MIN 0x0000000080000000UL -#define TIOCE_D32_MAX 0x00000000ffffffffUL -#define TIOCE_D32_ADDR(a) ((a) >= TIOCE_D32_MIN && (a) <= TIOCE_D32_MAX) - -#define TIOCE_M32_MIN 0x0000000000000000UL -#define TIOCE_M32_MAX 0x000000007fffffffUL -#define TIOCE_M32_ADDR(a) ((a) >= TIOCE_M32_MIN && (a) <= TIOCE_M32_MAX) - -#define TIOCE_M40_MIN 0x0000004000000000UL -#define TIOCE_M40_MAX 0x0000007fffffffffUL -#define TIOCE_M40_ADDR(a) ((a) >= TIOCE_M40_MIN && (a) <= TIOCE_M40_MAX) - -#define TIOCE_M40S_MIN 0x0000008000000000UL -#define TIOCE_M40S_MAX 0x000000ffffffffffUL -#define TIOCE_M40S_ADDR(a) ((a) >= TIOCE_M40S_MIN && (a) <= TIOCE_M40S_MAX) - -/* - * ATE manipulation macros. - */ - -#define ATE_PAGESHIFT(ps) (__ffs(ps)) -#define ATE_PAGEMASK(ps) ((ps)-1) - -#define ATE_PAGE(x, ps) ((x) >> ATE_PAGESHIFT(ps)) -#define ATE_NPAGES(start, len, pagesize) \ - (ATE_PAGE((start)+(len)-1, pagesize) - ATE_PAGE(start, pagesize) + 1) - -#define ATE_VALID(ate) ((ate) & (1UL << 63)) -#define ATE_MAKE(addr, ps, msi) \ - (((addr) & ~ATE_PAGEMASK(ps)) | (1UL << 63) | ((msi)?(1UL << 62):0)) - -/* - * Flavors of ate-based mapping supported by tioce_alloc_map() - */ - -#define TIOCE_ATE_M32 1 -#define TIOCE_ATE_M40 2 -#define TIOCE_ATE_M40S 3 - -#define KB(x) ((u64)(x) << 10) -#define MB(x) ((u64)(x) << 20) -#define GB(x) ((u64)(x) << 30) - -/** - * tioce_dma_d64 - create a DMA mapping using 64-bit direct mode - * @ct_addr: system coretalk address - * - * Map @ct_addr into 64-bit CE bus space. No device context is necessary - * and no CE mapping are consumed. - * - * Bits 53:0 come from the coretalk address. The remaining bits are set as - * follows: - * - * 63 - must be 1 to indicate d64 mode to CE hardware - * 62 - barrier bit ... controlled with tioce_dma_barrier() - * 61 - msi bit ... specified through dma_flags - * 60:54 - reserved, MBZ - */ -static u64 -tioce_dma_d64(unsigned long ct_addr, int dma_flags) -{ - u64 bus_addr; - - bus_addr = ct_addr | (1UL << 63); - if (dma_flags & SN_DMA_MSI) - bus_addr |= (1UL << 61); - - return bus_addr; -} - -/** - * pcidev_to_tioce - return misc ce related pointers given a pci_dev - * @pci_dev: pci device context - * @base: ptr to store struct tioce_mmr * for the CE holding this device - * @kernel: ptr to store struct tioce_kernel * for the CE holding this device - * @port: ptr to store the CE port number that this device is on - * - * Return pointers to various CE-related structures for the CE upstream of - * @pci_dev. - */ -static inline void -pcidev_to_tioce(struct pci_dev *pdev, struct tioce __iomem **base, - struct tioce_kernel **kernel, int *port) -{ - struct pcidev_info *pcidev_info; - struct tioce_common *ce_common; - struct tioce_kernel *ce_kernel; - - pcidev_info = SN_PCIDEV_INFO(pdev); - ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info; - ce_kernel = (struct tioce_kernel *)ce_common->ce_kernel_private; - - if (base) - *base = (struct tioce __iomem *)ce_common->ce_pcibus.bs_base; - if (kernel) - *kernel = ce_kernel; - - /* - * we use port as a zero-based value internally, even though the - * documentation is 1-based. - */ - if (port) - *port = - (pdev->bus->number < ce_kernel->ce_port1_secondary) ? 0 : 1; -} - -/** - * tioce_alloc_map - Given a coretalk address, map it to pcie bus address - * space using one of the various ATE-based address modes. - * @ce_kern: tioce context - * @type: map mode to use - * @port: 0-based port that the requesting device is downstream of - * @ct_addr: the coretalk address to map - * @len: number of bytes to map - * - * Given the addressing type, set up various parameters that define the - * ATE pool to use. Search for a contiguous block of entries to cover the - * length, and if enough resources exist, fill in the ATEs and construct a - * tioce_dmamap struct to track the mapping. - */ -static u64 -tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, - u64 ct_addr, int len, int dma_flags) -{ - int i; - int j; - int first; - int last; - int entries; - int nates; - u64 pagesize; - int msi_capable, msi_wanted; - u64 *ate_shadow; - u64 __iomem *ate_reg; - u64 addr; - struct tioce __iomem *ce_mmr; - u64 bus_base; - struct tioce_dmamap *map; - - ce_mmr = (struct tioce __iomem *)ce_kern->ce_common->ce_pcibus.bs_base; - - switch (type) { - case TIOCE_ATE_M32: - /* - * The first 64 entries of the ate3240 pool are dedicated to - * super-page (TIOCE_ATE_M40S) mode. - */ - first = 64; - entries = TIOCE_NUM_M3240_ATES - 64; - ate_shadow = ce_kern->ce_ate3240_shadow; - ate_reg = ce_mmr->ce_ure_ate3240; - pagesize = ce_kern->ce_ate3240_pagesize; - bus_base = TIOCE_M32_MIN; - msi_capable = 1; - break; - case TIOCE_ATE_M40: - first = 0; - entries = TIOCE_NUM_M40_ATES; - ate_shadow = ce_kern->ce_ate40_shadow; - ate_reg = ce_mmr->ce_ure_ate40; - pagesize = MB(64); - bus_base = TIOCE_M40_MIN; - msi_capable = 0; - break; - case TIOCE_ATE_M40S: - /* - * ate3240 entries 0-31 are dedicated to port1 super-page - * mappings. ate3240 entries 32-63 are dedicated to port2. - */ - first = port * 32; - entries = 32; - ate_shadow = ce_kern->ce_ate3240_shadow; - ate_reg = ce_mmr->ce_ure_ate3240; - pagesize = GB(16); - bus_base = TIOCE_M40S_MIN; - msi_capable = 0; - break; - default: - return 0; - } - - msi_wanted = dma_flags & SN_DMA_MSI; - if (msi_wanted && !msi_capable) - return 0; - - nates = ATE_NPAGES(ct_addr, len, pagesize); - if (nates > entries) - return 0; - - last = first + entries - nates; - for (i = first; i <= last; i++) { - if (ATE_VALID(ate_shadow[i])) - continue; - - for (j = i; j < i + nates; j++) - if (ATE_VALID(ate_shadow[j])) - break; - - if (j >= i + nates) - break; - } - - if (i > last) - return 0; - - map = kzalloc(sizeof(struct tioce_dmamap), GFP_ATOMIC); - if (!map) - return 0; - - addr = ct_addr; - for (j = 0; j < nates; j++) { - u64 ate; - - ate = ATE_MAKE(addr, pagesize, msi_wanted); - ate_shadow[i + j] = ate; - tioce_mmr_storei(ce_kern, &ate_reg[i + j], ate); - addr += pagesize; - } - - map->refcnt = 1; - map->nbytes = nates * pagesize; - map->ct_start = ct_addr & ~ATE_PAGEMASK(pagesize); - map->pci_start = bus_base + (i * pagesize); - map->ate_hw = &ate_reg[i]; - map->ate_shadow = &ate_shadow[i]; - map->ate_count = nates; - - list_add(&map->ce_dmamap_list, &ce_kern->ce_dmamap_list); - - return (map->pci_start + (ct_addr - map->ct_start)); -} - -/** - * tioce_dma_d32 - create a DMA mapping using 32-bit direct mode - * @pdev: linux pci_dev representing the function - * @paddr: system physical address - * - * Map @paddr into 32-bit bus space of the CE associated with @pcidev_info. - */ -static u64 -tioce_dma_d32(struct pci_dev *pdev, u64 ct_addr, int dma_flags) -{ - int dma_ok; - int port; - struct tioce __iomem *ce_mmr; - struct tioce_kernel *ce_kern; - u64 ct_upper; - u64 ct_lower; - dma_addr_t bus_addr; - - if (dma_flags & SN_DMA_MSI) - return 0; - - ct_upper = ct_addr & ~0x3fffffffUL; - ct_lower = ct_addr & 0x3fffffffUL; - - pcidev_to_tioce(pdev, &ce_mmr, &ce_kern, &port); - - if (ce_kern->ce_port[port].dirmap_refcnt == 0) { - u64 tmp; - - ce_kern->ce_port[port].dirmap_shadow = ct_upper; - tioce_mmr_storei(ce_kern, &ce_mmr->ce_ure_dir_map[port], - ct_upper); - tmp = ce_mmr->ce_ure_dir_map[port]; - dma_ok = 1; - } else - dma_ok = (ce_kern->ce_port[port].dirmap_shadow == ct_upper); - - if (dma_ok) { - ce_kern->ce_port[port].dirmap_refcnt++; - bus_addr = TIOCE_D32_MIN + ct_lower; - } else - bus_addr = 0; - - return bus_addr; -} - -/** - * tioce_dma_barrier - swizzle a TIOCE bus address to include or exclude - * the barrier bit. - * @bus_addr: bus address to swizzle - * - * Given a TIOCE bus address, set the appropriate bit to indicate barrier - * attributes. - */ -static u64 -tioce_dma_barrier(u64 bus_addr, int on) -{ - u64 barrier_bit; - - /* barrier not supported in M40/M40S mode */ - if (TIOCE_M40_ADDR(bus_addr) || TIOCE_M40S_ADDR(bus_addr)) - return bus_addr; - - if (TIOCE_D64_ADDR(bus_addr)) - barrier_bit = (1UL << 62); - else /* must be m32 or d32 */ - barrier_bit = (1UL << 30); - - return (on) ? (bus_addr | barrier_bit) : (bus_addr & ~barrier_bit); -} - -/** - * tioce_dma_unmap - release CE mapping resources - * @pdev: linux pci_dev representing the function - * @bus_addr: bus address returned by an earlier tioce_dma_map - * @dir: mapping direction (unused) - * - * Locate mapping resources associated with @bus_addr and release them. - * For mappings created using the direct modes there are no resources - * to release. - */ -void -tioce_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir) -{ - int i; - int port; - struct tioce_kernel *ce_kern; - struct tioce __iomem *ce_mmr; - unsigned long flags; - - bus_addr = tioce_dma_barrier(bus_addr, 0); - pcidev_to_tioce(pdev, &ce_mmr, &ce_kern, &port); - - /* nothing to do for D64 */ - - if (TIOCE_D64_ADDR(bus_addr)) - return; - - spin_lock_irqsave(&ce_kern->ce_lock, flags); - - if (TIOCE_D32_ADDR(bus_addr)) { - if (--ce_kern->ce_port[port].dirmap_refcnt == 0) { - ce_kern->ce_port[port].dirmap_shadow = 0; - tioce_mmr_storei(ce_kern, &ce_mmr->ce_ure_dir_map[port], - 0); - } - } else { - struct tioce_dmamap *map; - - list_for_each_entry(map, &ce_kern->ce_dmamap_list, - ce_dmamap_list) { - u64 last; - - last = map->pci_start + map->nbytes - 1; - if (bus_addr >= map->pci_start && bus_addr <= last) - break; - } - - if (&map->ce_dmamap_list == &ce_kern->ce_dmamap_list) { - printk(KERN_WARNING - "%s: %s - no map found for bus_addr 0x%llx\n", - __func__, pci_name(pdev), bus_addr); - } else if (--map->refcnt == 0) { - for (i = 0; i < map->ate_count; i++) { - map->ate_shadow[i] = 0; - tioce_mmr_storei(ce_kern, &map->ate_hw[i], 0); - } - - list_del(&map->ce_dmamap_list); - kfree(map); - } - } - - spin_unlock_irqrestore(&ce_kern->ce_lock, flags); -} - -/** - * tioce_do_dma_map - map pages for PCI DMA - * @pdev: linux pci_dev representing the function - * @paddr: host physical address to map - * @byte_count: bytes to map - * - * This is the main wrapper for mapping host physical pages to CE PCI space. - * The mapping mode used is based on the device's dma_mask. - */ -static u64 -tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, - int barrier, int dma_flags) -{ - unsigned long flags; - u64 ct_addr; - u64 mapaddr = 0; - struct tioce_kernel *ce_kern; - struct tioce_dmamap *map; - int port; - u64 dma_mask; - - dma_mask = (barrier) ? pdev->dev.coherent_dma_mask : pdev->dma_mask; - - /* cards must be able to address at least 31 bits */ - if (dma_mask < 0x7fffffffUL) - return 0; - - if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS) - ct_addr = PHYS_TO_TIODMA(paddr); - else - ct_addr = paddr; - - /* - * If the device can generate 64 bit addresses, create a D64 map. - */ - if (dma_mask == ~0UL) { - mapaddr = tioce_dma_d64(ct_addr, dma_flags); - if (mapaddr) - goto dma_map_done; - } - - pcidev_to_tioce(pdev, NULL, &ce_kern, &port); - - spin_lock_irqsave(&ce_kern->ce_lock, flags); - - /* - * D64 didn't work ... See if we have an existing map that covers - * this address range. Must account for devices dma_mask here since - * an existing map might have been done in a mode using more pci - * address bits than this device can support. - */ - list_for_each_entry(map, &ce_kern->ce_dmamap_list, ce_dmamap_list) { - u64 last; - - last = map->ct_start + map->nbytes - 1; - if (ct_addr >= map->ct_start && - ct_addr + byte_count - 1 <= last && - map->pci_start <= dma_mask) { - map->refcnt++; - mapaddr = map->pci_start + (ct_addr - map->ct_start); - break; - } - } - - /* - * If we don't have a map yet, and the card can generate 40 - * bit addresses, try the M40/M40S modes. Note these modes do not - * support a barrier bit, so if we need a consistent map these - * won't work. - */ - if (!mapaddr && !barrier && dma_mask >= 0xffffffffffUL) { - /* - * We have two options for 40-bit mappings: 16GB "super" ATEs - * and 64MB "regular" ATEs. We'll try both if needed for a - * given mapping but which one we try first depends on the - * size. For requests >64MB, prefer to use a super page with - * regular as the fallback. Otherwise, try in the reverse order. - */ - - if (byte_count > MB(64)) { - mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40S, - port, ct_addr, byte_count, - dma_flags); - if (!mapaddr) - mapaddr = - tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1, - ct_addr, byte_count, - dma_flags); - } else { - mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1, - ct_addr, byte_count, - dma_flags); - if (!mapaddr) - mapaddr = - tioce_alloc_map(ce_kern, TIOCE_ATE_M40S, - port, ct_addr, byte_count, - dma_flags); - } - } - - /* - * 32-bit direct is the next mode to try - */ - if (!mapaddr && dma_mask >= 0xffffffffUL) - mapaddr = tioce_dma_d32(pdev, ct_addr, dma_flags); - - /* - * Last resort, try 32-bit ATE-based map. - */ - if (!mapaddr) - mapaddr = - tioce_alloc_map(ce_kern, TIOCE_ATE_M32, -1, ct_addr, - byte_count, dma_flags); - - spin_unlock_irqrestore(&ce_kern->ce_lock, flags); - -dma_map_done: - if (mapaddr && barrier) - mapaddr = tioce_dma_barrier(mapaddr, 1); - - return mapaddr; -} - -/** - * tioce_dma - standard pci dma map interface - * @pdev: pci device requesting the map - * @paddr: system physical address to map into pci space - * @byte_count: # bytes to map - * - * Simply call tioce_do_dma_map() to create a map with the barrier bit clear - * in the address. - */ -static u64 -tioce_dma(struct pci_dev *pdev, unsigned long paddr, size_t byte_count, int dma_flags) -{ - return tioce_do_dma_map(pdev, paddr, byte_count, 0, dma_flags); -} - -/** - * tioce_dma_consistent - consistent pci dma map interface - * @pdev: pci device requesting the map - * @paddr: system physical address to map into pci space - * @byte_count: # bytes to map - * - * Simply call tioce_do_dma_map() to create a map with the barrier bit set - * in the address. - */ -static u64 -tioce_dma_consistent(struct pci_dev *pdev, unsigned long paddr, size_t byte_count, int dma_flags) -{ - return tioce_do_dma_map(pdev, paddr, byte_count, 1, dma_flags); -} - -/** - * tioce_error_intr_handler - SGI TIO CE error interrupt handler - * @irq: unused - * @arg: pointer to tioce_common struct for the given CE - * - * Handle a CE error interrupt. Simply a wrapper around a SAL call which - * defers processing to the SGI prom. - */ -static irqreturn_t -tioce_error_intr_handler(int irq, void *arg) -{ - struct tioce_common *soft = arg; - struct ia64_sal_retval ret_stuff; - ret_stuff.status = 0; - ret_stuff.v0 = 0; - - SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_ERROR_INTERRUPT, - soft->ce_pcibus.bs_persist_segment, - soft->ce_pcibus.bs_persist_busnum, 0, 0, 0, 0, 0); - - if (ret_stuff.v0) - panic("tioce_error_intr_handler: Fatal TIOCE error"); - - return IRQ_HANDLED; -} - -/** - * tioce_reserve_m32 - reserve M32 ATEs for the indicated address range - * @tioce_kernel: TIOCE context to reserve ATEs for - * @base: starting bus address to reserve - * @limit: last bus address to reserve - * - * If base/limit falls within the range of bus space mapped through the - * M32 space, reserve the resources corresponding to the range. - */ -static void -tioce_reserve_m32(struct tioce_kernel *ce_kern, u64 base, u64 limit) -{ - int ate_index, last_ate, ps; - struct tioce __iomem *ce_mmr; - - ce_mmr = (struct tioce __iomem *)ce_kern->ce_common->ce_pcibus.bs_base; - ps = ce_kern->ce_ate3240_pagesize; - ate_index = ATE_PAGE(base, ps); - last_ate = ate_index + ATE_NPAGES(base, limit-base+1, ps) - 1; - - if (ate_index < 64) - ate_index = 64; - - if (last_ate >= TIOCE_NUM_M3240_ATES) - last_ate = TIOCE_NUM_M3240_ATES - 1; - - while (ate_index <= last_ate) { - u64 ate; - - ate = ATE_MAKE(0xdeadbeef, ps, 0); - ce_kern->ce_ate3240_shadow[ate_index] = ate; - tioce_mmr_storei(ce_kern, &ce_mmr->ce_ure_ate3240[ate_index], - ate); - ate_index++; - } -} - -/** - * tioce_kern_init - init kernel structures related to a given TIOCE - * @tioce_common: ptr to a cached tioce_common struct that originated in prom - */ -static struct tioce_kernel * -tioce_kern_init(struct tioce_common *tioce_common) -{ - int i; - int ps; - int dev; - u32 tmp; - unsigned int seg, bus; - struct tioce __iomem *tioce_mmr; - struct tioce_kernel *tioce_kern; - - tioce_kern = kzalloc(sizeof(struct tioce_kernel), GFP_KERNEL); - if (!tioce_kern) { - return NULL; - } - - tioce_kern->ce_common = tioce_common; - spin_lock_init(&tioce_kern->ce_lock); - INIT_LIST_HEAD(&tioce_kern->ce_dmamap_list); - tioce_common->ce_kernel_private = (u64) tioce_kern; - - /* - * Determine the secondary bus number of the port2 logical PPB. - * This is used to decide whether a given pci device resides on - * port1 or port2. Note: We don't have enough plumbing set up - * here to use pci_read_config_xxx() so use raw_pci_read(). - */ - - seg = tioce_common->ce_pcibus.bs_persist_segment; - bus = tioce_common->ce_pcibus.bs_persist_busnum; - - raw_pci_read(seg, bus, PCI_DEVFN(2, 0), PCI_SECONDARY_BUS, 1,&tmp); - tioce_kern->ce_port1_secondary = (u8) tmp; - - /* - * Set PMU pagesize to the largest size available, and zero out - * the ATEs. - */ - - tioce_mmr = (struct tioce __iomem *)tioce_common->ce_pcibus.bs_base; - tioce_mmr_clri(tioce_kern, &tioce_mmr->ce_ure_page_map, - CE_URE_PAGESIZE_MASK); - tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_ure_page_map, - CE_URE_256K_PAGESIZE); - ps = tioce_kern->ce_ate3240_pagesize = KB(256); - - for (i = 0; i < TIOCE_NUM_M40_ATES; i++) { - tioce_kern->ce_ate40_shadow[i] = 0; - tioce_mmr_storei(tioce_kern, &tioce_mmr->ce_ure_ate40[i], 0); - } - - for (i = 0; i < TIOCE_NUM_M3240_ATES; i++) { - tioce_kern->ce_ate3240_shadow[i] = 0; - tioce_mmr_storei(tioce_kern, &tioce_mmr->ce_ure_ate3240[i], 0); - } - - /* - * Reserve ATEs corresponding to reserved address ranges. These - * include: - * - * Memory space covered by each PPB mem base/limit register - * Memory space covered by each PPB prefetch base/limit register - * - * These bus ranges are for pio (downstream) traffic only, and so - * cannot be used for DMA. - */ - - for (dev = 1; dev <= 2; dev++) { - u64 base, limit; - - /* mem base/limit */ - - raw_pci_read(seg, bus, PCI_DEVFN(dev, 0), - PCI_MEMORY_BASE, 2, &tmp); - base = (u64)tmp << 16; - - raw_pci_read(seg, bus, PCI_DEVFN(dev, 0), - PCI_MEMORY_LIMIT, 2, &tmp); - limit = (u64)tmp << 16; - limit |= 0xfffffUL; - - if (base < limit) - tioce_reserve_m32(tioce_kern, base, limit); - - /* - * prefetch mem base/limit. The tioce ppb's have 64-bit - * decoders, so read the upper portions w/o checking the - * attributes. - */ - - raw_pci_read(seg, bus, PCI_DEVFN(dev, 0), - PCI_PREF_MEMORY_BASE, 2, &tmp); - base = ((u64)tmp & PCI_PREF_RANGE_MASK) << 16; - - raw_pci_read(seg, bus, PCI_DEVFN(dev, 0), - PCI_PREF_BASE_UPPER32, 4, &tmp); - base |= (u64)tmp << 32; - - raw_pci_read(seg, bus, PCI_DEVFN(dev, 0), - PCI_PREF_MEMORY_LIMIT, 2, &tmp); - - limit = ((u64)tmp & PCI_PREF_RANGE_MASK) << 16; - limit |= 0xfffffUL; - - raw_pci_read(seg, bus, PCI_DEVFN(dev, 0), - PCI_PREF_LIMIT_UPPER32, 4, &tmp); - limit |= (u64)tmp << 32; - - if ((base < limit) && TIOCE_M32_ADDR(base)) - tioce_reserve_m32(tioce_kern, base, limit); - } - - return tioce_kern; -} - -/** - * tioce_force_interrupt - implement altix force_interrupt() backend for CE - * @sn_irq_info: sn asic irq that we need an interrupt generated for - * - * Given an sn_irq_info struct, set the proper bit in ce_adm_force_int to - * force a secondary interrupt to be generated. This is to work around an - * asic issue where there is a small window of opportunity for a legacy device - * interrupt to be lost. - */ -static void -tioce_force_interrupt(struct sn_irq_info *sn_irq_info) -{ - struct pcidev_info *pcidev_info; - struct tioce_common *ce_common; - struct tioce_kernel *ce_kern; - struct tioce __iomem *ce_mmr; - u64 force_int_val; - - if (!sn_irq_info->irq_bridge) - return; - - if (sn_irq_info->irq_bridge_type != PCIIO_ASIC_TYPE_TIOCE) - return; - - pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; - if (!pcidev_info) - return; - - ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info; - ce_mmr = (struct tioce __iomem *)ce_common->ce_pcibus.bs_base; - ce_kern = (struct tioce_kernel *)ce_common->ce_kernel_private; - - /* - * TIOCE Rev A workaround (PV 945826), force an interrupt by writing - * the TIO_INTx register directly (1/26/2006) - */ - if (ce_common->ce_rev == TIOCE_REV_A) { - u64 int_bit_mask = (1ULL << sn_irq_info->irq_int_bit); - u64 status; - - tioce_mmr_load(ce_kern, &ce_mmr->ce_adm_int_status, &status); - if (status & int_bit_mask) { - u64 force_irq = (1 << 8) | sn_irq_info->irq_irq; - u64 ctalk = sn_irq_info->irq_xtalkaddr; - u64 nasid, offset; - - nasid = (ctalk & CTALK_NASID_MASK) >> CTALK_NASID_SHFT; - offset = (ctalk & CTALK_NODE_OFFSET); - HUB_S(TIO_IOSPACE_ADDR(nasid, offset), force_irq); - } - - return; - } - - /* - * irq_int_bit is originally set up by prom, and holds the interrupt - * bit shift (not mask) as defined by the bit definitions in the - * ce_adm_int mmr. These shifts are not the same for the - * ce_adm_force_int register, so do an explicit mapping here to make - * things clearer. - */ - - switch (sn_irq_info->irq_int_bit) { - case CE_ADM_INT_PCIE_PORT1_DEV_A_SHFT: - force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_A_SHFT; - break; - case CE_ADM_INT_PCIE_PORT1_DEV_B_SHFT: - force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_B_SHFT; - break; - case CE_ADM_INT_PCIE_PORT1_DEV_C_SHFT: - force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_C_SHFT; - break; - case CE_ADM_INT_PCIE_PORT1_DEV_D_SHFT: - force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_D_SHFT; - break; - case CE_ADM_INT_PCIE_PORT2_DEV_A_SHFT: - force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_A_SHFT; - break; - case CE_ADM_INT_PCIE_PORT2_DEV_B_SHFT: - force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_B_SHFT; - break; - case CE_ADM_INT_PCIE_PORT2_DEV_C_SHFT: - force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_C_SHFT; - break; - case CE_ADM_INT_PCIE_PORT2_DEV_D_SHFT: - force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_D_SHFT; - break; - default: - return; - } - tioce_mmr_storei(ce_kern, &ce_mmr->ce_adm_force_int, force_int_val); -} - -/** - * tioce_target_interrupt - implement set_irq_affinity for tioce resident - * functions. Note: only applies to line interrupts, not MSI's. - * - * @sn_irq_info: SN IRQ context - * - * Given an sn_irq_info, set the associated CE device's interrupt destination - * register. Since the interrupt destination registers are on a per-ce-slot - * basis, this will retarget line interrupts for all functions downstream of - * the slot. - */ -static void -tioce_target_interrupt(struct sn_irq_info *sn_irq_info) -{ - struct pcidev_info *pcidev_info; - struct tioce_common *ce_common; - struct tioce_kernel *ce_kern; - struct tioce __iomem *ce_mmr; - int bit; - u64 vector; - - pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; - if (!pcidev_info) - return; - - ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info; - ce_mmr = (struct tioce __iomem *)ce_common->ce_pcibus.bs_base; - ce_kern = (struct tioce_kernel *)ce_common->ce_kernel_private; - - bit = sn_irq_info->irq_int_bit; - - tioce_mmr_seti(ce_kern, &ce_mmr->ce_adm_int_mask, (1UL << bit)); - vector = (u64)sn_irq_info->irq_irq << INTR_VECTOR_SHFT; - vector |= sn_irq_info->irq_xtalkaddr; - tioce_mmr_storei(ce_kern, &ce_mmr->ce_adm_int_dest[bit], vector); - tioce_mmr_clri(ce_kern, &ce_mmr->ce_adm_int_mask, (1UL << bit)); - - tioce_force_interrupt(sn_irq_info); -} - -/** - * tioce_bus_fixup - perform final PCI fixup for a TIO CE bus - * @prom_bussoft: Common prom/kernel struct representing the bus - * - * Replicates the tioce_common pointed to by @prom_bussoft in kernel - * space. Allocates and initializes a kernel-only area for a given CE, - * and sets up an irq for handling CE error interrupts. - * - * On successful setup, returns the kernel version of tioce_common back to - * the caller. - */ -static void * -tioce_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller) -{ - struct tioce_common *tioce_common; - struct tioce_kernel *tioce_kern; - struct tioce __iomem *tioce_mmr; - - /* - * Allocate kernel bus soft and copy from prom. - */ - - tioce_common = kzalloc(sizeof(struct tioce_common), GFP_KERNEL); - if (!tioce_common) - return NULL; - - memcpy(tioce_common, prom_bussoft, sizeof(struct tioce_common)); - tioce_common->ce_pcibus.bs_base = (unsigned long) - ioremap(REGION_OFFSET(tioce_common->ce_pcibus.bs_base), - sizeof(struct tioce_common)); - - tioce_kern = tioce_kern_init(tioce_common); - if (tioce_kern == NULL) { - kfree(tioce_common); - return NULL; - } - - /* - * Clear out any transient errors before registering the error - * interrupt handler. - */ - - tioce_mmr = (struct tioce __iomem *)tioce_common->ce_pcibus.bs_base; - tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_adm_int_status_alias, ~0ULL); - tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_adm_error_summary_alias, - ~0ULL); - tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_dre_comp_err_addr, 0ULL); - - if (request_irq(SGI_PCIASIC_ERROR, - tioce_error_intr_handler, - IRQF_SHARED, "TIOCE error", (void *)tioce_common)) - printk(KERN_WARNING - "%s: Unable to get irq %d. " - "Error interrupts won't be routed for " - "TIOCE bus %04x:%02x\n", - __func__, SGI_PCIASIC_ERROR, - tioce_common->ce_pcibus.bs_persist_segment, - tioce_common->ce_pcibus.bs_persist_busnum); - - irq_set_handler(SGI_PCIASIC_ERROR, handle_level_irq); - sn_set_err_irq_affinity(SGI_PCIASIC_ERROR); - return tioce_common; -} - -static struct sn_pcibus_provider tioce_pci_interfaces = { - .dma_map = tioce_dma, - .dma_map_consistent = tioce_dma_consistent, - .dma_unmap = tioce_dma_unmap, - .bus_fixup = tioce_bus_fixup, - .force_interrupt = tioce_force_interrupt, - .target_interrupt = tioce_target_interrupt -}; - -/** - * tioce_init_provider - init SN PCI provider ops for TIO CE - */ -int -tioce_init_provider(void) -{ - sn_pci_provider[PCIIO_ASIC_TYPE_TIOCE] = &tioce_pci_interfaces; - return 0; -} diff --git a/arch/ia64/uv/kernel/Makefile b/arch/ia64/uv/kernel/Makefile index 124e441d383d89d72ef72a5965e1d4875ece3b79..297196578d19d4094d37825a491d585239361563 100644 --- a/arch/ia64/uv/kernel/Makefile +++ b/arch/ia64/uv/kernel/Makefile @@ -10,4 +10,3 @@ ccflags-y := -Iarch/ia64/sn/include obj-y += setup.o -obj-$(CONFIG_IA64_GENERIC) += machvec.o diff --git a/arch/ia64/uv/kernel/machvec.c b/arch/ia64/uv/kernel/machvec.c deleted file mode 100644 index 50737a9dca7428a3157d973066408f8356b915f6..0000000000000000000000000000000000000000 --- a/arch/ia64/uv/kernel/machvec.c +++ /dev/null @@ -1,11 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. - */ - -#define MACHVEC_PLATFORM_NAME uv -#define MACHVEC_PLATFORM_HEADER -#include diff --git a/arch/ia64/uv/kernel/setup.c b/arch/ia64/uv/kernel/setup.c index f1490657bafc2a26fb2c7c5613d1e6f368a1706e..bb025486d7912d2f7edba99c4b620305c3372817 100644 --- a/arch/ia64/uv/kernel/setup.c +++ b/arch/ia64/uv/kernel/setup.c @@ -8,25 +8,20 @@ * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved. */ +#include +#include #include #include -#include +#include #include #include +bool ia64_is_uv; +EXPORT_SYMBOL_GPL(ia64_is_uv); + DEFINE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); EXPORT_PER_CPU_SYMBOL_GPL(__uv_hub_info); -#ifdef CONFIG_IA64_SGI_UV -int sn_prom_type; -long sn_partition_id; -EXPORT_SYMBOL(sn_partition_id); -long sn_coherency_id; -EXPORT_SYMBOL_GPL(sn_coherency_id); -long sn_region_size; -EXPORT_SYMBOL(sn_region_size); -#endif - struct redir_addr { unsigned long redirect; unsigned long alias; @@ -58,6 +53,34 @@ static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size) BUG(); } +void __init uv_probe_system_type(void) +{ + struct acpi_table_rsdp *rsdp; + struct acpi_table_xsdt *xsdt; + + if (efi.acpi20 == EFI_INVALID_TABLE_ADDR) { + pr_err("ACPI 2.0 RSDP not found.\n"); + return; + } + + rsdp = (struct acpi_table_rsdp *)__va(efi.acpi20); + if (strncmp(rsdp->signature, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)) { + pr_err("ACPI 2.0 RSDP signature incorrect.\n"); + return; + } + + xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_physical_address); + if (strncmp(xsdt->header.signature, ACPI_SIG_XSDT, + sizeof(ACPI_SIG_XSDT) - 1)) { + pr_err("ACPI 2.0 XSDT signature incorrect.\n"); + return; + } + + if (!strcmp(xsdt->header.oem_id, "SGI") && + !strcmp(xsdt->header.oem_table_id + 4, "UV")) + ia64_is_uv = true; +} + void __init uv_setup(char **cmdline_p) { union uvh_si_addr_map_config_u m_n_config; @@ -66,30 +89,11 @@ void __init uv_setup(char **cmdline_p) int nid, cpu, m_val, n_val; unsigned long mmr_base, lowmem_redir_base, lowmem_redir_size; - if (IS_MEDUSA()) { - lowmem_redir_base = 0; - lowmem_redir_size = 0; - node_id.v = 0; - m_n_config.s.m_skt = 37; - m_n_config.s.n_skt = 0; - mmr_base = 0; -#if 0 - /* Need BIOS calls - TDB */ - if (!ia64_sn_is_fake_prom()) - sn_prom_type = 1; - else -#endif - sn_prom_type = 2; - printk(KERN_INFO "Running on medusa with %s PROM\n", - (sn_prom_type == 1) ? "real" : "fake"); - } else { - get_lowmem_redirect(&lowmem_redir_base, &lowmem_redir_size); - node_id.v = uv_read_local_mmr(UVH_NODE_ID); - m_n_config.v = uv_read_local_mmr(UVH_SI_ADDR_MAP_CONFIG); - mmr_base = - uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) & - ~UV_MMR_ENABLE; - } + get_lowmem_redirect(&lowmem_redir_base, &lowmem_redir_size); + node_id.v = uv_read_local_mmr(UVH_NODE_ID); + m_n_config.v = uv_read_local_mmr(UVH_SI_ADDR_MAP_CONFIG); + mmr_base = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) & + ~UV_MMR_ENABLE; m_val = m_n_config.s.m_skt; n_val = m_n_config.s.n_skt; diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c index 902255e7b5b2ad56840561a112433e38d72ccb5c..73bf5ea9ee1bf1cf4a7631ee58e7eceb2c96534f 100644 --- a/arch/m68k/atari/config.c +++ b/arch/m68k/atari/config.c @@ -246,9 +246,9 @@ void __init config_atari(void) } else if (hwreg_present(tt_palette)) { ATARIHW_SET(TT_SHIFTER); pr_cont(" TT_SHIFTER"); - } else if (hwreg_present(&shifter.bas_hi)) { - if (hwreg_present(&shifter.bas_lo) && - (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) { + } else if (hwreg_present(&shifter_st.bas_hi)) { + if (hwreg_present(&shifter_st.bas_lo) && + (shifter_st.bas_lo = 0x0aau, shifter_st.bas_lo == 0x0aau)) { ATARIHW_SET(EXTD_SHIFTER); pr_cont(" EXTD_SHIFTER"); } else { diff --git a/arch/m68k/coldfire/gpio.c b/arch/m68k/coldfire/gpio.c index a838984261278c4369377e7880373d8a59553b4a..ca26de257871d608c4aecfc1264a6ac46560662e 100644 --- a/arch/m68k/coldfire/gpio.c +++ b/arch/m68k/coldfire/gpio.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig index 04e0f211afb3892502f0c542d6ed992671b4b921..9a33c1c006a1f9b8c891fe2b1545aef71958b73a 100644 --- a/arch/m68k/configs/amiga_defconfig +++ b/arch/m68k/configs/amiga_defconfig @@ -125,6 +125,7 @@ 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 @@ -250,9 +251,11 @@ CONFIG_IP6_NF_RAW=m CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m -CONFIG_NF_TABLES_BRIDGE=y +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m CONFIG_NFT_BRIDGE_REJECT=m CONFIG_NF_LOG_BRIDGE=m +CONFIG_NF_CONNTRACK_BRIDGE=m CONFIG_BRIDGE_NF_EBTABLES=m CONFIG_BRIDGE_EBT_BROUTE=m CONFIG_BRIDGE_EBT_T_FILTER=m @@ -330,7 +333,6 @@ CONFIG_RAID_ATTRS=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m -CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=m @@ -450,7 +452,6 @@ CONFIG_RTC_DRV_RP5C01=m # CONFIG_VIRTIO_MENU is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m -# CONFIG_VALIDATE_FS_PARSER is not set CONFIG_EXT4_FS=y CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m @@ -573,6 +574,7 @@ CONFIG_CRYPTO_KEYWRAP=m CONFIG_CRYPTO_ADIANTUM=m CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_XXHASH=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m @@ -582,8 +584,10 @@ CONFIG_CRYPTO_SHA3=m CONFIG_CRYPTO_SM3=m CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_CAST5=m @@ -618,6 +622,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_WW_MUTEX_SELFTEST=m CONFIG_TEST_LIST_SORT=m CONFIG_TEST_SORT=m +CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_HEXDUMP=m @@ -636,6 +641,7 @@ CONFIG_TEST_IDA=m CONFIG_TEST_VMALLOC=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m +CONFIG_TEST_BLACKHOLE_DEV=m CONFIG_FIND_BIT_BENCHMARK=m CONFIG_TEST_FIRMWARE=m CONFIG_TEST_SYSCTL=m @@ -644,4 +650,5 @@ CONFIG_TEST_STATIC_KEYS=m CONFIG_TEST_KMOD=m CONFIG_TEST_MEMCAT_P=m CONFIG_TEST_STACKINIT=m +CONFIG_TEST_MEMINIT=m CONFIG_EARLY_PRINTK=y diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig index c6abbb535878cc1d1f36ce3943f42d461ba842ac..7fdbc797a05d4d657b9dba9439c30c1c570d5061 100644 --- a/arch/m68k/configs/apollo_defconfig +++ b/arch/m68k/configs/apollo_defconfig @@ -121,6 +121,7 @@ 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 @@ -246,9 +247,11 @@ CONFIG_IP6_NF_RAW=m CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m -CONFIG_NF_TABLES_BRIDGE=y +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m CONFIG_NFT_BRIDGE_REJECT=m CONFIG_NF_LOG_BRIDGE=m +CONFIG_NF_CONNTRACK_BRIDGE=m CONFIG_BRIDGE_NF_EBTABLES=m CONFIG_BRIDGE_EBT_BROUTE=m CONFIG_BRIDGE_EBT_T_FILTER=m @@ -315,7 +318,6 @@ CONFIG_RAID_ATTRS=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m -CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=m @@ -410,7 +412,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_VIRTIO_MENU is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m -# CONFIG_VALIDATE_FS_PARSER is not set CONFIG_EXT4_FS=y CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m @@ -533,6 +534,7 @@ CONFIG_CRYPTO_KEYWRAP=m CONFIG_CRYPTO_ADIANTUM=m CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_XXHASH=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m @@ -542,8 +544,10 @@ CONFIG_CRYPTO_SHA3=m CONFIG_CRYPTO_SM3=m CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_CAST5=m @@ -578,6 +582,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_WW_MUTEX_SELFTEST=m CONFIG_TEST_LIST_SORT=m CONFIG_TEST_SORT=m +CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_HEXDUMP=m @@ -596,6 +601,7 @@ CONFIG_TEST_IDA=m CONFIG_TEST_VMALLOC=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m +CONFIG_TEST_BLACKHOLE_DEV=m CONFIG_FIND_BIT_BENCHMARK=m CONFIG_TEST_FIRMWARE=m CONFIG_TEST_SYSCTL=m @@ -604,4 +610,5 @@ CONFIG_TEST_STATIC_KEYS=m CONFIG_TEST_KMOD=m CONFIG_TEST_MEMCAT_P=m CONFIG_TEST_STACKINIT=m +CONFIG_TEST_MEMINIT=m CONFIG_EARLY_PRINTK=y diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig index 06ae65bad17713122026946ce2c95ea73afc9300..f1763405a53966c806d7ad8cba2e1f060e581d37 100644 --- a/arch/m68k/configs/atari_defconfig +++ b/arch/m68k/configs/atari_defconfig @@ -128,6 +128,7 @@ 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 @@ -253,9 +254,11 @@ CONFIG_IP6_NF_RAW=m CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m -CONFIG_NF_TABLES_BRIDGE=y +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m CONFIG_NFT_BRIDGE_REJECT=m CONFIG_NF_LOG_BRIDGE=m +CONFIG_NF_CONNTRACK_BRIDGE=m CONFIG_BRIDGE_NF_EBTABLES=m CONFIG_BRIDGE_EBT_BROUTE=m CONFIG_BRIDGE_EBT_T_FILTER=m @@ -330,7 +333,6 @@ CONFIG_RAID_ATTRS=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m -CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=m @@ -432,7 +434,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_VIRTIO_MENU is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m -# CONFIG_VALIDATE_FS_PARSER is not set CONFIG_EXT4_FS=y CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m @@ -555,6 +556,7 @@ CONFIG_CRYPTO_KEYWRAP=m CONFIG_CRYPTO_ADIANTUM=m CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_XXHASH=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m @@ -564,8 +566,10 @@ CONFIG_CRYPTO_SHA3=m CONFIG_CRYPTO_SM3=m CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_CAST5=m @@ -600,6 +604,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_WW_MUTEX_SELFTEST=m CONFIG_TEST_LIST_SORT=m CONFIG_TEST_SORT=m +CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_HEXDUMP=m @@ -618,6 +623,7 @@ CONFIG_TEST_IDA=m CONFIG_TEST_VMALLOC=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m +CONFIG_TEST_BLACKHOLE_DEV=m CONFIG_FIND_BIT_BENCHMARK=m CONFIG_TEST_FIRMWARE=m CONFIG_TEST_SYSCTL=m @@ -626,4 +632,5 @@ CONFIG_TEST_STATIC_KEYS=m CONFIG_TEST_KMOD=m CONFIG_TEST_MEMCAT_P=m CONFIG_TEST_STACKINIT=m +CONFIG_TEST_MEMINIT=m CONFIG_EARLY_PRINTK=y diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig index 5616b94053b6463395d0ccba7c363fa59e29b3ec..91154d6acb313c72ad7ace8e2ffe1e07fcf390ab 100644 --- a/arch/m68k/configs/bvme6000_defconfig +++ b/arch/m68k/configs/bvme6000_defconfig @@ -118,6 +118,7 @@ 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 @@ -243,9 +244,11 @@ CONFIG_IP6_NF_RAW=m CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m -CONFIG_NF_TABLES_BRIDGE=y +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m CONFIG_NFT_BRIDGE_REJECT=m CONFIG_NF_LOG_BRIDGE=m +CONFIG_NF_CONNTRACK_BRIDGE=m CONFIG_BRIDGE_NF_EBTABLES=m CONFIG_BRIDGE_EBT_BROUTE=m CONFIG_BRIDGE_EBT_T_FILTER=m @@ -312,7 +315,6 @@ CONFIG_RAID_ATTRS=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m -CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=m @@ -403,7 +405,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_VIRTIO_MENU is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m -# CONFIG_VALIDATE_FS_PARSER is not set CONFIG_EXT4_FS=y CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m @@ -526,6 +527,7 @@ CONFIG_CRYPTO_KEYWRAP=m CONFIG_CRYPTO_ADIANTUM=m CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_XXHASH=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m @@ -535,8 +537,10 @@ CONFIG_CRYPTO_SHA3=m CONFIG_CRYPTO_SM3=m CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_CAST5=m @@ -571,6 +575,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_WW_MUTEX_SELFTEST=m CONFIG_TEST_LIST_SORT=m CONFIG_TEST_SORT=m +CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_HEXDUMP=m @@ -589,6 +594,7 @@ CONFIG_TEST_IDA=m CONFIG_TEST_VMALLOC=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m +CONFIG_TEST_BLACKHOLE_DEV=m CONFIG_FIND_BIT_BENCHMARK=m CONFIG_TEST_FIRMWARE=m CONFIG_TEST_SYSCTL=m @@ -597,4 +603,5 @@ CONFIG_TEST_STATIC_KEYS=m CONFIG_TEST_KMOD=m CONFIG_TEST_MEMCAT_P=m CONFIG_TEST_STACKINIT=m +CONFIG_TEST_MEMINIT=m CONFIG_EARLY_PRINTK=y diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig index 1106521f3b56f6df41b91b5095237998365a2cd6..c398c4a94d95c6669e2dfb4870642f5c11aab366 100644 --- a/arch/m68k/configs/hp300_defconfig +++ b/arch/m68k/configs/hp300_defconfig @@ -120,6 +120,7 @@ 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 @@ -245,9 +246,11 @@ CONFIG_IP6_NF_RAW=m CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m -CONFIG_NF_TABLES_BRIDGE=y +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m CONFIG_NFT_BRIDGE_REJECT=m CONFIG_NF_LOG_BRIDGE=m +CONFIG_NF_CONNTRACK_BRIDGE=m CONFIG_BRIDGE_NF_EBTABLES=m CONFIG_BRIDGE_EBT_BROUTE=m CONFIG_BRIDGE_EBT_T_FILTER=m @@ -314,7 +317,6 @@ CONFIG_RAID_ATTRS=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m -CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=m @@ -412,7 +414,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_VIRTIO_MENU is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m -# CONFIG_VALIDATE_FS_PARSER is not set CONFIG_EXT4_FS=y CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m @@ -535,6 +536,7 @@ CONFIG_CRYPTO_KEYWRAP=m CONFIG_CRYPTO_ADIANTUM=m CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_XXHASH=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m @@ -544,8 +546,10 @@ CONFIG_CRYPTO_SHA3=m CONFIG_CRYPTO_SM3=m CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_CAST5=m @@ -580,6 +584,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_WW_MUTEX_SELFTEST=m CONFIG_TEST_LIST_SORT=m CONFIG_TEST_SORT=m +CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_HEXDUMP=m @@ -598,6 +603,7 @@ CONFIG_TEST_IDA=m CONFIG_TEST_VMALLOC=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m +CONFIG_TEST_BLACKHOLE_DEV=m CONFIG_FIND_BIT_BENCHMARK=m CONFIG_TEST_FIRMWARE=m CONFIG_TEST_SYSCTL=m @@ -606,4 +612,5 @@ CONFIG_TEST_STATIC_KEYS=m CONFIG_TEST_KMOD=m CONFIG_TEST_MEMCAT_P=m CONFIG_TEST_STACKINIT=m +CONFIG_TEST_MEMINIT=m CONFIG_EARLY_PRINTK=y diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig index 226c6c063cd44cce300eab48b49ded6eb07df45f..350d004559be84310d383d954b6eca16428ae11d 100644 --- a/arch/m68k/configs/mac_defconfig +++ b/arch/m68k/configs/mac_defconfig @@ -119,6 +119,7 @@ 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 @@ -244,9 +245,11 @@ CONFIG_IP6_NF_RAW=m CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m -CONFIG_NF_TABLES_BRIDGE=y +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m CONFIG_NFT_BRIDGE_REJECT=m CONFIG_NF_LOG_BRIDGE=m +CONFIG_NF_CONNTRACK_BRIDGE=m CONFIG_BRIDGE_NF_EBTABLES=m CONFIG_BRIDGE_EBT_BROUTE=m CONFIG_BRIDGE_EBT_T_FILTER=m @@ -321,7 +324,6 @@ CONFIG_RAID_ATTRS=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m -CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=m @@ -434,7 +436,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_VIRTIO_MENU is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m -# CONFIG_VALIDATE_FS_PARSER is not set CONFIG_EXT4_FS=y CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m @@ -557,6 +558,7 @@ CONFIG_CRYPTO_KEYWRAP=m CONFIG_CRYPTO_ADIANTUM=m CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_XXHASH=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m @@ -566,8 +568,10 @@ CONFIG_CRYPTO_SHA3=m CONFIG_CRYPTO_SM3=m CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_CAST5=m @@ -602,6 +606,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_WW_MUTEX_SELFTEST=m CONFIG_TEST_LIST_SORT=m CONFIG_TEST_SORT=m +CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_HEXDUMP=m @@ -620,6 +625,7 @@ CONFIG_TEST_IDA=m CONFIG_TEST_VMALLOC=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m +CONFIG_TEST_BLACKHOLE_DEV=m CONFIG_FIND_BIT_BENCHMARK=m CONFIG_TEST_FIRMWARE=m CONFIG_TEST_SYSCTL=m @@ -628,4 +634,5 @@ CONFIG_TEST_STATIC_KEYS=m CONFIG_TEST_KMOD=m CONFIG_TEST_MEMCAT_P=m CONFIG_TEST_STACKINIT=m +CONFIG_TEST_MEMINIT=m CONFIG_EARLY_PRINTK=y diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig index 39f603417928f31e577923d650890f8206eeca63..b838dd820348ede0680513ffea8ab0a7dc59aac0 100644 --- a/arch/m68k/configs/multi_defconfig +++ b/arch/m68k/configs/multi_defconfig @@ -139,6 +139,7 @@ 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 @@ -264,9 +265,11 @@ CONFIG_IP6_NF_RAW=m CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m -CONFIG_NF_TABLES_BRIDGE=y +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m CONFIG_NFT_BRIDGE_REJECT=m CONFIG_NF_LOG_BRIDGE=m +CONFIG_NF_CONNTRACK_BRIDGE=m CONFIG_BRIDGE_NF_EBTABLES=m CONFIG_BRIDGE_EBT_BROUTE=m CONFIG_BRIDGE_EBT_T_FILTER=m @@ -354,7 +357,6 @@ CONFIG_RAID_ATTRS=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m -CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=m @@ -516,7 +518,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_VIRTIO_MENU is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m -# CONFIG_VALIDATE_FS_PARSER is not set CONFIG_EXT4_FS=y CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m @@ -639,6 +640,7 @@ CONFIG_CRYPTO_KEYWRAP=m CONFIG_CRYPTO_ADIANTUM=m CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_XXHASH=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m @@ -648,8 +650,10 @@ CONFIG_CRYPTO_SHA3=m CONFIG_CRYPTO_SM3=m CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_CAST5=m @@ -684,6 +688,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_WW_MUTEX_SELFTEST=m CONFIG_TEST_LIST_SORT=m CONFIG_TEST_SORT=m +CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_HEXDUMP=m @@ -702,6 +707,7 @@ CONFIG_TEST_IDA=m CONFIG_TEST_VMALLOC=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m +CONFIG_TEST_BLACKHOLE_DEV=m CONFIG_FIND_BIT_BENCHMARK=m CONFIG_TEST_FIRMWARE=m CONFIG_TEST_SYSCTL=m @@ -710,4 +716,5 @@ CONFIG_TEST_STATIC_KEYS=m CONFIG_TEST_KMOD=m CONFIG_TEST_MEMCAT_P=m CONFIG_TEST_STACKINIT=m +CONFIG_TEST_MEMINIT=m CONFIG_EARLY_PRINTK=y diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig index 175a607f576cc75acf66177f3f9773db73f88cb8..3f8dd61559cf06b4dfca80e5c5c5610342cbda6a 100644 --- a/arch/m68k/configs/mvme147_defconfig +++ b/arch/m68k/configs/mvme147_defconfig @@ -117,6 +117,7 @@ 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 @@ -242,9 +243,11 @@ CONFIG_IP6_NF_RAW=m CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m -CONFIG_NF_TABLES_BRIDGE=y +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m CONFIG_NFT_BRIDGE_REJECT=m CONFIG_NF_LOG_BRIDGE=m +CONFIG_NF_CONNTRACK_BRIDGE=m CONFIG_BRIDGE_NF_EBTABLES=m CONFIG_BRIDGE_EBT_BROUTE=m CONFIG_BRIDGE_EBT_T_FILTER=m @@ -311,7 +314,6 @@ CONFIG_RAID_ATTRS=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m -CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=m @@ -402,7 +404,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_VIRTIO_MENU is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m -# CONFIG_VALIDATE_FS_PARSER is not set CONFIG_EXT4_FS=y CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m @@ -525,6 +526,7 @@ CONFIG_CRYPTO_KEYWRAP=m CONFIG_CRYPTO_ADIANTUM=m CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_XXHASH=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m @@ -534,8 +536,10 @@ CONFIG_CRYPTO_SHA3=m CONFIG_CRYPTO_SM3=m CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_CAST5=m @@ -570,6 +574,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_WW_MUTEX_SELFTEST=m CONFIG_TEST_LIST_SORT=m CONFIG_TEST_SORT=m +CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_HEXDUMP=m @@ -588,6 +593,7 @@ CONFIG_TEST_IDA=m CONFIG_TEST_VMALLOC=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m +CONFIG_TEST_BLACKHOLE_DEV=m CONFIG_FIND_BIT_BENCHMARK=m CONFIG_TEST_FIRMWARE=m CONFIG_TEST_SYSCTL=m @@ -596,4 +602,5 @@ CONFIG_TEST_STATIC_KEYS=m CONFIG_TEST_KMOD=m CONFIG_TEST_MEMCAT_P=m CONFIG_TEST_STACKINIT=m +CONFIG_TEST_MEMINIT=m CONFIG_EARLY_PRINTK=y diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig index f41c34d3cdd0a893d00132884869eecdfa7ff8df..ae3b2d4f636c7562ec5160d9c43de622a735bfc1 100644 --- a/arch/m68k/configs/mvme16x_defconfig +++ b/arch/m68k/configs/mvme16x_defconfig @@ -118,6 +118,7 @@ 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 @@ -243,9 +244,11 @@ CONFIG_IP6_NF_RAW=m CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m -CONFIG_NF_TABLES_BRIDGE=y +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m CONFIG_NFT_BRIDGE_REJECT=m CONFIG_NF_LOG_BRIDGE=m +CONFIG_NF_CONNTRACK_BRIDGE=m CONFIG_BRIDGE_NF_EBTABLES=m CONFIG_BRIDGE_EBT_BROUTE=m CONFIG_BRIDGE_EBT_T_FILTER=m @@ -312,7 +315,6 @@ CONFIG_RAID_ATTRS=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m -CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=m @@ -403,7 +405,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_VIRTIO_MENU is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m -# CONFIG_VALIDATE_FS_PARSER is not set CONFIG_EXT4_FS=y CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m @@ -526,6 +527,7 @@ CONFIG_CRYPTO_KEYWRAP=m CONFIG_CRYPTO_ADIANTUM=m CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_XXHASH=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m @@ -535,8 +537,10 @@ CONFIG_CRYPTO_SHA3=m CONFIG_CRYPTO_SM3=m CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_CAST5=m @@ -571,6 +575,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_WW_MUTEX_SELFTEST=m CONFIG_TEST_LIST_SORT=m CONFIG_TEST_SORT=m +CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_HEXDUMP=m @@ -589,6 +594,7 @@ CONFIG_TEST_IDA=m CONFIG_TEST_VMALLOC=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m +CONFIG_TEST_BLACKHOLE_DEV=m CONFIG_FIND_BIT_BENCHMARK=m CONFIG_TEST_FIRMWARE=m CONFIG_TEST_SYSCTL=m @@ -597,4 +603,5 @@ CONFIG_TEST_STATIC_KEYS=m CONFIG_TEST_KMOD=m CONFIG_TEST_MEMCAT_P=m CONFIG_TEST_STACKINIT=m +CONFIG_TEST_MEMINIT=m CONFIG_EARLY_PRINTK=y diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig index c9d2cb0a1cf4c9709ead8ecb7241c6bc6943acf1..cd61ef14b582812f1cd052e53bcece3d0db7f522 100644 --- a/arch/m68k/configs/q40_defconfig +++ b/arch/m68k/configs/q40_defconfig @@ -119,6 +119,7 @@ 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 @@ -244,9 +245,11 @@ CONFIG_IP6_NF_RAW=m CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m -CONFIG_NF_TABLES_BRIDGE=y +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m CONFIG_NFT_BRIDGE_REJECT=m CONFIG_NF_LOG_BRIDGE=m +CONFIG_NF_CONNTRACK_BRIDGE=m CONFIG_BRIDGE_NF_EBTABLES=m CONFIG_BRIDGE_EBT_BROUTE=m CONFIG_BRIDGE_EBT_T_FILTER=m @@ -320,7 +323,6 @@ CONFIG_RAID_ATTRS=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m -CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=m @@ -421,7 +423,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_VIRTIO_MENU is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m -# CONFIG_VALIDATE_FS_PARSER is not set CONFIG_EXT4_FS=y CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m @@ -544,6 +545,7 @@ CONFIG_CRYPTO_KEYWRAP=m CONFIG_CRYPTO_ADIANTUM=m CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_XXHASH=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m @@ -553,8 +555,10 @@ CONFIG_CRYPTO_SHA3=m CONFIG_CRYPTO_SM3=m CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_CAST5=m @@ -589,6 +593,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_WW_MUTEX_SELFTEST=m CONFIG_TEST_LIST_SORT=m CONFIG_TEST_SORT=m +CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_HEXDUMP=m @@ -607,6 +612,7 @@ CONFIG_TEST_IDA=m CONFIG_TEST_VMALLOC=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m +CONFIG_TEST_BLACKHOLE_DEV=m CONFIG_FIND_BIT_BENCHMARK=m CONFIG_TEST_FIRMWARE=m CONFIG_TEST_SYSCTL=m @@ -615,4 +621,5 @@ CONFIG_TEST_STATIC_KEYS=m CONFIG_TEST_KMOD=m CONFIG_TEST_MEMCAT_P=m CONFIG_TEST_STACKINIT=m +CONFIG_TEST_MEMINIT=m CONFIG_EARLY_PRINTK=y diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig index 79a64fdd6bf06e6339ee394337a24565c841471c..151f5371cd3d42e12567638f7efe44b567a53cfe 100644 --- a/arch/m68k/configs/sun3_defconfig +++ b/arch/m68k/configs/sun3_defconfig @@ -115,6 +115,7 @@ 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 @@ -240,9 +241,11 @@ CONFIG_IP6_NF_RAW=m CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m -CONFIG_NF_TABLES_BRIDGE=y +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m CONFIG_NFT_BRIDGE_REJECT=m CONFIG_NF_LOG_BRIDGE=m +CONFIG_NF_CONNTRACK_BRIDGE=m CONFIG_BRIDGE_NF_EBTABLES=m CONFIG_BRIDGE_EBT_BROUTE=m CONFIG_BRIDGE_EBT_T_FILTER=m @@ -309,7 +312,6 @@ CONFIG_RAID_ATTRS=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m -CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=m @@ -405,7 +407,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_VIRTIO_MENU is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m -# CONFIG_VALIDATE_FS_PARSER is not set CONFIG_EXT4_FS=y CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m @@ -528,6 +529,7 @@ CONFIG_CRYPTO_KEYWRAP=m CONFIG_CRYPTO_ADIANTUM=m CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_XXHASH=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m @@ -537,8 +539,10 @@ CONFIG_CRYPTO_SHA3=m CONFIG_CRYPTO_SM3=m CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_CAST5=m @@ -573,6 +577,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_WW_MUTEX_SELFTEST=m CONFIG_TEST_LIST_SORT=m CONFIG_TEST_SORT=m +CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_HEXDUMP=m @@ -591,6 +596,7 @@ CONFIG_TEST_IDA=m CONFIG_TEST_VMALLOC=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m +CONFIG_TEST_BLACKHOLE_DEV=m CONFIG_FIND_BIT_BENCHMARK=m CONFIG_TEST_FIRMWARE=m CONFIG_TEST_SYSCTL=m @@ -599,3 +605,4 @@ CONFIG_TEST_STATIC_KEYS=m CONFIG_TEST_KMOD=m CONFIG_TEST_MEMCAT_P=m CONFIG_TEST_STACKINIT=m +CONFIG_TEST_MEMINIT=m diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig index e3402a5d165b0bbd79af9bf36330ef807fd51d1f..1dcb0ee1fe98952278113629154ab6f4fb9dd007 100644 --- a/arch/m68k/configs/sun3x_defconfig +++ b/arch/m68k/configs/sun3x_defconfig @@ -115,6 +115,7 @@ 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 @@ -240,9 +241,11 @@ CONFIG_IP6_NF_RAW=m CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m -CONFIG_NF_TABLES_BRIDGE=y +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m CONFIG_NFT_BRIDGE_REJECT=m CONFIG_NF_LOG_BRIDGE=m +CONFIG_NF_CONNTRACK_BRIDGE=m CONFIG_BRIDGE_NF_EBTABLES=m CONFIG_BRIDGE_EBT_BROUTE=m CONFIG_BRIDGE_EBT_T_FILTER=m @@ -309,7 +312,6 @@ CONFIG_RAID_ATTRS=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m -CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=m @@ -404,7 +406,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_VIRTIO_MENU is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m -# CONFIG_VALIDATE_FS_PARSER is not set CONFIG_EXT4_FS=y CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m @@ -527,6 +528,7 @@ CONFIG_CRYPTO_KEYWRAP=m CONFIG_CRYPTO_ADIANTUM=m CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_XXHASH=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m @@ -536,8 +538,10 @@ CONFIG_CRYPTO_SHA3=m CONFIG_CRYPTO_SM3=m CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_AES_TI=m CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_CAST5=m @@ -572,6 +576,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_WW_MUTEX_SELFTEST=m CONFIG_TEST_LIST_SORT=m CONFIG_TEST_SORT=m +CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_HEXDUMP=m @@ -590,6 +595,7 @@ CONFIG_TEST_IDA=m CONFIG_TEST_VMALLOC=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m +CONFIG_TEST_BLACKHOLE_DEV=m CONFIG_FIND_BIT_BENCHMARK=m CONFIG_TEST_FIRMWARE=m CONFIG_TEST_SYSCTL=m @@ -598,4 +604,5 @@ CONFIG_TEST_STATIC_KEYS=m CONFIG_TEST_KMOD=m CONFIG_TEST_MEMCAT_P=m CONFIG_TEST_STACKINIT=m +CONFIG_TEST_MEMINIT=m CONFIG_EARLY_PRINTK=y diff --git a/arch/m68k/include/asm/atarihw.h b/arch/m68k/include/asm/atarihw.h index 533008262b691ad9cd7800e14b676a916a72b4b1..9a038a3edb8370dafeccee2f1d8bcb2c8bcc0dd1 100644 --- a/arch/m68k/include/asm/atarihw.h +++ b/arch/m68k/include/asm/atarihw.h @@ -22,7 +22,6 @@ #include #include -#include #include extern u_long atari_mch_cookie; @@ -132,14 +131,6 @@ extern struct atari_hw_present atari_hw_present; */ -#define atari_readb raw_inb -#define atari_writeb raw_outb - -#define atari_inb_p raw_inb -#define atari_outb_p raw_outb - - - #include #include @@ -170,7 +161,7 @@ static inline void dma_cache_maintenance( unsigned long paddr, #define TT_HIGH 6 #define SHF_BAS (0xffff8200) -struct SHIFTER +struct SHIFTER_ST { u_char pad1; u_char bas_hi; @@ -187,7 +178,7 @@ struct SHIFTER u_char pad7; u_char bas_lo; }; -# define shifter ((*(volatile struct SHIFTER *)SHF_BAS)) +# define shifter_st ((*(volatile struct SHIFTER_ST *)SHF_BAS)) #define SHF_FBAS (0xffff820e) struct SHIFTER_F030 diff --git a/arch/m68k/include/asm/io_mm.h b/arch/m68k/include/asm/io_mm.h index 6c03ca5bc436551e16cf9ec7019cf09414607ba0..819f611dccf28ee2bd27551eacc74305c70b3845 100644 --- a/arch/m68k/include/asm/io_mm.h +++ b/arch/m68k/include/asm/io_mm.h @@ -29,7 +29,11 @@ #include #ifdef CONFIG_ATARI -#include +#define atari_readb raw_inb +#define atari_writeb raw_outb + +#define atari_inb_p raw_inb +#define atari_outb_p raw_outb #endif diff --git a/arch/m68k/include/asm/kmap.h b/arch/m68k/include/asm/kmap.h index aac7f045f7f0aa8509cf5ef288f8030de8276bce..421b6c9c769d0ab3283a51786a52ad2fbfbbdf12 100644 --- a/arch/m68k/include/asm/kmap.h +++ b/arch/m68k/include/asm/kmap.h @@ -28,14 +28,8 @@ static inline void __iomem *ioremap(unsigned long physaddr, unsigned long size) return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); } -#define ioremap_nocache ioremap_nocache -static inline void __iomem *ioremap_nocache(unsigned long physaddr, - unsigned long size) -{ - return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); -} - -#define ioremap_uc ioremap_nocache +#define ioremap_nocache ioremap +#define ioremap_uc ioremap #define ioremap_wt ioremap_wt static inline void __iomem *ioremap_wt(unsigned long physaddr, unsigned long size) @@ -43,13 +37,6 @@ static inline void __iomem *ioremap_wt(unsigned long physaddr, return __ioremap(physaddr, size, IOMAP_WRITETHROUGH); } -#define ioremap_fullcache ioremap_fullcache -static inline void __iomem *ioremap_fullcache(unsigned long physaddr, - unsigned long size) -{ - return __ioremap(physaddr, size, IOMAP_FULL_CACHING); -} - #define memset_io memset_io static inline void memset_io(volatile void __iomem *addr, unsigned char val, int count) diff --git a/arch/m68k/include/asm/macintosh.h b/arch/m68k/include/asm/macintosh.h index d9a08bed4b128872cbe999ebfabe2479ccb9f317..8a43babcf53a617509a620d46ee8dd85c38decb9 100644 --- a/arch/m68k/include/asm/macintosh.h +++ b/arch/m68k/include/asm/macintosh.h @@ -4,6 +4,7 @@ #include #include +#include #include @@ -82,11 +83,11 @@ struct mac_model #define MAC_EXP_PDS_NUBUS 3 /* Accepts PDS card and/or NuBus card(s) */ #define MAC_EXP_PDS_COMM 4 /* Accepts PDS card or Comm Slot card */ -#define MAC_FLOPPY_IWM 0 -#define MAC_FLOPPY_SWIM_ADDR1 1 -#define MAC_FLOPPY_SWIM_ADDR2 2 -#define MAC_FLOPPY_SWIM_IOP 3 -#define MAC_FLOPPY_AV 4 +#define MAC_FLOPPY_UNSUPPORTED 0 +#define MAC_FLOPPY_SWIM_IOP 1 +#define MAC_FLOPPY_OLD 2 +#define MAC_FLOPPY_QUADRA 3 +#define MAC_FLOPPY_LC 4 extern struct mac_model *macintosh_config; diff --git a/arch/m68k/kernel/dma.c b/arch/m68k/kernel/dma.c index 30cd59caf037ee8490097677408532529c123b58..447849d1d645d97beee1a3315eb464adb6ba7b33 100644 --- a/arch/m68k/kernel/dma.c +++ b/arch/m68k/kernel/dma.c @@ -79,12 +79,3 @@ void arch_sync_dma_for_device(struct device *dev, phys_addr_t handle, break; } } - -void arch_setup_pdev_archdata(struct platform_device *pdev) -{ - if (pdev->dev.coherent_dma_mask == DMA_MASK_NONE && - pdev->dev.dma_mask == NULL) { - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; - } -} diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index 205ac75da13d6b095ebc904a2c8c11b921969775..611f73bfc87c95fe7fa0f514d38f4fb0161743eb 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -209,7 +209,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_OLD, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_NUBUS, - .floppy_type = MAC_FLOPPY_IWM, + .floppy_type = MAC_FLOPPY_UNSUPPORTED, /* IWM */ }, /* @@ -224,7 +224,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_OLD, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_NUBUS, - .floppy_type = MAC_FLOPPY_IWM, + .floppy_type = MAC_FLOPPY_UNSUPPORTED, /* IWM */ }, { .ident = MAC_MODEL_IIX, .name = "IIx", @@ -233,7 +233,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_OLD, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_IICX, .name = "IIcx", @@ -242,7 +242,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_OLD, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_SE30, .name = "SE/30", @@ -251,7 +251,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_OLD, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_PDS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, /* @@ -269,7 +269,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_OLD, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_IIFX, .name = "IIfx", @@ -278,7 +278,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_IIFX, .scc_type = MAC_SCC_IOP, .expansion_type = MAC_EXP_PDS_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_IOP, + .floppy_type = MAC_FLOPPY_SWIM_IOP, /* SWIM */ }, { .ident = MAC_MODEL_IISI, .name = "IIsi", @@ -287,7 +287,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_OLD, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_PDS_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_IIVI, .name = "IIvi", @@ -296,7 +296,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_LC, /* SWIM */ }, { .ident = MAC_MODEL_IIVX, .name = "IIvx", @@ -305,7 +305,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_LC, /* SWIM */ }, /* @@ -319,7 +319,7 @@ static struct mac_model mac_data_table[] = { .via_type = MAC_VIA_IICI, .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_LC, /* SWIM */ }, { .ident = MAC_MODEL_CCL, .name = "Color Classic", @@ -328,7 +328,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_PDS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_LC, /* SWIM 2 */ }, { .ident = MAC_MODEL_CCLII, .name = "Color Classic II", @@ -337,7 +337,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_PDS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_LC, /* SWIM 2 */ }, /* @@ -352,7 +352,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_PDS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_LC, /* SWIM */ }, { .ident = MAC_MODEL_LCII, .name = "LC II", @@ -361,7 +361,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_PDS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_LC, /* SWIM */ }, { .ident = MAC_MODEL_LCIII, .name = "LC III", @@ -370,7 +370,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_PDS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_LC, /* SWIM 2 */ }, /* @@ -391,7 +391,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_QUADRA, .scc_type = MAC_SCC_QUADRA, .expansion_type = MAC_EXP_PDS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR1, + .floppy_type = MAC_FLOPPY_QUADRA, /* SWIM 2 */ }, { .ident = MAC_MODEL_Q605_ACC, .name = "Quadra 605", @@ -400,7 +400,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_QUADRA, .scc_type = MAC_SCC_QUADRA, .expansion_type = MAC_EXP_PDS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR1, + .floppy_type = MAC_FLOPPY_QUADRA, /* SWIM 2 */ }, { .ident = MAC_MODEL_Q610, .name = "Quadra 610", @@ -410,7 +410,7 @@ static struct mac_model mac_data_table[] = { .scc_type = MAC_SCC_QUADRA, .ether_type = MAC_ETHER_SONIC, .expansion_type = MAC_EXP_PDS_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR1, + .floppy_type = MAC_FLOPPY_QUADRA, /* SWIM 2 */ }, { .ident = MAC_MODEL_Q630, .name = "Quadra 630", @@ -420,7 +420,7 @@ static struct mac_model mac_data_table[] = { .ide_type = MAC_IDE_QUADRA, .scc_type = MAC_SCC_QUADRA, .expansion_type = MAC_EXP_PDS_COMM, - .floppy_type = MAC_FLOPPY_SWIM_ADDR1, + .floppy_type = MAC_FLOPPY_QUADRA, /* SWIM 2 */ }, { .ident = MAC_MODEL_Q650, .name = "Quadra 650", @@ -430,7 +430,7 @@ static struct mac_model mac_data_table[] = { .scc_type = MAC_SCC_QUADRA, .ether_type = MAC_ETHER_SONIC, .expansion_type = MAC_EXP_PDS_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR1, + .floppy_type = MAC_FLOPPY_QUADRA, /* SWIM 2 */ }, /* The Q700 does have a NS Sonic */ { @@ -442,7 +442,7 @@ static struct mac_model mac_data_table[] = { .scc_type = MAC_SCC_QUADRA, .ether_type = MAC_ETHER_SONIC, .expansion_type = MAC_EXP_PDS_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR1, + .floppy_type = MAC_FLOPPY_QUADRA, /* SWIM */ }, { .ident = MAC_MODEL_Q800, .name = "Quadra 800", @@ -452,7 +452,7 @@ static struct mac_model mac_data_table[] = { .scc_type = MAC_SCC_QUADRA, .ether_type = MAC_ETHER_SONIC, .expansion_type = MAC_EXP_PDS_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR1, + .floppy_type = MAC_FLOPPY_QUADRA, /* SWIM 2 */ }, { .ident = MAC_MODEL_Q840, .name = "Quadra 840AV", @@ -462,7 +462,7 @@ static struct mac_model mac_data_table[] = { .scc_type = MAC_SCC_PSC, .ether_type = MAC_ETHER_MACE, .expansion_type = MAC_EXP_NUBUS, - .floppy_type = MAC_FLOPPY_AV, + .floppy_type = MAC_FLOPPY_UNSUPPORTED, /* New Age */ }, { .ident = MAC_MODEL_Q900, .name = "Quadra 900", @@ -472,7 +472,7 @@ static struct mac_model mac_data_table[] = { .scc_type = MAC_SCC_IOP, .ether_type = MAC_ETHER_SONIC, .expansion_type = MAC_EXP_PDS_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_IOP, + .floppy_type = MAC_FLOPPY_SWIM_IOP, /* SWIM */ }, { .ident = MAC_MODEL_Q950, .name = "Quadra 950", @@ -482,7 +482,7 @@ static struct mac_model mac_data_table[] = { .scc_type = MAC_SCC_IOP, .ether_type = MAC_ETHER_SONIC, .expansion_type = MAC_EXP_PDS_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_IOP, + .floppy_type = MAC_FLOPPY_SWIM_IOP, /* SWIM */ }, /* @@ -497,7 +497,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_PDS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_LC, /* SWIM 2 */ }, { .ident = MAC_MODEL_P475, .name = "Performa 475", @@ -506,7 +506,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_QUADRA, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_PDS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR1, + .floppy_type = MAC_FLOPPY_QUADRA, /* SWIM 2 */ }, { .ident = MAC_MODEL_P475F, .name = "Performa 475", @@ -515,7 +515,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_QUADRA, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_PDS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR1, + .floppy_type = MAC_FLOPPY_QUADRA, /* SWIM 2 */ }, { .ident = MAC_MODEL_P520, .name = "Performa 520", @@ -524,7 +524,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_PDS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_LC, /* SWIM 2 */ }, { .ident = MAC_MODEL_P550, .name = "Performa 550", @@ -533,7 +533,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_PDS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_LC, /* SWIM 2 */ }, /* These have the comm slot, and therefore possibly SONIC ethernet */ { @@ -544,7 +544,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_QUADRA, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_PDS_COMM, - .floppy_type = MAC_FLOPPY_SWIM_ADDR1, + .floppy_type = MAC_FLOPPY_QUADRA, /* SWIM 2 */ }, { .ident = MAC_MODEL_P588, .name = "Performa 588", @@ -554,7 +554,7 @@ static struct mac_model mac_data_table[] = { .ide_type = MAC_IDE_QUADRA, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_PDS_COMM, - .floppy_type = MAC_FLOPPY_SWIM_ADDR1, + .floppy_type = MAC_FLOPPY_QUADRA, /* SWIM 2 */ }, { .ident = MAC_MODEL_TV, .name = "TV", @@ -562,7 +562,7 @@ static struct mac_model mac_data_table[] = { .via_type = MAC_VIA_IICI, .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_LC, /* SWIM 2 */ }, { .ident = MAC_MODEL_P600, .name = "Performa 600", @@ -571,7 +571,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .expansion_type = MAC_EXP_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_LC, /* SWIM */ }, /* @@ -588,7 +588,7 @@ static struct mac_model mac_data_table[] = { .scc_type = MAC_SCC_QUADRA, .ether_type = MAC_ETHER_SONIC, .expansion_type = MAC_EXP_PDS_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR1, + .floppy_type = MAC_FLOPPY_QUADRA, /* SWIM 2 */ }, { .ident = MAC_MODEL_C650, .name = "Centris 650", @@ -598,7 +598,7 @@ static struct mac_model mac_data_table[] = { .scc_type = MAC_SCC_QUADRA, .ether_type = MAC_ETHER_SONIC, .expansion_type = MAC_EXP_PDS_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR1, + .floppy_type = MAC_FLOPPY_QUADRA, /* SWIM 2 */ }, { .ident = MAC_MODEL_C660, .name = "Centris 660AV", @@ -608,7 +608,7 @@ static struct mac_model mac_data_table[] = { .scc_type = MAC_SCC_PSC, .ether_type = MAC_ETHER_MACE, .expansion_type = MAC_EXP_PDS_NUBUS, - .floppy_type = MAC_FLOPPY_AV, + .floppy_type = MAC_FLOPPY_UNSUPPORTED, /* New Age */ }, /* @@ -624,7 +624,7 @@ static struct mac_model mac_data_table[] = { .via_type = MAC_VIA_QUADRA, .scsi_type = MAC_SCSI_OLD, .scc_type = MAC_SCC_QUADRA, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_PB145, .name = "PowerBook 145", @@ -632,7 +632,7 @@ static struct mac_model mac_data_table[] = { .via_type = MAC_VIA_QUADRA, .scsi_type = MAC_SCSI_OLD, .scc_type = MAC_SCC_QUADRA, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_PB150, .name = "PowerBook 150", @@ -641,7 +641,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_OLD, .ide_type = MAC_IDE_PB, .scc_type = MAC_SCC_QUADRA, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_PB160, .name = "PowerBook 160", @@ -649,7 +649,7 @@ static struct mac_model mac_data_table[] = { .via_type = MAC_VIA_QUADRA, .scsi_type = MAC_SCSI_OLD, .scc_type = MAC_SCC_QUADRA, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_PB165, .name = "PowerBook 165", @@ -657,7 +657,7 @@ static struct mac_model mac_data_table[] = { .via_type = MAC_VIA_QUADRA, .scsi_type = MAC_SCSI_OLD, .scc_type = MAC_SCC_QUADRA, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_PB165C, .name = "PowerBook 165c", @@ -665,7 +665,7 @@ static struct mac_model mac_data_table[] = { .via_type = MAC_VIA_QUADRA, .scsi_type = MAC_SCSI_OLD, .scc_type = MAC_SCC_QUADRA, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_PB170, .name = "PowerBook 170", @@ -673,7 +673,7 @@ static struct mac_model mac_data_table[] = { .via_type = MAC_VIA_QUADRA, .scsi_type = MAC_SCSI_OLD, .scc_type = MAC_SCC_QUADRA, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_PB180, .name = "PowerBook 180", @@ -681,7 +681,7 @@ static struct mac_model mac_data_table[] = { .via_type = MAC_VIA_QUADRA, .scsi_type = MAC_SCSI_OLD, .scc_type = MAC_SCC_QUADRA, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_PB180C, .name = "PowerBook 180c", @@ -689,7 +689,7 @@ static struct mac_model mac_data_table[] = { .via_type = MAC_VIA_QUADRA, .scsi_type = MAC_SCSI_OLD, .scc_type = MAC_SCC_QUADRA, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_PB190, .name = "PowerBook 190", @@ -698,7 +698,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_OLD, .ide_type = MAC_IDE_BABOON, .scc_type = MAC_SCC_QUADRA, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM 2 */ }, { .ident = MAC_MODEL_PB520, .name = "PowerBook 520", @@ -707,7 +707,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_OLD, .scc_type = MAC_SCC_QUADRA, .ether_type = MAC_ETHER_SONIC, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM 2 */ }, /* @@ -724,7 +724,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_DUO, .scc_type = MAC_SCC_QUADRA, .expansion_type = MAC_EXP_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_PB230, .name = "PowerBook Duo 230", @@ -733,7 +733,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_DUO, .scc_type = MAC_SCC_QUADRA, .expansion_type = MAC_EXP_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_PB250, .name = "PowerBook Duo 250", @@ -742,7 +742,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_DUO, .scc_type = MAC_SCC_QUADRA, .expansion_type = MAC_EXP_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_PB270C, .name = "PowerBook Duo 270c", @@ -751,7 +751,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_DUO, .scc_type = MAC_SCC_QUADRA, .expansion_type = MAC_EXP_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_PB280, .name = "PowerBook Duo 280", @@ -760,7 +760,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_DUO, .scc_type = MAC_SCC_QUADRA, .expansion_type = MAC_EXP_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, { .ident = MAC_MODEL_PB280C, .name = "PowerBook Duo 280c", @@ -769,7 +769,7 @@ static struct mac_model mac_data_table[] = { .scsi_type = MAC_SCSI_DUO, .scc_type = MAC_SCC_QUADRA, .expansion_type = MAC_EXP_NUBUS, - .floppy_type = MAC_FLOPPY_SWIM_ADDR2, + .floppy_type = MAC_FLOPPY_OLD, /* SWIM */ }, /* @@ -960,7 +960,7 @@ static const struct resource mac_scsi_ccl_rsrc[] __initconst = { int __init mac_platform_init(void) { - u8 *swim_base; + phys_addr_t swim_base = 0; if (!MACH_IS_MAC) return -ENODEV; @@ -977,22 +977,22 @@ int __init mac_platform_init(void) */ switch (macintosh_config->floppy_type) { - case MAC_FLOPPY_SWIM_ADDR1: - swim_base = (u8 *)(VIA1_BASE + 0x1E000); + case MAC_FLOPPY_QUADRA: + swim_base = 0x5001E000; break; - case MAC_FLOPPY_SWIM_ADDR2: - swim_base = (u8 *)(VIA1_BASE + 0x16000); + case MAC_FLOPPY_OLD: + swim_base = 0x50016000; break; - default: - swim_base = NULL; + case MAC_FLOPPY_LC: + swim_base = 0x50F16000; break; } if (swim_base) { struct resource swim_rsrc = { .flags = IORESOURCE_MEM, - .start = (resource_size_t)swim_base, - .end = (resource_size_t)swim_base + 0x1FFF, + .start = swim_base, + .end = swim_base + 0x1FFF, }; platform_device_register_simple("swim", -1, &swim_rsrc, 1); diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index 66566026409dac3dea9bea5a63ea14ab18625bc6..f14ad0538f4e39f0f7f416e86d8f4e49dd4cf079 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -103,7 +103,6 @@ CONFIG_FW_LOADER=m CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m -CONFIG_SGI_IOC4=m CONFIG_EEPROM_LEGACY=y CONFIG_EEPROM_MAX6875=y CONFIG_IDE=y diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig index 572cab91670c0d4429baeb4f31aa0b2ac4e7be3e..370884018aad144a7dedb61a1159723d6049edb6 100644 --- a/arch/mips/configs/ip32_defconfig +++ b/arch/mips/configs/ip32_defconfig @@ -46,7 +46,6 @@ CONFIG_CONNECTOR=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m -CONFIG_SGI_IOC4=y CONFIG_RAID_ATTRS=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y diff --git a/arch/mips/configs/markeins_defconfig b/arch/mips/configs/markeins_defconfig index ae93a94f8c718454bedc3e944cd6ee14d3591e65..507ad91b21e7cff577bd2df1a71d2a887df0038d 100644 --- a/arch/mips/configs/markeins_defconfig +++ b/arch/mips/configs/markeins_defconfig @@ -117,7 +117,6 @@ CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_CRYPTOLOOP=m -CONFIG_SGI_IOC4=m CONFIG_SCSI=m # CONFIG_SCSI_PROC_FS is not set CONFIG_BLK_DEV_SD=m diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig index 0f4b09f8a0eefe978c28813b40ccc90c9f98a918..8762e75f5d5f14dffe5dce6aeffb79da12bd6e7f 100644 --- a/arch/mips/configs/rm200_defconfig +++ b/arch/mips/configs/rm200_defconfig @@ -198,7 +198,6 @@ CONFIG_BLK_DEV_SX8=m CONFIG_BLK_DEV_RAM=m CONFIG_CDROM_PKTCDVD=m CONFIG_ATA_OVER_ETH=m -CONFIG_SGI_IOC4=m CONFIG_RAID_ATTRS=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y diff --git a/arch/mips/configs/sb1250_swarm_defconfig b/arch/mips/configs/sb1250_swarm_defconfig index 6883ea4477d4defdc260680b0a0d5e9c7a94e0b9..bb0b1b22ebe164e07347d865567eb004c35b274e 100644 --- a/arch/mips/configs/sb1250_swarm_defconfig +++ b/arch/mips/configs/sb1250_swarm_defconfig @@ -49,7 +49,6 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=9220 CONFIG_CDROM_PKTCDVD=m CONFIG_ATA_OVER_ETH=m -CONFIG_SGI_IOC4=m CONFIG_IDE=y CONFIG_BLK_DEV_IDECD=y CONFIG_BLK_DEV_IDETAPE=y diff --git a/arch/mips/include/asm/sn/ioc3.h b/arch/mips/include/asm/sn/ioc3.h index 25c8dccab51f1b8e69f929138b86806a36ef58a8..a947eed48feee1e68285bc520ca09c395ae6f3e5 100644 --- a/arch/mips/include/asm/sn/ioc3.h +++ b/arch/mips/include/asm/sn/ioc3.h @@ -3,169 +3,161 @@ * Copyright (C) 1999, 2000 Ralf Baechle * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ -#ifndef _IOC3_H -#define _IOC3_H +#ifndef MIPS_SN_IOC3_H +#define MIPS_SN_IOC3_H #include +/* serial port register map */ +struct ioc3_serialregs { + u32 sscr; + u32 stpir; + u32 stcir; + u32 srpir; + u32 srcir; + u32 srtr; + u32 shadow; +}; + /* SUPERIO uart register map */ -typedef volatile struct ioc3_uartregs { +struct ioc3_uartregs { union { - volatile u8 rbr; /* read only, DLAB == 0 */ - volatile u8 thr; /* write only, DLAB == 0 */ - volatile u8 dll; /* DLAB == 1 */ - } u1; + u8 iu_rbr; /* read only, DLAB == 0 */ + u8 iu_thr; /* write only, DLAB == 0 */ + u8 iu_dll; /* DLAB == 1 */ + }; union { - volatile u8 ier; /* DLAB == 0 */ - volatile u8 dlm; /* DLAB == 1 */ - } u2; + u8 iu_ier; /* DLAB == 0 */ + u8 iu_dlm; /* DLAB == 1 */ + }; union { - volatile u8 iir; /* read only */ - volatile u8 fcr; /* write only */ - } u3; - volatile u8 iu_lcr; - volatile u8 iu_mcr; - volatile u8 iu_lsr; - volatile u8 iu_msr; - volatile u8 iu_scr; -} ioc3_uregs_t; - -#define iu_rbr u1.rbr -#define iu_thr u1.thr -#define iu_dll u1.dll -#define iu_ier u2.ier -#define iu_dlm u2.dlm -#define iu_iir u3.iir -#define iu_fcr u3.fcr + u8 iu_iir; /* read only */ + u8 iu_fcr; /* write only */ + }; + u8 iu_lcr; + u8 iu_mcr; + u8 iu_lsr; + u8 iu_msr; + u8 iu_scr; +}; struct ioc3_sioregs { - volatile u8 fill[0x141]; /* starts at 0x141 */ + u8 fill[0x141]; /* starts at 0x141 */ - volatile u8 uartc; - volatile u8 kbdcg; + u8 uartc; + u8 kbdcg; - volatile u8 fill0[0x150 - 0x142 - 1]; + u8 fill0[0x150 - 0x142 - 1]; - volatile u8 pp_data; - volatile u8 pp_dsr; - volatile u8 pp_dcr; + u8 pp_data; + u8 pp_dsr; + u8 pp_dcr; - volatile u8 fill1[0x158 - 0x152 - 1]; + u8 fill1[0x158 - 0x152 - 1]; - volatile u8 pp_fifa; - volatile u8 pp_cfgb; - volatile u8 pp_ecr; + u8 pp_fifa; + u8 pp_cfgb; + u8 pp_ecr; - volatile u8 fill2[0x168 - 0x15a - 1]; + u8 fill2[0x168 - 0x15a - 1]; - volatile u8 rtcad; - volatile u8 rtcdat; + u8 rtcad; + u8 rtcdat; - volatile u8 fill3[0x170 - 0x169 - 1]; + u8 fill3[0x170 - 0x169 - 1]; struct ioc3_uartregs uartb; /* 0x20170 */ struct ioc3_uartregs uarta; /* 0x20178 */ }; +struct ioc3_ethregs { + u32 emcr; /* 0x000f0 */ + u32 eisr; /* 0x000f4 */ + u32 eier; /* 0x000f8 */ + u32 ercsr; /* 0x000fc */ + u32 erbr_h; /* 0x00100 */ + u32 erbr_l; /* 0x00104 */ + u32 erbar; /* 0x00108 */ + u32 ercir; /* 0x0010c */ + u32 erpir; /* 0x00110 */ + u32 ertr; /* 0x00114 */ + u32 etcsr; /* 0x00118 */ + u32 ersr; /* 0x0011c */ + u32 etcdc; /* 0x00120 */ + u32 ebir; /* 0x00124 */ + u32 etbr_h; /* 0x00128 */ + u32 etbr_l; /* 0x0012c */ + u32 etcir; /* 0x00130 */ + u32 etpir; /* 0x00134 */ + u32 emar_h; /* 0x00138 */ + u32 emar_l; /* 0x0013c */ + u32 ehar_h; /* 0x00140 */ + u32 ehar_l; /* 0x00144 */ + u32 micr; /* 0x00148 */ + u32 midr_r; /* 0x0014c */ + u32 midr_w; /* 0x00150 */ +}; + +struct ioc3_serioregs { + u32 km_csr; /* 0x0009c */ + u32 k_rd; /* 0x000a0 */ + u32 m_rd; /* 0x000a4 */ + u32 k_wd; /* 0x000a8 */ + u32 m_wd; /* 0x000ac */ +}; + /* Register layout of IOC3 in configuration space. */ struct ioc3 { - volatile u32 pad0[7]; /* 0x00000 */ - volatile u32 sio_ir; /* 0x0001c */ - volatile u32 sio_ies; /* 0x00020 */ - volatile u32 sio_iec; /* 0x00024 */ - volatile u32 sio_cr; /* 0x00028 */ - volatile u32 int_out; /* 0x0002c */ - volatile u32 mcr; /* 0x00030 */ + /* PCI Config Space registers */ + u32 pci_id; /* 0x00000 */ + u32 pci_scr; /* 0x00004 */ + u32 pci_rev; /* 0x00008 */ + u32 pci_lat; /* 0x0000c */ + u32 pci_addr; /* 0x00010 */ + u32 pci_err_addr_l; /* 0x00014 */ + u32 pci_err_addr_h; /* 0x00018 */ + + u32 sio_ir; /* 0x0001c */ + u32 sio_ies; /* 0x00020 */ + u32 sio_iec; /* 0x00024 */ + u32 sio_cr; /* 0x00028 */ + u32 int_out; /* 0x0002c */ + u32 mcr; /* 0x00030 */ /* General Purpose I/O registers */ - volatile u32 gpcr_s; /* 0x00034 */ - volatile u32 gpcr_c; /* 0x00038 */ - volatile u32 gpdr; /* 0x0003c */ - volatile u32 gppr_0; /* 0x00040 */ - volatile u32 gppr_1; /* 0x00044 */ - volatile u32 gppr_2; /* 0x00048 */ - volatile u32 gppr_3; /* 0x0004c */ - volatile u32 gppr_4; /* 0x00050 */ - volatile u32 gppr_5; /* 0x00054 */ - volatile u32 gppr_6; /* 0x00058 */ - volatile u32 gppr_7; /* 0x0005c */ - volatile u32 gppr_8; /* 0x00060 */ - volatile u32 gppr_9; /* 0x00064 */ - volatile u32 gppr_10; /* 0x00068 */ - volatile u32 gppr_11; /* 0x0006c */ - volatile u32 gppr_12; /* 0x00070 */ - volatile u32 gppr_13; /* 0x00074 */ - volatile u32 gppr_14; /* 0x00078 */ - volatile u32 gppr_15; /* 0x0007c */ + u32 gpcr_s; /* 0x00034 */ + u32 gpcr_c; /* 0x00038 */ + u32 gpdr; /* 0x0003c */ + u32 gppr[16]; /* 0x00040 */ /* Parallel Port Registers */ - volatile u32 ppbr_h_a; /* 0x00080 */ - volatile u32 ppbr_l_a; /* 0x00084 */ - volatile u32 ppcr_a; /* 0x00088 */ - volatile u32 ppcr; /* 0x0008c */ - volatile u32 ppbr_h_b; /* 0x00090 */ - volatile u32 ppbr_l_b; /* 0x00094 */ - volatile u32 ppcr_b; /* 0x00098 */ + u32 ppbr_h_a; /* 0x00080 */ + u32 ppbr_l_a; /* 0x00084 */ + u32 ppcr_a; /* 0x00088 */ + u32 ppcr; /* 0x0008c */ + u32 ppbr_h_b; /* 0x00090 */ + u32 ppbr_l_b; /* 0x00094 */ + u32 ppcr_b; /* 0x00098 */ /* Keyboard and Mouse Registers */ - volatile u32 km_csr; /* 0x0009c */ - volatile u32 k_rd; /* 0x000a0 */ - volatile u32 m_rd; /* 0x000a4 */ - volatile u32 k_wd; /* 0x000a8 */ - volatile u32 m_wd; /* 0x000ac */ + struct ioc3_serioregs serio; /* Serial Port Registers */ - volatile u32 sbbr_h; /* 0x000b0 */ - volatile u32 sbbr_l; /* 0x000b4 */ - volatile u32 sscr_a; /* 0x000b8 */ - volatile u32 stpir_a; /* 0x000bc */ - volatile u32 stcir_a; /* 0x000c0 */ - volatile u32 srpir_a; /* 0x000c4 */ - volatile u32 srcir_a; /* 0x000c8 */ - volatile u32 srtr_a; /* 0x000cc */ - volatile u32 shadow_a; /* 0x000d0 */ - volatile u32 sscr_b; /* 0x000d4 */ - volatile u32 stpir_b; /* 0x000d8 */ - volatile u32 stcir_b; /* 0x000dc */ - volatile u32 srpir_b; /* 0x000e0 */ - volatile u32 srcir_b; /* 0x000e4 */ - volatile u32 srtr_b; /* 0x000e8 */ - volatile u32 shadow_b; /* 0x000ec */ - - /* Ethernet Registers */ - volatile u32 emcr; /* 0x000f0 */ - volatile u32 eisr; /* 0x000f4 */ - volatile u32 eier; /* 0x000f8 */ - volatile u32 ercsr; /* 0x000fc */ - volatile u32 erbr_h; /* 0x00100 */ - volatile u32 erbr_l; /* 0x00104 */ - volatile u32 erbar; /* 0x00108 */ - volatile u32 ercir; /* 0x0010c */ - volatile u32 erpir; /* 0x00110 */ - volatile u32 ertr; /* 0x00114 */ - volatile u32 etcsr; /* 0x00118 */ - volatile u32 ersr; /* 0x0011c */ - volatile u32 etcdc; /* 0x00120 */ - volatile u32 ebir; /* 0x00124 */ - volatile u32 etbr_h; /* 0x00128 */ - volatile u32 etbr_l; /* 0x0012c */ - volatile u32 etcir; /* 0x00130 */ - volatile u32 etpir; /* 0x00134 */ - volatile u32 emar_h; /* 0x00138 */ - volatile u32 emar_l; /* 0x0013c */ - volatile u32 ehar_h; /* 0x00140 */ - volatile u32 ehar_l; /* 0x00144 */ - volatile u32 micr; /* 0x00148 */ - volatile u32 midr_r; /* 0x0014c */ - volatile u32 midr_w; /* 0x00150 */ - volatile u32 pad1[(0x20000 - 0x00154) / 4]; + u32 sbbr_h; /* 0x000b0 */ + u32 sbbr_l; /* 0x000b4 */ + struct ioc3_serialregs port_a; + struct ioc3_serialregs port_b; + + /* Ethernet Registers */ + struct ioc3_ethregs eth; + u32 pad1[(0x20000 - 0x00154) / 4]; /* SuperIO Registers XXX */ struct ioc3_sioregs sregs; /* 0x20000 */ - volatile u32 pad2[(0x40000 - 0x20180) / 4]; + u32 pad2[(0x40000 - 0x20180) / 4]; /* SSRAM Diagnostic Access */ - volatile u32 ssram[(0x80000 - 0x40000) / 4]; + u32 ssram[(0x80000 - 0x40000) / 4]; /* Bytebus device offsets 0x80000 - Access to the generic devices selected with DEV0 @@ -178,6 +170,20 @@ struct ioc3 { 0xFFFFF bytebus DEV_SEL_3 */ }; + +#define PCI_LAT 0xc /* Latency Timer */ +#define PCI_SCR_DROP_MODE_EN 0x00008000 /* drop pios on parity err */ +#define UARTA_BASE 0x178 +#define UARTB_BASE 0x170 + +/* + * Bytebus device space + */ +#define IOC3_BYTEBUS_DEV0 0x80000L +#define IOC3_BYTEBUS_DEV1 0xa0000L +#define IOC3_BYTEBUS_DEV2 0xc0000L +#define IOC3_BYTEBUS_DEV3 0xe0000L + /* * Ethernet RX Buffer */ @@ -233,28 +239,20 @@ struct ioc3_etxd { #define ETXD_B2CNT_MASK 0x7ff00000 #define ETXD_B2CNT_SHIFT 20 -/* - * Bytebus device space - */ -#define IOC3_BYTEBUS_DEV0 0x80000L -#define IOC3_BYTEBUS_DEV1 0xa0000L -#define IOC3_BYTEBUS_DEV2 0xc0000L -#define IOC3_BYTEBUS_DEV3 0xe0000L - /* ------------------------------------------------------------------------- */ /* Superio Registers (PIO Access) */ #define IOC3_SIO_BASE 0x20000 #define IOC3_SIO_UARTC (IOC3_SIO_BASE+0x141) /* UART Config */ #define IOC3_SIO_KBDCG (IOC3_SIO_BASE+0x142) /* KBD Config */ -#define IOC3_SIO_PP_BASE (IOC3_SIO_BASE+PP_BASE) /* Parallel Port */ +#define IOC3_SIO_PP_BASE (IOC3_SIO_BASE+PP_BASE) /* Parallel Port */ #define IOC3_SIO_RTC_BASE (IOC3_SIO_BASE+0x168) /* Real Time Clock */ #define IOC3_SIO_UB_BASE (IOC3_SIO_BASE+UARTB_BASE) /* UART B */ #define IOC3_SIO_UA_BASE (IOC3_SIO_BASE+UARTA_BASE) /* UART A */ /* SSRAM Diagnostic Access */ #define IOC3_SSRAM IOC3_RAM_OFF /* base of SSRAM diagnostic access */ -#define IOC3_SSRAM_LEN 0x40000 /* 256kb (address space size, may not be fully populated) */ +#define IOC3_SSRAM_LEN 0x40000 /* 256kb (addrspc sz, may not be populated) */ #define IOC3_SSRAM_DM 0x0000ffff /* data mask */ #define IOC3_SSRAM_PM 0x00010000 /* parity mask */ @@ -294,10 +292,10 @@ struct ioc3_etxd { SIO_IR to assert */ #define KM_CSR_M_TO_EN 0x00080000 /* KM_CSR_M_TO + KM_CSR_M_TO_EN = cause SIO_IR to assert */ -#define KM_CSR_K_CLAMP_ONE 0x00100000 /* Pull K_CLK low after rec. one char */ -#define KM_CSR_M_CLAMP_ONE 0x00200000 /* Pull M_CLK low after rec. one char */ -#define KM_CSR_K_CLAMP_THREE 0x00400000 /* Pull K_CLK low after rec. three chars */ -#define KM_CSR_M_CLAMP_THREE 0x00800000 /* Pull M_CLK low after rec. three char */ +#define KM_CSR_K_CLAMP_1 0x00100000 /* Pull K_CLK low aft recv 1 char */ +#define KM_CSR_M_CLAMP_1 0x00200000 /* Pull M_CLK low aft recv 1 char */ +#define KM_CSR_K_CLAMP_3 0x00400000 /* Pull K_CLK low aft recv 3 chars */ +#define KM_CSR_M_CLAMP_3 0x00800000 /* Pull M_CLK low aft recv 3 chars */ /* bitmasks for IOC3_K_RD and IOC3_M_RD */ #define KM_RD_DATA_2 0x000000ff /* 3rd char recvd since last read */ @@ -440,10 +438,6 @@ struct ioc3_etxd { SIO_IR_PP_INTB | SIO_IR_PP_MEMERR) #define SIO_IR_RT (SIO_IR_RT_INT | SIO_IR_GEN_INT1) -/* macro to load pending interrupts */ -#define IOC3_PENDING_INTRS(mem) (PCI_INW(&((mem)->sio_ir)) & \ - PCI_INW(&((mem)->sio_ies_ro))) - /* bitmasks for SIO_CR */ #define SIO_CR_SIO_RESET 0x00000001 /* reset the SIO */ #define SIO_CR_SER_A_BASE 0x000000fe /* DMA poll addr port A */ @@ -500,10 +494,11 @@ struct ioc3_etxd { #define GPCR_UARTB_MODESEL 0x40 /* pin is output to port B mode sel */ #define GPCR_UARTA_MODESEL 0x80 /* pin is output to port A mode sel */ -#define GPPR_PHY_RESET_PIN 5 /* GIO pin controlling phy reset */ -#define GPPR_UARTB_MODESEL_PIN 6 /* GIO pin controlling uart b mode select */ -#define GPPR_UARTA_MODESEL_PIN 7 /* GIO pin controlling uart a mode select */ +#define GPPR_PHY_RESET_PIN 5 /* GIO pin cntrlling phy reset */ +#define GPPR_UARTB_MODESEL_PIN 6 /* GIO pin cntrlling uart b mode sel */ +#define GPPR_UARTA_MODESEL_PIN 7 /* GIO pin cntrlling uart a mode sel */ +/* ethernet */ #define EMCR_DUPLEX 0x00000001 #define EMCR_PROMISC 0x00000002 #define EMCR_PADEN 0x00000004 @@ -595,70 +590,4 @@ struct ioc3_etxd { #define MIDR_DATA_MASK 0x0000ffff -#define ERXBUF_IPCKSUM_MASK 0x0000ffff -#define ERXBUF_BYTECNT_MASK 0x07ff0000 -#define ERXBUF_BYTECNT_SHIFT 16 -#define ERXBUF_V 0x80000000 - -#define ERXBUF_CRCERR 0x00000001 /* aka RSV15 */ -#define ERXBUF_FRAMERR 0x00000002 /* aka RSV14 */ -#define ERXBUF_CODERR 0x00000004 /* aka RSV13 */ -#define ERXBUF_INVPREAMB 0x00000008 /* aka RSV18 */ -#define ERXBUF_LOLEN 0x00007000 /* aka RSV2_0 */ -#define ERXBUF_HILEN 0x03ff0000 /* aka RSV12_3 */ -#define ERXBUF_MULTICAST 0x04000000 /* aka RSV16 */ -#define ERXBUF_BROADCAST 0x08000000 /* aka RSV17 */ -#define ERXBUF_LONGEVENT 0x10000000 /* aka RSV19 */ -#define ERXBUF_BADPKT 0x20000000 /* aka RSV20 */ -#define ERXBUF_GOODPKT 0x40000000 /* aka RSV21 */ -#define ERXBUF_CARRIER 0x80000000 /* aka RSV22 */ - -#define ETXD_BYTECNT_MASK 0x000007ff /* total byte count */ -#define ETXD_INTWHENDONE 0x00001000 /* intr when done */ -#define ETXD_D0V 0x00010000 /* data 0 valid */ -#define ETXD_B1V 0x00020000 /* buf 1 valid */ -#define ETXD_B2V 0x00040000 /* buf 2 valid */ -#define ETXD_DOCHECKSUM 0x00080000 /* insert ip cksum */ -#define ETXD_CHKOFF_MASK 0x07f00000 /* cksum byte offset */ -#define ETXD_CHKOFF_SHIFT 20 - -#define ETXD_D0CNT_MASK 0x0000007f -#define ETXD_B1CNT_MASK 0x0007ff00 -#define ETXD_B1CNT_SHIFT 8 -#define ETXD_B2CNT_MASK 0x7ff00000 -#define ETXD_B2CNT_SHIFT 20 - -typedef enum ioc3_subdevs_e { - ioc3_subdev_ether, - ioc3_subdev_generic, - ioc3_subdev_nic, - ioc3_subdev_kbms, - ioc3_subdev_ttya, - ioc3_subdev_ttyb, - ioc3_subdev_ecpp, - ioc3_subdev_rt, - ioc3_nsubdevs -} ioc3_subdev_t; - -/* subdevice disable bits, - * from the standard INFO_LBL_SUBDEVS - */ -#define IOC3_SDB_ETHER (1<iu_lsr & 0x20) == 0); - uart->iu_thr = c; + while ((readb(&uart->iu_lsr) & 0x20) == 0) + ; + writeb(c, &uart->iu_thr); } diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c index 066b33f50bcc4da9649360d2654c80e7a0da5e72..59d5375c902135e3fab474442fcbf34c3b800f97 100644 --- a/arch/mips/sgi-ip27/ip27-init.c +++ b/arch/mips/sgi-ip27/ip27-init.c @@ -130,17 +130,6 @@ cnodeid_t get_compact_nodeid(void) return NASID_TO_COMPACT_NODEID(get_nasid()); } -static inline void ioc3_eth_init(void) -{ - struct ioc3 *ioc3; - nasid_t nid; - - nid = get_nasid(); - ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base; - - ioc3->eier = 0; -} - extern void ip27_reboot_setup(void); void __init plat_mem_setup(void) @@ -182,8 +171,6 @@ void __init plat_mem_setup(void) panic("Kernel compiled for N mode."); #endif - ioc3_eth_init(); - ioport_resource.start = 0; ioport_resource.end = ~0UL; set_io_port_base(IO_BASE); diff --git a/arch/openrisc/boot/dts/or1ksim.dts b/arch/openrisc/boot/dts/or1ksim.dts index d8aa8309c9d30981c9129b8610fd4b306e884f8d..c0cb74e52f95567fb3c6b20215bd472eda3ea8b6 100644 --- a/arch/openrisc/boot/dts/or1ksim.dts +++ b/arch/openrisc/boot/dts/or1ksim.dts @@ -49,8 +49,9 @@ }; enet0: ethoc@92000000 { - compatible = "opencores,ethmac-rtlsvn338"; - reg = <0x92000000 0x100>; + compatible = "opencores,ethoc"; + reg = <0x92000000 0x800>; interrupts = <4>; + big-endian; }; }; diff --git a/arch/openrisc/boot/dts/simple_smp.dts b/arch/openrisc/boot/dts/simple_smp.dts index defbb92714ec1746e55799d97f6746dfbd478246..71af0e117bfe5f675806c63beaf78def53433a82 100644 --- a/arch/openrisc/boot/dts/simple_smp.dts +++ b/arch/openrisc/boot/dts/simple_smp.dts @@ -60,4 +60,10 @@ clock-frequency = <20000000>; }; + enet0: ethoc@92000000 { + compatible = "opencores,ethoc"; + reg = <0x92000000 0x800>; + interrupts = <4>; + big-endian; + }; }; diff --git a/arch/openrisc/include/asm/io.h b/arch/openrisc/include/asm/io.h index 06a710757789e7cc6a85f1caa7580ecf9ac0bc23..5b81a96ab85ee4acb1ccb4bd670f2771b483b28f 100644 --- a/arch/openrisc/include/asm/io.h +++ b/arch/openrisc/include/asm/io.h @@ -25,25 +25,11 @@ #define PIO_OFFSET 0 #define PIO_MASK 0 -#define ioremap_nocache ioremap_nocache +#define ioremap_nocache ioremap #include #include -extern void __iomem *__ioremap(phys_addr_t offset, unsigned long size, - pgprot_t prot); - -static inline void __iomem *ioremap(phys_addr_t offset, size_t size) -{ - return __ioremap(offset, size, PAGE_KERNEL); -} - -/* #define _PAGE_CI 0x002 */ -static inline void __iomem *ioremap_nocache(phys_addr_t offset, - unsigned long size) -{ - return __ioremap(offset, size, - __pgprot(pgprot_val(PAGE_KERNEL) | _PAGE_CI)); -} - +void __iomem *ioremap(phys_addr_t offset, unsigned long size); extern void iounmap(void *addr); + #endif diff --git a/arch/openrisc/include/asm/pgtable.h b/arch/openrisc/include/asm/pgtable.h index 497fd908a4c40c4d9b7119fad7a1f9d044e8c739..2fe9ff5b5d6f7d8b4ac00f35858036032820f207 100644 --- a/arch/openrisc/include/asm/pgtable.h +++ b/arch/openrisc/include/asm/pgtable.h @@ -97,7 +97,7 @@ extern void paging_init(void); /* Define some higher level generic page attributes. * * If you change _PAGE_CI definition be sure to change it in - * io.h for ioremap_nocache() too. + * io.h for ioremap() too. */ /* diff --git a/arch/openrisc/mm/ioremap.c b/arch/openrisc/mm/ioremap.c index e0c551ca0891776282db3827e38a04070e32e63e..8f8e97f7eac981302d621c5063e5ef349573f073 100644 --- a/arch/openrisc/mm/ioremap.c +++ b/arch/openrisc/mm/ioremap.c @@ -34,8 +34,7 @@ static unsigned int fixmaps_used __initdata; * have to convert them into an offset in a page-aligned mapping, but the * caller shouldn't need to know that small detail. */ -void __iomem *__ref -__ioremap(phys_addr_t addr, unsigned long size, pgprot_t prot) +void __iomem *__ref ioremap(phys_addr_t addr, unsigned long size) { phys_addr_t p; unsigned long v; @@ -66,7 +65,8 @@ __ioremap(phys_addr_t addr, unsigned long size, pgprot_t prot) fixmaps_used += (size >> PAGE_SHIFT); } - if (ioremap_page_range(v, v + size, p, prot)) { + if (ioremap_page_range(v, v + size, p, + __pgprot(pgprot_val(PAGE_KERNEL) | _PAGE_CI))) { if (likely(mem_init_done)) vfree(area->addr); else @@ -76,7 +76,7 @@ __ioremap(phys_addr_t addr, unsigned long size, pgprot_t prot) return (void __iomem *)(offset + (char *)v); } -EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(ioremap); void iounmap(void *addr) { diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 6d732e4510713391989914fa244f2798d37052be..2e757c785239a97a77bb4f1a04b63d374e4226e0 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -61,6 +61,8 @@ config PARISC select HAVE_KRETPROBES select HAVE_DYNAMIC_FTRACE if $(cc-option,-fpatchable-function-entry=1,1) select HAVE_FTRACE_MCOUNT_RECORD if HAVE_DYNAMIC_FTRACE + select HAVE_KPROBES_ON_FTRACE + select HAVE_DYNAMIC_FTRACE_WITH_REGS help The PA-RISC microprocessor is designed by Hewlett-Packard and used @@ -344,6 +346,29 @@ config NR_CPUS depends on SMP default "4" +config KEXEC + bool "Kexec system call" + select KEXEC_CORE + help + kexec is a system call that implements the ability to shutdown your + current kernel, and to start another kernel. It is like a reboot + but it is independent of the system firmware. And like a reboot + you can start any kernel with it, not just Linux. + + It is an ongoing process to be certain the hardware in a machine + shutdown, so do not be surprised if this code does not + initially work for you. + +config KEXEC_FILE + bool "kexec file based system call" + select KEXEC_CORE + select KEXEC_ELF + help + This enables the kexec_file_load() System call. This is + file based and takes file descriptors as system call argument + for kernel and initramfs as opposed to list of segments as + accepted by previous system call. + endmenu diff --git a/arch/parisc/boot/compressed/.gitignore b/arch/parisc/boot/compressed/.gitignore index ae06b9b4c02f79a7f6bc188dad222d20f5bd0bcf..926cd41c106915dac1dd9b7c1ff0c1176c884b7e 100644 --- a/arch/parisc/boot/compressed/.gitignore +++ b/arch/parisc/boot/compressed/.gitignore @@ -1,3 +1,5 @@ +firmware.c +real2.S sizes.h vmlinux vmlinux.lds diff --git a/arch/parisc/include/asm/alternative.h b/arch/parisc/include/asm/alternative.h index 793d8baa3a10d136e6f23a2aea8dcf4bf5d65b73..0ec54f43d6d250e69400f69be7ee3ea1461793bc 100644 --- a/arch/parisc/include/asm/alternative.h +++ b/arch/parisc/include/asm/alternative.h @@ -8,6 +8,7 @@ #define ALT_COND_NO_ICACHE 0x04 /* if system has no i-cache */ #define ALT_COND_NO_SPLIT_TLB 0x08 /* if split_tlb == 0 */ #define ALT_COND_NO_IOC_FDC 0x10 /* if I/O cache does not need flushes */ +#define ALT_COND_RUN_ON_QEMU 0x20 /* if running on QEMU */ #define INSN_PxTLB 0x02 /* modify pdtlb, pitlb */ #define INSN_NOP 0x08000240 /* nop */ @@ -21,7 +22,7 @@ struct alt_instr { s32 orig_offset; /* offset to original instructions */ - u32 len; /* end of original instructions */ + s32 len; /* end of original instructions */ u32 cond; /* see ALT_COND_XXX */ u32 replacement; /* replacement instruction or code */ }; @@ -40,12 +41,20 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end, #else +/* to replace one single instructions by a new instruction */ #define ALTERNATIVE(from, to, cond, replacement)\ .section .altinstructions, "aw" ! \ .word (from - .), (to - from)/4 ! \ .word cond, replacement ! \ .previous +/* to replace multiple instructions by new code */ +#define ALTERNATIVE_CODE(from, num_instructions, cond, new_instr_ptr)\ + .section .altinstructions, "aw" ! \ + .word (from - .), -num_instructions ! \ + .word cond, (new_instr_ptr - .) ! \ + .previous + #endif /* __ASSEMBLY__ */ #endif /* __ASM_PARISC_ALTERNATIVE_H */ diff --git a/arch/parisc/include/asm/fixmap.h b/arch/parisc/include/asm/fixmap.h index 288da73d4cc0d8c4fcb7121855673b27119919f5..e480b2c054078eb9a0f72ff809b2aa3363c27a67 100644 --- a/arch/parisc/include/asm/fixmap.h +++ b/arch/parisc/include/asm/fixmap.h @@ -30,6 +30,7 @@ enum fixed_addresses { /* Support writing RO kernel text via kprobes, jump labels, etc. */ FIX_TEXT_POKE0, + FIX_TEXT_KEXEC, FIX_BITMAP_COUNT }; diff --git a/arch/parisc/include/asm/ftrace.h b/arch/parisc/include/asm/ftrace.h index 958c0aa5dbb2552d7d2b590f583eb94763a0bcc6..a7cf0d05ccf467449759cb69d56a36d3c2a08b62 100644 --- a/arch/parisc/include/asm/ftrace.h +++ b/arch/parisc/include/asm/ftrace.h @@ -8,6 +8,7 @@ extern void mcount(void); #define MCOUNT_ADDR ((unsigned long)mcount) #define MCOUNT_INSN_SIZE 4 #define CC_USING_NOP_MCOUNT +#define ARCH_SUPPORTS_FTRACE_OPS 1 extern unsigned long sys_call_table[]; extern unsigned long return_address(unsigned int); diff --git a/arch/parisc/include/asm/kexec.h b/arch/parisc/include/asm/kexec.h new file mode 100644 index 0000000000000000000000000000000000000000..a99ea747d7edefb681d7eca88917efaca7c245aa --- /dev/null +++ b/arch/parisc/include/asm/kexec.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_PARISC_KEXEC_H +#define _ASM_PARISC_KEXEC_H + +#ifdef CONFIG_KEXEC + +/* Maximum physical address we can use pages from */ +#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) +/* Maximum address we can reach in physical address mode */ +#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) +/* Maximum address we can use for the control code buffer */ +#define KEXEC_CONTROL_MEMORY_LIMIT (-1UL) + +#define KEXEC_CONTROL_PAGE_SIZE 4096 + +#define KEXEC_ARCH KEXEC_ARCH_PARISC +#define ARCH_HAS_KIMAGE_ARCH + +#ifndef __ASSEMBLY__ + +struct kimage_arch { + unsigned long initrd_start; + unsigned long initrd_end; + unsigned long cmdline; +}; + +static inline void crash_setup_regs(struct pt_regs *newregs, + struct pt_regs *oldregs) +{ + /* Dummy implementation for now */ +} + +#endif /* __ASSEMBLY__ */ + +#endif /* CONFIG_KEXEC */ + +#endif /* _ASM_PARISC_KEXEC_H */ diff --git a/arch/parisc/include/asm/pdc.h b/arch/parisc/include/asm/pdc.h index 19bb2e46cd36cb942e275cc660f63d34fc1f0e09..b388d817658833126cc22b8d64b03ae4b60b5dae 100644 --- a/arch/parisc/include/asm/pdc.h +++ b/arch/parisc/include/asm/pdc.h @@ -91,6 +91,7 @@ int pdc_sti_call(unsigned long func, unsigned long flags, unsigned long inptr, unsigned long outputr, unsigned long glob_cfg); +int __pdc_cpu_rendezvous(void); static inline char * os_id_to_string(u16 os_id) { switch(os_id) { case OS_ID_NONE: return "No OS"; diff --git a/arch/parisc/include/asm/string.h b/arch/parisc/include/asm/string.h index f6e1132f4e352d40ab5c5454f3be06aa016b6211..4a0c9dbd62fd0cf56744490d069697f7062c9aa7 100644 --- a/arch/parisc/include/asm/string.h +++ b/arch/parisc/include/asm/string.h @@ -8,4 +8,19 @@ extern void * memset(void *, int, size_t); #define __HAVE_ARCH_MEMCPY void * memcpy(void * dest,const void *src,size_t count); +#define __HAVE_ARCH_STRLEN +extern size_t strlen(const char *s); + +#define __HAVE_ARCH_STRCPY +extern char *strcpy(char *dest, const char *src); + +#define __HAVE_ARCH_STRNCPY +extern char *strncpy(char *dest, const char *src, size_t count); + +#define __HAVE_ARCH_STRCAT +extern char *strcat(char *dest, const char *src); + +#define __HAVE_ARCH_MEMSET +extern void *memset(void *, int, size_t); + #endif diff --git a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile index c232266b517cb8f5760d6e2f0f6bf5c5146161ad..2663c8f8be115a0929b2e6f933f4b3e05ca9e98d 100644 --- a/arch/parisc/kernel/Makefile +++ b/arch/parisc/kernel/Makefile @@ -37,3 +37,5 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_KEXEC) += kexec.o relocate_kernel.o +obj-$(CONFIG_KEXEC_FILE) += kexec_file.o diff --git a/arch/parisc/kernel/alternative.c b/arch/parisc/kernel/alternative.c index ca1f5ca0540a1b603c6377d19f1520151ac8798b..3c66d5c4d90d309eacbc265227ce07fdb2a3625e 100644 --- a/arch/parisc/kernel/alternative.c +++ b/arch/parisc/kernel/alternative.c @@ -28,7 +28,8 @@ void __init_or_module apply_alternatives(struct alt_instr *start, for (entry = start; entry < end; entry++, index++) { - u32 *from, len, cond, replacement; + u32 *from, cond, replacement; + s32 len; from = (u32 *)((ulong)&entry->orig_offset + entry->orig_offset); len = entry->len; @@ -49,6 +50,8 @@ void __init_or_module apply_alternatives(struct alt_instr *start, continue; if ((cond & ALT_COND_NO_ICACHE) && (cache_info.ic_size != 0)) continue; + if ((cond & ALT_COND_RUN_ON_QEMU) && !running_on_qemu) + continue; /* * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit @@ -74,11 +77,19 @@ void __init_or_module apply_alternatives(struct alt_instr *start, if (replacement == INSN_NOP && len > 1) replacement = 0xe8000002 + (len-2)*8; /* "b,n .+8" */ - pr_debug("Do %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n", - index, cond, len, from, replacement); - - /* Replace instruction */ - *from = replacement; + pr_debug("ALTERNATIVE %3d: Cond %2x, Replace %2d instructions to 0x%08x @ 0x%px (%pS)\n", + index, cond, len, replacement, from, from); + + if (len < 0) { + /* Replace multiple instruction by new code */ + u32 *source; + len = -len; + source = (u32 *)((ulong)&entry->replacement + entry->replacement); + memcpy(from, source, 4 * len); + } else { + /* Replace by one instruction */ + *from = replacement; + } applied++; } diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index d9d3387f7c478bc6f53f12c0fa34384fefabe0c9..1d1d748c227f075685f79dc327bfc52a029885d1 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -1996,6 +1996,7 @@ _mcount: * calling mcount(), and 2 instructions for ftrace_stub(). That way we * have all on one L1 cacheline. */ + ldi 0, %arg3 b ftrace_function_trampoline copy %r3, %arg2 /* caller original %sp */ ftrace_stub: @@ -2048,6 +2049,7 @@ ftrace_caller: LDREG 0(%r3), %r25 copy %rp, %r26 ldo -8(%r25), %r25 + ldi 0, %r23 /* no pt_regs */ b,l ftrace_function_trampoline, %rp copy %r3, %r24 @@ -2075,6 +2077,103 @@ ftrace_caller: ENDPROC_CFI(ftrace_caller) +#ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS +ENTRY_CFI(ftrace_regs_caller,caller,frame=FTRACE_FRAME_SIZE+PT_SZ_ALGN, + CALLS,SAVE_RP,SAVE_SP) +ftrace_regs_caller: + .global ftrace_regs_caller + + ldo -FTRACE_FRAME_SIZE(%sp), %r1 + STREG %rp, -RP_OFFSET(%r1) + + copy %sp, %r1 + ldo PT_SZ_ALGN(%sp), %sp + + STREG %rp, PT_GR2(%r1) + STREG %r3, PT_GR3(%r1) + STREG %r4, PT_GR4(%r1) + STREG %r5, PT_GR5(%r1) + STREG %r6, PT_GR6(%r1) + STREG %r7, PT_GR7(%r1) + STREG %r8, PT_GR8(%r1) + STREG %r9, PT_GR9(%r1) + STREG %r10, PT_GR10(%r1) + STREG %r11, PT_GR11(%r1) + STREG %r12, PT_GR12(%r1) + STREG %r13, PT_GR13(%r1) + STREG %r14, PT_GR14(%r1) + STREG %r15, PT_GR15(%r1) + STREG %r16, PT_GR16(%r1) + STREG %r17, PT_GR17(%r1) + STREG %r18, PT_GR18(%r1) + STREG %r19, PT_GR19(%r1) + STREG %r20, PT_GR20(%r1) + STREG %r21, PT_GR21(%r1) + STREG %r22, PT_GR22(%r1) + STREG %r23, PT_GR23(%r1) + STREG %r24, PT_GR24(%r1) + STREG %r25, PT_GR25(%r1) + STREG %r26, PT_GR26(%r1) + STREG %r27, PT_GR27(%r1) + STREG %r28, PT_GR28(%r1) + STREG %r29, PT_GR29(%r1) + STREG %r30, PT_GR30(%r1) + STREG %r31, PT_GR31(%r1) + mfctl %cr11, %r26 + STREG %r26, PT_SAR(%r1) + + copy %rp, %r26 + LDREG -FTRACE_FRAME_SIZE-PT_SZ_ALGN(%sp), %r25 + ldo -8(%r25), %r25 + copy %r3, %arg2 + b,l ftrace_function_trampoline, %rp + copy %r1, %arg3 /* struct pt_regs */ + + ldo -PT_SZ_ALGN(%sp), %r1 + + LDREG PT_SAR(%r1), %rp + mtctl %rp, %cr11 + + LDREG PT_GR2(%r1), %rp + LDREG PT_GR3(%r1), %r3 + LDREG PT_GR4(%r1), %r4 + LDREG PT_GR5(%r1), %r5 + LDREG PT_GR6(%r1), %r6 + LDREG PT_GR7(%r1), %r7 + LDREG PT_GR8(%r1), %r8 + LDREG PT_GR9(%r1), %r9 + LDREG PT_GR10(%r1),%r10 + LDREG PT_GR11(%r1),%r11 + LDREG PT_GR12(%r1),%r12 + LDREG PT_GR13(%r1),%r13 + LDREG PT_GR14(%r1),%r14 + LDREG PT_GR15(%r1),%r15 + LDREG PT_GR16(%r1),%r16 + LDREG PT_GR17(%r1),%r17 + LDREG PT_GR18(%r1),%r18 + LDREG PT_GR19(%r1),%r19 + LDREG PT_GR20(%r1),%r20 + LDREG PT_GR21(%r1),%r21 + LDREG PT_GR22(%r1),%r22 + LDREG PT_GR23(%r1),%r23 + LDREG PT_GR24(%r1),%r24 + LDREG PT_GR25(%r1),%r25 + LDREG PT_GR26(%r1),%r26 + LDREG PT_GR27(%r1),%r27 + LDREG PT_GR28(%r1),%r28 + LDREG PT_GR29(%r1),%r29 + LDREG PT_GR30(%r1),%r30 + LDREG PT_GR31(%r1),%r31 + + ldo -PT_SZ_ALGN(%sp), %sp + LDREGM -FTRACE_FRAME_SIZE(%sp), %r1 + /* Adjust return point to jump back to beginning of traced function */ + ldo -4(%r1), %r1 + bv,n (%r1) + +ENDPROC_CFI(ftrace_regs_caller) + +#endif #endif #ifdef CONFIG_FUNCTION_GRAPH_TRACER diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index 58cc08e7fd122acace311f2364e00a6660a61f52..1d976f2ebff0fe6b9026b4ed81fe878449cf0e95 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -311,6 +311,19 @@ int pdc_chassis_disp(unsigned long disp) return retval; } +/** + * pdc_cpu_rendenzvous - Stop currently executing CPU + * @retval: -1 on error, 0 on success + */ +int __pdc_cpu_rendezvous(void) +{ + if (is_pdc_pat()) + return mem_pdc_call(PDC_PAT_CPU, PDC_PAT_CPU_RENDEZVOUS); + else + return mem_pdc_call(PDC_PROC, 1, 0); +} + + /** * pdc_chassis_warn - Fetches chassis warnings * @retval: -1 on error, 0 on success diff --git a/arch/parisc/kernel/ftrace.c b/arch/parisc/kernel/ftrace.c index b6fb30f2e4bfd26531145d8612b2be10b253da21..b836fc61a24f4b7cd1cdb7975fddc4962cef8a97 100644 --- a/arch/parisc/kernel/ftrace.c +++ b/arch/parisc/kernel/ftrace.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include @@ -48,17 +50,22 @@ static void __hot prepare_ftrace_return(unsigned long *parent, void notrace __hot ftrace_function_trampoline(unsigned long parent, unsigned long self_addr, - unsigned long org_sp_gr3) + unsigned long org_sp_gr3, + struct pt_regs *regs) { #ifndef CONFIG_DYNAMIC_FTRACE extern ftrace_func_t ftrace_trace_function; #endif - if (ftrace_trace_function != ftrace_stub) - ftrace_trace_function(self_addr, parent, NULL, NULL); + extern struct ftrace_ops *function_trace_op; + + if (function_trace_op->flags & FTRACE_OPS_FL_ENABLED && + ftrace_trace_function != ftrace_stub) + ftrace_trace_function(self_addr, parent, + function_trace_op, regs); #ifdef CONFIG_FUNCTION_GRAPH_TRACER if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub || - ftrace_graph_entry != ftrace_graph_entry_stub) { + ftrace_graph_entry != ftrace_graph_entry_stub) { unsigned long *parent_rp; /* calculate pointer to %rp in stack */ @@ -96,6 +103,12 @@ int ftrace_update_ftrace_func(ftrace_func_t func) return 0; } +int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, + unsigned long addr) +{ + return 0; +} + unsigned long ftrace_call_adjust(unsigned long addr) { return addr+(FTRACE_PATCHABLE_FUNCTION_SIZE-1)*4; @@ -187,3 +200,46 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, return 0; } #endif + +#ifdef CONFIG_KPROBES_ON_FTRACE +void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *ops, struct pt_regs *regs) +{ + struct kprobe_ctlblk *kcb; + struct kprobe *p = get_kprobe((kprobe_opcode_t *)ip); + + if (unlikely(!p) || kprobe_disabled(p)) + return; + + if (kprobe_running()) { + kprobes_inc_nmissed_count(p); + return; + } + + __this_cpu_write(current_kprobe, p); + + kcb = get_kprobe_ctlblk(); + kcb->kprobe_status = KPROBE_HIT_ACTIVE; + + regs->iaoq[0] = ip; + regs->iaoq[1] = ip + 4; + + if (!p->pre_handler || !p->pre_handler(p, regs)) { + regs->iaoq[0] = ip + 4; + regs->iaoq[1] = ip + 8; + + if (unlikely(p->post_handler)) { + kcb->kprobe_status = KPROBE_HIT_SSDONE; + p->post_handler(p, regs, 0); + } + } + __this_cpu_write(current_kprobe, NULL); +} +NOKPROBE_SYMBOL(kprobe_ftrace_handler); + +int arch_prepare_kprobe_ftrace(struct kprobe *p) +{ + p->ainsn.insn = NULL; + return 0; +} +#endif diff --git a/arch/parisc/kernel/kexec.c b/arch/parisc/kernel/kexec.c new file mode 100644 index 0000000000000000000000000000000000000000..5eb7f30edc1f7da3eedd284ada33cda9ef0a9d52 --- /dev/null +++ b/arch/parisc/kernel/kexec.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include + +extern void relocate_new_kernel(unsigned long head, + unsigned long start, + unsigned long phys); + +extern const unsigned int relocate_new_kernel_size; +extern unsigned int kexec_initrd_start_offset; +extern unsigned int kexec_initrd_end_offset; +extern unsigned int kexec_cmdline_offset; +extern unsigned int kexec_free_mem_offset; + +static void kexec_show_segment_info(const struct kimage *kimage, + unsigned long n) +{ + pr_debug(" segment[%lu]: %016lx - %016lx, 0x%lx bytes, %lu pages\n", + n, + kimage->segment[n].mem, + kimage->segment[n].mem + kimage->segment[n].memsz, + (unsigned long)kimage->segment[n].memsz, + (unsigned long)kimage->segment[n].memsz / PAGE_SIZE); +} + +static void kexec_image_info(const struct kimage *kimage) +{ + unsigned long i; + + pr_debug("kexec kimage info:\n"); + pr_debug(" type: %d\n", kimage->type); + pr_debug(" start: %lx\n", kimage->start); + pr_debug(" head: %lx\n", kimage->head); + pr_debug(" nr_segments: %lu\n", kimage->nr_segments); + + for (i = 0; i < kimage->nr_segments; i++) + kexec_show_segment_info(kimage, i); + +#ifdef CONFIG_KEXEC_FILE + if (kimage->file_mode) { + pr_debug("cmdline: %.*s\n", (int)kimage->cmdline_buf_len, + kimage->cmdline_buf); + } +#endif +} + +void machine_kexec_cleanup(struct kimage *kimage) +{ +} + +void machine_crash_shutdown(struct pt_regs *regs) +{ +} + +void machine_shutdown(void) +{ + smp_send_stop(); + while (num_online_cpus() > 1) { + cpu_relax(); + mdelay(1); + } +} + +void machine_kexec(struct kimage *image) +{ +#ifdef CONFIG_64BIT + Elf64_Fdesc desc; +#endif + void (*reloc)(unsigned long head, + unsigned long start, + unsigned long phys); + + unsigned long phys = page_to_phys(image->control_code_page); + void *virt = (void *)__fix_to_virt(FIX_TEXT_KEXEC); + struct kimage_arch *arch = &image->arch; + + set_fixmap(FIX_TEXT_KEXEC, phys); + + flush_cache_all(); + +#ifdef CONFIG_64BIT + reloc = (void *)&desc; + desc.addr = (long long)virt; +#else + reloc = (void *)virt; +#endif + + memcpy(virt, dereference_function_descriptor(relocate_new_kernel), + relocate_new_kernel_size); + + *(unsigned long *)(virt + kexec_cmdline_offset) = arch->cmdline; + *(unsigned long *)(virt + kexec_initrd_start_offset) = arch->initrd_start; + *(unsigned long *)(virt + kexec_initrd_end_offset) = arch->initrd_end; + *(unsigned long *)(virt + kexec_free_mem_offset) = PAGE0->mem_free; + + flush_cache_all(); + flush_tlb_all(); + local_irq_disable(); + + reloc(image->head & PAGE_MASK, image->start, phys); +} + +int machine_kexec_prepare(struct kimage *image) +{ + kexec_image_info(image); + return 0; +} diff --git a/arch/parisc/kernel/kexec_file.c b/arch/parisc/kernel/kexec_file.c new file mode 100644 index 0000000000000000000000000000000000000000..8c534204f0fdac4f9436338f38ecf5b710d15701 --- /dev/null +++ b/arch/parisc/kernel/kexec_file.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Load ELF vmlinux file for the kexec_file_load syscall. + * + * Copyright (c) 2019 Sven Schnelle + * + */ +#include +#include +#include +#include +#include +#include +#include + +static void *elf_load(struct kimage *image, char *kernel_buf, + unsigned long kernel_len, char *initrd, + unsigned long initrd_len, char *cmdline, + unsigned long cmdline_len) +{ + int ret, i; + unsigned long kernel_load_addr; + struct elfhdr ehdr; + struct kexec_elf_info elf_info; + struct kexec_buf kbuf = { .image = image, .buf_min = 0, + .buf_max = -1UL, }; + + ret = kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info); + if (ret) + goto out; + + ret = kexec_elf_load(image, &ehdr, &elf_info, &kbuf, &kernel_load_addr); + if (ret) + goto out; + + image->start = __pa(elf_info.ehdr->e_entry); + + for (i = 0; i < image->nr_segments; i++) + image->segment[i].mem = __pa(image->segment[i].mem); + + pr_debug("Loaded the kernel at 0x%lx, entry at 0x%lx\n", + kernel_load_addr, image->start); + + if (initrd != NULL) { + kbuf.buffer = initrd; + kbuf.bufsz = kbuf.memsz = initrd_len; + kbuf.buf_align = PAGE_SIZE; + kbuf.top_down = false; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + ret = kexec_add_buffer(&kbuf); + if (ret) + goto out; + + pr_debug("Loaded initrd at 0x%lx\n", kbuf.mem); + image->arch.initrd_start = kbuf.mem; + image->arch.initrd_end = kbuf.mem + initrd_len; + } + + if (cmdline != NULL) { + kbuf.buffer = cmdline; + kbuf.bufsz = kbuf.memsz = ALIGN(cmdline_len, 8); + kbuf.buf_align = PAGE_SIZE; + kbuf.top_down = false; + kbuf.buf_min = PAGE0->mem_free + PAGE_SIZE; + kbuf.buf_max = kernel_load_addr; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + ret = kexec_add_buffer(&kbuf); + if (ret) + goto out; + + pr_debug("Loaded cmdline at 0x%lx\n", kbuf.mem); + image->arch.cmdline = kbuf.mem; + } +out: + return NULL; +} + +const struct kexec_file_ops kexec_elf_ops = { + .probe = kexec_elf_probe, + .load = elf_load, +}; + +const struct kexec_file_ops * const kexec_file_loaders[] = { + &kexec_elf_ops, + NULL +}; diff --git a/arch/parisc/kernel/kprobes.c b/arch/parisc/kernel/kprobes.c index 5d7f2692ac5ab87ac93fd9f43d30cc3b7809d9ca..77ec5181891652afbb1f292e2a1e95c058a0afdc 100644 --- a/arch/parisc/kernel/kprobes.c +++ b/arch/parisc/kernel/kprobes.c @@ -281,10 +281,6 @@ int __kprobes arch_trampoline_kprobe(struct kprobe *p) { return p->addr == trampoline_p.addr; } -bool arch_kprobe_on_func_entry(unsigned long offset) -{ - return !offset; -} int __init arch_init_kprobes(void) { diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index df46b0e5a915fab2cbde7049ad4e4d9e602462fe..fa092ed1e837be43e3c0ee93b27bd67b968d6dd3 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -174,6 +174,15 @@ fdtdone: 2: bv %r0(%r2) nop + + /* + * When running in qemu, drop whole flush_tlb_all_local function and + * replace by one pdtlbe instruction, for which QEMU will drop all + * local TLB entries. + */ +3: pdtlbe %r0(%sr1,%r0) + bv,n %r0(%r2) + ALTERNATIVE_CODE(flush_tlb_all_local, 2, ALT_COND_RUN_ON_QEMU, 3b) ENDPROC_CFI(flush_tlb_all_local) .import cache_info,data diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c index e8a6a751dfd8eec60f337035d36feef0afe0007f..8ed409ecec9335e186a5d2684e3e10ad79facba4 100644 --- a/arch/parisc/kernel/parisc_ksyms.c +++ b/arch/parisc/kernel/parisc_ksyms.c @@ -17,6 +17,10 @@ #include EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strcpy); +EXPORT_SYMBOL(strncpy); +EXPORT_SYMBOL(strcat); #include EXPORT_SYMBOL(__xchg8); diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c index bc41ca243cfece3f7b9e57e5d8f449ad3a9c28ac..cf285b17a5aee2f44bde1a4b8a96282579306130 100644 --- a/arch/parisc/kernel/pci.c +++ b/arch/parisc/kernel/pci.c @@ -34,17 +34,6 @@ #define DBG_RES(x...) #endif -/* To be used as: mdelay(pci_post_reset_delay); - * - * post_reset is the time the kernel should stall to prevent anyone from - * accessing the PCI bus once #RESET is de-asserted. - * PCI spec somewhere says 1 second but with multi-PCI bus systems, - * this makes the boot time much longer than necessary. - * 20ms seems to work for all the HP PCI implementations to date. - * - * #define pci_post_reset_delay 50 - */ - struct pci_port_ops *pci_port __ro_after_init; struct pci_bios_ops *pci_bios __ro_after_init; diff --git a/arch/parisc/kernel/relocate_kernel.S b/arch/parisc/kernel/relocate_kernel.S new file mode 100644 index 0000000000000000000000000000000000000000..2561e52b8d9bc8f47f00b88600fa3e884c590d9f --- /dev/null +++ b/arch/parisc/kernel/relocate_kernel.S @@ -0,0 +1,149 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include +#include + +#include +#include +#include +#include +#include + +.level PA_ASM_LEVEL + +.macro kexec_param name +.align 8 +ENTRY(kexec\()_\name) +#ifdef CONFIG_64BIT + .dword 0 +#else + .word 0 +#endif + +ENTRY(kexec\()_\name\()_offset) + .word kexec\()_\name - relocate_new_kernel +.endm + +.text + +/* args: + * r26 - kimage->head + * r25 - start address of kernel + * r24 - physical address of relocate code + */ + +ENTRY_CFI(relocate_new_kernel) +0: copy %arg1, %rp + /* disable I and Q bit, so we are allowed to execute RFI */ + rsm PSW_SM_I, %r0 + nop + nop + nop + nop + nop + nop + nop + + rsm PSW_SM_Q, %r0 + nop + nop + nop + nop + nop + nop + nop + + /* + * After return-from-interrupt, we want to run without Code/Data + * translation enabled just like on a normal boot. + */ + + /* calculate new physical execution address */ + ldo 1f-0b(%arg2), %r1 + mtctl %r0, %cr17 /* IIASQ */ + mtctl %r0, %cr17 /* IIASQ */ + mtctl %r1, %cr18 /* IIAOQ */ + ldo 4(%r1),%r1 + mtctl %r1, %cr18 /* IIAOQ */ +#ifdef CONFIG_64BIT + depdi,z 1, PSW_W_BIT, 1, %r1 + mtctl %r1, %cr22 /* IPSW */ +#else + mtctl %r0, %cr22 /* IPSW */ +#endif + /* lets go... */ + rfi +1: nop + nop + +.Lloop: + LDREG,ma REG_SZ(%arg0), %r3 + /* If crash kernel, no copy needed */ + cmpib,COND(=),n 0,%r3,boot + + bb,<,n %r3, 31 - IND_DONE_BIT, boot + bb,>=,n %r3, 31 - IND_INDIRECTION_BIT, .Lnotind + /* indirection, load and restart */ + movb %r3, %arg0, .Lloop + depi 0, 31, PAGE_SHIFT, %arg0 + +.Lnotind: + bb,>=,n %r3, 31 - IND_DESTINATION_BIT, .Lnotdest + b .Lloop + copy %r3, %r20 + +.Lnotdest: + bb,>= %r3, 31 - IND_SOURCE_BIT, .Lloop + depi 0, 31, PAGE_SHIFT, %r3 + copy %r3, %r21 + + /* copy page */ + copy %r0, %r18 + zdepi 1, 31 - PAGE_SHIFT, 1, %r18 + add %r20, %r18, %r17 + + depi 0, 31, PAGE_SHIFT, %r20 +.Lcopy: + copy %r20, %r12 + LDREG,ma REG_SZ(%r21), %r8 + LDREG,ma REG_SZ(%r21), %r9 + LDREG,ma REG_SZ(%r21), %r10 + LDREG,ma REG_SZ(%r21), %r11 + STREG,ma %r8, REG_SZ(%r20) + STREG,ma %r9, REG_SZ(%r20) + STREG,ma %r10, REG_SZ(%r20) + STREG,ma %r11, REG_SZ(%r20) + +#ifndef CONFIG_64BIT + LDREG,ma REG_SZ(%r21), %r8 + LDREG,ma REG_SZ(%r21), %r9 + LDREG,ma REG_SZ(%r21), %r10 + LDREG,ma REG_SZ(%r21), %r11 + STREG,ma %r8, REG_SZ(%r20) + STREG,ma %r9, REG_SZ(%r20) + STREG,ma %r10, REG_SZ(%r20) + STREG,ma %r11, REG_SZ(%r20) +#endif + + fdc %r0(%r12) + cmpb,COND(<<) %r20,%r17,.Lcopy + fic (%sr4, %r12) + b,n .Lloop + +boot: + mtctl %r0, %cr15 + + LDREG kexec_free_mem-0b(%arg2), %arg0 + LDREG kexec_cmdline-0b(%arg2), %arg1 + LDREG kexec_initrd_end-0b(%arg2), %arg3 + LDREG kexec_initrd_start-0b(%arg2), %arg2 + bv,n %r0(%rp) + +ENDPROC_CFI(relocate_new_kernel); + +ENTRY(relocate_new_kernel_size) + .word relocate_new_kernel_size - relocate_new_kernel + +kexec_param cmdline +kexec_param initrd_start +kexec_param initrd_end +kexec_param free_mem diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index cbd074ba22dad3b9b84e5dbbf56d463121b7ff2a..e202c37e56af3d86db550f742bdd80622db46dbb 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -109,6 +109,7 @@ halt_processor(void) /* REVISIT : does PM *know* this CPU isn't available? */ set_cpu_online(smp_processor_id(), false); local_irq_disable(); + __pdc_cpu_rendezvous(); for (;;) ; } diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl index 670d1371aca1727e765f4c493edc00ea32cd1c1d..285ff516150cf41670aede1f1abf94464230dd55 100644 --- a/arch/parisc/kernel/syscalls/syscall.tbl +++ b/arch/parisc/kernel/syscalls/syscall.tbl @@ -399,7 +399,8 @@ 352 common pkey_alloc sys_pkey_alloc 353 common pkey_free sys_pkey_free 354 common rseq sys_rseq -# 355 through 402 are unassigned to sync up with generic numbers +355 common kexec_file_load sys_kexec_file_load sys_kexec_file_load +# up to 402 is unassigned and reserved for arch specific syscalls 403 32 clock_gettime64 sys_clock_gettime sys_clock_gettime 404 32 clock_settime64 sys_clock_settime sys_clock_settime 405 32 clock_adjtime64 sys_clock_adjtime sys_clock_adjtime diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index 58dcf445e32f6a41ae65c2c7f02cad7cbcba25f5..82fc011894889856e52423c1e37fb813d1fd6891 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -414,6 +415,7 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o { static DEFINE_SPINLOCK(terminate_lock); + (void)notify_die(DIE_OOPS, msg, regs, 0, code, SIGTRAP); bust_spinlocks(1); set_eiem(0); diff --git a/arch/parisc/lib/Makefile b/arch/parisc/lib/Makefile index 7b197667faf6cda53fa8ccafdd0e3ebddf3c22f3..2d7a9974dbaef3cdd84be3daf739589f18f8376a 100644 --- a/arch/parisc/lib/Makefile +++ b/arch/parisc/lib/Makefile @@ -3,7 +3,7 @@ # Makefile for parisc-specific library files # -lib-y := lusercopy.o bitops.o checksum.o io.o memset.o memcpy.o \ - ucmpdi2.o delay.o +lib-y := lusercopy.o bitops.o checksum.o io.o memcpy.o \ + ucmpdi2.o delay.o string.o obj-y := iomap.o diff --git a/arch/parisc/lib/memset.c b/arch/parisc/lib/memset.c deleted file mode 100644 index 1d7929bd7642be5d874bab5ad45d988442acc0ec..0000000000000000000000000000000000000000 --- a/arch/parisc/lib/memset.c +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright (C) 1991, 1997 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -/* Slight modifications for pa-risc linux - Paul Bame */ - -#include -#include - -#define OPSIZ (BITS_PER_LONG/8) -typedef unsigned long op_t; - -void * -memset (void *dstpp, int sc, size_t len) -{ - unsigned int c = sc; - long int dstp = (long int) dstpp; - - if (len >= 8) - { - size_t xlen; - op_t cccc; - - cccc = (unsigned char) c; - cccc |= cccc << 8; - cccc |= cccc << 16; - if (OPSIZ > 4) - /* Do the shift in two steps to avoid warning if long has 32 bits. */ - cccc |= (cccc << 16) << 16; - - /* There are at least some bytes to set. - No need to test for LEN == 0 in this alignment loop. */ - while (dstp % OPSIZ != 0) - { - ((unsigned char *) dstp)[0] = c; - dstp += 1; - len -= 1; - } - - /* Write 8 `op_t' per iteration until less than 8 `op_t' remain. */ - xlen = len / (OPSIZ * 8); - while (xlen > 0) - { - ((op_t *) dstp)[0] = cccc; - ((op_t *) dstp)[1] = cccc; - ((op_t *) dstp)[2] = cccc; - ((op_t *) dstp)[3] = cccc; - ((op_t *) dstp)[4] = cccc; - ((op_t *) dstp)[5] = cccc; - ((op_t *) dstp)[6] = cccc; - ((op_t *) dstp)[7] = cccc; - dstp += 8 * OPSIZ; - xlen -= 1; - } - len %= OPSIZ * 8; - - /* Write 1 `op_t' per iteration until less than OPSIZ bytes remain. */ - xlen = len / OPSIZ; - while (xlen > 0) - { - ((op_t *) dstp)[0] = cccc; - dstp += OPSIZ; - xlen -= 1; - } - len %= OPSIZ; - } - - /* Write the last few bytes. */ - while (len > 0) - { - ((unsigned char *) dstp)[0] = c; - dstp += 1; - len -= 1; - } - - return dstpp; -} diff --git a/arch/parisc/lib/string.S b/arch/parisc/lib/string.S new file mode 100644 index 0000000000000000000000000000000000000000..4a64264427a6369113878cc01346a82b2b6d7156 --- /dev/null +++ b/arch/parisc/lib/string.S @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PA-RISC assembly string functions + * + * Copyright (C) 2019 Helge Deller + */ + +#include +#include + + .section .text.hot + .level PA_ASM_LEVEL + + t0 = r20 + t1 = r21 + t2 = r22 + +ENTRY_CFI(strlen, frame=0,no_calls) + or,COND(<>) arg0,r0,ret0 + b,l,n .Lstrlen_null_ptr,r0 + depwi 0,31,2,ret0 + cmpb,COND(<>) arg0,ret0,.Lstrlen_not_aligned + ldw,ma 4(ret0),t0 + cmpib,tr 0,r0,.Lstrlen_loop + uxor,nbz r0,t0,r0 +.Lstrlen_not_aligned: + uaddcm arg0,ret0,t1 + shladd t1,3,r0,t1 + mtsar t1 + depwi -1,%sar,32,t0 + uxor,nbz r0,t0,r0 +.Lstrlen_loop: + b,l,n .Lstrlen_end_loop,r0 + ldw,ma 4(ret0),t0 + cmpib,tr 0,r0,.Lstrlen_loop + uxor,nbz r0,t0,r0 +.Lstrlen_end_loop: + extrw,u,<> t0,7,8,r0 + addib,tr,n -3,ret0,.Lstrlen_out + extrw,u,<> t0,15,8,r0 + addib,tr,n -2,ret0,.Lstrlen_out + extrw,u,<> t0,23,8,r0 + addi -1,ret0,ret0 +.Lstrlen_out: + bv r0(rp) + uaddcm ret0,arg0,ret0 +.Lstrlen_null_ptr: + bv,n r0(rp) +ENDPROC_CFI(strlen) + + +ENTRY_CFI(strcpy, frame=0,no_calls) + ldb 0(arg1),t0 + stb t0,0(arg0) + ldo 0(arg0),ret0 + ldo 1(arg1),t1 + cmpb,= r0,t0,2f + ldo 1(arg0),t2 +1: ldb 0(t1),arg1 + stb arg1,0(t2) + ldo 1(t1),t1 + cmpb,<> r0,arg1,1b + ldo 1(t2),t2 +2: bv,n r0(rp) +ENDPROC_CFI(strcpy) + + +ENTRY_CFI(strncpy, frame=0,no_calls) + ldb 0(arg1),t0 + stb t0,0(arg0) + ldo 1(arg1),t1 + ldo 0(arg0),ret0 + cmpb,= r0,t0,2f + ldo 1(arg0),arg1 +1: ldo -1(arg2),arg2 + cmpb,COND(=),n r0,arg2,2f + ldb 0(t1),arg0 + stb arg0,0(arg1) + ldo 1(t1),t1 + cmpb,<> r0,arg0,1b + ldo 1(arg1),arg1 +2: bv,n r0(rp) +ENDPROC_CFI(strncpy) + + +ENTRY_CFI(strcat, frame=0,no_calls) + ldb 0(arg0),t0 + cmpb,= t0,r0,2f + ldo 0(arg0),ret0 + ldo 1(arg0),arg0 +1: ldb 0(arg0),t1 + cmpb,<>,n r0,t1,1b + ldo 1(arg0),arg0 +2: ldb 0(arg1),t2 + stb t2,0(arg0) + ldo 1(arg0),arg0 + ldb 0(arg1),t0 + cmpb,<> r0,t0,2b + ldo 1(arg1),arg1 + bv,n r0(rp) +ENDPROC_CFI(strcat) + + +ENTRY_CFI(memset, frame=0,no_calls) + copy arg0,ret0 + cmpb,COND(=) r0,arg0,4f + copy arg0,t2 + cmpb,COND(=) r0,arg2,4f + ldo -1(arg2),arg3 + subi -1,arg3,t0 + subi 0,t0,t1 + cmpiclr,COND(>=) 0,t1,arg2 + ldo -1(t1),arg2 + extru arg2,31,2,arg0 +2: stb arg1,0(t2) + ldo 1(t2),t2 + addib,>= -1,arg0,2b + ldo -1(arg3),arg3 + cmpiclr,COND(<=) 4,arg2,r0 + b,l,n 4f,r0 +#ifdef CONFIG_64BIT + depd,* r0,63,2,arg2 +#else + depw r0,31,2,arg2 +#endif + ldo 1(t2),t2 +3: stb arg1,-1(t2) + stb arg1,0(t2) + stb arg1,1(t2) + stb arg1,2(t2) + addib,COND(>) -4,arg2,3b + ldo 4(t2),t2 +4: bv,n r0(rp) +ENDPROC_CFI(memset) + + .end diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index d8dcd8820369eb4be85e4493bf325779f3645e5f..891cd23f9c8b054cc6c813bd5fd0e47e510d8f2a 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -511,6 +511,7 @@ config KEXEC_FILE select KEXEC_CORE select HAVE_IMA_KEXEC select BUILD_BIN2C + select KEXEC_ELF depends on PPC64 depends on CRYPTO=y depends on CRYPTO_SHA256=y diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index c345b79414a96f07b9abae13eae09735cfa2dcdc..403f7e193833ad4f745b029715913f4f71e60a55 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -39,13 +39,11 @@ endif uname := $(shell uname -m) KBUILD_DEFCONFIG := $(if $(filter ppc%,$(uname)),$(uname),ppc64)_defconfig -ifdef CONFIG_PPC64 new_nm := $(shell if $(NM) --help 2>&1 | grep -- '--synthetic' > /dev/null; then echo y; else echo n; fi) ifeq ($(new_nm),y) NM := $(NM) --synthetic endif -endif # BITS is used as extension for files which are available in a 32 bit # and a 64 bit version to simplify shared Makefiles. diff --git a/arch/powerpc/include/asm/Kbuild b/arch/powerpc/include/asm/Kbuild index 9a1d2fc6ceb7503ab356f277c3b6c09b71b61748..64870c7be4a3f43b392899524b55274ea05012b6 100644 --- a/arch/powerpc/include/asm/Kbuild +++ b/arch/powerpc/include/asm/Kbuild @@ -11,4 +11,3 @@ generic-y += mcs_spinlock.h generic-y += preempt.h generic-y += vtime.h generic-y += msi.h -generic-y += simd.h diff --git a/arch/powerpc/include/asm/error-injection.h b/arch/powerpc/include/asm/error-injection.h deleted file mode 100644 index 62fd247398526b3db6566df6568e80ecd4f54e15..0000000000000000000000000000000000000000 --- a/arch/powerpc/include/asm/error-injection.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ - -#ifndef _ASM_ERROR_INJECTION_H -#define _ASM_ERROR_INJECTION_H - -#include -#include -#include -#include - -void override_function_with_return(struct pt_regs *regs); - -#endif /* _ASM_ERROR_INJECTION_H */ diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h index bb7c8cc77f1ae429ee158289bf118e6f08a8d1d9..04b2b927bb5ae10dab2815fe6cd55e50495847db 100644 --- a/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/arch/powerpc/include/asm/kvm_book3s_64.h @@ -535,7 +535,7 @@ static inline void note_hpte_modification(struct kvm *kvm, */ static inline struct kvm_memslots *kvm_memslots_raw(struct kvm *kvm) { - return rcu_dereference_raw_notrace(kvm->memslots[0]); + return rcu_dereference_raw_check(kvm->memslots[0]); } extern void kvmppc_mmu_debugfs_init(struct kvm *kvm); diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index e6e5f59aaa97919cb615d12990964fdbd3f20134..6fb5fb4779e0dcec8ece9116e2625e6f476d5460 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -232,11 +232,25 @@ struct revmap_entry { }; /* - * We use the top bit of each memslot->arch.rmap entry as a lock bit, - * and bit 32 as a present flag. The bottom 32 bits are the - * index in the guest HPT of a HPTE that points to the page. + * The rmap array of size number of guest pages is allocated for each memslot. + * This array is used to store usage specific information about the guest page. + * Below are the encodings of the various possible usage types. */ -#define KVMPPC_RMAP_LOCK_BIT 63 +/* Free bits which can be used to define a new usage */ +#define KVMPPC_RMAP_TYPE_MASK 0xff00000000000000 +#define KVMPPC_RMAP_NESTED 0xc000000000000000 /* Nested rmap array */ +#define KVMPPC_RMAP_HPT 0x0100000000000000 /* HPT guest */ + +/* + * rmap usage definition for a hash page table (hpt) guest: + * 0x0000080000000000 Lock bit + * 0x0000018000000000 RC bits + * 0x0000000100000000 Present bit + * 0x00000000ffffffff HPT index bits + * The bottom 32 bits are the index in the guest HPT of a HPTE that points to + * the page. + */ +#define KVMPPC_RMAP_LOCK_BIT 43 #define KVMPPC_RMAP_RC_SHIFT 32 #define KVMPPC_RMAP_REFERENCED (HPTE_R_R << KVMPPC_RMAP_RC_SHIFT) #define KVMPPC_RMAP_PRESENT 0x100000000ul diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 2484e6a8f5ca7a0fce8fb6a866e0b27984eb6b42..8e8514efb124394813e2a6ef09505f6491e86d76 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -598,6 +598,7 @@ extern int kvmppc_xive_native_get_vp(struct kvm_vcpu *vcpu, union kvmppc_one_reg *val); extern int kvmppc_xive_native_set_vp(struct kvm_vcpu *vcpu, union kvmppc_one_reg *val); +extern bool kvmppc_xive_native_supported(void); #else static inline int kvmppc_xive_set_xive(struct kvm *kvm, u32 irq, u32 server, diff --git a/arch/powerpc/include/asm/xive.h b/arch/powerpc/include/asm/xive.h index e4016985764ed03deaab693668c15d371fac81b7..818989e1167892f379cf2b4db16631dbb1ecf7aa 100644 --- a/arch/powerpc/include/asm/xive.h +++ b/arch/powerpc/include/asm/xive.h @@ -46,7 +46,15 @@ struct xive_irq_data { /* Setup/used by frontend */ int target; + /* + * saved_p means that there is a queue entry for this interrupt + * in some CPU's queue (not including guest vcpu queues), even + * if P is not set in the source ESB. + * stale_p means that there is no queue entry for this interrupt + * in some CPU's queue, even if P is set in the source ESB. + */ bool saved_p; + bool stale_p; }; #define XIVE_IRQ_FLAG_STORE_EOI 0x01 #define XIVE_IRQ_FLAG_LSI 0x02 @@ -127,6 +135,7 @@ extern int xive_native_get_queue_state(u32 vp_id, uint32_t prio, u32 *qtoggle, extern int xive_native_set_queue_state(u32 vp_id, uint32_t prio, u32 qtoggle, u32 qindex); extern int xive_native_get_vp_state(u32 vp_id, u64 *out_state); +extern bool xive_native_has_queue_state_support(void); #else diff --git a/arch/powerpc/kernel/kexec_elf_64.c b/arch/powerpc/kernel/kexec_elf_64.c index 83cf7b852876303fbbd14a2c93102221c8dc43f6..3072fd6dbe94a6349de451cd5f1501bd41d949ba 100644 --- a/arch/powerpc/kernel/kexec_elf_64.c +++ b/arch/powerpc/kernel/kexec_elf_64.c @@ -23,541 +23,6 @@ #include #include -#define PURGATORY_STACK_SIZE (16 * 1024) - -#define elf_addr_to_cpu elf64_to_cpu - -#ifndef Elf_Rel -#define Elf_Rel Elf64_Rel -#endif /* Elf_Rel */ - -struct elf_info { - /* - * Where the ELF binary contents are kept. - * Memory managed by the user of the struct. - */ - const char *buffer; - - const struct elfhdr *ehdr; - const struct elf_phdr *proghdrs; - struct elf_shdr *sechdrs; -}; - -static inline bool elf_is_elf_file(const struct elfhdr *ehdr) -{ - return memcmp(ehdr->e_ident, ELFMAG, SELFMAG) == 0; -} - -static uint64_t elf64_to_cpu(const struct elfhdr *ehdr, uint64_t value) -{ - if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) - value = le64_to_cpu(value); - else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) - value = be64_to_cpu(value); - - return value; -} - -static uint16_t elf16_to_cpu(const struct elfhdr *ehdr, uint16_t value) -{ - if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) - value = le16_to_cpu(value); - else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) - value = be16_to_cpu(value); - - return value; -} - -static uint32_t elf32_to_cpu(const struct elfhdr *ehdr, uint32_t value) -{ - if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) - value = le32_to_cpu(value); - else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) - value = be32_to_cpu(value); - - return value; -} - -/** - * elf_is_ehdr_sane - check that it is safe to use the ELF header - * @buf_len: size of the buffer in which the ELF file is loaded. - */ -static bool elf_is_ehdr_sane(const struct elfhdr *ehdr, size_t buf_len) -{ - if (ehdr->e_phnum > 0 && ehdr->e_phentsize != sizeof(struct elf_phdr)) { - pr_debug("Bad program header size.\n"); - return false; - } else if (ehdr->e_shnum > 0 && - ehdr->e_shentsize != sizeof(struct elf_shdr)) { - pr_debug("Bad section header size.\n"); - return false; - } else if (ehdr->e_ident[EI_VERSION] != EV_CURRENT || - ehdr->e_version != EV_CURRENT) { - pr_debug("Unknown ELF version.\n"); - return false; - } - - if (ehdr->e_phoff > 0 && ehdr->e_phnum > 0) { - size_t phdr_size; - - /* - * e_phnum is at most 65535 so calculating the size of the - * program header cannot overflow. - */ - phdr_size = sizeof(struct elf_phdr) * ehdr->e_phnum; - - /* Sanity check the program header table location. */ - if (ehdr->e_phoff + phdr_size < ehdr->e_phoff) { - pr_debug("Program headers at invalid location.\n"); - return false; - } else if (ehdr->e_phoff + phdr_size > buf_len) { - pr_debug("Program headers truncated.\n"); - return false; - } - } - - if (ehdr->e_shoff > 0 && ehdr->e_shnum > 0) { - size_t shdr_size; - - /* - * e_shnum is at most 65536 so calculating - * the size of the section header cannot overflow. - */ - shdr_size = sizeof(struct elf_shdr) * ehdr->e_shnum; - - /* Sanity check the section header table location. */ - if (ehdr->e_shoff + shdr_size < ehdr->e_shoff) { - pr_debug("Section headers at invalid location.\n"); - return false; - } else if (ehdr->e_shoff + shdr_size > buf_len) { - pr_debug("Section headers truncated.\n"); - return false; - } - } - - return true; -} - -static int elf_read_ehdr(const char *buf, size_t len, struct elfhdr *ehdr) -{ - struct elfhdr *buf_ehdr; - - if (len < sizeof(*buf_ehdr)) { - pr_debug("Buffer is too small to hold ELF header.\n"); - return -ENOEXEC; - } - - memset(ehdr, 0, sizeof(*ehdr)); - memcpy(ehdr->e_ident, buf, sizeof(ehdr->e_ident)); - if (!elf_is_elf_file(ehdr)) { - pr_debug("No ELF header magic.\n"); - return -ENOEXEC; - } - - if (ehdr->e_ident[EI_CLASS] != ELF_CLASS) { - pr_debug("Not a supported ELF class.\n"); - return -ENOEXEC; - } else if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB && - ehdr->e_ident[EI_DATA] != ELFDATA2MSB) { - pr_debug("Not a supported ELF data format.\n"); - return -ENOEXEC; - } - - buf_ehdr = (struct elfhdr *) buf; - if (elf16_to_cpu(ehdr, buf_ehdr->e_ehsize) != sizeof(*buf_ehdr)) { - pr_debug("Bad ELF header size.\n"); - return -ENOEXEC; - } - - ehdr->e_type = elf16_to_cpu(ehdr, buf_ehdr->e_type); - ehdr->e_machine = elf16_to_cpu(ehdr, buf_ehdr->e_machine); - ehdr->e_version = elf32_to_cpu(ehdr, buf_ehdr->e_version); - ehdr->e_entry = elf_addr_to_cpu(ehdr, buf_ehdr->e_entry); - ehdr->e_phoff = elf_addr_to_cpu(ehdr, buf_ehdr->e_phoff); - ehdr->e_shoff = elf_addr_to_cpu(ehdr, buf_ehdr->e_shoff); - ehdr->e_flags = elf32_to_cpu(ehdr, buf_ehdr->e_flags); - ehdr->e_phentsize = elf16_to_cpu(ehdr, buf_ehdr->e_phentsize); - ehdr->e_phnum = elf16_to_cpu(ehdr, buf_ehdr->e_phnum); - ehdr->e_shentsize = elf16_to_cpu(ehdr, buf_ehdr->e_shentsize); - ehdr->e_shnum = elf16_to_cpu(ehdr, buf_ehdr->e_shnum); - ehdr->e_shstrndx = elf16_to_cpu(ehdr, buf_ehdr->e_shstrndx); - - return elf_is_ehdr_sane(ehdr, len) ? 0 : -ENOEXEC; -} - -/** - * elf_is_phdr_sane - check that it is safe to use the program header - * @buf_len: size of the buffer in which the ELF file is loaded. - */ -static bool elf_is_phdr_sane(const struct elf_phdr *phdr, size_t buf_len) -{ - - if (phdr->p_offset + phdr->p_filesz < phdr->p_offset) { - pr_debug("ELF segment location wraps around.\n"); - return false; - } else if (phdr->p_offset + phdr->p_filesz > buf_len) { - pr_debug("ELF segment not in file.\n"); - return false; - } else if (phdr->p_paddr + phdr->p_memsz < phdr->p_paddr) { - pr_debug("ELF segment address wraps around.\n"); - return false; - } - - return true; -} - -static int elf_read_phdr(const char *buf, size_t len, struct elf_info *elf_info, - int idx) -{ - /* Override the const in proghdrs, we are the ones doing the loading. */ - struct elf_phdr *phdr = (struct elf_phdr *) &elf_info->proghdrs[idx]; - const char *pbuf; - struct elf_phdr *buf_phdr; - - pbuf = buf + elf_info->ehdr->e_phoff + (idx * sizeof(*buf_phdr)); - buf_phdr = (struct elf_phdr *) pbuf; - - phdr->p_type = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_type); - phdr->p_offset = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_offset); - phdr->p_paddr = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_paddr); - phdr->p_vaddr = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_vaddr); - phdr->p_flags = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_flags); - - /* - * The following fields have a type equivalent to Elf_Addr - * both in 32 bit and 64 bit ELF. - */ - phdr->p_filesz = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_filesz); - phdr->p_memsz = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_memsz); - phdr->p_align = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_align); - - return elf_is_phdr_sane(phdr, len) ? 0 : -ENOEXEC; -} - -/** - * elf_read_phdrs - read the program headers from the buffer - * - * This function assumes that the program header table was checked for sanity. - * Use elf_is_ehdr_sane() if it wasn't. - */ -static int elf_read_phdrs(const char *buf, size_t len, - struct elf_info *elf_info) -{ - size_t phdr_size, i; - const struct elfhdr *ehdr = elf_info->ehdr; - - /* - * e_phnum is at most 65535 so calculating the size of the - * program header cannot overflow. - */ - phdr_size = sizeof(struct elf_phdr) * ehdr->e_phnum; - - elf_info->proghdrs = kzalloc(phdr_size, GFP_KERNEL); - if (!elf_info->proghdrs) - return -ENOMEM; - - for (i = 0; i < ehdr->e_phnum; i++) { - int ret; - - ret = elf_read_phdr(buf, len, elf_info, i); - if (ret) { - kfree(elf_info->proghdrs); - elf_info->proghdrs = NULL; - return ret; - } - } - - return 0; -} - -/** - * elf_is_shdr_sane - check that it is safe to use the section header - * @buf_len: size of the buffer in which the ELF file is loaded. - */ -static bool elf_is_shdr_sane(const struct elf_shdr *shdr, size_t buf_len) -{ - bool size_ok; - - /* SHT_NULL headers have undefined values, so we can't check them. */ - if (shdr->sh_type == SHT_NULL) - return true; - - /* Now verify sh_entsize */ - switch (shdr->sh_type) { - case SHT_SYMTAB: - size_ok = shdr->sh_entsize == sizeof(Elf_Sym); - break; - case SHT_RELA: - size_ok = shdr->sh_entsize == sizeof(Elf_Rela); - break; - case SHT_DYNAMIC: - size_ok = shdr->sh_entsize == sizeof(Elf_Dyn); - break; - case SHT_REL: - size_ok = shdr->sh_entsize == sizeof(Elf_Rel); - break; - case SHT_NOTE: - case SHT_PROGBITS: - case SHT_HASH: - case SHT_NOBITS: - default: - /* - * This is a section whose entsize requirements - * I don't care about. If I don't know about - * the section I can't care about it's entsize - * requirements. - */ - size_ok = true; - break; - } - - if (!size_ok) { - pr_debug("ELF section with wrong entry size.\n"); - return false; - } else if (shdr->sh_addr + shdr->sh_size < shdr->sh_addr) { - pr_debug("ELF section address wraps around.\n"); - return false; - } - - if (shdr->sh_type != SHT_NOBITS) { - if (shdr->sh_offset + shdr->sh_size < shdr->sh_offset) { - pr_debug("ELF section location wraps around.\n"); - return false; - } else if (shdr->sh_offset + shdr->sh_size > buf_len) { - pr_debug("ELF section not in file.\n"); - return false; - } - } - - return true; -} - -static int elf_read_shdr(const char *buf, size_t len, struct elf_info *elf_info, - int idx) -{ - struct elf_shdr *shdr = &elf_info->sechdrs[idx]; - const struct elfhdr *ehdr = elf_info->ehdr; - const char *sbuf; - struct elf_shdr *buf_shdr; - - sbuf = buf + ehdr->e_shoff + idx * sizeof(*buf_shdr); - buf_shdr = (struct elf_shdr *) sbuf; - - shdr->sh_name = elf32_to_cpu(ehdr, buf_shdr->sh_name); - shdr->sh_type = elf32_to_cpu(ehdr, buf_shdr->sh_type); - shdr->sh_addr = elf_addr_to_cpu(ehdr, buf_shdr->sh_addr); - shdr->sh_offset = elf_addr_to_cpu(ehdr, buf_shdr->sh_offset); - shdr->sh_link = elf32_to_cpu(ehdr, buf_shdr->sh_link); - shdr->sh_info = elf32_to_cpu(ehdr, buf_shdr->sh_info); - - /* - * The following fields have a type equivalent to Elf_Addr - * both in 32 bit and 64 bit ELF. - */ - shdr->sh_flags = elf_addr_to_cpu(ehdr, buf_shdr->sh_flags); - shdr->sh_size = elf_addr_to_cpu(ehdr, buf_shdr->sh_size); - shdr->sh_addralign = elf_addr_to_cpu(ehdr, buf_shdr->sh_addralign); - shdr->sh_entsize = elf_addr_to_cpu(ehdr, buf_shdr->sh_entsize); - - return elf_is_shdr_sane(shdr, len) ? 0 : -ENOEXEC; -} - -/** - * elf_read_shdrs - read the section headers from the buffer - * - * This function assumes that the section header table was checked for sanity. - * Use elf_is_ehdr_sane() if it wasn't. - */ -static int elf_read_shdrs(const char *buf, size_t len, - struct elf_info *elf_info) -{ - size_t shdr_size, i; - - /* - * e_shnum is at most 65536 so calculating - * the size of the section header cannot overflow. - */ - shdr_size = sizeof(struct elf_shdr) * elf_info->ehdr->e_shnum; - - elf_info->sechdrs = kzalloc(shdr_size, GFP_KERNEL); - if (!elf_info->sechdrs) - return -ENOMEM; - - for (i = 0; i < elf_info->ehdr->e_shnum; i++) { - int ret; - - ret = elf_read_shdr(buf, len, elf_info, i); - if (ret) { - kfree(elf_info->sechdrs); - elf_info->sechdrs = NULL; - return ret; - } - } - - return 0; -} - -/** - * elf_read_from_buffer - read ELF file and sets up ELF header and ELF info - * @buf: Buffer to read ELF file from. - * @len: Size of @buf. - * @ehdr: Pointer to existing struct which will be populated. - * @elf_info: Pointer to existing struct which will be populated. - * - * This function allows reading ELF files with different byte order than - * the kernel, byte-swapping the fields as needed. - * - * Return: - * On success returns 0, and the caller should call elf_free_info(elf_info) to - * free the memory allocated for the section and program headers. - */ -int elf_read_from_buffer(const char *buf, size_t len, struct elfhdr *ehdr, - struct elf_info *elf_info) -{ - int ret; - - ret = elf_read_ehdr(buf, len, ehdr); - if (ret) - return ret; - - elf_info->buffer = buf; - elf_info->ehdr = ehdr; - if (ehdr->e_phoff > 0 && ehdr->e_phnum > 0) { - ret = elf_read_phdrs(buf, len, elf_info); - if (ret) - return ret; - } - if (ehdr->e_shoff > 0 && ehdr->e_shnum > 0) { - ret = elf_read_shdrs(buf, len, elf_info); - if (ret) { - kfree(elf_info->proghdrs); - return ret; - } - } - - return 0; -} - -/** - * elf_free_info - free memory allocated by elf_read_from_buffer - */ -void elf_free_info(struct elf_info *elf_info) -{ - kfree(elf_info->proghdrs); - kfree(elf_info->sechdrs); - memset(elf_info, 0, sizeof(*elf_info)); -} -/** - * build_elf_exec_info - read ELF executable and check that we can use it - */ -static int build_elf_exec_info(const char *buf, size_t len, struct elfhdr *ehdr, - struct elf_info *elf_info) -{ - int i; - int ret; - - ret = elf_read_from_buffer(buf, len, ehdr, elf_info); - if (ret) - return ret; - - /* Big endian vmlinux has type ET_DYN. */ - if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) { - pr_err("Not an ELF executable.\n"); - goto error; - } else if (!elf_info->proghdrs) { - pr_err("No ELF program header.\n"); - goto error; - } - - for (i = 0; i < ehdr->e_phnum; i++) { - /* - * Kexec does not support loading interpreters. - * In addition this check keeps us from attempting - * to kexec ordinay executables. - */ - if (elf_info->proghdrs[i].p_type == PT_INTERP) { - pr_err("Requires an ELF interpreter.\n"); - goto error; - } - } - - return 0; -error: - elf_free_info(elf_info); - return -ENOEXEC; -} - -static int elf64_probe(const char *buf, unsigned long len) -{ - struct elfhdr ehdr; - struct elf_info elf_info; - int ret; - - ret = build_elf_exec_info(buf, len, &ehdr, &elf_info); - if (ret) - return ret; - - elf_free_info(&elf_info); - - return elf_check_arch(&ehdr) ? 0 : -ENOEXEC; -} - -/** - * elf_exec_load - load ELF executable image - * @lowest_load_addr: On return, will be the address where the first PT_LOAD - * section will be loaded in memory. - * - * Return: - * 0 on success, negative value on failure. - */ -static int elf_exec_load(struct kimage *image, struct elfhdr *ehdr, - struct elf_info *elf_info, - unsigned long *lowest_load_addr) -{ - unsigned long base = 0, lowest_addr = UINT_MAX; - int ret; - size_t i; - struct kexec_buf kbuf = { .image = image, .buf_max = ppc64_rma_size, - .top_down = false }; - - /* Read in the PT_LOAD segments. */ - for (i = 0; i < ehdr->e_phnum; i++) { - unsigned long load_addr; - size_t size; - const struct elf_phdr *phdr; - - phdr = &elf_info->proghdrs[i]; - if (phdr->p_type != PT_LOAD) - continue; - - size = phdr->p_filesz; - if (size > phdr->p_memsz) - size = phdr->p_memsz; - - kbuf.buffer = (void *) elf_info->buffer + phdr->p_offset; - kbuf.bufsz = size; - kbuf.memsz = phdr->p_memsz; - kbuf.buf_align = phdr->p_align; - kbuf.buf_min = phdr->p_paddr + base; - kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; - ret = kexec_add_buffer(&kbuf); - if (ret) - goto out; - load_addr = kbuf.mem; - - if (load_addr < lowest_addr) - lowest_addr = load_addr; - } - - /* Update entry point to reflect new load address. */ - ehdr->e_entry += base; - - *lowest_load_addr = lowest_addr; - ret = 0; - out: - return ret; -} - static void *elf64_load(struct kimage *image, char *kernel_buf, unsigned long kernel_len, char *initrd, unsigned long initrd_len, char *cmdline, @@ -570,18 +35,18 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, void *fdt; const void *slave_code; struct elfhdr ehdr; - struct elf_info elf_info; + struct kexec_elf_info elf_info; struct kexec_buf kbuf = { .image = image, .buf_min = 0, .buf_max = ppc64_rma_size }; struct kexec_buf pbuf = { .image = image, .buf_min = 0, .buf_max = ppc64_rma_size, .top_down = true, .mem = KEXEC_BUF_MEM_UNKNOWN }; - ret = build_elf_exec_info(kernel_buf, kernel_len, &ehdr, &elf_info); + ret = kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info); if (ret) goto out; - ret = elf_exec_load(image, &ehdr, &elf_info, &kernel_load_addr); + ret = kexec_elf_load(image, &ehdr, &elf_info, &kbuf, &kernel_load_addr); if (ret) goto out; @@ -648,13 +113,13 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, pr_err("Error setting up the purgatory.\n"); out: - elf_free_info(&elf_info); + kexec_free_elf_info(&elf_info); /* Make kimage_file_post_load_cleanup free the fdt buffer for us. */ return ret ? ERR_PTR(ret) : fdt; } const struct kexec_file_ops kexec_elf64_ops = { - .probe = elf64_probe, + .probe = kexec_elf_probe, .load = elf64_load, }; diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 1f8db666468d74e10ccae52465af11bb2aba9dc1..5e6543aba1b32879e18cab1a4e6d1d45277c4ba5 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -778,12 +778,6 @@ void ppc_printk_progress(char *s, unsigned short hex) pr_info("%s\n", s); } -void arch_setup_pdev_archdata(struct platform_device *pdev) -{ - pdev->archdata.dma_mask = DMA_BIT_MASK(32); - pdev->dev.dma_mask = &pdev->archdata.dma_mask; -} - static __init void print_system_info(void) { pr_info("-----------------------------------------------------\n"); diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 9524d92bc45d69934944ab1b36236a32da72d382..d7fcdfa7fee40833a2b3d8fb586d6fa13fa34b3e 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -1083,9 +1083,11 @@ static int kvmppc_book3s_init(void) if (xics_on_xive()) { kvmppc_xive_init_module(); kvm_register_device_ops(&kvm_xive_ops, KVM_DEV_TYPE_XICS); - kvmppc_xive_native_init_module(); - kvm_register_device_ops(&kvm_xive_native_ops, - KVM_DEV_TYPE_XIVE); + if (kvmppc_xive_native_supported()) { + kvmppc_xive_native_init_module(); + kvm_register_device_ops(&kvm_xive_native_ops, + KVM_DEV_TYPE_XIVE); + } } else #endif kvm_register_device_ops(&kvm_xics_ops, KVM_DEV_TYPE_XICS); diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index cde3f5a4b3e4709fe06a0eb27628a3fd537e30b9..f8975c620f41c43758bb71c1d85cdb7b75150eff 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -1678,7 +1678,14 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, *val = get_reg_val(id, vcpu->arch.pspb); break; case KVM_REG_PPC_DPDES: - *val = get_reg_val(id, vcpu->arch.vcore->dpdes); + /* + * On POWER9, where we are emulating msgsndp etc., + * we return 1 bit for each vcpu, which can come from + * either vcore->dpdes or doorbell_request. + * On POWER8, doorbell_request is 0. + */ + *val = get_reg_val(id, vcpu->arch.vcore->dpdes | + vcpu->arch.doorbell_request); break; case KVM_REG_PPC_VTB: *val = get_reg_val(id, vcpu->arch.vcore->vtb); @@ -2860,7 +2867,7 @@ static void collect_piggybacks(struct core_info *cip, int target_threads) if (!spin_trylock(&pvc->lock)) continue; prepare_threads(pvc); - if (!pvc->n_runnable) { + if (!pvc->n_runnable || !pvc->kvm->arch.mmu_ready) { list_del_init(&pvc->preempt_list); if (pvc->runner == NULL) { pvc->vcore_state = VCORE_INACTIVE; @@ -2881,15 +2888,20 @@ static void collect_piggybacks(struct core_info *cip, int target_threads) spin_unlock(&lp->lock); } -static bool recheck_signals(struct core_info *cip) +static bool recheck_signals_and_mmu(struct core_info *cip) { int sub, i; struct kvm_vcpu *vcpu; + struct kvmppc_vcore *vc; - for (sub = 0; sub < cip->n_subcores; ++sub) - for_each_runnable_thread(i, vcpu, cip->vc[sub]) + for (sub = 0; sub < cip->n_subcores; ++sub) { + vc = cip->vc[sub]; + if (!vc->kvm->arch.mmu_ready) + return true; + for_each_runnable_thread(i, vcpu, vc) if (signal_pending(vcpu->arch.run_task)) return true; + } return false; } @@ -3119,7 +3131,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) local_irq_disable(); hard_irq_disable(); if (lazy_irq_pending() || need_resched() || - recheck_signals(&core_info) || !vc->kvm->arch.mmu_ready) { + recheck_signals_and_mmu(&core_info)) { local_irq_enable(); vc->vcore_state = VCORE_INACTIVE; /* Unlock all except the primary vcore */ diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c index 63e0ce91e29d34f9e14c711962584e081be95025..7186c65c61c9445608ab1e36bd8efde28382fc8b 100644 --- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c +++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c @@ -99,7 +99,7 @@ void kvmppc_add_revmap_chain(struct kvm *kvm, struct revmap_entry *rev, } else { rev->forw = rev->back = pte_index; *rmap = (*rmap & ~KVMPPC_RMAP_INDEX) | - pte_index | KVMPPC_RMAP_PRESENT; + pte_index | KVMPPC_RMAP_PRESENT | KVMPPC_RMAP_HPT; } unlock_rmap(rmap); } diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 337e64468d78f8a586844699f9199dde332e6529..07181d0dfcb79a0b582d1e8b3af2569955969d0f 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -942,6 +942,8 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_300) ld r11, VCPU_XIVE_SAVED_STATE(r4) li r9, TM_QW1_OS lwz r8, VCPU_XIVE_CAM_WORD(r4) + cmpwi r8, 0 + beq no_xive li r7, TM_QW1_OS + TM_WORD2 mfmsr r0 andi. r0, r0, MSR_DR /* in real mode? */ @@ -2831,29 +2833,39 @@ kvm_cede_prodded: kvm_cede_exit: ld r9, HSTATE_KVM_VCPU(r13) #ifdef CONFIG_KVM_XICS - /* Abort if we still have a pending escalation */ + /* are we using XIVE with single escalation? */ + ld r10, VCPU_XIVE_ESC_VADDR(r9) + cmpdi r10, 0 + beq 3f + li r6, XIVE_ESB_SET_PQ_00 + /* + * If we still have a pending escalation, abort the cede, + * and we must set PQ to 10 rather than 00 so that we don't + * potentially end up with two entries for the escalation + * interrupt in the XIVE interrupt queue. In that case + * we also don't want to set xive_esc_on to 1 here in + * case we race with xive_esc_irq(). + */ lbz r5, VCPU_XIVE_ESC_ON(r9) cmpwi r5, 0 - beq 1f + beq 4f li r0, 0 stb r0, VCPU_CEDED(r9) -1: /* Enable XIVE escalation */ - li r5, XIVE_ESB_SET_PQ_00 + li r6, XIVE_ESB_SET_PQ_10 + b 5f +4: li r0, 1 + stb r0, VCPU_XIVE_ESC_ON(r9) + /* make sure store to xive_esc_on is seen before xive_esc_irq runs */ + sync +5: /* Enable XIVE escalation */ mfmsr r0 andi. r0, r0, MSR_DR /* in real mode? */ beq 1f - ld r10, VCPU_XIVE_ESC_VADDR(r9) - cmpdi r10, 0 - beq 3f - ldx r0, r10, r5 + ldx r0, r10, r6 b 2f 1: ld r10, VCPU_XIVE_ESC_RADDR(r9) - cmpdi r10, 0 - beq 3f - ldcix r0, r10, r5 + ldcix r0, r10, r6 2: sync - li r0, 1 - stb r0, VCPU_XIVE_ESC_ON(r9) #endif /* CONFIG_KVM_XICS */ 3: b guest_exit_cont diff --git a/arch/powerpc/kvm/book3s_xive.c b/arch/powerpc/kvm/book3s_xive.c index e3ba67095895ab35c721b46675a8380fb073e01e..591bfb4bfd0fabb74cb2c81c35ff51acef8f58ba 100644 --- a/arch/powerpc/kvm/book3s_xive.c +++ b/arch/powerpc/kvm/book3s_xive.c @@ -67,8 +67,14 @@ void kvmppc_xive_push_vcpu(struct kvm_vcpu *vcpu) void __iomem *tima = local_paca->kvm_hstate.xive_tima_virt; u64 pq; - if (!tima) + /* + * Nothing to do if the platform doesn't have a XIVE + * or this vCPU doesn't have its own XIVE context + * (e.g. because it's not using an in-kernel interrupt controller). + */ + if (!tima || !vcpu->arch.xive_cam_word) return; + eieio(); __raw_writeq(vcpu->arch.xive_saved_state.w01, tima + TM_QW1_OS); __raw_writel(vcpu->arch.xive_cam_word, tima + TM_QW1_OS + TM_WORD2); @@ -160,6 +166,9 @@ static irqreturn_t xive_esc_irq(int irq, void *data) */ vcpu->arch.xive_esc_on = false; + /* This orders xive_esc_on = false vs. subsequent stale_p = true */ + smp_wmb(); /* goes with smp_mb() in cleanup_single_escalation */ + return IRQ_HANDLED; } @@ -1113,6 +1122,31 @@ void kvmppc_xive_disable_vcpu_interrupts(struct kvm_vcpu *vcpu) vcpu->arch.xive_esc_raddr = 0; } +/* + * In single escalation mode, the escalation interrupt is marked so + * that EOI doesn't re-enable it, but just sets the stale_p flag to + * indicate that the P bit has already been dealt with. However, the + * assembly code that enters the guest sets PQ to 00 without clearing + * stale_p (because it has no easy way to address it). Hence we have + * to adjust stale_p before shutting down the interrupt. + */ +void xive_cleanup_single_escalation(struct kvm_vcpu *vcpu, + struct kvmppc_xive_vcpu *xc, int irq) +{ + struct irq_data *d = irq_get_irq_data(irq); + struct xive_irq_data *xd = irq_data_get_irq_handler_data(d); + + /* + * This slightly odd sequence gives the right result + * (i.e. stale_p set if xive_esc_on is false) even if + * we race with xive_esc_irq() and xive_irq_eoi(). + */ + xd->stale_p = false; + smp_mb(); /* paired with smb_wmb in xive_esc_irq */ + if (!vcpu->arch.xive_esc_on) + xd->stale_p = true; +} + void kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu) { struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu; @@ -1134,20 +1168,28 @@ void kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu) /* Mask the VP IPI */ xive_vm_esb_load(&xc->vp_ipi_data, XIVE_ESB_SET_PQ_01); - /* Disable the VP */ - xive_native_disable_vp(xc->vp_id); - - /* Free the queues & associated interrupts */ + /* Free escalations */ for (i = 0; i < KVMPPC_XIVE_Q_COUNT; i++) { - struct xive_q *q = &xc->queues[i]; - - /* Free the escalation irq */ if (xc->esc_virq[i]) { + if (xc->xive->single_escalation) + xive_cleanup_single_escalation(vcpu, xc, + xc->esc_virq[i]); free_irq(xc->esc_virq[i], vcpu); irq_dispose_mapping(xc->esc_virq[i]); kfree(xc->esc_virq_names[i]); } - /* Free the queue */ + } + + /* Disable the VP */ + xive_native_disable_vp(xc->vp_id); + + /* Clear the cam word so guest entry won't try to push context */ + vcpu->arch.xive_cam_word = 0; + + /* Free the queues */ + for (i = 0; i < KVMPPC_XIVE_Q_COUNT; i++) { + struct xive_q *q = &xc->queues[i]; + xive_native_disable_queue(xc->vp_id, q, i); if (q->qpage) { free_pages((unsigned long)q->qpage, diff --git a/arch/powerpc/kvm/book3s_xive.h b/arch/powerpc/kvm/book3s_xive.h index 50494d0ee375e2b418dd84255ce9c9166647cef0..955b820ffd6da64f7c4471db47b271bbc1e8fafe 100644 --- a/arch/powerpc/kvm/book3s_xive.h +++ b/arch/powerpc/kvm/book3s_xive.h @@ -282,6 +282,8 @@ int kvmppc_xive_select_target(struct kvm *kvm, u32 *server, u8 prio); int kvmppc_xive_attach_escalation(struct kvm_vcpu *vcpu, u8 prio, bool single_escalation); struct kvmppc_xive *kvmppc_xive_get_device(struct kvm *kvm, u32 type); +void xive_cleanup_single_escalation(struct kvm_vcpu *vcpu, + struct kvmppc_xive_vcpu *xc, int irq); #endif /* CONFIG_KVM_XICS */ #endif /* _KVM_PPC_BOOK3S_XICS_H */ diff --git a/arch/powerpc/kvm/book3s_xive_native.c b/arch/powerpc/kvm/book3s_xive_native.c index a998823f68a322cf1b9400d9f2b7efdf916e92b6..248c1ea9e7881f2ebfc09f2149f5f7a4158ee413 100644 --- a/arch/powerpc/kvm/book3s_xive_native.c +++ b/arch/powerpc/kvm/book3s_xive_native.c @@ -67,20 +67,28 @@ void kvmppc_xive_native_cleanup_vcpu(struct kvm_vcpu *vcpu) xc->valid = false; kvmppc_xive_disable_vcpu_interrupts(vcpu); - /* Disable the VP */ - xive_native_disable_vp(xc->vp_id); - - /* Free the queues & associated interrupts */ + /* Free escalations */ for (i = 0; i < KVMPPC_XIVE_Q_COUNT; i++) { /* Free the escalation irq */ if (xc->esc_virq[i]) { + if (xc->xive->single_escalation) + xive_cleanup_single_escalation(vcpu, xc, + xc->esc_virq[i]); free_irq(xc->esc_virq[i], vcpu); irq_dispose_mapping(xc->esc_virq[i]); kfree(xc->esc_virq_names[i]); xc->esc_virq[i] = 0; } + } + + /* Disable the VP */ + xive_native_disable_vp(xc->vp_id); + + /* Clear the cam word so guest entry won't try to push context */ + vcpu->arch.xive_cam_word = 0; - /* Free the queue */ + /* Free the queues */ + for (i = 0; i < KVMPPC_XIVE_Q_COUNT; i++) { kvmppc_xive_native_cleanup_queue(vcpu, i); } @@ -1171,6 +1179,11 @@ int kvmppc_xive_native_set_vp(struct kvm_vcpu *vcpu, union kvmppc_one_reg *val) return 0; } +bool kvmppc_xive_native_supported(void) +{ + return xive_native_has_queue_state_support(); +} + static int xive_native_debug_show(struct seq_file *m, void *private) { struct kvmppc_xive *xive = m->private; diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c index b5a848a55504dff3344da7ac60b19cc4ab44b52a..00649ca5fa9a0977893773f83112b4a6cc85a8f2 100644 --- a/arch/powerpc/kvm/e500.c +++ b/arch/powerpc/kvm/e500.c @@ -440,6 +440,9 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_e500(struct kvm *kvm, struct kvm_vcpu *vcpu; int err; + BUILD_BUG_ON_MSG(offsetof(struct kvmppc_vcpu_e500, vcpu) != 0, + "struct kvm_vcpu must be at offset 0 for arch usercopy region"); + vcpu_e500 = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); if (!vcpu_e500) { err = -ENOMEM; diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c index bb4d09c1ad5676fc9dbc2c4f07300ff5b77bf0fa..6fca38ca791ff9246e2df1de40ce328a53b6af75 100644 --- a/arch/powerpc/kvm/emulate.c +++ b/arch/powerpc/kvm/emulate.c @@ -271,6 +271,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) */ if (inst == KVMPPC_INST_SW_BREAKPOINT) { run->exit_reason = KVM_EXIT_DEBUG; + run->debug.arch.status = 0; run->debug.arch.address = kvmppc_get_pc(vcpu); emulated = EMULATE_EXIT_USER; advance = 0; diff --git a/arch/powerpc/kvm/emulate_loadstore.c b/arch/powerpc/kvm/emulate_loadstore.c index 9208c82ed08dab4bbb5d230ee0a54bf9fcb2c5d8..2e496eb86e94a0106dda78a750c07574e44a8cac 100644 --- a/arch/powerpc/kvm/emulate_loadstore.c +++ b/arch/powerpc/kvm/emulate_loadstore.c @@ -89,12 +89,6 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) rs = get_rs(inst); rt = get_rt(inst); - /* - * if mmio_vsx_tx_sx_enabled == 0, copy data between - * VSR[0..31] and memory - * if mmio_vsx_tx_sx_enabled == 1, copy data between - * VSR[32..63] and memory - */ vcpu->arch.mmio_vsx_copy_nums = 0; vcpu->arch.mmio_vsx_offset = 0; vcpu->arch.mmio_copy_type = KVMPPC_VSX_COPY_NONE; diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 3e566c2e6066748c82cb3c43eed2fe27d255f982..3a77bb6434521ffe5e09bf59496358f5d838e9a0 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -561,7 +561,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) * a POWER9 processor) and the PowerNV platform, as * nested is not yet supported. */ - r = xive_enabled() && !!cpu_has_feature(CPU_FTR_HVMODE); + r = xive_enabled() && !!cpu_has_feature(CPU_FTR_HVMODE) && + kvmppc_xive_native_supported(); break; #endif diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c index 1cdb39575eae789acfb715d4be45f2281a59b810..be86fce1a84e697686cf7bdeb2aa1d1ad7b604de 100644 --- a/arch/powerpc/sysdev/xive/common.c +++ b/arch/powerpc/sysdev/xive/common.c @@ -135,7 +135,7 @@ static u32 xive_read_eq(struct xive_q *q, bool just_peek) static u32 xive_scan_interrupts(struct xive_cpu *xc, bool just_peek) { u32 irq = 0; - u8 prio; + u8 prio = 0; /* Find highest pending priority */ while (xc->pending_prio != 0) { @@ -148,8 +148,19 @@ static u32 xive_scan_interrupts(struct xive_cpu *xc, bool just_peek) irq = xive_read_eq(&xc->queue[prio], just_peek); /* Found something ? That's it */ - if (irq) - break; + if (irq) { + if (just_peek || irq_to_desc(irq)) + break; + /* + * We should never get here; if we do then we must + * have failed to synchronize the interrupt properly + * when shutting it down. + */ + pr_crit("xive: got interrupt %d without descriptor, dropping\n", + irq); + WARN_ON(1); + continue; + } /* Clear pending bits */ xc->pending_prio &= ~(1 << prio); @@ -307,6 +318,7 @@ static void xive_do_queue_eoi(struct xive_cpu *xc) */ static void xive_do_source_eoi(u32 hw_irq, struct xive_irq_data *xd) { + xd->stale_p = false; /* If the XIVE supports the new "store EOI facility, use it */ if (xd->flags & XIVE_IRQ_FLAG_STORE_EOI) xive_esb_write(xd, XIVE_ESB_STORE_EOI, 0); @@ -350,7 +362,7 @@ static void xive_do_source_eoi(u32 hw_irq, struct xive_irq_data *xd) } } -/* irq_chip eoi callback */ +/* irq_chip eoi callback, called with irq descriptor lock held */ static void xive_irq_eoi(struct irq_data *d) { struct xive_irq_data *xd = irq_data_get_irq_handler_data(d); @@ -366,6 +378,8 @@ static void xive_irq_eoi(struct irq_data *d) if (!irqd_irq_disabled(d) && !irqd_is_forwarded_to_vcpu(d) && !(xd->flags & XIVE_IRQ_NO_EOI)) xive_do_source_eoi(irqd_to_hwirq(d), xd); + else + xd->stale_p = true; /* * Clear saved_p to indicate that it's no longer occupying @@ -397,11 +411,16 @@ static void xive_do_source_set_mask(struct xive_irq_data *xd, */ if (mask) { val = xive_esb_read(xd, XIVE_ESB_SET_PQ_01); - xd->saved_p = !!(val & XIVE_ESB_VAL_P); - } else if (xd->saved_p) + if (!xd->stale_p && !!(val & XIVE_ESB_VAL_P)) + xd->saved_p = true; + xd->stale_p = false; + } else if (xd->saved_p) { xive_esb_read(xd, XIVE_ESB_SET_PQ_10); - else + xd->saved_p = false; + } else { xive_esb_read(xd, XIVE_ESB_SET_PQ_00); + xd->stale_p = false; + } } /* @@ -541,6 +560,8 @@ static unsigned int xive_irq_startup(struct irq_data *d) unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); int target, rc; + xd->saved_p = false; + xd->stale_p = false; pr_devel("xive_irq_startup: irq %d [0x%x] data @%p\n", d->irq, hw_irq, d); @@ -587,6 +608,7 @@ static unsigned int xive_irq_startup(struct irq_data *d) return 0; } +/* called with irq descriptor lock held */ static void xive_irq_shutdown(struct irq_data *d) { struct xive_irq_data *xd = irq_data_get_irq_handler_data(d); @@ -601,16 +623,6 @@ static void xive_irq_shutdown(struct irq_data *d) /* Mask the interrupt at the source */ xive_do_source_set_mask(xd, true); - /* - * The above may have set saved_p. We clear it otherwise it - * will prevent re-enabling later on. It is ok to forget the - * fact that the interrupt might be in a queue because we are - * accounting that already in xive_dec_target_count() and will - * be re-routing it to a new queue with proper accounting when - * it's started up again - */ - xd->saved_p = false; - /* * Mask the interrupt in HW in the IVT/EAS and set the number * to be the "bad" IRQ number @@ -797,6 +809,10 @@ static int xive_irq_retrigger(struct irq_data *d) return 1; } +/* + * Caller holds the irq descriptor lock, so this won't be called + * concurrently with xive_get_irqchip_state on the same interrupt. + */ static int xive_irq_set_vcpu_affinity(struct irq_data *d, void *state) { struct xive_irq_data *xd = irq_data_get_irq_handler_data(d); @@ -820,6 +836,10 @@ static int xive_irq_set_vcpu_affinity(struct irq_data *d, void *state) /* Set it to PQ=10 state to prevent further sends */ pq = xive_esb_read(xd, XIVE_ESB_SET_PQ_10); + if (!xd->stale_p) { + xd->saved_p = !!(pq & XIVE_ESB_VAL_P); + xd->stale_p = !xd->saved_p; + } /* No target ? nothing to do */ if (xd->target == XIVE_INVALID_TARGET) { @@ -827,7 +847,7 @@ static int xive_irq_set_vcpu_affinity(struct irq_data *d, void *state) * An untargetted interrupt should have been * also masked at the source */ - WARN_ON(pq & 2); + WARN_ON(xd->saved_p); return 0; } @@ -847,9 +867,8 @@ static int xive_irq_set_vcpu_affinity(struct irq_data *d, void *state) * This saved_p is cleared by the host EOI, when we know * for sure the queue slot is no longer in use. */ - if (pq & 2) { - pq = xive_esb_read(xd, XIVE_ESB_SET_PQ_11); - xd->saved_p = true; + if (xd->saved_p) { + xive_esb_read(xd, XIVE_ESB_SET_PQ_11); /* * Sync the XIVE source HW to ensure the interrupt @@ -862,8 +881,7 @@ static int xive_irq_set_vcpu_affinity(struct irq_data *d, void *state) */ if (xive_ops->sync_source) xive_ops->sync_source(hw_irq); - } else - xd->saved_p = false; + } } else { irqd_clr_forwarded_to_vcpu(d); @@ -914,6 +932,23 @@ static int xive_irq_set_vcpu_affinity(struct irq_data *d, void *state) return 0; } +/* Called with irq descriptor lock held. */ +static int xive_get_irqchip_state(struct irq_data *data, + enum irqchip_irq_state which, bool *state) +{ + struct xive_irq_data *xd = irq_data_get_irq_handler_data(data); + + switch (which) { + case IRQCHIP_STATE_ACTIVE: + *state = !xd->stale_p && + (xd->saved_p || + !!(xive_esb_read(xd, XIVE_ESB_GET) & XIVE_ESB_VAL_P)); + return 0; + default: + return -EINVAL; + } +} + static struct irq_chip xive_irq_chip = { .name = "XIVE-IRQ", .irq_startup = xive_irq_startup, @@ -925,6 +960,7 @@ static struct irq_chip xive_irq_chip = { .irq_set_type = xive_irq_set_type, .irq_retrigger = xive_irq_retrigger, .irq_set_vcpu_affinity = xive_irq_set_vcpu_affinity, + .irq_get_irqchip_state = xive_get_irqchip_state, }; bool is_xive_irq(struct irq_chip *chip) @@ -1337,6 +1373,11 @@ static void xive_flush_cpu_queue(unsigned int cpu, struct xive_cpu *xc) raw_spin_lock(&desc->lock); xd = irq_desc_get_handler_data(desc); + /* + * Clear saved_p to indicate that it's no longer pending + */ + xd->saved_p = false; + /* * For LSIs, we EOI, this will cause a resend if it's * still asserted. Otherwise do an MSI retrigger. diff --git a/arch/powerpc/sysdev/xive/native.c b/arch/powerpc/sysdev/xive/native.c index 2f26b74f6cfa66093b4e8aeb4a0cca6d257a154a..37987c815913a9f5a32e423e16d9ebf6791fa95d 100644 --- a/arch/powerpc/sysdev/xive/native.c +++ b/arch/powerpc/sysdev/xive/native.c @@ -800,6 +800,13 @@ int xive_native_set_queue_state(u32 vp_id, u32 prio, u32 qtoggle, u32 qindex) } EXPORT_SYMBOL_GPL(xive_native_set_queue_state); +bool xive_native_has_queue_state_support(void) +{ + return opal_check_token(OPAL_XIVE_GET_QUEUE_STATE) && + opal_check_token(OPAL_XIVE_SET_QUEUE_STATE); +} +EXPORT_SYMBOL_GPL(xive_native_has_queue_state_support); + int xive_native_get_vp_state(u32 vp_id, u64 *out_state) { __be64 state; diff --git a/arch/riscv/Kbuild b/arch/riscv/Kbuild new file mode 100644 index 0000000000000000000000000000000000000000..d1d0aa70fdf15c6e9ebb9a5d85757035b7189149 --- /dev/null +++ b/arch/riscv/Kbuild @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-y += kernel/ mm/ net/ diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 59a4727ecd6c074672e82d8bb4ec7638912957f6..1211543c330cccee3d0de9150c8df0286ab642f9 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -35,6 +35,8 @@ config RISCV select HAVE_DMA_CONTIGUOUS select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_PERF_EVENTS + select HAVE_PERF_REGS + select HAVE_PERF_USER_STACK_DUMP select HAVE_SYSCALL_TRACEPOINTS select IRQ_DOMAIN select SPARSE_IRQ @@ -48,12 +50,14 @@ config RISCV select PCI_MSI if PCI select RISCV_TIMER select GENERIC_IRQ_MULTI_HANDLER + select GENERIC_ARCH_TOPOLOGY if SMP select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_MMIOWB select HAVE_EBPF_JIT if 64BIT select EDAC_SUPPORT select ARCH_HAS_GIGANTIC_PAGE select ARCH_WANT_HUGE_PMD_SHARE if 64BIT + select SPARSEMEM_STATIC if 32BIT config MMU def_bool y @@ -62,12 +66,32 @@ config ZONE_DMA32 bool default y if 64BIT +config VA_BITS + int + default 32 if 32BIT + default 39 if 64BIT + +config PA_BITS + int + default 34 if 32BIT + default 56 if 64BIT + config PAGE_OFFSET hex default 0xC0000000 if 32BIT && MAXPHYSMEM_2GB default 0xffffffff80000000 if 64BIT && MAXPHYSMEM_2GB default 0xffffffe000000000 if 64BIT && MAXPHYSMEM_128GB +config ARCH_FLATMEM_ENABLE + def_bool y + +config ARCH_SPARSEMEM_ENABLE + def_bool y + select SPARSEMEM_VMEMMAP_ENABLE + +config ARCH_SELECT_MEMORY_MODEL + def_bool ARCH_SPARSEMEM_ENABLE + config ARCH_WANT_GENERAL_HUGETLB def_bool y diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 7a117be8297c89253fbe0ce07397a10a25181238..4f0a3d2018d2dbd04198a0c6abb391dfb6234531 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -54,6 +54,9 @@ endif ifeq ($(CONFIG_MODULE_SECTIONS),y) KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/riscv/kernel/module.lds endif +ifeq ($(CONFIG_PERF_EVENTS),y) + KBUILD_CFLAGS += -fno-omit-frame-pointer +endif KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-relax) @@ -72,7 +75,7 @@ KBUILD_IMAGE := $(boot)/Image.gz head-y := arch/riscv/kernel/head.o -core-y += arch/riscv/kernel/ arch/riscv/mm/ arch/riscv/net/ +core-y += arch/riscv/ libs-y += arch/riscv/lib/ diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h index 707e00a8430b01d66a9ee90e8977162bf24d2500..3db261c4810fc1b01750d3c5ca61fc73b55d681e 100644 --- a/arch/riscv/include/asm/page.h +++ b/arch/riscv/include/asm/page.h @@ -110,8 +110,10 @@ extern unsigned long min_low_pfn; #define page_to_bus(page) (page_to_phys(page)) #define phys_to_page(paddr) (pfn_to_page(phys_to_pfn(paddr))) +#ifdef CONFIG_FLATMEM #define pfn_valid(pfn) \ (((pfn) >= pfn_base) && (((pfn)-pfn_base) < max_mapnr)) +#endif #define ARCH_PFN_OFFSET (pfn_base) diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index c24a083b3e12d2e19bea16b1b5f6e240d788beff..80905b27ee987a7fa37b61945e34366429e06fea 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -83,6 +83,19 @@ extern pgd_t swapper_pg_dir[]; #define __S110 PAGE_SHARED_EXEC #define __S111 PAGE_SHARED_EXEC +/* + * Roughly size the vmemmap space to be large enough to fit enough + * struct pages to map half the virtual address space. Then + * position vmemmap directly below the VMALLOC region. + */ +#define VMEMMAP_SHIFT \ + (CONFIG_VA_BITS - PAGE_SHIFT - 1 + STRUCT_PAGE_MAX_SHIFT) +#define VMEMMAP_SIZE BIT(VMEMMAP_SHIFT) +#define VMEMMAP_END (VMALLOC_START - 1) +#define VMEMMAP_START (VMALLOC_START - VMEMMAP_SIZE) + +#define vmemmap ((struct page *)VMEMMAP_START) + /* * ZERO_PAGE is a global shared page that is always zero, * used for zero-mapped memory areas, etc. diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h index c6ed4d691deff8bce026397a862f7e6c3a23a696..a83451d73a4e2e88e6c64fde600511a48d1b78c5 100644 --- a/arch/riscv/include/asm/smp.h +++ b/arch/riscv/include/asm/smp.h @@ -61,11 +61,5 @@ static inline unsigned long cpuid_to_hartid_map(int cpu) return boot_cpu_hartid; } -static inline void riscv_cpuid_to_hartid_mask(const struct cpumask *in, - struct cpumask *out) -{ - cpumask_set_cpu(cpuid_to_hartid_map(0), out); -} - #endif /* CONFIG_SMP */ #endif /* _ASM_RISCV_SMP_H */ diff --git a/arch/riscv/include/asm/sparsemem.h b/arch/riscv/include/asm/sparsemem.h new file mode 100644 index 0000000000000000000000000000000000000000..b58ba2d9ed6efff51a62c392f5b64c4b7d395e32 --- /dev/null +++ b/arch/riscv/include/asm/sparsemem.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __ASM_SPARSEMEM_H +#define __ASM_SPARSEMEM_H + +#ifdef CONFIG_SPARSEMEM +#define MAX_PHYSMEM_BITS CONFIG_PA_BITS +#define SECTION_SIZE_BITS 27 +#endif /* CONFIG_SPARSEMEM */ + +#endif /* __ASM_SPARSEMEM_H */ diff --git a/arch/riscv/include/asm/timex.h b/arch/riscv/include/asm/timex.h index 6a703ec9d7968f19da201f72965dd3fa9d9dae47..c7ef131b9e4cbdd76f79687dac40dce4b922f93e 100644 --- a/arch/riscv/include/asm/timex.h +++ b/arch/riscv/include/asm/timex.h @@ -6,43 +6,41 @@ #ifndef _ASM_RISCV_TIMEX_H #define _ASM_RISCV_TIMEX_H -#include +#include typedef unsigned long cycles_t; -static inline cycles_t get_cycles_inline(void) +static inline cycles_t get_cycles(void) { - cycles_t n; - - __asm__ __volatile__ ( - "rdtime %0" - : "=r" (n)); - return n; + return csr_read(CSR_TIME); } -#define get_cycles get_cycles_inline +#define get_cycles get_cycles #ifdef CONFIG_64BIT -static inline uint64_t get_cycles64(void) +static inline u64 get_cycles64(void) +{ + return get_cycles(); +} +#else /* CONFIG_64BIT */ +static inline u32 get_cycles_hi(void) { - return get_cycles(); + return csr_read(CSR_TIMEH); } -#else -static inline uint64_t get_cycles64(void) + +static inline u64 get_cycles64(void) { - u32 lo, hi, tmp; - __asm__ __volatile__ ( - "1:\n" - "rdtimeh %0\n" - "rdtime %1\n" - "rdtimeh %2\n" - "bne %0, %2, 1b" - : "=&r" (hi), "=&r" (lo), "=&r" (tmp)); + u32 hi, lo; + + do { + hi = get_cycles_hi(); + lo = get_cycles(); + } while (hi != get_cycles_hi()); + return ((u64)hi << 32) | lo; } -#endif +#endif /* CONFIG_64BIT */ #define ARCH_HAS_READ_CURRENT_TIMER - static inline int read_current_timer(unsigned long *timer_val) { *timer_val = get_cycles(); diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h index 4d9bbe8438bf6a7cff301cfd2c6fec0d268a607c..37ae4e367ad203a55a56cfe47ee85202ed7f1781 100644 --- a/arch/riscv/include/asm/tlbflush.h +++ b/arch/riscv/include/asm/tlbflush.h @@ -25,8 +25,13 @@ static inline void local_flush_tlb_page(unsigned long addr) __asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory"); } -#ifndef CONFIG_SMP - +#ifdef CONFIG_SMP +void flush_tlb_all(void); +void flush_tlb_mm(struct mm_struct *mm); +void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr); +void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); +#else /* CONFIG_SMP */ #define flush_tlb_all() local_flush_tlb_all() #define flush_tlb_page(vma, addr) local_flush_tlb_page(addr) @@ -37,35 +42,6 @@ static inline void flush_tlb_range(struct vm_area_struct *vma, } #define flush_tlb_mm(mm) flush_tlb_all() - -#else /* CONFIG_SMP */ - -#include - -static inline void remote_sfence_vma(struct cpumask *cmask, unsigned long start, - unsigned long size) -{ - struct cpumask hmask; - - cpumask_clear(&hmask); - riscv_cpuid_to_hartid_mask(cmask, &hmask); - sbi_remote_sfence_vma(hmask.bits, start, size); -} - -#define flush_tlb_all() sbi_remote_sfence_vma(NULL, 0, -1) - -#define flush_tlb_range(vma, start, end) \ - remote_sfence_vma(mm_cpumask((vma)->vm_mm), start, (end) - (start)) - -static inline void flush_tlb_page(struct vm_area_struct *vma, - unsigned long addr) -{ - flush_tlb_range(vma, addr, addr + PAGE_SIZE); -} - -#define flush_tlb_mm(mm) \ - remote_sfence_vma(mm_cpumask(mm), 0, -1) - #endif /* CONFIG_SMP */ /* Flush a range of kernel pages */ diff --git a/arch/riscv/include/uapi/asm/perf_regs.h b/arch/riscv/include/uapi/asm/perf_regs.h new file mode 100644 index 0000000000000000000000000000000000000000..196f964bfcb4d8dd5b2d6d4fd4c6ef5e859774e4 --- /dev/null +++ b/arch/riscv/include/uapi/asm/perf_regs.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */ + +#ifndef _ASM_RISCV_PERF_REGS_H +#define _ASM_RISCV_PERF_REGS_H + +enum perf_event_riscv_regs { + PERF_REG_RISCV_PC, + PERF_REG_RISCV_RA, + PERF_REG_RISCV_SP, + PERF_REG_RISCV_GP, + PERF_REG_RISCV_TP, + PERF_REG_RISCV_T0, + PERF_REG_RISCV_T1, + PERF_REG_RISCV_T2, + PERF_REG_RISCV_S0, + PERF_REG_RISCV_S1, + PERF_REG_RISCV_A0, + PERF_REG_RISCV_A1, + PERF_REG_RISCV_A2, + PERF_REG_RISCV_A3, + PERF_REG_RISCV_A4, + PERF_REG_RISCV_A5, + PERF_REG_RISCV_A6, + PERF_REG_RISCV_A7, + PERF_REG_RISCV_S2, + PERF_REG_RISCV_S3, + PERF_REG_RISCV_S4, + PERF_REG_RISCV_S5, + PERF_REG_RISCV_S6, + PERF_REG_RISCV_S7, + PERF_REG_RISCV_S8, + PERF_REG_RISCV_S9, + PERF_REG_RISCV_S10, + PERF_REG_RISCV_S11, + PERF_REG_RISCV_T3, + PERF_REG_RISCV_T4, + PERF_REG_RISCV_T5, + PERF_REG_RISCV_T6, + PERF_REG_RISCV_MAX, +}; +#endif /* _ASM_RISCV_PERF_REGS_H */ diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index 2420d37d96de2586d71d1c691469831246af0fbd..696020ff72db6152f34595c58398e3b09077902b 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -38,6 +38,8 @@ obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o obj-$(CONFIG_DYNAMIC_FTRACE) += mcount-dyn.o -obj-$(CONFIG_PERF_EVENTS) += perf_event.o +obj-$(CONFIG_PERF_EVENTS) += perf_event.o +obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o +obj-$(CONFIG_HAVE_PERF_REGS) += perf_regs.o clean: diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index bc7a56e1ca6f48bc29a3a3fcb83c4fab7662a0f1..74ccfd4640714fff1f462d0ec47c0efb7ff09f95 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -167,7 +167,7 @@ ENTRY(handle_exception) tail do_IRQ 1: /* Exceptions run with interrupts enabled */ - csrs sstatus, SR_SIE + csrs CSR_SSTATUS, SR_SIE /* Handle syscalls */ li t0, EXC_SYSCALL @@ -222,7 +222,7 @@ ret_from_syscall: ret_from_exception: REG_L s0, PT_SSTATUS(sp) - csrc sstatus, SR_SIE + csrc CSR_SSTATUS, SR_SIE andi s0, s0, SR_SPP bnez s0, resume_kernel @@ -265,7 +265,7 @@ work_pending: bnez s1, work_resched work_notifysig: /* Handle pending signals and notify-resume requests */ - csrs sstatus, SR_SIE /* Enable interrupts for do_notify_resume() */ + csrs CSR_SSTATUS, SR_SIE /* Enable interrupts for do_notify_resume() */ move a0, sp /* pt_regs */ move a1, s0 /* current_thread_info->flags */ tail do_notify_resume diff --git a/arch/riscv/kernel/fpu.S b/arch/riscv/kernel/fpu.S index 1defb0618affa287d8da1f24a05fc94d6198fac8..631d31540660e09977ddd8a728fd885d4a4205cb 100644 --- a/arch/riscv/kernel/fpu.S +++ b/arch/riscv/kernel/fpu.S @@ -23,7 +23,7 @@ ENTRY(__fstate_save) li a2, TASK_THREAD_F0 add a0, a0, a2 li t1, SR_FS - csrs sstatus, t1 + csrs CSR_SSTATUS, t1 frcsr t0 fsd f0, TASK_THREAD_F0_F0(a0) fsd f1, TASK_THREAD_F1_F0(a0) @@ -58,7 +58,7 @@ ENTRY(__fstate_save) fsd f30, TASK_THREAD_F30_F0(a0) fsd f31, TASK_THREAD_F31_F0(a0) sw t0, TASK_THREAD_FCSR_F0(a0) - csrc sstatus, t1 + csrc CSR_SSTATUS, t1 ret ENDPROC(__fstate_save) @@ -67,7 +67,7 @@ ENTRY(__fstate_restore) add a0, a0, a2 li t1, SR_FS lw t0, TASK_THREAD_FCSR_F0(a0) - csrs sstatus, t1 + csrs CSR_SSTATUS, t1 fld f0, TASK_THREAD_F0_F0(a0) fld f1, TASK_THREAD_F1_F0(a0) fld f2, TASK_THREAD_F2_F0(a0) @@ -101,6 +101,6 @@ ENTRY(__fstate_restore) fld f30, TASK_THREAD_F30_F0(a0) fld f31, TASK_THREAD_F31_F0(a0) fscsr t0 - csrc sstatus, t1 + csrc CSR_SSTATUS, t1 ret ENDPROC(__fstate_restore) diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S index 52eec0c1bf30c11079d285f7defdf000b6583f22..15a9189f91ad27f445f96983d56ab1f3186940b4 100644 --- a/arch/riscv/kernel/head.S +++ b/arch/riscv/kernel/head.S @@ -61,7 +61,7 @@ _start_kernel: * floating point in kernel space */ li t0, SR_FS - csrc sstatus, t0 + csrc CSR_SSTATUS, t0 /* Pick one hart to run the main boot sequence */ la a3, hart_lottery diff --git a/arch/riscv/kernel/perf_callchain.c b/arch/riscv/kernel/perf_callchain.c new file mode 100644 index 0000000000000000000000000000000000000000..8d2804f05cf93b3bc03bf199f9d91e51d047e394 --- /dev/null +++ b/arch/riscv/kernel/perf_callchain.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */ + +#include +#include + +/* Kernel callchain */ +struct stackframe { + unsigned long fp; + unsigned long ra; +}; + +/* + * Get the return address for a single stackframe and return a pointer to the + * next frame tail. + */ +static unsigned long user_backtrace(struct perf_callchain_entry_ctx *entry, + unsigned long fp, unsigned long reg_ra) +{ + struct stackframe buftail; + unsigned long ra = 0; + unsigned long *user_frame_tail = + (unsigned long *)(fp - sizeof(struct stackframe)); + + /* Check accessibility of one struct frame_tail beyond */ + if (!access_ok(user_frame_tail, sizeof(buftail))) + return 0; + if (__copy_from_user_inatomic(&buftail, user_frame_tail, + sizeof(buftail))) + return 0; + + if (reg_ra != 0) + ra = reg_ra; + else + ra = buftail.ra; + + fp = buftail.fp; + if (ra != 0) + perf_callchain_store(entry, ra); + else + return 0; + + return fp; +} + +/* + * This will be called when the target is in user mode + * This function will only be called when we use + * "PERF_SAMPLE_CALLCHAIN" in + * kernel/events/core.c:perf_prepare_sample() + * + * How to trigger perf_callchain_[user/kernel] : + * $ perf record -e cpu-clock --call-graph fp ./program + * $ perf report --call-graph + * + * On RISC-V platform, the program being sampled and the C library + * need to be compiled with -fno-omit-frame-pointer, otherwise + * the user stack will not contain function frame. + */ +void perf_callchain_user(struct perf_callchain_entry_ctx *entry, + struct pt_regs *regs) +{ + unsigned long fp = 0; + + /* RISC-V does not support perf in guest mode. */ + if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) + return; + + fp = regs->s0; + perf_callchain_store(entry, regs->sepc); + + fp = user_backtrace(entry, fp, regs->ra); + while (fp && !(fp & 0x3) && entry->nr < entry->max_stack) + fp = user_backtrace(entry, fp, 0); +} + +bool fill_callchain(unsigned long pc, void *entry) +{ + return perf_callchain_store(entry, pc); +} + +void notrace walk_stackframe(struct task_struct *task, + struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg); +void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, + struct pt_regs *regs) +{ + /* RISC-V does not support perf in guest mode. */ + if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { + pr_warn("RISC-V does not support perf in guest mode!"); + return; + } + + walk_stackframe(NULL, regs, fill_callchain, entry); +} diff --git a/arch/riscv/kernel/perf_regs.c b/arch/riscv/kernel/perf_regs.c new file mode 100644 index 0000000000000000000000000000000000000000..04a38fbeb9c7a1e3322abceb9ce7c739faf48a55 --- /dev/null +++ b/arch/riscv/kernel/perf_regs.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */ + +#include +#include +#include +#include +#include +#include + +u64 perf_reg_value(struct pt_regs *regs, int idx) +{ + if (WARN_ON_ONCE((u32)idx >= PERF_REG_RISCV_MAX)) + return 0; + + return ((unsigned long *)regs)[idx]; +} + +#define REG_RESERVED (~((1ULL << PERF_REG_RISCV_MAX) - 1)) + +int perf_reg_validate(u64 mask) +{ + if (!mask || mask & REG_RESERVED) + return -EINVAL; + + return 0; +} + +u64 perf_reg_abi(struct task_struct *task) +{ +#if __riscv_xlen == 64 + return PERF_SAMPLE_REGS_ABI_64; +#else + return PERF_SAMPLE_REGS_ABI_32; +#endif +} + +void perf_get_regs_user(struct perf_regs *regs_user, + struct pt_regs *regs, + struct pt_regs *regs_user_copy) +{ + regs_user->regs = task_pt_regs(current); + regs_user->abi = perf_reg_abi(current); +} diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c index 5a9834503a2f9c3109f46932afa5cd8764f629dd..3836760d7aaf3497d80bbbca4d51b66fdc3553f8 100644 --- a/arch/riscv/kernel/smp.c +++ b/arch/riscv/kernel/smp.c @@ -56,6 +56,7 @@ void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out) { int cpu; + cpumask_clear(out); for_each_cpu(cpu, in) cpumask_set_cpu(cpuid_to_hartid_map(cpu), out); } @@ -78,13 +79,42 @@ static void ipi_stop(void) wait_for_interrupt(); } +static void send_ipi_mask(const struct cpumask *mask, enum ipi_message_type op) +{ + struct cpumask hartid_mask; + int cpu; + + smp_mb__before_atomic(); + for_each_cpu(cpu, mask) + set_bit(op, &ipi_data[cpu].bits); + smp_mb__after_atomic(); + + riscv_cpuid_to_hartid_mask(mask, &hartid_mask); + sbi_send_ipi(cpumask_bits(&hartid_mask)); +} + +static void send_ipi_single(int cpu, enum ipi_message_type op) +{ + int hartid = cpuid_to_hartid_map(cpu); + + smp_mb__before_atomic(); + set_bit(op, &ipi_data[cpu].bits); + smp_mb__after_atomic(); + + sbi_send_ipi(cpumask_bits(cpumask_of(hartid))); +} + +static inline void clear_ipi(void) +{ + csr_clear(CSR_SIP, SIE_SSIE); +} + void riscv_software_interrupt(void) { unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits; unsigned long *stats = ipi_data[smp_processor_id()].stats; - /* Clear pending IPI */ - csr_clear(CSR_SIP, SIE_SSIE); + clear_ipi(); while (true) { unsigned long ops; @@ -118,23 +148,6 @@ void riscv_software_interrupt(void) } } -static void -send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation) -{ - int cpuid, hartid; - struct cpumask hartid_mask; - - cpumask_clear(&hartid_mask); - mb(); - for_each_cpu(cpuid, to_whom) { - set_bit(operation, &ipi_data[cpuid].bits); - hartid = cpuid_to_hartid_map(cpuid); - cpumask_set_cpu(hartid, &hartid_mask); - } - mb(); - sbi_send_ipi(cpumask_bits(&hartid_mask)); -} - static const char * const ipi_names[] = { [IPI_RESCHEDULE] = "Rescheduling interrupts", [IPI_CALL_FUNC] = "Function call interrupts", @@ -156,12 +169,12 @@ void show_ipi_stats(struct seq_file *p, int prec) void arch_send_call_function_ipi_mask(struct cpumask *mask) { - send_ipi_message(mask, IPI_CALL_FUNC); + send_ipi_mask(mask, IPI_CALL_FUNC); } void arch_send_call_function_single_ipi(int cpu) { - send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC); + send_ipi_single(cpu, IPI_CALL_FUNC); } void smp_send_stop(void) @@ -176,7 +189,7 @@ void smp_send_stop(void) if (system_state <= SYSTEM_RUNNING) pr_crit("SMP: stopping secondary CPUs\n"); - send_ipi_message(&mask, IPI_CPU_STOP); + send_ipi_mask(&mask, IPI_CPU_STOP); } /* Wait up to one second for other CPUs to stop */ @@ -191,6 +204,5 @@ void smp_send_stop(void) void smp_send_reschedule(int cpu) { - send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); + send_ipi_single(cpu, IPI_RESCHEDULE); } - diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c index 7462a44304feb7023f923e965cad9f41b5883ed4..18ae6da5115e53d4612f84dc8a0898b863e8b55e 100644 --- a/arch/riscv/kernel/smpboot.c +++ b/arch/riscv/kernel/smpboot.c @@ -8,6 +8,7 @@ * Copyright (C) 2017 SiFive */ +#include #include #include #include @@ -35,6 +36,7 @@ static DECLARE_COMPLETION(cpu_running); void __init smp_prepare_boot_cpu(void) { + init_cpu_topology(); } void __init smp_prepare_cpus(unsigned int max_cpus) @@ -138,6 +140,7 @@ asmlinkage void __init smp_callin(void) trap_init(); notify_cpu_starting(smp_processor_id()); + update_siblings_masks(smp_processor_id()); set_cpu_online(smp_processor_id(), 1); /* * Remote TLB flushes are ignored while the CPU is offline, so emit diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c index f15642715d1a35f14408d9193c3ec0bd6698f567..0940681d2f682d4bbda28401f8ec7b24d69685e5 100644 --- a/arch/riscv/kernel/stacktrace.c +++ b/arch/riscv/kernel/stacktrace.c @@ -19,8 +19,8 @@ struct stackframe { unsigned long ra; }; -static void notrace walk_stackframe(struct task_struct *task, - struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg) +void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, + bool (*fn)(unsigned long, void *), void *arg) { unsigned long fp, sp, pc; diff --git a/arch/riscv/lib/uaccess.S b/arch/riscv/lib/uaccess.S index 399e6f0c2d98ee7be7926c490f3b356f2053f7d0..ed2696c0143d5aad57af20020f4515f50a8783eb 100644 --- a/arch/riscv/lib/uaccess.S +++ b/arch/riscv/lib/uaccess.S @@ -18,7 +18,7 @@ ENTRY(__asm_copy_from_user) /* Enable access to user memory */ li t6, SR_SUM - csrs sstatus, t6 + csrs CSR_SSTATUS, t6 add a3, a1, a2 /* Use word-oriented copy only if low-order bits match */ @@ -47,7 +47,7 @@ ENTRY(__asm_copy_from_user) 3: /* Disable access to user memory */ - csrc sstatus, t6 + csrc CSR_SSTATUS, t6 li a0, 0 ret 4: /* Edge case: unalignment */ @@ -72,7 +72,7 @@ ENTRY(__clear_user) /* Enable access to user memory */ li t6, SR_SUM - csrs sstatus, t6 + csrs CSR_SSTATUS, t6 add a3, a0, a1 addi t0, a0, SZREG-1 @@ -94,7 +94,7 @@ ENTRY(__clear_user) 3: /* Disable access to user memory */ - csrc sstatus, t6 + csrc CSR_SSTATUS, t6 li a0, 0 ret 4: /* Edge case: unalignment */ @@ -114,11 +114,11 @@ ENDPROC(__clear_user) /* Fixup code for __copy_user(10) and __clear_user(11) */ 10: /* Disable access to user memory */ - csrs sstatus, t6 + csrs CSR_SSTATUS, t6 mv a0, a2 ret 11: - csrs sstatus, t6 + csrs CSR_SSTATUS, t6 mv a0, a1 ret .previous diff --git a/arch/riscv/mm/Makefile b/arch/riscv/mm/Makefile index 74055e1d6f21303ef4e9c8ed166b8a228c7ddf76..9d9a173356868b6bcce2ca8657720bc26fd16527 100644 --- a/arch/riscv/mm/Makefile +++ b/arch/riscv/mm/Makefile @@ -13,4 +13,7 @@ obj-y += cacheflush.o obj-y += context.o obj-y += sifive_l2_cache.o +ifeq ($(CONFIG_MMU),y) +obj-$(CONFIG_SMP) += tlbflush.o +endif obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o diff --git a/arch/riscv/mm/cacheflush.c b/arch/riscv/mm/cacheflush.c index 9ebcff8ba263c07e84896e805e1ad243edefb5c5..3f15938dec893b1d945d4b85503590c909588ce0 100644 --- a/arch/riscv/mm/cacheflush.c +++ b/arch/riscv/mm/cacheflush.c @@ -47,7 +47,6 @@ void flush_icache_mm(struct mm_struct *mm, bool local) cpumask_andnot(&others, mm_cpumask(mm), cpumask_of(cpu)); local |= cpumask_empty(&others); if (mm != current->active_mm || !local) { - cpumask_clear(&hmask); riscv_cpuid_to_hartid_mask(&others, &hmask); sbi_remote_fence_i(hmask.bits); } else { diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c index 89ceb3cbe218b1a26f188407efde5935ceaf5d24..beeb5d7f92ea5aaccefc10e41ea036f5554da81a 100644 --- a/arch/riscv/mm/context.c +++ b/arch/riscv/mm/context.c @@ -57,12 +57,7 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next, cpumask_clear_cpu(cpu, mm_cpumask(prev)); cpumask_set_cpu(cpu, mm_cpumask(next)); - /* - * Use the old spbtr name instead of using the current satp - * name to support binutils 2.29 which doesn't know about the - * privileged ISA 1.10 yet. - */ - csr_write(sptbr, virt_to_pfn(next->pgd) | SATP_MODE); + csr_write(CSR_SATP, virt_to_pfn(next->pgd) | SATP_MODE); local_flush_tlb_all(); flush_icache_deferred(next); diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index 42bf939693d34d2bc679dcd294c60506eb232d75..f0ba71304b6e52b8622ac87e690673593ee8bb6d 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -435,13 +435,23 @@ static void __init setup_vm_final(void) clear_fixmap(FIX_PMD); /* Move to swapper page table */ - csr_write(sptbr, PFN_DOWN(__pa(swapper_pg_dir)) | SATP_MODE); + csr_write(CSR_SATP, PFN_DOWN(__pa(swapper_pg_dir)) | SATP_MODE); local_flush_tlb_all(); } void __init paging_init(void) { setup_vm_final(); + memblocks_present(); + sparse_init(); setup_zero_page(); zone_sizes_init(); } + +#ifdef CONFIG_SPARSEMEM +int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node, + struct vmem_altmap *altmap) +{ + return vmemmap_populate_basepages(start, end, node); +} +#endif diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c new file mode 100644 index 0000000000000000000000000000000000000000..24cd33d2c48f3cee41bd219f33ca1d857bbbd9d7 --- /dev/null +++ b/arch/riscv/mm/tlbflush.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include + +void flush_tlb_all(void) +{ + sbi_remote_sfence_vma(NULL, 0, -1); +} + +static void __sbi_tlb_flush_range(struct cpumask *cmask, unsigned long start, + unsigned long size) +{ + struct cpumask hmask; + + riscv_cpuid_to_hartid_mask(cmask, &hmask); + sbi_remote_sfence_vma(hmask.bits, start, size); +} + +void flush_tlb_mm(struct mm_struct *mm) +{ + __sbi_tlb_flush_range(mm_cpumask(mm), 0, -1); +} + +void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) +{ + __sbi_tlb_flush_range(mm_cpumask(vma->vm_mm), addr, PAGE_SIZE); +} + +void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + __sbi_tlb_flush_range(mm_cpumask(vma->vm_mm), start, end - start); +} diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index a4ad2733eedf652d7f215b3091341f1e1d938571..8c5b05d911067bbb5a44853e665f857ab6baa2ac 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -105,6 +105,7 @@ config S390 select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE select ARCH_KEEP_MEMBLOCK select ARCH_SAVE_PAGE_KEYS if HIBERNATION + select ARCH_STACKWALK select ARCH_SUPPORTS_ATOMIC_RMW select ARCH_SUPPORTS_NUMA_BALANCING select ARCH_USE_BUILTIN_BSWAP @@ -236,6 +237,10 @@ config HAVE_MARCH_Z14_FEATURES def_bool n select HAVE_MARCH_Z13_FEATURES +config HAVE_MARCH_Z15_FEATURES + def_bool n + select HAVE_MARCH_Z14_FEATURES + choice prompt "Processor type" default MARCH_Z196 @@ -307,6 +312,14 @@ config MARCH_Z14 and 3906 series). The kernel will be slightly faster but will not work on older machines. +config MARCH_Z15 + bool "IBM z15" + select HAVE_MARCH_Z15_FEATURES + help + Select this to enable optimizations for IBM z15 (8562 + and 8561 series). The kernel will be slightly faster but will not + work on older machines. + endchoice config MARCH_Z900_TUNE @@ -333,6 +346,9 @@ config MARCH_Z13_TUNE config MARCH_Z14_TUNE def_bool TUNE_Z14 || MARCH_Z14 && TUNE_DEFAULT +config MARCH_Z15_TUNE + def_bool TUNE_Z15 || MARCH_Z15 && TUNE_DEFAULT + choice prompt "Tune code generation" default TUNE_DEFAULT @@ -377,6 +393,9 @@ config TUNE_Z13 config TUNE_Z14 bool "IBM z14" +config TUNE_Z15 + bool "IBM z15" + endchoice config 64BIT diff --git a/arch/s390/Makefile b/arch/s390/Makefile index e0bab7ed4123a84c655b33b9c3487e6f975fb64f..478b645b20ddb0ee13f261aee4929f5b769b73a6 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -45,6 +45,7 @@ mflags-$(CONFIG_MARCH_Z196) := -march=z196 mflags-$(CONFIG_MARCH_ZEC12) := -march=zEC12 mflags-$(CONFIG_MARCH_Z13) := -march=z13 mflags-$(CONFIG_MARCH_Z14) := -march=z14 +mflags-$(CONFIG_MARCH_Z15) := -march=z15 export CC_FLAGS_MARCH := $(mflags-y) @@ -59,6 +60,7 @@ cflags-$(CONFIG_MARCH_Z196_TUNE) += -mtune=z196 cflags-$(CONFIG_MARCH_ZEC12_TUNE) += -mtune=zEC12 cflags-$(CONFIG_MARCH_Z13_TUNE) += -mtune=z13 cflags-$(CONFIG_MARCH_Z14_TUNE) += -mtune=z14 +cflags-$(CONFIG_MARCH_Z15_TUNE) += -mtune=z15 cflags-y += -Wa,-I$(srctree)/arch/$(ARCH)/include diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile index 4cf0bddb7d92e1496ea16c690871274fc8c6ed47..e2c47d3a1c891b7bf5bb783f156ca902c69f1fdf 100644 --- a/arch/s390/boot/Makefile +++ b/arch/s390/boot/Makefile @@ -36,7 +36,7 @@ CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char obj-y := head.o als.o startup.o mem_detect.o ipl_parm.o ipl_report.o obj-y += string.o ebcdic.o sclp_early_core.o mem.o ipl_vmparm.o cmdline.o -obj-y += version.o ctype.o text_dma.o +obj-y += version.o pgm_check_info.o ctype.o text_dma.o obj-$(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) += uv.o obj-$(CONFIG_RELOCATABLE) += machine_kexec_reloc.o obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o diff --git a/arch/s390/boot/boot.h b/arch/s390/boot/boot.h index 1c3b2b25763721899d06b06484104cc47dffee83..2ea603f70c3bd683ddcfa51bac0e45d30de972b4 100644 --- a/arch/s390/boot/boot.h +++ b/arch/s390/boot/boot.h @@ -10,6 +10,7 @@ void parse_boot_command_line(void); void setup_memory_end(void); void verify_facilities(void); void print_missing_facilities(void); +void print_pgm_check_info(void); unsigned long get_random_base(unsigned long safe_addr); extern int kaslr_enabled; diff --git a/arch/s390/boot/compressed/.gitignore b/arch/s390/boot/compressed/.gitignore index 45aeb4f087520e643091021ffdcdca3ee8de44a0..e72fcd7ecebbd121b85fba422f77e0c1ead76bac 100644 --- a/arch/s390/boot/compressed/.gitignore +++ b/arch/s390/boot/compressed/.gitignore @@ -1,5 +1,2 @@ -sizes.h vmlinux vmlinux.lds -vmlinux.scr.lds -vmlinux.bin.full diff --git a/arch/s390/boot/compressed/vmlinux.lds.S b/arch/s390/boot/compressed/vmlinux.lds.S index 635217eb3d91b2326b05edb0a4c0fc9c87d8027a..44561b2c3712452bf3dcc50736cd88fb3cc081ee 100644 --- a/arch/s390/boot/compressed/vmlinux.lds.S +++ b/arch/s390/boot/compressed/vmlinux.lds.S @@ -37,9 +37,9 @@ SECTIONS * .dma section for code, data, ex_table that need to stay below 2 GB, * even when the kernel is relocate: above 2 GB. */ + . = ALIGN(PAGE_SIZE); _sdma = .; .dma.text : { - . = ALIGN(PAGE_SIZE); _stext_dma = .; *(.dma.text) . = ALIGN(PAGE_SIZE); @@ -52,6 +52,7 @@ SECTIONS _stop_dma_ex_table = .; } .dma.data : { *(.dma.data) } + . = ALIGN(PAGE_SIZE); _edma = .; BOOT_DATA diff --git a/arch/s390/boot/head.S b/arch/s390/boot/head.S index 2087bed6e60f3e8fd72db7a93b2d78e53c068a55..4b86a8d3c1219a4528bf4f0e1bba9fac2788ae06 100644 --- a/arch/s390/boot/head.S +++ b/arch/s390/boot/head.S @@ -60,8 +60,10 @@ __HEAD .long 0x02000690,0x60000050 .long 0x020006e0,0x20000050 - .org 0x1a0 + .org __LC_RST_NEW_PSW # 0x1a0 .quad 0,iplstart + .org __LC_PGM_NEW_PSW # 0x1d0 + .quad 0x0000000180000000,startup_pgm_check_handler .org 0x200 @@ -351,6 +353,34 @@ ENTRY(startup_kdump) #include "head_kdump.S" +# +# This program check is active immediately after kernel start +# and until early_pgm_check_handler is set in kernel/early.c +# It simply saves general/control registers and psw in +# the save area and does disabled wait with a faulty address. +# +ENTRY(startup_pgm_check_handler) + stmg %r0,%r15,__LC_SAVE_AREA_SYNC + la %r1,4095 + stctg %c0,%c15,__LC_CREGS_SAVE_AREA-4095(%r1) + mvc __LC_GPREGS_SAVE_AREA-4095(128,%r1),__LC_SAVE_AREA_SYNC + mvc __LC_PSW_SAVE_AREA-4095(16,%r1),__LC_PGM_OLD_PSW + mvc __LC_RETURN_PSW(16),__LC_PGM_OLD_PSW + ni __LC_RETURN_PSW,0xfc # remove IO and EX bits + ni __LC_RETURN_PSW+1,0xfb # remove MCHK bit + oi __LC_RETURN_PSW+1,0x2 # set wait state bit + larl %r2,.Lold_psw_disabled_wait + stg %r2,__LC_PGM_NEW_PSW+8 + l %r15,.Ldump_info_stack-.Lold_psw_disabled_wait(%r2) + brasl %r14,print_pgm_check_info +.Lold_psw_disabled_wait: + la %r1,4095 + lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) + lpswe __LC_RETURN_PSW # disabled wait +.Ldump_info_stack: + .long 0x5000 + PAGE_SIZE - STACK_FRAME_OVERHEAD +ENDPROC(startup_pgm_check_handler) + # # params at 10400 (setup.h) # Must be keept in sync with struct parmarea in setup.h diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c index b8aa6a9f937b2e27839f27ab598adab074e706a3..24ef67eb1ceffd096e7c3b9050a02029cba2ca92 100644 --- a/arch/s390/boot/ipl_parm.c +++ b/arch/s390/boot/ipl_parm.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "boot.h" @@ -14,6 +15,7 @@ char __bootdata(early_command_line)[COMMAND_LINE_SIZE]; struct ipl_parameter_block __bootdata_preserved(ipl_block); int __bootdata_preserved(ipl_block_valid); +unsigned long __bootdata(vmalloc_size) = VMALLOC_DEFAULT_SIZE; unsigned long __bootdata(memory_end); int __bootdata(memory_end_set); int __bootdata(noexec_disabled); @@ -219,18 +221,21 @@ void parse_boot_command_line(void) while (*args) { args = next_arg(args, ¶m, &val); - if (!strcmp(param, "mem")) { - memory_end = memparse(val, NULL); + if (!strcmp(param, "mem") && val) { + memory_end = round_down(memparse(val, NULL), PAGE_SIZE); memory_end_set = 1; } + if (!strcmp(param, "vmalloc") && val) + vmalloc_size = round_up(memparse(val, NULL), PAGE_SIZE); + if (!strcmp(param, "noexec")) { rc = kstrtobool(val, &enabled); if (!rc && !enabled) noexec_disabled = 1; } - if (!strcmp(param, "facilities")) + if (!strcmp(param, "facilities") && val) modify_fac_list(val); if (!strcmp(param, "nokaslr")) diff --git a/arch/s390/boot/kaslr.c b/arch/s390/boot/kaslr.c index c34a6387ce384be2a72810d3cd77fa8786ec41ef..5d12352545c558d4f5598fd074048029cfd6218a 100644 --- a/arch/s390/boot/kaslr.c +++ b/arch/s390/boot/kaslr.c @@ -3,6 +3,7 @@ * Copyright IBM Corp. 2019 */ #include +#include #include #include #include @@ -90,8 +91,10 @@ static unsigned long get_random(unsigned long limit) unsigned long get_random_base(unsigned long safe_addr) { + unsigned long memory_limit = memory_end_set ? memory_end : 0; unsigned long base, start, end, kernel_size; unsigned long block_sum, offset; + unsigned long kasan_needs; int i; if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && INITRD_START && INITRD_SIZE) { @@ -100,14 +103,36 @@ unsigned long get_random_base(unsigned long safe_addr) } safe_addr = ALIGN(safe_addr, THREAD_SIZE); + if ((IS_ENABLED(CONFIG_KASAN))) { + /* + * Estimate kasan memory requirements, which it will reserve + * at the very end of available physical memory. To estimate + * that, we take into account that kasan would require + * 1/8 of available physical memory (for shadow memory) + + * creating page tables for the whole memory + shadow memory + * region (1 + 1/8). To keep page tables estimates simple take + * the double of combined ptes size. + */ + memory_limit = get_mem_detect_end(); + if (memory_end_set && memory_limit > memory_end) + memory_limit = memory_end; + + /* for shadow memory */ + kasan_needs = memory_limit / 8; + /* for paging structures */ + kasan_needs += (memory_limit + kasan_needs) / PAGE_SIZE / + _PAGE_ENTRIES * _PAGE_TABLE_SIZE * 2; + memory_limit -= kasan_needs; + } + kernel_size = vmlinux.image_size + vmlinux.bss_size; block_sum = 0; for_each_mem_detect_block(i, &start, &end) { - if (memory_end_set) { - if (start >= memory_end) + if (memory_limit) { + if (start >= memory_limit) break; - if (end > memory_end) - end = memory_end; + if (end > memory_limit) + end = memory_limit; } if (end - start < kernel_size) continue; @@ -125,11 +150,11 @@ unsigned long get_random_base(unsigned long safe_addr) base = safe_addr; block_sum = offset = 0; for_each_mem_detect_block(i, &start, &end) { - if (memory_end_set) { - if (start >= memory_end) + if (memory_limit) { + if (start >= memory_limit) break; - if (end > memory_end) - end = memory_end; + if (end > memory_limit) + end = memory_limit; } if (end - start < kernel_size) continue; diff --git a/arch/s390/boot/mem_detect.c b/arch/s390/boot/mem_detect.c index 5d316fe40480446b9dd5f90fc0bb4f3bba6d3b55..62e7c13ce85c7e2d6e078c133ca15750dd13f0c7 100644 --- a/arch/s390/boot/mem_detect.c +++ b/arch/s390/boot/mem_detect.c @@ -63,13 +63,6 @@ void add_mem_detect_block(u64 start, u64 end) mem_detect.count++; } -static unsigned long get_mem_detect_end(void) -{ - if (mem_detect.count) - return __get_mem_detect_block_ptr(mem_detect.count - 1)->end; - return 0; -} - static int __diag260(unsigned long rx1, unsigned long rx2) { register unsigned long _rx1 asm("2") = rx1; diff --git a/arch/s390/boot/pgm_check_info.c b/arch/s390/boot/pgm_check_info.c new file mode 100644 index 0000000000000000000000000000000000000000..83b5b7915c32d272fb7947bfaf8410e017e5af34 --- /dev/null +++ b/arch/s390/boot/pgm_check_info.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include "boot.h" + +const char hex_asc[] = "0123456789abcdef"; + +#define add_val_as_hex(dst, val) \ + __add_val_as_hex(dst, (const unsigned char *)&val, sizeof(val)) + +static char *__add_val_as_hex(char *dst, const unsigned char *src, size_t count) +{ + while (count--) + dst = hex_byte_pack(dst, *src++); + return dst; +} + +static char *add_str(char *dst, char *src) +{ + strcpy(dst, src); + return dst + strlen(dst); +} + +void print_pgm_check_info(void) +{ + struct psw_bits *psw = &psw_bits(S390_lowcore.psw_save_area); + unsigned short ilc = S390_lowcore.pgm_ilc >> 1; + char buf[256]; + int row, col; + char *p; + + add_str(buf, "Linux version "); + strlcat(buf, kernel_version, sizeof(buf)); + sclp_early_printk(buf); + + p = add_str(buf, "Kernel fault: interruption code "); + p = add_val_as_hex(buf + strlen(buf), S390_lowcore.pgm_code); + p = add_str(p, " ilc:"); + *p++ = hex_asc_lo(ilc); + add_str(p, "\n"); + sclp_early_printk(buf); + + p = add_str(buf, "PSW : "); + p = add_val_as_hex(p, S390_lowcore.psw_save_area.mask); + p = add_str(p, " "); + p = add_val_as_hex(p, S390_lowcore.psw_save_area.addr); + add_str(p, "\n"); + sclp_early_printk(buf); + + p = add_str(buf, " R:"); + *p++ = hex_asc_lo(psw->per); + p = add_str(p, " T:"); + *p++ = hex_asc_lo(psw->dat); + p = add_str(p, " IO:"); + *p++ = hex_asc_lo(psw->io); + p = add_str(p, " EX:"); + *p++ = hex_asc_lo(psw->ext); + p = add_str(p, " Key:"); + *p++ = hex_asc_lo(psw->key); + p = add_str(p, " M:"); + *p++ = hex_asc_lo(psw->mcheck); + p = add_str(p, " W:"); + *p++ = hex_asc_lo(psw->wait); + p = add_str(p, " P:"); + *p++ = hex_asc_lo(psw->pstate); + p = add_str(p, " AS:"); + *p++ = hex_asc_lo(psw->as); + p = add_str(p, " CC:"); + *p++ = hex_asc_lo(psw->cc); + p = add_str(p, " PM:"); + *p++ = hex_asc_lo(psw->pm); + p = add_str(p, " RI:"); + *p++ = hex_asc_lo(psw->ri); + p = add_str(p, " EA:"); + *p++ = hex_asc_lo(psw->eaba); + add_str(p, "\n"); + sclp_early_printk(buf); + + for (row = 0; row < 4; row++) { + p = add_str(buf, row == 0 ? "GPRS:" : " "); + for (col = 0; col < 4; col++) { + p = add_str(p, " "); + p = add_val_as_hex(p, S390_lowcore.gpregs_save_area[row * 4 + col]); + } + add_str(p, "\n"); + sclp_early_printk(buf); + } +} diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c index 7b0d05414618be9e992f96298b1b92b38fea898c..596ca7cc4d7b88a7c37b93cc58d87651ffe4bd9d 100644 --- a/arch/s390/boot/startup.c +++ b/arch/s390/boot/startup.c @@ -112,6 +112,11 @@ static void handle_relocs(unsigned long offset) } } +static void clear_bss_section(void) +{ + memset((void *)vmlinux.default_lma + vmlinux.image_size, 0, vmlinux.bss_size); +} + void startup_kernel(void) { unsigned long random_lma; @@ -151,6 +156,7 @@ void startup_kernel(void) } else if (__kaslr_offset) memcpy((void *)vmlinux.default_lma, img, vmlinux.image_size); + clear_bss_section(); copy_bootdata(); if (IS_ENABLED(CONFIG_RELOCATABLE)) handle_relocs(__kaslr_offset); diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig index 74e78ec5beb688f30eec648db92d14e655be0675..347f48702edb17154779c38db7fcb3c38be8a540 100644 --- a/arch/s390/configs/debug_defconfig +++ b/arch/s390/configs/debug_defconfig @@ -717,6 +717,8 @@ CONFIG_CRYPTO_PAES_S390=m CONFIG_CRYPTO_SHA1_S390=m CONFIG_CRYPTO_SHA256_S390=m CONFIG_CRYPTO_SHA512_S390=m +CONFIG_CRYPTO_SHA3_256_S390=m +CONFIG_CRYPTO_SHA3_512_S390=m CONFIG_CRYPTO_DES_S390=m CONFIG_CRYPTO_AES_S390=m CONFIG_CRYPTO_GHASH_S390=m diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig index 68d3ca83302b1c2ae61727a974a0188aba1dfe4b..8514b8b9500f30ae2479684130bc3d5e375b2290 100644 --- a/arch/s390/configs/defconfig +++ b/arch/s390/configs/defconfig @@ -710,6 +710,8 @@ CONFIG_CRYPTO_PAES_S390=m CONFIG_CRYPTO_SHA1_S390=m CONFIG_CRYPTO_SHA256_S390=m CONFIG_CRYPTO_SHA512_S390=m +CONFIG_CRYPTO_SHA3_256_S390=m +CONFIG_CRYPTO_SHA3_512_S390=m CONFIG_CRYPTO_DES_S390=m CONFIG_CRYPTO_AES_S390=m CONFIG_CRYPTO_GHASH_S390=m diff --git a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile index a51010ea62fa4785530cd69abca7f1cb1737ad0d..12889d4652ccaa4b102b5ad9306569097545e255 100644 --- a/arch/s390/crypto/Makefile +++ b/arch/s390/crypto/Makefile @@ -6,6 +6,8 @@ obj-$(CONFIG_CRYPTO_SHA1_S390) += sha1_s390.o sha_common.o obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o sha_common.o obj-$(CONFIG_CRYPTO_SHA512_S390) += sha512_s390.o sha_common.o +obj-$(CONFIG_CRYPTO_SHA3_256_S390) += sha3_256_s390.o sha_common.o +obj-$(CONFIG_CRYPTO_SHA3_512_S390) += sha3_512_s390.o sha_common.o obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o obj-$(CONFIG_CRYPTO_PAES_S390) += paes_s390.o diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index d00f84add5f4cf0633c074b7662e44a43aac75ae..9803e96d29247e862f14dff26afbd7b1bb733b74 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -108,7 +108,7 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, return 0; } -static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +static void crypto_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); @@ -119,7 +119,7 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) cpacf_km(sctx->fc, &sctx->key, out, in, AES_BLOCK_SIZE); } -static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +static void crypto_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); @@ -172,8 +172,8 @@ static struct crypto_alg aes_alg = { .cia_min_keysize = AES_MIN_KEY_SIZE, .cia_max_keysize = AES_MAX_KEY_SIZE, .cia_setkey = aes_set_key, - .cia_encrypt = aes_encrypt, - .cia_decrypt = aes_decrypt, + .cia_encrypt = crypto_aes_encrypt, + .cia_decrypt = crypto_aes_decrypt, } } }; @@ -512,7 +512,7 @@ static int xts_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, unsigned long fc; int err; - err = xts_check_key(tfm, in_key, key_len); + err = xts_fallback_setkey(tfm, in_key, key_len); if (err) return err; @@ -529,7 +529,7 @@ static int xts_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, /* Check if the function code is available */ xts_ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0; if (!xts_ctx->fc) - return xts_fallback_setkey(tfm, in_key, key_len); + return 0; /* Split the XTS key into the two subkeys */ key_len = key_len / 2; @@ -586,7 +586,10 @@ static int xts_aes_encrypt(struct blkcipher_desc *desc, struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; - if (unlikely(!xts_ctx->fc)) + if (!nbytes) + return -EINVAL; + + if (unlikely(!xts_ctx->fc || (nbytes % XTS_BLOCK_SIZE) != 0)) return xts_fallback_encrypt(desc, dst, src, nbytes); blkcipher_walk_init(&walk, dst, src, nbytes); @@ -600,7 +603,10 @@ static int xts_aes_decrypt(struct blkcipher_desc *desc, struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; - if (unlikely(!xts_ctx->fc)) + if (!nbytes) + return -EINVAL; + + if (unlikely(!xts_ctx->fc || (nbytes % XTS_BLOCK_SIZE) != 0)) return xts_fallback_decrypt(desc, dst, src, nbytes); blkcipher_walk_init(&walk, dst, src, nbytes); diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index 374b42fc76379a20f758eaf66ddb840c44f87f8a..439b100c6f2ea967845d3dd154f959b2efe7eee2 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #define DES3_KEY_SIZE (3 * DES_KEY_SIZE) @@ -35,27 +35,24 @@ static int des_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len) { struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); - u32 tmp[DES_EXPKEY_WORDS]; + int err; - /* check for weak keys */ - if (!des_ekey(tmp, key) && - (tfm->crt_flags & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) { - tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; - return -EINVAL; - } + err = crypto_des_verify_key(tfm, key); + if (err) + return err; memcpy(ctx->key, key, key_len); return 0; } -static void des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +static void s390_des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); cpacf_km(CPACF_KM_DEA, ctx->key, out, in, DES_BLOCK_SIZE); } -static void des_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +static void s390_des_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); @@ -76,8 +73,8 @@ static struct crypto_alg des_alg = { .cia_min_keysize = DES_KEY_SIZE, .cia_max_keysize = DES_KEY_SIZE, .cia_setkey = des_setkey, - .cia_encrypt = des_encrypt, - .cia_decrypt = des_decrypt, + .cia_encrypt = s390_des_encrypt, + .cia_decrypt = s390_des_decrypt, } } }; @@ -227,8 +224,8 @@ static int des3_setkey(struct crypto_tfm *tfm, const u8 *key, struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); int err; - err = __des3_verify_key(&tfm->crt_flags, key); - if (unlikely(err)) + err = crypto_des3_ede_verify_key(tfm, key); + if (err) return err; memcpy(ctx->key, key, key_len); diff --git a/arch/s390/crypto/ghash_s390.c b/arch/s390/crypto/ghash_s390.c index eeeb6a7737a4ae41634ccb55578e23537288937c..a3e7400e031cab530d53a50509be157b1de53c0f 100644 --- a/arch/s390/crypto/ghash_s390.c +++ b/arch/s390/crypto/ghash_s390.c @@ -153,4 +153,4 @@ module_exit(ghash_mod_exit); MODULE_ALIAS_CRYPTO("ghash"); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("GHASH Message Digest Algorithm, s390 implementation"); +MODULE_DESCRIPTION("GHASH hash function, s390 implementation"); diff --git a/arch/s390/crypto/paes_s390.c b/arch/s390/crypto/paes_s390.c index e8d9fa54569cd9254541d6c28c230ff86548949d..6184dceed340b649400d091b4b6efae06ed08352 100644 --- a/arch/s390/crypto/paes_s390.c +++ b/arch/s390/crypto/paes_s390.c @@ -5,7 +5,7 @@ * s390 implementation of the AES Cipher Algorithm with protected keys. * * s390 Version: - * Copyright IBM Corp. 2017 + * Copyright IBM Corp. 2017,2019 * Author(s): Martin Schwidefsky * Harald Freudenberger */ @@ -25,16 +25,59 @@ #include #include +/* + * Key blobs smaller/bigger than these defines are rejected + * by the common code even before the individual setkey function + * is called. As paes can handle different kinds of key blobs + * and padding is also possible, the limits need to be generous. + */ +#define PAES_MIN_KEYSIZE 64 +#define PAES_MAX_KEYSIZE 256 + static u8 *ctrblk; static DEFINE_SPINLOCK(ctrblk_lock); static cpacf_mask_t km_functions, kmc_functions, kmctr_functions; struct key_blob { - __u8 key[MAXKEYBLOBSIZE]; + /* + * Small keys will be stored in the keybuf. Larger keys are + * stored in extra allocated memory. In both cases does + * key point to the memory where the key is stored. + * The code distinguishes by checking keylen against + * sizeof(keybuf). See the two following helper functions. + */ + u8 *key; + u8 keybuf[128]; unsigned int keylen; }; +static inline int _copy_key_to_kb(struct key_blob *kb, + const u8 *key, + unsigned int keylen) +{ + if (keylen <= sizeof(kb->keybuf)) + kb->key = kb->keybuf; + else { + kb->key = kmalloc(keylen, GFP_KERNEL); + if (!kb->key) + return -ENOMEM; + } + memcpy(kb->key, key, keylen); + kb->keylen = keylen; + + return 0; +} + +static inline void _free_kb_keybuf(struct key_blob *kb) +{ + if (kb->key && kb->key != kb->keybuf + && kb->keylen > sizeof(kb->keybuf)) { + kfree(kb->key); + kb->key = NULL; + } +} + struct s390_paes_ctx { struct key_blob kb; struct pkey_protkey pk; @@ -80,13 +123,33 @@ static int __paes_set_key(struct s390_paes_ctx *ctx) return ctx->fc ? 0 : -EINVAL; } +static int ecb_paes_init(struct crypto_tfm *tfm) +{ + struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->kb.key = NULL; + + return 0; +} + +static void ecb_paes_exit(struct crypto_tfm *tfm) +{ + struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); + + _free_kb_keybuf(&ctx->kb); +} + static int ecb_paes_set_key(struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len) { + int rc; struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); - memcpy(ctx->kb.key, in_key, key_len); - ctx->kb.keylen = key_len; + _free_kb_keybuf(&ctx->kb); + rc = _copy_key_to_kb(&ctx->kb, in_key, key_len); + if (rc) + return rc; + if (__paes_set_key(ctx)) { tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; return -EINVAL; @@ -148,10 +211,12 @@ static struct crypto_alg ecb_paes_alg = { .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(ecb_paes_alg.cra_list), + .cra_init = ecb_paes_init, + .cra_exit = ecb_paes_exit, .cra_u = { .blkcipher = { - .min_keysize = MINKEYBLOBSIZE, - .max_keysize = MAXKEYBLOBSIZE, + .min_keysize = PAES_MIN_KEYSIZE, + .max_keysize = PAES_MAX_KEYSIZE, .setkey = ecb_paes_set_key, .encrypt = ecb_paes_encrypt, .decrypt = ecb_paes_decrypt, @@ -159,6 +224,22 @@ static struct crypto_alg ecb_paes_alg = { } }; +static int cbc_paes_init(struct crypto_tfm *tfm) +{ + struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->kb.key = NULL; + + return 0; +} + +static void cbc_paes_exit(struct crypto_tfm *tfm) +{ + struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); + + _free_kb_keybuf(&ctx->kb); +} + static int __cbc_paes_set_key(struct s390_paes_ctx *ctx) { unsigned long fc; @@ -180,10 +261,14 @@ static int __cbc_paes_set_key(struct s390_paes_ctx *ctx) static int cbc_paes_set_key(struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len) { + int rc; struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); - memcpy(ctx->kb.key, in_key, key_len); - ctx->kb.keylen = key_len; + _free_kb_keybuf(&ctx->kb); + rc = _copy_key_to_kb(&ctx->kb, in_key, key_len); + if (rc) + return rc; + if (__cbc_paes_set_key(ctx)) { tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; return -EINVAL; @@ -252,10 +337,12 @@ static struct crypto_alg cbc_paes_alg = { .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(cbc_paes_alg.cra_list), + .cra_init = cbc_paes_init, + .cra_exit = cbc_paes_exit, .cra_u = { .blkcipher = { - .min_keysize = MINKEYBLOBSIZE, - .max_keysize = MAXKEYBLOBSIZE, + .min_keysize = PAES_MIN_KEYSIZE, + .max_keysize = PAES_MAX_KEYSIZE, .ivsize = AES_BLOCK_SIZE, .setkey = cbc_paes_set_key, .encrypt = cbc_paes_encrypt, @@ -264,6 +351,24 @@ static struct crypto_alg cbc_paes_alg = { } }; +static int xts_paes_init(struct crypto_tfm *tfm) +{ + struct s390_pxts_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->kb[0].key = NULL; + ctx->kb[1].key = NULL; + + return 0; +} + +static void xts_paes_exit(struct crypto_tfm *tfm) +{ + struct s390_pxts_ctx *ctx = crypto_tfm_ctx(tfm); + + _free_kb_keybuf(&ctx->kb[0]); + _free_kb_keybuf(&ctx->kb[1]); +} + static int __xts_paes_set_key(struct s390_pxts_ctx *ctx) { unsigned long fc; @@ -287,20 +392,27 @@ static int __xts_paes_set_key(struct s390_pxts_ctx *ctx) } static int xts_paes_set_key(struct crypto_tfm *tfm, const u8 *in_key, - unsigned int key_len) + unsigned int xts_key_len) { + int rc; struct s390_pxts_ctx *ctx = crypto_tfm_ctx(tfm); u8 ckey[2 * AES_MAX_KEY_SIZE]; - unsigned int ckey_len, keytok_len; + unsigned int ckey_len, key_len; - if (key_len % 2) + if (xts_key_len % 2) return -EINVAL; - keytok_len = key_len / 2; - memcpy(ctx->kb[0].key, in_key, keytok_len); - ctx->kb[0].keylen = keytok_len; - memcpy(ctx->kb[1].key, in_key + keytok_len, keytok_len); - ctx->kb[1].keylen = keytok_len; + key_len = xts_key_len / 2; + + _free_kb_keybuf(&ctx->kb[0]); + _free_kb_keybuf(&ctx->kb[1]); + rc = _copy_key_to_kb(&ctx->kb[0], in_key, key_len); + if (rc) + return rc; + rc = _copy_key_to_kb(&ctx->kb[1], in_key + key_len, key_len); + if (rc) + return rc; + if (__xts_paes_set_key(ctx)) { tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; return -EINVAL; @@ -394,10 +506,12 @@ static struct crypto_alg xts_paes_alg = { .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(xts_paes_alg.cra_list), + .cra_init = xts_paes_init, + .cra_exit = xts_paes_exit, .cra_u = { .blkcipher = { - .min_keysize = 2 * MINKEYBLOBSIZE, - .max_keysize = 2 * MAXKEYBLOBSIZE, + .min_keysize = 2 * PAES_MIN_KEYSIZE, + .max_keysize = 2 * PAES_MAX_KEYSIZE, .ivsize = AES_BLOCK_SIZE, .setkey = xts_paes_set_key, .encrypt = xts_paes_encrypt, @@ -406,6 +520,22 @@ static struct crypto_alg xts_paes_alg = { } }; +static int ctr_paes_init(struct crypto_tfm *tfm) +{ + struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->kb.key = NULL; + + return 0; +} + +static void ctr_paes_exit(struct crypto_tfm *tfm) +{ + struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); + + _free_kb_keybuf(&ctx->kb); +} + static int __ctr_paes_set_key(struct s390_paes_ctx *ctx) { unsigned long fc; @@ -428,10 +558,14 @@ static int __ctr_paes_set_key(struct s390_paes_ctx *ctx) static int ctr_paes_set_key(struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len) { + int rc; struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); - memcpy(ctx->kb.key, in_key, key_len); - ctx->kb.keylen = key_len; + _free_kb_keybuf(&ctx->kb); + rc = _copy_key_to_kb(&ctx->kb, in_key, key_len); + if (rc) + return rc; + if (__ctr_paes_set_key(ctx)) { tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; return -EINVAL; @@ -541,10 +675,12 @@ static struct crypto_alg ctr_paes_alg = { .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(ctr_paes_alg.cra_list), + .cra_init = ctr_paes_init, + .cra_exit = ctr_paes_exit, .cra_u = { .blkcipher = { - .min_keysize = MINKEYBLOBSIZE, - .max_keysize = MAXKEYBLOBSIZE, + .min_keysize = PAES_MIN_KEYSIZE, + .max_keysize = PAES_MAX_KEYSIZE, .ivsize = AES_BLOCK_SIZE, .setkey = ctr_paes_set_key, .encrypt = ctr_paes_encrypt, diff --git a/arch/s390/crypto/sha.h b/arch/s390/crypto/sha.h index d6f8258b44df381943b8c570883ace6484363edb..ada2f98c27b73fb917d9a9cc8f3049c5b483e6d3 100644 --- a/arch/s390/crypto/sha.h +++ b/arch/s390/crypto/sha.h @@ -12,15 +12,17 @@ #include #include +#include /* must be big enough for the largest SHA variant */ -#define SHA_MAX_STATE_SIZE (SHA512_DIGEST_SIZE / 4) -#define SHA_MAX_BLOCK_SIZE SHA512_BLOCK_SIZE +#define SHA3_STATE_SIZE 200 +#define CPACF_MAX_PARMBLOCK_SIZE SHA3_STATE_SIZE +#define SHA_MAX_BLOCK_SIZE SHA3_224_BLOCK_SIZE struct s390_sha_ctx { - u64 count; /* message length in bytes */ - u32 state[SHA_MAX_STATE_SIZE]; - u8 buf[2 * SHA_MAX_BLOCK_SIZE]; + u64 count; /* message length in bytes */ + u32 state[CPACF_MAX_PARMBLOCK_SIZE / sizeof(u32)]; + u8 buf[SHA_MAX_BLOCK_SIZE]; int func; /* KIMD function to use */ }; diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c index af7505148f806ebd1286fa32e4c9f06e97d22499..b52c87e449398ff3ebf691a0431adfcecaf54566 100644 --- a/arch/s390/crypto/sha256_s390.c +++ b/arch/s390/crypto/sha256_s390.c @@ -17,7 +17,7 @@ #include "sha.h" -static int sha256_init(struct shash_desc *desc) +static int s390_sha256_init(struct shash_desc *desc) { struct s390_sha_ctx *sctx = shash_desc_ctx(desc); @@ -60,7 +60,7 @@ static int sha256_import(struct shash_desc *desc, const void *in) static struct shash_alg sha256_alg = { .digestsize = SHA256_DIGEST_SIZE, - .init = sha256_init, + .init = s390_sha256_init, .update = s390_sha_update, .final = s390_sha_final, .export = sha256_export, @@ -76,7 +76,7 @@ static struct shash_alg sha256_alg = { } }; -static int sha224_init(struct shash_desc *desc) +static int s390_sha224_init(struct shash_desc *desc) { struct s390_sha_ctx *sctx = shash_desc_ctx(desc); @@ -96,7 +96,7 @@ static int sha224_init(struct shash_desc *desc) static struct shash_alg sha224_alg = { .digestsize = SHA224_DIGEST_SIZE, - .init = sha224_init, + .init = s390_sha224_init, .update = s390_sha_update, .final = s390_sha_final, .export = sha256_export, diff --git a/arch/s390/crypto/sha3_256_s390.c b/arch/s390/crypto/sha3_256_s390.c new file mode 100644 index 0000000000000000000000000000000000000000..460cbbbaa44ad31c039fdeb6e6779381389d1f2c --- /dev/null +++ b/arch/s390/crypto/sha3_256_s390.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Cryptographic API. + * + * s390 implementation of the SHA256 and SHA224 Secure Hash Algorithm. + * + * s390 Version: + * Copyright IBM Corp. 2019 + * Author(s): Joerg Schmidbauer (jschmidb@de.ibm.com) + */ +#include +#include +#include +#include +#include +#include +#include + +#include "sha.h" + +static int sha3_256_init(struct shash_desc *desc) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + + memset(sctx->state, 0, sizeof(sctx->state)); + sctx->count = 0; + sctx->func = CPACF_KIMD_SHA3_256; + + return 0; +} + +static int sha3_256_export(struct shash_desc *desc, void *out) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + struct sha3_state *octx = out; + + octx->rsiz = sctx->count; + memcpy(octx->st, sctx->state, sizeof(octx->st)); + memcpy(octx->buf, sctx->buf, sizeof(octx->buf)); + + return 0; +} + +static int sha3_256_import(struct shash_desc *desc, const void *in) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + const struct sha3_state *ictx = in; + + sctx->count = ictx->rsiz; + memcpy(sctx->state, ictx->st, sizeof(ictx->st)); + memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf)); + sctx->func = CPACF_KIMD_SHA3_256; + + return 0; +} + +static int sha3_224_import(struct shash_desc *desc, const void *in) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + const struct sha3_state *ictx = in; + + sctx->count = ictx->rsiz; + memcpy(sctx->state, ictx->st, sizeof(ictx->st)); + memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf)); + sctx->func = CPACF_KIMD_SHA3_224; + + return 0; +} + +static struct shash_alg sha3_256_alg = { + .digestsize = SHA3_256_DIGEST_SIZE, /* = 32 */ + .init = sha3_256_init, + .update = s390_sha_update, + .final = s390_sha_final, + .export = sha3_256_export, + .import = sha3_256_import, + .descsize = sizeof(struct s390_sha_ctx), + .statesize = sizeof(struct sha3_state), + .base = { + .cra_name = "sha3-256", + .cra_driver_name = "sha3-256-s390", + .cra_priority = 300, + .cra_blocksize = SHA3_256_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +static int sha3_224_init(struct shash_desc *desc) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + + memset(sctx->state, 0, sizeof(sctx->state)); + sctx->count = 0; + sctx->func = CPACF_KIMD_SHA3_224; + + return 0; +} + +static struct shash_alg sha3_224_alg = { + .digestsize = SHA3_224_DIGEST_SIZE, + .init = sha3_224_init, + .update = s390_sha_update, + .final = s390_sha_final, + .export = sha3_256_export, /* same as for 256 */ + .import = sha3_224_import, /* function code different! */ + .descsize = sizeof(struct s390_sha_ctx), + .statesize = sizeof(struct sha3_state), + .base = { + .cra_name = "sha3-224", + .cra_driver_name = "sha3-224-s390", + .cra_priority = 300, + .cra_blocksize = SHA3_224_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +static int __init sha3_256_s390_init(void) +{ + int ret; + + if (!cpacf_query_func(CPACF_KIMD, CPACF_KIMD_SHA3_256)) + return -ENODEV; + + ret = crypto_register_shash(&sha3_256_alg); + if (ret < 0) + goto out; + + ret = crypto_register_shash(&sha3_224_alg); + if (ret < 0) + crypto_unregister_shash(&sha3_256_alg); +out: + return ret; +} + +static void __exit sha3_256_s390_fini(void) +{ + crypto_unregister_shash(&sha3_224_alg); + crypto_unregister_shash(&sha3_256_alg); +} + +module_cpu_feature_match(MSA, sha3_256_s390_init); +module_exit(sha3_256_s390_fini); + +MODULE_ALIAS_CRYPTO("sha3-256"); +MODULE_ALIAS_CRYPTO("sha3-224"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA3-256 and SHA3-224 Secure Hash Algorithm"); diff --git a/arch/s390/crypto/sha3_512_s390.c b/arch/s390/crypto/sha3_512_s390.c new file mode 100644 index 0000000000000000000000000000000000000000..72cf460a53e536dc15935bf8102f4d50623b593a --- /dev/null +++ b/arch/s390/crypto/sha3_512_s390.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Cryptographic API. + * + * s390 implementation of the SHA512 and SHA384 Secure Hash Algorithm. + * + * Copyright IBM Corp. 2019 + * Author(s): Joerg Schmidbauer (jschmidb@de.ibm.com) + */ +#include +#include +#include +#include +#include +#include +#include + +#include "sha.h" + +static int sha3_512_init(struct shash_desc *desc) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + + memset(sctx->state, 0, sizeof(sctx->state)); + sctx->count = 0; + sctx->func = CPACF_KIMD_SHA3_512; + + return 0; +} + +static int sha3_512_export(struct shash_desc *desc, void *out) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + struct sha3_state *octx = out; + + octx->rsiz = sctx->count; + octx->rsizw = sctx->count >> 32; + + memcpy(octx->st, sctx->state, sizeof(octx->st)); + memcpy(octx->buf, sctx->buf, sizeof(octx->buf)); + + return 0; +} + +static int sha3_512_import(struct shash_desc *desc, const void *in) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + const struct sha3_state *ictx = in; + + if (unlikely(ictx->rsizw)) + return -ERANGE; + sctx->count = ictx->rsiz; + + memcpy(sctx->state, ictx->st, sizeof(ictx->st)); + memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf)); + sctx->func = CPACF_KIMD_SHA3_512; + + return 0; +} + +static int sha3_384_import(struct shash_desc *desc, const void *in) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + const struct sha3_state *ictx = in; + + if (unlikely(ictx->rsizw)) + return -ERANGE; + sctx->count = ictx->rsiz; + + memcpy(sctx->state, ictx->st, sizeof(ictx->st)); + memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf)); + sctx->func = CPACF_KIMD_SHA3_384; + + return 0; +} + +static struct shash_alg sha3_512_alg = { + .digestsize = SHA3_512_DIGEST_SIZE, + .init = sha3_512_init, + .update = s390_sha_update, + .final = s390_sha_final, + .export = sha3_512_export, + .import = sha3_512_import, + .descsize = sizeof(struct s390_sha_ctx), + .statesize = sizeof(struct sha3_state), + .base = { + .cra_name = "sha3-512", + .cra_driver_name = "sha3-512-s390", + .cra_priority = 300, + .cra_blocksize = SHA3_512_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +MODULE_ALIAS_CRYPTO("sha3-512"); + +static int sha3_384_init(struct shash_desc *desc) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + + memset(sctx->state, 0, sizeof(sctx->state)); + sctx->count = 0; + sctx->func = CPACF_KIMD_SHA3_384; + + return 0; +} + +static struct shash_alg sha3_384_alg = { + .digestsize = SHA3_384_DIGEST_SIZE, + .init = sha3_384_init, + .update = s390_sha_update, + .final = s390_sha_final, + .export = sha3_512_export, /* same as for 512 */ + .import = sha3_384_import, /* function code different! */ + .descsize = sizeof(struct s390_sha_ctx), + .statesize = sizeof(struct sha3_state), + .base = { + .cra_name = "sha3-384", + .cra_driver_name = "sha3-384-s390", + .cra_priority = 300, + .cra_blocksize = SHA3_384_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct s390_sha_ctx), + .cra_module = THIS_MODULE, + } +}; + +MODULE_ALIAS_CRYPTO("sha3-384"); + +static int __init init(void) +{ + int ret; + + if (!cpacf_query_func(CPACF_KIMD, CPACF_KIMD_SHA3_512)) + return -ENODEV; + ret = crypto_register_shash(&sha3_512_alg); + if (ret < 0) + goto out; + ret = crypto_register_shash(&sha3_384_alg); + if (ret < 0) + crypto_unregister_shash(&sha3_512_alg); +out: + return ret; +} + +static void __exit fini(void) +{ + crypto_unregister_shash(&sha3_512_alg); + crypto_unregister_shash(&sha3_384_alg); +} + +module_cpu_feature_match(MSA, init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA3-512 and SHA3-384 Secure Hash Algorithm"); diff --git a/arch/s390/crypto/sha_common.c b/arch/s390/crypto/sha_common.c index cf0718d121bcbb02f035f39474481947e447cf0e..d39e0f07921708132c18be6e955d24d7dc4ad119 100644 --- a/arch/s390/crypto/sha_common.c +++ b/arch/s390/crypto/sha_common.c @@ -20,7 +20,7 @@ int s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len) unsigned int index, n; /* how much is already in the buffer? */ - index = ctx->count & (bsize - 1); + index = ctx->count % bsize; ctx->count += len; if ((index + len) < bsize) @@ -37,7 +37,7 @@ int s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len) /* process as many blocks as possible */ if (len >= bsize) { - n = len & ~(bsize - 1); + n = (len / bsize) * bsize; cpacf_kimd(ctx->func, ctx->state, data, n); data += n; len -= n; @@ -50,34 +50,63 @@ int s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len) } EXPORT_SYMBOL_GPL(s390_sha_update); +static int s390_crypto_shash_parmsize(int func) +{ + switch (func) { + case CPACF_KLMD_SHA_1: + return 20; + case CPACF_KLMD_SHA_256: + return 32; + case CPACF_KLMD_SHA_512: + return 64; + case CPACF_KLMD_SHA3_224: + case CPACF_KLMD_SHA3_256: + case CPACF_KLMD_SHA3_384: + case CPACF_KLMD_SHA3_512: + return 200; + default: + return -EINVAL; + } +} + int s390_sha_final(struct shash_desc *desc, u8 *out) { struct s390_sha_ctx *ctx = shash_desc_ctx(desc); unsigned int bsize = crypto_shash_blocksize(desc->tfm); u64 bits; - unsigned int index, end, plen; - - /* SHA-512 uses 128 bit padding length */ - plen = (bsize > SHA256_BLOCK_SIZE) ? 16 : 8; + unsigned int n, mbl_offset; - /* must perform manual padding */ - index = ctx->count & (bsize - 1); - end = (index < bsize - plen) ? bsize : (2 * bsize); - - /* start pad with 1 */ - ctx->buf[index] = 0x80; - index++; - - /* pad with zeros */ - memset(ctx->buf + index, 0x00, end - index - 8); - - /* - * Append message length. Well, SHA-512 wants a 128 bit length value, - * nevertheless we use u64, should be enough for now... - */ + n = ctx->count % bsize; bits = ctx->count * 8; - memcpy(ctx->buf + end - 8, &bits, sizeof(bits)); - cpacf_kimd(ctx->func, ctx->state, ctx->buf, end); + mbl_offset = s390_crypto_shash_parmsize(ctx->func) / sizeof(u32); + if (mbl_offset < 0) + return -EINVAL; + + /* set total msg bit length (mbl) in CPACF parmblock */ + switch (ctx->func) { + case CPACF_KLMD_SHA_1: + case CPACF_KLMD_SHA_256: + memcpy(ctx->state + mbl_offset, &bits, sizeof(bits)); + break; + case CPACF_KLMD_SHA_512: + /* + * the SHA512 parmblock has a 128-bit mbl field, clear + * high-order u64 field, copy bits to low-order u64 field + */ + memset(ctx->state + mbl_offset, 0x00, sizeof(bits)); + mbl_offset += sizeof(u64) / sizeof(u32); + memcpy(ctx->state + mbl_offset, &bits, sizeof(bits)); + break; + case CPACF_KLMD_SHA3_224: + case CPACF_KLMD_SHA3_256: + case CPACF_KLMD_SHA3_384: + case CPACF_KLMD_SHA3_512: + break; + default: + return -EINVAL; + } + + cpacf_klmd(ctx->func, ctx->state, ctx->buf, n); /* copy digest to out */ memcpy(out, ctx->state, crypto_shash_digestsize(desc->tfm)); diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index ccad1398abd406eba3298cc85bec320161443566..a4418fc425b8d23d46128d8477f7af56e64bc2ad 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -76,7 +76,7 @@ static void hypfs_remove(struct dentry *dentry) else simple_unlink(d_inode(parent), dentry); } - d_delete(dentry); + d_drop(dentry); dput(dentry); inode_unlock(d_inode(parent)); } diff --git a/arch/s390/include/asm/cpacf.h b/arch/s390/include/asm/cpacf.h index e3d53eb6bcf581215b4d52ee5e7a38e25f8112b7..a092f63aac6a2e9ec20d7a3e8a9a881d342975b0 100644 --- a/arch/s390/include/asm/cpacf.h +++ b/arch/s390/include/asm/cpacf.h @@ -93,6 +93,10 @@ #define CPACF_KIMD_SHA_1 0x01 #define CPACF_KIMD_SHA_256 0x02 #define CPACF_KIMD_SHA_512 0x03 +#define CPACF_KIMD_SHA3_224 0x20 +#define CPACF_KIMD_SHA3_256 0x21 +#define CPACF_KIMD_SHA3_384 0x22 +#define CPACF_KIMD_SHA3_512 0x23 #define CPACF_KIMD_GHASH 0x41 /* @@ -103,6 +107,10 @@ #define CPACF_KLMD_SHA_1 0x01 #define CPACF_KLMD_SHA_256 0x02 #define CPACF_KLMD_SHA_512 0x03 +#define CPACF_KLMD_SHA3_224 0x20 +#define CPACF_KLMD_SHA3_256 0x21 +#define CPACF_KLMD_SHA3_384 0x22 +#define CPACF_KLMD_SHA3_512 0x23 /* * function codes for the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h index fcbd638fb9f4c353523c7a3f1f7dd1b56ecfd0fe..37f96b6f0e611a21785adab66b01005d91b3f043 100644 --- a/arch/s390/include/asm/gmap.h +++ b/arch/s390/include/asm/gmap.h @@ -9,6 +9,8 @@ #ifndef _ASM_S390_GMAP_H #define _ASM_S390_GMAP_H +#include + /* Generic bits for GMAP notification on DAT table entry changes. */ #define GMAP_NOTIFY_SHADOW 0x2 #define GMAP_NOTIFY_MPROT 0x1 @@ -46,7 +48,7 @@ struct gmap { struct radix_tree_root guest_to_host; struct radix_tree_root host_to_guest; spinlock_t guest_table_lock; - atomic_t ref_count; + refcount_t ref_count; unsigned long *table; unsigned long asce; unsigned long asce_end; diff --git a/arch/s390/include/asm/mem_detect.h b/arch/s390/include/asm/mem_detect.h index 6114b92ab667b7f558447d6d0156304dc52ff311..a7c922a690509a22d279c42de7e2b8312152ec9d 100644 --- a/arch/s390/include/asm/mem_detect.h +++ b/arch/s390/include/asm/mem_detect.h @@ -79,4 +79,16 @@ static inline void get_mem_detect_reserved(unsigned long *start, *size = 0; } +static inline unsigned long get_mem_detect_end(void) +{ + unsigned long start; + unsigned long end; + + if (mem_detect.count) { + __get_mem_detect_block(mem_detect.count - 1, &start, &end); + return end; + } + return 0; +} + #endif diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 9b274fcaacb680b1d2cc63c2ac7c3fe57ec1cde1..0c4600725fc2e908b98578d9febaa93f82df4ed5 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -86,6 +86,7 @@ extern unsigned long zero_page_mask; */ extern unsigned long VMALLOC_START; extern unsigned long VMALLOC_END; +#define VMALLOC_DEFAULT_SIZE ((128UL << 30) - MODULES_LEN) extern struct page *vmemmap; #define VMEM_MAX_PHYS ((unsigned long) vmemmap) diff --git a/arch/s390/include/asm/pkey.h b/arch/s390/include/asm/pkey.h index 9b6e79077866b253f211820a7e64074ffee81f50..dd3d20c332ace4492240722f62c7b6c3b9e5a705 100644 --- a/arch/s390/include/asm/pkey.h +++ b/arch/s390/include/asm/pkey.h @@ -2,7 +2,7 @@ /* * Kernelspace interface to the pkey device driver * - * Copyright IBM Corp. 2016 + * Copyright IBM Corp. 2016,2019 * * Author: Harald Freudenberger * @@ -15,116 +15,6 @@ #include #include -/* - * Generate (AES) random secure key. - * @param cardnr may be -1 (use default card) - * @param domain may be -1 (use default domain) - * @param keytype one of the PKEY_KEYTYPE values - * @param seckey pointer to buffer receiving the secure key - * @return 0 on success, negative errno value on failure - */ -int pkey_genseckey(__u16 cardnr, __u16 domain, - __u32 keytype, struct pkey_seckey *seckey); - -/* - * Generate (AES) secure key with given key value. - * @param cardnr may be -1 (use default card) - * @param domain may be -1 (use default domain) - * @param keytype one of the PKEY_KEYTYPE values - * @param clrkey pointer to buffer with clear key data - * @param seckey pointer to buffer receiving the secure key - * @return 0 on success, negative errno value on failure - */ -int pkey_clr2seckey(__u16 cardnr, __u16 domain, __u32 keytype, - const struct pkey_clrkey *clrkey, - struct pkey_seckey *seckey); - -/* - * Derive (AES) proteced key from the (AES) secure key blob. - * @param cardnr may be -1 (use default card) - * @param domain may be -1 (use default domain) - * @param seckey pointer to buffer with the input secure key - * @param protkey pointer to buffer receiving the protected key and - * additional info (type, length) - * @return 0 on success, negative errno value on failure - */ -int pkey_sec2protkey(__u16 cardnr, __u16 domain, - const struct pkey_seckey *seckey, - struct pkey_protkey *protkey); - -/* - * Derive (AES) protected key from a given clear key value. - * @param keytype one of the PKEY_KEYTYPE values - * @param clrkey pointer to buffer with clear key data - * @param protkey pointer to buffer receiving the protected key and - * additional info (type, length) - * @return 0 on success, negative errno value on failure - */ -int pkey_clr2protkey(__u32 keytype, - const struct pkey_clrkey *clrkey, - struct pkey_protkey *protkey); - -/* - * Search for a matching crypto card based on the Master Key - * Verification Pattern provided inside a secure key. - * @param seckey pointer to buffer with the input secure key - * @param cardnr pointer to cardnr, receives the card number on success - * @param domain pointer to domain, receives the domain number on success - * @param verify if set, always verify by fetching verification pattern - * from card - * @return 0 on success, negative errno value on failure. If no card could be - * found, -ENODEV is returned. - */ -int pkey_findcard(const struct pkey_seckey *seckey, - __u16 *cardnr, __u16 *domain, int verify); - -/* - * Find card and transform secure key to protected key. - * @param seckey pointer to buffer with the input secure key - * @param protkey pointer to buffer receiving the protected key and - * additional info (type, length) - * @return 0 on success, negative errno value on failure - */ -int pkey_skey2pkey(const struct pkey_seckey *seckey, - struct pkey_protkey *protkey); - -/* - * Verify the given secure key for being able to be useable with - * the pkey module. Check for correct key type and check for having at - * least one crypto card being able to handle this key (master key - * or old master key verification pattern matches). - * Return some info about the key: keysize in bits, keytype (currently - * only AES), flag if key is wrapped with an old MKVP. - * @param seckey pointer to buffer with the input secure key - * @param pcardnr pointer to cardnr, receives the card number on success - * @param pdomain pointer to domain, receives the domain number on success - * @param pkeysize pointer to keysize, receives the bitsize of the key - * @param pattributes pointer to attributes, receives additional info - * PKEY_VERIFY_ATTR_AES if the key is an AES key - * PKEY_VERIFY_ATTR_OLD_MKVP if key has old mkvp stored in - * @return 0 on success, negative errno value on failure. If no card could - * be found which is able to handle this key, -ENODEV is returned. - */ -int pkey_verifykey(const struct pkey_seckey *seckey, - u16 *pcardnr, u16 *pdomain, - u16 *pkeysize, u32 *pattributes); - -/* - * In-kernel API: Generate (AES) random protected key. - * @param keytype one of the PKEY_KEYTYPE values - * @param protkey pointer to buffer receiving the protected key - * @return 0 on success, negative errno value on failure - */ -int pkey_genprotkey(__u32 keytype, struct pkey_protkey *protkey); - -/* - * In-kernel API: Verify an (AES) protected key. - * @param protkey pointer to buffer containing the protected key to verify - * @return 0 on success, negative errno value on failure. In case the protected - * key is not valid -EKEYREJECTED is returned - */ -int pkey_verifyprotkey(const struct pkey_protkey *protkey); - /* * In-kernel API: Transform an key blob (of any type) into a protected key. * @param key pointer to a buffer containing the key blob @@ -132,7 +22,7 @@ int pkey_verifyprotkey(const struct pkey_protkey *protkey); * @param protkey pointer to buffer receiving the protected key * @return 0 on success, negative errno value on failure */ -int pkey_keyblob2pkey(const __u8 *key, __u32 keylen, +int pkey_keyblob2pkey(const u8 *key, u32 keylen, struct pkey_protkey *protkey); #endif /* _KAPI_PKEY_H */ diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index d56c519bc69686824f443ef87e4344244cbfefa0..51a0e4a2dc9618df3a05240e58c53fc36ddb5160 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -324,11 +324,9 @@ static inline void __noreturn disabled_wait(void) * Basic Machine Check/Program Check Handler. */ -extern void s390_base_mcck_handler(void); extern void s390_base_pgm_handler(void); extern void s390_base_ext_handler(void); -extern void (*s390_base_mcck_handler_fn)(void); extern void (*s390_base_pgm_handler_fn)(void); extern void (*s390_base_ext_handler_fn)(void); diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index f647d565bd6dc1374151f65ab2f76f84d7322e16..78e8a888306d68d7214090c44fbf1df2aa374909 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h @@ -16,6 +16,7 @@ #define QDIO_MAX_QUEUES_PER_IRQ 4 #define QDIO_MAX_BUFFERS_PER_Q 128 #define QDIO_MAX_BUFFERS_MASK (QDIO_MAX_BUFFERS_PER_Q - 1) +#define QDIO_BUFNR(num) ((num) & QDIO_MAX_BUFFERS_MASK) #define QDIO_MAX_ELEMENTS_PER_BUFFER 16 #define QDIO_SBAL_SIZE 256 @@ -359,7 +360,7 @@ struct qdio_initialize { qdio_handler_t *output_handler; void (**queue_start_poll_array) (struct ccw_device *, int, unsigned long); - int scan_threshold; + unsigned int scan_threshold; unsigned long int_parm; struct qdio_buffer **input_sbal_addr_array; struct qdio_buffer **output_sbal_addr_array; @@ -416,6 +417,9 @@ extern int do_QDIO(struct ccw_device *, unsigned int, int, unsigned int, extern int qdio_start_irq(struct ccw_device *, int); extern int qdio_stop_irq(struct ccw_device *, int); extern int qdio_get_next_buffers(struct ccw_device *, int, int *, int *); +extern int qdio_inspect_queue(struct ccw_device *cdev, unsigned int nr, + bool is_input, unsigned int *bufnr, + unsigned int *error); extern int qdio_shutdown(struct ccw_device *, int); extern int qdio_free(struct ccw_device *); extern int qdio_get_ssqd_desc(struct ccw_device *, struct qdio_ssqd_desc *); diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index 70bd65724ec4c06310380465c39709f6d3b73ff5..6dc6c4fbc8e2b1a59796afb96bff120d4c0f8a21 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -83,6 +83,7 @@ struct parmarea { extern int noexec_disabled; extern int memory_end_set; extern unsigned long memory_end; +extern unsigned long vmalloc_size; extern unsigned long max_physmem_end; extern unsigned long __swsusp_reset_dma; diff --git a/arch/s390/include/asm/string.h b/arch/s390/include/asm/string.h index 70d87db54e627c5b6c3d59e395b30404db69c85f..4c0690fc5167ee70757710b1be040cd34327e744 100644 --- a/arch/s390/include/asm/string.h +++ b/arch/s390/include/asm/string.h @@ -71,11 +71,16 @@ extern void *__memmove(void *dest, const void *src, size_t n); #define memcpy(dst, src, len) __memcpy(dst, src, len) #define memmove(dst, src, len) __memmove(dst, src, len) #define memset(s, c, n) __memset(s, c, n) +#define strlen(s) __strlen(s) + +#define __no_sanitize_prefix_strfunc(x) __##x #ifndef __NO_FORTIFY #define __NO_FORTIFY /* FORTIFY_SOURCE uses __builtin_memcpy, etc. */ #endif +#else +#define __no_sanitize_prefix_strfunc(x) x #endif /* defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__) */ void *__memset16(uint16_t *s, uint16_t v, size_t count); @@ -163,8 +168,8 @@ static inline char *strcpy(char *dst, const char *src) } #endif -#ifdef __HAVE_ARCH_STRLEN -static inline size_t strlen(const char *s) +#if defined(__HAVE_ARCH_STRLEN) || (defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__)) +static inline size_t __no_sanitize_prefix_strfunc(strlen)(const char *s) { register unsigned long r0 asm("0") = 0; const char *tmp = s; diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h index 47104e5b47fd47b7941e3631e8e8eea4798e3d21..436ec7636927379ff40432478e9f175d886a1e7d 100644 --- a/arch/s390/include/uapi/asm/kvm.h +++ b/arch/s390/include/uapi/asm/kvm.h @@ -231,6 +231,12 @@ struct kvm_guest_debug_arch { #define KVM_SYNC_GSCB (1UL << 9) #define KVM_SYNC_BPBC (1UL << 10) #define KVM_SYNC_ETOKEN (1UL << 11) + +#define KVM_SYNC_S390_VALID_FIELDS \ + (KVM_SYNC_PREFIX | KVM_SYNC_GPRS | KVM_SYNC_ACRS | KVM_SYNC_CRS | \ + KVM_SYNC_ARCH0 | KVM_SYNC_PFAULT | KVM_SYNC_VRS | KVM_SYNC_RICCB | \ + KVM_SYNC_FPRS | KVM_SYNC_GSCB | KVM_SYNC_BPBC | KVM_SYNC_ETOKEN) + /* length and alignment of the sdnx as a power of two */ #define SDNXC 8 #define SDNXL (1UL << SDNXC) diff --git a/arch/s390/include/uapi/asm/pkey.h b/arch/s390/include/uapi/asm/pkey.h index c0e86ce4a00b095048c6402f355e2cd2b0afcee6..e22f0720bbb8b0a4a51679977ee574b22838080d 100644 --- a/arch/s390/include/uapi/asm/pkey.h +++ b/arch/s390/include/uapi/asm/pkey.h @@ -2,7 +2,7 @@ /* * Userspace interface to the pkey device driver * - * Copyright IBM Corp. 2017 + * Copyright IBM Corp. 2017, 2019 * * Author: Harald Freudenberger * @@ -20,38 +20,74 @@ #define PKEY_IOCTL_MAGIC 'p' -#define SECKEYBLOBSIZE 64 /* secure key blob size is always 64 bytes */ -#define PROTKEYBLOBSIZE 80 /* protected key blob size is always 80 bytes */ -#define MAXPROTKEYSIZE 64 /* a protected key blob may be up to 64 bytes */ -#define MAXCLRKEYSIZE 32 /* a clear key value may be up to 32 bytes */ +#define SECKEYBLOBSIZE 64 /* secure key blob size is always 64 bytes */ +#define PROTKEYBLOBSIZE 80 /* protected key blob size is always 80 bytes */ +#define MAXPROTKEYSIZE 64 /* a protected key blob may be up to 64 bytes */ +#define MAXCLRKEYSIZE 32 /* a clear key value may be up to 32 bytes */ +#define MAXAESCIPHERKEYSIZE 136 /* our aes cipher keys have always 136 bytes */ -#define MINKEYBLOBSIZE SECKEYBLOBSIZE /* Minimum size of a key blob */ -#define MAXKEYBLOBSIZE PROTKEYBLOBSIZE /* Maximum size of a key blob */ +/* Minimum and maximum size of a key blob */ +#define MINKEYBLOBSIZE SECKEYBLOBSIZE +#define MAXKEYBLOBSIZE MAXAESCIPHERKEYSIZE /* defines for the type field within the pkey_protkey struct */ -#define PKEY_KEYTYPE_AES_128 1 -#define PKEY_KEYTYPE_AES_192 2 -#define PKEY_KEYTYPE_AES_256 3 +#define PKEY_KEYTYPE_AES_128 1 +#define PKEY_KEYTYPE_AES_192 2 +#define PKEY_KEYTYPE_AES_256 3 -/* Struct to hold a secure key blob */ +/* the newer ioctls use a pkey_key_type enum for type information */ +enum pkey_key_type { + PKEY_TYPE_CCA_DATA = (__u32) 1, + PKEY_TYPE_CCA_CIPHER = (__u32) 2, +}; + +/* the newer ioctls use a pkey_key_size enum for key size information */ +enum pkey_key_size { + PKEY_SIZE_AES_128 = (__u32) 128, + PKEY_SIZE_AES_192 = (__u32) 192, + PKEY_SIZE_AES_256 = (__u32) 256, + PKEY_SIZE_UNKNOWN = (__u32) 0xFFFFFFFF, +}; + +/* some of the newer ioctls use these flags */ +#define PKEY_FLAGS_MATCH_CUR_MKVP 0x00000002 +#define PKEY_FLAGS_MATCH_ALT_MKVP 0x00000004 + +/* keygenflags defines for CCA AES cipher keys */ +#define PKEY_KEYGEN_XPRT_SYM 0x00008000 +#define PKEY_KEYGEN_XPRT_UASY 0x00004000 +#define PKEY_KEYGEN_XPRT_AASY 0x00002000 +#define PKEY_KEYGEN_XPRT_RAW 0x00001000 +#define PKEY_KEYGEN_XPRT_CPAC 0x00000800 +#define PKEY_KEYGEN_XPRT_DES 0x00000080 +#define PKEY_KEYGEN_XPRT_AES 0x00000040 +#define PKEY_KEYGEN_XPRT_RSA 0x00000008 + +/* Struct to hold apqn target info (card/domain pair) */ +struct pkey_apqn { + __u16 card; + __u16 domain; +}; + +/* Struct to hold a CCA AES secure key blob */ struct pkey_seckey { __u8 seckey[SECKEYBLOBSIZE]; /* the secure key blob */ }; /* Struct to hold protected key and length info */ struct pkey_protkey { - __u32 type; /* key type, one of the PKEY_KEYTYPE values */ + __u32 type; /* key type, one of the PKEY_KEYTYPE_AES values */ __u32 len; /* bytes actually stored in protkey[] */ __u8 protkey[MAXPROTKEYSIZE]; /* the protected key blob */ }; -/* Struct to hold a clear key value */ +/* Struct to hold an AES clear key value */ struct pkey_clrkey { __u8 clrkey[MAXCLRKEYSIZE]; /* 16, 24, or 32 byte clear key value */ }; /* - * Generate secure key + * Generate CCA AES secure key. */ struct pkey_genseck { __u16 cardnr; /* in: card to use or FFFF for any */ @@ -62,7 +98,7 @@ struct pkey_genseck { #define PKEY_GENSECK _IOWR(PKEY_IOCTL_MAGIC, 0x01, struct pkey_genseck) /* - * Construct secure key from clear key value + * Construct CCA AES secure key from clear key value */ struct pkey_clr2seck { __u16 cardnr; /* in: card to use or FFFF for any */ @@ -74,7 +110,7 @@ struct pkey_clr2seck { #define PKEY_CLR2SECK _IOWR(PKEY_IOCTL_MAGIC, 0x02, struct pkey_clr2seck) /* - * Fabricate protected key from a secure key + * Fabricate AES protected key from a CCA AES secure key */ struct pkey_sec2protk { __u16 cardnr; /* in: card to use or FFFF for any */ @@ -85,7 +121,7 @@ struct pkey_sec2protk { #define PKEY_SEC2PROTK _IOWR(PKEY_IOCTL_MAGIC, 0x03, struct pkey_sec2protk) /* - * Fabricate protected key from an clear key value + * Fabricate AES protected key from clear key value */ struct pkey_clr2protk { __u32 keytype; /* in: key type to generate */ @@ -96,7 +132,7 @@ struct pkey_clr2protk { /* * Search for matching crypto card based on the Master Key - * Verification Pattern provided inside a secure key. + * Verification Pattern provided inside a CCA AES secure key. */ struct pkey_findcard { struct pkey_seckey seckey; /* in: the secure key blob */ @@ -115,7 +151,7 @@ struct pkey_skey2pkey { #define PKEY_SKEY2PKEY _IOWR(PKEY_IOCTL_MAGIC, 0x06, struct pkey_skey2pkey) /* - * Verify the given secure key for being able to be useable with + * Verify the given CCA AES secure key for being able to be useable with * the pkey module. Check for correct key type and check for having at * least one crypto card being able to handle this key (master key * or old master key verification pattern matches). @@ -134,7 +170,7 @@ struct pkey_verifykey { #define PKEY_VERIFY_ATTR_OLD_MKVP 0x00000100 /* key has old MKVP value */ /* - * Generate (AES) random protected key. + * Generate AES random protected key. */ struct pkey_genprotk { __u32 keytype; /* in: key type to generate */ @@ -144,7 +180,7 @@ struct pkey_genprotk { #define PKEY_GENPROTK _IOWR(PKEY_IOCTL_MAGIC, 0x08, struct pkey_genprotk) /* - * Verify an (AES) protected key. + * Verify an AES protected key. */ struct pkey_verifyprotk { struct pkey_protkey protkey; /* in: the protected key to verify */ @@ -160,7 +196,184 @@ struct pkey_kblob2pkey { __u32 keylen; /* in: the key blob length */ struct pkey_protkey protkey; /* out: the protected key */ }; - #define PKEY_KBLOB2PROTK _IOWR(PKEY_IOCTL_MAGIC, 0x0A, struct pkey_kblob2pkey) +/* + * Generate secure key, version 2. + * Generate either a CCA AES secure key or a CCA AES cipher key. + * There needs to be a list of apqns given with at least one entry in there. + * All apqns in the list need to be exact apqns, 0xFFFF as ANY card or domain + * is not supported. The implementation walks through the list of apqns and + * tries to send the request to each apqn without any further checking (like + * card type or online state). If the apqn fails, simple the next one in the + * list is tried until success (return 0) or the end of the list is reached + * (return -1 with errno ENODEV). You may use the PKEY_APQNS4KT ioctl to + * generate a list of apqns based on the key type to generate. + * The keygenflags argument is passed to the low level generation functions + * individual for the key type and has a key type specific meaning. Currently + * only CCA AES cipher keys react to this parameter: Use one or more of the + * PKEY_KEYGEN_* flags to widen the export possibilities. By default a cipher + * key is only exportable for CPACF (PKEY_KEYGEN_XPRT_CPAC). + */ +struct pkey_genseck2 { + struct pkey_apqn __user *apqns; /* in: ptr to list of apqn targets*/ + __u32 apqn_entries; /* in: # of apqn target list entries */ + enum pkey_key_type type; /* in: key type to generate */ + enum pkey_key_size size; /* in: key size to generate */ + __u32 keygenflags; /* in: key generation flags */ + __u8 __user *key; /* in: pointer to key blob buffer */ + __u32 keylen; /* in: available key blob buffer size */ + /* out: actual key blob size */ +}; +#define PKEY_GENSECK2 _IOWR(PKEY_IOCTL_MAGIC, 0x11, struct pkey_genseck2) + +/* + * Generate secure key from clear key value, version 2. + * Construct a CCA AES secure key or CCA AES cipher key from a given clear key + * value. + * There needs to be a list of apqns given with at least one entry in there. + * All apqns in the list need to be exact apqns, 0xFFFF as ANY card or domain + * is not supported. The implementation walks through the list of apqns and + * tries to send the request to each apqn without any further checking (like + * card type or online state). If the apqn fails, simple the next one in the + * list is tried until success (return 0) or the end of the list is reached + * (return -1 with errno ENODEV). You may use the PKEY_APQNS4KT ioctl to + * generate a list of apqns based on the key type to generate. + * The keygenflags argument is passed to the low level generation functions + * individual for the key type and has a key type specific meaning. Currently + * only CCA AES cipher keys react to this parameter: Use one or more of the + * PKEY_KEYGEN_* flags to widen the export possibilities. By default a cipher + * key is only exportable for CPACF (PKEY_KEYGEN_XPRT_CPAC). + */ +struct pkey_clr2seck2 { + struct pkey_apqn __user *apqns; /* in: ptr to list of apqn targets */ + __u32 apqn_entries; /* in: # of apqn target list entries */ + enum pkey_key_type type; /* in: key type to generate */ + enum pkey_key_size size; /* in: key size to generate */ + __u32 keygenflags; /* in: key generation flags */ + struct pkey_clrkey clrkey; /* in: the clear key value */ + __u8 __user *key; /* in: pointer to key blob buffer */ + __u32 keylen; /* in: available key blob buffer size */ + /* out: actual key blob size */ +}; +#define PKEY_CLR2SECK2 _IOWR(PKEY_IOCTL_MAGIC, 0x12, struct pkey_clr2seck2) + +/* + * Verify the given secure key, version 2. + * Check for correct key type. If cardnr and domain are given (are not + * 0xFFFF) also check if this apqn is able to handle this type of key. + * If cardnr and/or domain is 0xFFFF, on return these values are filled + * with one apqn able to handle this key. + * The function also checks for the master key verification patterns + * of the key matching to the current or alternate mkvp of the apqn. + * Currently CCA AES secure keys and CCA AES cipher keys are supported. + * The flags field is updated with some additional info about the apqn mkvp + * match: If the current mkvp matches to the key's mkvp then the + * PKEY_FLAGS_MATCH_CUR_MKVP bit is set, if the alternate mkvp matches to + * the key's mkvp the PKEY_FLAGS_MATCH_ALT_MKVP is set. For CCA keys the + * alternate mkvp is the old master key verification pattern. + * CCA AES secure keys are also checked to have the CPACF export allowed + * bit enabled (XPRTCPAC) in the kmf1 field. + * The ioctl returns 0 as long as the given or found apqn matches to + * matches with the current or alternate mkvp to the key's mkvp. If the given + * apqn does not match or there is no such apqn found, -1 with errno + * ENODEV is returned. + */ +struct pkey_verifykey2 { + __u8 __user *key; /* in: pointer to key blob */ + __u32 keylen; /* in: key blob size */ + __u16 cardnr; /* in/out: card number */ + __u16 domain; /* in/out: domain number */ + enum pkey_key_type type; /* out: the key type */ + enum pkey_key_size size; /* out: the key size */ + __u32 flags; /* out: additional key info flags */ +}; +#define PKEY_VERIFYKEY2 _IOWR(PKEY_IOCTL_MAGIC, 0x17, struct pkey_verifykey2) + +/* + * Transform a key blob (of any type) into a protected key, version 2. + * There needs to be a list of apqns given with at least one entry in there. + * All apqns in the list need to be exact apqns, 0xFFFF as ANY card or domain + * is not supported. The implementation walks through the list of apqns and + * tries to send the request to each apqn without any further checking (like + * card type or online state). If the apqn fails, simple the next one in the + * list is tried until success (return 0) or the end of the list is reached + * (return -1 with errno ENODEV). You may use the PKEY_APQNS4K ioctl to + * generate a list of apqns based on the key. + */ +struct pkey_kblob2pkey2 { + __u8 __user *key; /* in: pointer to key blob */ + __u32 keylen; /* in: key blob size */ + struct pkey_apqn __user *apqns; /* in: ptr to list of apqn targets */ + __u32 apqn_entries; /* in: # of apqn target list entries */ + struct pkey_protkey protkey; /* out: the protected key */ +}; +#define PKEY_KBLOB2PROTK2 _IOWR(PKEY_IOCTL_MAGIC, 0x1A, struct pkey_kblob2pkey2) + +/* + * Build a list of APQNs based on a key blob given. + * Is able to find out which type of secure key is given (CCA AES secure + * key or CCA AES cipher key) and tries to find all matching crypto cards + * based on the MKVP and maybe other criterias (like CCA AES cipher keys + * need a CEX5C or higher). The list of APQNs is further filtered by the key's + * mkvp which needs to match to either the current mkvp or the alternate mkvp + * (which is the old mkvp on CCA adapters) of the apqns. The flags argument may + * be used to limit the matching apqns. If the PKEY_FLAGS_MATCH_CUR_MKVP is + * given, only the current mkvp of each apqn is compared. Likewise with the + * PKEY_FLAGS_MATCH_ALT_MKVP. If both are given, it is assumed to + * return apqns where either the current or the alternate mkvp + * matches. At least one of the matching flags needs to be given. + * The list of matching apqns is stored into the space given by the apqns + * argument and the number of stored entries goes into apqn_entries. If the list + * is empty (apqn_entries is 0) the apqn_entries field is updated to the number + * of apqn targets found and the ioctl returns with 0. If apqn_entries is > 0 + * but the number of apqn targets does not fit into the list, the apqn_targets + * field is updatedd with the number of reqired entries but there are no apqn + * values stored in the list and the ioctl returns with ENOSPC. If no matching + * APQN is found, the ioctl returns with 0 but the apqn_entries value is 0. + */ +struct pkey_apqns4key { + __u8 __user *key; /* in: pointer to key blob */ + __u32 keylen; /* in: key blob size */ + __u32 flags; /* in: match controlling flags */ + struct pkey_apqn __user *apqns; /* in/out: ptr to list of apqn targets*/ + __u32 apqn_entries; /* in: max # of apqn entries in the list */ + /* out: # apqns stored into the list */ +}; +#define PKEY_APQNS4K _IOWR(PKEY_IOCTL_MAGIC, 0x1B, struct pkey_apqns4key) + +/* + * Build a list of APQNs based on a key type given. + * Build a list of APQNs based on a given key type and maybe further + * restrict the list by given master key verification patterns. + * For different key types there may be different ways to match the + * master key verification patterns. For CCA keys (CCA data key and CCA + * cipher key) the first 8 bytes of cur_mkvp refer to the current mkvp value + * of the apqn and the first 8 bytes of the alt_mkvp refer to the old mkvp. + * The flags argument controls if the apqns current and/or alternate mkvp + * should match. If the PKEY_FLAGS_MATCH_CUR_MKVP is given, only the current + * mkvp of each apqn is compared. Likewise with the PKEY_FLAGS_MATCH_ALT_MKVP. + * If both are given, it is assumed to return apqns where either the + * current or the alternate mkvp matches. If no match flag is given + * (flags is 0) the mkvp values are ignored for the match process. + * The list of matching apqns is stored into the space given by the apqns + * argument and the number of stored entries goes into apqn_entries. If the list + * is empty (apqn_entries is 0) the apqn_entries field is updated to the number + * of apqn targets found and the ioctl returns with 0. If apqn_entries is > 0 + * but the number of apqn targets does not fit into the list, the apqn_targets + * field is updatedd with the number of reqired entries but there are no apqn + * values stored in the list and the ioctl returns with ENOSPC. If no matching + * APQN is found, the ioctl returns with 0 but the apqn_entries value is 0. + */ +struct pkey_apqns4keytype { + enum pkey_key_type type; /* in: key type */ + __u8 cur_mkvp[32]; /* in: current mkvp */ + __u8 alt_mkvp[32]; /* in: alternate mkvp */ + __u32 flags; /* in: match controlling flags */ + struct pkey_apqn __user *apqns; /* in/out: ptr to list of apqn targets*/ + __u32 apqn_entries; /* in: max # of apqn entries in the list */ + /* out: # apqns stored into the list */ +}; +#define PKEY_APQNS4KT _IOWR(PKEY_IOCTL_MAGIC, 0x1C, struct pkey_apqns4keytype) + #endif /* _UAPI_PKEY_H */ diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 0f255b54b0512a4d996704081a1cda97bf91576e..7edbbcd8228ab14775a36be2a12206adb257f493 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -10,20 +10,12 @@ CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) # Do not trace early setup code CFLAGS_REMOVE_early.o = $(CC_FLAGS_FTRACE) -CFLAGS_REMOVE_early_nobss.o = $(CC_FLAGS_FTRACE) endif GCOV_PROFILE_early.o := n -GCOV_PROFILE_early_nobss.o := n - KCOV_INSTRUMENT_early.o := n -KCOV_INSTRUMENT_early_nobss.o := n - UBSAN_SANITIZE_early.o := n -UBSAN_SANITIZE_early_nobss.o := n - -KASAN_SANITIZE_early_nobss.o := n KASAN_SANITIZE_ipl.o := n KASAN_SANITIZE_machine_kexec.o := n @@ -48,7 +40,7 @@ CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o -obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o early_nobss.o +obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o obj-y += sysinfo.o lgr.o os_info.o machine_kexec.o pgm_check.o obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o alternative.o @@ -90,6 +82,3 @@ obj-$(CONFIG_TRACEPOINTS) += trace.o # vdso obj-y += vdso64/ obj-$(CONFIG_COMPAT_VDSO) += vdso32/ - -chkbss := head64.o early_nobss.o -include $(srctree)/arch/s390/scripts/Makefile.chkbss diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S index 2f39ea57f3589440ff7e8f7c00c1dfda4f80edd8..b79e0fd571f83a30d28cff98b10402496f41b9ed 100644 --- a/arch/s390/kernel/base.S +++ b/arch/s390/kernel/base.S @@ -16,27 +16,6 @@ GEN_BR_THUNK %r9 GEN_BR_THUNK %r14 -ENTRY(s390_base_mcck_handler) - basr %r13,0 -0: lg %r15,__LC_NODAT_STACK # load panic stack - aghi %r15,-STACK_FRAME_OVERHEAD - larl %r1,s390_base_mcck_handler_fn - lg %r9,0(%r1) - ltgr %r9,%r9 - jz 1f - BASR_EX %r14,%r9 -1: la %r1,4095 - lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) - lpswe __LC_MCK_OLD_PSW -ENDPROC(s390_base_mcck_handler) - - .section .bss - .align 8 - .globl s390_base_mcck_handler_fn -s390_base_mcck_handler_fn: - .quad 0 - .previous - ENTRY(s390_base_ext_handler) stmg %r0,%r15,__LC_SAVE_AREA_ASYNC basr %r13,0 diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 6312fed48530b830e850c59627a643895592a90c..b432d63d0b373fa0d5abd62860f8e9fde54151c4 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -32,6 +32,21 @@ #include #include "entry.h" +static void __init reset_tod_clock(void) +{ + u64 time; + + if (store_tod_clock(&time) == 0) + return; + /* TOD clock not running. Set the clock to Unix Epoch. */ + if (set_tod_clock(TOD_UNIX_EPOCH) != 0 || store_tod_clock(&time) != 0) + disabled_wait(); + + memset(tod_clock_base, 0, 16); + *(__u64 *) &tod_clock_base[1] = TOD_UNIX_EPOCH; + S390_lowcore.last_update_clock = TOD_UNIX_EPOCH; +} + /* * Initialize storage key for kernel pages */ @@ -301,6 +316,7 @@ static void __init check_image_bootable(void) void __init startup_init(void) { + reset_tod_clock(); check_image_bootable(); time_early_init(); init_kernel_storage_key(); diff --git a/arch/s390/kernel/early_nobss.c b/arch/s390/kernel/early_nobss.c deleted file mode 100644 index 52a3ef959341a0be9f3f8f414ccfd6882a4eef4c..0000000000000000000000000000000000000000 --- a/arch/s390/kernel/early_nobss.c +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright IBM Corp. 2007, 2018 - */ - -/* - * Early setup functions which may not rely on an initialized bss - * section. The last thing that is supposed to happen here is - * initialization of the bss section. - */ - -#include -#include -#include -#include -#include -#include -#include "entry.h" - -static void __init reset_tod_clock(void) -{ - u64 time; - - if (store_tod_clock(&time) == 0) - return; - /* TOD clock not running. Set the clock to Unix Epoch. */ - if (set_tod_clock(TOD_UNIX_EPOCH) != 0 || store_tod_clock(&time) != 0) - disabled_wait(); - - memset(tod_clock_base, 0, 16); - *(__u64 *) &tod_clock_base[1] = TOD_UNIX_EPOCH; - S390_lowcore.last_update_clock = TOD_UNIX_EPOCH; -} - -static void __init clear_bss_section(void) -{ - memset(__bss_start, 0, __bss_stop - __bss_start); -} - -void __init startup_init_nobss(void) -{ - reset_tod_clock(); - clear_bss_section(); - kasan_early_init(); -} diff --git a/arch/s390/kernel/early_printk.c b/arch/s390/kernel/early_printk.c index 40c1dfec944e6040c3f1402679f318250190ffb4..6f24d83bc5dc0e57e57e8eae9bf857838b0169d0 100644 --- a/arch/s390/kernel/early_printk.c +++ b/arch/s390/kernel/early_printk.c @@ -25,7 +25,7 @@ static int __init setup_early_printk(char *buf) if (early_console) return 0; /* Accept only "earlyprintk" and "earlyprintk=sclp" */ - if (buf && strncmp(buf, "sclp", 4)) + if (buf && !str_has_prefix(buf, "sclp")) return 0; if (!sclp.has_linemode && !sclp.has_vt220) return 0; diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index f384a18e6c2609ef50c03afb288575893b2730c1..0d9ee198f4eb2dbe36eb98f3dd8a81635cd50033 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -34,11 +34,9 @@ ENTRY(startup_continue) larl %r14,init_task stg %r14,__LC_CURRENT larl %r15,init_thread_union+THREAD_SIZE-STACK_FRAME_OVERHEAD -# -# Early setup functions that may not rely on an initialized bss section, -# like moving the initrd. Returns with an initialized bss section. -# - brasl %r14,startup_init_nobss +#ifdef CONFIG_KASAN + brasl %r14,kasan_early_init +#endif # # Early machine initialization and detection functions. # diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 31889db609e904cbafbc2bdab9aa9500fe793b09..ba8f19bb438b85c0571dedf0d7295d4715091821 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -472,11 +472,11 @@ int module_finalize(const Elf_Ehdr *hdr, apply_alternatives(aseg, aseg + s->sh_size); if (IS_ENABLED(CONFIG_EXPOLINE) && - (!strncmp(".s390_indirect", secname, 14))) + (str_has_prefix(secname, ".s390_indirect"))) nospec_revert(aseg, aseg + s->sh_size); if (IS_ENABLED(CONFIG_EXPOLINE) && - (!strncmp(".s390_return", secname, 12))) + (str_has_prefix(secname, ".s390_return"))) nospec_revert(aseg, aseg + s->sh_size); } diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index 1266194afb026fb04d626ff8f0a598b7cb2f4cbe..292a452cd1f30f542d1de0fc452ace16d2eea796 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c @@ -514,7 +514,6 @@ static void extend_sampling_buffer(struct sf_buffer *sfb, sfb_pending_allocs(sfb, hwc)); } - /* Number of perf events counting hardware events */ static atomic_t num_events; /* Used to avoid races in calling reserve/release_cpumf_hardware */ @@ -923,9 +922,10 @@ static void cpumsf_pmu_enable(struct pmu *pmu) lpp(&S390_lowcore.lpp); debug_sprintf_event(sfdbg, 6, "pmu_enable: es=%i cs=%i ed=%i cd=%i " - "tear=%p dear=%p\n", cpuhw->lsctl.es, cpuhw->lsctl.cs, - cpuhw->lsctl.ed, cpuhw->lsctl.cd, - (void *) cpuhw->lsctl.tear, (void *) cpuhw->lsctl.dear); + "tear=%p dear=%p\n", cpuhw->lsctl.es, + cpuhw->lsctl.cs, cpuhw->lsctl.ed, cpuhw->lsctl.cd, + (void *) cpuhw->lsctl.tear, + (void *) cpuhw->lsctl.dear); } static void cpumsf_pmu_disable(struct pmu *pmu) @@ -1083,7 +1083,8 @@ static void debug_sample_entry(struct hws_basic_entry *sample, struct hws_trailer_entry *te) { debug_sprintf_event(sfdbg, 4, "hw_collect_samples: Found unknown " - "sampling data entry: te->f=%i basic.def=%04x (%p)\n", + "sampling data entry: te->f=%i basic.def=%04x " + "(%p)\n", te->f, sample->def, sample); } @@ -1216,7 +1217,7 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all) /* Timestamps are valid for full sample-data-blocks only */ debug_sprintf_event(sfdbg, 6, "hw_perf_event_update: sdbt=%p " - "overflow=%llu timestamp=0x%llx\n", + "overflow=%llu timestamp=%#llx\n", sdbt, te->overflow, (te->f) ? trailer_timestamp(te) : 0ULL); @@ -1879,10 +1880,12 @@ static struct attribute_group cpumsf_pmu_events_group = { .name = "events", .attrs = cpumsf_pmu_events_attr, }; + static struct attribute_group cpumsf_pmu_format_group = { .name = "format", .attrs = cpumsf_pmu_format_attr, }; + static const struct attribute_group *cpumsf_pmu_attr_groups[] = { &cpumsf_pmu_events_group, &cpumsf_pmu_format_group, @@ -1938,7 +1941,8 @@ static void cpumf_measurement_alert(struct ext_code ext_code, /* Report measurement alerts only for non-PRA codes */ if (alert != CPU_MF_INT_SF_PRA) - debug_sprintf_event(sfdbg, 6, "measurement alert: 0x%x\n", alert); + debug_sprintf_event(sfdbg, 6, "measurement alert: %#x\n", + alert); /* Sampling authorization change request */ if (alert & CPU_MF_INT_SF_SACA) @@ -1959,6 +1963,7 @@ static void cpumf_measurement_alert(struct ext_code ext_code, sf_disable(); } } + static int cpusf_pmu_setup(unsigned int cpu, int flags) { /* Ignore the notification if no events are scheduled on the PMU. @@ -2096,5 +2101,6 @@ static int __init init_cpum_sampling_pmu(void) out: return err; } + arch_initcall(init_cpum_sampling_pmu); core_param(cpum_sfb_size, CPUM_SF_MAX_SDB, sfb_size, 0640); diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 63873aa6693fe0881ad3eeb040bb285674025ca4..b0afec673f77844986bc68262bae4ddae88eb839 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -184,20 +184,30 @@ unsigned long get_wchan(struct task_struct *p) if (!p || p == current || p->state == TASK_RUNNING || !task_stack_page(p)) return 0; + + if (!try_get_task_stack(p)) + return 0; + low = task_stack_page(p); high = (struct stack_frame *) task_pt_regs(p); sf = (struct stack_frame *) p->thread.ksp; - if (sf <= low || sf > high) - return 0; + if (sf <= low || sf > high) { + return_address = 0; + goto out; + } for (count = 0; count < 16; count++) { - sf = (struct stack_frame *) sf->back_chain; - if (sf <= low || sf > high) - return 0; - return_address = sf->gprs[8]; + sf = (struct stack_frame *)READ_ONCE_NOCHECK(sf->back_chain); + if (sf <= low || sf > high) { + return_address = 0; + goto out; + } + return_address = READ_ONCE_NOCHECK(sf->gprs[8]); if (!in_sched_functions(return_address)) - return return_address; + goto out; } - return 0; +out: + put_task_stack(p); + return return_address; } unsigned long arch_align_stack(unsigned long sp) diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 2531779009503700f7d117e56f11c81df20d2108..3ff291bc63b7e596767aed95607a9138bdab95d4 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -99,6 +99,7 @@ int __bootdata_preserved(prot_virt_guest); int __bootdata(noexec_disabled); int __bootdata(memory_end_set); unsigned long __bootdata(memory_end); +unsigned long __bootdata(vmalloc_size); unsigned long __bootdata(max_physmem_end); struct mem_detect_info __bootdata(mem_detect); @@ -168,15 +169,15 @@ static void __init set_preferred_console(void) static int __init conmode_setup(char *str) { #if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) - if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0) + if (!strcmp(str, "hwc") || !strcmp(str, "sclp")) SET_CONSOLE_SCLP; #endif #if defined(CONFIG_TN3215_CONSOLE) - if (strncmp(str, "3215", 5) == 0) + if (!strcmp(str, "3215")) SET_CONSOLE_3215; #endif #if defined(CONFIG_TN3270_CONSOLE) - if (strncmp(str, "3270", 5) == 0) + if (!strcmp(str, "3270")) SET_CONSOLE_3270; #endif set_preferred_console(); @@ -211,7 +212,7 @@ static void __init conmode_default(void) #endif return; } - if (strncmp(ptr + 8, "3270", 4) == 0) { + if (str_has_prefix(ptr + 8, "3270")) { #if defined(CONFIG_TN3270_CONSOLE) SET_CONSOLE_3270; #elif defined(CONFIG_TN3215_CONSOLE) @@ -219,7 +220,7 @@ static void __init conmode_default(void) #elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) SET_CONSOLE_SCLP; #endif - } else if (strncmp(ptr + 8, "3215", 4) == 0) { + } else if (str_has_prefix(ptr + 8, "3215")) { #if defined(CONFIG_TN3215_CONSOLE) SET_CONSOLE_3215; #elif defined(CONFIG_TN3270_CONSOLE) @@ -302,15 +303,6 @@ void machine_power_off(void) void (*pm_power_off)(void) = machine_power_off; EXPORT_SYMBOL_GPL(pm_power_off); -static int __init parse_vmalloc(char *arg) -{ - if (!arg) - return -EINVAL; - VMALLOC_END = (memparse(arg, &arg) + PAGE_SIZE - 1) & PAGE_MASK; - return 0; -} -early_param("vmalloc", parse_vmalloc); - void *restart_stack __section(.data); unsigned long stack_alloc(void) @@ -563,10 +555,9 @@ static void __init setup_resources(void) static void __init setup_memory_end(void) { - unsigned long vmax, vmalloc_size, tmp; + unsigned long vmax, tmp; /* Choose kernel address space layout: 3 or 4 levels. */ - vmalloc_size = VMALLOC_END ?: (128UL << 30) - MODULES_LEN; if (IS_ENABLED(CONFIG_KASAN)) { vmax = IS_ENABLED(CONFIG_KASAN_S390_4_LEVEL_PAGING) ? _REGION1_SIZE @@ -990,6 +981,10 @@ static int __init setup_hwcaps(void) case 0x3907: strcpy(elf_platform, "z14"); break; + case 0x8561: + case 0x8562: + strcpy(elf_platform, "z15"); + break; } /* diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index f6a620f854e168b733ee73f7f6eeda0910317f7d..f8fc4f8aef9b1585252a25532d8d19f4498c3984 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c @@ -6,57 +6,19 @@ * Author(s): Heiko Carstens */ -#include -#include #include -#include -#include #include #include -void save_stack_trace(struct stack_trace *trace) +void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, + struct task_struct *task, struct pt_regs *regs) { struct unwind_state state; + unsigned long addr; - unwind_for_each_frame(&state, current, NULL, 0) { - if (trace->nr_entries >= trace->max_entries) + unwind_for_each_frame(&state, task, regs, 0) { + addr = unwind_get_return_address(&state); + if (!addr || !consume_entry(cookie, addr, false)) break; - if (trace->skip > 0) - trace->skip--; - else - trace->entries[trace->nr_entries++] = state.ip; } } -EXPORT_SYMBOL_GPL(save_stack_trace); - -void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) -{ - struct unwind_state state; - - unwind_for_each_frame(&state, tsk, NULL, 0) { - if (trace->nr_entries >= trace->max_entries) - break; - if (in_sched_functions(state.ip)) - continue; - if (trace->skip > 0) - trace->skip--; - else - trace->entries[trace->nr_entries++] = state.ip; - } -} -EXPORT_SYMBOL_GPL(save_stack_trace_tsk); - -void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) -{ - struct unwind_state state; - - unwind_for_each_frame(&state, current, regs, 0) { - if (trace->nr_entries >= trace->max_entries) - break; - if (trace->skip > 0) - trace->skip--; - else - trace->entries[trace->nr_entries++] = state.ip; - } -} -EXPORT_SYMBOL_GPL(save_stack_trace_regs); diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c index c6bc190f3c28c967604fc50d099cc05f25278736..ed1fc08ccea2e8430672ffd7e3ba060a5923d1d6 100644 --- a/arch/s390/kernel/vdso.c +++ b/arch/s390/kernel/vdso.c @@ -97,21 +97,13 @@ static const struct vm_special_mapping vdso_mapping = { .mremap = vdso_mremap, }; -static int __init vdso_setup(char *s) +static int __init vdso_setup(char *str) { - unsigned long val; - int rc; + bool enabled; - rc = 0; - if (strncmp(s, "on", 3) == 0) - vdso_enabled = 1; - else if (strncmp(s, "off", 4) == 0) - vdso_enabled = 0; - else { - rc = kstrtoul(s, 0, &val); - vdso_enabled = rc ? 0 : !!val; - } - return !rc; + if (!kstrtobool(str, &enabled)) + vdso_enabled = enabled; + return 1; } __setup("vdso=", vdso_setup); diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 39cff07bf2ebef248e2f9630517e4be31ab3530c..f6db0f1bc86749ab5d513a153e3abbe341408db7 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -4000,6 +4000,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) if (kvm_run->immediate_exit) return -EINTR; + if (kvm_run->kvm_valid_regs & ~KVM_SYNC_S390_VALID_FIELDS || + kvm_run->kvm_dirty_regs & ~KVM_SYNC_S390_VALID_FIELDS) + return -EINVAL; + vcpu_load(vcpu); if (guestdbg_exit_pending(vcpu)) { @@ -4257,7 +4261,7 @@ static long kvm_s390_guest_mem_op(struct kvm_vcpu *vcpu, const u64 supported_flags = KVM_S390_MEMOP_F_INJECT_EXCEPTION | KVM_S390_MEMOP_F_CHECK_ONLY; - if (mop->flags & ~supported_flags) + if (mop->flags & ~supported_flags || mop->ar >= NUM_ACRS || !mop->size) return -EINVAL; if (mop->size > MEM_OP_MAX_SIZE) diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index a1ec63abfb956d7ab4590c435221fe3b1d674e06..d7c218e8b559b1ce4af8bd3ed6ccd21a328babad 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile @@ -11,6 +11,3 @@ lib-$(CONFIG_UPROBES) += probes.o # Instrumenting memory accesses to __user data (in different address space) # produce false positives KASAN_SANITIZE_uaccess.o := n - -chkbss := mem.o -include $(srctree)/arch/s390/scripts/Makefile.chkbss diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 0b5622714c12c3bce64f23db9634ca38ee89c8e0..fd0dae9d10f4757508269196abbabc65e3539e23 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -64,7 +65,7 @@ struct dcss_segment { char res_name[16]; unsigned long start_addr; unsigned long end; - atomic_t ref_count; + refcount_t ref_count; int do_nonshared; unsigned int vm_segtype; struct qrange range[6]; @@ -362,7 +363,7 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long seg->start_addr = start_addr; seg->end = end_addr; seg->do_nonshared = do_nonshared; - atomic_set(&seg->ref_count, 1); + refcount_set(&seg->ref_count, 1); list_add(&seg->list, &dcss_list); *addr = seg->start_addr; *end = seg->end; @@ -422,7 +423,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr, rc = __segment_load (name, do_nonshared, addr, end); else { if (do_nonshared == seg->do_nonshared) { - atomic_inc(&seg->ref_count); + refcount_inc(&seg->ref_count); *addr = seg->start_addr; *end = seg->end; rc = seg->vm_segtype; @@ -468,7 +469,7 @@ segment_modify_shared (char *name, int do_nonshared) rc = 0; goto out_unlock; } - if (atomic_read (&seg->ref_count) != 1) { + if (refcount_read(&seg->ref_count) != 1) { pr_warn("DCSS %s is in use and cannot be reloaded\n", name); rc = -EAGAIN; goto out_unlock; @@ -544,7 +545,7 @@ segment_unload(char *name) pr_err("Unloading unknown DCSS %s failed\n", name); goto out_unlock; } - if (atomic_dec_return(&seg->ref_count) != 0) + if (!refcount_dec_and_test(&seg->ref_count)) goto out_unlock; release_resource(seg->res); kfree(seg->res); diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c index 39c3a6e3d26218161bd63e5746d862b9af335edd..cd8e03f04d6daac463af57b15fe26dcc7ddc658d 100644 --- a/arch/s390/mm/gmap.c +++ b/arch/s390/mm/gmap.c @@ -67,7 +67,7 @@ static struct gmap *gmap_alloc(unsigned long limit) INIT_RADIX_TREE(&gmap->host_to_rmap, GFP_ATOMIC); spin_lock_init(&gmap->guest_table_lock); spin_lock_init(&gmap->shadow_lock); - atomic_set(&gmap->ref_count, 1); + refcount_set(&gmap->ref_count, 1); page = alloc_pages(GFP_KERNEL, CRST_ALLOC_ORDER); if (!page) goto out_free; @@ -214,7 +214,7 @@ static void gmap_free(struct gmap *gmap) */ struct gmap *gmap_get(struct gmap *gmap) { - atomic_inc(&gmap->ref_count); + refcount_inc(&gmap->ref_count); return gmap; } EXPORT_SYMBOL_GPL(gmap_get); @@ -227,7 +227,7 @@ EXPORT_SYMBOL_GPL(gmap_get); */ void gmap_put(struct gmap *gmap) { - if (atomic_dec_return(&gmap->ref_count) == 0) + if (refcount_dec_and_test(&gmap->ref_count)) gmap_free(gmap); } EXPORT_SYMBOL_GPL(gmap_put); @@ -1594,7 +1594,7 @@ static struct gmap *gmap_find_shadow(struct gmap *parent, unsigned long asce, continue; if (!sg->initialized) return ERR_PTR(-EAGAIN); - atomic_inc(&sg->ref_count); + refcount_inc(&sg->ref_count); return sg; } return NULL; @@ -1682,7 +1682,7 @@ struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce, } } } - atomic_set(&new->ref_count, 2); + refcount_set(&new->ref_count, 2); list_add(&new->list, &parent->children); if (asce & _ASCE_REAL_SPACE) { /* nothing to protect, return right away */ diff --git a/arch/s390/mm/kasan_init.c b/arch/s390/mm/kasan_init.c index 0c1f257be422247b3e5835233582e07c80465e5c..460f2557294021f0f7bd49e1f31bcfbaed007f31 100644 --- a/arch/s390/mm/kasan_init.c +++ b/arch/s390/mm/kasan_init.c @@ -236,18 +236,6 @@ static void __init kasan_early_detect_facilities(void) } } -static unsigned long __init get_mem_detect_end(void) -{ - unsigned long start; - unsigned long end; - - if (mem_detect.count) { - __get_mem_detect_block(mem_detect.count - 1, &start, &end); - return end; - } - return 0; -} - void __init kasan_early_init(void) { unsigned long untracked_mem_end; @@ -273,6 +261,8 @@ void __init kasan_early_init(void) /* respect mem= cmdline parameter */ if (memory_end_set && memsize > memory_end) memsize = memory_end; + if (IS_ENABLED(CONFIG_CRASH_DUMP) && OLDMEM_BASE) + memsize = min(memsize, OLDMEM_SIZE); memsize = min(memsize, KASAN_SHADOW_START); if (IS_ENABLED(CONFIG_KASAN_S390_4_LEVEL_PAGING)) { diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c index dc3cede7f2ec9df1a886fc3e92821f2b7f9c6195..fc141893d028493df59883ac04a0450f22ab6e5e 100644 --- a/arch/s390/mm/page-states.c +++ b/arch/s390/mm/page-states.c @@ -21,17 +21,11 @@ static int cmma_flag = 1; static int __init cmma(char *str) { - char *parm; + bool enabled; - parm = strstrip(str); - if (strcmp(parm, "yes") == 0 || strcmp(parm, "on") == 0) { - cmma_flag = 1; - return 1; - } - cmma_flag = 0; - if (strcmp(parm, "no") == 0 || strcmp(parm, "off") == 0) - return 1; - return 0; + if (!kstrtobool(str, &enabled)) + cmma_flag = enabled; + return 1; } __setup("cmma=", cmma); diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index 955eb355c2fdea049412ecbcf81b84427e4cf406..ce88211b9c6cdda55164f82ef00327a98ba11b6d 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -502,7 +502,8 @@ static void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth) * NOTE: Use noinline because for gcov (-fprofile-arcs) gcc allocates a lot of * stack space for the large switch statement. */ -static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i) +static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, + int i, bool extra_pass) { struct bpf_insn *insn = &fp->insnsi[i]; int jmp_off, last, insn_count = 1; @@ -1011,10 +1012,14 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i */ case BPF_JMP | BPF_CALL: { - /* - * b0 = (__bpf_call_base + imm)(b1, b2, b3, b4, b5) - */ - const u64 func = (u64)__bpf_call_base + imm; + u64 func; + bool func_addr_fixed; + int ret; + + ret = bpf_jit_get_func_addr(fp, insn, extra_pass, + &func, &func_addr_fixed); + if (ret < 0) + return -1; REG_SET_SEEN(BPF_REG_5); jit->seen |= SEEN_FUNC; @@ -1283,7 +1288,8 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i /* * Compile eBPF program into s390x code */ -static int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp) +static int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp, + bool extra_pass) { int i, insn_count; @@ -1292,7 +1298,7 @@ static int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp) bpf_jit_prologue(jit, fp->aux->stack_depth); for (i = 0; i < fp->len; i += insn_count) { - insn_count = bpf_jit_insn(jit, fp, i); + insn_count = bpf_jit_insn(jit, fp, i, extra_pass); if (insn_count < 0) return -1; /* Next instruction address */ @@ -1311,6 +1317,12 @@ bool bpf_jit_needs_zext(void) return true; } +struct s390_jit_data { + struct bpf_binary_header *header; + struct bpf_jit ctx; + int pass; +}; + /* * Compile eBPF program "fp" */ @@ -1318,7 +1330,9 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) { struct bpf_prog *tmp, *orig_fp = fp; struct bpf_binary_header *header; + struct s390_jit_data *jit_data; bool tmp_blinded = false; + bool extra_pass = false; struct bpf_jit jit; int pass; @@ -1337,6 +1351,23 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) fp = tmp; } + jit_data = fp->aux->jit_data; + if (!jit_data) { + jit_data = kzalloc(sizeof(*jit_data), GFP_KERNEL); + if (!jit_data) { + fp = orig_fp; + goto out; + } + fp->aux->jit_data = jit_data; + } + if (jit_data->ctx.addrs) { + jit = jit_data->ctx; + header = jit_data->header; + extra_pass = true; + pass = jit_data->pass + 1; + goto skip_init_ctx; + } + memset(&jit, 0, sizeof(jit)); jit.addrs = kcalloc(fp->len + 1, sizeof(*jit.addrs), GFP_KERNEL); if (jit.addrs == NULL) { @@ -1349,7 +1380,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) * - 3: Calculate program size and addrs arrray */ for (pass = 1; pass <= 3; pass++) { - if (bpf_jit_prog(&jit, fp)) { + if (bpf_jit_prog(&jit, fp, extra_pass)) { fp = orig_fp; goto free_addrs; } @@ -1361,12 +1392,14 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) fp = orig_fp; goto free_addrs; } + header = bpf_jit_binary_alloc(jit.size, &jit.prg_buf, 2, jit_fill_hole); if (!header) { fp = orig_fp; goto free_addrs; } - if (bpf_jit_prog(&jit, fp)) { +skip_init_ctx: + if (bpf_jit_prog(&jit, fp, extra_pass)) { bpf_jit_binary_free(header); fp = orig_fp; goto free_addrs; @@ -1375,12 +1408,24 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) bpf_jit_dump(fp->len, jit.size, pass, jit.prg_buf); print_fn_code(jit.prg_buf, jit.size_prg); } - bpf_jit_binary_lock_ro(header); + if (!fp->is_func || extra_pass) { + bpf_jit_binary_lock_ro(header); + } else { + jit_data->header = header; + jit_data->ctx = jit; + jit_data->pass = pass; + } fp->bpf_func = (void *) jit.prg_buf; fp->jited = 1; fp->jited_len = jit.size; + + if (!fp->is_func || extra_pass) { + bpf_prog_fill_jited_linfo(fp, jit.addrs + 1); free_addrs: - kfree(jit.addrs); + kfree(jit.addrs); + kfree(jit_data); + fp->aux->jit_data = NULL; + } out: if (tmp_blinded) bpf_jit_prog_release_other(fp, fp == orig_fp ? diff --git a/arch/s390/numa/mode_emu.c b/arch/s390/numa/mode_emu.c index 71a12a4f49069624a85c5fb78a0f5c4241ba3b85..72d742bb2d17be01f105df7e75fa2ae4e932af85 100644 --- a/arch/s390/numa/mode_emu.c +++ b/arch/s390/numa/mode_emu.c @@ -558,9 +558,7 @@ static int __init early_parse_emu_nodes(char *p) { int count; - if (kstrtoint(p, 0, &count) != 0 || count <= 0) - return 0; - if (count <= 0) + if (!p || kstrtoint(p, 0, &count) != 0 || count <= 0) return 0; emu_nodes = min(count, MAX_NUMNODES); return 0; @@ -572,7 +570,8 @@ early_param("emu_nodes", early_parse_emu_nodes); */ static int __init early_parse_emu_size(char *p) { - emu_size = memparse(p, NULL); + if (p) + emu_size = memparse(p, NULL); return 0; } early_param("emu_size", early_parse_emu_size); diff --git a/arch/s390/numa/numa.c b/arch/s390/numa/numa.c index 8eb9e9743f5d8d4d85bf62c8a7bfebce8c248259..d2910fa834c8a2e56d77b7233df6d922a60f77c3 100644 --- a/arch/s390/numa/numa.c +++ b/arch/s390/numa/numa.c @@ -158,6 +158,8 @@ early_param("numa_debug", parse_debug); static int __init parse_numa(char *parm) { + if (!parm) + return 1; if (strcmp(parm, numa_mode_plain.name) == 0) mode = &numa_mode_plain; #ifdef CONFIG_NUMA_EMU diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index b0e3b9a0e4888ab3a56fa6fe027b280e5e85ef65..c7fea9bea8cb520f261d74d5c0bdcca67f68909e 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -431,13 +431,13 @@ static void zpci_map_resources(struct pci_dev *pdev) } #ifdef CONFIG_PCI_IOV - i = PCI_IOV_RESOURCES; + for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { + int bar = i + PCI_IOV_RESOURCES; - for (; i < PCI_SRIOV_NUM_BARS + PCI_IOV_RESOURCES; i++) { - len = pci_resource_len(pdev, i); + len = pci_resource_len(pdev, bar); if (!len) continue; - pdev->resource[i].parent = &iov_res; + pdev->resource[bar].parent = &iov_res; } #endif } diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c index 9e52d1527f71495f920a6d39989fb515410f3056..fb2c7db0164e6cbce83f80eeec975d3006d1e6bc 100644 --- a/arch/s390/pci/pci_dma.c +++ b/arch/s390/pci/pci_dma.c @@ -674,9 +674,9 @@ EXPORT_SYMBOL_GPL(s390_pci_dma_ops); static int __init s390_iommu_setup(char *str) { - if (!strncmp(str, "strict", 6)) + if (!strcmp(str, "strict")) s390_iommu_strict = 1; - return 0; + return 1; } __setup("s390_iommu=", s390_iommu_setup); diff --git a/arch/s390/pci/pci_irq.c b/arch/s390/pci/pci_irq.c index d80616ae8dd8ade256beae5268cab2924a379deb..fbe97ab2e22869a2e80c94ad6729363ba3d217ec 100644 --- a/arch/s390/pci/pci_irq.c +++ b/arch/s390/pci/pci_irq.c @@ -284,7 +284,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) return rc; irq_set_chip_and_handler(irq, &zpci_irq_chip, handle_percpu_irq); - msg.data = hwirq; + msg.data = hwirq - bit; if (irq_delivery == DIRECTED) { msg.address_lo = zdev->msi_addr & 0xff0000ff; msg.address_lo |= msi->affinity ? diff --git a/arch/s390/purgatory/Makefile b/arch/s390/purgatory/Makefile index dc1ae4ff79d7aa5fec71d29456437c0d579398f1..bc0d7a0d039453d28464432c2d74994b827b4c1d 100644 --- a/arch/s390/purgatory/Makefile +++ b/arch/s390/purgatory/Makefile @@ -7,9 +7,11 @@ purgatory-y := head.o purgatory.o string.o sha256.o mem.o targets += $(purgatory-y) purgatory.lds purgatory purgatory.ro PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y)) -$(obj)/sha256.o: $(srctree)/lib/sha256.c FORCE +$(obj)/sha256.o: $(srctree)/lib/crypto/sha256.c FORCE $(call if_changed_rule,cc_o_c) +CFLAGS_sha256.o := -D__DISABLE_EXPORTS + $(obj)/mem.o: $(srctree)/arch/s390/lib/mem.S FORCE $(call if_changed_rule,as_o_S) diff --git a/arch/s390/purgatory/purgatory.c b/arch/s390/purgatory/purgatory.c index 3528e6da4e8792f020b94786a99da13049d5ba46..0a423bcf674699f5264e1e709a325f2e0d807a87 100644 --- a/arch/s390/purgatory/purgatory.c +++ b/arch/s390/purgatory/purgatory.c @@ -8,8 +8,8 @@ */ #include -#include #include +#include #include int verify_sha256_digest(void) diff --git a/arch/s390/tools/gen_facilities.c b/arch/s390/tools/gen_facilities.c index cead9e0dcffbf3df05c7f6673c61e8b367dc780d..61ce5b59b828e9ab155e496f7ef1ba8b65e633f9 100644 --- a/arch/s390/tools/gen_facilities.c +++ b/arch/s390/tools/gen_facilities.c @@ -57,6 +57,9 @@ static struct facility_def facility_defs[] = { #endif #ifdef CONFIG_HAVE_MARCH_Z14_FEATURES 58, /* miscellaneous-instruction-extension 2 */ +#endif +#ifdef CONFIG_HAVE_MARCH_Z15_FEATURES + 61, /* miscellaneous-instruction-extension 3 */ #endif -1 /* END */ } diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index 8301a4378f502cdcf8ce87da797013708dab32ce..665cad452798bb41c94d1a509a3c737393a999b0 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c @@ -527,7 +527,6 @@ static int __init ap325rxa_devices_setup(void) /* Initialize CEU platform device separately to map memory first */ device_initialize(&ap325rxa_ceu_device.dev); - arch_setup_pdev_archdata(&ap325rxa_ceu_device); dma_declare_coherent_memory(&ap325rxa_ceu_device.dev, ceu_dma_membase, ceu_dma_membase, ceu_dma_membase + CEU_BUFFER_MEMORY_SIZE - 1); diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index f402aa741bf370a819b7840183909faa22419331..acaa97459531c60264ee7acd6bd5b299f3f774ae 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -1440,7 +1440,6 @@ static int __init arch_setup(void) /* Initialize CEU platform devices separately to map memory first */ device_initialize(&ecovec_ceu_devices[0]->dev); - arch_setup_pdev_archdata(ecovec_ceu_devices[0]); dma_declare_coherent_memory(&ecovec_ceu_devices[0]->dev, ceu0_dma_membase, ceu0_dma_membase, ceu0_dma_membase + @@ -1448,7 +1447,6 @@ static int __init arch_setup(void) platform_device_add(ecovec_ceu_devices[0]); device_initialize(&ecovec_ceu_devices[1]->dev); - arch_setup_pdev_archdata(ecovec_ceu_devices[1]); dma_declare_coherent_memory(&ecovec_ceu_devices[1]->dev, ceu1_dma_membase, ceu1_dma_membase, ceu1_dma_membase + diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index 1cf9a47ac90ed7fcb1580e5cb4526d980d3d918f..96538ba3aa323f5ac78e19ab4a8a100387ddc2af 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c @@ -601,7 +601,6 @@ static int __init kfr2r09_devices_setup(void) /* Initialize CEU platform device separately to map memory first */ device_initialize(&kfr2r09_ceu_device.dev); - arch_setup_pdev_archdata(&kfr2r09_ceu_device); dma_declare_coherent_memory(&kfr2r09_ceu_device.dev, ceu_dma_membase, ceu_dma_membase, ceu_dma_membase + CEU_BUFFER_MEMORY_SIZE - 1); diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 90702740f207c783f1a50b2c90ea22ab728da0a1..9ed369dad62df78b9e9d6e016a41ca2abeabb2d6 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -602,7 +602,6 @@ static int __init migor_devices_setup(void) /* Initialize CEU platform device separately to map memory first */ device_initialize(&migor_ceu_device.dev); - arch_setup_pdev_archdata(&migor_ceu_device); dma_declare_coherent_memory(&migor_ceu_device.dev, ceu_dma_membase, ceu_dma_membase, ceu_dma_membase + CEU_BUFFER_MEMORY_SIZE - 1); diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index 3674064816c73c7e6ee371f607d1b5b5f88bfbc9..32f5dd9448894a6477a9fe27eecba243c64f096c 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -937,7 +937,6 @@ static int __init devices_setup(void) /* Initialize CEU platform devices separately to map memory first */ device_initialize(&ms7724se_ceu_devices[0]->dev); - arch_setup_pdev_archdata(ms7724se_ceu_devices[0]); dma_declare_coherent_memory(&ms7724se_ceu_devices[0]->dev, ceu0_dma_membase, ceu0_dma_membase, ceu0_dma_membase + @@ -945,7 +944,6 @@ static int __init devices_setup(void) platform_device_add(ms7724se_ceu_devices[0]); device_initialize(&ms7724se_ceu_devices[1]->dev); - arch_setup_pdev_archdata(ms7724se_ceu_devices[1]); dma_declare_coherent_memory(&ms7724se_ceu_devices[1]->dev, ceu1_dma_membase, ceu1_dma_membase, ceu1_dma_membase + diff --git a/arch/sparc/crypto/aes_glue.c b/arch/sparc/crypto/aes_glue.c index 57b4741131682a7a72de53320e7f7a2766e0de75..7b946b3dee9d1fd73448ae8d735c72cd7d3b1d0b 100644 --- a/arch/sparc/crypto/aes_glue.c +++ b/arch/sparc/crypto/aes_glue.c @@ -197,14 +197,14 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, return 0; } -static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +static void crypto_aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { struct crypto_sparc64_aes_ctx *ctx = crypto_tfm_ctx(tfm); ctx->ops->encrypt(&ctx->key[0], (const u32 *) src, (u32 *) dst); } -static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +static void crypto_aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { struct crypto_sparc64_aes_ctx *ctx = crypto_tfm_ctx(tfm); @@ -396,8 +396,8 @@ static struct crypto_alg algs[] = { { .cia_min_keysize = AES_MIN_KEY_SIZE, .cia_max_keysize = AES_MAX_KEY_SIZE, .cia_setkey = aes_set_key, - .cia_encrypt = aes_encrypt, - .cia_decrypt = aes_decrypt + .cia_encrypt = crypto_aes_encrypt, + .cia_decrypt = crypto_aes_decrypt } } }, { diff --git a/arch/sparc/crypto/des_glue.c b/arch/sparc/crypto/des_glue.c index 281448f72c90da39b97d8a207778209efc9b380d..db6010b4e52e14452a7fdaaec20dd9c14b33698b 100644 --- a/arch/sparc/crypto/des_glue.c +++ b/arch/sparc/crypto/des_glue.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include @@ -45,19 +45,15 @@ static int des_set_key(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) { struct des_sparc64_ctx *dctx = crypto_tfm_ctx(tfm); - u32 *flags = &tfm->crt_flags; - u32 tmp[DES_EXPKEY_WORDS]; - int ret; + int err; /* Even though we have special instructions for key expansion, - * we call des_ekey() so that we don't have to write our own + * we call des_verify_key() so that we don't have to write our own * weak key detection code. */ - ret = des_ekey(tmp, key); - if (unlikely(ret == 0) && (*flags & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) { - *flags |= CRYPTO_TFM_RES_WEAK_KEY; - return -EINVAL; - } + err = crypto_des_verify_key(tfm, key); + if (err) + return err; des_sparc64_key_expand((const u32 *) key, &dctx->encrypt_expkey[0]); encrypt_to_decrypt(&dctx->decrypt_expkey[0], &dctx->encrypt_expkey[0]); @@ -68,7 +64,7 @@ static int des_set_key(struct crypto_tfm *tfm, const u8 *key, extern void des_sparc64_crypt(const u64 *key, const u64 *input, u64 *output); -static void des_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +static void sparc_des_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { struct des_sparc64_ctx *ctx = crypto_tfm_ctx(tfm); const u64 *K = ctx->encrypt_expkey; @@ -76,7 +72,7 @@ static void des_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) des_sparc64_crypt(K, (const u64 *) src, (u64 *) dst); } -static void des_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +static void sparc_des_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { struct des_sparc64_ctx *ctx = crypto_tfm_ctx(tfm); const u64 *K = ctx->decrypt_expkey; @@ -202,14 +198,13 @@ static int des3_ede_set_key(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) { struct des3_ede_sparc64_ctx *dctx = crypto_tfm_ctx(tfm); - u32 *flags = &tfm->crt_flags; u64 k1[DES_EXPKEY_WORDS / 2]; u64 k2[DES_EXPKEY_WORDS / 2]; u64 k3[DES_EXPKEY_WORDS / 2]; int err; - err = __des3_verify_key(flags, key); - if (unlikely(err)) + err = crypto_des3_ede_verify_key(tfm, key); + if (err) return err; des_sparc64_key_expand((const u32 *)key, k1); @@ -235,7 +230,7 @@ static int des3_ede_set_key(struct crypto_tfm *tfm, const u8 *key, extern void des3_ede_sparc64_crypt(const u64 *key, const u64 *input, u64 *output); -static void des3_ede_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +static void sparc_des3_ede_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { struct des3_ede_sparc64_ctx *ctx = crypto_tfm_ctx(tfm); const u64 *K = ctx->encrypt_expkey; @@ -243,7 +238,7 @@ static void des3_ede_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) des3_ede_sparc64_crypt(K, (const u64 *) src, (u64 *) dst); } -static void des3_ede_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +static void sparc_des3_ede_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { struct des3_ede_sparc64_ctx *ctx = crypto_tfm_ctx(tfm); const u64 *K = ctx->decrypt_expkey; @@ -390,8 +385,8 @@ static struct crypto_alg algs[] = { { .cia_min_keysize = DES_KEY_SIZE, .cia_max_keysize = DES_KEY_SIZE, .cia_setkey = des_set_key, - .cia_encrypt = des_encrypt, - .cia_decrypt = des_decrypt + .cia_encrypt = sparc_des_encrypt, + .cia_decrypt = sparc_des_decrypt } } }, { @@ -447,8 +442,8 @@ static struct crypto_alg algs[] = { { .cia_min_keysize = DES3_EDE_KEY_SIZE, .cia_max_keysize = DES3_EDE_KEY_SIZE, .cia_setkey = des3_ede_set_key, - .cia_encrypt = des3_ede_encrypt, - .cia_decrypt = des3_ede_decrypt + .cia_encrypt = sparc_des3_ede_encrypt, + .cia_decrypt = sparc_des3_ede_decrypt } } }, { diff --git a/arch/unicore32/kernel/irq.c b/arch/unicore32/kernel/irq.c index d1129828c41e07c3aa2356dbe37ae87bd5b75907..c014ae3c3e488ddd1892184b379ddbc4dd175f34 100644 --- a/arch/unicore32/kernel/irq.c +++ b/arch/unicore32/kernel/irq.c @@ -21,7 +21,6 @@ #include #include #include -#include #include diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 222855cc0158422f1d6dddc2d9307cb606433a37..4195f44c6a0955ef50c5eed87502b4a4c595d6d7 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -794,6 +794,7 @@ config KVM_GUEST bool "KVM Guest support (including kvmclock)" depends on PARAVIRT select PARAVIRT_CLOCK + select ARCH_CPUIDLE_HALTPOLL default y ---help--- This option enables various optimizations for running under the KVM @@ -802,6 +803,12 @@ config KVM_GUEST underlying device model, the host provides the guest with timing infrastructure such as time of day, and system time +config ARCH_CPUIDLE_HALTPOLL + def_bool n + prompt "Disable host haltpoll when loading haltpoll driver" + help + If virtualized under KVM, disable host haltpoll. + config PVH bool "Support for running PVH guests" ---help--- @@ -1503,7 +1510,7 @@ config X86_5LEVEL config X86_DIRECT_GBPAGES def_bool y - depends on X86_64 && !DEBUG_PAGEALLOC + depends on X86_64 ---help--- Certain kernel features effectively disable kernel linear 1 GB mappings (even if the CPU otherwise diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 71c92db47c412af588686489f4a9c6dec4e96929..bf9cd83de7773087951ad22dcafba77dba9b54f8 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -171,7 +171,7 @@ config HAVE_MMIOTRACE_SUPPORT config X86_DECODER_SELFTEST bool "x86 instruction decoder selftest" - depends on DEBUG_KERNEL && KPROBES + depends on DEBUG_KERNEL && INSTRUCTION_DECODER depends on !COMPILE_TEST ---help--- Perform x86 instruction decoder selftests at build time. diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index 19eca14b49a0a8c2cbef87025c094c168551e95e..ca866f1cca2ef1a733c1b91613bd5375962b5f3f 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -28,8 +28,6 @@ #include "cpuflags.h" /* Useful macros */ -#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) - #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) extern struct setup_header hdr; diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S index 37380c0d59996b8ed688d0e350111343e5dca0ae..5e30eaaf8576fb7ce0cca4c94fa931888c812101 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -140,7 +140,7 @@ ENTRY(startup_32) /* * Jump to the relocated address. */ - leal relocated(%ebx), %eax + leal .Lrelocated(%ebx), %eax jmp *%eax ENDPROC(startup_32) @@ -209,7 +209,7 @@ ENDPROC(efi32_stub_entry) #endif .text -relocated: +.Lrelocated: /* * Clear BSS (stack is currently empty) diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index 6233ae35d0d9a9d6682be147a1d3f305c59b3e30..d98cd483377eb7461d99ba563c7aaac466674466 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -87,7 +87,7 @@ ENTRY(startup_32) call verify_cpu testl %eax, %eax - jnz no_longmode + jnz .Lno_longmode /* * Compute the delta between where we were compiled to run at @@ -322,7 +322,7 @@ ENTRY(startup_64) 1: popq %rdi subq $1b, %rdi - call adjust_got + call .Ladjust_got /* * At this point we are in long mode with 4-level paging enabled, @@ -421,7 +421,7 @@ trampoline_return: /* The new adjustment is the relocation address */ movq %rbx, %rdi - call adjust_got + call .Ladjust_got /* * Copy the compressed kernel to the end of our buffer @@ -440,7 +440,7 @@ trampoline_return: /* * Jump to the relocated address. */ - leaq relocated(%rbx), %rax + leaq .Lrelocated(%rbx), %rax jmp *%rax #ifdef CONFIG_EFI_STUB @@ -511,7 +511,7 @@ ENDPROC(efi64_stub_entry) #endif .text -relocated: +.Lrelocated: /* * Clear BSS (stack is currently empty) @@ -548,7 +548,7 @@ relocated: * first time we touch GOT). * RDI is the new adjustment to apply. */ -adjust_got: +.Ladjust_got: /* Walk through the GOT adding the address to the entries */ leaq _got(%rip), %rdx leaq _egot(%rip), %rcx @@ -622,7 +622,7 @@ ENTRY(trampoline_32bit_src) movl %eax, %cr4 /* Calculate address of paging_enabled() once we are executing in the trampoline */ - leal paging_enabled - trampoline_32bit_src + TRAMPOLINE_32BIT_CODE_OFFSET(%ecx), %eax + leal .Lpaging_enabled - trampoline_32bit_src + TRAMPOLINE_32BIT_CODE_OFFSET(%ecx), %eax /* Prepare the stack for far return to Long Mode */ pushl $__KERNEL_CS @@ -635,7 +635,7 @@ ENTRY(trampoline_32bit_src) lret .code64 -paging_enabled: +.Lpaging_enabled: /* Return from the trampoline */ jmp *%rdi @@ -647,7 +647,7 @@ paging_enabled: .org trampoline_32bit_src + TRAMPOLINE_32BIT_CODE_SIZE .code32 -no_longmode: +.Lno_longmode: /* This isn't an x86-64 CPU, so hang intentionally, we cannot continue */ 1: hlt diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c index 996df3d586f0b83a728a4794d5e72f4eb83d8b5a..e3add857c2c9dfd91806c9c466cc86dfcf046de0 100644 --- a/arch/x86/boot/main.c +++ b/arch/x86/boot/main.c @@ -10,6 +10,7 @@ /* * Main module for the real-mode kernel code */ +#include #include "boot.h" #include "string.h" diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index 45734e1cf96720c07eefef5c99e36bfa161cb54a..759b1a927826b8bb72a1debb3e6a539302e352f7 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -14,11 +14,9 @@ sha256_ni_supported :=$(call as-instr,sha256msg1 %xmm0$(comma)%xmm1,yes,no) obj-$(CONFIG_CRYPTO_GLUE_HELPER_X86) += glue_helper.o -obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o obj-$(CONFIG_CRYPTO_SERPENT_SSE2_586) += serpent-sse2-i586.o -obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o obj-$(CONFIG_CRYPTO_DES3_EDE_X86_64) += des3_ede-x86_64.o obj-$(CONFIG_CRYPTO_CAMELLIA_X86_64) += camellia-x86_64.o obj-$(CONFIG_CRYPTO_BLOWFISH_X86_64) += blowfish-x86_64.o @@ -38,14 +36,6 @@ obj-$(CONFIG_CRYPTO_CRCT10DIF_PCLMUL) += crct10dif-pclmul.o obj-$(CONFIG_CRYPTO_POLY1305_X86_64) += poly1305-x86_64.o obj-$(CONFIG_CRYPTO_AEGIS128_AESNI_SSE2) += aegis128-aesni.o -obj-$(CONFIG_CRYPTO_AEGIS128L_AESNI_SSE2) += aegis128l-aesni.o -obj-$(CONFIG_CRYPTO_AEGIS256_AESNI_SSE2) += aegis256-aesni.o - -obj-$(CONFIG_CRYPTO_MORUS640_GLUE) += morus640_glue.o -obj-$(CONFIG_CRYPTO_MORUS1280_GLUE) += morus1280_glue.o - -obj-$(CONFIG_CRYPTO_MORUS640_SSE2) += morus640-sse2.o -obj-$(CONFIG_CRYPTO_MORUS1280_SSE2) += morus1280-sse2.o obj-$(CONFIG_CRYPTO_NHPOLY1305_SSE2) += nhpoly1305-sse2.o obj-$(CONFIG_CRYPTO_NHPOLY1305_AVX2) += nhpoly1305-avx2.o @@ -64,15 +54,11 @@ endif ifeq ($(avx2_supported),yes) obj-$(CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64) += camellia-aesni-avx2.o obj-$(CONFIG_CRYPTO_SERPENT_AVX2_X86_64) += serpent-avx2.o - - obj-$(CONFIG_CRYPTO_MORUS1280_AVX2) += morus1280-avx2.o endif -aes-i586-y := aes-i586-asm_32.o aes_glue.o twofish-i586-y := twofish-i586-asm_32.o twofish_glue.o serpent-sse2-i586-y := serpent-sse2-i586-asm_32.o serpent_sse2_glue.o -aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o des3_ede-x86_64-y := des3_ede-asm_64.o des3_ede_glue.o camellia-x86_64-y := camellia-x86_64-asm_64.o camellia_glue.o blowfish-x86_64-y := blowfish-x86_64-asm_64.o blowfish_glue.o @@ -82,11 +68,6 @@ chacha-x86_64-y := chacha-ssse3-x86_64.o chacha_glue.o serpent-sse2-x86_64-y := serpent-sse2-x86_64-asm_64.o serpent_sse2_glue.o aegis128-aesni-y := aegis128-aesni-asm.o aegis128-aesni-glue.o -aegis128l-aesni-y := aegis128l-aesni-asm.o aegis128l-aesni-glue.o -aegis256-aesni-y := aegis256-aesni-asm.o aegis256-aesni-glue.o - -morus640-sse2-y := morus640-sse2-asm.o morus640-sse2-glue.o -morus1280-sse2-y := morus1280-sse2-asm.o morus1280-sse2-glue.o nhpoly1305-sse2-y := nh-sse2-x86_64.o nhpoly1305-sse2-glue.o @@ -106,8 +87,6 @@ ifeq ($(avx2_supported),yes) chacha-x86_64-y += chacha-avx2-x86_64.o serpent-avx2-y := serpent-avx2-asm_64.o serpent_avx2_glue.o - morus1280-avx2-y := morus1280-avx2-asm.o morus1280-avx2-glue.o - nhpoly1305-avx2-y := nh-avx2-x86_64.o nhpoly1305-avx2-glue.o endif diff --git a/arch/x86/crypto/aegis128l-aesni-asm.S b/arch/x86/crypto/aegis128l-aesni-asm.S deleted file mode 100644 index 1461ef00c0e8b8ac6e69f0bac8288fd2ebc1c600..0000000000000000000000000000000000000000 --- a/arch/x86/crypto/aegis128l-aesni-asm.S +++ /dev/null @@ -1,823 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * AES-NI + SSE2 implementation of AEGIS-128L - * - * Copyright (c) 2017-2018 Ondrej Mosnacek - * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. - */ - -#include -#include - -#define STATE0 %xmm0 -#define STATE1 %xmm1 -#define STATE2 %xmm2 -#define STATE3 %xmm3 -#define STATE4 %xmm4 -#define STATE5 %xmm5 -#define STATE6 %xmm6 -#define STATE7 %xmm7 -#define MSG0 %xmm8 -#define MSG1 %xmm9 -#define T0 %xmm10 -#define T1 %xmm11 -#define T2 %xmm12 -#define T3 %xmm13 - -#define STATEP %rdi -#define LEN %rsi -#define SRC %rdx -#define DST %rcx - -.section .rodata.cst16.aegis128l_const, "aM", @progbits, 32 -.align 16 -.Laegis128l_const_0: - .byte 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d - .byte 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 -.Laegis128l_const_1: - .byte 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1 - .byte 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd - -.section .rodata.cst16.aegis128l_counter, "aM", @progbits, 16 -.align 16 -.Laegis128l_counter0: - .byte 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 - .byte 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f -.Laegis128l_counter1: - .byte 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 - .byte 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f - -.text - -/* - * __load_partial: internal ABI - * input: - * LEN - bytes - * SRC - src - * output: - * MSG0 - first message block - * MSG1 - second message block - * changed: - * T0 - * %r8 - * %r9 - */ -__load_partial: - xor %r9d, %r9d - pxor MSG0, MSG0 - pxor MSG1, MSG1 - - mov LEN, %r8 - and $0x1, %r8 - jz .Lld_partial_1 - - mov LEN, %r8 - and $0x1E, %r8 - add SRC, %r8 - mov (%r8), %r9b - -.Lld_partial_1: - mov LEN, %r8 - and $0x2, %r8 - jz .Lld_partial_2 - - mov LEN, %r8 - and $0x1C, %r8 - add SRC, %r8 - shl $0x10, %r9 - mov (%r8), %r9w - -.Lld_partial_2: - mov LEN, %r8 - and $0x4, %r8 - jz .Lld_partial_4 - - mov LEN, %r8 - and $0x18, %r8 - add SRC, %r8 - shl $32, %r9 - mov (%r8), %r8d - xor %r8, %r9 - -.Lld_partial_4: - movq %r9, MSG0 - - mov LEN, %r8 - and $0x8, %r8 - jz .Lld_partial_8 - - mov LEN, %r8 - and $0x10, %r8 - add SRC, %r8 - pslldq $8, MSG0 - movq (%r8), T0 - pxor T0, MSG0 - -.Lld_partial_8: - mov LEN, %r8 - and $0x10, %r8 - jz .Lld_partial_16 - - movdqa MSG0, MSG1 - movdqu (SRC), MSG0 - -.Lld_partial_16: - ret -ENDPROC(__load_partial) - -/* - * __store_partial: internal ABI - * input: - * LEN - bytes - * DST - dst - * output: - * T0 - first message block - * T1 - second message block - * changed: - * %r8 - * %r9 - * %r10 - */ -__store_partial: - mov LEN, %r8 - mov DST, %r9 - - cmp $16, %r8 - jl .Lst_partial_16 - - movdqu T0, (%r9) - movdqa T1, T0 - - sub $16, %r8 - add $16, %r9 - -.Lst_partial_16: - movq T0, %r10 - - cmp $8, %r8 - jl .Lst_partial_8 - - mov %r10, (%r9) - psrldq $8, T0 - movq T0, %r10 - - sub $8, %r8 - add $8, %r9 - -.Lst_partial_8: - cmp $4, %r8 - jl .Lst_partial_4 - - mov %r10d, (%r9) - shr $32, %r10 - - sub $4, %r8 - add $4, %r9 - -.Lst_partial_4: - cmp $2, %r8 - jl .Lst_partial_2 - - mov %r10w, (%r9) - shr $0x10, %r10 - - sub $2, %r8 - add $2, %r9 - -.Lst_partial_2: - cmp $1, %r8 - jl .Lst_partial_1 - - mov %r10b, (%r9) - -.Lst_partial_1: - ret -ENDPROC(__store_partial) - -.macro update - movdqa STATE7, T0 - aesenc STATE0, STATE7 - aesenc STATE1, STATE0 - aesenc STATE2, STATE1 - aesenc STATE3, STATE2 - aesenc STATE4, STATE3 - aesenc STATE5, STATE4 - aesenc STATE6, STATE5 - aesenc T0, STATE6 -.endm - -.macro update0 - update - pxor MSG0, STATE7 - pxor MSG1, STATE3 -.endm - -.macro update1 - update - pxor MSG0, STATE6 - pxor MSG1, STATE2 -.endm - -.macro update2 - update - pxor MSG0, STATE5 - pxor MSG1, STATE1 -.endm - -.macro update3 - update - pxor MSG0, STATE4 - pxor MSG1, STATE0 -.endm - -.macro update4 - update - pxor MSG0, STATE3 - pxor MSG1, STATE7 -.endm - -.macro update5 - update - pxor MSG0, STATE2 - pxor MSG1, STATE6 -.endm - -.macro update6 - update - pxor MSG0, STATE1 - pxor MSG1, STATE5 -.endm - -.macro update7 - update - pxor MSG0, STATE0 - pxor MSG1, STATE4 -.endm - -.macro state_load - movdqu 0x00(STATEP), STATE0 - movdqu 0x10(STATEP), STATE1 - movdqu 0x20(STATEP), STATE2 - movdqu 0x30(STATEP), STATE3 - movdqu 0x40(STATEP), STATE4 - movdqu 0x50(STATEP), STATE5 - movdqu 0x60(STATEP), STATE6 - movdqu 0x70(STATEP), STATE7 -.endm - -.macro state_store s0 s1 s2 s3 s4 s5 s6 s7 - movdqu \s7, 0x00(STATEP) - movdqu \s0, 0x10(STATEP) - movdqu \s1, 0x20(STATEP) - movdqu \s2, 0x30(STATEP) - movdqu \s3, 0x40(STATEP) - movdqu \s4, 0x50(STATEP) - movdqu \s5, 0x60(STATEP) - movdqu \s6, 0x70(STATEP) -.endm - -.macro state_store0 - state_store STATE0 STATE1 STATE2 STATE3 STATE4 STATE5 STATE6 STATE7 -.endm - -.macro state_store1 - state_store STATE7 STATE0 STATE1 STATE2 STATE3 STATE4 STATE5 STATE6 -.endm - -.macro state_store2 - state_store STATE6 STATE7 STATE0 STATE1 STATE2 STATE3 STATE4 STATE5 -.endm - -.macro state_store3 - state_store STATE5 STATE6 STATE7 STATE0 STATE1 STATE2 STATE3 STATE4 -.endm - -.macro state_store4 - state_store STATE4 STATE5 STATE6 STATE7 STATE0 STATE1 STATE2 STATE3 -.endm - -.macro state_store5 - state_store STATE3 STATE4 STATE5 STATE6 STATE7 STATE0 STATE1 STATE2 -.endm - -.macro state_store6 - state_store STATE2 STATE3 STATE4 STATE5 STATE6 STATE7 STATE0 STATE1 -.endm - -.macro state_store7 - state_store STATE1 STATE2 STATE3 STATE4 STATE5 STATE6 STATE7 STATE0 -.endm - -/* - * void crypto_aegis128l_aesni_init(void *state, const void *key, const void *iv); - */ -ENTRY(crypto_aegis128l_aesni_init) - FRAME_BEGIN - - /* load key: */ - movdqa (%rsi), MSG1 - movdqa MSG1, STATE0 - movdqa MSG1, STATE4 - movdqa MSG1, STATE5 - movdqa MSG1, STATE6 - movdqa MSG1, STATE7 - - /* load IV: */ - movdqu (%rdx), MSG0 - pxor MSG0, STATE0 - pxor MSG0, STATE4 - - /* load the constants: */ - movdqa .Laegis128l_const_0, STATE2 - movdqa .Laegis128l_const_1, STATE1 - movdqa STATE1, STATE3 - pxor STATE2, STATE5 - pxor STATE1, STATE6 - pxor STATE2, STATE7 - - /* update 10 times with IV and KEY: */ - update0 - update1 - update2 - update3 - update4 - update5 - update6 - update7 - update0 - update1 - - state_store1 - - FRAME_END - ret -ENDPROC(crypto_aegis128l_aesni_init) - -.macro ad_block a i - movdq\a (\i * 0x20 + 0x00)(SRC), MSG0 - movdq\a (\i * 0x20 + 0x10)(SRC), MSG1 - update\i - sub $0x20, LEN - cmp $0x20, LEN - jl .Lad_out_\i -.endm - -/* - * void crypto_aegis128l_aesni_ad(void *state, unsigned int length, - * const void *data); - */ -ENTRY(crypto_aegis128l_aesni_ad) - FRAME_BEGIN - - cmp $0x20, LEN - jb .Lad_out - - state_load - - mov SRC, %r8 - and $0xf, %r8 - jnz .Lad_u_loop - -.align 8 -.Lad_a_loop: - ad_block a 0 - ad_block a 1 - ad_block a 2 - ad_block a 3 - ad_block a 4 - ad_block a 5 - ad_block a 6 - ad_block a 7 - - add $0x100, SRC - jmp .Lad_a_loop - -.align 8 -.Lad_u_loop: - ad_block u 0 - ad_block u 1 - ad_block u 2 - ad_block u 3 - ad_block u 4 - ad_block u 5 - ad_block u 6 - ad_block u 7 - - add $0x100, SRC - jmp .Lad_u_loop - -.Lad_out_0: - state_store0 - FRAME_END - ret - -.Lad_out_1: - state_store1 - FRAME_END - ret - -.Lad_out_2: - state_store2 - FRAME_END - ret - -.Lad_out_3: - state_store3 - FRAME_END - ret - -.Lad_out_4: - state_store4 - FRAME_END - ret - -.Lad_out_5: - state_store5 - FRAME_END - ret - -.Lad_out_6: - state_store6 - FRAME_END - ret - -.Lad_out_7: - state_store7 - FRAME_END - ret - -.Lad_out: - FRAME_END - ret -ENDPROC(crypto_aegis128l_aesni_ad) - -.macro crypt m0 m1 s0 s1 s2 s3 s4 s5 s6 s7 - pxor \s1, \m0 - pxor \s6, \m0 - movdqa \s2, T3 - pand \s3, T3 - pxor T3, \m0 - - pxor \s2, \m1 - pxor \s5, \m1 - movdqa \s6, T3 - pand \s7, T3 - pxor T3, \m1 -.endm - -.macro crypt0 m0 m1 - crypt \m0 \m1 STATE0 STATE1 STATE2 STATE3 STATE4 STATE5 STATE6 STATE7 -.endm - -.macro crypt1 m0 m1 - crypt \m0 \m1 STATE7 STATE0 STATE1 STATE2 STATE3 STATE4 STATE5 STATE6 -.endm - -.macro crypt2 m0 m1 - crypt \m0 \m1 STATE6 STATE7 STATE0 STATE1 STATE2 STATE3 STATE4 STATE5 -.endm - -.macro crypt3 m0 m1 - crypt \m0 \m1 STATE5 STATE6 STATE7 STATE0 STATE1 STATE2 STATE3 STATE4 -.endm - -.macro crypt4 m0 m1 - crypt \m0 \m1 STATE4 STATE5 STATE6 STATE7 STATE0 STATE1 STATE2 STATE3 -.endm - -.macro crypt5 m0 m1 - crypt \m0 \m1 STATE3 STATE4 STATE5 STATE6 STATE7 STATE0 STATE1 STATE2 -.endm - -.macro crypt6 m0 m1 - crypt \m0 \m1 STATE2 STATE3 STATE4 STATE5 STATE6 STATE7 STATE0 STATE1 -.endm - -.macro crypt7 m0 m1 - crypt \m0 \m1 STATE1 STATE2 STATE3 STATE4 STATE5 STATE6 STATE7 STATE0 -.endm - -.macro encrypt_block a i - movdq\a (\i * 0x20 + 0x00)(SRC), MSG0 - movdq\a (\i * 0x20 + 0x10)(SRC), MSG1 - movdqa MSG0, T0 - movdqa MSG1, T1 - crypt\i T0, T1 - movdq\a T0, (\i * 0x20 + 0x00)(DST) - movdq\a T1, (\i * 0x20 + 0x10)(DST) - - update\i - - sub $0x20, LEN - cmp $0x20, LEN - jl .Lenc_out_\i -.endm - -.macro decrypt_block a i - movdq\a (\i * 0x20 + 0x00)(SRC), MSG0 - movdq\a (\i * 0x20 + 0x10)(SRC), MSG1 - crypt\i MSG0, MSG1 - movdq\a MSG0, (\i * 0x20 + 0x00)(DST) - movdq\a MSG1, (\i * 0x20 + 0x10)(DST) - - update\i - - sub $0x20, LEN - cmp $0x20, LEN - jl .Ldec_out_\i -.endm - -/* - * void crypto_aegis128l_aesni_enc(void *state, unsigned int length, - * const void *src, void *dst); - */ -ENTRY(crypto_aegis128l_aesni_enc) - FRAME_BEGIN - - cmp $0x20, LEN - jb .Lenc_out - - state_load - - mov SRC, %r8 - or DST, %r8 - and $0xf, %r8 - jnz .Lenc_u_loop - -.align 8 -.Lenc_a_loop: - encrypt_block a 0 - encrypt_block a 1 - encrypt_block a 2 - encrypt_block a 3 - encrypt_block a 4 - encrypt_block a 5 - encrypt_block a 6 - encrypt_block a 7 - - add $0x100, SRC - add $0x100, DST - jmp .Lenc_a_loop - -.align 8 -.Lenc_u_loop: - encrypt_block u 0 - encrypt_block u 1 - encrypt_block u 2 - encrypt_block u 3 - encrypt_block u 4 - encrypt_block u 5 - encrypt_block u 6 - encrypt_block u 7 - - add $0x100, SRC - add $0x100, DST - jmp .Lenc_u_loop - -.Lenc_out_0: - state_store0 - FRAME_END - ret - -.Lenc_out_1: - state_store1 - FRAME_END - ret - -.Lenc_out_2: - state_store2 - FRAME_END - ret - -.Lenc_out_3: - state_store3 - FRAME_END - ret - -.Lenc_out_4: - state_store4 - FRAME_END - ret - -.Lenc_out_5: - state_store5 - FRAME_END - ret - -.Lenc_out_6: - state_store6 - FRAME_END - ret - -.Lenc_out_7: - state_store7 - FRAME_END - ret - -.Lenc_out: - FRAME_END - ret -ENDPROC(crypto_aegis128l_aesni_enc) - -/* - * void crypto_aegis128l_aesni_enc_tail(void *state, unsigned int length, - * const void *src, void *dst); - */ -ENTRY(crypto_aegis128l_aesni_enc_tail) - FRAME_BEGIN - - state_load - - /* encrypt message: */ - call __load_partial - - movdqa MSG0, T0 - movdqa MSG1, T1 - crypt0 T0, T1 - - call __store_partial - - update0 - - state_store0 - - FRAME_END - ret -ENDPROC(crypto_aegis128l_aesni_enc_tail) - -/* - * void crypto_aegis128l_aesni_dec(void *state, unsigned int length, - * const void *src, void *dst); - */ -ENTRY(crypto_aegis128l_aesni_dec) - FRAME_BEGIN - - cmp $0x20, LEN - jb .Ldec_out - - state_load - - mov SRC, %r8 - or DST, %r8 - and $0xF, %r8 - jnz .Ldec_u_loop - -.align 8 -.Ldec_a_loop: - decrypt_block a 0 - decrypt_block a 1 - decrypt_block a 2 - decrypt_block a 3 - decrypt_block a 4 - decrypt_block a 5 - decrypt_block a 6 - decrypt_block a 7 - - add $0x100, SRC - add $0x100, DST - jmp .Ldec_a_loop - -.align 8 -.Ldec_u_loop: - decrypt_block u 0 - decrypt_block u 1 - decrypt_block u 2 - decrypt_block u 3 - decrypt_block u 4 - decrypt_block u 5 - decrypt_block u 6 - decrypt_block u 7 - - add $0x100, SRC - add $0x100, DST - jmp .Ldec_u_loop - -.Ldec_out_0: - state_store0 - FRAME_END - ret - -.Ldec_out_1: - state_store1 - FRAME_END - ret - -.Ldec_out_2: - state_store2 - FRAME_END - ret - -.Ldec_out_3: - state_store3 - FRAME_END - ret - -.Ldec_out_4: - state_store4 - FRAME_END - ret - -.Ldec_out_5: - state_store5 - FRAME_END - ret - -.Ldec_out_6: - state_store6 - FRAME_END - ret - -.Ldec_out_7: - state_store7 - FRAME_END - ret - -.Ldec_out: - FRAME_END - ret -ENDPROC(crypto_aegis128l_aesni_dec) - -/* - * void crypto_aegis128l_aesni_dec_tail(void *state, unsigned int length, - * const void *src, void *dst); - */ -ENTRY(crypto_aegis128l_aesni_dec_tail) - FRAME_BEGIN - - state_load - - /* decrypt message: */ - call __load_partial - - crypt0 MSG0, MSG1 - - movdqa MSG0, T0 - movdqa MSG1, T1 - call __store_partial - - /* mask with byte count: */ - movq LEN, T0 - punpcklbw T0, T0 - punpcklbw T0, T0 - punpcklbw T0, T0 - punpcklbw T0, T0 - movdqa T0, T1 - movdqa .Laegis128l_counter0, T2 - movdqa .Laegis128l_counter1, T3 - pcmpgtb T2, T0 - pcmpgtb T3, T1 - pand T0, MSG0 - pand T1, MSG1 - - update0 - - state_store0 - - FRAME_END - ret -ENDPROC(crypto_aegis128l_aesni_dec_tail) - -/* - * void crypto_aegis128l_aesni_final(void *state, void *tag_xor, - * u64 assoclen, u64 cryptlen); - */ -ENTRY(crypto_aegis128l_aesni_final) - FRAME_BEGIN - - state_load - - /* prepare length block: */ - movq %rdx, MSG0 - movq %rcx, T0 - pslldq $8, T0 - pxor T0, MSG0 - psllq $3, MSG0 /* multiply by 8 (to get bit count) */ - - pxor STATE2, MSG0 - movdqa MSG0, MSG1 - - /* update state: */ - update0 - update1 - update2 - update3 - update4 - update5 - update6 - - /* xor tag: */ - movdqu (%rsi), T0 - - pxor STATE1, T0 - pxor STATE2, T0 - pxor STATE3, T0 - pxor STATE4, T0 - pxor STATE5, T0 - pxor STATE6, T0 - pxor STATE7, T0 - - movdqu T0, (%rsi) - - FRAME_END - ret -ENDPROC(crypto_aegis128l_aesni_final) diff --git a/arch/x86/crypto/aegis128l-aesni-glue.c b/arch/x86/crypto/aegis128l-aesni-glue.c deleted file mode 100644 index 19eb28b316f048dadbcff139db69d69c02829f50..0000000000000000000000000000000000000000 --- a/arch/x86/crypto/aegis128l-aesni-glue.c +++ /dev/null @@ -1,293 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * The AEGIS-128L Authenticated-Encryption Algorithm - * Glue for AES-NI + SSE2 implementation - * - * Copyright (c) 2017-2018 Ondrej Mosnacek - * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define AEGIS128L_BLOCK_ALIGN 16 -#define AEGIS128L_BLOCK_SIZE 32 -#define AEGIS128L_NONCE_SIZE 16 -#define AEGIS128L_STATE_BLOCKS 8 -#define AEGIS128L_KEY_SIZE 16 -#define AEGIS128L_MIN_AUTH_SIZE 8 -#define AEGIS128L_MAX_AUTH_SIZE 16 - -asmlinkage void crypto_aegis128l_aesni_init(void *state, void *key, void *iv); - -asmlinkage void crypto_aegis128l_aesni_ad( - void *state, unsigned int length, const void *data); - -asmlinkage void crypto_aegis128l_aesni_enc( - void *state, unsigned int length, const void *src, void *dst); - -asmlinkage void crypto_aegis128l_aesni_dec( - void *state, unsigned int length, const void *src, void *dst); - -asmlinkage void crypto_aegis128l_aesni_enc_tail( - void *state, unsigned int length, const void *src, void *dst); - -asmlinkage void crypto_aegis128l_aesni_dec_tail( - void *state, unsigned int length, const void *src, void *dst); - -asmlinkage void crypto_aegis128l_aesni_final( - void *state, void *tag_xor, unsigned int cryptlen, - unsigned int assoclen); - -struct aegis_block { - u8 bytes[AEGIS128L_BLOCK_SIZE] __aligned(AEGIS128L_BLOCK_ALIGN); -}; - -struct aegis_state { - struct aegis_block blocks[AEGIS128L_STATE_BLOCKS]; -}; - -struct aegis_ctx { - struct aegis_block key; -}; - -struct aegis_crypt_ops { - int (*skcipher_walk_init)(struct skcipher_walk *walk, - struct aead_request *req, bool atomic); - - void (*crypt_blocks)(void *state, unsigned int length, const void *src, - void *dst); - void (*crypt_tail)(void *state, unsigned int length, const void *src, - void *dst); -}; - -static void crypto_aegis128l_aesni_process_ad( - struct aegis_state *state, struct scatterlist *sg_src, - unsigned int assoclen) -{ - struct scatter_walk walk; - struct aegis_block buf; - unsigned int pos = 0; - - scatterwalk_start(&walk, sg_src); - while (assoclen != 0) { - unsigned int size = scatterwalk_clamp(&walk, assoclen); - unsigned int left = size; - void *mapped = scatterwalk_map(&walk); - const u8 *src = (const u8 *)mapped; - - if (pos + size >= AEGIS128L_BLOCK_SIZE) { - if (pos > 0) { - unsigned int fill = AEGIS128L_BLOCK_SIZE - pos; - memcpy(buf.bytes + pos, src, fill); - crypto_aegis128l_aesni_ad(state, - AEGIS128L_BLOCK_SIZE, - buf.bytes); - pos = 0; - left -= fill; - src += fill; - } - - crypto_aegis128l_aesni_ad(state, left, src); - - src += left & ~(AEGIS128L_BLOCK_SIZE - 1); - left &= AEGIS128L_BLOCK_SIZE - 1; - } - - memcpy(buf.bytes + pos, src, left); - pos += left; - assoclen -= size; - - scatterwalk_unmap(mapped); - scatterwalk_advance(&walk, size); - scatterwalk_done(&walk, 0, assoclen); - } - - if (pos > 0) { - memset(buf.bytes + pos, 0, AEGIS128L_BLOCK_SIZE - pos); - crypto_aegis128l_aesni_ad(state, AEGIS128L_BLOCK_SIZE, buf.bytes); - } -} - -static void crypto_aegis128l_aesni_process_crypt( - struct aegis_state *state, struct skcipher_walk *walk, - const struct aegis_crypt_ops *ops) -{ - while (walk->nbytes >= AEGIS128L_BLOCK_SIZE) { - ops->crypt_blocks(state, round_down(walk->nbytes, - AEGIS128L_BLOCK_SIZE), - walk->src.virt.addr, walk->dst.virt.addr); - skcipher_walk_done(walk, walk->nbytes % AEGIS128L_BLOCK_SIZE); - } - - if (walk->nbytes) { - ops->crypt_tail(state, walk->nbytes, walk->src.virt.addr, - walk->dst.virt.addr); - skcipher_walk_done(walk, 0); - } -} - -static struct aegis_ctx *crypto_aegis128l_aesni_ctx(struct crypto_aead *aead) -{ - u8 *ctx = crypto_aead_ctx(aead); - ctx = PTR_ALIGN(ctx, __alignof__(struct aegis_ctx)); - return (void *)ctx; -} - -static int crypto_aegis128l_aesni_setkey(struct crypto_aead *aead, - const u8 *key, unsigned int keylen) -{ - struct aegis_ctx *ctx = crypto_aegis128l_aesni_ctx(aead); - - if (keylen != AEGIS128L_KEY_SIZE) { - crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - memcpy(ctx->key.bytes, key, AEGIS128L_KEY_SIZE); - - return 0; -} - -static int crypto_aegis128l_aesni_setauthsize(struct crypto_aead *tfm, - unsigned int authsize) -{ - if (authsize > AEGIS128L_MAX_AUTH_SIZE) - return -EINVAL; - if (authsize < AEGIS128L_MIN_AUTH_SIZE) - return -EINVAL; - return 0; -} - -static void crypto_aegis128l_aesni_crypt(struct aead_request *req, - struct aegis_block *tag_xor, - unsigned int cryptlen, - const struct aegis_crypt_ops *ops) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct aegis_ctx *ctx = crypto_aegis128l_aesni_ctx(tfm); - struct skcipher_walk walk; - struct aegis_state state; - - ops->skcipher_walk_init(&walk, req, true); - - kernel_fpu_begin(); - - crypto_aegis128l_aesni_init(&state, ctx->key.bytes, req->iv); - crypto_aegis128l_aesni_process_ad(&state, req->src, req->assoclen); - crypto_aegis128l_aesni_process_crypt(&state, &walk, ops); - crypto_aegis128l_aesni_final(&state, tag_xor, req->assoclen, cryptlen); - - kernel_fpu_end(); -} - -static int crypto_aegis128l_aesni_encrypt(struct aead_request *req) -{ - static const struct aegis_crypt_ops OPS = { - .skcipher_walk_init = skcipher_walk_aead_encrypt, - .crypt_blocks = crypto_aegis128l_aesni_enc, - .crypt_tail = crypto_aegis128l_aesni_enc_tail, - }; - - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct aegis_block tag = {}; - unsigned int authsize = crypto_aead_authsize(tfm); - unsigned int cryptlen = req->cryptlen; - - crypto_aegis128l_aesni_crypt(req, &tag, cryptlen, &OPS); - - scatterwalk_map_and_copy(tag.bytes, req->dst, - req->assoclen + cryptlen, authsize, 1); - return 0; -} - -static int crypto_aegis128l_aesni_decrypt(struct aead_request *req) -{ - static const struct aegis_block zeros = {}; - - static const struct aegis_crypt_ops OPS = { - .skcipher_walk_init = skcipher_walk_aead_decrypt, - .crypt_blocks = crypto_aegis128l_aesni_dec, - .crypt_tail = crypto_aegis128l_aesni_dec_tail, - }; - - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct aegis_block tag; - unsigned int authsize = crypto_aead_authsize(tfm); - unsigned int cryptlen = req->cryptlen - authsize; - - scatterwalk_map_and_copy(tag.bytes, req->src, - req->assoclen + cryptlen, authsize, 0); - - crypto_aegis128l_aesni_crypt(req, &tag, cryptlen, &OPS); - - return crypto_memneq(tag.bytes, zeros.bytes, authsize) ? -EBADMSG : 0; -} - -static int crypto_aegis128l_aesni_init_tfm(struct crypto_aead *aead) -{ - return 0; -} - -static void crypto_aegis128l_aesni_exit_tfm(struct crypto_aead *aead) -{ -} - -static struct aead_alg crypto_aegis128l_aesni_alg = { - .setkey = crypto_aegis128l_aesni_setkey, - .setauthsize = crypto_aegis128l_aesni_setauthsize, - .encrypt = crypto_aegis128l_aesni_encrypt, - .decrypt = crypto_aegis128l_aesni_decrypt, - .init = crypto_aegis128l_aesni_init_tfm, - .exit = crypto_aegis128l_aesni_exit_tfm, - - .ivsize = AEGIS128L_NONCE_SIZE, - .maxauthsize = AEGIS128L_MAX_AUTH_SIZE, - .chunksize = AEGIS128L_BLOCK_SIZE, - - .base = { - .cra_flags = CRYPTO_ALG_INTERNAL, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct aegis_ctx) + - __alignof__(struct aegis_ctx), - .cra_alignmask = 0, - .cra_priority = 400, - - .cra_name = "__aegis128l", - .cra_driver_name = "__aegis128l-aesni", - - .cra_module = THIS_MODULE, - } -}; - -static struct simd_aead_alg *simd_alg; - -static int __init crypto_aegis128l_aesni_module_init(void) -{ - if (!boot_cpu_has(X86_FEATURE_XMM2) || - !boot_cpu_has(X86_FEATURE_AES) || - !cpu_has_xfeatures(XFEATURE_MASK_SSE, NULL)) - return -ENODEV; - - return simd_register_aeads_compat(&crypto_aegis128l_aesni_alg, 1, - &simd_alg); -} - -static void __exit crypto_aegis128l_aesni_module_exit(void) -{ - simd_unregister_aeads(&crypto_aegis128l_aesni_alg, 1, &simd_alg); -} - -module_init(crypto_aegis128l_aesni_module_init); -module_exit(crypto_aegis128l_aesni_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ondrej Mosnacek "); -MODULE_DESCRIPTION("AEGIS-128L AEAD algorithm -- AESNI+SSE2 implementation"); -MODULE_ALIAS_CRYPTO("aegis128l"); -MODULE_ALIAS_CRYPTO("aegis128l-aesni"); diff --git a/arch/x86/crypto/aegis256-aesni-asm.S b/arch/x86/crypto/aegis256-aesni-asm.S deleted file mode 100644 index 37d9b13dfd852a2b1c4fd27aad88f3abade003c0..0000000000000000000000000000000000000000 --- a/arch/x86/crypto/aegis256-aesni-asm.S +++ /dev/null @@ -1,700 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * AES-NI + SSE2 implementation of AEGIS-128L - * - * Copyright (c) 2017-2018 Ondrej Mosnacek - * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. - */ - -#include -#include - -#define STATE0 %xmm0 -#define STATE1 %xmm1 -#define STATE2 %xmm2 -#define STATE3 %xmm3 -#define STATE4 %xmm4 -#define STATE5 %xmm5 -#define MSG %xmm6 -#define T0 %xmm7 -#define T1 %xmm8 -#define T2 %xmm9 -#define T3 %xmm10 - -#define STATEP %rdi -#define LEN %rsi -#define SRC %rdx -#define DST %rcx - -.section .rodata.cst16.aegis256_const, "aM", @progbits, 32 -.align 16 -.Laegis256_const_0: - .byte 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d - .byte 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 -.Laegis256_const_1: - .byte 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1 - .byte 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd - -.section .rodata.cst16.aegis256_counter, "aM", @progbits, 16 -.align 16 -.Laegis256_counter: - .byte 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 - .byte 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - -.text - -/* - * __load_partial: internal ABI - * input: - * LEN - bytes - * SRC - src - * output: - * MSG - message block - * changed: - * T0 - * %r8 - * %r9 - */ -__load_partial: - xor %r9d, %r9d - pxor MSG, MSG - - mov LEN, %r8 - and $0x1, %r8 - jz .Lld_partial_1 - - mov LEN, %r8 - and $0x1E, %r8 - add SRC, %r8 - mov (%r8), %r9b - -.Lld_partial_1: - mov LEN, %r8 - and $0x2, %r8 - jz .Lld_partial_2 - - mov LEN, %r8 - and $0x1C, %r8 - add SRC, %r8 - shl $0x10, %r9 - mov (%r8), %r9w - -.Lld_partial_2: - mov LEN, %r8 - and $0x4, %r8 - jz .Lld_partial_4 - - mov LEN, %r8 - and $0x18, %r8 - add SRC, %r8 - shl $32, %r9 - mov (%r8), %r8d - xor %r8, %r9 - -.Lld_partial_4: - movq %r9, MSG - - mov LEN, %r8 - and $0x8, %r8 - jz .Lld_partial_8 - - mov LEN, %r8 - and $0x10, %r8 - add SRC, %r8 - pslldq $8, MSG - movq (%r8), T0 - pxor T0, MSG - -.Lld_partial_8: - ret -ENDPROC(__load_partial) - -/* - * __store_partial: internal ABI - * input: - * LEN - bytes - * DST - dst - * output: - * T0 - message block - * changed: - * %r8 - * %r9 - * %r10 - */ -__store_partial: - mov LEN, %r8 - mov DST, %r9 - - movq T0, %r10 - - cmp $8, %r8 - jl .Lst_partial_8 - - mov %r10, (%r9) - psrldq $8, T0 - movq T0, %r10 - - sub $8, %r8 - add $8, %r9 - -.Lst_partial_8: - cmp $4, %r8 - jl .Lst_partial_4 - - mov %r10d, (%r9) - shr $32, %r10 - - sub $4, %r8 - add $4, %r9 - -.Lst_partial_4: - cmp $2, %r8 - jl .Lst_partial_2 - - mov %r10w, (%r9) - shr $0x10, %r10 - - sub $2, %r8 - add $2, %r9 - -.Lst_partial_2: - cmp $1, %r8 - jl .Lst_partial_1 - - mov %r10b, (%r9) - -.Lst_partial_1: - ret -ENDPROC(__store_partial) - -.macro update - movdqa STATE5, T0 - aesenc STATE0, STATE5 - aesenc STATE1, STATE0 - aesenc STATE2, STATE1 - aesenc STATE3, STATE2 - aesenc STATE4, STATE3 - aesenc T0, STATE4 -.endm - -.macro update0 m - update - pxor \m, STATE5 -.endm - -.macro update1 m - update - pxor \m, STATE4 -.endm - -.macro update2 m - update - pxor \m, STATE3 -.endm - -.macro update3 m - update - pxor \m, STATE2 -.endm - -.macro update4 m - update - pxor \m, STATE1 -.endm - -.macro update5 m - update - pxor \m, STATE0 -.endm - -.macro state_load - movdqu 0x00(STATEP), STATE0 - movdqu 0x10(STATEP), STATE1 - movdqu 0x20(STATEP), STATE2 - movdqu 0x30(STATEP), STATE3 - movdqu 0x40(STATEP), STATE4 - movdqu 0x50(STATEP), STATE5 -.endm - -.macro state_store s0 s1 s2 s3 s4 s5 - movdqu \s5, 0x00(STATEP) - movdqu \s0, 0x10(STATEP) - movdqu \s1, 0x20(STATEP) - movdqu \s2, 0x30(STATEP) - movdqu \s3, 0x40(STATEP) - movdqu \s4, 0x50(STATEP) -.endm - -.macro state_store0 - state_store STATE0 STATE1 STATE2 STATE3 STATE4 STATE5 -.endm - -.macro state_store1 - state_store STATE5 STATE0 STATE1 STATE2 STATE3 STATE4 -.endm - -.macro state_store2 - state_store STATE4 STATE5 STATE0 STATE1 STATE2 STATE3 -.endm - -.macro state_store3 - state_store STATE3 STATE4 STATE5 STATE0 STATE1 STATE2 -.endm - -.macro state_store4 - state_store STATE2 STATE3 STATE4 STATE5 STATE0 STATE1 -.endm - -.macro state_store5 - state_store STATE1 STATE2 STATE3 STATE4 STATE5 STATE0 -.endm - -/* - * void crypto_aegis256_aesni_init(void *state, const void *key, const void *iv); - */ -ENTRY(crypto_aegis256_aesni_init) - FRAME_BEGIN - - /* load key: */ - movdqa 0x00(%rsi), MSG - movdqa 0x10(%rsi), T1 - movdqa MSG, STATE4 - movdqa T1, STATE5 - - /* load IV: */ - movdqu 0x00(%rdx), T2 - movdqu 0x10(%rdx), T3 - pxor MSG, T2 - pxor T1, T3 - movdqa T2, STATE0 - movdqa T3, STATE1 - - /* load the constants: */ - movdqa .Laegis256_const_0, STATE3 - movdqa .Laegis256_const_1, STATE2 - pxor STATE3, STATE4 - pxor STATE2, STATE5 - - /* update 10 times with IV and KEY: */ - update0 MSG - update1 T1 - update2 T2 - update3 T3 - update4 MSG - update5 T1 - update0 T2 - update1 T3 - update2 MSG - update3 T1 - update4 T2 - update5 T3 - update0 MSG - update1 T1 - update2 T2 - update3 T3 - - state_store3 - - FRAME_END - ret -ENDPROC(crypto_aegis256_aesni_init) - -.macro ad_block a i - movdq\a (\i * 0x10)(SRC), MSG - update\i MSG - sub $0x10, LEN - cmp $0x10, LEN - jl .Lad_out_\i -.endm - -/* - * void crypto_aegis256_aesni_ad(void *state, unsigned int length, - * const void *data); - */ -ENTRY(crypto_aegis256_aesni_ad) - FRAME_BEGIN - - cmp $0x10, LEN - jb .Lad_out - - state_load - - mov SRC, %r8 - and $0xf, %r8 - jnz .Lad_u_loop - -.align 8 -.Lad_a_loop: - ad_block a 0 - ad_block a 1 - ad_block a 2 - ad_block a 3 - ad_block a 4 - ad_block a 5 - - add $0x60, SRC - jmp .Lad_a_loop - -.align 8 -.Lad_u_loop: - ad_block u 0 - ad_block u 1 - ad_block u 2 - ad_block u 3 - ad_block u 4 - ad_block u 5 - - add $0x60, SRC - jmp .Lad_u_loop - -.Lad_out_0: - state_store0 - FRAME_END - ret - -.Lad_out_1: - state_store1 - FRAME_END - ret - -.Lad_out_2: - state_store2 - FRAME_END - ret - -.Lad_out_3: - state_store3 - FRAME_END - ret - -.Lad_out_4: - state_store4 - FRAME_END - ret - -.Lad_out_5: - state_store5 - FRAME_END - ret - -.Lad_out: - FRAME_END - ret -ENDPROC(crypto_aegis256_aesni_ad) - -.macro crypt m s0 s1 s2 s3 s4 s5 - pxor \s1, \m - pxor \s4, \m - pxor \s5, \m - movdqa \s2, T3 - pand \s3, T3 - pxor T3, \m -.endm - -.macro crypt0 m - crypt \m STATE0 STATE1 STATE2 STATE3 STATE4 STATE5 -.endm - -.macro crypt1 m - crypt \m STATE5 STATE0 STATE1 STATE2 STATE3 STATE4 -.endm - -.macro crypt2 m - crypt \m STATE4 STATE5 STATE0 STATE1 STATE2 STATE3 -.endm - -.macro crypt3 m - crypt \m STATE3 STATE4 STATE5 STATE0 STATE1 STATE2 -.endm - -.macro crypt4 m - crypt \m STATE2 STATE3 STATE4 STATE5 STATE0 STATE1 -.endm - -.macro crypt5 m - crypt \m STATE1 STATE2 STATE3 STATE4 STATE5 STATE0 -.endm - -.macro encrypt_block a i - movdq\a (\i * 0x10)(SRC), MSG - movdqa MSG, T0 - crypt\i T0 - movdq\a T0, (\i * 0x10)(DST) - - update\i MSG - - sub $0x10, LEN - cmp $0x10, LEN - jl .Lenc_out_\i -.endm - -.macro decrypt_block a i - movdq\a (\i * 0x10)(SRC), MSG - crypt\i MSG - movdq\a MSG, (\i * 0x10)(DST) - - update\i MSG - - sub $0x10, LEN - cmp $0x10, LEN - jl .Ldec_out_\i -.endm - -/* - * void crypto_aegis256_aesni_enc(void *state, unsigned int length, - * const void *src, void *dst); - */ -ENTRY(crypto_aegis256_aesni_enc) - FRAME_BEGIN - - cmp $0x10, LEN - jb .Lenc_out - - state_load - - mov SRC, %r8 - or DST, %r8 - and $0xf, %r8 - jnz .Lenc_u_loop - -.align 8 -.Lenc_a_loop: - encrypt_block a 0 - encrypt_block a 1 - encrypt_block a 2 - encrypt_block a 3 - encrypt_block a 4 - encrypt_block a 5 - - add $0x60, SRC - add $0x60, DST - jmp .Lenc_a_loop - -.align 8 -.Lenc_u_loop: - encrypt_block u 0 - encrypt_block u 1 - encrypt_block u 2 - encrypt_block u 3 - encrypt_block u 4 - encrypt_block u 5 - - add $0x60, SRC - add $0x60, DST - jmp .Lenc_u_loop - -.Lenc_out_0: - state_store0 - FRAME_END - ret - -.Lenc_out_1: - state_store1 - FRAME_END - ret - -.Lenc_out_2: - state_store2 - FRAME_END - ret - -.Lenc_out_3: - state_store3 - FRAME_END - ret - -.Lenc_out_4: - state_store4 - FRAME_END - ret - -.Lenc_out_5: - state_store5 - FRAME_END - ret - -.Lenc_out: - FRAME_END - ret -ENDPROC(crypto_aegis256_aesni_enc) - -/* - * void crypto_aegis256_aesni_enc_tail(void *state, unsigned int length, - * const void *src, void *dst); - */ -ENTRY(crypto_aegis256_aesni_enc_tail) - FRAME_BEGIN - - state_load - - /* encrypt message: */ - call __load_partial - - movdqa MSG, T0 - crypt0 T0 - - call __store_partial - - update0 MSG - - state_store0 - - FRAME_END - ret -ENDPROC(crypto_aegis256_aesni_enc_tail) - -/* - * void crypto_aegis256_aesni_dec(void *state, unsigned int length, - * const void *src, void *dst); - */ -ENTRY(crypto_aegis256_aesni_dec) - FRAME_BEGIN - - cmp $0x10, LEN - jb .Ldec_out - - state_load - - mov SRC, %r8 - or DST, %r8 - and $0xF, %r8 - jnz .Ldec_u_loop - -.align 8 -.Ldec_a_loop: - decrypt_block a 0 - decrypt_block a 1 - decrypt_block a 2 - decrypt_block a 3 - decrypt_block a 4 - decrypt_block a 5 - - add $0x60, SRC - add $0x60, DST - jmp .Ldec_a_loop - -.align 8 -.Ldec_u_loop: - decrypt_block u 0 - decrypt_block u 1 - decrypt_block u 2 - decrypt_block u 3 - decrypt_block u 4 - decrypt_block u 5 - - add $0x60, SRC - add $0x60, DST - jmp .Ldec_u_loop - -.Ldec_out_0: - state_store0 - FRAME_END - ret - -.Ldec_out_1: - state_store1 - FRAME_END - ret - -.Ldec_out_2: - state_store2 - FRAME_END - ret - -.Ldec_out_3: - state_store3 - FRAME_END - ret - -.Ldec_out_4: - state_store4 - FRAME_END - ret - -.Ldec_out_5: - state_store5 - FRAME_END - ret - -.Ldec_out: - FRAME_END - ret -ENDPROC(crypto_aegis256_aesni_dec) - -/* - * void crypto_aegis256_aesni_dec_tail(void *state, unsigned int length, - * const void *src, void *dst); - */ -ENTRY(crypto_aegis256_aesni_dec_tail) - FRAME_BEGIN - - state_load - - /* decrypt message: */ - call __load_partial - - crypt0 MSG - - movdqa MSG, T0 - call __store_partial - - /* mask with byte count: */ - movq LEN, T0 - punpcklbw T0, T0 - punpcklbw T0, T0 - punpcklbw T0, T0 - punpcklbw T0, T0 - movdqa .Laegis256_counter, T1 - pcmpgtb T1, T0 - pand T0, MSG - - update0 MSG - - state_store0 - - FRAME_END - ret -ENDPROC(crypto_aegis256_aesni_dec_tail) - -/* - * void crypto_aegis256_aesni_final(void *state, void *tag_xor, - * u64 assoclen, u64 cryptlen); - */ -ENTRY(crypto_aegis256_aesni_final) - FRAME_BEGIN - - state_load - - /* prepare length block: */ - movq %rdx, MSG - movq %rcx, T0 - pslldq $8, T0 - pxor T0, MSG - psllq $3, MSG /* multiply by 8 (to get bit count) */ - - pxor STATE3, MSG - - /* update state: */ - update0 MSG - update1 MSG - update2 MSG - update3 MSG - update4 MSG - update5 MSG - update0 MSG - - /* xor tag: */ - movdqu (%rsi), MSG - - pxor STATE0, MSG - pxor STATE1, MSG - pxor STATE2, MSG - pxor STATE3, MSG - pxor STATE4, MSG - pxor STATE5, MSG - - movdqu MSG, (%rsi) - - FRAME_END - ret -ENDPROC(crypto_aegis256_aesni_final) diff --git a/arch/x86/crypto/aegis256-aesni-glue.c b/arch/x86/crypto/aegis256-aesni-glue.c deleted file mode 100644 index f84da27171d32c20cb73b3579cb3f199dcfd34a2..0000000000000000000000000000000000000000 --- a/arch/x86/crypto/aegis256-aesni-glue.c +++ /dev/null @@ -1,293 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * The AEGIS-256 Authenticated-Encryption Algorithm - * Glue for AES-NI + SSE2 implementation - * - * Copyright (c) 2017-2018 Ondrej Mosnacek - * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define AEGIS256_BLOCK_ALIGN 16 -#define AEGIS256_BLOCK_SIZE 16 -#define AEGIS256_NONCE_SIZE 32 -#define AEGIS256_STATE_BLOCKS 6 -#define AEGIS256_KEY_SIZE 32 -#define AEGIS256_MIN_AUTH_SIZE 8 -#define AEGIS256_MAX_AUTH_SIZE 16 - -asmlinkage void crypto_aegis256_aesni_init(void *state, void *key, void *iv); - -asmlinkage void crypto_aegis256_aesni_ad( - void *state, unsigned int length, const void *data); - -asmlinkage void crypto_aegis256_aesni_enc( - void *state, unsigned int length, const void *src, void *dst); - -asmlinkage void crypto_aegis256_aesni_dec( - void *state, unsigned int length, const void *src, void *dst); - -asmlinkage void crypto_aegis256_aesni_enc_tail( - void *state, unsigned int length, const void *src, void *dst); - -asmlinkage void crypto_aegis256_aesni_dec_tail( - void *state, unsigned int length, const void *src, void *dst); - -asmlinkage void crypto_aegis256_aesni_final( - void *state, void *tag_xor, unsigned int cryptlen, - unsigned int assoclen); - -struct aegis_block { - u8 bytes[AEGIS256_BLOCK_SIZE] __aligned(AEGIS256_BLOCK_ALIGN); -}; - -struct aegis_state { - struct aegis_block blocks[AEGIS256_STATE_BLOCKS]; -}; - -struct aegis_ctx { - struct aegis_block key[AEGIS256_KEY_SIZE / AEGIS256_BLOCK_SIZE]; -}; - -struct aegis_crypt_ops { - int (*skcipher_walk_init)(struct skcipher_walk *walk, - struct aead_request *req, bool atomic); - - void (*crypt_blocks)(void *state, unsigned int length, const void *src, - void *dst); - void (*crypt_tail)(void *state, unsigned int length, const void *src, - void *dst); -}; - -static void crypto_aegis256_aesni_process_ad( - struct aegis_state *state, struct scatterlist *sg_src, - unsigned int assoclen) -{ - struct scatter_walk walk; - struct aegis_block buf; - unsigned int pos = 0; - - scatterwalk_start(&walk, sg_src); - while (assoclen != 0) { - unsigned int size = scatterwalk_clamp(&walk, assoclen); - unsigned int left = size; - void *mapped = scatterwalk_map(&walk); - const u8 *src = (const u8 *)mapped; - - if (pos + size >= AEGIS256_BLOCK_SIZE) { - if (pos > 0) { - unsigned int fill = AEGIS256_BLOCK_SIZE - pos; - memcpy(buf.bytes + pos, src, fill); - crypto_aegis256_aesni_ad(state, - AEGIS256_BLOCK_SIZE, - buf.bytes); - pos = 0; - left -= fill; - src += fill; - } - - crypto_aegis256_aesni_ad(state, left, src); - - src += left & ~(AEGIS256_BLOCK_SIZE - 1); - left &= AEGIS256_BLOCK_SIZE - 1; - } - - memcpy(buf.bytes + pos, src, left); - pos += left; - assoclen -= size; - - scatterwalk_unmap(mapped); - scatterwalk_advance(&walk, size); - scatterwalk_done(&walk, 0, assoclen); - } - - if (pos > 0) { - memset(buf.bytes + pos, 0, AEGIS256_BLOCK_SIZE - pos); - crypto_aegis256_aesni_ad(state, AEGIS256_BLOCK_SIZE, buf.bytes); - } -} - -static void crypto_aegis256_aesni_process_crypt( - struct aegis_state *state, struct skcipher_walk *walk, - const struct aegis_crypt_ops *ops) -{ - while (walk->nbytes >= AEGIS256_BLOCK_SIZE) { - ops->crypt_blocks(state, - round_down(walk->nbytes, AEGIS256_BLOCK_SIZE), - walk->src.virt.addr, walk->dst.virt.addr); - skcipher_walk_done(walk, walk->nbytes % AEGIS256_BLOCK_SIZE); - } - - if (walk->nbytes) { - ops->crypt_tail(state, walk->nbytes, walk->src.virt.addr, - walk->dst.virt.addr); - skcipher_walk_done(walk, 0); - } -} - -static struct aegis_ctx *crypto_aegis256_aesni_ctx(struct crypto_aead *aead) -{ - u8 *ctx = crypto_aead_ctx(aead); - ctx = PTR_ALIGN(ctx, __alignof__(struct aegis_ctx)); - return (void *)ctx; -} - -static int crypto_aegis256_aesni_setkey(struct crypto_aead *aead, const u8 *key, - unsigned int keylen) -{ - struct aegis_ctx *ctx = crypto_aegis256_aesni_ctx(aead); - - if (keylen != AEGIS256_KEY_SIZE) { - crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - memcpy(ctx->key, key, AEGIS256_KEY_SIZE); - - return 0; -} - -static int crypto_aegis256_aesni_setauthsize(struct crypto_aead *tfm, - unsigned int authsize) -{ - if (authsize > AEGIS256_MAX_AUTH_SIZE) - return -EINVAL; - if (authsize < AEGIS256_MIN_AUTH_SIZE) - return -EINVAL; - return 0; -} - -static void crypto_aegis256_aesni_crypt(struct aead_request *req, - struct aegis_block *tag_xor, - unsigned int cryptlen, - const struct aegis_crypt_ops *ops) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct aegis_ctx *ctx = crypto_aegis256_aesni_ctx(tfm); - struct skcipher_walk walk; - struct aegis_state state; - - ops->skcipher_walk_init(&walk, req, true); - - kernel_fpu_begin(); - - crypto_aegis256_aesni_init(&state, ctx->key, req->iv); - crypto_aegis256_aesni_process_ad(&state, req->src, req->assoclen); - crypto_aegis256_aesni_process_crypt(&state, &walk, ops); - crypto_aegis256_aesni_final(&state, tag_xor, req->assoclen, cryptlen); - - kernel_fpu_end(); -} - -static int crypto_aegis256_aesni_encrypt(struct aead_request *req) -{ - static const struct aegis_crypt_ops OPS = { - .skcipher_walk_init = skcipher_walk_aead_encrypt, - .crypt_blocks = crypto_aegis256_aesni_enc, - .crypt_tail = crypto_aegis256_aesni_enc_tail, - }; - - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct aegis_block tag = {}; - unsigned int authsize = crypto_aead_authsize(tfm); - unsigned int cryptlen = req->cryptlen; - - crypto_aegis256_aesni_crypt(req, &tag, cryptlen, &OPS); - - scatterwalk_map_and_copy(tag.bytes, req->dst, - req->assoclen + cryptlen, authsize, 1); - return 0; -} - -static int crypto_aegis256_aesni_decrypt(struct aead_request *req) -{ - static const struct aegis_block zeros = {}; - - static const struct aegis_crypt_ops OPS = { - .skcipher_walk_init = skcipher_walk_aead_decrypt, - .crypt_blocks = crypto_aegis256_aesni_dec, - .crypt_tail = crypto_aegis256_aesni_dec_tail, - }; - - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct aegis_block tag; - unsigned int authsize = crypto_aead_authsize(tfm); - unsigned int cryptlen = req->cryptlen - authsize; - - scatterwalk_map_and_copy(tag.bytes, req->src, - req->assoclen + cryptlen, authsize, 0); - - crypto_aegis256_aesni_crypt(req, &tag, cryptlen, &OPS); - - return crypto_memneq(tag.bytes, zeros.bytes, authsize) ? -EBADMSG : 0; -} - -static int crypto_aegis256_aesni_init_tfm(struct crypto_aead *aead) -{ - return 0; -} - -static void crypto_aegis256_aesni_exit_tfm(struct crypto_aead *aead) -{ -} - -static struct aead_alg crypto_aegis256_aesni_alg = { - .setkey = crypto_aegis256_aesni_setkey, - .setauthsize = crypto_aegis256_aesni_setauthsize, - .encrypt = crypto_aegis256_aesni_encrypt, - .decrypt = crypto_aegis256_aesni_decrypt, - .init = crypto_aegis256_aesni_init_tfm, - .exit = crypto_aegis256_aesni_exit_tfm, - - .ivsize = AEGIS256_NONCE_SIZE, - .maxauthsize = AEGIS256_MAX_AUTH_SIZE, - .chunksize = AEGIS256_BLOCK_SIZE, - - .base = { - .cra_flags = CRYPTO_ALG_INTERNAL, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct aegis_ctx) + - __alignof__(struct aegis_ctx), - .cra_alignmask = 0, - .cra_priority = 400, - - .cra_name = "__aegis256", - .cra_driver_name = "__aegis256-aesni", - - .cra_module = THIS_MODULE, - } -}; - -static struct simd_aead_alg *simd_alg; - -static int __init crypto_aegis256_aesni_module_init(void) -{ - if (!boot_cpu_has(X86_FEATURE_XMM2) || - !boot_cpu_has(X86_FEATURE_AES) || - !cpu_has_xfeatures(XFEATURE_MASK_SSE, NULL)) - return -ENODEV; - - return simd_register_aeads_compat(&crypto_aegis256_aesni_alg, 1, - &simd_alg); -} - -static void __exit crypto_aegis256_aesni_module_exit(void) -{ - simd_unregister_aeads(&crypto_aegis256_aesni_alg, 1, &simd_alg); -} - -module_init(crypto_aegis256_aesni_module_init); -module_exit(crypto_aegis256_aesni_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ondrej Mosnacek "); -MODULE_DESCRIPTION("AEGIS-256 AEAD algorithm -- AESNI+SSE2 implementation"); -MODULE_ALIAS_CRYPTO("aegis256"); -MODULE_ALIAS_CRYPTO("aegis256-aesni"); diff --git a/arch/x86/crypto/aes-i586-asm_32.S b/arch/x86/crypto/aes-i586-asm_32.S deleted file mode 100644 index 2849dbc59e11738a3f7d2a9e063e6700eec7b694..0000000000000000000000000000000000000000 --- a/arch/x86/crypto/aes-i586-asm_32.S +++ /dev/null @@ -1,362 +0,0 @@ -// ------------------------------------------------------------------------- -// Copyright (c) 2001, Dr Brian Gladman < >, Worcester, UK. -// All rights reserved. -// -// LICENSE TERMS -// -// The free distribution and use of this software in both source and binary -// form is allowed (with or without changes) provided that: -// -// 1. distributions of this source code include the above copyright -// notice, this list of conditions and the following disclaimer// -// -// 2. distributions in binary form include the above copyright -// notice, this list of conditions and the following disclaimer -// in the documentation and/or other associated materials// -// -// 3. the copyright holder's name is not used to endorse products -// built using this software without specific written permission. -// -// -// ALTERNATIVELY, provided that this notice is retained in full, this product -// may be distributed under the terms of the GNU General Public License (GPL), -// in which case the provisions of the GPL apply INSTEAD OF those given above. -// -// Copyright (c) 2004 Linus Torvalds -// Copyright (c) 2004 Red Hat, Inc., James Morris - -// DISCLAIMER -// -// This software is provided 'as is' with no explicit or implied warranties -// in respect of its properties including, but not limited to, correctness -// and fitness for purpose. -// ------------------------------------------------------------------------- -// Issue Date: 29/07/2002 - -.file "aes-i586-asm.S" -.text - -#include -#include - -#define tlen 1024 // length of each of 4 'xor' arrays (256 32-bit words) - -/* offsets to parameters with one register pushed onto stack */ -#define ctx 8 -#define out_blk 12 -#define in_blk 16 - -/* offsets in crypto_aes_ctx structure */ -#define klen (480) -#define ekey (0) -#define dkey (240) - -// register mapping for encrypt and decrypt subroutines - -#define r0 eax -#define r1 ebx -#define r2 ecx -#define r3 edx -#define r4 esi -#define r5 edi - -#define eaxl al -#define eaxh ah -#define ebxl bl -#define ebxh bh -#define ecxl cl -#define ecxh ch -#define edxl dl -#define edxh dh - -#define _h(reg) reg##h -#define h(reg) _h(reg) - -#define _l(reg) reg##l -#define l(reg) _l(reg) - -// This macro takes a 32-bit word representing a column and uses -// each of its four bytes to index into four tables of 256 32-bit -// words to obtain values that are then xored into the appropriate -// output registers r0, r1, r4 or r5. - -// Parameters: -// table table base address -// %1 out_state[0] -// %2 out_state[1] -// %3 out_state[2] -// %4 out_state[3] -// idx input register for the round (destroyed) -// tmp scratch register for the round -// sched key schedule - -#define do_col(table, a1,a2,a3,a4, idx, tmp) \ - movzx %l(idx),%tmp; \ - xor table(,%tmp,4),%a1; \ - movzx %h(idx),%tmp; \ - shr $16,%idx; \ - xor table+tlen(,%tmp,4),%a2; \ - movzx %l(idx),%tmp; \ - movzx %h(idx),%idx; \ - xor table+2*tlen(,%tmp,4),%a3; \ - xor table+3*tlen(,%idx,4),%a4; - -// initialise output registers from the key schedule -// NB1: original value of a3 is in idx on exit -// NB2: original values of a1,a2,a4 aren't used -#define do_fcol(table, a1,a2,a3,a4, idx, tmp, sched) \ - mov 0 sched,%a1; \ - movzx %l(idx),%tmp; \ - mov 12 sched,%a2; \ - xor table(,%tmp,4),%a1; \ - mov 4 sched,%a4; \ - movzx %h(idx),%tmp; \ - shr $16,%idx; \ - xor table+tlen(,%tmp,4),%a2; \ - movzx %l(idx),%tmp; \ - movzx %h(idx),%idx; \ - xor table+3*tlen(,%idx,4),%a4; \ - mov %a3,%idx; \ - mov 8 sched,%a3; \ - xor table+2*tlen(,%tmp,4),%a3; - -// initialise output registers from the key schedule -// NB1: original value of a3 is in idx on exit -// NB2: original values of a1,a2,a4 aren't used -#define do_icol(table, a1,a2,a3,a4, idx, tmp, sched) \ - mov 0 sched,%a1; \ - movzx %l(idx),%tmp; \ - mov 4 sched,%a2; \ - xor table(,%tmp,4),%a1; \ - mov 12 sched,%a4; \ - movzx %h(idx),%tmp; \ - shr $16,%idx; \ - xor table+tlen(,%tmp,4),%a2; \ - movzx %l(idx),%tmp; \ - movzx %h(idx),%idx; \ - xor table+3*tlen(,%idx,4),%a4; \ - mov %a3,%idx; \ - mov 8 sched,%a3; \ - xor table+2*tlen(,%tmp,4),%a3; - - -// original Gladman had conditional saves to MMX regs. -#define save(a1, a2) \ - mov %a2,4*a1(%esp) - -#define restore(a1, a2) \ - mov 4*a2(%esp),%a1 - -// These macros perform a forward encryption cycle. They are entered with -// the first previous round column values in r0,r1,r4,r5 and -// exit with the final values in the same registers, using stack -// for temporary storage. - -// round column values -// on entry: r0,r1,r4,r5 -// on exit: r2,r1,r4,r5 -#define fwd_rnd1(arg, table) \ - save (0,r1); \ - save (1,r5); \ - \ - /* compute new column values */ \ - do_fcol(table, r2,r5,r4,r1, r0,r3, arg); /* idx=r0 */ \ - do_col (table, r4,r1,r2,r5, r0,r3); /* idx=r4 */ \ - restore(r0,0); \ - do_col (table, r1,r2,r5,r4, r0,r3); /* idx=r1 */ \ - restore(r0,1); \ - do_col (table, r5,r4,r1,r2, r0,r3); /* idx=r5 */ - -// round column values -// on entry: r2,r1,r4,r5 -// on exit: r0,r1,r4,r5 -#define fwd_rnd2(arg, table) \ - save (0,r1); \ - save (1,r5); \ - \ - /* compute new column values */ \ - do_fcol(table, r0,r5,r4,r1, r2,r3, arg); /* idx=r2 */ \ - do_col (table, r4,r1,r0,r5, r2,r3); /* idx=r4 */ \ - restore(r2,0); \ - do_col (table, r1,r0,r5,r4, r2,r3); /* idx=r1 */ \ - restore(r2,1); \ - do_col (table, r5,r4,r1,r0, r2,r3); /* idx=r5 */ - -// These macros performs an inverse encryption cycle. They are entered with -// the first previous round column values in r0,r1,r4,r5 and -// exit with the final values in the same registers, using stack -// for temporary storage - -// round column values -// on entry: r0,r1,r4,r5 -// on exit: r2,r1,r4,r5 -#define inv_rnd1(arg, table) \ - save (0,r1); \ - save (1,r5); \ - \ - /* compute new column values */ \ - do_icol(table, r2,r1,r4,r5, r0,r3, arg); /* idx=r0 */ \ - do_col (table, r4,r5,r2,r1, r0,r3); /* idx=r4 */ \ - restore(r0,0); \ - do_col (table, r1,r4,r5,r2, r0,r3); /* idx=r1 */ \ - restore(r0,1); \ - do_col (table, r5,r2,r1,r4, r0,r3); /* idx=r5 */ - -// round column values -// on entry: r2,r1,r4,r5 -// on exit: r0,r1,r4,r5 -#define inv_rnd2(arg, table) \ - save (0,r1); \ - save (1,r5); \ - \ - /* compute new column values */ \ - do_icol(table, r0,r1,r4,r5, r2,r3, arg); /* idx=r2 */ \ - do_col (table, r4,r5,r0,r1, r2,r3); /* idx=r4 */ \ - restore(r2,0); \ - do_col (table, r1,r4,r5,r0, r2,r3); /* idx=r1 */ \ - restore(r2,1); \ - do_col (table, r5,r0,r1,r4, r2,r3); /* idx=r5 */ - -// AES (Rijndael) Encryption Subroutine -/* void aes_enc_blk(struct crypto_aes_ctx *ctx, u8 *out_blk, const u8 *in_blk) */ - -.extern crypto_ft_tab -.extern crypto_fl_tab - -ENTRY(aes_enc_blk) - push %ebp - mov ctx(%esp),%ebp - -// CAUTION: the order and the values used in these assigns -// rely on the register mappings - -1: push %ebx - mov in_blk+4(%esp),%r2 - push %esi - mov klen(%ebp),%r3 // key size - push %edi -#if ekey != 0 - lea ekey(%ebp),%ebp // key pointer -#endif - -// input four columns and xor in first round key - - mov (%r2),%r0 - mov 4(%r2),%r1 - mov 8(%r2),%r4 - mov 12(%r2),%r5 - xor (%ebp),%r0 - xor 4(%ebp),%r1 - xor 8(%ebp),%r4 - xor 12(%ebp),%r5 - - sub $8,%esp // space for register saves on stack - add $16,%ebp // increment to next round key - cmp $24,%r3 - jb 4f // 10 rounds for 128-bit key - lea 32(%ebp),%ebp - je 3f // 12 rounds for 192-bit key - lea 32(%ebp),%ebp - -2: fwd_rnd1( -64(%ebp), crypto_ft_tab) // 14 rounds for 256-bit key - fwd_rnd2( -48(%ebp), crypto_ft_tab) -3: fwd_rnd1( -32(%ebp), crypto_ft_tab) // 12 rounds for 192-bit key - fwd_rnd2( -16(%ebp), crypto_ft_tab) -4: fwd_rnd1( (%ebp), crypto_ft_tab) // 10 rounds for 128-bit key - fwd_rnd2( +16(%ebp), crypto_ft_tab) - fwd_rnd1( +32(%ebp), crypto_ft_tab) - fwd_rnd2( +48(%ebp), crypto_ft_tab) - fwd_rnd1( +64(%ebp), crypto_ft_tab) - fwd_rnd2( +80(%ebp), crypto_ft_tab) - fwd_rnd1( +96(%ebp), crypto_ft_tab) - fwd_rnd2(+112(%ebp), crypto_ft_tab) - fwd_rnd1(+128(%ebp), crypto_ft_tab) - fwd_rnd2(+144(%ebp), crypto_fl_tab) // last round uses a different table - -// move final values to the output array. CAUTION: the -// order of these assigns rely on the register mappings - - add $8,%esp - mov out_blk+12(%esp),%ebp - mov %r5,12(%ebp) - pop %edi - mov %r4,8(%ebp) - pop %esi - mov %r1,4(%ebp) - pop %ebx - mov %r0,(%ebp) - pop %ebp - ret -ENDPROC(aes_enc_blk) - -// AES (Rijndael) Decryption Subroutine -/* void aes_dec_blk(struct crypto_aes_ctx *ctx, u8 *out_blk, const u8 *in_blk) */ - -.extern crypto_it_tab -.extern crypto_il_tab - -ENTRY(aes_dec_blk) - push %ebp - mov ctx(%esp),%ebp - -// CAUTION: the order and the values used in these assigns -// rely on the register mappings - -1: push %ebx - mov in_blk+4(%esp),%r2 - push %esi - mov klen(%ebp),%r3 // key size - push %edi -#if dkey != 0 - lea dkey(%ebp),%ebp // key pointer -#endif - -// input four columns and xor in first round key - - mov (%r2),%r0 - mov 4(%r2),%r1 - mov 8(%r2),%r4 - mov 12(%r2),%r5 - xor (%ebp),%r0 - xor 4(%ebp),%r1 - xor 8(%ebp),%r4 - xor 12(%ebp),%r5 - - sub $8,%esp // space for register saves on stack - add $16,%ebp // increment to next round key - cmp $24,%r3 - jb 4f // 10 rounds for 128-bit key - lea 32(%ebp),%ebp - je 3f // 12 rounds for 192-bit key - lea 32(%ebp),%ebp - -2: inv_rnd1( -64(%ebp), crypto_it_tab) // 14 rounds for 256-bit key - inv_rnd2( -48(%ebp), crypto_it_tab) -3: inv_rnd1( -32(%ebp), crypto_it_tab) // 12 rounds for 192-bit key - inv_rnd2( -16(%ebp), crypto_it_tab) -4: inv_rnd1( (%ebp), crypto_it_tab) // 10 rounds for 128-bit key - inv_rnd2( +16(%ebp), crypto_it_tab) - inv_rnd1( +32(%ebp), crypto_it_tab) - inv_rnd2( +48(%ebp), crypto_it_tab) - inv_rnd1( +64(%ebp), crypto_it_tab) - inv_rnd2( +80(%ebp), crypto_it_tab) - inv_rnd1( +96(%ebp), crypto_it_tab) - inv_rnd2(+112(%ebp), crypto_it_tab) - inv_rnd1(+128(%ebp), crypto_it_tab) - inv_rnd2(+144(%ebp), crypto_il_tab) // last round uses a different table - -// move final values to the output array. CAUTION: the -// order of these assigns rely on the register mappings - - add $8,%esp - mov out_blk+12(%esp),%ebp - mov %r5,12(%ebp) - pop %edi - mov %r4,8(%ebp) - pop %esi - mov %r1,4(%ebp) - pop %ebx - mov %r0,(%ebp) - pop %ebp - ret -ENDPROC(aes_dec_blk) diff --git a/arch/x86/crypto/aes-x86_64-asm_64.S b/arch/x86/crypto/aes-x86_64-asm_64.S deleted file mode 100644 index 8739cf7795de0f0073aca140b3a11c51a2a68e7c..0000000000000000000000000000000000000000 --- a/arch/x86/crypto/aes-x86_64-asm_64.S +++ /dev/null @@ -1,185 +0,0 @@ -/* AES (Rijndael) implementation (FIPS PUB 197) for x86_64 - * - * Copyright (C) 2005 Andreas Steinmetz, - * - * License: - * This code can be distributed under the terms of the GNU General Public - * License (GPL) Version 2 provided that the above header down to and - * including this sentence is retained in full. - */ - -.extern crypto_ft_tab -.extern crypto_it_tab -.extern crypto_fl_tab -.extern crypto_il_tab - -.text - -#include -#include - -#define R1 %rax -#define R1E %eax -#define R1X %ax -#define R1H %ah -#define R1L %al -#define R2 %rbx -#define R2E %ebx -#define R2X %bx -#define R2H %bh -#define R2L %bl -#define R3 %rcx -#define R3E %ecx -#define R3X %cx -#define R3H %ch -#define R3L %cl -#define R4 %rdx -#define R4E %edx -#define R4X %dx -#define R4H %dh -#define R4L %dl -#define R5 %rsi -#define R5E %esi -#define R6 %rdi -#define R6E %edi -#define R7 %r9 /* don't use %rbp; it breaks stack traces */ -#define R7E %r9d -#define R8 %r8 -#define R10 %r10 -#define R11 %r11 - -#define prologue(FUNC,KEY,B128,B192,r1,r2,r5,r6,r7,r8,r9,r10,r11) \ - ENTRY(FUNC); \ - movq r1,r2; \ - leaq KEY+48(r8),r9; \ - movq r10,r11; \ - movl (r7),r5 ## E; \ - movl 4(r7),r1 ## E; \ - movl 8(r7),r6 ## E; \ - movl 12(r7),r7 ## E; \ - movl 480(r8),r10 ## E; \ - xorl -48(r9),r5 ## E; \ - xorl -44(r9),r1 ## E; \ - xorl -40(r9),r6 ## E; \ - xorl -36(r9),r7 ## E; \ - cmpl $24,r10 ## E; \ - jb B128; \ - leaq 32(r9),r9; \ - je B192; \ - leaq 32(r9),r9; - -#define epilogue(FUNC,r1,r2,r5,r6,r7,r8,r9) \ - movq r1,r2; \ - movl r5 ## E,(r9); \ - movl r6 ## E,4(r9); \ - movl r7 ## E,8(r9); \ - movl r8 ## E,12(r9); \ - ret; \ - ENDPROC(FUNC); - -#define round(TAB,OFFSET,r1,r2,r3,r4,r5,r6,r7,r8,ra,rb,rc,rd) \ - movzbl r2 ## H,r5 ## E; \ - movzbl r2 ## L,r6 ## E; \ - movl TAB+1024(,r5,4),r5 ## E;\ - movw r4 ## X,r2 ## X; \ - movl TAB(,r6,4),r6 ## E; \ - roll $16,r2 ## E; \ - shrl $16,r4 ## E; \ - movzbl r4 ## L,r7 ## E; \ - movzbl r4 ## H,r4 ## E; \ - xorl OFFSET(r8),ra ## E; \ - xorl OFFSET+4(r8),rb ## E; \ - xorl TAB+3072(,r4,4),r5 ## E;\ - xorl TAB+2048(,r7,4),r6 ## E;\ - movzbl r1 ## L,r7 ## E; \ - movzbl r1 ## H,r4 ## E; \ - movl TAB+1024(,r4,4),r4 ## E;\ - movw r3 ## X,r1 ## X; \ - roll $16,r1 ## E; \ - shrl $16,r3 ## E; \ - xorl TAB(,r7,4),r5 ## E; \ - movzbl r3 ## L,r7 ## E; \ - movzbl r3 ## H,r3 ## E; \ - xorl TAB+3072(,r3,4),r4 ## E;\ - xorl TAB+2048(,r7,4),r5 ## E;\ - movzbl r1 ## L,r7 ## E; \ - movzbl r1 ## H,r3 ## E; \ - shrl $16,r1 ## E; \ - xorl TAB+3072(,r3,4),r6 ## E;\ - movl TAB+2048(,r7,4),r3 ## E;\ - movzbl r1 ## L,r7 ## E; \ - movzbl r1 ## H,r1 ## E; \ - xorl TAB+1024(,r1,4),r6 ## E;\ - xorl TAB(,r7,4),r3 ## E; \ - movzbl r2 ## H,r1 ## E; \ - movzbl r2 ## L,r7 ## E; \ - shrl $16,r2 ## E; \ - xorl TAB+3072(,r1,4),r3 ## E;\ - xorl TAB+2048(,r7,4),r4 ## E;\ - movzbl r2 ## H,r1 ## E; \ - movzbl r2 ## L,r2 ## E; \ - xorl OFFSET+8(r8),rc ## E; \ - xorl OFFSET+12(r8),rd ## E; \ - xorl TAB+1024(,r1,4),r3 ## E;\ - xorl TAB(,r2,4),r4 ## E; - -#define move_regs(r1,r2,r3,r4) \ - movl r3 ## E,r1 ## E; \ - movl r4 ## E,r2 ## E; - -#define entry(FUNC,KEY,B128,B192) \ - prologue(FUNC,KEY,B128,B192,R2,R8,R1,R3,R4,R6,R10,R5,R11) - -#define return(FUNC) epilogue(FUNC,R8,R2,R5,R6,R3,R4,R11) - -#define encrypt_round(TAB,OFFSET) \ - round(TAB,OFFSET,R1,R2,R3,R4,R5,R6,R7,R10,R5,R6,R3,R4) \ - move_regs(R1,R2,R5,R6) - -#define encrypt_final(TAB,OFFSET) \ - round(TAB,OFFSET,R1,R2,R3,R4,R5,R6,R7,R10,R5,R6,R3,R4) - -#define decrypt_round(TAB,OFFSET) \ - round(TAB,OFFSET,R2,R1,R4,R3,R6,R5,R7,R10,R5,R6,R3,R4) \ - move_regs(R1,R2,R5,R6) - -#define decrypt_final(TAB,OFFSET) \ - round(TAB,OFFSET,R2,R1,R4,R3,R6,R5,R7,R10,R5,R6,R3,R4) - -/* void aes_enc_blk(stuct crypto_tfm *tfm, u8 *out, const u8 *in) */ - - entry(aes_enc_blk,0,.Le128,.Le192) - encrypt_round(crypto_ft_tab,-96) - encrypt_round(crypto_ft_tab,-80) -.Le192: encrypt_round(crypto_ft_tab,-64) - encrypt_round(crypto_ft_tab,-48) -.Le128: encrypt_round(crypto_ft_tab,-32) - encrypt_round(crypto_ft_tab,-16) - encrypt_round(crypto_ft_tab, 0) - encrypt_round(crypto_ft_tab, 16) - encrypt_round(crypto_ft_tab, 32) - encrypt_round(crypto_ft_tab, 48) - encrypt_round(crypto_ft_tab, 64) - encrypt_round(crypto_ft_tab, 80) - encrypt_round(crypto_ft_tab, 96) - encrypt_final(crypto_fl_tab,112) - return(aes_enc_blk) - -/* void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in) */ - - entry(aes_dec_blk,240,.Ld128,.Ld192) - decrypt_round(crypto_it_tab,-96) - decrypt_round(crypto_it_tab,-80) -.Ld192: decrypt_round(crypto_it_tab,-64) - decrypt_round(crypto_it_tab,-48) -.Ld128: decrypt_round(crypto_it_tab,-32) - decrypt_round(crypto_it_tab,-16) - decrypt_round(crypto_it_tab, 0) - decrypt_round(crypto_it_tab, 16) - decrypt_round(crypto_it_tab, 32) - decrypt_round(crypto_it_tab, 48) - decrypt_round(crypto_it_tab, 64) - decrypt_round(crypto_it_tab, 80) - decrypt_round(crypto_it_tab, 96) - decrypt_final(crypto_il_tab,112) - return(aes_dec_blk) diff --git a/arch/x86/crypto/aes_glue.c b/arch/x86/crypto/aes_glue.c index 9e9d819e8bc3db5909f6c24c89c24993731cf83c..7b7dc05fa1a4a66a92ca8adbc0ca44b750bafe3c 100644 --- a/arch/x86/crypto/aes_glue.c +++ b/arch/x86/crypto/aes_glue.c @@ -1,71 +1 @@ // SPDX-License-Identifier: GPL-2.0-only -/* - * Glue Code for the asm optimized version of the AES Cipher Algorithm - * - */ - -#include -#include -#include - -asmlinkage void aes_enc_blk(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in); -asmlinkage void aes_dec_blk(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in); - -void crypto_aes_encrypt_x86(struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src) -{ - aes_enc_blk(ctx, dst, src); -} -EXPORT_SYMBOL_GPL(crypto_aes_encrypt_x86); - -void crypto_aes_decrypt_x86(struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src) -{ - aes_dec_blk(ctx, dst, src); -} -EXPORT_SYMBOL_GPL(crypto_aes_decrypt_x86); - -static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) -{ - aes_enc_blk(crypto_tfm_ctx(tfm), dst, src); -} - -static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) -{ - aes_dec_blk(crypto_tfm_ctx(tfm), dst, src); -} - -static struct crypto_alg aes_alg = { - .cra_name = "aes", - .cra_driver_name = "aes-asm", - .cra_priority = 200, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypto_aes_ctx), - .cra_module = THIS_MODULE, - .cra_u = { - .cipher = { - .cia_min_keysize = AES_MIN_KEY_SIZE, - .cia_max_keysize = AES_MAX_KEY_SIZE, - .cia_setkey = crypto_aes_set_key, - .cia_encrypt = aes_encrypt, - .cia_decrypt = aes_decrypt - } - } -}; - -static int __init aes_init(void) -{ - return crypto_register_alg(&aes_alg); -} - -static void __exit aes_fini(void) -{ - crypto_unregister_alg(&aes_alg); -} - -module_init(aes_init); -module_exit(aes_fini); - -MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, asm optimized"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CRYPTO("aes"); -MODULE_ALIAS_CRYPTO("aes-asm"); diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index 73c0ccb009a0f73f28e129bb92ceb9c784767eb8..3e707e81afdb416d076858238631fef447449108 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -329,7 +328,7 @@ static int aes_set_key_common(struct crypto_tfm *tfm, void *raw_ctx, } if (!crypto_simd_usable()) - err = crypto_aes_expand_key(ctx, in_key, key_len); + err = aes_expandkey(ctx, in_key, key_len); else { kernel_fpu_begin(); err = aesni_set_key(ctx, in_key, key_len); @@ -345,26 +344,26 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, return aes_set_key_common(tfm, crypto_tfm_ctx(tfm), in_key, key_len); } -static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +static void aesni_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm)); - if (!crypto_simd_usable()) - crypto_aes_encrypt_x86(ctx, dst, src); - else { + if (!crypto_simd_usable()) { + aes_encrypt(ctx, dst, src); + } else { kernel_fpu_begin(); aesni_enc(ctx, dst, src); kernel_fpu_end(); } } -static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +static void aesni_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm)); - if (!crypto_simd_usable()) - crypto_aes_decrypt_x86(ctx, dst, src); - else { + if (!crypto_simd_usable()) { + aes_decrypt(ctx, dst, src); + } else { kernel_fpu_begin(); aesni_dec(ctx, dst, src); kernel_fpu_end(); @@ -610,7 +609,8 @@ static int xts_encrypt(struct skcipher_request *req) return glue_xts_req_128bit(&aesni_enc_xts, req, XTS_TWEAK_CAST(aesni_xts_tweak), aes_ctx(ctx->raw_tweak_ctx), - aes_ctx(ctx->raw_crypt_ctx)); + aes_ctx(ctx->raw_crypt_ctx), + false); } static int xts_decrypt(struct skcipher_request *req) @@ -621,32 +621,28 @@ static int xts_decrypt(struct skcipher_request *req) return glue_xts_req_128bit(&aesni_dec_xts, req, XTS_TWEAK_CAST(aesni_xts_tweak), aes_ctx(ctx->raw_tweak_ctx), - aes_ctx(ctx->raw_crypt_ctx)); + aes_ctx(ctx->raw_crypt_ctx), + true); } static int rfc4106_set_hash_subkey(u8 *hash_subkey, const u8 *key, unsigned int key_len) { - struct crypto_cipher *tfm; + struct crypto_aes_ctx ctx; int ret; - tfm = crypto_alloc_cipher("aes", 0, 0); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); - - ret = crypto_cipher_setkey(tfm, key, key_len); + ret = aes_expandkey(&ctx, key, key_len); if (ret) - goto out_free_cipher; + return ret; /* Clear the data in the hash sub key container to zero.*/ /* We want to cipher all zeros to create the hash sub key. */ memset(hash_subkey, 0, RFC4106_HASH_SUBKEY_SIZE); - crypto_cipher_encrypt_one(tfm, hash_subkey, hash_subkey); + aes_encrypt(&ctx, hash_subkey, hash_subkey); -out_free_cipher: - crypto_free_cipher(tfm); - return ret; + memzero_explicit(&ctx, sizeof(ctx)); + return 0; } static int common_rfc4106_set_key(struct crypto_aead *aead, const u8 *key, @@ -919,8 +915,8 @@ static struct crypto_alg aesni_cipher_alg = { .cia_min_keysize = AES_MIN_KEY_SIZE, .cia_max_keysize = AES_MAX_KEY_SIZE, .cia_setkey = aes_set_key, - .cia_encrypt = aes_encrypt, - .cia_decrypt = aes_decrypt + .cia_encrypt = aesni_encrypt, + .cia_decrypt = aesni_decrypt } } }; diff --git a/arch/x86/crypto/camellia_aesni_avx2_glue.c b/arch/x86/crypto/camellia_aesni_avx2_glue.c index abf298c272dce80aaab50c3cd1db0b416b667edc..a4f00128ea55269699c8cda2d9d1b45555981428 100644 --- a/arch/x86/crypto/camellia_aesni_avx2_glue.c +++ b/arch/x86/crypto/camellia_aesni_avx2_glue.c @@ -182,7 +182,7 @@ static int xts_encrypt(struct skcipher_request *req) return glue_xts_req_128bit(&camellia_enc_xts, req, XTS_TWEAK_CAST(camellia_enc_blk), - &ctx->tweak_ctx, &ctx->crypt_ctx); + &ctx->tweak_ctx, &ctx->crypt_ctx, false); } static int xts_decrypt(struct skcipher_request *req) @@ -192,7 +192,7 @@ static int xts_decrypt(struct skcipher_request *req) return glue_xts_req_128bit(&camellia_dec_xts, req, XTS_TWEAK_CAST(camellia_enc_blk), - &ctx->tweak_ctx, &ctx->crypt_ctx); + &ctx->tweak_ctx, &ctx->crypt_ctx, true); } static struct skcipher_alg camellia_algs[] = { diff --git a/arch/x86/crypto/camellia_aesni_avx_glue.c b/arch/x86/crypto/camellia_aesni_avx_glue.c index 0c22d84750a3c58ee8024db8a6f6cc73f55e77c6..f28d282779b872a5872fe9928904923826acaccd 100644 --- a/arch/x86/crypto/camellia_aesni_avx_glue.c +++ b/arch/x86/crypto/camellia_aesni_avx_glue.c @@ -208,7 +208,7 @@ static int xts_encrypt(struct skcipher_request *req) return glue_xts_req_128bit(&camellia_enc_xts, req, XTS_TWEAK_CAST(camellia_enc_blk), - &ctx->tweak_ctx, &ctx->crypt_ctx); + &ctx->tweak_ctx, &ctx->crypt_ctx, false); } static int xts_decrypt(struct skcipher_request *req) @@ -218,7 +218,7 @@ static int xts_decrypt(struct skcipher_request *req) return glue_xts_req_128bit(&camellia_dec_xts, req, XTS_TWEAK_CAST(camellia_enc_blk), - &ctx->tweak_ctx, &ctx->crypt_ctx); + &ctx->tweak_ctx, &ctx->crypt_ctx, true); } static struct skcipher_alg camellia_algs[] = { diff --git a/arch/x86/crypto/cast6_avx_glue.c b/arch/x86/crypto/cast6_avx_glue.c index 645f8f16815c08f3b0230441f2618be6c9f53f40..a8a38fffb4a98f407c41093c99bb59528a7c5cf2 100644 --- a/arch/x86/crypto/cast6_avx_glue.c +++ b/arch/x86/crypto/cast6_avx_glue.c @@ -201,7 +201,7 @@ static int xts_encrypt(struct skcipher_request *req) return glue_xts_req_128bit(&cast6_enc_xts, req, XTS_TWEAK_CAST(__cast6_encrypt), - &ctx->tweak_ctx, &ctx->crypt_ctx); + &ctx->tweak_ctx, &ctx->crypt_ctx, false); } static int xts_decrypt(struct skcipher_request *req) @@ -211,7 +211,7 @@ static int xts_decrypt(struct skcipher_request *req) return glue_xts_req_128bit(&cast6_dec_xts, req, XTS_TWEAK_CAST(__cast6_encrypt), - &ctx->tweak_ctx, &ctx->crypt_ctx); + &ctx->tweak_ctx, &ctx->crypt_ctx, true); } static struct skcipher_alg cast6_algs[] = { diff --git a/arch/x86/crypto/des3_ede_glue.c b/arch/x86/crypto/des3_ede_glue.c index 968386c21ef45ca6d64bcb2c5cdf6e0f0f867990..89830e531350350cb8ea8c10ee213a4868652340 100644 --- a/arch/x86/crypto/des3_ede_glue.c +++ b/arch/x86/crypto/des3_ede_glue.c @@ -19,8 +19,8 @@ #include struct des3_ede_x86_ctx { - u32 enc_expkey[DES3_EDE_EXPKEY_WORDS]; - u32 dec_expkey[DES3_EDE_EXPKEY_WORDS]; + struct des3_ede_ctx enc; + struct des3_ede_ctx dec; }; /* regular block cipher functions */ @@ -34,7 +34,7 @@ asmlinkage void des3_ede_x86_64_crypt_blk_3way(const u32 *expkey, u8 *dst, static inline void des3_ede_enc_blk(struct des3_ede_x86_ctx *ctx, u8 *dst, const u8 *src) { - u32 *enc_ctx = ctx->enc_expkey; + u32 *enc_ctx = ctx->enc.expkey; des3_ede_x86_64_crypt_blk(enc_ctx, dst, src); } @@ -42,7 +42,7 @@ static inline void des3_ede_enc_blk(struct des3_ede_x86_ctx *ctx, u8 *dst, static inline void des3_ede_dec_blk(struct des3_ede_x86_ctx *ctx, u8 *dst, const u8 *src) { - u32 *dec_ctx = ctx->dec_expkey; + u32 *dec_ctx = ctx->dec.expkey; des3_ede_x86_64_crypt_blk(dec_ctx, dst, src); } @@ -50,7 +50,7 @@ static inline void des3_ede_dec_blk(struct des3_ede_x86_ctx *ctx, u8 *dst, static inline void des3_ede_enc_blk_3way(struct des3_ede_x86_ctx *ctx, u8 *dst, const u8 *src) { - u32 *enc_ctx = ctx->enc_expkey; + u32 *enc_ctx = ctx->enc.expkey; des3_ede_x86_64_crypt_blk_3way(enc_ctx, dst, src); } @@ -58,7 +58,7 @@ static inline void des3_ede_enc_blk_3way(struct des3_ede_x86_ctx *ctx, u8 *dst, static inline void des3_ede_dec_blk_3way(struct des3_ede_x86_ctx *ctx, u8 *dst, const u8 *src) { - u32 *dec_ctx = ctx->dec_expkey; + u32 *dec_ctx = ctx->dec.expkey; des3_ede_x86_64_crypt_blk_3way(dec_ctx, dst, src); } @@ -122,7 +122,7 @@ static int ecb_encrypt(struct skcipher_request *req) struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); - return ecb_crypt(req, ctx->enc_expkey); + return ecb_crypt(req, ctx->enc.expkey); } static int ecb_decrypt(struct skcipher_request *req) @@ -130,7 +130,7 @@ static int ecb_decrypt(struct skcipher_request *req) struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); - return ecb_crypt(req, ctx->dec_expkey); + return ecb_crypt(req, ctx->dec.expkey); } static unsigned int __cbc_encrypt(struct des3_ede_x86_ctx *ctx, @@ -348,20 +348,28 @@ static int des3_ede_x86_setkey(struct crypto_tfm *tfm, const u8 *key, u32 i, j, tmp; int err; - /* Generate encryption context using generic implementation. */ - err = __des3_ede_setkey(ctx->enc_expkey, &tfm->crt_flags, key, keylen); - if (err < 0) + err = des3_ede_expand_key(&ctx->enc, key, keylen); + if (err == -ENOKEY) { + if (crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS) + err = -EINVAL; + else + err = 0; + } + + if (err) { + memset(ctx, 0, sizeof(*ctx)); return err; + } /* Fix encryption context for this implementation and form decryption * context. */ j = DES3_EDE_EXPKEY_WORDS - 2; for (i = 0; i < DES3_EDE_EXPKEY_WORDS; i += 2, j -= 2) { - tmp = ror32(ctx->enc_expkey[i + 1], 4); - ctx->enc_expkey[i + 1] = tmp; + tmp = ror32(ctx->enc.expkey[i + 1], 4); + ctx->enc.expkey[i + 1] = tmp; - ctx->dec_expkey[j + 0] = ctx->enc_expkey[i + 0]; - ctx->dec_expkey[j + 1] = tmp; + ctx->dec.expkey[j + 0] = ctx->enc.expkey[i + 0]; + ctx->dec.expkey[j + 1] = tmp; } return 0; diff --git a/arch/x86/crypto/ghash-clmulni-intel_glue.c b/arch/x86/crypto/ghash-clmulni-intel_glue.c index ac76fe88ac4fdf7a1b1bcff5780bc2d52faddd8b..04d72a5a8ce9815ffca1db870b4110fe2a4c4166 100644 --- a/arch/x86/crypto/ghash-clmulni-intel_glue.c +++ b/arch/x86/crypto/ghash-clmulni-intel_glue.c @@ -357,6 +357,5 @@ module_init(ghash_pclmulqdqni_mod_init); module_exit(ghash_pclmulqdqni_mod_exit); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("GHASH Message Digest Algorithm, " - "accelerated by PCLMULQDQ-NI"); +MODULE_DESCRIPTION("GHASH hash function, accelerated by PCLMULQDQ-NI"); MODULE_ALIAS_CRYPTO("ghash"); diff --git a/arch/x86/crypto/glue_helper.c b/arch/x86/crypto/glue_helper.c index 9015514453875851508bb6e11a5f157ecf0d6229..d15b99397480be4681b3178ebba6ea9bbb087049 100644 --- a/arch/x86/crypto/glue_helper.c +++ b/arch/x86/crypto/glue_helper.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -259,17 +260,36 @@ static unsigned int __glue_xts_req_128bit(const struct common_glue_ctx *gctx, int glue_xts_req_128bit(const struct common_glue_ctx *gctx, struct skcipher_request *req, common_glue_func_t tweak_fn, void *tweak_ctx, - void *crypt_ctx) + void *crypt_ctx, bool decrypt) { + const bool cts = (req->cryptlen % XTS_BLOCK_SIZE); const unsigned int bsize = 128 / 8; + struct skcipher_request subreq; struct skcipher_walk walk; bool fpu_enabled = false; - unsigned int nbytes; + unsigned int nbytes, tail; int err; + if (req->cryptlen < XTS_BLOCK_SIZE) + return -EINVAL; + + if (unlikely(cts)) { + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + + tail = req->cryptlen % XTS_BLOCK_SIZE + XTS_BLOCK_SIZE; + + skcipher_request_set_tfm(&subreq, tfm); + skcipher_request_set_callback(&subreq, + crypto_skcipher_get_flags(tfm), + NULL, NULL); + skcipher_request_set_crypt(&subreq, req->src, req->dst, + req->cryptlen - tail, req->iv); + req = &subreq; + } + err = skcipher_walk_virt(&walk, req, false); nbytes = walk.nbytes; - if (!nbytes) + if (err) return err; /* set minimum length to bsize, for tweak_fn */ @@ -287,6 +307,47 @@ int glue_xts_req_128bit(const struct common_glue_ctx *gctx, nbytes = walk.nbytes; } + if (unlikely(cts)) { + u8 *next_tweak, *final_tweak = req->iv; + struct scatterlist *src, *dst; + struct scatterlist s[2], d[2]; + le128 b[2]; + + dst = src = scatterwalk_ffwd(s, req->src, req->cryptlen); + if (req->dst != req->src) + dst = scatterwalk_ffwd(d, req->dst, req->cryptlen); + + if (decrypt) { + next_tweak = memcpy(b, req->iv, XTS_BLOCK_SIZE); + gf128mul_x_ble(b, b); + } else { + next_tweak = req->iv; + } + + skcipher_request_set_crypt(&subreq, src, dst, XTS_BLOCK_SIZE, + next_tweak); + + err = skcipher_walk_virt(&walk, req, false) ?: + skcipher_walk_done(&walk, + __glue_xts_req_128bit(gctx, crypt_ctx, &walk)); + if (err) + goto out; + + scatterwalk_map_and_copy(b, dst, 0, XTS_BLOCK_SIZE, 0); + memcpy(b + 1, b, tail - XTS_BLOCK_SIZE); + scatterwalk_map_and_copy(b, src, XTS_BLOCK_SIZE, + tail - XTS_BLOCK_SIZE, 0); + scatterwalk_map_and_copy(b, dst, 0, tail, 1); + + skcipher_request_set_crypt(&subreq, dst, dst, XTS_BLOCK_SIZE, + final_tweak); + + err = skcipher_walk_virt(&walk, req, false) ?: + skcipher_walk_done(&walk, + __glue_xts_req_128bit(gctx, crypt_ctx, &walk)); + } + +out: glue_fpu_end(fpu_enabled); return err; diff --git a/arch/x86/crypto/morus1280-avx2-asm.S b/arch/x86/crypto/morus1280-avx2-asm.S deleted file mode 100644 index 5413fee334814ee2b5c8d3e0e73efb72589f1800..0000000000000000000000000000000000000000 --- a/arch/x86/crypto/morus1280-avx2-asm.S +++ /dev/null @@ -1,619 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * AVX2 implementation of MORUS-1280 - * - * Copyright (c) 2017-2018 Ondrej Mosnacek - * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. - */ - -#include -#include - -#define SHUFFLE_MASK(i0, i1, i2, i3) \ - (i0 | (i1 << 2) | (i2 << 4) | (i3 << 6)) - -#define MASK1 SHUFFLE_MASK(3, 0, 1, 2) -#define MASK2 SHUFFLE_MASK(2, 3, 0, 1) -#define MASK3 SHUFFLE_MASK(1, 2, 3, 0) - -#define STATE0 %ymm0 -#define STATE0_LOW %xmm0 -#define STATE1 %ymm1 -#define STATE2 %ymm2 -#define STATE3 %ymm3 -#define STATE4 %ymm4 -#define KEY %ymm5 -#define MSG %ymm5 -#define MSG_LOW %xmm5 -#define T0 %ymm6 -#define T0_LOW %xmm6 -#define T1 %ymm7 - -.section .rodata.cst32.morus1280_const, "aM", @progbits, 32 -.align 32 -.Lmorus1280_const: - .byte 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d - .byte 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 - .byte 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1 - .byte 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd - -.section .rodata.cst32.morus1280_counter, "aM", @progbits, 32 -.align 32 -.Lmorus1280_counter: - .byte 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 - .byte 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - .byte 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 - .byte 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f - -.text - -.macro morus1280_round s0, s1, s2, s3, s4, b, w - vpand \s1, \s2, T0 - vpxor T0, \s0, \s0 - vpxor \s3, \s0, \s0 - vpsllq $\b, \s0, T0 - vpsrlq $(64 - \b), \s0, \s0 - vpxor T0, \s0, \s0 - vpermq $\w, \s3, \s3 -.endm - -/* - * __morus1280_update: internal ABI - * input: - * STATE[0-4] - input state - * MSG - message block - * output: - * STATE[0-4] - output state - * changed: - * T0 - */ -__morus1280_update: - morus1280_round STATE0, STATE1, STATE2, STATE3, STATE4, 13, MASK1 - vpxor MSG, STATE1, STATE1 - morus1280_round STATE1, STATE2, STATE3, STATE4, STATE0, 46, MASK2 - vpxor MSG, STATE2, STATE2 - morus1280_round STATE2, STATE3, STATE4, STATE0, STATE1, 38, MASK3 - vpxor MSG, STATE3, STATE3 - morus1280_round STATE3, STATE4, STATE0, STATE1, STATE2, 7, MASK2 - vpxor MSG, STATE4, STATE4 - morus1280_round STATE4, STATE0, STATE1, STATE2, STATE3, 4, MASK1 - ret -ENDPROC(__morus1280_update) - -/* - * __morus1280_update_zero: internal ABI - * input: - * STATE[0-4] - input state - * output: - * STATE[0-4] - output state - * changed: - * T0 - */ -__morus1280_update_zero: - morus1280_round STATE0, STATE1, STATE2, STATE3, STATE4, 13, MASK1 - morus1280_round STATE1, STATE2, STATE3, STATE4, STATE0, 46, MASK2 - morus1280_round STATE2, STATE3, STATE4, STATE0, STATE1, 38, MASK3 - morus1280_round STATE3, STATE4, STATE0, STATE1, STATE2, 7, MASK2 - morus1280_round STATE4, STATE0, STATE1, STATE2, STATE3, 4, MASK1 - ret -ENDPROC(__morus1280_update_zero) - -/* - * __load_partial: internal ABI - * input: - * %rsi - src - * %rcx - bytes - * output: - * MSG - message block - * changed: - * %r8 - * %r9 - */ -__load_partial: - xor %r9d, %r9d - vpxor MSG, MSG, MSG - - mov %rcx, %r8 - and $0x1, %r8 - jz .Lld_partial_1 - - mov %rcx, %r8 - and $0x1E, %r8 - add %rsi, %r8 - mov (%r8), %r9b - -.Lld_partial_1: - mov %rcx, %r8 - and $0x2, %r8 - jz .Lld_partial_2 - - mov %rcx, %r8 - and $0x1C, %r8 - add %rsi, %r8 - shl $16, %r9 - mov (%r8), %r9w - -.Lld_partial_2: - mov %rcx, %r8 - and $0x4, %r8 - jz .Lld_partial_4 - - mov %rcx, %r8 - and $0x18, %r8 - add %rsi, %r8 - shl $32, %r9 - mov (%r8), %r8d - xor %r8, %r9 - -.Lld_partial_4: - movq %r9, MSG_LOW - - mov %rcx, %r8 - and $0x8, %r8 - jz .Lld_partial_8 - - mov %rcx, %r8 - and $0x10, %r8 - add %rsi, %r8 - pshufd $MASK2, MSG_LOW, MSG_LOW - pinsrq $0, (%r8), MSG_LOW - -.Lld_partial_8: - mov %rcx, %r8 - and $0x10, %r8 - jz .Lld_partial_16 - - vpermq $MASK2, MSG, MSG - movdqu (%rsi), MSG_LOW - -.Lld_partial_16: - ret -ENDPROC(__load_partial) - -/* - * __store_partial: internal ABI - * input: - * %rdx - dst - * %rcx - bytes - * output: - * T0 - message block - * changed: - * %r8 - * %r9 - * %r10 - */ -__store_partial: - mov %rcx, %r8 - mov %rdx, %r9 - - cmp $16, %r8 - jl .Lst_partial_16 - - movdqu T0_LOW, (%r9) - vpermq $MASK2, T0, T0 - - sub $16, %r8 - add $16, %r9 - -.Lst_partial_16: - movq T0_LOW, %r10 - - cmp $8, %r8 - jl .Lst_partial_8 - - mov %r10, (%r9) - pextrq $1, T0_LOW, %r10 - - sub $8, %r8 - add $8, %r9 - -.Lst_partial_8: - cmp $4, %r8 - jl .Lst_partial_4 - - mov %r10d, (%r9) - shr $32, %r10 - - sub $4, %r8 - add $4, %r9 - -.Lst_partial_4: - cmp $2, %r8 - jl .Lst_partial_2 - - mov %r10w, (%r9) - shr $16, %r10 - - sub $2, %r8 - add $2, %r9 - -.Lst_partial_2: - cmp $1, %r8 - jl .Lst_partial_1 - - mov %r10b, (%r9) - -.Lst_partial_1: - ret -ENDPROC(__store_partial) - -/* - * void crypto_morus1280_avx2_init(void *state, const void *key, - * const void *iv); - */ -ENTRY(crypto_morus1280_avx2_init) - FRAME_BEGIN - - /* load IV: */ - vpxor STATE0, STATE0, STATE0 - movdqu (%rdx), STATE0_LOW - /* load key: */ - vmovdqu (%rsi), KEY - vmovdqa KEY, STATE1 - /* load all ones: */ - vpcmpeqd STATE2, STATE2, STATE2 - /* load all zeros: */ - vpxor STATE3, STATE3, STATE3 - /* load the constant: */ - vmovdqa .Lmorus1280_const, STATE4 - - /* update 16 times with zero: */ - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - - /* xor-in the key again after updates: */ - vpxor KEY, STATE1, STATE1 - - /* store the state: */ - vmovdqu STATE0, (0 * 32)(%rdi) - vmovdqu STATE1, (1 * 32)(%rdi) - vmovdqu STATE2, (2 * 32)(%rdi) - vmovdqu STATE3, (3 * 32)(%rdi) - vmovdqu STATE4, (4 * 32)(%rdi) - - FRAME_END - ret -ENDPROC(crypto_morus1280_avx2_init) - -/* - * void crypto_morus1280_avx2_ad(void *state, const void *data, - * unsigned int length); - */ -ENTRY(crypto_morus1280_avx2_ad) - FRAME_BEGIN - - cmp $32, %rdx - jb .Lad_out - - /* load the state: */ - vmovdqu (0 * 32)(%rdi), STATE0 - vmovdqu (1 * 32)(%rdi), STATE1 - vmovdqu (2 * 32)(%rdi), STATE2 - vmovdqu (3 * 32)(%rdi), STATE3 - vmovdqu (4 * 32)(%rdi), STATE4 - - mov %rsi, %r8 - and $0x1F, %r8 - jnz .Lad_u_loop - -.align 4 -.Lad_a_loop: - vmovdqa (%rsi), MSG - call __morus1280_update - sub $32, %rdx - add $32, %rsi - cmp $32, %rdx - jge .Lad_a_loop - - jmp .Lad_cont -.align 4 -.Lad_u_loop: - vmovdqu (%rsi), MSG - call __morus1280_update - sub $32, %rdx - add $32, %rsi - cmp $32, %rdx - jge .Lad_u_loop - -.Lad_cont: - /* store the state: */ - vmovdqu STATE0, (0 * 32)(%rdi) - vmovdqu STATE1, (1 * 32)(%rdi) - vmovdqu STATE2, (2 * 32)(%rdi) - vmovdqu STATE3, (3 * 32)(%rdi) - vmovdqu STATE4, (4 * 32)(%rdi) - -.Lad_out: - FRAME_END - ret -ENDPROC(crypto_morus1280_avx2_ad) - -/* - * void crypto_morus1280_avx2_enc(void *state, const void *src, void *dst, - * unsigned int length); - */ -ENTRY(crypto_morus1280_avx2_enc) - FRAME_BEGIN - - cmp $32, %rcx - jb .Lenc_out - - /* load the state: */ - vmovdqu (0 * 32)(%rdi), STATE0 - vmovdqu (1 * 32)(%rdi), STATE1 - vmovdqu (2 * 32)(%rdi), STATE2 - vmovdqu (3 * 32)(%rdi), STATE3 - vmovdqu (4 * 32)(%rdi), STATE4 - - mov %rsi, %r8 - or %rdx, %r8 - and $0x1F, %r8 - jnz .Lenc_u_loop - -.align 4 -.Lenc_a_loop: - vmovdqa (%rsi), MSG - vmovdqa MSG, T0 - vpxor STATE0, T0, T0 - vpermq $MASK3, STATE1, T1 - vpxor T1, T0, T0 - vpand STATE2, STATE3, T1 - vpxor T1, T0, T0 - vmovdqa T0, (%rdx) - - call __morus1280_update - sub $32, %rcx - add $32, %rsi - add $32, %rdx - cmp $32, %rcx - jge .Lenc_a_loop - - jmp .Lenc_cont -.align 4 -.Lenc_u_loop: - vmovdqu (%rsi), MSG - vmovdqa MSG, T0 - vpxor STATE0, T0, T0 - vpermq $MASK3, STATE1, T1 - vpxor T1, T0, T0 - vpand STATE2, STATE3, T1 - vpxor T1, T0, T0 - vmovdqu T0, (%rdx) - - call __morus1280_update - sub $32, %rcx - add $32, %rsi - add $32, %rdx - cmp $32, %rcx - jge .Lenc_u_loop - -.Lenc_cont: - /* store the state: */ - vmovdqu STATE0, (0 * 32)(%rdi) - vmovdqu STATE1, (1 * 32)(%rdi) - vmovdqu STATE2, (2 * 32)(%rdi) - vmovdqu STATE3, (3 * 32)(%rdi) - vmovdqu STATE4, (4 * 32)(%rdi) - -.Lenc_out: - FRAME_END - ret -ENDPROC(crypto_morus1280_avx2_enc) - -/* - * void crypto_morus1280_avx2_enc_tail(void *state, const void *src, void *dst, - * unsigned int length); - */ -ENTRY(crypto_morus1280_avx2_enc_tail) - FRAME_BEGIN - - /* load the state: */ - vmovdqu (0 * 32)(%rdi), STATE0 - vmovdqu (1 * 32)(%rdi), STATE1 - vmovdqu (2 * 32)(%rdi), STATE2 - vmovdqu (3 * 32)(%rdi), STATE3 - vmovdqu (4 * 32)(%rdi), STATE4 - - /* encrypt message: */ - call __load_partial - - vmovdqa MSG, T0 - vpxor STATE0, T0, T0 - vpermq $MASK3, STATE1, T1 - vpxor T1, T0, T0 - vpand STATE2, STATE3, T1 - vpxor T1, T0, T0 - - call __store_partial - - call __morus1280_update - - /* store the state: */ - vmovdqu STATE0, (0 * 32)(%rdi) - vmovdqu STATE1, (1 * 32)(%rdi) - vmovdqu STATE2, (2 * 32)(%rdi) - vmovdqu STATE3, (3 * 32)(%rdi) - vmovdqu STATE4, (4 * 32)(%rdi) - - FRAME_END - ret -ENDPROC(crypto_morus1280_avx2_enc_tail) - -/* - * void crypto_morus1280_avx2_dec(void *state, const void *src, void *dst, - * unsigned int length); - */ -ENTRY(crypto_morus1280_avx2_dec) - FRAME_BEGIN - - cmp $32, %rcx - jb .Ldec_out - - /* load the state: */ - vmovdqu (0 * 32)(%rdi), STATE0 - vmovdqu (1 * 32)(%rdi), STATE1 - vmovdqu (2 * 32)(%rdi), STATE2 - vmovdqu (3 * 32)(%rdi), STATE3 - vmovdqu (4 * 32)(%rdi), STATE4 - - mov %rsi, %r8 - or %rdx, %r8 - and $0x1F, %r8 - jnz .Ldec_u_loop - -.align 4 -.Ldec_a_loop: - vmovdqa (%rsi), MSG - vpxor STATE0, MSG, MSG - vpermq $MASK3, STATE1, T0 - vpxor T0, MSG, MSG - vpand STATE2, STATE3, T0 - vpxor T0, MSG, MSG - vmovdqa MSG, (%rdx) - - call __morus1280_update - sub $32, %rcx - add $32, %rsi - add $32, %rdx - cmp $32, %rcx - jge .Ldec_a_loop - - jmp .Ldec_cont -.align 4 -.Ldec_u_loop: - vmovdqu (%rsi), MSG - vpxor STATE0, MSG, MSG - vpermq $MASK3, STATE1, T0 - vpxor T0, MSG, MSG - vpand STATE2, STATE3, T0 - vpxor T0, MSG, MSG - vmovdqu MSG, (%rdx) - - call __morus1280_update - sub $32, %rcx - add $32, %rsi - add $32, %rdx - cmp $32, %rcx - jge .Ldec_u_loop - -.Ldec_cont: - /* store the state: */ - vmovdqu STATE0, (0 * 32)(%rdi) - vmovdqu STATE1, (1 * 32)(%rdi) - vmovdqu STATE2, (2 * 32)(%rdi) - vmovdqu STATE3, (3 * 32)(%rdi) - vmovdqu STATE4, (4 * 32)(%rdi) - -.Ldec_out: - FRAME_END - ret -ENDPROC(crypto_morus1280_avx2_dec) - -/* - * void crypto_morus1280_avx2_dec_tail(void *state, const void *src, void *dst, - * unsigned int length); - */ -ENTRY(crypto_morus1280_avx2_dec_tail) - FRAME_BEGIN - - /* load the state: */ - vmovdqu (0 * 32)(%rdi), STATE0 - vmovdqu (1 * 32)(%rdi), STATE1 - vmovdqu (2 * 32)(%rdi), STATE2 - vmovdqu (3 * 32)(%rdi), STATE3 - vmovdqu (4 * 32)(%rdi), STATE4 - - /* decrypt message: */ - call __load_partial - - vpxor STATE0, MSG, MSG - vpermq $MASK3, STATE1, T0 - vpxor T0, MSG, MSG - vpand STATE2, STATE3, T0 - vpxor T0, MSG, MSG - vmovdqa MSG, T0 - - call __store_partial - - /* mask with byte count: */ - movq %rcx, T0_LOW - vpbroadcastb T0_LOW, T0 - vmovdqa .Lmorus1280_counter, T1 - vpcmpgtb T1, T0, T0 - vpand T0, MSG, MSG - - call __morus1280_update - - /* store the state: */ - vmovdqu STATE0, (0 * 32)(%rdi) - vmovdqu STATE1, (1 * 32)(%rdi) - vmovdqu STATE2, (2 * 32)(%rdi) - vmovdqu STATE3, (3 * 32)(%rdi) - vmovdqu STATE4, (4 * 32)(%rdi) - - FRAME_END - ret -ENDPROC(crypto_morus1280_avx2_dec_tail) - -/* - * void crypto_morus1280_avx2_final(void *state, void *tag_xor, - * u64 assoclen, u64 cryptlen); - */ -ENTRY(crypto_morus1280_avx2_final) - FRAME_BEGIN - - /* load the state: */ - vmovdqu (0 * 32)(%rdi), STATE0 - vmovdqu (1 * 32)(%rdi), STATE1 - vmovdqu (2 * 32)(%rdi), STATE2 - vmovdqu (3 * 32)(%rdi), STATE3 - vmovdqu (4 * 32)(%rdi), STATE4 - - /* xor state[0] into state[4]: */ - vpxor STATE0, STATE4, STATE4 - - /* prepare length block: */ - vpxor MSG, MSG, MSG - vpinsrq $0, %rdx, MSG_LOW, MSG_LOW - vpinsrq $1, %rcx, MSG_LOW, MSG_LOW - vpsllq $3, MSG, MSG /* multiply by 8 (to get bit count) */ - - /* update state: */ - call __morus1280_update - call __morus1280_update - call __morus1280_update - call __morus1280_update - call __morus1280_update - call __morus1280_update - call __morus1280_update - call __morus1280_update - call __morus1280_update - call __morus1280_update - - /* xor tag: */ - vmovdqu (%rsi), MSG - - vpxor STATE0, MSG, MSG - vpermq $MASK3, STATE1, T0 - vpxor T0, MSG, MSG - vpand STATE2, STATE3, T0 - vpxor T0, MSG, MSG - vmovdqu MSG, (%rsi) - - FRAME_END - ret -ENDPROC(crypto_morus1280_avx2_final) diff --git a/arch/x86/crypto/morus1280-avx2-glue.c b/arch/x86/crypto/morus1280-avx2-glue.c deleted file mode 100644 index 2d000d66ba4c44a4a75291cc09878c0626d6cfaa..0000000000000000000000000000000000000000 --- a/arch/x86/crypto/morus1280-avx2-glue.c +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * The MORUS-1280 Authenticated-Encryption Algorithm - * Glue for AVX2 implementation - * - * Copyright (c) 2016-2018 Ondrej Mosnacek - * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include - -asmlinkage void crypto_morus1280_avx2_init(void *state, const void *key, - const void *iv); -asmlinkage void crypto_morus1280_avx2_ad(void *state, const void *data, - unsigned int length); - -asmlinkage void crypto_morus1280_avx2_enc(void *state, const void *src, - void *dst, unsigned int length); -asmlinkage void crypto_morus1280_avx2_dec(void *state, const void *src, - void *dst, unsigned int length); - -asmlinkage void crypto_morus1280_avx2_enc_tail(void *state, const void *src, - void *dst, unsigned int length); -asmlinkage void crypto_morus1280_avx2_dec_tail(void *state, const void *src, - void *dst, unsigned int length); - -asmlinkage void crypto_morus1280_avx2_final(void *state, void *tag_xor, - u64 assoclen, u64 cryptlen); - -MORUS1280_DECLARE_ALG(avx2, "morus1280-avx2", 400); - -static struct simd_aead_alg *simd_alg; - -static int __init crypto_morus1280_avx2_module_init(void) -{ - if (!boot_cpu_has(X86_FEATURE_AVX2) || - !boot_cpu_has(X86_FEATURE_OSXSAVE) || - !cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL)) - return -ENODEV; - - return simd_register_aeads_compat(&crypto_morus1280_avx2_alg, 1, - &simd_alg); -} - -static void __exit crypto_morus1280_avx2_module_exit(void) -{ - simd_unregister_aeads(&crypto_morus1280_avx2_alg, 1, &simd_alg); -} - -module_init(crypto_morus1280_avx2_module_init); -module_exit(crypto_morus1280_avx2_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ondrej Mosnacek "); -MODULE_DESCRIPTION("MORUS-1280 AEAD algorithm -- AVX2 implementation"); -MODULE_ALIAS_CRYPTO("morus1280"); -MODULE_ALIAS_CRYPTO("morus1280-avx2"); diff --git a/arch/x86/crypto/morus1280-sse2-asm.S b/arch/x86/crypto/morus1280-sse2-asm.S deleted file mode 100644 index 0eece772866b284955b03bf91b2d2b68f4710bab..0000000000000000000000000000000000000000 --- a/arch/x86/crypto/morus1280-sse2-asm.S +++ /dev/null @@ -1,893 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * SSE2 implementation of MORUS-1280 - * - * Copyright (c) 2017-2018 Ondrej Mosnacek - * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. - */ - -#include -#include - -#define SHUFFLE_MASK(i0, i1, i2, i3) \ - (i0 | (i1 << 2) | (i2 << 4) | (i3 << 6)) - -#define MASK2 SHUFFLE_MASK(2, 3, 0, 1) - -#define STATE0_LO %xmm0 -#define STATE0_HI %xmm1 -#define STATE1_LO %xmm2 -#define STATE1_HI %xmm3 -#define STATE2_LO %xmm4 -#define STATE2_HI %xmm5 -#define STATE3_LO %xmm6 -#define STATE3_HI %xmm7 -#define STATE4_LO %xmm8 -#define STATE4_HI %xmm9 -#define KEY_LO %xmm10 -#define KEY_HI %xmm11 -#define MSG_LO %xmm10 -#define MSG_HI %xmm11 -#define T0_LO %xmm12 -#define T0_HI %xmm13 -#define T1_LO %xmm14 -#define T1_HI %xmm15 - -.section .rodata.cst16.morus640_const, "aM", @progbits, 16 -.align 16 -.Lmorus640_const_0: - .byte 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d - .byte 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 -.Lmorus640_const_1: - .byte 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1 - .byte 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd - -.section .rodata.cst16.morus640_counter, "aM", @progbits, 16 -.align 16 -.Lmorus640_counter_0: - .byte 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 - .byte 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f -.Lmorus640_counter_1: - .byte 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 - .byte 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f - -.text - -.macro rol1 hi, lo - /* - * HI_1 | HI_0 || LO_1 | LO_0 - * ==> - * HI_0 | HI_1 || LO_1 | LO_0 - * ==> - * HI_0 | LO_1 || LO_0 | HI_1 - */ - pshufd $MASK2, \hi, \hi - movdqa \hi, T0_LO - punpcklqdq \lo, T0_LO - punpckhqdq \hi, \lo - movdqa \lo, \hi - movdqa T0_LO, \lo -.endm - -.macro rol2 hi, lo - movdqa \lo, T0_LO - movdqa \hi, \lo - movdqa T0_LO, \hi -.endm - -.macro rol3 hi, lo - /* - * HI_1 | HI_0 || LO_1 | LO_0 - * ==> - * HI_0 | HI_1 || LO_1 | LO_0 - * ==> - * LO_0 | HI_1 || HI_0 | LO_1 - */ - pshufd $MASK2, \hi, \hi - movdqa \lo, T0_LO - punpckhqdq \hi, T0_LO - punpcklqdq \lo, \hi - movdqa T0_LO, \lo -.endm - -.macro morus1280_round s0_l, s0_h, s1_l, s1_h, s2_l, s2_h, s3_l, s3_h, s4_l, s4_h, b, w - movdqa \s1_l, T0_LO - pand \s2_l, T0_LO - pxor T0_LO, \s0_l - - movdqa \s1_h, T0_LO - pand \s2_h, T0_LO - pxor T0_LO, \s0_h - - pxor \s3_l, \s0_l - pxor \s3_h, \s0_h - - movdqa \s0_l, T0_LO - psllq $\b, T0_LO - psrlq $(64 - \b), \s0_l - pxor T0_LO, \s0_l - - movdqa \s0_h, T0_LO - psllq $\b, T0_LO - psrlq $(64 - \b), \s0_h - pxor T0_LO, \s0_h - - \w \s3_h, \s3_l -.endm - -/* - * __morus1280_update: internal ABI - * input: - * STATE[0-4] - input state - * MSG - message block - * output: - * STATE[0-4] - output state - * changed: - * T0 - */ -__morus1280_update: - morus1280_round \ - STATE0_LO, STATE0_HI, \ - STATE1_LO, STATE1_HI, \ - STATE2_LO, STATE2_HI, \ - STATE3_LO, STATE3_HI, \ - STATE4_LO, STATE4_HI, \ - 13, rol1 - pxor MSG_LO, STATE1_LO - pxor MSG_HI, STATE1_HI - morus1280_round \ - STATE1_LO, STATE1_HI, \ - STATE2_LO, STATE2_HI, \ - STATE3_LO, STATE3_HI, \ - STATE4_LO, STATE4_HI, \ - STATE0_LO, STATE0_HI, \ - 46, rol2 - pxor MSG_LO, STATE2_LO - pxor MSG_HI, STATE2_HI - morus1280_round \ - STATE2_LO, STATE2_HI, \ - STATE3_LO, STATE3_HI, \ - STATE4_LO, STATE4_HI, \ - STATE0_LO, STATE0_HI, \ - STATE1_LO, STATE1_HI, \ - 38, rol3 - pxor MSG_LO, STATE3_LO - pxor MSG_HI, STATE3_HI - morus1280_round \ - STATE3_LO, STATE3_HI, \ - STATE4_LO, STATE4_HI, \ - STATE0_LO, STATE0_HI, \ - STATE1_LO, STATE1_HI, \ - STATE2_LO, STATE2_HI, \ - 7, rol2 - pxor MSG_LO, STATE4_LO - pxor MSG_HI, STATE4_HI - morus1280_round \ - STATE4_LO, STATE4_HI, \ - STATE0_LO, STATE0_HI, \ - STATE1_LO, STATE1_HI, \ - STATE2_LO, STATE2_HI, \ - STATE3_LO, STATE3_HI, \ - 4, rol1 - ret -ENDPROC(__morus1280_update) - -/* - * __morus1280_update_zero: internal ABI - * input: - * STATE[0-4] - input state - * output: - * STATE[0-4] - output state - * changed: - * T0 - */ -__morus1280_update_zero: - morus1280_round \ - STATE0_LO, STATE0_HI, \ - STATE1_LO, STATE1_HI, \ - STATE2_LO, STATE2_HI, \ - STATE3_LO, STATE3_HI, \ - STATE4_LO, STATE4_HI, \ - 13, rol1 - morus1280_round \ - STATE1_LO, STATE1_HI, \ - STATE2_LO, STATE2_HI, \ - STATE3_LO, STATE3_HI, \ - STATE4_LO, STATE4_HI, \ - STATE0_LO, STATE0_HI, \ - 46, rol2 - morus1280_round \ - STATE2_LO, STATE2_HI, \ - STATE3_LO, STATE3_HI, \ - STATE4_LO, STATE4_HI, \ - STATE0_LO, STATE0_HI, \ - STATE1_LO, STATE1_HI, \ - 38, rol3 - morus1280_round \ - STATE3_LO, STATE3_HI, \ - STATE4_LO, STATE4_HI, \ - STATE0_LO, STATE0_HI, \ - STATE1_LO, STATE1_HI, \ - STATE2_LO, STATE2_HI, \ - 7, rol2 - morus1280_round \ - STATE4_LO, STATE4_HI, \ - STATE0_LO, STATE0_HI, \ - STATE1_LO, STATE1_HI, \ - STATE2_LO, STATE2_HI, \ - STATE3_LO, STATE3_HI, \ - 4, rol1 - ret -ENDPROC(__morus1280_update_zero) - -/* - * __load_partial: internal ABI - * input: - * %rsi - src - * %rcx - bytes - * output: - * MSG - message block - * changed: - * %r8 - * %r9 - */ -__load_partial: - xor %r9d, %r9d - pxor MSG_LO, MSG_LO - pxor MSG_HI, MSG_HI - - mov %rcx, %r8 - and $0x1, %r8 - jz .Lld_partial_1 - - mov %rcx, %r8 - and $0x1E, %r8 - add %rsi, %r8 - mov (%r8), %r9b - -.Lld_partial_1: - mov %rcx, %r8 - and $0x2, %r8 - jz .Lld_partial_2 - - mov %rcx, %r8 - and $0x1C, %r8 - add %rsi, %r8 - shl $16, %r9 - mov (%r8), %r9w - -.Lld_partial_2: - mov %rcx, %r8 - and $0x4, %r8 - jz .Lld_partial_4 - - mov %rcx, %r8 - and $0x18, %r8 - add %rsi, %r8 - shl $32, %r9 - mov (%r8), %r8d - xor %r8, %r9 - -.Lld_partial_4: - movq %r9, MSG_LO - - mov %rcx, %r8 - and $0x8, %r8 - jz .Lld_partial_8 - - mov %rcx, %r8 - and $0x10, %r8 - add %rsi, %r8 - pslldq $8, MSG_LO - movq (%r8), T0_LO - pxor T0_LO, MSG_LO - -.Lld_partial_8: - mov %rcx, %r8 - and $0x10, %r8 - jz .Lld_partial_16 - - movdqa MSG_LO, MSG_HI - movdqu (%rsi), MSG_LO - -.Lld_partial_16: - ret -ENDPROC(__load_partial) - -/* - * __store_partial: internal ABI - * input: - * %rdx - dst - * %rcx - bytes - * output: - * T0 - message block - * changed: - * %r8 - * %r9 - * %r10 - */ -__store_partial: - mov %rcx, %r8 - mov %rdx, %r9 - - cmp $16, %r8 - jl .Lst_partial_16 - - movdqu T0_LO, (%r9) - movdqa T0_HI, T0_LO - - sub $16, %r8 - add $16, %r9 - -.Lst_partial_16: - movq T0_LO, %r10 - - cmp $8, %r8 - jl .Lst_partial_8 - - mov %r10, (%r9) - psrldq $8, T0_LO - movq T0_LO, %r10 - - sub $8, %r8 - add $8, %r9 - -.Lst_partial_8: - cmp $4, %r8 - jl .Lst_partial_4 - - mov %r10d, (%r9) - shr $32, %r10 - - sub $4, %r8 - add $4, %r9 - -.Lst_partial_4: - cmp $2, %r8 - jl .Lst_partial_2 - - mov %r10w, (%r9) - shr $16, %r10 - - sub $2, %r8 - add $2, %r9 - -.Lst_partial_2: - cmp $1, %r8 - jl .Lst_partial_1 - - mov %r10b, (%r9) - -.Lst_partial_1: - ret -ENDPROC(__store_partial) - -/* - * void crypto_morus1280_sse2_init(void *state, const void *key, - * const void *iv); - */ -ENTRY(crypto_morus1280_sse2_init) - FRAME_BEGIN - - /* load IV: */ - pxor STATE0_HI, STATE0_HI - movdqu (%rdx), STATE0_LO - /* load key: */ - movdqu 0(%rsi), KEY_LO - movdqu 16(%rsi), KEY_HI - movdqa KEY_LO, STATE1_LO - movdqa KEY_HI, STATE1_HI - /* load all ones: */ - pcmpeqd STATE2_LO, STATE2_LO - pcmpeqd STATE2_HI, STATE2_HI - /* load all zeros: */ - pxor STATE3_LO, STATE3_LO - pxor STATE3_HI, STATE3_HI - /* load the constant: */ - movdqa .Lmorus640_const_0, STATE4_LO - movdqa .Lmorus640_const_1, STATE4_HI - - /* update 16 times with zero: */ - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - call __morus1280_update_zero - - /* xor-in the key again after updates: */ - pxor KEY_LO, STATE1_LO - pxor KEY_HI, STATE1_HI - - /* store the state: */ - movdqu STATE0_LO, (0 * 16)(%rdi) - movdqu STATE0_HI, (1 * 16)(%rdi) - movdqu STATE1_LO, (2 * 16)(%rdi) - movdqu STATE1_HI, (3 * 16)(%rdi) - movdqu STATE2_LO, (4 * 16)(%rdi) - movdqu STATE2_HI, (5 * 16)(%rdi) - movdqu STATE3_LO, (6 * 16)(%rdi) - movdqu STATE3_HI, (7 * 16)(%rdi) - movdqu STATE4_LO, (8 * 16)(%rdi) - movdqu STATE4_HI, (9 * 16)(%rdi) - - FRAME_END - ret -ENDPROC(crypto_morus1280_sse2_init) - -/* - * void crypto_morus1280_sse2_ad(void *state, const void *data, - * unsigned int length); - */ -ENTRY(crypto_morus1280_sse2_ad) - FRAME_BEGIN - - cmp $32, %rdx - jb .Lad_out - - /* load the state: */ - movdqu (0 * 16)(%rdi), STATE0_LO - movdqu (1 * 16)(%rdi), STATE0_HI - movdqu (2 * 16)(%rdi), STATE1_LO - movdqu (3 * 16)(%rdi), STATE1_HI - movdqu (4 * 16)(%rdi), STATE2_LO - movdqu (5 * 16)(%rdi), STATE2_HI - movdqu (6 * 16)(%rdi), STATE3_LO - movdqu (7 * 16)(%rdi), STATE3_HI - movdqu (8 * 16)(%rdi), STATE4_LO - movdqu (9 * 16)(%rdi), STATE4_HI - - mov %rsi, %r8 - and $0xF, %r8 - jnz .Lad_u_loop - -.align 4 -.Lad_a_loop: - movdqa 0(%rsi), MSG_LO - movdqa 16(%rsi), MSG_HI - call __morus1280_update - sub $32, %rdx - add $32, %rsi - cmp $32, %rdx - jge .Lad_a_loop - - jmp .Lad_cont -.align 4 -.Lad_u_loop: - movdqu 0(%rsi), MSG_LO - movdqu 16(%rsi), MSG_HI - call __morus1280_update - sub $32, %rdx - add $32, %rsi - cmp $32, %rdx - jge .Lad_u_loop - -.Lad_cont: - /* store the state: */ - movdqu STATE0_LO, (0 * 16)(%rdi) - movdqu STATE0_HI, (1 * 16)(%rdi) - movdqu STATE1_LO, (2 * 16)(%rdi) - movdqu STATE1_HI, (3 * 16)(%rdi) - movdqu STATE2_LO, (4 * 16)(%rdi) - movdqu STATE2_HI, (5 * 16)(%rdi) - movdqu STATE3_LO, (6 * 16)(%rdi) - movdqu STATE3_HI, (7 * 16)(%rdi) - movdqu STATE4_LO, (8 * 16)(%rdi) - movdqu STATE4_HI, (9 * 16)(%rdi) - -.Lad_out: - FRAME_END - ret -ENDPROC(crypto_morus1280_sse2_ad) - -/* - * void crypto_morus1280_sse2_enc(void *state, const void *src, void *dst, - * unsigned int length); - */ -ENTRY(crypto_morus1280_sse2_enc) - FRAME_BEGIN - - cmp $32, %rcx - jb .Lenc_out - - /* load the state: */ - movdqu (0 * 16)(%rdi), STATE0_LO - movdqu (1 * 16)(%rdi), STATE0_HI - movdqu (2 * 16)(%rdi), STATE1_LO - movdqu (3 * 16)(%rdi), STATE1_HI - movdqu (4 * 16)(%rdi), STATE2_LO - movdqu (5 * 16)(%rdi), STATE2_HI - movdqu (6 * 16)(%rdi), STATE3_LO - movdqu (7 * 16)(%rdi), STATE3_HI - movdqu (8 * 16)(%rdi), STATE4_LO - movdqu (9 * 16)(%rdi), STATE4_HI - - mov %rsi, %r8 - or %rdx, %r8 - and $0xF, %r8 - jnz .Lenc_u_loop - -.align 4 -.Lenc_a_loop: - movdqa 0(%rsi), MSG_LO - movdqa 16(%rsi), MSG_HI - movdqa STATE1_LO, T1_LO - movdqa STATE1_HI, T1_HI - rol3 T1_HI, T1_LO - movdqa MSG_LO, T0_LO - movdqa MSG_HI, T0_HI - pxor T1_LO, T0_LO - pxor T1_HI, T0_HI - pxor STATE0_LO, T0_LO - pxor STATE0_HI, T0_HI - movdqa STATE2_LO, T1_LO - movdqa STATE2_HI, T1_HI - pand STATE3_LO, T1_LO - pand STATE3_HI, T1_HI - pxor T1_LO, T0_LO - pxor T1_HI, T0_HI - movdqa T0_LO, 0(%rdx) - movdqa T0_HI, 16(%rdx) - - call __morus1280_update - sub $32, %rcx - add $32, %rsi - add $32, %rdx - cmp $32, %rcx - jge .Lenc_a_loop - - jmp .Lenc_cont -.align 4 -.Lenc_u_loop: - movdqu 0(%rsi), MSG_LO - movdqu 16(%rsi), MSG_HI - movdqa STATE1_LO, T1_LO - movdqa STATE1_HI, T1_HI - rol3 T1_HI, T1_LO - movdqa MSG_LO, T0_LO - movdqa MSG_HI, T0_HI - pxor T1_LO, T0_LO - pxor T1_HI, T0_HI - pxor STATE0_LO, T0_LO - pxor STATE0_HI, T0_HI - movdqa STATE2_LO, T1_LO - movdqa STATE2_HI, T1_HI - pand STATE3_LO, T1_LO - pand STATE3_HI, T1_HI - pxor T1_LO, T0_LO - pxor T1_HI, T0_HI - movdqu T0_LO, 0(%rdx) - movdqu T0_HI, 16(%rdx) - - call __morus1280_update - sub $32, %rcx - add $32, %rsi - add $32, %rdx - cmp $32, %rcx - jge .Lenc_u_loop - -.Lenc_cont: - /* store the state: */ - movdqu STATE0_LO, (0 * 16)(%rdi) - movdqu STATE0_HI, (1 * 16)(%rdi) - movdqu STATE1_LO, (2 * 16)(%rdi) - movdqu STATE1_HI, (3 * 16)(%rdi) - movdqu STATE2_LO, (4 * 16)(%rdi) - movdqu STATE2_HI, (5 * 16)(%rdi) - movdqu STATE3_LO, (6 * 16)(%rdi) - movdqu STATE3_HI, (7 * 16)(%rdi) - movdqu STATE4_LO, (8 * 16)(%rdi) - movdqu STATE4_HI, (9 * 16)(%rdi) - -.Lenc_out: - FRAME_END - ret -ENDPROC(crypto_morus1280_sse2_enc) - -/* - * void crypto_morus1280_sse2_enc_tail(void *state, const void *src, void *dst, - * unsigned int length); - */ -ENTRY(crypto_morus1280_sse2_enc_tail) - FRAME_BEGIN - - /* load the state: */ - movdqu (0 * 16)(%rdi), STATE0_LO - movdqu (1 * 16)(%rdi), STATE0_HI - movdqu (2 * 16)(%rdi), STATE1_LO - movdqu (3 * 16)(%rdi), STATE1_HI - movdqu (4 * 16)(%rdi), STATE2_LO - movdqu (5 * 16)(%rdi), STATE2_HI - movdqu (6 * 16)(%rdi), STATE3_LO - movdqu (7 * 16)(%rdi), STATE3_HI - movdqu (8 * 16)(%rdi), STATE4_LO - movdqu (9 * 16)(%rdi), STATE4_HI - - /* encrypt message: */ - call __load_partial - - movdqa STATE1_LO, T1_LO - movdqa STATE1_HI, T1_HI - rol3 T1_HI, T1_LO - movdqa MSG_LO, T0_LO - movdqa MSG_HI, T0_HI - pxor T1_LO, T0_LO - pxor T1_HI, T0_HI - pxor STATE0_LO, T0_LO - pxor STATE0_HI, T0_HI - movdqa STATE2_LO, T1_LO - movdqa STATE2_HI, T1_HI - pand STATE3_LO, T1_LO - pand STATE3_HI, T1_HI - pxor T1_LO, T0_LO - pxor T1_HI, T0_HI - - call __store_partial - - call __morus1280_update - - /* store the state: */ - movdqu STATE0_LO, (0 * 16)(%rdi) - movdqu STATE0_HI, (1 * 16)(%rdi) - movdqu STATE1_LO, (2 * 16)(%rdi) - movdqu STATE1_HI, (3 * 16)(%rdi) - movdqu STATE2_LO, (4 * 16)(%rdi) - movdqu STATE2_HI, (5 * 16)(%rdi) - movdqu STATE3_LO, (6 * 16)(%rdi) - movdqu STATE3_HI, (7 * 16)(%rdi) - movdqu STATE4_LO, (8 * 16)(%rdi) - movdqu STATE4_HI, (9 * 16)(%rdi) - - FRAME_END - ret -ENDPROC(crypto_morus1280_sse2_enc_tail) - -/* - * void crypto_morus1280_sse2_dec(void *state, const void *src, void *dst, - * unsigned int length); - */ -ENTRY(crypto_morus1280_sse2_dec) - FRAME_BEGIN - - cmp $32, %rcx - jb .Ldec_out - - /* load the state: */ - movdqu (0 * 16)(%rdi), STATE0_LO - movdqu (1 * 16)(%rdi), STATE0_HI - movdqu (2 * 16)(%rdi), STATE1_LO - movdqu (3 * 16)(%rdi), STATE1_HI - movdqu (4 * 16)(%rdi), STATE2_LO - movdqu (5 * 16)(%rdi), STATE2_HI - movdqu (6 * 16)(%rdi), STATE3_LO - movdqu (7 * 16)(%rdi), STATE3_HI - movdqu (8 * 16)(%rdi), STATE4_LO - movdqu (9 * 16)(%rdi), STATE4_HI - - mov %rsi, %r8 - or %rdx, %r8 - and $0xF, %r8 - jnz .Ldec_u_loop - -.align 4 -.Ldec_a_loop: - movdqa 0(%rsi), MSG_LO - movdqa 16(%rsi), MSG_HI - pxor STATE0_LO, MSG_LO - pxor STATE0_HI, MSG_HI - movdqa STATE1_LO, T1_LO - movdqa STATE1_HI, T1_HI - rol3 T1_HI, T1_LO - pxor T1_LO, MSG_LO - pxor T1_HI, MSG_HI - movdqa STATE2_LO, T1_LO - movdqa STATE2_HI, T1_HI - pand STATE3_LO, T1_LO - pand STATE3_HI, T1_HI - pxor T1_LO, MSG_LO - pxor T1_HI, MSG_HI - movdqa MSG_LO, 0(%rdx) - movdqa MSG_HI, 16(%rdx) - - call __morus1280_update - sub $32, %rcx - add $32, %rsi - add $32, %rdx - cmp $32, %rcx - jge .Ldec_a_loop - - jmp .Ldec_cont -.align 4 -.Ldec_u_loop: - movdqu 0(%rsi), MSG_LO - movdqu 16(%rsi), MSG_HI - pxor STATE0_LO, MSG_LO - pxor STATE0_HI, MSG_HI - movdqa STATE1_LO, T1_LO - movdqa STATE1_HI, T1_HI - rol3 T1_HI, T1_LO - pxor T1_LO, MSG_LO - pxor T1_HI, MSG_HI - movdqa STATE2_LO, T1_LO - movdqa STATE2_HI, T1_HI - pand STATE3_LO, T1_LO - pand STATE3_HI, T1_HI - pxor T1_LO, MSG_LO - pxor T1_HI, MSG_HI - movdqu MSG_LO, 0(%rdx) - movdqu MSG_HI, 16(%rdx) - - call __morus1280_update - sub $32, %rcx - add $32, %rsi - add $32, %rdx - cmp $32, %rcx - jge .Ldec_u_loop - -.Ldec_cont: - /* store the state: */ - movdqu STATE0_LO, (0 * 16)(%rdi) - movdqu STATE0_HI, (1 * 16)(%rdi) - movdqu STATE1_LO, (2 * 16)(%rdi) - movdqu STATE1_HI, (3 * 16)(%rdi) - movdqu STATE2_LO, (4 * 16)(%rdi) - movdqu STATE2_HI, (5 * 16)(%rdi) - movdqu STATE3_LO, (6 * 16)(%rdi) - movdqu STATE3_HI, (7 * 16)(%rdi) - movdqu STATE4_LO, (8 * 16)(%rdi) - movdqu STATE4_HI, (9 * 16)(%rdi) - -.Ldec_out: - FRAME_END - ret -ENDPROC(crypto_morus1280_sse2_dec) - -/* - * void crypto_morus1280_sse2_dec_tail(void *state, const void *src, void *dst, - * unsigned int length); - */ -ENTRY(crypto_morus1280_sse2_dec_tail) - FRAME_BEGIN - - /* load the state: */ - movdqu (0 * 16)(%rdi), STATE0_LO - movdqu (1 * 16)(%rdi), STATE0_HI - movdqu (2 * 16)(%rdi), STATE1_LO - movdqu (3 * 16)(%rdi), STATE1_HI - movdqu (4 * 16)(%rdi), STATE2_LO - movdqu (5 * 16)(%rdi), STATE2_HI - movdqu (6 * 16)(%rdi), STATE3_LO - movdqu (7 * 16)(%rdi), STATE3_HI - movdqu (8 * 16)(%rdi), STATE4_LO - movdqu (9 * 16)(%rdi), STATE4_HI - - /* decrypt message: */ - call __load_partial - - pxor STATE0_LO, MSG_LO - pxor STATE0_HI, MSG_HI - movdqa STATE1_LO, T1_LO - movdqa STATE1_HI, T1_HI - rol3 T1_HI, T1_LO - pxor T1_LO, MSG_LO - pxor T1_HI, MSG_HI - movdqa STATE2_LO, T1_LO - movdqa STATE2_HI, T1_HI - pand STATE3_LO, T1_LO - pand STATE3_HI, T1_HI - pxor T1_LO, MSG_LO - pxor T1_HI, MSG_HI - movdqa MSG_LO, T0_LO - movdqa MSG_HI, T0_HI - - call __store_partial - - /* mask with byte count: */ - movq %rcx, T0_LO - punpcklbw T0_LO, T0_LO - punpcklbw T0_LO, T0_LO - punpcklbw T0_LO, T0_LO - punpcklbw T0_LO, T0_LO - movdqa T0_LO, T0_HI - movdqa .Lmorus640_counter_0, T1_LO - movdqa .Lmorus640_counter_1, T1_HI - pcmpgtb T1_LO, T0_LO - pcmpgtb T1_HI, T0_HI - pand T0_LO, MSG_LO - pand T0_HI, MSG_HI - - call __morus1280_update - - /* store the state: */ - movdqu STATE0_LO, (0 * 16)(%rdi) - movdqu STATE0_HI, (1 * 16)(%rdi) - movdqu STATE1_LO, (2 * 16)(%rdi) - movdqu STATE1_HI, (3 * 16)(%rdi) - movdqu STATE2_LO, (4 * 16)(%rdi) - movdqu STATE2_HI, (5 * 16)(%rdi) - movdqu STATE3_LO, (6 * 16)(%rdi) - movdqu STATE3_HI, (7 * 16)(%rdi) - movdqu STATE4_LO, (8 * 16)(%rdi) - movdqu STATE4_HI, (9 * 16)(%rdi) - - FRAME_END - ret -ENDPROC(crypto_morus1280_sse2_dec_tail) - -/* - * void crypto_morus1280_sse2_final(void *state, void *tag_xor, - * u64 assoclen, u64 cryptlen); - */ -ENTRY(crypto_morus1280_sse2_final) - FRAME_BEGIN - - /* load the state: */ - movdqu (0 * 16)(%rdi), STATE0_LO - movdqu (1 * 16)(%rdi), STATE0_HI - movdqu (2 * 16)(%rdi), STATE1_LO - movdqu (3 * 16)(%rdi), STATE1_HI - movdqu (4 * 16)(%rdi), STATE2_LO - movdqu (5 * 16)(%rdi), STATE2_HI - movdqu (6 * 16)(%rdi), STATE3_LO - movdqu (7 * 16)(%rdi), STATE3_HI - movdqu (8 * 16)(%rdi), STATE4_LO - movdqu (9 * 16)(%rdi), STATE4_HI - - /* xor state[0] into state[4]: */ - pxor STATE0_LO, STATE4_LO - pxor STATE0_HI, STATE4_HI - - /* prepare length block: */ - movq %rdx, MSG_LO - movq %rcx, T0_LO - pslldq $8, T0_LO - pxor T0_LO, MSG_LO - psllq $3, MSG_LO /* multiply by 8 (to get bit count) */ - pxor MSG_HI, MSG_HI - - /* update state: */ - call __morus1280_update - call __morus1280_update - call __morus1280_update - call __morus1280_update - call __morus1280_update - call __morus1280_update - call __morus1280_update - call __morus1280_update - call __morus1280_update - call __morus1280_update - - /* xor tag: */ - movdqu 0(%rsi), MSG_LO - movdqu 16(%rsi), MSG_HI - - pxor STATE0_LO, MSG_LO - pxor STATE0_HI, MSG_HI - movdqa STATE1_LO, T0_LO - movdqa STATE1_HI, T0_HI - rol3 T0_HI, T0_LO - pxor T0_LO, MSG_LO - pxor T0_HI, MSG_HI - movdqa STATE2_LO, T0_LO - movdqa STATE2_HI, T0_HI - pand STATE3_LO, T0_LO - pand STATE3_HI, T0_HI - pxor T0_LO, MSG_LO - pxor T0_HI, MSG_HI - - movdqu MSG_LO, 0(%rsi) - movdqu MSG_HI, 16(%rsi) - - FRAME_END - ret -ENDPROC(crypto_morus1280_sse2_final) diff --git a/arch/x86/crypto/morus1280-sse2-glue.c b/arch/x86/crypto/morus1280-sse2-glue.c deleted file mode 100644 index aada9d7742938f7cf939896f9eb5fed0320d7dca..0000000000000000000000000000000000000000 --- a/arch/x86/crypto/morus1280-sse2-glue.c +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * The MORUS-1280 Authenticated-Encryption Algorithm - * Glue for SSE2 implementation - * - * Copyright (c) 2016-2018 Ondrej Mosnacek - * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include - -asmlinkage void crypto_morus1280_sse2_init(void *state, const void *key, - const void *iv); -asmlinkage void crypto_morus1280_sse2_ad(void *state, const void *data, - unsigned int length); - -asmlinkage void crypto_morus1280_sse2_enc(void *state, const void *src, - void *dst, unsigned int length); -asmlinkage void crypto_morus1280_sse2_dec(void *state, const void *src, - void *dst, unsigned int length); - -asmlinkage void crypto_morus1280_sse2_enc_tail(void *state, const void *src, - void *dst, unsigned int length); -asmlinkage void crypto_morus1280_sse2_dec_tail(void *state, const void *src, - void *dst, unsigned int length); - -asmlinkage void crypto_morus1280_sse2_final(void *state, void *tag_xor, - u64 assoclen, u64 cryptlen); - -MORUS1280_DECLARE_ALG(sse2, "morus1280-sse2", 350); - -static struct simd_aead_alg *simd_alg; - -static int __init crypto_morus1280_sse2_module_init(void) -{ - if (!boot_cpu_has(X86_FEATURE_XMM2) || - !cpu_has_xfeatures(XFEATURE_MASK_SSE, NULL)) - return -ENODEV; - - return simd_register_aeads_compat(&crypto_morus1280_sse2_alg, 1, - &simd_alg); -} - -static void __exit crypto_morus1280_sse2_module_exit(void) -{ - simd_unregister_aeads(&crypto_morus1280_sse2_alg, 1, &simd_alg); -} - -module_init(crypto_morus1280_sse2_module_init); -module_exit(crypto_morus1280_sse2_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ondrej Mosnacek "); -MODULE_DESCRIPTION("MORUS-1280 AEAD algorithm -- SSE2 implementation"); -MODULE_ALIAS_CRYPTO("morus1280"); -MODULE_ALIAS_CRYPTO("morus1280-sse2"); diff --git a/arch/x86/crypto/morus1280_glue.c b/arch/x86/crypto/morus1280_glue.c deleted file mode 100644 index ffbde8b22838afbefa40890203f80b66ac623ef5..0000000000000000000000000000000000000000 --- a/arch/x86/crypto/morus1280_glue.c +++ /dev/null @@ -1,205 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * The MORUS-1280 Authenticated-Encryption Algorithm - * Common x86 SIMD glue skeleton - * - * Copyright (c) 2016-2018 Ondrej Mosnacek - * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct morus1280_state { - struct morus1280_block s[MORUS_STATE_BLOCKS]; -}; - -struct morus1280_ops { - int (*skcipher_walk_init)(struct skcipher_walk *walk, - struct aead_request *req, bool atomic); - - void (*crypt_blocks)(void *state, const void *src, void *dst, - unsigned int length); - void (*crypt_tail)(void *state, const void *src, void *dst, - unsigned int length); -}; - -static void crypto_morus1280_glue_process_ad( - struct morus1280_state *state, - const struct morus1280_glue_ops *ops, - struct scatterlist *sg_src, unsigned int assoclen) -{ - struct scatter_walk walk; - struct morus1280_block buf; - unsigned int pos = 0; - - scatterwalk_start(&walk, sg_src); - while (assoclen != 0) { - unsigned int size = scatterwalk_clamp(&walk, assoclen); - unsigned int left = size; - void *mapped = scatterwalk_map(&walk); - const u8 *src = (const u8 *)mapped; - - if (pos + size >= MORUS1280_BLOCK_SIZE) { - if (pos > 0) { - unsigned int fill = MORUS1280_BLOCK_SIZE - pos; - memcpy(buf.bytes + pos, src, fill); - ops->ad(state, buf.bytes, MORUS1280_BLOCK_SIZE); - pos = 0; - left -= fill; - src += fill; - } - - ops->ad(state, src, left); - src += left & ~(MORUS1280_BLOCK_SIZE - 1); - left &= MORUS1280_BLOCK_SIZE - 1; - } - - memcpy(buf.bytes + pos, src, left); - - pos += left; - assoclen -= size; - scatterwalk_unmap(mapped); - scatterwalk_advance(&walk, size); - scatterwalk_done(&walk, 0, assoclen); - } - - if (pos > 0) { - memset(buf.bytes + pos, 0, MORUS1280_BLOCK_SIZE - pos); - ops->ad(state, buf.bytes, MORUS1280_BLOCK_SIZE); - } -} - -static void crypto_morus1280_glue_process_crypt(struct morus1280_state *state, - struct morus1280_ops ops, - struct skcipher_walk *walk) -{ - while (walk->nbytes >= MORUS1280_BLOCK_SIZE) { - ops.crypt_blocks(state, walk->src.virt.addr, - walk->dst.virt.addr, - round_down(walk->nbytes, - MORUS1280_BLOCK_SIZE)); - skcipher_walk_done(walk, walk->nbytes % MORUS1280_BLOCK_SIZE); - } - - if (walk->nbytes) { - ops.crypt_tail(state, walk->src.virt.addr, walk->dst.virt.addr, - walk->nbytes); - skcipher_walk_done(walk, 0); - } -} - -int crypto_morus1280_glue_setkey(struct crypto_aead *aead, const u8 *key, - unsigned int keylen) -{ - struct morus1280_ctx *ctx = crypto_aead_ctx(aead); - - if (keylen == MORUS1280_BLOCK_SIZE) { - memcpy(ctx->key.bytes, key, MORUS1280_BLOCK_SIZE); - } else if (keylen == MORUS1280_BLOCK_SIZE / 2) { - memcpy(ctx->key.bytes, key, keylen); - memcpy(ctx->key.bytes + keylen, key, keylen); - } else { - crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL_GPL(crypto_morus1280_glue_setkey); - -int crypto_morus1280_glue_setauthsize(struct crypto_aead *tfm, - unsigned int authsize) -{ - return (authsize <= MORUS_MAX_AUTH_SIZE) ? 0 : -EINVAL; -} -EXPORT_SYMBOL_GPL(crypto_morus1280_glue_setauthsize); - -static void crypto_morus1280_glue_crypt(struct aead_request *req, - struct morus1280_ops ops, - unsigned int cryptlen, - struct morus1280_block *tag_xor) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct morus1280_ctx *ctx = crypto_aead_ctx(tfm); - struct morus1280_state state; - struct skcipher_walk walk; - - ops.skcipher_walk_init(&walk, req, true); - - kernel_fpu_begin(); - - ctx->ops->init(&state, &ctx->key, req->iv); - crypto_morus1280_glue_process_ad(&state, ctx->ops, req->src, req->assoclen); - crypto_morus1280_glue_process_crypt(&state, ops, &walk); - ctx->ops->final(&state, tag_xor, req->assoclen, cryptlen); - - kernel_fpu_end(); -} - -int crypto_morus1280_glue_encrypt(struct aead_request *req) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct morus1280_ctx *ctx = crypto_aead_ctx(tfm); - struct morus1280_ops OPS = { - .skcipher_walk_init = skcipher_walk_aead_encrypt, - .crypt_blocks = ctx->ops->enc, - .crypt_tail = ctx->ops->enc_tail, - }; - - struct morus1280_block tag = {}; - unsigned int authsize = crypto_aead_authsize(tfm); - unsigned int cryptlen = req->cryptlen; - - crypto_morus1280_glue_crypt(req, OPS, cryptlen, &tag); - - scatterwalk_map_and_copy(tag.bytes, req->dst, - req->assoclen + cryptlen, authsize, 1); - return 0; -} -EXPORT_SYMBOL_GPL(crypto_morus1280_glue_encrypt); - -int crypto_morus1280_glue_decrypt(struct aead_request *req) -{ - static const u8 zeros[MORUS1280_BLOCK_SIZE] = {}; - - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct morus1280_ctx *ctx = crypto_aead_ctx(tfm); - struct morus1280_ops OPS = { - .skcipher_walk_init = skcipher_walk_aead_decrypt, - .crypt_blocks = ctx->ops->dec, - .crypt_tail = ctx->ops->dec_tail, - }; - - struct morus1280_block tag; - unsigned int authsize = crypto_aead_authsize(tfm); - unsigned int cryptlen = req->cryptlen - authsize; - - scatterwalk_map_and_copy(tag.bytes, req->src, - req->assoclen + cryptlen, authsize, 0); - - crypto_morus1280_glue_crypt(req, OPS, cryptlen, &tag); - - return crypto_memneq(tag.bytes, zeros, authsize) ? -EBADMSG : 0; -} -EXPORT_SYMBOL_GPL(crypto_morus1280_glue_decrypt); - -void crypto_morus1280_glue_init_ops(struct crypto_aead *aead, - const struct morus1280_glue_ops *ops) -{ - struct morus1280_ctx *ctx = crypto_aead_ctx(aead); - ctx->ops = ops; -} -EXPORT_SYMBOL_GPL(crypto_morus1280_glue_init_ops); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ondrej Mosnacek "); -MODULE_DESCRIPTION("MORUS-1280 AEAD mode -- glue for x86 optimizations"); diff --git a/arch/x86/crypto/morus640-sse2-asm.S b/arch/x86/crypto/morus640-sse2-asm.S deleted file mode 100644 index a60891101bbd41450d9f090230eaa96be1975b59..0000000000000000000000000000000000000000 --- a/arch/x86/crypto/morus640-sse2-asm.S +++ /dev/null @@ -1,612 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * SSE2 implementation of MORUS-640 - * - * Copyright (c) 2017-2018 Ondrej Mosnacek - * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. - */ - -#include -#include - -#define SHUFFLE_MASK(i0, i1, i2, i3) \ - (i0 | (i1 << 2) | (i2 << 4) | (i3 << 6)) - -#define MASK1 SHUFFLE_MASK(3, 0, 1, 2) -#define MASK2 SHUFFLE_MASK(2, 3, 0, 1) -#define MASK3 SHUFFLE_MASK(1, 2, 3, 0) - -#define STATE0 %xmm0 -#define STATE1 %xmm1 -#define STATE2 %xmm2 -#define STATE3 %xmm3 -#define STATE4 %xmm4 -#define KEY %xmm5 -#define MSG %xmm5 -#define T0 %xmm6 -#define T1 %xmm7 - -.section .rodata.cst16.morus640_const, "aM", @progbits, 32 -.align 16 -.Lmorus640_const_0: - .byte 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d - .byte 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 -.Lmorus640_const_1: - .byte 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1 - .byte 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd - -.section .rodata.cst16.morus640_counter, "aM", @progbits, 16 -.align 16 -.Lmorus640_counter: - .byte 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 - .byte 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - -.text - -.macro morus640_round s0, s1, s2, s3, s4, b, w - movdqa \s1, T0 - pand \s2, T0 - pxor T0, \s0 - pxor \s3, \s0 - movdqa \s0, T0 - pslld $\b, T0 - psrld $(32 - \b), \s0 - pxor T0, \s0 - pshufd $\w, \s3, \s3 -.endm - -/* - * __morus640_update: internal ABI - * input: - * STATE[0-4] - input state - * MSG - message block - * output: - * STATE[0-4] - output state - * changed: - * T0 - */ -__morus640_update: - morus640_round STATE0, STATE1, STATE2, STATE3, STATE4, 5, MASK1 - pxor MSG, STATE1 - morus640_round STATE1, STATE2, STATE3, STATE4, STATE0, 31, MASK2 - pxor MSG, STATE2 - morus640_round STATE2, STATE3, STATE4, STATE0, STATE1, 7, MASK3 - pxor MSG, STATE3 - morus640_round STATE3, STATE4, STATE0, STATE1, STATE2, 22, MASK2 - pxor MSG, STATE4 - morus640_round STATE4, STATE0, STATE1, STATE2, STATE3, 13, MASK1 - ret -ENDPROC(__morus640_update) - - -/* - * __morus640_update_zero: internal ABI - * input: - * STATE[0-4] - input state - * output: - * STATE[0-4] - output state - * changed: - * T0 - */ -__morus640_update_zero: - morus640_round STATE0, STATE1, STATE2, STATE3, STATE4, 5, MASK1 - morus640_round STATE1, STATE2, STATE3, STATE4, STATE0, 31, MASK2 - morus640_round STATE2, STATE3, STATE4, STATE0, STATE1, 7, MASK3 - morus640_round STATE3, STATE4, STATE0, STATE1, STATE2, 22, MASK2 - morus640_round STATE4, STATE0, STATE1, STATE2, STATE3, 13, MASK1 - ret -ENDPROC(__morus640_update_zero) - -/* - * __load_partial: internal ABI - * input: - * %rsi - src - * %rcx - bytes - * output: - * MSG - message block - * changed: - * T0 - * %r8 - * %r9 - */ -__load_partial: - xor %r9d, %r9d - pxor MSG, MSG - - mov %rcx, %r8 - and $0x1, %r8 - jz .Lld_partial_1 - - mov %rcx, %r8 - and $0x1E, %r8 - add %rsi, %r8 - mov (%r8), %r9b - -.Lld_partial_1: - mov %rcx, %r8 - and $0x2, %r8 - jz .Lld_partial_2 - - mov %rcx, %r8 - and $0x1C, %r8 - add %rsi, %r8 - shl $16, %r9 - mov (%r8), %r9w - -.Lld_partial_2: - mov %rcx, %r8 - and $0x4, %r8 - jz .Lld_partial_4 - - mov %rcx, %r8 - and $0x18, %r8 - add %rsi, %r8 - shl $32, %r9 - mov (%r8), %r8d - xor %r8, %r9 - -.Lld_partial_4: - movq %r9, MSG - - mov %rcx, %r8 - and $0x8, %r8 - jz .Lld_partial_8 - - mov %rcx, %r8 - and $0x10, %r8 - add %rsi, %r8 - pslldq $8, MSG - movq (%r8), T0 - pxor T0, MSG - -.Lld_partial_8: - ret -ENDPROC(__load_partial) - -/* - * __store_partial: internal ABI - * input: - * %rdx - dst - * %rcx - bytes - * output: - * T0 - message block - * changed: - * %r8 - * %r9 - * %r10 - */ -__store_partial: - mov %rcx, %r8 - mov %rdx, %r9 - - movq T0, %r10 - - cmp $8, %r8 - jl .Lst_partial_8 - - mov %r10, (%r9) - psrldq $8, T0 - movq T0, %r10 - - sub $8, %r8 - add $8, %r9 - -.Lst_partial_8: - cmp $4, %r8 - jl .Lst_partial_4 - - mov %r10d, (%r9) - shr $32, %r10 - - sub $4, %r8 - add $4, %r9 - -.Lst_partial_4: - cmp $2, %r8 - jl .Lst_partial_2 - - mov %r10w, (%r9) - shr $16, %r10 - - sub $2, %r8 - add $2, %r9 - -.Lst_partial_2: - cmp $1, %r8 - jl .Lst_partial_1 - - mov %r10b, (%r9) - -.Lst_partial_1: - ret -ENDPROC(__store_partial) - -/* - * void crypto_morus640_sse2_init(void *state, const void *key, const void *iv); - */ -ENTRY(crypto_morus640_sse2_init) - FRAME_BEGIN - - /* load IV: */ - movdqu (%rdx), STATE0 - /* load key: */ - movdqu (%rsi), KEY - movdqa KEY, STATE1 - /* load all ones: */ - pcmpeqd STATE2, STATE2 - /* load the constants: */ - movdqa .Lmorus640_const_0, STATE3 - movdqa .Lmorus640_const_1, STATE4 - - /* update 16 times with zero: */ - call __morus640_update_zero - call __morus640_update_zero - call __morus640_update_zero - call __morus640_update_zero - call __morus640_update_zero - call __morus640_update_zero - call __morus640_update_zero - call __morus640_update_zero - call __morus640_update_zero - call __morus640_update_zero - call __morus640_update_zero - call __morus640_update_zero - call __morus640_update_zero - call __morus640_update_zero - call __morus640_update_zero - call __morus640_update_zero - - /* xor-in the key again after updates: */ - pxor KEY, STATE1 - - /* store the state: */ - movdqu STATE0, (0 * 16)(%rdi) - movdqu STATE1, (1 * 16)(%rdi) - movdqu STATE2, (2 * 16)(%rdi) - movdqu STATE3, (3 * 16)(%rdi) - movdqu STATE4, (4 * 16)(%rdi) - - FRAME_END - ret -ENDPROC(crypto_morus640_sse2_init) - -/* - * void crypto_morus640_sse2_ad(void *state, const void *data, - * unsigned int length); - */ -ENTRY(crypto_morus640_sse2_ad) - FRAME_BEGIN - - cmp $16, %rdx - jb .Lad_out - - /* load the state: */ - movdqu (0 * 16)(%rdi), STATE0 - movdqu (1 * 16)(%rdi), STATE1 - movdqu (2 * 16)(%rdi), STATE2 - movdqu (3 * 16)(%rdi), STATE3 - movdqu (4 * 16)(%rdi), STATE4 - - mov %rsi, %r8 - and $0xF, %r8 - jnz .Lad_u_loop - -.align 4 -.Lad_a_loop: - movdqa (%rsi), MSG - call __morus640_update - sub $16, %rdx - add $16, %rsi - cmp $16, %rdx - jge .Lad_a_loop - - jmp .Lad_cont -.align 4 -.Lad_u_loop: - movdqu (%rsi), MSG - call __morus640_update - sub $16, %rdx - add $16, %rsi - cmp $16, %rdx - jge .Lad_u_loop - -.Lad_cont: - /* store the state: */ - movdqu STATE0, (0 * 16)(%rdi) - movdqu STATE1, (1 * 16)(%rdi) - movdqu STATE2, (2 * 16)(%rdi) - movdqu STATE3, (3 * 16)(%rdi) - movdqu STATE4, (4 * 16)(%rdi) - -.Lad_out: - FRAME_END - ret -ENDPROC(crypto_morus640_sse2_ad) - -/* - * void crypto_morus640_sse2_enc(void *state, const void *src, void *dst, - * unsigned int length); - */ -ENTRY(crypto_morus640_sse2_enc) - FRAME_BEGIN - - cmp $16, %rcx - jb .Lenc_out - - /* load the state: */ - movdqu (0 * 16)(%rdi), STATE0 - movdqu (1 * 16)(%rdi), STATE1 - movdqu (2 * 16)(%rdi), STATE2 - movdqu (3 * 16)(%rdi), STATE3 - movdqu (4 * 16)(%rdi), STATE4 - - mov %rsi, %r8 - or %rdx, %r8 - and $0xF, %r8 - jnz .Lenc_u_loop - -.align 4 -.Lenc_a_loop: - movdqa (%rsi), MSG - movdqa MSG, T0 - pxor STATE0, T0 - pshufd $MASK3, STATE1, T1 - pxor T1, T0 - movdqa STATE2, T1 - pand STATE3, T1 - pxor T1, T0 - movdqa T0, (%rdx) - - call __morus640_update - sub $16, %rcx - add $16, %rsi - add $16, %rdx - cmp $16, %rcx - jge .Lenc_a_loop - - jmp .Lenc_cont -.align 4 -.Lenc_u_loop: - movdqu (%rsi), MSG - movdqa MSG, T0 - pxor STATE0, T0 - pshufd $MASK3, STATE1, T1 - pxor T1, T0 - movdqa STATE2, T1 - pand STATE3, T1 - pxor T1, T0 - movdqu T0, (%rdx) - - call __morus640_update - sub $16, %rcx - add $16, %rsi - add $16, %rdx - cmp $16, %rcx - jge .Lenc_u_loop - -.Lenc_cont: - /* store the state: */ - movdqu STATE0, (0 * 16)(%rdi) - movdqu STATE1, (1 * 16)(%rdi) - movdqu STATE2, (2 * 16)(%rdi) - movdqu STATE3, (3 * 16)(%rdi) - movdqu STATE4, (4 * 16)(%rdi) - -.Lenc_out: - FRAME_END - ret -ENDPROC(crypto_morus640_sse2_enc) - -/* - * void crypto_morus640_sse2_enc_tail(void *state, const void *src, void *dst, - * unsigned int length); - */ -ENTRY(crypto_morus640_sse2_enc_tail) - FRAME_BEGIN - - /* load the state: */ - movdqu (0 * 16)(%rdi), STATE0 - movdqu (1 * 16)(%rdi), STATE1 - movdqu (2 * 16)(%rdi), STATE2 - movdqu (3 * 16)(%rdi), STATE3 - movdqu (4 * 16)(%rdi), STATE4 - - /* encrypt message: */ - call __load_partial - - movdqa MSG, T0 - pxor STATE0, T0 - pshufd $MASK3, STATE1, T1 - pxor T1, T0 - movdqa STATE2, T1 - pand STATE3, T1 - pxor T1, T0 - - call __store_partial - - call __morus640_update - - /* store the state: */ - movdqu STATE0, (0 * 16)(%rdi) - movdqu STATE1, (1 * 16)(%rdi) - movdqu STATE2, (2 * 16)(%rdi) - movdqu STATE3, (3 * 16)(%rdi) - movdqu STATE4, (4 * 16)(%rdi) - - FRAME_END - ret -ENDPROC(crypto_morus640_sse2_enc_tail) - -/* - * void crypto_morus640_sse2_dec(void *state, const void *src, void *dst, - * unsigned int length); - */ -ENTRY(crypto_morus640_sse2_dec) - FRAME_BEGIN - - cmp $16, %rcx - jb .Ldec_out - - /* load the state: */ - movdqu (0 * 16)(%rdi), STATE0 - movdqu (1 * 16)(%rdi), STATE1 - movdqu (2 * 16)(%rdi), STATE2 - movdqu (3 * 16)(%rdi), STATE3 - movdqu (4 * 16)(%rdi), STATE4 - - mov %rsi, %r8 - or %rdx, %r8 - and $0xF, %r8 - jnz .Ldec_u_loop - -.align 4 -.Ldec_a_loop: - movdqa (%rsi), MSG - pxor STATE0, MSG - pshufd $MASK3, STATE1, T0 - pxor T0, MSG - movdqa STATE2, T0 - pand STATE3, T0 - pxor T0, MSG - movdqa MSG, (%rdx) - - call __morus640_update - sub $16, %rcx - add $16, %rsi - add $16, %rdx - cmp $16, %rcx - jge .Ldec_a_loop - - jmp .Ldec_cont -.align 4 -.Ldec_u_loop: - movdqu (%rsi), MSG - pxor STATE0, MSG - pshufd $MASK3, STATE1, T0 - pxor T0, MSG - movdqa STATE2, T0 - pand STATE3, T0 - pxor T0, MSG - movdqu MSG, (%rdx) - - call __morus640_update - sub $16, %rcx - add $16, %rsi - add $16, %rdx - cmp $16, %rcx - jge .Ldec_u_loop - -.Ldec_cont: - /* store the state: */ - movdqu STATE0, (0 * 16)(%rdi) - movdqu STATE1, (1 * 16)(%rdi) - movdqu STATE2, (2 * 16)(%rdi) - movdqu STATE3, (3 * 16)(%rdi) - movdqu STATE4, (4 * 16)(%rdi) - -.Ldec_out: - FRAME_END - ret -ENDPROC(crypto_morus640_sse2_dec) - -/* - * void crypto_morus640_sse2_dec_tail(void *state, const void *src, void *dst, - * unsigned int length); - */ -ENTRY(crypto_morus640_sse2_dec_tail) - FRAME_BEGIN - - /* load the state: */ - movdqu (0 * 16)(%rdi), STATE0 - movdqu (1 * 16)(%rdi), STATE1 - movdqu (2 * 16)(%rdi), STATE2 - movdqu (3 * 16)(%rdi), STATE3 - movdqu (4 * 16)(%rdi), STATE4 - - /* decrypt message: */ - call __load_partial - - pxor STATE0, MSG - pshufd $MASK3, STATE1, T0 - pxor T0, MSG - movdqa STATE2, T0 - pand STATE3, T0 - pxor T0, MSG - movdqa MSG, T0 - - call __store_partial - - /* mask with byte count: */ - movq %rcx, T0 - punpcklbw T0, T0 - punpcklbw T0, T0 - punpcklbw T0, T0 - punpcklbw T0, T0 - movdqa .Lmorus640_counter, T1 - pcmpgtb T1, T0 - pand T0, MSG - - call __morus640_update - - /* store the state: */ - movdqu STATE0, (0 * 16)(%rdi) - movdqu STATE1, (1 * 16)(%rdi) - movdqu STATE2, (2 * 16)(%rdi) - movdqu STATE3, (3 * 16)(%rdi) - movdqu STATE4, (4 * 16)(%rdi) - - FRAME_END - ret -ENDPROC(crypto_morus640_sse2_dec_tail) - -/* - * void crypto_morus640_sse2_final(void *state, void *tag_xor, - * u64 assoclen, u64 cryptlen); - */ -ENTRY(crypto_morus640_sse2_final) - FRAME_BEGIN - - /* load the state: */ - movdqu (0 * 16)(%rdi), STATE0 - movdqu (1 * 16)(%rdi), STATE1 - movdqu (2 * 16)(%rdi), STATE2 - movdqu (3 * 16)(%rdi), STATE3 - movdqu (4 * 16)(%rdi), STATE4 - - /* xor state[0] into state[4]: */ - pxor STATE0, STATE4 - - /* prepare length block: */ - movq %rdx, MSG - movq %rcx, T0 - pslldq $8, T0 - pxor T0, MSG - psllq $3, MSG /* multiply by 8 (to get bit count) */ - - /* update state: */ - call __morus640_update - call __morus640_update - call __morus640_update - call __morus640_update - call __morus640_update - call __morus640_update - call __morus640_update - call __morus640_update - call __morus640_update - call __morus640_update - - /* xor tag: */ - movdqu (%rsi), MSG - - pxor STATE0, MSG - pshufd $MASK3, STATE1, T0 - pxor T0, MSG - movdqa STATE2, T0 - pand STATE3, T0 - pxor T0, MSG - - movdqu MSG, (%rsi) - - FRAME_END - ret -ENDPROC(crypto_morus640_sse2_final) diff --git a/arch/x86/crypto/morus640-sse2-glue.c b/arch/x86/crypto/morus640-sse2-glue.c deleted file mode 100644 index 8ef68134aef41222c5f3ca71dfdb8937915a352f..0000000000000000000000000000000000000000 --- a/arch/x86/crypto/morus640-sse2-glue.c +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * The MORUS-640 Authenticated-Encryption Algorithm - * Glue for SSE2 implementation - * - * Copyright (c) 2016-2018 Ondrej Mosnacek - * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include - -asmlinkage void crypto_morus640_sse2_init(void *state, const void *key, - const void *iv); -asmlinkage void crypto_morus640_sse2_ad(void *state, const void *data, - unsigned int length); - -asmlinkage void crypto_morus640_sse2_enc(void *state, const void *src, - void *dst, unsigned int length); -asmlinkage void crypto_morus640_sse2_dec(void *state, const void *src, - void *dst, unsigned int length); - -asmlinkage void crypto_morus640_sse2_enc_tail(void *state, const void *src, - void *dst, unsigned int length); -asmlinkage void crypto_morus640_sse2_dec_tail(void *state, const void *src, - void *dst, unsigned int length); - -asmlinkage void crypto_morus640_sse2_final(void *state, void *tag_xor, - u64 assoclen, u64 cryptlen); - -MORUS640_DECLARE_ALG(sse2, "morus640-sse2", 400); - -static struct simd_aead_alg *simd_alg; - -static int __init crypto_morus640_sse2_module_init(void) -{ - if (!boot_cpu_has(X86_FEATURE_XMM2) || - !cpu_has_xfeatures(XFEATURE_MASK_SSE, NULL)) - return -ENODEV; - - return simd_register_aeads_compat(&crypto_morus640_sse2_alg, 1, - &simd_alg); -} - -static void __exit crypto_morus640_sse2_module_exit(void) -{ - simd_unregister_aeads(&crypto_morus640_sse2_alg, 1, &simd_alg); -} - -module_init(crypto_morus640_sse2_module_init); -module_exit(crypto_morus640_sse2_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ondrej Mosnacek "); -MODULE_DESCRIPTION("MORUS-640 AEAD algorithm -- SSE2 implementation"); -MODULE_ALIAS_CRYPTO("morus640"); -MODULE_ALIAS_CRYPTO("morus640-sse2"); diff --git a/arch/x86/crypto/morus640_glue.c b/arch/x86/crypto/morus640_glue.c deleted file mode 100644 index d8b5fd6cef29ccf57208bc9b018a04660262ead5..0000000000000000000000000000000000000000 --- a/arch/x86/crypto/morus640_glue.c +++ /dev/null @@ -1,200 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * The MORUS-640 Authenticated-Encryption Algorithm - * Common x86 SIMD glue skeleton - * - * Copyright (c) 2016-2018 Ondrej Mosnacek - * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct morus640_state { - struct morus640_block s[MORUS_STATE_BLOCKS]; -}; - -struct morus640_ops { - int (*skcipher_walk_init)(struct skcipher_walk *walk, - struct aead_request *req, bool atomic); - - void (*crypt_blocks)(void *state, const void *src, void *dst, - unsigned int length); - void (*crypt_tail)(void *state, const void *src, void *dst, - unsigned int length); -}; - -static void crypto_morus640_glue_process_ad( - struct morus640_state *state, - const struct morus640_glue_ops *ops, - struct scatterlist *sg_src, unsigned int assoclen) -{ - struct scatter_walk walk; - struct morus640_block buf; - unsigned int pos = 0; - - scatterwalk_start(&walk, sg_src); - while (assoclen != 0) { - unsigned int size = scatterwalk_clamp(&walk, assoclen); - unsigned int left = size; - void *mapped = scatterwalk_map(&walk); - const u8 *src = (const u8 *)mapped; - - if (pos + size >= MORUS640_BLOCK_SIZE) { - if (pos > 0) { - unsigned int fill = MORUS640_BLOCK_SIZE - pos; - memcpy(buf.bytes + pos, src, fill); - ops->ad(state, buf.bytes, MORUS640_BLOCK_SIZE); - pos = 0; - left -= fill; - src += fill; - } - - ops->ad(state, src, left); - src += left & ~(MORUS640_BLOCK_SIZE - 1); - left &= MORUS640_BLOCK_SIZE - 1; - } - - memcpy(buf.bytes + pos, src, left); - - pos += left; - assoclen -= size; - scatterwalk_unmap(mapped); - scatterwalk_advance(&walk, size); - scatterwalk_done(&walk, 0, assoclen); - } - - if (pos > 0) { - memset(buf.bytes + pos, 0, MORUS640_BLOCK_SIZE - pos); - ops->ad(state, buf.bytes, MORUS640_BLOCK_SIZE); - } -} - -static void crypto_morus640_glue_process_crypt(struct morus640_state *state, - struct morus640_ops ops, - struct skcipher_walk *walk) -{ - while (walk->nbytes >= MORUS640_BLOCK_SIZE) { - ops.crypt_blocks(state, walk->src.virt.addr, - walk->dst.virt.addr, - round_down(walk->nbytes, MORUS640_BLOCK_SIZE)); - skcipher_walk_done(walk, walk->nbytes % MORUS640_BLOCK_SIZE); - } - - if (walk->nbytes) { - ops.crypt_tail(state, walk->src.virt.addr, walk->dst.virt.addr, - walk->nbytes); - skcipher_walk_done(walk, 0); - } -} - -int crypto_morus640_glue_setkey(struct crypto_aead *aead, const u8 *key, - unsigned int keylen) -{ - struct morus640_ctx *ctx = crypto_aead_ctx(aead); - - if (keylen != MORUS640_BLOCK_SIZE) { - crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - memcpy(ctx->key.bytes, key, MORUS640_BLOCK_SIZE); - return 0; -} -EXPORT_SYMBOL_GPL(crypto_morus640_glue_setkey); - -int crypto_morus640_glue_setauthsize(struct crypto_aead *tfm, - unsigned int authsize) -{ - return (authsize <= MORUS_MAX_AUTH_SIZE) ? 0 : -EINVAL; -} -EXPORT_SYMBOL_GPL(crypto_morus640_glue_setauthsize); - -static void crypto_morus640_glue_crypt(struct aead_request *req, - struct morus640_ops ops, - unsigned int cryptlen, - struct morus640_block *tag_xor) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct morus640_ctx *ctx = crypto_aead_ctx(tfm); - struct morus640_state state; - struct skcipher_walk walk; - - ops.skcipher_walk_init(&walk, req, true); - - kernel_fpu_begin(); - - ctx->ops->init(&state, &ctx->key, req->iv); - crypto_morus640_glue_process_ad(&state, ctx->ops, req->src, req->assoclen); - crypto_morus640_glue_process_crypt(&state, ops, &walk); - ctx->ops->final(&state, tag_xor, req->assoclen, cryptlen); - - kernel_fpu_end(); -} - -int crypto_morus640_glue_encrypt(struct aead_request *req) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct morus640_ctx *ctx = crypto_aead_ctx(tfm); - struct morus640_ops OPS = { - .skcipher_walk_init = skcipher_walk_aead_encrypt, - .crypt_blocks = ctx->ops->enc, - .crypt_tail = ctx->ops->enc_tail, - }; - - struct morus640_block tag = {}; - unsigned int authsize = crypto_aead_authsize(tfm); - unsigned int cryptlen = req->cryptlen; - - crypto_morus640_glue_crypt(req, OPS, cryptlen, &tag); - - scatterwalk_map_and_copy(tag.bytes, req->dst, - req->assoclen + cryptlen, authsize, 1); - return 0; -} -EXPORT_SYMBOL_GPL(crypto_morus640_glue_encrypt); - -int crypto_morus640_glue_decrypt(struct aead_request *req) -{ - static const u8 zeros[MORUS640_BLOCK_SIZE] = {}; - - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct morus640_ctx *ctx = crypto_aead_ctx(tfm); - struct morus640_ops OPS = { - .skcipher_walk_init = skcipher_walk_aead_decrypt, - .crypt_blocks = ctx->ops->dec, - .crypt_tail = ctx->ops->dec_tail, - }; - - struct morus640_block tag; - unsigned int authsize = crypto_aead_authsize(tfm); - unsigned int cryptlen = req->cryptlen - authsize; - - scatterwalk_map_and_copy(tag.bytes, req->src, - req->assoclen + cryptlen, authsize, 0); - - crypto_morus640_glue_crypt(req, OPS, cryptlen, &tag); - - return crypto_memneq(tag.bytes, zeros, authsize) ? -EBADMSG : 0; -} -EXPORT_SYMBOL_GPL(crypto_morus640_glue_decrypt); - -void crypto_morus640_glue_init_ops(struct crypto_aead *aead, - const struct morus640_glue_ops *ops) -{ - struct morus640_ctx *ctx = crypto_aead_ctx(aead); - ctx->ops = ops; -} -EXPORT_SYMBOL_GPL(crypto_morus640_glue_init_ops); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ondrej Mosnacek "); -MODULE_DESCRIPTION("MORUS-640 AEAD mode -- glue for x86 optimizations"); diff --git a/arch/x86/crypto/serpent_avx2_glue.c b/arch/x86/crypto/serpent_avx2_glue.c index b871728e0b2f5e5d1398edf4b86730c9db45ef62..13fd8d3d2da00df76fde9fb1b7db9923a907b674 100644 --- a/arch/x86/crypto/serpent_avx2_glue.c +++ b/arch/x86/crypto/serpent_avx2_glue.c @@ -167,7 +167,7 @@ static int xts_encrypt(struct skcipher_request *req) return glue_xts_req_128bit(&serpent_enc_xts, req, XTS_TWEAK_CAST(__serpent_encrypt), - &ctx->tweak_ctx, &ctx->crypt_ctx); + &ctx->tweak_ctx, &ctx->crypt_ctx, false); } static int xts_decrypt(struct skcipher_request *req) @@ -177,7 +177,7 @@ static int xts_decrypt(struct skcipher_request *req) return glue_xts_req_128bit(&serpent_dec_xts, req, XTS_TWEAK_CAST(__serpent_encrypt), - &ctx->tweak_ctx, &ctx->crypt_ctx); + &ctx->tweak_ctx, &ctx->crypt_ctx, true); } static struct skcipher_alg serpent_algs[] = { diff --git a/arch/x86/crypto/serpent_avx_glue.c b/arch/x86/crypto/serpent_avx_glue.c index 4a9a9f2ee1d8065af829a638a7552bba791b6dea..7d3dca38a5a2ec1cfa008273004a9346c9819954 100644 --- a/arch/x86/crypto/serpent_avx_glue.c +++ b/arch/x86/crypto/serpent_avx_glue.c @@ -207,7 +207,7 @@ static int xts_encrypt(struct skcipher_request *req) return glue_xts_req_128bit(&serpent_enc_xts, req, XTS_TWEAK_CAST(__serpent_encrypt), - &ctx->tweak_ctx, &ctx->crypt_ctx); + &ctx->tweak_ctx, &ctx->crypt_ctx, false); } static int xts_decrypt(struct skcipher_request *req) @@ -217,7 +217,7 @@ static int xts_decrypt(struct skcipher_request *req) return glue_xts_req_128bit(&serpent_dec_xts, req, XTS_TWEAK_CAST(__serpent_encrypt), - &ctx->tweak_ctx, &ctx->crypt_ctx); + &ctx->tweak_ctx, &ctx->crypt_ctx, true); } static struct skcipher_alg serpent_algs[] = { diff --git a/arch/x86/crypto/sha256_ssse3_glue.c b/arch/x86/crypto/sha256_ssse3_glue.c index 73867da3cbeeded6ae57149f2e7011ceb2445822..f9aff31fe59e8c598a82fb5567f4c456a0439956 100644 --- a/arch/x86/crypto/sha256_ssse3_glue.c +++ b/arch/x86/crypto/sha256_ssse3_glue.c @@ -45,8 +45,8 @@ asmlinkage void sha256_transform_ssse3(u32 *digest, const char *data, u64 rounds); typedef void (sha256_transform_fn)(u32 *digest, const char *data, u64 rounds); -static int sha256_update(struct shash_desc *desc, const u8 *data, - unsigned int len, sha256_transform_fn *sha256_xform) +static int _sha256_update(struct shash_desc *desc, const u8 *data, + unsigned int len, sha256_transform_fn *sha256_xform) { struct sha256_state *sctx = shash_desc_ctx(desc); @@ -84,7 +84,7 @@ static int sha256_finup(struct shash_desc *desc, const u8 *data, static int sha256_ssse3_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - return sha256_update(desc, data, len, sha256_transform_ssse3); + return _sha256_update(desc, data, len, sha256_transform_ssse3); } static int sha256_ssse3_finup(struct shash_desc *desc, const u8 *data, @@ -151,7 +151,7 @@ asmlinkage void sha256_transform_avx(u32 *digest, const char *data, static int sha256_avx_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - return sha256_update(desc, data, len, sha256_transform_avx); + return _sha256_update(desc, data, len, sha256_transform_avx); } static int sha256_avx_finup(struct shash_desc *desc, const u8 *data, @@ -233,7 +233,7 @@ asmlinkage void sha256_transform_rorx(u32 *digest, const char *data, static int sha256_avx2_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - return sha256_update(desc, data, len, sha256_transform_rorx); + return _sha256_update(desc, data, len, sha256_transform_rorx); } static int sha256_avx2_finup(struct shash_desc *desc, const u8 *data, @@ -313,7 +313,7 @@ asmlinkage void sha256_ni_transform(u32 *digest, const char *data, static int sha256_ni_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - return sha256_update(desc, data, len, sha256_ni_transform); + return _sha256_update(desc, data, len, sha256_ni_transform); } static int sha256_ni_finup(struct shash_desc *desc, const u8 *data, diff --git a/arch/x86/crypto/twofish_avx_glue.c b/arch/x86/crypto/twofish_avx_glue.c index 0dbf8e8b09d7f2df02aa3f0e12805575ef9d9b36..d561c821788b7d74067e99f08263496b38eefe4d 100644 --- a/arch/x86/crypto/twofish_avx_glue.c +++ b/arch/x86/crypto/twofish_avx_glue.c @@ -210,7 +210,7 @@ static int xts_encrypt(struct skcipher_request *req) return glue_xts_req_128bit(&twofish_enc_xts, req, XTS_TWEAK_CAST(twofish_enc_blk), - &ctx->tweak_ctx, &ctx->crypt_ctx); + &ctx->tweak_ctx, &ctx->crypt_ctx, false); } static int xts_decrypt(struct skcipher_request *req) @@ -220,7 +220,7 @@ static int xts_decrypt(struct skcipher_request *req) return glue_xts_req_128bit(&twofish_dec_xts, req, XTS_TWEAK_CAST(twofish_enc_blk), - &ctx->tweak_ctx, &ctx->crypt_ctx); + &ctx->tweak_ctx, &ctx->crypt_ctx, true); } static struct skcipher_alg twofish_algs[] = { diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c index 536b574b61613403618c3db62d72c6adac91af98..3f8e22615812bf4d82c3dd6a0e2c878ecf61f3ec 100644 --- a/arch/x86/entry/common.c +++ b/arch/x86/entry/common.c @@ -285,15 +285,16 @@ __visible void do_syscall_64(unsigned long nr, struct pt_regs *regs) if (READ_ONCE(ti->flags) & _TIF_WORK_SYSCALL_ENTRY) nr = syscall_trace_enter(regs); - /* - * NB: Native and x32 syscalls are dispatched from the same - * table. The only functional difference is the x32 bit in - * regs->orig_ax, which changes the behavior of some syscalls. - */ - nr &= __SYSCALL_MASK; if (likely(nr < NR_syscalls)) { nr = array_index_nospec(nr, NR_syscalls); regs->ax = sys_call_table[nr](regs); +#ifdef CONFIG_X86_X32_ABI + } else if (likely((nr & __X32_SYSCALL_BIT) && + (nr & ~__X32_SYSCALL_BIT) < X32_NR_syscalls)) { + nr = array_index_nospec(nr & ~__X32_SYSCALL_BIT, + X32_NR_syscalls); + regs->ax = x32_sys_call_table[nr](regs); +#endif } syscall_return_slowpath(regs); diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S index 4f86928246e7a37ada2b324e84cf6d26be70dff2..f83ca5aa8b7794102a9bf23e0eb0123a5d162e82 100644 --- a/arch/x86/entry/entry_32.S +++ b/arch/x86/entry/entry_32.S @@ -63,7 +63,7 @@ * enough to patch inline, increasing performance. */ -#ifdef CONFIG_PREEMPT +#ifdef CONFIG_PREEMPTION # define preempt_stop(clobbers) DISABLE_INTERRUPTS(clobbers); TRACE_IRQS_OFF #else # define preempt_stop(clobbers) @@ -1084,7 +1084,7 @@ restore_all: INTERRUPT_RETURN restore_all_kernel: -#ifdef CONFIG_PREEMPT +#ifdef CONFIG_PREEMPTION DISABLE_INTERRUPTS(CLBR_ANY) cmpl $0, PER_CPU_VAR(__preempt_count) jnz .Lno_preempt @@ -1364,7 +1364,7 @@ ENTRY(xen_hypervisor_callback) ENTRY(xen_do_upcall) 1: mov %esp, %eax call xen_evtchn_do_upcall -#ifndef CONFIG_PREEMPT +#ifndef CONFIG_PREEMPTION call xen_maybe_preempt_hcall #endif jmp ret_from_intr diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index be9ca198c581aea7ed29f4417aae9c1c1b835473..b7c3ea4cb19d45ff11313818b686e1285546a3a1 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -664,7 +664,7 @@ GLOBAL(swapgs_restore_regs_and_return_to_usermode) /* Returning to kernel space */ retint_kernel: -#ifdef CONFIG_PREEMPT +#ifdef CONFIG_PREEMPTION /* Interrupts are off */ /* Check if we need preemption */ btl $9, EFLAGS(%rsp) /* were interrupts off? */ @@ -1058,10 +1058,10 @@ ENTRY(native_load_gs_index) ENDPROC(native_load_gs_index) EXPORT_SYMBOL(native_load_gs_index) - _ASM_EXTABLE(.Lgs_change, bad_gs) + _ASM_EXTABLE(.Lgs_change, .Lbad_gs) .section .fixup, "ax" /* running with kernelgs */ -bad_gs: +.Lbad_gs: SWAPGS /* switch back to user gs */ .macro ZAP_GS /* This can't be a string because the preprocessor needs to see it. */ @@ -1115,7 +1115,7 @@ ENTRY(xen_do_hypervisor_callback) /* do_hypervisor_callback(struct *pt_regs) */ call xen_evtchn_do_upcall LEAVE_IRQ_STACK -#ifndef CONFIG_PREEMPT +#ifndef CONFIG_PREEMPTION call xen_maybe_preempt_hcall #endif jmp error_exit diff --git a/arch/x86/entry/syscall_64.c b/arch/x86/entry/syscall_64.c index d5252bc1e38058ebc2d071d9bd3b3bd3cc1a976a..b1bf31713374a94b26d595f73d05d8d82fd2e8be 100644 --- a/arch/x86/entry/syscall_64.c +++ b/arch/x86/entry/syscall_64.c @@ -10,10 +10,13 @@ /* this is a lie, but it does not hurt as sys_ni_syscall just returns -EINVAL */ extern asmlinkage long sys_ni_syscall(const struct pt_regs *); #define __SYSCALL_64(nr, sym, qual) extern asmlinkage long sym(const struct pt_regs *); +#define __SYSCALL_X32(nr, sym, qual) __SYSCALL_64(nr, sym, qual) #include #undef __SYSCALL_64 +#undef __SYSCALL_X32 #define __SYSCALL_64(nr, sym, qual) [nr] = sym, +#define __SYSCALL_X32(nr, sym, qual) asmlinkage const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = { /* @@ -23,3 +26,25 @@ asmlinkage const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = { [0 ... __NR_syscall_max] = &sys_ni_syscall, #include }; + +#undef __SYSCALL_64 +#undef __SYSCALL_X32 + +#ifdef CONFIG_X86_X32_ABI + +#define __SYSCALL_64(nr, sym, qual) +#define __SYSCALL_X32(nr, sym, qual) [nr] = sym, + +asmlinkage const sys_call_ptr_t x32_sys_call_table[__NR_syscall_x32_max+1] = { + /* + * Smells like a compiler bug -- it doesn't work + * when the & below is removed. + */ + [0 ... __NR_syscall_x32_max] = &sys_ni_syscall, +#include +}; + +#undef __SYSCALL_64 +#undef __SYSCALL_X32 + +#endif diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index c00019abd0769d60d7a142db83b611d076e9ab0b..3fe02546aed35ba16a6142bfd26ad4869c50e65f 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -186,11 +186,11 @@ 172 i386 prctl sys_prctl __ia32_sys_prctl 173 i386 rt_sigreturn sys_rt_sigreturn sys32_rt_sigreturn 174 i386 rt_sigaction sys_rt_sigaction __ia32_compat_sys_rt_sigaction -175 i386 rt_sigprocmask sys_rt_sigprocmask __ia32_sys_rt_sigprocmask +175 i386 rt_sigprocmask sys_rt_sigprocmask __ia32_compat_sys_rt_sigprocmask 176 i386 rt_sigpending sys_rt_sigpending __ia32_compat_sys_rt_sigpending 177 i386 rt_sigtimedwait sys_rt_sigtimedwait_time32 __ia32_compat_sys_rt_sigtimedwait_time32 178 i386 rt_sigqueueinfo sys_rt_sigqueueinfo __ia32_compat_sys_rt_sigqueueinfo -179 i386 rt_sigsuspend sys_rt_sigsuspend __ia32_sys_rt_sigsuspend +179 i386 rt_sigsuspend sys_rt_sigsuspend __ia32_compat_sys_rt_sigsuspend 180 i386 pread64 sys_pread64 __ia32_compat_sys_x86_pread 181 i386 pwrite64 sys_pwrite64 __ia32_compat_sys_x86_pwrite 182 i386 chown sys_chown16 __ia32_sys_chown16 diff --git a/arch/x86/entry/syscalls/syscalltbl.sh b/arch/x86/entry/syscalls/syscalltbl.sh index 94fcd1951acaae51a3391d061e429f866469baae..1af2be39e7d9e018ce00166f9b090a2f4de923bc 100644 --- a/arch/x86/entry/syscalls/syscalltbl.sh +++ b/arch/x86/entry/syscalls/syscalltbl.sh @@ -1,13 +1,13 @@ -#!/bin/sh +#!/bin/bash # SPDX-License-Identifier: GPL-2.0 in="$1" out="$2" syscall_macro() { - abi="$1" - nr="$2" - entry="$3" + local abi="$1" + local nr="$2" + local entry="$3" # Entry can be either just a function name or "function/qualifier" real_entry="${entry%%/*}" @@ -21,14 +21,14 @@ syscall_macro() { } emit() { - abi="$1" - nr="$2" - entry="$3" - compat="$4" - umlentry="" + local abi="$1" + local nr="$2" + local entry="$3" + local compat="$4" + local umlentry="" - if [ "$abi" = "64" -a -n "$compat" ]; then - echo "a compat entry for a 64-bit syscall makes no sense" >&2 + if [ "$abi" != "I386" -a -n "$compat" ]; then + echo "a compat entry ($abi: $compat) for a 64-bit syscall makes no sense" >&2 exit 1 fi @@ -62,14 +62,17 @@ grep '^[0-9]' "$in" | sort -n | ( while read nr abi name entry compat; do abi=`echo "$abi" | tr '[a-z]' '[A-Z]'` if [ "$abi" = "COMMON" -o "$abi" = "64" ]; then - # COMMON is the same as 64, except that we don't expect X32 - # programs to use it. Our expectation has nothing to do with - # any generated code, so treat them the same. emit 64 "$nr" "$entry" "$compat" + if [ "$abi" = "COMMON" ]; then + # COMMON means that this syscall exists in the same form for + # 64-bit and X32. + echo "#ifdef CONFIG_X86_X32_ABI" + emit X32 "$nr" "$entry" "$compat" + echo "#endif" + fi elif [ "$abi" = "X32" ]; then - # X32 is equivalent to 64 on an X32-compatible kernel. echo "#ifdef CONFIG_X86_X32_ABI" - emit 64 "$nr" "$entry" "$compat" + emit X32 "$nr" "$entry" "$compat" echo "#endif" elif [ "$abi" = "I386" ]; then emit "$abi" "$nr" "$entry" "$compat" diff --git a/arch/x86/entry/thunk_32.S b/arch/x86/entry/thunk_32.S index cb3464525b37ba55e3bdde523d08bd716b3b123b..2713490611a3b5361ee82f9d09555fc9f69953ae 100644 --- a/arch/x86/entry/thunk_32.S +++ b/arch/x86/entry/thunk_32.S @@ -34,7 +34,7 @@ THUNK trace_hardirqs_off_thunk,trace_hardirqs_off_caller,1 #endif -#ifdef CONFIG_PREEMPT +#ifdef CONFIG_PREEMPTION THUNK ___preempt_schedule, preempt_schedule THUNK ___preempt_schedule_notrace, preempt_schedule_notrace EXPORT_SYMBOL(___preempt_schedule) diff --git a/arch/x86/entry/thunk_64.S b/arch/x86/entry/thunk_64.S index cc20465b28672d3f8beb10a62cf9fc6fb86c196a..ea5c4167086c20325a5cccd5579e6bb9c152b42c 100644 --- a/arch/x86/entry/thunk_64.S +++ b/arch/x86/entry/thunk_64.S @@ -46,7 +46,7 @@ THUNK lockdep_sys_exit_thunk,lockdep_sys_exit #endif -#ifdef CONFIG_PREEMPT +#ifdef CONFIG_PREEMPTION THUNK ___preempt_schedule, preempt_schedule THUNK ___preempt_schedule_notrace, preempt_schedule_notrace EXPORT_SYMBOL(___preempt_schedule) @@ -55,7 +55,7 @@ #if defined(CONFIG_TRACE_IRQFLAGS) \ || defined(CONFIG_DEBUG_LOCK_ALLOC) \ - || defined(CONFIG_PREEMPT) + || defined(CONFIG_PREEMPTION) .L_restore: popq %r11 popq %r10 diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c index 349a61d8bf3490199c5d8ae911f4d48ab44cdb2d..f5937742b2901c80947714e8e12c0cc75ba3423d 100644 --- a/arch/x86/entry/vdso/vma.c +++ b/arch/x86/entry/vdso/vma.c @@ -122,7 +122,7 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, if (tsc_pg && vclock_was_used(VCLOCK_HVCLOCK)) return vmf_insert_pfn(vma, vmf->address, - vmalloc_to_pfn(tsc_pg)); + virt_to_phys(tsc_pg) >> PAGE_SHIFT); } return VM_FAULT_SIGBUS; diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 325959d19d9a859b0f153d9c3a09ec9fe54833a2..7b21455d7504c6d875fb1dda9b0b14088318e1f7 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -1005,6 +1005,27 @@ static int collect_events(struct cpu_hw_events *cpuc, struct perf_event *leader, /* current number of events already accepted */ n = cpuc->n_events; + if (!cpuc->n_events) + cpuc->pebs_output = 0; + + if (!cpuc->is_fake && leader->attr.precise_ip) { + /* + * For PEBS->PT, if !aux_event, the group leader (PT) went + * away, the group was broken down and this singleton event + * can't schedule any more. + */ + if (is_pebs_pt(leader) && !leader->aux_event) + return -EINVAL; + + /* + * pebs_output: 0: no PEBS so far, 1: PT, 2: DS + */ + if (cpuc->pebs_output && + cpuc->pebs_output != is_pebs_pt(leader) + 1) + return -EINVAL; + + cpuc->pebs_output = is_pebs_pt(leader) + 1; + } if (is_x86_event(leader)) { if (n >= max_count) @@ -2087,7 +2108,7 @@ static int x86_pmu_event_init(struct perf_event *event) static void refresh_pce(void *ignored) { - load_mm_cr4(this_cpu_read(cpu_tlbstate.loaded_mm)); + load_mm_cr4_irqsoff(this_cpu_read(cpu_tlbstate.loaded_mm)); } static void x86_pmu_event_mapped(struct perf_event *event, struct mm_struct *mm) @@ -2241,6 +2262,17 @@ static int x86_pmu_check_period(struct perf_event *event, u64 value) return 0; } +static int x86_pmu_aux_output_match(struct perf_event *event) +{ + if (!(pmu.capabilities & PERF_PMU_CAP_AUX_OUTPUT)) + return 0; + + if (x86_pmu.aux_output_match) + return x86_pmu.aux_output_match(event); + + return 0; +} + static struct pmu pmu = { .pmu_enable = x86_pmu_enable, .pmu_disable = x86_pmu_disable, @@ -2266,6 +2298,8 @@ static struct pmu pmu = { .sched_task = x86_pmu_sched_task, .task_ctx_size = sizeof(struct x86_perf_task_context), .check_period = x86_pmu_check_period, + + .aux_output_match = x86_pmu_aux_output_match, }; void arch_perf_update_userpage(struct perf_event *event, diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index e4c2cb65ea50a15ef8c35a934e87f23dfdf32ee0..27ee47a7be6685db3c7b4d20bc0b5ef7ab7a0006 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -3298,6 +3299,13 @@ static int intel_pmu_hw_config(struct perf_event *event) } } + if (event->attr.aux_output) { + if (!event->attr.precise_ip) + return -EINVAL; + + event->hw.flags |= PERF_X86_EVENT_PEBS_VIA_PT; + } + if (event->attr.type != PERF_TYPE_RAW) return 0; @@ -3816,6 +3824,14 @@ static int intel_pmu_check_period(struct perf_event *event, u64 value) return intel_pmu_has_bts_period(event, value) ? -EINVAL : 0; } +static int intel_pmu_aux_output_match(struct perf_event *event) +{ + if (!x86_pmu.intel_cap.pebs_output_pt_available) + return 0; + + return is_intel_pt_event(event); +} + PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63"); PMU_FORMAT_ATTR(ldlat, "config1:0-15"); @@ -3940,6 +3956,8 @@ static __initconst const struct x86_pmu intel_pmu = { .sched_task = intel_pmu_sched_task, .check_period = intel_pmu_check_period, + + .aux_output_match = intel_pmu_aux_output_match, }; static __init void intel_clovertown_quirk(void) @@ -3969,31 +3987,31 @@ static __init void intel_clovertown_quirk(void) } static const struct x86_cpu_desc isolation_ucodes[] = { - INTEL_CPU_DESC(INTEL_FAM6_HASWELL_CORE, 3, 0x0000001f), - INTEL_CPU_DESC(INTEL_FAM6_HASWELL_ULT, 1, 0x0000001e), - INTEL_CPU_DESC(INTEL_FAM6_HASWELL_GT3E, 1, 0x00000015), + INTEL_CPU_DESC(INTEL_FAM6_HASWELL, 3, 0x0000001f), + INTEL_CPU_DESC(INTEL_FAM6_HASWELL_L, 1, 0x0000001e), + INTEL_CPU_DESC(INTEL_FAM6_HASWELL_G, 1, 0x00000015), INTEL_CPU_DESC(INTEL_FAM6_HASWELL_X, 2, 0x00000037), INTEL_CPU_DESC(INTEL_FAM6_HASWELL_X, 4, 0x0000000a), - INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_CORE, 4, 0x00000023), - INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_GT3E, 1, 0x00000014), - INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_XEON_D, 2, 0x00000010), - INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_XEON_D, 3, 0x07000009), - INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_XEON_D, 4, 0x0f000009), - INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_XEON_D, 5, 0x0e000002), + INTEL_CPU_DESC(INTEL_FAM6_BROADWELL, 4, 0x00000023), + INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_G, 1, 0x00000014), + INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_D, 2, 0x00000010), + INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_D, 3, 0x07000009), + INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_D, 4, 0x0f000009), + INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_D, 5, 0x0e000002), INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_X, 2, 0x0b000014), INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_X, 3, 0x00000021), INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_X, 4, 0x00000000), - INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_MOBILE, 3, 0x0000007c), - INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_DESKTOP, 3, 0x0000007c), - INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_DESKTOP, 9, 0x0000004e), - INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_MOBILE, 9, 0x0000004e), - INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_MOBILE, 10, 0x0000004e), - INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_MOBILE, 11, 0x0000004e), - INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_MOBILE, 12, 0x0000004e), - INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_DESKTOP, 10, 0x0000004e), - INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_DESKTOP, 11, 0x0000004e), - INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_DESKTOP, 12, 0x0000004e), - INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_DESKTOP, 13, 0x0000004e), + INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_L, 3, 0x0000007c), + INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE, 3, 0x0000007c), + INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE, 9, 0x0000004e), + INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_L, 9, 0x0000004e), + INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_L, 10, 0x0000004e), + INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_L, 11, 0x0000004e), + INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE_L, 12, 0x0000004e), + INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE, 10, 0x0000004e), + INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE, 11, 0x0000004e), + INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE, 12, 0x0000004e), + INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE, 13, 0x0000004e), {} }; @@ -4151,7 +4169,7 @@ static const struct x86_cpu_desc counter_freezing_ucodes[] = { INTEL_CPU_DESC(INTEL_FAM6_ATOM_GOLDMONT, 2, 0x0000000e), INTEL_CPU_DESC(INTEL_FAM6_ATOM_GOLDMONT, 9, 0x0000002e), INTEL_CPU_DESC(INTEL_FAM6_ATOM_GOLDMONT, 10, 0x00000008), - INTEL_CPU_DESC(INTEL_FAM6_ATOM_GOLDMONT_X, 1, 0x00000028), + INTEL_CPU_DESC(INTEL_FAM6_ATOM_GOLDMONT_D, 1, 0x00000028), INTEL_CPU_DESC(INTEL_FAM6_ATOM_GOLDMONT_PLUS, 1, 0x00000028), INTEL_CPU_DESC(INTEL_FAM6_ATOM_GOLDMONT_PLUS, 8, 0x00000006), {} @@ -4649,7 +4667,7 @@ __init int intel_pmu_init(void) break; case INTEL_FAM6_ATOM_SILVERMONT: - case INTEL_FAM6_ATOM_SILVERMONT_X: + case INTEL_FAM6_ATOM_SILVERMONT_D: case INTEL_FAM6_ATOM_SILVERMONT_MID: case INTEL_FAM6_ATOM_AIRMONT: case INTEL_FAM6_ATOM_AIRMONT_MID: @@ -4671,7 +4689,7 @@ __init int intel_pmu_init(void) break; case INTEL_FAM6_ATOM_GOLDMONT: - case INTEL_FAM6_ATOM_GOLDMONT_X: + case INTEL_FAM6_ATOM_GOLDMONT_D: x86_add_quirk(intel_counter_freezing_quirk); memcpy(hw_cache_event_ids, glm_hw_cache_event_ids, sizeof(hw_cache_event_ids)); @@ -4727,7 +4745,7 @@ __init int intel_pmu_init(void) name = "goldmont_plus"; break; - case INTEL_FAM6_ATOM_TREMONT_X: + case INTEL_FAM6_ATOM_TREMONT_D: x86_pmu.late_ack = true; memcpy(hw_cache_event_ids, glp_hw_cache_event_ids, sizeof(hw_cache_event_ids)); @@ -4863,10 +4881,10 @@ __init int intel_pmu_init(void) break; - case INTEL_FAM6_HASWELL_CORE: + case INTEL_FAM6_HASWELL: case INTEL_FAM6_HASWELL_X: - case INTEL_FAM6_HASWELL_ULT: - case INTEL_FAM6_HASWELL_GT3E: + case INTEL_FAM6_HASWELL_L: + case INTEL_FAM6_HASWELL_G: x86_add_quirk(intel_ht_bug); x86_add_quirk(intel_pebs_isolation_quirk); x86_pmu.late_ack = true; @@ -4896,9 +4914,9 @@ __init int intel_pmu_init(void) name = "haswell"; break; - case INTEL_FAM6_BROADWELL_CORE: - case INTEL_FAM6_BROADWELL_XEON_D: - case INTEL_FAM6_BROADWELL_GT3E: + case INTEL_FAM6_BROADWELL: + case INTEL_FAM6_BROADWELL_D: + case INTEL_FAM6_BROADWELL_G: case INTEL_FAM6_BROADWELL_X: x86_add_quirk(intel_pebs_isolation_quirk); x86_pmu.late_ack = true; @@ -4961,10 +4979,10 @@ __init int intel_pmu_init(void) case INTEL_FAM6_SKYLAKE_X: pmem = true; /* fall through */ - case INTEL_FAM6_SKYLAKE_MOBILE: - case INTEL_FAM6_SKYLAKE_DESKTOP: - case INTEL_FAM6_KABYLAKE_MOBILE: - case INTEL_FAM6_KABYLAKE_DESKTOP: + case INTEL_FAM6_SKYLAKE_L: + case INTEL_FAM6_SKYLAKE: + case INTEL_FAM6_KABYLAKE_L: + case INTEL_FAM6_KABYLAKE: x86_add_quirk(intel_pebs_isolation_quirk); x86_pmu.late_ack = true; memcpy(hw_cache_event_ids, skl_hw_cache_event_ids, sizeof(hw_cache_event_ids)); @@ -5008,11 +5026,11 @@ __init int intel_pmu_init(void) break; case INTEL_FAM6_ICELAKE_X: - case INTEL_FAM6_ICELAKE_XEON_D: + case INTEL_FAM6_ICELAKE_D: pmem = true; /* fall through */ - case INTEL_FAM6_ICELAKE_MOBILE: - case INTEL_FAM6_ICELAKE_DESKTOP: + case INTEL_FAM6_ICELAKE_L: + case INTEL_FAM6_ICELAKE: x86_pmu.late_ack = true; memcpy(hw_cache_event_ids, skl_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, skl_hw_cache_extra_regs, sizeof(hw_cache_extra_regs)); diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c index 688592b34564987a726a944cc178a897175b5d68..9f2f39003d96eb2a9ae3a9917627536fe2cda4e8 100644 --- a/arch/x86/events/intel/cstate.c +++ b/arch/x86/events/intel/cstate.c @@ -446,7 +446,7 @@ static int cstate_cpu_init(unsigned int cpu) return 0; } -const struct attribute_group *core_attr_update[] = { +static const struct attribute_group *core_attr_update[] = { &group_cstate_core_c1, &group_cstate_core_c3, &group_cstate_core_c6, @@ -454,7 +454,7 @@ const struct attribute_group *core_attr_update[] = { NULL, }; -const struct attribute_group *pkg_attr_update[] = { +static const struct attribute_group *pkg_attr_update[] = { &group_cstate_pkg_c2, &group_cstate_pkg_c3, &group_cstate_pkg_c6, @@ -593,40 +593,40 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = { X86_CSTATES_MODEL(INTEL_FAM6_IVYBRIDGE, snb_cstates), X86_CSTATES_MODEL(INTEL_FAM6_IVYBRIDGE_X, snb_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_HASWELL_CORE, snb_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_HASWELL_X, snb_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_HASWELL_GT3E, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_HASWELL, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_HASWELL_X, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_HASWELL_G, snb_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_HASWELL_ULT, hswult_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_HASWELL_L, hswult_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_ATOM_SILVERMONT, slm_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_ATOM_SILVERMONT_X, slm_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_ATOM_AIRMONT, slm_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_ATOM_SILVERMONT, slm_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_ATOM_SILVERMONT_D, slm_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_ATOM_AIRMONT, slm_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_BROADWELL_CORE, snb_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_BROADWELL_XEON_D, snb_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_BROADWELL_GT3E, snb_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_BROADWELL_X, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_BROADWELL, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_BROADWELL_D, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_BROADWELL_G, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_BROADWELL_X, snb_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_MOBILE, snb_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_DESKTOP, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_L, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE, snb_cstates), X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_X, snb_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_KABYLAKE_MOBILE, hswult_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_KABYLAKE_DESKTOP, hswult_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_KABYLAKE_L, hswult_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_KABYLAKE, hswult_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_CANNONLAKE_MOBILE, cnl_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_CANNONLAKE_L, cnl_cstates), X86_CSTATES_MODEL(INTEL_FAM6_XEON_PHI_KNL, knl_cstates), X86_CSTATES_MODEL(INTEL_FAM6_XEON_PHI_KNM, knl_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT, glm_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT_X, glm_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT, glm_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT_D, glm_cstates), X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT_PLUS, glm_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_ICELAKE_MOBILE, snb_cstates), - X86_CSTATES_MODEL(INTEL_FAM6_ICELAKE_DESKTOP, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_ICELAKE_L, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_ICELAKE, snb_cstates), { }, }; MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match); diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c index f1269e804e9b70a1e144ede95677d6ddb5f76044..ce83950036c56ad8f88459a6a6f7a44decdeeb04 100644 --- a/arch/x86/events/intel/ds.c +++ b/arch/x86/events/intel/ds.c @@ -902,6 +902,9 @@ struct event_constraint *intel_pebs_constraints(struct perf_event *event) */ static inline bool pebs_needs_sched_cb(struct cpu_hw_events *cpuc) { + if (cpuc->n_pebs == cpuc->n_pebs_via_pt) + return false; + return cpuc->n_pebs && (cpuc->n_pebs == cpuc->n_large_pebs); } @@ -919,6 +922,9 @@ static inline void pebs_update_threshold(struct cpu_hw_events *cpuc) u64 threshold; int reserved; + if (cpuc->n_pebs_via_pt) + return; + if (x86_pmu.flags & PMU_FL_PEBS_ALL) reserved = x86_pmu.max_pebs_events + x86_pmu.num_counters_fixed; else @@ -1059,10 +1065,40 @@ void intel_pmu_pebs_add(struct perf_event *event) cpuc->n_pebs++; if (hwc->flags & PERF_X86_EVENT_LARGE_PEBS) cpuc->n_large_pebs++; + if (hwc->flags & PERF_X86_EVENT_PEBS_VIA_PT) + cpuc->n_pebs_via_pt++; pebs_update_state(needed_cb, cpuc, event, true); } +static void intel_pmu_pebs_via_pt_disable(struct perf_event *event) +{ + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + + if (!is_pebs_pt(event)) + return; + + if (!(cpuc->pebs_enabled & ~PEBS_VIA_PT_MASK)) + cpuc->pebs_enabled &= ~PEBS_VIA_PT_MASK; +} + +static void intel_pmu_pebs_via_pt_enable(struct perf_event *event) +{ + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + struct hw_perf_event *hwc = &event->hw; + struct debug_store *ds = cpuc->ds; + + if (!is_pebs_pt(event)) + return; + + if (!(event->hw.flags & PERF_X86_EVENT_LARGE_PEBS)) + cpuc->pebs_enabled |= PEBS_PMI_AFTER_EACH_RECORD; + + cpuc->pebs_enabled |= PEBS_OUTPUT_PT; + + wrmsrl(MSR_RELOAD_PMC0 + hwc->idx, ds->pebs_event_reset[hwc->idx]); +} + void intel_pmu_pebs_enable(struct perf_event *event) { struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); @@ -1100,6 +1136,8 @@ void intel_pmu_pebs_enable(struct perf_event *event) } else { ds->pebs_event_reset[hwc->idx] = 0; } + + intel_pmu_pebs_via_pt_enable(event); } void intel_pmu_pebs_del(struct perf_event *event) @@ -1111,6 +1149,8 @@ void intel_pmu_pebs_del(struct perf_event *event) cpuc->n_pebs--; if (hwc->flags & PERF_X86_EVENT_LARGE_PEBS) cpuc->n_large_pebs--; + if (hwc->flags & PERF_X86_EVENT_PEBS_VIA_PT) + cpuc->n_pebs_via_pt--; pebs_update_state(needed_cb, cpuc, event, false); } @@ -1120,7 +1160,8 @@ void intel_pmu_pebs_disable(struct perf_event *event) struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; - if (cpuc->n_pebs == cpuc->n_large_pebs) + if (cpuc->n_pebs == cpuc->n_large_pebs && + cpuc->n_pebs != cpuc->n_pebs_via_pt) intel_pmu_drain_pebs_buffer(); cpuc->pebs_enabled &= ~(1ULL << hwc->idx); @@ -1131,6 +1172,8 @@ void intel_pmu_pebs_disable(struct perf_event *event) else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST) cpuc->pebs_enabled &= ~(1ULL << 63); + intel_pmu_pebs_via_pt_disable(event); + if (cpuc->enabled) wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled); @@ -2031,6 +2074,12 @@ void __init intel_ds_init(void) PERF_SAMPLE_REGS_INTR); } pr_cont("PEBS fmt4%c%s, ", pebs_type, pebs_qual); + + if (x86_pmu.intel_cap.pebs_output_pt_available) { + pr_cont("PEBS-via-PT, "); + x86_get_pmu()->capabilities |= PERF_PMU_CAP_AUX_OUTPUT; + } + break; default: diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index 6f814a27416b4268b94f0d83a69b022548c226e3..ea54634eabf3d99b262404997c56296b784a3ec7 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -273,7 +273,7 @@ static inline bool lbr_from_signext_quirk_needed(void) return !tsx_support && (lbr_desc[lbr_format] & LBR_TSX); } -DEFINE_STATIC_KEY_FALSE(lbr_from_quirk_key); +static DEFINE_STATIC_KEY_FALSE(lbr_from_quirk_key); /* If quirk is enabled, ensure sign extension is 63 bits: */ inline u64 lbr_from_signext_quirk_wr(u64 val) diff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c index d3dc2274ddd419ed7db5d44af16b4ff70d4ec723..74e80ed9c6c474551b57c6d8b4d548aeb3ea8e4d 100644 --- a/arch/x86/events/intel/pt.c +++ b/arch/x86/events/intel/pt.c @@ -204,9 +204,9 @@ static int __init pt_pmu_hw_init(void) /* model-specific quirks */ switch (boot_cpu_data.x86_model) { - case INTEL_FAM6_BROADWELL_CORE: - case INTEL_FAM6_BROADWELL_XEON_D: - case INTEL_FAM6_BROADWELL_GT3E: + case INTEL_FAM6_BROADWELL: + case INTEL_FAM6_BROADWELL_D: + case INTEL_FAM6_BROADWELL_G: case INTEL_FAM6_BROADWELL_X: /* not setting BRANCH_EN will #GP, erratum BDM106 */ pt_pmu.branch_en_always_on = true; @@ -545,33 +545,62 @@ static void pt_config_buffer(void *buf, unsigned int topa_idx, wrmsrl(MSR_IA32_RTIT_OUTPUT_MASK, reg); } -/* - * Keep ToPA table-related metadata on the same page as the actual table, - * taking up a few words from the top - */ - -#define TENTS_PER_PAGE (((PAGE_SIZE - 40) / sizeof(struct topa_entry)) - 1) - /** - * struct topa - page-sized ToPA table with metadata at the top - * @table: actual ToPA table entries, as understood by PT hardware + * struct topa - ToPA metadata * @list: linkage to struct pt_buffer's list of tables - * @phys: physical address of this page * @offset: offset of the first entry in this table in the buffer * @size: total size of all entries in this table * @last: index of the last initialized entry in this table + * @z_count: how many times the first entry repeats */ struct topa { - struct topa_entry table[TENTS_PER_PAGE]; struct list_head list; - u64 phys; u64 offset; size_t size; int last; + unsigned int z_count; }; +/* + * Keep ToPA table-related metadata on the same page as the actual table, + * taking up a few words from the top + */ + +#define TENTS_PER_PAGE \ + ((PAGE_SIZE - sizeof(struct topa)) / sizeof(struct topa_entry)) + +/** + * struct topa_page - page-sized ToPA table with metadata at the top + * @table: actual ToPA table entries, as understood by PT hardware + * @topa: metadata + */ +struct topa_page { + struct topa_entry table[TENTS_PER_PAGE]; + struct topa topa; +}; + +static inline struct topa_page *topa_to_page(struct topa *topa) +{ + return container_of(topa, struct topa_page, topa); +} + +static inline struct topa_page *topa_entry_to_page(struct topa_entry *te) +{ + return (struct topa_page *)((unsigned long)te & PAGE_MASK); +} + +static inline phys_addr_t topa_pfn(struct topa *topa) +{ + return PFN_DOWN(virt_to_phys(topa_to_page(topa))); +} + /* make -1 stand for the last table entry */ -#define TOPA_ENTRY(t, i) ((i) == -1 ? &(t)->table[(t)->last] : &(t)->table[(i)]) +#define TOPA_ENTRY(t, i) \ + ((i) == -1 \ + ? &topa_to_page(t)->table[(t)->last] \ + : &topa_to_page(t)->table[(i)]) +#define TOPA_ENTRY_SIZE(t, i) (sizes(TOPA_ENTRY((t), (i))->size)) +#define TOPA_ENTRY_PAGES(t, i) (1 << TOPA_ENTRY((t), (i))->size) /** * topa_alloc() - allocate page-sized ToPA table @@ -583,27 +612,26 @@ struct topa { static struct topa *topa_alloc(int cpu, gfp_t gfp) { int node = cpu_to_node(cpu); - struct topa *topa; + struct topa_page *tp; struct page *p; p = alloc_pages_node(node, gfp | __GFP_ZERO, 0); if (!p) return NULL; - topa = page_address(p); - topa->last = 0; - topa->phys = page_to_phys(p); + tp = page_address(p); + tp->topa.last = 0; /* * In case of singe-entry ToPA, always put the self-referencing END * link as the 2nd entry in the table */ if (!intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries)) { - TOPA_ENTRY(topa, 1)->base = topa->phys >> TOPA_SHIFT; - TOPA_ENTRY(topa, 1)->end = 1; + TOPA_ENTRY(&tp->topa, 1)->base = page_to_phys(p); + TOPA_ENTRY(&tp->topa, 1)->end = 1; } - return topa; + return &tp->topa; } /** @@ -643,7 +671,7 @@ static void topa_insert_table(struct pt_buffer *buf, struct topa *topa) BUG_ON(last->last != TENTS_PER_PAGE - 1); - TOPA_ENTRY(last, -1)->base = topa->phys >> TOPA_SHIFT; + TOPA_ENTRY(last, -1)->base = topa_pfn(topa); TOPA_ENTRY(last, -1)->end = 1; } @@ -670,7 +698,7 @@ static bool topa_table_full(struct topa *topa) * * Return: 0 on success or error code. */ -static int topa_insert_pages(struct pt_buffer *buf, gfp_t gfp) +static int topa_insert_pages(struct pt_buffer *buf, int cpu, gfp_t gfp) { struct topa *topa = buf->last; int order = 0; @@ -681,13 +709,18 @@ static int topa_insert_pages(struct pt_buffer *buf, gfp_t gfp) order = page_private(p); if (topa_table_full(topa)) { - topa = topa_alloc(buf->cpu, gfp); + topa = topa_alloc(cpu, gfp); if (!topa) return -ENOMEM; topa_insert_table(buf, topa); } + if (topa->z_count == topa->last - 1) { + if (order == TOPA_ENTRY(topa, topa->last - 1)->size) + topa->z_count++; + } + TOPA_ENTRY(topa, -1)->base = page_to_phys(p) >> TOPA_SHIFT; TOPA_ENTRY(topa, -1)->size = order; if (!buf->snapshot && @@ -713,23 +746,26 @@ static void pt_topa_dump(struct pt_buffer *buf) struct topa *topa; list_for_each_entry(topa, &buf->tables, list) { + struct topa_page *tp = topa_to_page(topa); int i; - pr_debug("# table @%p (%016Lx), off %llx size %zx\n", topa->table, - topa->phys, topa->offset, topa->size); + pr_debug("# table @%p, off %llx size %zx\n", tp->table, + topa->offset, topa->size); for (i = 0; i < TENTS_PER_PAGE; i++) { pr_debug("# entry @%p (%lx sz %u %c%c%c) raw=%16llx\n", - &topa->table[i], - (unsigned long)topa->table[i].base << TOPA_SHIFT, - sizes(topa->table[i].size), - topa->table[i].end ? 'E' : ' ', - topa->table[i].intr ? 'I' : ' ', - topa->table[i].stop ? 'S' : ' ', - *(u64 *)&topa->table[i]); + &tp->table[i], + (unsigned long)tp->table[i].base << TOPA_SHIFT, + sizes(tp->table[i].size), + tp->table[i].end ? 'E' : ' ', + tp->table[i].intr ? 'I' : ' ', + tp->table[i].stop ? 'S' : ' ', + *(u64 *)&tp->table[i]); if ((intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries) && - topa->table[i].stop) || - topa->table[i].end) + tp->table[i].stop) || + tp->table[i].end) break; + if (!i && topa->z_count) + i += topa->z_count; } } } @@ -771,7 +807,7 @@ static void pt_update_head(struct pt *pt) /* offset of the current output region within this table */ for (topa_idx = 0; topa_idx < buf->cur_idx; topa_idx++) - base += sizes(buf->cur->table[topa_idx].size); + base += TOPA_ENTRY_SIZE(buf->cur, topa_idx); if (buf->snapshot) { local_set(&buf->data_size, base); @@ -791,7 +827,7 @@ static void pt_update_head(struct pt *pt) */ static void *pt_buffer_region(struct pt_buffer *buf) { - return phys_to_virt(buf->cur->table[buf->cur_idx].base << TOPA_SHIFT); + return phys_to_virt(TOPA_ENTRY(buf->cur, buf->cur_idx)->base << TOPA_SHIFT); } /** @@ -800,7 +836,7 @@ static void *pt_buffer_region(struct pt_buffer *buf) */ static size_t pt_buffer_region_size(struct pt_buffer *buf) { - return sizes(buf->cur->table[buf->cur_idx].size); + return TOPA_ENTRY_SIZE(buf->cur, buf->cur_idx); } /** @@ -830,7 +866,7 @@ static void pt_handle_status(struct pt *pt) * know. */ if (!intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries) || - buf->output_off == sizes(TOPA_ENTRY(buf->cur, buf->cur_idx)->size)) { + buf->output_off == pt_buffer_region_size(buf)) { perf_aux_output_flag(&pt->handle, PERF_AUX_FLAG_TRUNCATED); advance++; @@ -868,9 +904,11 @@ static void pt_handle_status(struct pt *pt) static void pt_read_offset(struct pt_buffer *buf) { u64 offset, base_topa; + struct topa_page *tp; rdmsrl(MSR_IA32_RTIT_OUTPUT_BASE, base_topa); - buf->cur = phys_to_virt(base_topa); + tp = phys_to_virt(base_topa); + buf->cur = &tp->topa; rdmsrl(MSR_IA32_RTIT_OUTPUT_MASK, offset); /* offset within current output region */ @@ -879,29 +917,97 @@ static void pt_read_offset(struct pt_buffer *buf) buf->cur_idx = (offset & 0xffffff80) >> 7; } -/** - * pt_topa_next_entry() - obtain index of the first page in the next ToPA entry - * @buf: PT buffer. - * @pg: Page offset in the buffer. - * - * When advancing to the next output region (ToPA entry), given a page offset - * into the buffer, we need to find the offset of the first page in the next - * region. - */ -static unsigned int pt_topa_next_entry(struct pt_buffer *buf, unsigned int pg) +static struct topa_entry * +pt_topa_entry_for_page(struct pt_buffer *buf, unsigned int pg) { - struct topa_entry *te = buf->topa_index[pg]; + struct topa_page *tp; + struct topa *topa; + unsigned int idx, cur_pg = 0, z_pg = 0, start_idx = 0; - /* one region */ - if (buf->first == buf->last && buf->first->last == 1) - return pg; + /* + * Indicates a bug in the caller. + */ + if (WARN_ON_ONCE(pg >= buf->nr_pages)) + return NULL; + + /* + * First, find the ToPA table where @pg fits. With high + * order allocations, there shouldn't be many of these. + */ + list_for_each_entry(topa, &buf->tables, list) { + if (topa->offset + topa->size > pg << PAGE_SHIFT) + goto found; + } + + /* + * Hitting this means we have a problem in the ToPA + * allocation code. + */ + WARN_ON_ONCE(1); - do { - pg++; - pg &= buf->nr_pages - 1; - } while (buf->topa_index[pg] == te); + return NULL; - return pg; +found: + /* + * Indicates a problem in the ToPA allocation code. + */ + if (WARN_ON_ONCE(topa->last == -1)) + return NULL; + + tp = topa_to_page(topa); + cur_pg = PFN_DOWN(topa->offset); + if (topa->z_count) { + z_pg = TOPA_ENTRY_PAGES(topa, 0) * (topa->z_count + 1); + start_idx = topa->z_count + 1; + } + + /* + * Multiple entries at the beginning of the table have the same size, + * ideally all of them; if @pg falls there, the search is done. + */ + if (pg >= cur_pg && pg < cur_pg + z_pg) { + idx = (pg - cur_pg) / TOPA_ENTRY_PAGES(topa, 0); + return &tp->table[idx]; + } + + /* + * Otherwise, slow path: iterate through the remaining entries. + */ + for (idx = start_idx, cur_pg += z_pg; idx < topa->last; idx++) { + if (cur_pg + TOPA_ENTRY_PAGES(topa, idx) > pg) + return &tp->table[idx]; + + cur_pg += TOPA_ENTRY_PAGES(topa, idx); + } + + /* + * Means we couldn't find a ToPA entry in the table that does match. + */ + WARN_ON_ONCE(1); + + return NULL; +} + +static struct topa_entry * +pt_topa_prev_entry(struct pt_buffer *buf, struct topa_entry *te) +{ + unsigned long table = (unsigned long)te & ~(PAGE_SIZE - 1); + struct topa_page *tp; + struct topa *topa; + + tp = (struct topa_page *)table; + if (tp->table != te) + return --te; + + topa = &tp->topa; + if (topa == buf->first) + topa = buf->last; + else + topa = list_prev_entry(topa, list); + + tp = topa_to_page(topa); + + return &tp->table[topa->last - 1]; } /** @@ -925,8 +1031,7 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf, unsigned long idx, npages, wakeup; /* can't stop in the middle of an output region */ - if (buf->output_off + handle->size + 1 < - sizes(TOPA_ENTRY(buf->cur, buf->cur_idx)->size)) { + if (buf->output_off + handle->size + 1 < pt_buffer_region_size(buf)) { perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED); return -EINVAL; } @@ -937,9 +1042,13 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf, return 0; /* clear STOP and INT from current entry */ - buf->topa_index[buf->stop_pos]->stop = 0; - buf->topa_index[buf->stop_pos]->intr = 0; - buf->topa_index[buf->intr_pos]->intr = 0; + if (buf->stop_te) { + buf->stop_te->stop = 0; + buf->stop_te->intr = 0; + } + + if (buf->intr_te) + buf->intr_te->intr = 0; /* how many pages till the STOP marker */ npages = handle->size >> PAGE_SHIFT; @@ -950,7 +1059,12 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf, idx = (head >> PAGE_SHIFT) + npages; idx &= buf->nr_pages - 1; - buf->stop_pos = idx; + + if (idx != buf->stop_pos) { + buf->stop_pos = idx; + buf->stop_te = pt_topa_entry_for_page(buf, idx); + buf->stop_te = pt_topa_prev_entry(buf, buf->stop_te); + } wakeup = handle->wakeup >> PAGE_SHIFT; @@ -960,50 +1074,19 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf, idx = wakeup; idx &= buf->nr_pages - 1; - buf->intr_pos = idx; + if (idx != buf->intr_pos) { + buf->intr_pos = idx; + buf->intr_te = pt_topa_entry_for_page(buf, idx); + buf->intr_te = pt_topa_prev_entry(buf, buf->intr_te); + } - buf->topa_index[buf->stop_pos]->stop = 1; - buf->topa_index[buf->stop_pos]->intr = 1; - buf->topa_index[buf->intr_pos]->intr = 1; + buf->stop_te->stop = 1; + buf->stop_te->intr = 1; + buf->intr_te->intr = 1; return 0; } -/** - * pt_buffer_setup_topa_index() - build topa_index[] table of regions - * @buf: PT buffer. - * - * topa_index[] references output regions indexed by offset into the - * buffer for purposes of quick reverse lookup. - */ -static void pt_buffer_setup_topa_index(struct pt_buffer *buf) -{ - struct topa *cur = buf->first, *prev = buf->last; - struct topa_entry *te_cur = TOPA_ENTRY(cur, 0), - *te_prev = TOPA_ENTRY(prev, prev->last - 1); - int pg = 0, idx = 0; - - while (pg < buf->nr_pages) { - int tidx; - - /* pages within one topa entry */ - for (tidx = 0; tidx < 1 << te_cur->size; tidx++, pg++) - buf->topa_index[pg] = te_prev; - - te_prev = te_cur; - - if (idx == cur->last - 1) { - /* advance to next topa table */ - idx = 0; - cur = list_entry(cur->list.next, struct topa, list); - } else { - idx++; - } - te_cur = TOPA_ENTRY(cur, idx); - } - -} - /** * pt_buffer_reset_offsets() - adjust buffer's write pointers from aux_head * @buf: PT buffer. @@ -1021,18 +1104,20 @@ static void pt_buffer_setup_topa_index(struct pt_buffer *buf) */ static void pt_buffer_reset_offsets(struct pt_buffer *buf, unsigned long head) { + struct topa_page *cur_tp; + struct topa_entry *te; int pg; if (buf->snapshot) head &= (buf->nr_pages << PAGE_SHIFT) - 1; pg = (head >> PAGE_SHIFT) & (buf->nr_pages - 1); - pg = pt_topa_next_entry(buf, pg); + te = pt_topa_entry_for_page(buf, pg); - buf->cur = (struct topa *)((unsigned long)buf->topa_index[pg] & PAGE_MASK); - buf->cur_idx = ((unsigned long)buf->topa_index[pg] - - (unsigned long)buf->cur) / sizeof(struct topa_entry); - buf->output_off = head & (sizes(buf->cur->table[buf->cur_idx].size) - 1); + cur_tp = topa_entry_to_page(te); + buf->cur = &cur_tp->topa; + buf->cur_idx = te - TOPA_ENTRY(buf->cur, 0); + buf->output_off = head & (pt_buffer_region_size(buf) - 1); local64_set(&buf->head, head); local_set(&buf->data_size, 0); @@ -1061,31 +1146,29 @@ static void pt_buffer_fini_topa(struct pt_buffer *buf) * @size: Total size of all regions within this ToPA. * @gfp: Allocation flags. */ -static int pt_buffer_init_topa(struct pt_buffer *buf, unsigned long nr_pages, - gfp_t gfp) +static int pt_buffer_init_topa(struct pt_buffer *buf, int cpu, + unsigned long nr_pages, gfp_t gfp) { struct topa *topa; int err; - topa = topa_alloc(buf->cpu, gfp); + topa = topa_alloc(cpu, gfp); if (!topa) return -ENOMEM; topa_insert_table(buf, topa); while (buf->nr_pages < nr_pages) { - err = topa_insert_pages(buf, gfp); + err = topa_insert_pages(buf, cpu, gfp); if (err) { pt_buffer_fini_topa(buf); return -ENOMEM; } } - pt_buffer_setup_topa_index(buf); - /* link last table to the first one, unless we're double buffering */ if (intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries)) { - TOPA_ENTRY(buf->last, -1)->base = buf->first->phys >> TOPA_SHIFT; + TOPA_ENTRY(buf->last, -1)->base = topa_pfn(buf->first); TOPA_ENTRY(buf->last, -1)->end = 1; } @@ -1119,18 +1202,18 @@ pt_buffer_setup_aux(struct perf_event *event, void **pages, cpu = raw_smp_processor_id(); node = cpu_to_node(cpu); - buf = kzalloc_node(offsetof(struct pt_buffer, topa_index[nr_pages]), - GFP_KERNEL, node); + buf = kzalloc_node(sizeof(struct pt_buffer), GFP_KERNEL, node); if (!buf) return NULL; - buf->cpu = cpu; buf->snapshot = snapshot; buf->data_pages = pages; + buf->stop_pos = -1; + buf->intr_pos = -1; INIT_LIST_HEAD(&buf->tables); - ret = pt_buffer_init_topa(buf, nr_pages, GFP_KERNEL); + ret = pt_buffer_init_topa(buf, cpu, nr_pages, GFP_KERNEL); if (ret) { kfree(buf); return NULL; @@ -1296,7 +1379,7 @@ void intel_pt_interrupt(void) return; } - pt_config_buffer(buf->cur->table, buf->cur_idx, + pt_config_buffer(topa_to_page(buf->cur)->table, buf->cur_idx, buf->output_off); pt_config(event); } @@ -1361,7 +1444,7 @@ static void pt_event_start(struct perf_event *event, int mode) WRITE_ONCE(pt->handle_nmi, 1); hwc->state = 0; - pt_config_buffer(buf->cur->table, buf->cur_idx, + pt_config_buffer(topa_to_page(buf->cur)->table, buf->cur_idx, buf->output_off); pt_config(event); @@ -1481,6 +1564,11 @@ void cpu_emergency_stop_pt(void) pt_event_stop(pt->handle.event, PERF_EF_UPDATE); } +int is_intel_pt_event(struct perf_event *event) +{ + return event->pmu == &pt_pmu.pmu; +} + static __init int pt_init(void) { int ret, cpu, prior_warn = 0; diff --git a/arch/x86/events/intel/pt.h b/arch/x86/events/intel/pt.h index 63fe4063fbd69f7b2e907c41febfb58fd9dee05c..1d2bb75723741461b47b70825fe3475cf9531127 100644 --- a/arch/x86/events/intel/pt.h +++ b/arch/x86/events/intel/pt.h @@ -53,7 +53,6 @@ struct pt_pmu { /** * struct pt_buffer - buffer configuration; one buffer per task_struct or * cpu, depending on perf event configuration - * @cpu: cpu for per-cpu allocation * @tables: list of ToPA tables in this buffer * @first: shorthand for first topa table * @last: shorthand for last topa table @@ -65,13 +64,14 @@ struct pt_pmu { * @lost: if data was lost/truncated * @head: logical write offset inside the buffer * @snapshot: if this is for a snapshot/overwrite counter - * @stop_pos: STOP topa entry in the buffer - * @intr_pos: INT topa entry in the buffer + * @stop_pos: STOP topa entry index + * @intr_pos: INT topa entry index + * @stop_te: STOP topa entry pointer + * @intr_te: INT topa entry pointer * @data_pages: array of pages from perf * @topa_index: table of topa entries indexed by page offset */ struct pt_buffer { - int cpu; struct list_head tables; struct topa *first, *last, *cur; unsigned int cur_idx; @@ -80,9 +80,9 @@ struct pt_buffer { local_t data_size; local64_t head; bool snapshot; - unsigned long stop_pos, intr_pos; + long stop_pos, intr_pos; + struct topa_entry *stop_te, *intr_te; void **data_pages; - struct topa_entry *topa_index[0]; }; #define PT_FILTERS_NUM 4 diff --git a/arch/x86/events/intel/rapl.c b/arch/x86/events/intel/rapl.c index 64ab51ffdf06308c22dba65134d654c599f07c22..5053a403e4ae0e9e9bea4831fa01b33696c5b9f5 100644 --- a/arch/x86/events/intel/rapl.c +++ b/arch/x86/events/intel/rapl.c @@ -634,7 +634,7 @@ static void cleanup_rapl_pmus(void) kfree(rapl_pmus); } -const struct attribute_group *rapl_attr_update[] = { +static const struct attribute_group *rapl_attr_update[] = { &rapl_events_cores_group, &rapl_events_pkg_group, &rapl_events_ram_group, @@ -720,27 +720,27 @@ static const struct x86_cpu_id rapl_model_match[] __initconst = { X86_RAPL_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE_X, model_snbep), X86_RAPL_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE, model_snb), X86_RAPL_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE_X, model_snbep), - X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_CORE, model_hsw), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL, model_hsw), X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_X, model_hsx), - X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_ULT, model_hsw), - X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_GT3E, model_hsw), - X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_CORE, model_hsw), - X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_GT3E, model_hsw), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_L, model_hsw), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_G, model_hsw), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL, model_hsw), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_G, model_hsw), X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_X, model_hsx), - X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_XEON_D, model_hsx), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_D, model_hsx), X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL, model_knl), X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNM, model_knl), - X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_MOBILE, model_skl), - X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_DESKTOP, model_skl), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_L, model_skl), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE, model_skl), X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_X, model_hsx), - X86_RAPL_MODEL_MATCH(INTEL_FAM6_KABYLAKE_MOBILE, model_skl), - X86_RAPL_MODEL_MATCH(INTEL_FAM6_KABYLAKE_DESKTOP, model_skl), - X86_RAPL_MODEL_MATCH(INTEL_FAM6_CANNONLAKE_MOBILE, model_skl), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_KABYLAKE_L, model_skl), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_KABYLAKE, model_skl), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_CANNONLAKE_L, model_skl), X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT, model_hsw), - X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT_X, model_hsw), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT_D, model_hsw), X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT_PLUS, model_hsw), - X86_RAPL_MODEL_MATCH(INTEL_FAM6_ICELAKE_MOBILE, model_skl), - X86_RAPL_MODEL_MATCH(INTEL_FAM6_ICELAKE_DESKTOP, model_skl), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_ICELAKE_L, model_skl), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_ICELAKE, model_skl), {}, }; diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c index 3694a5d0703d9f4126563e6d5454f553d3162432..6fc2e06ab4c6f9dfa45feb6f8762c97546203b2d 100644 --- a/arch/x86/events/intel/uncore.c +++ b/arch/x86/events/intel/uncore.c @@ -1451,29 +1451,29 @@ static const struct x86_cpu_id intel_uncore_match[] __initconst = { X86_UNCORE_MODEL_MATCH(INTEL_FAM6_WESTMERE_EP, nhm_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE, snb_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE, ivb_uncore_init), - X86_UNCORE_MODEL_MATCH(INTEL_FAM6_HASWELL_CORE, hsw_uncore_init), - X86_UNCORE_MODEL_MATCH(INTEL_FAM6_HASWELL_ULT, hsw_uncore_init), - X86_UNCORE_MODEL_MATCH(INTEL_FAM6_HASWELL_GT3E, hsw_uncore_init), - X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_CORE, bdw_uncore_init), - X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_GT3E, bdw_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_HASWELL, hsw_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_HASWELL_L, hsw_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_HASWELL_G, hsw_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL, bdw_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_G, bdw_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE_X, snbep_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_NEHALEM_EX, nhmex_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_WESTMERE_EX, nhmex_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE_X, ivbep_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_HASWELL_X, hswep_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_X, bdx_uncore_init), - X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_XEON_D, bdx_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_D, bdx_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL, knl_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNM, knl_uncore_init), - X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_DESKTOP,skl_uncore_init), - X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_MOBILE, skl_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE, skl_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_L, skl_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_X, skx_uncore_init), - X86_UNCORE_MODEL_MATCH(INTEL_FAM6_KABYLAKE_MOBILE, skl_uncore_init), - X86_UNCORE_MODEL_MATCH(INTEL_FAM6_KABYLAKE_DESKTOP, skl_uncore_init), - X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ICELAKE_MOBILE, icl_uncore_init), - X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ICELAKE_NNPI, icl_uncore_init), - X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ICELAKE_DESKTOP, icl_uncore_init), - X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ATOM_TREMONT_X, snr_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_KABYLAKE_L, skl_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_KABYLAKE, skl_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ICELAKE_L, icl_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ICELAKE_NNPI, icl_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ICELAKE, icl_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ATOM_TREMONT_D, snr_uncore_init), {}, }; diff --git a/arch/x86/events/msr.c b/arch/x86/events/msr.c index 9431447541e9707d54b74aa04dcae34cce670ee2..b1afc77f0704481157cd4c3cafbecfbb31a86136 100644 --- a/arch/x86/events/msr.c +++ b/arch/x86/events/msr.c @@ -59,22 +59,22 @@ static bool test_intel(int idx, void *data) case INTEL_FAM6_IVYBRIDGE: case INTEL_FAM6_IVYBRIDGE_X: - case INTEL_FAM6_HASWELL_CORE: + case INTEL_FAM6_HASWELL: case INTEL_FAM6_HASWELL_X: - case INTEL_FAM6_HASWELL_ULT: - case INTEL_FAM6_HASWELL_GT3E: + case INTEL_FAM6_HASWELL_L: + case INTEL_FAM6_HASWELL_G: - case INTEL_FAM6_BROADWELL_CORE: - case INTEL_FAM6_BROADWELL_XEON_D: - case INTEL_FAM6_BROADWELL_GT3E: + case INTEL_FAM6_BROADWELL: + case INTEL_FAM6_BROADWELL_D: + case INTEL_FAM6_BROADWELL_G: case INTEL_FAM6_BROADWELL_X: case INTEL_FAM6_ATOM_SILVERMONT: - case INTEL_FAM6_ATOM_SILVERMONT_X: + case INTEL_FAM6_ATOM_SILVERMONT_D: case INTEL_FAM6_ATOM_AIRMONT: case INTEL_FAM6_ATOM_GOLDMONT: - case INTEL_FAM6_ATOM_GOLDMONT_X: + case INTEL_FAM6_ATOM_GOLDMONT_D: case INTEL_FAM6_ATOM_GOLDMONT_PLUS: @@ -84,12 +84,12 @@ static bool test_intel(int idx, void *data) return true; break; - case INTEL_FAM6_SKYLAKE_MOBILE: - case INTEL_FAM6_SKYLAKE_DESKTOP: + case INTEL_FAM6_SKYLAKE_L: + case INTEL_FAM6_SKYLAKE: case INTEL_FAM6_SKYLAKE_X: - case INTEL_FAM6_KABYLAKE_MOBILE: - case INTEL_FAM6_KABYLAKE_DESKTOP: - case INTEL_FAM6_ICELAKE_MOBILE: + case INTEL_FAM6_KABYLAKE_L: + case INTEL_FAM6_KABYLAKE: + case INTEL_FAM6_ICELAKE_L: if (idx == PERF_MSR_SMI || idx == PERF_MSR_PPERF) return true; break; @@ -167,7 +167,7 @@ static const struct attribute_group *attr_groups[] = { NULL, }; -const struct attribute_group *attr_update[] = { +static const struct attribute_group *attr_update[] = { &group_aperf, &group_mperf, &group_pperf, diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index 8751008fc1703d231168ebfbcd4b1ed1107bb6f7..ecacfbf4ebc12c6fa3d64139f7cdf90ef02c76e1 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -76,6 +76,7 @@ static inline bool constraint_match(struct event_constraint *c, u64 ecode) #define PERF_X86_EVENT_EXCL_ACCT 0x0100 /* accounted EXCL event */ #define PERF_X86_EVENT_AUTO_RELOAD 0x0200 /* use PEBS auto-reload */ #define PERF_X86_EVENT_LARGE_PEBS 0x0400 /* use large PEBS */ +#define PERF_X86_EVENT_PEBS_VIA_PT 0x0800 /* use PT buffer for PEBS */ struct amd_nb { int nb_id; /* NorthBridge id */ @@ -85,6 +86,11 @@ struct amd_nb { }; #define PEBS_COUNTER_MASK ((1ULL << MAX_PEBS_EVENTS) - 1) +#define PEBS_PMI_AFTER_EACH_RECORD BIT_ULL(60) +#define PEBS_OUTPUT_OFFSET 61 +#define PEBS_OUTPUT_MASK (3ull << PEBS_OUTPUT_OFFSET) +#define PEBS_OUTPUT_PT (1ull << PEBS_OUTPUT_OFFSET) +#define PEBS_VIA_PT_MASK (PEBS_OUTPUT_PT | PEBS_PMI_AFTER_EACH_RECORD) /* * Flags PEBS can handle without an PMI. @@ -211,6 +217,8 @@ struct cpu_hw_events { u64 pebs_enabled; int n_pebs; int n_large_pebs; + int n_pebs_via_pt; + int pebs_output; /* Current super set of events hardware configuration */ u64 pebs_data_cfg; @@ -510,6 +518,8 @@ union perf_capabilities { */ u64 full_width_write:1; u64 pebs_baseline:1; + u64 pebs_metrics_available:1; + u64 pebs_output_pt_available:1; }; u64 capabilities; }; @@ -692,6 +702,8 @@ struct x86_pmu { * Check period value for PERF_EVENT_IOC_PERIOD ioctl. */ int (*check_period) (struct perf_event *event, u64 period); + + int (*aux_output_match) (struct perf_event *event); }; struct x86_perf_task_context { @@ -901,6 +913,11 @@ static inline int amd_pmu_init(void) #endif /* CONFIG_CPU_SUP_AMD */ +static inline int is_pebs_pt(struct perf_event *event) +{ + return !!(event->hw.flags & PERF_X86_EVENT_PEBS_VIA_PT); +} + #ifdef CONFIG_CPU_SUP_INTEL static inline bool intel_pmu_has_bts_period(struct perf_event *event, u64 period) diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c index 0d258688c8cf2ad7c12f1db3b63fc158b55e5f14..2db3972c0e0ff047621cb6ab173e34ec914e257b 100644 --- a/arch/x86/hyperv/hv_init.c +++ b/arch/x86/hyperv/hv_init.c @@ -37,6 +37,20 @@ EXPORT_SYMBOL_GPL(hyperv_pcpu_input_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_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; @@ -301,8 +315,6 @@ void __init hyperv_init(void) x86_init.pci.arch_init = hv_pci_init; - /* Register Hyper-V specific clocksource */ - hv_init_clocksource(); return; remove_cpuhp_state: diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index e647aa095867f292bdeb53a446ece659aa717157..2ebc17d9c72cddb06827afa038243dd56e1a3cd7 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -136,6 +136,7 @@ extern int lapic_get_maxlvt(void); extern void clear_local_APIC(void); extern void disconnect_bsp_APIC(int virt_wire_setup); extern void disable_local_APIC(void); +extern void apic_soft_disable(void); extern void lapic_shutdown(void); extern void sync_Arb_IDs(void); extern void init_bsp_APIC(void); @@ -176,6 +177,8 @@ extern void lapic_online(void); extern void lapic_offline(void); extern bool apic_needs_pit(void); +extern void apic_send_IPI_allbutself(unsigned int vector); + #else /* !CONFIG_X86_LOCAL_APIC */ static inline void lapic_shutdown(void) { } #define local_apic_timer_c2_ok 1 @@ -465,12 +468,6 @@ static inline unsigned default_get_apic_id(unsigned long x) #define TRAMPOLINE_PHYS_LOW 0x467 #define TRAMPOLINE_PHYS_HIGH 0x469 -#ifdef CONFIG_X86_64 -extern void apic_send_IPI_self(int vector); - -DECLARE_PER_CPU(int, x2apic_extra_bits); -#endif - extern void generic_bigsmp_probe(void); #ifdef CONFIG_X86_LOCAL_APIC @@ -506,8 +503,10 @@ extern int default_check_phys_apicid_present(int phys_apicid); #ifdef CONFIG_SMP bool apic_id_is_primary_thread(unsigned int id); +void apic_smt_update(void); #else static inline bool apic_id_is_primary_thread(unsigned int id) { return false; } +static inline void apic_smt_update(void) { } #endif extern void irq_enter(void); diff --git a/arch/x86/include/asm/apic_flat_64.h b/arch/x86/include/asm/apic_flat_64.h deleted file mode 100644 index d3a2b3876ce69b94308daa4c703ff2b966baf97b..0000000000000000000000000000000000000000 --- a/arch/x86/include/asm/apic_flat_64.h +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_X86_APIC_FLAT_64_H -#define _ASM_X86_APIC_FLAT_64_H - -extern void flat_init_apic_ldr(void); - -#endif - diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h index 84f848c2541a6e5febb218fc64d209270c80e9bc..7f828fe497978e3132a2c6d87786d02029719fd2 100644 --- a/arch/x86/include/asm/barrier.h +++ b/arch/x86/include/asm/barrier.h @@ -49,8 +49,7 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, #define array_index_mask_nospec array_index_mask_nospec /* Prevent speculative execution past this barrier. */ -#define barrier_nospec() alternative_2("", "mfence", X86_FEATURE_MFENCE_RDTSC, \ - "lfence", X86_FEATURE_LFENCE_RDTSC) +#define barrier_nospec() alternative("", "lfence", X86_FEATURE_LFENCE_RDTSC) #define dma_rmb() barrier() #define dma_wmb() barrier() diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h index ba15d53c1ca7eee3d726089fab57155e00a57aad..7d1f6a49bfae1192d25a672e34a438ca65288a89 100644 --- a/arch/x86/include/asm/bitops.h +++ b/arch/x86/include/asm/bitops.h @@ -45,14 +45,13 @@ * We do the locked ops that don't return the old value as * a mask operation on a byte. */ -#define IS_IMMEDIATE(nr) (__builtin_constant_p(nr)) #define CONST_MASK_ADDR(nr, addr) WBYTE_ADDR((void *)(addr) + ((nr)>>3)) #define CONST_MASK(nr) (1 << ((nr) & 7)) static __always_inline void arch_set_bit(long nr, volatile unsigned long *addr) { - if (IS_IMMEDIATE(nr)) { + if (__builtin_constant_p(nr)) { asm volatile(LOCK_PREFIX "orb %1,%0" : CONST_MASK_ADDR(nr, addr) : "iq" ((u8)CONST_MASK(nr)) @@ -72,7 +71,7 @@ arch___set_bit(long nr, volatile unsigned long *addr) static __always_inline void arch_clear_bit(long nr, volatile unsigned long *addr) { - if (IS_IMMEDIATE(nr)) { + if (__builtin_constant_p(nr)) { asm volatile(LOCK_PREFIX "andb %1,%0" : CONST_MASK_ADDR(nr, addr) : "iq" ((u8)~CONST_MASK(nr))); @@ -123,7 +122,7 @@ arch___change_bit(long nr, volatile unsigned long *addr) static __always_inline void arch_change_bit(long nr, volatile unsigned long *addr) { - if (IS_IMMEDIATE(nr)) { + if (__builtin_constant_p(nr)) { asm volatile(LOCK_PREFIX "xorb %1,%0" : CONST_MASK_ADDR(nr, addr) : "iq" ((u8)CONST_MASK(nr))); diff --git a/arch/x86/include/asm/bugs.h b/arch/x86/include/asm/bugs.h index 542509b53e0f5f1f0d6b8d65fc5b82dd5305fb32..794eb2129bc6b97f2e254a4d4871d7ea6747a2a5 100644 --- a/arch/x86/include/asm/bugs.h +++ b/arch/x86/include/asm/bugs.h @@ -18,4 +18,6 @@ int ppro_with_ram_bug(void); static inline int ppro_with_ram_bug(void) { return 0; } #endif +extern void cpu_bugs_smt_update(void); + #endif /* _ASM_X86_BUGS_H */ diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index c636a148f71fef2838deee306e1d9154d1f14713..48670eb3b4d74690443917d18410e317ccec0ed2 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -61,6 +61,13 @@ extern const char * const x86_bug_flags[NBUGINTS*32]; #define CHECK_BIT_IN_MASK_WORD(maskname, word, bit) \ (((bit)>>5)==(word) && (1UL<<((bit)&31) & maskname##word )) +/* + * {REQUIRED,DISABLED}_MASK_CHECK below may seem duplicated with the + * following BUILD_BUG_ON_ZERO() check but when NCAPINTS gets changed, all + * header macros which use NCAPINTS need to be changed. The duplicated macro + * use causes the compiler to issue errors for all headers so that all usage + * sites can be corrected. + */ #define REQUIRED_MASK_BIT_SET(feature_bit) \ ( CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 0, feature_bit) || \ CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 1, feature_bit) || \ diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index e880f2408e29d5e56bb659d851ccb254cc9a148e..0652d3eed9bda96828657cba8250cdc9903a2469 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -96,7 +96,6 @@ #define X86_FEATURE_SYSCALL32 ( 3*32+14) /* "" syscall in IA32 userspace */ #define X86_FEATURE_SYSENTER32 ( 3*32+15) /* "" sysenter in IA32 userspace */ #define X86_FEATURE_REP_GOOD ( 3*32+16) /* REP microcode works well */ -#define X86_FEATURE_MFENCE_RDTSC ( 3*32+17) /* "" MFENCE synchronizes RDTSC */ #define X86_FEATURE_LFENCE_RDTSC ( 3*32+18) /* "" LFENCE synchronizes RDTSC */ #define X86_FEATURE_ACC_POWER ( 3*32+19) /* AMD Accumulated Power Mechanism */ #define X86_FEATURE_NOPL ( 3*32+20) /* The NOPL (0F 1F) instructions */ @@ -232,6 +231,8 @@ #define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer VMMCALL to VMCALL */ #define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */ #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 */ /* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */ #define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/ @@ -355,6 +356,7 @@ /* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */ #define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */ #define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */ +#define X86_FEATURE_AVX512_VP2INTERSECT (18*32+ 8) /* AVX-512 Intersect for D/Q */ #define X86_FEATURE_MD_CLEAR (18*32+10) /* VERW clears CPU buffers */ #define X86_FEATURE_TSX_FORCE_ABORT (18*32+13) /* "" TSX_FORCE_ABORT */ #define X86_FEATURE_PCONFIG (18*32+18) /* Intel PCONFIG */ diff --git a/arch/x86/include/asm/cpuidle_haltpoll.h b/arch/x86/include/asm/cpuidle_haltpoll.h new file mode 100644 index 0000000000000000000000000000000000000000..c8b39c6716ff1798ab3e1391722e9b4f99aab2aa --- /dev/null +++ b/arch/x86/include/asm/cpuidle_haltpoll.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ARCH_HALTPOLL_H +#define _ARCH_HALTPOLL_H + +void arch_haltpoll_enable(unsigned int cpu); +void arch_haltpoll_disable(unsigned int cpu); + +#endif diff --git a/arch/x86/include/asm/crypto/aes.h b/arch/x86/include/asm/crypto/aes.h deleted file mode 100644 index c508521dd190fff3c4685fe23865ac358b21e182..0000000000000000000000000000000000000000 --- a/arch/x86/include/asm/crypto/aes.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef ASM_X86_AES_H -#define ASM_X86_AES_H - -#include -#include - -void crypto_aes_encrypt_x86(struct crypto_aes_ctx *ctx, u8 *dst, - const u8 *src); -void crypto_aes_decrypt_x86(struct crypto_aes_ctx *ctx, u8 *dst, - const u8 *src); -#endif diff --git a/arch/x86/include/asm/crypto/glue_helper.h b/arch/x86/include/asm/crypto/glue_helper.h index d1818634ae7ee921c1ef665f3b966a93821990d8..8d4a8e1226ee308eae62cc65a9dbad7e138411a6 100644 --- a/arch/x86/include/asm/crypto/glue_helper.h +++ b/arch/x86/include/asm/crypto/glue_helper.h @@ -114,7 +114,7 @@ extern int glue_ctr_req_128bit(const struct common_glue_ctx *gctx, extern int glue_xts_req_128bit(const struct common_glue_ctx *gctx, struct skcipher_request *req, common_glue_func_t tweak_fn, void *tweak_ctx, - void *crypt_ctx); + void *crypt_ctx, bool decrypt); extern void glue_xts_crypt_128bit_one(void *ctx, u128 *dst, const u128 *src, le128 *iv, common_glue_func_t fn); diff --git a/arch/x86/include/asm/div64.h b/arch/x86/include/asm/div64.h index 20a46150e0a86856dcce1f8727627cf982a4208b..9b8cb50768c27956840b13422ec5eb28d3976a6f 100644 --- a/arch/x86/include/asm/div64.h +++ b/arch/x86/include/asm/div64.h @@ -73,6 +73,19 @@ static inline u64 mul_u32_u32(u32 a, u32 b) #else # include + +static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 div) +{ + u64 q; + + asm ("mulq %2; divq %3" : "=a" (q) + : "a" (a), "rm" ((u64)mul), "rm" ((u64)div) + : "rdx"); + + return q; +} +#define mul_u64_u32_div mul_u64_u32_div + #endif /* CONFIG_X86_32 */ #endif /* _ASM_X86_DIV64_H */ diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 606a4b6a9812c3128a5d70fbcac1ef00f7fa0bbb..43a82e59c59d2657d9e319361e7285a15da2fac7 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -242,6 +242,7 @@ static inline bool efi_is_64bit(void) __efi_early()->runtime_services), __VA_ARGS__) extern bool efi_reboot_required(void); +extern bool efi_is_table_address(unsigned long phys_addr); #else static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {} @@ -249,6 +250,10 @@ static inline bool efi_reboot_required(void) { return false; } +static inline bool efi_is_table_address(unsigned long phys_addr) +{ + return false; +} #endif /* CONFIG_EFI */ #endif /* _ASM_X86_EFI_H */ diff --git a/arch/x86/include/asm/error-injection.h b/arch/x86/include/asm/error-injection.h deleted file mode 100644 index 47b7a1296245edc0698d46786dc13ed48e659c48..0000000000000000000000000000000000000000 --- a/arch/x86/include/asm/error-injection.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_ERROR_INJECTION_H -#define _ASM_ERROR_INJECTION_H - -#include -#include -#include -#include - -asmlinkage void just_return_func(void); -void override_function_with_return(struct pt_regs *regs); - -#endif /* _ASM_ERROR_INJECTION_H */ diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index 9da8cccdf3fb59d2fa9eb0f895f261709bc50102..0c47aa82e2e22ff01ca7ecced5dda7f5e41f971e 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h @@ -42,8 +42,7 @@ * Because of this, FIXADDR_TOP x86 integration was left as later work. */ #ifdef CONFIG_X86_32 -/* used by vmalloc.c, vsyscall.lds.S. - * +/* * Leave one empty page between vmalloc'ed areas and * the start of the fixmap. */ @@ -120,7 +119,7 @@ enum fixed_addresses { * before ioremap() is functional. * * If necessary we round it up to the next 512 pages boundary so - * that we can have a single pgd entry and a single pte table: + * that we can have a single pmd entry and a single pte table: */ #define NR_FIX_BTMAPS 64 #define FIX_BTMAPS_SLOTS 8 diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index cbd97e22d2f3197053f785dd45f59e08448e7d6a..4154bc5f6a4ed075952e60d6042889d964649a1c 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h @@ -153,8 +153,8 @@ extern char irq_entries_start[]; extern char spurious_entries_start[]; #define VECTOR_UNUSED NULL -#define VECTOR_SHUTDOWN ((void *)~0UL) -#define VECTOR_RETRIGGERED ((void *)~1UL) +#define VECTOR_SHUTDOWN ((void *)-1L) +#define VECTOR_RETRIGGERED ((void *)-2L) typedef struct irq_desc* vector_irq_t[NR_VECTORS]; DECLARE_PER_CPU(vector_irq_t, vector_irq); diff --git a/arch/x86/include/asm/hyperv-tlfs.h b/arch/x86/include/asm/hyperv-tlfs.h index af78cd72b8f340a5d00d32e0fdd2ea5b80758365..7a2705694f5b1363c277325cac649dd9675762fd 100644 --- a/arch/x86/include/asm/hyperv-tlfs.h +++ b/arch/x86/include/asm/hyperv-tlfs.h @@ -12,6 +12,16 @@ #include #include +/* + * While not explicitly listed in the TLFS, Hyper-V always runs with a page size + * of 4096. These definitions are used when communicating with Hyper-V using + * guest physical pages and guest physical page addresses, since the guest page + * size may not be 4096 on all architectures. + */ +#define HV_HYP_PAGE_SHIFT 12 +#define HV_HYP_PAGE_SIZE BIT(HV_HYP_PAGE_SHIFT) +#define HV_HYP_PAGE_MASK (~(HV_HYP_PAGE_SIZE - 1)) + /* * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent * is set by CPUID(HvCpuIdFunctionVersionAndFeatures). @@ -847,7 +857,7 @@ union hv_gpa_page_range { * count is equal with how many entries of union hv_gpa_page_range can * be populated into the input parameter page. */ -#define HV_MAX_FLUSH_REP_COUNT ((PAGE_SIZE - 2 * sizeof(u64)) / \ +#define HV_MAX_FLUSH_REP_COUNT ((HV_HYP_PAGE_SIZE - 2 * sizeof(u64)) / \ sizeof(union hv_gpa_page_range)) struct hv_guest_mapping_flush_list { diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h index fe7c205233f1cbb8fcccb7ec413c9322a19cc94c..f04622500da396ff87f63bac499abbb3d901409d 100644 --- a/arch/x86/include/asm/intel-family.h +++ b/arch/x86/include/asm/intel-family.h @@ -5,9 +5,6 @@ /* * "Big Core" Processors (Branded as Core, Xeon, etc...) * - * The "_X" parts are generally the EP and EX Xeons, or the - * "Extreme" ones, like Broadwell-E, or Atom microserver. - * * While adding a new CPUID for a new microarchitecture, add a new * group to keep logically sorted out in chronological order. Within * that group keep the CPUID for the variants sorted by model number. @@ -21,9 +18,19 @@ * MICROARCH Is the code name for the micro-architecture for this core. * N.B. Not the platform name. * OPTDIFF If needed, a short string to differentiate by market segment. - * Exact strings here will vary over time. _DESKTOP, _MOBILE, and - * _X (short for Xeon server) should be used when they are - * appropriate. + * + * Common OPTDIFFs: + * + * - regular client parts + * _L - regular mobile parts + * _G - parts with extra graphics on + * _X - regular server parts + * _D - micro server parts + * + * Historical OPTDIFFs: + * + * _EP - 2 socket server parts + * _EX - 4+ socket server parts * * The #define line may optionally include a comment including platform names. */ @@ -49,30 +56,33 @@ #define INTEL_FAM6_IVYBRIDGE 0x3A #define INTEL_FAM6_IVYBRIDGE_X 0x3E -#define INTEL_FAM6_HASWELL_CORE 0x3C +#define INTEL_FAM6_HASWELL 0x3C #define INTEL_FAM6_HASWELL_X 0x3F -#define INTEL_FAM6_HASWELL_ULT 0x45 -#define INTEL_FAM6_HASWELL_GT3E 0x46 +#define INTEL_FAM6_HASWELL_L 0x45 +#define INTEL_FAM6_HASWELL_G 0x46 -#define INTEL_FAM6_BROADWELL_CORE 0x3D -#define INTEL_FAM6_BROADWELL_GT3E 0x47 +#define INTEL_FAM6_BROADWELL 0x3D +#define INTEL_FAM6_BROADWELL_G 0x47 #define INTEL_FAM6_BROADWELL_X 0x4F -#define INTEL_FAM6_BROADWELL_XEON_D 0x56 +#define INTEL_FAM6_BROADWELL_D 0x56 -#define INTEL_FAM6_SKYLAKE_MOBILE 0x4E -#define INTEL_FAM6_SKYLAKE_DESKTOP 0x5E +#define INTEL_FAM6_SKYLAKE_L 0x4E +#define INTEL_FAM6_SKYLAKE 0x5E #define INTEL_FAM6_SKYLAKE_X 0x55 -#define INTEL_FAM6_KABYLAKE_MOBILE 0x8E -#define INTEL_FAM6_KABYLAKE_DESKTOP 0x9E +#define INTEL_FAM6_KABYLAKE_L 0x8E +#define INTEL_FAM6_KABYLAKE 0x9E -#define INTEL_FAM6_CANNONLAKE_MOBILE 0x66 +#define INTEL_FAM6_CANNONLAKE_L 0x66 #define INTEL_FAM6_ICELAKE_X 0x6A -#define INTEL_FAM6_ICELAKE_XEON_D 0x6C -#define INTEL_FAM6_ICELAKE_DESKTOP 0x7D -#define INTEL_FAM6_ICELAKE_MOBILE 0x7E +#define INTEL_FAM6_ICELAKE_D 0x6C +#define INTEL_FAM6_ICELAKE 0x7D +#define INTEL_FAM6_ICELAKE_L 0x7E #define INTEL_FAM6_ICELAKE_NNPI 0x9D +#define INTEL_FAM6_TIGERLAKE_L 0x8C +#define INTEL_FAM6_TIGERLAKE 0x8D + /* "Small Core" Processors (Atom) */ #define INTEL_FAM6_ATOM_BONNELL 0x1C /* Diamondville, Pineview */ @@ -83,17 +93,21 @@ #define INTEL_FAM6_ATOM_SALTWELL_TABLET 0x35 /* Cloverview */ #define INTEL_FAM6_ATOM_SILVERMONT 0x37 /* Bay Trail, Valleyview */ -#define INTEL_FAM6_ATOM_SILVERMONT_X 0x4D /* Avaton, Rangely */ +#define INTEL_FAM6_ATOM_SILVERMONT_D 0x4D /* Avaton, Rangely */ #define INTEL_FAM6_ATOM_SILVERMONT_MID 0x4A /* Merriefield */ #define INTEL_FAM6_ATOM_AIRMONT 0x4C /* Cherry Trail, Braswell */ #define INTEL_FAM6_ATOM_AIRMONT_MID 0x5A /* Moorefield */ +#define INTEL_FAM6_ATOM_AIRMONT_NP 0x75 /* Lightning Mountain */ #define INTEL_FAM6_ATOM_GOLDMONT 0x5C /* Apollo Lake */ -#define INTEL_FAM6_ATOM_GOLDMONT_X 0x5F /* Denverton */ +#define INTEL_FAM6_ATOM_GOLDMONT_D 0x5F /* Denverton */ + +/* Note: the micro-architecture is "Goldmont Plus" */ #define INTEL_FAM6_ATOM_GOLDMONT_PLUS 0x7A /* Gemini Lake */ -#define INTEL_FAM6_ATOM_TREMONT_X 0x86 /* Jacobsville */ +#define INTEL_FAM6_ATOM_TREMONT_D 0x86 /* Jacobsville */ +#define INTEL_FAM6_ATOM_TREMONT 0x96 /* Elkhart Lake */ /* Xeon Phi */ diff --git a/arch/x86/include/asm/intel_pt.h b/arch/x86/include/asm/intel_pt.h index 634f99b1dc22e8b584364c7544f787ab1d68641f..423b788f495e92ce8b059509c84feedbb66d9e37 100644 --- a/arch/x86/include/asm/intel_pt.h +++ b/arch/x86/include/asm/intel_pt.h @@ -28,10 +28,12 @@ enum pt_capabilities { void cpu_emergency_stop_pt(void); extern u32 intel_pt_validate_hw_cap(enum pt_capabilities cap); extern u32 intel_pt_validate_cap(u32 *caps, enum pt_capabilities cap); +extern int is_intel_pt_event(struct perf_event *event); #else static inline void cpu_emergency_stop_pt(void) {} static inline u32 intel_pt_validate_hw_cap(enum pt_capabilities cap) { return 0; } static inline u32 intel_pt_validate_cap(u32 *caps, enum pt_capabilities capability) { return 0; } +static inline int is_intel_pt_event(struct perf_event *event) { return 0; } #endif #endif /* _ASM_X86_INTEL_PT_H */ diff --git a/arch/x86/include/asm/iommu.h b/arch/x86/include/asm/iommu.h index baedab8ac5385f7d40ccbe7f17e583f8589bdb49..b91623d521d9f0ffeb23e825221353cba05e0ced 100644 --- a/arch/x86/include/asm/iommu.h +++ b/arch/x86/include/asm/iommu.h @@ -4,7 +4,6 @@ extern int force_iommu, no_iommu; extern int iommu_detected; -extern int iommu_pass_through; /* 10 seconds */ #define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) diff --git a/arch/x86/include/asm/ipi.h b/arch/x86/include/asm/ipi.h deleted file mode 100644 index f73076be546ac321d6ff5a948d16d6a922b16130..0000000000000000000000000000000000000000 --- a/arch/x86/include/asm/ipi.h +++ /dev/null @@ -1,109 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -#ifndef _ASM_X86_IPI_H -#define _ASM_X86_IPI_H - -#ifdef CONFIG_X86_LOCAL_APIC - -/* - * Copyright 2004 James Cleverdon, IBM. - * - * Generic APIC InterProcessor Interrupt code. - * - * Moved to include file by James Cleverdon from - * arch/x86-64/kernel/smp.c - * - * Copyrights from kernel/smp.c: - * - * (c) 1995 Alan Cox, Building #3 - * (c) 1998-99, 2000 Ingo Molnar - * (c) 2002,2003 Andi Kleen, SuSE Labs. - */ - -#include -#include -#include - -/* - * the following functions deal with sending IPIs between CPUs. - * - * We use 'broadcast', CPU->CPU IPIs and self-IPIs too. - */ - -static inline unsigned int __prepare_ICR(unsigned int shortcut, int vector, - unsigned int dest) -{ - unsigned int icr = shortcut | dest; - - switch (vector) { - default: - icr |= APIC_DM_FIXED | vector; - break; - case NMI_VECTOR: - icr |= APIC_DM_NMI; - break; - } - return icr; -} - -static inline int __prepare_ICR2(unsigned int mask) -{ - return SET_APIC_DEST_FIELD(mask); -} - -static inline void __xapic_wait_icr_idle(void) -{ - while (native_apic_mem_read(APIC_ICR) & APIC_ICR_BUSY) - cpu_relax(); -} - -void __default_send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest); - -/* - * This is used to send an IPI with no shorthand notation (the destination is - * specified in bits 56 to 63 of the ICR). - */ -void __default_send_IPI_dest_field(unsigned int mask, int vector, unsigned int dest); - -extern void default_send_IPI_single(int cpu, int vector); -extern void default_send_IPI_single_phys(int cpu, int vector); -extern void default_send_IPI_mask_sequence_phys(const struct cpumask *mask, - int vector); -extern void default_send_IPI_mask_allbutself_phys(const struct cpumask *mask, - int vector); - -/* Avoid include hell */ -#define NMI_VECTOR 0x02 - -extern int no_broadcast; - -static inline void __default_local_send_IPI_allbutself(int vector) -{ - if (no_broadcast || vector == NMI_VECTOR) - apic->send_IPI_mask_allbutself(cpu_online_mask, vector); - else - __default_send_IPI_shortcut(APIC_DEST_ALLBUT, vector, apic->dest_logical); -} - -static inline void __default_local_send_IPI_all(int vector) -{ - if (no_broadcast || vector == NMI_VECTOR) - apic->send_IPI_mask(cpu_online_mask, vector); - else - __default_send_IPI_shortcut(APIC_DEST_ALLINC, vector, apic->dest_logical); -} - -#ifdef CONFIG_X86_32 -extern void default_send_IPI_mask_sequence_logical(const struct cpumask *mask, - int vector); -extern void default_send_IPI_mask_allbutself_logical(const struct cpumask *mask, - int vector); -extern void default_send_IPI_mask_logical(const struct cpumask *mask, - int vector); -extern void default_send_IPI_allbutself(int vector); -extern void default_send_IPI_all(int vector); -extern void default_send_IPI_self(int vector); -#endif - -#endif - -#endif /* _ASM_X86_IPI_H */ diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h index 8f95686ec27e09662c1be58e2b6cb0d5aa79c67f..a176f6165d85b12e8d52e83eef6402c7148885b9 100644 --- a/arch/x86/include/asm/irq.h +++ b/arch/x86/include/asm/irq.h @@ -34,7 +34,7 @@ extern __visible void smp_kvm_posted_intr_nested_ipi(struct pt_regs *regs); extern void (*x86_platform_ipi_callback)(void); extern void native_init_IRQ(void); -extern bool handle_irq(struct irq_desc *desc, struct pt_regs *regs); +extern void handle_irq(struct irq_desc *desc, struct pt_regs *regs); extern __visible unsigned int do_IRQ(struct pt_regs *regs); diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index feab24cac610e25f276d3d1f71f4705c23106b00..77cf6c11f66bd86341ef58f5503d68b24e3b6833 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h @@ -229,7 +229,7 @@ struct x86_emulate_ops { int (*pre_leave_smm)(struct x86_emulate_ctxt *ctxt, const char *smstate); void (*post_leave_smm)(struct x86_emulate_ctxt *ctxt); - + int (*set_xcr)(struct x86_emulate_ctxt *ctxt, u32 index, u64 xcr); }; typedef u32 __attribute__((vector_size(16))) sse128_t; @@ -429,6 +429,7 @@ enum x86_intercept { x86_intercept_ins, x86_intercept_out, x86_intercept_outs, + x86_intercept_xsetbv, nr_x86_intercepts }; diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index bdc16b0aa7c6f8846a0c6864f3d098592542892c..a3a3ec73fa2f858073bf0eeadb7b89574093bc69 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -718,7 +718,7 @@ struct kvm_vcpu_arch { /* Cache MMIO info */ u64 mmio_gva; - unsigned access; + unsigned mmio_access; gfn_t mmio_gfn; u64 mmio_gen; @@ -1072,7 +1072,7 @@ struct kvm_x86_ops { void (*run)(struct kvm_vcpu *vcpu); int (*handle_exit)(struct kvm_vcpu *vcpu); - void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu); + int (*skip_emulated_instruction)(struct kvm_vcpu *vcpu); void (*set_interrupt_shadow)(struct kvm_vcpu *vcpu, int mask); u32 (*get_interrupt_shadow)(struct kvm_vcpu *vcpu); void (*patch_hypercall)(struct kvm_vcpu *vcpu, @@ -1211,6 +1211,8 @@ struct kvm_x86_ops { uint16_t (*nested_get_evmcs_version)(struct kvm_vcpu *vcpu); bool (*need_emulation_on_page_fault)(struct kvm_vcpu *vcpu); + + bool (*apic_init_signal_blocked)(struct kvm_vcpu *vcpu); }; struct kvm_arch_async_pf { @@ -1328,8 +1330,10 @@ int kvm_emulate_instruction_from_buffer(struct kvm_vcpu *vcpu, void kvm_enable_efer_bits(u64); bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer); -int kvm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr); -int kvm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr); +int kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data); +int kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data); +int kvm_emulate_rdmsr(struct kvm_vcpu *vcpu); +int kvm_emulate_wrmsr(struct kvm_vcpu *vcpu); struct x86_emulate_ctxt; @@ -1583,6 +1587,13 @@ bool kvm_intr_is_single_vcpu(struct kvm *kvm, struct kvm_lapic_irq *irq, void kvm_set_msi_irq(struct kvm *kvm, struct kvm_kernel_irq_routing_entry *e, struct kvm_lapic_irq *irq); +static inline bool kvm_irq_is_postable(struct kvm_lapic_irq *irq) +{ + /* We can only post Fixed and LowPrio IRQs */ + return (irq->delivery_mode == dest_Fixed || + irq->delivery_mode == dest_LowestPrio); +} + static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) { if (kvm_x86_ops->vcpu_blocking) diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h index 9024236693d2b1e6756e4e9a62f72102c7531d46..16ae821483c88db9905af36cc2dea34e922ab804 100644 --- a/arch/x86/include/asm/mmu_context.h +++ b/arch/x86/include/asm/mmu_context.h @@ -28,16 +28,16 @@ static inline void paravirt_activate_mm(struct mm_struct *prev, DECLARE_STATIC_KEY_FALSE(rdpmc_always_available_key); -static inline void load_mm_cr4(struct mm_struct *mm) +static inline void load_mm_cr4_irqsoff(struct mm_struct *mm) { if (static_branch_unlikely(&rdpmc_always_available_key) || atomic_read(&mm->context.perf_rdpmc_allowed)) - cr4_set_bits(X86_CR4_PCE); + cr4_set_bits_irqsoff(X86_CR4_PCE); else - cr4_clear_bits(X86_CR4_PCE); + cr4_clear_bits_irqsoff(X86_CR4_PCE); } #else -static inline void load_mm_cr4(struct mm_struct *mm) {} +static inline void load_mm_cr4_irqsoff(struct mm_struct *mm) {} #endif #ifdef CONFIG_MODIFY_LDT_SYSCALL diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index 2ef31cc8c529541074a70f5810c80e73366d8890..f4138aeb428086ba9d1352f1dc21f3d1ba312094 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -218,7 +218,8 @@ 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_free_hyperv_page(unsigned long addr); void hyperv_reenlightenment_intr(struct pt_regs *regs); void set_hv_tscchange_cb(void (*cb)(void)); void clear_hv_tscchange_cb(void); @@ -241,6 +242,8 @@ static inline void hv_apic_init(void) {} #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 271d837d69a8868118d811dabaa5739d482c2c0c..20ce682a2540f389dc62f29dbf07c0b3f32620ea 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -375,14 +375,22 @@ /* Alternative perfctr range with full access. */ #define MSR_IA32_PMC0 0x000004c1 -/* AMD64 MSRs. Not complete. See the architecture manual for a more - complete list. */ +/* Auto-reload via MSR instead of DS area */ +#define MSR_RELOAD_PMC0 0x000014c1 +#define MSR_RELOAD_FIXED_CTR0 0x00001309 +/* + * AMD64 MSRs. Not complete. See the architecture manual for a more + * complete list. + */ #define MSR_AMD64_PATCH_LEVEL 0x0000008b #define MSR_AMD64_TSC_RATIO 0xc0000104 #define MSR_AMD64_NB_CFG 0xc001001f #define MSR_AMD64_CPUID_FN_1 0xc0011004 #define MSR_AMD64_PATCH_LOADER 0xc0010020 +#define MSR_AMD_PERF_CTL 0xc0010062 +#define MSR_AMD_PERF_STATUS 0xc0010063 +#define MSR_AMD_PSTATE_DEF_BASE 0xc0010064 #define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140 #define MSR_AMD64_OSVW_STATUS 0xc0010141 #define MSR_AMD64_LS_CFG 0xc0011020 @@ -561,9 +569,6 @@ #define MSR_IA32_PERF_STATUS 0x00000198 #define MSR_IA32_PERF_CTL 0x00000199 #define INTEL_PERF_CTL_MASK 0xffff -#define MSR_AMD_PSTATE_DEF_BASE 0xc0010064 -#define MSR_AMD_PERF_STATUS 0xc0010063 -#define MSR_AMD_PERF_CTL 0xc0010062 #define MSR_IA32_MPERF 0x000000e7 #define MSR_IA32_APERF 0x000000e8 diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index 5cc3930cb465e7b9f0bab973b2d410a8ac92ff14..86f20d520a079e1ad809fe9f2fcd3d60a5408a39 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h @@ -233,8 +233,7 @@ static __always_inline unsigned long long rdtsc_ordered(void) * Thus, use the preferred barrier on the respective CPU, aiming for * RDTSCP as the default. */ - asm volatile(ALTERNATIVE_3("rdtsc", - "mfence; rdtsc", X86_FEATURE_MFENCE_RDTSC, + asm volatile(ALTERNATIVE_2("rdtsc", "lfence; rdtsc", X86_FEATURE_LFENCE_RDTSC, "rdtscp", X86_FEATURE_RDTSCP) : EAX_EDX_RET(val, low, high) diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index dce26f1d13e1a5e5a63d5feb2e2f30edecef97e3..69089d46f1285565c9ff5b32dbf934b5d80e15d5 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -139,18 +139,6 @@ static inline void __write_cr4(unsigned long x) PVOP_VCALL1(cpu.write_cr4, x); } -#ifdef CONFIG_X86_64 -static inline unsigned long read_cr8(void) -{ - return PVOP_CALL0(unsigned long, cpu.read_cr8); -} - -static inline void write_cr8(unsigned long x) -{ - PVOP_VCALL1(cpu.write_cr8, x); -} -#endif - static inline void arch_safe_halt(void) { PVOP_VCALL0(irq.safe_halt); diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h index 639b2df445ee6caff6b980cac0e106306e3f0329..70b654f3ffe575e628820c0ec8efb49b86efaeae 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h @@ -119,11 +119,6 @@ struct pv_cpu_ops { void (*write_cr4)(unsigned long); -#ifdef CONFIG_X86_64 - unsigned long (*read_cr8)(void); - void (*write_cr8)(unsigned long); -#endif - /* Segment descriptor handling */ void (*load_tr_desc)(void); void (*load_gdt)(const struct desc_ptr *); diff --git a/arch/x86/include/asm/preempt.h b/arch/x86/include/asm/preempt.h index 99a7fa9ab0a32a1c24e4b699aa3ad10b4640b9f5..3d4cb83a88284086448f45de9f7be0c0457f78cf 100644 --- a/arch/x86/include/asm/preempt.h +++ b/arch/x86/include/asm/preempt.h @@ -102,7 +102,7 @@ static __always_inline bool should_resched(int preempt_offset) return unlikely(raw_cpu_read_4(__preempt_count) == preempt_offset); } -#ifdef CONFIG_PREEMPT +#ifdef CONFIG_PREEMPTION extern asmlinkage void ___preempt_schedule(void); # define __preempt_schedule() \ asm volatile ("call ___preempt_schedule" : ASM_CALL_CONSTRAINT) diff --git a/arch/x86/include/asm/qspinlock.h b/arch/x86/include/asm/qspinlock.h index bd5ac6cc37db5f87c92cc3013138dffa8b2a0302..444d6fd9a6d8991bc152721720bb47fc3b258e46 100644 --- a/arch/x86/include/asm/qspinlock.h +++ b/arch/x86/include/asm/qspinlock.h @@ -63,10 +63,25 @@ static inline bool vcpu_is_preempted(long cpu) #endif #ifdef CONFIG_PARAVIRT +/* + * virt_spin_lock_key - enables (by default) the virt_spin_lock() hijack. + * + * Native (and PV wanting native due to vCPU pinning) should disable this key. + * It is done in this backwards fashion to only have a single direction change, + * which removes ordering between native_pv_spin_init() and HV setup. + */ DECLARE_STATIC_KEY_TRUE(virt_spin_lock_key); void native_pv_lock_init(void) __init; +/* + * Shortcut for the queued_spin_lock_slowpath() function that allows + * virt to hijack it. + * + * Returns: + * true - lock has been negotiated, all done; + * false - queued_spin_lock_slowpath() will do its thing. + */ #define virt_spin_lock virt_spin_lock static inline bool virt_spin_lock(struct qspinlock *lock) { diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h index c53682303c9c1252a79d90cf8dd19a96d126db93..09ecc32f65248dfb8e8167183ac90b6e9821f185 100644 --- a/arch/x86/include/asm/realmode.h +++ b/arch/x86/include/asm/realmode.h @@ -20,7 +20,6 @@ struct real_mode_header { u32 ro_end; /* SMP trampoline */ u32 trampoline_start; - u32 trampoline_status; u32 trampoline_header; #ifdef CONFIG_X86_64 u32 trampoline_pgd; diff --git a/arch/x86/include/asm/set_memory.h b/arch/x86/include/asm/set_memory.h index ae7b909dc242d17f0bc1be10130a42d08c3785ae..2ee8e469dcf5ce88845aca1cb62385b6df4a6dfd 100644 --- a/arch/x86/include/asm/set_memory.h +++ b/arch/x86/include/asm/set_memory.h @@ -40,7 +40,6 @@ int _set_memory_wt(unsigned long addr, int numpages); int _set_memory_wb(unsigned long addr, int numpages); int set_memory_uc(unsigned long addr, int numpages); int set_memory_wc(unsigned long addr, int numpages); -int set_memory_wt(unsigned long addr, int numpages); int set_memory_wb(unsigned long addr, int numpages); int set_memory_np(unsigned long addr, int numpages); int set_memory_4k(unsigned long addr, int numpages); @@ -48,11 +47,6 @@ int set_memory_encrypted(unsigned long addr, int numpages); int set_memory_decrypted(unsigned long addr, int numpages); int set_memory_np_noalias(unsigned long addr, int numpages); -int set_memory_array_uc(unsigned long *addr, int addrinarray); -int set_memory_array_wc(unsigned long *addr, int addrinarray); -int set_memory_array_wt(unsigned long *addr, int addrinarray); -int set_memory_array_wb(unsigned long *addr, int addrinarray); - int set_pages_array_uc(struct page **pages, int addrinarray); int set_pages_array_wc(struct page **pages, int addrinarray); int set_pages_array_wt(struct page **pages, int addrinarray); @@ -80,8 +74,6 @@ int set_pages_array_wb(struct page **pages, int addrinarray); int set_pages_uc(struct page *page, int numpages); int set_pages_wb(struct page *page, int numpages); -int set_pages_x(struct page *page, int numpages); -int set_pages_nx(struct page *page, int numpages); int set_pages_ro(struct page *page, int numpages); int set_pages_rw(struct page *page, int numpages); diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h index e1356a3b8223b03ec7d245a6eb7b1b5479e8f1c6..e15f364efbccab5b080f1d2616964ef6b97a9ed5 100644 --- a/arch/x86/include/asm/smp.h +++ b/arch/x86/include/asm/smp.h @@ -143,6 +143,7 @@ void play_dead_common(void); void wbinvd_on_cpu(int cpu); int wbinvd_on_all_cpus(void); +void native_smp_send_reschedule(int cpu); void native_send_call_func_ipi(const struct cpumask *mask); void native_send_call_func_single_ipi(int cpu); void x86_idle_thread_init(unsigned int cpu, struct task_struct *idle); diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h index 219be88a59d207c683e3be85ebcabcd9e8174393..6d37b8fcfc778cb52663c7a924aa4f5153b67bb3 100644 --- a/arch/x86/include/asm/special_insns.h +++ b/arch/x86/include/asm/special_insns.h @@ -73,20 +73,6 @@ static inline unsigned long native_read_cr4(void) void native_write_cr4(unsigned long val); -#ifdef CONFIG_X86_64 -static inline unsigned long native_read_cr8(void) -{ - unsigned long cr8; - asm volatile("movq %%cr8,%0" : "=r" (cr8)); - return cr8; -} - -static inline void native_write_cr8(unsigned long val) -{ - asm volatile("movq %0,%%cr8" :: "r" (val) : "memory"); -} -#endif - #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS static inline u32 rdpkru(void) { @@ -200,16 +186,6 @@ static inline void wbinvd(void) #ifdef CONFIG_X86_64 -static inline unsigned long read_cr8(void) -{ - return native_read_cr8(); -} - -static inline void write_cr8(unsigned long x) -{ - native_write_cr8(x); -} - static inline void load_gs_index(unsigned selector) { native_load_gs_index(selector); diff --git a/arch/x86/include/asm/suspend_64.h b/arch/x86/include/asm/suspend_64.h index a7af9f53c0cb773d05fd84ebe94525a1971e3ebb..35bb35d28733e52b7fe61886558bde878fbf01d3 100644 --- a/arch/x86/include/asm/suspend_64.h +++ b/arch/x86/include/asm/suspend_64.h @@ -34,7 +34,7 @@ struct saved_context { */ unsigned long kernelmode_gs_base, usermode_gs_base, fs_base; - unsigned long cr0, cr2, cr3, cr4, cr8; + unsigned long cr0, cr2, cr3, cr4; u64 misc_enable; bool misc_enable_saved; struct saved_msrs saved_msrs; diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h index 2dc4a021beea4e163bf56ae367404cfda79304bc..8db3fdb6102ecb373f085de3a6033c645fbe644c 100644 --- a/arch/x86/include/asm/syscall.h +++ b/arch/x86/include/asm/syscall.h @@ -36,6 +36,10 @@ extern const sys_call_ptr_t sys_call_table[]; extern const sys_call_ptr_t ia32_sys_call_table[]; #endif +#ifdef CONFIG_X86_X32_ABI +extern const sys_call_ptr_t x32_sys_call_table[]; +#endif + /* * Only the low 32 bits of orig_ax are meaningful, so we return int. * This importantly ignores the high bits on 64-bit, so comparisons diff --git a/arch/x86/include/asm/text-patching.h b/arch/x86/include/asm/text-patching.h index 70c09967a9996fb7186412d4ee66db0ed63a60da..5e8319bb207a845cd40237581fa6b0d8722037e6 100644 --- a/arch/x86/include/asm/text-patching.h +++ b/arch/x86/include/asm/text-patching.h @@ -45,8 +45,8 @@ extern void text_poke_early(void *addr, const void *opcode, size_t len); * no thread can be preempted in the instructions being modified (no iret to an * invalid instruction possible) or if the instructions are changed from a * consistent state to another consistent state atomically. - * On the local CPU you need to be protected again NMI or MCE handlers seeing an - * inconsistent instruction while you patch. + * On the local CPU you need to be protected against NMI or MCE handlers seeing + * an inconsistent instruction while you patch. */ extern void *text_poke(void *addr, const void *opcode, size_t len); extern void *text_poke_kgdb(void *addr, const void *opcode, size_t len); diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index dee37583196288df06c704b6dc78b6b58b819e28..6f66d841262d9c9713918d1014effff035f2bbeb 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -290,26 +290,42 @@ static inline void __cr4_set(unsigned long cr4) } /* Set in this cpu's CR4. */ -static inline void cr4_set_bits(unsigned long mask) +static inline void cr4_set_bits_irqsoff(unsigned long mask) { - unsigned long cr4, flags; + unsigned long cr4; - local_irq_save(flags); cr4 = this_cpu_read(cpu_tlbstate.cr4); if ((cr4 | mask) != cr4) __cr4_set(cr4 | mask); - local_irq_restore(flags); } /* Clear in this cpu's CR4. */ -static inline void cr4_clear_bits(unsigned long mask) +static inline void cr4_clear_bits_irqsoff(unsigned long mask) { - unsigned long cr4, flags; + unsigned long cr4; - local_irq_save(flags); cr4 = this_cpu_read(cpu_tlbstate.cr4); if ((cr4 & ~mask) != cr4) __cr4_set(cr4 & ~mask); +} + +/* Set in this cpu's CR4. */ +static inline void cr4_set_bits(unsigned long mask) +{ + unsigned long flags; + + local_irq_save(flags); + cr4_set_bits_irqsoff(mask); + local_irq_restore(flags); +} + +/* Clear in this cpu's CR4. */ +static inline void cr4_clear_bits(unsigned long mask) +{ + unsigned long flags; + + local_irq_save(flags); + cr4_clear_bits_irqsoff(mask); local_irq_restore(flags); } diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h index 097589753feceb68cb9be9e1f5255ff4e060117b..a7dd080749ce4e6aa527292dd1e61c352536da63 100644 --- a/arch/x86/include/asm/unistd.h +++ b/arch/x86/include/asm/unistd.h @@ -5,12 +5,6 @@ #include -# ifdef CONFIG_X86_X32_ABI -# define __SYSCALL_MASK (~(__X32_SYSCALL_BIT)) -# else -# define __SYSCALL_MASK (~0) -# endif - # ifdef CONFIG_X86_32 # include diff --git a/arch/x86/include/asm/uv/uv.h b/arch/x86/include/asm/uv/uv.h index e60c45fd3679bf900a8e1d53d2cb731c316d519f..6bc6d89d8e2ad8d36819ae2457a815c9083f2d4b 100644 --- a/arch/x86/include/asm/uv/uv.h +++ b/arch/x86/include/asm/uv/uv.h @@ -12,10 +12,12 @@ struct mm_struct; #ifdef CONFIG_X86_UV #include +extern unsigned long uv_systab_phys; + extern enum uv_system_type get_uv_system_type(void); static inline bool is_early_uv_system(void) { - return !((efi.uv_systab == EFI_INVALID_TABLE_ADDR) || !efi.uv_systab); + return uv_systab_phys && uv_systab_phys != EFI_INVALID_TABLE_ADDR; } extern int is_uv_system(void); extern int is_uv_hubless(void); diff --git a/arch/x86/include/asm/vdso/gettimeofday.h b/arch/x86/include/asm/vdso/gettimeofday.h index ba71a63cdac479d6428159ffbb0e24ba6c5a40f3..e9ee139cf29e05ab861d614209601b13d281cf4c 100644 --- a/arch/x86/include/asm/vdso/gettimeofday.h +++ b/arch/x86/include/asm/vdso/gettimeofday.h @@ -51,7 +51,7 @@ extern struct pvclock_vsyscall_time_info pvclock_page __attribute__((visibility("hidden"))); #endif -#ifdef CONFIG_HYPERV_TSCPAGE +#ifdef CONFIG_HYPERV_TIMER extern struct ms_hyperv_tsc_page hvclock_page __attribute__((visibility("hidden"))); #endif @@ -228,7 +228,7 @@ static u64 vread_pvclock(void) } #endif -#ifdef CONFIG_HYPERV_TSCPAGE +#ifdef CONFIG_HYPERV_TIMER static u64 vread_hvclock(void) { return hv_read_tsc_page(&hvclock_page); @@ -251,7 +251,7 @@ static inline u64 __arch_get_hw_counter(s32 clock_mode) return vread_pvclock(); } #endif -#ifdef CONFIG_HYPERV_TSCPAGE +#ifdef CONFIG_HYPERV_TIMER if (clock_mode == VCLOCK_HVCLOCK) { barrier(); return vread_hvclock(); diff --git a/arch/x86/include/asm/vmware.h b/arch/x86/include/asm/vmware.h new file mode 100644 index 0000000000000000000000000000000000000000..e00c9e87593327e781d72ff9c3b5a2545fc986c0 --- /dev/null +++ b/arch/x86/include/asm/vmware.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +#ifndef _ASM_X86_VMWARE_H +#define _ASM_X86_VMWARE_H + +#include +#include + +/* + * The hypercall definitions differ in the low word of the %edx argument + * in the following way: the old port base interface uses the port + * number to distinguish between high- and low bandwidth versions. + * + * The new vmcall interface instead uses a set of flags to select + * bandwidth mode and transfer direction. The flags should be loaded + * into %dx by any user and are automatically replaced by the port + * number if the VMWARE_HYPERVISOR_PORT method is used. + * + * In short, new driver code should strictly use the new definition of + * %dx content. + */ + +/* Old port-based version */ +#define VMWARE_HYPERVISOR_PORT "0x5658" +#define VMWARE_HYPERVISOR_PORT_HB "0x5659" + +/* Current vmcall / vmmcall version */ +#define VMWARE_HYPERVISOR_HB BIT(0) +#define VMWARE_HYPERVISOR_OUT BIT(1) + +/* The low bandwidth call. The low word of edx is presumed clear. */ +#define VMWARE_HYPERCALL \ + ALTERNATIVE_2("movw $" VMWARE_HYPERVISOR_PORT ", %%dx; inl (%%dx)", \ + "vmcall", X86_FEATURE_VMCALL, \ + "vmmcall", X86_FEATURE_VMW_VMMCALL) + +/* + * The high bandwidth out call. The low word of edx is presumed to have the + * HB and OUT bits set. + */ +#define VMWARE_HYPERCALL_HB_OUT \ + ALTERNATIVE_2("movw $" VMWARE_HYPERVISOR_PORT_HB ", %%dx; rep outsb", \ + "vmcall", X86_FEATURE_VMCALL, \ + "vmmcall", X86_FEATURE_VMW_VMMCALL) + +/* + * The high bandwidth in call. The low word of edx is presumed to have the + * HB bit set. + */ +#define VMWARE_HYPERCALL_HB_IN \ + ALTERNATIVE_2("movw $" VMWARE_HYPERVISOR_PORT_HB ", %%dx; rep insb", \ + "vmcall", X86_FEATURE_VMCALL, \ + "vmmcall", X86_FEATURE_VMW_VMMCALL) +#endif diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index a39136b0d509caacdf544b6ef719ba563be93623..b15e6465870f8c5fb99b34823dc86d1b7597ea89 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -562,6 +562,20 @@ enum vm_instruction_error_number { VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID = 28, }; +/* + * VM-instruction errors that can be encountered on VM-Enter, used to trace + * nested VM-Enter failures reported by hardware. Errors unique to VM-Enter + * from a SMI Transfer Monitor are not included as things have gone seriously + * sideways if we get one of those... + */ +#define VMX_VMENTER_INSTRUCTION_ERRORS \ + { VMXERR_VMLAUNCH_NONCLEAR_VMCS, "VMLAUNCH_NONCLEAR_VMCS" }, \ + { VMXERR_VMRESUME_NONLAUNCHED_VMCS, "VMRESUME_NONLAUNCHED_VMCS" }, \ + { VMXERR_VMRESUME_AFTER_VMXOFF, "VMRESUME_AFTER_VMXOFF" }, \ + { VMXERR_ENTRY_INVALID_CONTROL_FIELD, "VMENTRY_INVALID_CONTROL_FIELD" }, \ + { VMXERR_ENTRY_INVALID_HOST_STATE_FIELD, "VMENTRY_INVALID_HOST_STATE_FIELD" }, \ + { VMXERR_ENTRY_EVENTS_BLOCKED_BY_MOV_SS, "VMENTRY_EVENTS_BLOCKED_BY_MOV_SS" } + enum vmx_l1d_flush_state { VMENTER_L1D_FLUSH_AUTO, VMENTER_L1D_FLUSH_NEVER, diff --git a/arch/x86/include/uapi/asm/errno.h b/arch/x86/include/uapi/asm/errno.h deleted file mode 100644 index 4c82b503d92ffabcc6eb558a50ae5d6dba8a5f7c..0000000000000000000000000000000000000000 --- a/arch/x86/include/uapi/asm/errno.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/x86/include/uapi/asm/fcntl.h b/arch/x86/include/uapi/asm/fcntl.h deleted file mode 100644 index 46ab12db57397dfc44a7aa84f9c10ac5e97509d9..0000000000000000000000000000000000000000 --- a/arch/x86/include/uapi/asm/fcntl.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/x86/include/uapi/asm/ioctl.h b/arch/x86/include/uapi/asm/ioctl.h deleted file mode 100644 index b279fe06dfe5bea925eccf4b39c8908b23379b6a..0000000000000000000000000000000000000000 --- a/arch/x86/include/uapi/asm/ioctl.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/x86/include/uapi/asm/ioctls.h b/arch/x86/include/uapi/asm/ioctls.h deleted file mode 100644 index ec34c760665eaee4e4ee74311bdf6967bbad5b68..0000000000000000000000000000000000000000 --- a/arch/x86/include/uapi/asm/ioctls.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/x86/include/uapi/asm/ipcbuf.h b/arch/x86/include/uapi/asm/ipcbuf.h deleted file mode 100644 index 84c7e51cb6d0befd2b3c013c8bbbbaad6ae02297..0000000000000000000000000000000000000000 --- a/arch/x86/include/uapi/asm/ipcbuf.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/x86/include/uapi/asm/param.h b/arch/x86/include/uapi/asm/param.h deleted file mode 100644 index 965d45427975907ae67efb45e20c8f500fd1ad3a..0000000000000000000000000000000000000000 --- a/arch/x86/include/uapi/asm/param.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/x86/include/uapi/asm/resource.h b/arch/x86/include/uapi/asm/resource.h deleted file mode 100644 index 04bc4db8921b257e1bab8fbc1316222c7be9fdf5..0000000000000000000000000000000000000000 --- a/arch/x86/include/uapi/asm/resource.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/x86/include/uapi/asm/termbits.h b/arch/x86/include/uapi/asm/termbits.h deleted file mode 100644 index 3935b106de79bf2f8469b849576268ac1ca30bb2..0000000000000000000000000000000000000000 --- a/arch/x86/include/uapi/asm/termbits.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/x86/include/uapi/asm/termios.h b/arch/x86/include/uapi/asm/termios.h deleted file mode 100644 index 280d78a9d96637ccbc93bc4c0debc88eb9443bba..0000000000000000000000000000000000000000 --- a/arch/x86/include/uapi/asm/termios.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/x86/include/uapi/asm/types.h b/arch/x86/include/uapi/asm/types.h deleted file mode 100644 index 9d5c11a24279c62069fdfe347ae1260dc4aec9cc..0000000000000000000000000000000000000000 --- a/arch/x86/include/uapi/asm/types.h +++ /dev/null @@ -1,7 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _ASM_X86_TYPES_H -#define _ASM_X86_TYPES_H - -#include - -#endif /* _ASM_X86_TYPES_H */ diff --git a/arch/x86/include/uapi/asm/unistd.h b/arch/x86/include/uapi/asm/unistd.h index 30d7d04d72d6bad6dfb419f7606e8d5c8fd9b622..196fdd02b8b1b3d71ac994715f7dee8fa8b5fa52 100644 --- a/arch/x86/include/uapi/asm/unistd.h +++ b/arch/x86/include/uapi/asm/unistd.h @@ -3,7 +3,7 @@ #define _UAPI_ASM_X86_UNISTD_H /* x32 syscall flag bit */ -#define __X32_SYSCALL_BIT 0x40000000 +#define __X32_SYSCALL_BIT 0x40000000UL #ifndef __KERNEL__ # ifdef __i386__ diff --git a/arch/x86/include/uapi/asm/vmx.h b/arch/x86/include/uapi/asm/vmx.h index f0b0c90dd398246eb2882050d69c6b53ccca11af..f01950aa7faedb951bfc8480536f9e4fe0a8b408 100644 --- a/arch/x86/include/uapi/asm/vmx.h +++ b/arch/x86/include/uapi/asm/vmx.h @@ -31,6 +31,7 @@ #define EXIT_REASON_EXCEPTION_NMI 0 #define EXIT_REASON_EXTERNAL_INTERRUPT 1 #define EXIT_REASON_TRIPLE_FAULT 2 +#define EXIT_REASON_INIT_SIGNAL 3 #define EXIT_REASON_PENDING_INTERRUPT 7 #define EXIT_REASON_NMI_WINDOW 8 @@ -90,6 +91,7 @@ { EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \ { EXIT_REASON_EXTERNAL_INTERRUPT, "EXTERNAL_INTERRUPT" }, \ { EXIT_REASON_TRIPLE_FAULT, "TRIPLE_FAULT" }, \ + { EXIT_REASON_INIT_SIGNAL, "INIT_SIGNAL" }, \ { EXIT_REASON_PENDING_INTERRUPT, "PENDING_INTERRUPT" }, \ { EXIT_REASON_NMI_WINDOW, "NMI_WINDOW" }, \ { EXIT_REASON_TASK_SWITCH, "TASK_SWITCH" }, \ diff --git a/arch/x86/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S index b0715c3ac18d4bb7ae093045736805700d5ce572..7f9ade13bbcfefde7d940840f6c104b207941e84 100644 --- a/arch/x86/kernel/acpi/wakeup_64.S +++ b/arch/x86/kernel/acpi/wakeup_64.S @@ -18,8 +18,13 @@ ENTRY(wakeup_long64) movq saved_magic, %rax movq $0x123456789abcdef0, %rdx cmpq %rdx, %rax - jne bogus_64_magic + je 2f + /* stop here on a saved_magic mismatch */ + movq $0xbad6d61676963, %rcx +1: + jmp 1b +2: movw $__KERNEL_DS, %ax movw %ax, %ss movw %ax, %ds @@ -37,9 +42,6 @@ ENTRY(wakeup_long64) jmp *%rax ENDPROC(wakeup_long64) -bogus_64_magic: - jmp bogus_64_magic - ENTRY(do_suspend_lowlevel) FRAME_BEGIN subq $8, %rsp diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index ccd32013c47a21360c41653a3380429c33026911..9d3a971ea3643bccefb1cf134de279a597fbd994 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -713,7 +713,7 @@ void __init alternative_instructions(void) * Don't stop machine check exceptions while patching. * MCEs only happen when something got corrupted and in this * case we must do something about the corruption. - * Ignoring it is worse than a unlikely patching race. + * Ignoring it is worse than an unlikely patching race. * Also machine checks tend to be broadcast and if one CPU * goes into machine check the others follow quickly, so we don't * expect a machine check to cause undue problems during to code @@ -753,8 +753,8 @@ void __init alternative_instructions(void) * When you use this code to patch more than one byte of an instruction * you need to make sure that other CPUs cannot execute this code in parallel. * Also no thread must be currently preempted in the middle of these - * instructions. And on the local CPU you need to be protected again NMI or MCE - * handlers seeing an inconsistent instruction while you patch. + * instructions. And on the local CPU you need to be protected against NMI or + * MCE handlers seeing an inconsistent instruction while you patch. */ void __init_or_module text_poke_early(void *addr, const void *opcode, size_t len) diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index d63e63b7d1d9581d8036a98e439185e460eaffe8..251c795b4eb3cd75991aabd6b1cffa6b3fedb8fe 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -21,6 +21,7 @@ #define PCI_DEVICE_ID_AMD_17H_DF_F4 0x1464 #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F4 0x15ec #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F4 0x1494 +#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F4 0x1444 /* Protect the PCI config register pairs used for SMN and DF indirect access. */ static DEFINE_MUTEX(smn_mutex); @@ -50,6 +51,7 @@ const struct pci_device_id amd_nb_misc_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) }, {} }; EXPORT_SYMBOL_GPL(amd_nb_misc_ids); @@ -63,6 +65,7 @@ static const struct pci_device_id amd_nb_link_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F4) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F4) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F4) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F4) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F4) }, {} }; diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 08fb79f377936c7725af66bf7bdeaf8f94c70c02..9e2dd2b296cd570046fafc200d3662f4b368da12 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -65,10 +65,10 @@ unsigned int num_processors; unsigned disabled_cpus; /* Processor that is doing the boot up */ -unsigned int boot_cpu_physical_apicid = -1U; +unsigned int boot_cpu_physical_apicid __ro_after_init = -1U; EXPORT_SYMBOL_GPL(boot_cpu_physical_apicid); -u8 boot_cpu_apic_version; +u8 boot_cpu_apic_version __ro_after_init; /* * The highest APIC ID seen during enumeration. @@ -85,13 +85,13 @@ physid_mask_t phys_cpu_present_map; * disable_cpu_apicid=, mostly used for the kdump 2nd kernel to * avoid undefined behaviour caused by sending INIT from AP to BSP. */ -static unsigned int disabled_cpu_apicid __read_mostly = BAD_APICID; +static unsigned int disabled_cpu_apicid __ro_after_init = BAD_APICID; /* * This variable controls which CPUs receive external NMIs. By default, * external NMIs are delivered only to the BSP. */ -static int apic_extnmi = APIC_EXTNMI_BSP; +static int apic_extnmi __ro_after_init = APIC_EXTNMI_BSP; /* * Map cpu index to physical APIC ID @@ -114,7 +114,7 @@ EXPORT_EARLY_PER_CPU_SYMBOL(x86_cpu_to_acpiid); DEFINE_EARLY_PER_CPU_READ_MOSTLY(int, x86_cpu_to_logical_apicid, BAD_APICID); /* Local APIC was disabled by the BIOS and enabled by the kernel */ -static int enabled_via_apicbase; +static int enabled_via_apicbase __ro_after_init; /* * Handle interrupt mode configuration register (IMCR). @@ -172,23 +172,23 @@ static __init int setup_apicpmtimer(char *s) __setup("apicpmtimer", setup_apicpmtimer); #endif -unsigned long mp_lapic_addr; -int disable_apic; +unsigned long mp_lapic_addr __ro_after_init; +int disable_apic __ro_after_init; /* Disable local APIC timer from the kernel commandline or via dmi quirk */ static int disable_apic_timer __initdata; /* Local APIC timer works in C2 */ -int local_apic_timer_c2_ok; +int local_apic_timer_c2_ok __ro_after_init; EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok); /* * Debug level, exported for io_apic.c */ -int apic_verbosity; +int apic_verbosity __ro_after_init; -int pic_mode; +int pic_mode __ro_after_init; /* Have we found an MP table */ -int smp_found_config; +int smp_found_config __ro_after_init; static struct resource lapic_resource = { .name = "Local APIC", @@ -199,7 +199,7 @@ unsigned int lapic_timer_period = 0; static void apic_pm_activate(void); -static unsigned long apic_phys; +static unsigned long apic_phys __ro_after_init; /* * Get the LAPIC version @@ -590,21 +590,21 @@ static u32 skx_deadline_rev(void) static const struct x86_cpu_id deadline_match[] = { DEADLINE_MODEL_MATCH_FUNC( INTEL_FAM6_HASWELL_X, hsx_deadline_rev), DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL_X, 0x0b000020), - DEADLINE_MODEL_MATCH_FUNC( INTEL_FAM6_BROADWELL_XEON_D, bdx_deadline_rev), + DEADLINE_MODEL_MATCH_FUNC( INTEL_FAM6_BROADWELL_D, bdx_deadline_rev), DEADLINE_MODEL_MATCH_FUNC( INTEL_FAM6_SKYLAKE_X, skx_deadline_rev), - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL_CORE, 0x22), - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL_ULT, 0x20), - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL_GT3E, 0x17), + DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL, 0x22), + DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL_L, 0x20), + DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL_G, 0x17), - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL_CORE, 0x25), - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL_GT3E, 0x17), + DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL, 0x25), + DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL_G, 0x17), - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_SKYLAKE_MOBILE, 0xb2), - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_SKYLAKE_DESKTOP, 0xb2), + DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_SKYLAKE_L, 0xb2), + DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_SKYLAKE, 0xb2), - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_KABYLAKE_MOBILE, 0x52), - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_KABYLAKE_DESKTOP, 0x52), + DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_KABYLAKE_L, 0x52), + DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_KABYLAKE, 0x52), {}, }; @@ -1224,25 +1224,38 @@ void clear_local_APIC(void) } /** - * disable_local_APIC - clear and disable the local APIC + * apic_soft_disable - Clears and software disables the local APIC on hotplug + * + * Contrary to disable_local_APIC() this does not touch the enable bit in + * MSR_IA32_APICBASE. Clearing that bit on systems based on the 3 wire APIC + * bus would require a hardware reset as the APIC would lose track of bus + * arbitration. On systems with FSB delivery APICBASE could be disabled, + * but it has to be guaranteed that no interrupt is sent to the APIC while + * in that state and it's not clear from the SDM whether it still responds + * to INIT/SIPI messages. Stay on the safe side and use software disable. */ -void disable_local_APIC(void) +void apic_soft_disable(void) { - unsigned int value; - - /* APIC hasn't been mapped yet */ - if (!x2apic_mode && !apic_phys) - return; + u32 value; clear_local_APIC(); - /* - * Disable APIC (implies clearing of registers - * for 82489DX!). - */ + /* Soft disable APIC (implies clearing of registers for 82489DX!). */ value = apic_read(APIC_SPIV); value &= ~APIC_SPIV_APIC_ENABLED; apic_write(APIC_SPIV, value); +} + +/** + * disable_local_APIC - clear and disable the local APIC + */ +void disable_local_APIC(void) +{ + /* APIC hasn't been mapped yet */ + if (!x2apic_mode && !apic_phys) + return; + + apic_soft_disable(); #ifdef CONFIG_X86_32 /* @@ -1307,7 +1320,7 @@ void __init sync_Arb_IDs(void) APIC_INT_LEVELTRIG | APIC_DM_INIT); } -enum apic_intr_mode_id apic_intr_mode; +enum apic_intr_mode_id apic_intr_mode __ro_after_init; static int __init apic_intr_mode_select(void) { @@ -1495,54 +1508,72 @@ static void lapic_setup_esr(void) oldvalue, value); } -static void apic_pending_intr_clear(void) +#define APIC_IR_REGS APIC_ISR_NR +#define APIC_IR_BITS (APIC_IR_REGS * 32) +#define APIC_IR_MAPSIZE (APIC_IR_BITS / BITS_PER_LONG) + +union apic_ir { + unsigned long map[APIC_IR_MAPSIZE]; + u32 regs[APIC_IR_REGS]; +}; + +static bool apic_check_and_ack(union apic_ir *irr, union apic_ir *isr) { - long long max_loops = cpu_khz ? cpu_khz : 1000000; - unsigned long long tsc = 0, ntsc; - unsigned int queued; - unsigned long value; - int i, j, acked = 0; + int i, bit; + + /* Read the IRRs */ + for (i = 0; i < APIC_IR_REGS; i++) + irr->regs[i] = apic_read(APIC_IRR + i * 0x10); + + /* Read the ISRs */ + for (i = 0; i < APIC_IR_REGS; i++) + isr->regs[i] = apic_read(APIC_ISR + i * 0x10); - if (boot_cpu_has(X86_FEATURE_TSC)) - tsc = rdtsc(); /* - * After a crash, we no longer service the interrupts and a pending - * interrupt from previous kernel might still have ISR bit set. - * - * Most probably by now 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 a vector might get locked. It was noticed - * for timer irq (vector 0x31). Issue an extra EOI to clear ISR. + * If the ISR map is not empty. ACK the APIC and run another round + * to verify whether a pending IRR has been unblocked and turned + * into a ISR. */ - do { - queued = 0; - for (i = APIC_ISR_NR - 1; i >= 0; i--) - queued |= apic_read(APIC_IRR + i*0x10); - - for (i = APIC_ISR_NR - 1; i >= 0; i--) { - value = apic_read(APIC_ISR + i*0x10); - for_each_set_bit(j, &value, 32) { - ack_APIC_irq(); - acked++; - } - } - if (acked > 256) { - pr_err("LAPIC pending interrupts after %d EOI\n", acked); - break; - } - if (queued) { - if (boot_cpu_has(X86_FEATURE_TSC) && cpu_khz) { - ntsc = rdtsc(); - max_loops = (long long)cpu_khz << 10; - max_loops -= ntsc - tsc; - } else { - max_loops--; - } - } - } while (queued && max_loops > 0); - WARN_ON(max_loops <= 0); + if (!bitmap_empty(isr->map, APIC_IR_BITS)) { + /* + * There can be multiple ISR bits set when a high priority + * interrupt preempted a lower priority one. Issue an ACK + * per set bit. + */ + for_each_set_bit(bit, isr->map, APIC_IR_BITS) + ack_APIC_irq(); + return true; + } + + return !bitmap_empty(irr->map, APIC_IR_BITS); +} + +/* + * After a crash, we no longer service the interrupts and a pending + * interrupt from previous kernel might still have ISR bit set. + * + * 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 + * a vector might get locked. It was noticed for timer irq (vector + * 0x31). Issue an extra EOI to clear ISR. + * + * If there are pending IRR bits they turn into ISR bits after a higher + * priority ISR bit has been acked. + */ +static void apic_pending_intr_clear(void) +{ + union apic_ir irr, isr; + unsigned int i; + + /* 512 loops are way oversized and give the APIC a chance to obey. */ + for (i = 0; i < 512; i++) { + if (!apic_check_and_ack(&irr, &isr)) + return; + } + /* Dump the IRR/ISR content if that failed */ + pr_warn("APIC: Stale IRR: %256pb ISR: %256pb\n", irr.map, isr.map); } /** @@ -1559,12 +1590,19 @@ static void setup_local_APIC(void) int logical_apicid, ldr_apicid; #endif - if (disable_apic) { disable_ioapic_support(); return; } + /* + * If this comes from kexec/kcrash the APIC might be enabled in + * SPIV. Soft disable it before doing further initialization. + */ + value = apic_read(APIC_SPIV); + value &= ~APIC_SPIV_APIC_ENABLED; + apic_write(APIC_SPIV, value); + #ifdef CONFIG_X86_32 /* Pound the ESR really hard over the head with a big hammer - mbligh */ if (lapic_is_integrated() && apic->disable_esr) { @@ -1574,8 +1612,6 @@ static void setup_local_APIC(void) apic_write(APIC_ESR, 0); } #endif - perf_events_lapic_init(); - /* * Double-check whether this APIC is really registered. * This is meaningless in clustered apic mode, so we skip it. @@ -1603,13 +1639,17 @@ static void setup_local_APIC(void) #endif /* - * Set Task Priority to 'accept all'. We never change this - * later on. + * Set Task Priority to 'accept all except vectors 0-31'. An APIC + * vector in the 16-31 range could be delivered if TPR == 0, but we + * would think it's an exception and terrible things will happen. We + * never change this later on. */ value = apic_read(APIC_TASKPRI); value &= ~APIC_TPRI_MASK; + value |= 0x10; apic_write(APIC_TASKPRI, value); + /* Clear eventually stale ISR/IRR bits */ apic_pending_intr_clear(); /* @@ -1656,6 +1696,8 @@ static void setup_local_APIC(void) value |= SPURIOUS_APIC_VECTOR; apic_write(APIC_SPIV, value); + perf_events_lapic_init(); + /* * Set up LVT0, LVT1: * diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c index bbdca603f94a66a417ea6441186744a84ef22052..7862b152a052b5754df1c6866ebca724c65114ea 100644 --- a/arch/x86/kernel/apic/apic_flat_64.c +++ b/arch/x86/kernel/apic/apic_flat_64.c @@ -8,21 +8,14 @@ * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and * James Cleverdon. */ -#include -#include -#include #include -#include -#include -#include -#include #include +#include -#include -#include -#include -#include #include +#include + +#include "local.h" static struct apic apic_physflat; static struct apic apic_flat; @@ -83,35 +76,6 @@ flat_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector) _flat_send_IPI_mask(mask, vector); } -static void flat_send_IPI_allbutself(int vector) -{ - int cpu = smp_processor_id(); - - if (IS_ENABLED(CONFIG_HOTPLUG_CPU) || vector == NMI_VECTOR) { - if (!cpumask_equal(cpu_online_mask, cpumask_of(cpu))) { - unsigned long mask = cpumask_bits(cpu_online_mask)[0]; - - if (cpu < BITS_PER_LONG) - __clear_bit(cpu, &mask); - - _flat_send_IPI_mask(mask, vector); - } - } else if (num_online_cpus() > 1) { - __default_send_IPI_shortcut(APIC_DEST_ALLBUT, - vector, apic->dest_logical); - } -} - -static void flat_send_IPI_all(int vector) -{ - if (vector == NMI_VECTOR) { - flat_send_IPI_mask(cpu_online_mask, vector); - } else { - __default_send_IPI_shortcut(APIC_DEST_ALLINC, - vector, apic->dest_logical); - } -} - static unsigned int flat_get_apic_id(unsigned long x) { return (x >> 24) & 0xFF; @@ -173,9 +137,9 @@ static struct apic apic_flat __ro_after_init = { .send_IPI = default_send_IPI_single, .send_IPI_mask = flat_send_IPI_mask, .send_IPI_mask_allbutself = flat_send_IPI_mask_allbutself, - .send_IPI_allbutself = flat_send_IPI_allbutself, - .send_IPI_all = flat_send_IPI_all, - .send_IPI_self = apic_send_IPI_self, + .send_IPI_allbutself = default_send_IPI_allbutself, + .send_IPI_all = default_send_IPI_all, + .send_IPI_self = default_send_IPI_self, .inquire_remote_apic = default_inquire_remote_apic, @@ -225,16 +189,6 @@ static void physflat_init_apic_ldr(void) */ } -static void physflat_send_IPI_allbutself(int vector) -{ - default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector); -} - -static void physflat_send_IPI_all(int vector) -{ - default_send_IPI_mask_sequence_phys(cpu_online_mask, vector); -} - static int physflat_probe(void) { if (apic == &apic_physflat || num_possible_cpus() > 8 || @@ -276,9 +230,9 @@ static struct apic apic_physflat __ro_after_init = { .send_IPI = default_send_IPI_single_phys, .send_IPI_mask = default_send_IPI_mask_sequence_phys, .send_IPI_mask_allbutself = default_send_IPI_mask_allbutself_phys, - .send_IPI_allbutself = physflat_send_IPI_allbutself, - .send_IPI_all = physflat_send_IPI_all, - .send_IPI_self = apic_send_IPI_self, + .send_IPI_allbutself = default_send_IPI_allbutself, + .send_IPI_all = default_send_IPI_all, + .send_IPI_self = default_send_IPI_self, .inquire_remote_apic = default_inquire_remote_apic, diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c index 5078b5ce63a7aaf4569368e6447c9a4423271109..98c9bb75d1854d9ca14c0c43779c8da161dbb954 100644 --- a/arch/x86/kernel/apic/apic_noop.c +++ b/arch/x86/kernel/apic/apic_noop.c @@ -9,25 +9,9 @@ * to not uglify the caller's code and allow to call (some) apic routines * like self-ipi, etc... */ - -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include +#include static void noop_init_apic_ldr(void) { } static void noop_send_IPI(int cpu, int vector) { } diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c index a5464b8b6c464d117d8d2e03c8273bc21531f412..cdf45b4700f283967c9606a152eb98d05e69fea3 100644 --- a/arch/x86/kernel/apic/apic_numachip.c +++ b/arch/x86/kernel/apic/apic_numachip.c @@ -10,15 +10,15 @@ * Send feedback to * */ - +#include #include #include #include -#include -#include + #include -#include + +#include "local.h" u8 numachip_system __read_mostly; static const struct apic apic_numachip1; diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c index caedd8d60d3610b8b9bc11f5669de16521b3ac2a..38b5b51d42f6a33773e55e4ad4214356c86591d7 100644 --- a/arch/x86/kernel/apic/bigsmp_32.c +++ b/arch/x86/kernel/apic/bigsmp_32.c @@ -4,18 +4,13 @@ * * Drives the local APIC in "clustered mode". */ -#include #include -#include -#include #include #include -#include -#include -#include #include -#include + +#include "local.h" static unsigned bigsmp_get_apic_id(unsigned long x) { diff --git a/arch/x86/kernel/apic/ipi.c b/arch/x86/kernel/apic/ipi.c index 82f9244fe61fbe7aa8779298503e4884e7d94fa8..6ca0f91372fd2093d09ea1d9d07122ab30422f25 100644 --- a/arch/x86/kernel/apic/ipi.c +++ b/arch/x86/kernel/apic/ipi.c @@ -1,24 +1,113 @@ // SPDX-License-Identifier: GPL-2.0 + #include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -void __default_send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest) +#include + +#include "local.h" + +DEFINE_STATIC_KEY_FALSE(apic_use_ipi_shorthand); + +#ifdef CONFIG_SMP +static int apic_ipi_shorthand_off __ro_after_init; + +static __init int apic_ipi_shorthand(char *str) +{ + get_option(&str, &apic_ipi_shorthand_off); + return 1; +} +__setup("no_ipi_broadcast=", apic_ipi_shorthand); + +static int __init print_ipi_mode(void) +{ + pr_info("IPI shorthand broadcast: %s\n", + apic_ipi_shorthand_off ? "disabled" : "enabled"); + return 0; +} +late_initcall(print_ipi_mode); + +void apic_smt_update(void) +{ + /* + * Do not switch to broadcast mode if: + * - Disabled on the command line + * - Only a single CPU is online + * - Not all present CPUs have been at least booted once + * + * The latter is important as the local APIC might be in some + * random state and a broadcast might cause havoc. That's + * especially true for NMI broadcasting. + */ + if (apic_ipi_shorthand_off || num_online_cpus() == 1 || + !cpumask_equal(cpu_present_mask, &cpus_booted_once_mask)) { + static_branch_disable(&apic_use_ipi_shorthand); + } else { + static_branch_enable(&apic_use_ipi_shorthand); + } +} + +void apic_send_IPI_allbutself(unsigned int vector) +{ + if (num_online_cpus() < 2) + return; + + if (static_branch_likely(&apic_use_ipi_shorthand)) + apic->send_IPI_allbutself(vector); + else + apic->send_IPI_mask_allbutself(cpu_online_mask, vector); +} + +/* + * Send a 'reschedule' IPI to another CPU. It goes straight through and + * wastes no time serializing anything. Worst case is that we lose a + * reschedule ... + */ +void native_smp_send_reschedule(int cpu) +{ + if (unlikely(cpu_is_offline(cpu))) { + WARN(1, "sched: Unexpected reschedule of offline CPU#%d!\n", cpu); + return; + } + apic->send_IPI(cpu, RESCHEDULE_VECTOR); +} + +void native_send_call_func_single_ipi(int cpu) +{ + apic->send_IPI(cpu, CALL_FUNCTION_SINGLE_VECTOR); +} + +void native_send_call_func_ipi(const struct cpumask *mask) +{ + if (static_branch_likely(&apic_use_ipi_shorthand)) { + unsigned int cpu = smp_processor_id(); + + if (!cpumask_or_equal(mask, cpumask_of(cpu), cpu_online_mask)) + goto sendmask; + + if (cpumask_test_cpu(cpu, mask)) + apic->send_IPI_all(CALL_FUNCTION_VECTOR); + else if (num_online_cpus() > 1) + apic->send_IPI_allbutself(CALL_FUNCTION_VECTOR); + return; + } + +sendmask: + apic->send_IPI_mask(mask, CALL_FUNCTION_VECTOR); +} + +#endif /* CONFIG_SMP */ + +static inline int __prepare_ICR2(unsigned int mask) +{ + return SET_APIC_DEST_FIELD(mask); +} + +static inline void __xapic_wait_icr_idle(void) +{ + while (native_apic_mem_read(APIC_ICR) & APIC_ICR_BUSY) + cpu_relax(); +} + +void __default_send_IPI_shortcut(unsigned int shortcut, int vector) { /* * Subtle. In the case of the 'never do double writes' workaround @@ -32,12 +121,16 @@ void __default_send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int /* * Wait for idle. */ - __xapic_wait_icr_idle(); + if (unlikely(vector == NMI_VECTOR)) + safe_apic_wait_icr_idle(); + else + __xapic_wait_icr_idle(); /* - * No need to touch the target chip field + * No need to touch the target chip field. Also the destination + * mode is ignored when a shorthand is used. */ - cfg = __prepare_ICR(shortcut, vector, dest); + cfg = __prepare_ICR(shortcut, vector, 0); /* * Send the IPI. The write to APIC_ICR fires this off. @@ -133,6 +226,21 @@ void default_send_IPI_single(int cpu, int vector) apic->send_IPI_mask(cpumask_of(cpu), vector); } +void default_send_IPI_allbutself(int vector) +{ + __default_send_IPI_shortcut(APIC_DEST_ALLBUT, vector); +} + +void default_send_IPI_all(int vector) +{ + __default_send_IPI_shortcut(APIC_DEST_ALLINC, vector); +} + +void default_send_IPI_self(int vector) +{ + __default_send_IPI_shortcut(APIC_DEST_SELF, vector); +} + #ifdef CONFIG_X86_32 void default_send_IPI_mask_sequence_logical(const struct cpumask *mask, @@ -192,28 +300,6 @@ void default_send_IPI_mask_logical(const struct cpumask *cpumask, int vector) local_irq_restore(flags); } -void default_send_IPI_allbutself(int vector) -{ - /* - * if there are no other CPUs in the system then we get an APIC send - * error if we try to broadcast, thus avoid sending IPIs in this case. - */ - if (!(num_online_cpus() > 1)) - return; - - __default_local_send_IPI_allbutself(vector); -} - -void default_send_IPI_all(int vector) -{ - __default_local_send_IPI_all(vector); -} - -void default_send_IPI_self(int vector) -{ - __default_send_IPI_shortcut(APIC_DEST_SELF, vector, apic->dest_logical); -} - /* must come after the send_IPI functions above for inlining */ static int convert_apicid_to_cpu(int apic_id) { diff --git a/arch/x86/kernel/apic/local.h b/arch/x86/kernel/apic/local.h new file mode 100644 index 0000000000000000000000000000000000000000..04797f05ce942d183e8c512dd86f947d11556691 --- /dev/null +++ b/arch/x86/kernel/apic/local.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Historical copyright notices: + * + * Copyright 2004 James Cleverdon, IBM. + * (c) 1995 Alan Cox, Building #3 + * (c) 1998-99, 2000 Ingo Molnar + * (c) 2002,2003 Andi Kleen, SuSE Labs. + */ + +#include + +#include + +/* APIC flat 64 */ +void flat_init_apic_ldr(void); + +/* X2APIC */ +int x2apic_apic_id_valid(u32 apicid); +int x2apic_apic_id_registered(void); +void __x2apic_send_IPI_dest(unsigned int apicid, int vector, unsigned int dest); +unsigned int x2apic_get_apic_id(unsigned long id); +u32 x2apic_set_apic_id(unsigned int id); +int x2apic_phys_pkg_id(int initial_apicid, int index_msb); +void x2apic_send_IPI_self(int vector); +void __x2apic_send_IPI_shorthand(int vector, u32 which); + +/* IPI */ + +DECLARE_STATIC_KEY_FALSE(apic_use_ipi_shorthand); + +static inline unsigned int __prepare_ICR(unsigned int shortcut, int vector, + unsigned int dest) +{ + unsigned int icr = shortcut | dest; + + switch (vector) { + default: + icr |= APIC_DM_FIXED | vector; + break; + case NMI_VECTOR: + icr |= APIC_DM_NMI; + break; + } + return icr; +} + +void __default_send_IPI_shortcut(unsigned int shortcut, int vector); + +/* + * This is used to send an IPI with no shorthand notation (the destination is + * specified in bits 56 to 63 of the ICR). + */ +void __default_send_IPI_dest_field(unsigned int mask, int vector, unsigned int dest); + +void default_send_IPI_single(int cpu, int vector); +void default_send_IPI_single_phys(int cpu, int vector); +void default_send_IPI_mask_sequence_phys(const struct cpumask *mask, int vector); +void default_send_IPI_mask_allbutself_phys(const struct cpumask *mask, int vector); +void default_send_IPI_allbutself(int vector); +void default_send_IPI_all(int vector); +void default_send_IPI_self(int vector); + +#ifdef CONFIG_X86_32 +void default_send_IPI_mask_sequence_logical(const struct cpumask *mask, int vector); +void default_send_IPI_mask_allbutself_logical(const struct cpumask *mask, int vector); +void default_send_IPI_mask_logical(const struct cpumask *mask, int vector); +#endif diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c index ee2d91e382f1c576aead6dc28b719c5129c85a16..67b33d67002f9dbe52d267ae30719bc17756b3a6 100644 --- a/arch/x86/kernel/apic/probe_32.c +++ b/arch/x86/kernel/apic/probe_32.c @@ -6,51 +6,14 @@ * * Generic x86 APIC driver probe layer. */ -#include -#include #include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include - #include -#include -#include +#include #include -#include -#ifdef CONFIG_HOTPLUG_CPU -#define DEFAULT_SEND_IPI (1) -#else -#define DEFAULT_SEND_IPI (0) -#endif - -int no_broadcast = DEFAULT_SEND_IPI; - -static __init int no_ipi_broadcast(char *str) -{ - get_option(&str, &no_broadcast); - pr_info("Using %s mode\n", - no_broadcast ? "No IPI Broadcast" : "IPI Broadcast"); - return 1; -} -__setup("no_ipi_broadcast=", no_ipi_broadcast); - -static int __init print_ipi_mode(void) -{ - pr_info("Using IPI %s mode\n", - no_broadcast ? "No-Shortcut" : "Shortcut"); - return 0; -} -late_initcall(print_ipi_mode); +#include "local.h" static int default_x86_32_early_logical_apicid(int cpu) { diff --git a/arch/x86/kernel/apic/probe_64.c b/arch/x86/kernel/apic/probe_64.c index e6560a02eb46104313c7e6e92c3a9e9290793994..29f0e0984557ebb152d7fcf971398d0e1cf5b63b 100644 --- a/arch/x86/kernel/apic/probe_64.c +++ b/arch/x86/kernel/apic/probe_64.c @@ -8,19 +8,9 @@ * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and * James Cleverdon. */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include #include -#include -#include + +#include "local.h" /* * Check the APIC IDs in bios_cpu_apicid and choose the APIC mode. @@ -46,13 +36,6 @@ void __init default_setup_apic_routing(void) x86_platform.apic_post_init(); } -/* Same for both flat and physical. */ - -void apic_send_IPI_self(int vector) -{ - __default_send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL); -} - int __init default_acpi_madt_oem_check(char *oem_id, char *oem_table_id) { struct apic **drv; diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index fdacb864c3dd4f8f3756ebf715678136876b0ebc..2c5676b0a6e7f72c70e6fbab2a8ae485e14e9220 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -398,6 +398,17 @@ static int activate_reserved(struct irq_data *irqd) if (!irqd_can_reserve(irqd)) apicd->can_reserve = false; } + + /* + * Check to ensure that the effective affinity mask is a subset + * the user supplied affinity mask, and warn the user if it is not + */ + if (!cpumask_subset(irq_data_get_effective_affinity_mask(irqd), + irq_data_get_affinity_mask(irqd))) { + pr_warn("irq %u: Affinity broken due to vector space exhaustion.\n", + irqd->irq); + } + return ret; } diff --git a/arch/x86/kernel/apic/x2apic.h b/arch/x86/kernel/apic/x2apic.h deleted file mode 100644 index a49b3604027f677375b2bf1feb9eebcd72769112..0000000000000000000000000000000000000000 --- a/arch/x86/kernel/apic/x2apic.h +++ /dev/null @@ -1,9 +0,0 @@ -/* Common bits for X2APIC cluster/physical modes. */ - -int x2apic_apic_id_valid(u32 apicid); -int x2apic_apic_id_registered(void); -void __x2apic_send_IPI_dest(unsigned int apicid, int vector, unsigned int dest); -unsigned int x2apic_get_apic_id(unsigned long id); -u32 x2apic_set_apic_id(unsigned int id); -int x2apic_phys_pkg_id(int initial_apicid, int index_msb); -void x2apic_send_IPI_self(int vector); diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c index 609e499387a1aad695feebdcfed43d830ae65607..45e92cba92f52cb1627e7dc270d96abf1b0e491e 100644 --- a/arch/x86/kernel/apic/x2apic_cluster.c +++ b/arch/x86/kernel/apic/x2apic_cluster.c @@ -1,15 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 -#include + +#include #include -#include -#include -#include -#include -#include -#include +#include +#include + +#include -#include -#include "x2apic.h" +#include "local.h" struct cluster_mask { unsigned int clusterid; @@ -84,12 +82,12 @@ x2apic_send_IPI_mask_allbutself(const struct cpumask *mask, int vector) static void x2apic_send_IPI_allbutself(int vector) { - __x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLBUT); + __x2apic_send_IPI_shorthand(vector, APIC_DEST_ALLBUT); } static void x2apic_send_IPI_all(int vector) { - __x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLINC); + __x2apic_send_IPI_shorthand(vector, APIC_DEST_ALLINC); } static u32 x2apic_calc_apicid(unsigned int cpu) diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c index b5cf9e7b3830c67128ae710911dd3ac6158f149f..bc9693841353c8555c97ca01a0296727eaa61a60 100644 --- a/arch/x86/kernel/apic/x2apic_phys.c +++ b/arch/x86/kernel/apic/x2apic_phys.c @@ -1,14 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 -#include + #include -#include -#include -#include -#include +#include -#include -#include -#include "x2apic.h" +#include "local.h" int x2apic_phys; @@ -80,12 +75,12 @@ static void static void x2apic_send_IPI_allbutself(int vector) { - __x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLBUT); + __x2apic_send_IPI_shorthand(vector, APIC_DEST_ALLBUT); } static void x2apic_send_IPI_all(int vector) { - __x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLINC); + __x2apic_send_IPI_shorthand(vector, APIC_DEST_ALLINC); } static void init_x2apic_ldr(void) @@ -117,6 +112,14 @@ void __x2apic_send_IPI_dest(unsigned int apicid, int vector, unsigned int dest) native_x2apic_icr_write(cfg, apicid); } +void __x2apic_send_IPI_shorthand(int vector, u32 which) +{ + unsigned long cfg = __prepare_ICR(which, vector, 0); + + x2apic_wrmsr_fence(); + native_x2apic_icr_write(cfg, 0); +} + unsigned int x2apic_get_apic_id(unsigned long id) { return id; diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 1e225528f0d7f4a1226dec1bdfba0920fa7da4d3..e6230af1986468d2f0a03464988dcd576e7ca081 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -7,42 +7,22 @@ * * Copyright (C) 2007-2014 Silicon Graphics, Inc. All rights reserved. */ +#include +#include #include -#include #include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include +#include #include #include -#include -#include #include #include #include -#include -#include -#include -#include -#include -DEFINE_PER_CPU(int, x2apic_extra_bits); +static DEFINE_PER_CPU(int, x2apic_extra_bits); static enum uv_system_type uv_system_type; static bool uv_hubless_system; diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c index d3d075226c0aa39761e9f4a33ae05cec321d36d7..24d2fde30d0086d6d87ca4c09f17f12bd6bc0384 100644 --- a/arch/x86/kernel/asm-offsets_64.c +++ b/arch/x86/kernel/asm-offsets_64.c @@ -6,13 +6,28 @@ #include #define __SYSCALL_64(nr, sym, qual) [nr] = 1, +#define __SYSCALL_X32(nr, sym, qual) static char syscalls_64[] = { #include }; +#undef __SYSCALL_64 +#undef __SYSCALL_X32 + +#ifdef CONFIG_X86_X32_ABI +#define __SYSCALL_64(nr, sym, qual) +#define __SYSCALL_X32(nr, sym, qual) [nr] = 1, +static char syscalls_x32[] = { +#include +}; +#undef __SYSCALL_64 +#undef __SYSCALL_X32 +#endif + #define __SYSCALL_I386(nr, sym, qual) [nr] = 1, static char syscalls_ia32[] = { #include }; +#undef __SYSCALL_I386 #if defined(CONFIG_KVM_GUEST) && defined(CONFIG_PARAVIRT_SPINLOCKS) #include @@ -62,7 +77,6 @@ int main(void) ENTRY(cr2); ENTRY(cr3); ENTRY(cr4); - ENTRY(cr8); ENTRY(gdt_desc); BLANK(); #undef ENTRY @@ -80,6 +94,11 @@ int main(void) DEFINE(__NR_syscall_max, sizeof(syscalls_64) - 1); DEFINE(NR_syscalls, sizeof(syscalls_64)); +#ifdef CONFIG_X86_X32_ABI + DEFINE(__NR_syscall_x32_max, sizeof(syscalls_x32) - 1); + DEFINE(X32_NR_syscalls, sizeof(syscalls_x32)); +#endif + DEFINE(__NR_syscall_compat_max, sizeof(syscalls_ia32) - 1); DEFINE(IA32_NR_syscalls, sizeof(syscalls_ia32)); diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 68c363c341bf2a3794ec26f29df4dd28281d4dc5..90f75e5158769c8690f745184c1271ddc6dffd20 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -889,6 +890,10 @@ static void init_amd_zn(struct cpuinfo_x86 *c) { set_cpu_cap(c, X86_FEATURE_ZEN); +#ifdef CONFIG_NUMA + node_reclaim_distance = 32; +#endif + /* * Fix erratum 1076: CPB feature bit not being set in CPUID. * Always set it, except when running under a hypervisor. @@ -945,12 +950,8 @@ static void init_amd(struct cpuinfo_x86 *c) init_amd_cacheinfo(c); if (cpu_has(c, X86_FEATURE_XMM2)) { - unsigned long long val; - int ret; - /* - * A serializing LFENCE has less overhead than MFENCE, so - * use it for execution serialization. On families which + * Use LFENCE for execution serialization. On families which * don't have that MSR, LFENCE is already serializing. * msr_set_bit() uses the safe accessors, too, even if the MSR * is not present. @@ -958,19 +959,8 @@ static void init_amd(struct cpuinfo_x86 *c) msr_set_bit(MSR_F10H_DECFG, MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT); - /* - * Verify that the MSR write was successful (could be running - * under a hypervisor) and only then assume that LFENCE is - * serializing. - */ - ret = rdmsrl_safe(MSR_F10H_DECFG, &val); - if (!ret && (val & MSR_F10H_DECFG_LFENCE_SERIALIZE)) { - /* A serializing LFENCE stops RDTSC speculation */ - set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC); - } else { - /* MFENCE stops RDTSC speculation */ - set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC); - } + /* A serializing LFENCE stops RDTSC speculation */ + set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC); } /* diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index c6fa3ef10b4ef2f400ac256973958b51861479db..91c2561b905f3e1b264e72eec420af50bd820469 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -787,7 +787,7 @@ static void update_mds_branch_idle(void) #define MDS_MSG_SMT "MDS CPU bug present and SMT on, data leak possible. See https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/mds.html for more details.\n" -void arch_smt_update(void) +void cpu_bugs_smt_update(void) { /* Enhanced IBRS implies STIBP. No update required. */ if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED) @@ -1184,15 +1184,15 @@ static void override_cache_bits(struct cpuinfo_x86 *c) case INTEL_FAM6_WESTMERE: case INTEL_FAM6_SANDYBRIDGE: case INTEL_FAM6_IVYBRIDGE: - case INTEL_FAM6_HASWELL_CORE: - case INTEL_FAM6_HASWELL_ULT: - case INTEL_FAM6_HASWELL_GT3E: - case INTEL_FAM6_BROADWELL_CORE: - case INTEL_FAM6_BROADWELL_GT3E: - case INTEL_FAM6_SKYLAKE_MOBILE: - case INTEL_FAM6_SKYLAKE_DESKTOP: - case INTEL_FAM6_KABYLAKE_MOBILE: - case INTEL_FAM6_KABYLAKE_DESKTOP: + case INTEL_FAM6_HASWELL: + case INTEL_FAM6_HASWELL_L: + case INTEL_FAM6_HASWELL_G: + case INTEL_FAM6_BROADWELL: + case INTEL_FAM6_BROADWELL_G: + case INTEL_FAM6_SKYLAKE_L: + case INTEL_FAM6_SKYLAKE: + case INTEL_FAM6_KABYLAKE_L: + case INTEL_FAM6_KABYLAKE: if (c->x86_cache_bits < 44) c->x86_cache_bits = 44; break; diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index f125bf7ecb6fbca590df390956f53b46d95aec48..9ae7d1bcd4f4bc14b1ad110d77b6472afe85a0c6 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1050,7 +1050,7 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = { VULNWL_INTEL(ATOM_BONNELL_MID, NO_SPECULATION), VULNWL_INTEL(ATOM_SILVERMONT, NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS), - VULNWL_INTEL(ATOM_SILVERMONT_X, NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS), + VULNWL_INTEL(ATOM_SILVERMONT_D, NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS), VULNWL_INTEL(ATOM_SILVERMONT_MID, NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS), VULNWL_INTEL(ATOM_AIRMONT, NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS), VULNWL_INTEL(XEON_PHI_KNL, NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS), @@ -1059,9 +1059,10 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = { VULNWL_INTEL(CORE_YONAH, NO_SSB), VULNWL_INTEL(ATOM_AIRMONT_MID, NO_L1TF | MSBDS_ONLY | NO_SWAPGS), + VULNWL_INTEL(ATOM_AIRMONT_NP, NO_L1TF | NO_SWAPGS), VULNWL_INTEL(ATOM_GOLDMONT, NO_MDS | NO_L1TF | NO_SWAPGS), - VULNWL_INTEL(ATOM_GOLDMONT_X, NO_MDS | NO_L1TF | NO_SWAPGS), + VULNWL_INTEL(ATOM_GOLDMONT_D, NO_MDS | NO_L1TF | NO_SWAPGS), VULNWL_INTEL(ATOM_GOLDMONT_PLUS, NO_MDS | NO_L1TF | NO_SWAPGS), /* @@ -1957,3 +1958,14 @@ void microcode_check(void) pr_warn("x86/CPU: CPU features have changed after loading microcode, but might not take effect.\n"); pr_warn("x86/CPU: Please consider either early loading through initrd/built-in or a potential BIOS update.\n"); } + +/* + * Invoked from core CPU hotplug code after hotplug operations + */ +void arch_smt_update(void) +{ + /* Handle the speculative execution misfeatures */ + cpu_bugs_smt_update(); + /* Check whether IPI broadcasting can be enabled */ + apic_smt_update(); +} diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c index b5353244749b5e6835ee70eb128a5aaf9b61e83e..3cbe24ca80abd9b1033657a080da305e29d31a3c 100644 --- a/arch/x86/kernel/cpu/cpuid-deps.c +++ b/arch/x86/kernel/cpu/cpuid-deps.c @@ -20,54 +20,55 @@ struct cpuid_dep { * but it's difficult to tell that to the init reference checker. */ static const struct cpuid_dep cpuid_deps[] = { - { X86_FEATURE_FXSR, X86_FEATURE_FPU }, - { X86_FEATURE_XSAVEOPT, X86_FEATURE_XSAVE }, - { X86_FEATURE_XSAVEC, X86_FEATURE_XSAVE }, - { X86_FEATURE_XSAVES, X86_FEATURE_XSAVE }, - { X86_FEATURE_AVX, X86_FEATURE_XSAVE }, - { X86_FEATURE_PKU, X86_FEATURE_XSAVE }, - { X86_FEATURE_MPX, X86_FEATURE_XSAVE }, - { X86_FEATURE_XGETBV1, X86_FEATURE_XSAVE }, - { X86_FEATURE_CMOV, X86_FEATURE_FXSR }, - { X86_FEATURE_MMX, X86_FEATURE_FXSR }, - { X86_FEATURE_MMXEXT, X86_FEATURE_MMX }, - { X86_FEATURE_FXSR_OPT, X86_FEATURE_FXSR }, - { X86_FEATURE_XSAVE, X86_FEATURE_FXSR }, - { X86_FEATURE_XMM, X86_FEATURE_FXSR }, - { X86_FEATURE_XMM2, X86_FEATURE_XMM }, - { X86_FEATURE_XMM3, X86_FEATURE_XMM2 }, - { X86_FEATURE_XMM4_1, X86_FEATURE_XMM2 }, - { X86_FEATURE_XMM4_2, X86_FEATURE_XMM2 }, - { X86_FEATURE_XMM3, X86_FEATURE_XMM2 }, - { X86_FEATURE_PCLMULQDQ, X86_FEATURE_XMM2 }, - { X86_FEATURE_SSSE3, X86_FEATURE_XMM2, }, - { X86_FEATURE_F16C, X86_FEATURE_XMM2, }, - { X86_FEATURE_AES, X86_FEATURE_XMM2 }, - { X86_FEATURE_SHA_NI, X86_FEATURE_XMM2 }, - { X86_FEATURE_FMA, X86_FEATURE_AVX }, - { X86_FEATURE_AVX2, X86_FEATURE_AVX, }, - { X86_FEATURE_AVX512F, X86_FEATURE_AVX, }, - { X86_FEATURE_AVX512IFMA, X86_FEATURE_AVX512F }, - { X86_FEATURE_AVX512PF, X86_FEATURE_AVX512F }, - { X86_FEATURE_AVX512ER, X86_FEATURE_AVX512F }, - { X86_FEATURE_AVX512CD, X86_FEATURE_AVX512F }, - { X86_FEATURE_AVX512DQ, X86_FEATURE_AVX512F }, - { X86_FEATURE_AVX512BW, X86_FEATURE_AVX512F }, - { X86_FEATURE_AVX512VL, X86_FEATURE_AVX512F }, - { X86_FEATURE_AVX512VBMI, X86_FEATURE_AVX512F }, - { X86_FEATURE_AVX512_VBMI2, X86_FEATURE_AVX512VL }, - { X86_FEATURE_GFNI, X86_FEATURE_AVX512VL }, - { X86_FEATURE_VAES, X86_FEATURE_AVX512VL }, - { X86_FEATURE_VPCLMULQDQ, X86_FEATURE_AVX512VL }, - { X86_FEATURE_AVX512_VNNI, X86_FEATURE_AVX512VL }, - { X86_FEATURE_AVX512_BITALG, X86_FEATURE_AVX512VL }, - { X86_FEATURE_AVX512_4VNNIW, X86_FEATURE_AVX512F }, - { X86_FEATURE_AVX512_4FMAPS, X86_FEATURE_AVX512F }, - { X86_FEATURE_AVX512_VPOPCNTDQ, X86_FEATURE_AVX512F }, - { X86_FEATURE_CQM_OCCUP_LLC, X86_FEATURE_CQM_LLC }, - { X86_FEATURE_CQM_MBM_TOTAL, X86_FEATURE_CQM_LLC }, - { X86_FEATURE_CQM_MBM_LOCAL, X86_FEATURE_CQM_LLC }, - { X86_FEATURE_AVX512_BF16, X86_FEATURE_AVX512VL }, + { X86_FEATURE_FXSR, X86_FEATURE_FPU }, + { X86_FEATURE_XSAVEOPT, X86_FEATURE_XSAVE }, + { X86_FEATURE_XSAVEC, X86_FEATURE_XSAVE }, + { X86_FEATURE_XSAVES, X86_FEATURE_XSAVE }, + { X86_FEATURE_AVX, X86_FEATURE_XSAVE }, + { X86_FEATURE_PKU, X86_FEATURE_XSAVE }, + { X86_FEATURE_MPX, X86_FEATURE_XSAVE }, + { X86_FEATURE_XGETBV1, X86_FEATURE_XSAVE }, + { X86_FEATURE_CMOV, X86_FEATURE_FXSR }, + { X86_FEATURE_MMX, X86_FEATURE_FXSR }, + { X86_FEATURE_MMXEXT, X86_FEATURE_MMX }, + { X86_FEATURE_FXSR_OPT, X86_FEATURE_FXSR }, + { X86_FEATURE_XSAVE, X86_FEATURE_FXSR }, + { X86_FEATURE_XMM, X86_FEATURE_FXSR }, + { X86_FEATURE_XMM2, X86_FEATURE_XMM }, + { X86_FEATURE_XMM3, X86_FEATURE_XMM2 }, + { X86_FEATURE_XMM4_1, X86_FEATURE_XMM2 }, + { X86_FEATURE_XMM4_2, X86_FEATURE_XMM2 }, + { X86_FEATURE_XMM3, X86_FEATURE_XMM2 }, + { X86_FEATURE_PCLMULQDQ, X86_FEATURE_XMM2 }, + { X86_FEATURE_SSSE3, X86_FEATURE_XMM2, }, + { X86_FEATURE_F16C, X86_FEATURE_XMM2, }, + { X86_FEATURE_AES, X86_FEATURE_XMM2 }, + { X86_FEATURE_SHA_NI, X86_FEATURE_XMM2 }, + { X86_FEATURE_FMA, X86_FEATURE_AVX }, + { X86_FEATURE_AVX2, X86_FEATURE_AVX, }, + { X86_FEATURE_AVX512F, X86_FEATURE_AVX, }, + { X86_FEATURE_AVX512IFMA, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512PF, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512ER, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512CD, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512DQ, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512BW, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512VL, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512VBMI, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512_VBMI2, X86_FEATURE_AVX512VL }, + { X86_FEATURE_GFNI, X86_FEATURE_AVX512VL }, + { X86_FEATURE_VAES, X86_FEATURE_AVX512VL }, + { X86_FEATURE_VPCLMULQDQ, X86_FEATURE_AVX512VL }, + { X86_FEATURE_AVX512_VNNI, X86_FEATURE_AVX512VL }, + { X86_FEATURE_AVX512_BITALG, X86_FEATURE_AVX512VL }, + { X86_FEATURE_AVX512_4VNNIW, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512_4FMAPS, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512_VPOPCNTDQ, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512_VP2INTERSECT, X86_FEATURE_AVX512VL }, + { X86_FEATURE_CQM_OCCUP_LLC, X86_FEATURE_CQM_LLC }, + { X86_FEATURE_CQM_MBM_TOTAL, X86_FEATURE_CQM_LLC }, + { X86_FEATURE_CQM_MBM_LOCAL, X86_FEATURE_CQM_LLC }, + { X86_FEATURE_AVX512_BF16, X86_FEATURE_AVX512VL }, {} }; diff --git a/arch/x86/kernel/cpu/hygon.c b/arch/x86/kernel/cpu/hygon.c index 415621ddb8a236a232b2974a0a19cc373b677051..4e28c1fc874997ac1274e348d65e998a1958458c 100644 --- a/arch/x86/kernel/cpu/hygon.c +++ b/arch/x86/kernel/cpu/hygon.c @@ -330,12 +330,8 @@ static void init_hygon(struct cpuinfo_x86 *c) init_hygon_cacheinfo(c); if (cpu_has(c, X86_FEATURE_XMM2)) { - unsigned long long val; - int ret; - /* - * A serializing LFENCE has less overhead than MFENCE, so - * use it for execution serialization. On families which + * Use LFENCE for execution serialization. On families which * don't have that MSR, LFENCE is already serializing. * msr_set_bit() uses the safe accessors, too, even if the MSR * is not present. @@ -343,19 +339,8 @@ static void init_hygon(struct cpuinfo_x86 *c) msr_set_bit(MSR_F10H_DECFG, MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT); - /* - * Verify that the MSR write was successful (could be running - * under a hypervisor) and only then assume that LFENCE is - * serializing. - */ - ret = rdmsrl_safe(MSR_F10H_DECFG, &val); - if (!ret && (val & MSR_F10H_DECFG_LFENCE_SERIALIZE)) { - /* A serializing LFENCE stops RDTSC speculation */ - set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC); - } else { - /* MFENCE stops RDTSC speculation */ - set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC); - } + /* A serializing LFENCE stops RDTSC speculation */ + set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC); } /* diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 8d6d92ebeb54c57ad549294d1af712b005f96412..c2fdc00df1633f6d846ae96353045ec1dc71f8eb 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -142,21 +142,21 @@ struct sku_microcode { u32 microcode; }; static const struct sku_microcode spectre_bad_microcodes[] = { - { INTEL_FAM6_KABYLAKE_DESKTOP, 0x0B, 0x80 }, - { INTEL_FAM6_KABYLAKE_DESKTOP, 0x0A, 0x80 }, - { INTEL_FAM6_KABYLAKE_DESKTOP, 0x09, 0x80 }, - { INTEL_FAM6_KABYLAKE_MOBILE, 0x0A, 0x80 }, - { INTEL_FAM6_KABYLAKE_MOBILE, 0x09, 0x80 }, + { INTEL_FAM6_KABYLAKE, 0x0B, 0x80 }, + { INTEL_FAM6_KABYLAKE, 0x0A, 0x80 }, + { INTEL_FAM6_KABYLAKE, 0x09, 0x80 }, + { INTEL_FAM6_KABYLAKE_L, 0x0A, 0x80 }, + { INTEL_FAM6_KABYLAKE_L, 0x09, 0x80 }, { INTEL_FAM6_SKYLAKE_X, 0x03, 0x0100013e }, { INTEL_FAM6_SKYLAKE_X, 0x04, 0x0200003c }, - { INTEL_FAM6_BROADWELL_CORE, 0x04, 0x28 }, - { INTEL_FAM6_BROADWELL_GT3E, 0x01, 0x1b }, - { INTEL_FAM6_BROADWELL_XEON_D, 0x02, 0x14 }, - { INTEL_FAM6_BROADWELL_XEON_D, 0x03, 0x07000011 }, + { INTEL_FAM6_BROADWELL, 0x04, 0x28 }, + { INTEL_FAM6_BROADWELL_G, 0x01, 0x1b }, + { INTEL_FAM6_BROADWELL_D, 0x02, 0x14 }, + { INTEL_FAM6_BROADWELL_D, 0x03, 0x07000011 }, { INTEL_FAM6_BROADWELL_X, 0x01, 0x0b000025 }, - { INTEL_FAM6_HASWELL_ULT, 0x01, 0x21 }, - { INTEL_FAM6_HASWELL_GT3E, 0x01, 0x18 }, - { INTEL_FAM6_HASWELL_CORE, 0x03, 0x23 }, + { INTEL_FAM6_HASWELL_L, 0x01, 0x21 }, + { INTEL_FAM6_HASWELL_G, 0x01, 0x18 }, + { INTEL_FAM6_HASWELL, 0x03, 0x23 }, { INTEL_FAM6_HASWELL_X, 0x02, 0x3b }, { INTEL_FAM6_HASWELL_X, 0x04, 0x10 }, { INTEL_FAM6_IVYBRIDGE_X, 0x04, 0x42a }, @@ -265,9 +265,10 @@ static void early_init_intel(struct cpuinfo_x86 *c) /* Penwell and Cloverview have the TSC which doesn't sleep on S3 */ if (c->x86 == 6) { switch (c->x86_model) { - case 0x27: /* Penwell */ - case 0x35: /* Cloverview */ - case 0x4a: /* Merrifield */ + case INTEL_FAM6_ATOM_SALTWELL_MID: + case INTEL_FAM6_ATOM_SALTWELL_TABLET: + case INTEL_FAM6_ATOM_SILVERMONT_MID: + case INTEL_FAM6_ATOM_AIRMONT_NP: set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC_S3); break; default: diff --git a/arch/x86/kernel/cpu/mce/intel.c b/arch/x86/kernel/cpu/mce/intel.c index e43eb6732630ae9b06201e809b1086765afd36fd..88cd9598fa57ccad3b344af075a4f269aafee0a3 100644 --- a/arch/x86/kernel/cpu/mce/intel.c +++ b/arch/x86/kernel/cpu/mce/intel.c @@ -479,7 +479,7 @@ static void intel_ppin_init(struct cpuinfo_x86 *c) switch (c->x86_model) { case INTEL_FAM6_IVYBRIDGE_X: case INTEL_FAM6_HASWELL_X: - case INTEL_FAM6_BROADWELL_XEON_D: + case INTEL_FAM6_BROADWELL_D: case INTEL_FAM6_BROADWELL_X: case INTEL_FAM6_SKYLAKE_X: case INTEL_FAM6_XEON_PHI_KNL: diff --git a/arch/x86/kernel/cpu/mce/severity.c b/arch/x86/kernel/cpu/mce/severity.c index 210f1f5db5f75e3f320002a9b6660c62b7806683..87bcdc6dc2f0c54048447faac2f53e5d4aa1733e 100644 --- a/arch/x86/kernel/cpu/mce/severity.c +++ b/arch/x86/kernel/cpu/mce/severity.c @@ -107,11 +107,11 @@ static struct severity { */ MCESEV( AO, "Action optional: memory scrubbing error", - SER, MASK(MCI_STATUS_OVER|MCI_UC_AR|MCACOD_SCRUBMSK, MCI_STATUS_UC|MCACOD_SCRUB) + SER, MASK(MCI_UC_AR|MCACOD_SCRUBMSK, MCI_STATUS_UC|MCACOD_SCRUB) ), MCESEV( AO, "Action optional: last level cache writeback error", - SER, MASK(MCI_STATUS_OVER|MCI_UC_AR|MCACOD, MCI_STATUS_UC|MCACOD_L3WB) + SER, MASK(MCI_UC_AR|MCACOD, MCI_STATUS_UC|MCACOD_L3WB) ), /* ignore OVER for UCNA */ diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index 062f77279ce3bbbc439d9b9754f831b1165f2b2b..267daad8c0360890672e7db5369fde36fb58174e 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -29,6 +29,7 @@ #include #include #include +#include struct ms_hyperv_info ms_hyperv; EXPORT_SYMBOL_GPL(ms_hyperv); @@ -338,6 +339,15 @@ static void __init ms_hyperv_init_platform(void) x2apic_phys = 1; # endif + /* Register Hyper-V specific clocksource */ + hv_init_clocksource(); +#endif +} + +void hv_setup_sched_clock(void *sched_clock) +{ +#ifdef CONFIG_PARAVIRT + pv_ops.time.sched_clock = sched_clock; #endif } diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c index 3c648476d4fbabf09002690e8855816b428e424a..9735139cfdf86bcdaee7ea29a3ba7ab9a6d99270 100644 --- a/arch/x86/kernel/cpu/vmware.c +++ b/arch/x86/kernel/cpu/vmware.c @@ -30,34 +30,69 @@ #include #include #include +#include #undef pr_fmt #define pr_fmt(fmt) "vmware: " fmt -#define CPUID_VMWARE_INFO_LEAF 0x40000000 +#define CPUID_VMWARE_INFO_LEAF 0x40000000 +#define CPUID_VMWARE_FEATURES_LEAF 0x40000010 +#define CPUID_VMWARE_FEATURES_ECX_VMMCALL BIT(0) +#define CPUID_VMWARE_FEATURES_ECX_VMCALL BIT(1) + #define VMWARE_HYPERVISOR_MAGIC 0x564D5868 -#define VMWARE_HYPERVISOR_PORT 0x5658 -#define VMWARE_PORT_CMD_GETVERSION 10 -#define VMWARE_PORT_CMD_GETHZ 45 -#define VMWARE_PORT_CMD_GETVCPU_INFO 68 -#define VMWARE_PORT_CMD_LEGACY_X2APIC 3 -#define VMWARE_PORT_CMD_VCPU_RESERVED 31 +#define VMWARE_CMD_GETVERSION 10 +#define VMWARE_CMD_GETHZ 45 +#define VMWARE_CMD_GETVCPU_INFO 68 +#define VMWARE_CMD_LEGACY_X2APIC 3 +#define VMWARE_CMD_VCPU_RESERVED 31 #define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \ __asm__("inl (%%dx)" : \ - "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \ - "0"(VMWARE_HYPERVISOR_MAGIC), \ - "1"(VMWARE_PORT_CMD_##cmd), \ - "2"(VMWARE_HYPERVISOR_PORT), "3"(UINT_MAX) : \ - "memory"); + "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \ + "a"(VMWARE_HYPERVISOR_MAGIC), \ + "c"(VMWARE_CMD_##cmd), \ + "d"(VMWARE_HYPERVISOR_PORT), "b"(UINT_MAX) : \ + "memory") + +#define VMWARE_VMCALL(cmd, eax, ebx, ecx, edx) \ + __asm__("vmcall" : \ + "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \ + "a"(VMWARE_HYPERVISOR_MAGIC), \ + "c"(VMWARE_CMD_##cmd), \ + "d"(0), "b"(UINT_MAX) : \ + "memory") + +#define VMWARE_VMMCALL(cmd, eax, ebx, ecx, edx) \ + __asm__("vmmcall" : \ + "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \ + "a"(VMWARE_HYPERVISOR_MAGIC), \ + "c"(VMWARE_CMD_##cmd), \ + "d"(0), "b"(UINT_MAX) : \ + "memory") + +#define VMWARE_CMD(cmd, eax, ebx, ecx, edx) do { \ + switch (vmware_hypercall_mode) { \ + case CPUID_VMWARE_FEATURES_ECX_VMCALL: \ + VMWARE_VMCALL(cmd, eax, ebx, ecx, edx); \ + break; \ + case CPUID_VMWARE_FEATURES_ECX_VMMCALL: \ + VMWARE_VMMCALL(cmd, eax, ebx, ecx, edx); \ + break; \ + default: \ + VMWARE_PORT(cmd, eax, ebx, ecx, edx); \ + break; \ + } \ + } while (0) static unsigned long vmware_tsc_khz __ro_after_init; +static u8 vmware_hypercall_mode __ro_after_init; static inline int __vmware_platform(void) { uint32_t eax, ebx, ecx, edx; - VMWARE_PORT(GETVERSION, eax, ebx, ecx, edx); + VMWARE_CMD(GETVERSION, eax, ebx, ecx, edx); return eax != (uint32_t)-1 && ebx == VMWARE_HYPERVISOR_MAGIC; } @@ -129,6 +164,10 @@ 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_hypercall_mode == CPUID_VMWARE_FEATURES_ECX_VMCALL) + setup_force_cpu_cap(X86_FEATURE_VMCALL); + else if (vmware_hypercall_mode == CPUID_VMWARE_FEATURES_ECX_VMMCALL) + setup_force_cpu_cap(X86_FEATURE_VMW_VMMCALL); } static void __init vmware_platform_setup(void) @@ -136,7 +175,7 @@ static void __init vmware_platform_setup(void) uint32_t eax, ebx, ecx, edx; uint64_t lpj, tsc_khz; - VMWARE_PORT(GETHZ, eax, ebx, ecx, edx); + VMWARE_CMD(GETHZ, eax, ebx, ecx, edx); if (ebx != UINT_MAX) { lpj = tsc_khz = eax | (((uint64_t)ebx) << 32); @@ -174,10 +213,21 @@ static void __init vmware_platform_setup(void) vmware_set_capabilities(); } +static u8 vmware_select_hypercall(void) +{ + int eax, ebx, ecx, edx; + + cpuid(CPUID_VMWARE_FEATURES_LEAF, &eax, &ebx, &ecx, &edx); + return (ecx & (CPUID_VMWARE_FEATURES_ECX_VMMCALL | + CPUID_VMWARE_FEATURES_ECX_VMCALL)); +} + /* * While checking the dmi string information, just checking the product * serial key should be enough, as this will always have a VMware * specific string when running under VMware hypervisor. + * If !boot_cpu_has(X86_FEATURE_HYPERVISOR), vmware_hypercall_mode + * intentionally defaults to 0. */ static uint32_t __init vmware_platform(void) { @@ -187,8 +237,16 @@ static uint32_t __init vmware_platform(void) cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &hyper_vendor_id[0], &hyper_vendor_id[1], &hyper_vendor_id[2]); - if (!memcmp(hyper_vendor_id, "VMwareVMware", 12)) + if (!memcmp(hyper_vendor_id, "VMwareVMware", 12)) { + if (eax >= CPUID_VMWARE_FEATURES_LEAF) + vmware_hypercall_mode = + vmware_select_hypercall(); + + pr_info("hypercall mode: 0x%02x\n", + (unsigned int) vmware_hypercall_mode); + return CPUID_VMWARE_INFO_LEAF; + } } else if (dmi_available && dmi_name_in_serial("VMware") && __vmware_platform()) return 1; @@ -200,9 +258,9 @@ static uint32_t __init vmware_platform(void) static bool __init vmware_legacy_x2apic_available(void) { uint32_t eax, ebx, ecx, edx; - VMWARE_PORT(GETVCPU_INFO, eax, ebx, ecx, edx); - return (eax & (1 << VMWARE_PORT_CMD_VCPU_RESERVED)) == 0 && - (eax & (1 << VMWARE_PORT_CMD_LEGACY_X2APIC)) != 0; + VMWARE_CMD(GETVCPU_INFO, eax, ebx, ecx, edx); + return (eax & (1 << VMWARE_CMD_VCPU_RESERVED)) == 0 && + (eax & (1 << VMWARE_CMD_LEGACY_X2APIC)) != 0; } const __initconst struct hypervisor_x86 x86_hyper_vmware = { diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index 2bf70a2fed905975f943e5a89df2fafb3f0bc0c8..eb651fbde92ac137f42bc0d93c00a98b40827030 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -225,8 +225,6 @@ static int elf_header_exclude_ranges(struct crash_mem *cmem) if (crashk_low_res.end) { ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end); - if (ret) - return ret; } return ret; diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 2b5886401e5f4eb2c221f813675927a53cc97d61..e07424e19274b4125098c3d301fb20b6f54a8399 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -367,13 +367,18 @@ NOKPROBE_SYMBOL(oops_end); int __die(const char *str, struct pt_regs *regs, long err) { + const char *pr = ""; + /* Save the regs of the first oops for the executive summary later. */ if (!die_counter) exec_summary_regs = *regs; + if (IS_ENABLED(CONFIG_PREEMPTION)) + pr = IS_ENABLED(CONFIG_PREEMPT_RT) ? " PREEMPT_RT" : " PREEMPT"; + printk(KERN_DEFAULT "%s: %04lx [#%d]%s%s%s%s%s\n", str, err & 0xffff, ++die_counter, - IS_ENABLED(CONFIG_PREEMPT) ? " PREEMPT" : "", + pr, IS_ENABLED(CONFIG_SMP) ? " SMP" : "", debug_pagealloc_enabled() ? " DEBUG_PAGEALLOC" : "", IS_ENABLED(CONFIG_KASAN) ? " KASAN" : "", diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 4215653f8a8e8223c16cf2cb49a0686799d9a4de..21efee32e2b12e9a92658402793fb103bb4d501e 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -243,11 +243,15 @@ __visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs) RCU_LOCKDEP_WARN(!rcu_is_watching(), "IRQ failed to wake up RCU"); desc = __this_cpu_read(vector_irq[vector]); - - if (!handle_irq(desc, regs)) { + if (likely(!IS_ERR_OR_NULL(desc))) { + if (IS_ENABLED(CONFIG_X86_32)) + handle_irq(desc, regs); + else + generic_handle_irq_desc(desc); + } else { ack_APIC_irq(); - if (desc != VECTOR_RETRIGGERED && desc != VECTOR_SHUTDOWN) { + if (desc == VECTOR_UNUSED) { pr_emerg_ratelimited("%s: %d.%d No irq handler for vector\n", __func__, smp_processor_id(), vector); diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index fc34816c6f044923ffdc82c0800f6efa68982e9a..a759ca97cd01cb5f9d3603987ce8676c2edb18e7 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c @@ -148,18 +148,13 @@ void do_softirq_own_stack(void) call_on_stack(__do_softirq, isp); } -bool handle_irq(struct irq_desc *desc, struct pt_regs *regs) +void handle_irq(struct irq_desc *desc, struct pt_regs *regs) { int overflow = check_stack_overflow(); - if (IS_ERR_OR_NULL(desc)) - return false; - if (user_mode(regs) || !execute_on_irq_stack(overflow, desc)) { if (unlikely(overflow)) print_stack_overflow(); generic_handle_irq_desc(desc); } - - return true; } diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c index 6bf6517a05bba3dafbcab3ad0499843d04e05be0..12df3a4abfdd84f54aa611a72489b0dcf3bb19fd 100644 --- a/arch/x86/kernel/irq_64.c +++ b/arch/x86/kernel/irq_64.c @@ -26,15 +26,6 @@ DEFINE_PER_CPU_PAGE_ALIGNED(struct irq_stack, irq_stack_backing_store) __visible; DECLARE_INIT_PER_CPU(irq_stack_backing_store); -bool handle_irq(struct irq_desc *desc, struct pt_regs *regs) -{ - if (IS_ERR_OR_NULL(desc)) - return false; - - generic_handle_irq_desc(desc); - return true; -} - #ifdef CONFIG_VMAP_STACK /* * VMAP the backing store with guard pages diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index 23297ea64f5fc2086415f0181c269b5852ab730d..c44fe7d8d9a4e1e7a1701a697c42431b2dd8cea1 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -416,7 +416,7 @@ static void kgdb_disable_hw_debug(struct pt_regs *regs) */ void kgdb_roundup_cpus(void) { - apic->send_IPI_allbutself(APIC_DM_NMI); + apic_send_IPI_allbutself(NMI_VECTOR); } #endif diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 0e0b08008b5abe900515a31d7c4b56df0482d317..43fc13c831af0c77db4ff29bbfa8e4b7c9f8bd48 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -580,7 +580,7 @@ static void setup_singlestep(struct kprobe *p, struct pt_regs *regs, if (setup_detour_execution(p, regs, reenter)) return; -#if !defined(CONFIG_PREEMPT) +#if !defined(CONFIG_PREEMPTION) if (p->ainsn.boostable && !p->post_handler) { /* Boost up -- we can execute copied instructions directly */ if (!reenter) diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c index 9d4aedece363cc28c696be0dbfa1af8deaba9fa3..b348dd506d58acc58feacbebe1a10a1f0d739949 100644 --- a/arch/x86/kernel/kprobes/opt.c +++ b/arch/x86/kernel/kprobes/opt.c @@ -403,7 +403,7 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, (u8 *)op->kp.addr + op->optinsn.size); len += RELATIVEJUMP_SIZE; - /* We have to use text_poke for instuction buffer because it is RO */ + /* We have to use text_poke() for instruction buffer because it is RO */ text_poke(slot, buf, len); ret = 0; out: diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 4ab377c9fffede8af8c93b620bdb9d90803fd353..e820568ed4d5c701cc4ef76886df84212ddce57c 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -311,7 +311,7 @@ static void kvm_guest_cpu_init(void) if (kvm_para_has_feature(KVM_FEATURE_ASYNC_PF) && kvmapf) { u64 pa = slow_virt_to_phys(this_cpu_ptr(&apf_reason)); -#ifdef CONFIG_PREEMPT +#ifdef CONFIG_PREEMPTION pa |= KVM_ASYNC_PF_SEND_ALWAYS; #endif pa |= KVM_ASYNC_PF_ENABLED; @@ -502,16 +502,6 @@ static void kvm_send_ipi_mask_allbutself(const struct cpumask *mask, int vector) __send_ipi_mask(local_mask, vector); } -static void kvm_send_ipi_allbutself(int vector) -{ - kvm_send_ipi_mask_allbutself(cpu_online_mask, vector); -} - -static void kvm_send_ipi_all(int vector) -{ - __send_ipi_mask(cpu_online_mask, vector); -} - /* * Set the IPI entry points */ @@ -519,8 +509,6 @@ static void kvm_setup_pv_ipi(void) { apic->send_IPI_mask = kvm_send_ipi_mask; apic->send_IPI_mask_allbutself = kvm_send_ipi_mask_allbutself; - apic->send_IPI_allbutself = kvm_send_ipi_allbutself; - apic->send_IPI_all = kvm_send_ipi_all; pr_info("KVM setup pv IPIs\n"); } @@ -705,6 +693,7 @@ unsigned int kvm_arch_para_hints(void) { return cpuid_edx(kvm_cpuid_base() | KVM_CPUID_FEATURES); } +EXPORT_SYMBOL_GPL(kvm_arch_para_hints); static uint32_t __init kvm_detect(void) { @@ -867,3 +856,39 @@ void __init kvm_spinlock_init(void) } #endif /* CONFIG_PARAVIRT_SPINLOCKS */ + +#ifdef CONFIG_ARCH_CPUIDLE_HALTPOLL + +static void kvm_disable_host_haltpoll(void *i) +{ + wrmsrl(MSR_KVM_POLL_CONTROL, 0); +} + +static void kvm_enable_host_haltpoll(void *i) +{ + wrmsrl(MSR_KVM_POLL_CONTROL, 1); +} + +void arch_haltpoll_enable(unsigned int cpu) +{ + if (!kvm_para_has_feature(KVM_FEATURE_POLL_CONTROL)) { + pr_err_once("kvm: host does not support poll control\n"); + pr_err_once("kvm: host upgrade recommended\n"); + return; + } + + /* Enable guest halt poll disables host halt poll */ + smp_call_function_single(cpu, kvm_disable_host_haltpoll, NULL, 1); +} +EXPORT_SYMBOL_GPL(arch_haltpoll_enable); + +void arch_haltpoll_disable(unsigned int cpu) +{ + if (!kvm_para_has_feature(KVM_FEATURE_POLL_CONTROL)) + return; + + /* Enable guest halt poll disables host halt poll */ + smp_call_function_single(cpu, kvm_enable_host_haltpoll, NULL, 1); +} +EXPORT_SYMBOL_GPL(arch_haltpoll_disable); +#endif diff --git a/arch/x86/kernel/machine_kexec_32.c b/arch/x86/kernel/machine_kexec_32.c index 77854b192fef669e8546cf59d43991dbbef3a253..7b45e8daad22e78b4854d1c760a8d0e65c55b9c0 100644 --- a/arch/x86/kernel/machine_kexec_32.c +++ b/arch/x86/kernel/machine_kexec_32.c @@ -148,7 +148,7 @@ int machine_kexec_prepare(struct kimage *image) { int error; - set_pages_x(image->control_code_page, 1); + set_memory_x((unsigned long)page_address(image->control_code_page), 1); error = machine_kexec_alloc_page_tables(image); if (error) return error; @@ -162,7 +162,7 @@ int machine_kexec_prepare(struct kimage *image) */ void machine_kexec_cleanup(struct kimage *image) { - set_pages_nx(image->control_code_page, 1); + set_memory_nx((unsigned long)page_address(image->control_code_page), 1); machine_kexec_free_page_tables(image); } diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c index 4df7705022b9d99500d3c36e8c524f00aed4dfe6..e676a9916c498225ea32822a5cae851288d6737c 100644 --- a/arch/x86/kernel/nmi.c +++ b/arch/x86/kernel/nmi.c @@ -512,6 +512,9 @@ NOKPROBE_SYMBOL(is_debug_stack); dotraplinkage notrace void do_nmi(struct pt_regs *regs, long error_code) { + if (IS_ENABLED(CONFIG_SMP) && cpu_is_offline(smp_processor_id())) + return; + if (this_cpu_read(nmi_state) != NMI_NOT_RUNNING) { this_cpu_write(nmi_state, NMI_LATCHED); return; diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index 0aa6256eedd83e15b57090e33d6b501481757efd..59d3d2763a9e6e9d0d992e8d2f70d06e6c7124ac 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -311,10 +311,6 @@ struct paravirt_patch_template pv_ops = { .cpu.read_cr0 = native_read_cr0, .cpu.write_cr0 = native_write_cr0, .cpu.write_cr4 = native_write_cr4, -#ifdef CONFIG_X86_64 - .cpu.read_cr8 = native_read_cr8, - .cpu.write_cr8 = native_write_cr8, -#endif .cpu.wbinvd = native_wbinvd, .cpu.read_msr = native_read_msr, .cpu.write_msr = native_write_msr, diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index f62b498b18fb7f5e7cc6766feba88827e8fce079..fa4352dce491c855ba6f0a1866390c750b4b42a9 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include #include +#include #include #include #include @@ -34,21 +35,6 @@ int no_iommu __read_mostly; /* Set this to 1 if there is a HW IOMMU in the system */ int iommu_detected __read_mostly = 0; -/* - * This variable becomes 1 if iommu=pt is passed on the kernel command line. - * If this variable is 1, IOMMU implementations do no DMA translation for - * devices and allow every device to access to whole physical memory. This is - * useful if a user wants to use an IOMMU only for KVM device assignment to - * guests and not for driver dma translation. - * It is also possible to disable by default in kernel config, and enable with - * iommu=nopt at boot time. - */ -#ifdef CONFIG_IOMMU_DEFAULT_PASSTHROUGH -int iommu_pass_through __read_mostly = 1; -#else -int iommu_pass_through __read_mostly; -#endif - extern struct iommu_table_entry __iommu_table[], __iommu_table_end[]; void __init pci_iommu_alloc(void) @@ -120,9 +106,9 @@ static __init int iommu_setup(char *p) swiotlb = 1; #endif if (!strncmp(p, "pt", 2)) - iommu_pass_through = 1; + iommu_set_default_passthrough(true); if (!strncmp(p, "nopt", 4)) - iommu_pass_through = 0; + iommu_set_default_translated(true); gart_parse_options(p); diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 75fea0d48c0efc09e068082f7d65ded2c2fbbcff..5e94c4354d4e44101f14c205fc009a6f7c9dc50a 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -580,7 +580,7 @@ void __cpuidle default_idle(void) safe_halt(); trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id()); } -#ifdef CONFIG_APM_MODULE +#if defined(CONFIG_APM_MODULE) || defined(CONFIG_HALTPOLL_CPUIDLE_MODULE) EXPORT_SYMBOL(default_idle); #endif diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index 8451f38ad3999fcb95d85c7c453de544745d0c4b..1daf8f2aa21f515e88243a6178d4b2709f5151eb 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c @@ -90,8 +90,6 @@ static void ich_force_hpet_resume(void) BUG(); else printk(KERN_DEBUG "Force enabled HPET at resume\n"); - - return; } static void ich_force_enable_hpet(struct pci_dev *dev) @@ -448,7 +446,6 @@ static void nvidia_force_enable_hpet(struct pci_dev *dev) dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at 0x%lx\n", force_hpet_address); cached_dev = dev; - return; } /* ISA Bridges */ @@ -513,7 +510,6 @@ static void e6xx_force_enable_hpet(struct pci_dev *dev) force_hpet_resume_type = NONE_FORCE_HPET_RESUME; dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at " "0x%lx\n", force_hpet_address); - return; } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E6XX_CU, e6xx_force_enable_hpet); diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 09d6bded3c1e569fbce3426ecfd10995212ec6e8..0cc7c0b106bbfa3d563f36bce2fe781726c830cf 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -828,11 +828,6 @@ static int crash_nmi_callback(unsigned int val, struct pt_regs *regs) return NMI_HANDLED; } -static void smp_send_nmi_allbutself(void) -{ - apic->send_IPI_allbutself(NMI_VECTOR); -} - /* * Halt all other CPUs, calling the specified function on each of them * @@ -861,7 +856,7 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback) */ wmb(); - smp_send_nmi_allbutself(); + apic_send_IPI_allbutself(NMI_VECTOR); /* Kick CPUs looping in NMI context. */ WRITE_ONCE(crash_ipi_issued, 1); diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index 96421f97e75cffd2297a755881e354eab0ec0394..b8d4e9c3c070c07dc94f429dc21df25787a49a75 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c @@ -115,46 +115,6 @@ static atomic_t stopping_cpu = ATOMIC_INIT(-1); static bool smp_no_nmi_ipi = false; -/* - * this function sends a 'reschedule' IPI to another CPU. - * it goes straight through and wastes no time serializing - * anything. Worst case is that we lose a reschedule ... - */ -static void native_smp_send_reschedule(int cpu) -{ - if (unlikely(cpu_is_offline(cpu))) { - WARN(1, "sched: Unexpected reschedule of offline CPU#%d!\n", cpu); - return; - } - apic->send_IPI(cpu, RESCHEDULE_VECTOR); -} - -void native_send_call_func_single_ipi(int cpu) -{ - apic->send_IPI(cpu, CALL_FUNCTION_SINGLE_VECTOR); -} - -void native_send_call_func_ipi(const struct cpumask *mask) -{ - cpumask_var_t allbutself; - - if (!alloc_cpumask_var(&allbutself, GFP_ATOMIC)) { - apic->send_IPI_mask(mask, CALL_FUNCTION_VECTOR); - return; - } - - cpumask_copy(allbutself, cpu_online_mask); - __cpumask_clear_cpu(smp_processor_id(), allbutself); - - if (cpumask_equal(mask, allbutself) && - cpumask_equal(cpu_online_mask, cpu_callout_mask)) - apic->send_IPI_allbutself(CALL_FUNCTION_VECTOR); - else - apic->send_IPI_mask(mask, CALL_FUNCTION_VECTOR); - - free_cpumask_var(allbutself); -} - static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs) { /* We are registered on stopping cpu too, avoid spurious NMI */ @@ -179,6 +139,12 @@ asmlinkage __visible void smp_reboot_interrupt(void) irq_exit(); } +static int register_stop_handler(void) +{ + return register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback, + NMI_FLAG_FIRST, "smp_stop"); +} + static void native_stop_other_cpus(int wait) { unsigned long flags; @@ -209,42 +175,44 @@ static void native_stop_other_cpus(int wait) /* sync above data before sending IRQ */ wmb(); - apic->send_IPI_allbutself(REBOOT_VECTOR); + apic_send_IPI_allbutself(REBOOT_VECTOR); /* - * Don't wait longer than a second if the caller - * didn't ask us to wait. + * Don't wait longer than a second for IPI completion. The + * wait request is not checked here because that would + * prevent an NMI shutdown attempt in case that not all + * CPUs reach shutdown state. */ timeout = USEC_PER_SEC; - while (num_online_cpus() > 1 && (wait || timeout--)) + while (num_online_cpus() > 1 && timeout--) udelay(1); } - - /* if the REBOOT_VECTOR didn't work, try with the NMI */ - if ((num_online_cpus() > 1) && (!smp_no_nmi_ipi)) { - if (register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback, - NMI_FLAG_FIRST, "smp_stop")) - /* Note: we ignore failures here */ - /* Hope the REBOOT_IRQ is good enough */ - goto finish; - /* sync above data before sending IRQ */ - wmb(); - - pr_emerg("Shutting down cpus with NMI\n"); + /* if the REBOOT_VECTOR didn't work, try with the NMI */ + if (num_online_cpus() > 1) { + /* + * If NMI IPI is enabled, try to register the stop handler + * and send the IPI. In any case try to wait for the other + * CPUs to stop. + */ + if (!smp_no_nmi_ipi && !register_stop_handler()) { + /* Sync above data before sending IRQ */ + wmb(); - apic->send_IPI_allbutself(NMI_VECTOR); + pr_emerg("Shutting down cpus with NMI\n"); + apic_send_IPI_allbutself(NMI_VECTOR); + } /* - * Don't wait longer than a 10 ms if the caller - * didn't ask us to wait. + * Don't wait longer than 10 ms if the caller didn't + * reqeust it. If wait is true, the machine hangs here if + * one or more CPUs do not reach shutdown state. */ timeout = USEC_PER_MSEC * 10; while (num_online_cpus() > 1 && (wait || timeout--)) udelay(1); } -finish: local_irq_save(flags); disable_local_APIC(); mcheck_cpu_clear(this_cpu_ptr(&cpu_info)); diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index fdbd47ceb84d45cc9db743633e42f29e18913d59..69881b2d446ce29de1c61640d2e90e0e02ad5e7c 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1023,8 +1023,6 @@ int common_cpu_up(unsigned int cpu, struct task_struct *idle) static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle, int *cpu0_nmi_registered) { - volatile u32 *trampoline_status = - (volatile u32 *) __va(real_mode_header->trampoline_status); /* start_ip had better be page-aligned! */ unsigned long start_ip = real_mode_header->trampoline_start; @@ -1116,9 +1114,6 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle, } } - /* mark "stuck" area as not stuck */ - *trampoline_status = 0; - if (x86_platform.legacy.warm_reset) { /* * Cleanup possible dangling ends... @@ -1596,7 +1591,12 @@ int native_cpu_disable(void) if (ret) return ret; - clear_local_APIC(); + /* + * Disable the local APIC. Otherwise IPI broadcasts will reach + * it. It still responds normally to INIT, NMI, SMI, and SIPI + * messages. + */ + apic_soft_disable(); cpu_disable_common(); return 0; diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 57d87f79558f2306ebc3415ad4d78740e3d97784..c59454c382fdcd78c45be54cdfe43e064f58f766 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -638,7 +638,7 @@ unsigned long native_calibrate_tsc(void) * clock. */ if (crystal_khz == 0 && - boot_cpu_data.x86_model == INTEL_FAM6_ATOM_GOLDMONT_X) + boot_cpu_data.x86_model == INTEL_FAM6_ATOM_GOLDMONT_D) crystal_khz = 25000; /* diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c index 067858fe4db8fcf5063dcf0952cfb90add3e59de..e0cbe4f2af493deef46199b1712c2f95d472a18a 100644 --- a/arch/x86/kernel/tsc_msr.c +++ b/arch/x86/kernel/tsc_msr.c @@ -58,6 +58,10 @@ static const struct freq_desc freq_desc_ann = { 1, { 83300, 100000, 133300, 100000, 0, 0, 0, 0 } }; +static const struct freq_desc freq_desc_lgm = { + 1, { 78000, 78000, 78000, 78000, 78000, 78000, 78000, 78000 } +}; + static const struct x86_cpu_id tsc_msr_cpu_ids[] = { INTEL_CPU_FAM6(ATOM_SALTWELL_MID, freq_desc_pnw), INTEL_CPU_FAM6(ATOM_SALTWELL_TABLET, freq_desc_clv), @@ -65,6 +69,7 @@ static const struct x86_cpu_id tsc_msr_cpu_ids[] = { INTEL_CPU_FAM6(ATOM_SILVERMONT_MID, freq_desc_tng), INTEL_CPU_FAM6(ATOM_AIRMONT, freq_desc_cht), INTEL_CPU_FAM6(ATOM_AIRMONT_MID, freq_desc_ann), + INTEL_CPU_FAM6(ATOM_AIRMONT_NP, freq_desc_lgm), {} }; diff --git a/arch/x86/kernel/umip.c b/arch/x86/kernel/umip.c index 5b345add550f07e4fd0df227afa4428c3db2b188..548fefed71eecdcfcd2437341ae7f7f4dfa7197e 100644 --- a/arch/x86/kernel/umip.c +++ b/arch/x86/kernel/umip.c @@ -19,7 +19,7 @@ /** DOC: Emulation for User-Mode Instruction Prevention (UMIP) * * The feature User-Mode Instruction Prevention present in recent Intel - * processor prevents a group of instructions (sgdt, sidt, sldt, smsw, and str) + * processor prevents a group of instructions (SGDT, SIDT, SLDT, SMSW and STR) * from being executed with CPL > 0. Otherwise, a general protection fault is * issued. * @@ -36,8 +36,8 @@ * DOSEMU2) rely on this subset of instructions to function. * * The instructions protected by UMIP can be split in two groups. Those which - * return a kernel memory address (sgdt and sidt) and those which return a - * value (sldt, str and smsw). + * return a kernel memory address (SGDT and SIDT) and those which return a + * value (SLDT, STR and SMSW). * * For the instructions that return a kernel memory address, applications * such as WineHQ rely on the result being located in the kernel memory space, @@ -45,15 +45,13 @@ * value that, lies close to the top of the kernel memory. The limit for the GDT * and the IDT are set to zero. * - * Given that sldt and str are not commonly used in programs that run on WineHQ + * Given that SLDT and STR are not commonly used in programs that run on WineHQ * or DOSEMU2, they are not emulated. * * The instruction smsw is emulated to return the value that the register CR0 * has at boot time as set in the head_32. * - * Also, emulation is provided only for 32-bit processes; 64-bit processes - * that attempt to use the instructions that UMIP protects will receive the - * SIGSEGV signal issued as a consequence of the general protection fault. + * Emulation is provided for both 32-bit and 64-bit processes. * * Care is taken to appropriately emulate the results when segmentation is * used. That is, rather than relying on USER_DS and USER_CS, the function @@ -63,17 +61,18 @@ * application uses a local descriptor table. */ -#define UMIP_DUMMY_GDT_BASE 0xfffe0000 -#define UMIP_DUMMY_IDT_BASE 0xffff0000 +#define UMIP_DUMMY_GDT_BASE 0xfffffffffffe0000ULL +#define UMIP_DUMMY_IDT_BASE 0xffffffffffff0000ULL /* * The SGDT and SIDT instructions store the contents of the global descriptor * table and interrupt table registers, respectively. The destination is a * memory operand of X+2 bytes. X bytes are used to store the base address of - * the table and 2 bytes are used to store the limit. In 32-bit processes, the - * only processes for which emulation is provided, X has a value of 4. + * the table and 2 bytes are used to store the limit. In 32-bit processes X + * has a value of 4, in 64-bit processes X has a value of 8. */ -#define UMIP_GDT_IDT_BASE_SIZE 4 +#define UMIP_GDT_IDT_BASE_SIZE_64BIT 8 +#define UMIP_GDT_IDT_BASE_SIZE_32BIT 4 #define UMIP_GDT_IDT_LIMIT_SIZE 2 #define UMIP_INST_SGDT 0 /* 0F 01 /0 */ @@ -189,6 +188,7 @@ static int identify_insn(struct insn *insn) * @umip_inst: A constant indicating the instruction to emulate * @data: Buffer into which the dummy result is stored * @data_size: Size of the emulated result + * @x86_64: true if process is 64-bit, false otherwise * * Emulate an instruction protected by UMIP and provide a dummy result. The * result of the emulation is saved in @data. The size of the results depends @@ -202,11 +202,8 @@ static int identify_insn(struct insn *insn) * 0 on success, -EINVAL on error while emulating. */ static int emulate_umip_insn(struct insn *insn, int umip_inst, - unsigned char *data, int *data_size) + unsigned char *data, int *data_size, bool x86_64) { - unsigned long dummy_base_addr, dummy_value; - unsigned short dummy_limit = 0; - if (!data || !data_size || !insn) return -EINVAL; /* @@ -219,6 +216,9 @@ static int emulate_umip_insn(struct insn *insn, int umip_inst, * is always returned irrespective of the operand size. */ if (umip_inst == UMIP_INST_SGDT || umip_inst == UMIP_INST_SIDT) { + u64 dummy_base_addr; + u16 dummy_limit = 0; + /* SGDT and SIDT do not use registers operands. */ if (X86_MODRM_MOD(insn->modrm.value) == 3) return -EINVAL; @@ -228,13 +228,24 @@ static int emulate_umip_insn(struct insn *insn, int umip_inst, else dummy_base_addr = UMIP_DUMMY_IDT_BASE; - *data_size = UMIP_GDT_IDT_LIMIT_SIZE + UMIP_GDT_IDT_BASE_SIZE; + /* + * 64-bit processes use the entire dummy base address. + * 32-bit processes use the lower 32 bits of the base address. + * dummy_base_addr is always 64 bits, but we memcpy the correct + * number of bytes from it to the destination. + */ + if (x86_64) + *data_size = UMIP_GDT_IDT_BASE_SIZE_64BIT; + else + *data_size = UMIP_GDT_IDT_BASE_SIZE_32BIT; + + memcpy(data + 2, &dummy_base_addr, *data_size); - memcpy(data + 2, &dummy_base_addr, UMIP_GDT_IDT_BASE_SIZE); + *data_size += UMIP_GDT_IDT_LIMIT_SIZE; memcpy(data, &dummy_limit, UMIP_GDT_IDT_LIMIT_SIZE); } else if (umip_inst == UMIP_INST_SMSW) { - dummy_value = CR0_STATE; + unsigned long dummy_value = CR0_STATE; /* * Even though the CR0 register has 4 bytes, the number @@ -290,11 +301,10 @@ static void force_sig_info_umip_fault(void __user *addr, struct pt_regs *regs) * fixup_umip_exception() - Fixup a general protection fault caused by UMIP * @regs: Registers as saved when entering the #GP handler * - * The instructions sgdt, sidt, str, smsw, sldt cause a general protection - * fault if executed with CPL > 0 (i.e., from user space). If the offending - * user-space process is not in long mode, this function fixes the exception - * up and provides dummy results for sgdt, sidt and smsw; str and sldt are not - * fixed up. Also long mode user-space processes are not fixed up. + * The instructions SGDT, SIDT, STR, SMSW and SLDT cause a general protection + * fault if executed with CPL > 0 (i.e., from user space). This function fixes + * the exception up and provides dummy results for SGDT, SIDT and SMSW; STR + * and SLDT are not fixed up. * * If operands are memory addresses, results are copied to user-space memory as * indicated by the instruction pointed by eIP using the registers indicated in @@ -373,13 +383,14 @@ bool fixup_umip_exception(struct pt_regs *regs) umip_pr_warning(regs, "%s instruction cannot be used by applications.\n", umip_insns[umip_inst]); - /* Do not emulate SLDT, STR or user long mode processes. */ - if (umip_inst == UMIP_INST_STR || umip_inst == UMIP_INST_SLDT || user_64bit_mode(regs)) + /* Do not emulate (spoof) SLDT or STR. */ + if (umip_inst == UMIP_INST_STR || umip_inst == UMIP_INST_SLDT) return false; umip_pr_warning(regs, "For now, expensive software emulation returns the result.\n"); - if (emulate_umip_insn(&insn, umip_inst, dummy_data, &dummy_data_size)) + if (emulate_umip_insn(&insn, umip_inst, dummy_data, &dummy_data_size, + user_64bit_mode(regs))) return false; /* diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 22c2720cd948e321d3f0021670c1dce1e0b5799f..dd5985eb61b4c3ca617e26d145066cbfb149c217 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -392,6 +392,12 @@ static inline void do_cpuid_7_mask(struct kvm_cpuid_entry2 *entry, int index) entry->edx &= kvm_cpuid_7_0_edx_x86_features; cpuid_mask(&entry->edx, CPUID_7_EDX); + if (boot_cpu_has(X86_FEATURE_IBPB) && boot_cpu_has(X86_FEATURE_IBRS)) + entry->edx |= F(SPEC_CTRL); + if (boot_cpu_has(X86_FEATURE_STIBP)) + entry->edx |= F(INTEL_STIBP); + if (boot_cpu_has(X86_FEATURE_SSBD)) + entry->edx |= F(SPEC_CTRL_SSBD); /* * We emulate ARCH_CAPABILITIES in software even * if the host doesn't support it. @@ -729,18 +735,23 @@ static inline int __do_cpuid_func(struct kvm_cpuid_entry2 *entry, u32 function, g_phys_as = phys_as; entry->eax = g_phys_as | (virt_as << 8); entry->edx = 0; + entry->ebx &= kvm_cpuid_8000_0008_ebx_x86_features; + cpuid_mask(&entry->ebx, CPUID_8000_0008_EBX); /* - * IBRS, IBPB and VIRT_SSBD aren't necessarily present in - * hardware cpuid + * AMD has separate bits for each SPEC_CTRL bit. + * arch/x86/kernel/cpu/bugs.c is kind enough to + * record that in cpufeatures so use them. */ - if (boot_cpu_has(X86_FEATURE_AMD_IBPB)) + if (boot_cpu_has(X86_FEATURE_IBPB)) entry->ebx |= F(AMD_IBPB); - if (boot_cpu_has(X86_FEATURE_AMD_IBRS)) + if (boot_cpu_has(X86_FEATURE_IBRS)) entry->ebx |= F(AMD_IBRS); - if (boot_cpu_has(X86_FEATURE_VIRT_SSBD)) - entry->ebx |= F(VIRT_SSBD); - entry->ebx &= kvm_cpuid_8000_0008_ebx_x86_features; - cpuid_mask(&entry->ebx, CPUID_8000_0008_EBX); + if (boot_cpu_has(X86_FEATURE_STIBP)) + entry->ebx |= F(AMD_STIBP); + if (boot_cpu_has(X86_FEATURE_SSBD)) + entry->ebx |= F(AMD_SSBD); + if (!boot_cpu_has_bug(X86_BUG_SPEC_STORE_BYPASS)) + entry->ebx |= F(AMD_SSB_NO); /* * The preference is to use SPEC CTRL MSR instead of the * VIRT_SPEC MSR. diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 718f7d9afedc498747bf538cde8469a17469cef6..698efb8c38971913eee17875fd84b1ea2b5d57e4 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -4156,6 +4156,20 @@ static int em_fxrstor(struct x86_emulate_ctxt *ctxt) return rc; } +static int em_xsetbv(struct x86_emulate_ctxt *ctxt) +{ + u32 eax, ecx, edx; + + eax = reg_read(ctxt, VCPU_REGS_RAX); + edx = reg_read(ctxt, VCPU_REGS_RDX); + ecx = reg_read(ctxt, VCPU_REGS_RCX); + + if (ctxt->ops->set_xcr(ctxt, ecx, ((u64)edx << 32) | eax)) + return emulate_gp(ctxt, 0); + + return X86EMUL_CONTINUE; +} + static bool valid_cr(int nr) { switch (nr) { @@ -4409,6 +4423,12 @@ static const struct opcode group7_rm1[] = { N, N, N, N, N, N, }; +static const struct opcode group7_rm2[] = { + N, + II(ImplicitOps | Priv, em_xsetbv, xsetbv), + N, N, N, N, N, N, +}; + static const struct opcode group7_rm3[] = { DIP(SrcNone | Prot | Priv, vmrun, check_svme_pa), II(SrcNone | Prot | EmulateOnUD, em_hypercall, vmmcall), @@ -4498,7 +4518,8 @@ static const struct group_dual group7 = { { }, { EXT(0, group7_rm0), EXT(0, group7_rm1), - N, EXT(0, group7_rm3), + EXT(0, group7_rm2), + EXT(0, group7_rm3), II(SrcNone | DstMem | Mov, em_smsw, smsw), N, II(SrcMem16 | Mov | Priv, em_lmsw, lmsw), EXT(0, group7_rm7), @@ -5144,7 +5165,7 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) else { rc = __do_insn_fetch_bytes(ctxt, 1); if (rc != X86EMUL_CONTINUE) - return rc; + goto done; } switch (mode) { @@ -5395,6 +5416,8 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) ctxt->memopp->addr.mem.ea + ctxt->_eip); done: + if (rc == X86EMUL_PROPAGATE_FAULT) + ctxt->have_exception = true; return (rc != X86EMUL_CONTINUE) ? EMULATION_FAILED : EMULATION_OK; } diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index e904ff06a83d84c9ab5ccd08bdfcc14b1cc3768a..8675458c220598baa89515aa70dc2eb572e3d247 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1198,10 +1198,8 @@ void kvm_apic_set_eoi_accelerated(struct kvm_vcpu *vcpu, int vector) } EXPORT_SYMBOL_GPL(kvm_apic_set_eoi_accelerated); -static void apic_send_ipi(struct kvm_lapic *apic) +static void apic_send_ipi(struct kvm_lapic *apic, u32 icr_low, u32 icr_high) { - u32 icr_low = kvm_lapic_get_reg(apic, APIC_ICR); - u32 icr_high = kvm_lapic_get_reg(apic, APIC_ICR2); struct kvm_lapic_irq irq; irq.vector = icr_low & APIC_VECTOR_MASK; @@ -1598,7 +1596,7 @@ static void start_sw_tscdeadline(struct kvm_lapic *apic) likely(ns > apic->lapic_timer.timer_advance_ns)) { expire = ktime_add_ns(now, ns); expire = ktime_sub_ns(expire, ktimer->timer_advance_ns); - hrtimer_start(&ktimer->timer, expire, HRTIMER_MODE_ABS); + hrtimer_start(&ktimer->timer, expire, HRTIMER_MODE_ABS_HARD); } else apic_timer_expired(apic); @@ -1914,8 +1912,9 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) } case APIC_ICR: /* No delay here, so we always clear the pending bit */ - kvm_lapic_set_reg(apic, APIC_ICR, val & ~(1 << 12)); - apic_send_ipi(apic); + val &= ~(1 << 12); + apic_send_ipi(apic, val, kvm_lapic_get_reg(apic, APIC_ICR2)); + kvm_lapic_set_reg(apic, APIC_ICR, val); break; case APIC_ICR2: @@ -2299,7 +2298,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu, int timer_advance_ns) apic->vcpu = vcpu; hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC, - HRTIMER_MODE_ABS); + HRTIMER_MODE_ABS_HARD); apic->lapic_timer.timer.function = apic_timer_fn; if (timer_advance_ns == -1) { apic->lapic_timer.timer_advance_ns = LAPIC_TIMER_ADVANCE_ADJUST_INIT; @@ -2484,7 +2483,7 @@ void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) timer = &vcpu->arch.apic->lapic_timer.timer; if (hrtimer_cancel(timer)) - hrtimer_start_expires(timer, HRTIMER_MODE_ABS); + hrtimer_start_expires(timer, HRTIMER_MODE_ABS_HARD); } /* @@ -2707,11 +2706,14 @@ void kvm_apic_accept_events(struct kvm_vcpu *vcpu) return; /* - * INITs are latched while in SMM. Because an SMM CPU cannot - * be in KVM_MP_STATE_INIT_RECEIVED state, just eat SIPIs - * and delay processing of INIT until the next RSM. + * INITs are latched while CPU is in specific states + * (SMM, VMX non-root mode, SVM with GIF=0). + * Because a CPU cannot be in these states immediately + * after it has processed an INIT signal (and thus in + * KVM_MP_STATE_INIT_RECEIVED state), just eat SIPIs + * and leave the INIT pending. */ - if (is_smm(vcpu)) { + if (is_smm(vcpu) || kvm_x86_ops->apic_init_signal_blocked(vcpu)) { WARN_ON_ONCE(vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED); if (test_bit(KVM_APIC_SIPI, &apic->pending_events)) clear_bit(KVM_APIC_SIPI, &apic->pending_events); diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index a63964e7cec7bdd67f2b1886adefe98f03972185..a10af9c87f8ac1a2b42bf5a6f182840bd2fce276 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -214,6 +214,7 @@ static u64 __read_mostly shadow_accessed_mask; static u64 __read_mostly shadow_dirty_mask; static u64 __read_mostly shadow_mmio_mask; static u64 __read_mostly shadow_mmio_value; +static u64 __read_mostly shadow_mmio_access_mask; static u64 __read_mostly shadow_present_mask; static u64 __read_mostly shadow_me_mask; @@ -299,14 +300,21 @@ static void kvm_flush_remote_tlbs_with_address(struct kvm *kvm, kvm_flush_remote_tlbs_with_range(kvm, &range); } -void kvm_mmu_set_mmio_spte_mask(u64 mmio_mask, u64 mmio_value) +void kvm_mmu_set_mmio_spte_mask(u64 mmio_mask, u64 mmio_value, u64 access_mask) { + BUG_ON((u64)(unsigned)access_mask != access_mask); BUG_ON((mmio_mask & mmio_value) != mmio_value); shadow_mmio_value = mmio_value | SPTE_SPECIAL_MASK; shadow_mmio_mask = mmio_mask | SPTE_SPECIAL_MASK; + shadow_mmio_access_mask = access_mask; } EXPORT_SYMBOL_GPL(kvm_mmu_set_mmio_spte_mask); +static bool is_mmio_spte(u64 spte) +{ + return (spte & shadow_mmio_mask) == shadow_mmio_value; +} + static inline bool sp_ad_disabled(struct kvm_mmu_page *sp) { return sp->role.ad_disabled; @@ -314,19 +322,19 @@ static inline bool sp_ad_disabled(struct kvm_mmu_page *sp) static inline bool spte_ad_enabled(u64 spte) { - MMU_WARN_ON((spte & shadow_mmio_mask) == shadow_mmio_value); + MMU_WARN_ON(is_mmio_spte(spte)); return !(spte & shadow_acc_track_value); } static inline u64 spte_shadow_accessed_mask(u64 spte) { - MMU_WARN_ON((spte & shadow_mmio_mask) == shadow_mmio_value); + MMU_WARN_ON(is_mmio_spte(spte)); return spte_ad_enabled(spte) ? shadow_accessed_mask : 0; } static inline u64 spte_shadow_dirty_mask(u64 spte) { - MMU_WARN_ON((spte & shadow_mmio_mask) == shadow_mmio_value); + MMU_WARN_ON(is_mmio_spte(spte)); return spte_ad_enabled(spte) ? shadow_dirty_mask : 0; } @@ -389,7 +397,7 @@ static void mark_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, u64 gfn, u64 mask = generation_mmio_spte_mask(gen); u64 gpa = gfn << PAGE_SHIFT; - access &= ACC_WRITE_MASK | ACC_USER_MASK; + access &= shadow_mmio_access_mask; mask |= shadow_mmio_value | access; mask |= gpa | shadow_nonpresent_or_rsvd_mask; mask |= (gpa & shadow_nonpresent_or_rsvd_mask) @@ -401,11 +409,6 @@ static void mark_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, u64 gfn, mmu_spte_set(sptep, mask); } -static bool is_mmio_spte(u64 spte) -{ - return (spte & shadow_mmio_mask) == shadow_mmio_value; -} - static gfn_t get_mmio_spte_gfn(u64 spte) { u64 gpa = spte & shadow_nonpresent_or_rsvd_lower_gfn_mask; @@ -418,8 +421,7 @@ static gfn_t get_mmio_spte_gfn(u64 spte) static unsigned get_mmio_spte_access(u64 spte) { - u64 mask = generation_mmio_spte_mask(MMIO_SPTE_GEN_MASK) | shadow_mmio_mask; - return (spte & ~mask) & ~PAGE_MASK; + return spte & shadow_mmio_access_mask; } static bool set_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn, @@ -3302,7 +3304,8 @@ static bool handle_abnormal_pfn(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn, } if (unlikely(is_noslot_pfn(pfn))) - vcpu_cache_mmio_info(vcpu, gva, gfn, access); + vcpu_cache_mmio_info(vcpu, gva, gfn, + access & shadow_mmio_access_mask); return false; } @@ -5611,13 +5614,13 @@ slot_handle_leaf(struct kvm *kvm, struct kvm_memory_slot *memslot, PT_PAGE_TABLE_LEVEL, lock_flush_tlb); } -static void free_mmu_pages(struct kvm_vcpu *vcpu) +static void free_mmu_pages(struct kvm_mmu *mmu) { - free_page((unsigned long)vcpu->arch.mmu->pae_root); - free_page((unsigned long)vcpu->arch.mmu->lm_root); + free_page((unsigned long)mmu->pae_root); + free_page((unsigned long)mmu->lm_root); } -static int alloc_mmu_pages(struct kvm_vcpu *vcpu) +static int alloc_mmu_pages(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu) { struct page *page; int i; @@ -5638,9 +5641,9 @@ static int alloc_mmu_pages(struct kvm_vcpu *vcpu) if (!page) return -ENOMEM; - vcpu->arch.mmu->pae_root = page_address(page); + mmu->pae_root = page_address(page); for (i = 0; i < 4; ++i) - vcpu->arch.mmu->pae_root[i] = INVALID_PAGE; + mmu->pae_root[i] = INVALID_PAGE; return 0; } @@ -5648,6 +5651,7 @@ static int alloc_mmu_pages(struct kvm_vcpu *vcpu) int kvm_mmu_create(struct kvm_vcpu *vcpu) { uint i; + int ret; vcpu->arch.mmu = &vcpu->arch.root_mmu; vcpu->arch.walk_mmu = &vcpu->arch.root_mmu; @@ -5665,7 +5669,19 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu) vcpu->arch.guest_mmu.prev_roots[i] = KVM_MMU_ROOT_INFO_INVALID; vcpu->arch.nested_mmu.translate_gpa = translate_nested_gpa; - return alloc_mmu_pages(vcpu); + + ret = alloc_mmu_pages(vcpu, &vcpu->arch.guest_mmu); + if (ret) + return ret; + + ret = alloc_mmu_pages(vcpu, &vcpu->arch.root_mmu); + if (ret) + goto fail_allocate_root; + + return ret; + fail_allocate_root: + free_mmu_pages(&vcpu->arch.guest_mmu); + return ret; } @@ -6094,7 +6110,7 @@ static void kvm_set_mmio_spte_mask(void) if (IS_ENABLED(CONFIG_X86_64) && shadow_phys_bits == 52) mask &= ~1ull; - kvm_mmu_set_mmio_spte_mask(mask, mask); + kvm_mmu_set_mmio_spte_mask(mask, mask, ACC_WRITE_MASK | ACC_USER_MASK); } int kvm_mmu_module_init(void) @@ -6168,7 +6184,8 @@ unsigned long kvm_mmu_calculate_default_mmu_pages(struct kvm *kvm) void kvm_mmu_destroy(struct kvm_vcpu *vcpu) { kvm_mmu_unload(vcpu); - free_mmu_pages(vcpu); + free_mmu_pages(&vcpu->arch.root_mmu); + free_mmu_pages(&vcpu->arch.guest_mmu); mmu_free_memory_caches(vcpu); } diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index 54c2a377795be6920bee9676e58555110c3a56b9..11f8ec89433b628150c58c4130fca6406ebf5161 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -51,7 +51,7 @@ static inline u64 rsvd_bits(int s, int e) return ((1ULL << (e - s + 1)) - 1) << s; } -void kvm_mmu_set_mmio_spte_mask(u64 mmio_mask, u64 mmio_value); +void kvm_mmu_set_mmio_spte_mask(u64 mmio_mask, u64 mmio_value, u64 access_mask); void reset_shadow_zero_bits_mask(struct kvm_vcpu *vcpu, struct kvm_mmu *context); diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index e0368076a1ef90660a460bf64f56bfa7b549fd2c..04fe21849b6e46adcc7dc4f7b32bea3541bf6cea 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -68,10 +68,8 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id); #define SEG_TYPE_LDT 2 #define SEG_TYPE_BUSY_TSS16 3 -#define SVM_FEATURE_NPT (1 << 0) #define SVM_FEATURE_LBRV (1 << 1) #define SVM_FEATURE_SVML (1 << 2) -#define SVM_FEATURE_NRIP (1 << 3) #define SVM_FEATURE_TSC_RATE (1 << 4) #define SVM_FEATURE_VMCB_CLEAN (1 << 5) #define SVM_FEATURE_FLUSH_ASID (1 << 6) @@ -770,7 +768,7 @@ static void svm_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) } -static void skip_emulated_instruction(struct kvm_vcpu *vcpu) +static int skip_emulated_instruction(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -779,18 +777,17 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu) svm->next_rip = svm->vmcb->control.next_rip; } - if (!svm->next_rip) { - if (kvm_emulate_instruction(vcpu, EMULTYPE_SKIP) != - EMULATE_DONE) - printk(KERN_DEBUG "%s: NOP\n", __func__); - return; - } + if (!svm->next_rip) + return kvm_emulate_instruction(vcpu, EMULTYPE_SKIP); + if (svm->next_rip - kvm_rip_read(vcpu) > MAX_INST_SIZE) printk(KERN_ERR "%s: ip 0x%lx next 0x%llx\n", __func__, kvm_rip_read(vcpu), svm->next_rip); kvm_rip_write(vcpu, svm->next_rip); svm_set_interrupt_shadow(vcpu, 0); + + return EMULATE_DONE; } static void svm_queue_exception(struct kvm_vcpu *vcpu) @@ -821,7 +818,7 @@ static void svm_queue_exception(struct kvm_vcpu *vcpu) * raises a fault that is not intercepted. Still better than * failing in all cases. */ - skip_emulated_instruction(&svm->vcpu); + (void)skip_emulated_instruction(&svm->vcpu); rip = kvm_rip_read(&svm->vcpu); svm->int3_rip = rip + svm->vmcb->save.cs.base; svm->int3_injected = rip - old_rip; @@ -1269,11 +1266,11 @@ static void grow_ple_window(struct kvm_vcpu *vcpu) pause_filter_count_grow, pause_filter_count_max); - if (control->pause_filter_count != old) + if (control->pause_filter_count != old) { mark_dirty(svm->vmcb, VMCB_INTERCEPTS); - - trace_kvm_ple_window_grow(vcpu->vcpu_id, - control->pause_filter_count, old); + trace_kvm_ple_window_update(vcpu->vcpu_id, + control->pause_filter_count, old); + } } static void shrink_ple_window(struct kvm_vcpu *vcpu) @@ -1287,11 +1284,11 @@ static void shrink_ple_window(struct kvm_vcpu *vcpu) pause_filter_count, pause_filter_count_shrink, pause_filter_count); - if (control->pause_filter_count != old) + if (control->pause_filter_count != old) { mark_dirty(svm->vmcb, VMCB_INTERCEPTS); - - trace_kvm_ple_window_shrink(vcpu->vcpu_id, - control->pause_filter_count, old); + trace_kvm_ple_window_update(vcpu->vcpu_id, + control->pause_filter_count, old); + } } static __init int svm_hardware_setup(void) @@ -2136,6 +2133,9 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) struct page *nested_msrpm_pages; int err; + BUILD_BUG_ON_MSG(offsetof(struct vcpu_svm, vcpu) != 0, + "struct kvm_vcpu must be at offset 0 for arch usercopy region"); + svm = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL_ACCOUNT); if (!svm) { err = -ENOMEM; @@ -2903,13 +2903,11 @@ static int nop_on_interception(struct vcpu_svm *svm) static int halt_interception(struct vcpu_svm *svm) { - svm->next_rip = kvm_rip_read(&svm->vcpu) + 1; return kvm_emulate_halt(&svm->vcpu); } static int vmmcall_interception(struct vcpu_svm *svm) { - svm->next_rip = kvm_rip_read(&svm->vcpu) + 3; return kvm_emulate_hypercall(&svm->vcpu); } @@ -3588,9 +3586,9 @@ static void enter_svm_guest_mode(struct vcpu_svm *svm, u64 vmcb_gpa, mark_all_dirty(svm->vmcb); } -static bool nested_svm_vmrun(struct vcpu_svm *svm) +static int nested_svm_vmrun(struct vcpu_svm *svm) { - int rc; + int ret; struct vmcb *nested_vmcb; struct vmcb *hsave = svm->nested.hsave; struct vmcb *vmcb = svm->vmcb; @@ -3599,13 +3597,16 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm) vmcb_gpa = svm->vmcb->save.rax; - rc = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(vmcb_gpa), &map); - if (rc) { - if (rc == -EINVAL) - kvm_inject_gp(&svm->vcpu, 0); - return false; + ret = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(vmcb_gpa), &map); + if (ret == -EINVAL) { + kvm_inject_gp(&svm->vcpu, 0); + return 1; + } else if (ret) { + return kvm_skip_emulated_instruction(&svm->vcpu); } + ret = kvm_skip_emulated_instruction(&svm->vcpu); + nested_vmcb = map.hva; if (!nested_vmcb_checks(nested_vmcb)) { @@ -3616,7 +3617,7 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm) kvm_vcpu_unmap(&svm->vcpu, &map, true); - return false; + return ret; } trace_kvm_nested_vmrun(svm->vmcb->save.rip, vmcb_gpa, @@ -3660,7 +3661,16 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm) enter_svm_guest_mode(svm, vmcb_gpa, nested_vmcb, &map); - return true; + if (!nested_svm_vmrun_msrpm(svm)) { + svm->vmcb->control.exit_code = SVM_EXIT_ERR; + svm->vmcb->control.exit_code_hi = 0; + svm->vmcb->control.exit_info_1 = 0; + svm->vmcb->control.exit_info_2 = 0; + + nested_svm_vmexit(svm); + } + + return ret; } static void nested_svm_vmloadsave(struct vmcb *from_vmcb, struct vmcb *to_vmcb) @@ -3697,7 +3707,6 @@ static int vmload_interception(struct vcpu_svm *svm) nested_vmcb = map.hva; - svm->next_rip = kvm_rip_read(&svm->vcpu) + 3; ret = kvm_skip_emulated_instruction(&svm->vcpu); nested_svm_vmloadsave(nested_vmcb, svm->vmcb); @@ -3724,7 +3733,6 @@ static int vmsave_interception(struct vcpu_svm *svm) nested_vmcb = map.hva; - svm->next_rip = kvm_rip_read(&svm->vcpu) + 3; ret = kvm_skip_emulated_instruction(&svm->vcpu); nested_svm_vmloadsave(svm->vmcb, nested_vmcb); @@ -3738,27 +3746,7 @@ static int vmrun_interception(struct vcpu_svm *svm) if (nested_svm_check_permissions(svm)) return 1; - /* Save rip after vmrun instruction */ - kvm_rip_write(&svm->vcpu, kvm_rip_read(&svm->vcpu) + 3); - - if (!nested_svm_vmrun(svm)) - return 1; - - if (!nested_svm_vmrun_msrpm(svm)) - goto failed; - - return 1; - -failed: - - svm->vmcb->control.exit_code = SVM_EXIT_ERR; - svm->vmcb->control.exit_code_hi = 0; - svm->vmcb->control.exit_info_1 = 0; - svm->vmcb->control.exit_info_2 = 0; - - nested_svm_vmexit(svm); - - return 1; + return nested_svm_vmrun(svm); } static int stgi_interception(struct vcpu_svm *svm) @@ -3775,7 +3763,6 @@ static int stgi_interception(struct vcpu_svm *svm) if (vgif_enabled(svm)) clr_intercept(svm, INTERCEPT_STGI); - svm->next_rip = kvm_rip_read(&svm->vcpu) + 3; ret = kvm_skip_emulated_instruction(&svm->vcpu); kvm_make_request(KVM_REQ_EVENT, &svm->vcpu); @@ -3791,7 +3778,6 @@ static int clgi_interception(struct vcpu_svm *svm) if (nested_svm_check_permissions(svm)) return 1; - svm->next_rip = kvm_rip_read(&svm->vcpu) + 3; ret = kvm_skip_emulated_instruction(&svm->vcpu); disable_gif(svm); @@ -3816,7 +3802,6 @@ static int invlpga_interception(struct vcpu_svm *svm) /* Let's treat INVLPGA the same as INVLPG (can be optimized!) */ kvm_mmu_invlpg(vcpu, kvm_rax_read(&svm->vcpu)); - svm->next_rip = kvm_rip_read(&svm->vcpu) + 3; return kvm_skip_emulated_instruction(&svm->vcpu); } @@ -3839,7 +3824,6 @@ static int xsetbv_interception(struct vcpu_svm *svm) u32 index = kvm_rcx_read(&svm->vcpu); if (kvm_set_xcr(&svm->vcpu, index, new_bv) == 0) { - svm->next_rip = kvm_rip_read(&svm->vcpu) + 3; return kvm_skip_emulated_instruction(&svm->vcpu); } @@ -3898,25 +3882,29 @@ static int task_switch_interception(struct vcpu_svm *svm) if (reason != TASK_SWITCH_GATE || int_type == SVM_EXITINTINFO_TYPE_SOFT || (int_type == SVM_EXITINTINFO_TYPE_EXEPT && - (int_vec == OF_VECTOR || int_vec == BP_VECTOR))) - skip_emulated_instruction(&svm->vcpu); + (int_vec == OF_VECTOR || int_vec == BP_VECTOR))) { + if (skip_emulated_instruction(&svm->vcpu) != EMULATE_DONE) + goto fail; + } if (int_type != SVM_EXITINTINFO_TYPE_SOFT) int_vec = -1; if (kvm_task_switch(&svm->vcpu, tss_selector, int_vec, reason, - has_error_code, error_code) == EMULATE_FAIL) { - svm->vcpu.run->exit_reason = KVM_EXIT_INTERNAL_ERROR; - svm->vcpu.run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; - svm->vcpu.run->internal.ndata = 0; - return 0; - } + has_error_code, error_code) == EMULATE_FAIL) + goto fail; + return 1; + +fail: + svm->vcpu.run->exit_reason = KVM_EXIT_INTERNAL_ERROR; + svm->vcpu.run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; + svm->vcpu.run->internal.ndata = 0; + return 0; } static int cpuid_interception(struct vcpu_svm *svm) { - svm->next_rip = kvm_rip_read(&svm->vcpu) + 2; return kvm_emulate_cpuid(&svm->vcpu); } @@ -4232,23 +4220,7 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) static int rdmsr_interception(struct vcpu_svm *svm) { - u32 ecx = kvm_rcx_read(&svm->vcpu); - struct msr_data msr_info; - - msr_info.index = ecx; - msr_info.host_initiated = false; - if (svm_get_msr(&svm->vcpu, &msr_info)) { - trace_kvm_msr_read_ex(ecx); - kvm_inject_gp(&svm->vcpu, 0); - return 1; - } else { - trace_kvm_msr_read(ecx, msr_info.data); - - kvm_rax_write(&svm->vcpu, msr_info.data & 0xffffffff); - kvm_rdx_write(&svm->vcpu, msr_info.data >> 32); - svm->next_rip = kvm_rip_read(&svm->vcpu) + 2; - return kvm_skip_emulated_instruction(&svm->vcpu); - } + return kvm_emulate_rdmsr(&svm->vcpu); } static int svm_set_vm_cr(struct kvm_vcpu *vcpu, u64 data) @@ -4438,23 +4410,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) static int wrmsr_interception(struct vcpu_svm *svm) { - struct msr_data msr; - u32 ecx = kvm_rcx_read(&svm->vcpu); - u64 data = kvm_read_edx_eax(&svm->vcpu); - - msr.data = data; - msr.index = ecx; - msr.host_initiated = false; - - svm->next_rip = kvm_rip_read(&svm->vcpu) + 2; - if (kvm_set_msr(&svm->vcpu, &msr)) { - trace_kvm_msr_write_ex(ecx, data); - kvm_inject_gp(&svm->vcpu, 0); - return 1; - } else { - trace_kvm_msr_write(ecx, data); - return kvm_skip_emulated_instruction(&svm->vcpu); - } + return kvm_emulate_wrmsr(&svm->vcpu); } static int msr_interception(struct vcpu_svm *svm) @@ -5025,9 +4981,14 @@ static int handle_exit(struct kvm_vcpu *vcpu) if (exit_code >= ARRAY_SIZE(svm_exit_handlers) || !svm_exit_handlers[exit_code]) { - WARN_ONCE(1, "svm: unexpected exit reason 0x%x\n", exit_code); - kvm_queue_exception(vcpu, UD_VECTOR); - return 1; + vcpu_unimpl(vcpu, "svm: unexpected exit reason 0x%x\n", exit_code); + dump_vmcb(vcpu); + vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; + vcpu->run->internal.suberror = + KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON; + vcpu->run->internal.ndata = 1; + vcpu->run->internal.data[0] = exit_code; + return 0; } return svm_exit_handlers[exit_code](svm); @@ -5274,7 +5235,8 @@ get_pi_vcpu_info(struct kvm *kvm, struct kvm_kernel_irq_routing_entry *e, kvm_set_msi_irq(kvm, e, &irq); - if (!kvm_intr_is_single_vcpu(kvm, &irq, &vcpu)) { + if (!kvm_intr_is_single_vcpu(kvm, &irq, &vcpu) || + !kvm_irq_is_postable(&irq)) { pr_debug("SVM: %s: use legacy intr remap mode for irq %u\n", __func__, irq.vector); return -1; @@ -5328,6 +5290,7 @@ static int svm_update_pi_irte(struct kvm *kvm, unsigned int host_irq, * 1. When cannot target interrupt to a specific vcpu. * 2. Unsetting posted interrupt. * 3. APIC virtialization 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 && kvm_vcpu_apicv_active(&svm->vcpu)) { @@ -5933,6 +5896,8 @@ static void svm_cpuid_update(struct kvm_vcpu *vcpu) guest_cpuid_clear(vcpu, X86_FEATURE_X2APIC); } +#define F(x) bit(X86_FEATURE_##x) + static void svm_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry) { switch (func) { @@ -5944,6 +5909,11 @@ static void svm_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry) if (nested) entry->ecx |= (1 << 2); /* Set SVM bit */ break; + case 0x80000008: + if (boot_cpu_has(X86_FEATURE_LS_CFG_SSBD) || + boot_cpu_has(X86_FEATURE_AMD_SSBD)) + entry->ebx |= F(VIRT_SSBD); + break; case 0x8000000A: entry->eax = 1; /* SVM revision 1 */ entry->ebx = 8; /* Lets support 8 ASIDs in case we add proper @@ -5954,11 +5924,11 @@ static void svm_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry) /* Support next_rip if host supports it */ if (boot_cpu_has(X86_FEATURE_NRIPS)) - entry->edx |= SVM_FEATURE_NRIP; + entry->edx |= F(NRIPS); /* Support NPT for the guest if enabled */ if (npt_enabled) - entry->edx |= SVM_FEATURE_NPT; + entry->edx |= F(NPT); break; case 0x8000001F: @@ -6067,6 +6037,7 @@ static const struct __x86_intercept { [x86_intercept_ins] = POST_EX(SVM_EXIT_IOIO), [x86_intercept_out] = POST_EX(SVM_EXIT_IOIO), [x86_intercept_outs] = POST_EX(SVM_EXIT_IOIO), + [x86_intercept_xsetbv] = PRE_EX(SVM_EXIT_XSETBV), }; #undef PRE_EX @@ -7193,6 +7164,21 @@ static bool svm_need_emulation_on_page_fault(struct kvm_vcpu *vcpu) return false; } +static bool svm_apic_init_signal_blocked(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + /* + * TODO: Last condition latch INIT signals on vCPU when + * vCPU is in guest-mode and vmcb12 defines intercept on INIT. + * To properly emulate the INIT intercept, SVM should implement + * kvm_x86_ops->check_nested_events() and call nested_svm_vmexit() + * there if an INIT signal is pending. + */ + return !gif_set(svm) || + (svm->vmcb->control.intercept & (1ULL << INTERCEPT_INIT)); +} + static struct kvm_x86_ops svm_x86_ops __ro_after_init = { .cpu_has_kvm_support = has_svm, .disabled_by_bios = is_disabled, @@ -7329,6 +7315,8 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = { .nested_get_evmcs_version = NULL, .need_emulation_on_page_fault = svm_need_emulation_on_page_fault, + + .apic_init_signal_blocked = svm_apic_init_signal_blocked, }; static int __init svm_init(void) diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index b5c831e79094d40467cf065a7056a3666e278237..7c741a0c5f808466354c7e786d81f2e6acdf12ee 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -232,17 +232,20 @@ TRACE_EVENT(kvm_exit, __field( u32, isa ) __field( u64, info1 ) __field( u64, info2 ) + __field( unsigned int, vcpu_id ) ), TP_fast_assign( __entry->exit_reason = exit_reason; __entry->guest_rip = kvm_rip_read(vcpu); __entry->isa = isa; + __entry->vcpu_id = vcpu->vcpu_id; kvm_x86_ops->get_exit_info(vcpu, &__entry->info1, &__entry->info2); ), - TP_printk("reason %s rip 0x%lx info %llx %llx", + TP_printk("vcpu %u reason %s rip 0x%lx info %llx %llx", + __entry->vcpu_id, (__entry->isa == KVM_ISA_VMX) ? __print_symbolic(__entry->exit_reason, VMX_EXIT_REASONS) : __print_symbolic(__entry->exit_reason, SVM_EXIT_REASONS), @@ -887,36 +890,27 @@ TRACE_EVENT(kvm_pml_full, TP_printk("vcpu %d: PML full", __entry->vcpu_id) ); -TRACE_EVENT(kvm_ple_window, - TP_PROTO(bool grow, unsigned int vcpu_id, int new, int old), - TP_ARGS(grow, vcpu_id, new, old), +TRACE_EVENT(kvm_ple_window_update, + TP_PROTO(unsigned int vcpu_id, unsigned int new, unsigned int old), + TP_ARGS(vcpu_id, new, old), TP_STRUCT__entry( - __field( bool, grow ) __field( unsigned int, vcpu_id ) - __field( int, new ) - __field( int, old ) + __field( unsigned int, new ) + __field( unsigned int, old ) ), TP_fast_assign( - __entry->grow = grow; __entry->vcpu_id = vcpu_id; __entry->new = new; __entry->old = old; ), - TP_printk("vcpu %u: ple_window %d (%s %d)", - __entry->vcpu_id, - __entry->new, - __entry->grow ? "grow" : "shrink", - __entry->old) + TP_printk("vcpu %u old %u new %u (%s)", + __entry->vcpu_id, __entry->old, __entry->new, + __entry->old < __entry->new ? "growed" : "shrinked") ); -#define trace_kvm_ple_window_grow(vcpu_id, new, old) \ - trace_kvm_ple_window(true, vcpu_id, new, old) -#define trace_kvm_ple_window_shrink(vcpu_id, new, old) \ - trace_kvm_ple_window(false, vcpu_id, new, old) - TRACE_EVENT(kvm_pvclock_update, TP_PROTO(unsigned int vcpu_id, struct pvclock_vcpu_time_info *pvclock), TP_ARGS(vcpu_id, pvclock), @@ -1320,7 +1314,7 @@ TRACE_EVENT(kvm_avic_incomplete_ipi, __entry->index = index; ), - TP_printk("vcpu=%u, icrh:icrl=%#010x:%08x, id=%u, index=%u\n", + TP_printk("vcpu=%u, icrh:icrl=%#010x:%08x, id=%u, index=%u", __entry->vcpu, __entry->icrh, __entry->icrl, __entry->id, __entry->index) ); @@ -1345,7 +1339,7 @@ TRACE_EVENT(kvm_avic_unaccelerated_access, __entry->vec = vec; ), - TP_printk("vcpu=%u, offset=%#x(%s), %s, %s, vec=%#x\n", + TP_printk("vcpu=%u, offset=%#x(%s), %s, %s, vec=%#x", __entry->vcpu, __entry->offset, __print_symbolic(__entry->offset, kvm_trace_symbol_apic), @@ -1462,6 +1456,46 @@ TRACE_EVENT(kvm_hv_send_ipi_ex, __entry->vector, __entry->format, __entry->valid_bank_mask) ); + +TRACE_EVENT(kvm_pv_tlb_flush, + TP_PROTO(unsigned int vcpu_id, bool need_flush_tlb), + TP_ARGS(vcpu_id, need_flush_tlb), + + TP_STRUCT__entry( + __field( unsigned int, vcpu_id ) + __field( bool, need_flush_tlb ) + ), + + TP_fast_assign( + __entry->vcpu_id = vcpu_id; + __entry->need_flush_tlb = need_flush_tlb; + ), + + TP_printk("vcpu %u need_flush_tlb %s", __entry->vcpu_id, + __entry->need_flush_tlb ? "true" : "false") +); + +/* + * Tracepoint for failed nested VMX VM-Enter. + */ +TRACE_EVENT(kvm_nested_vmenter_failed, + TP_PROTO(const char *msg, u32 err), + TP_ARGS(msg, err), + + TP_STRUCT__entry( + __field(const char *, msg) + __field(u32, err) + ), + + TP_fast_assign( + __entry->msg = msg; + __entry->err = err; + ), + + TP_printk("%s%s", __entry->msg, !__entry->err ? "" : + __print_symbolic(__entry->err, VMX_VMENTER_INSTRUCTION_ERRORS)) +); + #endif /* _TRACE_KVM_H */ #undef TRACE_INCLUDE_PATH diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index a3cba321b5c5ddb7b2730835c01635c0307e1bb1..1a10cd3519402d7c82dfe137e30d5e86c78aa66f 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -19,6 +19,14 @@ module_param_named(enable_shadow_vmcs, enable_shadow_vmcs, bool, S_IRUGO); static bool __read_mostly nested_early_check = 0; module_param(nested_early_check, bool, S_IRUGO); +#define CC(consistency_check) \ +({ \ + bool failed = (consistency_check); \ + if (failed) \ + trace_kvm_nested_vmenter_failed(#consistency_check, 0); \ + failed; \ +}) + /* * Hyper-V requires all of these, so mark them as supported even though * they are just treated the same as all-context. @@ -430,8 +438,8 @@ static int nested_vmx_check_io_bitmap_controls(struct kvm_vcpu *vcpu, if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS)) return 0; - if (!page_address_valid(vcpu, vmcs12->io_bitmap_a) || - !page_address_valid(vcpu, vmcs12->io_bitmap_b)) + if (CC(!page_address_valid(vcpu, vmcs12->io_bitmap_a)) || + CC(!page_address_valid(vcpu, vmcs12->io_bitmap_b))) return -EINVAL; return 0; @@ -443,7 +451,7 @@ static int nested_vmx_check_msr_bitmap_controls(struct kvm_vcpu *vcpu, if (!nested_cpu_has(vmcs12, CPU_BASED_USE_MSR_BITMAPS)) return 0; - if (!page_address_valid(vcpu, vmcs12->msr_bitmap)) + if (CC(!page_address_valid(vcpu, vmcs12->msr_bitmap))) return -EINVAL; return 0; @@ -455,7 +463,7 @@ static int nested_vmx_check_tpr_shadow_controls(struct kvm_vcpu *vcpu, if (!nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW)) return 0; - if (!page_address_valid(vcpu, vmcs12->virtual_apic_page_addr)) + if (CC(!page_address_valid(vcpu, vmcs12->virtual_apic_page_addr))) return -EINVAL; return 0; @@ -688,7 +696,7 @@ static int nested_vmx_check_apic_access_controls(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { if (nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES) && - !page_address_valid(vcpu, vmcs12->apic_access_addr)) + CC(!page_address_valid(vcpu, vmcs12->apic_access_addr))) return -EINVAL; else return 0; @@ -707,16 +715,15 @@ static int nested_vmx_check_apicv_controls(struct kvm_vcpu *vcpu, * If virtualize x2apic mode is enabled, * virtualize apic access must be disabled. */ - if (nested_cpu_has_virt_x2apic_mode(vmcs12) && - nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) + if (CC(nested_cpu_has_virt_x2apic_mode(vmcs12) && + nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES))) return -EINVAL; /* * If virtual interrupt delivery is enabled, * we must exit on external interrupts. */ - if (nested_cpu_has_vid(vmcs12) && - !nested_exit_on_intr(vcpu)) + if (CC(nested_cpu_has_vid(vmcs12) && !nested_exit_on_intr(vcpu))) return -EINVAL; /* @@ -727,15 +734,15 @@ static int nested_vmx_check_apicv_controls(struct kvm_vcpu *vcpu, * bits 5:0 of posted_intr_desc_addr should be zero. */ if (nested_cpu_has_posted_intr(vmcs12) && - (!nested_cpu_has_vid(vmcs12) || - !nested_exit_intr_ack_set(vcpu) || - (vmcs12->posted_intr_nv & 0xff00) || - (vmcs12->posted_intr_desc_addr & 0x3f) || - (vmcs12->posted_intr_desc_addr >> cpuid_maxphyaddr(vcpu)))) + (CC(!nested_cpu_has_vid(vmcs12)) || + CC(!nested_exit_intr_ack_set(vcpu)) || + CC((vmcs12->posted_intr_nv & 0xff00)) || + CC((vmcs12->posted_intr_desc_addr & 0x3f)) || + CC((vmcs12->posted_intr_desc_addr >> cpuid_maxphyaddr(vcpu))))) return -EINVAL; /* tpr shadow is needed by all apicv features. */ - if (!nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW)) + if (CC(!nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW))) return -EINVAL; return 0; @@ -759,10 +766,12 @@ static int nested_vmx_check_msr_switch(struct kvm_vcpu *vcpu, static int nested_vmx_check_exit_msr_switch_controls(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { - if (nested_vmx_check_msr_switch(vcpu, vmcs12->vm_exit_msr_load_count, - vmcs12->vm_exit_msr_load_addr) || - nested_vmx_check_msr_switch(vcpu, vmcs12->vm_exit_msr_store_count, - vmcs12->vm_exit_msr_store_addr)) + if (CC(nested_vmx_check_msr_switch(vcpu, + vmcs12->vm_exit_msr_load_count, + vmcs12->vm_exit_msr_load_addr)) || + CC(nested_vmx_check_msr_switch(vcpu, + vmcs12->vm_exit_msr_store_count, + vmcs12->vm_exit_msr_store_addr))) return -EINVAL; return 0; @@ -771,8 +780,9 @@ static int nested_vmx_check_exit_msr_switch_controls(struct kvm_vcpu *vcpu, static int nested_vmx_check_entry_msr_switch_controls(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { - if (nested_vmx_check_msr_switch(vcpu, vmcs12->vm_entry_msr_load_count, - vmcs12->vm_entry_msr_load_addr)) + if (CC(nested_vmx_check_msr_switch(vcpu, + vmcs12->vm_entry_msr_load_count, + vmcs12->vm_entry_msr_load_addr))) return -EINVAL; return 0; @@ -784,8 +794,8 @@ static int nested_vmx_check_pml_controls(struct kvm_vcpu *vcpu, if (!nested_cpu_has_pml(vmcs12)) return 0; - if (!nested_cpu_has_ept(vmcs12) || - !page_address_valid(vcpu, vmcs12->pml_address)) + if (CC(!nested_cpu_has_ept(vmcs12)) || + CC(!page_address_valid(vcpu, vmcs12->pml_address))) return -EINVAL; return 0; @@ -794,8 +804,8 @@ static int nested_vmx_check_pml_controls(struct kvm_vcpu *vcpu, static int nested_vmx_check_unrestricted_guest_controls(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { - if (nested_cpu_has2(vmcs12, SECONDARY_EXEC_UNRESTRICTED_GUEST) && - !nested_cpu_has_ept(vmcs12)) + if (CC(nested_cpu_has2(vmcs12, SECONDARY_EXEC_UNRESTRICTED_GUEST) && + !nested_cpu_has_ept(vmcs12))) return -EINVAL; return 0; } @@ -803,8 +813,8 @@ static int nested_vmx_check_unrestricted_guest_controls(struct kvm_vcpu *vcpu, static int nested_vmx_check_mode_based_ept_exec_controls(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { - if (nested_cpu_has2(vmcs12, SECONDARY_EXEC_MODE_BASED_EPT_EXEC) && - !nested_cpu_has_ept(vmcs12)) + if (CC(nested_cpu_has2(vmcs12, SECONDARY_EXEC_MODE_BASED_EPT_EXEC) && + !nested_cpu_has_ept(vmcs12))) return -EINVAL; return 0; } @@ -815,8 +825,8 @@ static int nested_vmx_check_shadow_vmcs_controls(struct kvm_vcpu *vcpu, if (!nested_cpu_has_shadow_vmcs(vmcs12)) return 0; - if (!page_address_valid(vcpu, vmcs12->vmread_bitmap) || - !page_address_valid(vcpu, vmcs12->vmwrite_bitmap)) + if (CC(!page_address_valid(vcpu, vmcs12->vmread_bitmap)) || + CC(!page_address_valid(vcpu, vmcs12->vmwrite_bitmap))) return -EINVAL; return 0; @@ -826,12 +836,12 @@ static int nested_vmx_msr_check_common(struct kvm_vcpu *vcpu, struct vmx_msr_entry *e) { /* x2APIC MSR accesses are not allowed */ - if (vcpu->arch.apic_base & X2APIC_ENABLE && e->index >> 8 == 0x8) + if (CC(vcpu->arch.apic_base & X2APIC_ENABLE && e->index >> 8 == 0x8)) return -EINVAL; - if (e->index == MSR_IA32_UCODE_WRITE || /* SDM Table 35-2 */ - e->index == MSR_IA32_UCODE_REV) + if (CC(e->index == MSR_IA32_UCODE_WRITE) || /* SDM Table 35-2 */ + CC(e->index == MSR_IA32_UCODE_REV)) return -EINVAL; - if (e->reserved != 0) + if (CC(e->reserved != 0)) return -EINVAL; return 0; } @@ -839,9 +849,9 @@ static int nested_vmx_msr_check_common(struct kvm_vcpu *vcpu, static int nested_vmx_load_msr_check(struct kvm_vcpu *vcpu, struct vmx_msr_entry *e) { - if (e->index == MSR_FS_BASE || - e->index == MSR_GS_BASE || - e->index == MSR_IA32_SMM_MONITOR_CTL || /* SMM is not supported */ + if (CC(e->index == MSR_FS_BASE) || + CC(e->index == MSR_GS_BASE) || + CC(e->index == MSR_IA32_SMM_MONITOR_CTL) || /* SMM is not supported */ nested_vmx_msr_check_common(vcpu, e)) return -EINVAL; return 0; @@ -850,7 +860,7 @@ static int nested_vmx_load_msr_check(struct kvm_vcpu *vcpu, static int nested_vmx_store_msr_check(struct kvm_vcpu *vcpu, struct vmx_msr_entry *e) { - if (e->index == MSR_IA32_SMBASE || /* SMM is not supported */ + if (CC(e->index == MSR_IA32_SMBASE) || /* SMM is not supported */ nested_vmx_msr_check_common(vcpu, e)) return -EINVAL; return 0; @@ -864,9 +874,7 @@ static u32 nested_vmx_load_msr(struct kvm_vcpu *vcpu, u64 gpa, u32 count) { u32 i; struct vmx_msr_entry e; - struct msr_data msr; - msr.host_initiated = false; for (i = 0; i < count; i++) { if (kvm_vcpu_read_guest(vcpu, gpa + i * sizeof(e), &e, sizeof(e))) { @@ -881,9 +889,7 @@ static u32 nested_vmx_load_msr(struct kvm_vcpu *vcpu, u64 gpa, u32 count) __func__, i, e.index, e.reserved); goto fail; } - msr.index = e.index; - msr.data = e.value; - if (kvm_set_msr(vcpu, &msr)) { + if (kvm_set_msr(vcpu, e.index, e.value)) { pr_debug_ratelimited( "%s cannot write MSR (%u, 0x%x, 0x%llx)\n", __func__, i, e.index, e.value); @@ -897,11 +903,11 @@ static u32 nested_vmx_load_msr(struct kvm_vcpu *vcpu, u64 gpa, u32 count) static int nested_vmx_store_msr(struct kvm_vcpu *vcpu, u64 gpa, u32 count) { + u64 data; u32 i; struct vmx_msr_entry e; for (i = 0; i < count; i++) { - struct msr_data msr_info; if (kvm_vcpu_read_guest(vcpu, gpa + i * sizeof(e), &e, 2 * sizeof(u32))) { @@ -916,9 +922,7 @@ static int nested_vmx_store_msr(struct kvm_vcpu *vcpu, u64 gpa, u32 count) __func__, i, e.index, e.reserved); return -EINVAL; } - msr_info.host_initiated = false; - msr_info.index = e.index; - if (kvm_get_msr(vcpu, &msr_info)) { + if (kvm_get_msr(vcpu, e.index, &data)) { pr_debug_ratelimited( "%s cannot read MSR (%u, 0x%x)\n", __func__, i, e.index); @@ -927,10 +931,10 @@ static int nested_vmx_store_msr(struct kvm_vcpu *vcpu, u64 gpa, u32 count) if (kvm_vcpu_write_guest(vcpu, gpa + i * sizeof(e) + offsetof(struct vmx_msr_entry, value), - &msr_info.data, sizeof(msr_info.data))) { + &data, sizeof(data))) { pr_debug_ratelimited( "%s cannot write MSR (%u, 0x%x, 0x%llx)\n", - __func__, i, e.index, msr_info.data); + __func__, i, e.index, data); return -EINVAL; } } @@ -955,7 +959,7 @@ static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool ne u32 *entry_failure_code) { if (cr3 != kvm_read_cr3(vcpu) || (!nested_ept && pdptrs_changed(vcpu))) { - if (!nested_cr3_valid(vcpu, cr3)) { + if (CC(!nested_cr3_valid(vcpu, cr3))) { *entry_failure_code = ENTRY_FAIL_DEFAULT; return -EINVAL; } @@ -965,7 +969,7 @@ static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool ne * must not be dereferenced. */ if (is_pae_paging(vcpu) && !nested_ept) { - if (!load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3)) { + if (CC(!load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3))) { *entry_failure_code = ENTRY_FAIL_PDPTE; return -EINVAL; } @@ -2411,12 +2415,12 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, static int nested_vmx_check_nmi_controls(struct vmcs12 *vmcs12) { - if (!nested_cpu_has_nmi_exiting(vmcs12) && - nested_cpu_has_virtual_nmis(vmcs12)) + if (CC(!nested_cpu_has_nmi_exiting(vmcs12) && + nested_cpu_has_virtual_nmis(vmcs12))) return -EINVAL; - if (!nested_cpu_has_virtual_nmis(vmcs12) && - nested_cpu_has(vmcs12, CPU_BASED_VIRTUAL_NMI_PENDING)) + if (CC(!nested_cpu_has_virtual_nmis(vmcs12) && + nested_cpu_has(vmcs12, CPU_BASED_VIRTUAL_NMI_PENDING))) return -EINVAL; return 0; @@ -2430,11 +2434,11 @@ static bool valid_ept_address(struct kvm_vcpu *vcpu, u64 address) /* Check for memory type validity */ switch (address & VMX_EPTP_MT_MASK) { case VMX_EPTP_MT_UC: - if (!(vmx->nested.msrs.ept_caps & VMX_EPTP_UC_BIT)) + if (CC(!(vmx->nested.msrs.ept_caps & VMX_EPTP_UC_BIT))) return false; break; case VMX_EPTP_MT_WB: - if (!(vmx->nested.msrs.ept_caps & VMX_EPTP_WB_BIT)) + if (CC(!(vmx->nested.msrs.ept_caps & VMX_EPTP_WB_BIT))) return false; break; default: @@ -2442,16 +2446,16 @@ static bool valid_ept_address(struct kvm_vcpu *vcpu, u64 address) } /* only 4 levels page-walk length are valid */ - if ((address & VMX_EPTP_PWL_MASK) != VMX_EPTP_PWL_4) + if (CC((address & VMX_EPTP_PWL_MASK) != VMX_EPTP_PWL_4)) return false; /* Reserved bits should not be set */ - if (address >> maxphyaddr || ((address >> 7) & 0x1f)) + if (CC(address >> maxphyaddr || ((address >> 7) & 0x1f))) return false; /* AD, if set, should be supported */ if (address & VMX_EPTP_AD_ENABLE_BIT) { - if (!(vmx->nested.msrs.ept_caps & VMX_EPT_AD_BIT)) + if (CC(!(vmx->nested.msrs.ept_caps & VMX_EPT_AD_BIT))) return false; } @@ -2466,21 +2470,21 @@ static int nested_check_vm_execution_controls(struct kvm_vcpu *vcpu, { struct vcpu_vmx *vmx = to_vmx(vcpu); - if (!vmx_control_verify(vmcs12->pin_based_vm_exec_control, - vmx->nested.msrs.pinbased_ctls_low, - vmx->nested.msrs.pinbased_ctls_high) || - !vmx_control_verify(vmcs12->cpu_based_vm_exec_control, - vmx->nested.msrs.procbased_ctls_low, - vmx->nested.msrs.procbased_ctls_high)) + if (CC(!vmx_control_verify(vmcs12->pin_based_vm_exec_control, + vmx->nested.msrs.pinbased_ctls_low, + vmx->nested.msrs.pinbased_ctls_high)) || + CC(!vmx_control_verify(vmcs12->cpu_based_vm_exec_control, + vmx->nested.msrs.procbased_ctls_low, + vmx->nested.msrs.procbased_ctls_high))) return -EINVAL; if (nested_cpu_has(vmcs12, CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) && - !vmx_control_verify(vmcs12->secondary_vm_exec_control, - vmx->nested.msrs.secondary_ctls_low, - vmx->nested.msrs.secondary_ctls_high)) + CC(!vmx_control_verify(vmcs12->secondary_vm_exec_control, + vmx->nested.msrs.secondary_ctls_low, + vmx->nested.msrs.secondary_ctls_high))) return -EINVAL; - if (vmcs12->cr3_target_count > nested_cpu_vmx_misc_cr3_count(vcpu) || + if (CC(vmcs12->cr3_target_count > nested_cpu_vmx_misc_cr3_count(vcpu)) || nested_vmx_check_io_bitmap_controls(vcpu, vmcs12) || nested_vmx_check_msr_bitmap_controls(vcpu, vmcs12) || nested_vmx_check_tpr_shadow_controls(vcpu, vmcs12) || @@ -2491,7 +2495,7 @@ static int nested_check_vm_execution_controls(struct kvm_vcpu *vcpu, nested_vmx_check_unrestricted_guest_controls(vcpu, vmcs12) || nested_vmx_check_mode_based_ept_exec_controls(vcpu, vmcs12) || nested_vmx_check_shadow_vmcs_controls(vcpu, vmcs12) || - (nested_cpu_has_vpid(vmcs12) && !vmcs12->virtual_processor_id)) + CC(nested_cpu_has_vpid(vmcs12) && !vmcs12->virtual_processor_id)) return -EINVAL; if (!nested_cpu_has_preemption_timer(vmcs12) && @@ -2499,17 +2503,17 @@ static int nested_check_vm_execution_controls(struct kvm_vcpu *vcpu, return -EINVAL; if (nested_cpu_has_ept(vmcs12) && - !valid_ept_address(vcpu, vmcs12->ept_pointer)) + CC(!valid_ept_address(vcpu, vmcs12->ept_pointer))) return -EINVAL; if (nested_cpu_has_vmfunc(vmcs12)) { - if (vmcs12->vm_function_control & - ~vmx->nested.msrs.vmfunc_controls) + if (CC(vmcs12->vm_function_control & + ~vmx->nested.msrs.vmfunc_controls)) return -EINVAL; if (nested_cpu_has_eptp_switching(vmcs12)) { - if (!nested_cpu_has_ept(vmcs12) || - !page_address_valid(vcpu, vmcs12->eptp_list_address)) + if (CC(!nested_cpu_has_ept(vmcs12)) || + CC(!page_address_valid(vcpu, vmcs12->eptp_list_address))) return -EINVAL; } } @@ -2525,10 +2529,10 @@ static int nested_check_vm_exit_controls(struct kvm_vcpu *vcpu, { struct vcpu_vmx *vmx = to_vmx(vcpu); - if (!vmx_control_verify(vmcs12->vm_exit_controls, - vmx->nested.msrs.exit_ctls_low, - vmx->nested.msrs.exit_ctls_high) || - nested_vmx_check_exit_msr_switch_controls(vcpu, vmcs12)) + if (CC(!vmx_control_verify(vmcs12->vm_exit_controls, + vmx->nested.msrs.exit_ctls_low, + vmx->nested.msrs.exit_ctls_high)) || + CC(nested_vmx_check_exit_msr_switch_controls(vcpu, vmcs12))) return -EINVAL; return 0; @@ -2542,9 +2546,9 @@ static int nested_check_vm_entry_controls(struct kvm_vcpu *vcpu, { struct vcpu_vmx *vmx = to_vmx(vcpu); - if (!vmx_control_verify(vmcs12->vm_entry_controls, - vmx->nested.msrs.entry_ctls_low, - vmx->nested.msrs.entry_ctls_high)) + if (CC(!vmx_control_verify(vmcs12->vm_entry_controls, + vmx->nested.msrs.entry_ctls_low, + vmx->nested.msrs.entry_ctls_high))) return -EINVAL; /* @@ -2564,31 +2568,31 @@ static int nested_check_vm_entry_controls(struct kvm_vcpu *vcpu, bool prot_mode = !urg || vmcs12->guest_cr0 & X86_CR0_PE; /* VM-entry interruption-info field: interruption type */ - if (intr_type == INTR_TYPE_RESERVED || - (intr_type == INTR_TYPE_OTHER_EVENT && - !nested_cpu_supports_monitor_trap_flag(vcpu))) + if (CC(intr_type == INTR_TYPE_RESERVED) || + CC(intr_type == INTR_TYPE_OTHER_EVENT && + !nested_cpu_supports_monitor_trap_flag(vcpu))) return -EINVAL; /* VM-entry interruption-info field: vector */ - if ((intr_type == INTR_TYPE_NMI_INTR && vector != NMI_VECTOR) || - (intr_type == INTR_TYPE_HARD_EXCEPTION && vector > 31) || - (intr_type == INTR_TYPE_OTHER_EVENT && vector != 0)) + if (CC(intr_type == INTR_TYPE_NMI_INTR && vector != NMI_VECTOR) || + CC(intr_type == INTR_TYPE_HARD_EXCEPTION && vector > 31) || + CC(intr_type == INTR_TYPE_OTHER_EVENT && vector != 0)) return -EINVAL; /* VM-entry interruption-info field: deliver error code */ should_have_error_code = intr_type == INTR_TYPE_HARD_EXCEPTION && prot_mode && x86_exception_has_error_code(vector); - if (has_error_code != should_have_error_code) + if (CC(has_error_code != should_have_error_code)) return -EINVAL; /* VM-entry exception error code */ - if (has_error_code && - vmcs12->vm_entry_exception_error_code & GENMASK(31, 15)) + if (CC(has_error_code && + vmcs12->vm_entry_exception_error_code & GENMASK(31, 15))) return -EINVAL; /* VM-entry interruption-info field: reserved bits */ - if (intr_info & INTR_INFO_RESVD_BITS_MASK) + if (CC(intr_info & INTR_INFO_RESVD_BITS_MASK)) return -EINVAL; /* VM-entry instruction length */ @@ -2596,9 +2600,9 @@ static int nested_check_vm_entry_controls(struct kvm_vcpu *vcpu, case INTR_TYPE_SOFT_EXCEPTION: case INTR_TYPE_SOFT_INTR: case INTR_TYPE_PRIV_SW_EXCEPTION: - if ((vmcs12->vm_entry_instruction_len > 15) || - (vmcs12->vm_entry_instruction_len == 0 && - !nested_cpu_has_zero_length_injection(vcpu))) + if (CC(vmcs12->vm_entry_instruction_len > 15) || + CC(vmcs12->vm_entry_instruction_len == 0 && + CC(!nested_cpu_has_zero_length_injection(vcpu)))) return -EINVAL; } } @@ -2625,40 +2629,40 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu, { bool ia32e; - if (!nested_host_cr0_valid(vcpu, vmcs12->host_cr0) || - !nested_host_cr4_valid(vcpu, vmcs12->host_cr4) || - !nested_cr3_valid(vcpu, vmcs12->host_cr3)) + if (CC(!nested_host_cr0_valid(vcpu, vmcs12->host_cr0)) || + CC(!nested_host_cr4_valid(vcpu, vmcs12->host_cr4)) || + CC(!nested_cr3_valid(vcpu, vmcs12->host_cr3))) return -EINVAL; - if (is_noncanonical_address(vmcs12->host_ia32_sysenter_esp, vcpu) || - is_noncanonical_address(vmcs12->host_ia32_sysenter_eip, vcpu)) + if (CC(is_noncanonical_address(vmcs12->host_ia32_sysenter_esp, vcpu)) || + CC(is_noncanonical_address(vmcs12->host_ia32_sysenter_eip, vcpu))) return -EINVAL; if ((vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PAT) && - !kvm_pat_valid(vmcs12->host_ia32_pat)) + CC(!kvm_pat_valid(vmcs12->host_ia32_pat))) return -EINVAL; ia32e = (vmcs12->vm_exit_controls & VM_EXIT_HOST_ADDR_SPACE_SIZE) != 0; - if (vmcs12->host_cs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) || - vmcs12->host_ss_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) || - vmcs12->host_ds_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) || - vmcs12->host_es_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) || - vmcs12->host_fs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) || - vmcs12->host_gs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) || - vmcs12->host_tr_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) || - vmcs12->host_cs_selector == 0 || - vmcs12->host_tr_selector == 0 || - (vmcs12->host_ss_selector == 0 && !ia32e)) + if (CC(vmcs12->host_cs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK)) || + CC(vmcs12->host_ss_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK)) || + CC(vmcs12->host_ds_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK)) || + CC(vmcs12->host_es_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK)) || + CC(vmcs12->host_fs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK)) || + CC(vmcs12->host_gs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK)) || + CC(vmcs12->host_tr_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK)) || + CC(vmcs12->host_cs_selector == 0) || + CC(vmcs12->host_tr_selector == 0) || + CC(vmcs12->host_ss_selector == 0 && !ia32e)) return -EINVAL; #ifdef CONFIG_X86_64 - if (is_noncanonical_address(vmcs12->host_fs_base, vcpu) || - is_noncanonical_address(vmcs12->host_gs_base, vcpu) || - is_noncanonical_address(vmcs12->host_gdtr_base, vcpu) || - is_noncanonical_address(vmcs12->host_idtr_base, vcpu) || - is_noncanonical_address(vmcs12->host_tr_base, vcpu)) + if (CC(is_noncanonical_address(vmcs12->host_fs_base, vcpu)) || + CC(is_noncanonical_address(vmcs12->host_gs_base, vcpu)) || + CC(is_noncanonical_address(vmcs12->host_gdtr_base, vcpu)) || + CC(is_noncanonical_address(vmcs12->host_idtr_base, vcpu)) || + CC(is_noncanonical_address(vmcs12->host_tr_base, vcpu))) return -EINVAL; #endif @@ -2669,9 +2673,9 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu, * the host address-space size VM-exit control. */ if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER) { - if (!kvm_valid_efer(vcpu, vmcs12->host_ia32_efer) || - ia32e != !!(vmcs12->host_ia32_efer & EFER_LMA) || - ia32e != !!(vmcs12->host_ia32_efer & EFER_LME)) + if (CC(!kvm_valid_efer(vcpu, vmcs12->host_ia32_efer)) || + CC(ia32e != !!(vmcs12->host_ia32_efer & EFER_LMA)) || + CC(ia32e != !!(vmcs12->host_ia32_efer & EFER_LME))) return -EINVAL; } @@ -2688,16 +2692,16 @@ static int nested_vmx_check_vmcs_link_ptr(struct kvm_vcpu *vcpu, if (vmcs12->vmcs_link_pointer == -1ull) return 0; - if (!page_address_valid(vcpu, vmcs12->vmcs_link_pointer)) + if (CC(!page_address_valid(vcpu, vmcs12->vmcs_link_pointer))) return -EINVAL; - if (kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->vmcs_link_pointer), &map)) + if (CC(kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->vmcs_link_pointer), &map))) return -EINVAL; shadow = map.hva; - if (shadow->hdr.revision_id != VMCS12_REVISION || - shadow->hdr.shadow_vmcs != nested_cpu_has_shadow_vmcs(vmcs12)) + if (CC(shadow->hdr.revision_id != VMCS12_REVISION) || + CC(shadow->hdr.shadow_vmcs != nested_cpu_has_shadow_vmcs(vmcs12))) r = -EINVAL; kvm_vcpu_unmap(vcpu, &map, false); @@ -2709,8 +2713,8 @@ static int nested_vmx_check_vmcs_link_ptr(struct kvm_vcpu *vcpu, */ static int nested_check_guest_non_reg_state(struct vmcs12 *vmcs12) { - if (vmcs12->guest_activity_state != GUEST_ACTIVITY_ACTIVE && - vmcs12->guest_activity_state != GUEST_ACTIVITY_HLT) + if (CC(vmcs12->guest_activity_state != GUEST_ACTIVITY_ACTIVE && + vmcs12->guest_activity_state != GUEST_ACTIVITY_HLT)) return -EINVAL; return 0; @@ -2724,12 +2728,12 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu, *exit_qual = ENTRY_FAIL_DEFAULT; - if (!nested_guest_cr0_valid(vcpu, vmcs12->guest_cr0) || - !nested_guest_cr4_valid(vcpu, vmcs12->guest_cr4)) + if (CC(!nested_guest_cr0_valid(vcpu, vmcs12->guest_cr0)) || + CC(!nested_guest_cr4_valid(vcpu, vmcs12->guest_cr4))) return -EINVAL; if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PAT) && - !kvm_pat_valid(vmcs12->guest_ia32_pat)) + CC(!kvm_pat_valid(vmcs12->guest_ia32_pat))) return -EINVAL; if (nested_vmx_check_vmcs_link_ptr(vcpu, vmcs12)) { @@ -2749,16 +2753,16 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu, if (to_vmx(vcpu)->nested.nested_run_pending && (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER)) { ia32e = (vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) != 0; - if (!kvm_valid_efer(vcpu, vmcs12->guest_ia32_efer) || - ia32e != !!(vmcs12->guest_ia32_efer & EFER_LMA) || - ((vmcs12->guest_cr0 & X86_CR0_PG) && - ia32e != !!(vmcs12->guest_ia32_efer & EFER_LME))) + if (CC(!kvm_valid_efer(vcpu, vmcs12->guest_ia32_efer)) || + CC(ia32e != !!(vmcs12->guest_ia32_efer & EFER_LMA)) || + CC(((vmcs12->guest_cr0 & X86_CR0_PG) && + ia32e != !!(vmcs12->guest_ia32_efer & EFER_LME)))) return -EINVAL; } if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS) && - (is_noncanonical_address(vmcs12->guest_bndcfgs & PAGE_MASK, vcpu) || - (vmcs12->guest_bndcfgs & MSR_IA32_BNDCFGS_RSVD))) + (CC(is_noncanonical_address(vmcs12->guest_bndcfgs & PAGE_MASK, vcpu)) || + CC((vmcs12->guest_bndcfgs & MSR_IA32_BNDCFGS_RSVD)))) return -EINVAL; if (nested_check_guest_non_reg_state(vmcs12)) @@ -2841,9 +2845,13 @@ static int nested_vmx_check_vmentry_hw(struct kvm_vcpu *vcpu) vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr); if (vm_fail) { + u32 error = vmcs_read32(VM_INSTRUCTION_ERROR); + preempt_enable(); - WARN_ON_ONCE(vmcs_read32(VM_INSTRUCTION_ERROR) != - VMXERR_ENTRY_INVALID_CONTROL_FIELD); + + trace_kvm_nested_vmenter_failed( + "early hardware check VM-instruction error: ", error); + WARN_ON_ONCE(error != VMXERR_ENTRY_INVALID_CONTROL_FIELD); return 1; } @@ -3401,6 +3409,15 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr) unsigned long exit_qual; bool block_nested_events = vmx->nested.nested_run_pending || kvm_event_needs_reinjection(vcpu); + struct kvm_lapic *apic = vcpu->arch.apic; + + if (lapic_in_kernel(vcpu) && + test_bit(KVM_APIC_INIT, &apic->pending_events)) { + if (block_nested_events) + return -EBUSY; + nested_vmx_vmexit(vcpu, EXIT_REASON_INIT_SIGNAL, 0, 0); + return 0; + } if (vcpu->arch.exception.pending && nested_vmx_check_exception(vcpu, &exit_qual)) { @@ -3889,7 +3906,6 @@ static void nested_vmx_restore_host_state(struct kvm_vcpu *vcpu) struct vmcs12 *vmcs12 = get_vmcs12(vcpu); struct vcpu_vmx *vmx = to_vmx(vcpu); struct vmx_msr_entry g, h; - struct msr_data msr; gpa_t gpa; u32 i, j; @@ -3949,7 +3965,6 @@ static void nested_vmx_restore_host_state(struct kvm_vcpu *vcpu) * from the guest value. The intent is to stuff host state as * silently as possible, not to fully process the exit load list. */ - msr.host_initiated = false; for (i = 0; i < vmcs12->vm_entry_msr_load_count; i++) { gpa = vmcs12->vm_entry_msr_load_addr + (i * sizeof(g)); if (kvm_vcpu_read_guest(vcpu, gpa, &g, sizeof(g))) { @@ -3979,9 +3994,7 @@ static void nested_vmx_restore_host_state(struct kvm_vcpu *vcpu) goto vmabort; } - msr.index = h.index; - msr.data = h.value; - if (kvm_set_msr(vcpu, &msr)) { + if (kvm_set_msr(vcpu, h.index, h.value)) { pr_debug_ratelimited( "%s WRMSR failed (%u, 0x%x, 0x%llx)\n", __func__, j, h.index, h.value); @@ -4466,7 +4479,12 @@ static int handle_vmoff(struct kvm_vcpu *vcpu) { if (!nested_vmx_check_permission(vcpu)) return 1; + free_nested(vcpu); + + /* Process a latched INIT during time CPU was in VMX operation */ + kvm_make_request(KVM_REQ_EVENT, vcpu); + return nested_vmx_succeed(vcpu); } @@ -5261,8 +5279,9 @@ bool nested_vmx_exit_reflected(struct kvm_vcpu *vcpu, u32 exit_reason) return false; if (unlikely(vmx->fail)) { - pr_info_ratelimited("%s failed vm entry %x\n", __func__, - vmcs_read32(VM_INSTRUCTION_ERROR)); + trace_kvm_nested_vmenter_failed( + "hardware VM-instruction error: ", + vmcs_read32(VM_INSTRUCTION_ERROR)); return true; } diff --git a/arch/x86/kvm/vmx/vmenter.S b/arch/x86/kvm/vmx/vmenter.S index 4010d519eb8c2d98f80f02b2c19259ea4a8bd967..751a384c2eb0dae2f5a1c946fb1b05a976005504 100644 --- a/arch/x86/kvm/vmx/vmenter.S +++ b/arch/x86/kvm/vmx/vmenter.S @@ -94,7 +94,7 @@ ENDPROC(vmx_vmexit) /** * __vmx_vcpu_run - Run a vCPU via a transition to VMX guest mode - * @vmx: struct vcpu_vmx * + * @vmx: struct vcpu_vmx * (forwarded to vmx_update_host_rsp) * @regs: unsigned long * (to guest registers) * @launched: %true if the VMCS has been launched * @@ -151,7 +151,7 @@ ENTRY(__vmx_vcpu_run) mov VCPU_R14(%_ASM_AX), %r14 mov VCPU_R15(%_ASM_AX), %r15 #endif - /* Load guest RAX. This kills the vmx_vcpu pointer! */ + /* Load guest RAX. This kills the @regs pointer! */ mov VCPU_RAX(%_ASM_AX), %_ASM_AX /* Enter guest mode */ diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index c030c96fc81a817f6e11e3b1580aa907b8bc63f7..4a99be1fae4e58193116d5e08a98ef42a4debd2b 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -1472,8 +1472,11 @@ static int vmx_rtit_ctl_check(struct kvm_vcpu *vcpu, u64 data) return 0; } - -static void skip_emulated_instruction(struct kvm_vcpu *vcpu) +/* + * Returns an int to be compatible with SVM implementation (which can fail). + * Do not use directly, use skip_emulated_instruction() instead. + */ +static int __skip_emulated_instruction(struct kvm_vcpu *vcpu) { unsigned long rip; @@ -1483,6 +1486,13 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu) /* skipping an emulated instruction also counts */ vmx_set_interrupt_shadow(vcpu, 0); + + return EMULATE_DONE; +} + +static inline void skip_emulated_instruction(struct kvm_vcpu *vcpu) +{ + (void)__skip_emulated_instruction(vcpu); } static void vmx_clear_hlt(struct kvm_vcpu *vcpu) @@ -4026,7 +4036,7 @@ static void ept_set_mmio_spte_mask(void) * of an EPT paging-structure entry is 110b (write/execute). */ kvm_mmu_set_mmio_spte_mask(VMX_EPT_RWX_MASK, - VMX_EPT_MISCONFIG_WX_VALUE); + VMX_EPT_MISCONFIG_WX_VALUE, 0); } #define VMX_XSS_EXIT_BITMAP 0 @@ -4152,6 +4162,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) vcpu->arch.microcode_version = 0x100000000ULL; vmx->vcpu.arch.regs[VCPU_REGS_RDX] = get_rdx_init_val(); + vmx->hv_deadline_tsc = -1; kvm_set_cr8(vcpu, 0); if (!init_event) { @@ -4856,41 +4867,12 @@ static int handle_cpuid(struct kvm_vcpu *vcpu) static int handle_rdmsr(struct kvm_vcpu *vcpu) { - u32 ecx = kvm_rcx_read(vcpu); - struct msr_data msr_info; - - msr_info.index = ecx; - msr_info.host_initiated = false; - if (vmx_get_msr(vcpu, &msr_info)) { - trace_kvm_msr_read_ex(ecx); - kvm_inject_gp(vcpu, 0); - return 1; - } - - trace_kvm_msr_read(ecx, msr_info.data); - - kvm_rax_write(vcpu, msr_info.data & -1u); - kvm_rdx_write(vcpu, (msr_info.data >> 32) & -1u); - return kvm_skip_emulated_instruction(vcpu); + return kvm_emulate_rdmsr(vcpu); } static int handle_wrmsr(struct kvm_vcpu *vcpu) { - struct msr_data msr; - u32 ecx = kvm_rcx_read(vcpu); - u64 data = kvm_read_edx_eax(vcpu); - - msr.data = data; - msr.index = ecx; - msr.host_initiated = false; - if (kvm_set_msr(vcpu, &msr) != 0) { - trace_kvm_msr_write_ex(ecx, data); - kvm_inject_gp(vcpu, 0); - return 1; - } - - trace_kvm_msr_write(ecx, data); - return kvm_skip_emulated_instruction(vcpu); + return kvm_emulate_wrmsr(vcpu); } static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu) @@ -5227,31 +5209,33 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu) static void grow_ple_window(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); - int old = vmx->ple_window; + unsigned int old = vmx->ple_window; vmx->ple_window = __grow_ple_window(old, ple_window, ple_window_grow, ple_window_max); - if (vmx->ple_window != old) + if (vmx->ple_window != old) { vmx->ple_window_dirty = true; - - trace_kvm_ple_window_grow(vcpu->vcpu_id, vmx->ple_window, old); + trace_kvm_ple_window_update(vcpu->vcpu_id, + vmx->ple_window, old); + } } static void shrink_ple_window(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); - int old = vmx->ple_window; + unsigned int old = vmx->ple_window; vmx->ple_window = __shrink_ple_window(old, ple_window, ple_window_shrink, ple_window); - if (vmx->ple_window != old) + if (vmx->ple_window != old) { vmx->ple_window_dirty = true; - - trace_kvm_ple_window_shrink(vcpu->vcpu_id, vmx->ple_window, old); + trace_kvm_ple_window_update(vcpu->vcpu_id, + vmx->ple_window, old); + } } /* @@ -5887,8 +5871,13 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu) else { vcpu_unimpl(vcpu, "vmx: unexpected exit reason 0x%x\n", exit_reason); - kvm_queue_exception(vcpu, UD_VECTOR); - return 1; + dump_vmcs(); + vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; + vcpu->run->internal.suberror = + KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON; + vcpu->run->internal.ndata = 1; + vcpu->run->internal.data[0] = exit_reason; + return 0; } } @@ -6615,6 +6604,9 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) unsigned long *msr_bitmap; int cpu; + BUILD_BUG_ON_MSG(offsetof(struct vcpu_vmx, vcpu) != 0, + "struct kvm_vcpu must be at offset 0 for arch usercopy region"); + vmx = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL_ACCOUNT); if (!vmx) return ERR_PTR(-ENOMEM); @@ -7369,10 +7361,14 @@ static int vmx_update_pi_irte(struct kvm *kvm, unsigned int host_irq, * irqbalance to make the interrupts single-CPU. * * We will support full lowest-priority interrupt later. + * + * In addition, we can only inject generic interrupts using + * the PI mechanism, refuse to route others through it. */ kvm_set_msi_irq(kvm, e, &irq); - if (!kvm_intr_is_single_vcpu(kvm, &irq, &vcpu)) { + if (!kvm_intr_is_single_vcpu(kvm, &irq, &vcpu) || + !kvm_irq_is_postable(&irq)) { /* * Make sure the IRTE is in remapped mode if * we don't handle it in posted mode. @@ -7474,6 +7470,11 @@ static bool vmx_need_emulation_on_page_fault(struct kvm_vcpu *vcpu) return false; } +static bool vmx_apic_init_signal_blocked(struct kvm_vcpu *vcpu) +{ + return to_vmx(vcpu)->nested.vmxon; +} + static __init int hardware_setup(void) { unsigned long host_bndcfgs; @@ -7705,7 +7706,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = { .run = vmx_vcpu_run, .handle_exit = vmx_handle_exit, - .skip_emulated_instruction = skip_emulated_instruction, + .skip_emulated_instruction = __skip_emulated_instruction, .set_interrupt_shadow = vmx_set_interrupt_shadow, .get_interrupt_shadow = vmx_get_interrupt_shadow, .patch_hypercall = vmx_patch_hypercall, @@ -7799,6 +7800,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = { .nested_enable_evmcs = NULL, .nested_get_evmcs_version = NULL, .need_emulation_on_page_fault = vmx_need_emulation_on_page_fault, + .apic_init_signal_blocked = vmx_apic_init_signal_blocked, }; static void vmx_cleanup_l1d_flush(void) diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index 82d0bc3a4d52246f731be6c0e23163ebd05f9f34..64d5a4890aa9e3e5f88343a6f0aec2c63e21d36e 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -253,7 +253,7 @@ struct vcpu_vmx { struct nested_vmx nested; /* Dynamic PLE window. */ - int ple_window; + unsigned int ple_window; bool ple_window_dirty; bool req_immediate_exit; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 91602d310a3fbf0be916d794d0eff9c3beb1b9b2..dfd64124356806325022e22dd8d149db6826803b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -674,8 +674,14 @@ static int kvm_read_nested_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn, data, offset, len, access); } +static inline u64 pdptr_rsvd_bits(struct kvm_vcpu *vcpu) +{ + return rsvd_bits(cpuid_maxphyaddr(vcpu), 63) | rsvd_bits(5, 8) | + rsvd_bits(1, 2); +} + /* - * Load the pae pdptrs. Return true is they are all valid. + * Load the pae pdptrs. Return 1 if they are all valid, 0 otherwise. */ int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3) { @@ -694,8 +700,7 @@ int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3) } for (i = 0; i < ARRAY_SIZE(pdpte); ++i) { if ((pdpte[i] & PT_PRESENT_MASK) && - (pdpte[i] & - vcpu->arch.mmu->guest_rsvd_check.rsvd_bits_mask[0][2])) { + (pdpte[i] & pdptr_rsvd_bits(vcpu))) { ret = 0; goto out; } @@ -1254,6 +1259,13 @@ static u64 kvm_get_arch_capabilities(void) if (l1tf_vmx_mitigation != VMENTER_L1D_FLUSH_NEVER) data |= ARCH_CAP_SKIP_VMENTRY_L1DFLUSH; + if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN)) + data |= ARCH_CAP_RDCL_NO; + if (!boot_cpu_has_bug(X86_BUG_SPEC_STORE_BYPASS)) + data |= ARCH_CAP_SSB_NO; + if (!boot_cpu_has_bug(X86_BUG_MDS)) + data |= ARCH_CAP_MDS_NO; + return data; } @@ -1351,19 +1363,23 @@ void kvm_enable_efer_bits(u64 mask) EXPORT_SYMBOL_GPL(kvm_enable_efer_bits); /* - * Writes msr value into into the appropriate "register". + * Write @data into the MSR specified by @index. Select MSR specific fault + * checks are bypassed if @host_initiated is %true. * Returns 0 on success, non-0 otherwise. * Assumes vcpu_load() was already called. */ -int kvm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) +static int __kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data, + bool host_initiated) { - switch (msr->index) { + struct msr_data msr; + + switch (index) { case MSR_FS_BASE: case MSR_GS_BASE: case MSR_KERNEL_GS_BASE: case MSR_CSTAR: case MSR_LSTAR: - if (is_noncanonical_address(msr->data, vcpu)) + if (is_noncanonical_address(data, vcpu)) return 1; break; case MSR_IA32_SYSENTER_EIP: @@ -1380,38 +1396,95 @@ int kvm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) * value, and that something deterministic happens if the guest * invokes 64-bit SYSENTER. */ - msr->data = get_canonical(msr->data, vcpu_virt_addr_bits(vcpu)); + data = get_canonical(data, vcpu_virt_addr_bits(vcpu)); } - return kvm_x86_ops->set_msr(vcpu, msr); + + msr.data = data; + msr.index = index; + msr.host_initiated = host_initiated; + + return kvm_x86_ops->set_msr(vcpu, &msr); } -EXPORT_SYMBOL_GPL(kvm_set_msr); /* - * Adapt set_msr() to msr_io()'s calling convention + * Read the MSR specified by @index into @data. Select MSR specific fault + * checks are bypassed if @host_initiated is %true. + * Returns 0 on success, non-0 otherwise. + * Assumes vcpu_load() was already called. */ -static int do_get_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) +static int __kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data, + bool host_initiated) { struct msr_data msr; - int r; + int ret; msr.index = index; - msr.host_initiated = true; - r = kvm_get_msr(vcpu, &msr); - if (r) - return r; + msr.host_initiated = host_initiated; - *data = msr.data; - return 0; + ret = kvm_x86_ops->get_msr(vcpu, &msr); + if (!ret) + *data = msr.data; + return ret; } -static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) +int kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data) { - struct msr_data msr; + return __kvm_get_msr(vcpu, index, data, false); +} +EXPORT_SYMBOL_GPL(kvm_get_msr); - msr.data = *data; - msr.index = index; - msr.host_initiated = true; - return kvm_set_msr(vcpu, &msr); +int kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data) +{ + return __kvm_set_msr(vcpu, index, data, false); +} +EXPORT_SYMBOL_GPL(kvm_set_msr); + +int kvm_emulate_rdmsr(struct kvm_vcpu *vcpu) +{ + u32 ecx = kvm_rcx_read(vcpu); + u64 data; + + if (kvm_get_msr(vcpu, ecx, &data)) { + trace_kvm_msr_read_ex(ecx); + kvm_inject_gp(vcpu, 0); + return 1; + } + + trace_kvm_msr_read(ecx, data); + + kvm_rax_write(vcpu, data & -1u); + kvm_rdx_write(vcpu, (data >> 32) & -1u); + return kvm_skip_emulated_instruction(vcpu); +} +EXPORT_SYMBOL_GPL(kvm_emulate_rdmsr); + +int kvm_emulate_wrmsr(struct kvm_vcpu *vcpu) +{ + u32 ecx = kvm_rcx_read(vcpu); + u64 data = kvm_read_edx_eax(vcpu); + + if (kvm_set_msr(vcpu, ecx, data)) { + trace_kvm_msr_write_ex(ecx, data); + kvm_inject_gp(vcpu, 0); + return 1; + } + + trace_kvm_msr_write(ecx, data); + return kvm_skip_emulated_instruction(vcpu); +} +EXPORT_SYMBOL_GPL(kvm_emulate_wrmsr); + +/* + * Adapt set_msr() to msr_io()'s calling convention + */ +static int do_get_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) +{ + return __kvm_get_msr(vcpu, index, data, true); +} + +static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) +{ + return __kvm_set_msr(vcpu, index, *data, true); } #ifdef CONFIG_X86_64 @@ -2452,6 +2525,8 @@ static void record_steal_time(struct kvm_vcpu *vcpu) * Doing a TLB flush here, on the guest's behalf, can avoid * expensive IPIs. */ + trace_kvm_pv_tlb_flush(vcpu->vcpu_id, + vcpu->arch.st.steal.preempted & KVM_VCPU_FLUSH_TLB); if (xchg(&vcpu->arch.st.steal.preempted, 0) & KVM_VCPU_FLUSH_TLB) kvm_vcpu_flush_tlb(vcpu, false); @@ -2748,18 +2823,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) } EXPORT_SYMBOL_GPL(kvm_set_msr_common); - -/* - * Reads an msr value (of 'msr_index') into 'pdata'. - * Returns 0 on success, non-0 otherwise. - * Assumes vcpu_load() was already called. - */ -int kvm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) -{ - return kvm_x86_ops->get_msr(vcpu, msr); -} -EXPORT_SYMBOL_GPL(kvm_get_msr); - static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host) { u64 data; @@ -3506,8 +3569,7 @@ static int kvm_vcpu_ioctl_x86_setup_mce(struct kvm_vcpu *vcpu, for (bank = 0; bank < bank_num; bank++) vcpu->arch.mce_banks[bank*4] = ~(u64)0; - if (kvm_x86_ops->setup_mce) - kvm_x86_ops->setup_mce(vcpu); + kvm_x86_ops->setup_mce(vcpu); out: return r; } @@ -5377,7 +5439,7 @@ static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva, */ if (vcpu_match_mmio_gva(vcpu, gva) && !permission_fault(vcpu, vcpu->arch.walk_mmu, - vcpu->arch.access, 0, access)) { + vcpu->arch.mmio_access, 0, access)) { *gpa = vcpu->arch.mmio_gfn << PAGE_SHIFT | (gva & (PAGE_SIZE - 1)); trace_vcpu_match_mmio(gva, *gpa, write, false); @@ -5971,28 +6033,13 @@ static void emulator_set_segment(struct x86_emulate_ctxt *ctxt, u16 selector, static int emulator_get_msr(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 *pdata) { - struct msr_data msr; - int r; - - msr.index = msr_index; - msr.host_initiated = false; - r = kvm_get_msr(emul_to_vcpu(ctxt), &msr); - if (r) - return r; - - *pdata = msr.data; - return 0; + return kvm_get_msr(emul_to_vcpu(ctxt), msr_index, pdata); } static int emulator_set_msr(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 data) { - struct msr_data msr; - - msr.data = data; - msr.index = msr_index; - msr.host_initiated = false; - return kvm_set_msr(emul_to_vcpu(ctxt), &msr); + return kvm_set_msr(emul_to_vcpu(ctxt), msr_index, data); } static u64 emulator_get_smbase(struct x86_emulate_ctxt *ctxt) @@ -6075,6 +6122,11 @@ static void emulator_post_leave_smm(struct x86_emulate_ctxt *ctxt) kvm_smm_changed(emul_to_vcpu(ctxt)); } +static int emulator_set_xcr(struct x86_emulate_ctxt *ctxt, u32 index, u64 xcr) +{ + return __kvm_set_xcr(emul_to_vcpu(ctxt), index, xcr); +} + static const struct x86_emulate_ops emulate_ops = { .read_gpr = emulator_read_gpr, .write_gpr = emulator_write_gpr, @@ -6116,6 +6168,7 @@ static const struct x86_emulate_ops emulate_ops = { .set_hflags = emulator_set_hflags, .pre_leave_smm = emulator_pre_leave_smm, .post_leave_smm = emulator_post_leave_smm, + .set_xcr = emulator_set_xcr, }; static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask) @@ -6390,9 +6443,11 @@ static void kvm_vcpu_do_singlestep(struct kvm_vcpu *vcpu, int *r) int kvm_skip_emulated_instruction(struct kvm_vcpu *vcpu) { unsigned long rflags = kvm_x86_ops->get_rflags(vcpu); - int r = EMULATE_DONE; + int r; - kvm_x86_ops->skip_emulated_instruction(vcpu); + r = kvm_x86_ops->skip_emulated_instruction(vcpu); + if (unlikely(r != EMULATE_DONE)) + return 0; /* * rflags is the old, "raw" value of the flags. The new value has @@ -6528,8 +6583,16 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, if (reexecute_instruction(vcpu, cr2, write_fault_to_spt, emulation_type)) return EMULATE_DONE; - if (ctxt->have_exception && inject_emulated_exception(vcpu)) + if (ctxt->have_exception) { + /* + * #UD should result in just EMULATION_FAILED, and trap-like + * exception should not be encountered during decode. + */ + WARN_ON_ONCE(ctxt->exception.vector == UD_VECTOR || + exception_type(ctxt->exception.vector) == EXCPT_TRAP); + inject_emulated_exception(vcpu); return EMULATE_DONE; + } if (emulation_type & EMULTYPE_SKIP) return EMULATE_FAIL; return handle_emulation_failure(vcpu, emulation_type); @@ -6544,6 +6607,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, kvm_rip_write(vcpu, ctxt->_eip); if (ctxt->eflags & X86_EFLAGS_RF) kvm_set_rflags(vcpu, ctxt->eflags & ~X86_EFLAGS_RF); + kvm_x86_ops->set_interrupt_shadow(vcpu, 0); return EMULATE_DONE; } @@ -9322,10 +9386,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) kvm_page_track_init(kvm); kvm_mmu_init_vm(kvm); - if (kvm_x86_ops->vm_init) - return kvm_x86_ops->vm_init(kvm); - - return 0; + return kvm_x86_ops->vm_init(kvm); } static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu) @@ -10017,7 +10078,7 @@ EXPORT_SYMBOL_GPL(kvm_arch_has_noncoherent_dma); bool kvm_arch_has_irq_bypass(void) { - return kvm_x86_ops->update_pi_irte != NULL; + return true; } int kvm_arch_irq_bypass_add_producer(struct irq_bypass_consumer *cons, @@ -10057,9 +10118,6 @@ void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons, int kvm_arch_update_irqfd_routing(struct kvm *kvm, unsigned int host_irq, uint32_t guest_irq, bool set) { - if (!kvm_x86_ops->update_pi_irte) - return -EINVAL; - return kvm_x86_ops->update_pi_irte(kvm, host_irq, guest_irq, set); } @@ -10086,11 +10144,12 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_vmrun); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_vmexit); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_vmexit_inject); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_intr_vmexit); +EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_vmenter_failed); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_invlpga); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_skinit); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_intercepts); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_write_tsc_offset); -EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_ple_window); +EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_ple_window_update); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_pml_full); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_pi_irte_update); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_unaccelerated_access); diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 6594020c069167f4f889570960698b2d61ba6379..b5274e2a53cfa8b5922e188bdc33a99121608621 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -196,7 +196,7 @@ static inline void vcpu_cache_mmio_info(struct kvm_vcpu *vcpu, * actually a nGPA. */ vcpu->arch.mmio_gva = mmu_is_nested(vcpu) ? 0 : gva & PAGE_MASK; - vcpu->arch.access = access; + vcpu->arch.mmio_access = access; vcpu->arch.mmio_gfn = gfn; vcpu->arch.mmio_gen = gen; } diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index 4fe1601dbc5d857dfb3639600629584fd8f9c15b..86976b55ae743ef3b534d05475e2dcced6241962 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S @@ -33,7 +33,7 @@ 102: .section .fixup,"ax" 103: addl %ecx,%edx /* ecx is zerorest also */ - jmp copy_user_handle_tail + jmp .Lcopy_user_handle_tail .previous _ASM_EXTABLE_UA(100b, 103b) @@ -113,7 +113,7 @@ ENTRY(copy_user_generic_unrolled) 40: leal (%rdx,%rcx,8),%edx jmp 60f 50: movl %ecx,%edx -60: jmp copy_user_handle_tail /* ecx is zerorest also */ +60: jmp .Lcopy_user_handle_tail /* ecx is zerorest also */ .previous _ASM_EXTABLE_UA(1b, 30b) @@ -177,7 +177,7 @@ ENTRY(copy_user_generic_string) .section .fixup,"ax" 11: leal (%rdx,%rcx,8),%ecx 12: movl %ecx,%edx /* ecx is zerorest also */ - jmp copy_user_handle_tail + jmp .Lcopy_user_handle_tail .previous _ASM_EXTABLE_UA(1b, 11b) @@ -210,7 +210,7 @@ ENTRY(copy_user_enhanced_fast_string) .section .fixup,"ax" 12: movl %ecx,%edx /* ecx is zerorest also */ - jmp copy_user_handle_tail + jmp .Lcopy_user_handle_tail .previous _ASM_EXTABLE_UA(1b, 12b) @@ -231,7 +231,7 @@ EXPORT_SYMBOL(copy_user_enhanced_fast_string) * eax uncopied bytes or 0 if successful. */ ALIGN; -copy_user_handle_tail: +.Lcopy_user_handle_tail: movl %edx,%ecx 1: rep movsb 2: mov %ecx,%eax @@ -239,7 +239,7 @@ copy_user_handle_tail: ret _ASM_EXTABLE_UA(1b, 2b) -END(copy_user_handle_tail) +END(.Lcopy_user_handle_tail) /* * copy_user_nocache - Uncached memory copy with exception handling @@ -364,7 +364,7 @@ ENTRY(__copy_user_nocache) movl %ecx,%edx .L_fixup_handle_tail: sfence - jmp copy_user_handle_tail + jmp .Lcopy_user_handle_tail .previous _ASM_EXTABLE_UA(1b, .L_fixup_4x8b_copy) diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S index 304f958c27b29cd54aed4f736e5e4601bce5ae94..9578eb88fc878ce265defa0eb89d8ca318c1248a 100644 --- a/arch/x86/lib/getuser.S +++ b/arch/x86/lib/getuser.S @@ -115,7 +115,7 @@ ENDPROC(__get_user_8) EXPORT_SYMBOL(__get_user_8) -bad_get_user_clac: +.Lbad_get_user_clac: ASM_CLAC bad_get_user: xor %edx,%edx @@ -123,7 +123,7 @@ bad_get_user: ret #ifdef CONFIG_X86_32 -bad_get_user_8_clac: +.Lbad_get_user_8_clac: ASM_CLAC bad_get_user_8: xor %edx,%edx @@ -132,12 +132,12 @@ bad_get_user_8: ret #endif - _ASM_EXTABLE_UA(1b, bad_get_user_clac) - _ASM_EXTABLE_UA(2b, bad_get_user_clac) - _ASM_EXTABLE_UA(3b, bad_get_user_clac) + _ASM_EXTABLE_UA(1b, .Lbad_get_user_clac) + _ASM_EXTABLE_UA(2b, .Lbad_get_user_clac) + _ASM_EXTABLE_UA(3b, .Lbad_get_user_clac) #ifdef CONFIG_X86_64 - _ASM_EXTABLE_UA(4b, bad_get_user_clac) + _ASM_EXTABLE_UA(4b, .Lbad_get_user_clac) #else - _ASM_EXTABLE_UA(4b, bad_get_user_8_clac) - _ASM_EXTABLE_UA(5b, bad_get_user_8_clac) + _ASM_EXTABLE_UA(4b, .Lbad_get_user_8_clac) + _ASM_EXTABLE_UA(5b, .Lbad_get_user_8_clac) #endif diff --git a/arch/x86/lib/putuser.S b/arch/x86/lib/putuser.S index 14bf78341d3c731ab3d3e242003c21dbd8c33a50..126dd6a9ec9b54c69e7ab2e25ee6ecae2151ee34 100644 --- a/arch/x86/lib/putuser.S +++ b/arch/x86/lib/putuser.S @@ -37,7 +37,7 @@ ENTRY(__put_user_1) ENTER cmp TASK_addr_limit(%_ASM_BX),%_ASM_CX - jae bad_put_user + jae .Lbad_put_user ASM_STAC 1: movb %al,(%_ASM_CX) xor %eax,%eax @@ -51,7 +51,7 @@ ENTRY(__put_user_2) mov TASK_addr_limit(%_ASM_BX),%_ASM_BX sub $1,%_ASM_BX cmp %_ASM_BX,%_ASM_CX - jae bad_put_user + jae .Lbad_put_user ASM_STAC 2: movw %ax,(%_ASM_CX) xor %eax,%eax @@ -65,7 +65,7 @@ ENTRY(__put_user_4) mov TASK_addr_limit(%_ASM_BX),%_ASM_BX sub $3,%_ASM_BX cmp %_ASM_BX,%_ASM_CX - jae bad_put_user + jae .Lbad_put_user ASM_STAC 3: movl %eax,(%_ASM_CX) xor %eax,%eax @@ -79,7 +79,7 @@ ENTRY(__put_user_8) mov TASK_addr_limit(%_ASM_BX),%_ASM_BX sub $7,%_ASM_BX cmp %_ASM_BX,%_ASM_CX - jae bad_put_user + jae .Lbad_put_user ASM_STAC 4: mov %_ASM_AX,(%_ASM_CX) #ifdef CONFIG_X86_32 @@ -91,16 +91,16 @@ ENTRY(__put_user_8) ENDPROC(__put_user_8) EXPORT_SYMBOL(__put_user_8) -bad_put_user_clac: +.Lbad_put_user_clac: ASM_CLAC -bad_put_user: +.Lbad_put_user: movl $-EFAULT,%eax RET - _ASM_EXTABLE_UA(1b, bad_put_user_clac) - _ASM_EXTABLE_UA(2b, bad_put_user_clac) - _ASM_EXTABLE_UA(3b, bad_put_user_clac) - _ASM_EXTABLE_UA(4b, bad_put_user_clac) + _ASM_EXTABLE_UA(1b, .Lbad_put_user_clac) + _ASM_EXTABLE_UA(2b, .Lbad_put_user_clac) + _ASM_EXTABLE_UA(3b, .Lbad_put_user_clac) + _ASM_EXTABLE_UA(4b, .Lbad_put_user_clac) #ifdef CONFIG_X86_32 - _ASM_EXTABLE_UA(5b, bad_put_user_clac) + _ASM_EXTABLE_UA(5b, .Lbad_put_user_clac) #endif diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 4068abb9427f9e9731316484c62a11fa4c72af63..930edeb41ec33417755d38293f85ad1717cdee90 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -916,7 +916,7 @@ static void mark_nxdata_nx(void) if (__supported_pte_mask & _PAGE_NX) printk(KERN_INFO "NX-protecting the kernel data: %luk\n", size >> 10); - set_pages_nx(virt_to_page(start), size >> PAGE_SHIFT); + set_memory_nx(start, size >> PAGE_SHIFT); } void mark_rodata_ro(void) diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 63e99f15d7cf0eedc9b5b522b4d24e36a2708fde..a39dcdb5ae34e018393276f4e2fd502ade7f30e2 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index e6dad600614c2af268fc5e4df6c19468ee798877..4123100e0eafe002f2a50e935bda44914599bdbc 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -861,9 +861,9 @@ void numa_remove_cpu(int cpu) */ const struct cpumask *cpumask_of_node(int node) { - if (node >= nr_node_ids) { + if ((unsigned)node >= nr_node_ids) { printk(KERN_WARNING - "cpumask_of_node(%d): node > nr_node_ids(%u)\n", + "cpumask_of_node(%d): (unsigned)node >= nr_node_ids(%u)\n", node, nr_node_ids); dump_stack(); return cpu_none_mask; diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index e14e95ea7338a3adaf013acb7cd848d909f4dd95..0d09cc5aad6142e3591e3e90acb2376cf6be3430 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -1819,63 +1819,6 @@ int set_memory_uc(unsigned long addr, int numpages) } EXPORT_SYMBOL(set_memory_uc); -static int _set_memory_array(unsigned long *addr, int numpages, - enum page_cache_mode new_type) -{ - enum page_cache_mode set_type; - int i, j; - int ret; - - for (i = 0; i < numpages; i++) { - ret = reserve_memtype(__pa(addr[i]), __pa(addr[i]) + PAGE_SIZE, - new_type, NULL); - if (ret) - goto out_free; - } - - /* If WC, set to UC- first and then WC */ - set_type = (new_type == _PAGE_CACHE_MODE_WC) ? - _PAGE_CACHE_MODE_UC_MINUS : new_type; - - ret = change_page_attr_set(addr, numpages, - cachemode2pgprot(set_type), 1); - - if (!ret && new_type == _PAGE_CACHE_MODE_WC) - ret = change_page_attr_set_clr(addr, numpages, - cachemode2pgprot( - _PAGE_CACHE_MODE_WC), - __pgprot(_PAGE_CACHE_MASK), - 0, CPA_ARRAY, NULL); - if (ret) - goto out_free; - - return 0; - -out_free: - for (j = 0; j < i; j++) - free_memtype(__pa(addr[j]), __pa(addr[j]) + PAGE_SIZE); - - return ret; -} - -int set_memory_array_uc(unsigned long *addr, int numpages) -{ - return _set_memory_array(addr, numpages, _PAGE_CACHE_MODE_UC_MINUS); -} -EXPORT_SYMBOL(set_memory_array_uc); - -int set_memory_array_wc(unsigned long *addr, int numpages) -{ - return _set_memory_array(addr, numpages, _PAGE_CACHE_MODE_WC); -} -EXPORT_SYMBOL(set_memory_array_wc); - -int set_memory_array_wt(unsigned long *addr, int numpages) -{ - return _set_memory_array(addr, numpages, _PAGE_CACHE_MODE_WT); -} -EXPORT_SYMBOL_GPL(set_memory_array_wt); - int _set_memory_wc(unsigned long addr, int numpages) { int ret; @@ -1915,23 +1858,6 @@ int _set_memory_wt(unsigned long addr, int numpages) cachemode2pgprot(_PAGE_CACHE_MODE_WT), 0); } -int set_memory_wt(unsigned long addr, int numpages) -{ - int ret; - - ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE, - _PAGE_CACHE_MODE_WT, NULL); - if (ret) - return ret; - - ret = _set_memory_wt(addr, numpages); - if (ret) - free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE); - - return ret; -} -EXPORT_SYMBOL_GPL(set_memory_wt); - int _set_memory_wb(unsigned long addr, int numpages) { /* WB cache mode is hard wired to all cache attribute bits being 0 */ @@ -1952,24 +1878,6 @@ int set_memory_wb(unsigned long addr, int numpages) } EXPORT_SYMBOL(set_memory_wb); -int set_memory_array_wb(unsigned long *addr, int numpages) -{ - int i; - int ret; - - /* WB cache mode is hard wired to all cache attribute bits being 0 */ - ret = change_page_attr_clear(addr, numpages, - __pgprot(_PAGE_CACHE_MASK), 1); - if (ret) - return ret; - - for (i = 0; i < numpages; i++) - free_memtype(__pa(addr[i]), __pa(addr[i]) + PAGE_SIZE); - - return 0; -} -EXPORT_SYMBOL(set_memory_array_wb); - int set_memory_x(unsigned long addr, int numpages) { if (!(__supported_pte_mask & _PAGE_NX)) @@ -1977,7 +1885,6 @@ int set_memory_x(unsigned long addr, int numpages) return change_page_attr_clear(&addr, numpages, __pgprot(_PAGE_NX), 0); } -EXPORT_SYMBOL(set_memory_x); int set_memory_nx(unsigned long addr, int numpages) { @@ -1986,7 +1893,6 @@ int set_memory_nx(unsigned long addr, int numpages) return change_page_attr_set(&addr, numpages, __pgprot(_PAGE_NX), 0); } -EXPORT_SYMBOL(set_memory_nx); int set_memory_ro(unsigned long addr, int numpages) { @@ -2190,22 +2096,6 @@ int set_pages_array_wb(struct page **pages, int numpages) } EXPORT_SYMBOL(set_pages_array_wb); -int set_pages_x(struct page *page, int numpages) -{ - unsigned long addr = (unsigned long)page_address(page); - - return set_memory_x(addr, numpages); -} -EXPORT_SYMBOL(set_pages_x); - -int set_pages_nx(struct page *page, int numpages) -{ - unsigned long addr = (unsigned long)page_address(page); - - return set_memory_nx(addr, numpages); -} -EXPORT_SYMBOL(set_pages_nx); - int set_pages_ro(struct page *page, int numpages) { unsigned long addr = (unsigned long)page_address(page); diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c index b196524759ec57b1cce790fff4d807765df8900d..7f2140414440dbc3193b95b3c1ddbda917eaf794 100644 --- a/arch/x86/mm/pti.c +++ b/arch/x86/mm/pti.c @@ -330,13 +330,15 @@ pti_clone_pgtable(unsigned long start, unsigned long end, pud = pud_offset(p4d, addr); if (pud_none(*pud)) { - addr += PUD_SIZE; + WARN_ON_ONCE(addr & ~PUD_MASK); + addr = round_up(addr + 1, PUD_SIZE); continue; } pmd = pmd_offset(pud, addr); if (pmd_none(*pmd)) { - addr += PMD_SIZE; + WARN_ON_ONCE(addr & ~PMD_MASK); + addr = round_up(addr + 1, PMD_SIZE); continue; } @@ -666,6 +668,8 @@ void __init pti_init(void) */ void pti_finalize(void) { + if (!boot_cpu_has(X86_FEATURE_PTI)) + return; /* * We need to clone everything (again) that maps parts of the * kernel image. diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 4de9704c4aaf388a0cc65fc9df2089555ca1dbed..e6a9edc5baaf07b99925519351a895520e2d7949 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -440,7 +440,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, this_cpu_write(cpu_tlbstate.loaded_mm_asid, new_asid); if (next != real_prev) { - load_mm_cr4(next); + load_mm_cr4_irqsoff(next); switch_ldt(real_prev, next); } } diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 7389db538c304d86611a1da10f1938c40e3a346d..6fa42e9c4e6fa283e8ad2a8a426629fa8a81d0de 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c @@ -29,6 +29,7 @@ static bool pci_mmcfg_running_state; static bool pci_mmcfg_arch_init_failed; static DEFINE_MUTEX(pci_mmcfg_lock); +#define pci_mmcfg_lock_held() lock_is_held(&(pci_mmcfg_lock).dep_map) LIST_HEAD(pci_mmcfg_list); @@ -54,7 +55,7 @@ static void list_add_sorted(struct pci_mmcfg_region *new) struct pci_mmcfg_region *cfg; /* keep list sorted by segment and starting bus number */ - list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) { + list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list, pci_mmcfg_lock_held()) { if (cfg->segment > new->segment || (cfg->segment == new->segment && cfg->start_bus >= new->start_bus)) { @@ -118,7 +119,7 @@ struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus) { struct pci_mmcfg_region *cfg; - list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) + list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list, pci_mmcfg_lock_held()) if (cfg->segment == segment && cfg->start_bus <= bus && bus <= cfg->end_bus) return cfg; diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index a7189a3b4d70f759ab9743f8b43c4a2b83c1e47f..c202e1b07e290c9f7bceeeb8a0c0deb887e990f6 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -59,11 +59,34 @@ static efi_system_table_t efi_systab __initdata; static efi_config_table_type_t arch_tables[] __initdata = { #ifdef CONFIG_X86_UV - {UV_SYSTEM_TABLE_GUID, "UVsystab", &efi.uv_systab}, + {UV_SYSTEM_TABLE_GUID, "UVsystab", &uv_systab_phys}, #endif {NULL_GUID, NULL, NULL}, }; +static const unsigned long * const efi_tables[] = { + &efi.mps, + &efi.acpi, + &efi.acpi20, + &efi.smbios, + &efi.smbios3, + &efi.boot_info, + &efi.hcdp, + &efi.uga, +#ifdef CONFIG_X86_UV + &uv_systab_phys, +#endif + &efi.fw_vendor, + &efi.runtime, + &efi.config_table, + &efi.esrt, + &efi.properties_table, + &efi.mem_attr_table, +#ifdef CONFIG_EFI_RCI2_TABLE + &rci2_table_phys, +#endif +}; + u64 efi_setup; /* efi setup_data physical address */ static int add_efi_memmap __initdata; @@ -1049,3 +1072,17 @@ static int __init arch_parse_efi_cmdline(char *str) return 0; } early_param("efi", arch_parse_efi_cmdline); + +bool efi_is_table_address(unsigned long phys_addr) +{ + unsigned int i; + + if (phys_addr == EFI_INVALID_TABLE_ADDR) + return false; + + for (i = 0; i < ARRAY_SIZE(efi_tables); i++) + if (*(efi_tables[i]) == phys_addr) + return true; + + return false; +} diff --git a/arch/x86/platform/intel/iosf_mbi.c b/arch/x86/platform/intel/iosf_mbi.c index 2e796b54cbde1453461a42c7f8a524eb45159c78..9e244450042827f5f3a6c42da13aed2e2c3adee7 100644 --- a/arch/x86/platform/intel/iosf_mbi.c +++ b/arch/x86/platform/intel/iosf_mbi.c @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -201,23 +202,45 @@ EXPORT_SYMBOL(iosf_mbi_available); #define PUNIT_SEMAPHORE_BIT BIT(0) #define PUNIT_SEMAPHORE_ACQUIRE BIT(1) -static DEFINE_MUTEX(iosf_mbi_punit_mutex); -static DEFINE_MUTEX(iosf_mbi_block_punit_i2c_access_count_mutex); +static DEFINE_MUTEX(iosf_mbi_pmic_access_mutex); static BLOCKING_NOTIFIER_HEAD(iosf_mbi_pmic_bus_access_notifier); -static u32 iosf_mbi_block_punit_i2c_access_count; +static DECLARE_WAIT_QUEUE_HEAD(iosf_mbi_pmic_access_waitq); +static u32 iosf_mbi_pmic_punit_access_count; +static u32 iosf_mbi_pmic_i2c_access_count; static u32 iosf_mbi_sem_address; static unsigned long iosf_mbi_sem_acquired; static struct pm_qos_request iosf_mbi_pm_qos; void iosf_mbi_punit_acquire(void) { - mutex_lock(&iosf_mbi_punit_mutex); + /* Wait for any I2C PMIC accesses from in kernel drivers to finish. */ + mutex_lock(&iosf_mbi_pmic_access_mutex); + while (iosf_mbi_pmic_i2c_access_count != 0) { + mutex_unlock(&iosf_mbi_pmic_access_mutex); + wait_event(iosf_mbi_pmic_access_waitq, + iosf_mbi_pmic_i2c_access_count == 0); + mutex_lock(&iosf_mbi_pmic_access_mutex); + } + /* + * We do not need to do anything to allow the PUNIT to safely access + * the PMIC, other then block in kernel accesses to the PMIC. + */ + iosf_mbi_pmic_punit_access_count++; + mutex_unlock(&iosf_mbi_pmic_access_mutex); } EXPORT_SYMBOL(iosf_mbi_punit_acquire); void iosf_mbi_punit_release(void) { - mutex_unlock(&iosf_mbi_punit_mutex); + bool do_wakeup; + + mutex_lock(&iosf_mbi_pmic_access_mutex); + iosf_mbi_pmic_punit_access_count--; + do_wakeup = iosf_mbi_pmic_punit_access_count == 0; + mutex_unlock(&iosf_mbi_pmic_access_mutex); + + if (do_wakeup) + wake_up(&iosf_mbi_pmic_access_waitq); } EXPORT_SYMBOL(iosf_mbi_punit_release); @@ -256,34 +279,32 @@ static void iosf_mbi_reset_semaphore(void) * already blocked P-Unit accesses because it wants them blocked over multiple * i2c-transfers, for e.g. read-modify-write of an I2C client register. * - * The P-Unit accesses already being blocked is tracked through the - * iosf_mbi_block_punit_i2c_access_count variable which is protected by the - * iosf_mbi_block_punit_i2c_access_count_mutex this mutex is hold for the - * entire duration of the function. - * - * If access is not blocked yet, this function takes the following steps: + * To allow safe PMIC i2c bus accesses this function takes the following steps: * * 1) Some code sends request to the P-Unit which make it access the PMIC * I2C bus. Testing has shown that the P-Unit does not check its internal * PMIC bus semaphore for these requests. Callers of these requests call * iosf_mbi_punit_acquire()/_release() around their P-Unit accesses, these - * functions lock/unlock the iosf_mbi_punit_mutex. - * As the first step we lock the iosf_mbi_punit_mutex, to wait for any in - * flight requests to finish and to block any new requests. + * functions increase/decrease iosf_mbi_pmic_punit_access_count, so first + * we wait for iosf_mbi_pmic_punit_access_count to become 0. + * + * 2) Check iosf_mbi_pmic_i2c_access_count, if access has already + * been blocked by another caller, we only need to increment + * iosf_mbi_pmic_i2c_access_count and we can skip the other steps. * - * 2) Some code makes such P-Unit requests from atomic contexts where it + * 3) Some code makes such P-Unit requests from atomic contexts where it * cannot call iosf_mbi_punit_acquire() as that may sleep. * As the second step we call a notifier chain which allows any code * needing P-Unit resources from atomic context to acquire them before * we take control over the PMIC I2C bus. * - * 3) When CPU cores enter C6 or C7 the P-Unit needs to talk to the PMIC + * 4) When CPU cores enter C6 or C7 the P-Unit needs to talk to the PMIC * if this happens while the kernel itself is accessing the PMIC I2C bus * the SoC hangs. * As the third step we call pm_qos_update_request() to disallow the CPU * to enter C6 or C7. * - * 4) The P-Unit has a PMIC bus semaphore which we can request to stop + * 5) The P-Unit has a PMIC bus semaphore which we can request to stop * autonomous P-Unit tasks from accessing the PMIC I2C bus while we hold it. * As the fourth and final step we request this semaphore and wait for our * request to be acknowledged. @@ -297,12 +318,18 @@ int iosf_mbi_block_punit_i2c_access(void) if (WARN_ON(!mbi_pdev || !iosf_mbi_sem_address)) return -ENXIO; - mutex_lock(&iosf_mbi_block_punit_i2c_access_count_mutex); + mutex_lock(&iosf_mbi_pmic_access_mutex); - if (iosf_mbi_block_punit_i2c_access_count > 0) + while (iosf_mbi_pmic_punit_access_count != 0) { + mutex_unlock(&iosf_mbi_pmic_access_mutex); + wait_event(iosf_mbi_pmic_access_waitq, + iosf_mbi_pmic_punit_access_count == 0); + mutex_lock(&iosf_mbi_pmic_access_mutex); + } + + if (iosf_mbi_pmic_i2c_access_count > 0) goto success; - mutex_lock(&iosf_mbi_punit_mutex); blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier, MBI_PMIC_BUS_ACCESS_BEGIN, NULL); @@ -330,10 +357,6 @@ int iosf_mbi_block_punit_i2c_access(void) iosf_mbi_sem_acquired = jiffies; dev_dbg(&mbi_pdev->dev, "P-Unit semaphore acquired after %ums\n", jiffies_to_msecs(jiffies - start)); - /* - * Success, keep iosf_mbi_punit_mutex locked till - * iosf_mbi_unblock_punit_i2c_access() gets called. - */ goto success; } @@ -344,15 +367,13 @@ int iosf_mbi_block_punit_i2c_access(void) dev_err(&mbi_pdev->dev, "Error P-Unit semaphore timed out, resetting\n"); error: iosf_mbi_reset_semaphore(); - mutex_unlock(&iosf_mbi_punit_mutex); - if (!iosf_mbi_get_sem(&sem)) dev_err(&mbi_pdev->dev, "P-Unit semaphore: %d\n", sem); success: if (!WARN_ON(ret)) - iosf_mbi_block_punit_i2c_access_count++; + iosf_mbi_pmic_i2c_access_count++; - mutex_unlock(&iosf_mbi_block_punit_i2c_access_count_mutex); + mutex_unlock(&iosf_mbi_pmic_access_mutex); return ret; } @@ -360,17 +381,20 @@ EXPORT_SYMBOL(iosf_mbi_block_punit_i2c_access); void iosf_mbi_unblock_punit_i2c_access(void) { - mutex_lock(&iosf_mbi_block_punit_i2c_access_count_mutex); + bool do_wakeup = false; - iosf_mbi_block_punit_i2c_access_count--; - if (iosf_mbi_block_punit_i2c_access_count == 0) { + mutex_lock(&iosf_mbi_pmic_access_mutex); + iosf_mbi_pmic_i2c_access_count--; + if (iosf_mbi_pmic_i2c_access_count == 0) { iosf_mbi_reset_semaphore(); - mutex_unlock(&iosf_mbi_punit_mutex); dev_dbg(&mbi_pdev->dev, "punit semaphore held for %ums\n", jiffies_to_msecs(jiffies - iosf_mbi_sem_acquired)); + do_wakeup = true; } + mutex_unlock(&iosf_mbi_pmic_access_mutex); - mutex_unlock(&iosf_mbi_block_punit_i2c_access_count_mutex); + if (do_wakeup) + wake_up(&iosf_mbi_pmic_access_waitq); } EXPORT_SYMBOL(iosf_mbi_unblock_punit_i2c_access); @@ -379,10 +403,10 @@ int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb) int ret; /* Wait for the bus to go inactive before registering */ - mutex_lock(&iosf_mbi_punit_mutex); + iosf_mbi_punit_acquire(); ret = blocking_notifier_chain_register( &iosf_mbi_pmic_bus_access_notifier, nb); - mutex_unlock(&iosf_mbi_punit_mutex); + iosf_mbi_punit_release(); return ret; } @@ -403,9 +427,9 @@ int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb) int ret; /* Wait for the bus to go inactive before unregistering */ - mutex_lock(&iosf_mbi_punit_mutex); + iosf_mbi_punit_acquire(); ret = iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(nb); - mutex_unlock(&iosf_mbi_punit_mutex); + iosf_mbi_punit_release(); return ret; } @@ -413,7 +437,7 @@ EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier); void iosf_mbi_assert_punit_acquired(void) { - WARN_ON(!mutex_is_locked(&iosf_mbi_punit_mutex)); + WARN_ON(iosf_mbi_pmic_punit_access_count == 0); } EXPORT_SYMBOL(iosf_mbi_assert_punit_acquired); diff --git a/arch/x86/platform/olpc/olpc-xo1-sci.c b/arch/x86/platform/olpc/olpc-xo1-sci.c index 25ce1b3b0732dc941de0fc039a7f191633019fc8..99a28ce2244c79ab4e4237ee95dde5bba9bbcf45 100644 --- a/arch/x86/platform/olpc/olpc-xo1-sci.c +++ b/arch/x86/platform/olpc/olpc-xo1-sci.c @@ -157,6 +157,12 @@ static ssize_t lid_wake_mode_set(struct device *dev, static DEVICE_ATTR(lid_wake_mode, S_IWUSR | S_IRUGO, lid_wake_mode_show, lid_wake_mode_set); +static struct attribute *lid_attrs[] = { + &dev_attr_lid_wake_mode.attr, + NULL, +}; +ATTRIBUTE_GROUPS(lid); + /* * Process all items in the EC's SCI queue. * @@ -510,17 +516,8 @@ static int setup_lid_switch(struct platform_device *pdev) goto err_register; } - r = device_create_file(&lid_switch_idev->dev, &dev_attr_lid_wake_mode); - if (r) { - dev_err(&pdev->dev, "failed to create wake mode attr: %d\n", r); - goto err_create_attr; - } - return 0; -err_create_attr: - input_unregister_device(lid_switch_idev); - lid_switch_idev = NULL; err_register: input_free_device(lid_switch_idev); return r; @@ -528,7 +525,6 @@ static int setup_lid_switch(struct platform_device *pdev) static void free_lid_switch(void) { - device_remove_file(&lid_switch_idev->dev, &dev_attr_lid_wake_mode); input_unregister_device(lid_switch_idev); } @@ -624,6 +620,7 @@ static int xo1_sci_remove(struct platform_device *pdev) static struct platform_driver xo1_sci_driver = { .driver = { .name = "olpc-xo1-sci-acpi", + .dev_groups = lid_groups, }, .probe = xo1_sci_probe, .remove = xo1_sci_remove, diff --git a/arch/x86/platform/uv/bios_uv.c b/arch/x86/platform/uv/bios_uv.c index 7c69652ffeea2e6c3de91a8c6a349eea60b4bf55..c2ee31953372d4ed2b8a5fc9b19d9856eeaa9398 100644 --- a/arch/x86/platform/uv/bios_uv.c +++ b/arch/x86/platform/uv/bios_uv.c @@ -14,6 +14,8 @@ #include #include +unsigned long uv_systab_phys __ro_after_init = EFI_INVALID_TABLE_ADDR; + struct uv_systab *uv_systab; static s64 __uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, @@ -185,13 +187,13 @@ EXPORT_SYMBOL_GPL(uv_bios_set_legacy_vga_target); void uv_bios_init(void) { uv_systab = NULL; - if ((efi.uv_systab == EFI_INVALID_TABLE_ADDR) || - !efi.uv_systab || efi_runtime_disabled()) { + if ((uv_systab_phys == EFI_INVALID_TABLE_ADDR) || + !uv_systab_phys || efi_runtime_disabled()) { pr_crit("UV: UVsystab: missing\n"); return; } - uv_systab = ioremap(efi.uv_systab, sizeof(struct uv_systab)); + uv_systab = ioremap(uv_systab_phys, sizeof(struct uv_systab)); if (!uv_systab || strncmp(uv_systab->signature, UV_SYSTAB_SIG, 4)) { pr_err("UV: UVsystab: bad signature!\n"); iounmap(uv_systab); @@ -203,7 +205,7 @@ void uv_bios_init(void) int size = uv_systab->size; iounmap(uv_systab); - uv_systab = ioremap(efi.uv_systab, size); + uv_systab = ioremap(uv_systab_phys, size); if (!uv_systab) { pr_err("UV: UVsystab: ioremap(%d) failed!\n", size); return; diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c index 20c389a91b8033c1a8f134bff08dd7ada9a4d9bd..5f0a96bf27a1fa7286bb1d0071b483ddbb086be0 100644 --- a/arch/x86/platform/uv/tlb_uv.c +++ b/arch/x86/platform/uv/tlb_uv.c @@ -1804,9 +1804,9 @@ static void pq_init(int node, int pnode) plsize = (DEST_Q_SIZE + 1) * sizeof(struct bau_pq_entry); vp = kmalloc_node(plsize, GFP_KERNEL, node); - pqp = (struct bau_pq_entry *)vp; - BUG_ON(!pqp); + BUG_ON(!vp); + pqp = (struct bau_pq_entry *)vp; cp = (char *)pqp + 31; pqp = (struct bau_pq_entry *)(((unsigned long)cp >> 5) << 5); diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c index c9ef6a7a4a1aa4783e515d9378fa2886451bbb02..915bb163976324edd41b615b08fd8ecb95c2c33c 100644 --- a/arch/x86/power/cpu.c +++ b/arch/x86/power/cpu.c @@ -123,9 +123,6 @@ static void __save_processor_state(struct saved_context *ctxt) ctxt->cr2 = read_cr2(); ctxt->cr3 = __read_cr3(); ctxt->cr4 = __read_cr4(); -#ifdef CONFIG_X86_64 - ctxt->cr8 = read_cr8(); -#endif ctxt->misc_enable_saved = !rdmsrl_safe(MSR_IA32_MISC_ENABLE, &ctxt->misc_enable); msr_save_context(ctxt); @@ -208,7 +205,6 @@ static void notrace __restore_processor_state(struct saved_context *ctxt) #else /* CONFIG X86_64 */ wrmsrl(MSR_EFER, ctxt->efer); - write_cr8(ctxt->cr8); __write_cr4(ctxt->cr4); #endif write_cr3(ctxt->cr3); diff --git a/arch/x86/purgatory/Makefile b/arch/x86/purgatory/Makefile index 10fb42da0007e9d3c914143ec4e427dd1eec42f5..527749066d31e7faee3ab0dc5de228b488acba74 100644 --- a/arch/x86/purgatory/Makefile +++ b/arch/x86/purgatory/Makefile @@ -9,9 +9,11 @@ PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y)) $(obj)/string.o: $(srctree)/arch/x86/boot/compressed/string.c FORCE $(call if_changed_rule,cc_o_c) -$(obj)/sha256.o: $(srctree)/lib/sha256.c FORCE +$(obj)/sha256.o: $(srctree)/lib/crypto/sha256.c FORCE $(call if_changed_rule,cc_o_c) +CFLAGS_sha256.o := -D__DISABLE_EXPORTS + LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined -nostdlib -z nodefaultlib targets += purgatory.ro diff --git a/arch/x86/purgatory/purgatory.c b/arch/x86/purgatory/purgatory.c index b607bda786f6b9ff0c60cb5889b4f99353d0edcb..3b95410ff0f887469b2392f949a9da7539aab8e9 100644 --- a/arch/x86/purgatory/purgatory.c +++ b/arch/x86/purgatory/purgatory.c @@ -9,7 +9,7 @@ */ #include -#include +#include #include #include "../boot/string.h" diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S index 30b0d30d861a22679b69127c2bfa0ebe2c5ea4d6..6363761cc74cf59b22b9c896590b06afdf30721b 100644 --- a/arch/x86/realmode/rm/header.S +++ b/arch/x86/realmode/rm/header.S @@ -19,7 +19,6 @@ GLOBAL(real_mode_header) .long pa_ro_end /* SMP trampoline */ .long pa_trampoline_start - .long pa_trampoline_status .long pa_trampoline_header #ifdef CONFIG_X86_64 .long pa_trampoline_pgd; diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S index 2dd866c9e21ea4f8fb7e04180ff408978d87d4f4..1868b158480d47af5f0e6c67fc5c88a4a08e94bc 100644 --- a/arch/x86/realmode/rm/trampoline_32.S +++ b/arch/x86/realmode/rm/trampoline_32.S @@ -41,9 +41,6 @@ ENTRY(trampoline_start) movl tr_start, %eax # where we need to go - movl $0xA5A5A5A5, trampoline_status - # write marker for master knows we're running - /* * GDT tables in non default location kernel can be beyond 16MB and * lgdt will not be able to load the address as in real mode default diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S index 24bb7598774e6aa94203e601f41329d31308692e..aee2b45d83b879ac7475024de38c9b9cfca7f45b 100644 --- a/arch/x86/realmode/rm/trampoline_64.S +++ b/arch/x86/realmode/rm/trampoline_64.S @@ -49,9 +49,6 @@ ENTRY(trampoline_start) mov %ax, %es mov %ax, %ss - movl $0xA5A5A5A5, trampoline_status - # write marker for master knows we're running - # Setup stack movl $rm_stack_end, %esp diff --git a/arch/x86/realmode/rm/trampoline_common.S b/arch/x86/realmode/rm/trampoline_common.S index 7c706772ab59f15ce4d5713cb1eac5a6538d3153..8d8208dcca244e7c2b2f23518c585816799cdbb9 100644 --- a/arch/x86/realmode/rm/trampoline_common.S +++ b/arch/x86/realmode/rm/trampoline_common.S @@ -2,7 +2,3 @@ .section ".rodata","a" .balign 16 tr_idt: .fill 1, 6, 0 - - .bss - .balign 4 -GLOBAL(trampoline_status) .space 4 diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c index 7ceb32821093a226995a86e9832c59b9b9d586ae..58f79ab32358429ea4f948ccccbdfe86e9e294e3 100644 --- a/arch/x86/xen/enlighten_pv.c +++ b/arch/x86/xen/enlighten_pv.c @@ -877,16 +877,6 @@ static void xen_write_cr4(unsigned long cr4) native_write_cr4(cr4); } -#ifdef CONFIG_X86_64 -static inline unsigned long xen_read_cr8(void) -{ - return 0; -} -static inline void xen_write_cr8(unsigned long val) -{ - BUG_ON(val); -} -#endif static u64 xen_read_msr_safe(unsigned int msr, int *err) { @@ -1023,11 +1013,6 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = { .write_cr4 = xen_write_cr4, -#ifdef CONFIG_X86_64 - .read_cr8 = xen_read_cr8, - .write_cr8 = xen_write_cr8, -#endif - .wbinvd = native_wbinvd, .read_msr = xen_read_msr, diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index ebc135bda92119f38abfc5cb2eb8c2d91f760d41..fb64469ca8f0ee2e14012496245fd6cb3871a837 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -385,6 +385,54 @@ config FAST_SYSCALL_SPILL_REGISTERS If unsure, say N. +config USER_ABI_CALL0 + bool + +choice + prompt "Userspace ABI" + default USER_ABI_DEFAULT + help + Select supported userspace ABI. + + If unsure, choose the default ABI. + +config USER_ABI_DEFAULT + bool "Default ABI only" + help + Assume default userspace ABI. For XEA2 cores it is windowed ABI. + call0 ABI binaries may be run on such kernel, but signal delivery + will not work correctly for them. + +config USER_ABI_CALL0_ONLY + bool "Call0 ABI only" + select USER_ABI_CALL0 + help + Select this option to support only call0 ABI in userspace. + Windowed ABI binaries will crash with a segfault caused by + an illegal instruction exception on the first 'entry' opcode. + + Choose this option if you're planning to run only user code + built with call0 ABI. + +config USER_ABI_CALL0_PROBE + bool "Support both windowed and call0 ABI by probing" + select USER_ABI_CALL0 + help + Select this option to support both windowed and call0 userspace + ABIs. When enabled all processes are started with PS.WOE disabled + and a fast user exception handler for an illegal instruction is + used to turn on PS.WOE bit on the first 'entry' opcode executed by + the userspace. + + This option should be enabled for the kernel that must support + both call0 and windowed ABIs in userspace at the same time. + + Note that Xtensa ISA does not guarantee that entry opcode will + raise an illegal instruction exception on cores with XEA2 when + PS.WOE is disabled, check whether the target core supports it. + +endchoice + endmenu config XTENSA_CALIBRATE_CCOUNT diff --git a/arch/xtensa/boot/dts/virt.dts b/arch/xtensa/boot/dts/virt.dts index 6aecbc0f3549ae6c039e19b24b33b880755cfb7f..a9dcd87b6eb1ee894fc540d173dcd77030ed54da 100644 --- a/arch/xtensa/boot/dts/virt.dts +++ b/arch/xtensa/boot/dts/virt.dts @@ -52,12 +52,12 @@ #size-cells = <2>; #interrupt-cells = <0x1>; - bus-range = <0x0 0x3f>; - reg = <0xc0000000 0x04000000>; + bus-range = <0x0 0x3e>; + reg = <0xf0100000 0x03f00000>; // BUS_ADDRESS(3) CPU_PHYSICAL(1) SIZE(2) - ranges = <0x01000000 0x0 0xc4000000 0xc4000000 0x0 0x04000000>, - <0x02000000 0x0 0xc8000000 0xc8000000 0x0 0x18000000>; + ranges = <0x01000000 0x0 0xf0000000 0xf0000000 0x0 0x00010000>, + <0x02000000 0x0 0xf4000000 0xf4000000 0x0 0x08000000>; // PCI_DEVICE(3) INT#(1) CONTROLLER(PHANDLE) CONTROLLER_DATA(2) interrupt-map = < diff --git a/arch/xtensa/include/asm/io.h b/arch/xtensa/include/asm/io.h index da3e783f896b34c3fd60cfc94a1aa44a6465365b..988e08530a5c77aeee213a80d015b33e66b95e08 100644 --- a/arch/xtensa/include/asm/io.h +++ b/arch/xtensa/include/asm/io.h @@ -21,6 +21,7 @@ #define IOADDR(x) (XCHAL_KIO_BYPASS_VADDR + (x)) #define IO_SPACE_LIMIT ~0 +#define PCI_IOBASE ((void __iomem *)XCHAL_KIO_BYPASS_VADDR) #ifdef CONFIG_MMU diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h index 19f6b54e358b1d53594896bb6c2f29113ec0b849..7495520d7a3e92b65c57207220f48142cb874214 100644 --- a/arch/xtensa/include/asm/processor.h +++ b/arch/xtensa/include/asm/processor.h @@ -176,14 +176,21 @@ struct thread_struct { /* * Do necessary setup to start up a newly executed thread. - * Note: We set-up ps as if we did a call4 to the new pc. + * Note: When windowed ABI is used for userspace we set-up ps + * as if we did a call4 to the new pc. * set_thread_state in signal.c depends on it. */ -#define USER_PS_VALUE ((1 << PS_WOE_BIT) | \ +#if IS_ENABLED(CONFIG_USER_ABI_CALL0) +#define USER_PS_VALUE ((USER_RING << PS_RING_SHIFT) | \ + (1 << PS_UM_BIT) | \ + (1 << PS_EXCM_BIT)) +#else +#define USER_PS_VALUE (PS_WOE_MASK | \ (1 << PS_CALLINC_SHIFT) | \ (USER_RING << PS_RING_SHIFT) | \ (1 << PS_UM_BIT) | \ (1 << PS_EXCM_BIT)) +#endif /* Clearing a0 terminates the backtrace. */ #define start_thread(regs, new_pc, new_sp) \ diff --git a/arch/xtensa/include/asm/regs.h b/arch/xtensa/include/asm/regs.h index 477594e5817f2f2bd04dfadd5c2454803eeb05df..ce184e7dee91e70b76dde38b9121db0be99a55bc 100644 --- a/arch/xtensa/include/asm/regs.h +++ b/arch/xtensa/include/asm/regs.h @@ -81,6 +81,7 @@ /* PS register fields. */ #define PS_WOE_BIT 18 +#define PS_WOE_MASK 0x00040000 #define PS_CALLINC_SHIFT 16 #define PS_CALLINC_MASK 0x00030000 #define PS_OWB_SHIFT 8 diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index 183fa8e0bb5b80366a5344e22cefcf69aac0e8be..9e3676879168ab920696c4e0809696edcda44ffe 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S @@ -414,7 +414,7 @@ common_exception: movi a3, LOCKLEVEL .Lexception: - movi a0, 1 << PS_WOE_BIT + movi a0, PS_WOE_MASK or a3, a3, a0 #else addi a2, a2, -EXCCAUSE_LEVEL1_INTERRUPT @@ -422,7 +422,7 @@ common_exception: extui a3, a3, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH # a3 = PS.INTLEVEL moveqz a3, a0, a2 # a3 = LOCKLEVEL iff interrupt - movi a2, 1 << PS_WOE_BIT + movi a2, PS_WOE_MASK or a3, a3, a2 rsr a2, exccause #endif @@ -922,7 +922,7 @@ ENTRY(unrecoverable_exception) wsr a1, windowbase rsync - movi a1, (1 << PS_WOE_BIT) | LOCKLEVEL + movi a1, PS_WOE_MASK | LOCKLEVEL wsr a1, ps rsync @@ -1003,7 +1003,41 @@ ENTRY(fast_alloca) 4: j _WindowUnderflow4 ENDPROC(fast_alloca) +#ifdef CONFIG_USER_ABI_CALL0_PROBE /* + * fast illegal instruction handler. + * + * This is used to fix up user PS.WOE on the exception caused + * by the first opcode related to register window. If PS.WOE is + * already set it goes directly to the common user exception handler. + * + * Entry condition: + * + * a0: trashed, original value saved on stack (PT_AREG0) + * a1: a1 + * a2: new stack pointer, original in DEPC + * a3: a3 + * depc: a2, original value saved on stack (PT_DEPC) + * excsave_1: dispatch table + */ + +ENTRY(fast_illegal_instruction_user) + + rsr a0, ps + bbsi.l a0, PS_WOE_BIT, user_exception + s32i a3, a2, PT_AREG3 + movi a3, PS_WOE_MASK + or a0, a0, a3 + wsr a0, ps + l32i a3, a2, PT_AREG3 + l32i a0, a2, PT_AREG0 + rsr a2, depc + rfe + +ENDPROC(fast_illegal_instruction_user) +#endif + + /* * fast system calls. * * WARNING: The kernel doesn't save the entire user context before @@ -1359,7 +1393,7 @@ ENTRY(fast_syscall_spill_registers) rsr a3, excsave1 l32i a1, a3, EXC_TABLE_KSTK - movi a4, (1 << PS_WOE_BIT) | LOCKLEVEL + movi a4, PS_WOE_MASK | LOCKLEVEL wsr a4, ps rsync diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S index 7f009719304efeaf29bd998043e37a729ef77636..4ae998b5a3480631bf8f0fd1dc24156c9e3d3d06 100644 --- a/arch/xtensa/kernel/head.S +++ b/arch/xtensa/kernel/head.S @@ -193,7 +193,7 @@ ENTRY(_startup) movi a1, start_info l32i a1, a1, 0 - movi a2, (1 << PS_WOE_BIT) | LOCKLEVEL + movi a2, PS_WOE_MASK | LOCKLEVEL # WOE=1, INTLEVEL=LOCKLEVEL, UM=0 wsr a2, ps # (enable reg-windows; progmode stack) rsync diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c index 7c3106093c7584e44daaa2e6af660afa05ff4132..e0e1e1892b86b3a2a040e95242041c3e759a92ed 100644 --- a/arch/xtensa/kernel/setup.c +++ b/arch/xtensa/kernel/setup.c @@ -61,7 +61,6 @@ struct screen_info screen_info = { #ifdef CONFIG_BLK_DEV_INITRD extern unsigned long initrd_start; extern unsigned long initrd_end; -int initrd_is_mapped = 0; extern int initrd_below_start_ok; #endif @@ -332,13 +331,11 @@ void __init setup_arch(char **cmdline_p) /* Reserve some memory regions */ #ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start < initrd_end) { - initrd_is_mapped = mem_reserve(__pa(initrd_start), - __pa(initrd_end)) == 0; + if (initrd_start < initrd_end && + !mem_reserve(__pa(initrd_start), __pa(initrd_end))) initrd_below_start_ok = 1; - } else { + else initrd_start = 0; - } #endif mem_reserve(__pa(_stext), __pa(_end)); diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index fbedf2aba09dcb69d4e60df107cce1d7dea8daab..dae83cddd6ca2d09b16d77656da1a0adf87c4556 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -335,7 +335,8 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set, { struct rt_sigframe *frame; int err = 0, sig = ksig->sig; - unsigned long sp, ra, tp; + unsigned long sp, ra, tp, ps; + unsigned int base; sp = regs->areg[1]; @@ -385,17 +386,26 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set, /* Set up registers for signal handler; preserve the threadptr */ tp = regs->threadptr; + ps = regs->ps; start_thread(regs, (unsigned long) ksig->ka.sa.sa_handler, (unsigned long) frame); - /* Set up a stack frame for a call4 - * Note: PS.CALLINC is set to one by start_thread - */ - regs->areg[4] = (((unsigned long) ra) & 0x3fffffff) | 0x40000000; - regs->areg[6] = (unsigned long) sig; - regs->areg[7] = (unsigned long) &frame->info; - regs->areg[8] = (unsigned long) &frame->uc; + /* Set up a stack frame for a call4 if userspace uses windowed ABI */ + if (ps & PS_WOE_MASK) { + base = 4; + regs->areg[base] = + (((unsigned long) ra) & 0x3fffffff) | 0x40000000; + ps = (ps & ~(PS_CALLINC_MASK | PS_OWB_MASK)) | + (1 << PS_CALLINC_SHIFT); + } else { + base = 0; + regs->areg[base] = (unsigned long) ra; + } + regs->areg[base + 2] = (unsigned long) sig; + regs->areg[base + 3] = (unsigned long) &frame->info; + regs->areg[base + 4] = (unsigned long) &frame->uc; regs->threadptr = tp; + regs->ps = ps; pr_debug("SIG rt deliver (%s:%d): signal=%d sp=%p pc=%08lx\n", current->comm, current->pid, sig, frame, regs->pc); diff --git a/arch/xtensa/kernel/stacktrace.c b/arch/xtensa/kernel/stacktrace.c index b9f82510c65019506ffb98f3f23ac494f7285efa..c822abb93d2084921a6a85873c499c944205c499 100644 --- a/arch/xtensa/kernel/stacktrace.c +++ b/arch/xtensa/kernel/stacktrace.c @@ -44,6 +44,11 @@ void xtensa_backtrace_user(struct pt_regs *regs, unsigned int depth, if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data)) return; + if (IS_ENABLED(CONFIG_USER_ABI_CALL0_ONLY) || + (IS_ENABLED(CONFIG_USER_ABI_CALL0_PROBE) && + !(regs->ps & PS_WOE_MASK))) + return; + /* Two steps: * * 1. Look through the register window for the diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c index f060348c1b233a04373294dad0d834e0a129f60d..4a6c495ce9b6da69302b9a16075ab99933964724 100644 --- a/arch/xtensa/kernel/traps.c +++ b/arch/xtensa/kernel/traps.c @@ -51,6 +51,7 @@ extern void kernel_exception(void); extern void user_exception(void); +extern void fast_illegal_instruction_user(void); extern void fast_syscall_user(void); extern void fast_alloca(void); extern void fast_unaligned(void); @@ -87,6 +88,9 @@ typedef struct { static dispatch_init_table_t __initdata dispatch_init_table[] = { +#ifdef CONFIG_USER_ABI_CALL0_PROBE +{ EXCCAUSE_ILLEGAL_INSTRUCTION, USER, fast_illegal_instruction_user }, +#endif { EXCCAUSE_ILLEGAL_INSTRUCTION, 0, do_illegal_instruction}, { EXCCAUSE_SYSTEM_CALL, USER, fast_syscall_user }, { EXCCAUSE_SYSTEM_CALL, 0, system_call }, diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c index 79467c74941666bf3c7738cbc416a92128498636..d898ed67d890c7c49625c447db711397b788cc45 100644 --- a/arch/xtensa/mm/init.c +++ b/arch/xtensa/mm/init.c @@ -203,16 +203,6 @@ void __init mem_init(void) (unsigned long)(__bss_stop - __bss_start) >> 10); } -#ifdef CONFIG_BLK_DEV_INITRD -extern int initrd_is_mapped; - -void free_initrd_mem(unsigned long start, unsigned long end) -{ - if (initrd_is_mapped) - free_reserved_area((void *)start, (void *)end, -1, "initrd"); -} -#endif - static void __init parse_memmap_one(char *p) { char *oldp; diff --git a/block/Kconfig b/block/Kconfig index 8b5f8e560eb4eaf5fef02298edfc6ebc9c03efd6..41c0917ce6223db176ccf5922186465e12abebef 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -26,6 +26,9 @@ menuconfig BLOCK if BLOCK +config BLK_RQ_ALLOC_TIME + bool + config BLK_SCSI_REQUEST bool @@ -132,6 +135,16 @@ config BLK_CGROUP_IOLATENCY Note, this is an experimental interface and could be changed someday. +config BLK_CGROUP_IOCOST + bool "Enable support for cost model based cgroup IO controller" + depends on BLK_CGROUP=y + select BLK_RQ_ALLOC_TIME + ---help--- + Enabling this option enables the .weight interface for cost + model based proportional IO control. The IO controller + distributes IO capacity between different groups based on + their share of the overall weight distribution. + config BLK_WBT_MQ bool "Multiqueue writeback throttling" default y diff --git a/block/Makefile b/block/Makefile index eee1b4ceecf915cf3dab90820ff6f5608ea3bb04..9ef57ace90d46c1cd6544369a80b802896ce99c9 100644 --- a/block/Makefile +++ b/block/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_BLK_DEV_BSGLIB) += bsg-lib.o obj-$(CONFIG_BLK_CGROUP) += blk-cgroup.o obj-$(CONFIG_BLK_DEV_THROTTLING) += blk-throttle.o obj-$(CONFIG_BLK_CGROUP_IOLATENCY) += blk-iolatency.o +obj-$(CONFIG_BLK_CGROUP_IOCOST) += blk-iocost.o obj-$(CONFIG_MQ_IOSCHED_DEADLINE) += mq-deadline.o obj-$(CONFIG_MQ_IOSCHED_KYBER) += kyber-iosched.o bfq-y := bfq-iosched.o bfq-wf2q.o bfq-cgroup.o diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c index 0f6cd688924fbd23177438f4a2afba03331777bc..86a607cf19a1023271c4bd7a4090b451e2bb3fde 100644 --- a/block/bfq-cgroup.c +++ b/block/bfq-cgroup.c @@ -501,11 +501,12 @@ static void bfq_cpd_free(struct blkcg_policy_data *cpd) kfree(cpd_to_bfqgd(cpd)); } -static struct blkg_policy_data *bfq_pd_alloc(gfp_t gfp, int node) +static struct blkg_policy_data *bfq_pd_alloc(gfp_t gfp, struct request_queue *q, + struct blkcg *blkcg) { struct bfq_group *bfqg; - bfqg = kzalloc_node(sizeof(*bfqg), gfp, node); + bfqg = kzalloc_node(sizeof(*bfqg), gfp, q->node); if (!bfqg) return NULL; @@ -904,7 +905,7 @@ void bfq_end_wr_async(struct bfq_data *bfqd) bfq_end_wr_async_queues(bfqd, bfqd->root_group); } -static int bfq_io_show_weight(struct seq_file *sf, void *v) +static int bfq_io_show_weight_legacy(struct seq_file *sf, void *v) { struct blkcg *blkcg = css_to_blkcg(seq_css(sf)); struct bfq_group_data *bfqgd = blkcg_to_bfqgd(blkcg); @@ -918,6 +919,60 @@ static int bfq_io_show_weight(struct seq_file *sf, void *v) return 0; } +static u64 bfqg_prfill_weight_device(struct seq_file *sf, + struct blkg_policy_data *pd, int off) +{ + struct bfq_group *bfqg = pd_to_bfqg(pd); + + if (!bfqg->entity.dev_weight) + return 0; + return __blkg_prfill_u64(sf, pd, bfqg->entity.dev_weight); +} + +static int bfq_io_show_weight(struct seq_file *sf, void *v) +{ + struct blkcg *blkcg = css_to_blkcg(seq_css(sf)); + struct bfq_group_data *bfqgd = blkcg_to_bfqgd(blkcg); + + seq_printf(sf, "default %u\n", bfqgd->weight); + blkcg_print_blkgs(sf, blkcg, bfqg_prfill_weight_device, + &blkcg_policy_bfq, 0, false); + return 0; +} + +static void bfq_group_set_weight(struct bfq_group *bfqg, u64 weight, u64 dev_weight) +{ + weight = dev_weight ?: weight; + + bfqg->entity.dev_weight = dev_weight; + /* + * Setting the prio_changed flag of the entity + * to 1 with new_weight == weight would re-set + * the value of the weight to its ioprio mapping. + * Set the flag only if necessary. + */ + if ((unsigned short)weight != bfqg->entity.new_weight) { + bfqg->entity.new_weight = (unsigned short)weight; + /* + * Make sure that the above new value has been + * stored in bfqg->entity.new_weight before + * setting the prio_changed flag. In fact, + * this flag may be read asynchronously (in + * critical sections protected by a different + * lock than that held here), and finding this + * flag set may cause the execution of the code + * for updating parameters whose value may + * depend also on bfqg->entity.new_weight (in + * __bfq_entity_update_weight_prio). + * This barrier makes sure that the new value + * of bfqg->entity.new_weight is correctly + * seen in that code. + */ + smp_wmb(); + bfqg->entity.prio_changed = 1; + } +} + static int bfq_io_set_weight_legacy(struct cgroup_subsys_state *css, struct cftype *cftype, u64 val) @@ -936,55 +991,72 @@ static int bfq_io_set_weight_legacy(struct cgroup_subsys_state *css, hlist_for_each_entry(blkg, &blkcg->blkg_list, blkcg_node) { struct bfq_group *bfqg = blkg_to_bfqg(blkg); - if (!bfqg) - continue; - /* - * Setting the prio_changed flag of the entity - * to 1 with new_weight == weight would re-set - * the value of the weight to its ioprio mapping. - * Set the flag only if necessary. - */ - if ((unsigned short)val != bfqg->entity.new_weight) { - bfqg->entity.new_weight = (unsigned short)val; - /* - * Make sure that the above new value has been - * stored in bfqg->entity.new_weight before - * setting the prio_changed flag. In fact, - * this flag may be read asynchronously (in - * critical sections protected by a different - * lock than that held here), and finding this - * flag set may cause the execution of the code - * for updating parameters whose value may - * depend also on bfqg->entity.new_weight (in - * __bfq_entity_update_weight_prio). - * This barrier makes sure that the new value - * of bfqg->entity.new_weight is correctly - * seen in that code. - */ - smp_wmb(); - bfqg->entity.prio_changed = 1; - } + if (bfqg) + bfq_group_set_weight(bfqg, val, 0); } spin_unlock_irq(&blkcg->lock); return ret; } -static ssize_t bfq_io_set_weight(struct kernfs_open_file *of, - char *buf, size_t nbytes, - loff_t off) +static ssize_t bfq_io_set_device_weight(struct kernfs_open_file *of, + char *buf, size_t nbytes, + loff_t off) { - u64 weight; - /* First unsigned long found in the file is used */ - int ret = kstrtoull(strim(buf), 0, &weight); + int ret; + struct blkg_conf_ctx ctx; + struct blkcg *blkcg = css_to_blkcg(of_css(of)); + struct bfq_group *bfqg; + u64 v; + ret = blkg_conf_prep(blkcg, &blkcg_policy_bfq, buf, &ctx); if (ret) return ret; - ret = bfq_io_set_weight_legacy(of_css(of), NULL, weight); + if (sscanf(ctx.body, "%llu", &v) == 1) { + /* require "default" on dfl */ + ret = -ERANGE; + if (!v) + goto out; + } else if (!strcmp(strim(ctx.body), "default")) { + v = 0; + } else { + ret = -EINVAL; + goto out; + } + + bfqg = blkg_to_bfqg(ctx.blkg); + + ret = -ERANGE; + if (!v || (v >= BFQ_MIN_WEIGHT && v <= BFQ_MAX_WEIGHT)) { + bfq_group_set_weight(bfqg, bfqg->entity.weight, v); + ret = 0; + } +out: + blkg_conf_finish(&ctx); return ret ?: nbytes; } +static ssize_t bfq_io_set_weight(struct kernfs_open_file *of, + char *buf, size_t nbytes, + loff_t off) +{ + char *endp; + int ret; + u64 v; + + buf = strim(buf); + + /* "WEIGHT" or "default WEIGHT" sets the default weight */ + v = simple_strtoull(buf, &endp, 0); + if (*endp == '\0' || sscanf(buf, "default %llu", &v) == 1) { + ret = bfq_io_set_weight_legacy(of_css(of), NULL, v); + return ret ?: nbytes; + } + + return bfq_io_set_device_weight(of, buf, nbytes, off); +} + #ifdef CONFIG_BFQ_CGROUP_DEBUG static int bfqg_print_stat(struct seq_file *sf, void *v) { @@ -1141,9 +1213,15 @@ struct cftype bfq_blkcg_legacy_files[] = { { .name = "bfq.weight", .flags = CFTYPE_NOT_ON_ROOT, - .seq_show = bfq_io_show_weight, + .seq_show = bfq_io_show_weight_legacy, .write_u64 = bfq_io_set_weight_legacy, }, + { + .name = "bfq.weight_device", + .flags = CFTYPE_NOT_ON_ROOT, + .seq_show = bfq_io_show_weight, + .write = bfq_io_set_weight, + }, /* statistics, covers only the tasks in the bfqg */ { diff --git a/block/bfq-iosched.h b/block/bfq-iosched.h index e80adf822bbeabb2ee00fe53d168103738bd72fe..5d1a519640f6a3a94e2fabfe9fe7678905f26bc8 100644 --- a/block/bfq-iosched.h +++ b/block/bfq-iosched.h @@ -168,6 +168,9 @@ struct bfq_entity { /* budget, used also to calculate F_i: F_i = S_i + @budget / @weight */ int budget; + /* device weight, if non-zero, it overrides the default weight of + * bfq_group_data */ + int dev_weight; /* weight of the queue */ int weight; /* next weight if a change is in progress */ diff --git a/block/bfq-wf2q.c b/block/bfq-wf2q.c index c9ba225081ceef58d5d36a569541af689526c7fd..05f0bf4a1144d79fc26e0024221907f1066182c5 100644 --- a/block/bfq-wf2q.c +++ b/block/bfq-wf2q.c @@ -744,6 +744,8 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st, } #endif + /* Matches the smp_wmb() in bfq_group_set_weight. */ + smp_rmb(); old_st->wsum -= entity->weight; if (entity->new_weight != entity->orig_weight) { diff --git a/block/bio.c b/block/bio.c index 299a0e7651ec00336f8b41b9d515eabc7d65ac0e..8f0ed6228fc59494c6319b3f50a26ba49669a221 100644 --- a/block/bio.c +++ b/block/bio.c @@ -646,25 +646,20 @@ static inline bool page_is_mergeable(const struct bio_vec *bv, return true; } -/* - * Check if the @page can be added to the current segment(@bv), and make - * sure to call it only if page_is_mergeable(@bv, @page) is true - */ -static bool can_add_page_to_seg(struct request_queue *q, - struct bio_vec *bv, struct page *page, unsigned len, - unsigned offset) +static bool bio_try_merge_pc_page(struct request_queue *q, struct bio *bio, + struct page *page, unsigned len, unsigned offset, + bool *same_page) { + struct bio_vec *bv = &bio->bi_io_vec[bio->bi_vcnt - 1]; unsigned long mask = queue_segment_boundary(q); phys_addr_t addr1 = page_to_phys(bv->bv_page) + bv->bv_offset; phys_addr_t addr2 = page_to_phys(page) + offset + len - 1; if ((addr1 | mask) != (addr2 | mask)) return false; - if (bv->bv_len + len > queue_max_segment_size(q)) return false; - - return true; + return __bio_try_merge_page(bio, page, len, offset, same_page); } /** @@ -674,7 +669,7 @@ static bool can_add_page_to_seg(struct request_queue *q, * @page: page to add * @len: vec entry length * @offset: vec entry offset - * @put_same_page: put the page if it is same with last added page + * @same_page: return if the merge happen inside the same page * * Attempt to add a page to the bio_vec maplist. This can fail for a * number of reasons, such as the bio being full or target block device @@ -685,10 +680,9 @@ static bool can_add_page_to_seg(struct request_queue *q, */ static int __bio_add_pc_page(struct request_queue *q, struct bio *bio, struct page *page, unsigned int len, unsigned int offset, - bool put_same_page) + bool *same_page) { struct bio_vec *bvec; - bool same_page = false; /* * cloned bio must not modify vec list @@ -700,28 +694,16 @@ static int __bio_add_pc_page(struct request_queue *q, struct bio *bio, return 0; if (bio->bi_vcnt > 0) { - bvec = &bio->bi_io_vec[bio->bi_vcnt - 1]; - - if (page == bvec->bv_page && - offset == bvec->bv_offset + bvec->bv_len) { - if (put_same_page) - put_page(page); - bvec->bv_len += len; - goto done; - } + if (bio_try_merge_pc_page(q, bio, page, len, offset, same_page)) + return len; /* - * If the queue doesn't support SG gaps and adding this - * offset would create a gap, disallow it. + * If the queue doesn't support SG gaps and adding this segment + * would create a gap, disallow it. */ + bvec = &bio->bi_io_vec[bio->bi_vcnt - 1]; if (bvec_gap_to_prev(q, bvec, offset)) return 0; - - if (page_is_mergeable(bvec, page, len, offset, &same_page) && - can_add_page_to_seg(q, bvec, page, len, offset)) { - bvec->bv_len += len; - goto done; - } } if (bio_full(bio, len)) @@ -735,7 +717,6 @@ static int __bio_add_pc_page(struct request_queue *q, struct bio *bio, bvec->bv_len = len; bvec->bv_offset = offset; bio->bi_vcnt++; - done: bio->bi_iter.bi_size += len; return len; } @@ -743,7 +724,8 @@ static int __bio_add_pc_page(struct request_queue *q, struct bio *bio, int bio_add_pc_page(struct request_queue *q, struct bio *bio, struct page *page, unsigned int len, unsigned int offset) { - return __bio_add_pc_page(q, bio, page, len, offset, false); + bool same_page = false; + return __bio_add_pc_page(q, bio, page, len, offset, &same_page); } EXPORT_SYMBOL(bio_add_pc_page); @@ -806,6 +788,9 @@ void __bio_add_page(struct bio *bio, struct page *page, bio->bi_iter.bi_size += len; bio->bi_vcnt++; + + if (!bio_flagged(bio, BIO_WORKINGSET) && unlikely(PageWorkingset(page))) + bio_set_flag(bio, BIO_WORKINGSET); } EXPORT_SYMBOL_GPL(__bio_add_page); @@ -1384,13 +1369,17 @@ struct bio *bio_map_user_iov(struct request_queue *q, for (j = 0; j < npages; j++) { struct page *page = pages[j]; unsigned int n = PAGE_SIZE - offs; + bool same_page = false; if (n > bytes) n = bytes; if (!__bio_add_pc_page(q, bio, page, n, offs, - true)) + &same_page)) { + if (same_page) + put_page(page); break; + } added += n; bytes -= n; @@ -1521,7 +1510,6 @@ struct bio *bio_map_kern(struct request_queue *q, void *data, unsigned int len, bio->bi_end_io = bio_map_kern_endio; return bio; } -EXPORT_SYMBOL(bio_map_kern); static void bio_copy_kern_endio(struct bio *bio) { @@ -1842,8 +1830,8 @@ EXPORT_SYMBOL(bio_endio); * @bio, and updates @bio to represent the remaining sectors. * * Unless this is a discard request the newly allocated bio will point - * to @bio's bi_io_vec; it is the caller's responsibility to ensure that - * @bio is not freed before the split. + * to @bio's bi_io_vec. It is the caller's responsibility to ensure that + * neither @bio nor @bs are freed before the split bio. */ struct bio *bio_split(struct bio *bio, int sectors, gfp_t gfp, struct bio_set *bs) diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 55a7dc227dfbd6af883a2832d09c8abf2c16d3d0..b6f20be0fc78c16a2984294386a25b2893f677fc 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -175,7 +175,7 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct request_queue *q, continue; /* alloc per-policy data and attach it to blkg */ - pd = pol->pd_alloc_fn(gfp_mask, q->node); + pd = pol->pd_alloc_fn(gfp_mask, q, blkcg); if (!pd) goto err_free; @@ -753,6 +753,44 @@ static struct blkcg_gq *blkg_lookup_check(struct blkcg *blkcg, return __blkg_lookup(blkcg, q, true /* update_hint */); } +/** + * blkg_conf_prep - parse and prepare for per-blkg config update + * @inputp: input string pointer + * + * Parse the device node prefix part, MAJ:MIN, of per-blkg config update + * from @input and get and return the matching gendisk. *@inputp is + * updated to point past the device node prefix. Returns an ERR_PTR() + * value on error. + * + * Use this function iff blkg_conf_prep() can't be used for some reason. + */ +struct gendisk *blkcg_conf_get_disk(char **inputp) +{ + char *input = *inputp; + unsigned int major, minor; + struct gendisk *disk; + int key_len, part; + + if (sscanf(input, "%u:%u%n", &major, &minor, &key_len) != 2) + return ERR_PTR(-EINVAL); + + input += key_len; + if (!isspace(*input)) + return ERR_PTR(-EINVAL); + input = skip_spaces(input); + + disk = get_gendisk(MKDEV(major, minor), &part); + if (!disk) + return ERR_PTR(-ENODEV); + if (part) { + put_disk_and_module(disk); + return ERR_PTR(-ENODEV); + } + + *inputp = input; + return disk; +} + /** * blkg_conf_prep - parse and prepare for per-blkg config update * @blkcg: target block cgroup @@ -772,25 +810,11 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol, struct gendisk *disk; struct request_queue *q; struct blkcg_gq *blkg; - unsigned int major, minor; - int key_len, part, ret; - char *body; - - if (sscanf(input, "%u:%u%n", &major, &minor, &key_len) != 2) - return -EINVAL; - - body = input + key_len; - if (!isspace(*body)) - return -EINVAL; - body = skip_spaces(body); + int ret; - disk = get_gendisk(MKDEV(major, minor), &part); - if (!disk) - return -ENODEV; - if (part) { - ret = -ENODEV; - goto fail; - } + disk = blkcg_conf_get_disk(&input); + if (IS_ERR(disk)) + return PTR_ERR(disk); q = disk->queue; @@ -856,7 +880,7 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol, success: ctx->disk = disk; ctx->blkg = blkg; - ctx->body = body; + ctx->body = input; return 0; fail_unlock: @@ -876,6 +900,7 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol, } return ret; } +EXPORT_SYMBOL_GPL(blkg_conf_prep); /** * blkg_conf_finish - finish up per-blkg config update @@ -891,6 +916,7 @@ void blkg_conf_finish(struct blkg_conf_ctx *ctx) rcu_read_unlock(); put_disk_and_module(ctx->disk); } +EXPORT_SYMBOL_GPL(blkg_conf_finish); static int blkcg_print_stat(struct seq_file *sf, void *v) { @@ -1346,7 +1372,7 @@ int blkcg_activate_policy(struct request_queue *q, blk_mq_freeze_queue(q); pd_prealloc: if (!pd_prealloc) { - pd_prealloc = pol->pd_alloc_fn(GFP_KERNEL, q->node); + pd_prealloc = pol->pd_alloc_fn(GFP_KERNEL, q, &blkcg_root); if (!pd_prealloc) { ret = -ENOMEM; goto out_bypass_end; @@ -1362,7 +1388,7 @@ int blkcg_activate_policy(struct request_queue *q, if (blkg->pd[pol->plid]) continue; - pd = pol->pd_alloc_fn(GFP_NOWAIT | __GFP_NOWARN, q->node); + pd = pol->pd_alloc_fn(GFP_NOWAIT | __GFP_NOWARN, q, &blkcg_root); if (!pd) swap(pd, pd_prealloc); if (!pd) { @@ -1475,7 +1501,8 @@ int blkcg_policy_register(struct blkcg_policy *pol) blkcg->cpd[pol->plid] = cpd; cpd->blkcg = blkcg; cpd->plid = pol->plid; - pol->cpd_init_fn(cpd); + if (pol->cpd_init_fn) + pol->cpd_init_fn(cpd); } } diff --git a/block/blk-core.c b/block/blk-core.c index d0cc6e14d2f0748e91001d770cbebfa091066889..875e8d105067a2248b7829e487bd66c5f4c9281c 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -36,6 +36,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -129,6 +130,7 @@ static const char *const blk_op_name[] = { REQ_OP_NAME(DISCARD), REQ_OP_NAME(SECURE_ERASE), REQ_OP_NAME(ZONE_RESET), + REQ_OP_NAME(ZONE_RESET_ALL), REQ_OP_NAME(WRITE_SAME), REQ_OP_NAME(WRITE_ZEROES), REQ_OP_NAME(SCSI_IN), @@ -344,7 +346,8 @@ void blk_cleanup_queue(struct request_queue *q) /* * Drain all requests queued before DYING marking. Set DEAD flag to - * prevent that q->request_fn() gets invoked after draining finished. + * prevent that blk_mq_run_hw_queues() accesses the hardware queues + * after draining finished. */ blk_freeze_queue(q); @@ -479,7 +482,6 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) if (!q) return NULL; - INIT_LIST_HEAD(&q->queue_head); q->last_merge = NULL; q->id = ida_simple_get(&blk_queue_ida, 0, 0, gfp_mask); @@ -518,6 +520,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) mutex_init(&q->blk_trace_mutex); #endif mutex_init(&q->sysfs_lock); + mutex_init(&q->sysfs_dir_lock); spin_lock_init(&q->queue_lock); init_waitqueue_head(&q->mq_freeze_wq); @@ -601,6 +604,7 @@ bool bio_attempt_back_merge(struct request *req, struct bio *bio, return false; trace_block_bio_backmerge(req->q, req, bio); + rq_qos_merge(req->q, req, bio); if ((req->cmd_flags & REQ_FAILFAST_MASK) != ff) blk_rq_set_mixed_merge(req); @@ -622,6 +626,7 @@ bool bio_attempt_front_merge(struct request *req, struct bio *bio, return false; trace_block_bio_frontmerge(req->q, req, bio); + rq_qos_merge(req->q, req, bio); if ((req->cmd_flags & REQ_FAILFAST_MASK) != ff) blk_rq_set_mixed_merge(req); @@ -647,6 +652,8 @@ bool bio_attempt_discard_merge(struct request_queue *q, struct request *req, blk_rq_get_max_sectors(req, blk_rq_pos(req))) goto no_merge; + rq_qos_merge(q, req, bio); + req->biotail->bi_next = bio; req->biotail = bio; req->__data_len += bio->bi_iter.bi_size; @@ -931,6 +938,10 @@ generic_make_request_checks(struct bio *bio) if (!blk_queue_is_zoned(q)) goto not_supported; break; + case REQ_OP_ZONE_RESET_ALL: + if (!blk_queue_is_zoned(q) || !blk_queue_zone_resetall(q)) + goto not_supported; + break; case REQ_OP_WRITE_ZEROES: if (!q->limits.max_write_zeroes_sectors) goto not_supported; @@ -1128,6 +1139,10 @@ EXPORT_SYMBOL_GPL(direct_make_request); */ blk_qc_t submit_bio(struct bio *bio) { + bool workingset_read = false; + unsigned long pflags; + blk_qc_t ret; + if (blkcg_punt_bio_submit(bio)) return BLK_QC_T_NONE; @@ -1146,6 +1161,8 @@ blk_qc_t submit_bio(struct bio *bio) if (op_is_write(bio_op(bio))) { count_vm_events(PGPGOUT, count); } else { + if (bio_flagged(bio, BIO_WORKINGSET)) + workingset_read = true; task_io_account_read(bio->bi_iter.bi_size); count_vm_events(PGPGIN, count); } @@ -1160,7 +1177,21 @@ blk_qc_t submit_bio(struct bio *bio) } } - return generic_make_request(bio); + /* + * If we're reading data that is part of the userspace + * workingset, count submission time as memory stall. When the + * device is congested, or the submitting cgroup IO-throttled, + * submission can be a significant part of overall IO time. + */ + if (workingset_read) + psi_memstall_enter(&pflags); + + ret = generic_make_request(bio); + + if (workingset_read) + psi_memstall_leave(&pflags); + + return ret; } EXPORT_SYMBOL(submit_bio); diff --git a/block/blk-iocost.c b/block/blk-iocost.c new file mode 100644 index 0000000000000000000000000000000000000000..3b39deb8b9f820620b86c0d964b30eb1dbb362b6 --- /dev/null +++ b/block/blk-iocost.c @@ -0,0 +1,2457 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * IO cost model based controller. + * + * Copyright (C) 2019 Tejun Heo + * Copyright (C) 2019 Andy Newell + * Copyright (C) 2019 Facebook + * + * One challenge of controlling IO resources is the lack of trivially + * observable cost metric. This is distinguished from CPU and memory where + * wallclock time and the number of bytes can serve as accurate enough + * approximations. + * + * Bandwidth and iops are the most commonly used metrics for IO devices but + * depending on the type and specifics of the device, different IO patterns + * easily lead to multiple orders of magnitude variations rendering them + * useless for the purpose of IO capacity distribution. While on-device + * time, with a lot of clutches, could serve as a useful approximation for + * non-queued rotational devices, this is no longer viable with modern + * devices, even the rotational ones. + * + * While there is no cost metric we can trivially observe, it isn't a + * complete mystery. For example, on a rotational device, seek cost + * dominates while a contiguous transfer contributes a smaller amount + * proportional to the size. If we can characterize at least the relative + * costs of these different types of IOs, it should be possible to + * implement a reasonable work-conserving proportional IO resource + * distribution. + * + * 1. IO Cost Model + * + * IO cost model estimates the cost of an IO given its basic parameters and + * history (e.g. the end sector of the last IO). The cost is measured in + * device time. If a given IO is estimated to cost 10ms, the device should + * be able to process ~100 of those IOs in a second. + * + * Currently, there's only one builtin cost model - linear. Each IO is + * classified as sequential or random and given a base cost accordingly. + * On top of that, a size cost proportional to the length of the IO is + * added. While simple, this model captures the operational + * characteristics of a wide varienty of devices well enough. Default + * paramters for several different classes of devices are provided and the + * parameters can be configured from userspace via + * /sys/fs/cgroup/io.cost.model. + * + * If needed, tools/cgroup/iocost_coef_gen.py can be used to generate + * device-specific coefficients. + * + * If needed, tools/cgroup/iocost_coef_gen.py can be used to generate + * device-specific coefficients. + * + * 2. Control Strategy + * + * The device virtual time (vtime) is used as the primary control metric. + * The control strategy is composed of the following three parts. + * + * 2-1. Vtime Distribution + * + * When a cgroup becomes active in terms of IOs, its hierarchical share is + * calculated. Please consider the following hierarchy where the numbers + * inside parentheses denote the configured weights. + * + * root + * / \ + * A (w:100) B (w:300) + * / \ + * A0 (w:100) A1 (w:100) + * + * If B is idle and only A0 and A1 are actively issuing IOs, as the two are + * of equal weight, each gets 50% share. If then B starts issuing IOs, B + * gets 300/(100+300) or 75% share, and A0 and A1 equally splits the rest, + * 12.5% each. The distribution mechanism only cares about these flattened + * shares. They're called hweights (hierarchical weights) and always add + * upto 1 (HWEIGHT_WHOLE). + * + * A given cgroup's vtime runs slower in inverse proportion to its hweight. + * For example, with 12.5% weight, A0's time runs 8 times slower (100/12.5) + * against the device vtime - an IO which takes 10ms on the underlying + * device is considered to take 80ms on A0. + * + * This constitutes the basis of IO capacity distribution. Each cgroup's + * vtime is running at a rate determined by its hweight. A cgroup tracks + * the vtime consumed by past IOs and can issue a new IO iff doing so + * wouldn't outrun the current device vtime. Otherwise, the IO is + * suspended until the vtime has progressed enough to cover it. + * + * 2-2. Vrate Adjustment + * + * It's unrealistic to expect the cost model to be perfect. There are too + * many devices and even on the same device the overall performance + * fluctuates depending on numerous factors such as IO mixture and device + * internal garbage collection. The controller needs to adapt dynamically. + * + * This is achieved by adjusting the overall IO rate according to how busy + * the device is. If the device becomes overloaded, we're sending down too + * many IOs and should generally slow down. If there are waiting issuers + * but the device isn't saturated, we're issuing too few and should + * generally speed up. + * + * To slow down, we lower the vrate - the rate at which the device vtime + * passes compared to the wall clock. For example, if the vtime is running + * at the vrate of 75%, all cgroups added up would only be able to issue + * 750ms worth of IOs per second, and vice-versa for speeding up. + * + * Device business is determined using two criteria - rq wait and + * completion latencies. + * + * When a device gets saturated, the on-device and then the request queues + * fill up and a bio which is ready to be issued has to wait for a request + * to become available. When this delay becomes noticeable, it's a clear + * indication that the device is saturated and we lower the vrate. This + * saturation signal is fairly conservative as it only triggers when both + * hardware and software queues are filled up, and is used as the default + * busy signal. + * + * As devices can have deep queues and be unfair in how the queued commands + * are executed, soley depending on rq wait may not result in satisfactory + * control quality. For a better control quality, completion latency QoS + * parameters can be configured so that the device is considered saturated + * if N'th percentile completion latency rises above the set point. + * + * The completion latency requirements are a function of both the + * underlying device characteristics and the desired IO latency quality of + * service. There is an inherent trade-off - the tighter the latency QoS, + * the higher the bandwidth lossage. Latency QoS is disabled by default + * and can be set through /sys/fs/cgroup/io.cost.qos. + * + * 2-3. Work Conservation + * + * Imagine two cgroups A and B with equal weights. A is issuing a small IO + * periodically while B is sending out enough parallel IOs to saturate the + * device on its own. Let's say A's usage amounts to 100ms worth of IO + * cost per second, i.e., 10% of the device capacity. The naive + * distribution of half and half would lead to 60% utilization of the + * device, a significant reduction in the total amount of work done + * compared to free-for-all competition. This is too high a cost to pay + * for IO control. + * + * To conserve the total amount of work done, we keep track of how much + * each active cgroup is actually using and yield part of its weight if + * there are other cgroups which can make use of it. In the above case, + * A's weight will be lowered so that it hovers above the actual usage and + * B would be able to use the rest. + * + * As we don't want to penalize a cgroup for donating its weight, the + * surplus weight adjustment factors in a margin and has an immediate + * snapback mechanism in case the cgroup needs more IO vtime for itself. + * + * Note that adjusting down surplus weights has the same effects as + * accelerating vtime for other cgroups and work conservation can also be + * implemented by adjusting vrate dynamically. However, squaring who can + * donate and should take back how much requires hweight propagations + * anyway making it easier to implement and understand as a separate + * mechanism. + * + * 3. Monitoring + * + * Instead of debugfs or other clumsy monitoring mechanisms, this + * controller uses a drgn based monitoring script - + * tools/cgroup/iocost_monitor.py. For details on drgn, please see + * https://github.com/osandov/drgn. The ouput looks like the following. + * + * sdb RUN per=300ms cur_per=234.218:v203.695 busy= +1 vrate= 62.12% + * active weight hweight% inflt% dbt delay usages% + * test/a * 50/ 50 33.33/ 33.33 27.65 2 0*041 033:033:033 + * test/b * 100/ 100 66.67/ 66.67 17.56 0 0*000 066:079:077 + * + * - per : Timer period + * - cur_per : Internal wall and device vtime clock + * - vrate : Device virtual time rate against wall clock + * - weight : Surplus-adjusted and configured weights + * - hweight : Surplus-adjusted and configured hierarchical weights + * - inflt : The percentage of in-flight IO cost at the end of last period + * - del_ms : Deferred issuer delay induction level and duration + * - usages : Usage history + */ + +#include +#include +#include +#include +#include +#include +#include +#include "blk-rq-qos.h" +#include "blk-stat.h" +#include "blk-wbt.h" + +#ifdef CONFIG_TRACEPOINTS + +/* copied from TRACE_CGROUP_PATH, see cgroup-internal.h */ +#define TRACE_IOCG_PATH_LEN 1024 +static DEFINE_SPINLOCK(trace_iocg_path_lock); +static char trace_iocg_path[TRACE_IOCG_PATH_LEN]; + +#define TRACE_IOCG_PATH(type, iocg, ...) \ + do { \ + unsigned long flags; \ + if (trace_iocost_##type##_enabled()) { \ + spin_lock_irqsave(&trace_iocg_path_lock, flags); \ + cgroup_path(iocg_to_blkg(iocg)->blkcg->css.cgroup, \ + trace_iocg_path, TRACE_IOCG_PATH_LEN); \ + trace_iocost_##type(iocg, trace_iocg_path, \ + ##__VA_ARGS__); \ + spin_unlock_irqrestore(&trace_iocg_path_lock, flags); \ + } \ + } while (0) + +#else /* CONFIG_TRACE_POINTS */ +#define TRACE_IOCG_PATH(type, iocg, ...) do { } while (0) +#endif /* CONFIG_TRACE_POINTS */ + +enum { + MILLION = 1000000, + + /* timer period is calculated from latency requirements, bound it */ + MIN_PERIOD = USEC_PER_MSEC, + MAX_PERIOD = USEC_PER_SEC, + + /* + * A cgroup's vtime can run 50% behind the device vtime, which + * serves as its IO credit buffer. Surplus weight adjustment is + * immediately canceled if the vtime margin runs below 10%. + */ + MARGIN_PCT = 50, + INUSE_MARGIN_PCT = 10, + + /* Have some play in waitq timer operations */ + WAITQ_TIMER_MARGIN_PCT = 5, + + /* + * vtime can wrap well within a reasonable uptime when vrate is + * consistently raised. Don't trust recorded cgroup vtime if the + * period counter indicates that it's older than 5mins. + */ + VTIME_VALID_DUR = 300 * USEC_PER_SEC, + + /* + * Remember the past three non-zero usages and use the max for + * surplus calculation. Three slots guarantee that we remember one + * full period usage from the last active stretch even after + * partial deactivation and re-activation periods. Don't start + * giving away weight before collecting two data points to prevent + * hweight adjustments based on one partial activation period. + */ + NR_USAGE_SLOTS = 3, + MIN_VALID_USAGES = 2, + + /* 1/64k is granular enough and can easily be handled w/ u32 */ + HWEIGHT_WHOLE = 1 << 16, + + /* + * As vtime is used to calculate the cost of each IO, it needs to + * be fairly high precision. For example, it should be able to + * represent the cost of a single page worth of discard with + * suffificient accuracy. At the same time, it should be able to + * represent reasonably long enough durations to be useful and + * convenient during operation. + * + * 1s worth of vtime is 2^37. This gives us both sub-nanosecond + * granularity and days of wrap-around time even at extreme vrates. + */ + VTIME_PER_SEC_SHIFT = 37, + VTIME_PER_SEC = 1LLU << VTIME_PER_SEC_SHIFT, + VTIME_PER_USEC = VTIME_PER_SEC / USEC_PER_SEC, + + /* bound vrate adjustments within two orders of magnitude */ + VRATE_MIN_PPM = 10000, /* 1% */ + VRATE_MAX_PPM = 100000000, /* 10000% */ + + VRATE_MIN = VTIME_PER_USEC * VRATE_MIN_PPM / MILLION, + VRATE_CLAMP_ADJ_PCT = 4, + + /* if IOs end up waiting for requests, issue less */ + RQ_WAIT_BUSY_PCT = 5, + + /* unbusy hysterisis */ + UNBUSY_THR_PCT = 75, + + /* don't let cmds which take a very long time pin lagging for too long */ + MAX_LAGGING_PERIODS = 10, + + /* + * If usage% * 1.25 + 2% is lower than hweight% by more than 3%, + * donate the surplus. + */ + SURPLUS_SCALE_PCT = 125, /* * 125% */ + SURPLUS_SCALE_ABS = HWEIGHT_WHOLE / 50, /* + 2% */ + SURPLUS_MIN_ADJ_DELTA = HWEIGHT_WHOLE / 33, /* 3% */ + + /* switch iff the conditions are met for longer than this */ + AUTOP_CYCLE_NSEC = 10LLU * NSEC_PER_SEC, + + /* + * Count IO size in 4k pages. The 12bit shift helps keeping + * size-proportional components of cost calculation in closer + * numbers of digits to per-IO cost components. + */ + IOC_PAGE_SHIFT = 12, + IOC_PAGE_SIZE = 1 << IOC_PAGE_SHIFT, + IOC_SECT_TO_PAGE_SHIFT = IOC_PAGE_SHIFT - SECTOR_SHIFT, + + /* if apart further than 16M, consider randio for linear model */ + LCOEF_RANDIO_PAGES = 4096, +}; + +enum ioc_running { + IOC_IDLE, + IOC_RUNNING, + IOC_STOP, +}; + +/* io.cost.qos controls including per-dev enable of the whole controller */ +enum { + QOS_ENABLE, + QOS_CTRL, + NR_QOS_CTRL_PARAMS, +}; + +/* io.cost.qos params */ +enum { + QOS_RPPM, + QOS_RLAT, + QOS_WPPM, + QOS_WLAT, + QOS_MIN, + QOS_MAX, + NR_QOS_PARAMS, +}; + +/* io.cost.model controls */ +enum { + COST_CTRL, + COST_MODEL, + NR_COST_CTRL_PARAMS, +}; + +/* builtin linear cost model coefficients */ +enum { + I_LCOEF_RBPS, + I_LCOEF_RSEQIOPS, + I_LCOEF_RRANDIOPS, + I_LCOEF_WBPS, + I_LCOEF_WSEQIOPS, + I_LCOEF_WRANDIOPS, + NR_I_LCOEFS, +}; + +enum { + LCOEF_RPAGE, + LCOEF_RSEQIO, + LCOEF_RRANDIO, + LCOEF_WPAGE, + LCOEF_WSEQIO, + LCOEF_WRANDIO, + NR_LCOEFS, +}; + +enum { + AUTOP_INVALID, + AUTOP_HDD, + AUTOP_SSD_QD1, + AUTOP_SSD_DFL, + AUTOP_SSD_FAST, +}; + +struct ioc_gq; + +struct ioc_params { + u32 qos[NR_QOS_PARAMS]; + u64 i_lcoefs[NR_I_LCOEFS]; + u64 lcoefs[NR_LCOEFS]; + u32 too_fast_vrate_pct; + u32 too_slow_vrate_pct; +}; + +struct ioc_missed { + u32 nr_met; + u32 nr_missed; + u32 last_met; + u32 last_missed; +}; + +struct ioc_pcpu_stat { + struct ioc_missed missed[2]; + + u64 rq_wait_ns; + u64 last_rq_wait_ns; +}; + +/* per device */ +struct ioc { + struct rq_qos rqos; + + bool enabled; + + struct ioc_params params; + u32 period_us; + u32 margin_us; + u64 vrate_min; + u64 vrate_max; + + spinlock_t lock; + struct timer_list timer; + struct list_head active_iocgs; /* active cgroups */ + struct ioc_pcpu_stat __percpu *pcpu_stat; + + enum ioc_running running; + atomic64_t vtime_rate; + + seqcount_t period_seqcount; + u32 period_at; /* wallclock starttime */ + u64 period_at_vtime; /* vtime starttime */ + + atomic64_t cur_period; /* inc'd each period */ + int busy_level; /* saturation history */ + + u64 inuse_margin_vtime; + bool weights_updated; + atomic_t hweight_gen; /* for lazy hweights */ + + u64 autop_too_fast_at; + u64 autop_too_slow_at; + int autop_idx; + bool user_qos_params:1; + bool user_cost_model:1; +}; + +/* per device-cgroup pair */ +struct ioc_gq { + struct blkg_policy_data pd; + struct ioc *ioc; + + /* + * A iocg can get its weight from two sources - an explicit + * per-device-cgroup configuration or the default weight of the + * cgroup. `cfg_weight` is the explicit per-device-cgroup + * configuration. `weight` is the effective considering both + * sources. + * + * When an idle cgroup becomes active its `active` goes from 0 to + * `weight`. `inuse` is the surplus adjusted active weight. + * `active` and `inuse` are used to calculate `hweight_active` and + * `hweight_inuse`. + * + * `last_inuse` remembers `inuse` while an iocg is idle to persist + * surplus adjustments. + */ + u32 cfg_weight; + u32 weight; + u32 active; + u32 inuse; + u32 last_inuse; + + sector_t cursor; /* to detect randio */ + + /* + * `vtime` is this iocg's vtime cursor which progresses as IOs are + * issued. If lagging behind device vtime, the delta represents + * the currently available IO budget. If runnning ahead, the + * overage. + * + * `vtime_done` is the same but progressed on completion rather + * than issue. The delta behind `vtime` represents the cost of + * currently in-flight IOs. + * + * `last_vtime` is used to remember `vtime` at the end of the last + * period to calculate utilization. + */ + atomic64_t vtime; + atomic64_t done_vtime; + atomic64_t abs_vdebt; + u64 last_vtime; + + /* + * The period this iocg was last active in. Used for deactivation + * and invalidating `vtime`. + */ + atomic64_t active_period; + struct list_head active_list; + + /* see __propagate_active_weight() and current_hweight() for details */ + u64 child_active_sum; + u64 child_inuse_sum; + int hweight_gen; + u32 hweight_active; + u32 hweight_inuse; + bool has_surplus; + + struct wait_queue_head waitq; + struct hrtimer waitq_timer; + struct hrtimer delay_timer; + + /* usage is recorded as fractions of HWEIGHT_WHOLE */ + int usage_idx; + u32 usages[NR_USAGE_SLOTS]; + + /* this iocg's depth in the hierarchy and ancestors including self */ + int level; + struct ioc_gq *ancestors[]; +}; + +/* per cgroup */ +struct ioc_cgrp { + struct blkcg_policy_data cpd; + unsigned int dfl_weight; +}; + +struct ioc_now { + u64 now_ns; + u32 now; + u64 vnow; + u64 vrate; +}; + +struct iocg_wait { + struct wait_queue_entry wait; + struct bio *bio; + u64 abs_cost; + bool committed; +}; + +struct iocg_wake_ctx { + struct ioc_gq *iocg; + u32 hw_inuse; + s64 vbudget; +}; + +static const struct ioc_params autop[] = { + [AUTOP_HDD] = { + .qos = { + [QOS_RLAT] = 50000, /* 50ms */ + [QOS_WLAT] = 50000, + [QOS_MIN] = VRATE_MIN_PPM, + [QOS_MAX] = VRATE_MAX_PPM, + }, + .i_lcoefs = { + [I_LCOEF_RBPS] = 174019176, + [I_LCOEF_RSEQIOPS] = 41708, + [I_LCOEF_RRANDIOPS] = 370, + [I_LCOEF_WBPS] = 178075866, + [I_LCOEF_WSEQIOPS] = 42705, + [I_LCOEF_WRANDIOPS] = 378, + }, + }, + [AUTOP_SSD_QD1] = { + .qos = { + [QOS_RLAT] = 25000, /* 25ms */ + [QOS_WLAT] = 25000, + [QOS_MIN] = VRATE_MIN_PPM, + [QOS_MAX] = VRATE_MAX_PPM, + }, + .i_lcoefs = { + [I_LCOEF_RBPS] = 245855193, + [I_LCOEF_RSEQIOPS] = 61575, + [I_LCOEF_RRANDIOPS] = 6946, + [I_LCOEF_WBPS] = 141365009, + [I_LCOEF_WSEQIOPS] = 33716, + [I_LCOEF_WRANDIOPS] = 26796, + }, + }, + [AUTOP_SSD_DFL] = { + .qos = { + [QOS_RLAT] = 25000, /* 25ms */ + [QOS_WLAT] = 25000, + [QOS_MIN] = VRATE_MIN_PPM, + [QOS_MAX] = VRATE_MAX_PPM, + }, + .i_lcoefs = { + [I_LCOEF_RBPS] = 488636629, + [I_LCOEF_RSEQIOPS] = 8932, + [I_LCOEF_RRANDIOPS] = 8518, + [I_LCOEF_WBPS] = 427891549, + [I_LCOEF_WSEQIOPS] = 28755, + [I_LCOEF_WRANDIOPS] = 21940, + }, + .too_fast_vrate_pct = 500, + }, + [AUTOP_SSD_FAST] = { + .qos = { + [QOS_RLAT] = 5000, /* 5ms */ + [QOS_WLAT] = 5000, + [QOS_MIN] = VRATE_MIN_PPM, + [QOS_MAX] = VRATE_MAX_PPM, + }, + .i_lcoefs = { + [I_LCOEF_RBPS] = 3102524156LLU, + [I_LCOEF_RSEQIOPS] = 724816, + [I_LCOEF_RRANDIOPS] = 778122, + [I_LCOEF_WBPS] = 1742780862LLU, + [I_LCOEF_WSEQIOPS] = 425702, + [I_LCOEF_WRANDIOPS] = 443193, + }, + .too_slow_vrate_pct = 10, + }, +}; + +/* + * vrate adjust percentages indexed by ioc->busy_level. We adjust up on + * vtime credit shortage and down on device saturation. + */ +static u32 vrate_adj_pct[] = + { 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 16 }; + +static struct blkcg_policy blkcg_policy_iocost; + +/* accessors and helpers */ +static struct ioc *rqos_to_ioc(struct rq_qos *rqos) +{ + return container_of(rqos, struct ioc, rqos); +} + +static struct ioc *q_to_ioc(struct request_queue *q) +{ + return rqos_to_ioc(rq_qos_id(q, RQ_QOS_COST)); +} + +static const char *q_name(struct request_queue *q) +{ + if (test_bit(QUEUE_FLAG_REGISTERED, &q->queue_flags)) + return kobject_name(q->kobj.parent); + else + return ""; +} + +static const char __maybe_unused *ioc_name(struct ioc *ioc) +{ + return q_name(ioc->rqos.q); +} + +static struct ioc_gq *pd_to_iocg(struct blkg_policy_data *pd) +{ + return pd ? container_of(pd, struct ioc_gq, pd) : NULL; +} + +static struct ioc_gq *blkg_to_iocg(struct blkcg_gq *blkg) +{ + return pd_to_iocg(blkg_to_pd(blkg, &blkcg_policy_iocost)); +} + +static struct blkcg_gq *iocg_to_blkg(struct ioc_gq *iocg) +{ + return pd_to_blkg(&iocg->pd); +} + +static struct ioc_cgrp *blkcg_to_iocc(struct blkcg *blkcg) +{ + return container_of(blkcg_to_cpd(blkcg, &blkcg_policy_iocost), + struct ioc_cgrp, cpd); +} + +/* + * Scale @abs_cost to the inverse of @hw_inuse. The lower the hierarchical + * weight, the more expensive each IO. Must round up. + */ +static u64 abs_cost_to_cost(u64 abs_cost, u32 hw_inuse) +{ + return DIV64_U64_ROUND_UP(abs_cost * HWEIGHT_WHOLE, hw_inuse); +} + +/* + * The inverse of abs_cost_to_cost(). Must round up. + */ +static u64 cost_to_abs_cost(u64 cost, u32 hw_inuse) +{ + return DIV64_U64_ROUND_UP(cost * hw_inuse, HWEIGHT_WHOLE); +} + +static void iocg_commit_bio(struct ioc_gq *iocg, struct bio *bio, u64 cost) +{ + bio->bi_iocost_cost = cost; + atomic64_add(cost, &iocg->vtime); +} + +#define CREATE_TRACE_POINTS +#include + +/* latency Qos params changed, update period_us and all the dependent params */ +static void ioc_refresh_period_us(struct ioc *ioc) +{ + u32 ppm, lat, multi, period_us; + + lockdep_assert_held(&ioc->lock); + + /* pick the higher latency target */ + if (ioc->params.qos[QOS_RLAT] >= ioc->params.qos[QOS_WLAT]) { + ppm = ioc->params.qos[QOS_RPPM]; + lat = ioc->params.qos[QOS_RLAT]; + } else { + ppm = ioc->params.qos[QOS_WPPM]; + lat = ioc->params.qos[QOS_WLAT]; + } + + /* + * We want the period to be long enough to contain a healthy number + * of IOs while short enough for granular control. Define it as a + * multiple of the latency target. Ideally, the multiplier should + * be scaled according to the percentile so that it would nominally + * contain a certain number of requests. Let's be simpler and + * scale it linearly so that it's 2x >= pct(90) and 10x at pct(50). + */ + if (ppm) + multi = max_t(u32, (MILLION - ppm) / 50000, 2); + else + multi = 2; + period_us = multi * lat; + period_us = clamp_t(u32, period_us, MIN_PERIOD, MAX_PERIOD); + + /* calculate dependent params */ + ioc->period_us = period_us; + ioc->margin_us = period_us * MARGIN_PCT / 100; + ioc->inuse_margin_vtime = DIV64_U64_ROUND_UP( + period_us * VTIME_PER_USEC * INUSE_MARGIN_PCT, 100); +} + +static int ioc_autop_idx(struct ioc *ioc) +{ + int idx = ioc->autop_idx; + const struct ioc_params *p = &autop[idx]; + u32 vrate_pct; + u64 now_ns; + + /* rotational? */ + if (!blk_queue_nonrot(ioc->rqos.q)) + return AUTOP_HDD; + + /* handle SATA SSDs w/ broken NCQ */ + if (blk_queue_depth(ioc->rqos.q) == 1) + return AUTOP_SSD_QD1; + + /* use one of the normal ssd sets */ + if (idx < AUTOP_SSD_DFL) + return AUTOP_SSD_DFL; + + /* if user is overriding anything, maintain what was there */ + if (ioc->user_qos_params || ioc->user_cost_model) + return idx; + + /* step up/down based on the vrate */ + vrate_pct = div64_u64(atomic64_read(&ioc->vtime_rate) * 100, + VTIME_PER_USEC); + now_ns = ktime_get_ns(); + + if (p->too_fast_vrate_pct && p->too_fast_vrate_pct <= vrate_pct) { + if (!ioc->autop_too_fast_at) + ioc->autop_too_fast_at = now_ns; + if (now_ns - ioc->autop_too_fast_at >= AUTOP_CYCLE_NSEC) + return idx + 1; + } else { + ioc->autop_too_fast_at = 0; + } + + if (p->too_slow_vrate_pct && p->too_slow_vrate_pct >= vrate_pct) { + if (!ioc->autop_too_slow_at) + ioc->autop_too_slow_at = now_ns; + if (now_ns - ioc->autop_too_slow_at >= AUTOP_CYCLE_NSEC) + return idx - 1; + } else { + ioc->autop_too_slow_at = 0; + } + + return idx; +} + +/* + * Take the followings as input + * + * @bps maximum sequential throughput + * @seqiops maximum sequential 4k iops + * @randiops maximum random 4k iops + * + * and calculate the linear model cost coefficients. + * + * *@page per-page cost 1s / (@bps / 4096) + * *@seqio base cost of a seq IO max((1s / @seqiops) - *@page, 0) + * @randiops base cost of a rand IO max((1s / @randiops) - *@page, 0) + */ +static void calc_lcoefs(u64 bps, u64 seqiops, u64 randiops, + u64 *page, u64 *seqio, u64 *randio) +{ + u64 v; + + *page = *seqio = *randio = 0; + + if (bps) + *page = DIV64_U64_ROUND_UP(VTIME_PER_SEC, + DIV_ROUND_UP_ULL(bps, IOC_PAGE_SIZE)); + + if (seqiops) { + v = DIV64_U64_ROUND_UP(VTIME_PER_SEC, seqiops); + if (v > *page) + *seqio = v - *page; + } + + if (randiops) { + v = DIV64_U64_ROUND_UP(VTIME_PER_SEC, randiops); + if (v > *page) + *randio = v - *page; + } +} + +static void ioc_refresh_lcoefs(struct ioc *ioc) +{ + u64 *u = ioc->params.i_lcoefs; + u64 *c = ioc->params.lcoefs; + + calc_lcoefs(u[I_LCOEF_RBPS], u[I_LCOEF_RSEQIOPS], u[I_LCOEF_RRANDIOPS], + &c[LCOEF_RPAGE], &c[LCOEF_RSEQIO], &c[LCOEF_RRANDIO]); + calc_lcoefs(u[I_LCOEF_WBPS], u[I_LCOEF_WSEQIOPS], u[I_LCOEF_WRANDIOPS], + &c[LCOEF_WPAGE], &c[LCOEF_WSEQIO], &c[LCOEF_WRANDIO]); +} + +static bool ioc_refresh_params(struct ioc *ioc, bool force) +{ + const struct ioc_params *p; + int idx; + + lockdep_assert_held(&ioc->lock); + + idx = ioc_autop_idx(ioc); + p = &autop[idx]; + + if (idx == ioc->autop_idx && !force) + return false; + + if (idx != ioc->autop_idx) + atomic64_set(&ioc->vtime_rate, VTIME_PER_USEC); + + ioc->autop_idx = idx; + ioc->autop_too_fast_at = 0; + ioc->autop_too_slow_at = 0; + + if (!ioc->user_qos_params) + memcpy(ioc->params.qos, p->qos, sizeof(p->qos)); + if (!ioc->user_cost_model) + memcpy(ioc->params.i_lcoefs, p->i_lcoefs, sizeof(p->i_lcoefs)); + + ioc_refresh_period_us(ioc); + ioc_refresh_lcoefs(ioc); + + ioc->vrate_min = DIV64_U64_ROUND_UP((u64)ioc->params.qos[QOS_MIN] * + VTIME_PER_USEC, MILLION); + ioc->vrate_max = div64_u64((u64)ioc->params.qos[QOS_MAX] * + VTIME_PER_USEC, MILLION); + + return true; +} + +/* take a snapshot of the current [v]time and vrate */ +static void ioc_now(struct ioc *ioc, struct ioc_now *now) +{ + unsigned seq; + + now->now_ns = ktime_get(); + now->now = ktime_to_us(now->now_ns); + now->vrate = atomic64_read(&ioc->vtime_rate); + + /* + * The current vtime is + * + * vtime at period start + (wallclock time since the start) * vrate + * + * As a consistent snapshot of `period_at_vtime` and `period_at` is + * needed, they're seqcount protected. + */ + do { + seq = read_seqcount_begin(&ioc->period_seqcount); + now->vnow = ioc->period_at_vtime + + (now->now - ioc->period_at) * now->vrate; + } while (read_seqcount_retry(&ioc->period_seqcount, seq)); +} + +static void ioc_start_period(struct ioc *ioc, struct ioc_now *now) +{ + lockdep_assert_held(&ioc->lock); + WARN_ON_ONCE(ioc->running != IOC_RUNNING); + + write_seqcount_begin(&ioc->period_seqcount); + ioc->period_at = now->now; + ioc->period_at_vtime = now->vnow; + write_seqcount_end(&ioc->period_seqcount); + + ioc->timer.expires = jiffies + usecs_to_jiffies(ioc->period_us); + add_timer(&ioc->timer); +} + +/* + * Update @iocg's `active` and `inuse` to @active and @inuse, update level + * weight sums and propagate upwards accordingly. + */ +static void __propagate_active_weight(struct ioc_gq *iocg, u32 active, u32 inuse) +{ + struct ioc *ioc = iocg->ioc; + int lvl; + + lockdep_assert_held(&ioc->lock); + + inuse = min(active, inuse); + + for (lvl = iocg->level - 1; lvl >= 0; lvl--) { + struct ioc_gq *parent = iocg->ancestors[lvl]; + struct ioc_gq *child = iocg->ancestors[lvl + 1]; + u32 parent_active = 0, parent_inuse = 0; + + /* update the level sums */ + parent->child_active_sum += (s32)(active - child->active); + parent->child_inuse_sum += (s32)(inuse - child->inuse); + /* apply the udpates */ + child->active = active; + child->inuse = inuse; + + /* + * The delta between inuse and active sums indicates that + * that much of weight is being given away. Parent's inuse + * and active should reflect the ratio. + */ + if (parent->child_active_sum) { + parent_active = parent->weight; + parent_inuse = DIV64_U64_ROUND_UP( + parent_active * parent->child_inuse_sum, + parent->child_active_sum); + } + + /* do we need to keep walking up? */ + if (parent_active == parent->active && + parent_inuse == parent->inuse) + break; + + active = parent_active; + inuse = parent_inuse; + } + + ioc->weights_updated = true; +} + +static void commit_active_weights(struct ioc *ioc) +{ + lockdep_assert_held(&ioc->lock); + + if (ioc->weights_updated) { + /* paired with rmb in current_hweight(), see there */ + smp_wmb(); + atomic_inc(&ioc->hweight_gen); + ioc->weights_updated = false; + } +} + +static void propagate_active_weight(struct ioc_gq *iocg, u32 active, u32 inuse) +{ + __propagate_active_weight(iocg, active, inuse); + commit_active_weights(iocg->ioc); +} + +static void current_hweight(struct ioc_gq *iocg, u32 *hw_activep, u32 *hw_inusep) +{ + struct ioc *ioc = iocg->ioc; + int lvl; + u32 hwa, hwi; + int ioc_gen; + + /* hot path - if uptodate, use cached */ + ioc_gen = atomic_read(&ioc->hweight_gen); + if (ioc_gen == iocg->hweight_gen) + goto out; + + /* + * Paired with wmb in commit_active_weights(). If we saw the + * updated hweight_gen, all the weight updates from + * __propagate_active_weight() are visible too. + * + * We can race with weight updates during calculation and get it + * wrong. However, hweight_gen would have changed and a future + * reader will recalculate and we're guaranteed to discard the + * wrong result soon. + */ + smp_rmb(); + + hwa = hwi = HWEIGHT_WHOLE; + for (lvl = 0; lvl <= iocg->level - 1; lvl++) { + struct ioc_gq *parent = iocg->ancestors[lvl]; + struct ioc_gq *child = iocg->ancestors[lvl + 1]; + u32 active_sum = READ_ONCE(parent->child_active_sum); + u32 inuse_sum = READ_ONCE(parent->child_inuse_sum); + u32 active = READ_ONCE(child->active); + u32 inuse = READ_ONCE(child->inuse); + + /* we can race with deactivations and either may read as zero */ + if (!active_sum || !inuse_sum) + continue; + + active_sum = max(active, active_sum); + hwa = hwa * active / active_sum; /* max 16bits * 10000 */ + + inuse_sum = max(inuse, inuse_sum); + hwi = hwi * inuse / inuse_sum; /* max 16bits * 10000 */ + } + + iocg->hweight_active = max_t(u32, hwa, 1); + iocg->hweight_inuse = max_t(u32, hwi, 1); + iocg->hweight_gen = ioc_gen; +out: + if (hw_activep) + *hw_activep = iocg->hweight_active; + if (hw_inusep) + *hw_inusep = iocg->hweight_inuse; +} + +static void weight_updated(struct ioc_gq *iocg) +{ + struct ioc *ioc = iocg->ioc; + struct blkcg_gq *blkg = iocg_to_blkg(iocg); + struct ioc_cgrp *iocc = blkcg_to_iocc(blkg->blkcg); + u32 weight; + + lockdep_assert_held(&ioc->lock); + + weight = iocg->cfg_weight ?: iocc->dfl_weight; + if (weight != iocg->weight && iocg->active) + propagate_active_weight(iocg, weight, + DIV64_U64_ROUND_UP(iocg->inuse * weight, iocg->weight)); + iocg->weight = weight; +} + +static bool iocg_activate(struct ioc_gq *iocg, struct ioc_now *now) +{ + struct ioc *ioc = iocg->ioc; + u64 last_period, cur_period, max_period_delta; + u64 vtime, vmargin, vmin; + int i; + + /* + * If seem to be already active, just update the stamp to tell the + * timer that we're still active. We don't mind occassional races. + */ + if (!list_empty(&iocg->active_list)) { + ioc_now(ioc, now); + cur_period = atomic64_read(&ioc->cur_period); + if (atomic64_read(&iocg->active_period) != cur_period) + atomic64_set(&iocg->active_period, cur_period); + return true; + } + + /* racy check on internal node IOs, treat as root level IOs */ + if (iocg->child_active_sum) + return false; + + spin_lock_irq(&ioc->lock); + + ioc_now(ioc, now); + + /* update period */ + cur_period = atomic64_read(&ioc->cur_period); + last_period = atomic64_read(&iocg->active_period); + atomic64_set(&iocg->active_period, cur_period); + + /* already activated or breaking leaf-only constraint? */ + for (i = iocg->level; i > 0; i--) + if (!list_empty(&iocg->active_list)) + goto fail_unlock; + if (iocg->child_active_sum) + goto fail_unlock; + + /* + * vtime may wrap when vrate is raised substantially due to + * underestimated IO costs. Look at the period and ignore its + * vtime if the iocg has been idle for too long. Also, cap the + * budget it can start with to the margin. + */ + max_period_delta = DIV64_U64_ROUND_UP(VTIME_VALID_DUR, ioc->period_us); + vtime = atomic64_read(&iocg->vtime); + vmargin = ioc->margin_us * now->vrate; + vmin = now->vnow - vmargin; + + if (last_period + max_period_delta < cur_period || + time_before64(vtime, vmin)) { + atomic64_add(vmin - vtime, &iocg->vtime); + atomic64_add(vmin - vtime, &iocg->done_vtime); + vtime = vmin; + } + + /* + * Activate, propagate weight and start period timer if not + * running. Reset hweight_gen to avoid accidental match from + * wrapping. + */ + iocg->hweight_gen = atomic_read(&ioc->hweight_gen) - 1; + list_add(&iocg->active_list, &ioc->active_iocgs); + propagate_active_weight(iocg, iocg->weight, + iocg->last_inuse ?: iocg->weight); + + TRACE_IOCG_PATH(iocg_activate, iocg, now, + last_period, cur_period, vtime); + + iocg->last_vtime = vtime; + + if (ioc->running == IOC_IDLE) { + ioc->running = IOC_RUNNING; + ioc_start_period(ioc, now); + } + + spin_unlock_irq(&ioc->lock); + return true; + +fail_unlock: + spin_unlock_irq(&ioc->lock); + return false; +} + +static int iocg_wake_fn(struct wait_queue_entry *wq_entry, unsigned mode, + int flags, void *key) +{ + struct iocg_wait *wait = container_of(wq_entry, struct iocg_wait, wait); + struct iocg_wake_ctx *ctx = (struct iocg_wake_ctx *)key; + u64 cost = abs_cost_to_cost(wait->abs_cost, ctx->hw_inuse); + + ctx->vbudget -= cost; + + if (ctx->vbudget < 0) + return -1; + + iocg_commit_bio(ctx->iocg, wait->bio, cost); + + /* + * autoremove_wake_function() removes the wait entry only when it + * actually changed the task state. We want the wait always + * removed. Remove explicitly and use default_wake_function(). + */ + list_del_init(&wq_entry->entry); + wait->committed = true; + + default_wake_function(wq_entry, mode, flags, key); + return 0; +} + +static void iocg_kick_waitq(struct ioc_gq *iocg, struct ioc_now *now) +{ + struct ioc *ioc = iocg->ioc; + struct iocg_wake_ctx ctx = { .iocg = iocg }; + u64 margin_ns = (u64)(ioc->period_us * + WAITQ_TIMER_MARGIN_PCT / 100) * NSEC_PER_USEC; + u64 abs_vdebt, vdebt, vshortage, expires, oexpires; + s64 vbudget; + u32 hw_inuse; + + lockdep_assert_held(&iocg->waitq.lock); + + current_hweight(iocg, NULL, &hw_inuse); + vbudget = now->vnow - atomic64_read(&iocg->vtime); + + /* pay off debt */ + abs_vdebt = atomic64_read(&iocg->abs_vdebt); + vdebt = abs_cost_to_cost(abs_vdebt, hw_inuse); + if (vdebt && vbudget > 0) { + u64 delta = min_t(u64, vbudget, vdebt); + u64 abs_delta = min(cost_to_abs_cost(delta, hw_inuse), + abs_vdebt); + + atomic64_add(delta, &iocg->vtime); + atomic64_add(delta, &iocg->done_vtime); + atomic64_sub(abs_delta, &iocg->abs_vdebt); + if (WARN_ON_ONCE(atomic64_read(&iocg->abs_vdebt) < 0)) + atomic64_set(&iocg->abs_vdebt, 0); + } + + /* + * Wake up the ones which are due and see how much vtime we'll need + * for the next one. + */ + ctx.hw_inuse = hw_inuse; + ctx.vbudget = vbudget - vdebt; + __wake_up_locked_key(&iocg->waitq, TASK_NORMAL, &ctx); + if (!waitqueue_active(&iocg->waitq)) + return; + if (WARN_ON_ONCE(ctx.vbudget >= 0)) + return; + + /* determine next wakeup, add a quarter margin to guarantee chunking */ + vshortage = -ctx.vbudget; + expires = now->now_ns + + DIV64_U64_ROUND_UP(vshortage, now->vrate) * NSEC_PER_USEC; + expires += margin_ns / 4; + + /* if already active and close enough, don't bother */ + oexpires = ktime_to_ns(hrtimer_get_softexpires(&iocg->waitq_timer)); + if (hrtimer_is_queued(&iocg->waitq_timer) && + abs(oexpires - expires) <= margin_ns / 4) + return; + + hrtimer_start_range_ns(&iocg->waitq_timer, ns_to_ktime(expires), + margin_ns / 4, HRTIMER_MODE_ABS); +} + +static enum hrtimer_restart iocg_waitq_timer_fn(struct hrtimer *timer) +{ + struct ioc_gq *iocg = container_of(timer, struct ioc_gq, waitq_timer); + struct ioc_now now; + unsigned long flags; + + ioc_now(iocg->ioc, &now); + + spin_lock_irqsave(&iocg->waitq.lock, flags); + iocg_kick_waitq(iocg, &now); + spin_unlock_irqrestore(&iocg->waitq.lock, flags); + + return HRTIMER_NORESTART; +} + +static void iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now, u64 cost) +{ + struct ioc *ioc = iocg->ioc; + struct blkcg_gq *blkg = iocg_to_blkg(iocg); + u64 vtime = atomic64_read(&iocg->vtime); + u64 vmargin = ioc->margin_us * now->vrate; + u64 margin_ns = ioc->margin_us * NSEC_PER_USEC; + u64 expires, oexpires; + u32 hw_inuse; + + /* debt-adjust vtime */ + current_hweight(iocg, NULL, &hw_inuse); + vtime += abs_cost_to_cost(atomic64_read(&iocg->abs_vdebt), hw_inuse); + + /* clear or maintain depending on the overage */ + if (time_before_eq64(vtime, now->vnow)) { + blkcg_clear_delay(blkg); + return; + } + if (!atomic_read(&blkg->use_delay) && + time_before_eq64(vtime, now->vnow + vmargin)) + return; + + /* use delay */ + if (cost) { + u64 cost_ns = DIV64_U64_ROUND_UP(cost * NSEC_PER_USEC, + now->vrate); + blkcg_add_delay(blkg, now->now_ns, cost_ns); + } + blkcg_use_delay(blkg); + + expires = now->now_ns + DIV64_U64_ROUND_UP(vtime - now->vnow, + now->vrate) * NSEC_PER_USEC; + + /* if already active and close enough, don't bother */ + oexpires = ktime_to_ns(hrtimer_get_softexpires(&iocg->delay_timer)); + if (hrtimer_is_queued(&iocg->delay_timer) && + abs(oexpires - expires) <= margin_ns / 4) + return; + + hrtimer_start_range_ns(&iocg->delay_timer, ns_to_ktime(expires), + margin_ns / 4, HRTIMER_MODE_ABS); +} + +static enum hrtimer_restart iocg_delay_timer_fn(struct hrtimer *timer) +{ + struct ioc_gq *iocg = container_of(timer, struct ioc_gq, delay_timer); + struct ioc_now now; + + ioc_now(iocg->ioc, &now); + iocg_kick_delay(iocg, &now, 0); + + return HRTIMER_NORESTART; +} + +static void ioc_lat_stat(struct ioc *ioc, u32 *missed_ppm_ar, u32 *rq_wait_pct_p) +{ + u32 nr_met[2] = { }; + u32 nr_missed[2] = { }; + u64 rq_wait_ns = 0; + int cpu, rw; + + for_each_online_cpu(cpu) { + struct ioc_pcpu_stat *stat = per_cpu_ptr(ioc->pcpu_stat, cpu); + u64 this_rq_wait_ns; + + for (rw = READ; rw <= WRITE; rw++) { + u32 this_met = READ_ONCE(stat->missed[rw].nr_met); + u32 this_missed = READ_ONCE(stat->missed[rw].nr_missed); + + nr_met[rw] += this_met - stat->missed[rw].last_met; + nr_missed[rw] += this_missed - stat->missed[rw].last_missed; + stat->missed[rw].last_met = this_met; + stat->missed[rw].last_missed = this_missed; + } + + this_rq_wait_ns = READ_ONCE(stat->rq_wait_ns); + rq_wait_ns += this_rq_wait_ns - stat->last_rq_wait_ns; + stat->last_rq_wait_ns = this_rq_wait_ns; + } + + for (rw = READ; rw <= WRITE; rw++) { + if (nr_met[rw] + nr_missed[rw]) + missed_ppm_ar[rw] = + DIV64_U64_ROUND_UP((u64)nr_missed[rw] * MILLION, + nr_met[rw] + nr_missed[rw]); + else + missed_ppm_ar[rw] = 0; + } + + *rq_wait_pct_p = div64_u64(rq_wait_ns * 100, + ioc->period_us * NSEC_PER_USEC); +} + +/* was iocg idle this period? */ +static bool iocg_is_idle(struct ioc_gq *iocg) +{ + struct ioc *ioc = iocg->ioc; + + /* did something get issued this period? */ + if (atomic64_read(&iocg->active_period) == + atomic64_read(&ioc->cur_period)) + return false; + + /* is something in flight? */ + if (atomic64_read(&iocg->done_vtime) < atomic64_read(&iocg->vtime)) + return false; + + return true; +} + +/* returns usage with margin added if surplus is large enough */ +static u32 surplus_adjusted_hweight_inuse(u32 usage, u32 hw_inuse) +{ + /* add margin */ + usage = DIV_ROUND_UP(usage * SURPLUS_SCALE_PCT, 100); + usage += SURPLUS_SCALE_ABS; + + /* don't bother if the surplus is too small */ + if (usage + SURPLUS_MIN_ADJ_DELTA > hw_inuse) + return 0; + + return usage; +} + +static void ioc_timer_fn(struct timer_list *timer) +{ + struct ioc *ioc = container_of(timer, struct ioc, timer); + struct ioc_gq *iocg, *tiocg; + struct ioc_now now; + int nr_surpluses = 0, nr_shortages = 0, nr_lagging = 0; + u32 ppm_rthr = MILLION - ioc->params.qos[QOS_RPPM]; + u32 ppm_wthr = MILLION - ioc->params.qos[QOS_WPPM]; + u32 missed_ppm[2], rq_wait_pct; + u64 period_vtime; + int i; + + /* how were the latencies during the period? */ + ioc_lat_stat(ioc, missed_ppm, &rq_wait_pct); + + /* take care of active iocgs */ + spin_lock_irq(&ioc->lock); + + ioc_now(ioc, &now); + + period_vtime = now.vnow - ioc->period_at_vtime; + if (WARN_ON_ONCE(!period_vtime)) { + spin_unlock_irq(&ioc->lock); + return; + } + + /* + * Waiters determine the sleep durations based on the vrate they + * saw at the time of sleep. If vrate has increased, some waiters + * could be sleeping for too long. Wake up tardy waiters which + * should have woken up in the last period and expire idle iocgs. + */ + list_for_each_entry_safe(iocg, tiocg, &ioc->active_iocgs, active_list) { + if (!waitqueue_active(&iocg->waitq) && + !atomic64_read(&iocg->abs_vdebt) && !iocg_is_idle(iocg)) + continue; + + spin_lock(&iocg->waitq.lock); + + if (waitqueue_active(&iocg->waitq) || + atomic64_read(&iocg->abs_vdebt)) { + /* might be oversleeping vtime / hweight changes, kick */ + iocg_kick_waitq(iocg, &now); + iocg_kick_delay(iocg, &now, 0); + } else if (iocg_is_idle(iocg)) { + /* no waiter and idle, deactivate */ + iocg->last_inuse = iocg->inuse; + __propagate_active_weight(iocg, 0, 0); + list_del_init(&iocg->active_list); + } + + spin_unlock(&iocg->waitq.lock); + } + commit_active_weights(ioc); + + /* calc usages and see whether some weights need to be moved around */ + list_for_each_entry(iocg, &ioc->active_iocgs, active_list) { + u64 vdone, vtime, vusage, vmargin, vmin; + u32 hw_active, hw_inuse, usage; + + /* + * Collect unused and wind vtime closer to vnow to prevent + * iocgs from accumulating a large amount of budget. + */ + vdone = atomic64_read(&iocg->done_vtime); + vtime = atomic64_read(&iocg->vtime); + current_hweight(iocg, &hw_active, &hw_inuse); + + /* + * Latency QoS detection doesn't account for IOs which are + * in-flight for longer than a period. Detect them by + * comparing vdone against period start. If lagging behind + * IOs from past periods, don't increase vrate. + */ + if (!atomic_read(&iocg_to_blkg(iocg)->use_delay) && + time_after64(vtime, vdone) && + time_after64(vtime, now.vnow - + MAX_LAGGING_PERIODS * period_vtime) && + time_before64(vdone, now.vnow - period_vtime)) + nr_lagging++; + + if (waitqueue_active(&iocg->waitq)) + vusage = now.vnow - iocg->last_vtime; + else if (time_before64(iocg->last_vtime, vtime)) + vusage = vtime - iocg->last_vtime; + else + vusage = 0; + + iocg->last_vtime += vusage; + /* + * Factor in in-flight vtime into vusage to avoid + * high-latency completions appearing as idle. This should + * be done after the above ->last_time adjustment. + */ + vusage = max(vusage, vtime - vdone); + + /* calculate hweight based usage ratio and record */ + if (vusage) { + usage = DIV64_U64_ROUND_UP(vusage * hw_inuse, + period_vtime); + iocg->usage_idx = (iocg->usage_idx + 1) % NR_USAGE_SLOTS; + iocg->usages[iocg->usage_idx] = usage; + } else { + usage = 0; + } + + /* see whether there's surplus vtime */ + vmargin = ioc->margin_us * now.vrate; + vmin = now.vnow - vmargin; + + iocg->has_surplus = false; + + if (!waitqueue_active(&iocg->waitq) && + time_before64(vtime, vmin)) { + u64 delta = vmin - vtime; + + /* throw away surplus vtime */ + atomic64_add(delta, &iocg->vtime); + atomic64_add(delta, &iocg->done_vtime); + iocg->last_vtime += delta; + /* if usage is sufficiently low, maybe it can donate */ + if (surplus_adjusted_hweight_inuse(usage, hw_inuse)) { + iocg->has_surplus = true; + nr_surpluses++; + } + } else if (hw_inuse < hw_active) { + u32 new_hwi, new_inuse; + + /* was donating but might need to take back some */ + if (waitqueue_active(&iocg->waitq)) { + new_hwi = hw_active; + } else { + new_hwi = max(hw_inuse, + usage * SURPLUS_SCALE_PCT / 100 + + SURPLUS_SCALE_ABS); + } + + new_inuse = div64_u64((u64)iocg->inuse * new_hwi, + hw_inuse); + new_inuse = clamp_t(u32, new_inuse, 1, iocg->active); + + if (new_inuse > iocg->inuse) { + TRACE_IOCG_PATH(inuse_takeback, iocg, &now, + iocg->inuse, new_inuse, + hw_inuse, new_hwi); + __propagate_active_weight(iocg, iocg->weight, + new_inuse); + } + } else { + /* genuninely out of vtime */ + nr_shortages++; + } + } + + if (!nr_shortages || !nr_surpluses) + goto skip_surplus_transfers; + + /* there are both shortages and surpluses, transfer surpluses */ + list_for_each_entry(iocg, &ioc->active_iocgs, active_list) { + u32 usage, hw_active, hw_inuse, new_hwi, new_inuse; + int nr_valid = 0; + + if (!iocg->has_surplus) + continue; + + /* base the decision on max historical usage */ + for (i = 0, usage = 0; i < NR_USAGE_SLOTS; i++) { + if (iocg->usages[i]) { + usage = max(usage, iocg->usages[i]); + nr_valid++; + } + } + if (nr_valid < MIN_VALID_USAGES) + continue; + + current_hweight(iocg, &hw_active, &hw_inuse); + new_hwi = surplus_adjusted_hweight_inuse(usage, hw_inuse); + if (!new_hwi) + continue; + + new_inuse = DIV64_U64_ROUND_UP((u64)iocg->inuse * new_hwi, + hw_inuse); + if (new_inuse < iocg->inuse) { + TRACE_IOCG_PATH(inuse_giveaway, iocg, &now, + iocg->inuse, new_inuse, + hw_inuse, new_hwi); + __propagate_active_weight(iocg, iocg->weight, new_inuse); + } + } +skip_surplus_transfers: + commit_active_weights(ioc); + + /* + * If q is getting clogged or we're missing too much, we're issuing + * too much IO and should lower vtime rate. If we're not missing + * and experiencing shortages but not surpluses, we're too stingy + * and should increase vtime rate. + */ + if (rq_wait_pct > RQ_WAIT_BUSY_PCT || + missed_ppm[READ] > ppm_rthr || + missed_ppm[WRITE] > ppm_wthr) { + ioc->busy_level = max(ioc->busy_level, 0); + ioc->busy_level++; + } else if (nr_lagging) { + ioc->busy_level = max(ioc->busy_level, 0); + } else if (nr_shortages && !nr_surpluses && + rq_wait_pct <= RQ_WAIT_BUSY_PCT * UNBUSY_THR_PCT / 100 && + missed_ppm[READ] <= ppm_rthr * UNBUSY_THR_PCT / 100 && + missed_ppm[WRITE] <= ppm_wthr * UNBUSY_THR_PCT / 100) { + ioc->busy_level = min(ioc->busy_level, 0); + ioc->busy_level--; + } else { + ioc->busy_level = 0; + } + + ioc->busy_level = clamp(ioc->busy_level, -1000, 1000); + + if (ioc->busy_level) { + u64 vrate = atomic64_read(&ioc->vtime_rate); + u64 vrate_min = ioc->vrate_min, vrate_max = ioc->vrate_max; + + /* rq_wait signal is always reliable, ignore user vrate_min */ + if (rq_wait_pct > RQ_WAIT_BUSY_PCT) + vrate_min = VRATE_MIN; + + /* + * If vrate is out of bounds, apply clamp gradually as the + * bounds can change abruptly. Otherwise, apply busy_level + * based adjustment. + */ + if (vrate < vrate_min) { + vrate = div64_u64(vrate * (100 + VRATE_CLAMP_ADJ_PCT), + 100); + vrate = min(vrate, vrate_min); + } else if (vrate > vrate_max) { + vrate = div64_u64(vrate * (100 - VRATE_CLAMP_ADJ_PCT), + 100); + vrate = max(vrate, vrate_max); + } else { + int idx = min_t(int, abs(ioc->busy_level), + ARRAY_SIZE(vrate_adj_pct) - 1); + u32 adj_pct = vrate_adj_pct[idx]; + + if (ioc->busy_level > 0) + adj_pct = 100 - adj_pct; + else + adj_pct = 100 + adj_pct; + + vrate = clamp(DIV64_U64_ROUND_UP(vrate * adj_pct, 100), + vrate_min, vrate_max); + } + + trace_iocost_ioc_vrate_adj(ioc, vrate, &missed_ppm, rq_wait_pct, + nr_lagging, nr_shortages, + nr_surpluses); + + atomic64_set(&ioc->vtime_rate, vrate); + ioc->inuse_margin_vtime = DIV64_U64_ROUND_UP( + ioc->period_us * vrate * INUSE_MARGIN_PCT, 100); + } + + ioc_refresh_params(ioc, false); + + /* + * This period is done. Move onto the next one. If nothing's + * going on with the device, stop the timer. + */ + atomic64_inc(&ioc->cur_period); + + if (ioc->running != IOC_STOP) { + if (!list_empty(&ioc->active_iocgs)) { + ioc_start_period(ioc, &now); + } else { + ioc->busy_level = 0; + ioc->running = IOC_IDLE; + } + } + + spin_unlock_irq(&ioc->lock); +} + +static void calc_vtime_cost_builtin(struct bio *bio, struct ioc_gq *iocg, + bool is_merge, u64 *costp) +{ + struct ioc *ioc = iocg->ioc; + u64 coef_seqio, coef_randio, coef_page; + u64 pages = max_t(u64, bio_sectors(bio) >> IOC_SECT_TO_PAGE_SHIFT, 1); + u64 seek_pages = 0; + u64 cost = 0; + + switch (bio_op(bio)) { + case REQ_OP_READ: + coef_seqio = ioc->params.lcoefs[LCOEF_RSEQIO]; + coef_randio = ioc->params.lcoefs[LCOEF_RRANDIO]; + coef_page = ioc->params.lcoefs[LCOEF_RPAGE]; + break; + case REQ_OP_WRITE: + coef_seqio = ioc->params.lcoefs[LCOEF_WSEQIO]; + coef_randio = ioc->params.lcoefs[LCOEF_WRANDIO]; + coef_page = ioc->params.lcoefs[LCOEF_WPAGE]; + break; + default: + goto out; + } + + if (iocg->cursor) { + seek_pages = abs(bio->bi_iter.bi_sector - iocg->cursor); + seek_pages >>= IOC_SECT_TO_PAGE_SHIFT; + } + + if (!is_merge) { + if (seek_pages > LCOEF_RANDIO_PAGES) { + cost += coef_randio; + } else { + cost += coef_seqio; + } + } + cost += pages * coef_page; +out: + *costp = cost; +} + +static u64 calc_vtime_cost(struct bio *bio, struct ioc_gq *iocg, bool is_merge) +{ + u64 cost; + + calc_vtime_cost_builtin(bio, iocg, is_merge, &cost); + return cost; +} + +static void ioc_rqos_throttle(struct rq_qos *rqos, struct bio *bio) +{ + struct blkcg_gq *blkg = bio->bi_blkg; + struct ioc *ioc = rqos_to_ioc(rqos); + struct ioc_gq *iocg = blkg_to_iocg(blkg); + struct ioc_now now; + struct iocg_wait wait; + u32 hw_active, hw_inuse; + u64 abs_cost, cost, vtime; + + /* bypass IOs if disabled or for root cgroup */ + if (!ioc->enabled || !iocg->level) + return; + + /* always activate so that even 0 cost IOs get protected to some level */ + if (!iocg_activate(iocg, &now)) + return; + + /* calculate the absolute vtime cost */ + abs_cost = calc_vtime_cost(bio, iocg, false); + if (!abs_cost) + return; + + iocg->cursor = bio_end_sector(bio); + + vtime = atomic64_read(&iocg->vtime); + current_hweight(iocg, &hw_active, &hw_inuse); + + if (hw_inuse < hw_active && + time_after_eq64(vtime + ioc->inuse_margin_vtime, now.vnow)) { + TRACE_IOCG_PATH(inuse_reset, iocg, &now, + iocg->inuse, iocg->weight, hw_inuse, hw_active); + spin_lock_irq(&ioc->lock); + propagate_active_weight(iocg, iocg->weight, iocg->weight); + spin_unlock_irq(&ioc->lock); + current_hweight(iocg, &hw_active, &hw_inuse); + } + + cost = abs_cost_to_cost(abs_cost, hw_inuse); + + /* + * If no one's waiting and within budget, issue right away. The + * tests are racy but the races aren't systemic - we only miss once + * in a while which is fine. + */ + if (!waitqueue_active(&iocg->waitq) && + !atomic64_read(&iocg->abs_vdebt) && + time_before_eq64(vtime + cost, now.vnow)) { + iocg_commit_bio(iocg, bio, cost); + return; + } + + /* + * We're over budget. If @bio has to be issued regardless, + * remember the abs_cost instead of advancing vtime. + * iocg_kick_waitq() will pay off the debt before waking more IOs. + * This way, the debt is continuously paid off each period with the + * actual budget available to the cgroup. If we just wound vtime, + * we would incorrectly use the current hw_inuse for the entire + * amount which, for example, can lead to the cgroup staying + * blocked for a long time even with substantially raised hw_inuse. + */ + if (bio_issue_as_root_blkg(bio) || fatal_signal_pending(current)) { + atomic64_add(abs_cost, &iocg->abs_vdebt); + iocg_kick_delay(iocg, &now, cost); + return; + } + + /* + * Append self to the waitq and schedule the wakeup timer if we're + * the first waiter. The timer duration is calculated based on the + * current vrate. vtime and hweight changes can make it too short + * or too long. Each wait entry records the absolute cost it's + * waiting for to allow re-evaluation using a custom wait entry. + * + * If too short, the timer simply reschedules itself. If too long, + * the period timer will notice and trigger wakeups. + * + * All waiters are on iocg->waitq and the wait states are + * synchronized using waitq.lock. + */ + spin_lock_irq(&iocg->waitq.lock); + + /* + * We activated above but w/o any synchronization. Deactivation is + * synchronized with waitq.lock and we won't get deactivated as + * long as we're waiting, so we're good if we're activated here. + * In the unlikely case that we are deactivated, just issue the IO. + */ + if (unlikely(list_empty(&iocg->active_list))) { + spin_unlock_irq(&iocg->waitq.lock); + iocg_commit_bio(iocg, bio, cost); + return; + } + + init_waitqueue_func_entry(&wait.wait, iocg_wake_fn); + wait.wait.private = current; + wait.bio = bio; + wait.abs_cost = abs_cost; + wait.committed = false; /* will be set true by waker */ + + __add_wait_queue_entry_tail(&iocg->waitq, &wait.wait); + iocg_kick_waitq(iocg, &now); + + spin_unlock_irq(&iocg->waitq.lock); + + while (true) { + set_current_state(TASK_UNINTERRUPTIBLE); + if (wait.committed) + break; + io_schedule(); + } + + /* waker already committed us, proceed */ + finish_wait(&iocg->waitq, &wait.wait); +} + +static void ioc_rqos_merge(struct rq_qos *rqos, struct request *rq, + struct bio *bio) +{ + struct ioc_gq *iocg = blkg_to_iocg(bio->bi_blkg); + struct ioc *ioc = iocg->ioc; + sector_t bio_end = bio_end_sector(bio); + struct ioc_now now; + u32 hw_inuse; + u64 abs_cost, cost; + + /* bypass if disabled or for root cgroup */ + if (!ioc->enabled || !iocg->level) + return; + + abs_cost = calc_vtime_cost(bio, iocg, true); + if (!abs_cost) + return; + + ioc_now(ioc, &now); + current_hweight(iocg, NULL, &hw_inuse); + cost = abs_cost_to_cost(abs_cost, hw_inuse); + + /* update cursor if backmerging into the request at the cursor */ + if (blk_rq_pos(rq) < bio_end && + blk_rq_pos(rq) + blk_rq_sectors(rq) == iocg->cursor) + iocg->cursor = bio_end; + + /* + * Charge if there's enough vtime budget and the existing request + * has cost assigned. Otherwise, account it as debt. See debt + * handling in ioc_rqos_throttle() for details. + */ + if (rq->bio && rq->bio->bi_iocost_cost && + time_before_eq64(atomic64_read(&iocg->vtime) + cost, now.vnow)) + iocg_commit_bio(iocg, bio, cost); + else + atomic64_add(abs_cost, &iocg->abs_vdebt); +} + +static void ioc_rqos_done_bio(struct rq_qos *rqos, struct bio *bio) +{ + struct ioc_gq *iocg = blkg_to_iocg(bio->bi_blkg); + + if (iocg && bio->bi_iocost_cost) + atomic64_add(bio->bi_iocost_cost, &iocg->done_vtime); +} + +static void ioc_rqos_done(struct rq_qos *rqos, struct request *rq) +{ + struct ioc *ioc = rqos_to_ioc(rqos); + u64 on_q_ns, rq_wait_ns; + int pidx, rw; + + if (!ioc->enabled || !rq->alloc_time_ns || !rq->start_time_ns) + return; + + switch (req_op(rq) & REQ_OP_MASK) { + case REQ_OP_READ: + pidx = QOS_RLAT; + rw = READ; + break; + case REQ_OP_WRITE: + pidx = QOS_WLAT; + rw = WRITE; + break; + default: + return; + } + + on_q_ns = ktime_get_ns() - rq->alloc_time_ns; + rq_wait_ns = rq->start_time_ns - rq->alloc_time_ns; + + if (on_q_ns <= ioc->params.qos[pidx] * NSEC_PER_USEC) + this_cpu_inc(ioc->pcpu_stat->missed[rw].nr_met); + else + this_cpu_inc(ioc->pcpu_stat->missed[rw].nr_missed); + + this_cpu_add(ioc->pcpu_stat->rq_wait_ns, rq_wait_ns); +} + +static void ioc_rqos_queue_depth_changed(struct rq_qos *rqos) +{ + struct ioc *ioc = rqos_to_ioc(rqos); + + spin_lock_irq(&ioc->lock); + ioc_refresh_params(ioc, false); + spin_unlock_irq(&ioc->lock); +} + +static void ioc_rqos_exit(struct rq_qos *rqos) +{ + struct ioc *ioc = rqos_to_ioc(rqos); + + blkcg_deactivate_policy(rqos->q, &blkcg_policy_iocost); + + spin_lock_irq(&ioc->lock); + ioc->running = IOC_STOP; + spin_unlock_irq(&ioc->lock); + + del_timer_sync(&ioc->timer); + free_percpu(ioc->pcpu_stat); + kfree(ioc); +} + +static struct rq_qos_ops ioc_rqos_ops = { + .throttle = ioc_rqos_throttle, + .merge = ioc_rqos_merge, + .done_bio = ioc_rqos_done_bio, + .done = ioc_rqos_done, + .queue_depth_changed = ioc_rqos_queue_depth_changed, + .exit = ioc_rqos_exit, +}; + +static int blk_iocost_init(struct request_queue *q) +{ + struct ioc *ioc; + struct rq_qos *rqos; + int ret; + + ioc = kzalloc(sizeof(*ioc), GFP_KERNEL); + if (!ioc) + return -ENOMEM; + + ioc->pcpu_stat = alloc_percpu(struct ioc_pcpu_stat); + if (!ioc->pcpu_stat) { + kfree(ioc); + return -ENOMEM; + } + + rqos = &ioc->rqos; + rqos->id = RQ_QOS_COST; + rqos->ops = &ioc_rqos_ops; + rqos->q = q; + + spin_lock_init(&ioc->lock); + timer_setup(&ioc->timer, ioc_timer_fn, 0); + INIT_LIST_HEAD(&ioc->active_iocgs); + + ioc->running = IOC_IDLE; + atomic64_set(&ioc->vtime_rate, VTIME_PER_USEC); + seqcount_init(&ioc->period_seqcount); + ioc->period_at = ktime_to_us(ktime_get()); + atomic64_set(&ioc->cur_period, 0); + atomic_set(&ioc->hweight_gen, 0); + + spin_lock_irq(&ioc->lock); + ioc->autop_idx = AUTOP_INVALID; + ioc_refresh_params(ioc, true); + spin_unlock_irq(&ioc->lock); + + rq_qos_add(q, rqos); + ret = blkcg_activate_policy(q, &blkcg_policy_iocost); + if (ret) { + rq_qos_del(q, rqos); + free_percpu(ioc->pcpu_stat); + kfree(ioc); + return ret; + } + return 0; +} + +static struct blkcg_policy_data *ioc_cpd_alloc(gfp_t gfp) +{ + struct ioc_cgrp *iocc; + + iocc = kzalloc(sizeof(struct ioc_cgrp), gfp); + if (!iocc) + return NULL; + + iocc->dfl_weight = CGROUP_WEIGHT_DFL; + return &iocc->cpd; +} + +static void ioc_cpd_free(struct blkcg_policy_data *cpd) +{ + kfree(container_of(cpd, struct ioc_cgrp, cpd)); +} + +static struct blkg_policy_data *ioc_pd_alloc(gfp_t gfp, struct request_queue *q, + struct blkcg *blkcg) +{ + int levels = blkcg->css.cgroup->level + 1; + struct ioc_gq *iocg; + + iocg = kzalloc_node(sizeof(*iocg) + levels * sizeof(iocg->ancestors[0]), + gfp, q->node); + if (!iocg) + return NULL; + + return &iocg->pd; +} + +static void ioc_pd_init(struct blkg_policy_data *pd) +{ + struct ioc_gq *iocg = pd_to_iocg(pd); + struct blkcg_gq *blkg = pd_to_blkg(&iocg->pd); + struct ioc *ioc = q_to_ioc(blkg->q); + struct ioc_now now; + struct blkcg_gq *tblkg; + unsigned long flags; + + ioc_now(ioc, &now); + + iocg->ioc = ioc; + atomic64_set(&iocg->vtime, now.vnow); + atomic64_set(&iocg->done_vtime, now.vnow); + atomic64_set(&iocg->abs_vdebt, 0); + atomic64_set(&iocg->active_period, atomic64_read(&ioc->cur_period)); + INIT_LIST_HEAD(&iocg->active_list); + iocg->hweight_active = HWEIGHT_WHOLE; + iocg->hweight_inuse = HWEIGHT_WHOLE; + + init_waitqueue_head(&iocg->waitq); + hrtimer_init(&iocg->waitq_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + iocg->waitq_timer.function = iocg_waitq_timer_fn; + hrtimer_init(&iocg->delay_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + iocg->delay_timer.function = iocg_delay_timer_fn; + + iocg->level = blkg->blkcg->css.cgroup->level; + + for (tblkg = blkg; tblkg; tblkg = tblkg->parent) { + struct ioc_gq *tiocg = blkg_to_iocg(tblkg); + iocg->ancestors[tiocg->level] = tiocg; + } + + spin_lock_irqsave(&ioc->lock, flags); + weight_updated(iocg); + spin_unlock_irqrestore(&ioc->lock, flags); +} + +static void ioc_pd_free(struct blkg_policy_data *pd) +{ + struct ioc_gq *iocg = pd_to_iocg(pd); + struct ioc *ioc = iocg->ioc; + + if (ioc) { + spin_lock(&ioc->lock); + if (!list_empty(&iocg->active_list)) { + propagate_active_weight(iocg, 0, 0); + list_del_init(&iocg->active_list); + } + spin_unlock(&ioc->lock); + + hrtimer_cancel(&iocg->waitq_timer); + hrtimer_cancel(&iocg->delay_timer); + } + kfree(iocg); +} + +static u64 ioc_weight_prfill(struct seq_file *sf, struct blkg_policy_data *pd, + int off) +{ + const char *dname = blkg_dev_name(pd->blkg); + struct ioc_gq *iocg = pd_to_iocg(pd); + + if (dname && iocg->cfg_weight) + seq_printf(sf, "%s %u\n", dname, iocg->cfg_weight); + return 0; +} + + +static int ioc_weight_show(struct seq_file *sf, void *v) +{ + struct blkcg *blkcg = css_to_blkcg(seq_css(sf)); + struct ioc_cgrp *iocc = blkcg_to_iocc(blkcg); + + seq_printf(sf, "default %u\n", iocc->dfl_weight); + blkcg_print_blkgs(sf, blkcg, ioc_weight_prfill, + &blkcg_policy_iocost, seq_cft(sf)->private, false); + return 0; +} + +static ssize_t ioc_weight_write(struct kernfs_open_file *of, char *buf, + size_t nbytes, loff_t off) +{ + struct blkcg *blkcg = css_to_blkcg(of_css(of)); + struct ioc_cgrp *iocc = blkcg_to_iocc(blkcg); + struct blkg_conf_ctx ctx; + struct ioc_gq *iocg; + u32 v; + int ret; + + if (!strchr(buf, ':')) { + struct blkcg_gq *blkg; + + if (!sscanf(buf, "default %u", &v) && !sscanf(buf, "%u", &v)) + return -EINVAL; + + if (v < CGROUP_WEIGHT_MIN || v > CGROUP_WEIGHT_MAX) + return -EINVAL; + + spin_lock(&blkcg->lock); + iocc->dfl_weight = v; + hlist_for_each_entry(blkg, &blkcg->blkg_list, blkcg_node) { + struct ioc_gq *iocg = blkg_to_iocg(blkg); + + if (iocg) { + spin_lock_irq(&iocg->ioc->lock); + weight_updated(iocg); + spin_unlock_irq(&iocg->ioc->lock); + } + } + spin_unlock(&blkcg->lock); + + return nbytes; + } + + ret = blkg_conf_prep(blkcg, &blkcg_policy_iocost, buf, &ctx); + if (ret) + return ret; + + iocg = blkg_to_iocg(ctx.blkg); + + if (!strncmp(ctx.body, "default", 7)) { + v = 0; + } else { + if (!sscanf(ctx.body, "%u", &v)) + goto einval; + if (v < CGROUP_WEIGHT_MIN || v > CGROUP_WEIGHT_MAX) + goto einval; + } + + spin_lock_irq(&iocg->ioc->lock); + iocg->cfg_weight = v; + weight_updated(iocg); + spin_unlock_irq(&iocg->ioc->lock); + + blkg_conf_finish(&ctx); + return nbytes; + +einval: + blkg_conf_finish(&ctx); + return -EINVAL; +} + +static u64 ioc_qos_prfill(struct seq_file *sf, struct blkg_policy_data *pd, + int off) +{ + const char *dname = blkg_dev_name(pd->blkg); + struct ioc *ioc = pd_to_iocg(pd)->ioc; + + if (!dname) + return 0; + + seq_printf(sf, "%s enable=%d ctrl=%s rpct=%u.%02u rlat=%u wpct=%u.%02u wlat=%u min=%u.%02u max=%u.%02u\n", + dname, ioc->enabled, ioc->user_qos_params ? "user" : "auto", + ioc->params.qos[QOS_RPPM] / 10000, + ioc->params.qos[QOS_RPPM] % 10000 / 100, + ioc->params.qos[QOS_RLAT], + ioc->params.qos[QOS_WPPM] / 10000, + ioc->params.qos[QOS_WPPM] % 10000 / 100, + ioc->params.qos[QOS_WLAT], + ioc->params.qos[QOS_MIN] / 10000, + ioc->params.qos[QOS_MIN] % 10000 / 100, + ioc->params.qos[QOS_MAX] / 10000, + ioc->params.qos[QOS_MAX] % 10000 / 100); + return 0; +} + +static int ioc_qos_show(struct seq_file *sf, void *v) +{ + struct blkcg *blkcg = css_to_blkcg(seq_css(sf)); + + blkcg_print_blkgs(sf, blkcg, ioc_qos_prfill, + &blkcg_policy_iocost, seq_cft(sf)->private, false); + return 0; +} + +static const match_table_t qos_ctrl_tokens = { + { QOS_ENABLE, "enable=%u" }, + { QOS_CTRL, "ctrl=%s" }, + { NR_QOS_CTRL_PARAMS, NULL }, +}; + +static const match_table_t qos_tokens = { + { QOS_RPPM, "rpct=%s" }, + { QOS_RLAT, "rlat=%u" }, + { QOS_WPPM, "wpct=%s" }, + { QOS_WLAT, "wlat=%u" }, + { QOS_MIN, "min=%s" }, + { QOS_MAX, "max=%s" }, + { NR_QOS_PARAMS, NULL }, +}; + +static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input, + size_t nbytes, loff_t off) +{ + struct gendisk *disk; + struct ioc *ioc; + u32 qos[NR_QOS_PARAMS]; + bool enable, user; + char *p; + int ret; + + disk = blkcg_conf_get_disk(&input); + if (IS_ERR(disk)) + return PTR_ERR(disk); + + ioc = q_to_ioc(disk->queue); + if (!ioc) { + ret = blk_iocost_init(disk->queue); + if (ret) + goto err; + ioc = q_to_ioc(disk->queue); + } + + spin_lock_irq(&ioc->lock); + memcpy(qos, ioc->params.qos, sizeof(qos)); + enable = ioc->enabled; + user = ioc->user_qos_params; + spin_unlock_irq(&ioc->lock); + + while ((p = strsep(&input, " \t\n"))) { + substring_t args[MAX_OPT_ARGS]; + char buf[32]; + int tok; + s64 v; + + if (!*p) + continue; + + switch (match_token(p, qos_ctrl_tokens, args)) { + case QOS_ENABLE: + match_u64(&args[0], &v); + enable = v; + continue; + case QOS_CTRL: + match_strlcpy(buf, &args[0], sizeof(buf)); + if (!strcmp(buf, "auto")) + user = false; + else if (!strcmp(buf, "user")) + user = true; + else + goto einval; + continue; + } + + tok = match_token(p, qos_tokens, args); + switch (tok) { + case QOS_RPPM: + case QOS_WPPM: + if (match_strlcpy(buf, &args[0], sizeof(buf)) >= + sizeof(buf)) + goto einval; + if (cgroup_parse_float(buf, 2, &v)) + goto einval; + if (v < 0 || v > 10000) + goto einval; + qos[tok] = v * 100; + break; + case QOS_RLAT: + case QOS_WLAT: + if (match_u64(&args[0], &v)) + goto einval; + qos[tok] = v; + break; + case QOS_MIN: + case QOS_MAX: + if (match_strlcpy(buf, &args[0], sizeof(buf)) >= + sizeof(buf)) + goto einval; + if (cgroup_parse_float(buf, 2, &v)) + goto einval; + if (v < 0) + goto einval; + qos[tok] = clamp_t(s64, v * 100, + VRATE_MIN_PPM, VRATE_MAX_PPM); + break; + default: + goto einval; + } + user = true; + } + + if (qos[QOS_MIN] > qos[QOS_MAX]) + goto einval; + + spin_lock_irq(&ioc->lock); + + if (enable) { + blk_queue_flag_set(QUEUE_FLAG_RQ_ALLOC_TIME, ioc->rqos.q); + ioc->enabled = true; + } else { + blk_queue_flag_clear(QUEUE_FLAG_RQ_ALLOC_TIME, ioc->rqos.q); + ioc->enabled = false; + } + + if (user) { + memcpy(ioc->params.qos, qos, sizeof(qos)); + ioc->user_qos_params = true; + } else { + ioc->user_qos_params = false; + } + + ioc_refresh_params(ioc, true); + spin_unlock_irq(&ioc->lock); + + put_disk_and_module(disk); + return nbytes; +einval: + ret = -EINVAL; +err: + put_disk_and_module(disk); + return ret; +} + +static u64 ioc_cost_model_prfill(struct seq_file *sf, + struct blkg_policy_data *pd, int off) +{ + const char *dname = blkg_dev_name(pd->blkg); + struct ioc *ioc = pd_to_iocg(pd)->ioc; + u64 *u = ioc->params.i_lcoefs; + + if (!dname) + return 0; + + seq_printf(sf, "%s ctrl=%s model=linear " + "rbps=%llu rseqiops=%llu rrandiops=%llu " + "wbps=%llu wseqiops=%llu wrandiops=%llu\n", + dname, ioc->user_cost_model ? "user" : "auto", + u[I_LCOEF_RBPS], u[I_LCOEF_RSEQIOPS], u[I_LCOEF_RRANDIOPS], + u[I_LCOEF_WBPS], u[I_LCOEF_WSEQIOPS], u[I_LCOEF_WRANDIOPS]); + return 0; +} + +static int ioc_cost_model_show(struct seq_file *sf, void *v) +{ + struct blkcg *blkcg = css_to_blkcg(seq_css(sf)); + + blkcg_print_blkgs(sf, blkcg, ioc_cost_model_prfill, + &blkcg_policy_iocost, seq_cft(sf)->private, false); + return 0; +} + +static const match_table_t cost_ctrl_tokens = { + { COST_CTRL, "ctrl=%s" }, + { COST_MODEL, "model=%s" }, + { NR_COST_CTRL_PARAMS, NULL }, +}; + +static const match_table_t i_lcoef_tokens = { + { I_LCOEF_RBPS, "rbps=%u" }, + { I_LCOEF_RSEQIOPS, "rseqiops=%u" }, + { I_LCOEF_RRANDIOPS, "rrandiops=%u" }, + { I_LCOEF_WBPS, "wbps=%u" }, + { I_LCOEF_WSEQIOPS, "wseqiops=%u" }, + { I_LCOEF_WRANDIOPS, "wrandiops=%u" }, + { NR_I_LCOEFS, NULL }, +}; + +static ssize_t ioc_cost_model_write(struct kernfs_open_file *of, char *input, + size_t nbytes, loff_t off) +{ + struct gendisk *disk; + struct ioc *ioc; + u64 u[NR_I_LCOEFS]; + bool user; + char *p; + int ret; + + disk = blkcg_conf_get_disk(&input); + if (IS_ERR(disk)) + return PTR_ERR(disk); + + ioc = q_to_ioc(disk->queue); + if (!ioc) { + ret = blk_iocost_init(disk->queue); + if (ret) + goto err; + ioc = q_to_ioc(disk->queue); + } + + spin_lock_irq(&ioc->lock); + memcpy(u, ioc->params.i_lcoefs, sizeof(u)); + user = ioc->user_cost_model; + spin_unlock_irq(&ioc->lock); + + while ((p = strsep(&input, " \t\n"))) { + substring_t args[MAX_OPT_ARGS]; + char buf[32]; + int tok; + u64 v; + + if (!*p) + continue; + + switch (match_token(p, cost_ctrl_tokens, args)) { + case COST_CTRL: + match_strlcpy(buf, &args[0], sizeof(buf)); + if (!strcmp(buf, "auto")) + user = false; + else if (!strcmp(buf, "user")) + user = true; + else + goto einval; + continue; + case COST_MODEL: + match_strlcpy(buf, &args[0], sizeof(buf)); + if (strcmp(buf, "linear")) + goto einval; + continue; + } + + tok = match_token(p, i_lcoef_tokens, args); + if (tok == NR_I_LCOEFS) + goto einval; + if (match_u64(&args[0], &v)) + goto einval; + u[tok] = v; + user = true; + } + + spin_lock_irq(&ioc->lock); + if (user) { + memcpy(ioc->params.i_lcoefs, u, sizeof(u)); + ioc->user_cost_model = true; + } else { + ioc->user_cost_model = false; + } + ioc_refresh_params(ioc, true); + spin_unlock_irq(&ioc->lock); + + put_disk_and_module(disk); + return nbytes; + +einval: + ret = -EINVAL; +err: + put_disk_and_module(disk); + return ret; +} + +static struct cftype ioc_files[] = { + { + .name = "weight", + .flags = CFTYPE_NOT_ON_ROOT, + .seq_show = ioc_weight_show, + .write = ioc_weight_write, + }, + { + .name = "cost.qos", + .flags = CFTYPE_ONLY_ON_ROOT, + .seq_show = ioc_qos_show, + .write = ioc_qos_write, + }, + { + .name = "cost.model", + .flags = CFTYPE_ONLY_ON_ROOT, + .seq_show = ioc_cost_model_show, + .write = ioc_cost_model_write, + }, + {} +}; + +static struct blkcg_policy blkcg_policy_iocost = { + .dfl_cftypes = ioc_files, + .cpd_alloc_fn = ioc_cpd_alloc, + .cpd_free_fn = ioc_cpd_free, + .pd_alloc_fn = ioc_pd_alloc, + .pd_init_fn = ioc_pd_init, + .pd_free_fn = ioc_pd_free, +}; + +static int __init ioc_init(void) +{ + return blkcg_policy_register(&blkcg_policy_iocost); +} + +static void __exit ioc_exit(void) +{ + return blkcg_policy_unregister(&blkcg_policy_iocost); +} + +module_init(ioc_init); +module_exit(ioc_exit); diff --git a/block/blk-iolatency.c b/block/blk-iolatency.c index 0fff7b56df0e4d0fa0f82be4102f3ceb03735034..c128d50cb4107969cab6460e3447b93f7c54553f 100644 --- a/block/blk-iolatency.c +++ b/block/blk-iolatency.c @@ -725,7 +725,7 @@ int blk_iolatency_init(struct request_queue *q) return -ENOMEM; rqos = &blkiolat->rqos; - rqos->id = RQ_QOS_CGROUP; + rqos->id = RQ_QOS_LATENCY; rqos->ops = &blkcg_iolatency_ops; rqos->q = q; @@ -934,11 +934,13 @@ static size_t iolatency_pd_stat(struct blkg_policy_data *pd, char *buf, } -static struct blkg_policy_data *iolatency_pd_alloc(gfp_t gfp, int node) +static struct blkg_policy_data *iolatency_pd_alloc(gfp_t gfp, + struct request_queue *q, + struct blkcg *blkcg) { struct iolatency_grp *iolat; - iolat = kzalloc_node(sizeof(*iolat), gfp, node); + iolat = kzalloc_node(sizeof(*iolat), gfp, q->node); if (!iolat) return NULL; iolat->stats = __alloc_percpu_gfp(sizeof(struct latency_stat), diff --git a/block/blk-merge.c b/block/blk-merge.c index 57f7990b342dd1957077ae48baf71283663c0e73..48e6725b32eeacc749664d19fe151df6e2b7818c 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -132,19 +132,32 @@ static struct bio *blk_bio_write_same_split(struct request_queue *q, return bio_split(bio, q->limits.max_write_same_sectors, GFP_NOIO, bs); } +/* + * Return the maximum number of sectors from the start of a bio that may be + * submitted as a single request to a block device. If enough sectors remain, + * align the end to the physical block size. Otherwise align the end to the + * logical block size. This approach minimizes the number of non-aligned + * requests that are submitted to a block device if the start of a bio is not + * aligned to a physical block boundary. + */ static inline unsigned get_max_io_size(struct request_queue *q, struct bio *bio) { unsigned sectors = blk_max_size_offset(q, bio->bi_iter.bi_sector); - unsigned mask = queue_logical_block_size(q) - 1; + unsigned max_sectors = sectors; + unsigned pbs = queue_physical_block_size(q) >> SECTOR_SHIFT; + unsigned lbs = queue_logical_block_size(q) >> SECTOR_SHIFT; + unsigned start_offset = bio->bi_iter.bi_sector & (pbs - 1); - /* aligned to logical block size */ - sectors &= ~(mask >> 9); + max_sectors += start_offset; + max_sectors &= ~(pbs - 1); + if (max_sectors > start_offset) + return max_sectors - start_offset; - return sectors; + return sectors & (lbs - 1); } -static unsigned get_max_segment_size(struct request_queue *q, +static unsigned get_max_segment_size(const struct request_queue *q, unsigned offset) { unsigned long mask = queue_segment_boundary(q); @@ -157,26 +170,41 @@ static unsigned get_max_segment_size(struct request_queue *q, queue_max_segment_size(q)); } -/* - * Split the bvec @bv into segments, and update all kinds of - * variables. +/** + * bvec_split_segs - verify whether or not a bvec should be split in the middle + * @q: [in] request queue associated with the bio associated with @bv + * @bv: [in] bvec to examine + * @nsegs: [in,out] Number of segments in the bio being built. Incremented + * by the number of segments from @bv that may be appended to that + * bio without exceeding @max_segs + * @sectors: [in,out] Number of sectors in the bio being built. Incremented + * by the number of sectors from @bv that may be appended to that + * bio without exceeding @max_sectors + * @max_segs: [in] upper bound for *@nsegs + * @max_sectors: [in] upper bound for *@sectors + * + * When splitting a bio, it can happen that a bvec is encountered that is too + * big to fit in a single segment and hence that it has to be split in the + * middle. This function verifies whether or not that should happen. The value + * %true is returned if and only if appending the entire @bv to a bio with + * *@nsegs segments and *@sectors sectors would make that bio unacceptable for + * the block driver. */ -static bool bvec_split_segs(struct request_queue *q, struct bio_vec *bv, - unsigned *nsegs, unsigned *sectors, unsigned max_segs) +static bool bvec_split_segs(const struct request_queue *q, + const struct bio_vec *bv, unsigned *nsegs, + unsigned *sectors, unsigned max_segs, + unsigned max_sectors) { - unsigned len = bv->bv_len; + unsigned max_len = (min(max_sectors, UINT_MAX >> 9) - *sectors) << 9; + unsigned len = min(bv->bv_len, max_len); unsigned total_len = 0; - unsigned new_nsegs = 0, seg_size = 0; + unsigned seg_size = 0; - /* - * Multi-page bvec may be too big to hold in one segment, so the - * current bvec has to be splitted as multiple segments. - */ - while (len && new_nsegs + *nsegs < max_segs) { + while (len && *nsegs < max_segs) { seg_size = get_max_segment_size(q, bv->bv_offset + total_len); seg_size = min(seg_size, len); - new_nsegs++; + (*nsegs)++; total_len += seg_size; len -= seg_size; @@ -184,16 +212,31 @@ static bool bvec_split_segs(struct request_queue *q, struct bio_vec *bv, break; } - if (new_nsegs) { - *nsegs += new_nsegs; - if (sectors) - *sectors += total_len >> 9; - } + *sectors += total_len >> 9; - /* split in the middle of the bvec if len != 0 */ - return !!len; + /* tell the caller to split the bvec if it is too big to fit */ + return len > 0 || bv->bv_len > max_len; } +/** + * blk_bio_segment_split - split a bio in two bios + * @q: [in] request queue pointer + * @bio: [in] bio to be split + * @bs: [in] bio set to allocate the clone from + * @segs: [out] number of segments in the bio with the first half of the sectors + * + * Clone @bio, update the bi_iter of the clone to represent the first sectors + * of @bio and update @bio->bi_iter to represent the remaining sectors. The + * following is guaranteed for the cloned bio: + * - That it has at most get_max_io_size(@q, @bio) sectors. + * - That it has at most queue_max_segments(@q) segments. + * + * Except for discard requests the cloned bio will point at the bi_io_vec of + * the original bio. It is the responsibility of the caller to ensure that the + * original bio is not freed before the cloned bio. The caller is also + * responsible for ensuring that @bs is only destroyed after processing of the + * split bio has finished. + */ static struct bio *blk_bio_segment_split(struct request_queue *q, struct bio *bio, struct bio_set *bs, @@ -213,34 +256,18 @@ static struct bio *blk_bio_segment_split(struct request_queue *q, if (bvprvp && bvec_gap_to_prev(q, bvprvp, bv.bv_offset)) goto split; - if (sectors + (bv.bv_len >> 9) > max_sectors) { - /* - * Consider this a new segment if we're splitting in - * the middle of this vector. - */ - if (nsegs < max_segs && - sectors < max_sectors) { - /* split in the middle of bvec */ - bv.bv_len = (max_sectors - sectors) << 9; - bvec_split_segs(q, &bv, &nsegs, - §ors, max_segs); - } + if (nsegs < max_segs && + sectors + (bv.bv_len >> 9) <= max_sectors && + bv.bv_offset + bv.bv_len <= PAGE_SIZE) { + nsegs++; + sectors += bv.bv_len >> 9; + } else if (bvec_split_segs(q, &bv, &nsegs, §ors, max_segs, + max_sectors)) { goto split; } - if (nsegs == max_segs) - goto split; - bvprv = bv; bvprvp = &bvprv; - - if (bv.bv_offset + bv.bv_len <= PAGE_SIZE) { - nsegs++; - sectors += bv.bv_len >> 9; - } else if (bvec_split_segs(q, &bv, &nsegs, §ors, - max_segs)) { - goto split; - } } *segs = nsegs; @@ -250,6 +277,19 @@ static struct bio *blk_bio_segment_split(struct request_queue *q, return bio_split(bio, sectors, GFP_NOIO, bs); } +/** + * __blk_queue_split - split a bio and submit the second half + * @q: [in] request queue pointer + * @bio: [in, out] bio to be split + * @nr_segs: [out] number of segments in the first bio + * + * Split a bio into two bios, chain the two bios, submit the second half and + * store a pointer to the first half in *@bio. If the second bio is still too + * big it will be split by a recursive call to this function. Since this + * function may allocate a new bio from @q->bio_split, it is the responsibility + * of the caller to ensure that @q is only released after processing of the + * split bio has finished. + */ void __blk_queue_split(struct request_queue *q, struct bio **bio, unsigned int *nr_segs) { @@ -294,6 +334,17 @@ void __blk_queue_split(struct request_queue *q, struct bio **bio, } } +/** + * blk_queue_split - split a bio and submit the second half + * @q: [in] request queue pointer + * @bio: [in, out] bio to be split + * + * Split a bio into two bios, chains the two bios, submit the second half and + * store a pointer to the first half in *@bio. Since this function may allocate + * a new bio from @q->bio_split, it is the responsibility of the caller to + * ensure that @q is only released after processing of the split bio has + * finished. + */ void blk_queue_split(struct request_queue *q, struct bio **bio) { unsigned int nr_segs; @@ -305,6 +356,7 @@ EXPORT_SYMBOL(blk_queue_split); unsigned int blk_recalc_rq_segments(struct request *rq) { unsigned int nr_phys_segs = 0; + unsigned int nr_sectors = 0; struct req_iterator iter; struct bio_vec bv; @@ -321,7 +373,8 @@ unsigned int blk_recalc_rq_segments(struct request *rq) } rq_for_each_bvec(bv, rq, iter) - bvec_split_segs(rq->q, &bv, &nr_phys_segs, NULL, UINT_MAX); + bvec_split_segs(rq->q, &bv, &nr_phys_segs, &nr_sectors, + UINT_MAX, UINT_MAX); return nr_phys_segs; } diff --git a/block/blk-mq-cpumap.c b/block/blk-mq-cpumap.c index f945621a0e8f2864a0829a84f1e8530236854bca..0157f2b3485a1d14da1aaa0239f0cc020dbf20be 100644 --- a/block/blk-mq-cpumap.c +++ b/block/blk-mq-cpumap.c @@ -15,10 +15,10 @@ #include "blk.h" #include "blk-mq.h" -static int cpu_to_queue_index(struct blk_mq_queue_map *qmap, - unsigned int nr_queues, const int cpu) +static int queue_index(struct blk_mq_queue_map *qmap, + unsigned int nr_queues, const int q) { - return qmap->queue_offset + (cpu % nr_queues); + return qmap->queue_offset + (q % nr_queues); } static int get_first_sibling(unsigned int cpu) @@ -36,21 +36,36 @@ int blk_mq_map_queues(struct blk_mq_queue_map *qmap) { unsigned int *map = qmap->mq_map; unsigned int nr_queues = qmap->nr_queues; - unsigned int cpu, first_sibling; + unsigned int cpu, first_sibling, q = 0; + + for_each_possible_cpu(cpu) + map[cpu] = -1; + + /* + * Spread queues among present CPUs first for minimizing + * count of dead queues which are mapped by all un-present CPUs + */ + for_each_present_cpu(cpu) { + if (q >= nr_queues) + break; + map[cpu] = queue_index(qmap, nr_queues, q++); + } for_each_possible_cpu(cpu) { + if (map[cpu] != -1) + continue; /* * First do sequential mapping between CPUs and queues. * In case we still have CPUs to map, and we have some number of * threads per cores then map sibling threads to the same queue * for performance optimizations. */ - if (cpu < nr_queues) { - map[cpu] = cpu_to_queue_index(qmap, nr_queues, cpu); + if (q < nr_queues) { + map[cpu] = queue_index(qmap, nr_queues, q++); } else { first_sibling = get_first_sibling(cpu); if (first_sibling == cpu) - map[cpu] = cpu_to_queue_index(qmap, nr_queues, cpu); + map[cpu] = queue_index(qmap, nr_queues, q++); else map[cpu] = map[first_sibling]; } diff --git a/block/blk-mq-sysfs.c b/block/blk-mq-sysfs.c index d6e1a9bd7131c6d7b5c6027fc000b323934ba901..a0d3ce30fa0893e6d854e4097bc627685d97cc7a 100644 --- a/block/blk-mq-sysfs.c +++ b/block/blk-mq-sysfs.c @@ -270,7 +270,7 @@ void blk_mq_unregister_dev(struct device *dev, struct request_queue *q) struct blk_mq_hw_ctx *hctx; int i; - lockdep_assert_held(&q->sysfs_lock); + lockdep_assert_held(&q->sysfs_dir_lock); queue_for_each_hw_ctx(q, hctx, i) blk_mq_unregister_hctx(hctx); @@ -320,7 +320,7 @@ int __blk_mq_register_dev(struct device *dev, struct request_queue *q) int ret, i; WARN_ON_ONCE(!q->kobj.parent); - lockdep_assert_held(&q->sysfs_lock); + lockdep_assert_held(&q->sysfs_dir_lock); ret = kobject_add(q->mq_kobj, kobject_get(&dev->kobj), "%s", "mq"); if (ret < 0) @@ -349,23 +349,12 @@ int __blk_mq_register_dev(struct device *dev, struct request_queue *q) return ret; } -int blk_mq_register_dev(struct device *dev, struct request_queue *q) -{ - int ret; - - mutex_lock(&q->sysfs_lock); - ret = __blk_mq_register_dev(dev, q); - mutex_unlock(&q->sysfs_lock); - - return ret; -} - void blk_mq_sysfs_unregister(struct request_queue *q) { struct blk_mq_hw_ctx *hctx; int i; - mutex_lock(&q->sysfs_lock); + mutex_lock(&q->sysfs_dir_lock); if (!q->mq_sysfs_init_done) goto unlock; @@ -373,7 +362,7 @@ void blk_mq_sysfs_unregister(struct request_queue *q) blk_mq_unregister_hctx(hctx); unlock: - mutex_unlock(&q->sysfs_lock); + mutex_unlock(&q->sysfs_dir_lock); } int blk_mq_sysfs_register(struct request_queue *q) @@ -381,7 +370,7 @@ int blk_mq_sysfs_register(struct request_queue *q) struct blk_mq_hw_ctx *hctx; int i, ret = 0; - mutex_lock(&q->sysfs_lock); + mutex_lock(&q->sysfs_dir_lock); if (!q->mq_sysfs_init_done) goto unlock; @@ -392,7 +381,7 @@ int blk_mq_sysfs_register(struct request_queue *q) } unlock: - mutex_unlock(&q->sysfs_lock); + mutex_unlock(&q->sysfs_dir_lock); return ret; } diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c index da19f0bc8876d21d9f0263ed79f8f15720935739..008388e82b5c55f2e06b224998a46bf5b46a9d39 100644 --- a/block/blk-mq-tag.c +++ b/block/blk-mq-tag.c @@ -10,6 +10,7 @@ #include #include +#include #include "blk.h" #include "blk-mq.h" #include "blk-mq-tag.h" @@ -354,6 +355,37 @@ void blk_mq_tagset_busy_iter(struct blk_mq_tag_set *tagset, } EXPORT_SYMBOL(blk_mq_tagset_busy_iter); +static bool blk_mq_tagset_count_completed_rqs(struct request *rq, + void *data, bool reserved) +{ + unsigned *count = data; + + if (blk_mq_request_completed(rq)) + (*count)++; + return true; +} + +/** + * blk_mq_tagset_wait_completed_request - wait until all completed req's + * complete funtion is run + * @tagset: Tag set to drain completed request + * + * Note: This function has to be run after all IO queues are shutdown + */ +void blk_mq_tagset_wait_completed_request(struct blk_mq_tag_set *tagset) +{ + while (true) { + unsigned count = 0; + + blk_mq_tagset_busy_iter(tagset, + blk_mq_tagset_count_completed_rqs, &count); + if (!count) + break; + msleep(5); + } +} +EXPORT_SYMBOL(blk_mq_tagset_wait_completed_request); + /** * blk_mq_queue_tag_busy_iter - iterate over all requests with a driver tag * @q: Request queue to examine. diff --git a/block/blk-mq.c b/block/blk-mq.c index 0835f4d8d42e7e34c043acc040d8f5406b2e2268..20a49be536b512dcaf5092334f45fd0e1b691c83 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -44,12 +44,12 @@ static void blk_mq_poll_stats_fn(struct blk_stat_callback *cb); static int blk_mq_poll_stats_bkt(const struct request *rq) { - int ddir, bytes, bucket; + int ddir, sectors, bucket; ddir = rq_data_dir(rq); - bytes = blk_rq_bytes(rq); + sectors = blk_rq_stats_sectors(rq); - bucket = ddir + 2*(ilog2(bytes) - 9); + bucket = ddir + 2 * ilog2(sectors); if (bucket < 0) return -1; @@ -282,16 +282,16 @@ bool blk_mq_can_queue(struct blk_mq_hw_ctx *hctx) EXPORT_SYMBOL(blk_mq_can_queue); /* - * Only need start/end time stamping if we have stats enabled, or using - * an IO scheduler. + * Only need start/end time stamping if we have iostat or + * blk stats enabled, or using an IO scheduler. */ static inline bool blk_mq_need_time_stamp(struct request *rq) { - return (rq->rq_flags & RQF_IO_STAT) || rq->q->elevator; + return (rq->rq_flags & (RQF_IO_STAT | RQF_STATS)) || rq->q->elevator; } static struct request *blk_mq_rq_ctx_init(struct blk_mq_alloc_data *data, - unsigned int tag, unsigned int op) + unsigned int tag, unsigned int op, u64 alloc_time_ns) { struct blk_mq_tags *tags = blk_mq_tags_from_data(data); struct request *rq = tags->static_rqs[tag]; @@ -325,11 +325,15 @@ static struct request *blk_mq_rq_ctx_init(struct blk_mq_alloc_data *data, RB_CLEAR_NODE(&rq->rb_node); rq->rq_disk = NULL; rq->part = NULL; +#ifdef CONFIG_BLK_RQ_ALLOC_TIME + rq->alloc_time_ns = alloc_time_ns; +#endif if (blk_mq_need_time_stamp(rq)) rq->start_time_ns = ktime_get_ns(); else rq->start_time_ns = 0; rq->io_start_time_ns = 0; + rq->stats_sectors = 0; rq->nr_phys_segments = 0; #if defined(CONFIG_BLK_DEV_INTEGRITY) rq->nr_integrity_segments = 0; @@ -356,8 +360,14 @@ static struct request *blk_mq_get_request(struct request_queue *q, struct request *rq; unsigned int tag; bool clear_ctx_on_error = false; + u64 alloc_time_ns = 0; blk_queue_enter_live(q); + + /* alloc_time includes depth and tag waits */ + if (blk_queue_rq_alloc_time(q)) + alloc_time_ns = ktime_get_ns(); + data->q = q; if (likely(!data->ctx)) { data->ctx = blk_mq_get_ctx(q); @@ -393,7 +403,7 @@ static struct request *blk_mq_get_request(struct request_queue *q, return NULL; } - rq = blk_mq_rq_ctx_init(data, tag, data->cmd_flags); + rq = blk_mq_rq_ctx_init(data, tag, data->cmd_flags, alloc_time_ns); if (!op_is_flush(data->cmd_flags)) { rq->elv.icq = NULL; if (e && e->type->ops.prepare_request) { @@ -652,19 +662,18 @@ bool blk_mq_complete_request(struct request *rq) } EXPORT_SYMBOL(blk_mq_complete_request); -void blk_mq_complete_request_sync(struct request *rq) -{ - WRITE_ONCE(rq->state, MQ_RQ_COMPLETE); - rq->q->mq_ops->complete(rq); -} -EXPORT_SYMBOL_GPL(blk_mq_complete_request_sync); - int blk_mq_request_started(struct request *rq) { return blk_mq_rq_state(rq) != MQ_RQ_IDLE; } EXPORT_SYMBOL_GPL(blk_mq_request_started); +int blk_mq_request_completed(struct request *rq) +{ + return blk_mq_rq_state(rq) == MQ_RQ_COMPLETE; +} +EXPORT_SYMBOL_GPL(blk_mq_request_completed); + void blk_mq_start_request(struct request *rq) { struct request_queue *q = rq->q; @@ -673,9 +682,7 @@ void blk_mq_start_request(struct request *rq) if (test_bit(QUEUE_FLAG_STATS, &q->queue_flags)) { rq->io_start_time_ns = ktime_get_ns(); -#ifdef CONFIG_BLK_DEV_THROTTLING_LOW - rq->throtl_size = blk_rq_sectors(rq); -#endif + rq->stats_sectors = blk_rq_sectors(rq); rq->rq_flags |= RQF_STATS; rq_qos_issue(q, rq); } @@ -2453,11 +2460,6 @@ static void blk_mq_map_swqueue(struct request_queue *q) struct blk_mq_ctx *ctx; struct blk_mq_tag_set *set = q->tag_set; - /* - * Avoid others reading imcomplete hctx->cpumask through sysfs - */ - mutex_lock(&q->sysfs_lock); - queue_for_each_hw_ctx(q, hctx, i) { cpumask_clear(hctx->cpumask); hctx->nr_ctx = 0; @@ -2518,8 +2520,6 @@ static void blk_mq_map_swqueue(struct request_queue *q) HCTX_TYPE_DEFAULT, i); } - mutex_unlock(&q->sysfs_lock); - queue_for_each_hw_ctx(q, hctx, i) { /* * If no software queues are mapped to this hardware queue, @@ -2688,7 +2688,11 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set) if (!uninit_q) return ERR_PTR(-ENOMEM); - q = blk_mq_init_allocated_queue(set, uninit_q); + /* + * Initialize the queue without an elevator. device_add_disk() will do + * the initialization. + */ + q = blk_mq_init_allocated_queue(set, uninit_q, false); if (IS_ERR(q)) blk_cleanup_queue(uninit_q); @@ -2839,7 +2843,8 @@ static unsigned int nr_hw_queues(struct blk_mq_tag_set *set) } struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, - struct request_queue *q) + struct request_queue *q, + bool elevator_init) { /* mark the queue as mq asap */ q->mq_ops = set->ops; @@ -2901,18 +2906,14 @@ struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, blk_mq_add_queue_tag_set(set, q); blk_mq_map_swqueue(q); - if (!(set->flags & BLK_MQ_F_NO_SCHED)) { - int ret; - - ret = elevator_init_mq(q); - if (ret) - return ERR_PTR(ret); - } + if (elevator_init) + elevator_init_mq(q); return q; err_hctxs: kfree(q->queue_hw_ctx); + q->nr_hw_queues = 0; err_sys_init: blk_mq_sysfs_deinit(q); err_poll: @@ -3411,15 +3412,14 @@ static bool blk_mq_poll_hybrid_sleep(struct request_queue *q, kt = nsecs; mode = HRTIMER_MODE_REL; - hrtimer_init_on_stack(&hs.timer, CLOCK_MONOTONIC, mode); + hrtimer_init_sleeper_on_stack(&hs, CLOCK_MONOTONIC, mode); hrtimer_set_expires(&hs.timer, kt); - hrtimer_init_sleeper(&hs, current); do { if (blk_mq_rq_state(rq) == MQ_RQ_COMPLETE) break; set_current_state(TASK_UNINTERRUPTIBLE); - hrtimer_start_expires(&hs.timer, mode); + hrtimer_sleeper_start_expires(&hs, mode); if (hs.task) io_schedule(); hrtimer_cancel(&hs.timer); diff --git a/block/blk-pm.c b/block/blk-pm.c index 0a028c1898977c5208223928c3f2d490c4213999..1adc1cd748b4038d8bb441d76fa9ca277d333c0c 100644 --- a/block/blk-pm.c +++ b/block/blk-pm.c @@ -207,10 +207,12 @@ EXPORT_SYMBOL(blk_post_runtime_resume); */ void blk_set_runtime_active(struct request_queue *q) { - spin_lock_irq(&q->queue_lock); - q->rpm_status = RPM_ACTIVE; - pm_runtime_mark_last_busy(q->dev); - pm_request_autosuspend(q->dev); - spin_unlock_irq(&q->queue_lock); + if (q->dev) { + spin_lock_irq(&q->queue_lock); + q->rpm_status = RPM_ACTIVE; + pm_runtime_mark_last_busy(q->dev); + pm_request_autosuspend(q->dev); + spin_unlock_irq(&q->queue_lock); + } } EXPORT_SYMBOL(blk_set_runtime_active); diff --git a/block/blk-rq-qos.c b/block/blk-rq-qos.c index 3954c0dc14433d21c4baf7f9b007c2710fa67d64..61b635bc2a3181be4432513d2c4a6a177d36e3ca 100644 --- a/block/blk-rq-qos.c +++ b/block/blk-rq-qos.c @@ -83,6 +83,15 @@ void __rq_qos_track(struct rq_qos *rqos, struct request *rq, struct bio *bio) } while (rqos); } +void __rq_qos_merge(struct rq_qos *rqos, struct request *rq, struct bio *bio) +{ + do { + if (rqos->ops->merge) + rqos->ops->merge(rqos, rq, bio); + rqos = rqos->next; + } while (rqos); +} + void __rq_qos_done_bio(struct rq_qos *rqos, struct bio *bio) { do { @@ -92,6 +101,15 @@ void __rq_qos_done_bio(struct rq_qos *rqos, struct bio *bio) } while (rqos); } +void __rq_qos_queue_depth_changed(struct rq_qos *rqos) +{ + do { + if (rqos->ops->queue_depth_changed) + rqos->ops->queue_depth_changed(rqos); + rqos = rqos->next; + } while (rqos); +} + /* * Return true, if we can't increase the depth further by scaling */ diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h index 2300e038b9fafa2353394ab71ee76b40269e6672..08a09dbe0f4bfb39eb60f543f2e00e15fb72ab86 100644 --- a/block/blk-rq-qos.h +++ b/block/blk-rq-qos.h @@ -14,7 +14,8 @@ struct blk_mq_debugfs_attr; enum rq_qos_id { RQ_QOS_WBT, - RQ_QOS_CGROUP, + RQ_QOS_LATENCY, + RQ_QOS_COST, }; struct rq_wait { @@ -35,11 +36,13 @@ struct rq_qos { struct rq_qos_ops { void (*throttle)(struct rq_qos *, struct bio *); void (*track)(struct rq_qos *, struct request *, struct bio *); + void (*merge)(struct rq_qos *, struct request *, struct bio *); void (*issue)(struct rq_qos *, struct request *); void (*requeue)(struct rq_qos *, struct request *); void (*done)(struct rq_qos *, struct request *); void (*done_bio)(struct rq_qos *, struct bio *); void (*cleanup)(struct rq_qos *, struct bio *); + void (*queue_depth_changed)(struct rq_qos *); void (*exit)(struct rq_qos *); const struct blk_mq_debugfs_attr *debugfs_attrs; }; @@ -72,7 +75,7 @@ static inline struct rq_qos *wbt_rq_qos(struct request_queue *q) static inline struct rq_qos *blkcg_rq_qos(struct request_queue *q) { - return rq_qos_id(q, RQ_QOS_CGROUP); + return rq_qos_id(q, RQ_QOS_LATENCY); } static inline const char *rq_qos_id_to_name(enum rq_qos_id id) @@ -80,8 +83,10 @@ static inline const char *rq_qos_id_to_name(enum rq_qos_id id) switch (id) { case RQ_QOS_WBT: return "wbt"; - case RQ_QOS_CGROUP: - return "cgroup"; + case RQ_QOS_LATENCY: + return "latency"; + case RQ_QOS_COST: + return "cost"; } return "unknown"; } @@ -135,7 +140,9 @@ void __rq_qos_issue(struct rq_qos *rqos, struct request *rq); void __rq_qos_requeue(struct rq_qos *rqos, struct request *rq); void __rq_qos_throttle(struct rq_qos *rqos, struct bio *bio); void __rq_qos_track(struct rq_qos *rqos, struct request *rq, struct bio *bio); +void __rq_qos_merge(struct rq_qos *rqos, struct request *rq, struct bio *bio); void __rq_qos_done_bio(struct rq_qos *rqos, struct bio *bio); +void __rq_qos_queue_depth_changed(struct rq_qos *rqos); static inline void rq_qos_cleanup(struct request_queue *q, struct bio *bio) { @@ -185,6 +192,19 @@ static inline void rq_qos_track(struct request_queue *q, struct request *rq, __rq_qos_track(q->rq_qos, rq, bio); } +static inline void rq_qos_merge(struct request_queue *q, struct request *rq, + struct bio *bio) +{ + if (q->rq_qos) + __rq_qos_merge(q->rq_qos, rq, bio); +} + +static inline void rq_qos_queue_depth_changed(struct request_queue *q) +{ + if (q->rq_qos) + __rq_qos_queue_depth_changed(q->rq_qos); +} + void rq_qos_exit(struct request_queue *); #endif diff --git a/block/blk-settings.c b/block/blk-settings.c index 2c1831207a8f74de455679551f79d8862450eed0..6bd1e3b082d8e811da833070c4813a41bcfa11c4 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -805,7 +805,7 @@ EXPORT_SYMBOL(blk_queue_update_dma_alignment); void blk_set_queue_depth(struct request_queue *q, unsigned int depth) { q->queue_depth = depth; - wbt_set_queue_depth(q, depth); + rq_qos_queue_depth_changed(q); } EXPORT_SYMBOL(blk_set_queue_depth); @@ -832,6 +832,22 @@ void blk_queue_write_cache(struct request_queue *q, bool wc, bool fua) } EXPORT_SYMBOL_GPL(blk_queue_write_cache); +/** + * blk_queue_required_elevator_features - Set a queue required elevator features + * @q: the request queue for the target device + * @features: Required elevator features OR'ed together + * + * Tell the block layer that for the device controlled through @q, only the + * only elevators that can be used are those that implement at least the set of + * features specified by @features. + */ +void blk_queue_required_elevator_features(struct request_queue *q, + unsigned int features) +{ + q->required_elevator_features = features; +} +EXPORT_SYMBOL_GPL(blk_queue_required_elevator_features); + static int __init blk_settings_init(void) { blk_max_low_pfn = max_low_pfn - 1; diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 9bfa3ea4ed63038606067f1bb9d2f0c957a90279..b82736c781c5171cc2d49f1c87abcb24d24e5868 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -941,14 +941,14 @@ int blk_register_queue(struct gendisk *disk) int ret; struct device *dev = disk_to_dev(disk); struct request_queue *q = disk->queue; + bool has_elevator = false; if (WARN_ON(!q)) return -ENXIO; - WARN_ONCE(test_bit(QUEUE_FLAG_REGISTERED, &q->queue_flags), + WARN_ONCE(blk_queue_registered(q), "%s is registering an already registered queue\n", kobject_name(&dev->kobj)); - blk_queue_flag_set(QUEUE_FLAG_REGISTERED, q); /* * SCSI probing may synchronously create and destroy a lot of @@ -968,8 +968,7 @@ int blk_register_queue(struct gendisk *disk) if (ret) return ret; - /* Prevent changes through sysfs until registration is completed. */ - mutex_lock(&q->sysfs_lock); + mutex_lock(&q->sysfs_dir_lock); ret = kobject_add(&q->kobj, kobject_get(&dev->kobj), "%s", "queue"); if (ret < 0) { @@ -990,26 +989,36 @@ int blk_register_queue(struct gendisk *disk) blk_mq_debugfs_register(q); } - kobject_uevent(&q->kobj, KOBJ_ADD); - - wbt_enable_default(q); - - blk_throtl_register_queue(q); - + /* + * The flag of QUEUE_FLAG_REGISTERED isn't set yet, so elevator + * switch won't happen at all. + */ if (q->elevator) { - ret = elv_register_queue(q); + ret = elv_register_queue(q, false); if (ret) { - mutex_unlock(&q->sysfs_lock); - kobject_uevent(&q->kobj, KOBJ_REMOVE); + mutex_unlock(&q->sysfs_dir_lock); kobject_del(&q->kobj); blk_trace_remove_sysfs(dev); kobject_put(&dev->kobj); return ret; } + has_elevator = true; } + + mutex_lock(&q->sysfs_lock); + blk_queue_flag_set(QUEUE_FLAG_REGISTERED, q); + wbt_enable_default(q); + blk_throtl_register_queue(q); + + /* Now everything is ready and send out KOBJ_ADD uevent */ + kobject_uevent(&q->kobj, KOBJ_ADD); + if (has_elevator) + kobject_uevent(&q->elevator->kobj, KOBJ_ADD); + mutex_unlock(&q->sysfs_lock); + ret = 0; unlock: - mutex_unlock(&q->sysfs_lock); + mutex_unlock(&q->sysfs_dir_lock); return ret; } EXPORT_SYMBOL_GPL(blk_register_queue); @@ -1029,7 +1038,7 @@ void blk_unregister_queue(struct gendisk *disk) return; /* Return early if disk->queue was never registered. */ - if (!test_bit(QUEUE_FLAG_REGISTERED, &q->queue_flags)) + if (!blk_queue_registered(q)) return; /* @@ -1038,25 +1047,28 @@ void blk_unregister_queue(struct gendisk *disk) * concurrent elv_iosched_store() calls. */ mutex_lock(&q->sysfs_lock); - blk_queue_flag_clear(QUEUE_FLAG_REGISTERED, q); + mutex_unlock(&q->sysfs_lock); + mutex_lock(&q->sysfs_dir_lock); /* * Remove the sysfs attributes before unregistering the queue data * structures that can be modified through sysfs. */ if (queue_is_mq(q)) blk_mq_unregister_dev(disk_to_dev(disk), q); - mutex_unlock(&q->sysfs_lock); kobject_uevent(&q->kobj, KOBJ_REMOVE); kobject_del(&q->kobj); blk_trace_remove_sysfs(disk_to_dev(disk)); - mutex_lock(&q->sysfs_lock); + /* + * q->kobj has been removed, so it is safe to check if elevator + * exists without holding q->sysfs_lock. + */ if (q->elevator) elv_unregister_queue(q); - mutex_unlock(&q->sysfs_lock); + mutex_unlock(&q->sysfs_dir_lock); kobject_put(&disk_to_dev(disk)->kobj); } diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 8ab6c8153223630a6b8d4b6fc4b1acc23ad8fc04..18f773e52dfb1d8da00b3809171e106cca780f87 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -478,12 +478,14 @@ static void throtl_service_queue_init(struct throtl_service_queue *sq) timer_setup(&sq->pending_timer, throtl_pending_timer_fn, 0); } -static struct blkg_policy_data *throtl_pd_alloc(gfp_t gfp, int node) +static struct blkg_policy_data *throtl_pd_alloc(gfp_t gfp, + struct request_queue *q, + struct blkcg *blkcg) { struct throtl_grp *tg; int rw; - tg = kzalloc_node(sizeof(*tg), gfp, node); + tg = kzalloc_node(sizeof(*tg), gfp, q->node); if (!tg) return NULL; @@ -2246,7 +2248,8 @@ void blk_throtl_stat_add(struct request *rq, u64 time_ns) struct request_queue *q = rq->q; struct throtl_data *td = q->td; - throtl_track_latency(td, rq->throtl_size, req_op(rq), time_ns >> 10); + throtl_track_latency(td, blk_rq_stats_sectors(rq), req_op(rq), + time_ns >> 10); } void blk_throtl_bio_endio(struct bio *bio) diff --git a/block/blk-wbt.c b/block/blk-wbt.c index 313f45a37e9d5f1c2771e680a4abcdb62e207301..8af553a0ba00daaf09994be44c7c71aca9a3bfdc 100644 --- a/block/blk-wbt.c +++ b/block/blk-wbt.c @@ -629,15 +629,6 @@ static void wbt_requeue(struct rq_qos *rqos, struct request *rq) } } -void wbt_set_queue_depth(struct request_queue *q, unsigned int depth) -{ - struct rq_qos *rqos = wbt_rq_qos(q); - if (rqos) { - RQWB(rqos)->rq_depth.queue_depth = depth; - __wbt_update_limits(RQWB(rqos)); - } -} - void wbt_set_write_cache(struct request_queue *q, bool write_cache_on) { struct rq_qos *rqos = wbt_rq_qos(q); @@ -656,7 +647,7 @@ void wbt_enable_default(struct request_queue *q) return; /* Queue not registered? Maybe shutting down... */ - if (!test_bit(QUEUE_FLAG_REGISTERED, &q->queue_flags)) + if (!blk_queue_registered(q)) return; if (queue_is_mq(q) && IS_ENABLED(CONFIG_BLK_WBT_MQ)) @@ -689,6 +680,12 @@ static int wbt_data_dir(const struct request *rq) return -1; } +static void wbt_queue_depth_changed(struct rq_qos *rqos) +{ + RQWB(rqos)->rq_depth.queue_depth = blk_queue_depth(rqos->q); + __wbt_update_limits(RQWB(rqos)); +} + static void wbt_exit(struct rq_qos *rqos) { struct rq_wb *rwb = RQWB(rqos); @@ -811,6 +808,7 @@ static struct rq_qos_ops wbt_rqos_ops = { .requeue = wbt_requeue, .done = wbt_done, .cleanup = wbt_cleanup, + .queue_depth_changed = wbt_queue_depth_changed, .exit = wbt_exit, #ifdef CONFIG_BLK_DEBUG_FS .debugfs_attrs = wbt_debugfs_attrs, @@ -853,7 +851,7 @@ int wbt_init(struct request_queue *q) rwb->min_lat_nsec = wbt_default_latency_nsec(q); - wbt_set_queue_depth(q, blk_queue_depth(q)); + wbt_queue_depth_changed(&rwb->rqos); wbt_set_write_cache(q, test_bit(QUEUE_FLAG_WC, &q->queue_flags)); return 0; diff --git a/block/blk-wbt.h b/block/blk-wbt.h index f47218d5b3b2081c81f92c40d3f4fc247f3f9242..8e4e376609710e2d6443bea904a73dac4b3dad9c 100644 --- a/block/blk-wbt.h +++ b/block/blk-wbt.h @@ -95,7 +95,6 @@ void wbt_enable_default(struct request_queue *); u64 wbt_get_min_lat(struct request_queue *q); void wbt_set_min_lat(struct request_queue *q, u64 val); -void wbt_set_queue_depth(struct request_queue *, unsigned int); void wbt_set_write_cache(struct request_queue *, bool); u64 wbt_default_latency_nsec(struct request_queue *); @@ -118,9 +117,6 @@ static inline void wbt_disable_default(struct request_queue *q) static inline void wbt_enable_default(struct request_queue *q) { } -static inline void wbt_set_queue_depth(struct request_queue *q, unsigned int depth) -{ -} static inline void wbt_set_write_cache(struct request_queue *q, bool wc) { } diff --git a/block/blk-zoned.c b/block/blk-zoned.c index 6c503824ba3f71def2a1165a44236fdd22651e36..4bc5f260248a6225fe83d80d407b92f5141ad4ee 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c @@ -202,6 +202,42 @@ int blkdev_report_zones(struct block_device *bdev, sector_t sector, } EXPORT_SYMBOL_GPL(blkdev_report_zones); +/* + * Special case of zone reset operation to reset all zones in one command, + * useful for applications like mkfs. + */ +static int __blkdev_reset_all_zones(struct block_device *bdev, gfp_t gfp_mask) +{ + struct bio *bio = bio_alloc(gfp_mask, 0); + int ret; + + /* across the zones operations, don't need any sectors */ + bio_set_dev(bio, bdev); + bio_set_op_attrs(bio, REQ_OP_ZONE_RESET_ALL, 0); + + ret = submit_bio_wait(bio); + bio_put(bio); + + return ret; +} + +static inline bool blkdev_allow_reset_all_zones(struct block_device *bdev, + sector_t nr_sectors) +{ + if (!blk_queue_zone_resetall(bdev_get_queue(bdev))) + return false; + + if (nr_sectors != part_nr_sects_read(bdev->bd_part)) + return false; + /* + * REQ_OP_ZONE_RESET_ALL can be executed only if the block device is + * the entire disk, that is, if the blocks device start offset is 0 and + * its capacity is the same as the entire disk. + */ + return get_start_sect(bdev) == 0 && + part_nr_sects_read(bdev->bd_part) == get_capacity(bdev->bd_disk); +} + /** * blkdev_reset_zones - Reset zones write pointer * @bdev: Target block device @@ -235,6 +271,9 @@ int blkdev_reset_zones(struct block_device *bdev, /* Out of range */ return -EINVAL; + if (blkdev_allow_reset_all_zones(bdev, nr_sectors)) + return __blkdev_reset_all_zones(bdev, gfp_mask); + /* Check alignment (handle eventual smaller last zone) */ zone_sectors = blk_queue_zone_sectors(q); if (sector & (zone_sectors - 1)) diff --git a/block/blk.h b/block/blk.h index de6b2e146d6eb64c0be5e9f0cdb80777897c179b..ed347f7a97b138e294cbd7066d7bc7a097483cea 100644 --- a/block/blk.h +++ b/block/blk.h @@ -184,11 +184,11 @@ void blk_account_io_done(struct request *req, u64 now); void blk_insert_flush(struct request *rq); -int elevator_init_mq(struct request_queue *q); +void elevator_init_mq(struct request_queue *q); int elevator_switch_mq(struct request_queue *q, struct elevator_type *new_e); void __elevator_exit(struct request_queue *, struct elevator_queue *); -int elv_register_queue(struct request_queue *q); +int elv_register_queue(struct request_queue *q, bool uevent); void elv_unregister_queue(struct request_queue *q); static inline void elevator_exit(struct request_queue *q, diff --git a/block/elevator.c b/block/elevator.c index 2f17d66d0e617e31b9b8dfb76899b2a0dbc5f8aa..bba10e83478a0902dc883e7924a6f5cb66bec83b 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -83,8 +83,26 @@ bool elv_bio_merge_ok(struct request *rq, struct bio *bio) } EXPORT_SYMBOL(elv_bio_merge_ok); -static bool elevator_match(const struct elevator_type *e, const char *name) +static inline bool elv_support_features(unsigned int elv_features, + unsigned int required_features) { + return (required_features & elv_features) == required_features; +} + +/** + * elevator_match - Test an elevator name and features + * @e: Scheduler to test + * @name: Elevator name to test + * @required_features: Features that the elevator must provide + * + * Return true is the elevator @e name matches @name and if @e provides all the + * the feratures spcified by @required_features. + */ +static bool elevator_match(const struct elevator_type *e, const char *name, + unsigned int required_features) +{ + if (!elv_support_features(e->elevator_features, required_features)) + return false; if (!strcmp(e->elevator_name, name)) return true; if (e->elevator_alias && !strcmp(e->elevator_alias, name)) @@ -93,15 +111,21 @@ static bool elevator_match(const struct elevator_type *e, const char *name) return false; } -/* - * Return scheduler with name 'name' +/** + * elevator_find - Find an elevator + * @name: Name of the elevator to find + * @required_features: Features that the elevator must provide + * + * Return the first registered scheduler with name @name and supporting the + * features @required_features and NULL otherwise. */ -static struct elevator_type *elevator_find(const char *name) +static struct elevator_type *elevator_find(const char *name, + unsigned int required_features) { struct elevator_type *e; list_for_each_entry(e, &elv_list, list) { - if (elevator_match(e, name)) + if (elevator_match(e, name, required_features)) return e; } @@ -120,12 +144,12 @@ static struct elevator_type *elevator_get(struct request_queue *q, spin_lock(&elv_list_lock); - e = elevator_find(name); + e = elevator_find(name, q->required_elevator_features); if (!e && try_loading) { spin_unlock(&elv_list_lock); request_module("%s-iosched", name); spin_lock(&elv_list_lock); - e = elevator_find(name); + e = elevator_find(name, q->required_elevator_features); } if (e && !try_module_get(e->elevator_owner)) @@ -135,20 +159,6 @@ static struct elevator_type *elevator_get(struct request_queue *q, return e; } -static char chosen_elevator[ELV_NAME_MAX]; - -static int __init elevator_setup(char *str) -{ - /* - * Be backwards-compatible with previous kernels, so users - * won't get the wrong elevator. - */ - strncpy(chosen_elevator, str, sizeof(chosen_elevator) - 1); - return 1; -} - -__setup("elevator=", elevator_setup); - static struct kobj_type elv_ktype; struct elevator_queue *elevator_alloc(struct request_queue *q, @@ -470,13 +480,16 @@ static struct kobj_type elv_ktype = { .release = elevator_release, }; -int elv_register_queue(struct request_queue *q) +/* + * elv_register_queue is called from either blk_register_queue or + * elevator_switch, elevator switch is prevented from being happen + * in the two paths, so it is safe to not hold q->sysfs_lock. + */ +int elv_register_queue(struct request_queue *q, bool uevent) { struct elevator_queue *e = q->elevator; int error; - lockdep_assert_held(&q->sysfs_lock); - error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched"); if (!error) { struct elv_fs_entry *attr = e->type->elevator_attrs; @@ -487,24 +500,34 @@ int elv_register_queue(struct request_queue *q) attr++; } } - kobject_uevent(&e->kobj, KOBJ_ADD); + if (uevent) + kobject_uevent(&e->kobj, KOBJ_ADD); + + mutex_lock(&q->sysfs_lock); e->registered = 1; + mutex_unlock(&q->sysfs_lock); } return error; } +/* + * elv_unregister_queue is called from either blk_unregister_queue or + * elevator_switch, elevator switch is prevented from being happen + * in the two paths, so it is safe to not hold q->sysfs_lock. + */ void elv_unregister_queue(struct request_queue *q) { - lockdep_assert_held(&q->sysfs_lock); - if (q) { struct elevator_queue *e = q->elevator; kobject_uevent(&e->kobj, KOBJ_REMOVE); kobject_del(&e->kobj); + + mutex_lock(&q->sysfs_lock); e->registered = 0; /* Re-enable throttling in case elevator disabled it */ wbt_enable_default(q); + mutex_unlock(&q->sysfs_lock); } } @@ -526,7 +549,7 @@ int elv_register(struct elevator_type *e) /* register, don't allow duplicate names */ spin_lock(&elv_list_lock); - if (elevator_find(e->elevator_name)) { + if (elevator_find(e->elevator_name, 0)) { spin_unlock(&elv_list_lock); kmem_cache_destroy(e->icq_cache); return -EBUSY; @@ -567,10 +590,32 @@ int elevator_switch_mq(struct request_queue *q, lockdep_assert_held(&q->sysfs_lock); if (q->elevator) { - if (q->elevator->registered) + if (q->elevator->registered) { + mutex_unlock(&q->sysfs_lock); + + /* + * Concurrent elevator switch can't happen becasue + * sysfs write is always exclusively on same file. + * + * Also the elevator queue won't be freed after + * sysfs_lock is released becasue kobject_del() in + * blk_unregister_queue() waits for completion of + * .store & .show on its attributes. + */ elv_unregister_queue(q); + + mutex_lock(&q->sysfs_lock); + } ioc_clear_queue(q); elevator_exit(q, q->elevator); + + /* + * sysfs_lock may be dropped, so re-check if queue is + * unregistered. If yes, don't switch to new elevator + * any more + */ + if (!blk_queue_registered(q)) + return 0; } ret = blk_mq_init_sched(q, new_e); @@ -578,7 +623,11 @@ int elevator_switch_mq(struct request_queue *q, goto out; if (new_e) { - ret = elv_register_queue(q); + mutex_unlock(&q->sysfs_lock); + + ret = elv_register_queue(q, true); + + mutex_lock(&q->sysfs_lock); if (ret) { elevator_exit(q, q->elevator); goto out; @@ -594,37 +643,89 @@ int elevator_switch_mq(struct request_queue *q, return ret; } +static inline bool elv_support_iosched(struct request_queue *q) +{ + if (q->tag_set && (q->tag_set->flags & BLK_MQ_F_NO_SCHED)) + return false; + return true; +} + /* - * For blk-mq devices, we default to using mq-deadline, if available, for single - * queue devices. If deadline isn't available OR we have multiple queues, - * default to "none". + * For single queue devices, default to using mq-deadline. If we have multiple + * queues or mq-deadline is not available, default to "none". */ -int elevator_init_mq(struct request_queue *q) +static struct elevator_type *elevator_get_default(struct request_queue *q) +{ + if (q->nr_hw_queues != 1) + return NULL; + + return elevator_get(q, "mq-deadline", false); +} + +/* + * Get the first elevator providing the features required by the request queue. + * Default to "none" if no matching elevator is found. + */ +static struct elevator_type *elevator_get_by_features(struct request_queue *q) +{ + struct elevator_type *e, *found = NULL; + + spin_lock(&elv_list_lock); + + list_for_each_entry(e, &elv_list, list) { + if (elv_support_features(e->elevator_features, + q->required_elevator_features)) { + found = e; + break; + } + } + + if (found && !try_module_get(found->elevator_owner)) + found = NULL; + + spin_unlock(&elv_list_lock); + return found; +} + +/* + * For a device queue that has no required features, use the default elevator + * settings. Otherwise, use the first elevator available matching the required + * features. If no suitable elevator is find or if the chosen elevator + * initialization fails, fall back to the "none" elevator (no elevator). + */ +void elevator_init_mq(struct request_queue *q) { struct elevator_type *e; - int err = 0; + int err; - if (q->nr_hw_queues != 1) - return 0; + if (!elv_support_iosched(q)) + return; + + WARN_ON_ONCE(test_bit(QUEUE_FLAG_REGISTERED, &q->queue_flags)); - /* - * q->sysfs_lock must be held to provide mutual exclusion between - * elevator_switch() and here. - */ - mutex_lock(&q->sysfs_lock); if (unlikely(q->elevator)) - goto out_unlock; + return; - e = elevator_get(q, "mq-deadline", false); + if (!q->required_elevator_features) + e = elevator_get_default(q); + else + e = elevator_get_by_features(q); if (!e) - goto out_unlock; + return; + + blk_mq_freeze_queue(q); + blk_mq_quiesce_queue(q); err = blk_mq_init_sched(q, e); - if (err) + + blk_mq_unquiesce_queue(q); + blk_mq_unfreeze_queue(q); + + if (err) { + pr_warn("\"%s\" elevator initialization failed, " + "falling back to \"none\"\n", e->elevator_name); elevator_put(e); -out_unlock: - mutex_unlock(&q->sysfs_lock); - return err; + } } @@ -660,7 +761,7 @@ static int __elevator_change(struct request_queue *q, const char *name) struct elevator_type *e; /* Make sure queue is not in the middle of being removed */ - if (!test_bit(QUEUE_FLAG_REGISTERED, &q->queue_flags)) + if (!blk_queue_registered(q)) return -ENOENT; /* @@ -677,7 +778,8 @@ static int __elevator_change(struct request_queue *q, const char *name) if (!e) return -EINVAL; - if (q->elevator && elevator_match(q->elevator->type, elevator_name)) { + if (q->elevator && + elevator_match(q->elevator->type, elevator_name, 0)) { elevator_put(e); return 0; } @@ -685,13 +787,6 @@ static int __elevator_change(struct request_queue *q, const char *name) return elevator_switch(q, e); } -static inline bool elv_support_iosched(struct request_queue *q) -{ - if (q->tag_set && (q->tag_set->flags & BLK_MQ_F_NO_SCHED)) - return false; - return true; -} - ssize_t elv_iosched_store(struct request_queue *q, const char *name, size_t count) { @@ -724,11 +819,13 @@ ssize_t elv_iosched_show(struct request_queue *q, char *name) spin_lock(&elv_list_lock); list_for_each_entry(__e, &elv_list, list) { - if (elv && elevator_match(elv, __e->elevator_name)) { + if (elv && elevator_match(elv, __e->elevator_name, 0)) { len += sprintf(name+len, "[%s] ", elv->elevator_name); continue; } - if (elv_support_iosched(q)) + if (elv_support_iosched(q) && + elevator_match(__e, __e->elevator_name, + q->required_elevator_features)) len += sprintf(name+len, "%s ", __e->elevator_name); } spin_unlock(&elv_list_lock); diff --git a/block/genhd.c b/block/genhd.c index 54f1f0d381f4d28c7b4d07d4044e4f0f7d2ddb05..26b31fcae217fd3d936ccb32c6d7847ff5654805 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -695,6 +695,15 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk, dev_t devt; int retval; + /* + * The disk queue should now be all set with enough information about + * the device for the elevator code to pick an adequate default + * elevator if one is needed, that is, for devices requesting queue + * registration. + */ + if (register_queue) + elevator_init_mq(disk->queue); + /* minors == 0 indicates to use ext devt from part0 and should * be accompanied with EXT_DEVT flag. Make sure all * parameters make sense. diff --git a/block/mq-deadline.c b/block/mq-deadline.c index 2a2a2e82832e7f298e14de491690ad0d48b85951..b490f47fd553ce7956d16d1f287558f580c57457 100644 --- a/block/mq-deadline.c +++ b/block/mq-deadline.c @@ -377,13 +377,6 @@ static struct request *__dd_dispatch_request(struct deadline_data *dd) * hardware queue, but we may return a request that is for a * different hardware queue. This is because mq-deadline has shared * state for all hardware queues, in terms of sorting, FIFOs, etc. - * - * For a zoned block device, __dd_dispatch_request() may return NULL - * if all the queued write requests are directed at zones that are already - * locked due to on-going write requests. In this case, make sure to mark - * the queue as needing a restart to ensure that the queue is run again - * and the pending writes dispatched once the target zones for the ongoing - * write requests are unlocked in dd_finish_request(). */ static struct request *dd_dispatch_request(struct blk_mq_hw_ctx *hctx) { @@ -392,9 +385,6 @@ static struct request *dd_dispatch_request(struct blk_mq_hw_ctx *hctx) spin_lock(&dd->lock); rq = __dd_dispatch_request(dd); - if (!rq && blk_queue_is_zoned(hctx->queue) && - !list_empty(&dd->fifo_list[WRITE])) - blk_mq_sched_mark_restart_hctx(hctx); spin_unlock(&dd->lock); return rq; @@ -561,6 +551,13 @@ static void dd_prepare_request(struct request *rq, struct bio *bio) * spinlock so that the zone is never unlocked while deadline_fifo_request() * or deadline_next_request() are executing. This function is called for * all requests, whether or not these requests complete successfully. + * + * For a zoned block device, __dd_dispatch_request() may have stopped + * dispatching requests if all the queued requests are write requests directed + * at zones that are already locked due to on-going write requests. To ensure + * write request dispatch progress in this case, mark the queue as needing a + * restart to ensure that the queue is run again after completion of the + * request and zones being unlocked. */ static void dd_finish_request(struct request *rq) { @@ -572,6 +569,8 @@ static void dd_finish_request(struct request *rq) spin_lock_irqsave(&dd->zone_lock, flags); blk_req_zone_write_unlock(rq); + if (!list_empty(&dd->fifo_list[WRITE])) + blk_mq_sched_mark_restart_hctx(rq->mq_hctx); spin_unlock_irqrestore(&dd->zone_lock, flags); } } @@ -795,6 +794,7 @@ static struct elevator_type mq_deadline = { .elevator_attrs = deadline_attrs, .elevator_name = "mq-deadline", .elevator_alias = "deadline", + .elevator_features = ELEVATOR_F_ZBD_SEQ_WRITE, .elevator_owner = THIS_MODULE, }; MODULE_ALIAS("mq-deadline-iosched"); diff --git a/block/opal_proto.h b/block/opal_proto.h index 466ec7be16effab6c76da65d34fec6fb47796a7f..5532412d567c0b23f8330cc1e61d84dd37c8d83c 100644 --- a/block/opal_proto.h +++ b/block/opal_proto.h @@ -119,8 +119,6 @@ enum opal_uid { OPAL_UID_HEXFF, }; -#define OPAL_METHOD_LENGTH 8 - /* Enum for indexing the OPALMETHOD array */ enum opal_method { OPAL_PROPERTIES, @@ -167,7 +165,6 @@ enum opal_token { OPAL_TABLE_LASTID = 0x0A, OPAL_TABLE_MIN = 0x0B, OPAL_TABLE_MAX = 0x0C, - /* authority table */ OPAL_PIN = 0x03, /* locking tokens */ @@ -182,7 +179,7 @@ enum opal_token { OPAL_LIFECYCLE = 0x06, /* locking info table */ OPAL_MAXRANGES = 0x04, - /* mbr control */ + /* mbr control */ OPAL_MBRENABLE = 0x01, OPAL_MBRDONE = 0x02, /* properties */ diff --git a/block/sed-opal.c b/block/sed-opal.c index 7e1a444a25b2372967ad0aac0bb3a3a2d44238dd..4e95a9792162582d5a4c7bd4fc48f95a5135fcec 100644 --- a/block/sed-opal.c +++ b/block/sed-opal.c @@ -129,7 +129,6 @@ static const u8 opaluid[][OPAL_UID_LENGTH] = { { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 }, /* tables */ - [OPAL_TABLE_TABLE] { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01 }, [OPAL_LOCKINGRANGE_GLOBAL] = @@ -152,7 +151,6 @@ static const u8 opaluid[][OPAL_UID_LENGTH] = { { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 }, /* C_PIN_TABLE object ID's */ - [OPAL_C_PIN_MSID] = { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02}, [OPAL_C_PIN_SID] = @@ -161,7 +159,6 @@ static const u8 opaluid[][OPAL_UID_LENGTH] = { { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01}, /* half UID's (only first 4 bytes used) */ - [OPAL_HALF_UID_AUTHORITY_OBJ_REF] = { 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff }, [OPAL_HALF_UID_BOOLEAN_ACE] = @@ -517,6 +514,7 @@ static int opal_discovery0(struct opal_dev *dev, void *data) ret = opal_recv_cmd(dev); if (ret) return ret; + return opal_discovery0_end(dev); } @@ -525,6 +523,7 @@ static int opal_discovery0_step(struct opal_dev *dev) const struct opal_step discovery0_step = { opal_discovery0, }; + return execute_step(dev, &discovery0_step, 0); } @@ -551,6 +550,7 @@ static void add_token_u8(int *err, struct opal_dev *cmd, u8 tok) { if (!can_add(err, cmd, 1)) return; + cmd->cmd[cmd->pos++] = tok; } @@ -577,6 +577,7 @@ static void add_medium_atom_header(struct opal_dev *cmd, bool bytestring, header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0; header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0; header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK; + cmd->cmd[cmd->pos++] = header0; cmd->cmd[cmd->pos++] = len; } @@ -649,6 +650,7 @@ static int build_locking_range(u8 *buffer, size_t length, u8 lr) if (lr == 0) return 0; + buffer[5] = LOCKING_RANGE_NON_GLOBAL; buffer[7] = lr; @@ -903,10 +905,6 @@ static int response_parse(const u8 *buf, size_t length, num_entries++; } - if (num_entries == 0) { - pr_debug("Couldn't parse response.\n"); - return -EINVAL; - } resp->num = num_entries; return 0; @@ -945,6 +943,7 @@ static size_t response_get_string(const struct parsed_resp *resp, int n, } *store = tok->pos + skip; + return tok->len - skip; } @@ -1062,6 +1061,7 @@ static int start_opal_session_cont(struct opal_dev *dev) dev->hsn = hsn; dev->tsn = tsn; + return 0; } @@ -1084,6 +1084,7 @@ static int end_session_cont(struct opal_dev *dev) { dev->hsn = 0; dev->tsn = 0; + return parse_and_check_status(dev); } @@ -1172,6 +1173,7 @@ static int gen_key(struct opal_dev *dev, void *data) return err; } + return finalize_and_send(dev, parse_and_check_status); } @@ -1184,12 +1186,14 @@ static int get_active_key_cont(struct opal_dev *dev) error = parse_and_check_status(dev); if (error) return error; + keylen = response_get_string(&dev->parsed, 4, &activekey); if (!activekey) { pr_debug("%s: Couldn't extract the Activekey from the response\n", __func__); return OPAL_INVAL_PARAM; } + dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL); if (!dev->prev_data) @@ -1251,6 +1255,7 @@ static int generic_lr_enable_disable(struct opal_dev *dev, add_token_u8(&err, dev, OPAL_ENDLIST); add_token_u8(&err, dev, OPAL_ENDNAME); + return err; } @@ -1263,6 +1268,7 @@ static inline int enable_global_lr(struct opal_dev *dev, u8 *uid, 0, 0); if (err) pr_debug("Failed to create enable global lr command\n"); + return err; } @@ -1313,7 +1319,6 @@ static int setup_locking_range(struct opal_dev *dev, void *data) if (err) { pr_debug("Error building Setup Locking range command.\n"); return err; - } return finalize_and_send(dev, parse_and_check_status); @@ -1393,6 +1398,7 @@ static int start_SIDASP_opal_session(struct opal_dev *dev, void *data) kfree(key); dev->prev_data = NULL; } + return ret; } @@ -1518,6 +1524,7 @@ static int erase_locking_range(struct opal_dev *dev, void *data) pr_debug("Error building Erase Locking Range Command.\n"); return err; } + return finalize_and_send(dev, parse_and_check_status); } @@ -1636,6 +1643,7 @@ static int write_shadow_mbr(struct opal_dev *dev, void *data) off += len; } + return err; } @@ -1816,6 +1824,7 @@ static int lock_unlock_locking_range(struct opal_dev *dev, void *data) pr_debug("Error building SET command.\n"); return err; } + return finalize_and_send(dev, parse_and_check_status); } @@ -1857,6 +1866,7 @@ static int lock_unlock_locking_range_sum(struct opal_dev *dev, void *data) pr_debug("Error building SET command.\n"); return ret; } + return finalize_and_send(dev, parse_and_check_status); } @@ -1957,6 +1967,7 @@ static int end_opal_session(struct opal_dev *dev, void *data) if (err < 0) return err; + return finalize_and_send(dev, end_session_cont); } @@ -1965,6 +1976,7 @@ static int end_opal_session_error(struct opal_dev *dev) const struct opal_step error_end_session = { end_opal_session, }; + return execute_step(dev, &error_end_session, 0); } @@ -1984,6 +1996,7 @@ static int check_opal_support(struct opal_dev *dev) ret = opal_discovery0_step(dev); dev->supported = !ret; mutex_unlock(&dev->dev_lock); + return ret; } @@ -2004,6 +2017,7 @@ void free_opal_dev(struct opal_dev *dev) { if (!dev) return; + clean_opal_dev(dev); kfree(dev); } @@ -2026,6 +2040,7 @@ struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv) kfree(dev); return NULL; } + return dev; } EXPORT_SYMBOL(init_opal_dev); @@ -2045,6 +2060,7 @@ static int opal_secure_erase_locking_range(struct opal_dev *dev, setup_opal_dev(dev); ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps)); mutex_unlock(&dev->dev_lock); + return ret; } @@ -2062,6 +2078,7 @@ static int opal_erase_locking_range(struct opal_dev *dev, setup_opal_dev(dev); ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps)); mutex_unlock(&dev->dev_lock); + return ret; } @@ -2089,6 +2106,7 @@ static int opal_enable_disable_shadow_mbr(struct opal_dev *dev, setup_opal_dev(dev); ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps)); mutex_unlock(&dev->dev_lock); + return ret; } @@ -2113,6 +2131,7 @@ static int opal_set_mbr_done(struct opal_dev *dev, setup_opal_dev(dev); ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps)); mutex_unlock(&dev->dev_lock); + return ret; } @@ -2133,6 +2152,7 @@ static int opal_write_shadow_mbr(struct opal_dev *dev, setup_opal_dev(dev); ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps)); mutex_unlock(&dev->dev_lock); + return ret; } @@ -2151,6 +2171,7 @@ static int opal_save(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk) setup_opal_dev(dev); add_suspend_info(dev, suspend); mutex_unlock(&dev->dev_lock); + return 0; } @@ -2169,12 +2190,14 @@ static int opal_add_user_to_lr(struct opal_dev *dev, pr_debug("Locking state was not RO or RW\n"); return -EINVAL; } + if (lk_unlk->session.who < OPAL_USER1 || lk_unlk->session.who > OPAL_USER9) { pr_debug("Authority was not within the range of users: %d\n", lk_unlk->session.who); return -EINVAL; } + if (lk_unlk->session.sum) { pr_debug("%s not supported in sum. Use setup locking range\n", __func__); @@ -2185,6 +2208,7 @@ static int opal_add_user_to_lr(struct opal_dev *dev, setup_opal_dev(dev); ret = execute_steps(dev, steps, ARRAY_SIZE(steps)); mutex_unlock(&dev->dev_lock); + return ret; } @@ -2267,6 +2291,7 @@ static int opal_lock_unlock(struct opal_dev *dev, mutex_lock(&dev->dev_lock); ret = __opal_lock_unlock(dev, lk_unlk); mutex_unlock(&dev->dev_lock); + return ret; } @@ -2289,6 +2314,7 @@ static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal) setup_opal_dev(dev); ret = execute_steps(dev, owner_steps, ARRAY_SIZE(owner_steps)); mutex_unlock(&dev->dev_lock); + return ret; } @@ -2310,6 +2336,7 @@ static int opal_activate_lsp(struct opal_dev *dev, setup_opal_dev(dev); ret = execute_steps(dev, active_steps, ARRAY_SIZE(active_steps)); mutex_unlock(&dev->dev_lock); + return ret; } @@ -2327,6 +2354,7 @@ static int opal_setup_locking_range(struct opal_dev *dev, setup_opal_dev(dev); ret = execute_steps(dev, lr_steps, ARRAY_SIZE(lr_steps)); mutex_unlock(&dev->dev_lock); + return ret; } @@ -2347,6 +2375,7 @@ static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw) setup_opal_dev(dev); ret = execute_steps(dev, pw_steps, ARRAY_SIZE(pw_steps)); mutex_unlock(&dev->dev_lock); + return ret; } @@ -2371,6 +2400,7 @@ static int opal_activate_user(struct opal_dev *dev, setup_opal_dev(dev); ret = execute_steps(dev, act_steps, ARRAY_SIZE(act_steps)); mutex_unlock(&dev->dev_lock); + return ret; } @@ -2382,6 +2412,7 @@ bool opal_unlock_from_suspend(struct opal_dev *dev) if (!dev) return false; + if (!dev->supported) return false; @@ -2399,6 +2430,7 @@ bool opal_unlock_from_suspend(struct opal_dev *dev) suspend->unlk.session.sum); was_failure = true; } + if (dev->mbr_enabled) { ret = __opal_set_mbr_done(dev, &suspend->unlk.session.opal_key); if (ret) @@ -2406,6 +2438,7 @@ bool opal_unlock_from_suspend(struct opal_dev *dev) } } mutex_unlock(&dev->dev_lock); + return was_failure; } EXPORT_SYMBOL(opal_unlock_from_suspend); diff --git a/crypto/Kconfig b/crypto/Kconfig index e801450bcb1cf01de295d83dfeb9389525bb34cc..ad86463de715fece52e108748630d7a3447f3380 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -306,19 +306,10 @@ config CRYPTO_AEGIS128 help Support for the AEGIS-128 dedicated AEAD algorithm. -config CRYPTO_AEGIS128L - tristate "AEGIS-128L AEAD algorithm" - select CRYPTO_AEAD - select CRYPTO_AES # for AES S-box tables - help - Support for the AEGIS-128L dedicated AEAD algorithm. - -config CRYPTO_AEGIS256 - tristate "AEGIS-256 AEAD algorithm" - select CRYPTO_AEAD - select CRYPTO_AES # for AES S-box tables - help - Support for the AEGIS-256 dedicated AEAD algorithm. +config CRYPTO_AEGIS128_SIMD + bool "Support SIMD acceleration for AEGIS-128" + depends on CRYPTO_AEGIS128 && ((ARM || ARM64) && KERNEL_MODE_NEON) + default y config CRYPTO_AEGIS128_AESNI_SSE2 tristate "AEGIS-128 AEAD algorithm (x86_64 AESNI+SSE2 implementation)" @@ -328,78 +319,6 @@ config CRYPTO_AEGIS128_AESNI_SSE2 help AESNI+SSE2 implementation of the AEGIS-128 dedicated AEAD algorithm. -config CRYPTO_AEGIS128L_AESNI_SSE2 - tristate "AEGIS-128L AEAD algorithm (x86_64 AESNI+SSE2 implementation)" - depends on X86 && 64BIT - select CRYPTO_AEAD - select CRYPTO_SIMD - help - AESNI+SSE2 implementation of the AEGIS-128L dedicated AEAD algorithm. - -config CRYPTO_AEGIS256_AESNI_SSE2 - tristate "AEGIS-256 AEAD algorithm (x86_64 AESNI+SSE2 implementation)" - depends on X86 && 64BIT - select CRYPTO_AEAD - select CRYPTO_SIMD - help - AESNI+SSE2 implementation of the AEGIS-256 dedicated AEAD algorithm. - -config CRYPTO_MORUS640 - tristate "MORUS-640 AEAD algorithm" - select CRYPTO_AEAD - help - Support for the MORUS-640 dedicated AEAD algorithm. - -config CRYPTO_MORUS640_GLUE - tristate - depends on X86 - select CRYPTO_AEAD - select CRYPTO_SIMD - help - Common glue for SIMD optimizations of the MORUS-640 dedicated AEAD - algorithm. - -config CRYPTO_MORUS640_SSE2 - tristate "MORUS-640 AEAD algorithm (x86_64 SSE2 implementation)" - depends on X86 && 64BIT - select CRYPTO_AEAD - select CRYPTO_MORUS640_GLUE - help - SSE2 implementation of the MORUS-640 dedicated AEAD algorithm. - -config CRYPTO_MORUS1280 - tristate "MORUS-1280 AEAD algorithm" - select CRYPTO_AEAD - help - Support for the MORUS-1280 dedicated AEAD algorithm. - -config CRYPTO_MORUS1280_GLUE - tristate - depends on X86 - select CRYPTO_AEAD - select CRYPTO_SIMD - help - Common glue for SIMD optimizations of the MORUS-1280 dedicated AEAD - algorithm. - -config CRYPTO_MORUS1280_SSE2 - tristate "MORUS-1280 AEAD algorithm (x86_64 SSE2 implementation)" - depends on X86 && 64BIT - select CRYPTO_AEAD - select CRYPTO_MORUS1280_GLUE - help - SSE2 optimizedimplementation of the MORUS-1280 dedicated AEAD - algorithm. - -config CRYPTO_MORUS1280_AVX2 - tristate "MORUS-1280 AEAD algorithm (x86_64 AVX2 implementation)" - depends on X86 && 64BIT - select CRYPTO_AEAD - select CRYPTO_MORUS1280_GLUE - help - AVX2 optimized implementation of the MORUS-1280 dedicated AEAD - algorithm. - config CRYPTO_SEQIV tristate "Sequence Number IV Generator" select CRYPTO_AEAD @@ -728,11 +647,12 @@ config CRYPTO_VPMSUM_TESTER Unless you are testing these algorithms, you don't need this. config CRYPTO_GHASH - tristate "GHASH digest algorithm" + tristate "GHASH hash function" select CRYPTO_GF128MUL select CRYPTO_HASH help - GHASH is message digest algorithm for GCM (Galois/Counter Mode). + GHASH is the hash function used in GCM (Galois/Counter Mode). + It is not a general-purpose cryptographic hash function. config CRYPTO_POLY1305 tristate "Poly1305 authenticator algorithm" @@ -929,9 +849,13 @@ config CRYPTO_SHA1_PPC_SPE SHA-1 secure hash standard (DFIPS 180-4) implemented using powerpc SPE SIMD instruction set. +config CRYPTO_LIB_SHA256 + tristate + config CRYPTO_SHA256 tristate "SHA224 and SHA256 digest algorithm" select CRYPTO_HASH + select CRYPTO_LIB_SHA256 help SHA256 secure hash standard (DFIPS 180-2). @@ -1057,18 +981,22 @@ config CRYPTO_WP512 config CRYPTO_GHASH_CLMUL_NI_INTEL - tristate "GHASH digest algorithm (CLMUL-NI accelerated)" + tristate "GHASH hash function (CLMUL-NI accelerated)" depends on X86 && 64BIT select CRYPTO_CRYPTD help - GHASH is message digest algorithm for GCM (Galois/Counter Mode). - The implementation is accelerated by CLMUL-NI of Intel. + This is the x86_64 CLMUL-NI accelerated implementation of + GHASH, the hash function used in GCM (Galois/Counter mode). comment "Ciphers" +config CRYPTO_LIB_AES + tristate + config CRYPTO_AES tristate "AES cipher algorithms" select CRYPTO_ALGAPI + select CRYPTO_LIB_AES help AES cipher algorithms (FIPS-197). AES uses the Rijndael algorithm. @@ -1089,6 +1017,7 @@ config CRYPTO_AES config CRYPTO_AES_TI tristate "Fixed time AES cipher" select CRYPTO_ALGAPI + select CRYPTO_LIB_AES help This is a generic implementation of AES that attempts to eliminate data dependent latencies as much as possible without affecting @@ -1104,56 +1033,11 @@ config CRYPTO_AES_TI block. Interrupts are also disabled to avoid races where cachelines are evicted when the CPU is interrupted to do something else. -config CRYPTO_AES_586 - tristate "AES cipher algorithms (i586)" - depends on (X86 || UML_X86) && !64BIT - select CRYPTO_ALGAPI - select CRYPTO_AES - help - AES cipher algorithms (FIPS-197). AES uses the Rijndael - algorithm. - - Rijndael appears to be consistently a very good performer in - both hardware and software across a wide range of computing - environments regardless of its use in feedback or non-feedback - modes. Its key setup time is excellent, and its key agility is - good. Rijndael's very low memory requirements make it very well - suited for restricted-space environments, in which it also - demonstrates excellent performance. Rijndael's operations are - among the easiest to defend against power and timing attacks. - - The AES specifies three key sizes: 128, 192 and 256 bits - - See for more information. - -config CRYPTO_AES_X86_64 - tristate "AES cipher algorithms (x86_64)" - depends on (X86 || UML_X86) && 64BIT - select CRYPTO_ALGAPI - select CRYPTO_AES - help - AES cipher algorithms (FIPS-197). AES uses the Rijndael - algorithm. - - Rijndael appears to be consistently a very good performer in - both hardware and software across a wide range of computing - environments regardless of its use in feedback or non-feedback - modes. Its key setup time is excellent, and its key agility is - good. Rijndael's very low memory requirements make it very well - suited for restricted-space environments, in which it also - demonstrates excellent performance. Rijndael's operations are - among the easiest to defend against power and timing attacks. - - The AES specifies three key sizes: 128, 192 and 256 bits - - See for more information. - config CRYPTO_AES_NI_INTEL tristate "AES cipher algorithms (AES-NI)" depends on X86 select CRYPTO_AEAD - select CRYPTO_AES_X86_64 if 64BIT - select CRYPTO_AES_586 if !64BIT + select CRYPTO_LIB_AES select CRYPTO_ALGAPI select CRYPTO_BLKCIPHER select CRYPTO_GLUE_HELPER_X86 if 64BIT @@ -1426,9 +1310,13 @@ config CRYPTO_CAST6_AVX_X86_64 This module provides the Cast6 cipher algorithm that processes eight blocks parallel using the AVX instruction set. +config CRYPTO_LIB_DES + tristate + config CRYPTO_DES tristate "DES and Triple DES EDE cipher algorithms" select CRYPTO_ALGAPI + select CRYPTO_LIB_DES help DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). @@ -1436,7 +1324,7 @@ config CRYPTO_DES_SPARC64 tristate "DES and Triple DES EDE cipher algorithms (SPARC64)" depends on SPARC64 select CRYPTO_ALGAPI - select CRYPTO_DES + select CRYPTO_LIB_DES help DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3), optimized using SPARC64 crypto opcodes. @@ -1445,7 +1333,7 @@ config CRYPTO_DES3_EDE_X86_64 tristate "Triple DES EDE cipher algorithm (x86-64)" depends on X86 && 64BIT select CRYPTO_BLKCIPHER - select CRYPTO_DES + select CRYPTO_LIB_DES help Triple DES EDE (FIPS 46-3) algorithm. diff --git a/crypto/Makefile b/crypto/Makefile index 9479e1a45d8cce0aba911a630910affc270f379c..0d2cdd523fd982cf532451d07ff32e7a3d6e9802 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -90,10 +90,26 @@ obj-$(CONFIG_CRYPTO_GCM) += gcm.o obj-$(CONFIG_CRYPTO_CCM) += ccm.o obj-$(CONFIG_CRYPTO_CHACHA20POLY1305) += chacha20poly1305.o obj-$(CONFIG_CRYPTO_AEGIS128) += aegis128.o -obj-$(CONFIG_CRYPTO_AEGIS128L) += aegis128l.o -obj-$(CONFIG_CRYPTO_AEGIS256) += aegis256.o -obj-$(CONFIG_CRYPTO_MORUS640) += morus640.o -obj-$(CONFIG_CRYPTO_MORUS1280) += morus1280.o +aegis128-y := aegis128-core.o + +ifeq ($(ARCH),arm) +CFLAGS_aegis128-neon-inner.o += -ffreestanding -march=armv7-a -mfloat-abi=softfp +CFLAGS_aegis128-neon-inner.o += -mfpu=crypto-neon-fp-armv8 +aegis128-$(CONFIG_CRYPTO_AEGIS128_SIMD) += aegis128-neon.o aegis128-neon-inner.o +endif +ifeq ($(ARCH),arm64) +aegis128-cflags-y := -ffreestanding -mcpu=generic+crypto +aegis128-cflags-$(CONFIG_CC_IS_GCC) += -ffixed-q16 -ffixed-q17 -ffixed-q18 \ + -ffixed-q19 -ffixed-q20 -ffixed-q21 \ + -ffixed-q22 -ffixed-q23 -ffixed-q24 \ + -ffixed-q25 -ffixed-q26 -ffixed-q27 \ + -ffixed-q28 -ffixed-q29 -ffixed-q30 \ + -ffixed-q31 +CFLAGS_aegis128-neon-inner.o += $(aegis128-cflags-y) +CFLAGS_REMOVE_aegis128-neon-inner.o += -mgeneral-regs-only +aegis128-$(CONFIG_CRYPTO_AEGIS128_SIMD) += aegis128-neon.o aegis128-neon-inner.o +endif + obj-$(CONFIG_CRYPTO_PCRYPT) += pcrypt.o obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o obj-$(CONFIG_CRYPTO_DES) += des_generic.o @@ -136,6 +152,8 @@ obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o obj-$(CONFIG_CRYPTO_DRBG) += drbg.o obj-$(CONFIG_CRYPTO_JITTERENTROPY) += jitterentropy_rng.o CFLAGS_jitterentropy.o = -O0 +KASAN_SANITIZE_jitterentropy.o = n +UBSAN_SANITIZE_jitterentropy.o = n jitterentropy_rng-y := jitterentropy.o jitterentropy-kcapi.o obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o obj-$(CONFIG_CRYPTO_GHASH) += ghash-generic.o diff --git a/crypto/aead.c b/crypto/aead.c index fbf0ec93bc8e1ea343ea19ab276a2f112df9c336..ce035589cf577b962423de8181d3520daf260818 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -70,7 +70,8 @@ int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) { int err; - if (authsize > crypto_aead_maxauthsize(tfm)) + if ((!authsize && crypto_aead_maxauthsize(tfm)) || + authsize > crypto_aead_maxauthsize(tfm)) return -EINVAL; if (crypto_aead_alg(tfm)->setauthsize) { diff --git a/crypto/aegis.h b/crypto/aegis.h index 41a3090cda8ee069cb4b8cd315871e38fe7cc3be..6920ebe7767953c53261960f5e203aa8422c9359 100644 --- a/crypto/aegis.h +++ b/crypto/aegis.h @@ -10,6 +10,7 @@ #define _CRYPTO_AEGIS_H #include +#include #include #define AEGIS_BLOCK_SIZE 16 @@ -23,46 +24,32 @@ union aegis_block { #define AEGIS_BLOCK_ALIGN (__alignof__(union aegis_block)) #define AEGIS_ALIGNED(p) IS_ALIGNED((uintptr_t)p, AEGIS_BLOCK_ALIGN) -static const union aegis_block crypto_aegis_const[2] = { - { .words64 = { - cpu_to_le64(U64_C(0x0d08050302010100)), - cpu_to_le64(U64_C(0x6279e99059372215)), - } }, - { .words64 = { - cpu_to_le64(U64_C(0xf12fc26d55183ddb)), - cpu_to_le64(U64_C(0xdd28b57342311120)), - } }, -}; - -static void crypto_aegis_block_xor(union aegis_block *dst, - const union aegis_block *src) +static __always_inline void crypto_aegis_block_xor(union aegis_block *dst, + const union aegis_block *src) { dst->words64[0] ^= src->words64[0]; dst->words64[1] ^= src->words64[1]; } -static void crypto_aegis_block_and(union aegis_block *dst, - const union aegis_block *src) +static __always_inline void crypto_aegis_block_and(union aegis_block *dst, + const union aegis_block *src) { dst->words64[0] &= src->words64[0]; dst->words64[1] &= src->words64[1]; } -static void crypto_aegis_aesenc(union aegis_block *dst, - const union aegis_block *src, - const union aegis_block *key) +static __always_inline void crypto_aegis_aesenc(union aegis_block *dst, + const union aegis_block *src, + const union aegis_block *key) { const u8 *s = src->bytes; - const u32 *t0 = crypto_ft_tab[0]; - const u32 *t1 = crypto_ft_tab[1]; - const u32 *t2 = crypto_ft_tab[2]; - const u32 *t3 = crypto_ft_tab[3]; + const u32 *t = crypto_ft_tab[0]; u32 d0, d1, d2, d3; - d0 = t0[s[ 0]] ^ t1[s[ 5]] ^ t2[s[10]] ^ t3[s[15]]; - d1 = t0[s[ 4]] ^ t1[s[ 9]] ^ t2[s[14]] ^ t3[s[ 3]]; - d2 = t0[s[ 8]] ^ t1[s[13]] ^ t2[s[ 2]] ^ t3[s[ 7]]; - d3 = t0[s[12]] ^ t1[s[ 1]] ^ t2[s[ 6]] ^ t3[s[11]]; + d0 = t[s[ 0]] ^ rol32(t[s[ 5]], 8) ^ rol32(t[s[10]], 16) ^ rol32(t[s[15]], 24); + d1 = t[s[ 4]] ^ rol32(t[s[ 9]], 8) ^ rol32(t[s[14]], 16) ^ rol32(t[s[ 3]], 24); + d2 = t[s[ 8]] ^ rol32(t[s[13]], 8) ^ rol32(t[s[ 2]], 16) ^ rol32(t[s[ 7]], 24); + d3 = t[s[12]] ^ rol32(t[s[ 1]], 8) ^ rol32(t[s[ 6]], 16) ^ rol32(t[s[11]], 24); dst->words32[0] = cpu_to_le32(d0) ^ key->words32[0]; dst->words32[1] = cpu_to_le32(d1) ^ key->words32[1]; diff --git a/crypto/aegis128.c b/crypto/aegis128-core.c similarity index 87% rename from crypto/aegis128.c rename to crypto/aegis128-core.c index d78f77fc5dd18f8474c537eddc727230c40268ce..80e73611bd5cdfd09b8f1b6ef2f8d80e1dda5a17 100644 --- a/crypto/aegis128.c +++ b/crypto/aegis128-core.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -16,6 +17,8 @@ #include #include +#include + #include "aegis.h" #define AEGIS128_NONCE_SIZE 16 @@ -40,6 +43,35 @@ struct aegis128_ops { const u8 *src, unsigned int size); }; +static bool have_simd; + +static const union aegis_block crypto_aegis_const[2] = { + { .words64 = { + cpu_to_le64(U64_C(0x0d08050302010100)), + cpu_to_le64(U64_C(0x6279e99059372215)), + } }, + { .words64 = { + cpu_to_le64(U64_C(0xf12fc26d55183ddb)), + cpu_to_le64(U64_C(0xdd28b57342311120)), + } }, +}; + +static bool aegis128_do_simd(void) +{ +#ifdef CONFIG_CRYPTO_AEGIS128_SIMD + if (have_simd) + return crypto_simd_usable(); +#endif + return false; +} + +bool crypto_aegis128_have_simd(void); +void crypto_aegis128_update_simd(struct aegis_state *state, const void *msg); +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); + static void crypto_aegis128_update(struct aegis_state *state) { union aegis_block tmp; @@ -55,12 +87,22 @@ static void crypto_aegis128_update(struct aegis_state *state) static void crypto_aegis128_update_a(struct aegis_state *state, const union aegis_block *msg) { + if (aegis128_do_simd()) { + crypto_aegis128_update_simd(state, msg); + return; + } + crypto_aegis128_update(state); crypto_aegis_block_xor(&state->blocks[0], msg); } static void crypto_aegis128_update_u(struct aegis_state *state, const void *msg) { + if (aegis128_do_simd()) { + crypto_aegis128_update_simd(state, msg); + return; + } + crypto_aegis128_update(state); crypto_xor(state->blocks[0].bytes, msg, AEGIS_BLOCK_SIZE); } @@ -365,7 +407,7 @@ static void crypto_aegis128_crypt(struct aead_request *req, static int crypto_aegis128_encrypt(struct aead_request *req) { - static const struct aegis128_ops ops = { + const struct aegis128_ops *ops = &(struct aegis128_ops){ .skcipher_walk_init = skcipher_walk_aead_encrypt, .crypt_chunk = crypto_aegis128_encrypt_chunk, }; @@ -375,7 +417,12 @@ static int crypto_aegis128_encrypt(struct aead_request *req) unsigned int authsize = crypto_aead_authsize(tfm); unsigned int cryptlen = req->cryptlen; - crypto_aegis128_crypt(req, &tag, cryptlen, &ops); + if (aegis128_do_simd()) + ops = &(struct aegis128_ops){ + .skcipher_walk_init = skcipher_walk_aead_encrypt, + .crypt_chunk = crypto_aegis128_encrypt_chunk_simd }; + + crypto_aegis128_crypt(req, &tag, cryptlen, ops); scatterwalk_map_and_copy(tag.bytes, req->dst, req->assoclen + cryptlen, authsize, 1); @@ -384,7 +431,7 @@ static int crypto_aegis128_encrypt(struct aead_request *req) static int crypto_aegis128_decrypt(struct aead_request *req) { - static const struct aegis128_ops ops = { + const struct aegis128_ops *ops = &(struct aegis128_ops){ .skcipher_walk_init = skcipher_walk_aead_decrypt, .crypt_chunk = crypto_aegis128_decrypt_chunk, }; @@ -398,18 +445,14 @@ static int crypto_aegis128_decrypt(struct aead_request *req) scatterwalk_map_and_copy(tag.bytes, req->src, req->assoclen + cryptlen, authsize, 0); - crypto_aegis128_crypt(req, &tag, cryptlen, &ops); + if (aegis128_do_simd()) + ops = &(struct aegis128_ops){ + .skcipher_walk_init = skcipher_walk_aead_decrypt, + .crypt_chunk = crypto_aegis128_decrypt_chunk_simd }; - return crypto_memneq(tag.bytes, zeros, authsize) ? -EBADMSG : 0; -} - -static int crypto_aegis128_init_tfm(struct crypto_aead *tfm) -{ - return 0; -} + crypto_aegis128_crypt(req, &tag, cryptlen, ops); -static void crypto_aegis128_exit_tfm(struct crypto_aead *tfm) -{ + return crypto_memneq(tag.bytes, zeros, authsize) ? -EBADMSG : 0; } static struct aead_alg crypto_aegis128_alg = { @@ -417,8 +460,6 @@ static struct aead_alg crypto_aegis128_alg = { .setauthsize = crypto_aegis128_setauthsize, .encrypt = crypto_aegis128_encrypt, .decrypt = crypto_aegis128_decrypt, - .init = crypto_aegis128_init_tfm, - .exit = crypto_aegis128_exit_tfm, .ivsize = AEGIS128_NONCE_SIZE, .maxauthsize = AEGIS128_MAX_AUTH_SIZE, @@ -440,6 +481,9 @@ static struct aead_alg crypto_aegis128_alg = { static int __init crypto_aegis128_module_init(void) { + if (IS_ENABLED(CONFIG_CRYPTO_AEGIS128_SIMD)) + have_simd = crypto_aegis128_have_simd(); + return crypto_register_aead(&crypto_aegis128_alg); } diff --git a/crypto/aegis128-neon-inner.c b/crypto/aegis128-neon-inner.c new file mode 100644 index 0000000000000000000000000000000000000000..f05310ca22aa8bee8403355edeb72e4afcafb8a3 --- /dev/null +++ b/crypto/aegis128-neon-inner.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2019 Linaro, Ltd. + */ + +#ifdef CONFIG_ARM64 +#include + +#define AES_ROUND "aese %0.16b, %1.16b \n\t aesmc %0.16b, %0.16b" +#else +#include + +#define AES_ROUND "aese.8 %q0, %q1 \n\t aesmc.8 %q0, %q0" +#endif + +#define AEGIS_BLOCK_SIZE 16 + +#include + +extern int aegis128_have_aes_insn; + +void *memcpy(void *dest, const void *src, size_t n); +void *memset(void *s, int c, size_t n); + +struct aegis128_state { + uint8x16_t v[5]; +}; + +extern const uint8_t crypto_aes_sbox[]; + +static struct aegis128_state aegis128_load_state_neon(const void *state) +{ + return (struct aegis128_state){ { + vld1q_u8(state), + vld1q_u8(state + 16), + vld1q_u8(state + 32), + vld1q_u8(state + 48), + vld1q_u8(state + 64) + } }; +} + +static void aegis128_save_state_neon(struct aegis128_state st, void *state) +{ + vst1q_u8(state, st.v[0]); + vst1q_u8(state + 16, st.v[1]); + vst1q_u8(state + 32, st.v[2]); + vst1q_u8(state + 48, st.v[3]); + vst1q_u8(state + 64, st.v[4]); +} + +static inline __attribute__((always_inline)) +uint8x16_t aegis_aes_round(uint8x16_t w) +{ + uint8x16_t z = {}; + +#ifdef CONFIG_ARM64 + if (!__builtin_expect(aegis128_have_aes_insn, 1)) { + static const uint8_t shift_rows[] = { + 0x0, 0x5, 0xa, 0xf, 0x4, 0x9, 0xe, 0x3, + 0x8, 0xd, 0x2, 0x7, 0xc, 0x1, 0x6, 0xb, + }; + static const uint8_t ror32by8[] = { + 0x1, 0x2, 0x3, 0x0, 0x5, 0x6, 0x7, 0x4, + 0x9, 0xa, 0xb, 0x8, 0xd, 0xe, 0xf, 0xc, + }; + uint8x16_t v; + + // shift rows + w = vqtbl1q_u8(w, vld1q_u8(shift_rows)); + + // sub bytes +#ifndef CONFIG_CC_IS_GCC + v = vqtbl4q_u8(vld1q_u8_x4(crypto_aes_sbox), w); + v = vqtbx4q_u8(v, vld1q_u8_x4(crypto_aes_sbox + 0x40), w - 0x40); + v = vqtbx4q_u8(v, vld1q_u8_x4(crypto_aes_sbox + 0x80), w - 0x80); + v = vqtbx4q_u8(v, vld1q_u8_x4(crypto_aes_sbox + 0xc0), w - 0xc0); +#else + asm("tbl %0.16b, {v16.16b-v19.16b}, %1.16b" : "=w"(v) : "w"(w)); + w -= 0x40; + asm("tbx %0.16b, {v20.16b-v23.16b}, %1.16b" : "+w"(v) : "w"(w)); + w -= 0x40; + asm("tbx %0.16b, {v24.16b-v27.16b}, %1.16b" : "+w"(v) : "w"(w)); + w -= 0x40; + asm("tbx %0.16b, {v28.16b-v31.16b}, %1.16b" : "+w"(v) : "w"(w)); +#endif + + // mix columns + w = (v << 1) ^ (uint8x16_t)(((int8x16_t)v >> 7) & 0x1b); + w ^= (uint8x16_t)vrev32q_u16((uint16x8_t)v); + w ^= vqtbl1q_u8(v ^ w, vld1q_u8(ror32by8)); + + return w; + } +#endif + + /* + * We use inline asm here instead of the vaeseq_u8/vaesmcq_u8 intrinsics + * to force the compiler to issue the aese/aesmc instructions in pairs. + * This is much faster on many cores, where the instruction pair can + * execute in a single cycle. + */ + asm(AES_ROUND : "+w"(w) : "w"(z)); + return w; +} + +static inline __attribute__((always_inline)) +struct aegis128_state aegis128_update_neon(struct aegis128_state st, + uint8x16_t m) +{ + m ^= aegis_aes_round(st.v[4]); + st.v[4] ^= aegis_aes_round(st.v[3]); + st.v[3] ^= aegis_aes_round(st.v[2]); + st.v[2] ^= aegis_aes_round(st.v[1]); + st.v[1] ^= aegis_aes_round(st.v[0]); + st.v[0] ^= m; + + return st; +} + +static inline __attribute__((always_inline)) +void preload_sbox(void) +{ + if (!IS_ENABLED(CONFIG_ARM64) || + !IS_ENABLED(CONFIG_CC_IS_GCC) || + __builtin_expect(aegis128_have_aes_insn, 1)) + return; + + asm("ld1 {v16.16b-v19.16b}, [%0], #64 \n\t" + "ld1 {v20.16b-v23.16b}, [%0], #64 \n\t" + "ld1 {v24.16b-v27.16b}, [%0], #64 \n\t" + "ld1 {v28.16b-v31.16b}, [%0] \n\t" + :: "r"(crypto_aes_sbox)); +} + +void crypto_aegis128_update_neon(void *state, const void *msg) +{ + struct aegis128_state st = aegis128_load_state_neon(state); + + preload_sbox(); + + st = aegis128_update_neon(st, vld1q_u8(msg)); + + aegis128_save_state_neon(st, state); +} + +void crypto_aegis128_encrypt_chunk_neon(void *state, void *dst, const void *src, + unsigned int size) +{ + struct aegis128_state st = aegis128_load_state_neon(state); + uint8x16_t msg; + + preload_sbox(); + + while (size >= AEGIS_BLOCK_SIZE) { + uint8x16_t s = st.v[1] ^ (st.v[2] & st.v[3]) ^ st.v[4]; + + msg = vld1q_u8(src); + st = aegis128_update_neon(st, msg); + vst1q_u8(dst, msg ^ s); + + size -= AEGIS_BLOCK_SIZE; + src += AEGIS_BLOCK_SIZE; + dst += AEGIS_BLOCK_SIZE; + } + + if (size > 0) { + uint8x16_t s = st.v[1] ^ (st.v[2] & st.v[3]) ^ st.v[4]; + uint8_t buf[AEGIS_BLOCK_SIZE] = {}; + + memcpy(buf, src, size); + msg = vld1q_u8(buf); + st = aegis128_update_neon(st, msg); + vst1q_u8(buf, msg ^ s); + memcpy(dst, buf, size); + } + + aegis128_save_state_neon(st, state); +} + +void crypto_aegis128_decrypt_chunk_neon(void *state, void *dst, const void *src, + unsigned int size) +{ + struct aegis128_state st = aegis128_load_state_neon(state); + uint8x16_t msg; + + preload_sbox(); + + while (size >= AEGIS_BLOCK_SIZE) { + msg = vld1q_u8(src) ^ st.v[1] ^ (st.v[2] & st.v[3]) ^ st.v[4]; + st = aegis128_update_neon(st, msg); + vst1q_u8(dst, msg); + + size -= AEGIS_BLOCK_SIZE; + src += AEGIS_BLOCK_SIZE; + dst += AEGIS_BLOCK_SIZE; + } + + if (size > 0) { + uint8x16_t s = st.v[1] ^ (st.v[2] & st.v[3]) ^ st.v[4]; + uint8_t buf[AEGIS_BLOCK_SIZE]; + + vst1q_u8(buf, s); + memcpy(buf, src, size); + msg = vld1q_u8(buf) ^ s; + vst1q_u8(buf, msg); + memcpy(dst, buf, size); + + st = aegis128_update_neon(st, msg); + } + + aegis128_save_state_neon(st, state); +} diff --git a/crypto/aegis128-neon.c b/crypto/aegis128-neon.c new file mode 100644 index 0000000000000000000000000000000000000000..751f9c195aa42a0b43916c16362e15b32497000c --- /dev/null +++ b/crypto/aegis128-neon.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2019 Linaro Ltd + */ + +#include +#include + +#include "aegis.h" + +void crypto_aegis128_update_neon(void *state, const void *msg); +void crypto_aegis128_encrypt_chunk_neon(void *state, void *dst, const void *src, + unsigned int size); +void crypto_aegis128_decrypt_chunk_neon(void *state, void *dst, const void *src, + unsigned int size); + +int aegis128_have_aes_insn __ro_after_init; + +bool crypto_aegis128_have_simd(void) +{ + if (cpu_have_feature(cpu_feature(AES))) { + aegis128_have_aes_insn = 1; + return true; + } + return IS_ENABLED(CONFIG_ARM64); +} + +void crypto_aegis128_update_simd(union aegis_block *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, + const u8 *src, unsigned int size) +{ + kernel_neon_begin(); + crypto_aegis128_encrypt_chunk_neon(state, dst, src, size); + kernel_neon_end(); +} + +void crypto_aegis128_decrypt_chunk_simd(union aegis_block *state, u8 *dst, + const u8 *src, unsigned int size) +{ + kernel_neon_begin(); + crypto_aegis128_decrypt_chunk_neon(state, dst, src, size); + kernel_neon_end(); +} diff --git a/crypto/aegis128l.c b/crypto/aegis128l.c deleted file mode 100644 index 9bca3d619a22b5be44940f7cf6343e6b495afeec..0000000000000000000000000000000000000000 --- a/crypto/aegis128l.c +++ /dev/null @@ -1,522 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * The AEGIS-128L Authenticated-Encryption Algorithm - * - * Copyright (c) 2017-2018 Ondrej Mosnacek - * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "aegis.h" - -#define AEGIS128L_CHUNK_BLOCKS 2 -#define AEGIS128L_CHUNK_SIZE (AEGIS128L_CHUNK_BLOCKS * AEGIS_BLOCK_SIZE) -#define AEGIS128L_NONCE_SIZE 16 -#define AEGIS128L_STATE_BLOCKS 8 -#define AEGIS128L_KEY_SIZE 16 -#define AEGIS128L_MIN_AUTH_SIZE 8 -#define AEGIS128L_MAX_AUTH_SIZE 16 - -union aegis_chunk { - union aegis_block blocks[AEGIS128L_CHUNK_BLOCKS]; - u8 bytes[AEGIS128L_CHUNK_SIZE]; -}; - -struct aegis_state { - union aegis_block blocks[AEGIS128L_STATE_BLOCKS]; -}; - -struct aegis_ctx { - union aegis_block key; -}; - -struct aegis128l_ops { - int (*skcipher_walk_init)(struct skcipher_walk *walk, - struct aead_request *req, bool atomic); - - void (*crypt_chunk)(struct aegis_state *state, u8 *dst, - const u8 *src, unsigned int size); -}; - -static void crypto_aegis128l_update(struct aegis_state *state) -{ - union aegis_block tmp; - unsigned int i; - - tmp = state->blocks[AEGIS128L_STATE_BLOCKS - 1]; - for (i = AEGIS128L_STATE_BLOCKS - 1; i > 0; i--) - crypto_aegis_aesenc(&state->blocks[i], &state->blocks[i - 1], - &state->blocks[i]); - crypto_aegis_aesenc(&state->blocks[0], &tmp, &state->blocks[0]); -} - -static void crypto_aegis128l_update_a(struct aegis_state *state, - const union aegis_chunk *msg) -{ - crypto_aegis128l_update(state); - crypto_aegis_block_xor(&state->blocks[0], &msg->blocks[0]); - crypto_aegis_block_xor(&state->blocks[4], &msg->blocks[1]); -} - -static void crypto_aegis128l_update_u(struct aegis_state *state, - const void *msg) -{ - crypto_aegis128l_update(state); - crypto_xor(state->blocks[0].bytes, msg + 0 * AEGIS_BLOCK_SIZE, - AEGIS_BLOCK_SIZE); - crypto_xor(state->blocks[4].bytes, msg + 1 * AEGIS_BLOCK_SIZE, - AEGIS_BLOCK_SIZE); -} - -static void crypto_aegis128l_init(struct aegis_state *state, - const union aegis_block *key, - const u8 *iv) -{ - union aegis_block key_iv; - union aegis_chunk chunk; - unsigned int i; - - memcpy(chunk.blocks[0].bytes, iv, AEGIS_BLOCK_SIZE); - chunk.blocks[1] = *key; - - key_iv = *key; - crypto_aegis_block_xor(&key_iv, &chunk.blocks[0]); - - state->blocks[0] = key_iv; - state->blocks[1] = crypto_aegis_const[1]; - state->blocks[2] = crypto_aegis_const[0]; - state->blocks[3] = crypto_aegis_const[1]; - state->blocks[4] = key_iv; - state->blocks[5] = *key; - state->blocks[6] = *key; - state->blocks[7] = *key; - - crypto_aegis_block_xor(&state->blocks[5], &crypto_aegis_const[0]); - crypto_aegis_block_xor(&state->blocks[6], &crypto_aegis_const[1]); - crypto_aegis_block_xor(&state->blocks[7], &crypto_aegis_const[0]); - - for (i = 0; i < 10; i++) { - crypto_aegis128l_update_a(state, &chunk); - } -} - -static void crypto_aegis128l_ad(struct aegis_state *state, - const u8 *src, unsigned int size) -{ - if (AEGIS_ALIGNED(src)) { - const union aegis_chunk *src_chunk = - (const union aegis_chunk *)src; - - while (size >= AEGIS128L_CHUNK_SIZE) { - crypto_aegis128l_update_a(state, src_chunk); - - size -= AEGIS128L_CHUNK_SIZE; - src_chunk += 1; - } - } else { - while (size >= AEGIS128L_CHUNK_SIZE) { - crypto_aegis128l_update_u(state, src); - - size -= AEGIS128L_CHUNK_SIZE; - src += AEGIS128L_CHUNK_SIZE; - } - } -} - -static void crypto_aegis128l_encrypt_chunk(struct aegis_state *state, u8 *dst, - const u8 *src, unsigned int size) -{ - union aegis_chunk tmp; - union aegis_block *tmp0 = &tmp.blocks[0]; - union aegis_block *tmp1 = &tmp.blocks[1]; - - if (AEGIS_ALIGNED(src) && AEGIS_ALIGNED(dst)) { - while (size >= AEGIS128L_CHUNK_SIZE) { - union aegis_chunk *dst_blk = - (union aegis_chunk *)dst; - const union aegis_chunk *src_blk = - (const union aegis_chunk *)src; - - *tmp0 = state->blocks[2]; - crypto_aegis_block_and(tmp0, &state->blocks[3]); - crypto_aegis_block_xor(tmp0, &state->blocks[6]); - crypto_aegis_block_xor(tmp0, &state->blocks[1]); - crypto_aegis_block_xor(tmp0, &src_blk->blocks[0]); - - *tmp1 = state->blocks[6]; - crypto_aegis_block_and(tmp1, &state->blocks[7]); - crypto_aegis_block_xor(tmp1, &state->blocks[5]); - crypto_aegis_block_xor(tmp1, &state->blocks[2]); - crypto_aegis_block_xor(tmp1, &src_blk->blocks[1]); - - crypto_aegis128l_update_a(state, src_blk); - - *dst_blk = tmp; - - size -= AEGIS128L_CHUNK_SIZE; - src += AEGIS128L_CHUNK_SIZE; - dst += AEGIS128L_CHUNK_SIZE; - } - } else { - while (size >= AEGIS128L_CHUNK_SIZE) { - *tmp0 = state->blocks[2]; - crypto_aegis_block_and(tmp0, &state->blocks[3]); - crypto_aegis_block_xor(tmp0, &state->blocks[6]); - crypto_aegis_block_xor(tmp0, &state->blocks[1]); - crypto_xor(tmp0->bytes, src + 0 * AEGIS_BLOCK_SIZE, - AEGIS_BLOCK_SIZE); - - *tmp1 = state->blocks[6]; - crypto_aegis_block_and(tmp1, &state->blocks[7]); - crypto_aegis_block_xor(tmp1, &state->blocks[5]); - crypto_aegis_block_xor(tmp1, &state->blocks[2]); - crypto_xor(tmp1->bytes, src + 1 * AEGIS_BLOCK_SIZE, - AEGIS_BLOCK_SIZE); - - crypto_aegis128l_update_u(state, src); - - memcpy(dst, tmp.bytes, AEGIS128L_CHUNK_SIZE); - - size -= AEGIS128L_CHUNK_SIZE; - src += AEGIS128L_CHUNK_SIZE; - dst += AEGIS128L_CHUNK_SIZE; - } - } - - if (size > 0) { - union aegis_chunk msg = {}; - memcpy(msg.bytes, src, size); - - *tmp0 = state->blocks[2]; - crypto_aegis_block_and(tmp0, &state->blocks[3]); - crypto_aegis_block_xor(tmp0, &state->blocks[6]); - crypto_aegis_block_xor(tmp0, &state->blocks[1]); - - *tmp1 = state->blocks[6]; - crypto_aegis_block_and(tmp1, &state->blocks[7]); - crypto_aegis_block_xor(tmp1, &state->blocks[5]); - crypto_aegis_block_xor(tmp1, &state->blocks[2]); - - crypto_aegis128l_update_a(state, &msg); - - crypto_aegis_block_xor(&msg.blocks[0], tmp0); - crypto_aegis_block_xor(&msg.blocks[1], tmp1); - - memcpy(dst, msg.bytes, size); - } -} - -static void crypto_aegis128l_decrypt_chunk(struct aegis_state *state, u8 *dst, - const u8 *src, unsigned int size) -{ - union aegis_chunk tmp; - union aegis_block *tmp0 = &tmp.blocks[0]; - union aegis_block *tmp1 = &tmp.blocks[1]; - - if (AEGIS_ALIGNED(src) && AEGIS_ALIGNED(dst)) { - while (size >= AEGIS128L_CHUNK_SIZE) { - union aegis_chunk *dst_blk = - (union aegis_chunk *)dst; - const union aegis_chunk *src_blk = - (const union aegis_chunk *)src; - - *tmp0 = state->blocks[2]; - crypto_aegis_block_and(tmp0, &state->blocks[3]); - crypto_aegis_block_xor(tmp0, &state->blocks[6]); - crypto_aegis_block_xor(tmp0, &state->blocks[1]); - crypto_aegis_block_xor(tmp0, &src_blk->blocks[0]); - - *tmp1 = state->blocks[6]; - crypto_aegis_block_and(tmp1, &state->blocks[7]); - crypto_aegis_block_xor(tmp1, &state->blocks[5]); - crypto_aegis_block_xor(tmp1, &state->blocks[2]); - crypto_aegis_block_xor(tmp1, &src_blk->blocks[1]); - - crypto_aegis128l_update_a(state, &tmp); - - *dst_blk = tmp; - - size -= AEGIS128L_CHUNK_SIZE; - src += AEGIS128L_CHUNK_SIZE; - dst += AEGIS128L_CHUNK_SIZE; - } - } else { - while (size >= AEGIS128L_CHUNK_SIZE) { - *tmp0 = state->blocks[2]; - crypto_aegis_block_and(tmp0, &state->blocks[3]); - crypto_aegis_block_xor(tmp0, &state->blocks[6]); - crypto_aegis_block_xor(tmp0, &state->blocks[1]); - crypto_xor(tmp0->bytes, src + 0 * AEGIS_BLOCK_SIZE, - AEGIS_BLOCK_SIZE); - - *tmp1 = state->blocks[6]; - crypto_aegis_block_and(tmp1, &state->blocks[7]); - crypto_aegis_block_xor(tmp1, &state->blocks[5]); - crypto_aegis_block_xor(tmp1, &state->blocks[2]); - crypto_xor(tmp1->bytes, src + 1 * AEGIS_BLOCK_SIZE, - AEGIS_BLOCK_SIZE); - - crypto_aegis128l_update_a(state, &tmp); - - memcpy(dst, tmp.bytes, AEGIS128L_CHUNK_SIZE); - - size -= AEGIS128L_CHUNK_SIZE; - src += AEGIS128L_CHUNK_SIZE; - dst += AEGIS128L_CHUNK_SIZE; - } - } - - if (size > 0) { - union aegis_chunk msg = {}; - memcpy(msg.bytes, src, size); - - *tmp0 = state->blocks[2]; - crypto_aegis_block_and(tmp0, &state->blocks[3]); - crypto_aegis_block_xor(tmp0, &state->blocks[6]); - crypto_aegis_block_xor(tmp0, &state->blocks[1]); - crypto_aegis_block_xor(&msg.blocks[0], tmp0); - - *tmp1 = state->blocks[6]; - crypto_aegis_block_and(tmp1, &state->blocks[7]); - crypto_aegis_block_xor(tmp1, &state->blocks[5]); - crypto_aegis_block_xor(tmp1, &state->blocks[2]); - crypto_aegis_block_xor(&msg.blocks[1], tmp1); - - memset(msg.bytes + size, 0, AEGIS128L_CHUNK_SIZE - size); - - crypto_aegis128l_update_a(state, &msg); - - memcpy(dst, msg.bytes, size); - } -} - -static void crypto_aegis128l_process_ad(struct aegis_state *state, - struct scatterlist *sg_src, - unsigned int assoclen) -{ - struct scatter_walk walk; - union aegis_chunk buf; - unsigned int pos = 0; - - scatterwalk_start(&walk, sg_src); - while (assoclen != 0) { - unsigned int size = scatterwalk_clamp(&walk, assoclen); - unsigned int left = size; - void *mapped = scatterwalk_map(&walk); - const u8 *src = (const u8 *)mapped; - - if (pos + size >= AEGIS128L_CHUNK_SIZE) { - if (pos > 0) { - unsigned int fill = AEGIS128L_CHUNK_SIZE - pos; - memcpy(buf.bytes + pos, src, fill); - crypto_aegis128l_update_a(state, &buf); - pos = 0; - left -= fill; - src += fill; - } - - crypto_aegis128l_ad(state, src, left); - src += left & ~(AEGIS128L_CHUNK_SIZE - 1); - left &= AEGIS128L_CHUNK_SIZE - 1; - } - - memcpy(buf.bytes + pos, src, left); - - pos += left; - assoclen -= size; - scatterwalk_unmap(mapped); - scatterwalk_advance(&walk, size); - scatterwalk_done(&walk, 0, assoclen); - } - - if (pos > 0) { - memset(buf.bytes + pos, 0, AEGIS128L_CHUNK_SIZE - pos); - crypto_aegis128l_update_a(state, &buf); - } -} - -static void crypto_aegis128l_process_crypt(struct aegis_state *state, - struct aead_request *req, - const struct aegis128l_ops *ops) -{ - struct skcipher_walk walk; - - ops->skcipher_walk_init(&walk, req, false); - - while (walk.nbytes) { - unsigned int nbytes = walk.nbytes; - - if (nbytes < walk.total) - nbytes = round_down(nbytes, walk.stride); - - ops->crypt_chunk(state, walk.dst.virt.addr, walk.src.virt.addr, - nbytes); - - skcipher_walk_done(&walk, walk.nbytes - nbytes); - } -} - -static void crypto_aegis128l_final(struct aegis_state *state, - union aegis_block *tag_xor, - u64 assoclen, u64 cryptlen) -{ - u64 assocbits = assoclen * 8; - u64 cryptbits = cryptlen * 8; - - union aegis_chunk tmp; - unsigned int i; - - tmp.blocks[0].words64[0] = cpu_to_le64(assocbits); - tmp.blocks[0].words64[1] = cpu_to_le64(cryptbits); - - crypto_aegis_block_xor(&tmp.blocks[0], &state->blocks[2]); - - tmp.blocks[1] = tmp.blocks[0]; - for (i = 0; i < 7; i++) - crypto_aegis128l_update_a(state, &tmp); - - for (i = 0; i < 7; i++) - crypto_aegis_block_xor(tag_xor, &state->blocks[i]); -} - -static int crypto_aegis128l_setkey(struct crypto_aead *aead, const u8 *key, - unsigned int keylen) -{ - struct aegis_ctx *ctx = crypto_aead_ctx(aead); - - if (keylen != AEGIS128L_KEY_SIZE) { - crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - memcpy(ctx->key.bytes, key, AEGIS128L_KEY_SIZE); - return 0; -} - -static int crypto_aegis128l_setauthsize(struct crypto_aead *tfm, - unsigned int authsize) -{ - if (authsize > AEGIS128L_MAX_AUTH_SIZE) - return -EINVAL; - if (authsize < AEGIS128L_MIN_AUTH_SIZE) - return -EINVAL; - return 0; -} - -static void crypto_aegis128l_crypt(struct aead_request *req, - union aegis_block *tag_xor, - unsigned int cryptlen, - const struct aegis128l_ops *ops) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct aegis_ctx *ctx = crypto_aead_ctx(tfm); - struct aegis_state state; - - crypto_aegis128l_init(&state, &ctx->key, req->iv); - crypto_aegis128l_process_ad(&state, req->src, req->assoclen); - crypto_aegis128l_process_crypt(&state, req, ops); - crypto_aegis128l_final(&state, tag_xor, req->assoclen, cryptlen); -} - -static int crypto_aegis128l_encrypt(struct aead_request *req) -{ - static const struct aegis128l_ops ops = { - .skcipher_walk_init = skcipher_walk_aead_encrypt, - .crypt_chunk = crypto_aegis128l_encrypt_chunk, - }; - - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - union aegis_block tag = {}; - unsigned int authsize = crypto_aead_authsize(tfm); - unsigned int cryptlen = req->cryptlen; - - crypto_aegis128l_crypt(req, &tag, cryptlen, &ops); - - scatterwalk_map_and_copy(tag.bytes, req->dst, req->assoclen + cryptlen, - authsize, 1); - return 0; -} - -static int crypto_aegis128l_decrypt(struct aead_request *req) -{ - static const struct aegis128l_ops ops = { - .skcipher_walk_init = skcipher_walk_aead_decrypt, - .crypt_chunk = crypto_aegis128l_decrypt_chunk, - }; - static const u8 zeros[AEGIS128L_MAX_AUTH_SIZE] = {}; - - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - union aegis_block tag; - unsigned int authsize = crypto_aead_authsize(tfm); - unsigned int cryptlen = req->cryptlen - authsize; - - scatterwalk_map_and_copy(tag.bytes, req->src, req->assoclen + cryptlen, - authsize, 0); - - crypto_aegis128l_crypt(req, &tag, cryptlen, &ops); - - return crypto_memneq(tag.bytes, zeros, authsize) ? -EBADMSG : 0; -} - -static int crypto_aegis128l_init_tfm(struct crypto_aead *tfm) -{ - return 0; -} - -static void crypto_aegis128l_exit_tfm(struct crypto_aead *tfm) -{ -} - -static struct aead_alg crypto_aegis128l_alg = { - .setkey = crypto_aegis128l_setkey, - .setauthsize = crypto_aegis128l_setauthsize, - .encrypt = crypto_aegis128l_encrypt, - .decrypt = crypto_aegis128l_decrypt, - .init = crypto_aegis128l_init_tfm, - .exit = crypto_aegis128l_exit_tfm, - - .ivsize = AEGIS128L_NONCE_SIZE, - .maxauthsize = AEGIS128L_MAX_AUTH_SIZE, - .chunksize = AEGIS128L_CHUNK_SIZE, - - .base = { - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct aegis_ctx), - .cra_alignmask = 0, - - .cra_priority = 100, - - .cra_name = "aegis128l", - .cra_driver_name = "aegis128l-generic", - - .cra_module = THIS_MODULE, - } -}; - -static int __init crypto_aegis128l_module_init(void) -{ - return crypto_register_aead(&crypto_aegis128l_alg); -} - -static void __exit crypto_aegis128l_module_exit(void) -{ - crypto_unregister_aead(&crypto_aegis128l_alg); -} - -subsys_initcall(crypto_aegis128l_module_init); -module_exit(crypto_aegis128l_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ondrej Mosnacek "); -MODULE_DESCRIPTION("AEGIS-128L AEAD algorithm"); -MODULE_ALIAS_CRYPTO("aegis128l"); -MODULE_ALIAS_CRYPTO("aegis128l-generic"); diff --git a/crypto/aegis256.c b/crypto/aegis256.c deleted file mode 100644 index b47fd39595ad71d55f7552db480fd50f49eb63fd..0000000000000000000000000000000000000000 --- a/crypto/aegis256.c +++ /dev/null @@ -1,473 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * The AEGIS-256 Authenticated-Encryption Algorithm - * - * Copyright (c) 2017-2018 Ondrej Mosnacek - * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "aegis.h" - -#define AEGIS256_NONCE_SIZE 32 -#define AEGIS256_STATE_BLOCKS 6 -#define AEGIS256_KEY_SIZE 32 -#define AEGIS256_MIN_AUTH_SIZE 8 -#define AEGIS256_MAX_AUTH_SIZE 16 - -struct aegis_state { - union aegis_block blocks[AEGIS256_STATE_BLOCKS]; -}; - -struct aegis_ctx { - union aegis_block key[AEGIS256_KEY_SIZE / AEGIS_BLOCK_SIZE]; -}; - -struct aegis256_ops { - int (*skcipher_walk_init)(struct skcipher_walk *walk, - struct aead_request *req, bool atomic); - - void (*crypt_chunk)(struct aegis_state *state, u8 *dst, - const u8 *src, unsigned int size); -}; - -static void crypto_aegis256_update(struct aegis_state *state) -{ - union aegis_block tmp; - unsigned int i; - - tmp = state->blocks[AEGIS256_STATE_BLOCKS - 1]; - for (i = AEGIS256_STATE_BLOCKS - 1; i > 0; i--) - crypto_aegis_aesenc(&state->blocks[i], &state->blocks[i - 1], - &state->blocks[i]); - crypto_aegis_aesenc(&state->blocks[0], &tmp, &state->blocks[0]); -} - -static void crypto_aegis256_update_a(struct aegis_state *state, - const union aegis_block *msg) -{ - crypto_aegis256_update(state); - crypto_aegis_block_xor(&state->blocks[0], msg); -} - -static void crypto_aegis256_update_u(struct aegis_state *state, const void *msg) -{ - crypto_aegis256_update(state); - crypto_xor(state->blocks[0].bytes, msg, AEGIS_BLOCK_SIZE); -} - -static void crypto_aegis256_init(struct aegis_state *state, - const union aegis_block *key, - const u8 *iv) -{ - union aegis_block key_iv[2]; - unsigned int i; - - key_iv[0] = key[0]; - key_iv[1] = key[1]; - crypto_xor(key_iv[0].bytes, iv + 0 * AEGIS_BLOCK_SIZE, - AEGIS_BLOCK_SIZE); - crypto_xor(key_iv[1].bytes, iv + 1 * AEGIS_BLOCK_SIZE, - AEGIS_BLOCK_SIZE); - - state->blocks[0] = key_iv[0]; - state->blocks[1] = key_iv[1]; - state->blocks[2] = crypto_aegis_const[1]; - state->blocks[3] = crypto_aegis_const[0]; - state->blocks[4] = key[0]; - state->blocks[5] = key[1]; - - crypto_aegis_block_xor(&state->blocks[4], &crypto_aegis_const[0]); - crypto_aegis_block_xor(&state->blocks[5], &crypto_aegis_const[1]); - - for (i = 0; i < 4; i++) { - crypto_aegis256_update_a(state, &key[0]); - crypto_aegis256_update_a(state, &key[1]); - crypto_aegis256_update_a(state, &key_iv[0]); - crypto_aegis256_update_a(state, &key_iv[1]); - } -} - -static void crypto_aegis256_ad(struct aegis_state *state, - const u8 *src, unsigned int size) -{ - if (AEGIS_ALIGNED(src)) { - const union aegis_block *src_blk = - (const union aegis_block *)src; - - while (size >= AEGIS_BLOCK_SIZE) { - crypto_aegis256_update_a(state, src_blk); - - size -= AEGIS_BLOCK_SIZE; - src_blk++; - } - } else { - while (size >= AEGIS_BLOCK_SIZE) { - crypto_aegis256_update_u(state, src); - - size -= AEGIS_BLOCK_SIZE; - src += AEGIS_BLOCK_SIZE; - } - } -} - -static void crypto_aegis256_encrypt_chunk(struct aegis_state *state, u8 *dst, - const u8 *src, unsigned int size) -{ - union aegis_block tmp; - - if (AEGIS_ALIGNED(src) && AEGIS_ALIGNED(dst)) { - while (size >= AEGIS_BLOCK_SIZE) { - union aegis_block *dst_blk = - (union aegis_block *)dst; - const union aegis_block *src_blk = - (const union aegis_block *)src; - - tmp = state->blocks[2]; - crypto_aegis_block_and(&tmp, &state->blocks[3]); - crypto_aegis_block_xor(&tmp, &state->blocks[5]); - crypto_aegis_block_xor(&tmp, &state->blocks[4]); - crypto_aegis_block_xor(&tmp, &state->blocks[1]); - crypto_aegis_block_xor(&tmp, src_blk); - - crypto_aegis256_update_a(state, src_blk); - - *dst_blk = tmp; - - size -= AEGIS_BLOCK_SIZE; - src += AEGIS_BLOCK_SIZE; - dst += AEGIS_BLOCK_SIZE; - } - } else { - while (size >= AEGIS_BLOCK_SIZE) { - tmp = state->blocks[2]; - crypto_aegis_block_and(&tmp, &state->blocks[3]); - crypto_aegis_block_xor(&tmp, &state->blocks[5]); - crypto_aegis_block_xor(&tmp, &state->blocks[4]); - crypto_aegis_block_xor(&tmp, &state->blocks[1]); - crypto_xor(tmp.bytes, src, AEGIS_BLOCK_SIZE); - - crypto_aegis256_update_u(state, src); - - memcpy(dst, tmp.bytes, AEGIS_BLOCK_SIZE); - - size -= AEGIS_BLOCK_SIZE; - src += AEGIS_BLOCK_SIZE; - dst += AEGIS_BLOCK_SIZE; - } - } - - if (size > 0) { - union aegis_block msg = {}; - memcpy(msg.bytes, src, size); - - tmp = state->blocks[2]; - crypto_aegis_block_and(&tmp, &state->blocks[3]); - crypto_aegis_block_xor(&tmp, &state->blocks[5]); - crypto_aegis_block_xor(&tmp, &state->blocks[4]); - crypto_aegis_block_xor(&tmp, &state->blocks[1]); - - crypto_aegis256_update_a(state, &msg); - - crypto_aegis_block_xor(&msg, &tmp); - - memcpy(dst, msg.bytes, size); - } -} - -static void crypto_aegis256_decrypt_chunk(struct aegis_state *state, u8 *dst, - const u8 *src, unsigned int size) -{ - union aegis_block tmp; - - if (AEGIS_ALIGNED(src) && AEGIS_ALIGNED(dst)) { - while (size >= AEGIS_BLOCK_SIZE) { - union aegis_block *dst_blk = - (union aegis_block *)dst; - const union aegis_block *src_blk = - (const union aegis_block *)src; - - tmp = state->blocks[2]; - crypto_aegis_block_and(&tmp, &state->blocks[3]); - crypto_aegis_block_xor(&tmp, &state->blocks[5]); - crypto_aegis_block_xor(&tmp, &state->blocks[4]); - crypto_aegis_block_xor(&tmp, &state->blocks[1]); - crypto_aegis_block_xor(&tmp, src_blk); - - crypto_aegis256_update_a(state, &tmp); - - *dst_blk = tmp; - - size -= AEGIS_BLOCK_SIZE; - src += AEGIS_BLOCK_SIZE; - dst += AEGIS_BLOCK_SIZE; - } - } else { - while (size >= AEGIS_BLOCK_SIZE) { - tmp = state->blocks[2]; - crypto_aegis_block_and(&tmp, &state->blocks[3]); - crypto_aegis_block_xor(&tmp, &state->blocks[5]); - crypto_aegis_block_xor(&tmp, &state->blocks[4]); - crypto_aegis_block_xor(&tmp, &state->blocks[1]); - crypto_xor(tmp.bytes, src, AEGIS_BLOCK_SIZE); - - crypto_aegis256_update_a(state, &tmp); - - memcpy(dst, tmp.bytes, AEGIS_BLOCK_SIZE); - - size -= AEGIS_BLOCK_SIZE; - src += AEGIS_BLOCK_SIZE; - dst += AEGIS_BLOCK_SIZE; - } - } - - if (size > 0) { - union aegis_block msg = {}; - memcpy(msg.bytes, src, size); - - tmp = state->blocks[2]; - crypto_aegis_block_and(&tmp, &state->blocks[3]); - crypto_aegis_block_xor(&tmp, &state->blocks[5]); - crypto_aegis_block_xor(&tmp, &state->blocks[4]); - crypto_aegis_block_xor(&tmp, &state->blocks[1]); - crypto_aegis_block_xor(&msg, &tmp); - - memset(msg.bytes + size, 0, AEGIS_BLOCK_SIZE - size); - - crypto_aegis256_update_a(state, &msg); - - memcpy(dst, msg.bytes, size); - } -} - -static void crypto_aegis256_process_ad(struct aegis_state *state, - struct scatterlist *sg_src, - unsigned int assoclen) -{ - struct scatter_walk walk; - union aegis_block buf; - unsigned int pos = 0; - - scatterwalk_start(&walk, sg_src); - while (assoclen != 0) { - unsigned int size = scatterwalk_clamp(&walk, assoclen); - unsigned int left = size; - void *mapped = scatterwalk_map(&walk); - const u8 *src = (const u8 *)mapped; - - if (pos + size >= AEGIS_BLOCK_SIZE) { - if (pos > 0) { - unsigned int fill = AEGIS_BLOCK_SIZE - pos; - memcpy(buf.bytes + pos, src, fill); - crypto_aegis256_update_a(state, &buf); - pos = 0; - left -= fill; - src += fill; - } - - crypto_aegis256_ad(state, src, left); - src += left & ~(AEGIS_BLOCK_SIZE - 1); - left &= AEGIS_BLOCK_SIZE - 1; - } - - memcpy(buf.bytes + pos, src, left); - - pos += left; - assoclen -= size; - scatterwalk_unmap(mapped); - scatterwalk_advance(&walk, size); - scatterwalk_done(&walk, 0, assoclen); - } - - if (pos > 0) { - memset(buf.bytes + pos, 0, AEGIS_BLOCK_SIZE - pos); - crypto_aegis256_update_a(state, &buf); - } -} - -static void crypto_aegis256_process_crypt(struct aegis_state *state, - struct aead_request *req, - const struct aegis256_ops *ops) -{ - struct skcipher_walk walk; - - ops->skcipher_walk_init(&walk, req, false); - - while (walk.nbytes) { - unsigned int nbytes = walk.nbytes; - - if (nbytes < walk.total) - nbytes = round_down(nbytes, walk.stride); - - ops->crypt_chunk(state, walk.dst.virt.addr, walk.src.virt.addr, - nbytes); - - skcipher_walk_done(&walk, walk.nbytes - nbytes); - } -} - -static void crypto_aegis256_final(struct aegis_state *state, - union aegis_block *tag_xor, - u64 assoclen, u64 cryptlen) -{ - u64 assocbits = assoclen * 8; - u64 cryptbits = cryptlen * 8; - - union aegis_block tmp; - unsigned int i; - - tmp.words64[0] = cpu_to_le64(assocbits); - tmp.words64[1] = cpu_to_le64(cryptbits); - - crypto_aegis_block_xor(&tmp, &state->blocks[3]); - - for (i = 0; i < 7; i++) - crypto_aegis256_update_a(state, &tmp); - - for (i = 0; i < AEGIS256_STATE_BLOCKS; i++) - crypto_aegis_block_xor(tag_xor, &state->blocks[i]); -} - -static int crypto_aegis256_setkey(struct crypto_aead *aead, const u8 *key, - unsigned int keylen) -{ - struct aegis_ctx *ctx = crypto_aead_ctx(aead); - - if (keylen != AEGIS256_KEY_SIZE) { - crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - memcpy(ctx->key[0].bytes, key, AEGIS_BLOCK_SIZE); - memcpy(ctx->key[1].bytes, key + AEGIS_BLOCK_SIZE, - AEGIS_BLOCK_SIZE); - return 0; -} - -static int crypto_aegis256_setauthsize(struct crypto_aead *tfm, - unsigned int authsize) -{ - if (authsize > AEGIS256_MAX_AUTH_SIZE) - return -EINVAL; - if (authsize < AEGIS256_MIN_AUTH_SIZE) - return -EINVAL; - return 0; -} - -static void crypto_aegis256_crypt(struct aead_request *req, - union aegis_block *tag_xor, - unsigned int cryptlen, - const struct aegis256_ops *ops) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct aegis_ctx *ctx = crypto_aead_ctx(tfm); - struct aegis_state state; - - crypto_aegis256_init(&state, ctx->key, req->iv); - crypto_aegis256_process_ad(&state, req->src, req->assoclen); - crypto_aegis256_process_crypt(&state, req, ops); - crypto_aegis256_final(&state, tag_xor, req->assoclen, cryptlen); -} - -static int crypto_aegis256_encrypt(struct aead_request *req) -{ - static const struct aegis256_ops ops = { - .skcipher_walk_init = skcipher_walk_aead_encrypt, - .crypt_chunk = crypto_aegis256_encrypt_chunk, - }; - - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - union aegis_block tag = {}; - unsigned int authsize = crypto_aead_authsize(tfm); - unsigned int cryptlen = req->cryptlen; - - crypto_aegis256_crypt(req, &tag, cryptlen, &ops); - - scatterwalk_map_and_copy(tag.bytes, req->dst, req->assoclen + cryptlen, - authsize, 1); - return 0; -} - -static int crypto_aegis256_decrypt(struct aead_request *req) -{ - static const struct aegis256_ops ops = { - .skcipher_walk_init = skcipher_walk_aead_decrypt, - .crypt_chunk = crypto_aegis256_decrypt_chunk, - }; - static const u8 zeros[AEGIS256_MAX_AUTH_SIZE] = {}; - - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - union aegis_block tag; - unsigned int authsize = crypto_aead_authsize(tfm); - unsigned int cryptlen = req->cryptlen - authsize; - - scatterwalk_map_and_copy(tag.bytes, req->src, req->assoclen + cryptlen, - authsize, 0); - - crypto_aegis256_crypt(req, &tag, cryptlen, &ops); - - return crypto_memneq(tag.bytes, zeros, authsize) ? -EBADMSG : 0; -} - -static int crypto_aegis256_init_tfm(struct crypto_aead *tfm) -{ - return 0; -} - -static void crypto_aegis256_exit_tfm(struct crypto_aead *tfm) -{ -} - -static struct aead_alg crypto_aegis256_alg = { - .setkey = crypto_aegis256_setkey, - .setauthsize = crypto_aegis256_setauthsize, - .encrypt = crypto_aegis256_encrypt, - .decrypt = crypto_aegis256_decrypt, - .init = crypto_aegis256_init_tfm, - .exit = crypto_aegis256_exit_tfm, - - .ivsize = AEGIS256_NONCE_SIZE, - .maxauthsize = AEGIS256_MAX_AUTH_SIZE, - .chunksize = AEGIS_BLOCK_SIZE, - - .base = { - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct aegis_ctx), - .cra_alignmask = 0, - - .cra_priority = 100, - - .cra_name = "aegis256", - .cra_driver_name = "aegis256-generic", - - .cra_module = THIS_MODULE, - } -}; - -static int __init crypto_aegis256_module_init(void) -{ - return crypto_register_aead(&crypto_aegis256_alg); -} - -static void __exit crypto_aegis256_module_exit(void) -{ - crypto_unregister_aead(&crypto_aegis256_alg); -} - -subsys_initcall(crypto_aegis256_module_init); -module_exit(crypto_aegis256_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ondrej Mosnacek "); -MODULE_DESCRIPTION("AEGIS-256 AEAD algorithm"); -MODULE_ALIAS_CRYPTO("aegis256"); -MODULE_ALIAS_CRYPTO("aegis256-generic"); diff --git a/crypto/aes_generic.c b/crypto/aes_generic.c index f217568917e42d6a199bf7d0355c461095c6682b..22e5867177f146aba33ab3dd712c640b6d222069 100644 --- a/crypto/aes_generic.c +++ b/crypto/aes_generic.c @@ -61,8 +61,6 @@ static inline u8 byte(const u32 x, const unsigned n) return x >> (n << 3); } -static const u32 rco_tab[10] = { 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 }; - /* cacheline-aligned to facilitate prefetching into cache */ __visible const u32 crypto_ft_tab[4][256] ____cacheline_aligned = { { @@ -328,7 +326,7 @@ __visible const u32 crypto_ft_tab[4][256] ____cacheline_aligned = { } }; -__visible const u32 crypto_fl_tab[4][256] ____cacheline_aligned = { +static const u32 crypto_fl_tab[4][256] ____cacheline_aligned = { { 0x00000063, 0x0000007c, 0x00000077, 0x0000007b, 0x000000f2, 0x0000006b, 0x0000006f, 0x000000c5, @@ -856,7 +854,7 @@ __visible const u32 crypto_it_tab[4][256] ____cacheline_aligned = { } }; -__visible const u32 crypto_il_tab[4][256] ____cacheline_aligned = { +static const u32 crypto_il_tab[4][256] ____cacheline_aligned = { { 0x00000052, 0x00000009, 0x0000006a, 0x000000d5, 0x00000030, 0x00000036, 0x000000a5, 0x00000038, @@ -1121,158 +1119,7 @@ __visible const u32 crypto_il_tab[4][256] ____cacheline_aligned = { }; EXPORT_SYMBOL_GPL(crypto_ft_tab); -EXPORT_SYMBOL_GPL(crypto_fl_tab); EXPORT_SYMBOL_GPL(crypto_it_tab); -EXPORT_SYMBOL_GPL(crypto_il_tab); - -/* initialise the key schedule from the user supplied key */ - -#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b) - -#define imix_col(y, x) do { \ - u = star_x(x); \ - v = star_x(u); \ - w = star_x(v); \ - t = w ^ (x); \ - (y) = u ^ v ^ w; \ - (y) ^= ror32(u ^ t, 8) ^ \ - ror32(v ^ t, 16) ^ \ - ror32(t, 24); \ -} while (0) - -#define ls_box(x) \ - crypto_fl_tab[0][byte(x, 0)] ^ \ - crypto_fl_tab[1][byte(x, 1)] ^ \ - crypto_fl_tab[2][byte(x, 2)] ^ \ - crypto_fl_tab[3][byte(x, 3)] - -#define loop4(i) do { \ - t = ror32(t, 8); \ - t = ls_box(t) ^ rco_tab[i]; \ - t ^= ctx->key_enc[4 * i]; \ - ctx->key_enc[4 * i + 4] = t; \ - t ^= ctx->key_enc[4 * i + 1]; \ - ctx->key_enc[4 * i + 5] = t; \ - t ^= ctx->key_enc[4 * i + 2]; \ - ctx->key_enc[4 * i + 6] = t; \ - t ^= ctx->key_enc[4 * i + 3]; \ - ctx->key_enc[4 * i + 7] = t; \ -} while (0) - -#define loop6(i) do { \ - t = ror32(t, 8); \ - t = ls_box(t) ^ rco_tab[i]; \ - t ^= ctx->key_enc[6 * i]; \ - ctx->key_enc[6 * i + 6] = t; \ - t ^= ctx->key_enc[6 * i + 1]; \ - ctx->key_enc[6 * i + 7] = t; \ - t ^= ctx->key_enc[6 * i + 2]; \ - ctx->key_enc[6 * i + 8] = t; \ - t ^= ctx->key_enc[6 * i + 3]; \ - ctx->key_enc[6 * i + 9] = t; \ - t ^= ctx->key_enc[6 * i + 4]; \ - ctx->key_enc[6 * i + 10] = t; \ - t ^= ctx->key_enc[6 * i + 5]; \ - ctx->key_enc[6 * i + 11] = t; \ -} while (0) - -#define loop8tophalf(i) do { \ - t = ror32(t, 8); \ - t = ls_box(t) ^ rco_tab[i]; \ - t ^= ctx->key_enc[8 * i]; \ - ctx->key_enc[8 * i + 8] = t; \ - t ^= ctx->key_enc[8 * i + 1]; \ - ctx->key_enc[8 * i + 9] = t; \ - t ^= ctx->key_enc[8 * i + 2]; \ - ctx->key_enc[8 * i + 10] = t; \ - t ^= ctx->key_enc[8 * i + 3]; \ - ctx->key_enc[8 * i + 11] = t; \ -} while (0) - -#define loop8(i) do { \ - loop8tophalf(i); \ - t = ctx->key_enc[8 * i + 4] ^ ls_box(t); \ - ctx->key_enc[8 * i + 12] = t; \ - t ^= ctx->key_enc[8 * i + 5]; \ - ctx->key_enc[8 * i + 13] = t; \ - t ^= ctx->key_enc[8 * i + 6]; \ - ctx->key_enc[8 * i + 14] = t; \ - t ^= ctx->key_enc[8 * i + 7]; \ - ctx->key_enc[8 * i + 15] = t; \ -} while (0) - -/** - * crypto_aes_expand_key - Expands the AES key as described in FIPS-197 - * @ctx: The location where the computed key will be stored. - * @in_key: The supplied key. - * @key_len: The length of the supplied key. - * - * Returns 0 on success. The function fails only if an invalid key size (or - * pointer) is supplied. - * The expanded key size is 240 bytes (max of 14 rounds with a unique 16 bytes - * key schedule plus a 16 bytes key which is used before the first round). - * The decryption key is prepared for the "Equivalent Inverse Cipher" as - * described in FIPS-197. The first slot (16 bytes) of each key (enc or dec) is - * for the initial combination, the second slot for the first round and so on. - */ -int crypto_aes_expand_key(struct crypto_aes_ctx *ctx, const u8 *in_key, - unsigned int key_len) -{ - u32 i, t, u, v, w, j; - - if (key_len != AES_KEYSIZE_128 && key_len != AES_KEYSIZE_192 && - key_len != AES_KEYSIZE_256) - return -EINVAL; - - ctx->key_length = key_len; - - ctx->key_enc[0] = get_unaligned_le32(in_key); - ctx->key_enc[1] = get_unaligned_le32(in_key + 4); - ctx->key_enc[2] = get_unaligned_le32(in_key + 8); - ctx->key_enc[3] = get_unaligned_le32(in_key + 12); - - ctx->key_dec[key_len + 24] = ctx->key_enc[0]; - ctx->key_dec[key_len + 25] = ctx->key_enc[1]; - ctx->key_dec[key_len + 26] = ctx->key_enc[2]; - ctx->key_dec[key_len + 27] = ctx->key_enc[3]; - - switch (key_len) { - case AES_KEYSIZE_128: - t = ctx->key_enc[3]; - for (i = 0; i < 10; ++i) - loop4(i); - break; - - case AES_KEYSIZE_192: - ctx->key_enc[4] = get_unaligned_le32(in_key + 16); - t = ctx->key_enc[5] = get_unaligned_le32(in_key + 20); - for (i = 0; i < 8; ++i) - loop6(i); - break; - - case AES_KEYSIZE_256: - ctx->key_enc[4] = get_unaligned_le32(in_key + 16); - ctx->key_enc[5] = get_unaligned_le32(in_key + 20); - ctx->key_enc[6] = get_unaligned_le32(in_key + 24); - t = ctx->key_enc[7] = get_unaligned_le32(in_key + 28); - for (i = 0; i < 6; ++i) - loop8(i); - loop8tophalf(i); - break; - } - - ctx->key_dec[0] = ctx->key_enc[key_len + 24]; - ctx->key_dec[1] = ctx->key_enc[key_len + 25]; - ctx->key_dec[2] = ctx->key_enc[key_len + 26]; - ctx->key_dec[3] = ctx->key_enc[key_len + 27]; - - for (i = 4; i < key_len + 24; ++i) { - j = key_len + 24 - (i & ~3) + (i & 3); - imix_col(ctx->key_dec[j], ctx->key_enc[i]); - } - return 0; -} -EXPORT_SYMBOL_GPL(crypto_aes_expand_key); /** * crypto_aes_set_key - Set the AES key. @@ -1281,7 +1128,7 @@ EXPORT_SYMBOL_GPL(crypto_aes_expand_key); * @key_len: The size of the key. * * Returns 0 on success, on failure the %CRYPTO_TFM_RES_BAD_KEY_LEN flag in tfm - * is set. The function uses crypto_aes_expand_key() to expand the key. + * is set. The function uses aes_expand_key() to expand the key. * &crypto_aes_ctx _must_ be the private data embedded in @tfm which is * retrieved with crypto_tfm_ctx(). */ @@ -1292,7 +1139,7 @@ int crypto_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, u32 *flags = &tfm->crt_flags; int ret; - ret = crypto_aes_expand_key(ctx, in_key, key_len); + ret = aes_expandkey(ctx, in_key, key_len); if (!ret) return 0; @@ -1332,7 +1179,7 @@ EXPORT_SYMBOL_GPL(crypto_aes_set_key); f_rl(bo, bi, 3, k); \ } while (0) -static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +static void crypto_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { const struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); u32 b0[4], b1[4]; @@ -1402,7 +1249,7 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) i_rl(bo, bi, 3, k); \ } while (0) -static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +static void crypto_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { const struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); u32 b0[4], b1[4]; @@ -1454,8 +1301,8 @@ static struct crypto_alg aes_alg = { .cia_min_keysize = AES_MIN_KEY_SIZE, .cia_max_keysize = AES_MAX_KEY_SIZE, .cia_setkey = crypto_aes_set_key, - .cia_encrypt = aes_encrypt, - .cia_decrypt = aes_decrypt + .cia_encrypt = crypto_aes_encrypt, + .cia_decrypt = crypto_aes_decrypt } } }; diff --git a/crypto/aes_ti.c b/crypto/aes_ti.c index 798fc9a2c8d609d07e74c9152751baa92a324e1d..205c2c257d4926b327af3f806088e45dfa4fbdd9 100644 --- a/crypto/aes_ti.c +++ b/crypto/aes_ti.c @@ -8,271 +8,19 @@ #include #include #include -#include - -/* - * Emit the sbox as volatile const to prevent the compiler from doing - * constant folding on sbox references involving fixed indexes. - */ -static volatile const u8 __cacheline_aligned __aesti_sbox[] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, - 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, - 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, - 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, - 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, - 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, - 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, - 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, - 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, - 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, - 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, - 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, - 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, - 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, - 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, - 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, -}; - -static volatile const u8 __cacheline_aligned __aesti_inv_sbox[] = { - 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, - 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, - 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, - 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, - 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, - 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, - 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, - 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, - 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, - 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, - 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, - 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, - 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, - 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, - 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, - 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, - 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, - 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, - 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, - 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, - 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, - 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, - 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, - 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, - 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, - 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, - 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, - 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, - 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, - 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, - 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d, -}; - -static u32 mul_by_x(u32 w) -{ - u32 x = w & 0x7f7f7f7f; - u32 y = w & 0x80808080; - - /* multiply by polynomial 'x' (0b10) in GF(2^8) */ - return (x << 1) ^ (y >> 7) * 0x1b; -} - -static u32 mul_by_x2(u32 w) -{ - u32 x = w & 0x3f3f3f3f; - u32 y = w & 0x80808080; - u32 z = w & 0x40404040; - - /* multiply by polynomial 'x^2' (0b100) in GF(2^8) */ - return (x << 2) ^ (y >> 7) * 0x36 ^ (z >> 6) * 0x1b; -} - -static u32 mix_columns(u32 x) -{ - /* - * Perform the following matrix multiplication in GF(2^8) - * - * | 0x2 0x3 0x1 0x1 | | x[0] | - * | 0x1 0x2 0x3 0x1 | | x[1] | - * | 0x1 0x1 0x2 0x3 | x | x[2] | - * | 0x3 0x1 0x1 0x2 | | x[3] | - */ - u32 y = mul_by_x(x) ^ ror32(x, 16); - - return y ^ ror32(x ^ y, 8); -} - -static u32 inv_mix_columns(u32 x) -{ - /* - * Perform the following matrix multiplication in GF(2^8) - * - * | 0xe 0xb 0xd 0x9 | | x[0] | - * | 0x9 0xe 0xb 0xd | | x[1] | - * | 0xd 0x9 0xe 0xb | x | x[2] | - * | 0xb 0xd 0x9 0xe | | x[3] | - * - * which can conveniently be reduced to - * - * | 0x2 0x3 0x1 0x1 | | 0x5 0x0 0x4 0x0 | | x[0] | - * | 0x1 0x2 0x3 0x1 | | 0x0 0x5 0x0 0x4 | | x[1] | - * | 0x1 0x1 0x2 0x3 | x | 0x4 0x0 0x5 0x0 | x | x[2] | - * | 0x3 0x1 0x1 0x2 | | 0x0 0x4 0x0 0x5 | | x[3] | - */ - u32 y = mul_by_x2(x); - - return mix_columns(x ^ y ^ ror32(y, 16)); -} - -static __always_inline u32 subshift(u32 in[], int pos) -{ - return (__aesti_sbox[in[pos] & 0xff]) ^ - (__aesti_sbox[(in[(pos + 1) % 4] >> 8) & 0xff] << 8) ^ - (__aesti_sbox[(in[(pos + 2) % 4] >> 16) & 0xff] << 16) ^ - (__aesti_sbox[(in[(pos + 3) % 4] >> 24) & 0xff] << 24); -} - -static __always_inline u32 inv_subshift(u32 in[], int pos) -{ - return (__aesti_inv_sbox[in[pos] & 0xff]) ^ - (__aesti_inv_sbox[(in[(pos + 3) % 4] >> 8) & 0xff] << 8) ^ - (__aesti_inv_sbox[(in[(pos + 2) % 4] >> 16) & 0xff] << 16) ^ - (__aesti_inv_sbox[(in[(pos + 1) % 4] >> 24) & 0xff] << 24); -} - -static u32 subw(u32 in) -{ - return (__aesti_sbox[in & 0xff]) ^ - (__aesti_sbox[(in >> 8) & 0xff] << 8) ^ - (__aesti_sbox[(in >> 16) & 0xff] << 16) ^ - (__aesti_sbox[(in >> 24) & 0xff] << 24); -} - -static int aesti_expand_key(struct crypto_aes_ctx *ctx, const u8 *in_key, - unsigned int key_len) -{ - u32 kwords = key_len / sizeof(u32); - u32 rc, i, j; - - if (key_len != AES_KEYSIZE_128 && - key_len != AES_KEYSIZE_192 && - key_len != AES_KEYSIZE_256) - return -EINVAL; - - ctx->key_length = key_len; - - for (i = 0; i < kwords; i++) - ctx->key_enc[i] = get_unaligned_le32(in_key + i * sizeof(u32)); - - for (i = 0, rc = 1; i < 10; i++, rc = mul_by_x(rc)) { - u32 *rki = ctx->key_enc + (i * kwords); - u32 *rko = rki + kwords; - - rko[0] = ror32(subw(rki[kwords - 1]), 8) ^ rc ^ rki[0]; - rko[1] = rko[0] ^ rki[1]; - rko[2] = rko[1] ^ rki[2]; - rko[3] = rko[2] ^ rki[3]; - - if (key_len == 24) { - if (i >= 7) - break; - rko[4] = rko[3] ^ rki[4]; - rko[5] = rko[4] ^ rki[5]; - } else if (key_len == 32) { - if (i >= 6) - break; - rko[4] = subw(rko[3]) ^ rki[4]; - rko[5] = rko[4] ^ rki[5]; - rko[6] = rko[5] ^ rki[6]; - rko[7] = rko[6] ^ rki[7]; - } - } - - /* - * Generate the decryption keys for the Equivalent Inverse Cipher. - * This involves reversing the order of the round keys, and applying - * the Inverse Mix Columns transformation to all but the first and - * the last one. - */ - ctx->key_dec[0] = ctx->key_enc[key_len + 24]; - ctx->key_dec[1] = ctx->key_enc[key_len + 25]; - ctx->key_dec[2] = ctx->key_enc[key_len + 26]; - ctx->key_dec[3] = ctx->key_enc[key_len + 27]; - - for (i = 4, j = key_len + 20; j > 0; i += 4, j -= 4) { - ctx->key_dec[i] = inv_mix_columns(ctx->key_enc[j]); - ctx->key_dec[i + 1] = inv_mix_columns(ctx->key_enc[j + 1]); - ctx->key_dec[i + 2] = inv_mix_columns(ctx->key_enc[j + 2]); - ctx->key_dec[i + 3] = inv_mix_columns(ctx->key_enc[j + 3]); - } - - ctx->key_dec[i] = ctx->key_enc[0]; - ctx->key_dec[i + 1] = ctx->key_enc[1]; - ctx->key_dec[i + 2] = ctx->key_enc[2]; - ctx->key_dec[i + 3] = ctx->key_enc[3]; - - return 0; -} static int aesti_set_key(struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len) { struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); - int err; - - err = aesti_expand_key(ctx, in_key, key_len); - if (err) - return err; - - /* - * In order to force the compiler to emit data independent Sbox lookups - * at the start of each block, xor the first round key with values at - * fixed indexes in the Sbox. This will need to be repeated each time - * the key is used, which will pull the entire Sbox into the D-cache - * before any data dependent Sbox lookups are performed. - */ - ctx->key_enc[0] ^= __aesti_sbox[ 0] ^ __aesti_sbox[128]; - ctx->key_enc[1] ^= __aesti_sbox[32] ^ __aesti_sbox[160]; - ctx->key_enc[2] ^= __aesti_sbox[64] ^ __aesti_sbox[192]; - ctx->key_enc[3] ^= __aesti_sbox[96] ^ __aesti_sbox[224]; - - ctx->key_dec[0] ^= __aesti_inv_sbox[ 0] ^ __aesti_inv_sbox[128]; - ctx->key_dec[1] ^= __aesti_inv_sbox[32] ^ __aesti_inv_sbox[160]; - ctx->key_dec[2] ^= __aesti_inv_sbox[64] ^ __aesti_inv_sbox[192]; - ctx->key_dec[3] ^= __aesti_inv_sbox[96] ^ __aesti_inv_sbox[224]; - return 0; + return aes_expandkey(ctx, in_key, key_len); } static void aesti_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { const struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); - const u32 *rkp = ctx->key_enc + 4; - int rounds = 6 + ctx->key_length / 4; - u32 st0[4], st1[4]; unsigned long flags; - int round; - - st0[0] = ctx->key_enc[0] ^ get_unaligned_le32(in); - st0[1] = ctx->key_enc[1] ^ get_unaligned_le32(in + 4); - st0[2] = ctx->key_enc[2] ^ get_unaligned_le32(in + 8); - st0[3] = ctx->key_enc[3] ^ get_unaligned_le32(in + 12); /* * Temporarily disable interrupts to avoid races where cachelines are @@ -280,30 +28,7 @@ static void aesti_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) */ local_irq_save(flags); - st0[0] ^= __aesti_sbox[ 0] ^ __aesti_sbox[128]; - st0[1] ^= __aesti_sbox[32] ^ __aesti_sbox[160]; - st0[2] ^= __aesti_sbox[64] ^ __aesti_sbox[192]; - st0[3] ^= __aesti_sbox[96] ^ __aesti_sbox[224]; - - for (round = 0;; round += 2, rkp += 8) { - st1[0] = mix_columns(subshift(st0, 0)) ^ rkp[0]; - st1[1] = mix_columns(subshift(st0, 1)) ^ rkp[1]; - st1[2] = mix_columns(subshift(st0, 2)) ^ rkp[2]; - st1[3] = mix_columns(subshift(st0, 3)) ^ rkp[3]; - - if (round == rounds - 2) - break; - - st0[0] = mix_columns(subshift(st1, 0)) ^ rkp[4]; - st0[1] = mix_columns(subshift(st1, 1)) ^ rkp[5]; - st0[2] = mix_columns(subshift(st1, 2)) ^ rkp[6]; - st0[3] = mix_columns(subshift(st1, 3)) ^ rkp[7]; - } - - put_unaligned_le32(subshift(st1, 0) ^ rkp[4], out); - put_unaligned_le32(subshift(st1, 1) ^ rkp[5], out + 4); - put_unaligned_le32(subshift(st1, 2) ^ rkp[6], out + 8); - put_unaligned_le32(subshift(st1, 3) ^ rkp[7], out + 12); + aes_encrypt(ctx, out, in); local_irq_restore(flags); } @@ -311,16 +36,7 @@ static void aesti_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) static void aesti_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { const struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); - const u32 *rkp = ctx->key_dec + 4; - int rounds = 6 + ctx->key_length / 4; - u32 st0[4], st1[4]; unsigned long flags; - int round; - - st0[0] = ctx->key_dec[0] ^ get_unaligned_le32(in); - st0[1] = ctx->key_dec[1] ^ get_unaligned_le32(in + 4); - st0[2] = ctx->key_dec[2] ^ get_unaligned_le32(in + 8); - st0[3] = ctx->key_dec[3] ^ get_unaligned_le32(in + 12); /* * Temporarily disable interrupts to avoid races where cachelines are @@ -328,30 +44,7 @@ static void aesti_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) */ local_irq_save(flags); - st0[0] ^= __aesti_inv_sbox[ 0] ^ __aesti_inv_sbox[128]; - st0[1] ^= __aesti_inv_sbox[32] ^ __aesti_inv_sbox[160]; - st0[2] ^= __aesti_inv_sbox[64] ^ __aesti_inv_sbox[192]; - st0[3] ^= __aesti_inv_sbox[96] ^ __aesti_inv_sbox[224]; - - for (round = 0;; round += 2, rkp += 8) { - st1[0] = inv_mix_columns(inv_subshift(st0, 0)) ^ rkp[0]; - st1[1] = inv_mix_columns(inv_subshift(st0, 1)) ^ rkp[1]; - st1[2] = inv_mix_columns(inv_subshift(st0, 2)) ^ rkp[2]; - st1[3] = inv_mix_columns(inv_subshift(st0, 3)) ^ rkp[3]; - - if (round == rounds - 2) - break; - - st0[0] = inv_mix_columns(inv_subshift(st1, 0)) ^ rkp[4]; - st0[1] = inv_mix_columns(inv_subshift(st1, 1)) ^ rkp[5]; - st0[2] = inv_mix_columns(inv_subshift(st1, 2)) ^ rkp[6]; - st0[3] = inv_mix_columns(inv_subshift(st1, 3)) ^ rkp[7]; - } - - put_unaligned_le32(inv_subshift(st1, 0) ^ rkp[4], out); - put_unaligned_le32(inv_subshift(st1, 1) ^ rkp[5], out + 4); - put_unaligned_le32(inv_subshift(st1, 2) ^ rkp[6], out + 8); - put_unaligned_le32(inv_subshift(st1, 3) ^ rkp[7], out + 12); + aes_decrypt(ctx, out, in); local_irq_restore(flags); } diff --git a/crypto/cryptd.c b/crypto/cryptd.c index 3748f9b4516de1a20e4112255d4afda5d9999c26..927760b316a4df7ed8b402f346e284cddf0b32ff 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -63,7 +63,7 @@ struct aead_instance_ctx { }; struct cryptd_skcipher_ctx { - atomic_t refcnt; + refcount_t refcnt; struct crypto_sync_skcipher *child; }; @@ -72,7 +72,7 @@ struct cryptd_skcipher_request_ctx { }; struct cryptd_hash_ctx { - atomic_t refcnt; + refcount_t refcnt; struct crypto_shash *child; }; @@ -82,7 +82,7 @@ struct cryptd_hash_request_ctx { }; struct cryptd_aead_ctx { - atomic_t refcnt; + refcount_t refcnt; struct crypto_aead *child; }; @@ -127,7 +127,7 @@ static int cryptd_enqueue_request(struct cryptd_queue *queue, { int cpu, err; struct cryptd_cpu_queue *cpu_queue; - atomic_t *refcnt; + refcount_t *refcnt; cpu = get_cpu(); cpu_queue = this_cpu_ptr(queue->cpu_queue); @@ -140,10 +140,10 @@ static int cryptd_enqueue_request(struct cryptd_queue *queue, queue_work_on(cpu, cryptd_wq, &cpu_queue->work); - if (!atomic_read(refcnt)) + if (!refcount_read(refcnt)) goto out_put_cpu; - atomic_inc(refcnt); + refcount_inc(refcnt); out_put_cpu: put_cpu(); @@ -270,13 +270,13 @@ static void cryptd_skcipher_complete(struct skcipher_request *req, int err) struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); struct cryptd_skcipher_request_ctx *rctx = skcipher_request_ctx(req); - int refcnt = atomic_read(&ctx->refcnt); + int refcnt = refcount_read(&ctx->refcnt); local_bh_disable(); rctx->complete(&req->base, err); local_bh_enable(); - if (err != -EINPROGRESS && refcnt && atomic_dec_and_test(&ctx->refcnt)) + if (err != -EINPROGRESS && refcnt && refcount_dec_and_test(&ctx->refcnt)) crypto_free_skcipher(tfm); } @@ -521,13 +521,13 @@ static void cryptd_hash_complete(struct ahash_request *req, int err) struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct cryptd_hash_ctx *ctx = crypto_ahash_ctx(tfm); struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req); - int refcnt = atomic_read(&ctx->refcnt); + int refcnt = refcount_read(&ctx->refcnt); local_bh_disable(); rctx->complete(&req->base, err); local_bh_enable(); - if (err != -EINPROGRESS && refcnt && atomic_dec_and_test(&ctx->refcnt)) + if (err != -EINPROGRESS && refcnt && refcount_dec_and_test(&ctx->refcnt)) crypto_free_ahash(tfm); } @@ -772,13 +772,13 @@ static void cryptd_aead_crypt(struct aead_request *req, out: ctx = crypto_aead_ctx(tfm); - refcnt = atomic_read(&ctx->refcnt); + refcnt = refcount_read(&ctx->refcnt); local_bh_disable(); compl(&req->base, err); local_bh_enable(); - if (err != -EINPROGRESS && refcnt && atomic_dec_and_test(&ctx->refcnt)) + if (err != -EINPROGRESS && refcnt && refcount_dec_and_test(&ctx->refcnt)) crypto_free_aead(tfm); } @@ -979,7 +979,7 @@ struct cryptd_skcipher *cryptd_alloc_skcipher(const char *alg_name, } ctx = crypto_skcipher_ctx(tfm); - atomic_set(&ctx->refcnt, 1); + refcount_set(&ctx->refcnt, 1); return container_of(tfm, struct cryptd_skcipher, base); } @@ -997,7 +997,7 @@ bool cryptd_skcipher_queued(struct cryptd_skcipher *tfm) { struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(&tfm->base); - return atomic_read(&ctx->refcnt) - 1; + return refcount_read(&ctx->refcnt) - 1; } EXPORT_SYMBOL_GPL(cryptd_skcipher_queued); @@ -1005,7 +1005,7 @@ void cryptd_free_skcipher(struct cryptd_skcipher *tfm) { struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(&tfm->base); - if (atomic_dec_and_test(&ctx->refcnt)) + if (refcount_dec_and_test(&ctx->refcnt)) crypto_free_skcipher(&tfm->base); } EXPORT_SYMBOL_GPL(cryptd_free_skcipher); @@ -1029,7 +1029,7 @@ struct cryptd_ahash *cryptd_alloc_ahash(const char *alg_name, } ctx = crypto_ahash_ctx(tfm); - atomic_set(&ctx->refcnt, 1); + refcount_set(&ctx->refcnt, 1); return __cryptd_ahash_cast(tfm); } @@ -1054,7 +1054,7 @@ bool cryptd_ahash_queued(struct cryptd_ahash *tfm) { struct cryptd_hash_ctx *ctx = crypto_ahash_ctx(&tfm->base); - return atomic_read(&ctx->refcnt) - 1; + return refcount_read(&ctx->refcnt) - 1; } EXPORT_SYMBOL_GPL(cryptd_ahash_queued); @@ -1062,7 +1062,7 @@ void cryptd_free_ahash(struct cryptd_ahash *tfm) { struct cryptd_hash_ctx *ctx = crypto_ahash_ctx(&tfm->base); - if (atomic_dec_and_test(&ctx->refcnt)) + if (refcount_dec_and_test(&ctx->refcnt)) crypto_free_ahash(&tfm->base); } EXPORT_SYMBOL_GPL(cryptd_free_ahash); @@ -1086,7 +1086,7 @@ struct cryptd_aead *cryptd_alloc_aead(const char *alg_name, } ctx = crypto_aead_ctx(tfm); - atomic_set(&ctx->refcnt, 1); + refcount_set(&ctx->refcnt, 1); return __cryptd_aead_cast(tfm); } @@ -1104,7 +1104,7 @@ bool cryptd_aead_queued(struct cryptd_aead *tfm) { struct cryptd_aead_ctx *ctx = crypto_aead_ctx(&tfm->base); - return atomic_read(&ctx->refcnt) - 1; + return refcount_read(&ctx->refcnt) - 1; } EXPORT_SYMBOL_GPL(cryptd_aead_queued); @@ -1112,7 +1112,7 @@ void cryptd_free_aead(struct cryptd_aead *tfm) { struct cryptd_aead_ctx *ctx = crypto_aead_ctx(&tfm->base); - if (atomic_dec_and_test(&ctx->refcnt)) + if (refcount_dec_and_test(&ctx->refcnt)) crypto_free_aead(&tfm->base); } EXPORT_SYMBOL_GPL(cryptd_free_aead); diff --git a/crypto/crypto_engine.c b/crypto/crypto_engine.c index d7502ec37f2087f7b327fd41768614510075ddef..055d179772807280566a1e0a746d1df61b6dca3c 100644 --- a/crypto/crypto_engine.c +++ b/crypto/crypto_engine.c @@ -425,7 +425,7 @@ EXPORT_SYMBOL_GPL(crypto_engine_stop); */ struct crypto_engine *crypto_engine_alloc_init(struct device *dev, bool rt) { - struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; + struct sched_param param = { .sched_priority = MAX_RT_PRIO / 2 }; struct crypto_engine *engine; if (!dev) diff --git a/crypto/crypto_user_base.c b/crypto/crypto_user_base.c index c65e39005ce2a3268270eedeb9fd8289aa49efef..910e0b46012e37e8097f6578e2a305ddfc75a9b7 100644 --- a/crypto/crypto_user_base.c +++ b/crypto/crypto_user_base.c @@ -10,9 +10,10 @@ #include #include #include -#include #include +#include #include +#include #include #include #include @@ -25,9 +26,6 @@ static DEFINE_MUTEX(crypto_cfg_mutex); -/* The crypto netlink socket */ -struct sock *crypto_nlsk; - struct crypto_dump_info { struct sk_buff *in_skb; struct sk_buff *out_skb; @@ -186,6 +184,7 @@ static int crypto_report_alg(struct crypto_alg *alg, static int crypto_report(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, struct nlattr **attrs) { + struct net *net = sock_net(in_skb->sk); struct crypto_user_alg *p = nlmsg_data(in_nlh); struct crypto_alg *alg; struct sk_buff *skb; @@ -217,7 +216,7 @@ static int crypto_report(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, if (err) return err; - return nlmsg_unicast(crypto_nlsk, skb, NETLINK_CB(in_skb).portid); + return nlmsg_unicast(net->crypto_nlsk, skb, NETLINK_CB(in_skb).portid); } static int crypto_dump_report(struct sk_buff *skb, struct netlink_callback *cb) @@ -420,6 +419,7 @@ static const struct crypto_link { static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) { + struct net *net = sock_net(skb->sk); struct nlattr *attrs[CRYPTOCFGA_MAX+1]; const struct crypto_link *link; int type, err; @@ -450,7 +450,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, .done = link->done, .min_dump_alloc = min(dump_alloc, 65535UL), }; - err = netlink_dump_start(crypto_nlsk, skb, nlh, &c); + err = netlink_dump_start(net->crypto_nlsk, skb, nlh, &c); } return err; @@ -474,22 +474,35 @@ static void crypto_netlink_rcv(struct sk_buff *skb) mutex_unlock(&crypto_cfg_mutex); } -static int __init crypto_user_init(void) +static int __net_init crypto_netlink_init(struct net *net) { struct netlink_kernel_cfg cfg = { .input = crypto_netlink_rcv, }; - crypto_nlsk = netlink_kernel_create(&init_net, NETLINK_CRYPTO, &cfg); - if (!crypto_nlsk) - return -ENOMEM; + net->crypto_nlsk = netlink_kernel_create(net, NETLINK_CRYPTO, &cfg); + return net->crypto_nlsk == NULL ? -ENOMEM : 0; +} - return 0; +static void __net_exit crypto_netlink_exit(struct net *net) +{ + netlink_kernel_release(net->crypto_nlsk); + net->crypto_nlsk = NULL; +} + +static struct pernet_operations crypto_netlink_net_ops = { + .init = crypto_netlink_init, + .exit = crypto_netlink_exit, +}; + +static int __init crypto_user_init(void) +{ + return register_pernet_subsys(&crypto_netlink_net_ops); } static void __exit crypto_user_exit(void) { - netlink_kernel_release(crypto_nlsk); + unregister_pernet_subsys(&crypto_netlink_net_ops); } module_init(crypto_user_init); diff --git a/crypto/crypto_user_stat.c b/crypto/crypto_user_stat.c index a03f326a63d32a15536fe9a570843082288f7c0b..8bad88413de163e831edc3beb374fed74a3d4dd8 100644 --- a/crypto/crypto_user_stat.c +++ b/crypto/crypto_user_stat.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -298,6 +299,7 @@ static int crypto_reportstat_alg(struct crypto_alg *alg, int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, struct nlattr **attrs) { + struct net *net = sock_net(in_skb->sk); struct crypto_user_alg *p = nlmsg_data(in_nlh); struct crypto_alg *alg; struct sk_buff *skb; @@ -329,7 +331,7 @@ int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, if (err) return err; - return nlmsg_unicast(crypto_nlsk, skb, NETLINK_CB(in_skb).portid); + return nlmsg_unicast(net->crypto_nlsk, skb, NETLINK_CB(in_skb).portid); } MODULE_LICENSE("GPL"); diff --git a/crypto/des_generic.c b/crypto/des_generic.c index dc085514408a40aa17000db5a49870b9c7bb4f11..6e13a4a29ecb0b9f158ece39b8a4eddbd615ad96 100644 --- a/crypto/des_generic.c +++ b/crypto/des_generic.c @@ -13,934 +13,79 @@ #include #include #include -#include -#include - -#define ROL(x, r) ((x) = rol32((x), (r))) -#define ROR(x, r) ((x) = ror32((x), (r))) - -struct des_ctx { - u32 expkey[DES_EXPKEY_WORDS]; -}; - -struct des3_ede_ctx { - u32 expkey[DES3_EDE_EXPKEY_WORDS]; -}; - -/* Lookup tables for key expansion */ - -static const u8 pc1[256] = { - 0x00, 0x00, 0x40, 0x04, 0x10, 0x10, 0x50, 0x14, - 0x04, 0x40, 0x44, 0x44, 0x14, 0x50, 0x54, 0x54, - 0x02, 0x02, 0x42, 0x06, 0x12, 0x12, 0x52, 0x16, - 0x06, 0x42, 0x46, 0x46, 0x16, 0x52, 0x56, 0x56, - 0x80, 0x08, 0xc0, 0x0c, 0x90, 0x18, 0xd0, 0x1c, - 0x84, 0x48, 0xc4, 0x4c, 0x94, 0x58, 0xd4, 0x5c, - 0x82, 0x0a, 0xc2, 0x0e, 0x92, 0x1a, 0xd2, 0x1e, - 0x86, 0x4a, 0xc6, 0x4e, 0x96, 0x5a, 0xd6, 0x5e, - 0x20, 0x20, 0x60, 0x24, 0x30, 0x30, 0x70, 0x34, - 0x24, 0x60, 0x64, 0x64, 0x34, 0x70, 0x74, 0x74, - 0x22, 0x22, 0x62, 0x26, 0x32, 0x32, 0x72, 0x36, - 0x26, 0x62, 0x66, 0x66, 0x36, 0x72, 0x76, 0x76, - 0xa0, 0x28, 0xe0, 0x2c, 0xb0, 0x38, 0xf0, 0x3c, - 0xa4, 0x68, 0xe4, 0x6c, 0xb4, 0x78, 0xf4, 0x7c, - 0xa2, 0x2a, 0xe2, 0x2e, 0xb2, 0x3a, 0xf2, 0x3e, - 0xa6, 0x6a, 0xe6, 0x6e, 0xb6, 0x7a, 0xf6, 0x7e, - 0x08, 0x80, 0x48, 0x84, 0x18, 0x90, 0x58, 0x94, - 0x0c, 0xc0, 0x4c, 0xc4, 0x1c, 0xd0, 0x5c, 0xd4, - 0x0a, 0x82, 0x4a, 0x86, 0x1a, 0x92, 0x5a, 0x96, - 0x0e, 0xc2, 0x4e, 0xc6, 0x1e, 0xd2, 0x5e, 0xd6, - 0x88, 0x88, 0xc8, 0x8c, 0x98, 0x98, 0xd8, 0x9c, - 0x8c, 0xc8, 0xcc, 0xcc, 0x9c, 0xd8, 0xdc, 0xdc, - 0x8a, 0x8a, 0xca, 0x8e, 0x9a, 0x9a, 0xda, 0x9e, - 0x8e, 0xca, 0xce, 0xce, 0x9e, 0xda, 0xde, 0xde, - 0x28, 0xa0, 0x68, 0xa4, 0x38, 0xb0, 0x78, 0xb4, - 0x2c, 0xe0, 0x6c, 0xe4, 0x3c, 0xf0, 0x7c, 0xf4, - 0x2a, 0xa2, 0x6a, 0xa6, 0x3a, 0xb2, 0x7a, 0xb6, - 0x2e, 0xe2, 0x6e, 0xe6, 0x3e, 0xf2, 0x7e, 0xf6, - 0xa8, 0xa8, 0xe8, 0xac, 0xb8, 0xb8, 0xf8, 0xbc, - 0xac, 0xe8, 0xec, 0xec, 0xbc, 0xf8, 0xfc, 0xfc, - 0xaa, 0xaa, 0xea, 0xae, 0xba, 0xba, 0xfa, 0xbe, - 0xae, 0xea, 0xee, 0xee, 0xbe, 0xfa, 0xfe, 0xfe -}; - -static const u8 rs[256] = { - 0x00, 0x00, 0x80, 0x80, 0x02, 0x02, 0x82, 0x82, - 0x04, 0x04, 0x84, 0x84, 0x06, 0x06, 0x86, 0x86, - 0x08, 0x08, 0x88, 0x88, 0x0a, 0x0a, 0x8a, 0x8a, - 0x0c, 0x0c, 0x8c, 0x8c, 0x0e, 0x0e, 0x8e, 0x8e, - 0x10, 0x10, 0x90, 0x90, 0x12, 0x12, 0x92, 0x92, - 0x14, 0x14, 0x94, 0x94, 0x16, 0x16, 0x96, 0x96, - 0x18, 0x18, 0x98, 0x98, 0x1a, 0x1a, 0x9a, 0x9a, - 0x1c, 0x1c, 0x9c, 0x9c, 0x1e, 0x1e, 0x9e, 0x9e, - 0x20, 0x20, 0xa0, 0xa0, 0x22, 0x22, 0xa2, 0xa2, - 0x24, 0x24, 0xa4, 0xa4, 0x26, 0x26, 0xa6, 0xa6, - 0x28, 0x28, 0xa8, 0xa8, 0x2a, 0x2a, 0xaa, 0xaa, - 0x2c, 0x2c, 0xac, 0xac, 0x2e, 0x2e, 0xae, 0xae, - 0x30, 0x30, 0xb0, 0xb0, 0x32, 0x32, 0xb2, 0xb2, - 0x34, 0x34, 0xb4, 0xb4, 0x36, 0x36, 0xb6, 0xb6, - 0x38, 0x38, 0xb8, 0xb8, 0x3a, 0x3a, 0xba, 0xba, - 0x3c, 0x3c, 0xbc, 0xbc, 0x3e, 0x3e, 0xbe, 0xbe, - 0x40, 0x40, 0xc0, 0xc0, 0x42, 0x42, 0xc2, 0xc2, - 0x44, 0x44, 0xc4, 0xc4, 0x46, 0x46, 0xc6, 0xc6, - 0x48, 0x48, 0xc8, 0xc8, 0x4a, 0x4a, 0xca, 0xca, - 0x4c, 0x4c, 0xcc, 0xcc, 0x4e, 0x4e, 0xce, 0xce, - 0x50, 0x50, 0xd0, 0xd0, 0x52, 0x52, 0xd2, 0xd2, - 0x54, 0x54, 0xd4, 0xd4, 0x56, 0x56, 0xd6, 0xd6, - 0x58, 0x58, 0xd8, 0xd8, 0x5a, 0x5a, 0xda, 0xda, - 0x5c, 0x5c, 0xdc, 0xdc, 0x5e, 0x5e, 0xde, 0xde, - 0x60, 0x60, 0xe0, 0xe0, 0x62, 0x62, 0xe2, 0xe2, - 0x64, 0x64, 0xe4, 0xe4, 0x66, 0x66, 0xe6, 0xe6, - 0x68, 0x68, 0xe8, 0xe8, 0x6a, 0x6a, 0xea, 0xea, - 0x6c, 0x6c, 0xec, 0xec, 0x6e, 0x6e, 0xee, 0xee, - 0x70, 0x70, 0xf0, 0xf0, 0x72, 0x72, 0xf2, 0xf2, - 0x74, 0x74, 0xf4, 0xf4, 0x76, 0x76, 0xf6, 0xf6, - 0x78, 0x78, 0xf8, 0xf8, 0x7a, 0x7a, 0xfa, 0xfa, - 0x7c, 0x7c, 0xfc, 0xfc, 0x7e, 0x7e, 0xfe, 0xfe -}; - -static const u32 pc2[1024] = { - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00040000, 0x00000000, 0x04000000, 0x00100000, - 0x00400000, 0x00000008, 0x00000800, 0x40000000, - 0x00440000, 0x00000008, 0x04000800, 0x40100000, - 0x00000400, 0x00000020, 0x08000000, 0x00000100, - 0x00040400, 0x00000020, 0x0c000000, 0x00100100, - 0x00400400, 0x00000028, 0x08000800, 0x40000100, - 0x00440400, 0x00000028, 0x0c000800, 0x40100100, - 0x80000000, 0x00000010, 0x00000000, 0x00800000, - 0x80040000, 0x00000010, 0x04000000, 0x00900000, - 0x80400000, 0x00000018, 0x00000800, 0x40800000, - 0x80440000, 0x00000018, 0x04000800, 0x40900000, - 0x80000400, 0x00000030, 0x08000000, 0x00800100, - 0x80040400, 0x00000030, 0x0c000000, 0x00900100, - 0x80400400, 0x00000038, 0x08000800, 0x40800100, - 0x80440400, 0x00000038, 0x0c000800, 0x40900100, - 0x10000000, 0x00000000, 0x00200000, 0x00001000, - 0x10040000, 0x00000000, 0x04200000, 0x00101000, - 0x10400000, 0x00000008, 0x00200800, 0x40001000, - 0x10440000, 0x00000008, 0x04200800, 0x40101000, - 0x10000400, 0x00000020, 0x08200000, 0x00001100, - 0x10040400, 0x00000020, 0x0c200000, 0x00101100, - 0x10400400, 0x00000028, 0x08200800, 0x40001100, - 0x10440400, 0x00000028, 0x0c200800, 0x40101100, - 0x90000000, 0x00000010, 0x00200000, 0x00801000, - 0x90040000, 0x00000010, 0x04200000, 0x00901000, - 0x90400000, 0x00000018, 0x00200800, 0x40801000, - 0x90440000, 0x00000018, 0x04200800, 0x40901000, - 0x90000400, 0x00000030, 0x08200000, 0x00801100, - 0x90040400, 0x00000030, 0x0c200000, 0x00901100, - 0x90400400, 0x00000038, 0x08200800, 0x40801100, - 0x90440400, 0x00000038, 0x0c200800, 0x40901100, - 0x00000200, 0x00080000, 0x00000000, 0x00000004, - 0x00040200, 0x00080000, 0x04000000, 0x00100004, - 0x00400200, 0x00080008, 0x00000800, 0x40000004, - 0x00440200, 0x00080008, 0x04000800, 0x40100004, - 0x00000600, 0x00080020, 0x08000000, 0x00000104, - 0x00040600, 0x00080020, 0x0c000000, 0x00100104, - 0x00400600, 0x00080028, 0x08000800, 0x40000104, - 0x00440600, 0x00080028, 0x0c000800, 0x40100104, - 0x80000200, 0x00080010, 0x00000000, 0x00800004, - 0x80040200, 0x00080010, 0x04000000, 0x00900004, - 0x80400200, 0x00080018, 0x00000800, 0x40800004, - 0x80440200, 0x00080018, 0x04000800, 0x40900004, - 0x80000600, 0x00080030, 0x08000000, 0x00800104, - 0x80040600, 0x00080030, 0x0c000000, 0x00900104, - 0x80400600, 0x00080038, 0x08000800, 0x40800104, - 0x80440600, 0x00080038, 0x0c000800, 0x40900104, - 0x10000200, 0x00080000, 0x00200000, 0x00001004, - 0x10040200, 0x00080000, 0x04200000, 0x00101004, - 0x10400200, 0x00080008, 0x00200800, 0x40001004, - 0x10440200, 0x00080008, 0x04200800, 0x40101004, - 0x10000600, 0x00080020, 0x08200000, 0x00001104, - 0x10040600, 0x00080020, 0x0c200000, 0x00101104, - 0x10400600, 0x00080028, 0x08200800, 0x40001104, - 0x10440600, 0x00080028, 0x0c200800, 0x40101104, - 0x90000200, 0x00080010, 0x00200000, 0x00801004, - 0x90040200, 0x00080010, 0x04200000, 0x00901004, - 0x90400200, 0x00080018, 0x00200800, 0x40801004, - 0x90440200, 0x00080018, 0x04200800, 0x40901004, - 0x90000600, 0x00080030, 0x08200000, 0x00801104, - 0x90040600, 0x00080030, 0x0c200000, 0x00901104, - 0x90400600, 0x00080038, 0x08200800, 0x40801104, - 0x90440600, 0x00080038, 0x0c200800, 0x40901104, - 0x00000002, 0x00002000, 0x20000000, 0x00000001, - 0x00040002, 0x00002000, 0x24000000, 0x00100001, - 0x00400002, 0x00002008, 0x20000800, 0x40000001, - 0x00440002, 0x00002008, 0x24000800, 0x40100001, - 0x00000402, 0x00002020, 0x28000000, 0x00000101, - 0x00040402, 0x00002020, 0x2c000000, 0x00100101, - 0x00400402, 0x00002028, 0x28000800, 0x40000101, - 0x00440402, 0x00002028, 0x2c000800, 0x40100101, - 0x80000002, 0x00002010, 0x20000000, 0x00800001, - 0x80040002, 0x00002010, 0x24000000, 0x00900001, - 0x80400002, 0x00002018, 0x20000800, 0x40800001, - 0x80440002, 0x00002018, 0x24000800, 0x40900001, - 0x80000402, 0x00002030, 0x28000000, 0x00800101, - 0x80040402, 0x00002030, 0x2c000000, 0x00900101, - 0x80400402, 0x00002038, 0x28000800, 0x40800101, - 0x80440402, 0x00002038, 0x2c000800, 0x40900101, - 0x10000002, 0x00002000, 0x20200000, 0x00001001, - 0x10040002, 0x00002000, 0x24200000, 0x00101001, - 0x10400002, 0x00002008, 0x20200800, 0x40001001, - 0x10440002, 0x00002008, 0x24200800, 0x40101001, - 0x10000402, 0x00002020, 0x28200000, 0x00001101, - 0x10040402, 0x00002020, 0x2c200000, 0x00101101, - 0x10400402, 0x00002028, 0x28200800, 0x40001101, - 0x10440402, 0x00002028, 0x2c200800, 0x40101101, - 0x90000002, 0x00002010, 0x20200000, 0x00801001, - 0x90040002, 0x00002010, 0x24200000, 0x00901001, - 0x90400002, 0x00002018, 0x20200800, 0x40801001, - 0x90440002, 0x00002018, 0x24200800, 0x40901001, - 0x90000402, 0x00002030, 0x28200000, 0x00801101, - 0x90040402, 0x00002030, 0x2c200000, 0x00901101, - 0x90400402, 0x00002038, 0x28200800, 0x40801101, - 0x90440402, 0x00002038, 0x2c200800, 0x40901101, - 0x00000202, 0x00082000, 0x20000000, 0x00000005, - 0x00040202, 0x00082000, 0x24000000, 0x00100005, - 0x00400202, 0x00082008, 0x20000800, 0x40000005, - 0x00440202, 0x00082008, 0x24000800, 0x40100005, - 0x00000602, 0x00082020, 0x28000000, 0x00000105, - 0x00040602, 0x00082020, 0x2c000000, 0x00100105, - 0x00400602, 0x00082028, 0x28000800, 0x40000105, - 0x00440602, 0x00082028, 0x2c000800, 0x40100105, - 0x80000202, 0x00082010, 0x20000000, 0x00800005, - 0x80040202, 0x00082010, 0x24000000, 0x00900005, - 0x80400202, 0x00082018, 0x20000800, 0x40800005, - 0x80440202, 0x00082018, 0x24000800, 0x40900005, - 0x80000602, 0x00082030, 0x28000000, 0x00800105, - 0x80040602, 0x00082030, 0x2c000000, 0x00900105, - 0x80400602, 0x00082038, 0x28000800, 0x40800105, - 0x80440602, 0x00082038, 0x2c000800, 0x40900105, - 0x10000202, 0x00082000, 0x20200000, 0x00001005, - 0x10040202, 0x00082000, 0x24200000, 0x00101005, - 0x10400202, 0x00082008, 0x20200800, 0x40001005, - 0x10440202, 0x00082008, 0x24200800, 0x40101005, - 0x10000602, 0x00082020, 0x28200000, 0x00001105, - 0x10040602, 0x00082020, 0x2c200000, 0x00101105, - 0x10400602, 0x00082028, 0x28200800, 0x40001105, - 0x10440602, 0x00082028, 0x2c200800, 0x40101105, - 0x90000202, 0x00082010, 0x20200000, 0x00801005, - 0x90040202, 0x00082010, 0x24200000, 0x00901005, - 0x90400202, 0x00082018, 0x20200800, 0x40801005, - 0x90440202, 0x00082018, 0x24200800, 0x40901005, - 0x90000602, 0x00082030, 0x28200000, 0x00801105, - 0x90040602, 0x00082030, 0x2c200000, 0x00901105, - 0x90400602, 0x00082038, 0x28200800, 0x40801105, - 0x90440602, 0x00082038, 0x2c200800, 0x40901105, - - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000008, 0x00080000, 0x10000000, - 0x02000000, 0x00000000, 0x00000080, 0x00001000, - 0x02000000, 0x00000008, 0x00080080, 0x10001000, - 0x00004000, 0x00000000, 0x00000040, 0x00040000, - 0x00004000, 0x00000008, 0x00080040, 0x10040000, - 0x02004000, 0x00000000, 0x000000c0, 0x00041000, - 0x02004000, 0x00000008, 0x000800c0, 0x10041000, - 0x00020000, 0x00008000, 0x08000000, 0x00200000, - 0x00020000, 0x00008008, 0x08080000, 0x10200000, - 0x02020000, 0x00008000, 0x08000080, 0x00201000, - 0x02020000, 0x00008008, 0x08080080, 0x10201000, - 0x00024000, 0x00008000, 0x08000040, 0x00240000, - 0x00024000, 0x00008008, 0x08080040, 0x10240000, - 0x02024000, 0x00008000, 0x080000c0, 0x00241000, - 0x02024000, 0x00008008, 0x080800c0, 0x10241000, - 0x00000000, 0x01000000, 0x00002000, 0x00000020, - 0x00000000, 0x01000008, 0x00082000, 0x10000020, - 0x02000000, 0x01000000, 0x00002080, 0x00001020, - 0x02000000, 0x01000008, 0x00082080, 0x10001020, - 0x00004000, 0x01000000, 0x00002040, 0x00040020, - 0x00004000, 0x01000008, 0x00082040, 0x10040020, - 0x02004000, 0x01000000, 0x000020c0, 0x00041020, - 0x02004000, 0x01000008, 0x000820c0, 0x10041020, - 0x00020000, 0x01008000, 0x08002000, 0x00200020, - 0x00020000, 0x01008008, 0x08082000, 0x10200020, - 0x02020000, 0x01008000, 0x08002080, 0x00201020, - 0x02020000, 0x01008008, 0x08082080, 0x10201020, - 0x00024000, 0x01008000, 0x08002040, 0x00240020, - 0x00024000, 0x01008008, 0x08082040, 0x10240020, - 0x02024000, 0x01008000, 0x080020c0, 0x00241020, - 0x02024000, 0x01008008, 0x080820c0, 0x10241020, - 0x00000400, 0x04000000, 0x00100000, 0x00000004, - 0x00000400, 0x04000008, 0x00180000, 0x10000004, - 0x02000400, 0x04000000, 0x00100080, 0x00001004, - 0x02000400, 0x04000008, 0x00180080, 0x10001004, - 0x00004400, 0x04000000, 0x00100040, 0x00040004, - 0x00004400, 0x04000008, 0x00180040, 0x10040004, - 0x02004400, 0x04000000, 0x001000c0, 0x00041004, - 0x02004400, 0x04000008, 0x001800c0, 0x10041004, - 0x00020400, 0x04008000, 0x08100000, 0x00200004, - 0x00020400, 0x04008008, 0x08180000, 0x10200004, - 0x02020400, 0x04008000, 0x08100080, 0x00201004, - 0x02020400, 0x04008008, 0x08180080, 0x10201004, - 0x00024400, 0x04008000, 0x08100040, 0x00240004, - 0x00024400, 0x04008008, 0x08180040, 0x10240004, - 0x02024400, 0x04008000, 0x081000c0, 0x00241004, - 0x02024400, 0x04008008, 0x081800c0, 0x10241004, - 0x00000400, 0x05000000, 0x00102000, 0x00000024, - 0x00000400, 0x05000008, 0x00182000, 0x10000024, - 0x02000400, 0x05000000, 0x00102080, 0x00001024, - 0x02000400, 0x05000008, 0x00182080, 0x10001024, - 0x00004400, 0x05000000, 0x00102040, 0x00040024, - 0x00004400, 0x05000008, 0x00182040, 0x10040024, - 0x02004400, 0x05000000, 0x001020c0, 0x00041024, - 0x02004400, 0x05000008, 0x001820c0, 0x10041024, - 0x00020400, 0x05008000, 0x08102000, 0x00200024, - 0x00020400, 0x05008008, 0x08182000, 0x10200024, - 0x02020400, 0x05008000, 0x08102080, 0x00201024, - 0x02020400, 0x05008008, 0x08182080, 0x10201024, - 0x00024400, 0x05008000, 0x08102040, 0x00240024, - 0x00024400, 0x05008008, 0x08182040, 0x10240024, - 0x02024400, 0x05008000, 0x081020c0, 0x00241024, - 0x02024400, 0x05008008, 0x081820c0, 0x10241024, - 0x00000800, 0x00010000, 0x20000000, 0x00000010, - 0x00000800, 0x00010008, 0x20080000, 0x10000010, - 0x02000800, 0x00010000, 0x20000080, 0x00001010, - 0x02000800, 0x00010008, 0x20080080, 0x10001010, - 0x00004800, 0x00010000, 0x20000040, 0x00040010, - 0x00004800, 0x00010008, 0x20080040, 0x10040010, - 0x02004800, 0x00010000, 0x200000c0, 0x00041010, - 0x02004800, 0x00010008, 0x200800c0, 0x10041010, - 0x00020800, 0x00018000, 0x28000000, 0x00200010, - 0x00020800, 0x00018008, 0x28080000, 0x10200010, - 0x02020800, 0x00018000, 0x28000080, 0x00201010, - 0x02020800, 0x00018008, 0x28080080, 0x10201010, - 0x00024800, 0x00018000, 0x28000040, 0x00240010, - 0x00024800, 0x00018008, 0x28080040, 0x10240010, - 0x02024800, 0x00018000, 0x280000c0, 0x00241010, - 0x02024800, 0x00018008, 0x280800c0, 0x10241010, - 0x00000800, 0x01010000, 0x20002000, 0x00000030, - 0x00000800, 0x01010008, 0x20082000, 0x10000030, - 0x02000800, 0x01010000, 0x20002080, 0x00001030, - 0x02000800, 0x01010008, 0x20082080, 0x10001030, - 0x00004800, 0x01010000, 0x20002040, 0x00040030, - 0x00004800, 0x01010008, 0x20082040, 0x10040030, - 0x02004800, 0x01010000, 0x200020c0, 0x00041030, - 0x02004800, 0x01010008, 0x200820c0, 0x10041030, - 0x00020800, 0x01018000, 0x28002000, 0x00200030, - 0x00020800, 0x01018008, 0x28082000, 0x10200030, - 0x02020800, 0x01018000, 0x28002080, 0x00201030, - 0x02020800, 0x01018008, 0x28082080, 0x10201030, - 0x00024800, 0x01018000, 0x28002040, 0x00240030, - 0x00024800, 0x01018008, 0x28082040, 0x10240030, - 0x02024800, 0x01018000, 0x280020c0, 0x00241030, - 0x02024800, 0x01018008, 0x280820c0, 0x10241030, - 0x00000c00, 0x04010000, 0x20100000, 0x00000014, - 0x00000c00, 0x04010008, 0x20180000, 0x10000014, - 0x02000c00, 0x04010000, 0x20100080, 0x00001014, - 0x02000c00, 0x04010008, 0x20180080, 0x10001014, - 0x00004c00, 0x04010000, 0x20100040, 0x00040014, - 0x00004c00, 0x04010008, 0x20180040, 0x10040014, - 0x02004c00, 0x04010000, 0x201000c0, 0x00041014, - 0x02004c00, 0x04010008, 0x201800c0, 0x10041014, - 0x00020c00, 0x04018000, 0x28100000, 0x00200014, - 0x00020c00, 0x04018008, 0x28180000, 0x10200014, - 0x02020c00, 0x04018000, 0x28100080, 0x00201014, - 0x02020c00, 0x04018008, 0x28180080, 0x10201014, - 0x00024c00, 0x04018000, 0x28100040, 0x00240014, - 0x00024c00, 0x04018008, 0x28180040, 0x10240014, - 0x02024c00, 0x04018000, 0x281000c0, 0x00241014, - 0x02024c00, 0x04018008, 0x281800c0, 0x10241014, - 0x00000c00, 0x05010000, 0x20102000, 0x00000034, - 0x00000c00, 0x05010008, 0x20182000, 0x10000034, - 0x02000c00, 0x05010000, 0x20102080, 0x00001034, - 0x02000c00, 0x05010008, 0x20182080, 0x10001034, - 0x00004c00, 0x05010000, 0x20102040, 0x00040034, - 0x00004c00, 0x05010008, 0x20182040, 0x10040034, - 0x02004c00, 0x05010000, 0x201020c0, 0x00041034, - 0x02004c00, 0x05010008, 0x201820c0, 0x10041034, - 0x00020c00, 0x05018000, 0x28102000, 0x00200034, - 0x00020c00, 0x05018008, 0x28182000, 0x10200034, - 0x02020c00, 0x05018000, 0x28102080, 0x00201034, - 0x02020c00, 0x05018008, 0x28182080, 0x10201034, - 0x00024c00, 0x05018000, 0x28102040, 0x00240034, - 0x00024c00, 0x05018008, 0x28182040, 0x10240034, - 0x02024c00, 0x05018000, 0x281020c0, 0x00241034, - 0x02024c00, 0x05018008, 0x281820c0, 0x10241034 -}; - -/* S-box lookup tables */ - -static const u32 S1[64] = { - 0x01010400, 0x00000000, 0x00010000, 0x01010404, - 0x01010004, 0x00010404, 0x00000004, 0x00010000, - 0x00000400, 0x01010400, 0x01010404, 0x00000400, - 0x01000404, 0x01010004, 0x01000000, 0x00000004, - 0x00000404, 0x01000400, 0x01000400, 0x00010400, - 0x00010400, 0x01010000, 0x01010000, 0x01000404, - 0x00010004, 0x01000004, 0x01000004, 0x00010004, - 0x00000000, 0x00000404, 0x00010404, 0x01000000, - 0x00010000, 0x01010404, 0x00000004, 0x01010000, - 0x01010400, 0x01000000, 0x01000000, 0x00000400, - 0x01010004, 0x00010000, 0x00010400, 0x01000004, - 0x00000400, 0x00000004, 0x01000404, 0x00010404, - 0x01010404, 0x00010004, 0x01010000, 0x01000404, - 0x01000004, 0x00000404, 0x00010404, 0x01010400, - 0x00000404, 0x01000400, 0x01000400, 0x00000000, - 0x00010004, 0x00010400, 0x00000000, 0x01010004 -}; - -static const u32 S2[64] = { - 0x80108020, 0x80008000, 0x00008000, 0x00108020, - 0x00100000, 0x00000020, 0x80100020, 0x80008020, - 0x80000020, 0x80108020, 0x80108000, 0x80000000, - 0x80008000, 0x00100000, 0x00000020, 0x80100020, - 0x00108000, 0x00100020, 0x80008020, 0x00000000, - 0x80000000, 0x00008000, 0x00108020, 0x80100000, - 0x00100020, 0x80000020, 0x00000000, 0x00108000, - 0x00008020, 0x80108000, 0x80100000, 0x00008020, - 0x00000000, 0x00108020, 0x80100020, 0x00100000, - 0x80008020, 0x80100000, 0x80108000, 0x00008000, - 0x80100000, 0x80008000, 0x00000020, 0x80108020, - 0x00108020, 0x00000020, 0x00008000, 0x80000000, - 0x00008020, 0x80108000, 0x00100000, 0x80000020, - 0x00100020, 0x80008020, 0x80000020, 0x00100020, - 0x00108000, 0x00000000, 0x80008000, 0x00008020, - 0x80000000, 0x80100020, 0x80108020, 0x00108000 -}; - -static const u32 S3[64] = { - 0x00000208, 0x08020200, 0x00000000, 0x08020008, - 0x08000200, 0x00000000, 0x00020208, 0x08000200, - 0x00020008, 0x08000008, 0x08000008, 0x00020000, - 0x08020208, 0x00020008, 0x08020000, 0x00000208, - 0x08000000, 0x00000008, 0x08020200, 0x00000200, - 0x00020200, 0x08020000, 0x08020008, 0x00020208, - 0x08000208, 0x00020200, 0x00020000, 0x08000208, - 0x00000008, 0x08020208, 0x00000200, 0x08000000, - 0x08020200, 0x08000000, 0x00020008, 0x00000208, - 0x00020000, 0x08020200, 0x08000200, 0x00000000, - 0x00000200, 0x00020008, 0x08020208, 0x08000200, - 0x08000008, 0x00000200, 0x00000000, 0x08020008, - 0x08000208, 0x00020000, 0x08000000, 0x08020208, - 0x00000008, 0x00020208, 0x00020200, 0x08000008, - 0x08020000, 0x08000208, 0x00000208, 0x08020000, - 0x00020208, 0x00000008, 0x08020008, 0x00020200 -}; - -static const u32 S4[64] = { - 0x00802001, 0x00002081, 0x00002081, 0x00000080, - 0x00802080, 0x00800081, 0x00800001, 0x00002001, - 0x00000000, 0x00802000, 0x00802000, 0x00802081, - 0x00000081, 0x00000000, 0x00800080, 0x00800001, - 0x00000001, 0x00002000, 0x00800000, 0x00802001, - 0x00000080, 0x00800000, 0x00002001, 0x00002080, - 0x00800081, 0x00000001, 0x00002080, 0x00800080, - 0x00002000, 0x00802080, 0x00802081, 0x00000081, - 0x00800080, 0x00800001, 0x00802000, 0x00802081, - 0x00000081, 0x00000000, 0x00000000, 0x00802000, - 0x00002080, 0x00800080, 0x00800081, 0x00000001, - 0x00802001, 0x00002081, 0x00002081, 0x00000080, - 0x00802081, 0x00000081, 0x00000001, 0x00002000, - 0x00800001, 0x00002001, 0x00802080, 0x00800081, - 0x00002001, 0x00002080, 0x00800000, 0x00802001, - 0x00000080, 0x00800000, 0x00002000, 0x00802080 -}; - -static const u32 S5[64] = { - 0x00000100, 0x02080100, 0x02080000, 0x42000100, - 0x00080000, 0x00000100, 0x40000000, 0x02080000, - 0x40080100, 0x00080000, 0x02000100, 0x40080100, - 0x42000100, 0x42080000, 0x00080100, 0x40000000, - 0x02000000, 0x40080000, 0x40080000, 0x00000000, - 0x40000100, 0x42080100, 0x42080100, 0x02000100, - 0x42080000, 0x40000100, 0x00000000, 0x42000000, - 0x02080100, 0x02000000, 0x42000000, 0x00080100, - 0x00080000, 0x42000100, 0x00000100, 0x02000000, - 0x40000000, 0x02080000, 0x42000100, 0x40080100, - 0x02000100, 0x40000000, 0x42080000, 0x02080100, - 0x40080100, 0x00000100, 0x02000000, 0x42080000, - 0x42080100, 0x00080100, 0x42000000, 0x42080100, - 0x02080000, 0x00000000, 0x40080000, 0x42000000, - 0x00080100, 0x02000100, 0x40000100, 0x00080000, - 0x00000000, 0x40080000, 0x02080100, 0x40000100 -}; - -static const u32 S6[64] = { - 0x20000010, 0x20400000, 0x00004000, 0x20404010, - 0x20400000, 0x00000010, 0x20404010, 0x00400000, - 0x20004000, 0x00404010, 0x00400000, 0x20000010, - 0x00400010, 0x20004000, 0x20000000, 0x00004010, - 0x00000000, 0x00400010, 0x20004010, 0x00004000, - 0x00404000, 0x20004010, 0x00000010, 0x20400010, - 0x20400010, 0x00000000, 0x00404010, 0x20404000, - 0x00004010, 0x00404000, 0x20404000, 0x20000000, - 0x20004000, 0x00000010, 0x20400010, 0x00404000, - 0x20404010, 0x00400000, 0x00004010, 0x20000010, - 0x00400000, 0x20004000, 0x20000000, 0x00004010, - 0x20000010, 0x20404010, 0x00404000, 0x20400000, - 0x00404010, 0x20404000, 0x00000000, 0x20400010, - 0x00000010, 0x00004000, 0x20400000, 0x00404010, - 0x00004000, 0x00400010, 0x20004010, 0x00000000, - 0x20404000, 0x20000000, 0x00400010, 0x20004010 -}; - -static const u32 S7[64] = { - 0x00200000, 0x04200002, 0x04000802, 0x00000000, - 0x00000800, 0x04000802, 0x00200802, 0x04200800, - 0x04200802, 0x00200000, 0x00000000, 0x04000002, - 0x00000002, 0x04000000, 0x04200002, 0x00000802, - 0x04000800, 0x00200802, 0x00200002, 0x04000800, - 0x04000002, 0x04200000, 0x04200800, 0x00200002, - 0x04200000, 0x00000800, 0x00000802, 0x04200802, - 0x00200800, 0x00000002, 0x04000000, 0x00200800, - 0x04000000, 0x00200800, 0x00200000, 0x04000802, - 0x04000802, 0x04200002, 0x04200002, 0x00000002, - 0x00200002, 0x04000000, 0x04000800, 0x00200000, - 0x04200800, 0x00000802, 0x00200802, 0x04200800, - 0x00000802, 0x04000002, 0x04200802, 0x04200000, - 0x00200800, 0x00000000, 0x00000002, 0x04200802, - 0x00000000, 0x00200802, 0x04200000, 0x00000800, - 0x04000002, 0x04000800, 0x00000800, 0x00200002 -}; - -static const u32 S8[64] = { - 0x10001040, 0x00001000, 0x00040000, 0x10041040, - 0x10000000, 0x10001040, 0x00000040, 0x10000000, - 0x00040040, 0x10040000, 0x10041040, 0x00041000, - 0x10041000, 0x00041040, 0x00001000, 0x00000040, - 0x10040000, 0x10000040, 0x10001000, 0x00001040, - 0x00041000, 0x00040040, 0x10040040, 0x10041000, - 0x00001040, 0x00000000, 0x00000000, 0x10040040, - 0x10000040, 0x10001000, 0x00041040, 0x00040000, - 0x00041040, 0x00040000, 0x10041000, 0x00001000, - 0x00000040, 0x10040040, 0x00001000, 0x00041040, - 0x10001000, 0x00000040, 0x10000040, 0x10040000, - 0x10040040, 0x10000000, 0x00040000, 0x10001040, - 0x00000000, 0x10041040, 0x00040040, 0x10000040, - 0x10040000, 0x10001000, 0x10001040, 0x00000000, - 0x10041040, 0x00041000, 0x00041000, 0x00001040, - 0x00001040, 0x00040040, 0x10000000, 0x10041000 -}; - -/* Encryption components: IP, FP, and round function */ - -#define IP(L, R, T) \ - ROL(R, 4); \ - T = L; \ - L ^= R; \ - L &= 0xf0f0f0f0; \ - R ^= L; \ - L ^= T; \ - ROL(R, 12); \ - T = L; \ - L ^= R; \ - L &= 0xffff0000; \ - R ^= L; \ - L ^= T; \ - ROR(R, 14); \ - T = L; \ - L ^= R; \ - L &= 0xcccccccc; \ - R ^= L; \ - L ^= T; \ - ROL(R, 6); \ - T = L; \ - L ^= R; \ - L &= 0xff00ff00; \ - R ^= L; \ - L ^= T; \ - ROR(R, 7); \ - T = L; \ - L ^= R; \ - L &= 0xaaaaaaaa; \ - R ^= L; \ - L ^= T; \ - ROL(L, 1); - -#define FP(L, R, T) \ - ROR(L, 1); \ - T = L; \ - L ^= R; \ - L &= 0xaaaaaaaa; \ - R ^= L; \ - L ^= T; \ - ROL(R, 7); \ - T = L; \ - L ^= R; \ - L &= 0xff00ff00; \ - R ^= L; \ - L ^= T; \ - ROR(R, 6); \ - T = L; \ - L ^= R; \ - L &= 0xcccccccc; \ - R ^= L; \ - L ^= T; \ - ROL(R, 14); \ - T = L; \ - L ^= R; \ - L &= 0xffff0000; \ - R ^= L; \ - L ^= T; \ - ROR(R, 12); \ - T = L; \ - L ^= R; \ - L &= 0xf0f0f0f0; \ - R ^= L; \ - L ^= T; \ - ROR(R, 4); - -#define ROUND(L, R, A, B, K, d) \ - B = K[0]; A = K[1]; K += d; \ - B ^= R; A ^= R; \ - B &= 0x3f3f3f3f; ROR(A, 4); \ - L ^= S8[0xff & B]; A &= 0x3f3f3f3f; \ - L ^= S6[0xff & (B >> 8)]; B >>= 16; \ - L ^= S7[0xff & A]; \ - L ^= S5[0xff & (A >> 8)]; A >>= 16; \ - L ^= S4[0xff & B]; \ - L ^= S2[0xff & (B >> 8)]; \ - L ^= S3[0xff & A]; \ - L ^= S1[0xff & (A >> 8)]; - -/* - * PC2 lookup tables are organized as 2 consecutive sets of 4 interleaved - * tables of 128 elements. One set is for C_i and the other for D_i, while - * the 4 interleaved tables correspond to four 7-bit subsets of C_i or D_i. - * - * After PC1 each of the variables a,b,c,d contains a 7 bit subset of C_i - * or D_i in bits 7-1 (bit 0 being the least significant). - */ - -#define T1(x) pt[2 * (x) + 0] -#define T2(x) pt[2 * (x) + 1] -#define T3(x) pt[2 * (x) + 2] -#define T4(x) pt[2 * (x) + 3] - -#define DES_PC2(a, b, c, d) (T4(d) | T3(c) | T2(b) | T1(a)) - -/* - * Encryption key expansion - * - * RFC2451: Weak key checks SHOULD be performed. - * - * FIPS 74: - * - * Keys having duals are keys which produce all zeros, all ones, or - * alternating zero-one patterns in the C and D registers after Permuted - * Choice 1 has operated on the key. - * - */ -unsigned long des_ekey(u32 *pe, const u8 *k) -{ - /* K&R: long is at least 32 bits */ - unsigned long a, b, c, d, w; - const u32 *pt = pc2; - - d = k[4]; d &= 0x0e; d <<= 4; d |= k[0] & 0x1e; d = pc1[d]; - c = k[5]; c &= 0x0e; c <<= 4; c |= k[1] & 0x1e; c = pc1[c]; - b = k[6]; b &= 0x0e; b <<= 4; b |= k[2] & 0x1e; b = pc1[b]; - a = k[7]; a &= 0x0e; a <<= 4; a |= k[3] & 0x1e; a = pc1[a]; - - pe[15 * 2 + 0] = DES_PC2(a, b, c, d); d = rs[d]; - pe[14 * 2 + 0] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b]; - pe[13 * 2 + 0] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d]; - pe[12 * 2 + 0] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b]; - pe[11 * 2 + 0] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d]; - pe[10 * 2 + 0] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b]; - pe[ 9 * 2 + 0] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d]; - pe[ 8 * 2 + 0] = DES_PC2(d, a, b, c); c = rs[c]; - pe[ 7 * 2 + 0] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a]; - pe[ 6 * 2 + 0] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c]; - pe[ 5 * 2 + 0] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a]; - pe[ 4 * 2 + 0] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c]; - pe[ 3 * 2 + 0] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a]; - pe[ 2 * 2 + 0] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c]; - pe[ 1 * 2 + 0] = DES_PC2(c, d, a, b); b = rs[b]; - pe[ 0 * 2 + 0] = DES_PC2(b, c, d, a); - - /* Check if first half is weak */ - w = (a ^ c) | (b ^ d) | (rs[a] ^ c) | (b ^ rs[d]); - - /* Skip to next table set */ - pt += 512; - - d = k[0]; d &= 0xe0; d >>= 4; d |= k[4] & 0xf0; d = pc1[d + 1]; - c = k[1]; c &= 0xe0; c >>= 4; c |= k[5] & 0xf0; c = pc1[c + 1]; - b = k[2]; b &= 0xe0; b >>= 4; b |= k[6] & 0xf0; b = pc1[b + 1]; - a = k[3]; a &= 0xe0; a >>= 4; a |= k[7] & 0xf0; a = pc1[a + 1]; - - /* Check if second half is weak */ - w |= (a ^ c) | (b ^ d) | (rs[a] ^ c) | (b ^ rs[d]); - - pe[15 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; - pe[14 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b]; - pe[13 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d]; - pe[12 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b]; - pe[11 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d]; - pe[10 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b]; - pe[ 9 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d]; - pe[ 8 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; - pe[ 7 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a]; - pe[ 6 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c]; - pe[ 5 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a]; - pe[ 4 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c]; - pe[ 3 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a]; - pe[ 2 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c]; - pe[ 1 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; - pe[ 0 * 2 + 1] = DES_PC2(b, c, d, a); - - /* Fixup: 2413 5768 -> 1357 2468 */ - for (d = 0; d < 16; ++d) { - a = pe[2 * d]; - b = pe[2 * d + 1]; - c = a ^ b; - c &= 0xffff0000; - a ^= c; - b ^= c; - ROL(b, 18); - pe[2 * d] = a; - pe[2 * d + 1] = b; - } - - /* Zero if weak key */ - return w; -} -EXPORT_SYMBOL_GPL(des_ekey); - -/* - * Decryption key expansion - * - * No weak key checking is performed, as this is only used by triple DES - * - */ -static void dkey(u32 *pe, const u8 *k) -{ - /* K&R: long is at least 32 bits */ - unsigned long a, b, c, d; - const u32 *pt = pc2; - - d = k[4]; d &= 0x0e; d <<= 4; d |= k[0] & 0x1e; d = pc1[d]; - c = k[5]; c &= 0x0e; c <<= 4; c |= k[1] & 0x1e; c = pc1[c]; - b = k[6]; b &= 0x0e; b <<= 4; b |= k[2] & 0x1e; b = pc1[b]; - a = k[7]; a &= 0x0e; a <<= 4; a |= k[3] & 0x1e; a = pc1[a]; - - pe[ 0 * 2] = DES_PC2(a, b, c, d); d = rs[d]; - pe[ 1 * 2] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b]; - pe[ 2 * 2] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d]; - pe[ 3 * 2] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b]; - pe[ 4 * 2] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d]; - pe[ 5 * 2] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b]; - pe[ 6 * 2] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d]; - pe[ 7 * 2] = DES_PC2(d, a, b, c); c = rs[c]; - pe[ 8 * 2] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a]; - pe[ 9 * 2] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c]; - pe[10 * 2] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a]; - pe[11 * 2] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c]; - pe[12 * 2] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a]; - pe[13 * 2] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c]; - pe[14 * 2] = DES_PC2(c, d, a, b); b = rs[b]; - pe[15 * 2] = DES_PC2(b, c, d, a); - - /* Skip to next table set */ - pt += 512; - - d = k[0]; d &= 0xe0; d >>= 4; d |= k[4] & 0xf0; d = pc1[d + 1]; - c = k[1]; c &= 0xe0; c >>= 4; c |= k[5] & 0xf0; c = pc1[c + 1]; - b = k[2]; b &= 0xe0; b >>= 4; b |= k[6] & 0xf0; b = pc1[b + 1]; - a = k[3]; a &= 0xe0; a >>= 4; a |= k[7] & 0xf0; a = pc1[a + 1]; - - pe[ 0 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; - pe[ 1 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b]; - pe[ 2 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d]; - pe[ 3 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b]; - pe[ 4 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d]; - pe[ 5 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b]; - pe[ 6 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d]; - pe[ 7 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; - pe[ 8 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a]; - pe[ 9 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c]; - pe[10 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a]; - pe[11 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c]; - pe[12 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a]; - pe[13 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c]; - pe[14 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; - pe[15 * 2 + 1] = DES_PC2(b, c, d, a); - - /* Fixup: 2413 5768 -> 1357 2468 */ - for (d = 0; d < 16; ++d) { - a = pe[2 * d]; - b = pe[2 * d + 1]; - c = a ^ b; - c &= 0xffff0000; - a ^= c; - b ^= c; - ROL(b, 18); - pe[2 * d] = a; - pe[2 * d + 1] = b; - } -} +#include static int des_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) { struct des_ctx *dctx = crypto_tfm_ctx(tfm); - u32 *flags = &tfm->crt_flags; - u32 tmp[DES_EXPKEY_WORDS]; - int ret; - - /* Expand to tmp */ - ret = des_ekey(tmp, key); + int err; - if (unlikely(ret == 0) && (*flags & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) { - *flags |= CRYPTO_TFM_RES_WEAK_KEY; - return -EINVAL; + err = des_expand_key(dctx, key, keylen); + if (err == -ENOKEY) { + if (crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS) + err = -EINVAL; + else + err = 0; } - /* Copy to output */ - memcpy(dctx->expkey, tmp, sizeof(dctx->expkey)); - - return 0; -} - -static void des_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) -{ - struct des_ctx *ctx = crypto_tfm_ctx(tfm); - const u32 *K = ctx->expkey; - const __le32 *s = (const __le32 *)src; - __le32 *d = (__le32 *)dst; - u32 L, R, A, B; - int i; - - L = le32_to_cpu(s[0]); - R = le32_to_cpu(s[1]); - - IP(L, R, A); - for (i = 0; i < 8; i++) { - ROUND(L, R, A, B, K, 2); - ROUND(R, L, A, B, K, 2); + if (err) { + memset(dctx, 0, sizeof(*dctx)); + crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_WEAK_KEY); } - FP(R, L, A); - - d[0] = cpu_to_le32(R); - d[1] = cpu_to_le32(L); + return err; } -static void des_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +static void crypto_des_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { - struct des_ctx *ctx = crypto_tfm_ctx(tfm); - const u32 *K = ctx->expkey + DES_EXPKEY_WORDS - 2; - const __le32 *s = (const __le32 *)src; - __le32 *d = (__le32 *)dst; - u32 L, R, A, B; - int i; - - L = le32_to_cpu(s[0]); - R = le32_to_cpu(s[1]); + const struct des_ctx *dctx = crypto_tfm_ctx(tfm); - IP(L, R, A); - for (i = 0; i < 8; i++) { - ROUND(L, R, A, B, K, -2); - ROUND(R, L, A, B, K, -2); - } - FP(R, L, A); - - d[0] = cpu_to_le32(R); - d[1] = cpu_to_le32(L); + des_encrypt(dctx, dst, src); } -/* - * RFC2451: - * - * For DES-EDE3, there is no known need to reject weak or - * complementation keys. Any weakness is obviated by the use of - * multiple keys. - * - * However, if the first two or last two independent 64-bit keys are - * equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the - * same as DES. Implementers MUST reject keys that exhibit this - * property. - * - */ -int __des3_ede_setkey(u32 *expkey, u32 *flags, const u8 *key, - unsigned int keylen) +static void crypto_des_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { - int err; + const struct des_ctx *dctx = crypto_tfm_ctx(tfm); - err = __des3_verify_key(flags, key); - if (unlikely(err)) - return err; - - des_ekey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE; - dkey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE; - des_ekey(expkey, key); - - return 0; + des_decrypt(dctx, dst, src); } -EXPORT_SYMBOL_GPL(__des3_ede_setkey); static int des3_ede_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) { struct des3_ede_ctx *dctx = crypto_tfm_ctx(tfm); - u32 *flags = &tfm->crt_flags; - u32 *expkey = dctx->expkey; - - return __des3_ede_setkey(expkey, flags, key, keylen); -} - -static void des3_ede_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) -{ - struct des3_ede_ctx *dctx = crypto_tfm_ctx(tfm); - const u32 *K = dctx->expkey; - const __le32 *s = (const __le32 *)src; - __le32 *d = (__le32 *)dst; - u32 L, R, A, B; - int i; - - L = le32_to_cpu(s[0]); - R = le32_to_cpu(s[1]); + int err; - IP(L, R, A); - for (i = 0; i < 8; i++) { - ROUND(L, R, A, B, K, 2); - ROUND(R, L, A, B, K, 2); + err = des3_ede_expand_key(dctx, key, keylen); + if (err == -ENOKEY) { + if (crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS) + err = -EINVAL; + else + err = 0; } - for (i = 0; i < 8; i++) { - ROUND(R, L, A, B, K, 2); - ROUND(L, R, A, B, K, 2); - } - for (i = 0; i < 8; i++) { - ROUND(L, R, A, B, K, 2); - ROUND(R, L, A, B, K, 2); - } - FP(R, L, A); - d[0] = cpu_to_le32(R); - d[1] = cpu_to_le32(L); + if (err) { + memset(dctx, 0, sizeof(*dctx)); + crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_WEAK_KEY); + } + return err; } -static void des3_ede_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +static void crypto_des3_ede_encrypt(struct crypto_tfm *tfm, u8 *dst, + const u8 *src) { - struct des3_ede_ctx *dctx = crypto_tfm_ctx(tfm); - const u32 *K = dctx->expkey + DES3_EDE_EXPKEY_WORDS - 2; - const __le32 *s = (const __le32 *)src; - __le32 *d = (__le32 *)dst; - u32 L, R, A, B; - int i; + const struct des3_ede_ctx *dctx = crypto_tfm_ctx(tfm); - L = le32_to_cpu(s[0]); - R = le32_to_cpu(s[1]); + des3_ede_encrypt(dctx, dst, src); +} - IP(L, R, A); - for (i = 0; i < 8; i++) { - ROUND(L, R, A, B, K, -2); - ROUND(R, L, A, B, K, -2); - } - for (i = 0; i < 8; i++) { - ROUND(R, L, A, B, K, -2); - ROUND(L, R, A, B, K, -2); - } - for (i = 0; i < 8; i++) { - ROUND(L, R, A, B, K, -2); - ROUND(R, L, A, B, K, -2); - } - FP(R, L, A); +static void crypto_des3_ede_decrypt(struct crypto_tfm *tfm, u8 *dst, + const u8 *src) +{ + const struct des3_ede_ctx *dctx = crypto_tfm_ctx(tfm); - d[0] = cpu_to_le32(R); - d[1] = cpu_to_le32(L); + des3_ede_decrypt(dctx, dst, src); } static struct crypto_alg des_algs[2] = { { @@ -951,13 +96,12 @@ static struct crypto_alg des_algs[2] = { { .cra_blocksize = DES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct des_ctx), .cra_module = THIS_MODULE, - .cra_alignmask = 3, .cra_u = { .cipher = { .cia_min_keysize = DES_KEY_SIZE, .cia_max_keysize = DES_KEY_SIZE, .cia_setkey = des_setkey, - .cia_encrypt = des_encrypt, - .cia_decrypt = des_decrypt } } + .cia_encrypt = crypto_des_encrypt, + .cia_decrypt = crypto_des_decrypt } } }, { .cra_name = "des3_ede", .cra_driver_name = "des3_ede-generic", @@ -966,13 +110,12 @@ static struct crypto_alg des_algs[2] = { { .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct des3_ede_ctx), .cra_module = THIS_MODULE, - .cra_alignmask = 3, .cra_u = { .cipher = { .cia_min_keysize = DES3_EDE_KEY_SIZE, .cia_max_keysize = DES3_EDE_KEY_SIZE, .cia_setkey = des3_ede_setkey, - .cia_encrypt = des3_ede_encrypt, - .cia_decrypt = des3_ede_decrypt } } + .cia_encrypt = crypto_des3_ede_encrypt, + .cia_decrypt = crypto_des3_ede_decrypt } } } }; static int __init des_generic_mod_init(void) diff --git a/crypto/fips.c b/crypto/fips.c index c0b3a3c3452dd49da5756c8568706356ee7be4ed..7b1d8caee669292b5f039c5ab1047fddcf09966e 100644 --- a/crypto/fips.c +++ b/crypto/fips.c @@ -11,10 +11,14 @@ #include #include #include +#include int fips_enabled; EXPORT_SYMBOL_GPL(fips_enabled); +ATOMIC_NOTIFIER_HEAD(fips_fail_notif_chain); +EXPORT_SYMBOL_GPL(fips_fail_notif_chain); + /* Process kernel command-line parameter at boot time. fips=0 or fips=1 */ static int fips_enable(char *str) { @@ -58,6 +62,13 @@ static void crypto_proc_fips_exit(void) unregister_sysctl_table(crypto_sysctls); } +void fips_fail_notify(void) +{ + if (fips_enabled) + atomic_notifier_call_chain(&fips_fail_notif_chain, 0, NULL); +} +EXPORT_SYMBOL_GPL(fips_fail_notify); + static int __init fips_init(void) { crypto_proc_fips_init(); diff --git a/crypto/gcm.c b/crypto/gcm.c index f254e2d4c206aacc341548dd40744f02459956ab..73884208f07532761ac3c957c8c29897628ca455 100644 --- a/crypto/gcm.c +++ b/crypto/gcm.c @@ -152,20 +152,7 @@ static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key, static int crypto_gcm_setauthsize(struct crypto_aead *tfm, unsigned int authsize) { - switch (authsize) { - case 4: - case 8: - case 12: - case 13: - case 14: - case 15: - case 16: - break; - default: - return -EINVAL; - } - - return 0; + return crypto_gcm_check_authsize(authsize); } static void crypto_gcm_init_common(struct aead_request *req) @@ -762,15 +749,11 @@ static int crypto_rfc4106_setauthsize(struct crypto_aead *parent, unsigned int authsize) { struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent); + int err; - switch (authsize) { - case 8: - case 12: - case 16: - break; - default: - return -EINVAL; - } + err = crypto_rfc4106_check_authsize(authsize); + if (err) + return err; return crypto_aead_setauthsize(ctx->child, authsize); } @@ -818,8 +801,11 @@ static struct aead_request *crypto_rfc4106_crypt(struct aead_request *req) static int crypto_rfc4106_encrypt(struct aead_request *req) { - if (req->assoclen != 16 && req->assoclen != 20) - return -EINVAL; + int err; + + err = crypto_ipsec_check_assoclen(req->assoclen); + if (err) + return err; req = crypto_rfc4106_crypt(req); @@ -828,8 +814,11 @@ static int crypto_rfc4106_encrypt(struct aead_request *req) static int crypto_rfc4106_decrypt(struct aead_request *req) { - if (req->assoclen != 16 && req->assoclen != 20) - return -EINVAL; + int err; + + err = crypto_ipsec_check_assoclen(req->assoclen); + if (err) + return err; req = crypto_rfc4106_crypt(req); @@ -1045,12 +1034,14 @@ static int crypto_rfc4543_copy_src_to_dst(struct aead_request *req, bool enc) static int crypto_rfc4543_encrypt(struct aead_request *req) { - return crypto_rfc4543_crypt(req, true); + return crypto_ipsec_check_assoclen(req->assoclen) ?: + crypto_rfc4543_crypt(req, true); } static int crypto_rfc4543_decrypt(struct aead_request *req) { - return crypto_rfc4543_crypt(req, false); + return crypto_ipsec_check_assoclen(req->assoclen) ?: + crypto_rfc4543_crypt(req, false); } static int crypto_rfc4543_init_tfm(struct crypto_aead *tfm) diff --git a/crypto/ghash-generic.c b/crypto/ghash-generic.c index dad9e1f91a783f66f6cfcaf9521de45c6f57ba32..5027b3461c921eb90fddbbf1401b529452a63c4b 100644 --- a/crypto/ghash-generic.c +++ b/crypto/ghash-generic.c @@ -1,12 +1,37 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * GHASH: digest algorithm for GCM (Galois/Counter Mode). + * GHASH: hash function for GCM (Galois/Counter Mode). * * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen * Copyright (c) 2009 Intel Corp. * Author: Huang Ying + */ + +/* + * GHASH is a keyed hash function used in GCM authentication tag generation. + * + * The original GCM paper [1] presents GHASH as a function GHASH(H, A, C) which + * takes a 16-byte hash key H, additional authenticated data A, and a ciphertext + * C. It formats A and C into a single byte string X, interprets X as a + * polynomial over GF(2^128), and evaluates this polynomial at the point H. + * + * However, the NIST standard for GCM [2] presents GHASH as GHASH(H, X) where X + * is the already-formatted byte string containing both A and C. + * + * "ghash" in the Linux crypto API uses the 'X' (pre-formatted) convention, + * since the API supports only a single data stream per hash. Thus, the + * formatting of 'A' and 'C' is done in the "gcm" template, not in "ghash". + * + * The reason "ghash" is separate from "gcm" is to allow "gcm" to use an + * accelerated "ghash" when a standalone accelerated "gcm(aes)" is unavailable. + * It is generally inappropriate to use "ghash" for other purposes, since it is + * an "ε-almost-XOR-universal hash function", not a cryptographic hash function. + * It can only be used securely in crypto modes specially designed to use it. * - * The algorithm implementation is copied from gcm.c. + * [1] The Galois/Counter Mode of Operation (GCM) + * (http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.694.695&rep=rep1&type=pdf) + * [2] Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC + * (https://csrc.nist.gov/publications/detail/sp/800-38d/final) */ #include @@ -156,6 +181,6 @@ subsys_initcall(ghash_mod_init); module_exit(ghash_mod_exit); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("GHASH Message Digest Algorithm"); +MODULE_DESCRIPTION("GHASH hash function"); MODULE_ALIAS_CRYPTO("ghash"); MODULE_ALIAS_CRYPTO("ghash-generic"); diff --git a/crypto/morus1280.c b/crypto/morus1280.c deleted file mode 100644 index f8734c6576af6125a8f067fa89e1e9dc1ecd171b..0000000000000000000000000000000000000000 --- a/crypto/morus1280.c +++ /dev/null @@ -1,542 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * The MORUS-1280 Authenticated-Encryption Algorithm - * - * Copyright (c) 2016-2018 Ondrej Mosnacek - * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MORUS1280_WORD_SIZE 8 -#define MORUS1280_BLOCK_SIZE (MORUS_BLOCK_WORDS * MORUS1280_WORD_SIZE) -#define MORUS1280_BLOCK_ALIGN (__alignof__(__le64)) -#define MORUS1280_ALIGNED(p) IS_ALIGNED((uintptr_t)p, MORUS1280_BLOCK_ALIGN) - -struct morus1280_block { - u64 words[MORUS_BLOCK_WORDS]; -}; - -union morus1280_block_in { - __le64 words[MORUS_BLOCK_WORDS]; - u8 bytes[MORUS1280_BLOCK_SIZE]; -}; - -struct morus1280_state { - struct morus1280_block s[MORUS_STATE_BLOCKS]; -}; - -struct morus1280_ctx { - struct morus1280_block key; -}; - -struct morus1280_ops { - int (*skcipher_walk_init)(struct skcipher_walk *walk, - struct aead_request *req, bool atomic); - - void (*crypt_chunk)(struct morus1280_state *state, - u8 *dst, const u8 *src, unsigned int size); -}; - -static const struct morus1280_block crypto_morus1280_const[1] = { - { .words = { - U64_C(0x0d08050302010100), - U64_C(0x6279e99059372215), - U64_C(0xf12fc26d55183ddb), - U64_C(0xdd28b57342311120), - } }, -}; - -static void crypto_morus1280_round(struct morus1280_block *b0, - struct morus1280_block *b1, - struct morus1280_block *b2, - struct morus1280_block *b3, - struct morus1280_block *b4, - const struct morus1280_block *m, - unsigned int b, unsigned int w) -{ - unsigned int i; - struct morus1280_block tmp; - - for (i = 0; i < MORUS_BLOCK_WORDS; i++) { - b0->words[i] ^= b1->words[i] & b2->words[i]; - b0->words[i] ^= b3->words[i]; - b0->words[i] ^= m->words[i]; - b0->words[i] = rol64(b0->words[i], b); - } - - tmp = *b3; - for (i = 0; i < MORUS_BLOCK_WORDS; i++) - b3->words[(i + w) % MORUS_BLOCK_WORDS] = tmp.words[i]; -} - -static void crypto_morus1280_update(struct morus1280_state *state, - const struct morus1280_block *m) -{ - static const struct morus1280_block z = {}; - - struct morus1280_block *s = state->s; - - crypto_morus1280_round(&s[0], &s[1], &s[2], &s[3], &s[4], &z, 13, 1); - crypto_morus1280_round(&s[1], &s[2], &s[3], &s[4], &s[0], m, 46, 2); - crypto_morus1280_round(&s[2], &s[3], &s[4], &s[0], &s[1], m, 38, 3); - crypto_morus1280_round(&s[3], &s[4], &s[0], &s[1], &s[2], m, 7, 2); - crypto_morus1280_round(&s[4], &s[0], &s[1], &s[2], &s[3], m, 4, 1); -} - -static void crypto_morus1280_load_a(struct morus1280_block *dst, const u8 *src) -{ - unsigned int i; - for (i = 0; i < MORUS_BLOCK_WORDS; i++) { - dst->words[i] = le64_to_cpu(*(const __le64 *)src); - src += MORUS1280_WORD_SIZE; - } -} - -static void crypto_morus1280_load_u(struct morus1280_block *dst, const u8 *src) -{ - unsigned int i; - for (i = 0; i < MORUS_BLOCK_WORDS; i++) { - dst->words[i] = get_unaligned_le64(src); - src += MORUS1280_WORD_SIZE; - } -} - -static void crypto_morus1280_load(struct morus1280_block *dst, const u8 *src) -{ - if (MORUS1280_ALIGNED(src)) - crypto_morus1280_load_a(dst, src); - else - crypto_morus1280_load_u(dst, src); -} - -static void crypto_morus1280_store_a(u8 *dst, const struct morus1280_block *src) -{ - unsigned int i; - for (i = 0; i < MORUS_BLOCK_WORDS; i++) { - *(__le64 *)dst = cpu_to_le64(src->words[i]); - dst += MORUS1280_WORD_SIZE; - } -} - -static void crypto_morus1280_store_u(u8 *dst, const struct morus1280_block *src) -{ - unsigned int i; - for (i = 0; i < MORUS_BLOCK_WORDS; i++) { - put_unaligned_le64(src->words[i], dst); - dst += MORUS1280_WORD_SIZE; - } -} - -static void crypto_morus1280_store(u8 *dst, const struct morus1280_block *src) -{ - if (MORUS1280_ALIGNED(dst)) - crypto_morus1280_store_a(dst, src); - else - crypto_morus1280_store_u(dst, src); -} - -static void crypto_morus1280_ad(struct morus1280_state *state, const u8 *src, - unsigned int size) -{ - struct morus1280_block m; - - if (MORUS1280_ALIGNED(src)) { - while (size >= MORUS1280_BLOCK_SIZE) { - crypto_morus1280_load_a(&m, src); - crypto_morus1280_update(state, &m); - - size -= MORUS1280_BLOCK_SIZE; - src += MORUS1280_BLOCK_SIZE; - } - } else { - while (size >= MORUS1280_BLOCK_SIZE) { - crypto_morus1280_load_u(&m, src); - crypto_morus1280_update(state, &m); - - size -= MORUS1280_BLOCK_SIZE; - src += MORUS1280_BLOCK_SIZE; - } - } -} - -static void crypto_morus1280_core(const struct morus1280_state *state, - struct morus1280_block *blk) -{ - unsigned int i; - - for (i = 0; i < MORUS_BLOCK_WORDS; i++) - blk->words[(i + 3) % MORUS_BLOCK_WORDS] ^= state->s[1].words[i]; - - for (i = 0; i < MORUS_BLOCK_WORDS; i++) { - blk->words[i] ^= state->s[0].words[i]; - blk->words[i] ^= state->s[2].words[i] & state->s[3].words[i]; - } -} - -static void crypto_morus1280_encrypt_chunk(struct morus1280_state *state, - u8 *dst, const u8 *src, - unsigned int size) -{ - struct morus1280_block c, m; - - if (MORUS1280_ALIGNED(src) && MORUS1280_ALIGNED(dst)) { - while (size >= MORUS1280_BLOCK_SIZE) { - crypto_morus1280_load_a(&m, src); - c = m; - crypto_morus1280_core(state, &c); - crypto_morus1280_store_a(dst, &c); - crypto_morus1280_update(state, &m); - - src += MORUS1280_BLOCK_SIZE; - dst += MORUS1280_BLOCK_SIZE; - size -= MORUS1280_BLOCK_SIZE; - } - } else { - while (size >= MORUS1280_BLOCK_SIZE) { - crypto_morus1280_load_u(&m, src); - c = m; - crypto_morus1280_core(state, &c); - crypto_morus1280_store_u(dst, &c); - crypto_morus1280_update(state, &m); - - src += MORUS1280_BLOCK_SIZE; - dst += MORUS1280_BLOCK_SIZE; - size -= MORUS1280_BLOCK_SIZE; - } - } - - if (size > 0) { - union morus1280_block_in tail; - - memcpy(tail.bytes, src, size); - memset(tail.bytes + size, 0, MORUS1280_BLOCK_SIZE - size); - - crypto_morus1280_load_a(&m, tail.bytes); - c = m; - crypto_morus1280_core(state, &c); - crypto_morus1280_store_a(tail.bytes, &c); - crypto_morus1280_update(state, &m); - - memcpy(dst, tail.bytes, size); - } -} - -static void crypto_morus1280_decrypt_chunk(struct morus1280_state *state, - u8 *dst, const u8 *src, - unsigned int size) -{ - struct morus1280_block m; - - if (MORUS1280_ALIGNED(src) && MORUS1280_ALIGNED(dst)) { - while (size >= MORUS1280_BLOCK_SIZE) { - crypto_morus1280_load_a(&m, src); - crypto_morus1280_core(state, &m); - crypto_morus1280_store_a(dst, &m); - crypto_morus1280_update(state, &m); - - src += MORUS1280_BLOCK_SIZE; - dst += MORUS1280_BLOCK_SIZE; - size -= MORUS1280_BLOCK_SIZE; - } - } else { - while (size >= MORUS1280_BLOCK_SIZE) { - crypto_morus1280_load_u(&m, src); - crypto_morus1280_core(state, &m); - crypto_morus1280_store_u(dst, &m); - crypto_morus1280_update(state, &m); - - src += MORUS1280_BLOCK_SIZE; - dst += MORUS1280_BLOCK_SIZE; - size -= MORUS1280_BLOCK_SIZE; - } - } - - if (size > 0) { - union morus1280_block_in tail; - - memcpy(tail.bytes, src, size); - memset(tail.bytes + size, 0, MORUS1280_BLOCK_SIZE - size); - - crypto_morus1280_load_a(&m, tail.bytes); - crypto_morus1280_core(state, &m); - crypto_morus1280_store_a(tail.bytes, &m); - memset(tail.bytes + size, 0, MORUS1280_BLOCK_SIZE - size); - crypto_morus1280_load_a(&m, tail.bytes); - crypto_morus1280_update(state, &m); - - memcpy(dst, tail.bytes, size); - } -} - -static void crypto_morus1280_init(struct morus1280_state *state, - const struct morus1280_block *key, - const u8 *iv) -{ - static const struct morus1280_block z = {}; - - union morus1280_block_in tmp; - unsigned int i; - - memcpy(tmp.bytes, iv, MORUS_NONCE_SIZE); - memset(tmp.bytes + MORUS_NONCE_SIZE, 0, - MORUS1280_BLOCK_SIZE - MORUS_NONCE_SIZE); - - crypto_morus1280_load(&state->s[0], tmp.bytes); - state->s[1] = *key; - for (i = 0; i < MORUS_BLOCK_WORDS; i++) - state->s[2].words[i] = U64_C(0xFFFFFFFFFFFFFFFF); - state->s[3] = z; - state->s[4] = crypto_morus1280_const[0]; - - for (i = 0; i < 16; i++) - crypto_morus1280_update(state, &z); - - for (i = 0; i < MORUS_BLOCK_WORDS; i++) - state->s[1].words[i] ^= key->words[i]; -} - -static void crypto_morus1280_process_ad(struct morus1280_state *state, - struct scatterlist *sg_src, - unsigned int assoclen) -{ - struct scatter_walk walk; - struct morus1280_block m; - union morus1280_block_in buf; - unsigned int pos = 0; - - scatterwalk_start(&walk, sg_src); - while (assoclen != 0) { - unsigned int size = scatterwalk_clamp(&walk, assoclen); - unsigned int left = size; - void *mapped = scatterwalk_map(&walk); - const u8 *src = (const u8 *)mapped; - - if (pos + size >= MORUS1280_BLOCK_SIZE) { - if (pos > 0) { - unsigned int fill = MORUS1280_BLOCK_SIZE - pos; - memcpy(buf.bytes + pos, src, fill); - - crypto_morus1280_load_a(&m, buf.bytes); - crypto_morus1280_update(state, &m); - - pos = 0; - left -= fill; - src += fill; - } - - crypto_morus1280_ad(state, src, left); - src += left & ~(MORUS1280_BLOCK_SIZE - 1); - left &= MORUS1280_BLOCK_SIZE - 1; - } - - memcpy(buf.bytes + pos, src, left); - - pos += left; - assoclen -= size; - scatterwalk_unmap(mapped); - scatterwalk_advance(&walk, size); - scatterwalk_done(&walk, 0, assoclen); - } - - if (pos > 0) { - memset(buf.bytes + pos, 0, MORUS1280_BLOCK_SIZE - pos); - - crypto_morus1280_load_a(&m, buf.bytes); - crypto_morus1280_update(state, &m); - } -} - -static void crypto_morus1280_process_crypt(struct morus1280_state *state, - struct aead_request *req, - const struct morus1280_ops *ops) -{ - struct skcipher_walk walk; - - ops->skcipher_walk_init(&walk, req, false); - - while (walk.nbytes) { - unsigned int nbytes = walk.nbytes; - - if (nbytes < walk.total) - nbytes = round_down(nbytes, walk.stride); - - ops->crypt_chunk(state, walk.dst.virt.addr, walk.src.virt.addr, - nbytes); - - skcipher_walk_done(&walk, walk.nbytes - nbytes); - } -} - -static void crypto_morus1280_final(struct morus1280_state *state, - struct morus1280_block *tag_xor, - u64 assoclen, u64 cryptlen) -{ - struct morus1280_block tmp; - unsigned int i; - - tmp.words[0] = assoclen * 8; - tmp.words[1] = cryptlen * 8; - tmp.words[2] = 0; - tmp.words[3] = 0; - - for (i = 0; i < MORUS_BLOCK_WORDS; i++) - state->s[4].words[i] ^= state->s[0].words[i]; - - for (i = 0; i < 10; i++) - crypto_morus1280_update(state, &tmp); - - crypto_morus1280_core(state, tag_xor); -} - -static int crypto_morus1280_setkey(struct crypto_aead *aead, const u8 *key, - unsigned int keylen) -{ - struct morus1280_ctx *ctx = crypto_aead_ctx(aead); - union morus1280_block_in tmp; - - if (keylen == MORUS1280_BLOCK_SIZE) - crypto_morus1280_load(&ctx->key, key); - else if (keylen == MORUS1280_BLOCK_SIZE / 2) { - memcpy(tmp.bytes, key, keylen); - memcpy(tmp.bytes + keylen, key, keylen); - - crypto_morus1280_load(&ctx->key, tmp.bytes); - } else { - crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - return 0; -} - -static int crypto_morus1280_setauthsize(struct crypto_aead *tfm, - unsigned int authsize) -{ - return (authsize <= MORUS_MAX_AUTH_SIZE) ? 0 : -EINVAL; -} - -static void crypto_morus1280_crypt(struct aead_request *req, - struct morus1280_block *tag_xor, - unsigned int cryptlen, - const struct morus1280_ops *ops) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct morus1280_ctx *ctx = crypto_aead_ctx(tfm); - struct morus1280_state state; - - crypto_morus1280_init(&state, &ctx->key, req->iv); - crypto_morus1280_process_ad(&state, req->src, req->assoclen); - crypto_morus1280_process_crypt(&state, req, ops); - crypto_morus1280_final(&state, tag_xor, req->assoclen, cryptlen); -} - -static int crypto_morus1280_encrypt(struct aead_request *req) -{ - static const struct morus1280_ops ops = { - .skcipher_walk_init = skcipher_walk_aead_encrypt, - .crypt_chunk = crypto_morus1280_encrypt_chunk, - }; - - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct morus1280_block tag = {}; - union morus1280_block_in tag_out; - unsigned int authsize = crypto_aead_authsize(tfm); - unsigned int cryptlen = req->cryptlen; - - crypto_morus1280_crypt(req, &tag, cryptlen, &ops); - crypto_morus1280_store(tag_out.bytes, &tag); - - scatterwalk_map_and_copy(tag_out.bytes, req->dst, - req->assoclen + cryptlen, authsize, 1); - return 0; -} - -static int crypto_morus1280_decrypt(struct aead_request *req) -{ - static const struct morus1280_ops ops = { - .skcipher_walk_init = skcipher_walk_aead_decrypt, - .crypt_chunk = crypto_morus1280_decrypt_chunk, - }; - static const u8 zeros[MORUS1280_BLOCK_SIZE] = {}; - - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - union morus1280_block_in tag_in; - struct morus1280_block tag; - unsigned int authsize = crypto_aead_authsize(tfm); - unsigned int cryptlen = req->cryptlen - authsize; - - scatterwalk_map_and_copy(tag_in.bytes, req->src, - req->assoclen + cryptlen, authsize, 0); - - crypto_morus1280_load(&tag, tag_in.bytes); - crypto_morus1280_crypt(req, &tag, cryptlen, &ops); - crypto_morus1280_store(tag_in.bytes, &tag); - - return crypto_memneq(tag_in.bytes, zeros, authsize) ? -EBADMSG : 0; -} - -static int crypto_morus1280_init_tfm(struct crypto_aead *tfm) -{ - return 0; -} - -static void crypto_morus1280_exit_tfm(struct crypto_aead *tfm) -{ -} - -static struct aead_alg crypto_morus1280_alg = { - .setkey = crypto_morus1280_setkey, - .setauthsize = crypto_morus1280_setauthsize, - .encrypt = crypto_morus1280_encrypt, - .decrypt = crypto_morus1280_decrypt, - .init = crypto_morus1280_init_tfm, - .exit = crypto_morus1280_exit_tfm, - - .ivsize = MORUS_NONCE_SIZE, - .maxauthsize = MORUS_MAX_AUTH_SIZE, - .chunksize = MORUS1280_BLOCK_SIZE, - - .base = { - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct morus1280_ctx), - .cra_alignmask = 0, - - .cra_priority = 100, - - .cra_name = "morus1280", - .cra_driver_name = "morus1280-generic", - - .cra_module = THIS_MODULE, - } -}; - - -static int __init crypto_morus1280_module_init(void) -{ - return crypto_register_aead(&crypto_morus1280_alg); -} - -static void __exit crypto_morus1280_module_exit(void) -{ - crypto_unregister_aead(&crypto_morus1280_alg); -} - -subsys_initcall(crypto_morus1280_module_init); -module_exit(crypto_morus1280_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ondrej Mosnacek "); -MODULE_DESCRIPTION("MORUS-1280 AEAD algorithm"); -MODULE_ALIAS_CRYPTO("morus1280"); -MODULE_ALIAS_CRYPTO("morus1280-generic"); diff --git a/crypto/morus640.c b/crypto/morus640.c deleted file mode 100644 index ae5aa9482cb45860cae83c500b70c62194cd07fe..0000000000000000000000000000000000000000 --- a/crypto/morus640.c +++ /dev/null @@ -1,533 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * The MORUS-640 Authenticated-Encryption Algorithm - * - * Copyright (c) 2016-2018 Ondrej Mosnacek - * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MORUS640_WORD_SIZE 4 -#define MORUS640_BLOCK_SIZE (MORUS_BLOCK_WORDS * MORUS640_WORD_SIZE) -#define MORUS640_BLOCK_ALIGN (__alignof__(__le32)) -#define MORUS640_ALIGNED(p) IS_ALIGNED((uintptr_t)p, MORUS640_BLOCK_ALIGN) - -struct morus640_block { - u32 words[MORUS_BLOCK_WORDS]; -}; - -union morus640_block_in { - __le32 words[MORUS_BLOCK_WORDS]; - u8 bytes[MORUS640_BLOCK_SIZE]; -}; - -struct morus640_state { - struct morus640_block s[MORUS_STATE_BLOCKS]; -}; - -struct morus640_ctx { - struct morus640_block key; -}; - -struct morus640_ops { - int (*skcipher_walk_init)(struct skcipher_walk *walk, - struct aead_request *req, bool atomic); - - void (*crypt_chunk)(struct morus640_state *state, - u8 *dst, const u8 *src, unsigned int size); -}; - -static const struct morus640_block crypto_morus640_const[2] = { - { .words = { - U32_C(0x02010100), - U32_C(0x0d080503), - U32_C(0x59372215), - U32_C(0x6279e990), - } }, - { .words = { - U32_C(0x55183ddb), - U32_C(0xf12fc26d), - U32_C(0x42311120), - U32_C(0xdd28b573), - } }, -}; - -static void crypto_morus640_round(struct morus640_block *b0, - struct morus640_block *b1, - struct morus640_block *b2, - struct morus640_block *b3, - struct morus640_block *b4, - const struct morus640_block *m, - unsigned int b, unsigned int w) -{ - unsigned int i; - struct morus640_block tmp; - - for (i = 0; i < MORUS_BLOCK_WORDS; i++) { - b0->words[i] ^= b1->words[i] & b2->words[i]; - b0->words[i] ^= b3->words[i]; - b0->words[i] ^= m->words[i]; - b0->words[i] = rol32(b0->words[i], b); - } - - tmp = *b3; - for (i = 0; i < MORUS_BLOCK_WORDS; i++) - b3->words[(i + w) % MORUS_BLOCK_WORDS] = tmp.words[i]; -} - -static void crypto_morus640_update(struct morus640_state *state, - const struct morus640_block *m) -{ - static const struct morus640_block z = {}; - - struct morus640_block *s = state->s; - - crypto_morus640_round(&s[0], &s[1], &s[2], &s[3], &s[4], &z, 5, 1); - crypto_morus640_round(&s[1], &s[2], &s[3], &s[4], &s[0], m, 31, 2); - crypto_morus640_round(&s[2], &s[3], &s[4], &s[0], &s[1], m, 7, 3); - crypto_morus640_round(&s[3], &s[4], &s[0], &s[1], &s[2], m, 22, 2); - crypto_morus640_round(&s[4], &s[0], &s[1], &s[2], &s[3], m, 13, 1); -} - -static void crypto_morus640_load_a(struct morus640_block *dst, const u8 *src) -{ - unsigned int i; - for (i = 0; i < MORUS_BLOCK_WORDS; i++) { - dst->words[i] = le32_to_cpu(*(const __le32 *)src); - src += MORUS640_WORD_SIZE; - } -} - -static void crypto_morus640_load_u(struct morus640_block *dst, const u8 *src) -{ - unsigned int i; - for (i = 0; i < MORUS_BLOCK_WORDS; i++) { - dst->words[i] = get_unaligned_le32(src); - src += MORUS640_WORD_SIZE; - } -} - -static void crypto_morus640_load(struct morus640_block *dst, const u8 *src) -{ - if (MORUS640_ALIGNED(src)) - crypto_morus640_load_a(dst, src); - else - crypto_morus640_load_u(dst, src); -} - -static void crypto_morus640_store_a(u8 *dst, const struct morus640_block *src) -{ - unsigned int i; - for (i = 0; i < MORUS_BLOCK_WORDS; i++) { - *(__le32 *)dst = cpu_to_le32(src->words[i]); - dst += MORUS640_WORD_SIZE; - } -} - -static void crypto_morus640_store_u(u8 *dst, const struct morus640_block *src) -{ - unsigned int i; - for (i = 0; i < MORUS_BLOCK_WORDS; i++) { - put_unaligned_le32(src->words[i], dst); - dst += MORUS640_WORD_SIZE; - } -} - -static void crypto_morus640_store(u8 *dst, const struct morus640_block *src) -{ - if (MORUS640_ALIGNED(dst)) - crypto_morus640_store_a(dst, src); - else - crypto_morus640_store_u(dst, src); -} - -static void crypto_morus640_ad(struct morus640_state *state, const u8 *src, - unsigned int size) -{ - struct morus640_block m; - - if (MORUS640_ALIGNED(src)) { - while (size >= MORUS640_BLOCK_SIZE) { - crypto_morus640_load_a(&m, src); - crypto_morus640_update(state, &m); - - size -= MORUS640_BLOCK_SIZE; - src += MORUS640_BLOCK_SIZE; - } - } else { - while (size >= MORUS640_BLOCK_SIZE) { - crypto_morus640_load_u(&m, src); - crypto_morus640_update(state, &m); - - size -= MORUS640_BLOCK_SIZE; - src += MORUS640_BLOCK_SIZE; - } - } -} - -static void crypto_morus640_core(const struct morus640_state *state, - struct morus640_block *blk) -{ - unsigned int i; - - for (i = 0; i < MORUS_BLOCK_WORDS; i++) - blk->words[(i + 3) % MORUS_BLOCK_WORDS] ^= state->s[1].words[i]; - - for (i = 0; i < MORUS_BLOCK_WORDS; i++) { - blk->words[i] ^= state->s[0].words[i]; - blk->words[i] ^= state->s[2].words[i] & state->s[3].words[i]; - } -} - -static void crypto_morus640_encrypt_chunk(struct morus640_state *state, u8 *dst, - const u8 *src, unsigned int size) -{ - struct morus640_block c, m; - - if (MORUS640_ALIGNED(src) && MORUS640_ALIGNED(dst)) { - while (size >= MORUS640_BLOCK_SIZE) { - crypto_morus640_load_a(&m, src); - c = m; - crypto_morus640_core(state, &c); - crypto_morus640_store_a(dst, &c); - crypto_morus640_update(state, &m); - - src += MORUS640_BLOCK_SIZE; - dst += MORUS640_BLOCK_SIZE; - size -= MORUS640_BLOCK_SIZE; - } - } else { - while (size >= MORUS640_BLOCK_SIZE) { - crypto_morus640_load_u(&m, src); - c = m; - crypto_morus640_core(state, &c); - crypto_morus640_store_u(dst, &c); - crypto_morus640_update(state, &m); - - src += MORUS640_BLOCK_SIZE; - dst += MORUS640_BLOCK_SIZE; - size -= MORUS640_BLOCK_SIZE; - } - } - - if (size > 0) { - union morus640_block_in tail; - - memcpy(tail.bytes, src, size); - memset(tail.bytes + size, 0, MORUS640_BLOCK_SIZE - size); - - crypto_morus640_load_a(&m, tail.bytes); - c = m; - crypto_morus640_core(state, &c); - crypto_morus640_store_a(tail.bytes, &c); - crypto_morus640_update(state, &m); - - memcpy(dst, tail.bytes, size); - } -} - -static void crypto_morus640_decrypt_chunk(struct morus640_state *state, u8 *dst, - const u8 *src, unsigned int size) -{ - struct morus640_block m; - - if (MORUS640_ALIGNED(src) && MORUS640_ALIGNED(dst)) { - while (size >= MORUS640_BLOCK_SIZE) { - crypto_morus640_load_a(&m, src); - crypto_morus640_core(state, &m); - crypto_morus640_store_a(dst, &m); - crypto_morus640_update(state, &m); - - src += MORUS640_BLOCK_SIZE; - dst += MORUS640_BLOCK_SIZE; - size -= MORUS640_BLOCK_SIZE; - } - } else { - while (size >= MORUS640_BLOCK_SIZE) { - crypto_morus640_load_u(&m, src); - crypto_morus640_core(state, &m); - crypto_morus640_store_u(dst, &m); - crypto_morus640_update(state, &m); - - src += MORUS640_BLOCK_SIZE; - dst += MORUS640_BLOCK_SIZE; - size -= MORUS640_BLOCK_SIZE; - } - } - - if (size > 0) { - union morus640_block_in tail; - - memcpy(tail.bytes, src, size); - memset(tail.bytes + size, 0, MORUS640_BLOCK_SIZE - size); - - crypto_morus640_load_a(&m, tail.bytes); - crypto_morus640_core(state, &m); - crypto_morus640_store_a(tail.bytes, &m); - memset(tail.bytes + size, 0, MORUS640_BLOCK_SIZE - size); - crypto_morus640_load_a(&m, tail.bytes); - crypto_morus640_update(state, &m); - - memcpy(dst, tail.bytes, size); - } -} - -static void crypto_morus640_init(struct morus640_state *state, - const struct morus640_block *key, - const u8 *iv) -{ - static const struct morus640_block z = {}; - - unsigned int i; - - crypto_morus640_load(&state->s[0], iv); - state->s[1] = *key; - for (i = 0; i < MORUS_BLOCK_WORDS; i++) - state->s[2].words[i] = U32_C(0xFFFFFFFF); - state->s[3] = crypto_morus640_const[0]; - state->s[4] = crypto_morus640_const[1]; - - for (i = 0; i < 16; i++) - crypto_morus640_update(state, &z); - - for (i = 0; i < MORUS_BLOCK_WORDS; i++) - state->s[1].words[i] ^= key->words[i]; -} - -static void crypto_morus640_process_ad(struct morus640_state *state, - struct scatterlist *sg_src, - unsigned int assoclen) -{ - struct scatter_walk walk; - struct morus640_block m; - union morus640_block_in buf; - unsigned int pos = 0; - - scatterwalk_start(&walk, sg_src); - while (assoclen != 0) { - unsigned int size = scatterwalk_clamp(&walk, assoclen); - unsigned int left = size; - void *mapped = scatterwalk_map(&walk); - const u8 *src = (const u8 *)mapped; - - if (pos + size >= MORUS640_BLOCK_SIZE) { - if (pos > 0) { - unsigned int fill = MORUS640_BLOCK_SIZE - pos; - memcpy(buf.bytes + pos, src, fill); - - crypto_morus640_load_a(&m, buf.bytes); - crypto_morus640_update(state, &m); - - pos = 0; - left -= fill; - src += fill; - } - - crypto_morus640_ad(state, src, left); - src += left & ~(MORUS640_BLOCK_SIZE - 1); - left &= MORUS640_BLOCK_SIZE - 1; - } - - memcpy(buf.bytes + pos, src, left); - - pos += left; - assoclen -= size; - scatterwalk_unmap(mapped); - scatterwalk_advance(&walk, size); - scatterwalk_done(&walk, 0, assoclen); - } - - if (pos > 0) { - memset(buf.bytes + pos, 0, MORUS640_BLOCK_SIZE - pos); - - crypto_morus640_load_a(&m, buf.bytes); - crypto_morus640_update(state, &m); - } -} - -static void crypto_morus640_process_crypt(struct morus640_state *state, - struct aead_request *req, - const struct morus640_ops *ops) -{ - struct skcipher_walk walk; - - ops->skcipher_walk_init(&walk, req, false); - - while (walk.nbytes) { - unsigned int nbytes = walk.nbytes; - - if (nbytes < walk.total) - nbytes = round_down(nbytes, walk.stride); - - ops->crypt_chunk(state, walk.dst.virt.addr, walk.src.virt.addr, - nbytes); - - skcipher_walk_done(&walk, walk.nbytes - nbytes); - } -} - -static void crypto_morus640_final(struct morus640_state *state, - struct morus640_block *tag_xor, - u64 assoclen, u64 cryptlen) -{ - struct morus640_block tmp; - unsigned int i; - - tmp.words[0] = lower_32_bits(assoclen * 8); - tmp.words[1] = upper_32_bits(assoclen * 8); - tmp.words[2] = lower_32_bits(cryptlen * 8); - tmp.words[3] = upper_32_bits(cryptlen * 8); - - for (i = 0; i < MORUS_BLOCK_WORDS; i++) - state->s[4].words[i] ^= state->s[0].words[i]; - - for (i = 0; i < 10; i++) - crypto_morus640_update(state, &tmp); - - crypto_morus640_core(state, tag_xor); -} - -static int crypto_morus640_setkey(struct crypto_aead *aead, const u8 *key, - unsigned int keylen) -{ - struct morus640_ctx *ctx = crypto_aead_ctx(aead); - - if (keylen != MORUS640_BLOCK_SIZE) { - crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - crypto_morus640_load(&ctx->key, key); - return 0; -} - -static int crypto_morus640_setauthsize(struct crypto_aead *tfm, - unsigned int authsize) -{ - return (authsize <= MORUS_MAX_AUTH_SIZE) ? 0 : -EINVAL; -} - -static void crypto_morus640_crypt(struct aead_request *req, - struct morus640_block *tag_xor, - unsigned int cryptlen, - const struct morus640_ops *ops) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct morus640_ctx *ctx = crypto_aead_ctx(tfm); - struct morus640_state state; - - crypto_morus640_init(&state, &ctx->key, req->iv); - crypto_morus640_process_ad(&state, req->src, req->assoclen); - crypto_morus640_process_crypt(&state, req, ops); - crypto_morus640_final(&state, tag_xor, req->assoclen, cryptlen); -} - -static int crypto_morus640_encrypt(struct aead_request *req) -{ - static const struct morus640_ops ops = { - .skcipher_walk_init = skcipher_walk_aead_encrypt, - .crypt_chunk = crypto_morus640_encrypt_chunk, - }; - - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct morus640_block tag = {}; - union morus640_block_in tag_out; - unsigned int authsize = crypto_aead_authsize(tfm); - unsigned int cryptlen = req->cryptlen; - - crypto_morus640_crypt(req, &tag, cryptlen, &ops); - crypto_morus640_store(tag_out.bytes, &tag); - - scatterwalk_map_and_copy(tag_out.bytes, req->dst, - req->assoclen + cryptlen, authsize, 1); - return 0; -} - -static int crypto_morus640_decrypt(struct aead_request *req) -{ - static const struct morus640_ops ops = { - .skcipher_walk_init = skcipher_walk_aead_decrypt, - .crypt_chunk = crypto_morus640_decrypt_chunk, - }; - static const u8 zeros[MORUS640_BLOCK_SIZE] = {}; - - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - union morus640_block_in tag_in; - struct morus640_block tag; - unsigned int authsize = crypto_aead_authsize(tfm); - unsigned int cryptlen = req->cryptlen - authsize; - - scatterwalk_map_and_copy(tag_in.bytes, req->src, - req->assoclen + cryptlen, authsize, 0); - - crypto_morus640_load(&tag, tag_in.bytes); - crypto_morus640_crypt(req, &tag, cryptlen, &ops); - crypto_morus640_store(tag_in.bytes, &tag); - - return crypto_memneq(tag_in.bytes, zeros, authsize) ? -EBADMSG : 0; -} - -static int crypto_morus640_init_tfm(struct crypto_aead *tfm) -{ - return 0; -} - -static void crypto_morus640_exit_tfm(struct crypto_aead *tfm) -{ -} - -static struct aead_alg crypto_morus640_alg = { - .setkey = crypto_morus640_setkey, - .setauthsize = crypto_morus640_setauthsize, - .encrypt = crypto_morus640_encrypt, - .decrypt = crypto_morus640_decrypt, - .init = crypto_morus640_init_tfm, - .exit = crypto_morus640_exit_tfm, - - .ivsize = MORUS_NONCE_SIZE, - .maxauthsize = MORUS_MAX_AUTH_SIZE, - .chunksize = MORUS640_BLOCK_SIZE, - - .base = { - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct morus640_ctx), - .cra_alignmask = 0, - - .cra_priority = 100, - - .cra_name = "morus640", - .cra_driver_name = "morus640-generic", - - .cra_module = THIS_MODULE, - } -}; - -static int __init crypto_morus640_module_init(void) -{ - return crypto_register_aead(&crypto_morus640_alg); -} - -static void __exit crypto_morus640_module_exit(void) -{ - crypto_unregister_aead(&crypto_morus640_alg); -} - -subsys_initcall(crypto_morus640_module_init); -module_exit(crypto_morus640_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ondrej Mosnacek "); -MODULE_DESCRIPTION("MORUS-640 AEAD algorithm"); -MODULE_ALIAS_CRYPTO("morus640"); -MODULE_ALIAS_CRYPTO("morus640-generic"); diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c index 0edf5b54fc778d6f2f159821496f8bac267bea50..543792e0ebf0341306f34ba3efeae635b6d84f6d 100644 --- a/crypto/pcrypt.c +++ b/crypto/pcrypt.c @@ -18,34 +18,8 @@ #include #include -struct padata_pcrypt { - struct padata_instance *pinst; - struct workqueue_struct *wq; - - /* - * Cpumask for callback CPUs. It should be - * equal to serial cpumask of corresponding padata instance, - * so it is updated when padata notifies us about serial - * cpumask change. - * - * cb_cpumask is protected by RCU. This fact prevents us from - * using cpumask_var_t directly because the actual type of - * cpumsak_var_t depends on kernel configuration(particularly on - * CONFIG_CPUMASK_OFFSTACK macro). Depending on the configuration - * cpumask_var_t may be either a pointer to the struct cpumask - * or a variable allocated on the stack. Thus we can not safely use - * cpumask_var_t with RCU operations such as rcu_assign_pointer or - * rcu_dereference. So cpumask_var_t is wrapped with struct - * pcrypt_cpumask which makes possible to use it with RCU. - */ - struct pcrypt_cpumask { - cpumask_var_t mask; - } *cb_cpumask; - struct notifier_block nblock; -}; - -static struct padata_pcrypt pencrypt; -static struct padata_pcrypt pdecrypt; +static struct padata_instance *pencrypt; +static struct padata_instance *pdecrypt; static struct kset *pcrypt_kset; struct pcrypt_instance_ctx { @@ -58,35 +32,6 @@ struct pcrypt_aead_ctx { unsigned int cb_cpu; }; -static int pcrypt_do_parallel(struct padata_priv *padata, unsigned int *cb_cpu, - struct padata_pcrypt *pcrypt) -{ - unsigned int cpu_index, cpu, i; - struct pcrypt_cpumask *cpumask; - - cpu = *cb_cpu; - - rcu_read_lock_bh(); - cpumask = rcu_dereference_bh(pcrypt->cb_cpumask); - if (cpumask_test_cpu(cpu, cpumask->mask)) - goto out; - - if (!cpumask_weight(cpumask->mask)) - goto out; - - cpu_index = cpu % cpumask_weight(cpumask->mask); - - cpu = cpumask_first(cpumask->mask); - for (i = 0; i < cpu_index; i++) - cpu = cpumask_next(cpu, cpumask->mask); - - *cb_cpu = cpu; - -out: - rcu_read_unlock_bh(); - return padata_do_parallel(pcrypt->pinst, padata, cpu); -} - static int pcrypt_aead_setkey(struct crypto_aead *parent, const u8 *key, unsigned int keylen) { @@ -158,7 +103,7 @@ static int pcrypt_aead_encrypt(struct aead_request *req) req->cryptlen, req->iv); aead_request_set_ad(creq, req->assoclen); - err = pcrypt_do_parallel(padata, &ctx->cb_cpu, &pencrypt); + err = padata_do_parallel(pencrypt, padata, &ctx->cb_cpu); if (!err) return -EINPROGRESS; @@ -200,7 +145,7 @@ static int pcrypt_aead_decrypt(struct aead_request *req) req->cryptlen, req->iv); aead_request_set_ad(creq, req->assoclen); - err = pcrypt_do_parallel(padata, &ctx->cb_cpu, &pdecrypt); + err = padata_do_parallel(pdecrypt, padata, &ctx->cb_cpu); if (!err) return -EINPROGRESS; @@ -347,36 +292,6 @@ static int pcrypt_create(struct crypto_template *tmpl, struct rtattr **tb) return -EINVAL; } -static int pcrypt_cpumask_change_notify(struct notifier_block *self, - unsigned long val, void *data) -{ - struct padata_pcrypt *pcrypt; - struct pcrypt_cpumask *new_mask, *old_mask; - struct padata_cpumask *cpumask = (struct padata_cpumask *)data; - - if (!(val & PADATA_CPU_SERIAL)) - return 0; - - pcrypt = container_of(self, struct padata_pcrypt, nblock); - new_mask = kmalloc(sizeof(*new_mask), GFP_KERNEL); - if (!new_mask) - return -ENOMEM; - if (!alloc_cpumask_var(&new_mask->mask, GFP_KERNEL)) { - kfree(new_mask); - return -ENOMEM; - } - - old_mask = pcrypt->cb_cpumask; - - cpumask_copy(new_mask->mask, cpumask->cbcpu); - rcu_assign_pointer(pcrypt->cb_cpumask, new_mask); - synchronize_rcu(); - - free_cpumask_var(old_mask->mask); - kfree(old_mask); - return 0; -} - static int pcrypt_sysfs_add(struct padata_instance *pinst, const char *name) { int ret; @@ -389,71 +304,25 @@ static int pcrypt_sysfs_add(struct padata_instance *pinst, const char *name) return ret; } -static int pcrypt_init_padata(struct padata_pcrypt *pcrypt, - const char *name) +static int pcrypt_init_padata(struct padata_instance **pinst, const char *name) { int ret = -ENOMEM; - struct pcrypt_cpumask *mask; - get_online_cpus(); - - pcrypt->wq = alloc_workqueue("%s", WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, - 1, name); - if (!pcrypt->wq) - goto err; - - pcrypt->pinst = padata_alloc_possible(pcrypt->wq); - if (!pcrypt->pinst) - goto err_destroy_workqueue; - - mask = kmalloc(sizeof(*mask), GFP_KERNEL); - if (!mask) - goto err_free_padata; - if (!alloc_cpumask_var(&mask->mask, GFP_KERNEL)) { - kfree(mask); - goto err_free_padata; - } + *pinst = padata_alloc_possible(name); + if (!*pinst) + return ret; - cpumask_and(mask->mask, cpu_possible_mask, cpu_online_mask); - rcu_assign_pointer(pcrypt->cb_cpumask, mask); - - pcrypt->nblock.notifier_call = pcrypt_cpumask_change_notify; - ret = padata_register_cpumask_notifier(pcrypt->pinst, &pcrypt->nblock); - if (ret) - goto err_free_cpumask; - - ret = pcrypt_sysfs_add(pcrypt->pinst, name); + ret = pcrypt_sysfs_add(*pinst, name); if (ret) - goto err_unregister_notifier; - - put_online_cpus(); - - return ret; - -err_unregister_notifier: - padata_unregister_cpumask_notifier(pcrypt->pinst, &pcrypt->nblock); -err_free_cpumask: - free_cpumask_var(mask->mask); - kfree(mask); -err_free_padata: - padata_free(pcrypt->pinst); -err_destroy_workqueue: - destroy_workqueue(pcrypt->wq); -err: - put_online_cpus(); + padata_free(*pinst); return ret; } -static void pcrypt_fini_padata(struct padata_pcrypt *pcrypt) +static void pcrypt_fini_padata(struct padata_instance *pinst) { - free_cpumask_var(pcrypt->cb_cpumask->mask); - kfree(pcrypt->cb_cpumask); - - padata_stop(pcrypt->pinst); - padata_unregister_cpumask_notifier(pcrypt->pinst, &pcrypt->nblock); - destroy_workqueue(pcrypt->wq); - padata_free(pcrypt->pinst); + padata_stop(pinst); + padata_free(pinst); } static struct crypto_template pcrypt_tmpl = { @@ -478,13 +347,13 @@ static int __init pcrypt_init(void) if (err) goto err_deinit_pencrypt; - padata_start(pencrypt.pinst); - padata_start(pdecrypt.pinst); + padata_start(pencrypt); + padata_start(pdecrypt); return crypto_register_template(&pcrypt_tmpl); err_deinit_pencrypt: - pcrypt_fini_padata(&pencrypt); + pcrypt_fini_padata(pencrypt); err_unreg_kset: kset_unregister(pcrypt_kset); err: @@ -493,8 +362,8 @@ static int __init pcrypt_init(void) static void __exit pcrypt_exit(void) { - pcrypt_fini_padata(&pencrypt); - pcrypt_fini_padata(&pdecrypt); + pcrypt_fini_padata(pencrypt); + pcrypt_fini_padata(pdecrypt); kset_unregister(pcrypt_kset); crypto_unregister_template(&pcrypt_tmpl); diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c index b7502a96a0d4129b7ac62190bac489ffa36f2c4b..f2d7095d4f2d6486b65aa36ed4628d2f49ee7207 100644 --- a/crypto/sha256_generic.c +++ b/crypto/sha256_generic.c @@ -1,11 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Cryptographic API. - * - * SHA-256, as specified in - * http://csrc.nist.gov/groups/STM/cavp/documents/shs/sha256-384-512.pdf - * - * SHA-256 code by Jean-Luc Cooke . + * Crypto API wrapper for the generic SHA256 code from lib/crypto/sha256.c * * Copyright (c) Jean-Luc Cooke * Copyright (c) Andrew McDonald @@ -38,229 +33,44 @@ const u8 sha256_zero_message_hash[SHA256_DIGEST_SIZE] = { }; EXPORT_SYMBOL_GPL(sha256_zero_message_hash); -static inline u32 Ch(u32 x, u32 y, u32 z) -{ - return z ^ (x & (y ^ z)); -} - -static inline u32 Maj(u32 x, u32 y, u32 z) +static int crypto_sha256_init(struct shash_desc *desc) { - return (x & y) | (z & (x | y)); + return sha256_init(shash_desc_ctx(desc)); } -#define e0(x) (ror32(x, 2) ^ ror32(x,13) ^ ror32(x,22)) -#define e1(x) (ror32(x, 6) ^ ror32(x,11) ^ ror32(x,25)) -#define s0(x) (ror32(x, 7) ^ ror32(x,18) ^ (x >> 3)) -#define s1(x) (ror32(x,17) ^ ror32(x,19) ^ (x >> 10)) - -static inline void LOAD_OP(int I, u32 *W, const u8 *input) +static int crypto_sha224_init(struct shash_desc *desc) { - W[I] = get_unaligned_be32((__u32 *)input + I); -} - -static inline void BLEND_OP(int I, u32 *W) -{ - W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16]; -} - -static void sha256_transform(u32 *state, const u8 *input) -{ - u32 a, b, c, d, e, f, g, h, t1, t2; - u32 W[64]; - int i; - - /* load the input */ - for (i = 0; i < 16; i++) - LOAD_OP(i, W, input); - - /* now blend */ - for (i = 16; i < 64; i++) - BLEND_OP(i, W); - - /* load the state into our registers */ - a=state[0]; b=state[1]; c=state[2]; d=state[3]; - e=state[4]; f=state[5]; g=state[6]; h=state[7]; - - /* now iterate */ - t1 = h + e1(e) + Ch(e,f,g) + 0x428a2f98 + W[ 0]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0x71374491 + W[ 1]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0xb5c0fbcf + W[ 2]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0xe9b5dba5 + W[ 3]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x3956c25b + W[ 4]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0x59f111f1 + W[ 5]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x923f82a4 + W[ 6]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0xab1c5ed5 + W[ 7]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0xd807aa98 + W[ 8]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0x12835b01 + W[ 9]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0x243185be + W[10]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0x550c7dc3 + W[11]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x72be5d74 + W[12]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0x80deb1fe + W[13]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x9bdc06a7 + W[14]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0xc19bf174 + W[15]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0xe49b69c1 + W[16]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0xefbe4786 + W[17]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0x0fc19dc6 + W[18]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0x240ca1cc + W[19]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x2de92c6f + W[20]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0x4a7484aa + W[21]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x5cb0a9dc + W[22]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0x76f988da + W[23]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0x983e5152 + W[24]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0xa831c66d + W[25]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0xb00327c8 + W[26]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0xbf597fc7 + W[27]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0xc6e00bf3 + W[28]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0xd5a79147 + W[29]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x06ca6351 + W[30]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0x14292967 + W[31]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0x27b70a85 + W[32]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0x2e1b2138 + W[33]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0x4d2c6dfc + W[34]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0x53380d13 + W[35]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x650a7354 + W[36]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0x766a0abb + W[37]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x81c2c92e + W[38]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0x92722c85 + W[39]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0xa2bfe8a1 + W[40]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0xa81a664b + W[41]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0xc24b8b70 + W[42]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0xc76c51a3 + W[43]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0xd192e819 + W[44]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0xd6990624 + W[45]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0xf40e3585 + W[46]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0x106aa070 + W[47]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0x19a4c116 + W[48]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0x1e376c08 + W[49]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0x2748774c + W[50]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0x34b0bcb5 + W[51]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x391c0cb3 + W[52]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0x4ed8aa4a + W[53]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x5b9cca4f + W[54]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0x682e6ff3 + W[55]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0x748f82ee + W[56]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0x78a5636f + W[57]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0x84c87814 + W[58]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0x8cc70208 + W[59]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x90befffa + W[60]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0xa4506ceb + W[61]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0xbef9a3f7 + W[62]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0xc67178f2 + W[63]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - state[0] += a; state[1] += b; state[2] += c; state[3] += d; - state[4] += e; state[5] += f; state[6] += g; state[7] += h; - - /* clear any sensitive info... */ - a = b = c = d = e = f = g = h = t1 = t2 = 0; - memzero_explicit(W, 64 * sizeof(u32)); -} - -static void sha256_generic_block_fn(struct sha256_state *sst, u8 const *src, - int blocks) -{ - while (blocks--) { - sha256_transform(sst->state, src); - src += SHA256_BLOCK_SIZE; - } + return sha224_init(shash_desc_ctx(desc)); } int crypto_sha256_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - return sha256_base_do_update(desc, data, len, sha256_generic_block_fn); + return sha256_update(shash_desc_ctx(desc), data, len); } EXPORT_SYMBOL(crypto_sha256_update); -static int sha256_final(struct shash_desc *desc, u8 *out) +static int crypto_sha256_final(struct shash_desc *desc, u8 *out) { - sha256_base_do_finalize(desc, sha256_generic_block_fn); - return sha256_base_finish(desc, out); + if (crypto_shash_digestsize(desc->tfm) == SHA224_DIGEST_SIZE) + return sha224_final(shash_desc_ctx(desc), out); + else + return sha256_final(shash_desc_ctx(desc), out); } int crypto_sha256_finup(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *hash) { - sha256_base_do_update(desc, data, len, sha256_generic_block_fn); - return sha256_final(desc, hash); + sha256_update(shash_desc_ctx(desc), data, len); + return crypto_sha256_final(desc, hash); } EXPORT_SYMBOL(crypto_sha256_finup); static struct shash_alg sha256_algs[2] = { { .digestsize = SHA256_DIGEST_SIZE, - .init = sha256_base_init, + .init = crypto_sha256_init, .update = crypto_sha256_update, - .final = sha256_final, + .final = crypto_sha256_final, .finup = crypto_sha256_finup, .descsize = sizeof(struct sha256_state), .base = { @@ -272,9 +82,9 @@ static struct shash_alg sha256_algs[2] = { { } }, { .digestsize = SHA224_DIGEST_SIZE, - .init = sha224_base_init, + .init = crypto_sha224_init, .update = crypto_sha256_update, - .final = sha256_final, + .final = crypto_sha256_final, .finup = crypto_sha256_finup, .descsize = sizeof(struct sha256_state), .base = { diff --git a/crypto/skcipher.c b/crypto/skcipher.c index 5d836fc3df3e71632e5c192da82c1f10776a5373..22753c1c720229d3529e37ecaf4eb77a51e5b0af 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -90,7 +90,7 @@ static inline u8 *skcipher_get_spot(u8 *start, unsigned int len) return max(start, end_page); } -static void skcipher_done_slow(struct skcipher_walk *walk, unsigned int bsize) +static int skcipher_done_slow(struct skcipher_walk *walk, unsigned int bsize) { u8 *addr; @@ -98,19 +98,21 @@ static void skcipher_done_slow(struct skcipher_walk *walk, unsigned int bsize) addr = skcipher_get_spot(addr, bsize); scatterwalk_copychunks(addr, &walk->out, bsize, (walk->flags & SKCIPHER_WALK_PHYS) ? 2 : 1); + return 0; } int skcipher_walk_done(struct skcipher_walk *walk, int err) { - unsigned int n; /* bytes processed */ - bool more; + unsigned int n = walk->nbytes; + unsigned int nbytes = 0; - if (unlikely(err < 0)) + if (!n) goto finish; - n = walk->nbytes - err; - walk->total -= n; - more = (walk->total != 0); + if (likely(err >= 0)) { + n -= err; + nbytes = walk->total - n; + } if (likely(!(walk->flags & (SKCIPHER_WALK_PHYS | SKCIPHER_WALK_SLOW | @@ -126,7 +128,7 @@ int skcipher_walk_done(struct skcipher_walk *walk, int err) memcpy(walk->dst.virt.addr, walk->page, n); skcipher_unmap_dst(walk); } else if (unlikely(walk->flags & SKCIPHER_WALK_SLOW)) { - if (err) { + if (err > 0) { /* * Didn't process all bytes. Either the algorithm is * broken, or this was the last step and it turned out @@ -134,27 +136,29 @@ int skcipher_walk_done(struct skcipher_walk *walk, int err) * the algorithm requires it. */ err = -EINVAL; - goto finish; - } - skcipher_done_slow(walk, n); - goto already_advanced; + nbytes = 0; + } else + n = skcipher_done_slow(walk, n); } + if (err > 0) + err = 0; + + walk->total = nbytes; + walk->nbytes = 0; + scatterwalk_advance(&walk->in, n); scatterwalk_advance(&walk->out, n); -already_advanced: - scatterwalk_done(&walk->in, 0, more); - scatterwalk_done(&walk->out, 1, more); + scatterwalk_done(&walk->in, 0, nbytes); + scatterwalk_done(&walk->out, 1, nbytes); - if (more) { + if (nbytes) { crypto_yield(walk->flags & SKCIPHER_WALK_SLEEP ? CRYPTO_TFM_REQ_MAY_SLEEP : 0); return skcipher_walk_next(walk); } - err = 0; -finish: - walk->nbytes = 0; +finish: /* Short-circuit for the common/fast path. */ if (!((unsigned long)walk->buffer | (unsigned long)walk->page)) goto out; diff --git a/crypto/streebog_generic.c b/crypto/streebog_generic.c index 63663c3bab7e9740650fffb69d87c24c3091c6a8..dc625ffc54ad7f57db883bf330588cd33888f902 100644 --- a/crypto/streebog_generic.c +++ b/crypto/streebog_generic.c @@ -148,52 +148,6 @@ static const struct streebog_uint512 C[12] = { } } }; -static const u8 Tau[64] = { - 0, 8, 16, 24, 32, 40, 48, 56, - 1, 9, 17, 25, 33, 41, 49, 57, - 2, 10, 18, 26, 34, 42, 50, 58, - 3, 11, 19, 27, 35, 43, 51, 59, - 4, 12, 20, 28, 36, 44, 52, 60, - 5, 13, 21, 29, 37, 45, 53, 61, - 6, 14, 22, 30, 38, 46, 54, 62, - 7, 15, 23, 31, 39, 47, 55, 63 -}; - -static const u8 Pi[256] = { - 252, 238, 221, 17, 207, 110, 49, 22, - 251, 196, 250, 218, 35, 197, 4, 77, - 233, 119, 240, 219, 147, 46, 153, 186, - 23, 54, 241, 187, 20, 205, 95, 193, - 249, 24, 101, 90, 226, 92, 239, 33, - 129, 28, 60, 66, 139, 1, 142, 79, - 5, 132, 2, 174, 227, 106, 143, 160, - 6, 11, 237, 152, 127, 212, 211, 31, - 235, 52, 44, 81, 234, 200, 72, 171, - 242, 42, 104, 162, 253, 58, 206, 204, - 181, 112, 14, 86, 8, 12, 118, 18, - 191, 114, 19, 71, 156, 183, 93, 135, - 21, 161, 150, 41, 16, 123, 154, 199, - 243, 145, 120, 111, 157, 158, 178, 177, - 50, 117, 25, 61, 255, 53, 138, 126, - 109, 84, 198, 128, 195, 189, 13, 87, - 223, 245, 36, 169, 62, 168, 67, 201, - 215, 121, 214, 246, 124, 34, 185, 3, - 224, 15, 236, 222, 122, 148, 176, 188, - 220, 232, 40, 80, 78, 51, 10, 74, - 167, 151, 96, 115, 30, 0, 98, 68, - 26, 184, 56, 130, 100, 159, 38, 65, - 173, 69, 70, 146, 39, 94, 85, 47, - 140, 163, 165, 125, 105, 213, 149, 59, - 7, 88, 179, 64, 134, 172, 29, 247, - 48, 55, 107, 228, 136, 217, 231, 137, - 225, 27, 131, 73, 76, 63, 248, 254, - 141, 83, 170, 144, 202, 216, 133, 97, - 32, 113, 103, 164, 45, 43, 9, 91, - 203, 155, 37, 208, 190, 229, 108, 82, - 89, 166, 116, 210, 230, 244, 180, 192, - 209, 102, 175, 194, 57, 75, 99, 182 -}; - static const unsigned long long Ax[8][256] = { { 0xd01f715b5c7ef8e6ULL, 0x16fa240980778325ULL, 0xa8a42e857ee049c8ULL, diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index ad78ab5b93cbc22249ba3ca22a2b79c2a6e14f9d..83ad0b1fab30a5f591dbfbc6f44fb9f39ccc8052 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -2327,6 +2327,22 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) 0, speed_template_32); break; + case 220: + test_acipher_speed("essiv(cbc(aes),sha256)", + ENCRYPT, sec, NULL, 0, + speed_template_16_24_32); + test_acipher_speed("essiv(cbc(aes),sha256)", + DECRYPT, sec, NULL, 0, + speed_template_16_24_32); + break; + + case 221: + test_aead_speed("aegis128", ENCRYPT, sec, + NULL, 0, 16, 8, speed_template_16); + test_aead_speed("aegis128", DECRYPT, sec, + NULL, 0, 16, 8, speed_template_16); + break; + case 300: if (alg) { test_hash_speed(alg, sec, generic_hash_speed_template); diff --git a/crypto/testmgr.c b/crypto/testmgr.c index d0b5b33806a67cdf7aa27a5ac8cdea46cf469c00..c39e39e55dc203be3284458184a611bcfc65c612 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -3886,18 +3886,6 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .aead = __VECS(aegis128_tv_template) } - }, { - .alg = "aegis128l", - .test = alg_test_aead, - .suite = { - .aead = __VECS(aegis128l_tv_template) - } - }, { - .alg = "aegis256", - .test = alg_test_aead, - .suite = { - .aead = __VECS(aegis256_tv_template) - } }, { .alg = "ansi_cprng", .test = alg_test_cprng, @@ -4556,6 +4544,20 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .akcipher = __VECS(ecrdsa_tv_template) } + }, { + .alg = "essiv(authenc(hmac(sha256),cbc(aes)),sha256)", + .test = alg_test_aead, + .fips_allowed = 1, + .suite = { + .aead = __VECS(essiv_hmac_sha256_aes_cbc_tv_temp) + } + }, { + .alg = "essiv(cbc(aes),sha256)", + .test = alg_test_skcipher, + .fips_allowed = 1, + .suite = { + .cipher = __VECS(essiv_aes_cbc_tv_template) + } }, { .alg = "gcm(aes)", .generic_driver = "gcm_base(ctr(aes-generic),ghash-generic)", @@ -4740,6 +4742,16 @@ static const struct alg_test_desc alg_test_descs[] = { .decomp = __VECS(lzo_decomp_tv_template) } } + }, { + .alg = "lzo-rle", + .test = alg_test_comp, + .fips_allowed = 1, + .suite = { + .comp = { + .comp = __VECS(lzorle_comp_tv_template), + .decomp = __VECS(lzorle_decomp_tv_template) + } + } }, { .alg = "md4", .test = alg_test_hash, @@ -4758,18 +4770,6 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .hash = __VECS(michael_mic_tv_template) } - }, { - .alg = "morus1280", - .test = alg_test_aead, - .suite = { - .aead = __VECS(morus1280_tv_template) - } - }, { - .alg = "morus640", - .test = alg_test_aead, - .suite = { - .aead = __VECS(morus640_tv_template) - } }, { .alg = "nhpoly1305", .test = alg_test_hash, @@ -5240,9 +5240,11 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask) type, mask); test_done: - if (rc && (fips_enabled || panic_on_fail)) + if (rc && (fips_enabled || panic_on_fail)) { + fips_fail_notify(); panic("alg: self-tests for %s (%s) failed in %s mode!\n", driver, alg, fips_enabled ? "fips" : "panic_on_fail"); + } if (fips_enabled && !rc) pr_info("alg: self-tests for %s (%s) passed\n", driver, alg); diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 073bd2efafca22b816f1763a2ed9d99cf09248aa..ef7d21f39d4a9463c0783af643920888fbb612c8 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -19489,3679 +19489,988 @@ static const struct aead_testvec aegis128_tv_template[] = { }; /* - * AEGIS-128L test vectors - generated via reference implementation from - * SUPERCOP (https://bench.cr.yp.to/supercop.html): + * All key wrapping test vectors taken from + * http://csrc.nist.gov/groups/STM/cavp/documents/mac/kwtestvectors.zip * - * https://bench.cr.yp.to/supercop/supercop-20170228.tar.xz - * (see crypto_aead/aegis128l/) + * Note: as documented in keywrap.c, the ivout for encryption is the first + * semiblock of the ciphertext from the test vector. For decryption, iv is + * the first semiblock of the ciphertext. */ -static const struct aead_testvec aegis128l_tv_template[] = { +static const struct cipher_testvec aes_kw_tv_template[] = { { - .key = "\x0f\xc9\x8e\x67\x44\x9e\xaa\x86" - "\x20\x36\x2c\x24\xfe\xc9\x30\x81", - .klen = 16, - .iv = "\x1e\x92\x1c\xcf\x88\x3d\x54\x0d" - "\x40\x6d\x59\x48\xfc\x92\x61\x03", - .assoc = "", - .alen = 0, - .ptext = "", - .plen = 0, - .ctext = "\x30\x4f\xf3\xe9\xb1\xfa\x81\xa6" - "\x20\x72\x78\xdd\x93\xc8\x57\xef", - .clen = 16, - }, { - .key = "\x4b\xed\xc8\x07\x54\x1a\x52\xa2" - "\xa1\x10\xde\xb5\xf8\xed\xf3\x87", - .klen = 16, - .iv = "\x5a\xb7\x56\x6e\x98\xb9\xfd\x29" - "\xc1\x47\x0b\xda\xf6\xb6\x23\x09", - .assoc = "", - .alen = 0, - .ptext = "\x79", - .plen = 1, - .ctext = "\xa9\x24\xa0\xb6\x2d\xdd\x29\xdb" - "\x40\xb3\x71\xc5\x22\x58\x31\x77" - "\x6d", - .clen = 17, - }, { - .key = "\x88\x12\x01\xa6\x64\x96\xfb\xbe" - "\x22\xea\x90\x47\xf2\x11\xb5\x8e", + .key = "\x75\x75\xda\x3a\x93\x60\x7c\xc2" + "\xbf\xd8\xce\xc7\xaa\xdf\xd9\xa6", .klen = 16, - .iv = "\x97\xdb\x90\x0e\xa8\x35\xa5\x45" - "\x42\x21\xbd\x6b\xf0\xda\xe6\x0f", - .assoc = "", - .alen = 0, - .ptext = "\xb5\x6e\xad\xdd\x30\x72\xfa\x53" - "\x82\x8e\x16\xb4\xed\x6d\x47", - .plen = 15, - .ctext = "\xbb\x0a\x53\xc4\xaa\x7e\xa4\x03" - "\x2b\xee\x62\x99\x7b\x98\x13\x1f" - "\xe0\x76\x4c\x2e\x53\x99\x4f\xbe" - "\xe1\xa8\x04\x7f\xe1\x71\xbe", - .clen = 31, + .ptext = "\x42\x13\x6d\x3c\x38\x4a\x3e\xea" + "\xc9\x5a\x06\x6f\xd2\x8f\xed\x3f", + .ctext = "\xf6\x85\x94\x81\x6f\x64\xca\xa3" + "\xf5\x6f\xab\xea\x25\x48\xf5\xfb", + .len = 16, + .iv_out = "\x03\x1f\x6b\xd7\xe6\x1e\x64\x3d", + .generates_iv = true, }, { - .key = "\xc4\x37\x3b\x45\x74\x11\xa4\xda" - "\xa2\xc5\x42\xd8\xec\x36\x78\x94", + .key = "\x80\xaa\x99\x73\x27\xa4\x80\x6b" + "\x6a\x7a\x41\xa5\x2b\x86\xc3\x71" + "\x03\x86\xf9\x32\x78\x6e\xf7\x96" + "\x76\xfa\xfb\x90\xb8\x26\x3c\x5f", + .klen = 32, + .ptext = "\x0a\x25\x6b\xa7\x5c\xfa\x03\xaa" + "\xa0\x2b\xa9\x42\x03\xf1\x5b\xaa", + .ctext = "\xd3\x3d\x3d\x97\x7b\xf0\xa9\x15" + "\x59\xf9\x9c\x8a\xcd\x29\x3d\x43", + .len = 16, + .iv_out = "\x42\x3c\x96\x0d\x8a\x2a\xc4\xc1", + .generates_iv = true, + }, +}; + +/* + * ANSI X9.31 Continuous Pseudo-Random Number Generator (AES mode) + * test vectors, taken from Appendix B.2.9 and B.2.10: + * http://csrc.nist.gov/groups/STM/cavp/documents/rng/RNGVS.pdf + * Only AES-128 is supported at this time. + */ +static const struct cprng_testvec ansi_cprng_aes_tv_template[] = { + { + .key = "\xf3\xb1\x66\x6d\x13\x60\x72\x42" + "\xed\x06\x1c\xab\xb8\xd4\x62\x02", .klen = 16, - .iv = "\xd3\x00\xc9\xad\xb8\xb0\x4e\x61" - "\xc3\xfb\x6f\xfd\xea\xff\xa9\x15", - .assoc = "", - .alen = 0, - .ptext = "\xf2\x92\xe6\x7d\x40\xee\xa3\x6f" - "\x03\x68\xc8\x45\xe7\x91\x0a\x18", - .plen = 16, - .ctext = "\x66\xdf\x6e\x71\xc0\x6e\xa4\x4c" - "\x9d\xb7\x8c\x9a\xdb\x1f\xd2\x2e" - "\x23\xb6\xa4\xfb\xd3\x86\xdd\xbb" - "\xde\x54\x9b\xf5\x92\x8b\x93\xc5", - .clen = 32, + .dt = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62" + "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xf9", + .dtlen = 16, + .v = "\x80\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .vlen = 16, + .result = "\x59\x53\x1e\xd1\x3b\xb0\xc0\x55" + "\x84\x79\x66\x85\xc1\x2f\x76\x41", + .rlen = 16, + .loops = 1, }, { - .key = "\x01\x5c\x75\xe5\x84\x8d\x4d\xf6" - "\x23\x9f\xf4\x6a\xe6\x5a\x3b\x9a", + .key = "\xf3\xb1\x66\x6d\x13\x60\x72\x42" + "\xed\x06\x1c\xab\xb8\xd4\x62\x02", .klen = 16, - .iv = "\x10\x25\x03\x4c\xc8\x2c\xf7\x7d" - "\x44\xd5\x21\x8e\xe4\x23\x6b\x1c", - .assoc = "", - .alen = 0, - .ptext = "\x2e\xb7\x20\x1c\x50\x6a\x4b\x8b" - "\x84\x42\x7a\xd7\xe1\xb5\xcd\x1f" - "\xd3", - .plen = 17, - .ctext = "\x4f\xc3\x69\xb6\xd3\xa4\x64\x8b" - "\x71\xc3\x8a\x91\x22\x4f\x1b\xd2" - "\x33\x6d\x86\xbc\xf8\x2f\x06\xf9" - "\x82\x64\xc7\x72\x00\x30\xfc\xf0" - "\xf8", - .clen = 33, + .dt = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62" + "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfa", + .dtlen = 16, + .v = "\xc0\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .vlen = 16, + .result = "\x7c\x22\x2c\xf4\xca\x8f\xa2\x4c" + "\x1c\x9c\xb6\x41\xa9\xf3\x22\x0d", + .rlen = 16, + .loops = 1, }, { - .key = "\x3d\x80\xae\x84\x94\x09\xf6\x12" - "\xa4\x79\xa6\xfb\xe0\x7f\xfd\xa0", + .key = "\xf3\xb1\x66\x6d\x13\x60\x72\x42" + "\xed\x06\x1c\xab\xb8\xd4\x62\x02", .klen = 16, - .iv = "\x4c\x49\x3d\xec\xd8\xa8\xa0\x98" - "\xc5\xb0\xd3\x1f\xde\x48\x2e\x22", - .assoc = "", - .alen = 0, - .ptext = "\x6b\xdc\x5a\xbb\x60\xe5\xf4\xa6" - "\x05\x1d\x2c\x68\xdb\xda\x8f\x25" - "\xfe\x8d\x45\x19\x1e\xc0\x0b\x99" - "\x88\x11\x39\x12\x1c\x3a\xbb", - .plen = 31, - .ctext = "\xe3\x93\x15\xae\x5f\x9d\x3c\xb5" - "\xd6\x9d\xee\xee\xcf\xaa\xaf\xe1" - "\x45\x10\x96\xe0\xbf\x55\x0f\x4c" - "\x1a\xfd\xf4\xda\x4e\x10\xde\xc9" - "\x0e\x6f\xc7\x3c\x49\x94\x41\xfc" - "\x59\x28\x88\x3c\x79\x10\x6b", - .clen = 47, + .dt = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62" + "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfb", + .dtlen = 16, + .v = "\xe0\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .vlen = 16, + .result = "\x8a\xaa\x00\x39\x66\x67\x5b\xe5" + "\x29\x14\x28\x81\xa9\x4d\x4e\xc7", + .rlen = 16, + .loops = 1, }, { - .key = "\x7a\xa5\xe8\x23\xa4\x84\x9e\x2d" - "\x25\x53\x58\x8c\xda\xa3\xc0\xa6", + .key = "\xf3\xb1\x66\x6d\x13\x60\x72\x42" + "\xed\x06\x1c\xab\xb8\xd4\x62\x02", .klen = 16, - .iv = "\x89\x6e\x77\x8b\xe8\x23\x49\xb4" - "\x45\x8a\x85\xb1\xd8\x6c\xf1\x28", - .assoc = "", - .alen = 0, - .ptext = "\xa7\x00\x93\x5b\x70\x61\x9d\xc2" - "\x86\xf7\xde\xfa\xd5\xfe\x52\x2b" - "\x28\x50\x51\x9d\x24\x60\x8d\xb3" - "\x49\x3e\x17\xea\xf6\x99\x5a\xdd", - .plen = 32, - .ctext = "\x1c\x8e\x22\x34\xfd\xab\xe6\x0d" - "\x1c\x9f\x06\x54\x8b\x0b\xb4\x40" - "\xde\x11\x59\x3e\xfd\x74\xf6\x42" - "\x97\x17\xf7\x24\xb6\x7e\xc4\xc6" - "\x06\xa3\x94\xda\x3d\x7f\x55\x0a" - "\x92\x07\x2f\xa6\xf3\x6b\x2c\xfc", - .clen = 48, + .dt = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62" + "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfc", + .dtlen = 16, + .v = "\xf0\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .vlen = 16, + .result = "\x88\xdd\xa4\x56\x30\x24\x23\xe5" + "\xf6\x9d\xa5\x7e\x7b\x95\xc7\x3a", + .rlen = 16, + .loops = 1, }, { - .key = "\xb6\xca\x22\xc3\xb4\x00\x47\x49" - "\xa6\x2d\x0a\x1e\xd4\xc7\x83\xad", + .key = "\xf3\xb1\x66\x6d\x13\x60\x72\x42" + "\xed\x06\x1c\xab\xb8\xd4\x62\x02", .klen = 16, - .iv = "\xc5\x93\xb0\x2a\xf8\x9f\xf1\xd0" - "\xc6\x64\x37\x42\xd2\x90\xb3\x2e", - .assoc = "\xd5", - .alen = 1, - .ptext = "", - .plen = 0, - .ctext = "\xa0\x2a\xb4\x9a\x91\x00\x15\xb8" - "\x0f\x9a\x15\x60\x0e\x9b\x13\x8f", - .clen = 16, - }, { - .key = "\xf3\xee\x5c\x62\xc4\x7c\xf0\x65" - "\x27\x08\xbd\xaf\xce\xec\x45\xb3", + .dt = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62" + "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfd", + .dtlen = 16, + .v = "\xf8\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .vlen = 16, + .result = "\x05\x25\x92\x46\x61\x79\xd2\xcb" + "\x78\xc4\x0b\x14\x0a\x5a\x9a\xc8", + .rlen = 16, + .loops = 1, + }, { /* Monte Carlo Test */ + .key = "\x9f\x5b\x51\x20\x0b\xf3\x34\xb5" + "\xd8\x2b\xe8\xc3\x72\x55\xc8\x48", .klen = 16, - .iv = "\x02\xb8\xea\xca\x09\x1b\x9a\xec" - "\x47\x3e\xe9\xd4\xcc\xb5\x76\x34", - .assoc = "\x11\x81\x78\x32\x4d\xb9\x44\x73" - "\x68\x75\x16\xf8\xcb\x7e\xa7", - .alen = 15, - .ptext = "", - .plen = 0, - .ctext = "\x4c\x26\xad\x9c\x14\xfd\x9c\x8c" - "\x84\xfb\x26\xfb\xd5\xca\x62\x39", - .clen = 16, + .dt = "\x63\x76\xbb\xe5\x29\x02\xba\x3b" + "\x67\xc9\x25\xfa\x70\x1f\x11\xac", + .dtlen = 16, + .v = "\x57\x2c\x8e\x76\x87\x26\x47\x97" + "\x7e\x74\xfb\xdd\xc4\x95\x01\xd1", + .vlen = 16, + .result = "\x48\xe9\xbd\x0d\x06\xee\x18\xfb" + "\xe4\x57\x90\xd5\xc3\xfc\x9b\x73", + .rlen = 16, + .loops = 10000, + }, +}; + +/* + * SP800-90A DRBG Test vectors from + * http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip + * + * Test vectors for DRBG with prediction resistance. All types of DRBGs + * (Hash, HMAC, CTR) are tested with all permutations of use cases (w/ and + * w/o personalization string, w/ and w/o additional input string). + */ +static const struct drbg_testvec drbg_pr_sha256_tv_template[] = { + { + .entropy = (unsigned char *) + "\x72\x88\x4c\xcd\x6c\x85\x57\x70\xf7\x0b\x8b\x86" + "\xc1\xeb\xd2\x4e\x36\x14\xab\x18\xc4\x9c\xc9\xcf" + "\x1a\xe8\xf7\x7b\x02\x49\x73\xd7\xf1\x42\x7d\xc6" + "\x3f\x29\x2d\xec\xd3\x66\x51\x3f\x1d\x8d\x5b\x4e", + .entropylen = 48, + .entpra = (unsigned char *) + "\x38\x9c\x91\xfa\xc2\xa3\x46\x89\x56\x08\x3f\x62" + "\x73\xd5\x22\xa9\x29\x63\x3a\x1d\xe5\x5d\x5e\x4f" + "\x67\xb0\x67\x7a\x5e\x9e\x0c\x62", + .entprb = (unsigned char *) + "\xb2\x8f\x36\xb2\xf6\x8d\x39\x13\xfa\x6c\x66\xcf" + "\x62\x8a\x7e\x8c\x12\x33\x71\x9c\x69\xe4\xa5\xf0" + "\x8c\xee\xeb\x9c\xf5\x31\x98\x31", + .entprlen = 32, + .expected = (unsigned char *) + "\x52\x7b\xa3\xad\x71\x77\xa4\x49\x42\x04\x61\xc7" + "\xf0\xaf\xa5\xfd\xd3\xb3\x0d\x6a\x61\xba\x35\x49" + "\xbb\xaa\xaf\xe4\x25\x7d\xb5\x48\xaf\x5c\x18\x3d" + "\x33\x8d\x9d\x45\xdf\x98\xd5\x94\xa8\xda\x92\xfe" + "\xc4\x3c\x94\x2a\xcf\x7f\x7b\xf2\xeb\x28\xa9\xf1" + "\xe0\x86\x30\xa8\xfe\xf2\x48\x90\x91\x0c\x75\xb5" + "\x3c\x00\xf0\x4d\x09\x4f\x40\xa7\xa2\x8c\x52\xdf" + "\x52\xef\x17\xbf\x3d\xd1\xa2\x31\xb4\xb8\xdc\xe6" + "\x5b\x0d\x1f\x78\x36\xb4\xe6\x4b\xa7\x11\x25\xd5" + "\x94\xc6\x97\x36\xab\xf0\xe5\x31\x28\x6a\xbb\xce" + "\x30\x81\xa6\x8f\x27\x14\xf8\x1c", + .expectedlen = 128, + .addtla = NULL, + .addtlb = NULL, + .addtllen = 0, + .pers = NULL, + .perslen = 0, }, { - .key = "\x2f\x13\x95\x01\xd5\xf7\x99\x81" - "\xa8\xe2\x6f\x41\xc8\x10\x08\xb9", - .klen = 16, - .iv = "\x3f\xdc\x24\x69\x19\x96\x43\x08" - "\xc8\x18\x9b\x65\xc6\xd9\x39\x3b", - .assoc = "\x4e\xa5\xb2\xd1\x5d\x35\xed\x8f" - "\xe8\x4f\xc8\x89\xc5\xa2\x69\xbc", - .alen = 16, - .ptext = "", - .plen = 0, - .ctext = "\x45\x85\x0e\x0f\xf4\xae\x96\xa1" - "\x99\x4d\x6d\xb4\x67\x32\xb0\x3a", - .clen = 16, - }, { - .key = "\x6c\x38\xcf\xa1\xe5\x73\x41\x9d" - "\x29\xbc\x21\xd2\xc2\x35\xcb\xbf", - .klen = 16, - .iv = "\x7b\x01\x5d\x08\x29\x12\xec\x24" - "\x49\xf3\x4d\xf7\xc0\xfe\xfb\x41", - .assoc = "\x8a\xca\xec\x70\x6d\xb1\x96\xab" - "\x69\x29\x7a\x1b\xbf\xc7\x2c\xc2" - "\x07", - .alen = 17, - .ptext = "", - .plen = 0, - .ctext = "\x33\xb1\x42\x97\x8e\x16\x7b\x63" - "\x06\xba\x5b\xcb\xae\x6d\x8b\x56", - .clen = 16, + .entropy = (unsigned char *) + "\x5d\xf2\x14\xbc\xf6\xb5\x4e\x0b\xf0\x0d\x6f\x2d" + "\xe2\x01\x66\x7b\xd0\xa4\x73\xa4\x21\xdd\xb0\xc0" + "\x51\x79\x09\xf4\xea\xa9\x08\xfa\xa6\x67\xe0\xe1" + "\xd1\x88\xa8\xad\xee\x69\x74\xb3\x55\x06\x9b\xf6", + .entropylen = 48, + .entpra = (unsigned char *) + "\xef\x48\x06\xa2\xc2\x45\xf1\x44\xfa\x34\x2c\xeb" + "\x8d\x78\x3c\x09\x8f\x34\x72\x20\xf2\xe7\xfd\x13" + "\x76\x0a\xf6\xdc\x3c\xf5\xc0\x15", + .entprb = (unsigned char *) + "\x4b\xbe\xe5\x24\xed\x6a\x2d\x0c\xdb\x73\x5e\x09" + "\xf9\xad\x67\x7c\x51\x47\x8b\x6b\x30\x2a\xc6\xde" + "\x76\xaa\x55\x04\x8b\x0a\x72\x95", + .entprlen = 32, + .expected = (unsigned char *) + "\x3b\x14\x71\x99\xa1\xda\xa0\x42\xe6\xc8\x85\x32" + "\x70\x20\x32\x53\x9a\xbe\xd1\x1e\x15\xef\xfb\x4c" + "\x25\x6e\x19\x3a\xf0\xb9\xcb\xde\xf0\x3b\xc6\x18" + "\x4d\x85\x5a\x9b\xf1\xe3\xc2\x23\x03\x93\x08\xdb" + "\xa7\x07\x4b\x33\x78\x40\x4d\xeb\x24\xf5\x6e\x81" + "\x4a\x1b\x6e\xa3\x94\x52\x43\xb0\xaf\x2e\x21\xf4" + "\x42\x46\x8e\x90\xed\x34\x21\x75\xea\xda\x67\xb6" + "\xe4\xf6\xff\xc6\x31\x6c\x9a\x5a\xdb\xb3\x97\x13" + "\x09\xd3\x20\x98\x33\x2d\x6d\xd7\xb5\x6a\xa8\xa9" + "\x9a\x5b\xd6\x87\x52\xa1\x89\x2b\x4b\x9c\x64\x60" + "\x50\x47\xa3\x63\x81\x16\xaf\x19", + .expectedlen = 128, + .addtla = (unsigned char *) + "\xbe\x13\xdb\x2a\xe9\xa8\xfe\x09\x97\xe1\xce\x5d" + "\xe8\xbb\xc0\x7c\x4f\xcb\x62\x19\x3f\x0f\xd2\xad" + "\xa9\xd0\x1d\x59\x02\xc4\xff\x70", + .addtlb = (unsigned char *) + "\x6f\x96\x13\xe2\xa7\xf5\x6c\xfe\xdf\x66\xe3\x31" + "\x63\x76\xbf\x20\x27\x06\x49\xf1\xf3\x01\x77\x41" + "\x9f\xeb\xe4\x38\xfe\x67\x00\xcd", + .addtllen = 32, + .pers = NULL, + .perslen = 0, }, { - .key = "\xa8\x5c\x09\x40\xf5\xef\xea\xb8" - "\xaa\x96\xd3\x64\xbc\x59\x8d\xc6", - .klen = 16, - .iv = "\xb8\x26\x97\xa8\x39\x8e\x94\x3f" - "\xca\xcd\xff\x88\xba\x22\xbe\x47", - .assoc = "\xc7\xef\x26\x10\x7d\x2c\x3f\xc6" - "\xea\x03\x2c\xac\xb9\xeb\xef\xc9" - "\x31\x6b\x08\x12\xfc\xd8\x37\x2d" - "\xe0\x17\x3a\x2e\x83\x5c\x8f", - .alen = 31, - .ptext = "", - .plen = 0, - .ctext = "\xda\x44\x08\x8c\x2a\xa5\x07\x35" - "\x0b\x54\x4e\x6d\xe3\xfd\xc4\x5f", - .clen = 16, + .entropy = (unsigned char *) + "\xc6\x1c\xaf\x83\xa2\x56\x38\xf9\xb0\xbc\xd9\x85" + "\xf5\x2e\xc4\x46\x9c\xe1\xb9\x40\x98\x70\x10\x72" + "\xd7\x7d\x15\x85\xa1\x83\x5a\x97\xdf\xc8\xa8\xe8" + "\x03\x4c\xcb\x70\x35\x8b\x90\x94\x46\x8a\x6e\xa1", + .entropylen = 48, + .entpra = (unsigned char *) + "\xc9\x05\xa4\xcf\x28\x80\x4b\x93\x0f\x8b\xc6\xf9" + "\x09\x41\x58\x74\xe9\xec\x28\xc7\x53\x0a\x73\x60" + "\xba\x0a\xde\x57\x5b\x4b\x9f\x29", + .entprb = (unsigned char *) + "\x4f\x31\xd2\xeb\xac\xfa\xa8\xe2\x01\x7d\xf3\xbd" + "\x42\xbd\x20\xa0\x30\x65\x74\xd5\x5d\xd2\xad\xa4" + "\xa9\xeb\x1f\x4d\xf6\xfd\xb8\x26", + .entprlen = 32, + .expected = (unsigned char *) + "\xf6\x13\x05\xcb\x83\x60\x16\x42\x49\x1d\xc6\x25" + "\x3b\x8c\x31\xa3\xbe\x8b\xbd\x1c\xe2\xec\x1d\xde" + "\xbb\xbf\xa1\xac\xa8\x9f\x50\xce\x69\xce\xef\xd5" + "\xd6\xf2\xef\x6a\xf7\x81\x38\xdf\xbc\xa7\x5a\xb9" + "\xb2\x42\x65\xab\xe4\x86\x8d\x2d\x9d\x59\x99\x2c" + "\x5a\x0d\x71\x55\x98\xa4\x45\xc2\x8d\xdb\x05\x5e" + "\x50\x21\xf7\xcd\xe8\x98\x43\xce\x57\x74\x63\x4c" + "\xf3\xb1\xa5\x14\x1e\x9e\x01\xeb\x54\xd9\x56\xae" + "\xbd\xb6\x6f\x1a\x47\x6b\x3b\x44\xe4\xa2\xe9\x3c" + "\x6c\x83\x12\x30\xb8\x78\x7f\x8e\x54\x82\xd4\xfe" + "\x90\x35\x0d\x4c\x4d\x85\xe7\x13", + .expectedlen = 128, + .addtla = NULL, + .addtlb = NULL, + .addtllen = 0, + .pers = (unsigned char *) + "\xa5\xbf\xac\x4f\x71\xa1\xbb\x67\x94\xc6\x50\xc7" + "\x2a\x45\x9e\x10\xa8\xed\xf7\x52\x4f\xfe\x21\x90" + "\xa4\x1b\xe1\xe2\x53\xcc\x61\x47", + .perslen = 32, }, { - .key = "\xe5\x81\x42\xdf\x05\x6a\x93\xd4" - "\x2b\x70\x85\xf5\xb6\x7d\x50\xcc", - .klen = 16, - .iv = "\xf4\x4a\xd1\x47\x49\x09\x3d\x5b" - "\x4b\xa7\xb1\x19\xb4\x46\x81\x4d", - .assoc = "\x03\x14\x5f\xaf\x8d\xa8\xe7\xe2" - "\x6b\xde\xde\x3e\xb3\x10\xb1\xcf" - "\x5c\x2d\x14\x96\x01\x78\xb9\x47" - "\xa1\x44\x19\x06\x5d\xbb\x2e\x2f", - .alen = 32, - .ptext = "", - .plen = 0, - .ctext = "\x1b\xb1\xf1\xa8\x9e\xc2\xb2\x88" - "\x40\x7f\x7b\x19\x7a\x52\x8c\xf0", - .clen = 16, + .entropy = (unsigned char *) + "\xb6\xc1\x8d\xdf\x99\x54\xbe\x95\x10\x48\xd9\xf6" + "\xd7\x48\xa8\x73\x2d\x74\xde\x1e\xde\x57\x7e\xf4" + "\x7b\x7b\x64\xef\x88\x7a\xa8\x10\x4b\xe1\xc1\x87" + "\xbb\x0b\xe1\x39\x39\x50\xaf\x68\x9c\xa2\xbf\x5e", + .entropylen = 48, + .entpra = (unsigned char *) + "\xdc\x81\x0a\x01\x58\xa7\x2e\xce\xee\x48\x8c\x7c" + "\x77\x9e\x3c\xf1\x17\x24\x7a\xbb\xab\x9f\xca\x12" + "\x19\xaf\x97\x2d\x5f\xf9\xff\xfc", + .entprb = (unsigned char *) + "\xaf\xfc\x4f\x98\x8b\x93\x95\xc1\xb5\x8b\x7f\x73" + "\x6d\xa6\xbe\x6d\x33\xeb\x2c\x82\xb1\xaf\xc1\xb6" + "\xb6\x05\xe2\x44\xaa\xfd\xe7\xdb", + .entprlen = 32, + .expected = (unsigned char *) + "\x51\x79\xde\x1c\x0f\x58\xf3\xf4\xc9\x57\x2e\x31" + "\xa7\x09\xa1\x53\x64\x63\xa2\xc5\x1d\x84\x88\x65" + "\x01\x1b\xc6\x16\x3c\x49\x5b\x42\x8e\x53\xf5\x18" + "\xad\x94\x12\x0d\x4f\x55\xcc\x45\x5c\x98\x0f\x42" + "\x28\x2f\x47\x11\xf9\xc4\x01\x97\x6b\xa0\x94\x50" + "\xa9\xd1\x5e\x06\x54\x3f\xdf\xbb\xc4\x98\xee\x8b" + "\xba\xa9\xfa\x49\xee\x1d\xdc\xfb\x50\xf6\x51\x9f" + "\x6c\x4a\x9a\x6f\x63\xa2\x7d\xad\xaf\x3a\x24\xa0" + "\xd9\x9f\x07\xeb\x15\xee\x26\xe0\xd5\x63\x39\xda" + "\x3c\x59\xd6\x33\x6c\x02\xe8\x05\x71\x46\x68\x44" + "\x63\x4a\x68\x72\xe9\xf5\x55\xfe", + .expectedlen = 128, + .addtla = (unsigned char *) + "\x15\x20\x2f\xf6\x98\x28\x63\xa2\xc4\x4e\xbb\x6c" + "\xb2\x25\x92\x61\x79\xc9\x22\xc4\x61\x54\x96\xff" + "\x4a\x85\xca\x80\xfe\x0d\x1c\xd0", + .addtlb = (unsigned char *) + "\xde\x29\x8e\x03\x42\x61\xa3\x28\x5e\xc8\x80\xc2" + "\x6d\xbf\xad\x13\xe1\x8d\x2a\xc7\xe8\xc7\x18\x89" + "\x42\x58\x9e\xd6\xcc\xad\x7b\x1e", + .addtllen = 32, + .pers = (unsigned char *) + "\x84\xc3\x73\x9e\xce\xb3\xbc\x89\xf7\x62\xb3\xe1" + "\xd7\x48\x45\x8a\xa9\xcc\xe9\xed\xd5\x81\x84\x52" + "\x82\x4c\xdc\x19\xb8\xf8\x92\x5c", + .perslen = 32, + }, +}; + +static const struct drbg_testvec drbg_pr_hmac_sha256_tv_template[] = { + { + .entropy = (unsigned char *) + "\x99\x69\xe5\x4b\x47\x03\xff\x31\x78\x5b\x87\x9a" + "\x7e\x5c\x0e\xae\x0d\x3e\x30\x95\x59\xe9\xfe\x96" + "\xb0\x67\x6d\x49\xd5\x91\xea\x4d\x07\xd2\x0d\x46" + "\xd0\x64\x75\x7d\x30\x23\xca\xc2\x37\x61\x27\xab", + .entropylen = 48, + .entpra = (unsigned char *) + "\xc6\x0f\x29\x99\x10\x0f\x73\x8c\x10\xf7\x47\x92" + "\x67\x6a\x3f\xc4\xa2\x62\xd1\x37\x21\x79\x80\x46" + "\xe2\x9a\x29\x51\x81\x56\x9f\x54", + .entprb = (unsigned char *) + "\xc1\x1d\x45\x24\xc9\x07\x1b\xd3\x09\x60\x15\xfc" + "\xf7\xbc\x24\xa6\x07\xf2\x2f\xa0\x65\xc9\x37\x65" + "\x8a\x2a\x77\xa8\x69\x90\x89\xf4", + .entprlen = 32, + .expected = (unsigned char *) + "\xab\xc0\x15\x85\x60\x94\x80\x3a\x93\x8d\xff\xd2" + "\x0d\xa9\x48\x43\x87\x0e\xf9\x35\xb8\x2c\xfe\xc1" + "\x77\x06\xb8\xf5\x51\xb8\x38\x50\x44\x23\x5d\xd4" + "\x4b\x59\x9f\x94\xb3\x9b\xe7\x8d\xd4\x76\xe0\xcf" + "\x11\x30\x9c\x99\x5a\x73\x34\xe0\xa7\x8b\x37\xbc" + "\x95\x86\x23\x50\x86\xfa\x3b\x63\x7b\xa9\x1c\xf8" + "\xfb\x65\xef\xa2\x2a\x58\x9c\x13\x75\x31\xaa\x7b" + "\x2d\x4e\x26\x07\xaa\xc2\x72\x92\xb0\x1c\x69\x8e" + "\x6e\x01\xae\x67\x9e\xb8\x7c\x01\xa8\x9c\x74\x22" + "\xd4\x37\x2d\x6d\x75\x4a\xba\xbb\x4b\xf8\x96\xfc" + "\xb1\xcd\x09\xd6\x92\xd0\x28\x3f", + .expectedlen = 128, + .addtla = NULL, + .addtlb = NULL, + .addtllen = 0, + .pers = NULL, + .perslen = 0, }, { - .key = "\x22\xa6\x7c\x7f\x15\xe6\x3c\xf0" - "\xac\x4b\x37\x86\xb0\xa2\x13\xd2", - .klen = 16, - .iv = "\x31\x6f\x0b\xe6\x59\x85\xe6\x77" - "\xcc\x81\x63\xab\xae\x6b\x43\x54", - .assoc = "\x40", - .alen = 1, - .ptext = "\x4f", - .plen = 1, - .ctext = "\x6e\xc8\xfb\x15\x9d\x98\x49\xc9" - "\xa0\x98\x09\x85\xbe\x56\x8e\x79" - "\xf4", - .clen = 17, + .entropy = (unsigned char *) + "\xb9\x1f\xe9\xef\xdd\x9b\x7d\x20\xb6\xec\xe0\x2f" + "\xdb\x76\x24\xce\x41\xc8\x3a\x4a\x12\x7f\x3e\x2f" + "\xae\x05\x99\xea\xb5\x06\x71\x0d\x0c\x4c\xb4\x05" + "\x26\xc6\xbd\xf5\x7f\x2a\x3d\xf2\xb5\x49\x7b\xda", + .entropylen = 48, + .entpra = (unsigned char *) + "\xef\x67\x50\x9c\xa7\x7d\xdf\xb7\x2d\x81\x01\xa4" + "\x62\x81\x6a\x69\x5b\xb3\x37\x45\xa7\x34\x8e\x26" + "\x46\xd9\x26\xa2\x19\xd4\x94\x43", + .entprb = (unsigned char *) + "\x97\x75\x53\x53\xba\xb4\xa6\xb2\x91\x60\x71\x79" + "\xd1\x6b\x4a\x24\x9a\x34\x66\xcc\x33\xab\x07\x98" + "\x51\x78\x72\xb2\x79\xfd\x2c\xff", + .entprlen = 32, + .expected = (unsigned char *) + "\x9c\xdc\x63\x8a\x19\x23\x22\x66\x0c\xc5\xb9\xd7" + "\xfb\x2a\xb0\x31\xe3\x8a\x36\xa8\x5a\xa8\x14\xda" + "\x1e\xa9\xcc\xfe\xb8\x26\x44\x83\x9f\xf6\xff\xaa" + "\xc8\x98\xb8\x30\x35\x3b\x3d\x36\xd2\x49\xd4\x40" + "\x62\x0a\x65\x10\x76\x55\xef\xc0\x95\x9c\xa7\xda" + "\x3f\xcf\xb7\x7b\xc6\xe1\x28\x52\xfc\x0c\xe2\x37" + "\x0d\x83\xa7\x51\x4b\x31\x47\x3c\xe1\x3c\xae\x70" + "\x01\xc8\xa3\xd3\xc2\xac\x77\x9c\xd1\x68\x77\x9b" + "\x58\x27\x3b\xa5\x0f\xc2\x7a\x8b\x04\x65\x62\xd5" + "\xe8\xd6\xfe\x2a\xaf\xd3\xd3\xfe\xbd\x18\xfb\xcd" + "\xcd\x66\xb5\x01\x69\x66\xa0\x3c", + .expectedlen = 128, + .addtla = (unsigned char *) + "\x17\xc1\x56\xcb\xcc\x50\xd6\x03\x7d\x45\x76\xa3" + "\x75\x76\xc1\x4a\x66\x1b\x2e\xdf\xb0\x2e\x7d\x56" + "\x6d\x99\x3b\xc6\x58\xda\x03\xf6", + .addtlb = (unsigned char *) + "\x7c\x7b\x4a\x4b\x32\x5e\x6f\x67\x34\xf5\x21\x4c" + "\xf9\x96\xf9\xbf\x1c\x8c\x81\xd3\x9b\x60\x6a\x44" + "\xc6\x03\xa2\xfb\x13\x20\x19\xb7", + .addtllen = 32, + .pers = NULL, + .perslen = 0, }, { - .key = "\x5e\xcb\xb6\x1e\x25\x62\xe4\x0c" - "\x2d\x25\xe9\x18\xaa\xc6\xd5\xd8", - .klen = 16, - .iv = "\x6d\x94\x44\x86\x69\x00\x8f\x93" - "\x4d\x5b\x15\x3c\xa8\x8f\x06\x5a", - .assoc = "\x7c\x5d\xd3\xee\xad\x9f\x39\x1a" - "\x6d\x92\x42\x61\xa7\x58\x37", - .alen = 15, - .ptext = "\x8b\x26\x61\x55\xf1\x3e\xe3\xa1" - "\x8d\xc8\x6e\x85\xa5\x21\x67", - .plen = 15, - .ctext = "\x99\x2e\x84\x50\x64\x5c\xab\x29" - "\x20\xba\xb9\x2f\x62\x3a\xce\x2a" - "\x75\x25\x3b\xe3\x40\xe0\x1d\xfc" - "\x20\x63\x0b\x49\x7e\x97\x08", - .clen = 31, - }, { - .key = "\x9b\xef\xf0\xbd\x35\xdd\x8d\x28" - "\xad\xff\x9b\xa9\xa4\xeb\x98\xdf", - .klen = 16, - .iv = "\xaa\xb8\x7e\x25\x79\x7c\x37\xaf" - "\xce\x36\xc7\xce\xa2\xb4\xc9\x60", - .assoc = "\xb9\x82\x0c\x8d\xbd\x1b\xe2\x36" - "\xee\x6c\xf4\xf2\xa1\x7d\xf9\xe2", - .alen = 16, - .ptext = "\xc8\x4b\x9b\xf5\x01\xba\x8c\xbd" - "\x0e\xa3\x21\x16\x9f\x46\x2a\x63", - .plen = 16, - .ctext = "\xd9\x8e\xfd\x50\x8f\x02\x9f\xee" - "\x78\x08\x12\xec\x09\xaf\x53\x14" - "\x90\x3e\x3d\x76\xad\x71\x21\x08" - "\x77\xe5\x4b\x15\xc2\xe6\xbc\xdb", - .clen = 32, - }, { - .key = "\xd7\x14\x29\x5d\x45\x59\x36\x44" - "\x2e\xd9\x4d\x3b\x9e\x0f\x5b\xe5", - .klen = 16, - .iv = "\xe6\xdd\xb8\xc4\x89\xf8\xe0\xca" - "\x4f\x10\x7a\x5f\x9c\xd8\x8b\x66", - .assoc = "\xf5\xa6\x46\x2c\xce\x97\x8a\x51" - "\x6f\x46\xa6\x83\x9b\xa1\xbc\xe8" - "\x05", - .alen = 17, - .ptext = "\x05\x70\xd5\x94\x12\x36\x35\xd8" - "\x8f\x7d\xd3\xa8\x99\x6a\xed\x69" - "\xd0", - .plen = 17, - .ctext = "\xf3\xe7\x95\x86\xcf\x34\x95\x96" - "\x17\xfe\x1b\xae\x1b\x31\xf2\x1a" - "\xbd\xbc\xc9\x4e\x11\x29\x09\x5c" - "\x05\xd3\xb4\x2e\x4a\x74\x59\x49" - "\x7d", - .clen = 33, - }, { - .key = "\x14\x39\x63\xfc\x56\xd5\xdf\x5f" - "\xaf\xb3\xff\xcc\x98\x33\x1d\xeb", - .klen = 16, - .iv = "\x23\x02\xf1\x64\x9a\x73\x89\xe6" - "\xd0\xea\x2c\xf1\x96\xfc\x4e\x6d", - .assoc = "\x32\xcb\x80\xcc\xde\x12\x33\x6d" - "\xf0\x20\x58\x15\x95\xc6\x7f\xee" - "\x2f\xf9\x4e\x2c\x1b\x98\x43\xc7" - "\x68\x28\x73\x40\x9f\x96\x4a", - .alen = 31, - .ptext = "\x41\x94\x0e\x33\x22\xb1\xdd\xf4" - "\x10\x57\x85\x39\x93\x8f\xaf\x70" - "\xfa\xa9\xd0\x4d\x5c\x40\x23\xcd" - "\x98\x34\xab\x37\x56\xae\x32", - .plen = 31, - .ctext = "\x06\x96\xb2\xbf\x63\xf4\x1e\x24" - "\x0d\x19\x15\x61\x65\x3b\x06\x26" - "\x71\xe8\x7e\x16\xdb\x96\x01\x01" - "\x52\xcd\x49\x5b\x07\x33\x4e\xe7" - "\xaa\x91\xf5\xd5\xc6\xfe\x41\xb5" - "\xed\x90\xce\xb9\xcd\xcc\xa1", - .clen = 47, - }, { - .key = "\x50\x5d\x9d\x9b\x66\x50\x88\x7b" - "\x30\x8e\xb1\x5e\x92\x58\xe0\xf1", - .klen = 16, - .iv = "\x5f\x27\x2b\x03\xaa\xef\x32\x02" - "\x50\xc4\xde\x82\x90\x21\x11\x73", - .assoc = "\x6e\xf0\xba\x6b\xee\x8e\xdc\x89" - "\x71\xfb\x0a\xa6\x8f\xea\x41\xf4" - "\x5a\xbb\x59\xb0\x20\x38\xc5\xe0" - "\x29\x56\x52\x19\x79\xf5\xe9\x37", - .alen = 32, - .ptext = "\x7e\xb9\x48\xd3\x32\x2d\x86\x10" - "\x91\x31\x37\xcb\x8d\xb3\x72\x76" - "\x24\x6b\xdc\xd1\x61\xe0\xa5\xe7" - "\x5a\x61\x8a\x0f\x30\x0d\xd1\xec", - .plen = 32, - .ctext = "\xf9\xd7\xee\x17\xfd\x24\xcd\xf1" - "\xbc\x0f\x35\x97\x97\x0c\x4b\x18" - "\xce\x58\xc8\x3b\xd4\x85\x93\x79" - "\xcc\x9c\xea\xc1\x73\x13\x0b\x4c" - "\xcc\x6f\x28\xf8\xa4\x4e\xb8\x56" - "\x64\x4e\x47\xce\xb2\xb4\x92\xb4", - .clen = 48, - }, { - .key = "\x8d\x82\xd6\x3b\x76\xcc\x30\x97" - "\xb1\x68\x63\xef\x8c\x7c\xa3\xf7", - .klen = 16, - .iv = "\x9c\x4b\x65\xa2\xba\x6b\xdb\x1e" - "\xd1\x9e\x90\x13\x8a\x45\xd3\x79", - .assoc = "\xab\x14\xf3\x0a\xfe\x0a\x85\xa5" - "\xf2\xd5\xbc\x38\x89\x0e\x04\xfb" - "\x84\x7d\x65\x34\x25\xd8\x47\xfa" - "\xeb\x83\x31\xf1\x54\x54\x89\x0d" - "\x9d", - .alen = 33, - .ptext = "\xba\xde\x82\x72\x42\xa9\x2f\x2c" - "\x12\x0b\xe9\x5c\x87\xd7\x35\x7c" - "\x4f\x2e\xe8\x55\x66\x80\x27\x00" - "\x1b\x8f\x68\xe7\x0a\x6c\x71\xc3" - "\x21\x78\x55\x9d\x9c\x65\x7b\xcd" - "\x0a\x34\x97\xff\x47\x37\xb0\x2a" - "\x80\x0d\x19\x98\x33\xa9\x7a\xe3" - "\x2e\x4c\xc6\xf3\x8c\x88\x42\x01" - "\xbd", - .plen = 65, - .ctext = "\x58\xfa\x3a\x3d\xd9\x88\x63\xe8" - "\xc5\x78\x50\x8b\x4a\xc9\xdf\x7f" - "\x4b\xfa\xc8\x2e\x67\x43\xf3\x63" - "\x42\x8e\x99\x5a\x9c\x0b\x84\x77" - "\xbc\x46\x76\x48\x82\xc7\x57\x96" - "\xe1\x65\xd1\xed\x1d\xdd\x80\x24" - "\xa6\x4d\xa9\xf1\x53\x8b\x5e\x0e" - "\x26\xb9\xcc\x37\xe5\x43\xe1\x5a" - "\x8a\xd6\x8c\x5a\xe4\x95\xd1\x8d" - "\xf7\x33\x64\xc1\xd3\xf2\xfc\x35" - "\x01", - .clen = 81, - }, { - .key = "\xc9\xa7\x10\xda\x86\x48\xd9\xb3" - "\x32\x42\x15\x80\x85\xa1\x65\xfe", - .klen = 16, - .iv = "\xd8\x70\x9f\x42\xca\xe6\x83\x3a" - "\x52\x79\x42\xa5\x84\x6a\x96\x7f", - .assoc = "\xe8\x39\x2d\xaa\x0e\x85\x2d\xc1" - "\x72\xaf\x6e\xc9\x82\x33\xc7\x01" - "\xaf\x40\x70\xb8\x2a\x78\xc9\x14" - "\xac\xb1\x10\xca\x2e\xb3\x28\xe4" - "\xac\xfa\x58\x7f\xe5\x73\x09\x8c" - "\x1d\x40\x87\x8c\xd9\x75\xc0\x55" - "\xa2\xda\x07\xd1\xc2\xa9\xd1\xbb" - "\x09\x4f\x77\x62\x88\x2d\xf2\x68" - "\x54", - .alen = 65, - .ptext = "\xf7\x02\xbb\x11\x52\x24\xd8\x48" - "\x93\xe6\x9b\xee\x81\xfc\xf7\x82" - "\x79\xf0\xf3\xd9\x6c\x20\xa9\x1a" - "\xdc\xbc\x47\xc0\xe4\xcb\x10\x99" - "\x2f", - .plen = 33, - .ctext = "\x4c\xa9\xac\x71\xed\x10\xa6\x24" - "\xb7\xa7\xdf\x8b\xf5\xc2\x41\xcb" - "\x05\xc9\xd6\x97\xb6\x10\x7f\x17" - "\xc2\xc0\x93\xcf\xe0\x94\xfd\x99" - "\xf2\x62\x25\x28\x01\x23\x6f\x8b" - "\x04\x52\xbc\xb0\x3e\x66\x52\x90" - "\x9f", - .clen = 49, - }, { - .key = "\x06\xcc\x4a\x79\x96\xc3\x82\xcf" - "\xb3\x1c\xc7\x12\x7f\xc5\x28\x04", - .klen = 16, - .iv = "\x15\x95\xd8\xe1\xda\x62\x2c\x56" - "\xd3\x53\xf4\x36\x7e\x8e\x59\x85", - .assoc = "\x24\x5e\x67\x49\x1e\x01\xd6\xdd" - "\xf3\x89\x20\x5b\x7c\x57\x89\x07", - .alen = 16, - .ptext = "\x33\x27\xf5\xb1\x62\xa0\x80\x63" - "\x14\xc0\x4d\x7f\x7b\x20\xba\x89", - .plen = 16, - .ctext = "\x6d\xed\x04\x7a\x2f\x0c\x30\xa5" - "\x96\xe6\x97\xe4\x10\xeb\x40\x95" - "\xc5\x9a\xdf\x31\xd5\xa5\xa6\xec" - "\x05\xa8\x31\x50\x11\x19\x44", - .clen = 31, - }, { - .key = "\x42\xf0\x84\x19\xa6\x3f\x2b\xea" - "\x34\xf6\x79\xa3\x79\xe9\xeb\x0a", - .klen = 16, - .iv = "\x51\xb9\x12\x80\xea\xde\xd5\x71" - "\x54\x2d\xa6\xc8\x78\xb2\x1b\x8c", - .assoc = "\x61\x83\xa0\xe8\x2e\x7d\x7f\xf8" - "\x74\x63\xd2\xec\x76\x7c\x4c\x0d", - .alen = 16, - .ptext = "\x70\x4c\x2f\x50\x72\x1c\x29\x7f" - "\x95\x9a\xff\x10\x75\x45\x7d\x8f", - .plen = 16, - .ctext = "\x30\x95\x7d\xea\xdc\x62\xc0\x88" - "\xa1\xe3\x8d\x8c\xac\x04\x10\xa7" - "\xfa\xfa\x07\xbd\xa0\xf0\x36\xeb" - "\x21\x93\x2e\x31\x84\x83", - .clen = 30, + .entropy = (unsigned char *) + "\x13\x54\x96\xfc\x1b\x7d\x28\xf3\x18\xc9\xa7\x89" + "\xb6\xb3\xc8\x72\xac\x00\xd4\x59\x36\x25\x05\xaf" + "\xa5\xdb\x96\xcb\x3c\x58\x46\x87\xa5\xaa\xbf\x20" + "\x3b\xfe\x23\x0e\xd1\xc7\x41\x0f\x3f\xc9\xb3\x67", + .entropylen = 48, + .entpra = (unsigned char *) + "\xe2\xbd\xb7\x48\x08\x06\xf3\xe1\x93\x3c\xac\x79" + "\xa7\x2b\x11\xda\xe3\x2e\xe1\x91\xa5\x02\x19\x57" + "\x20\x28\xad\xf2\x60\xd7\xcd\x45", + .entprb = (unsigned char *) + "\x8b\xd4\x69\xfc\xff\x59\x95\x95\xc6\x51\xde\x71" + "\x68\x5f\xfc\xf9\x4a\xab\xec\x5a\xcb\xbe\xd3\x66" + "\x1f\xfa\x74\xd3\xac\xa6\x74\x60", + .entprlen = 32, + .expected = (unsigned char *) + "\x1f\x9e\xaf\xe4\xd2\x46\xb7\x47\x41\x4c\x65\x99" + "\x01\xe9\x3b\xbb\x83\x0c\x0a\xb0\xc1\x3a\xe2\xb3" + "\x31\x4e\xeb\x93\x73\xee\x0b\x26\xc2\x63\xa5\x75" + "\x45\x99\xd4\x5c\x9f\xa1\xd4\x45\x87\x6b\x20\x61" + "\x40\xea\x78\xa5\x32\xdf\x9e\x66\x17\xaf\xb1\x88" + "\x9e\x2e\x23\xdd\xc1\xda\x13\x97\x88\xa5\xb6\x5e" + "\x90\x14\x4e\xef\x13\xab\x5c\xd9\x2c\x97\x9e\x7c" + "\xd7\xf8\xce\xea\x81\xf5\xcd\x71\x15\x49\x44\xce" + "\x83\xb6\x05\xfb\x7d\x30\xb5\x57\x2c\x31\x4f\xfc" + "\xfe\x80\xb6\xc0\x13\x0c\x5b\x9b\x2e\x8f\x3d\xfc" + "\xc2\xa3\x0c\x11\x1b\x80\x5f\xf3", + .expectedlen = 128, + .addtla = NULL, + .addtlb = NULL, + .addtllen = 0, + .pers = (unsigned char *) + "\x64\xb6\xfc\x60\xbc\x61\x76\x23\x6d\x3f\x4a\x0f" + "\xe1\xb4\xd5\x20\x9e\x70\xdd\x03\x53\x6d\xbf\xce" + "\xcd\x56\x80\xbc\xb8\x15\xc8\xaa", + .perslen = 32, }, { - .key = "\x7f\x15\xbd\xb8\xb6\xba\xd3\x06" - "\xb5\xd1\x2b\x35\x73\x0e\xad\x10", - .klen = 16, - .iv = "\x8e\xde\x4c\x20\xfa\x59\x7e\x8d" - "\xd5\x07\x58\x59\x72\xd7\xde\x92", - .assoc = "\x9d\xa7\xda\x88\x3e\xf8\x28\x14" - "\xf5\x3e\x85\x7d\x70\xa0\x0f\x13", - .alen = 16, - .ptext = "\xac\x70\x69\xef\x82\x97\xd2\x9b" - "\x15\x74\xb1\xa2\x6f\x69\x3f\x95", - .plen = 16, - .ctext = "\x93\xcd\xee\xd4\xcb\x9d\x8d\x16" - "\x63\x0d\x43\xd5\x49\xca\xa8\x85" - "\x49\xc0\xae\x13\xbc\x26\x1d\x4b", - .clen = 24, + .entropy = (unsigned char *) + "\xc7\xcc\xbc\x67\x7e\x21\x66\x1e\x27\x2b\x63\xdd" + "\x3a\x78\xdc\xdf\x66\x6d\x3f\x24\xae\xcf\x37\x01" + "\xa9\x0d\x89\x8a\xa7\xdc\x81\x58\xae\xb2\x10\x15" + "\x7e\x18\x44\x6d\x13\xea\xdf\x37\x85\xfe\x81\xfb", + .entropylen = 48, + .entpra = (unsigned char *) + "\x7b\xa1\x91\x5b\x3c\x04\xc4\x1b\x1d\x19\x2f\x1a" + "\x18\x81\x60\x3c\x6c\x62\x91\xb7\xe9\xf5\xcb\x96" + "\xbb\x81\x6a\xcc\xb5\xae\x55\xb6", + .entprb = (unsigned char *) + "\x99\x2c\xc7\x78\x7e\x3b\x88\x12\xef\xbe\xd3\xd2" + "\x7d\x2a\xa5\x86\xda\x8d\x58\x73\x4a\x0a\xb2\x2e" + "\xbb\x4c\x7e\xe3\x9a\xb6\x81\xc1", + .entprlen = 32, + .expected = (unsigned char *) + "\x95\x6f\x95\xfc\x3b\xb7\xfe\x3e\xd0\x4e\x1a\x14" + "\x6c\x34\x7f\x7b\x1d\x0d\x63\x5e\x48\x9c\x69\xe6" + "\x46\x07\xd2\x87\xf3\x86\x52\x3d\x98\x27\x5e\xd7" + "\x54\xe7\x75\x50\x4f\xfb\x4d\xfd\xac\x2f\x4b\x77" + "\xcf\x9e\x8e\xcc\x16\xa2\x24\xcd\x53\xde\x3e\xc5" + "\x55\x5d\xd5\x26\x3f\x89\xdf\xca\x8b\x4e\x1e\xb6" + "\x88\x78\x63\x5c\xa2\x63\x98\x4e\x6f\x25\x59\xb1" + "\x5f\x2b\x23\xb0\x4b\xa5\x18\x5d\xc2\x15\x74\x40" + "\x59\x4c\xb4\x1e\xcf\x9a\x36\xfd\x43\xe2\x03\xb8" + "\x59\x91\x30\x89\x2a\xc8\x5a\x43\x23\x7c\x73\x72" + "\xda\x3f\xad\x2b\xba\x00\x6b\xd1", + .expectedlen = 128, + .addtla = (unsigned char *) + "\x18\xe8\x17\xff\xef\x39\xc7\x41\x5c\x73\x03\x03" + "\xf6\x3d\xe8\x5f\xc8\xab\xe4\xab\x0f\xad\xe8\xd6" + "\x86\x88\x55\x28\xc1\x69\xdd\x76", + .addtlb = (unsigned char *) + "\xac\x07\xfc\xbe\x87\x0e\xd3\xea\x1f\x7e\xb8\xe7" + "\x9d\xec\xe8\xe7\xbc\xf3\x18\x25\x77\x35\x4a\xaa" + "\x00\x99\x2a\xdd\x0a\x00\x50\x82", + .addtllen = 32, + .pers = (unsigned char *) + "\xbc\x55\xab\x3c\xf6\x52\xb0\x11\x3d\x7b\x90\xb8" + "\x24\xc9\x26\x4e\x5a\x1e\x77\x0d\x3d\x58\x4a\xda" + "\xd1\x81\xe9\xf8\xeb\x30\x8f\x6f", + .perslen = 32, }, }; -/* - * AEGIS-256 test vectors - generated via reference implementation from - * SUPERCOP (https://bench.cr.yp.to/supercop.html): - * - * https://bench.cr.yp.to/supercop/supercop-20170228.tar.xz - * (see crypto_aead/aegis256/) - */ -static const struct aead_testvec aegis256_tv_template[] = { +static const struct drbg_testvec drbg_pr_ctr_aes128_tv_template[] = { { - .key = "\x0f\xc9\x8e\x67\x44\x9e\xaa\x86" - "\x20\x36\x2c\x24\xfe\xc9\x30\x81" - "\xca\xb0\x82\x21\x41\xa8\xe0\x06" - "\x30\x0b\x37\xf6\xb6\x17\xe7\xb5", - .klen = 32, - .iv = "\x1e\x92\x1c\xcf\x88\x3d\x54\x0d" - "\x40\x6d\x59\x48\xfc\x92\x61\x03" - "\x95\x61\x05\x42\x82\x50\xc0\x0c" - "\x60\x16\x6f\xec\x6d\x2f\xcf\x6b", - .assoc = "", - .alen = 0, - .ptext = "", - .plen = 0, - .ctext = "\xd5\x65\x3a\xa9\x03\x51\xd7\xaa" - "\xfa\x4b\xd8\xa2\x41\x9b\xc1\xb2", - .clen = 16, - }, { - .key = "\x4b\xed\xc8\x07\x54\x1a\x52\xa2" - "\xa1\x10\xde\xb5\xf8\xed\xf3\x87" - "\xf4\x72\x8e\xa5\x46\x48\x62\x20" - "\xf1\x38\x16\xce\x90\x76\x87\x8c", - .klen = 32, - .iv = "\x5a\xb7\x56\x6e\x98\xb9\xfd\x29" - "\xc1\x47\x0b\xda\xf6\xb6\x23\x09" - "\xbf\x23\x11\xc6\x87\xf0\x42\x26" - "\x22\x44\x4e\xc4\x47\x8e\x6e\x41", - .assoc = "", - .alen = 0, - .ptext = "\x79", - .plen = 1, - .ctext = "\x84\xa2\x8f\xad\xdb\x8d\x2c\x16" - "\x9e\x89\xd9\x06\xa6\xa8\x14\x29" - "\x8b", - .clen = 17, + .entropy = (unsigned char *) + "\xd1\x44\xc6\x61\x81\x6d\xca\x9d\x15\x28\x8a\x42" + "\x94\xd7\x28\x9c\x43\x77\x19\x29\x1a\x6d\xc3\xa2", + .entropylen = 24, + .entpra = (unsigned char *) + "\x96\xd8\x9e\x45\x32\xc9\xd2\x08\x7a\x6d\x97\x15" + "\xb4\xec\x80\xb1", + .entprb = (unsigned char *) + "\x8b\xb6\x72\xb5\x24\x0b\x98\x65\x95\x95\xe9\xc9" + "\x28\x07\xeb\xc2", + .entprlen = 16, + .expected = (unsigned char *) + "\x70\x19\xd0\x4c\x45\x78\xd6\x68\xa9\x9a\xaa\xfe" + "\xc1\xdf\x27\x9a\x1c\x0d\x0d\xf7\x24\x75\x46\xcc" + "\x77\x6b\xdf\x89\xc6\x94\xdc\x74\x50\x10\x70\x18" + "\x9b\xdc\x96\xb4\x89\x23\x40\x1a\xce\x09\x87\xce" + "\xd2\xf3\xd5\xe4\x51\x67\x74\x11\x5a\xcc\x8b\x3b" + "\x8a\xf1\x23\xa8", + .expectedlen = 64, + .addtla = NULL, + .addtlb = NULL, + .addtllen = 0, + .pers = NULL, + .perslen = 0, }, { - .key = "\x88\x12\x01\xa6\x64\x96\xfb\xbe" - "\x22\xea\x90\x47\xf2\x11\xb5\x8e" - "\x1f\x35\x9a\x29\x4b\xe8\xe4\x39" - "\xb3\x66\xf5\xa6\x6a\xd5\x26\x62", - .klen = 32, - .iv = "\x97\xdb\x90\x0e\xa8\x35\xa5\x45" - "\x42\x21\xbd\x6b\xf0\xda\xe6\x0f" - "\xe9\xe5\x1d\x4a\x8c\x90\xc4\x40" - "\xe3\x71\x2d\x9c\x21\xed\x0e\x18", - .assoc = "", - .alen = 0, - .ptext = "\xb5\x6e\xad\xdd\x30\x72\xfa\x53" - "\x82\x8e\x16\xb4\xed\x6d\x47", - .plen = 15, - .ctext = "\x09\x94\x1f\xa6\x13\xc3\x74\x75" - "\x17\xad\x8a\x0e\xd8\x66\x9a\x28" - "\xd7\x30\x66\x09\x2a\xdc\xfa\x2a" - "\x9f\x3b\xd7\xdd\x66\xd1\x2b", - .clen = 31, + .entropy = (unsigned char *) + "\x8e\x83\xe0\xeb\x37\xea\x3e\x53\x5e\x17\x6e\x77" + "\xbd\xb1\x53\x90\xfc\xdc\xc1\x3c\x9a\x88\x22\x94", + .entropylen = 24, + .entpra = (unsigned char *) + "\x6a\x85\xe7\x37\xc8\xf1\x04\x31\x98\x4f\xc8\x73" + "\x67\xd1\x08\xf8", + .entprb = (unsigned char *) + "\xd7\xa4\x68\xe2\x12\x74\xc3\xd9\xf1\xb7\x05\xbc" + "\xd4\xba\x04\x58", + .entprlen = 16, + .expected = (unsigned char *) + "\x78\xd6\xa6\x70\xff\xd1\x82\xf5\xa2\x88\x7f\x6d" + "\x3d\x8c\x39\xb1\xa8\xcb\x2c\x91\xab\x14\x7e\xbc" + "\x95\x45\x9f\x24\xb8\x20\xac\x21\x23\xdb\x72\xd7" + "\x12\x8d\x48\x95\xf3\x19\x0c\x43\xc6\x19\x45\xfc" + "\x8b\xac\x40\x29\x73\x00\x03\x45\x5e\x12\xff\x0c" + "\xc1\x02\x41\x82", + .expectedlen = 64, + .addtla = (unsigned char *) + "\xa2\xd9\x38\xcf\x8b\x29\x67\x5b\x65\x62\x6f\xe8" + "\xeb\xb3\x01\x76", + .addtlb = (unsigned char *) + "\x59\x63\x1e\x81\x8a\x14\xa8\xbb\xa1\xb8\x41\x25" + "\xd0\x7f\xcc\x43", + .addtllen = 16, + .pers = NULL, + .perslen = 0, }, { - .key = "\xc4\x37\x3b\x45\x74\x11\xa4\xda" - "\xa2\xc5\x42\xd8\xec\x36\x78\x94" - "\x49\xf7\xa5\xad\x50\x88\x66\x53" - "\x74\x94\xd4\x7f\x44\x34\xc5\x39", - .klen = 32, - .iv = "\xd3\x00\xc9\xad\xb8\xb0\x4e\x61" - "\xc3\xfb\x6f\xfd\xea\xff\xa9\x15" - "\x14\xa8\x28\xce\x92\x30\x46\x59" - "\xa4\x9f\x0b\x75\xfb\x4c\xad\xee", - .assoc = "", - .alen = 0, - .ptext = "\xf2\x92\xe6\x7d\x40\xee\xa3\x6f" - "\x03\x68\xc8\x45\xe7\x91\x0a\x18", - .plen = 16, - .ctext = "\x8a\x46\xa2\x22\x8c\x03\xab\x6f" - "\x54\x63\x4e\x7f\xc9\x8e\xfa\x70" - "\x7b\xe5\x8d\x78\xbc\xe9\xb6\xa1" - "\x29\x17\xc8\x3b\x52\xa4\x98\x72", - .clen = 32, + .entropy = (unsigned char *) + "\x04\xd9\x49\xa6\xdc\xe8\x6e\xbb\xf1\x08\x77\x2b" + "\x9e\x08\xca\x92\x65\x16\xda\x99\xa2\x59\xf3\xe8", + .entropylen = 24, + .entpra = (unsigned char *) + "\x38\x7e\x3f\x6b\x51\x70\x7b\x20\xec\x53\xd0\x66" + "\xc3\x0f\xe3\xb0", + .entprb = (unsigned char *) + "\xe0\x86\xa6\xaa\x5f\x72\x2f\xad\xf7\xef\x06\xb8" + "\xd6\x9c\x9d\xe8", + .entprlen = 16, + .expected = (unsigned char *) + "\xc9\x0a\xaf\x85\x89\x71\x44\x66\x4f\x25\x0b\x2b" + "\xde\xd8\xfa\xff\x52\x5a\x1b\x32\x5e\x41\x7a\x10" + "\x1f\xef\x1e\x62\x23\xe9\x20\x30\xc9\x0d\xad\x69" + "\xb4\x9c\x5b\xf4\x87\x42\xd5\xae\x5e\x5e\x43\xcc" + "\xd9\xfd\x0b\x93\x4a\xe3\xd4\x06\x37\x36\x0f\x3f" + "\x72\x82\x0c\xcf", + .expectedlen = 64, + .addtla = NULL, + .addtlb = NULL, + .addtllen = 0, + .pers = (unsigned char *) + "\xbf\xa4\x9a\x8f\x7b\xd8\xb1\x7a\x9d\xfa\x45\xed" + "\x21\x52\xb3\xad", + .perslen = 16, }, { - .key = "\x01\x5c\x75\xe5\x84\x8d\x4d\xf6" - "\x23\x9f\xf4\x6a\xe6\x5a\x3b\x9a" - "\x74\xb9\xb1\x32\x55\x28\xe8\x6d" - "\x35\xc1\xb3\x57\x1f\x93\x64\x0f", - .klen = 32, - .iv = "\x10\x25\x03\x4c\xc8\x2c\xf7\x7d" - "\x44\xd5\x21\x8e\xe4\x23\x6b\x1c" - "\x3e\x6a\x34\x53\x97\xd0\xc8\x73" - "\x66\xcd\xea\x4d\xd5\xab\x4c\xc5", - .assoc = "", - .alen = 0, - .ptext = "\x2e\xb7\x20\x1c\x50\x6a\x4b\x8b" - "\x84\x42\x7a\xd7\xe1\xb5\xcd\x1f" - "\xd3", - .plen = 17, - .ctext = "\x71\x6b\x37\x0b\x02\x61\x28\x12" - "\x83\xab\x66\x90\x84\xc7\xd1\xc5" - "\xb2\x7a\xb4\x7b\xb4\xfe\x02\xb2" - "\xc0\x00\x39\x13\xb5\x51\x68\x44" - "\xad", - .clen = 33, + .entropy = (unsigned char *) + "\x92\x89\x8f\x31\xfa\x1c\xff\x6d\x18\x2f\x26\x06" + "\x43\xdf\xf8\x18\xc2\xa4\xd9\x72\xc3\xb9\xb6\x97", + .entropylen = 24, + .entpra = (unsigned char *) + "\x20\x72\x8a\x06\xf8\x6f\x8d\xd4\x41\xe2\x72\xb7" + "\xc4\x2c\xe8\x10", + .entprb = (unsigned char *) + "\x3d\xb0\xf0\x94\xf3\x05\x50\x33\x17\x86\x3e\x22" + "\x08\xf7\xa5\x01", + .entprlen = 16, + .expected = (unsigned char *) + "\x5a\x35\x39\x87\x0f\x4d\x22\xa4\x09\x24\xee\x71" + "\xc9\x6f\xac\x72\x0a\xd6\xf0\x88\x82\xd0\x83\x28" + "\x73\xec\x3f\x93\xd8\xab\x45\x23\xf0\x7e\xac\x45" + "\x14\x5e\x93\x9f\xb1\xd6\x76\x43\x3d\xb6\xe8\x08" + "\x88\xf6\xda\x89\x08\x77\x42\xfe\x1a\xf4\x3f\xc4" + "\x23\xc5\x1f\x68", + .expectedlen = 64, + .addtla = (unsigned char *) + "\x1a\x40\xfa\xe3\xcc\x6c\x7c\xa0\xf8\xda\xba\x59" + "\x23\x6d\xad\x1d", + .addtlb = (unsigned char *) + "\x9f\x72\x76\x6c\xc7\x46\xe5\xed\x2e\x53\x20\x12" + "\xbc\x59\x31\x8c", + .addtllen = 16, + .pers = (unsigned char *) + "\xea\x65\xee\x60\x26\x4e\x7e\xb6\x0e\x82\x68\xc4" + "\x37\x3c\x5c\x0b", + .perslen = 16, + }, +}; + +/* + * SP800-90A DRBG Test vectors from + * http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip + * + * Test vectors for DRBG without prediction resistance. All types of DRBGs + * (Hash, HMAC, CTR) are tested with all permutations of use cases (w/ and + * w/o personalization string, w/ and w/o additional input string). + */ +static const struct drbg_testvec drbg_nopr_sha256_tv_template[] = { + { + .entropy = (unsigned char *) + "\xa6\x5a\xd0\xf3\x45\xdb\x4e\x0e\xff\xe8\x75\xc3" + "\xa2\xe7\x1f\x42\xc7\x12\x9d\x62\x0f\xf5\xc1\x19" + "\xa9\xef\x55\xf0\x51\x85\xe0\xfb\x85\x81\xf9\x31" + "\x75\x17\x27\x6e\x06\xe9\x60\x7d\xdb\xcb\xcc\x2e", + .entropylen = 48, + .expected = (unsigned char *) + "\xd3\xe1\x60\xc3\x5b\x99\xf3\x40\xb2\x62\x82\x64" + "\xd1\x75\x10\x60\xe0\x04\x5d\xa3\x83\xff\x57\xa5" + "\x7d\x73\xa6\x73\xd2\xb8\xd8\x0d\xaa\xf6\xa6\xc3" + "\x5a\x91\xbb\x45\x79\xd7\x3f\xd0\xc8\xfe\xd1\x11" + "\xb0\x39\x13\x06\x82\x8a\xdf\xed\x52\x8f\x01\x81" + "\x21\xb3\xfe\xbd\xc3\x43\xe7\x97\xb8\x7d\xbb\x63" + "\xdb\x13\x33\xde\xd9\xd1\xec\xe1\x77\xcf\xa6\xb7" + "\x1f\xe8\xab\x1d\xa4\x66\x24\xed\x64\x15\xe5\x1c" + "\xcd\xe2\xc7\xca\x86\xe2\x83\x99\x0e\xea\xeb\x91" + "\x12\x04\x15\x52\x8b\x22\x95\x91\x02\x81\xb0\x2d" + "\xd4\x31\xf4\xc9\xf7\x04\x27\xdf", + .expectedlen = 128, + .addtla = NULL, + .addtlb = NULL, + .addtllen = 0, + .pers = NULL, + .perslen = 0, }, { - .key = "\x3d\x80\xae\x84\x94\x09\xf6\x12" - "\xa4\x79\xa6\xfb\xe0\x7f\xfd\xa0" - "\x9e\x7c\xbc\xb6\x5b\xc8\x6a\x86" - "\xf7\xef\x91\x30\xf9\xf2\x04\xe6", - .klen = 32, - .iv = "\x4c\x49\x3d\xec\xd8\xa8\xa0\x98" - "\xc5\xb0\xd3\x1f\xde\x48\x2e\x22" - "\x69\x2c\x3f\xd7\x9c\x70\x4a\x8d" - "\x27\xfa\xc9\x26\xaf\x0a\xeb\x9c", - .assoc = "", - .alen = 0, - .ptext = "\x6b\xdc\x5a\xbb\x60\xe5\xf4\xa6" - "\x05\x1d\x2c\x68\xdb\xda\x8f\x25" - "\xfe\x8d\x45\x19\x1e\xc0\x0b\x99" - "\x88\x11\x39\x12\x1c\x3a\xbb", - .plen = 31, - .ctext = "\xaf\xa4\x34\x0d\x59\xe6\x1c\x2f" - "\x06\x3b\x52\x18\x49\x75\x1b\xf0" - "\x53\x09\x72\x7b\x45\x79\xe0\xbe" - "\x89\x85\x23\x15\xb8\x79\x07\x4c" - "\x53\x7a\x15\x37\x0a\xee\xb7\xfb" - "\xc4\x1f\x12\x27\xcf\x77\x90", - .clen = 47, + .entropy = (unsigned char *) + "\x73\xd3\xfb\xa3\x94\x5f\x2b\x5f\xb9\x8f\xf6\x9c" + "\x8a\x93\x17\xae\x19\xc3\x4c\xc3\xd6\xca\xa3\x2d" + "\x16\xfc\x42\xd2\x2d\xd5\x6f\x56\xcc\x1d\x30\xff" + "\x9e\x06\x3e\x09\xce\x58\xe6\x9a\x35\xb3\xa6\x56", + .entropylen = 48, + .expected = (unsigned char *) + "\x71\x7b\x93\x46\x1a\x40\xaa\x35\xa4\xaa\xc5\xe7" + "\x6d\x5b\x5b\x8a\xa0\xdf\x39\x7d\xae\x71\x58\x5b" + "\x3c\x7c\xb4\xf0\x89\xfa\x4a\x8c\xa9\x5c\x54\xc0" + "\x40\xdf\xbc\xce\x26\x81\x34\xf8\xba\x7d\x1c\xe8" + "\xad\x21\xe0\x74\xcf\x48\x84\x30\x1f\xa1\xd5\x4f" + "\x81\x42\x2f\xf4\xdb\x0b\x23\xf8\x73\x27\xb8\x1d" + "\x42\xf8\x44\x58\xd8\x5b\x29\x27\x0a\xf8\x69\x59" + "\xb5\x78\x44\xeb\x9e\xe0\x68\x6f\x42\x9a\xb0\x5b" + "\xe0\x4e\xcb\x6a\xaa\xe2\xd2\xd5\x33\x25\x3e\xe0" + "\x6c\xc7\x6a\x07\xa5\x03\x83\x9f\xe2\x8b\xd1\x1c" + "\x70\xa8\x07\x59\x97\xeb\xf6\xbe", + .expectedlen = 128, + .addtla = (unsigned char *) + "\xf4\xd5\x98\x3d\xa8\xfc\xfa\x37\xb7\x54\x67\x73" + "\xc7\xc3\xdd\x47\x34\x71\x02\x5d\xc1\xa0\xd3\x10" + "\xc1\x8b\xbd\xf5\x66\x34\x6f\xdd", + .addtlb = (unsigned char *) + "\xf7\x9e\x6a\x56\x0e\x73\xe9\xd9\x7a\xd1\x69\xe0" + "\x6f\x8c\x55\x1c\x44\xd1\xce\x6f\x28\xcc\xa4\x4d" + "\xa8\xc0\x85\xd1\x5a\x0c\x59\x40", + .addtllen = 32, + .pers = NULL, + .perslen = 0, }, { - .key = "\x7a\xa5\xe8\x23\xa4\x84\x9e\x2d" - "\x25\x53\x58\x8c\xda\xa3\xc0\xa6" - "\xc8\x3e\xc8\x3a\x60\x68\xec\xa0" - "\xb8\x1c\x70\x08\xd3\x51\xa3\xbd", - .klen = 32, - .iv = "\x89\x6e\x77\x8b\xe8\x23\x49\xb4" - "\x45\x8a\x85\xb1\xd8\x6c\xf1\x28" - "\x93\xef\x4b\x5b\xa1\x10\xcc\xa6" - "\xe8\x28\xa8\xfe\x89\x69\x8b\x72", - .assoc = "", - .alen = 0, - .ptext = "\xa7\x00\x93\x5b\x70\x61\x9d\xc2" - "\x86\xf7\xde\xfa\xd5\xfe\x52\x2b" - "\x28\x50\x51\x9d\x24\x60\x8d\xb3" - "\x49\x3e\x17\xea\xf6\x99\x5a\xdd", - .plen = 32, - .ctext = "\xe2\xc9\x0b\x33\x31\x02\xb3\xb4" - "\x33\xfe\xeb\xa8\xb7\x9b\xb2\xd7" - "\xeb\x0f\x05\x2b\xba\xb3\xca\xef" - "\xf6\xd1\xb6\xc0\xb9\x9b\x85\xc5" - "\xbf\x7a\x3e\xcc\x31\x76\x09\x80" - "\x32\x5d\xbb\xe8\x38\x0e\x77\xd3", - .clen = 48, + .entropy = (unsigned char *) + "\x2a\x85\xa9\x8b\xd0\xda\x83\xd6\xad\xab\x9f\xbb" + "\x54\x31\x15\x95\x1c\x4d\x49\x9f\x6a\x15\xf6\xe4" + "\x15\x50\x88\x06\x29\x0d\xed\x8d\xb9\x6f\x96\xe1" + "\x83\x9f\xf7\x88\xda\x84\xbf\x44\x28\xd9\x1d\xaa", + .entropylen = 48, + .expected = (unsigned char *) + "\x2d\x55\xde\xc9\xed\x05\x47\x07\x3d\x04\xfc\x28" + "\x0f\x92\xf0\x4d\xd8\x00\x32\x47\x0a\x1b\x1c\x4b" + "\xef\xd9\x97\xa1\x17\x67\xda\x26\x6c\xfe\x76\x46" + "\x6f\xbc\x6d\x82\x4e\x83\x8a\x98\x66\x6c\x01\xb6" + "\xe6\x64\xe0\x08\x10\x6f\xd3\x5d\x90\xe7\x0d\x72" + "\xa6\xa7\xe3\xbb\x98\x11\x12\x56\x23\xc2\x6d\xd1" + "\xc8\xa8\x7a\x39\xf3\x34\xe3\xb8\xf8\x66\x00\x77" + "\x7d\xcf\x3c\x3e\xfa\xc9\x0f\xaf\xe0\x24\xfa\xe9" + "\x84\xf9\x6a\x01\xf6\x35\xdb\x5c\xab\x2a\xef\x4e" + "\xac\xab\x55\xb8\x9b\xef\x98\x68\xaf\x51\xd8\x16" + "\xa5\x5e\xae\xf9\x1e\xd2\xdb\xe6", + .expectedlen = 128, + .addtla = NULL, + .addtlb = NULL, + .addtllen = 0, + .pers = (unsigned char *) + "\xa8\x80\xec\x98\x30\x98\x15\xd2\xc6\xc4\x68\xf1" + "\x3a\x1c\xbf\xce\x6a\x40\x14\xeb\x36\x99\x53\xda" + "\x57\x6b\xce\xa4\x1c\x66\x3d\xbc", + .perslen = 32, }, { - .key = "\xb6\xca\x22\xc3\xb4\x00\x47\x49" - "\xa6\x2d\x0a\x1e\xd4\xc7\x83\xad" - "\xf3\x00\xd4\xbf\x65\x08\x6e\xb9" - "\x7a\x4a\x4f\xe0\xad\xb0\x42\x93", - .klen = 32, - .iv = "\xc5\x93\xb0\x2a\xf8\x9f\xf1\xd0" - "\xc6\x64\x37\x42\xd2\x90\xb3\x2e" - "\xbd\xb1\x57\xe0\xa6\xb0\x4e\xc0" - "\xaa\x55\x87\xd6\x63\xc8\x2a\x49", - .assoc = "\xd5", - .alen = 1, - .ptext = "", - .plen = 0, - .ctext = "\x96\x43\x30\xca\x6c\x4f\xd7\x12" - "\xba\xd9\xb3\x18\x86\xdf\xc3\x52", - .clen = 16, - }, { - .key = "\xf3\xee\x5c\x62\xc4\x7c\xf0\x65" - "\x27\x08\xbd\xaf\xce\xec\x45\xb3" - "\x1d\xc3\xdf\x43\x6a\xa8\xf0\xd3" - "\x3b\x77\x2e\xb9\x87\x0f\xe1\x6a", - .klen = 32, - .iv = "\x02\xb8\xea\xca\x09\x1b\x9a\xec" - "\x47\x3e\xe9\xd4\xcc\xb5\x76\x34" - "\xe8\x73\x62\x64\xab\x50\xd0\xda" - "\x6b\x83\x66\xaf\x3e\x27\xc9\x1f", - .assoc = "\x11\x81\x78\x32\x4d\xb9\x44\x73" - "\x68\x75\x16\xf8\xcb\x7e\xa7", - .alen = 15, - .ptext = "", - .plen = 0, - .ctext = "\x2f\xab\x45\xe2\xa7\x46\xc5\x83" - "\x11\x9f\xb0\x74\xee\xc7\x03\xdd", - .clen = 16, - }, { - .key = "\x2f\x13\x95\x01\xd5\xf7\x99\x81" - "\xa8\xe2\x6f\x41\xc8\x10\x08\xb9" - "\x47\x85\xeb\xc7\x6f\x48\x72\xed" - "\xfc\xa5\x0d\x91\x61\x6e\x81\x40", - .klen = 32, - .iv = "\x3f\xdc\x24\x69\x19\x96\x43\x08" - "\xc8\x18\x9b\x65\xc6\xd9\x39\x3b" - "\x12\x35\x6e\xe8\xb0\xf0\x52\xf3" - "\x2d\xb0\x45\x87\x18\x86\x68\xf6", - .assoc = "\x4e\xa5\xb2\xd1\x5d\x35\xed\x8f" - "\xe8\x4f\xc8\x89\xc5\xa2\x69\xbc", - .alen = 16, - .ptext = "", - .plen = 0, - .ctext = "\x16\x44\x73\x33\x5d\xf2\xb9\x04" - "\x6b\x79\x98\xef\xdb\xd5\xc5\xf1", - .clen = 16, - }, { - .key = "\x6c\x38\xcf\xa1\xe5\x73\x41\x9d" - "\x29\xbc\x21\xd2\xc2\x35\xcb\xbf" - "\x72\x47\xf6\x4b\x74\xe8\xf4\x06" - "\xbe\xd3\xec\x6a\x3b\xcd\x20\x17", - .klen = 32, - .iv = "\x7b\x01\x5d\x08\x29\x12\xec\x24" - "\x49\xf3\x4d\xf7\xc0\xfe\xfb\x41" - "\x3c\xf8\x79\x6c\xb6\x90\xd4\x0d" - "\xee\xde\x23\x60\xf2\xe5\x08\xcc", - .assoc = "\x8a\xca\xec\x70\x6d\xb1\x96\xab" - "\x69\x29\x7a\x1b\xbf\xc7\x2c\xc2" - "\x07", - .alen = 17, - .ptext = "", - .plen = 0, - .ctext = "\xa4\x9b\xb8\x47\xc0\xed\x7a\x45" - "\x98\x54\x8c\xed\x3d\x17\xf0\xdd", - .clen = 16, - }, { - .key = "\xa8\x5c\x09\x40\xf5\xef\xea\xb8" - "\xaa\x96\xd3\x64\xbc\x59\x8d\xc6" - "\x9c\x0a\x02\xd0\x79\x88\x76\x20" - "\x7f\x00\xca\x42\x15\x2c\xbf\xed", - .klen = 32, - .iv = "\xb8\x26\x97\xa8\x39\x8e\x94\x3f" - "\xca\xcd\xff\x88\xba\x22\xbe\x47" - "\x67\xba\x85\xf1\xbb\x30\x56\x26" - "\xaf\x0b\x02\x38\xcc\x44\xa7\xa3", - .assoc = "\xc7\xef\x26\x10\x7d\x2c\x3f\xc6" - "\xea\x03\x2c\xac\xb9\xeb\xef\xc9" - "\x31\x6b\x08\x12\xfc\xd8\x37\x2d" - "\xe0\x17\x3a\x2e\x83\x5c\x8f", - .alen = 31, - .ptext = "", - .plen = 0, - .ctext = "\x20\x24\xe2\x33\x5c\x60\xc9\xf0" - "\xa4\x96\x2f\x0d\x53\xc2\xf8\xfc", - .clen = 16, - }, { - .key = "\xe5\x81\x42\xdf\x05\x6a\x93\xd4" - "\x2b\x70\x85\xf5\xb6\x7d\x50\xcc" - "\xc6\xcc\x0e\x54\x7f\x28\xf8\x3a" - "\x40\x2e\xa9\x1a\xf0\x8b\x5e\xc4", - .klen = 32, - .iv = "\xf4\x4a\xd1\x47\x49\x09\x3d\x5b" - "\x4b\xa7\xb1\x19\xb4\x46\x81\x4d" - "\x91\x7c\x91\x75\xc0\xd0\xd8\x40" - "\x71\x39\xe1\x10\xa6\xa3\x46\x7a", - .assoc = "\x03\x14\x5f\xaf\x8d\xa8\xe7\xe2" - "\x6b\xde\xde\x3e\xb3\x10\xb1\xcf" - "\x5c\x2d\x14\x96\x01\x78\xb9\x47" - "\xa1\x44\x19\x06\x5d\xbb\x2e\x2f", - .alen = 32, - .ptext = "", - .plen = 0, - .ctext = "\x6f\x4a\xb9\xe0\xff\x51\xa3\xf1" - "\xd2\x64\x3e\x66\x6a\xb2\x03\xc0", - .clen = 16, - }, { - .key = "\x22\xa6\x7c\x7f\x15\xe6\x3c\xf0" - "\xac\x4b\x37\x86\xb0\xa2\x13\xd2" - "\xf1\x8e\x19\xd8\x84\xc8\x7a\x53" - "\x02\x5b\x88\xf3\xca\xea\xfe\x9b", - .klen = 32, - .iv = "\x31\x6f\x0b\xe6\x59\x85\xe6\x77" - "\xcc\x81\x63\xab\xae\x6b\x43\x54" - "\xbb\x3f\x9c\xf9\xc5\x70\x5a\x5a" - "\x32\x67\xc0\xe9\x80\x02\xe5\x50", - .assoc = "\x40", - .alen = 1, - .ptext = "\x4f", - .plen = 1, - .ctext = "\x2c\xfb\xad\x7e\xbe\xa0\x9a\x5b" - "\x7a\x3f\x81\xf7\xfc\x1b\x79\x83" - "\xc7", - .clen = 17, - }, { - .key = "\x5e\xcb\xb6\x1e\x25\x62\xe4\x0c" - "\x2d\x25\xe9\x18\xaa\xc6\xd5\xd8" - "\x1b\x50\x25\x5d\x89\x68\xfc\x6d" - "\xc3\x89\x67\xcb\xa4\x49\x9d\x71", - .klen = 32, - .iv = "\x6d\x94\x44\x86\x69\x00\x8f\x93" - "\x4d\x5b\x15\x3c\xa8\x8f\x06\x5a" - "\xe6\x01\xa8\x7e\xca\x10\xdc\x73" - "\xf4\x94\x9f\xc1\x5a\x61\x85\x27", - .assoc = "\x7c\x5d\xd3\xee\xad\x9f\x39\x1a" - "\x6d\x92\x42\x61\xa7\x58\x37", - .alen = 15, - .ptext = "\x8b\x26\x61\x55\xf1\x3e\xe3\xa1" - "\x8d\xc8\x6e\x85\xa5\x21\x67", - .plen = 15, - .ctext = "\x1f\x7f\xca\x3c\x2b\xe7\x27\xba" - "\x7e\x98\x83\x02\x34\x23\xf7\x94" - "\xde\x35\xe6\x1d\x14\x18\xe5\x38" - "\x14\x80\x6a\xa7\x1b\xae\x1d", - .clen = 31, - }, { - .key = "\x9b\xef\xf0\xbd\x35\xdd\x8d\x28" - "\xad\xff\x9b\xa9\xa4\xeb\x98\xdf" - "\x46\x13\x31\xe1\x8e\x08\x7e\x87" - "\x85\xb6\x46\xa3\x7e\xa8\x3c\x48", - .klen = 32, - .iv = "\xaa\xb8\x7e\x25\x79\x7c\x37\xaf" - "\xce\x36\xc7\xce\xa2\xb4\xc9\x60" - "\x10\xc3\xb3\x02\xcf\xb0\x5e\x8d" - "\xb5\xc2\x7e\x9a\x35\xc0\x24\xfd", - .assoc = "\xb9\x82\x0c\x8d\xbd\x1b\xe2\x36" - "\xee\x6c\xf4\xf2\xa1\x7d\xf9\xe2", - .alen = 16, - .ptext = "\xc8\x4b\x9b\xf5\x01\xba\x8c\xbd" - "\x0e\xa3\x21\x16\x9f\x46\x2a\x63", - .plen = 16, - .ctext = "\x05\x86\x9e\xd7\x2b\xa3\x97\x01" - "\xbe\x28\x98\x10\x6f\xe9\x61\x32" - "\x96\xbb\xb1\x2e\x8f\x0c\x44\xb9" - "\x46\x2d\x55\xe3\x42\x67\xf2\xaf", - .clen = 32, - }, { - .key = "\xd7\x14\x29\x5d\x45\x59\x36\x44" - "\x2e\xd9\x4d\x3b\x9e\x0f\x5b\xe5" - "\x70\xd5\x3c\x65\x93\xa8\x00\xa0" - "\x46\xe4\x25\x7c\x58\x08\xdb\x1e", - .klen = 32, - .iv = "\xe6\xdd\xb8\xc4\x89\xf8\xe0\xca" - "\x4f\x10\x7a\x5f\x9c\xd8\x8b\x66" - "\x3b\x86\xbf\x86\xd4\x50\xe0\xa7" - "\x76\xef\x5c\x72\x0f\x1f\xc3\xd4", - .assoc = "\xf5\xa6\x46\x2c\xce\x97\x8a\x51" - "\x6f\x46\xa6\x83\x9b\xa1\xbc\xe8" - "\x05", - .alen = 17, - .ptext = "\x05\x70\xd5\x94\x12\x36\x35\xd8" - "\x8f\x7d\xd3\xa8\x99\x6a\xed\x69" - "\xd0", - .plen = 17, - .ctext = "\x9c\xe0\x06\x7b\x86\xcf\x2e\xd8" - "\x45\x65\x1b\x72\x9b\xaa\xa3\x1e" - "\x87\x9d\x26\xdf\xff\x81\x11\xd2" - "\x47\x41\xb9\x24\xc1\x8a\xa3\x8b" - "\x55", - .clen = 33, - }, { - .key = "\x14\x39\x63\xfc\x56\xd5\xdf\x5f" - "\xaf\xb3\xff\xcc\x98\x33\x1d\xeb" - "\x9a\x97\x48\xe9\x98\x48\x82\xba" - "\x07\x11\x04\x54\x32\x67\x7b\xf5", - .klen = 32, - .iv = "\x23\x02\xf1\x64\x9a\x73\x89\xe6" - "\xd0\xea\x2c\xf1\x96\xfc\x4e\x6d" - "\x65\x48\xcb\x0a\xda\xf0\x62\xc0" - "\x38\x1d\x3b\x4a\xe9\x7e\x62\xaa", - .assoc = "\x32\xcb\x80\xcc\xde\x12\x33\x6d" - "\xf0\x20\x58\x15\x95\xc6\x7f\xee" - "\x2f\xf9\x4e\x2c\x1b\x98\x43\xc7" - "\x68\x28\x73\x40\x9f\x96\x4a", - .alen = 31, - .ptext = "\x41\x94\x0e\x33\x22\xb1\xdd\xf4" - "\x10\x57\x85\x39\x93\x8f\xaf\x70" - "\xfa\xa9\xd0\x4d\x5c\x40\x23\xcd" - "\x98\x34\xab\x37\x56\xae\x32", - .plen = 31, - .ctext = "\xa0\xc8\xde\x83\x0d\xc3\x4e\xd5" - "\x69\x7f\x7a\xdd\x8c\x46\xda\xba" - "\x0a\x5c\x0e\x7f\xac\xee\x02\xd2" - "\xe5\x4b\x0a\xba\xb8\xa4\x7b\x66" - "\xde\xae\xdb\xc2\xc0\x0b\xf7\x2b" - "\xdf\xb8\xea\xd8\xa9\x38\xed", - .clen = 47, - }, { - .key = "\x50\x5d\x9d\x9b\x66\x50\x88\x7b" - "\x30\x8e\xb1\x5e\x92\x58\xe0\xf1" - "\xc5\x5a\x53\x6e\x9d\xe8\x04\xd4" - "\xc9\x3f\xe2\x2d\x0c\xc6\x1a\xcb", - .klen = 32, - .iv = "\x5f\x27\x2b\x03\xaa\xef\x32\x02" - "\x50\xc4\xde\x82\x90\x21\x11\x73" - "\x8f\x0a\xd6\x8f\xdf\x90\xe4\xda" - "\xf9\x4a\x1a\x23\xc3\xdd\x02\x81", - .assoc = "\x6e\xf0\xba\x6b\xee\x8e\xdc\x89" - "\x71\xfb\x0a\xa6\x8f\xea\x41\xf4" - "\x5a\xbb\x59\xb0\x20\x38\xc5\xe0" - "\x29\x56\x52\x19\x79\xf5\xe9\x37", - .alen = 32, - .ptext = "\x7e\xb9\x48\xd3\x32\x2d\x86\x10" - "\x91\x31\x37\xcb\x8d\xb3\x72\x76" - "\x24\x6b\xdc\xd1\x61\xe0\xa5\xe7" - "\x5a\x61\x8a\x0f\x30\x0d\xd1\xec", - .plen = 32, - .ctext = "\xd3\x68\x14\x70\x3c\x01\x43\x86" - "\x02\xab\xbe\x75\xaa\xe7\xf5\x53" - "\x5c\x05\xbd\x9b\x19\xbb\x2a\x61" - "\x8f\x69\x05\x75\x8e\xca\x60\x0c" - "\x5b\xa2\x48\x61\x32\x74\x11\x2b" - "\xf6\xcf\x06\x78\x6f\x78\x1a\x4a", - .clen = 48, - }, { - .key = "\x8d\x82\xd6\x3b\x76\xcc\x30\x97" - "\xb1\x68\x63\xef\x8c\x7c\xa3\xf7" - "\xef\x1c\x5f\xf2\xa3\x88\x86\xed" - "\x8a\x6d\xc1\x05\xe7\x25\xb9\xa2", - .klen = 32, - .iv = "\x9c\x4b\x65\xa2\xba\x6b\xdb\x1e" - "\xd1\x9e\x90\x13\x8a\x45\xd3\x79" - "\xba\xcd\xe2\x13\xe4\x30\x66\xf4" - "\xba\x78\xf9\xfb\x9d\x3c\xa1\x58", - .assoc = "\xab\x14\xf3\x0a\xfe\x0a\x85\xa5" - "\xf2\xd5\xbc\x38\x89\x0e\x04\xfb" - "\x84\x7d\x65\x34\x25\xd8\x47\xfa" - "\xeb\x83\x31\xf1\x54\x54\x89\x0d" - "\x9d", - .alen = 33, - .ptext = "\xba\xde\x82\x72\x42\xa9\x2f\x2c" - "\x12\x0b\xe9\x5c\x87\xd7\x35\x7c" - "\x4f\x2e\xe8\x55\x66\x80\x27\x00" - "\x1b\x8f\x68\xe7\x0a\x6c\x71\xc3" - "\x21\x78\x55\x9d\x9c\x65\x7b\xcd" - "\x0a\x34\x97\xff\x47\x37\xb0\x2a" - "\x80\x0d\x19\x98\x33\xa9\x7a\xe3" - "\x2e\x4c\xc6\xf3\x8c\x88\x42\x01" - "\xbd", - .plen = 65, - .ctext = "\x07\x0a\x35\xb0\x82\x03\x5a\xd2" - "\x15\x3a\x6c\x72\x83\x9b\xb1\x75" - "\xea\xf2\xfc\xff\xc6\xf1\x13\xa4" - "\x1a\x93\x33\x79\x97\x82\x81\xc0" - "\x96\xc2\x00\xab\x39\xae\xa1\x62" - "\x53\xa3\x86\xc9\x07\x8c\xaf\x22" - "\x47\x31\x29\xca\x4a\x95\xf5\xd5" - "\x20\x63\x5a\x54\x80\x2c\x4a\x63" - "\xfb\x18\x73\x31\x4f\x08\x21\x5d" - "\x20\xe9\xc3\x7e\xea\x25\x77\x3a" - "\x65", - .clen = 81, - }, { - .key = "\xc9\xa7\x10\xda\x86\x48\xd9\xb3" - "\x32\x42\x15\x80\x85\xa1\x65\xfe" - "\x19\xde\x6b\x76\xa8\x28\x08\x07" - "\x4b\x9a\xa0\xdd\xc1\x84\x58\x79", - .klen = 32, - .iv = "\xd8\x70\x9f\x42\xca\xe6\x83\x3a" - "\x52\x79\x42\xa5\x84\x6a\x96\x7f" - "\xe4\x8f\xed\x97\xe9\xd0\xe8\x0d" - "\x7c\xa6\xd8\xd4\x77\x9b\x40\x2e", - .assoc = "\xe8\x39\x2d\xaa\x0e\x85\x2d\xc1" - "\x72\xaf\x6e\xc9\x82\x33\xc7\x01" - "\xaf\x40\x70\xb8\x2a\x78\xc9\x14" - "\xac\xb1\x10\xca\x2e\xb3\x28\xe4" - "\xac\xfa\x58\x7f\xe5\x73\x09\x8c" - "\x1d\x40\x87\x8c\xd9\x75\xc0\x55" - "\xa2\xda\x07\xd1\xc2\xa9\xd1\xbb" - "\x09\x4f\x77\x62\x88\x2d\xf2\x68" - "\x54", - .alen = 65, - .ptext = "\xf7\x02\xbb\x11\x52\x24\xd8\x48" - "\x93\xe6\x9b\xee\x81\xfc\xf7\x82" - "\x79\xf0\xf3\xd9\x6c\x20\xa9\x1a" - "\xdc\xbc\x47\xc0\xe4\xcb\x10\x99" - "\x2f", - .plen = 33, - .ctext = "\x33\xc1\xda\xfa\x15\x21\x07\x8e" - "\x93\x68\xea\x64\x7b\x3d\x4b\x6b" - "\x71\x5e\x5e\x6b\x92\xaa\x65\xc2" - "\x7a\x2a\xc1\xa9\x0a\xa1\x24\x81" - "\x26\x3a\x5a\x09\xe8\xce\x73\x72" - "\xde\x7b\x58\x9e\x85\xb9\xa4\x28" - "\xda", - .clen = 49, - }, { - .key = "\x06\xcc\x4a\x79\x96\xc3\x82\xcf" - "\xb3\x1c\xc7\x12\x7f\xc5\x28\x04" - "\x44\xa1\x76\xfb\xad\xc8\x8a\x21" - "\x0d\xc8\x7f\xb6\x9b\xe3\xf8\x4f", - .klen = 32, - .iv = "\x15\x95\xd8\xe1\xda\x62\x2c\x56" - "\xd3\x53\xf4\x36\x7e\x8e\x59\x85" - "\x0e\x51\xf9\x1c\xee\x70\x6a\x27" - "\x3d\xd3\xb7\xac\x51\xfa\xdf\x05", - .assoc = "\x24\x5e\x67\x49\x1e\x01\xd6\xdd" - "\xf3\x89\x20\x5b\x7c\x57\x89\x07", - .alen = 16, - .ptext = "\x33\x27\xf5\xb1\x62\xa0\x80\x63" - "\x14\xc0\x4d\x7f\x7b\x20\xba\x89", - .plen = 16, - .ctext = "\x3e\xf8\x86\x3d\x39\xf8\x96\x02" - "\x0f\xdf\xc9\x6e\x37\x1e\x57\x99" - "\x07\x2a\x1a\xac\xd1\xda\xfd\x3b" - "\xc7\xff\xbd\xbc\x85\x09\x0b", - .clen = 31, - }, { - .key = "\x42\xf0\x84\x19\xa6\x3f\x2b\xea" - "\x34\xf6\x79\xa3\x79\xe9\xeb\x0a" - "\x6e\x63\x82\x7f\xb2\x68\x0c\x3a" - "\xce\xf5\x5e\x8e\x75\x42\x97\x26", - .klen = 32, - .iv = "\x51\xb9\x12\x80\xea\xde\xd5\x71" - "\x54\x2d\xa6\xc8\x78\xb2\x1b\x8c" - "\x39\x14\x05\xa0\xf3\x10\xec\x41" - "\xff\x01\x95\x84\x2b\x59\x7f\xdb", - .assoc = "\x61\x83\xa0\xe8\x2e\x7d\x7f\xf8" - "\x74\x63\xd2\xec\x76\x7c\x4c\x0d", - .alen = 16, - .ptext = "\x70\x4c\x2f\x50\x72\x1c\x29\x7f" - "\x95\x9a\xff\x10\x75\x45\x7d\x8f", - .plen = 16, - .ctext = "\x2f\xc4\xd8\x0d\xa6\x07\xef\x2e" - "\x6c\xd9\x84\x63\x70\x97\x61\x37" - "\x08\x2f\x16\x90\x9e\x62\x30\x0d" - "\x62\xd5\xc8\xf0\x46\x1a", - .clen = 30, - }, { - .key = "\x7f\x15\xbd\xb8\xb6\xba\xd3\x06" - "\xb5\xd1\x2b\x35\x73\x0e\xad\x10" - "\x98\x25\x8d\x03\xb7\x08\x8e\x54" - "\x90\x23\x3d\x67\x4f\xa1\x36\xfc", - .klen = 32, - .iv = "\x8e\xde\x4c\x20\xfa\x59\x7e\x8d" - "\xd5\x07\x58\x59\x72\xd7\xde\x92" - "\x63\xd6\x10\x24\xf8\xb0\x6e\x5a" - "\xc0\x2e\x74\x5d\x06\xb8\x1e\xb2", - .assoc = "\x9d\xa7\xda\x88\x3e\xf8\x28\x14" - "\xf5\x3e\x85\x7d\x70\xa0\x0f\x13", - .alen = 16, - .ptext = "\xac\x70\x69\xef\x82\x97\xd2\x9b" - "\x15\x74\xb1\xa2\x6f\x69\x3f\x95", - .plen = 16, - .ctext = "\xce\xf3\x17\x87\x49\xc2\x00\x46" - "\xc6\x12\x5c\x8f\x81\x38\xaa\x55" - "\xf8\x67\x75\xf1\x75\xe3\x2a\x24", - .clen = 24, + .entropy = (unsigned char *) + "\x69\xed\x82\xa9\xc5\x7b\xbf\xe5\x1d\x2f\xcb\x7a" + "\xd3\x50\x7d\x96\xb4\xb9\x2b\x50\x77\x51\x27\x74" + "\x33\x74\xba\xf1\x30\xdf\x8e\xdf\x87\x1d\x87\xbc" + "\x96\xb2\xc3\xa7\xed\x60\x5e\x61\x4e\x51\x29\x1a", + .entropylen = 48, + .expected = (unsigned char *) + "\xa5\x71\x24\x31\x11\xfe\x13\xe1\xa8\x24\x12\xfb" + "\x37\xa1\x27\xa5\xab\x77\xa1\x9f\xae\x8f\xaf\x13" + "\x93\xf7\x53\x85\x91\xb6\x1b\xab\xd4\x6b\xea\xb6" + "\xef\xda\x4c\x90\x6e\xef\x5f\xde\xe1\xc7\x10\x36" + "\xd5\x67\xbd\x14\xb6\x89\x21\x0c\xc9\x92\x65\x64" + "\xd0\xf3\x23\xe0\x7f\xd1\xe8\x75\xc2\x85\x06\xea" + "\xca\xc0\xcb\x79\x2d\x29\x82\xfc\xaa\x9a\xc6\x95" + "\x7e\xdc\x88\x65\xba\xec\x0e\x16\x87\xec\xa3\x9e" + "\xd8\x8c\x80\xab\x3a\x64\xe0\xcb\x0e\x45\x98\xdd" + "\x7c\x6c\x6c\x26\x11\x13\xc8\xce\xa9\x47\xa6\x06" + "\x57\xa2\x66\xbb\x2d\x7f\xf3\xc1", + .expectedlen = 128, + .addtla = (unsigned char *) + "\x74\xd3\x6d\xda\xe8\xd6\x86\x5f\x63\x01\xfd\xf2" + "\x7d\x06\x29\x6d\x94\xd1\x66\xf0\xd2\x72\x67\x4e" + "\x77\xc5\x3d\x9e\x03\xe3\xa5\x78", + .addtlb = (unsigned char *) + "\xf6\xb6\x3d\xf0\x7c\x26\x04\xc5\x8b\xcd\x3e\x6a" + "\x9f\x9c\x3a\x2e\xdb\x47\x87\xe5\x8e\x00\x5e\x2b" + "\x74\x7f\xa6\xf6\x80\xcd\x9b\x21", + .addtllen = 32, + .pers = (unsigned char *) + "\x74\xa6\xe0\x08\xf9\x27\xee\x1d\x6e\x3c\x28\x20" + "\x87\xdd\xd7\x54\x31\x47\x78\x4b\xe5\x6d\xa3\x73" + "\xa9\x65\xb1\x10\xc1\xdc\x77\x7c", + .perslen = 32, }, }; -/* - * MORUS-640 test vectors - generated via reference implementation from - * SUPERCOP (https://bench.cr.yp.to/supercop.html): - * - * https://bench.cr.yp.to/supercop/supercop-20170228.tar.xz - * (see crypto_aead/morus640128v2/) - */ -static const struct aead_testvec morus640_tv_template[] = { +static const struct drbg_testvec drbg_nopr_hmac_sha256_tv_template[] = { { - .key = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .klen = 16, - .iv = "\x0f\xc9\x8e\x67\x44\x9e\xaa\x86" - "\x20\x36\x2c\x24\xfe\xc9\x30\x81", - .assoc = "", - .alen = 0, - .ptext = "", - .plen = 0, - .ctext = "\x89\x62\x7d\xf3\x07\x9d\x52\x05" - "\x53\xc3\x04\x60\x93\xb4\x37\x9a", - .clen = 16, + .entropy = (unsigned char *) + "\xca\x85\x19\x11\x34\x93\x84\xbf\xfe\x89\xde\x1c" + "\xbd\xc4\x6e\x68\x31\xe4\x4d\x34\xa4\xfb\x93\x5e" + "\xe2\x85\xdd\x14\xb7\x1a\x74\x88\x65\x9b\xa9\x6c" + "\x60\x1d\xc6\x9f\xc9\x02\x94\x08\x05\xec\x0c\xa8", + .entropylen = 48, + .expected = (unsigned char *) + "\xe5\x28\xe9\xab\xf2\xde\xce\x54\xd4\x7c\x7e\x75" + "\xe5\xfe\x30\x21\x49\xf8\x17\xea\x9f\xb4\xbe\xe6" + "\xf4\x19\x96\x97\xd0\x4d\x5b\x89\xd5\x4f\xbb\x97" + "\x8a\x15\xb5\xc4\x43\xc9\xec\x21\x03\x6d\x24\x60" + "\xb6\xf7\x3e\xba\xd0\xdc\x2a\xba\x6e\x62\x4a\xbf" + "\x07\x74\x5b\xc1\x07\x69\x4b\xb7\x54\x7b\xb0\x99" + "\x5f\x70\xde\x25\xd6\xb2\x9e\x2d\x30\x11\xbb\x19" + "\xd2\x76\x76\xc0\x71\x62\xc8\xb5\xcc\xde\x06\x68" + "\x96\x1d\xf8\x68\x03\x48\x2c\xb3\x7e\xd6\xd5\xc0" + "\xbb\x8d\x50\xcf\x1f\x50\xd4\x76\xaa\x04\x58\xbd" + "\xab\xa8\x06\xf4\x8b\xe9\xdc\xb8", + .expectedlen = 128, + .addtla = NULL, + .addtlb = NULL, + .addtllen = 0, + .pers = NULL, + .perslen = 0, }, { - .key = "\x3c\x24\x39\x9f\x10\x7b\xa8\x1b" - "\x80\xda\xb2\x91\xf9\x24\xc2\x06", - .klen = 16, - .iv = "\x4b\xed\xc8\x07\x54\x1a\x52\xa2" - "\xa1\x10\xde\xb5\xf8\xed\xf3\x87", - .assoc = "", - .alen = 0, - .ptext = "\x69", - .plen = 1, - .ctext = "\xa8\x8d\xe4\x90\xb5\x50\x8f\x78" - "\xb6\x10\x9a\x59\x5f\x61\x37\x70" - "\x09", - .clen = 17, + .entropy = (unsigned char *) + "\xf9\x7a\x3c\xfd\x91\xfa\xa0\x46\xb9\xe6\x1b\x94" + "\x93\xd4\x36\xc4\x93\x1f\x60\x4b\x22\xf1\x08\x15" + "\x21\xb3\x41\x91\x51\xe8\xff\x06\x11\xf3\xa7\xd4" + "\x35\x95\x35\x7d\x58\x12\x0b\xd1\xe2\xdd\x8a\xed", + .entropylen = 48, + .expected = (unsigned char *) + "\xc6\x87\x1c\xff\x08\x24\xfe\x55\xea\x76\x89\xa5" + "\x22\x29\x88\x67\x30\x45\x0e\x5d\x36\x2d\xa5\xbf" + "\x59\x0d\xcf\x9a\xcd\x67\xfe\xd4\xcb\x32\x10\x7d" + "\xf5\xd0\x39\x69\xa6\x6b\x1f\x64\x94\xfd\xf5\xd6" + "\x3d\x5b\x4d\x0d\x34\xea\x73\x99\xa0\x7d\x01\x16" + "\x12\x6d\x0d\x51\x8c\x7c\x55\xba\x46\xe1\x2f\x62" + "\xef\xc8\xfe\x28\xa5\x1c\x9d\x42\x8e\x6d\x37\x1d" + "\x73\x97\xab\x31\x9f\xc7\x3d\xed\x47\x22\xe5\xb4" + "\xf3\x00\x04\x03\x2a\x61\x28\xdf\x5e\x74\x97\xec" + "\xf8\x2c\xa7\xb0\xa5\x0e\x86\x7e\xf6\x72\x8a\x4f" + "\x50\x9a\x8c\x85\x90\x87\x03\x9c", + .expectedlen = 128, + .addtla = (unsigned char *) + "\x51\x72\x89\xaf\xe4\x44\xa0\xfe\x5e\xd1\xa4\x1d" + "\xbb\xb5\xeb\x17\x15\x00\x79\xbd\xd3\x1e\x29\xcf" + "\x2f\xf3\x00\x34\xd8\x26\x8e\x3b", + .addtlb = (unsigned char *) + "\x88\x02\x8d\x29\xef\x80\xb4\xe6\xf0\xfe\x12\xf9" + "\x1d\x74\x49\xfe\x75\x06\x26\x82\xe8\x9c\x57\x14" + "\x40\xc0\xc9\xb5\x2c\x42\xa6\xe0", + .addtllen = 32, + .pers = NULL, + .perslen = 0, }, { - .key = "\x79\x49\x73\x3e\x20\xf7\x51\x37" - "\x01\xb4\x64\x22\xf3\x48\x85\x0c", - .klen = 16, - .iv = "\x88\x12\x01\xa6\x64\x96\xfb\xbe" - "\x22\xea\x90\x47\xf2\x11\xb5\x8e", - .assoc = "", - .alen = 0, - .ptext = "\xa6\xa4\x1e\x76\xec\xd4\x50\xcc" - "\x62\x58\xe9\x8f\xef\xa4\x17", - .plen = 15, - .ctext = "\x76\xdd\xb9\x05\x3d\xce\x61\x38" - "\xf3\xef\xf7\xe5\xd7\xfd\x70\xa5" - "\xcf\x9d\x64\xb8\x0a\x9f\xfd\x8b" - "\xd4\x6e\xfe\xd9\xc8\x63\x4b", - .clen = 31, + .entropy = (unsigned char *) + "\x8d\xf0\x13\xb4\xd1\x03\x52\x30\x73\x91\x7d\xdf" + "\x6a\x86\x97\x93\x05\x9e\x99\x43\xfc\x86\x54\x54" + "\x9e\x7a\xb2\x2f\x7c\x29\xf1\x22\xda\x26\x25\xaf" + "\x2d\xdd\x4a\xbc\xce\x3c\xf4\xfa\x46\x59\xd8\x4e", + .entropylen = 48, + .expected = (unsigned char *) + "\xb9\x1c\xba\x4c\xc8\x4f\xa2\x5d\xf8\x61\x0b\x81" + "\xb6\x41\x40\x27\x68\xa2\x09\x72\x34\x93\x2e\x37" + "\xd5\x90\xb1\x15\x4c\xbd\x23\xf9\x74\x52\xe3\x10" + "\xe2\x91\xc4\x51\x46\x14\x7f\x0d\xa2\xd8\x17\x61" + "\xfe\x90\xfb\xa6\x4f\x94\x41\x9c\x0f\x66\x2b\x28" + "\xc1\xed\x94\xda\x48\x7b\xb7\xe7\x3e\xec\x79\x8f" + "\xbc\xf9\x81\xb7\x91\xd1\xbe\x4f\x17\x7a\x89\x07" + "\xaa\x3c\x40\x16\x43\xa5\xb6\x2b\x87\xb8\x9d\x66" + "\xb3\xa6\x0e\x40\xd4\xa8\xe4\xe9\xd8\x2a\xf6\xd2" + "\x70\x0e\x6f\x53\x5c\xdb\x51\xf7\x5c\x32\x17\x29" + "\x10\x37\x41\x03\x0c\xcc\x3a\x56", + .expectedlen = 128, + .addtla = NULL, + .addtlb = NULL, + .addtllen = 0, + .pers = (unsigned char *) + "\xb5\x71\xe6\x6d\x7c\x33\x8b\xc0\x7b\x76\xad\x37" + "\x57\xbb\x2f\x94\x52\xbf\x7e\x07\x43\x7a\xe8\x58" + "\x1c\xe7\xbc\x7c\x3a\xc6\x51\xa9", + .perslen = 32, }, { - .key = "\xb5\x6e\xad\xdd\x30\x72\xfa\x53" - "\x82\x8e\x16\xb4\xed\x6d\x47\x12", - .klen = 16, - .iv = "\xc4\x37\x3b\x45\x74\x11\xa4\xda" - "\xa2\xc5\x42\xd8\xec\x36\x78\x94", - .assoc = "", - .alen = 0, - .ptext = "\xe2\xc9\x58\x15\xfc\x4f\xf8\xe8" - "\xe3\x32\x9b\x21\xe9\xc8\xd9\x97", - .plen = 16, - .ctext = "\xdc\x72\xe8\x14\xfb\x63\xad\x72" - "\x1f\x57\x9a\x1f\x88\x81\xdb\xd6" - "\xc1\x91\x9d\xb9\x25\xc4\x99\x4c" - "\x97\xcd\x8a\x0c\x9d\x68\x00\x1c", - .clen = 32, + .entropy = (unsigned char *) + "\xc2\xa5\x66\xa9\xa1\x81\x7b\x15\xc5\xc3\xb7\x78" + "\x17\x7a\xc8\x7c\x24\xe7\x97\xbe\x0a\x84\x5f\x11" + "\xc2\xfe\x39\x9d\xd3\x77\x32\xf2\xcb\x18\x94\xeb" + "\x2b\x97\xb3\xc5\x6e\x62\x83\x29\x51\x6f\x86\xec", + .entropylen = 48, + .expected = (unsigned char *) + "\xb3\xa3\x69\x8d\x77\x76\x99\xa0\xdd\x9f\xa3\xf0" + "\xa9\xfa\x57\x83\x2d\x3c\xef\xac\x5d\xf2\x44\x37" + "\xc6\xd7\x3a\x0f\xe4\x10\x40\xf1\x72\x90\x38\xae" + "\xf1\xe9\x26\x35\x2e\xa5\x9d\xe1\x20\xbf\xb7\xb0" + "\x73\x18\x3a\x34\x10\x6e\xfe\xd6\x27\x8f\xf8\xad" + "\x84\x4b\xa0\x44\x81\x15\xdf\xdd\xf3\x31\x9a\x82" + "\xde\x6b\xb1\x1d\x80\xbd\x87\x1a\x9a\xcd\x35\xc7" + "\x36\x45\xe1\x27\x0f\xb9\xfe\x4f\xa8\x8e\xc0\xe4" + "\x65\x40\x9e\xa0\xcb\xa8\x09\xfe\x2f\x45\xe0\x49" + "\x43\xa2\xe3\x96\xbb\xb7\xdd\x2f\x4e\x07\x95\x30" + "\x35\x24\xcc\x9c\xc5\xea\x54\xa1", + .expectedlen = 128, + .addtla = (unsigned char *) + "\x41\x3d\xd8\x3f\xe5\x68\x35\xab\xd4\x78\xcb\x96" + "\x93\xd6\x76\x35\x90\x1c\x40\x23\x9a\x26\x64\x62" + "\xd3\x13\x3b\x83\xe4\x9c\x82\x0b", + .addtlb = (unsigned char *) + "\xd5\xc4\xa7\x1f\x9d\x6d\x95\xa1\xbe\xdf\x0b\xd2" + "\x24\x7c\x27\x7d\x1f\x84\xa4\xe5\x7a\x4a\x88\x25" + "\xb8\x2a\x2d\x09\x7d\xe6\x3e\xf1", + .addtllen = 32, + .pers = (unsigned char *) + "\x13\xce\x4d\x8d\xd2\xdb\x97\x96\xf9\x41\x56\xc8" + "\xe8\xf0\x76\x9b\x0a\xa1\xc8\x2c\x13\x23\xb6\x15" + "\x36\x60\x3b\xca\x37\xc9\xee\x29", + .perslen = 32, + }, +}; + +static const struct drbg_testvec drbg_nopr_ctr_aes192_tv_template[] = { + { + .entropy = (unsigned char *) + "\xc3\x5c\x2f\xa2\xa8\x9d\x52\xa1\x1f\xa3\x2a\xa9" + "\x6c\x95\xb8\xf1\xc9\xa8\xf9\xcb\x24\x5a\x8b\x40" + "\xf3\xa6\xe5\xa7\xfb\xd9\xd3\xc6\x8e\x27\x7b\xa9" + "\xac\x9b\xbb\x00", + .entropylen = 40, + .expected = (unsigned char *) + "\x8c\x2e\x72\xab\xfd\x9b\xb8\x28\x4d\xb7\x9e\x17" + "\xa4\x3a\x31\x46\xcd\x76\x94\xe3\x52\x49\xfc\x33" + "\x83\x91\x4a\x71\x17\xf4\x13\x68\xe6\xd4\xf1\x48" + "\xff\x49\xbf\x29\x07\x6b\x50\x15\xc5\x9f\x45\x79" + "\x45\x66\x2e\x3d\x35\x03\x84\x3f\x4a\xa5\xa3\xdf" + "\x9a\x9d\xf1\x0d", + .expectedlen = 64, + .addtla = NULL, + .addtlb = NULL, + .addtllen = 0, + .pers = NULL, + .perslen = 0, + }, +}; + +static const struct drbg_testvec drbg_nopr_ctr_aes256_tv_template[] = { + { + .entropy = (unsigned char *) + "\x36\x40\x19\x40\xfa\x8b\x1f\xba\x91\xa1\x66\x1f" + "\x21\x1d\x78\xa0\xb9\x38\x9a\x74\xe5\xbc\xcf\xec" + "\xe8\xd7\x66\xaf\x1a\x6d\x3b\x14\x49\x6f\x25\xb0" + "\xf1\x30\x1b\x4f\x50\x1b\xe3\x03\x80\xa1\x37\xeb", + .entropylen = 48, + .expected = (unsigned char *) + "\x58\x62\xeb\x38\xbd\x55\x8d\xd9\x78\xa6\x96\xe6" + "\xdf\x16\x47\x82\xdd\xd8\x87\xe7\xe9\xa6\xc9\xf3" + "\xf1\xfb\xaf\xb7\x89\x41\xb5\x35\xa6\x49\x12\xdf" + "\xd2\x24\xc6\xdc\x74\x54\xe5\x25\x0b\x3d\x97\x16" + "\x5e\x16\x26\x0c\x2f\xaf\x1c\xc7\x73\x5c\xb7\x5f" + "\xb4\xf0\x7e\x1d", + .expectedlen = 64, + .addtla = NULL, + .addtlb = NULL, + .addtllen = 0, + .pers = NULL, + .perslen = 0, + }, +}; + +static const struct drbg_testvec drbg_nopr_ctr_aes128_tv_template[] = { + { + .entropy = (unsigned char *) + "\x87\xe1\xc5\x32\x99\x7f\x57\xa3\x5c\x28\x6d\xe8" + "\x64\xbf\xf2\x64\xa3\x9e\x98\xdb\x6c\x10\x78\x7f", + .entropylen = 24, + .expected = (unsigned char *) + "\x2c\x14\x7e\x24\x11\x9a\xd8\xd4\xb2\xed\x61\xc1" + "\x53\xd0\x50\xc9\x24\xff\x59\x75\x15\xf1\x17\x3a" + "\x3d\xf4\x4b\x2c\x84\x28\xef\x89\x0e\xb9\xde\xf3" + "\xe4\x78\x04\xb2\xfd\x9b\x35\x7f\xe1\x3f\x8a\x3e" + "\x10\xc8\x67\x0a\xf9\xdf\x2d\x6c\x96\xfb\xb2\xb8" + "\xcb\x2d\xd6\xb0", + .expectedlen = 64, + .addtla = NULL, + .addtlb = NULL, + .addtllen = 0, + .pers = NULL, + .perslen = 0, }, { - .key = "\xf2\x92\xe6\x7d\x40\xee\xa3\x6f" - "\x03\x68\xc8\x45\xe7\x91\x0a\x18", - .klen = 16, - .iv = "\x01\x5c\x75\xe5\x84\x8d\x4d\xf6" - "\x23\x9f\xf4\x6a\xe6\x5a\x3b\x9a", - .assoc = "", - .alen = 0, - .ptext = "\x1f\xee\x92\xb4\x0c\xcb\xa1\x04" - "\x64\x0c\x4d\xb2\xe3\xec\x9c\x9d" - "\x09", - .plen = 17, - .ctext = "\x6b\x4f\x3b\x90\x9a\xa2\xb3\x82" - "\x0a\xb8\x55\xee\xeb\x73\x4d\x7f" - "\x54\x11\x3a\x8a\x31\xa3\xb5\xf2" - "\xcd\x49\xdb\xf3\xee\x26\xbd\xa2" - "\x0d", - .clen = 33, + .entropy = (unsigned char *) + "\x71\xbd\xce\x35\x42\x7d\x20\xbf\x58\xcf\x17\x74" + "\xce\x72\xd8\x33\x34\x50\x2d\x8f\x5b\x14\xc4\xdd", + .entropylen = 24, + .expected = (unsigned char *) + "\x97\x33\xe8\x20\x12\xe2\x7b\xa1\x46\x8f\xf2\x34" + "\xb3\xc9\xb6\x6b\x20\xb2\x4f\xee\x27\xd8\x0b\x21" + "\x8c\xff\x63\x73\x69\x29\xfb\xf3\x85\xcd\x88\x8e" + "\x43\x2c\x71\x8b\xa2\x55\xd2\x0f\x1d\x7f\xe3\xe1" + "\x2a\xa3\xe9\x2c\x25\x89\xc7\x14\x52\x99\x56\xcc" + "\xc3\xdf\xb3\x81", + .expectedlen = 64, + .addtla = (unsigned char *) + "\x66\xef\x42\xd6\x9a\x8c\x3d\x6d\x4a\x9e\x95\xa6" + "\x91\x4d\x81\x56", + .addtlb = (unsigned char *) + "\xe3\x18\x83\xd9\x4b\x5e\xc4\xcc\xaa\x61\x2f\xbb" + "\x4a\x55\xd1\xc6", + .addtllen = 16, + .pers = NULL, + .perslen = 0, }, { - .key = "\x2e\xb7\x20\x1c\x50\x6a\x4b\x8b" - "\x84\x42\x7a\xd7\xe1\xb5\xcd\x1f", - .klen = 16, - .iv = "\x3d\x80\xae\x84\x94\x09\xf6\x12" - "\xa4\x79\xa6\xfb\xe0\x7f\xfd\xa0", - .assoc = "", - .alen = 0, - .ptext = "\x5c\x13\xcb\x54\x1c\x47\x4a\x1f" - "\xe5\xe6\xff\x44\xdd\x11\x5f\xa3" - "\x33\xdd\xc2\xf8\xdd\x18\x2b\x93" - "\x57\x05\x01\x1c\x66\x22\xd3", - .plen = 31, - .ctext = "\x59\xd1\x0f\x6b\xee\x27\x84\x92" - "\xb7\xa9\xb5\xdd\x02\xa4\x12\xa5" - "\x50\x32\xb4\x9a\x2e\x35\x83\x55" - "\x36\x12\x12\xed\xa3\x31\xc5\x30" - "\xa7\xe2\x4a\x6d\x05\x59\x43\x91" - "\x75\xfa\x6c\x17\xc6\x73\xca", - .clen = 47, + .entropy = (unsigned char *) + "\xca\x4b\x1e\xfa\x75\xbd\x69\x36\x38\x73\xb8\xf9" + "\xdb\x4d\x35\x0e\x47\xbf\x6c\x37\x72\xfd\xf7\xa9", + .entropylen = 24, + .expected = (unsigned char *) + "\x59\xc3\x19\x79\x1b\xb1\xf3\x0e\xe9\x34\xae\x6e" + "\x8b\x1f\xad\x1f\x74\xca\x25\x45\x68\xb8\x7f\x75" + "\x12\xf8\xf2\xab\x4c\x23\x01\x03\x05\xe1\x70\xee" + "\x75\xd8\xcb\xeb\x23\x4c\x7a\x23\x6e\x12\x27\xdb" + "\x6f\x7a\xac\x3c\x44\xb7\x87\x4b\x65\x56\x74\x45" + "\x34\x30\x0c\x3d", + .expectedlen = 64, + .addtla = NULL, + .addtlb = NULL, + .addtllen = 0, + .pers = (unsigned char *) + "\xeb\xaa\x60\x2c\x4d\xbe\x33\xff\x1b\xef\xbf\x0a" + "\x0b\xc6\x97\x54", + .perslen = 16, }, { - .key = "\x6b\xdc\x5a\xbb\x60\xe5\xf4\xa6" - "\x05\x1d\x2c\x68\xdb\xda\x8f\x25", - .klen = 16, - .iv = "\x7a\xa5\xe8\x23\xa4\x84\x9e\x2d" - "\x25\x53\x58\x8c\xda\xa3\xc0\xa6", - .assoc = "", - .alen = 0, - .ptext = "\x98\x37\x05\xf3\x2c\xc2\xf3\x3b" - "\x66\xc0\xb1\xd5\xd7\x35\x21\xaa" - "\x5d\x9f\xce\x7c\xe2\xb8\xad\xad" - "\x19\x33\xe0\xf4\x40\x81\x72\x28", - .plen = 32, - .ctext = "\xdb\x49\x68\x0f\x91\x5b\x21\xb1" - "\xcf\x50\xb2\x4c\x32\xe1\xa6\x69" - "\xc0\xfb\x44\x1f\xa0\x9a\xeb\x39" - "\x1b\xde\x68\x38\xcc\x27\x52\xc5" - "\xf6\x3e\x74\xea\x66\x5b\x5f\x0c" - "\x65\x9e\x58\xe6\x52\xa2\xfe\x59", - .clen = 48, - }, { - .key = "\xa7\x00\x93\x5b\x70\x61\x9d\xc2" - "\x86\xf7\xde\xfa\xd5\xfe\x52\x2b", - .klen = 16, - .iv = "\xb6\xca\x22\xc3\xb4\x00\x47\x49" - "\xa6\x2d\x0a\x1e\xd4\xc7\x83\xad", - .assoc = "\xc5", - .alen = 1, - .ptext = "", - .plen = 0, - .ctext = "\x56\xe7\x24\x52\xdd\x95\x60\x5b" - "\x09\x48\x39\x69\x9c\xb3\x62\x46", - .clen = 16, - }, { - .key = "\xe4\x25\xcd\xfa\x80\xdd\x46\xde" - "\x07\xd1\x90\x8b\xcf\x23\x15\x31", - .klen = 16, - .iv = "\xf3\xee\x5c\x62\xc4\x7c\xf0\x65" - "\x27\x08\xbd\xaf\xce\xec\x45\xb3", - .assoc = "\x02\xb8\xea\xca\x09\x1b\x9a\xec" - "\x47\x3e\xe9\xd4\xcc\xb5\x76", - .alen = 15, - .ptext = "", - .plen = 0, - .ctext = "\xdd\xfa\x6c\x1f\x5d\x86\x87\x01" - "\x13\xe5\x73\x46\x46\xf2\x5c\xe1", - .clen = 16, - }, { - .key = "\x20\x4a\x07\x99\x91\x58\xee\xfa" - "\x88\xab\x42\x1c\xc9\x47\xd7\x38", - .klen = 16, - .iv = "\x2f\x13\x95\x01\xd5\xf7\x99\x81" - "\xa8\xe2\x6f\x41\xc8\x10\x08\xb9", - .assoc = "\x3f\xdc\x24\x69\x19\x96\x43\x08" - "\xc8\x18\x9b\x65\xc6\xd9\x39\x3b", - .alen = 16, - .ptext = "", - .plen = 0, - .ctext = "\xa6\x1b\xb9\xd7\x5e\x3c\xcf\xac" - "\xa9\x21\x45\x0b\x16\x52\xf7\xe1", - .clen = 16, - }, { - .key = "\x5d\x6f\x41\x39\xa1\xd4\x97\x16" - "\x09\x85\xf4\xae\xc3\x6b\x9a\x3e", - .klen = 16, - .iv = "\x6c\x38\xcf\xa1\xe5\x73\x41\x9d" - "\x29\xbc\x21\xd2\xc2\x35\xcb\xbf", - .assoc = "\x7b\x01\x5d\x08\x29\x12\xec\x24" - "\x49\xf3\x4d\xf7\xc0\xfe\xfb\x41" - "\x3c", - .alen = 17, - .ptext = "", - .plen = 0, - .ctext = "\x15\xff\xde\x3b\x34\xfc\xf6\xf9" - "\xbb\xa8\x62\xad\x0a\xf5\x48\x60", - .clen = 16, - }, { - .key = "\x99\x93\x7a\xd8\xb1\x50\x40\x31" - "\x8a\x60\xa6\x3f\xbd\x90\x5d\x44", - .klen = 16, - .iv = "\xa8\x5c\x09\x40\xf5\xef\xea\xb8" - "\xaa\x96\xd3\x64\xbc\x59\x8d\xc6", - .assoc = "\xb8\x26\x97\xa8\x39\x8e\x94\x3f" - "\xca\xcd\xff\x88\xba\x22\xbe\x47" - "\x67\xba\x85\xf1\xbb\x30\x56\x26" - "\xaf\x0b\x02\x38\xcc\x44\xa7", - .alen = 31, - .ptext = "", - .plen = 0, - .ctext = "\xd2\x9d\xf8\x3b\xd7\x84\xe9\x2d" - "\x4b\xef\x75\x16\x0a\x99\xae\x6b", - .clen = 16, - }, { - .key = "\xd6\xb8\xb4\x77\xc1\xcb\xe9\x4d" - "\x0a\x3a\x58\xd1\xb7\xb4\x1f\x4a", - .klen = 16, - .iv = "\xe5\x81\x42\xdf\x05\x6a\x93\xd4" - "\x2b\x70\x85\xf5\xb6\x7d\x50\xcc", - .assoc = "\xf4\x4a\xd1\x47\x49\x09\x3d\x5b" - "\x4b\xa7\xb1\x19\xb4\x46\x81\x4d" - "\x91\x7c\x91\x75\xc0\xd0\xd8\x40" - "\x71\x39\xe1\x10\xa6\xa3\x46\x7a", - .alen = 32, - .ptext = "", - .plen = 0, - .ctext = "\xe4\x8d\xa7\xa7\x45\xc1\x31\x4f" - "\xce\xfb\xaf\xd6\xc2\xe6\xee\xc0", - .clen = 16, - }, { - .key = "\x12\xdd\xee\x17\xd1\x47\x92\x69" - "\x8b\x14\x0a\x62\xb1\xd9\xe2\x50", - .klen = 16, - .iv = "\x22\xa6\x7c\x7f\x15\xe6\x3c\xf0" - "\xac\x4b\x37\x86\xb0\xa2\x13\xd2", - .assoc = "\x31", - .alen = 1, - .ptext = "\x40", - .plen = 1, - .ctext = "\xe2\x67\x38\x4f\xb9\xad\x7d\x38" - "\x01\xfe\x84\x14\x85\xf8\xd1\xe3" - "\x22", - .clen = 17, - }, { - .key = "\x4f\x01\x27\xb6\xe1\xc3\x3a\x85" - "\x0c\xee\xbc\xf4\xab\xfd\xa5\x57", - .klen = 16, - .iv = "\x5e\xcb\xb6\x1e\x25\x62\xe4\x0c" - "\x2d\x25\xe9\x18\xaa\xc6\xd5\xd8", - .assoc = "\x6d\x94\x44\x86\x69\x00\x8f\x93" - "\x4d\x5b\x15\x3c\xa8\x8f\x06", - .alen = 15, - .ptext = "\x7c\x5d\xd3\xee\xad\x9f\x39\x1a" - "\x6d\x92\x42\x61\xa7\x58\x37", - .plen = 15, - .ctext = "\x77\x32\x61\xeb\xb4\x33\x29\x92" - "\x29\x95\xc5\x8e\x85\x76\xab\xfc" - "\x07\x95\xa7\x44\x74\xf7\x22\xff" - "\xd8\xd8\x36\x3d\x8a\x7f\x9e", - .clen = 31, - }, { - .key = "\x8b\x26\x61\x55\xf1\x3e\xe3\xa1" - "\x8d\xc8\x6e\x85\xa5\x21\x67\x5d", - .klen = 16, - .iv = "\x9b\xef\xf0\xbd\x35\xdd\x8d\x28" - "\xad\xff\x9b\xa9\xa4\xeb\x98\xdf", - .assoc = "\xaa\xb8\x7e\x25\x79\x7c\x37\xaf" - "\xce\x36\xc7\xce\xa2\xb4\xc9\x60", - .alen = 16, - .ptext = "\xb9\x82\x0c\x8d\xbd\x1b\xe2\x36" - "\xee\x6c\xf4\xf2\xa1\x7d\xf9\xe2", - .plen = 16, - .ctext = "\xd8\xfd\x44\x45\xf6\x42\x12\x38" - "\xf2\x0b\xea\x4f\x9e\x11\x61\x07" - "\x48\x67\x98\x18\x9b\xd0\x0c\x59" - "\x67\xa4\x11\xb3\x2b\xd6\xc1\x70", - .clen = 32, - }, { - .key = "\xc8\x4b\x9b\xf5\x01\xba\x8c\xbd" - "\x0e\xa3\x21\x16\x9f\x46\x2a\x63", - .klen = 16, - .iv = "\xd7\x14\x29\x5d\x45\x59\x36\x44" - "\x2e\xd9\x4d\x3b\x9e\x0f\x5b\xe5", - .assoc = "\xe6\xdd\xb8\xc4\x89\xf8\xe0\xca" - "\x4f\x10\x7a\x5f\x9c\xd8\x8b\x66" - "\x3b", - .alen = 17, - .ptext = "\xf5\xa6\x46\x2c\xce\x97\x8a\x51" - "\x6f\x46\xa6\x83\x9b\xa1\xbc\xe8" - "\x05", - .plen = 17, - .ctext = "\xb1\xab\x53\x4e\xc7\x40\x16\xb6" - "\x71\x3a\x00\x9f\x41\x88\xb0\xb2" - "\x71\x83\x85\x5f\xc8\x79\x0a\x99" - "\x99\xdc\x89\x1c\x88\xd2\x3e\xf9" - "\x83", - .clen = 33, - }, { - .key = "\x05\x70\xd5\x94\x12\x36\x35\xd8" - "\x8f\x7d\xd3\xa8\x99\x6a\xed\x69", - .klen = 16, - .iv = "\x14\x39\x63\xfc\x56\xd5\xdf\x5f" - "\xaf\xb3\xff\xcc\x98\x33\x1d\xeb", - .assoc = "\x23\x02\xf1\x64\x9a\x73\x89\xe6" - "\xd0\xea\x2c\xf1\x96\xfc\x4e\x6d" - "\x65\x48\xcb\x0a\xda\xf0\x62\xc0" - "\x38\x1d\x3b\x4a\xe9\x7e\x62", - .alen = 31, - .ptext = "\x32\xcb\x80\xcc\xde\x12\x33\x6d" - "\xf0\x20\x58\x15\x95\xc6\x7f\xee" - "\x2f\xf9\x4e\x2c\x1b\x98\x43\xc7" - "\x68\x28\x73\x40\x9f\x96\x4a", - .plen = 31, - .ctext = "\x29\xc4\xf0\x03\xc1\x86\xdf\x06" - "\x5c\x7b\xef\x64\x87\x00\xd1\x37" - "\xa7\x08\xbc\x7f\x8f\x41\x54\xd0" - "\x3e\xf1\xc3\xa2\x96\x84\xdd\x2a" - "\x2d\x21\x30\xf9\x02\xdb\x06\x0c" - "\xf1\x5a\x66\x69\xe0\xca\x83", - .clen = 47, - }, { - .key = "\x41\x94\x0e\x33\x22\xb1\xdd\xf4" - "\x10\x57\x85\x39\x93\x8f\xaf\x70", - .klen = 16, - .iv = "\x50\x5d\x9d\x9b\x66\x50\x88\x7b" - "\x30\x8e\xb1\x5e\x92\x58\xe0\xf1", - .assoc = "\x5f\x27\x2b\x03\xaa\xef\x32\x02" - "\x50\xc4\xde\x82\x90\x21\x11\x73" - "\x8f\x0a\xd6\x8f\xdf\x90\xe4\xda" - "\xf9\x4a\x1a\x23\xc3\xdd\x02\x81", - .alen = 32, - .ptext = "\x6e\xf0\xba\x6b\xee\x8e\xdc\x89" - "\x71\xfb\x0a\xa6\x8f\xea\x41\xf4" - "\x5a\xbb\x59\xb0\x20\x38\xc5\xe0" - "\x29\x56\x52\x19\x79\xf5\xe9\x37", - .plen = 32, - .ctext = "\xe2\x2e\x44\xdf\xd3\x60\x6d\xb2" - "\x70\x57\x37\xc5\xc2\x4f\x8d\x14" - "\xc6\xbf\x8b\xec\xf5\x62\x67\xf2" - "\x2f\xa1\xe6\xd6\xa7\xb1\x8c\x54" - "\xe5\x6b\x49\xf9\x6e\x90\xc3\xaa" - "\x7a\x00\x2e\x4d\x7f\x31\x2e\x81", - .clen = 48, - }, { - .key = "\x7e\xb9\x48\xd3\x32\x2d\x86\x10" - "\x91\x31\x37\xcb\x8d\xb3\x72\x76", - .klen = 16, - .iv = "\x8d\x82\xd6\x3b\x76\xcc\x30\x97" - "\xb1\x68\x63\xef\x8c\x7c\xa3\xf7", - .assoc = "\x9c\x4b\x65\xa2\xba\x6b\xdb\x1e" - "\xd1\x9e\x90\x13\x8a\x45\xd3\x79" - "\xba\xcd\xe2\x13\xe4\x30\x66\xf4" - "\xba\x78\xf9\xfb\x9d\x3c\xa1\x58" - "\x1a", - .alen = 33, - .ptext = "\xab\x14\xf3\x0a\xfe\x0a\x85\xa5" - "\xf2\xd5\xbc\x38\x89\x0e\x04\xfb" - "\x84\x7d\x65\x34\x25\xd8\x47\xfa" - "\xeb\x83\x31\xf1\x54\x54\x89\x0d" - "\x9d\x4d\x54\x51\x84\x61\xf6\x8e" - "\x03\x31\xf2\x25\x16\xcc\xaa\xc6" - "\x75\x73\x20\x30\x59\x54\xb2\xf0" - "\x3a\x4b\xe0\x23\x8e\xa6\x08\x35" - "\x8a", - .plen = 65, - .ctext = "\xc7\xca\x26\x61\x57\xee\xa2\xb9" - "\xb1\x37\xde\x95\x06\x90\x11\x08" - "\x4d\x30\x9f\x24\xc0\x56\xb7\xe1" - "\x0b\x9f\xd2\x57\xe9\xd2\xb1\x76" - "\x56\x9a\xb4\x58\xc5\x08\xfc\xb5" - "\xf2\x31\x9b\xc9\xcd\xb3\x64\xdb" - "\x6f\x50\xbf\xf4\x73\x9d\xfb\x6b" - "\xef\x35\x25\x48\xed\xcf\x29\xa8" - "\xac\xc3\xb9\xcb\x61\x8f\x73\x92" - "\x2c\x7a\x6f\xda\xf9\x09\x6f\xe1" - "\xc4", - .clen = 81, - }, { - .key = "\xba\xde\x82\x72\x42\xa9\x2f\x2c" - "\x12\x0b\xe9\x5c\x87\xd7\x35\x7c", - .klen = 16, - .iv = "\xc9\xa7\x10\xda\x86\x48\xd9\xb3" - "\x32\x42\x15\x80\x85\xa1\x65\xfe", - .assoc = "\xd8\x70\x9f\x42\xca\xe6\x83\x3a" - "\x52\x79\x42\xa5\x84\x6a\x96\x7f" - "\xe4\x8f\xed\x97\xe9\xd0\xe8\x0d" - "\x7c\xa6\xd8\xd4\x77\x9b\x40\x2e" - "\x28\xce\x57\x34\xcd\x6e\x84\x4c" - "\x17\x3c\xe1\xb2\xa8\x0b\xbb\xf1" - "\x96\x41\x0d\x69\xe8\x54\x0a\xc8" - "\x15\x4e\x91\x92\x89\x4b\xb7\x9b" - "\x21", - .alen = 65, - .ptext = "\xe8\x39\x2d\xaa\x0e\x85\x2d\xc1" - "\x72\xaf\x6e\xc9\x82\x33\xc7\x01" - "\xaf\x40\x70\xb8\x2a\x78\xc9\x14" - "\xac\xb1\x10\xca\x2e\xb3\x28\xe4" - "\xac", - .plen = 33, - .ctext = "\x57\xcd\x3d\x46\xc5\xf9\x68\x3b" - "\x2c\x0f\xb4\x7e\x7b\x64\x3e\x40" - "\xf3\x78\x63\x34\x89\x79\x39\x6b" - "\x61\x64\x4a\x9a\xfa\x70\xa4\xd3" - "\x54\x0b\xea\x05\xa6\x95\x64\xed" - "\x3d\x69\xa2\x0c\x27\x56\x2f\x34" - "\x66", - .clen = 49, - }, { - .key = "\xf7\x02\xbb\x11\x52\x24\xd8\x48" - "\x93\xe6\x9b\xee\x81\xfc\xf7\x82", - .klen = 16, - .iv = "\x06\xcc\x4a\x79\x96\xc3\x82\xcf" - "\xb3\x1c\xc7\x12\x7f\xc5\x28\x04", - .assoc = "\x15\x95\xd8\xe1\xda\x62\x2c\x56" - "\xd3\x53\xf4\x36\x7e\x8e\x59\x85", - .alen = 16, - .ptext = "\x24\x5e\x67\x49\x1e\x01\xd6\xdd" - "\xf3\x89\x20\x5b\x7c\x57\x89\x07", - .plen = 16, - .ctext = "\xfc\x85\x06\x28\x8f\xe8\x23\x1f" - "\x33\x98\x87\xde\x08\xb6\xb6\xae" - "\x3e\xa4\xf8\x19\xf1\x92\x60\x39" - "\xb9\x6b\x3f\xdf\xc8\xcb\x30", - .clen = 31, - }, { - .key = "\x33\x27\xf5\xb1\x62\xa0\x80\x63" - "\x14\xc0\x4d\x7f\x7b\x20\xba\x89", - .klen = 16, - .iv = "\x42\xf0\x84\x19\xa6\x3f\x2b\xea" - "\x34\xf6\x79\xa3\x79\xe9\xeb\x0a", - .assoc = "\x51\xb9\x12\x80\xea\xde\xd5\x71" - "\x54\x2d\xa6\xc8\x78\xb2\x1b\x8c", - .alen = 16, - .ptext = "\x61\x83\xa0\xe8\x2e\x7d\x7f\xf8" - "\x74\x63\xd2\xec\x76\x7c\x4c\x0d", - .plen = 16, - .ctext = "\x74\x7d\x70\x07\xe9\xba\x01\xee" - "\x6c\xc6\x6f\x50\x25\x33\xbe\x50" - "\x17\xb8\x17\x62\xed\x80\xa2\xf5" - "\x03\xde\x85\x71\x5d\x34", - .clen = 30, - }, { - .key = "\x70\x4c\x2f\x50\x72\x1c\x29\x7f" - "\x95\x9a\xff\x10\x75\x45\x7d\x8f", - .klen = 16, - .iv = "\x7f\x15\xbd\xb8\xb6\xba\xd3\x06" - "\xb5\xd1\x2b\x35\x73\x0e\xad\x10", - .assoc = "\x8e\xde\x4c\x20\xfa\x59\x7e\x8d" - "\xd5\x07\x58\x59\x72\xd7\xde\x92", - .alen = 16, - .ptext = "\x9d\xa7\xda\x88\x3e\xf8\x28\x14" - "\xf5\x3e\x85\x7d\x70\xa0\x0f\x13", - .plen = 16, - .ctext = "\xf4\xb3\x85\xf9\xac\xde\xb1\x38" - "\x29\xfd\x6c\x7c\x49\xe5\x1d\xaf" - "\xba\xea\xd4\xfa\x3f\x11\x33\x98", - .clen = 24, - }, { - .key = "\xac\x70\x69\xef\x82\x97\xd2\x9b" - "\x15\x74\xb1\xa2\x6f\x69\x3f\x95", - .klen = 16, - .iv = "\xbb\x3a\xf7\x57\xc6\x36\x7c\x22" - "\x36\xab\xde\xc6\x6d\x32\x70\x17", - .assoc = "\xcb\x03\x85\xbf\x0a\xd5\x26\xa9" - "\x56\xe1\x0a\xeb\x6c\xfb\xa1\x98", - .alen = 16, - .ptext = "\xda\xcc\x14\x27\x4e\x74\xd1\x30" - "\x76\x18\x37\x0f\x6a\xc4\xd1\x1a", - .plen = 16, - .ctext = "\xe6\x5c\x49\x4f\x78\xf3\x62\x86" - "\xe1\xb7\xa5\xc3\x32\x88\x3c\x8c" - "\x6e", - .clen = 17, + .entropy = (unsigned char *) + "\xc0\x70\x1f\x92\x50\x75\x8f\xcd\xf2\xbe\x73\x98" + "\x80\xdb\x66\xeb\x14\x68\xb4\xa5\x87\x9c\x2d\xa6", + .entropylen = 24, + .expected = (unsigned char *) + "\x97\xc0\xc0\xe5\xa0\xcc\xf2\x4f\x33\x63\x48\x8a" + "\xdb\x13\x0a\x35\x89\xbf\x80\x65\x62\xee\x13\x95" + "\x7c\x33\xd3\x7d\xf4\x07\x77\x7a\x2b\x65\x0b\x5f" + "\x45\x5c\x13\xf1\x90\x77\x7f\xc5\x04\x3f\xcc\x1a" + "\x38\xf8\xcd\x1b\xbb\xd5\x57\xd1\x4a\x4c\x2e\x8a" + "\x2b\x49\x1e\x5c", + .expectedlen = 64, + .addtla = (unsigned char *) + "\xf9\x01\xf8\x16\x7a\x1d\xff\xde\x8e\x3c\x83\xe2" + "\x44\x85\xe7\xfe", + .addtlb = (unsigned char *) + "\x17\x1c\x09\x38\xc2\x38\x9f\x97\x87\x60\x55\xb4" + "\x82\x16\x62\x7f", + .addtllen = 16, + .pers = (unsigned char *) + "\x80\x08\xae\xe8\xe9\x69\x40\xc5\x08\x73\xc7\x9f" + "\x8e\xcf\xe0\x02", + .perslen = 16, }, }; -/* - * MORUS-1280 test vectors - generated via reference implementation from - * SUPERCOP (https://bench.cr.yp.to/supercop.html): - * - * https://bench.cr.yp.to/supercop/supercop-20170228.tar.xz - * (see crypto_aead/morus1280128v2/ and crypto_aead/morus1280256v2/ ) - */ -static const struct aead_testvec morus1280_tv_template[] = { +/* Cast5 test vectors from RFC 2144 */ +static const struct cipher_testvec cast5_tv_template[] = { { - .key = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .klen = 16, - .iv = "\x0f\xc9\x8e\x67\x44\x9e\xaa\x86" - "\x20\x36\x2c\x24\xfe\xc9\x30\x81", - .assoc = "", - .alen = 0, - .ptext = "", - .plen = 0, - .ctext = "\x91\x85\x0f\xf5\x52\x9e\xce\xce" - "\x65\x99\xc7\xbf\xd3\x76\xe8\x98", - .clen = 16, - }, { - .key = "\x3c\x24\x39\x9f\x10\x7b\xa8\x1b" - "\x80\xda\xb2\x91\xf9\x24\xc2\x06", - .klen = 16, - .iv = "\x4b\xed\xc8\x07\x54\x1a\x52\xa2" - "\xa1\x10\xde\xb5\xf8\xed\xf3\x87", - .assoc = "", - .alen = 0, - .ptext = "\x69", - .plen = 1, - .ctext = "\x88\xc3\x4c\xf0\x2f\x43\x76\x13" - "\x96\xda\x76\x34\x33\x4e\xd5\x39" - "\x73", - .clen = 17, - }, { - .key = "\x79\x49\x73\x3e\x20\xf7\x51\x37" - "\x01\xb4\x64\x22\xf3\x48\x85\x0c", - .klen = 16, - .iv = "\x88\x12\x01\xa6\x64\x96\xfb\xbe" - "\x22\xea\x90\x47\xf2\x11\xb5\x8e", - .assoc = "", - .alen = 0, - .ptext = "\xa6\xa4\x1e\x76\xec\xd4\x50\xcc" - "\x62\x58\xe9\x8f\xef\xa4\x17\x91" - "\xb4\x96\x9f\x6b\xce\x38\xa5\x46" - "\x13\x7d\x64\x93\xd7\x05\xf5", - .plen = 31, - .ctext = "\x3e\x5c\x3b\x58\x3b\x7d\x2a\x22" - "\x75\x0b\x24\xa6\x0e\xc3\xde\x52" - "\x97\x0b\x64\xd4\xce\x90\x52\xf7" - "\xef\xdb\x6a\x38\xd2\xa8\xa1\x0d" - "\xe0\x61\x33\x24\xc6\x4d\x51\xbc" - "\xa4\x21\x74\xcf\x19\x16\x59", - .clen = 47, - }, { - .key = "\xb5\x6e\xad\xdd\x30\x72\xfa\x53" - "\x82\x8e\x16\xb4\xed\x6d\x47\x12", - .klen = 16, - .iv = "\xc4\x37\x3b\x45\x74\x11\xa4\xda" - "\xa2\xc5\x42\xd8\xec\x36\x78\x94", - .assoc = "", - .alen = 0, - .ptext = "\xe2\xc9\x58\x15\xfc\x4f\xf8\xe8" - "\xe3\x32\x9b\x21\xe9\xc8\xd9\x97" - "\xde\x58\xab\xf0\xd3\xd8\x27\x60" - "\xd5\xaa\x43\x6b\xb1\x64\x95\xa4", - .plen = 32, - .ctext = "\x30\x82\x9c\x2b\x67\xcb\xf9\x1f" - "\xde\x9f\x77\xb2\xda\x92\x61\x5c" - "\x09\x0b\x2d\x9a\x26\xaa\x1c\x06" - "\xab\x74\xb7\x2b\x95\x5f\x9f\xa1" - "\x9a\xff\x50\xa0\xa2\xff\xc5\xad" - "\x21\x8e\x84\x5c\x12\x61\xb2\xae", - .clen = 48, - }, { - .key = "\xf2\x92\xe6\x7d\x40\xee\xa3\x6f" - "\x03\x68\xc8\x45\xe7\x91\x0a\x18", - .klen = 16, - .iv = "\x01\x5c\x75\xe5\x84\x8d\x4d\xf6" - "\x23\x9f\xf4\x6a\xe6\x5a\x3b\x9a", - .assoc = "", - .alen = 0, - .ptext = "\x1f\xee\x92\xb4\x0c\xcb\xa1\x04" - "\x64\x0c\x4d\xb2\xe3\xec\x9c\x9d" - "\x09\x1a\xb7\x74\xd8\x78\xa9\x79" - "\x96\xd8\x22\x43\x8c\xc3\x34\x7b" - "\xc4", - .plen = 33, - .ctext = "\x67\x5d\x8e\x45\xc8\x39\xf5\x17" - "\xc1\x1d\x2a\xdd\x88\x67\xda\x1f" - "\x6d\xe8\x37\x28\x5a\xc1\x5e\x9f" - "\xa6\xec\xc6\x92\x05\x4b\xc0\xa3" - "\x63\xef\x88\xa4\x9b\x0a\x5c\xed" - "\x2b\x6a\xac\x63\x52\xaa\x10\x94" - "\xd0", - .clen = 49, - }, { - .key = "\x2e\xb7\x20\x1c\x50\x6a\x4b\x8b" - "\x84\x42\x7a\xd7\xe1\xb5\xcd\x1f", - .klen = 16, - .iv = "\x3d\x80\xae\x84\x94\x09\xf6\x12" - "\xa4\x79\xa6\xfb\xe0\x7f\xfd\xa0", - .assoc = "", - .alen = 0, - .ptext = "\x5c\x13\xcb\x54\x1c\x47\x4a\x1f" - "\xe5\xe6\xff\x44\xdd\x11\x5f\xa3" - "\x33\xdd\xc2\xf8\xdd\x18\x2b\x93" - "\x57\x05\x01\x1c\x66\x22\xd3\x51" - "\xd3\xdf\x18\xc9\x30\x66\xed\xb1" - "\x96\x58\xd5\x8c\x64\x8c\x7c\xf5" - "\x01\xd0\x74\x5f\x9b\xaa\xf6\xd1" - "\xe6\x16\xa2\xac\xde\x47\x40", - .plen = 63, - .ctext = "\x7d\x61\x1a\x35\x20\xcc\x07\x88" - "\x03\x98\x87\xcf\xc0\x6e\x4d\x19" - "\xe3\xd4\x0b\xfb\x29\x8f\x49\x1a" - "\x3a\x06\x77\xce\x71\x2c\xcd\xdd" - "\xed\xf6\xc9\xbe\xa6\x3b\xb8\xfc" - "\x6c\xbe\x77\xed\x74\x0e\x20\x85" - "\xd0\x65\xde\x24\x6f\xe3\x25\xc5" - "\xdf\x5b\x0f\xbd\x8a\x88\x78\xc9" - "\xe5\x81\x37\xde\x84\x7a\xf6\x84" - "\x99\x7a\x72\x9c\x54\x31\xa1", - .clen = 79, - }, { - .key = "\x6b\xdc\x5a\xbb\x60\xe5\xf4\xa6" - "\x05\x1d\x2c\x68\xdb\xda\x8f\x25", + .key = "\x01\x23\x45\x67\x12\x34\x56\x78" + "\x23\x45\x67\x89\x34\x56\x78\x9a", .klen = 16, - .iv = "\x7a\xa5\xe8\x23\xa4\x84\x9e\x2d" - "\x25\x53\x58\x8c\xda\xa3\xc0\xa6", - .assoc = "", - .alen = 0, - .ptext = "\x98\x37\x05\xf3\x2c\xc2\xf3\x3b" - "\x66\xc0\xb1\xd5\xd7\x35\x21\xaa" - "\x5d\x9f\xce\x7c\xe2\xb8\xad\xad" - "\x19\x33\xe0\xf4\x40\x81\x72\x28" - "\xe1\x8b\x1c\xf8\x91\x78\xff\xaf" - "\xb0\x68\x69\xf2\x27\x35\x91\x84" - "\x2e\x37\x5b\x00\x04\xff\x16\x9c" - "\xb5\x19\x39\xeb\xd9\xcd\x29\x9a", - .plen = 64, - .ctext = "\x05\xc5\xb1\xf9\x1b\xb9\xab\x2c" - "\xa5\x07\x12\xa7\x12\x39\x60\x66" - "\x30\x81\x4a\x03\x78\x28\x45\x52" - "\xd2\x2b\x24\xfd\x8b\xa5\xb7\x66" - "\x6f\x45\xd7\x3b\x67\x6f\x51\xb9" - "\xc0\x3d\x6c\xca\x1e\xae\xff\xb6" - "\x79\xa9\xe4\x82\x5d\x4c\x2d\xdf" - "\xeb\x71\x40\xc9\x2c\x40\x45\x6d" - "\x73\x77\x01\xf3\x4f\xf3\x9d\x2a" - "\x5d\x57\xa8\xa1\x18\xa2\xad\xcb", - .clen = 80, + .ptext = "\x01\x23\x45\x67\x89\xab\xcd\xef", + .ctext = "\x23\x8b\x4f\xe5\x84\x7e\x44\xb2", + .len = 8, }, { - .key = "\xa7\x00\x93\x5b\x70\x61\x9d\xc2" - "\x86\xf7\xde\xfa\xd5\xfe\x52\x2b", - .klen = 16, - .iv = "\xb6\xca\x22\xc3\xb4\x00\x47\x49" - "\xa6\x2d\x0a\x1e\xd4\xc7\x83\xad", - .assoc = "\xc5", - .alen = 1, - .ptext = "", - .plen = 0, - .ctext = "\x4d\xbf\x11\xac\x7f\x97\x0b\x2e" - "\x89\x3b\x9d\x0f\x83\x1c\x08\xc3", - .clen = 16, + .key = "\x01\x23\x45\x67\x12\x34\x56\x78" + "\x23\x45", + .klen = 10, + .ptext = "\x01\x23\x45\x67\x89\xab\xcd\xef", + .ctext = "\xeb\x6a\x71\x1a\x2c\x02\x27\x1b", + .len = 8, }, { - .key = "\xe4\x25\xcd\xfa\x80\xdd\x46\xde" - "\x07\xd1\x90\x8b\xcf\x23\x15\x31", - .klen = 16, - .iv = "\xf3\xee\x5c\x62\xc4\x7c\xf0\x65" - "\x27\x08\xbd\xaf\xce\xec\x45\xb3", - .assoc = "\x02\xb8\xea\xca\x09\x1b\x9a\xec" - "\x47\x3e\xe9\xd4\xcc\xb5\x76\x34" - "\xe8\x73\x62\x64\xab\x50\xd0\xda" - "\x6b\x83\x66\xaf\x3e\x27\xc9", - .alen = 31, - .ptext = "", - .plen = 0, - .ctext = "\x5b\xc0\x8d\x54\xe4\xec\xbe\x38" - "\x03\x12\xf9\xcc\x9e\x46\x42\x92", - .clen = 16, - }, { - .key = "\x20\x4a\x07\x99\x91\x58\xee\xfa" - "\x88\xab\x42\x1c\xc9\x47\xd7\x38", - .klen = 16, - .iv = "\x2f\x13\x95\x01\xd5\xf7\x99\x81" - "\xa8\xe2\x6f\x41\xc8\x10\x08\xb9", - .assoc = "\x3f\xdc\x24\x69\x19\x96\x43\x08" - "\xc8\x18\x9b\x65\xc6\xd9\x39\x3b" - "\x12\x35\x6e\xe8\xb0\xf0\x52\xf3" - "\x2d\xb0\x45\x87\x18\x86\x68\xf6", - .alen = 32, - .ptext = "", - .plen = 0, - .ctext = "\x48\xc5\xc3\x4c\x40\x2e\x2f\xc2" - "\x6d\x65\xe0\x67\x9c\x1d\xa0\xf0", - .clen = 16, - }, { - .key = "\x5d\x6f\x41\x39\xa1\xd4\x97\x16" - "\x09\x85\xf4\xae\xc3\x6b\x9a\x3e", - .klen = 16, - .iv = "\x6c\x38\xcf\xa1\xe5\x73\x41\x9d" - "\x29\xbc\x21\xd2\xc2\x35\xcb\xbf", - .assoc = "\x7b\x01\x5d\x08\x29\x12\xec\x24" - "\x49\xf3\x4d\xf7\xc0\xfe\xfb\x41" - "\x3c\xf8\x79\x6c\xb6\x90\xd4\x0d" - "\xee\xde\x23\x60\xf2\xe5\x08\xcc" - "\x97", - .alen = 33, - .ptext = "", - .plen = 0, - .ctext = "\x28\x64\x78\x51\x55\xd8\x56\x4a" - "\x58\x3e\xf7\xbe\xee\x21\xfe\x94", - .clen = 16, - }, { - .key = "\x99\x93\x7a\xd8\xb1\x50\x40\x31" - "\x8a\x60\xa6\x3f\xbd\x90\x5d\x44", - .klen = 16, - .iv = "\xa8\x5c\x09\x40\xf5\xef\xea\xb8" - "\xaa\x96\xd3\x64\xbc\x59\x8d\xc6", - .assoc = "\xb8\x26\x97\xa8\x39\x8e\x94\x3f" - "\xca\xcd\xff\x88\xba\x22\xbe\x47" - "\x67\xba\x85\xf1\xbb\x30\x56\x26" - "\xaf\x0b\x02\x38\xcc\x44\xa7\xa3" - "\xa6\xbf\x31\x93\x60\xcd\xda\x63" - "\x2c\xb1\xaa\x19\xc8\x19\xf8\xeb" - "\x03\xa1\xe8\xbe\x37\x54\xec\xa2" - "\xcd\x2c\x45\x58\xbd\x8e\x80", - .alen = 63, - .ptext = "", - .plen = 0, - .ctext = "\xb3\xa6\x00\x4e\x09\x20\xac\x21" - "\x77\x72\x69\x76\x2d\x36\xe5\xc8", - .clen = 16, - }, { - .key = "\xd6\xb8\xb4\x77\xc1\xcb\xe9\x4d" - "\x0a\x3a\x58\xd1\xb7\xb4\x1f\x4a", - .klen = 16, - .iv = "\xe5\x81\x42\xdf\x05\x6a\x93\xd4" - "\x2b\x70\x85\xf5\xb6\x7d\x50\xcc", - .assoc = "\xf4\x4a\xd1\x47\x49\x09\x3d\x5b" - "\x4b\xa7\xb1\x19\xb4\x46\x81\x4d" - "\x91\x7c\x91\x75\xc0\xd0\xd8\x40" - "\x71\x39\xe1\x10\xa6\xa3\x46\x7a" - "\xb4\x6b\x35\xc2\xc1\xdf\xed\x60" - "\x46\xc1\x3e\x7f\x8c\xc2\x0e\x7a" - "\x30\x08\xd0\x5f\xa0\xaa\x0c\x6d" - "\x9c\x2f\xdb\x97\xb8\x15\x69\x01", - .alen = 64, - .ptext = "", - .plen = 0, - .ctext = "\x65\x33\x7b\xa1\x63\xf4\x20\xdd" - "\xe4\xb9\x4a\xaa\x9a\x21\xaa\x14", - .clen = 16, - }, { - .key = "\x12\xdd\xee\x17\xd1\x47\x92\x69" - "\x8b\x14\x0a\x62\xb1\xd9\xe2\x50", - .klen = 16, - .iv = "\x22\xa6\x7c\x7f\x15\xe6\x3c\xf0" - "\xac\x4b\x37\x86\xb0\xa2\x13\xd2", - .assoc = "\x31", - .alen = 1, - .ptext = "\x40", - .plen = 1, - .ctext = "\x1d\x47\x17\x34\x86\xf5\x54\x1a" - "\x6d\x28\xb8\x5d\x6c\xcf\xa0\xb9" - "\xbf", - .clen = 17, - }, { - .key = "\x4f\x01\x27\xb6\xe1\xc3\x3a\x85" - "\x0c\xee\xbc\xf4\xab\xfd\xa5\x57", - .klen = 16, - .iv = "\x5e\xcb\xb6\x1e\x25\x62\xe4\x0c" - "\x2d\x25\xe9\x18\xaa\xc6\xd5\xd8", - .assoc = "\x6d\x94\x44\x86\x69\x00\x8f\x93" - "\x4d\x5b\x15\x3c\xa8\x8f\x06\x5a" - "\xe6\x01\xa8\x7e\xca\x10\xdc\x73" - "\xf4\x94\x9f\xc1\x5a\x61\x85", - .alen = 31, - .ptext = "\x7c\x5d\xd3\xee\xad\x9f\x39\x1a" - "\x6d\x92\x42\x61\xa7\x58\x37\xdb" - "\xb0\xb2\x2b\x9f\x0b\xb8\xbd\x7a" - "\x24\xa0\xd6\xb7\x11\x79\x6c", - .plen = 31, - .ctext = "\x78\x90\x52\xae\x0f\xf7\x2e\xef" - "\x63\x09\x08\x58\xb5\x56\xbd\x72" - "\x6e\x42\xcf\x27\x04\x7c\xdb\x92" - "\x18\xe9\xa4\x33\x90\xba\x62\xb5" - "\x70\xd3\x88\x9b\x4f\x05\xa7\x51" - "\x85\x87\x17\x09\x42\xed\x4e", - .clen = 47, - }, { - .key = "\x8b\x26\x61\x55\xf1\x3e\xe3\xa1" - "\x8d\xc8\x6e\x85\xa5\x21\x67\x5d", - .klen = 16, - .iv = "\x9b\xef\xf0\xbd\x35\xdd\x8d\x28" - "\xad\xff\x9b\xa9\xa4\xeb\x98\xdf", - .assoc = "\xaa\xb8\x7e\x25\x79\x7c\x37\xaf" - "\xce\x36\xc7\xce\xa2\xb4\xc9\x60" - "\x10\xc3\xb3\x02\xcf\xb0\x5e\x8d" - "\xb5\xc2\x7e\x9a\x35\xc0\x24\xfd", - .alen = 32, - .ptext = "\xb9\x82\x0c\x8d\xbd\x1b\xe2\x36" - "\xee\x6c\xf4\xf2\xa1\x7d\xf9\xe2" - "\xdb\x74\x36\x23\x11\x58\x3f\x93" - "\xe5\xcd\xb5\x90\xeb\xd8\x0c\xb3", - .plen = 32, - .ctext = "\x1d\x2c\x57\xe0\x50\x38\x3d\x41" - "\x2e\x71\xc8\x3b\x92\x43\x58\xaf" - "\x5a\xfb\xad\x8f\xd9\xd5\x8a\x5e" - "\xdb\xf3\xcd\x3a\x2b\xe1\x2c\x1a" - "\xb0\xed\xe3\x0c\x6e\xf9\xf2\xd6" - "\x90\xe6\xb1\x0e\xa5\x8a\xac\xb7", - .clen = 48, - }, { - .key = "\xc8\x4b\x9b\xf5\x01\xba\x8c\xbd" - "\x0e\xa3\x21\x16\x9f\x46\x2a\x63", - .klen = 16, - .iv = "\xd7\x14\x29\x5d\x45\x59\x36\x44" - "\x2e\xd9\x4d\x3b\x9e\x0f\x5b\xe5", - .assoc = "\xe6\xdd\xb8\xc4\x89\xf8\xe0\xca" - "\x4f\x10\x7a\x5f\x9c\xd8\x8b\x66" - "\x3b\x86\xbf\x86\xd4\x50\xe0\xa7" - "\x76\xef\x5c\x72\x0f\x1f\xc3\xd4" - "\xee", - .alen = 33, - .ptext = "\xf5\xa6\x46\x2c\xce\x97\x8a\x51" - "\x6f\x46\xa6\x83\x9b\xa1\xbc\xe8" - "\x05\x36\x42\xa7\x16\xf8\xc1\xad" - "\xa7\xfb\x94\x68\xc5\x37\xab\x8a" - "\x72", - .plen = 33, - .ctext = "\x59\x10\x84\x1c\x83\x4c\x8b\xfc" - "\xfd\x2e\x4b\x46\x84\xff\x78\x4e" - "\x50\xda\x5c\xb9\x61\x1d\xf5\xb9" - "\xfe\xbb\x7f\xae\x8c\xc1\x24\xbd" - "\x8c\x6f\x1f\x9b\xce\xc6\xc1\x37" - "\x08\x06\x5a\xe5\x96\x10\x95\xc2" - "\x5e", - .clen = 49, - }, { - .key = "\x05\x70\xd5\x94\x12\x36\x35\xd8" - "\x8f\x7d\xd3\xa8\x99\x6a\xed\x69", - .klen = 16, - .iv = "\x14\x39\x63\xfc\x56\xd5\xdf\x5f" - "\xaf\xb3\xff\xcc\x98\x33\x1d\xeb", - .assoc = "\x23\x02\xf1\x64\x9a\x73\x89\xe6" - "\xd0\xea\x2c\xf1\x96\xfc\x4e\x6d" - "\x65\x48\xcb\x0a\xda\xf0\x62\xc0" - "\x38\x1d\x3b\x4a\xe9\x7e\x62\xaa" - "\xfd\xc9\x4a\xa9\xa9\x39\x4b\x54" - "\xc8\x0e\x24\x7f\x5e\x10\x7a\x45" - "\x10\x0b\x56\x85\xad\x54\xaa\x66" - "\xa8\x43\xcd\xd4\x9b\xb7\xfa", - .alen = 63, - .ptext = "\x32\xcb\x80\xcc\xde\x12\x33\x6d" - "\xf0\x20\x58\x15\x95\xc6\x7f\xee" - "\x2f\xf9\x4e\x2c\x1b\x98\x43\xc7" - "\x68\x28\x73\x40\x9f\x96\x4a\x60" - "\x80\xf4\x4b\xf4\xc1\x3d\xd0\x93" - "\xcf\x12\xc9\x59\x8f\x7a\x7f\xa8" - "\x1b\xa5\x50\xed\x87\xa9\x72\x59" - "\x9c\x44\xb2\xa4\x99\x98\x34", - .plen = 63, - .ctext = "\x9a\x12\xbc\xdf\x72\xa8\x56\x22" - "\x49\x2d\x07\x92\xfc\x3d\x6d\x5f" - "\xef\x36\x19\xae\x91\xfa\xd6\x63" - "\x46\xea\x8a\x39\x14\x21\xa6\x37" - "\x18\xfc\x97\x3e\x16\xa5\x4d\x39" - "\x45\x2e\x69\xcc\x9c\x5f\xdf\x6d" - "\x5e\xa2\xbf\xac\x83\x32\x72\x52" - "\x58\x58\x23\x40\xfd\xa5\xc2\xe6" - "\xe9\x5a\x50\x98\x00\x58\xc9\x86" - "\x4f\x20\x37\xdb\x7b\x22\xa3", - .clen = 79, - }, { - .key = "\x41\x94\x0e\x33\x22\xb1\xdd\xf4" - "\x10\x57\x85\x39\x93\x8f\xaf\x70", - .klen = 16, - .iv = "\x50\x5d\x9d\x9b\x66\x50\x88\x7b" - "\x30\x8e\xb1\x5e\x92\x58\xe0\xf1", - .assoc = "\x5f\x27\x2b\x03\xaa\xef\x32\x02" - "\x50\xc4\xde\x82\x90\x21\x11\x73" - "\x8f\x0a\xd6\x8f\xdf\x90\xe4\xda" - "\xf9\x4a\x1a\x23\xc3\xdd\x02\x81" - "\x0b\x76\x4f\xd7\x0a\x4b\x5e\x51" - "\xe3\x1d\xb9\xe5\x21\xb9\x8f\xd4" - "\x3d\x72\x3e\x26\x16\xa9\xca\x32" - "\x77\x47\x63\x14\x95\x3d\xe4\x34", - .alen = 64, - .ptext = "\x6e\xf0\xba\x6b\xee\x8e\xdc\x89" - "\x71\xfb\x0a\xa6\x8f\xea\x41\xf4" - "\x5a\xbb\x59\xb0\x20\x38\xc5\xe0" - "\x29\x56\x52\x19\x79\xf5\xe9\x37" - "\x8f\xa1\x50\x23\x22\x4f\xe3\x91" - "\xe9\x21\x5e\xbf\x52\x23\x95\x37" - "\x48\x0c\x38\x8f\xf0\xff\x92\x24" - "\x6b\x47\x49\xe3\x94\x1f\x1e\x01", - .plen = 64, - .ctext = "\xe6\xeb\x92\x5a\x5b\xf0\x2d\xbb" - "\x23\xec\x35\xe3\xae\xc9\xfb\x0b" - "\x90\x14\x46\xeb\xa8\x8d\xb0\x9b" - "\x39\xda\x8b\x48\xec\xb2\x00\x4e" - "\x80\x6f\x46\x4f\x9b\x1e\xbb\x35" - "\xea\x5a\xbc\xa2\x36\xa5\x89\x45" - "\xc2\xd6\xd7\x15\x0b\xf6\x6c\x56" - "\xec\x99\x7d\x61\xb3\x15\x93\xed" - "\x83\x1e\xd9\x48\x84\x0b\x37\xfe" - "\x95\x74\x44\xd5\x54\xa6\x27\x06", - .clen = 80, - }, { - .key = "\x7e\xb9\x48\xd3\x32\x2d\x86\x10" - "\x91\x31\x37\xcb\x8d\xb3\x72\x76", - .klen = 16, - .iv = "\x8d\x82\xd6\x3b\x76\xcc\x30\x97" - "\xb1\x68\x63\xef\x8c\x7c\xa3\xf7", - .assoc = "\x9c\x4b\x65\xa2\xba\x6b\xdb\x1e" - "\xd1\x9e\x90\x13\x8a\x45\xd3\x79" - "\xba\xcd\xe2\x13\xe4\x30\x66\xf4" - "\xba\x78\xf9\xfb\x9d\x3c\xa1\x58" - "\x1a\x22\x53\x05\x6b\x5c\x71\x4f" - "\xfd\x2d\x4d\x4c\xe5\x62\xa5\x63" - "\x6a\xda\x26\xc8\x7f\xff\xea\xfd" - "\x46\x4a\xfa\x53\x8f\xc4\xcd\x68" - "\x58", - .alen = 65, - .ptext = "\xab\x14\xf3\x0a\xfe\x0a\x85\xa5" - "\xf2\xd5\xbc\x38\x89\x0e\x04\xfb" - "\x84\x7d\x65\x34\x25\xd8\x47\xfa" - "\xeb\x83\x31\xf1\x54\x54\x89\x0d" - "\x9d\x4d\x54\x51\x84\x61\xf6\x8e" - "\x03\x31\xf2\x25\x16\xcc\xaa\xc6" - "\x75\x73\x20\x30\x59\x54\xb2\xf0" - "\x3a\x4b\xe0\x23\x8e\xa6\x08\x35" - "\x8a\xdf\x27\xa0\xe4\x60\x99\xae" - "\x8e\x43\xd9\x39\x7b\x10\x40\x67" - "\x5c\x7e\xc9\x70\x63\x34\xca\x59" - "\xfe\x86\xbc\xb7\x9c\x39\xf3\x6d" - "\x6a\x41\x64\x6f\x16\x7f\x65\x7e" - "\x89\x84\x68\xeb\xb0\x51\xbe\x55" - "\x33\x16\x59\x6c\x3b\xef\x88\xad" - "\x2f\xab\xbc\x25\x76\x87\x41\x2f" - "\x36", - .plen = 129, - .ctext = "\x89\x24\x27\x86\xdc\xd7\x6b\xd9" - "\xd1\xcd\xdc\x16\xdd\x2c\xc1\xfb" - "\x52\xb5\xb3\xab\x50\x99\x3f\xa0" - "\x38\xa4\x74\xa5\x04\x15\x63\x05" - "\x8f\x54\x81\x06\x5a\x6b\xa4\x63" - "\x6d\xa7\x21\xcb\xff\x42\x30\x8e" - "\x3b\xd1\xca\x3f\x4b\x1a\xb8\xc3" - "\x42\x01\xe6\xbc\x75\x15\x87\xee" - "\xc9\x8e\x65\x01\xd9\xd8\xb5\x9f" - "\x48\x86\xa6\x5f\x2c\xc7\xb5\xb0" - "\xed\x5d\x14\x7c\x3f\x40\xb1\x0b" - "\x72\xef\x94\x8d\x7a\x85\x56\xe5" - "\x56\x08\x15\x56\xba\xaf\xbd\xf0" - "\x20\xef\xa0\xf6\xa9\xad\xa2\xc9" - "\x1c\x3b\x28\x51\x7e\x77\xb2\x18" - "\x4f\x61\x64\x37\x22\x36\x6d\x78" - "\xed\xed\x35\xe8\x83\xa5\xec\x25" - "\x6b\xff\x5f\x1a\x09\x96\x3d\xdc" - "\x20", - .clen = 145, - }, { - .key = "\xba\xde\x82\x72\x42\xa9\x2f\x2c" - "\x12\x0b\xe9\x5c\x87\xd7\x35\x7c", - .klen = 16, - .iv = "\xc9\xa7\x10\xda\x86\x48\xd9\xb3" - "\x32\x42\x15\x80\x85\xa1\x65\xfe", - .assoc = "\xd8\x70\x9f\x42\xca\xe6\x83\x3a" - "\x52\x79\x42\xa5\x84\x6a\x96\x7f" - "\xe4\x8f\xed\x97\xe9\xd0\xe8\x0d" - "\x7c\xa6\xd8\xd4\x77\x9b\x40\x2e" - "\x28\xce\x57\x34\xcd\x6e\x84\x4c" - "\x17\x3c\xe1\xb2\xa8\x0b\xbb\xf1" - "\x96\x41\x0d\x69\xe8\x54\x0a\xc8" - "\x15\x4e\x91\x92\x89\x4b\xb7\x9b" - "\x21\xf7\x42\x89\xac\x12\x2a\x54" - "\x69\xee\x18\xc7\x8d\xed\xe8\xfd" - "\xbb\x04\x28\xe6\x8a\x3c\x98\xc1" - "\x04\x2d\xa9\xa1\x24\x83\xff\xe9" - "\x55\x7a\xf0\xd1\xf6\x63\x05\xe1" - "\xd9\x1e\x75\x72\xc1\x9f\xae\x32" - "\xe1\x6b\xcd\x9e\x61\x19\x23\x86" - "\xd9\xd2\xaf\x8e\xd5\xd3\xa8\xa9" - "\x51", - .alen = 129, - .ptext = "\xe8\x39\x2d\xaa\x0e\x85\x2d\xc1" - "\x72\xaf\x6e\xc9\x82\x33\xc7\x01" - "\xaf\x40\x70\xb8\x2a\x78\xc9\x14" - "\xac\xb1\x10\xca\x2e\xb3\x28\xe4" - "\xac\xfa\x58\x7f\xe5\x73\x09\x8c" - "\x1d\x40\x87\x8c\xd9\x75\xc0\x55" - "\xa2\xda\x07\xd1\xc2\xa9\xd1\xbb" - "\x09\x4f\x77\x62\x88\x2d\xf2\x68" - "\x54", - .plen = 65, - .ctext = "\x36\x78\xb9\x22\xde\x62\x35\x55" - "\x1a\x7a\xf5\x45\xbc\xd7\x15\x82" - "\x01\xe9\x5a\x07\xea\x46\xaf\x91" - "\xcb\x73\xa5\xee\xe1\xb4\xbf\xc2" - "\xdb\xd2\x9d\x59\xde\xfc\x83\x00" - "\xf5\x46\xac\x97\xd5\x57\xa9\xb9" - "\x1f\x8c\xe8\xca\x68\x8b\x91\x0c" - "\x01\xbe\x0a\xaf\x7c\xf6\x67\xa4" - "\xbf\xbc\x88\x3f\x5d\xd1\xf9\x19" - "\x0f\x9d\xb2\xaf\xb9\x6e\x17\xdf" - "\xa2", - .clen = 81, - }, { - .key = "\xf7\x02\xbb\x11\x52\x24\xd8\x48" - "\x93\xe6\x9b\xee\x81\xfc\xf7\x82", - .klen = 16, - .iv = "\x06\xcc\x4a\x79\x96\xc3\x82\xcf" - "\xb3\x1c\xc7\x12\x7f\xc5\x28\x04", - .assoc = "\x15\x95\xd8\xe1\xda\x62\x2c\x56" - "\xd3\x53\xf4\x36\x7e\x8e\x59\x85" - "\x0e\x51\xf9\x1c\xee\x70\x6a\x27" - "\x3d\xd3\xb7\xac\x51\xfa\xdf\x05", - .alen = 32, - .ptext = "\x24\x5e\x67\x49\x1e\x01\xd6\xdd" - "\xf3\x89\x20\x5b\x7c\x57\x89\x07" - "\xd9\x02\x7c\x3d\x2f\x18\x4b\x2d" - "\x6e\xde\xee\xa2\x08\x12\xc7\xba", - .plen = 32, - .ctext = "\x08\x1b\x95\x0e\x41\x95\x02\x4b" - "\x9c\xbb\xa8\xd0\x7c\xd3\x44\x6e" - "\x89\x14\x33\x70\x0a\xbc\xea\x39" - "\x88\xaa\x2b\xd5\x73\x11\x55\xf5" - "\x33\x33\x9c\xd7\x42\x34\x49\x8e" - "\x2f\x03\x30\x05\x47\xaf\x34", - .clen = 47, - }, { - .key = "\x33\x27\xf5\xb1\x62\xa0\x80\x63" - "\x14\xc0\x4d\x7f\x7b\x20\xba\x89", - .klen = 16, - .iv = "\x42\xf0\x84\x19\xa6\x3f\x2b\xea" - "\x34\xf6\x79\xa3\x79\xe9\xeb\x0a", - .assoc = "\x51\xb9\x12\x80\xea\xde\xd5\x71" - "\x54\x2d\xa6\xc8\x78\xb2\x1b\x8c" - "\x39\x14\x05\xa0\xf3\x10\xec\x41" - "\xff\x01\x95\x84\x2b\x59\x7f\xdb", - .alen = 32, - .ptext = "\x61\x83\xa0\xe8\x2e\x7d\x7f\xf8" - "\x74\x63\xd2\xec\x76\x7c\x4c\x0d" - "\x03\xc4\x88\xc1\x35\xb8\xcd\x47" - "\x2f\x0c\xcd\x7a\xe2\x71\x66\x91", - .plen = 32, - .ctext = "\x97\xca\xf4\xe0\x8d\x89\xbf\x68" - "\x0c\x60\xb9\x27\xdf\xaa\x41\xc6" - "\x25\xd8\xf7\x1f\x10\x15\x48\x61" - "\x4c\x95\x00\xdf\x51\x9b\x7f\xe6" - "\x24\x40\x9e\xbe\x3b\xeb\x1b\x98" - "\xb9\x9c\xe5\xef\xf2\x05", - .clen = 46, - }, { - .key = "\x70\x4c\x2f\x50\x72\x1c\x29\x7f" - "\x95\x9a\xff\x10\x75\x45\x7d\x8f", - .klen = 16, - .iv = "\x7f\x15\xbd\xb8\xb6\xba\xd3\x06" - "\xb5\xd1\x2b\x35\x73\x0e\xad\x10", - .assoc = "\x8e\xde\x4c\x20\xfa\x59\x7e\x8d" - "\xd5\x07\x58\x59\x72\xd7\xde\x92" - "\x63\xd6\x10\x24\xf8\xb0\x6e\x5a" - "\xc0\x2e\x74\x5d\x06\xb8\x1e\xb2", - .alen = 32, - .ptext = "\x9d\xa7\xda\x88\x3e\xf8\x28\x14" - "\xf5\x3e\x85\x7d\x70\xa0\x0f\x13" - "\x2e\x86\x93\x45\x3a\x58\x4f\x61" - "\xf0\x3a\xac\x53\xbc\xd0\x06\x68", - .plen = 32, - .ctext = "\x63\x4c\x2a\x8e\xb4\x6b\x63\x0d" - "\xb5\xec\x9b\x4e\x12\x23\xa3\xcf" - "\x1a\x5a\x70\x15\x5a\x10\x40\x51" - "\xca\x47\x4c\x9d\xc9\x97\xf4\x77" - "\xdb\xc8\x10\x2d\xdc\x65\x20\x3f", - .clen = 40, - }, { - .key = "\xac\x70\x69\xef\x82\x97\xd2\x9b" - "\x15\x74\xb1\xa2\x6f\x69\x3f\x95", - .klen = 16, - .iv = "\xbb\x3a\xf7\x57\xc6\x36\x7c\x22" - "\x36\xab\xde\xc6\x6d\x32\x70\x17", - .assoc = "\xcb\x03\x85\xbf\x0a\xd5\x26\xa9" - "\x56\xe1\x0a\xeb\x6c\xfb\xa1\x98" - "\x8d\x98\x1c\xa8\xfe\x50\xf0\x74" - "\x81\x5c\x53\x35\xe0\x17\xbd\x88", - .alen = 32, - .ptext = "\xda\xcc\x14\x27\x4e\x74\xd1\x30" - "\x76\x18\x37\x0f\x6a\xc4\xd1\x1a" - "\x58\x49\x9f\xc9\x3f\xf8\xd1\x7a" - "\xb2\x67\x8b\x2b\x96\x2f\xa5\x3e", - .plen = 32, - .ctext = "\xf1\x62\x44\xc7\x5f\x19\xca\x43" - "\x47\x2c\xaf\x68\x82\xbd\x51\xef" - "\x3d\x65\xd8\x45\x2d\x06\x07\x78" - "\x08\x2e\xb3\x23\xcd\x81\x12\x55" - "\x1a", - .clen = 33, - }, { - .key = "\xe9\x95\xa2\x8f\x93\x13\x7b\xb7" - "\x96\x4e\x63\x33\x69\x8d\x02\x9b" - "\x23\xf9\x22\xeb\x80\xa0\xb1\x81" - "\xe2\x73\xc3\x21\x4d\x47\x8d\xf4", - .klen = 32, - .iv = "\xf8\x5e\x31\xf7\xd7\xb2\x25\x3e" - "\xb7\x85\x90\x58\x67\x57\x33\x1d", - .assoc = "", - .alen = 0, - .ptext = "", - .plen = 0, - .ctext = "\xdf\x2f\x83\xc0\x45\x4a\x2c\xcf" - "\xb9\xd2\x41\xf6\x80\xa1\x52\x70", - .clen = 16, - }, { - .key = "\x25\xba\xdc\x2e\xa3\x8f\x24\xd3" - "\x17\x29\x15\xc5\x63\xb2\xc5\xa1" - "\x4d\xbc\x2d\x6f\x85\x40\x33\x9a" - "\xa3\xa0\xa1\xfa\x27\xa6\x2c\xca", - .klen = 32, - .iv = "\x34\x83\x6a\x96\xe7\x2d\xce\x5a" - "\x38\x5f\x42\xe9\x61\x7b\xf5\x23", - .assoc = "", - .alen = 0, - .ptext = "\x53", - .plen = 1, - .ctext = "\x01\xd8\x55\x3c\xc0\x5a\x4b\xc7" - "\x01\xf4\x08\xe3\x0d\xf7\xf0\x78" - "\x53", - .clen = 17, - }, { - .key = "\x62\xdf\x16\xcd\xb3\x0a\xcc\xef" - "\x98\x03\xc7\x56\x5d\xd6\x87\xa8" - "\x77\x7e\x39\xf3\x8a\xe0\xb5\xb4" - "\x65\xce\x80\xd2\x01\x05\xcb\xa1", - .klen = 32, - .iv = "\x71\xa8\xa4\x35\xf7\xa9\x76\x75" - "\xb8\x39\xf4\x7a\x5b\x9f\xb8\x29", - .assoc = "", - .alen = 0, - .ptext = "\x8f\x3a\xc1\x05\x7f\xe7\xcb\x83" - "\xf9\xa6\x4d\xc3\x58\x31\x19\x2c" - "\xd7\x90\xc2\x56\x4e\xd8\x57\xc7" - "\xf6\xf0\x27\xb4\x25\x4c\x83", - .plen = 31, - .ctext = "\xc2\x4b\x41\x0f\x2d\xb9\x62\x07" - "\xff\x8e\x74\xf8\xa1\xa6\xd5\x37" - "\xa5\x64\x31\x5c\xca\x73\x9b\x43" - "\xe6\x70\x63\x46\x95\xcb\xf7\xb5" - "\x20\x8c\x75\x7a\x2a\x17\x2f\xa9" - "\xb8\x4d\x11\x42\xd1\xf8\xf1", - .clen = 47, - }, { - .key = "\x9e\x03\x4f\x6d\xc3\x86\x75\x0a" - "\x19\xdd\x79\xe8\x57\xfb\x4a\xae" - "\xa2\x40\x45\x77\x90\x80\x37\xce" - "\x26\xfb\x5f\xaa\xdb\x64\x6b\x77", - .klen = 32, - .iv = "\xae\xcc\xde\xd5\x07\x25\x1f\x91" - "\x39\x14\xa6\x0c\x55\xc4\x7b\x30", - .assoc = "", - .alen = 0, - .ptext = "\xcc\x5f\xfb\xa4\x8f\x63\x74\x9f" - "\x7a\x81\xff\x55\x52\x56\xdc\x33" - "\x01\x52\xcd\xdb\x53\x78\xd9\xe1" - "\xb7\x1d\x06\x8d\xff\xab\x22\x98", - .plen = 32, - .ctext = "\xbb\x01\x7c\xd1\x2c\x33\x7b\x37" - "\x0a\xee\xc4\x30\x19\xd7\x3a\x6f" - "\xf8\x2b\x67\xf5\x3b\x84\x87\x2a" - "\xfb\x07\x7a\x82\xb5\xe4\x85\x26" - "\x1e\xa8\xe5\x04\x54\xce\xe5\x5f" - "\xb5\x3f\xc1\xd5\x7f\xbd\xd2\xa6", - .clen = 48, - }, { - .key = "\xdb\x28\x89\x0c\xd3\x01\x1e\x26" - "\x9a\xb7\x2b\x79\x51\x1f\x0d\xb4" - "\xcc\x03\x50\xfc\x95\x20\xb9\xe7" - "\xe8\x29\x3e\x83\xb5\xc3\x0a\x4e", - .klen = 32, - .iv = "\xea\xf1\x18\x74\x17\xa0\xc8\xad" - "\xba\xee\x58\x9d\x4f\xe8\x3d\x36", - .assoc = "", - .alen = 0, - .ptext = "\x08\x84\x34\x44\x9f\xde\x1c\xbb" - "\xfb\x5b\xb1\xe6\x4c\x7a\x9f\x39" - "\x2c\x14\xd9\x5f\x59\x18\x5b\xfb" - "\x79\x4b\xe5\x65\xd9\x0a\xc1\x6f" - "\x2e", - .plen = 33, - .ctext = "\xc2\xf4\x40\x55\xf9\x59\xff\x73" - "\x08\xf5\x98\x92\x0c\x7b\x35\x9a" - "\xa8\xf4\x42\x7e\x6f\x93\xca\x22" - "\x23\x06\x1e\xf8\x89\x22\xf4\x46" - "\x7c\x7c\x67\x75\xab\xe5\x75\xaa" - "\x15\xd7\x83\x19\xfd\x31\x59\x5b" - "\x32", - .clen = 49, - }, { - .key = "\x17\x4d\xc3\xab\xe3\x7d\xc7\x42" - "\x1b\x91\xdd\x0a\x4b\x43\xcf\xba" - "\xf6\xc5\x5c\x80\x9a\xc0\x3b\x01" - "\xa9\x56\x1d\x5b\x8f\x22\xa9\x25", - .klen = 32, - .iv = "\x27\x16\x51\x13\x27\x1c\x71\xc9" - "\x3b\xc8\x0a\x2f\x49\x0c\x00\x3c", - .assoc = "", - .alen = 0, - .ptext = "\x45\xa8\x6e\xe3\xaf\x5a\xc5\xd7" - "\x7c\x35\x63\x77\x46\x9f\x61\x3f" - "\x56\xd7\xe4\xe3\x5e\xb8\xdc\x14" - "\x3a\x79\xc4\x3e\xb3\x69\x61\x46" - "\x3c\xb6\x83\x4e\xb4\x26\xc7\x73" - "\x22\xda\x52\x8b\x7d\x11\x98\xea" - "\x62\xe1\x14\x1e\xdc\xfe\x0f\xad" - "\x20\x76\x5a\xdc\x4e\x71\x13", - .plen = 63, - .ctext = "\xc9\x82\x3b\x4b\x87\x84\xa5\xdb" - "\xa0\x8c\xd3\x3e\x7f\x8d\xe8\x28" - "\x2a\xdc\xfa\x01\x84\x87\x9a\x70" - "\x81\x75\x37\x0a\xd2\x75\xa9\xb6" - "\x21\x72\xee\x7e\x65\x95\xe5\xcc" - "\x01\xb7\x39\xa6\x51\x15\xca\xff" - "\x61\xdc\x97\x38\xcc\xf4\xca\xc7" - "\x83\x9b\x05\x11\x72\x60\xf0\xb4" - "\x7e\x06\xab\x0a\xc0\xbb\x59\x23" - "\xaa\x2d\xfc\x4e\x35\x05\x59", - .clen = 79, - }, { - .key = "\x54\x71\xfd\x4b\xf3\xf9\x6f\x5e" - "\x9c\x6c\x8f\x9c\x45\x68\x92\xc1" - "\x21\x87\x67\x04\x9f\x60\xbd\x1b" - "\x6a\x84\xfc\x34\x6a\x81\x48\xfb", - .klen = 32, - .iv = "\x63\x3b\x8b\xb3\x37\x98\x1a\xe5" - "\xbc\xa2\xbc\xc0\x43\x31\xc2\x42", - .assoc = "", - .alen = 0, - .ptext = "\x81\xcd\xa8\x82\xbf\xd6\x6e\xf3" - "\xfd\x0f\x15\x09\x40\xc3\x24\x45" - "\x81\x99\xf0\x67\x63\x58\x5e\x2e" - "\xfb\xa6\xa3\x16\x8d\xc8\x00\x1c" - "\x4b\x62\x87\x7c\x15\x38\xda\x70" - "\x3d\xea\xe7\xf2\x40\xba\xae\x79" - "\x8f\x48\xfc\xbf\x45\x53\x2e\x78" - "\xef\x79\xf0\x1b\x49\xf7\xfd\x9c", - .plen = 64, - .ctext = "\x11\x7c\x7d\xef\xce\x29\x95\xec" - "\x7e\x9f\x42\xa6\x26\x07\xa1\x75" - "\x2f\x4e\x09\x9a\xf6\x6b\xc2\xfa" - "\x0d\xd0\x17\xdc\x25\x1e\x9b\xdc" - "\x5f\x8c\x1c\x60\x15\x4f\x9b\x20" - "\x7b\xff\xcd\x82\x60\x84\xf4\xa5" - "\x20\x9a\x05\x19\x5b\x02\x0a\x72" - "\x43\x11\x26\x58\xcf\xc5\x41\xcf" - "\x13\xcc\xde\x32\x92\xfa\x86\xf2" - "\xaf\x16\xe8\x8f\xca\xb6\xfd\x54", - .clen = 80, - }, { - .key = "\x90\x96\x36\xea\x03\x74\x18\x7a" - "\x1d\x46\x42\x2d\x3f\x8c\x54\xc7" - "\x4b\x4a\x73\x89\xa4\x00\x3f\x34" - "\x2c\xb1\xdb\x0c\x44\xe0\xe8\xd2", - .klen = 32, - .iv = "\xa0\x5f\xc5\x52\x47\x13\xc2\x01" - "\x3d\x7c\x6e\x52\x3d\x55\x85\x48", - .assoc = "\xaf", - .alen = 1, - .ptext = "", - .plen = 0, - .ctext = "\x9b\xc5\x3b\x20\x0a\x88\x56\xbe" - "\x69\xdf\xc4\xc4\x02\x46\x3a\xf0", - .clen = 16, - }, { - .key = "\xcd\xbb\x70\x89\x13\xf0\xc1\x95" - "\x9e\x20\xf4\xbf\x39\xb1\x17\xcd" - "\x76\x0c\x7f\x0d\xa9\xa0\xc1\x4e" - "\xed\xdf\xb9\xe4\x1e\x3f\x87\xa8", - .klen = 32, - .iv = "\xdc\x84\xfe\xf1\x58\x8f\x6b\x1c" - "\xbe\x57\x20\xe3\x37\x7a\x48\x4f", - .assoc = "\xeb\x4d\x8d\x59\x9c\x2e\x15\xa3" - "\xde\x8d\x4d\x07\x36\x43\x78\xd0" - "\x0b\x6d\x84\x4f\x2c\xf0\x82\x5b" - "\x4e\xf6\x29\xd1\x8b\x6f\x56", - .alen = 31, - .ptext = "", - .plen = 0, - .ctext = "\xe0\x6d\xa1\x07\x98\x2f\x40\x2d" - "\x2e\x9a\xd6\x61\x43\xc0\x74\x69", - .clen = 16, - }, { - .key = "\x0a\xe0\xaa\x29\x24\x6c\x6a\xb1" - "\x1f\xfa\xa6\x50\x33\xd5\xda\xd3" - "\xa0\xce\x8a\x91\xae\x40\x43\x68" - "\xae\x0d\x98\xbd\xf8\x9e\x26\x7f", - .klen = 32, - .iv = "\x19\xa9\x38\x91\x68\x0b\x14\x38" - "\x3f\x31\xd2\x74\x31\x9e\x0a\x55", - .assoc = "\x28\x72\xc7\xf8\xac\xaa\xbe\xbf" - "\x5f\x67\xff\x99\x30\x67\x3b\xd6" - "\x35\x2f\x90\xd3\x31\x90\x04\x74" - "\x0f\x23\x08\xa9\x65\xce\xf6\xea", - .alen = 32, - .ptext = "", - .plen = 0, - .ctext = "\xb9\x57\x13\x3e\x82\x31\x61\x65" - "\x0d\x7f\x6c\x96\x93\x5c\x50\xe2", - .clen = 16, - }, { - .key = "\x46\x04\xe3\xc8\x34\xe7\x12\xcd" - "\xa0\xd4\x58\xe2\x2d\xf9\x9c\xda" - "\xca\x91\x96\x15\xb4\xe0\xc5\x81" - "\x70\x3a\x77\x95\xd2\xfd\xc5\x55", - .klen = 32, - .iv = "\x55\xcd\x72\x30\x78\x86\xbd\x54" - "\xc0\x0b\x84\x06\x2b\xc2\xcd\x5b", - .assoc = "\x64\x97\x00\x98\xbc\x25\x67\xdb" - "\xe0\x41\xb1\x2a\x2a\x8c\xfe\xdd" - "\x5f\xf2\x9c\x58\x36\x30\x86\x8e" - "\xd1\x51\xe6\x81\x3f\x2d\x95\xc1" - "\x01", - .alen = 33, - .ptext = "", - .plen = 0, - .ctext = "\x81\x96\x34\xde\xbb\x36\xdd\x3e" - "\x4e\x5e\xcb\x44\x21\xb8\x3f\xf1", - .clen = 16, - }, { - .key = "\x83\x29\x1d\x67\x44\x63\xbb\xe9" - "\x20\xaf\x0a\x73\x27\x1e\x5f\xe0" - "\xf5\x53\xa1\x9a\xb9\x80\x47\x9b" - "\x31\x68\x56\x6e\xac\x5c\x65\x2c", - .klen = 32, - .iv = "\x92\xf2\xac\xcf\x88\x02\x65\x70" - "\x41\xe5\x36\x97\x25\xe7\x90\x61", - .assoc = "\xa1\xbb\x3a\x37\xcc\xa1\x10\xf7" - "\x61\x1c\x63\xbc\x24\xb0\xc0\xe3" - "\x8a\xb4\xa7\xdc\x3b\xd0\x08\xa8" - "\x92\x7f\xc5\x5a\x19\x8c\x34\x97" - "\x0f\x95\x9b\x18\xe4\x8d\xb4\x24" - "\xb9\x33\x28\x18\xe1\x9d\x14\xe0" - "\x64\xb2\x89\x7d\x78\xa8\x05\x7e" - "\x07\x8c\xfc\x88\x2d\xb8\x53", - .alen = 63, - .ptext = "", - .plen = 0, - .ctext = "\x2e\x99\xb6\x79\x57\x56\x80\x36" - "\x8e\xc4\x1c\x12\x7d\x71\x36\x0c", - .clen = 16, - }, { - .key = "\xbf\x4e\x57\x07\x54\xdf\x64\x05" - "\xa1\x89\xbc\x04\x21\x42\x22\xe6" - "\x1f\x15\xad\x1e\xbe\x20\xc9\xb4" - "\xf3\x95\x35\x46\x86\xbb\x04\x03", - .klen = 32, - .iv = "\xce\x17\xe5\x6f\x98\x7e\x0e\x8c" - "\xc2\xbf\xe8\x29\x1f\x0b\x52\x68", - .assoc = "\xdd\xe0\x74\xd6\xdc\x1d\xb8\x13" - "\xe2\xf6\x15\x4d\x1e\xd4\x83\xe9" - "\xb4\x76\xb3\x60\x40\x70\x8a\xc1" - "\x53\xac\xa4\x32\xf3\xeb\xd3\x6e" - "\x1e\x42\xa0\x46\x45\x9f\xc7\x22" - "\xd3\x43\xbc\x7e\xa5\x47\x2a\x6f" - "\x91\x19\x70\x1e\xe1\xfe\x25\x49" - "\xd6\x8f\x93\xc7\x28\x3f\x3d\x03", - .alen = 64, - .ptext = "", - .plen = 0, - .ctext = "\x7b\x25\x3d\x47\xd4\xa7\x08\xce" - "\x3b\x89\x40\x36\xba\x6d\x0e\xa2", - .clen = 16, - }, { - .key = "\xfc\x72\x90\xa6\x64\x5a\x0d\x21" - "\x22\x63\x6e\x96\x1b\x67\xe4\xec" - "\x49\xd7\xb9\xa2\xc3\xc0\x4b\xce" - "\xb4\xc3\x14\x1e\x61\x1a\xa3\xd9", - .klen = 32, - .iv = "\x0b\x3c\x1f\x0e\xa8\xf9\xb7\xa7" - "\x42\x9a\x9a\xba\x19\x30\x15\x6e", - .assoc = "\x1a", - .alen = 1, - .ptext = "\x29", - .plen = 1, - .ctext = "\xe6\x09\x6f\x95\x9a\x18\xc8\xf6" - "\x17\x75\x81\x16\xdf\x26\xff\x67" - "\x92", - .clen = 17, - }, { - .key = "\x38\x97\xca\x45\x74\xd6\xb6\x3c" - "\xa3\x3d\x20\x27\x15\x8b\xa7\xf2" - "\x74\x9a\xc4\x27\xc8\x60\xcd\xe8" - "\x75\xf0\xf2\xf7\x3b\x79\x42\xb0", - .klen = 32, - .iv = "\x47\x60\x59\xad\xb8\x75\x60\xc3" - "\xc3\x74\x4c\x4c\x13\x54\xd8\x74", - .assoc = "\x56\x29\xe7\x15\xfc\x14\x0a\x4a" - "\xe4\xaa\x79\x70\x12\x1d\x08\xf6" - "\x09\xfb\xca\x69\x4b\xb0\x8e\xf5" - "\xd6\x07\x62\xe3\xa8\xa9\x12", - .alen = 31, - .ptext = "\x66\xf3\x75\x7d\x40\xb3\xb4\xd1" - "\x04\xe1\xa6\x94\x10\xe6\x39\x77" - "\xd3\xac\x4d\x8a\x8c\x58\x6e\xfb" - "\x06\x13\x9a\xd9\x5e\xc0\xfa", - .plen = 31, - .ctext = "\x82\xc0\x56\xf0\xd7\xc4\xc9\xfd" - "\x3c\xd1\x2a\xd4\x15\x86\x9d\xda" - "\xea\x6c\x6f\xa1\x33\xb0\x7a\x01" - "\x57\xe7\xf3\x7b\x73\xe7\x54\x10" - "\xc6\x91\xe2\xc6\xa0\x69\xe7\xe6" - "\x76\xc3\xf5\x3a\x76\xfd\x4a", - .clen = 47, - }, { - .key = "\x75\xbc\x04\xe5\x84\x52\x5e\x58" - "\x24\x17\xd2\xb9\x0e\xaf\x6a\xf9" - "\x9e\x5c\xd0\xab\xcd\x00\x4f\x01" - "\x37\x1e\xd1\xcf\x15\xd8\xe2\x86", - .klen = 32, - .iv = "\x84\x85\x92\x4d\xc8\xf1\x08\xdf" - "\x44\x4e\xff\xdd\x0d\x78\x9a\x7a", - .assoc = "\x93\x4e\x21\xb4\x0c\x90\xb3\x66" - "\x65\x84\x2b\x01\x0b\x42\xcb\xfc" - "\x33\xbd\xd6\xed\x50\x50\x10\x0e" - "\x97\x35\x41\xbb\x82\x08\xb1\xf2", - .alen = 32, - .ptext = "\xa2\x17\xaf\x1c\x50\x2e\x5d\xed" - "\x85\xbb\x58\x26\x0a\x0b\xfc\x7d" - "\xfe\x6e\x59\x0e\x91\xf8\xf0\x15" - "\xc8\x40\x78\xb1\x38\x1f\x99\xa7", - .plen = 32, - .ctext = "\x01\x47\x8e\x6c\xf6\x64\x89\x3a" - "\x71\xce\xe4\xaa\x45\x70\xe6\x84" - "\x62\x48\x08\x64\x86\x6a\xdf\xec" - "\xb4\xa0\xfb\x34\x03\x0c\x19\xf4" - "\x2b\x7b\x36\x73\xec\x54\xa9\x1e" - "\x30\x85\xdb\xe4\xac\xe9\x2c\xca", - .clen = 48, - }, { - .key = "\xb1\xe1\x3e\x84\x94\xcd\x07\x74" - "\xa5\xf2\x84\x4a\x08\xd4\x2c\xff" - "\xc8\x1e\xdb\x2f\xd2\xa0\xd1\x1b" - "\xf8\x4c\xb0\xa8\xef\x37\x81\x5d", - .klen = 32, - .iv = "\xc0\xaa\xcc\xec\xd8\x6c\xb1\xfb" - "\xc5\x28\xb1\x6e\x07\x9d\x5d\x81", - .assoc = "\xd0\x73\x5a\x54\x1d\x0b\x5b\x82" - "\xe5\x5f\xdd\x93\x05\x66\x8e\x02" - "\x5e\x80\xe1\x71\x55\xf0\x92\x28" - "\x59\x62\x20\x94\x5c\x67\x50\xc8" - "\x58", - .alen = 33, - .ptext = "\xdf\x3c\xe9\xbc\x61\xaa\x06\x09" - "\x06\x95\x0a\xb7\x04\x2f\xbe\x84" - "\x28\x30\x64\x92\x96\x98\x72\x2e" - "\x89\x6e\x57\x8a\x13\x7e\x38\x7e" - "\xdb", - .plen = 33, - .ctext = "\x85\xe0\xf8\x0f\x8e\x49\xe3\x60" - "\xcb\x4a\x54\x94\xcf\xf5\x7e\x34" - "\xe9\xf8\x80\x65\x53\xd0\x72\x70" - "\x4f\x7d\x9d\xd1\x15\x6f\xb9\x2c" - "\xfa\xe8\xdd\xac\x2e\xe1\x3f\x67" - "\x63\x0f\x1a\x59\xb7\x89\xdb\xf4" - "\xc3", - .clen = 49, - }, { - .key = "\xee\x05\x77\x23\xa5\x49\xb0\x90" - "\x26\xcc\x36\xdc\x02\xf8\xef\x05" - "\xf3\xe1\xe7\xb3\xd8\x40\x53\x35" - "\xb9\x79\x8f\x80\xc9\x96\x20\x33", - .klen = 32, - .iv = "\xfd\xce\x06\x8b\xe9\xe8\x5a\x17" - "\x46\x02\x63\x00\x01\xc1\x20\x87", - .assoc = "\x0c\x98\x94\xf3\x2d\x87\x04\x9e" - "\x66\x39\x8f\x24\xff\x8a\x50\x08" - "\x88\x42\xed\xf6\x5a\x90\x14\x42" - "\x1a\x90\xfe\x6c\x36\xc6\xf0\x9f" - "\x66\xa0\xb5\x2d\x2c\xf8\x25\x15" - "\x55\x90\xa2\x7e\x77\x94\x96\x3a" - "\x71\x1c\xf7\x44\xee\xa8\xc3\x42" - "\xe2\xa3\x84\x04\x0b\xe1\xce", - .alen = 63, - .ptext = "\x1b\x61\x23\x5b\x71\x26\xae\x25" - "\x87\x6f\xbc\x49\xfe\x53\x81\x8a" - "\x53\xf2\x70\x17\x9b\x38\xf4\x48" - "\x4b\x9b\x36\x62\xed\xdd\xd8\x54" - "\xea\xcb\xb6\x79\x45\xfc\xaa\x54" - "\x5c\x94\x47\x58\xa7\xff\x9c\x9e" - "\x7c\xb6\xf1\xac\xc8\xfd\x8b\x35" - "\xd5\xa4\x6a\xd4\x09\xc2\x08", - .plen = 63, - .ctext = "\x00\xe5\x5b\x87\x5c\x20\x22\x8a" - "\xda\x1f\xd3\xff\xbb\xb2\xb0\xf8" - "\xef\xe9\xeb\x9e\x7c\x80\xf4\x2b" - "\x59\xc0\x79\xbc\x17\xa0\x15\x01" - "\xf5\x72\xfb\x5a\xe7\xaf\x07\xe3" - "\x1b\x49\x21\x34\x23\x63\x55\x5e" - "\xee\x4f\x34\x17\xfa\xfe\xa5\x0c" - "\xed\x0b\x23\xea\x9b\xda\x57\x2f" - "\xf6\xa9\xae\x0d\x4e\x40\x96\x45" - "\x7f\xfa\xf0\xbf\xc4\x98\x78", - .clen = 79, - }, { - .key = "\x2a\x2a\xb1\xc3\xb5\xc5\x59\xac" - "\xa7\xa6\xe8\x6d\xfc\x1d\xb2\x0b" - "\x1d\xa3\xf3\x38\xdd\xe0\xd5\x4e" - "\x7b\xa7\x6e\x58\xa3\xf5\xbf\x0a", - .klen = 32, - .iv = "\x39\xf3\x3f\x2b\xf9\x64\x03\x33" - "\xc7\xdd\x15\x91\xfb\xe6\xe2\x8d", - .assoc = "\x49\xbc\xce\x92\x3d\x02\xad\xba" - "\xe7\x13\x41\xb6\xf9\xaf\x13\x0f" - "\xb2\x04\xf8\x7a\x5f\x30\x96\x5b" - "\xdc\xbd\xdd\x44\x10\x25\x8f\x75" - "\x75\x4d\xb9\x5b\x8e\x0a\x38\x13" - "\x6f\x9f\x36\xe4\x3a\x3e\xac\xc9" - "\x9d\x83\xde\xe5\x57\xfd\xe3\x0e" - "\xb1\xa7\x1b\x44\x05\x67\xb7\x37", - .alen = 64, - .ptext = "\x58\x85\x5c\xfa\x81\xa1\x57\x40" - "\x08\x4a\x6e\xda\xf8\x78\x44\x90" - "\x7d\xb5\x7b\x9b\xa1\xd8\x76\x62" - "\x0c\xc9\x15\x3b\xc7\x3c\x77\x2b" - "\xf8\x78\xba\xa7\xa6\x0e\xbd\x52" - "\x76\xa3\xdc\xbe\x6b\xa8\xb1\x2d" - "\xa9\x1d\xd8\x4e\x31\x53\xab\x00" - "\xa5\xa7\x01\x13\x04\x49\xf2\x04", - .plen = 64, - .ctext = "\x28\xdd\xb9\x4a\x12\xc7\x0a\xe1" - "\x58\x06\x1a\x9b\x8c\x67\xdf\xeb" - "\x35\x35\x60\x9d\x06\x40\x65\xc1" - "\x93\xe8\xb3\x82\x50\x29\xdd\xb5" - "\x2b\xcb\xde\x18\x78\x6b\x42\xbe" - "\x6d\x24\xd0\xb2\x7d\xd7\x08\x8f" - "\x4a\x18\x98\xad\x8c\xf2\x97\xb4" - "\xf4\x77\xe4\xbf\x41\x3b\xc4\x06" - "\xce\x9e\x34\x81\xf0\x89\x11\x13" - "\x02\x65\xa1\x7c\xdf\x07\x33\x06", - .clen = 80, - }, { - .key = "\x67\x4f\xeb\x62\xc5\x40\x01\xc7" - "\x28\x80\x9a\xfe\xf6\x41\x74\x12" - "\x48\x65\xfe\xbc\xe2\x80\x57\x68" - "\x3c\xd4\x4d\x31\x7d\x54\x5f\xe1", - .klen = 32, - .iv = "\x76\x18\x79\xca\x09\xdf\xac\x4e" - "\x48\xb7\xc7\x23\xf5\x0a\xa5\x93", - .assoc = "\x85\xe1\x08\x32\x4d\x7e\x56\xd5" - "\x68\xed\xf3\x47\xf3\xd3\xd6\x15" - "\xdd\xc7\x04\xfe\x64\xd0\x18\x75" - "\x9d\xeb\xbc\x1d\xea\x84\x2e\x4c" - "\x83\xf9\xbe\x8a\xef\x1c\x4b\x10" - "\x89\xaf\xcb\x4b\xfe\xe7\xc1\x58" - "\xca\xea\xc6\x87\xc0\x53\x03\xd9" - "\x80\xaa\xb2\x83\xff\xee\xa1\x6a" - "\x04", - .alen = 65, - .ptext = "\x94\xaa\x96\x9a\x91\x1d\x00\x5c" - "\x88\x24\x20\x6b\xf2\x9c\x06\x96" - "\xa7\x77\x87\x1f\xa6\x78\xf8\x7b" - "\xcd\xf6\xf4\x13\xa1\x9b\x16\x02" - "\x07\x24\xbf\xd5\x08\x20\xd0\x4f" - "\x90\xb3\x70\x24\x2f\x51\xc7\xbb" - "\xd6\x84\xc0\xef\x9a\xa8\xca\xcc" - "\x74\xab\x97\x53\xfe\xd0\xdb\x37" - "\x37\x6a\x0e\x9f\x3f\xa3\x2a\xe3" - "\x1b\x34\x6d\x51\x72\x2b\x17\xe7" - "\x4d\xaa\x2c\x18\xda\xa3\x33\x89" - "\x2a\x9f\xf4\xd2\xed\x76\x3d\x3f" - "\x3c\x15\x9d\x8e\x4f\x3c\x27\xb0" - "\x42\x3f\x2f\x8a\xd4\xc2\x10\xb2" - "\x27\x7f\xe3\x34\x80\x02\x49\x4b" - "\x07\x68\x22\x2a\x88\x25\x53\xb2" - "\x2f", - .plen = 129, - .ctext = "\x85\x39\x69\x35\xfb\xf9\xb0\xa6" - "\x85\x43\x88\xd0\xd7\x78\x60\x19" - "\x3e\x1f\xb1\xa4\xd6\xc5\x96\xec" - "\xf7\x84\x85\xc7\x27\x0f\x74\x57" - "\x28\x9e\xdd\x90\x3c\x43\x12\xc5" - "\x51\x3d\x39\x8f\xa5\xf4\xe0\x0b" - "\x57\x04\xf1\x6d\xfe\x9b\x84\x27" - "\xe8\xeb\x4d\xda\x02\x0a\xc5\x49" - "\x1a\x55\x5e\x50\x56\x4d\x94\xda" - "\x20\xf8\x12\x54\x50\xb3\x11\xda" - "\xed\x44\x27\x67\xd5\xd1\x8b\x4b" - "\x38\x67\x56\x65\x59\xda\xe6\x97" - "\x81\xae\x2f\x92\x3b\xae\x22\x1c" - "\x91\x59\x38\x18\x00\xe8\xba\x92" - "\x04\x19\x56\xdf\xb0\x82\xeb\x6f" - "\x2e\xdb\x54\x3c\x4b\xbb\x60\x90" - "\x4c\x50\x10\x62\xba\x7a\xb1\x68" - "\x37\xd7\x87\x4e\xe4\x66\x09\x1f" - "\xa5", - .clen = 145, - }, { - .key = "\xa3\x73\x24\x01\xd5\xbc\xaa\xe3" - "\xa9\x5a\x4c\x90\xf0\x65\x37\x18" - "\x72\x28\x0a\x40\xe7\x20\xd9\x82" - "\xfe\x02\x2b\x09\x57\xb3\xfe\xb7", - .klen = 32, - .iv = "\xb3\x3d\xb3\x69\x19\x5b\x54\x6a" - "\xc9\x91\x79\xb4\xef\x2e\x68\x99", - .assoc = "\xc2\x06\x41\xd1\x5d\xfa\xff\xf1" - "\xe9\xc7\xa5\xd9\xed\xf8\x98\x1b" - "\x07\x89\x10\x82\x6a\x70\x9a\x8f" - "\x5e\x19\x9b\xf5\xc5\xe3\xcd\x22" - "\x92\xa5\xc2\xb8\x51\x2e\x5e\x0e" - "\xa4\xbe\x5f\xb1\xc1\x90\xd7\xe7" - "\xf7\x52\xae\x28\x29\xa8\x22\xa4" - "\x4f\xae\x48\xc2\xfa\x75\x8b\x9e" - "\xce\x83\x2a\x88\x07\x55\xbb\x89" - "\xf6\xdf\xac\xdf\x83\x08\xbf\x7d" - "\xac\x30\x8b\x8e\x02\xac\x00\xf1" - "\x30\x46\xe1\xbc\x75\xbf\x49\xbb" - "\x26\x4e\x29\xf0\x2f\x21\xc6\x13" - "\x92\xd9\x3d\x11\xe4\x10\x00\x8e" - "\xd4\xd4\x58\x65\xa6\x2b\xe3\x25" - "\xb1\x8f\x15\x93\xe7\x71\xb9\x2c" - "\x4b", - .alen = 129, - .ptext = "\xd1\xcf\xd0\x39\xa1\x99\xa9\x78" - "\x09\xfe\xd2\xfd\xec\xc1\xc9\x9d" - "\xd2\x39\x93\xa3\xab\x18\x7a\x95" - "\x8f\x24\xd3\xeb\x7b\xfa\xb5\xd8" - "\x15\xd1\xc3\x04\x69\x32\xe3\x4d" - "\xaa\xc2\x04\x8b\xf2\xfa\xdc\x4a" - "\x02\xeb\xa8\x90\x03\xfd\xea\x97" - "\x43\xaf\x2e\x92\xf8\x57\xc5\x6a" - "\x00", - .plen = 65, - .ctext = "\x7d\xde\x53\x22\xe4\x23\x3b\x30" - "\x78\xde\x35\x90\x7a\xd9\x0b\x93" - "\xf6\x0e\x0b\xed\x40\xee\x10\x9c" - "\x96\x3a\xd3\x34\xb2\xd0\x67\xcf" - "\x63\x7f\x2d\x0c\xcf\x96\xec\x64" - "\x1a\x87\xcc\x7d\x2c\x5e\x81\x4b" - "\xd2\x8f\x4c\x7c\x00\xb1\xb4\xe0" - "\x87\x4d\xb1\xbc\xd8\x78\x2c\x17" - "\xf2\x3b\xd8\x28\x40\xe2\x76\xf6" - "\x20\x13\x83\x46\xaf\xff\xe3\x0f" - "\x72", - .clen = 81, - }, { - .key = "\xe0\x98\x5e\xa1\xe5\x38\x53\xff" - "\x2a\x35\xfe\x21\xea\x8a\xfa\x1e" - "\x9c\xea\x15\xc5\xec\xc0\x5b\x9b" - "\xbf\x2f\x0a\xe1\x32\x12\x9d\x8e", - .klen = 32, - .iv = "\xef\x61\xed\x08\x29\xd7\xfd\x86" - "\x4a\x6b\x2b\x46\xe9\x53\x2a\xa0", - .assoc = "\xfe\x2a\x7b\x70\x6d\x75\xa7\x0d" - "\x6a\xa2\x57\x6a\xe7\x1c\x5b\x21" - "\x31\x4b\x1b\x07\x6f\x10\x1c\xa8" - "\x20\x46\x7a\xce\x9f\x42\x6d\xf9", - .alen = 32, - .ptext = "\x0d\xf4\x09\xd8\xb1\x14\x51\x94" - "\x8a\xd8\x84\x8e\xe6\xe5\x8c\xa3" - "\xfc\xfc\x9e\x28\xb0\xb8\xfc\xaf" - "\x50\x52\xb1\xc4\x55\x59\x55\xaf", - .plen = 32, - .ctext = "\x5a\xcd\x8c\x57\xf2\x6a\xb6\xbe" - "\x53\xc7\xaa\x9a\x60\x74\x9c\xc4" - "\xa2\xc2\xd0\x6d\xe1\x03\x63\xdc" - "\xbb\x51\x7e\x9c\x89\x73\xde\x4e" - "\x24\xf8\x52\x7c\x15\x41\x0e\xba" - "\x69\x0e\x36\x5f\x2f\x22\x8c", - .clen = 47, - }, { - .key = "\x1c\xbd\x98\x40\xf5\xb3\xfc\x1b" - "\xaa\x0f\xb0\xb3\xe4\xae\xbc\x24" - "\xc7\xac\x21\x49\xf1\x60\xdd\xb5" - "\x80\x5d\xe9\xba\x0c\x71\x3c\x64", - .klen = 32, - .iv = "\x2c\x86\x26\xa8\x39\x52\xa6\xa2" - "\xcb\x45\xdd\xd7\xe3\x77\xed\xa6", - .assoc = "\x3b\x4f\xb5\x10\x7d\xf1\x50\x29" - "\xeb\x7c\x0a\xfb\xe1\x40\x1e\x27" - "\x5c\x0d\x27\x8b\x74\xb0\x9e\xc2" - "\xe1\x74\x59\xa6\x79\xa1\x0c\xd0", - .alen = 32, - .ptext = "\x4a\x18\x43\x77\xc1\x90\xfa\xb0" - "\x0b\xb2\x36\x20\xe0\x09\x4e\xa9" - "\x26\xbe\xaa\xac\xb5\x58\x7e\xc8" - "\x11\x7f\x90\x9c\x2f\xb8\xf4\x85", - .plen = 32, - .ctext = "\x47\xd6\xce\x78\xd6\xbf\x4a\x51" - "\xb8\xda\x92\x3c\xfd\xda\xac\x8e" - "\x8d\x88\xd7\x4d\x90\xe5\xeb\xa1" - "\xab\xd6\x7c\x76\xad\xea\x7d\x76" - "\x53\xee\xb0\xcd\xd0\x02\xbb\x70" - "\x5b\x6f\x7b\xe2\x8c\xe8", - .clen = 46, - }, { - .key = "\x59\xe1\xd2\xdf\x05\x2f\xa4\x37" - "\x2b\xe9\x63\x44\xde\xd3\x7f\x2b" - "\xf1\x6f\x2d\xcd\xf6\x00\x5f\xcf" - "\x42\x8a\xc8\x92\xe6\xd0\xdc\x3b", - .klen = 32, - .iv = "\x68\xab\x60\x47\x49\xce\x4f\xbe" - "\x4c\x20\x8f\x68\xdd\x9c\xb0\xac", - .assoc = "\x77\x74\xee\xaf\x8d\x6d\xf9\x45" - "\x6c\x56\xbc\x8d\xdb\x65\xe0\x2e" - "\x86\xd0\x32\x0f\x79\x50\x20\xdb" - "\xa2\xa1\x37\x7e\x53\x00\xab\xa6", - .alen = 32, - .ptext = "\x86\x3d\x7d\x17\xd1\x0c\xa3\xcc" - "\x8c\x8d\xe8\xb1\xda\x2e\x11\xaf" - "\x51\x80\xb5\x30\xba\xf8\x00\xe2" - "\xd3\xad\x6f\x75\x09\x18\x93\x5c", - .plen = 32, - .ctext = "\x9f\xa9\x2b\xa4\x8f\x00\x05\x2b" - "\xe7\x68\x81\x51\xbb\xfb\xdf\x60" - "\xbb\xac\xe8\xc1\xdc\x68\xae\x68" - "\x3a\xcd\x7a\x06\x49\xfe\x80\x11" - "\xe6\x61\x99\xe2\xdd\xbe\x2c\xbf", - .clen = 40, - }, { - .key = "\x96\x06\x0b\x7f\x15\xab\x4d\x53" - "\xac\xc3\x15\xd6\xd8\xf7\x42\x31" - "\x1b\x31\x38\x51\xfc\xa0\xe1\xe8" - "\x03\xb8\xa7\x6b\xc0\x2f\x7b\x11", - .klen = 32, - .iv = "\xa5\xcf\x9a\xe6\x59\x4a\xf7\xd9" - "\xcd\xfa\x41\xfa\xd7\xc0\x72\xb2", - .assoc = "\xb4\x99\x28\x4e\x9d\xe8\xa2\x60" - "\xed\x30\x6e\x1e\xd5\x89\xa3\x34" - "\xb1\x92\x3e\x93\x7e\xf0\xa2\xf5" - "\x64\xcf\x16\x57\x2d\x5f\x4a\x7d", - .alen = 32, - .ptext = "\xc3\x62\xb7\xb6\xe2\x87\x4c\xe7" - "\x0d\x67\x9a\x43\xd4\x52\xd4\xb5" - "\x7b\x43\xc1\xb5\xbf\x98\x82\xfc" - "\x94\xda\x4e\x4d\xe4\x77\x32\x32", - .plen = 32, - .ctext = "\xe2\x34\xfa\x25\xfd\xfb\x89\x5e" - "\x5b\x4e\x0b\x15\x6e\x39\xfb\x0c" - "\x73\xc7\xd9\x6b\xbe\xce\x9b\x70" - "\xc7\x4f\x96\x16\x03\xfc\xea\xfb" - "\x56", - .clen = 33, - }, -}; - -/* - * All key wrapping test vectors taken from - * http://csrc.nist.gov/groups/STM/cavp/documents/mac/kwtestvectors.zip - * - * Note: as documented in keywrap.c, the ivout for encryption is the first - * semiblock of the ciphertext from the test vector. For decryption, iv is - * the first semiblock of the ciphertext. - */ -static const struct cipher_testvec aes_kw_tv_template[] = { - { - .key = "\x75\x75\xda\x3a\x93\x60\x7c\xc2" - "\xbf\xd8\xce\xc7\xaa\xdf\xd9\xa6", - .klen = 16, - .ptext = "\x42\x13\x6d\x3c\x38\x4a\x3e\xea" - "\xc9\x5a\x06\x6f\xd2\x8f\xed\x3f", - .ctext = "\xf6\x85\x94\x81\x6f\x64\xca\xa3" - "\xf5\x6f\xab\xea\x25\x48\xf5\xfb", - .len = 16, - .iv_out = "\x03\x1f\x6b\xd7\xe6\x1e\x64\x3d", - .generates_iv = true, - }, { - .key = "\x80\xaa\x99\x73\x27\xa4\x80\x6b" - "\x6a\x7a\x41\xa5\x2b\x86\xc3\x71" - "\x03\x86\xf9\x32\x78\x6e\xf7\x96" - "\x76\xfa\xfb\x90\xb8\x26\x3c\x5f", - .klen = 32, - .ptext = "\x0a\x25\x6b\xa7\x5c\xfa\x03\xaa" - "\xa0\x2b\xa9\x42\x03\xf1\x5b\xaa", - .ctext = "\xd3\x3d\x3d\x97\x7b\xf0\xa9\x15" - "\x59\xf9\x9c\x8a\xcd\x29\x3d\x43", - .len = 16, - .iv_out = "\x42\x3c\x96\x0d\x8a\x2a\xc4\xc1", - .generates_iv = true, - }, -}; - -/* - * ANSI X9.31 Continuous Pseudo-Random Number Generator (AES mode) - * test vectors, taken from Appendix B.2.9 and B.2.10: - * http://csrc.nist.gov/groups/STM/cavp/documents/rng/RNGVS.pdf - * Only AES-128 is supported at this time. - */ -static const struct cprng_testvec ansi_cprng_aes_tv_template[] = { - { - .key = "\xf3\xb1\x66\x6d\x13\x60\x72\x42" - "\xed\x06\x1c\xab\xb8\xd4\x62\x02", - .klen = 16, - .dt = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62" - "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xf9", - .dtlen = 16, - .v = "\x80\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .vlen = 16, - .result = "\x59\x53\x1e\xd1\x3b\xb0\xc0\x55" - "\x84\x79\x66\x85\xc1\x2f\x76\x41", - .rlen = 16, - .loops = 1, - }, { - .key = "\xf3\xb1\x66\x6d\x13\x60\x72\x42" - "\xed\x06\x1c\xab\xb8\xd4\x62\x02", - .klen = 16, - .dt = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62" - "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfa", - .dtlen = 16, - .v = "\xc0\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .vlen = 16, - .result = "\x7c\x22\x2c\xf4\xca\x8f\xa2\x4c" - "\x1c\x9c\xb6\x41\xa9\xf3\x22\x0d", - .rlen = 16, - .loops = 1, - }, { - .key = "\xf3\xb1\x66\x6d\x13\x60\x72\x42" - "\xed\x06\x1c\xab\xb8\xd4\x62\x02", - .klen = 16, - .dt = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62" - "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfb", - .dtlen = 16, - .v = "\xe0\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .vlen = 16, - .result = "\x8a\xaa\x00\x39\x66\x67\x5b\xe5" - "\x29\x14\x28\x81\xa9\x4d\x4e\xc7", - .rlen = 16, - .loops = 1, - }, { - .key = "\xf3\xb1\x66\x6d\x13\x60\x72\x42" - "\xed\x06\x1c\xab\xb8\xd4\x62\x02", - .klen = 16, - .dt = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62" - "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfc", - .dtlen = 16, - .v = "\xf0\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .vlen = 16, - .result = "\x88\xdd\xa4\x56\x30\x24\x23\xe5" - "\xf6\x9d\xa5\x7e\x7b\x95\xc7\x3a", - .rlen = 16, - .loops = 1, - }, { - .key = "\xf3\xb1\x66\x6d\x13\x60\x72\x42" - "\xed\x06\x1c\xab\xb8\xd4\x62\x02", - .klen = 16, - .dt = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62" - "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfd", - .dtlen = 16, - .v = "\xf8\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .vlen = 16, - .result = "\x05\x25\x92\x46\x61\x79\xd2\xcb" - "\x78\xc4\x0b\x14\x0a\x5a\x9a\xc8", - .rlen = 16, - .loops = 1, - }, { /* Monte Carlo Test */ - .key = "\x9f\x5b\x51\x20\x0b\xf3\x34\xb5" - "\xd8\x2b\xe8\xc3\x72\x55\xc8\x48", - .klen = 16, - .dt = "\x63\x76\xbb\xe5\x29\x02\xba\x3b" - "\x67\xc9\x25\xfa\x70\x1f\x11\xac", - .dtlen = 16, - .v = "\x57\x2c\x8e\x76\x87\x26\x47\x97" - "\x7e\x74\xfb\xdd\xc4\x95\x01\xd1", - .vlen = 16, - .result = "\x48\xe9\xbd\x0d\x06\xee\x18\xfb" - "\xe4\x57\x90\xd5\xc3\xfc\x9b\x73", - .rlen = 16, - .loops = 10000, - }, -}; - -/* - * SP800-90A DRBG Test vectors from - * http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip - * - * Test vectors for DRBG with prediction resistance. All types of DRBGs - * (Hash, HMAC, CTR) are tested with all permutations of use cases (w/ and - * w/o personalization string, w/ and w/o additional input string). - */ -static const struct drbg_testvec drbg_pr_sha256_tv_template[] = { - { - .entropy = (unsigned char *) - "\x72\x88\x4c\xcd\x6c\x85\x57\x70\xf7\x0b\x8b\x86" - "\xc1\xeb\xd2\x4e\x36\x14\xab\x18\xc4\x9c\xc9\xcf" - "\x1a\xe8\xf7\x7b\x02\x49\x73\xd7\xf1\x42\x7d\xc6" - "\x3f\x29\x2d\xec\xd3\x66\x51\x3f\x1d\x8d\x5b\x4e", - .entropylen = 48, - .entpra = (unsigned char *) - "\x38\x9c\x91\xfa\xc2\xa3\x46\x89\x56\x08\x3f\x62" - "\x73\xd5\x22\xa9\x29\x63\x3a\x1d\xe5\x5d\x5e\x4f" - "\x67\xb0\x67\x7a\x5e\x9e\x0c\x62", - .entprb = (unsigned char *) - "\xb2\x8f\x36\xb2\xf6\x8d\x39\x13\xfa\x6c\x66\xcf" - "\x62\x8a\x7e\x8c\x12\x33\x71\x9c\x69\xe4\xa5\xf0" - "\x8c\xee\xeb\x9c\xf5\x31\x98\x31", - .entprlen = 32, - .expected = (unsigned char *) - "\x52\x7b\xa3\xad\x71\x77\xa4\x49\x42\x04\x61\xc7" - "\xf0\xaf\xa5\xfd\xd3\xb3\x0d\x6a\x61\xba\x35\x49" - "\xbb\xaa\xaf\xe4\x25\x7d\xb5\x48\xaf\x5c\x18\x3d" - "\x33\x8d\x9d\x45\xdf\x98\xd5\x94\xa8\xda\x92\xfe" - "\xc4\x3c\x94\x2a\xcf\x7f\x7b\xf2\xeb\x28\xa9\xf1" - "\xe0\x86\x30\xa8\xfe\xf2\x48\x90\x91\x0c\x75\xb5" - "\x3c\x00\xf0\x4d\x09\x4f\x40\xa7\xa2\x8c\x52\xdf" - "\x52\xef\x17\xbf\x3d\xd1\xa2\x31\xb4\xb8\xdc\xe6" - "\x5b\x0d\x1f\x78\x36\xb4\xe6\x4b\xa7\x11\x25\xd5" - "\x94\xc6\x97\x36\xab\xf0\xe5\x31\x28\x6a\xbb\xce" - "\x30\x81\xa6\x8f\x27\x14\xf8\x1c", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x5d\xf2\x14\xbc\xf6\xb5\x4e\x0b\xf0\x0d\x6f\x2d" - "\xe2\x01\x66\x7b\xd0\xa4\x73\xa4\x21\xdd\xb0\xc0" - "\x51\x79\x09\xf4\xea\xa9\x08\xfa\xa6\x67\xe0\xe1" - "\xd1\x88\xa8\xad\xee\x69\x74\xb3\x55\x06\x9b\xf6", - .entropylen = 48, - .entpra = (unsigned char *) - "\xef\x48\x06\xa2\xc2\x45\xf1\x44\xfa\x34\x2c\xeb" - "\x8d\x78\x3c\x09\x8f\x34\x72\x20\xf2\xe7\xfd\x13" - "\x76\x0a\xf6\xdc\x3c\xf5\xc0\x15", - .entprb = (unsigned char *) - "\x4b\xbe\xe5\x24\xed\x6a\x2d\x0c\xdb\x73\x5e\x09" - "\xf9\xad\x67\x7c\x51\x47\x8b\x6b\x30\x2a\xc6\xde" - "\x76\xaa\x55\x04\x8b\x0a\x72\x95", - .entprlen = 32, - .expected = (unsigned char *) - "\x3b\x14\x71\x99\xa1\xda\xa0\x42\xe6\xc8\x85\x32" - "\x70\x20\x32\x53\x9a\xbe\xd1\x1e\x15\xef\xfb\x4c" - "\x25\x6e\x19\x3a\xf0\xb9\xcb\xde\xf0\x3b\xc6\x18" - "\x4d\x85\x5a\x9b\xf1\xe3\xc2\x23\x03\x93\x08\xdb" - "\xa7\x07\x4b\x33\x78\x40\x4d\xeb\x24\xf5\x6e\x81" - "\x4a\x1b\x6e\xa3\x94\x52\x43\xb0\xaf\x2e\x21\xf4" - "\x42\x46\x8e\x90\xed\x34\x21\x75\xea\xda\x67\xb6" - "\xe4\xf6\xff\xc6\x31\x6c\x9a\x5a\xdb\xb3\x97\x13" - "\x09\xd3\x20\x98\x33\x2d\x6d\xd7\xb5\x6a\xa8\xa9" - "\x9a\x5b\xd6\x87\x52\xa1\x89\x2b\x4b\x9c\x64\x60" - "\x50\x47\xa3\x63\x81\x16\xaf\x19", - .expectedlen = 128, - .addtla = (unsigned char *) - "\xbe\x13\xdb\x2a\xe9\xa8\xfe\x09\x97\xe1\xce\x5d" - "\xe8\xbb\xc0\x7c\x4f\xcb\x62\x19\x3f\x0f\xd2\xad" - "\xa9\xd0\x1d\x59\x02\xc4\xff\x70", - .addtlb = (unsigned char *) - "\x6f\x96\x13\xe2\xa7\xf5\x6c\xfe\xdf\x66\xe3\x31" - "\x63\x76\xbf\x20\x27\x06\x49\xf1\xf3\x01\x77\x41" - "\x9f\xeb\xe4\x38\xfe\x67\x00\xcd", - .addtllen = 32, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\xc6\x1c\xaf\x83\xa2\x56\x38\xf9\xb0\xbc\xd9\x85" - "\xf5\x2e\xc4\x46\x9c\xe1\xb9\x40\x98\x70\x10\x72" - "\xd7\x7d\x15\x85\xa1\x83\x5a\x97\xdf\xc8\xa8\xe8" - "\x03\x4c\xcb\x70\x35\x8b\x90\x94\x46\x8a\x6e\xa1", - .entropylen = 48, - .entpra = (unsigned char *) - "\xc9\x05\xa4\xcf\x28\x80\x4b\x93\x0f\x8b\xc6\xf9" - "\x09\x41\x58\x74\xe9\xec\x28\xc7\x53\x0a\x73\x60" - "\xba\x0a\xde\x57\x5b\x4b\x9f\x29", - .entprb = (unsigned char *) - "\x4f\x31\xd2\xeb\xac\xfa\xa8\xe2\x01\x7d\xf3\xbd" - "\x42\xbd\x20\xa0\x30\x65\x74\xd5\x5d\xd2\xad\xa4" - "\xa9\xeb\x1f\x4d\xf6\xfd\xb8\x26", - .entprlen = 32, - .expected = (unsigned char *) - "\xf6\x13\x05\xcb\x83\x60\x16\x42\x49\x1d\xc6\x25" - "\x3b\x8c\x31\xa3\xbe\x8b\xbd\x1c\xe2\xec\x1d\xde" - "\xbb\xbf\xa1\xac\xa8\x9f\x50\xce\x69\xce\xef\xd5" - "\xd6\xf2\xef\x6a\xf7\x81\x38\xdf\xbc\xa7\x5a\xb9" - "\xb2\x42\x65\xab\xe4\x86\x8d\x2d\x9d\x59\x99\x2c" - "\x5a\x0d\x71\x55\x98\xa4\x45\xc2\x8d\xdb\x05\x5e" - "\x50\x21\xf7\xcd\xe8\x98\x43\xce\x57\x74\x63\x4c" - "\xf3\xb1\xa5\x14\x1e\x9e\x01\xeb\x54\xd9\x56\xae" - "\xbd\xb6\x6f\x1a\x47\x6b\x3b\x44\xe4\xa2\xe9\x3c" - "\x6c\x83\x12\x30\xb8\x78\x7f\x8e\x54\x82\xd4\xfe" - "\x90\x35\x0d\x4c\x4d\x85\xe7\x13", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\xa5\xbf\xac\x4f\x71\xa1\xbb\x67\x94\xc6\x50\xc7" - "\x2a\x45\x9e\x10\xa8\xed\xf7\x52\x4f\xfe\x21\x90" - "\xa4\x1b\xe1\xe2\x53\xcc\x61\x47", - .perslen = 32, - }, { - .entropy = (unsigned char *) - "\xb6\xc1\x8d\xdf\x99\x54\xbe\x95\x10\x48\xd9\xf6" - "\xd7\x48\xa8\x73\x2d\x74\xde\x1e\xde\x57\x7e\xf4" - "\x7b\x7b\x64\xef\x88\x7a\xa8\x10\x4b\xe1\xc1\x87" - "\xbb\x0b\xe1\x39\x39\x50\xaf\x68\x9c\xa2\xbf\x5e", - .entropylen = 48, - .entpra = (unsigned char *) - "\xdc\x81\x0a\x01\x58\xa7\x2e\xce\xee\x48\x8c\x7c" - "\x77\x9e\x3c\xf1\x17\x24\x7a\xbb\xab\x9f\xca\x12" - "\x19\xaf\x97\x2d\x5f\xf9\xff\xfc", - .entprb = (unsigned char *) - "\xaf\xfc\x4f\x98\x8b\x93\x95\xc1\xb5\x8b\x7f\x73" - "\x6d\xa6\xbe\x6d\x33\xeb\x2c\x82\xb1\xaf\xc1\xb6" - "\xb6\x05\xe2\x44\xaa\xfd\xe7\xdb", - .entprlen = 32, - .expected = (unsigned char *) - "\x51\x79\xde\x1c\x0f\x58\xf3\xf4\xc9\x57\x2e\x31" - "\xa7\x09\xa1\x53\x64\x63\xa2\xc5\x1d\x84\x88\x65" - "\x01\x1b\xc6\x16\x3c\x49\x5b\x42\x8e\x53\xf5\x18" - "\xad\x94\x12\x0d\x4f\x55\xcc\x45\x5c\x98\x0f\x42" - "\x28\x2f\x47\x11\xf9\xc4\x01\x97\x6b\xa0\x94\x50" - "\xa9\xd1\x5e\x06\x54\x3f\xdf\xbb\xc4\x98\xee\x8b" - "\xba\xa9\xfa\x49\xee\x1d\xdc\xfb\x50\xf6\x51\x9f" - "\x6c\x4a\x9a\x6f\x63\xa2\x7d\xad\xaf\x3a\x24\xa0" - "\xd9\x9f\x07\xeb\x15\xee\x26\xe0\xd5\x63\x39\xda" - "\x3c\x59\xd6\x33\x6c\x02\xe8\x05\x71\x46\x68\x44" - "\x63\x4a\x68\x72\xe9\xf5\x55\xfe", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x15\x20\x2f\xf6\x98\x28\x63\xa2\xc4\x4e\xbb\x6c" - "\xb2\x25\x92\x61\x79\xc9\x22\xc4\x61\x54\x96\xff" - "\x4a\x85\xca\x80\xfe\x0d\x1c\xd0", - .addtlb = (unsigned char *) - "\xde\x29\x8e\x03\x42\x61\xa3\x28\x5e\xc8\x80\xc2" - "\x6d\xbf\xad\x13\xe1\x8d\x2a\xc7\xe8\xc7\x18\x89" - "\x42\x58\x9e\xd6\xcc\xad\x7b\x1e", - .addtllen = 32, - .pers = (unsigned char *) - "\x84\xc3\x73\x9e\xce\xb3\xbc\x89\xf7\x62\xb3\xe1" - "\xd7\x48\x45\x8a\xa9\xcc\xe9\xed\xd5\x81\x84\x52" - "\x82\x4c\xdc\x19\xb8\xf8\x92\x5c", - .perslen = 32, - }, -}; - -static const struct drbg_testvec drbg_pr_hmac_sha256_tv_template[] = { - { - .entropy = (unsigned char *) - "\x99\x69\xe5\x4b\x47\x03\xff\x31\x78\x5b\x87\x9a" - "\x7e\x5c\x0e\xae\x0d\x3e\x30\x95\x59\xe9\xfe\x96" - "\xb0\x67\x6d\x49\xd5\x91\xea\x4d\x07\xd2\x0d\x46" - "\xd0\x64\x75\x7d\x30\x23\xca\xc2\x37\x61\x27\xab", - .entropylen = 48, - .entpra = (unsigned char *) - "\xc6\x0f\x29\x99\x10\x0f\x73\x8c\x10\xf7\x47\x92" - "\x67\x6a\x3f\xc4\xa2\x62\xd1\x37\x21\x79\x80\x46" - "\xe2\x9a\x29\x51\x81\x56\x9f\x54", - .entprb = (unsigned char *) - "\xc1\x1d\x45\x24\xc9\x07\x1b\xd3\x09\x60\x15\xfc" - "\xf7\xbc\x24\xa6\x07\xf2\x2f\xa0\x65\xc9\x37\x65" - "\x8a\x2a\x77\xa8\x69\x90\x89\xf4", - .entprlen = 32, - .expected = (unsigned char *) - "\xab\xc0\x15\x85\x60\x94\x80\x3a\x93\x8d\xff\xd2" - "\x0d\xa9\x48\x43\x87\x0e\xf9\x35\xb8\x2c\xfe\xc1" - "\x77\x06\xb8\xf5\x51\xb8\x38\x50\x44\x23\x5d\xd4" - "\x4b\x59\x9f\x94\xb3\x9b\xe7\x8d\xd4\x76\xe0\xcf" - "\x11\x30\x9c\x99\x5a\x73\x34\xe0\xa7\x8b\x37\xbc" - "\x95\x86\x23\x50\x86\xfa\x3b\x63\x7b\xa9\x1c\xf8" - "\xfb\x65\xef\xa2\x2a\x58\x9c\x13\x75\x31\xaa\x7b" - "\x2d\x4e\x26\x07\xaa\xc2\x72\x92\xb0\x1c\x69\x8e" - "\x6e\x01\xae\x67\x9e\xb8\x7c\x01\xa8\x9c\x74\x22" - "\xd4\x37\x2d\x6d\x75\x4a\xba\xbb\x4b\xf8\x96\xfc" - "\xb1\xcd\x09\xd6\x92\xd0\x28\x3f", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\xb9\x1f\xe9\xef\xdd\x9b\x7d\x20\xb6\xec\xe0\x2f" - "\xdb\x76\x24\xce\x41\xc8\x3a\x4a\x12\x7f\x3e\x2f" - "\xae\x05\x99\xea\xb5\x06\x71\x0d\x0c\x4c\xb4\x05" - "\x26\xc6\xbd\xf5\x7f\x2a\x3d\xf2\xb5\x49\x7b\xda", - .entropylen = 48, - .entpra = (unsigned char *) - "\xef\x67\x50\x9c\xa7\x7d\xdf\xb7\x2d\x81\x01\xa4" - "\x62\x81\x6a\x69\x5b\xb3\x37\x45\xa7\x34\x8e\x26" - "\x46\xd9\x26\xa2\x19\xd4\x94\x43", - .entprb = (unsigned char *) - "\x97\x75\x53\x53\xba\xb4\xa6\xb2\x91\x60\x71\x79" - "\xd1\x6b\x4a\x24\x9a\x34\x66\xcc\x33\xab\x07\x98" - "\x51\x78\x72\xb2\x79\xfd\x2c\xff", - .entprlen = 32, - .expected = (unsigned char *) - "\x9c\xdc\x63\x8a\x19\x23\x22\x66\x0c\xc5\xb9\xd7" - "\xfb\x2a\xb0\x31\xe3\x8a\x36\xa8\x5a\xa8\x14\xda" - "\x1e\xa9\xcc\xfe\xb8\x26\x44\x83\x9f\xf6\xff\xaa" - "\xc8\x98\xb8\x30\x35\x3b\x3d\x36\xd2\x49\xd4\x40" - "\x62\x0a\x65\x10\x76\x55\xef\xc0\x95\x9c\xa7\xda" - "\x3f\xcf\xb7\x7b\xc6\xe1\x28\x52\xfc\x0c\xe2\x37" - "\x0d\x83\xa7\x51\x4b\x31\x47\x3c\xe1\x3c\xae\x70" - "\x01\xc8\xa3\xd3\xc2\xac\x77\x9c\xd1\x68\x77\x9b" - "\x58\x27\x3b\xa5\x0f\xc2\x7a\x8b\x04\x65\x62\xd5" - "\xe8\xd6\xfe\x2a\xaf\xd3\xd3\xfe\xbd\x18\xfb\xcd" - "\xcd\x66\xb5\x01\x69\x66\xa0\x3c", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x17\xc1\x56\xcb\xcc\x50\xd6\x03\x7d\x45\x76\xa3" - "\x75\x76\xc1\x4a\x66\x1b\x2e\xdf\xb0\x2e\x7d\x56" - "\x6d\x99\x3b\xc6\x58\xda\x03\xf6", - .addtlb = (unsigned char *) - "\x7c\x7b\x4a\x4b\x32\x5e\x6f\x67\x34\xf5\x21\x4c" - "\xf9\x96\xf9\xbf\x1c\x8c\x81\xd3\x9b\x60\x6a\x44" - "\xc6\x03\xa2\xfb\x13\x20\x19\xb7", - .addtllen = 32, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x13\x54\x96\xfc\x1b\x7d\x28\xf3\x18\xc9\xa7\x89" - "\xb6\xb3\xc8\x72\xac\x00\xd4\x59\x36\x25\x05\xaf" - "\xa5\xdb\x96\xcb\x3c\x58\x46\x87\xa5\xaa\xbf\x20" - "\x3b\xfe\x23\x0e\xd1\xc7\x41\x0f\x3f\xc9\xb3\x67", - .entropylen = 48, - .entpra = (unsigned char *) - "\xe2\xbd\xb7\x48\x08\x06\xf3\xe1\x93\x3c\xac\x79" - "\xa7\x2b\x11\xda\xe3\x2e\xe1\x91\xa5\x02\x19\x57" - "\x20\x28\xad\xf2\x60\xd7\xcd\x45", - .entprb = (unsigned char *) - "\x8b\xd4\x69\xfc\xff\x59\x95\x95\xc6\x51\xde\x71" - "\x68\x5f\xfc\xf9\x4a\xab\xec\x5a\xcb\xbe\xd3\x66" - "\x1f\xfa\x74\xd3\xac\xa6\x74\x60", - .entprlen = 32, - .expected = (unsigned char *) - "\x1f\x9e\xaf\xe4\xd2\x46\xb7\x47\x41\x4c\x65\x99" - "\x01\xe9\x3b\xbb\x83\x0c\x0a\xb0\xc1\x3a\xe2\xb3" - "\x31\x4e\xeb\x93\x73\xee\x0b\x26\xc2\x63\xa5\x75" - "\x45\x99\xd4\x5c\x9f\xa1\xd4\x45\x87\x6b\x20\x61" - "\x40\xea\x78\xa5\x32\xdf\x9e\x66\x17\xaf\xb1\x88" - "\x9e\x2e\x23\xdd\xc1\xda\x13\x97\x88\xa5\xb6\x5e" - "\x90\x14\x4e\xef\x13\xab\x5c\xd9\x2c\x97\x9e\x7c" - "\xd7\xf8\xce\xea\x81\xf5\xcd\x71\x15\x49\x44\xce" - "\x83\xb6\x05\xfb\x7d\x30\xb5\x57\x2c\x31\x4f\xfc" - "\xfe\x80\xb6\xc0\x13\x0c\x5b\x9b\x2e\x8f\x3d\xfc" - "\xc2\xa3\x0c\x11\x1b\x80\x5f\xf3", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\x64\xb6\xfc\x60\xbc\x61\x76\x23\x6d\x3f\x4a\x0f" - "\xe1\xb4\xd5\x20\x9e\x70\xdd\x03\x53\x6d\xbf\xce" - "\xcd\x56\x80\xbc\xb8\x15\xc8\xaa", - .perslen = 32, - }, { - .entropy = (unsigned char *) - "\xc7\xcc\xbc\x67\x7e\x21\x66\x1e\x27\x2b\x63\xdd" - "\x3a\x78\xdc\xdf\x66\x6d\x3f\x24\xae\xcf\x37\x01" - "\xa9\x0d\x89\x8a\xa7\xdc\x81\x58\xae\xb2\x10\x15" - "\x7e\x18\x44\x6d\x13\xea\xdf\x37\x85\xfe\x81\xfb", - .entropylen = 48, - .entpra = (unsigned char *) - "\x7b\xa1\x91\x5b\x3c\x04\xc4\x1b\x1d\x19\x2f\x1a" - "\x18\x81\x60\x3c\x6c\x62\x91\xb7\xe9\xf5\xcb\x96" - "\xbb\x81\x6a\xcc\xb5\xae\x55\xb6", - .entprb = (unsigned char *) - "\x99\x2c\xc7\x78\x7e\x3b\x88\x12\xef\xbe\xd3\xd2" - "\x7d\x2a\xa5\x86\xda\x8d\x58\x73\x4a\x0a\xb2\x2e" - "\xbb\x4c\x7e\xe3\x9a\xb6\x81\xc1", - .entprlen = 32, - .expected = (unsigned char *) - "\x95\x6f\x95\xfc\x3b\xb7\xfe\x3e\xd0\x4e\x1a\x14" - "\x6c\x34\x7f\x7b\x1d\x0d\x63\x5e\x48\x9c\x69\xe6" - "\x46\x07\xd2\x87\xf3\x86\x52\x3d\x98\x27\x5e\xd7" - "\x54\xe7\x75\x50\x4f\xfb\x4d\xfd\xac\x2f\x4b\x77" - "\xcf\x9e\x8e\xcc\x16\xa2\x24\xcd\x53\xde\x3e\xc5" - "\x55\x5d\xd5\x26\x3f\x89\xdf\xca\x8b\x4e\x1e\xb6" - "\x88\x78\x63\x5c\xa2\x63\x98\x4e\x6f\x25\x59\xb1" - "\x5f\x2b\x23\xb0\x4b\xa5\x18\x5d\xc2\x15\x74\x40" - "\x59\x4c\xb4\x1e\xcf\x9a\x36\xfd\x43\xe2\x03\xb8" - "\x59\x91\x30\x89\x2a\xc8\x5a\x43\x23\x7c\x73\x72" - "\xda\x3f\xad\x2b\xba\x00\x6b\xd1", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x18\xe8\x17\xff\xef\x39\xc7\x41\x5c\x73\x03\x03" - "\xf6\x3d\xe8\x5f\xc8\xab\xe4\xab\x0f\xad\xe8\xd6" - "\x86\x88\x55\x28\xc1\x69\xdd\x76", - .addtlb = (unsigned char *) - "\xac\x07\xfc\xbe\x87\x0e\xd3\xea\x1f\x7e\xb8\xe7" - "\x9d\xec\xe8\xe7\xbc\xf3\x18\x25\x77\x35\x4a\xaa" - "\x00\x99\x2a\xdd\x0a\x00\x50\x82", - .addtllen = 32, - .pers = (unsigned char *) - "\xbc\x55\xab\x3c\xf6\x52\xb0\x11\x3d\x7b\x90\xb8" - "\x24\xc9\x26\x4e\x5a\x1e\x77\x0d\x3d\x58\x4a\xda" - "\xd1\x81\xe9\xf8\xeb\x30\x8f\x6f", - .perslen = 32, - }, -}; - -static const struct drbg_testvec drbg_pr_ctr_aes128_tv_template[] = { - { - .entropy = (unsigned char *) - "\xd1\x44\xc6\x61\x81\x6d\xca\x9d\x15\x28\x8a\x42" - "\x94\xd7\x28\x9c\x43\x77\x19\x29\x1a\x6d\xc3\xa2", - .entropylen = 24, - .entpra = (unsigned char *) - "\x96\xd8\x9e\x45\x32\xc9\xd2\x08\x7a\x6d\x97\x15" - "\xb4\xec\x80\xb1", - .entprb = (unsigned char *) - "\x8b\xb6\x72\xb5\x24\x0b\x98\x65\x95\x95\xe9\xc9" - "\x28\x07\xeb\xc2", - .entprlen = 16, - .expected = (unsigned char *) - "\x70\x19\xd0\x4c\x45\x78\xd6\x68\xa9\x9a\xaa\xfe" - "\xc1\xdf\x27\x9a\x1c\x0d\x0d\xf7\x24\x75\x46\xcc" - "\x77\x6b\xdf\x89\xc6\x94\xdc\x74\x50\x10\x70\x18" - "\x9b\xdc\x96\xb4\x89\x23\x40\x1a\xce\x09\x87\xce" - "\xd2\xf3\xd5\xe4\x51\x67\x74\x11\x5a\xcc\x8b\x3b" - "\x8a\xf1\x23\xa8", - .expectedlen = 64, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x8e\x83\xe0\xeb\x37\xea\x3e\x53\x5e\x17\x6e\x77" - "\xbd\xb1\x53\x90\xfc\xdc\xc1\x3c\x9a\x88\x22\x94", - .entropylen = 24, - .entpra = (unsigned char *) - "\x6a\x85\xe7\x37\xc8\xf1\x04\x31\x98\x4f\xc8\x73" - "\x67\xd1\x08\xf8", - .entprb = (unsigned char *) - "\xd7\xa4\x68\xe2\x12\x74\xc3\xd9\xf1\xb7\x05\xbc" - "\xd4\xba\x04\x58", - .entprlen = 16, - .expected = (unsigned char *) - "\x78\xd6\xa6\x70\xff\xd1\x82\xf5\xa2\x88\x7f\x6d" - "\x3d\x8c\x39\xb1\xa8\xcb\x2c\x91\xab\x14\x7e\xbc" - "\x95\x45\x9f\x24\xb8\x20\xac\x21\x23\xdb\x72\xd7" - "\x12\x8d\x48\x95\xf3\x19\x0c\x43\xc6\x19\x45\xfc" - "\x8b\xac\x40\x29\x73\x00\x03\x45\x5e\x12\xff\x0c" - "\xc1\x02\x41\x82", - .expectedlen = 64, - .addtla = (unsigned char *) - "\xa2\xd9\x38\xcf\x8b\x29\x67\x5b\x65\x62\x6f\xe8" - "\xeb\xb3\x01\x76", - .addtlb = (unsigned char *) - "\x59\x63\x1e\x81\x8a\x14\xa8\xbb\xa1\xb8\x41\x25" - "\xd0\x7f\xcc\x43", - .addtllen = 16, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x04\xd9\x49\xa6\xdc\xe8\x6e\xbb\xf1\x08\x77\x2b" - "\x9e\x08\xca\x92\x65\x16\xda\x99\xa2\x59\xf3\xe8", - .entropylen = 24, - .entpra = (unsigned char *) - "\x38\x7e\x3f\x6b\x51\x70\x7b\x20\xec\x53\xd0\x66" - "\xc3\x0f\xe3\xb0", - .entprb = (unsigned char *) - "\xe0\x86\xa6\xaa\x5f\x72\x2f\xad\xf7\xef\x06\xb8" - "\xd6\x9c\x9d\xe8", - .entprlen = 16, - .expected = (unsigned char *) - "\xc9\x0a\xaf\x85\x89\x71\x44\x66\x4f\x25\x0b\x2b" - "\xde\xd8\xfa\xff\x52\x5a\x1b\x32\x5e\x41\x7a\x10" - "\x1f\xef\x1e\x62\x23\xe9\x20\x30\xc9\x0d\xad\x69" - "\xb4\x9c\x5b\xf4\x87\x42\xd5\xae\x5e\x5e\x43\xcc" - "\xd9\xfd\x0b\x93\x4a\xe3\xd4\x06\x37\x36\x0f\x3f" - "\x72\x82\x0c\xcf", - .expectedlen = 64, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\xbf\xa4\x9a\x8f\x7b\xd8\xb1\x7a\x9d\xfa\x45\xed" - "\x21\x52\xb3\xad", - .perslen = 16, - }, { - .entropy = (unsigned char *) - "\x92\x89\x8f\x31\xfa\x1c\xff\x6d\x18\x2f\x26\x06" - "\x43\xdf\xf8\x18\xc2\xa4\xd9\x72\xc3\xb9\xb6\x97", - .entropylen = 24, - .entpra = (unsigned char *) - "\x20\x72\x8a\x06\xf8\x6f\x8d\xd4\x41\xe2\x72\xb7" - "\xc4\x2c\xe8\x10", - .entprb = (unsigned char *) - "\x3d\xb0\xf0\x94\xf3\x05\x50\x33\x17\x86\x3e\x22" - "\x08\xf7\xa5\x01", - .entprlen = 16, - .expected = (unsigned char *) - "\x5a\x35\x39\x87\x0f\x4d\x22\xa4\x09\x24\xee\x71" - "\xc9\x6f\xac\x72\x0a\xd6\xf0\x88\x82\xd0\x83\x28" - "\x73\xec\x3f\x93\xd8\xab\x45\x23\xf0\x7e\xac\x45" - "\x14\x5e\x93\x9f\xb1\xd6\x76\x43\x3d\xb6\xe8\x08" - "\x88\xf6\xda\x89\x08\x77\x42\xfe\x1a\xf4\x3f\xc4" - "\x23\xc5\x1f\x68", - .expectedlen = 64, - .addtla = (unsigned char *) - "\x1a\x40\xfa\xe3\xcc\x6c\x7c\xa0\xf8\xda\xba\x59" - "\x23\x6d\xad\x1d", - .addtlb = (unsigned char *) - "\x9f\x72\x76\x6c\xc7\x46\xe5\xed\x2e\x53\x20\x12" - "\xbc\x59\x31\x8c", - .addtllen = 16, - .pers = (unsigned char *) - "\xea\x65\xee\x60\x26\x4e\x7e\xb6\x0e\x82\x68\xc4" - "\x37\x3c\x5c\x0b", - .perslen = 16, - }, -}; - -/* - * SP800-90A DRBG Test vectors from - * http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip - * - * Test vectors for DRBG without prediction resistance. All types of DRBGs - * (Hash, HMAC, CTR) are tested with all permutations of use cases (w/ and - * w/o personalization string, w/ and w/o additional input string). - */ -static const struct drbg_testvec drbg_nopr_sha256_tv_template[] = { - { - .entropy = (unsigned char *) - "\xa6\x5a\xd0\xf3\x45\xdb\x4e\x0e\xff\xe8\x75\xc3" - "\xa2\xe7\x1f\x42\xc7\x12\x9d\x62\x0f\xf5\xc1\x19" - "\xa9\xef\x55\xf0\x51\x85\xe0\xfb\x85\x81\xf9\x31" - "\x75\x17\x27\x6e\x06\xe9\x60\x7d\xdb\xcb\xcc\x2e", - .entropylen = 48, - .expected = (unsigned char *) - "\xd3\xe1\x60\xc3\x5b\x99\xf3\x40\xb2\x62\x82\x64" - "\xd1\x75\x10\x60\xe0\x04\x5d\xa3\x83\xff\x57\xa5" - "\x7d\x73\xa6\x73\xd2\xb8\xd8\x0d\xaa\xf6\xa6\xc3" - "\x5a\x91\xbb\x45\x79\xd7\x3f\xd0\xc8\xfe\xd1\x11" - "\xb0\x39\x13\x06\x82\x8a\xdf\xed\x52\x8f\x01\x81" - "\x21\xb3\xfe\xbd\xc3\x43\xe7\x97\xb8\x7d\xbb\x63" - "\xdb\x13\x33\xde\xd9\xd1\xec\xe1\x77\xcf\xa6\xb7" - "\x1f\xe8\xab\x1d\xa4\x66\x24\xed\x64\x15\xe5\x1c" - "\xcd\xe2\xc7\xca\x86\xe2\x83\x99\x0e\xea\xeb\x91" - "\x12\x04\x15\x52\x8b\x22\x95\x91\x02\x81\xb0\x2d" - "\xd4\x31\xf4\xc9\xf7\x04\x27\xdf", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x73\xd3\xfb\xa3\x94\x5f\x2b\x5f\xb9\x8f\xf6\x9c" - "\x8a\x93\x17\xae\x19\xc3\x4c\xc3\xd6\xca\xa3\x2d" - "\x16\xfc\x42\xd2\x2d\xd5\x6f\x56\xcc\x1d\x30\xff" - "\x9e\x06\x3e\x09\xce\x58\xe6\x9a\x35\xb3\xa6\x56", - .entropylen = 48, - .expected = (unsigned char *) - "\x71\x7b\x93\x46\x1a\x40\xaa\x35\xa4\xaa\xc5\xe7" - "\x6d\x5b\x5b\x8a\xa0\xdf\x39\x7d\xae\x71\x58\x5b" - "\x3c\x7c\xb4\xf0\x89\xfa\x4a\x8c\xa9\x5c\x54\xc0" - "\x40\xdf\xbc\xce\x26\x81\x34\xf8\xba\x7d\x1c\xe8" - "\xad\x21\xe0\x74\xcf\x48\x84\x30\x1f\xa1\xd5\x4f" - "\x81\x42\x2f\xf4\xdb\x0b\x23\xf8\x73\x27\xb8\x1d" - "\x42\xf8\x44\x58\xd8\x5b\x29\x27\x0a\xf8\x69\x59" - "\xb5\x78\x44\xeb\x9e\xe0\x68\x6f\x42\x9a\xb0\x5b" - "\xe0\x4e\xcb\x6a\xaa\xe2\xd2\xd5\x33\x25\x3e\xe0" - "\x6c\xc7\x6a\x07\xa5\x03\x83\x9f\xe2\x8b\xd1\x1c" - "\x70\xa8\x07\x59\x97\xeb\xf6\xbe", - .expectedlen = 128, - .addtla = (unsigned char *) - "\xf4\xd5\x98\x3d\xa8\xfc\xfa\x37\xb7\x54\x67\x73" - "\xc7\xc3\xdd\x47\x34\x71\x02\x5d\xc1\xa0\xd3\x10" - "\xc1\x8b\xbd\xf5\x66\x34\x6f\xdd", - .addtlb = (unsigned char *) - "\xf7\x9e\x6a\x56\x0e\x73\xe9\xd9\x7a\xd1\x69\xe0" - "\x6f\x8c\x55\x1c\x44\xd1\xce\x6f\x28\xcc\xa4\x4d" - "\xa8\xc0\x85\xd1\x5a\x0c\x59\x40", - .addtllen = 32, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x2a\x85\xa9\x8b\xd0\xda\x83\xd6\xad\xab\x9f\xbb" - "\x54\x31\x15\x95\x1c\x4d\x49\x9f\x6a\x15\xf6\xe4" - "\x15\x50\x88\x06\x29\x0d\xed\x8d\xb9\x6f\x96\xe1" - "\x83\x9f\xf7\x88\xda\x84\xbf\x44\x28\xd9\x1d\xaa", - .entropylen = 48, - .expected = (unsigned char *) - "\x2d\x55\xde\xc9\xed\x05\x47\x07\x3d\x04\xfc\x28" - "\x0f\x92\xf0\x4d\xd8\x00\x32\x47\x0a\x1b\x1c\x4b" - "\xef\xd9\x97\xa1\x17\x67\xda\x26\x6c\xfe\x76\x46" - "\x6f\xbc\x6d\x82\x4e\x83\x8a\x98\x66\x6c\x01\xb6" - "\xe6\x64\xe0\x08\x10\x6f\xd3\x5d\x90\xe7\x0d\x72" - "\xa6\xa7\xe3\xbb\x98\x11\x12\x56\x23\xc2\x6d\xd1" - "\xc8\xa8\x7a\x39\xf3\x34\xe3\xb8\xf8\x66\x00\x77" - "\x7d\xcf\x3c\x3e\xfa\xc9\x0f\xaf\xe0\x24\xfa\xe9" - "\x84\xf9\x6a\x01\xf6\x35\xdb\x5c\xab\x2a\xef\x4e" - "\xac\xab\x55\xb8\x9b\xef\x98\x68\xaf\x51\xd8\x16" - "\xa5\x5e\xae\xf9\x1e\xd2\xdb\xe6", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\xa8\x80\xec\x98\x30\x98\x15\xd2\xc6\xc4\x68\xf1" - "\x3a\x1c\xbf\xce\x6a\x40\x14\xeb\x36\x99\x53\xda" - "\x57\x6b\xce\xa4\x1c\x66\x3d\xbc", - .perslen = 32, - }, { - .entropy = (unsigned char *) - "\x69\xed\x82\xa9\xc5\x7b\xbf\xe5\x1d\x2f\xcb\x7a" - "\xd3\x50\x7d\x96\xb4\xb9\x2b\x50\x77\x51\x27\x74" - "\x33\x74\xba\xf1\x30\xdf\x8e\xdf\x87\x1d\x87\xbc" - "\x96\xb2\xc3\xa7\xed\x60\x5e\x61\x4e\x51\x29\x1a", - .entropylen = 48, - .expected = (unsigned char *) - "\xa5\x71\x24\x31\x11\xfe\x13\xe1\xa8\x24\x12\xfb" - "\x37\xa1\x27\xa5\xab\x77\xa1\x9f\xae\x8f\xaf\x13" - "\x93\xf7\x53\x85\x91\xb6\x1b\xab\xd4\x6b\xea\xb6" - "\xef\xda\x4c\x90\x6e\xef\x5f\xde\xe1\xc7\x10\x36" - "\xd5\x67\xbd\x14\xb6\x89\x21\x0c\xc9\x92\x65\x64" - "\xd0\xf3\x23\xe0\x7f\xd1\xe8\x75\xc2\x85\x06\xea" - "\xca\xc0\xcb\x79\x2d\x29\x82\xfc\xaa\x9a\xc6\x95" - "\x7e\xdc\x88\x65\xba\xec\x0e\x16\x87\xec\xa3\x9e" - "\xd8\x8c\x80\xab\x3a\x64\xe0\xcb\x0e\x45\x98\xdd" - "\x7c\x6c\x6c\x26\x11\x13\xc8\xce\xa9\x47\xa6\x06" - "\x57\xa2\x66\xbb\x2d\x7f\xf3\xc1", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x74\xd3\x6d\xda\xe8\xd6\x86\x5f\x63\x01\xfd\xf2" - "\x7d\x06\x29\x6d\x94\xd1\x66\xf0\xd2\x72\x67\x4e" - "\x77\xc5\x3d\x9e\x03\xe3\xa5\x78", - .addtlb = (unsigned char *) - "\xf6\xb6\x3d\xf0\x7c\x26\x04\xc5\x8b\xcd\x3e\x6a" - "\x9f\x9c\x3a\x2e\xdb\x47\x87\xe5\x8e\x00\x5e\x2b" - "\x74\x7f\xa6\xf6\x80\xcd\x9b\x21", - .addtllen = 32, - .pers = (unsigned char *) - "\x74\xa6\xe0\x08\xf9\x27\xee\x1d\x6e\x3c\x28\x20" - "\x87\xdd\xd7\x54\x31\x47\x78\x4b\xe5\x6d\xa3\x73" - "\xa9\x65\xb1\x10\xc1\xdc\x77\x7c", - .perslen = 32, - }, -}; - -static const struct drbg_testvec drbg_nopr_hmac_sha256_tv_template[] = { - { - .entropy = (unsigned char *) - "\xca\x85\x19\x11\x34\x93\x84\xbf\xfe\x89\xde\x1c" - "\xbd\xc4\x6e\x68\x31\xe4\x4d\x34\xa4\xfb\x93\x5e" - "\xe2\x85\xdd\x14\xb7\x1a\x74\x88\x65\x9b\xa9\x6c" - "\x60\x1d\xc6\x9f\xc9\x02\x94\x08\x05\xec\x0c\xa8", - .entropylen = 48, - .expected = (unsigned char *) - "\xe5\x28\xe9\xab\xf2\xde\xce\x54\xd4\x7c\x7e\x75" - "\xe5\xfe\x30\x21\x49\xf8\x17\xea\x9f\xb4\xbe\xe6" - "\xf4\x19\x96\x97\xd0\x4d\x5b\x89\xd5\x4f\xbb\x97" - "\x8a\x15\xb5\xc4\x43\xc9\xec\x21\x03\x6d\x24\x60" - "\xb6\xf7\x3e\xba\xd0\xdc\x2a\xba\x6e\x62\x4a\xbf" - "\x07\x74\x5b\xc1\x07\x69\x4b\xb7\x54\x7b\xb0\x99" - "\x5f\x70\xde\x25\xd6\xb2\x9e\x2d\x30\x11\xbb\x19" - "\xd2\x76\x76\xc0\x71\x62\xc8\xb5\xcc\xde\x06\x68" - "\x96\x1d\xf8\x68\x03\x48\x2c\xb3\x7e\xd6\xd5\xc0" - "\xbb\x8d\x50\xcf\x1f\x50\xd4\x76\xaa\x04\x58\xbd" - "\xab\xa8\x06\xf4\x8b\xe9\xdc\xb8", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\xf9\x7a\x3c\xfd\x91\xfa\xa0\x46\xb9\xe6\x1b\x94" - "\x93\xd4\x36\xc4\x93\x1f\x60\x4b\x22\xf1\x08\x15" - "\x21\xb3\x41\x91\x51\xe8\xff\x06\x11\xf3\xa7\xd4" - "\x35\x95\x35\x7d\x58\x12\x0b\xd1\xe2\xdd\x8a\xed", - .entropylen = 48, - .expected = (unsigned char *) - "\xc6\x87\x1c\xff\x08\x24\xfe\x55\xea\x76\x89\xa5" - "\x22\x29\x88\x67\x30\x45\x0e\x5d\x36\x2d\xa5\xbf" - "\x59\x0d\xcf\x9a\xcd\x67\xfe\xd4\xcb\x32\x10\x7d" - "\xf5\xd0\x39\x69\xa6\x6b\x1f\x64\x94\xfd\xf5\xd6" - "\x3d\x5b\x4d\x0d\x34\xea\x73\x99\xa0\x7d\x01\x16" - "\x12\x6d\x0d\x51\x8c\x7c\x55\xba\x46\xe1\x2f\x62" - "\xef\xc8\xfe\x28\xa5\x1c\x9d\x42\x8e\x6d\x37\x1d" - "\x73\x97\xab\x31\x9f\xc7\x3d\xed\x47\x22\xe5\xb4" - "\xf3\x00\x04\x03\x2a\x61\x28\xdf\x5e\x74\x97\xec" - "\xf8\x2c\xa7\xb0\xa5\x0e\x86\x7e\xf6\x72\x8a\x4f" - "\x50\x9a\x8c\x85\x90\x87\x03\x9c", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x51\x72\x89\xaf\xe4\x44\xa0\xfe\x5e\xd1\xa4\x1d" - "\xbb\xb5\xeb\x17\x15\x00\x79\xbd\xd3\x1e\x29\xcf" - "\x2f\xf3\x00\x34\xd8\x26\x8e\x3b", - .addtlb = (unsigned char *) - "\x88\x02\x8d\x29\xef\x80\xb4\xe6\xf0\xfe\x12\xf9" - "\x1d\x74\x49\xfe\x75\x06\x26\x82\xe8\x9c\x57\x14" - "\x40\xc0\xc9\xb5\x2c\x42\xa6\xe0", - .addtllen = 32, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x8d\xf0\x13\xb4\xd1\x03\x52\x30\x73\x91\x7d\xdf" - "\x6a\x86\x97\x93\x05\x9e\x99\x43\xfc\x86\x54\x54" - "\x9e\x7a\xb2\x2f\x7c\x29\xf1\x22\xda\x26\x25\xaf" - "\x2d\xdd\x4a\xbc\xce\x3c\xf4\xfa\x46\x59\xd8\x4e", - .entropylen = 48, - .expected = (unsigned char *) - "\xb9\x1c\xba\x4c\xc8\x4f\xa2\x5d\xf8\x61\x0b\x81" - "\xb6\x41\x40\x27\x68\xa2\x09\x72\x34\x93\x2e\x37" - "\xd5\x90\xb1\x15\x4c\xbd\x23\xf9\x74\x52\xe3\x10" - "\xe2\x91\xc4\x51\x46\x14\x7f\x0d\xa2\xd8\x17\x61" - "\xfe\x90\xfb\xa6\x4f\x94\x41\x9c\x0f\x66\x2b\x28" - "\xc1\xed\x94\xda\x48\x7b\xb7\xe7\x3e\xec\x79\x8f" - "\xbc\xf9\x81\xb7\x91\xd1\xbe\x4f\x17\x7a\x89\x07" - "\xaa\x3c\x40\x16\x43\xa5\xb6\x2b\x87\xb8\x9d\x66" - "\xb3\xa6\x0e\x40\xd4\xa8\xe4\xe9\xd8\x2a\xf6\xd2" - "\x70\x0e\x6f\x53\x5c\xdb\x51\xf7\x5c\x32\x17\x29" - "\x10\x37\x41\x03\x0c\xcc\x3a\x56", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\xb5\x71\xe6\x6d\x7c\x33\x8b\xc0\x7b\x76\xad\x37" - "\x57\xbb\x2f\x94\x52\xbf\x7e\x07\x43\x7a\xe8\x58" - "\x1c\xe7\xbc\x7c\x3a\xc6\x51\xa9", - .perslen = 32, - }, { - .entropy = (unsigned char *) - "\xc2\xa5\x66\xa9\xa1\x81\x7b\x15\xc5\xc3\xb7\x78" - "\x17\x7a\xc8\x7c\x24\xe7\x97\xbe\x0a\x84\x5f\x11" - "\xc2\xfe\x39\x9d\xd3\x77\x32\xf2\xcb\x18\x94\xeb" - "\x2b\x97\xb3\xc5\x6e\x62\x83\x29\x51\x6f\x86\xec", - .entropylen = 48, - .expected = (unsigned char *) - "\xb3\xa3\x69\x8d\x77\x76\x99\xa0\xdd\x9f\xa3\xf0" - "\xa9\xfa\x57\x83\x2d\x3c\xef\xac\x5d\xf2\x44\x37" - "\xc6\xd7\x3a\x0f\xe4\x10\x40\xf1\x72\x90\x38\xae" - "\xf1\xe9\x26\x35\x2e\xa5\x9d\xe1\x20\xbf\xb7\xb0" - "\x73\x18\x3a\x34\x10\x6e\xfe\xd6\x27\x8f\xf8\xad" - "\x84\x4b\xa0\x44\x81\x15\xdf\xdd\xf3\x31\x9a\x82" - "\xde\x6b\xb1\x1d\x80\xbd\x87\x1a\x9a\xcd\x35\xc7" - "\x36\x45\xe1\x27\x0f\xb9\xfe\x4f\xa8\x8e\xc0\xe4" - "\x65\x40\x9e\xa0\xcb\xa8\x09\xfe\x2f\x45\xe0\x49" - "\x43\xa2\xe3\x96\xbb\xb7\xdd\x2f\x4e\x07\x95\x30" - "\x35\x24\xcc\x9c\xc5\xea\x54\xa1", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x41\x3d\xd8\x3f\xe5\x68\x35\xab\xd4\x78\xcb\x96" - "\x93\xd6\x76\x35\x90\x1c\x40\x23\x9a\x26\x64\x62" - "\xd3\x13\x3b\x83\xe4\x9c\x82\x0b", - .addtlb = (unsigned char *) - "\xd5\xc4\xa7\x1f\x9d\x6d\x95\xa1\xbe\xdf\x0b\xd2" - "\x24\x7c\x27\x7d\x1f\x84\xa4\xe5\x7a\x4a\x88\x25" - "\xb8\x2a\x2d\x09\x7d\xe6\x3e\xf1", - .addtllen = 32, - .pers = (unsigned char *) - "\x13\xce\x4d\x8d\xd2\xdb\x97\x96\xf9\x41\x56\xc8" - "\xe8\xf0\x76\x9b\x0a\xa1\xc8\x2c\x13\x23\xb6\x15" - "\x36\x60\x3b\xca\x37\xc9\xee\x29", - .perslen = 32, - }, -}; - -static const struct drbg_testvec drbg_nopr_ctr_aes192_tv_template[] = { - { - .entropy = (unsigned char *) - "\xc3\x5c\x2f\xa2\xa8\x9d\x52\xa1\x1f\xa3\x2a\xa9" - "\x6c\x95\xb8\xf1\xc9\xa8\xf9\xcb\x24\x5a\x8b\x40" - "\xf3\xa6\xe5\xa7\xfb\xd9\xd3\xc6\x8e\x27\x7b\xa9" - "\xac\x9b\xbb\x00", - .entropylen = 40, - .expected = (unsigned char *) - "\x8c\x2e\x72\xab\xfd\x9b\xb8\x28\x4d\xb7\x9e\x17" - "\xa4\x3a\x31\x46\xcd\x76\x94\xe3\x52\x49\xfc\x33" - "\x83\x91\x4a\x71\x17\xf4\x13\x68\xe6\xd4\xf1\x48" - "\xff\x49\xbf\x29\x07\x6b\x50\x15\xc5\x9f\x45\x79" - "\x45\x66\x2e\x3d\x35\x03\x84\x3f\x4a\xa5\xa3\xdf" - "\x9a\x9d\xf1\x0d", - .expectedlen = 64, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, -}; - -static const struct drbg_testvec drbg_nopr_ctr_aes256_tv_template[] = { - { - .entropy = (unsigned char *) - "\x36\x40\x19\x40\xfa\x8b\x1f\xba\x91\xa1\x66\x1f" - "\x21\x1d\x78\xa0\xb9\x38\x9a\x74\xe5\xbc\xcf\xec" - "\xe8\xd7\x66\xaf\x1a\x6d\x3b\x14\x49\x6f\x25\xb0" - "\xf1\x30\x1b\x4f\x50\x1b\xe3\x03\x80\xa1\x37\xeb", - .entropylen = 48, - .expected = (unsigned char *) - "\x58\x62\xeb\x38\xbd\x55\x8d\xd9\x78\xa6\x96\xe6" - "\xdf\x16\x47\x82\xdd\xd8\x87\xe7\xe9\xa6\xc9\xf3" - "\xf1\xfb\xaf\xb7\x89\x41\xb5\x35\xa6\x49\x12\xdf" - "\xd2\x24\xc6\xdc\x74\x54\xe5\x25\x0b\x3d\x97\x16" - "\x5e\x16\x26\x0c\x2f\xaf\x1c\xc7\x73\x5c\xb7\x5f" - "\xb4\xf0\x7e\x1d", - .expectedlen = 64, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, -}; - -static const struct drbg_testvec drbg_nopr_ctr_aes128_tv_template[] = { - { - .entropy = (unsigned char *) - "\x87\xe1\xc5\x32\x99\x7f\x57\xa3\x5c\x28\x6d\xe8" - "\x64\xbf\xf2\x64\xa3\x9e\x98\xdb\x6c\x10\x78\x7f", - .entropylen = 24, - .expected = (unsigned char *) - "\x2c\x14\x7e\x24\x11\x9a\xd8\xd4\xb2\xed\x61\xc1" - "\x53\xd0\x50\xc9\x24\xff\x59\x75\x15\xf1\x17\x3a" - "\x3d\xf4\x4b\x2c\x84\x28\xef\x89\x0e\xb9\xde\xf3" - "\xe4\x78\x04\xb2\xfd\x9b\x35\x7f\xe1\x3f\x8a\x3e" - "\x10\xc8\x67\x0a\xf9\xdf\x2d\x6c\x96\xfb\xb2\xb8" - "\xcb\x2d\xd6\xb0", - .expectedlen = 64, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x71\xbd\xce\x35\x42\x7d\x20\xbf\x58\xcf\x17\x74" - "\xce\x72\xd8\x33\x34\x50\x2d\x8f\x5b\x14\xc4\xdd", - .entropylen = 24, - .expected = (unsigned char *) - "\x97\x33\xe8\x20\x12\xe2\x7b\xa1\x46\x8f\xf2\x34" - "\xb3\xc9\xb6\x6b\x20\xb2\x4f\xee\x27\xd8\x0b\x21" - "\x8c\xff\x63\x73\x69\x29\xfb\xf3\x85\xcd\x88\x8e" - "\x43\x2c\x71\x8b\xa2\x55\xd2\x0f\x1d\x7f\xe3\xe1" - "\x2a\xa3\xe9\x2c\x25\x89\xc7\x14\x52\x99\x56\xcc" - "\xc3\xdf\xb3\x81", - .expectedlen = 64, - .addtla = (unsigned char *) - "\x66\xef\x42\xd6\x9a\x8c\x3d\x6d\x4a\x9e\x95\xa6" - "\x91\x4d\x81\x56", - .addtlb = (unsigned char *) - "\xe3\x18\x83\xd9\x4b\x5e\xc4\xcc\xaa\x61\x2f\xbb" - "\x4a\x55\xd1\xc6", - .addtllen = 16, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\xca\x4b\x1e\xfa\x75\xbd\x69\x36\x38\x73\xb8\xf9" - "\xdb\x4d\x35\x0e\x47\xbf\x6c\x37\x72\xfd\xf7\xa9", - .entropylen = 24, - .expected = (unsigned char *) - "\x59\xc3\x19\x79\x1b\xb1\xf3\x0e\xe9\x34\xae\x6e" - "\x8b\x1f\xad\x1f\x74\xca\x25\x45\x68\xb8\x7f\x75" - "\x12\xf8\xf2\xab\x4c\x23\x01\x03\x05\xe1\x70\xee" - "\x75\xd8\xcb\xeb\x23\x4c\x7a\x23\x6e\x12\x27\xdb" - "\x6f\x7a\xac\x3c\x44\xb7\x87\x4b\x65\x56\x74\x45" - "\x34\x30\x0c\x3d", - .expectedlen = 64, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\xeb\xaa\x60\x2c\x4d\xbe\x33\xff\x1b\xef\xbf\x0a" - "\x0b\xc6\x97\x54", - .perslen = 16, - }, { - .entropy = (unsigned char *) - "\xc0\x70\x1f\x92\x50\x75\x8f\xcd\xf2\xbe\x73\x98" - "\x80\xdb\x66\xeb\x14\x68\xb4\xa5\x87\x9c\x2d\xa6", - .entropylen = 24, - .expected = (unsigned char *) - "\x97\xc0\xc0\xe5\xa0\xcc\xf2\x4f\x33\x63\x48\x8a" - "\xdb\x13\x0a\x35\x89\xbf\x80\x65\x62\xee\x13\x95" - "\x7c\x33\xd3\x7d\xf4\x07\x77\x7a\x2b\x65\x0b\x5f" - "\x45\x5c\x13\xf1\x90\x77\x7f\xc5\x04\x3f\xcc\x1a" - "\x38\xf8\xcd\x1b\xbb\xd5\x57\xd1\x4a\x4c\x2e\x8a" - "\x2b\x49\x1e\x5c", - .expectedlen = 64, - .addtla = (unsigned char *) - "\xf9\x01\xf8\x16\x7a\x1d\xff\xde\x8e\x3c\x83\xe2" - "\x44\x85\xe7\xfe", - .addtlb = (unsigned char *) - "\x17\x1c\x09\x38\xc2\x38\x9f\x97\x87\x60\x55\xb4" - "\x82\x16\x62\x7f", - .addtllen = 16, - .pers = (unsigned char *) - "\x80\x08\xae\xe8\xe9\x69\x40\xc5\x08\x73\xc7\x9f" - "\x8e\xcf\xe0\x02", - .perslen = 16, - }, -}; - -/* Cast5 test vectors from RFC 2144 */ -static const struct cipher_testvec cast5_tv_template[] = { - { - .key = "\x01\x23\x45\x67\x12\x34\x56\x78" - "\x23\x45\x67\x89\x34\x56\x78\x9a", - .klen = 16, - .ptext = "\x01\x23\x45\x67\x89\xab\xcd\xef", - .ctext = "\x23\x8b\x4f\xe5\x84\x7e\x44\xb2", - .len = 8, - }, { - .key = "\x01\x23\x45\x67\x12\x34\x56\x78" - "\x23\x45", - .klen = 10, - .ptext = "\x01\x23\x45\x67\x89\xab\xcd\xef", - .ctext = "\xeb\x6a\x71\x1a\x2c\x02\x27\x1b", - .len = 8, - }, { - .key = "\x01\x23\x45\x67\x12", - .klen = 5, - .ptext = "\x01\x23\x45\x67\x89\xab\xcd\xef", - .ctext = "\x7a\xc8\x16\xd1\x6e\x9b\x30\x2e", - .len = 8, - }, { /* Generated from TF test vectors */ - .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" - "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", + .key = "\x01\x23\x45\x67\x12", + .klen = 5, + .ptext = "\x01\x23\x45\x67\x89\xab\xcd\xef", + .ctext = "\x7a\xc8\x16\xd1\x6e\x9b\x30\x2e", + .len = 8, + }, { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", .klen = 16, .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F", .ptext = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" @@ -32373,50 +29682,128 @@ static const struct comp_testvec zlib_deflate_decomp_tv_template[] = { }, }; -/* - * LZO test vectors (null-terminated strings). - */ -static const struct comp_testvec lzo_comp_tv_template[] = { +/* + * LZO test vectors (null-terminated strings). + */ +static const struct comp_testvec lzo_comp_tv_template[] = { + { + .inlen = 70, + .outlen = 57, + .input = "Join us now and share the software " + "Join us now and share the software ", + .output = "\x00\x0d\x4a\x6f\x69\x6e\x20\x75" + "\x73\x20\x6e\x6f\x77\x20\x61\x6e" + "\x64\x20\x73\x68\x61\x72\x65\x20" + "\x74\x68\x65\x20\x73\x6f\x66\x74" + "\x77\x70\x01\x32\x88\x00\x0c\x65" + "\x20\x74\x68\x65\x20\x73\x6f\x66" + "\x74\x77\x61\x72\x65\x20\x11\x00" + "\x00", + }, { + .inlen = 159, + .outlen = 131, + .input = "This document describes a compression method based on the LZO " + "compression algorithm. This document defines the application of " + "the LZO algorithm used in UBIFS.", + .output = "\x00\x2c\x54\x68\x69\x73\x20\x64" + "\x6f\x63\x75\x6d\x65\x6e\x74\x20" + "\x64\x65\x73\x63\x72\x69\x62\x65" + "\x73\x20\x61\x20\x63\x6f\x6d\x70" + "\x72\x65\x73\x73\x69\x6f\x6e\x20" + "\x6d\x65\x74\x68\x6f\x64\x20\x62" + "\x61\x73\x65\x64\x20\x6f\x6e\x20" + "\x74\x68\x65\x20\x4c\x5a\x4f\x20" + "\x2a\x8c\x00\x09\x61\x6c\x67\x6f" + "\x72\x69\x74\x68\x6d\x2e\x20\x20" + "\x2e\x54\x01\x03\x66\x69\x6e\x65" + "\x73\x20\x74\x06\x05\x61\x70\x70" + "\x6c\x69\x63\x61\x74\x76\x0a\x6f" + "\x66\x88\x02\x60\x09\x27\xf0\x00" + "\x0c\x20\x75\x73\x65\x64\x20\x69" + "\x6e\x20\x55\x42\x49\x46\x53\x2e" + "\x11\x00\x00", + }, +}; + +static const struct comp_testvec lzo_decomp_tv_template[] = { + { + .inlen = 133, + .outlen = 159, + .input = "\x00\x2b\x54\x68\x69\x73\x20\x64" + "\x6f\x63\x75\x6d\x65\x6e\x74\x20" + "\x64\x65\x73\x63\x72\x69\x62\x65" + "\x73\x20\x61\x20\x63\x6f\x6d\x70" + "\x72\x65\x73\x73\x69\x6f\x6e\x20" + "\x6d\x65\x74\x68\x6f\x64\x20\x62" + "\x61\x73\x65\x64\x20\x6f\x6e\x20" + "\x74\x68\x65\x20\x4c\x5a\x4f\x2b" + "\x8c\x00\x0d\x61\x6c\x67\x6f\x72" + "\x69\x74\x68\x6d\x2e\x20\x20\x54" + "\x68\x69\x73\x2a\x54\x01\x02\x66" + "\x69\x6e\x65\x73\x94\x06\x05\x61" + "\x70\x70\x6c\x69\x63\x61\x74\x76" + "\x0a\x6f\x66\x88\x02\x60\x09\x27" + "\xf0\x00\x0c\x20\x75\x73\x65\x64" + "\x20\x69\x6e\x20\x55\x42\x49\x46" + "\x53\x2e\x11\x00\x00", + .output = "This document describes a compression method based on the LZO " + "compression algorithm. This document defines the application of " + "the LZO algorithm used in UBIFS.", + }, { + .inlen = 46, + .outlen = 70, + .input = "\x00\x0d\x4a\x6f\x69\x6e\x20\x75" + "\x73\x20\x6e\x6f\x77\x20\x61\x6e" + "\x64\x20\x73\x68\x61\x72\x65\x20" + "\x74\x68\x65\x20\x73\x6f\x66\x74" + "\x77\x70\x01\x01\x4a\x6f\x69\x6e" + "\x3d\x88\x00\x11\x00\x00", + .output = "Join us now and share the software " + "Join us now and share the software ", + }, +}; + +static const struct comp_testvec lzorle_comp_tv_template[] = { { .inlen = 70, - .outlen = 57, + .outlen = 59, .input = "Join us now and share the software " "Join us now and share the software ", - .output = "\x00\x0d\x4a\x6f\x69\x6e\x20\x75" - "\x73\x20\x6e\x6f\x77\x20\x61\x6e" - "\x64\x20\x73\x68\x61\x72\x65\x20" - "\x74\x68\x65\x20\x73\x6f\x66\x74" - "\x77\x70\x01\x32\x88\x00\x0c\x65" - "\x20\x74\x68\x65\x20\x73\x6f\x66" - "\x74\x77\x61\x72\x65\x20\x11\x00" - "\x00", + .output = "\x11\x01\x00\x0d\x4a\x6f\x69\x6e" + "\x20\x75\x73\x20\x6e\x6f\x77\x20" + "\x61\x6e\x64\x20\x73\x68\x61\x72" + "\x65\x20\x74\x68\x65\x20\x73\x6f" + "\x66\x74\x77\x70\x01\x32\x88\x00" + "\x0c\x65\x20\x74\x68\x65\x20\x73" + "\x6f\x66\x74\x77\x61\x72\x65\x20" + "\x11\x00\x00", }, { .inlen = 159, - .outlen = 131, + .outlen = 133, .input = "This document describes a compression method based on the LZO " "compression algorithm. This document defines the application of " "the LZO algorithm used in UBIFS.", - .output = "\x00\x2c\x54\x68\x69\x73\x20\x64" - "\x6f\x63\x75\x6d\x65\x6e\x74\x20" - "\x64\x65\x73\x63\x72\x69\x62\x65" - "\x73\x20\x61\x20\x63\x6f\x6d\x70" - "\x72\x65\x73\x73\x69\x6f\x6e\x20" - "\x6d\x65\x74\x68\x6f\x64\x20\x62" - "\x61\x73\x65\x64\x20\x6f\x6e\x20" - "\x74\x68\x65\x20\x4c\x5a\x4f\x20" - "\x2a\x8c\x00\x09\x61\x6c\x67\x6f" - "\x72\x69\x74\x68\x6d\x2e\x20\x20" - "\x2e\x54\x01\x03\x66\x69\x6e\x65" - "\x73\x20\x74\x06\x05\x61\x70\x70" - "\x6c\x69\x63\x61\x74\x76\x0a\x6f" - "\x66\x88\x02\x60\x09\x27\xf0\x00" - "\x0c\x20\x75\x73\x65\x64\x20\x69" - "\x6e\x20\x55\x42\x49\x46\x53\x2e" - "\x11\x00\x00", + .output = "\x11\x01\x00\x2c\x54\x68\x69\x73" + "\x20\x64\x6f\x63\x75\x6d\x65\x6e" + "\x74\x20\x64\x65\x73\x63\x72\x69" + "\x62\x65\x73\x20\x61\x20\x63\x6f" + "\x6d\x70\x72\x65\x73\x73\x69\x6f" + "\x6e\x20\x6d\x65\x74\x68\x6f\x64" + "\x20\x62\x61\x73\x65\x64\x20\x6f" + "\x6e\x20\x74\x68\x65\x20\x4c\x5a" + "\x4f\x20\x2a\x8c\x00\x09\x61\x6c" + "\x67\x6f\x72\x69\x74\x68\x6d\x2e" + "\x20\x20\x2e\x54\x01\x03\x66\x69" + "\x6e\x65\x73\x20\x74\x06\x05\x61" + "\x70\x70\x6c\x69\x63\x61\x74\x76" + "\x0a\x6f\x66\x88\x02\x60\x09\x27" + "\xf0\x00\x0c\x20\x75\x73\x65\x64" + "\x20\x69\x6e\x20\x55\x42\x49\x46" + "\x53\x2e\x11\x00\x00", }, }; -static const struct comp_testvec lzo_decomp_tv_template[] = { +static const struct comp_testvec lzorle_decomp_tv_template[] = { { .inlen = 133, .outlen = 159, @@ -32441,14 +29828,16 @@ static const struct comp_testvec lzo_decomp_tv_template[] = { "compression algorithm. This document defines the application of " "the LZO algorithm used in UBIFS.", }, { - .inlen = 46, + .inlen = 59, .outlen = 70, - .input = "\x00\x0d\x4a\x6f\x69\x6e\x20\x75" - "\x73\x20\x6e\x6f\x77\x20\x61\x6e" - "\x64\x20\x73\x68\x61\x72\x65\x20" - "\x74\x68\x65\x20\x73\x6f\x66\x74" - "\x77\x70\x01\x01\x4a\x6f\x69\x6e" - "\x3d\x88\x00\x11\x00\x00", + .input = "\x11\x01\x00\x0d\x4a\x6f\x69\x6e" + "\x20\x75\x73\x20\x6e\x6f\x77\x20" + "\x61\x6e\x64\x20\x73\x68\x61\x72" + "\x65\x20\x74\x68\x65\x20\x73\x6f" + "\x66\x74\x77\x70\x01\x32\x88\x00" + "\x0c\x65\x20\x74\x68\x65\x20\x73" + "\x6f\x66\x74\x77\x61\x72\x65\x20" + "\x11\x00\x00", .output = "Join us now and share the software " "Join us now and share the software ", }, @@ -33646,39 +31035,536 @@ static const struct comp_testvec zstd_comp_tv_template[] = { }, }; -static const struct comp_testvec zstd_decomp_tv_template[] = { - { - .inlen = 43, - .outlen = 68, - .input = "\x28\xb5\x2f\xfd\x04\x50\xf5\x00\x00\xb8\x54\x68\x65" - "\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x20\x69\x73" - "\x20\x7a\x73\x74\x64\x2e\x20\x01\x00\x55\x73\x36\x01" - "\x6b\xf4\x13\x35", - .output = "The algorithm is zstd. " - "The algorithm is zstd. " - "The algorithm is zstd.", - }, - { - .inlen = 155, - .outlen = 244, - .input = "\x28\xb5\x2f\xfd\x04\x50\x75\x04\x00\x42\x4b\x1e\x17" - "\x90\x81\x31\x00\xf2\x2f\xe4\x36\xc9\xef\x92\x88\x32" - "\xc9\xf2\x24\x94\xd8\x68\x9a\x0f\x00\x0c\xc4\x31\x6f" - "\x0d\x0c\x38\xac\x5c\x48\x03\xcd\x63\x67\xc0\xf3\xad" - "\x4e\x90\xaa\x78\xa0\xa4\xc5\x99\xda\x2f\xb6\x24\x60" - "\xe2\x79\x4b\xaa\xb6\x6b\x85\x0b\xc9\xc6\x04\x66\x86" - "\xe2\xcc\xe2\x25\x3f\x4f\x09\xcd\xb8\x9d\xdb\xc1\x90" - "\xa9\x11\xbc\x35\x44\x69\x2d\x9c\x64\x4f\x13\x31\x64" - "\xcc\xfb\x4d\x95\x93\x86\x7f\x33\x7f\x1a\xef\xe9\x30" - "\xf9\x67\xa1\x94\x0a\x69\x0f\x60\xcd\xc3\xab\x99\xdc" - "\x42\xed\x97\x05\x00\x33\xc3\x15\x95\x3a\x06\xa0\x0e" - "\x20\xa9\x0e\x82\xb9\x43\x45\x01\xaa\x6d\xda\x0d", - .output = "zstd, short for Zstandard, is a fast lossless " - "compression algorithm, targeting real-time " - "compression scenarios at zlib-level and better " - "compression ratios. The zstd compression library " - "provides in-memory compression and decompression " - "functions.", - }, -}; +static const struct comp_testvec zstd_decomp_tv_template[] = { + { + .inlen = 43, + .outlen = 68, + .input = "\x28\xb5\x2f\xfd\x04\x50\xf5\x00\x00\xb8\x54\x68\x65" + "\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x20\x69\x73" + "\x20\x7a\x73\x74\x64\x2e\x20\x01\x00\x55\x73\x36\x01" + "\x6b\xf4\x13\x35", + .output = "The algorithm is zstd. " + "The algorithm is zstd. " + "The algorithm is zstd.", + }, + { + .inlen = 155, + .outlen = 244, + .input = "\x28\xb5\x2f\xfd\x04\x50\x75\x04\x00\x42\x4b\x1e\x17" + "\x90\x81\x31\x00\xf2\x2f\xe4\x36\xc9\xef\x92\x88\x32" + "\xc9\xf2\x24\x94\xd8\x68\x9a\x0f\x00\x0c\xc4\x31\x6f" + "\x0d\x0c\x38\xac\x5c\x48\x03\xcd\x63\x67\xc0\xf3\xad" + "\x4e\x90\xaa\x78\xa0\xa4\xc5\x99\xda\x2f\xb6\x24\x60" + "\xe2\x79\x4b\xaa\xb6\x6b\x85\x0b\xc9\xc6\x04\x66\x86" + "\xe2\xcc\xe2\x25\x3f\x4f\x09\xcd\xb8\x9d\xdb\xc1\x90" + "\xa9\x11\xbc\x35\x44\x69\x2d\x9c\x64\x4f\x13\x31\x64" + "\xcc\xfb\x4d\x95\x93\x86\x7f\x33\x7f\x1a\xef\xe9\x30" + "\xf9\x67\xa1\x94\x0a\x69\x0f\x60\xcd\xc3\xab\x99\xdc" + "\x42\xed\x97\x05\x00\x33\xc3\x15\x95\x3a\x06\xa0\x0e" + "\x20\xa9\x0e\x82\xb9\x43\x45\x01\xaa\x6d\xda\x0d", + .output = "zstd, short for Zstandard, is a fast lossless " + "compression algorithm, targeting real-time " + "compression scenarios at zlib-level and better " + "compression ratios. The zstd compression library " + "provides in-memory compression and decompression " + "functions.", + }, +}; + +/* based on aes_cbc_tv_template */ +static const struct cipher_testvec essiv_aes_cbc_tv_template[] = { + { + .key = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b" + "\x51\x2e\x03\xd5\x34\x12\x00\x06", + .klen = 16, + .iv = "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .ptext = "Single block msg", + .ctext = "\xfa\x59\xe7\x5f\x41\x56\x65\xc3" + "\x36\xca\x6b\x72\x10\x9f\x8c\xd4", + .len = 16, + }, { + .key = "\xc2\x86\x69\x6d\x88\x7c\x9a\xa0" + "\x61\x1b\xbb\x3e\x20\x25\xa4\x5a", + .klen = 16, + .iv = "\x56\x2e\x17\x99\x6d\x09\x3d\x28" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .ptext = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + .ctext = "\xc8\x59\x9a\xfe\x79\xe6\x7b\x20" + "\x06\x7d\x55\x0a\x5e\xc7\xb5\xa7" + "\x0b\x9c\x80\xd2\x15\xa1\xb8\x6d" + "\xc6\xab\x7b\x65\xd9\xfd\x88\xeb", + .len = 32, + }, { + .key = "\x8e\x73\xb0\xf7\xda\x0e\x64\x52" + "\xc8\x10\xf3\x2b\x80\x90\x79\xe5" + "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", + .klen = 24, + .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" + "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" + "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" + "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" + "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + .ctext = "\x96\x6d\xa9\x7a\x42\xe6\x01\xc7" + "\x17\xfc\xa7\x41\xd3\x38\x0b\xe5" + "\x51\x48\xf7\x7e\x5e\x26\xa9\xfe" + "\x45\x72\x1c\xd9\xde\xab\xf3\x4d" + "\x39\x47\xc5\x4f\x97\x3a\x55\x63" + "\x80\x29\x64\x4c\x33\xe8\x21\x8a" + "\x6a\xef\x6b\x6a\x8f\x43\xc0\xcb" + "\xf0\xf3\x6e\x74\x54\x44\x92\x44", + .len = 64, + }, { + .key = "\x60\x3d\xeb\x10\x15\xca\x71\xbe" + "\x2b\x73\xae\xf0\x85\x7d\x77\x81" + "\x1f\x35\x2c\x07\x3b\x61\x08\xd7" + "\x2d\x98\x10\xa3\x09\x14\xdf\xf4", + .klen = 32, + .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" + "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" + "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" + "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" + "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + .ctext = "\x24\x52\xf1\x48\x74\xd0\xa7\x93" + "\x75\x9b\x63\x46\xc0\x1c\x1e\x17" + "\x4d\xdc\x5b\x3a\x27\x93\x2a\x63" + "\xf7\xf1\xc7\xb3\x54\x56\x5b\x50" + "\xa3\x31\xa5\x8b\xd6\xfd\xb6\x3c" + "\x8b\xf6\xf2\x45\x05\x0c\xc8\xbb" + "\x32\x0b\x26\x1c\xe9\x8b\x02\xc0" + "\xb2\x6f\x37\xa7\x5b\xa8\xa9\x42", + .len = 64, + }, { + .key = "\xC9\x83\xA6\xC9\xEC\x0F\x32\x55" + "\x0F\x32\x55\x78\x9B\xBE\x78\x9B" + "\xBE\xE1\x04\x27\xE1\x04\x27\x4A" + "\x6D\x90\x4A\x6D\x90\xB3\xD6\xF9", + .klen = 32, + .iv = "\xE7\x82\x1D\xB8\x53\x11\xAC\x47" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .ptext = "\x50\xB9\x22\xAE\x17\x80\x0C\x75" + "\xDE\x47\xD3\x3C\xA5\x0E\x9A\x03" + "\x6C\xF8\x61\xCA\x33\xBF\x28\x91" + "\x1D\x86\xEF\x58\xE4\x4D\xB6\x1F" + "\xAB\x14\x7D\x09\x72\xDB\x44\xD0" + "\x39\xA2\x0B\x97\x00\x69\xF5\x5E" + "\xC7\x30\xBC\x25\x8E\x1A\x83\xEC" + "\x55\xE1\x4A\xB3\x1C\xA8\x11\x7A" + "\x06\x6F\xD8\x41\xCD\x36\x9F\x08" + "\x94\xFD\x66\xF2\x5B\xC4\x2D\xB9" + "\x22\x8B\x17\x80\xE9\x52\xDE\x47" + "\xB0\x19\xA5\x0E\x77\x03\x6C\xD5" + "\x3E\xCA\x33\x9C\x05\x91\xFA\x63" + "\xEF\x58\xC1\x2A\xB6\x1F\x88\x14" + "\x7D\xE6\x4F\xDB\x44\xAD\x16\xA2" + "\x0B\x74\x00\x69\xD2\x3B\xC7\x30" + "\x99\x02\x8E\xF7\x60\xEC\x55\xBE" + "\x27\xB3\x1C\x85\x11\x7A\xE3\x4C" + "\xD8\x41\xAA\x13\x9F\x08\x71\xFD" + "\x66\xCF\x38\xC4\x2D\x96\x22\x8B" + "\xF4\x5D\xE9\x52\xBB\x24\xB0\x19" + "\x82\x0E\x77\xE0\x49\xD5\x3E\xA7" + "\x10\x9C\x05\x6E\xFA\x63\xCC\x35" + "\xC1\x2A\x93\x1F\x88\xF1\x5A\xE6" + "\x4F\xB8\x21\xAD\x16\x7F\x0B\x74" + "\xDD\x46\xD2\x3B\xA4\x0D\x99\x02" + "\x6B\xF7\x60\xC9\x32\xBE\x27\x90" + "\x1C\x85\xEE\x57\xE3\x4C\xB5\x1E" + "\xAA\x13\x7C\x08\x71\xDA\x43\xCF" + "\x38\xA1\x0A\x96\xFF\x68\xF4\x5D" + "\xC6\x2F\xBB\x24\x8D\x19\x82\xEB" + "\x54\xE0\x49\xB2\x1B\xA7\x10\x79" + "\x05\x6E\xD7\x40\xCC\x35\x9E\x07" + "\x93\xFC\x65\xF1\x5A\xC3\x2C\xB8" + "\x21\x8A\x16\x7F\xE8\x51\xDD\x46" + "\xAF\x18\xA4\x0D\x76\x02\x6B\xD4" + "\x3D\xC9\x32\x9B\x04\x90\xF9\x62" + "\xEE\x57\xC0\x29\xB5\x1E\x87\x13" + "\x7C\xE5\x4E\xDA\x43\xAC\x15\xA1" + "\x0A\x73\xFF\x68\xD1\x3A\xC6\x2F" + "\x98\x01\x8D\xF6\x5F\xEB\x54\xBD" + "\x26\xB2\x1B\x84\x10\x79\xE2\x4B" + "\xD7\x40\xA9\x12\x9E\x07\x70\xFC" + "\x65\xCE\x37\xC3\x2C\x95\x21\x8A" + "\xF3\x5C\xE8\x51\xBA\x23\xAF\x18" + "\x81\x0D\x76\xDF\x48\xD4\x3D\xA6" + "\x0F\x9B\x04\x6D\xF9\x62\xCB\x34" + "\xC0\x29\x92\x1E\x87\xF0\x59\xE5" + "\x4E\xB7\x20\xAC\x15\x7E\x0A\x73" + "\xDC\x45\xD1\x3A\xA3\x0C\x98\x01" + "\x6A\xF6\x5F\xC8\x31\xBD\x26\x8F" + "\x1B\x84\xED\x56\xE2\x4B\xB4\x1D" + "\xA9\x12\x7B\x07\x70\xD9\x42\xCE" + "\x37\xA0\x09\x95\xFE\x67\xF3\x5C" + "\xC5\x2E\xBA\x23\x8C\x18\x81\xEA" + "\x53\xDF\x48\xB1\x1A\xA6\x0F\x78" + "\x04\x6D\xD6\x3F\xCB\x34\x9D\x06" + "\x92\xFB\x64\xF0\x59\xC2\x2B\xB7" + "\x20\x89\x15\x7E\xE7\x50\xDC\x45" + "\xAE\x17\xA3\x0C\x75\x01\x6A\xD3" + "\x3C\xC8\x31\x9A\x03\x8F\xF8\x61" + "\xED\x56\xBF\x28\xB4\x1D\x86\x12", + .ctext = "\x97\x7f\x69\x0f\x0f\x34\xa6\x33" + "\x66\x49\x7e\xd0\x4d\x1b\xc9\x64" + "\xf9\x61\x95\x98\x11\x00\x88\xf8" + "\x2e\x88\x01\x0f\x2b\xe1\xae\x3e" + "\xfe\xd6\x47\x30\x11\x68\x7d\x99" + "\xad\x69\x6a\xe8\x41\x5f\x1e\x16" + "\x00\x3a\x47\xdf\x8e\x7d\x23\x1c" + "\x19\x5b\x32\x76\x60\x03\x05\xc1" + "\xa0\xff\xcf\xcc\x74\x39\x46\x63" + "\xfe\x5f\xa6\x35\xa7\xb4\xc1\xf9" + "\x4b\x5e\x38\xcc\x8c\xc1\xa2\xcf" + "\x9a\xc3\xae\x55\x42\x46\x93\xd9" + "\xbd\x22\xd3\x8a\x19\x96\xc3\xb3" + "\x7d\x03\x18\xf9\x45\x09\x9c\xc8" + "\x90\xf3\x22\xb3\x25\x83\x9a\x75" + "\xbb\x04\x48\x97\x3a\x63\x08\x04" + "\xa0\x69\xf6\x52\xd4\x89\x93\x69" + "\xb4\x33\xa2\x16\x58\xec\x4b\x26" + "\x76\x54\x10\x0b\x6e\x53\x1e\xbc" + "\x16\x18\x42\xb1\xb1\xd3\x4b\xda" + "\x06\x9f\x8b\x77\xf7\xab\xd6\xed" + "\xa3\x1d\x90\xda\x49\x38\x20\xb8" + "\x6c\xee\xae\x3e\xae\x6c\x03\xb8" + "\x0b\xed\xc8\xaa\x0e\xc5\x1f\x90" + "\x60\xe2\xec\x1b\x76\xd0\xcf\xda" + "\x29\x1b\xb8\x5a\xbc\xf4\xba\x13" + "\x91\xa6\xcb\x83\x3f\xeb\xe9\x7b" + "\x03\xba\x40\x9e\xe6\x7a\xb2\x4a" + "\x73\x49\xfc\xed\xfb\x55\xa4\x24" + "\xc7\xa4\xd7\x4b\xf5\xf7\x16\x62" + "\x80\xd3\x19\x31\x52\x25\xa8\x69" + "\xda\x9a\x87\xf5\xf2\xee\x5d\x61" + "\xc1\x12\x72\x3e\x52\x26\x45\x3a" + "\xd8\x9d\x57\xfa\x14\xe2\x9b\x2f" + "\xd4\xaa\x5e\x31\xf4\x84\x89\xa4" + "\xe3\x0e\xb0\x58\x41\x75\x6a\xcb" + "\x30\x01\x98\x90\x15\x80\xf5\x27" + "\x92\x13\x81\xf0\x1c\x1e\xfc\xb1" + "\x33\xf7\x63\xb0\x67\xec\x2e\x5c" + "\x85\xe3\x5b\xd0\x43\x8a\xb8\x5f" + "\x44\x9f\xec\x19\xc9\x8f\xde\xdf" + "\x79\xef\xf8\xee\x14\x87\xb3\x34" + "\x76\x00\x3a\x9b\xc7\xed\xb1\x3d" + "\xef\x07\xb0\xe4\xfd\x68\x9e\xeb" + "\xc2\xb4\x1a\x85\x9a\x7d\x11\x88" + "\xf8\xab\x43\x55\x2b\x8a\x4f\x60" + "\x85\x9a\xf4\xba\xae\x48\x81\xeb" + "\x93\x07\x97\x9e\xde\x2a\xfc\x4e" + "\x31\xde\xaa\x44\xf7\x2a\xc3\xee" + "\x60\xa2\x98\x2c\x0a\x88\x50\xc5" + "\x6d\x89\xd3\xe4\xb6\xa7\xf4\xb0" + "\xcf\x0e\x89\xe3\x5e\x8f\x82\xf4" + "\x9d\xd1\xa9\x51\x50\x8a\xd2\x18" + "\x07\xb2\xaa\x3b\x7f\x58\x9b\xf4" + "\xb7\x24\x39\xd3\x66\x2f\x1e\xc0" + "\x11\xa3\x56\x56\x2a\x10\x73\xbc" + "\xe1\x23\xbf\xa9\x37\x07\x9c\xc3" + "\xb2\xc9\xa8\x1c\x5b\x5c\x58\xa4" + "\x77\x02\x26\xad\xc3\x40\x11\x53" + "\x93\x68\x72\xde\x05\x8b\x10\xbc" + "\xa6\xd4\x1b\xd9\x27\xd8\x16\x12" + "\x61\x2b\x31\x2a\x44\x87\x96\x58", + .len = 496, + }, +}; + +/* based on hmac_sha256_aes_cbc_tv_temp */ +static const struct aead_testvec essiv_hmac_sha256_aes_cbc_tv_temp[] = { + { +#ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ + "\x01\x00" /* rta type */ +#else + .key = "\x00\x08" /* rta length */ + "\x00\x01" /* rta type */ +#endif + "\x00\x00\x00\x10" /* enc key length */ + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x06\xa9\x21\x40\x36\xb8\xa1\x5b" + "\x51\x2e\x03\xd5\x34\x12\x00\x06", + .klen = 8 + 32 + 16, + .iv = "\xb3\x0c\x5a\x11\x41\xad\xc1\x04" + "\xbc\x1e\x7e\x35\xb0\x5d\x78\x29", + .assoc = "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30" + "\xb4\x22\xda\x80\x2c\x9f\xac\x41", + .alen = 16, + .ptext = "Single block msg", + .plen = 16, + .ctext = "\xe3\x53\x77\x9c\x10\x79\xae\xb8" + "\x27\x08\x94\x2d\xbe\x77\x18\x1a" + "\xcc\xde\x2d\x6a\xae\xf1\x0b\xcc" + "\x38\x06\x38\x51\xb4\xb8\xf3\x5b" + "\x5c\x34\xa6\xa3\x6e\x0b\x05\xe5" + "\x6a\x6d\x44\xaa\x26\xa8\x44\xa5", + .clen = 16 + 32, + }, { +#ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ + "\x01\x00" /* rta type */ +#else + .key = "\x00\x08" /* rta length */ + "\x00\x01" /* rta type */ +#endif + "\x00\x00\x00\x10" /* enc key length */ + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\xc2\x86\x69\x6d\x88\x7c\x9a\xa0" + "\x61\x1b\xbb\x3e\x20\x25\xa4\x5a", + .klen = 8 + 32 + 16, + .iv = "\x56\xe8\x14\xa5\x74\x18\x75\x13" + "\x2f\x79\xe7\xc8\x65\xe3\x48\x45", + .assoc = "\x56\x2e\x17\x99\x6d\x09\x3d\x28" + "\xdd\xb3\xba\x69\x5a\x2e\x6f\x58", + .alen = 16, + .ptext = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + .plen = 32, + .ctext = "\xd2\x96\xcd\x94\xc2\xcc\xcf\x8a" + "\x3a\x86\x30\x28\xb5\xe1\xdc\x0a" + "\x75\x86\x60\x2d\x25\x3c\xff\xf9" + "\x1b\x82\x66\xbe\xa6\xd6\x1a\xb1" + "\xf5\x33\x53\xf3\x68\x85\x2a\x99" + "\x0e\x06\x58\x8f\xba\xf6\x06\xda" + "\x49\x69\x0d\x5b\xd4\x36\x06\x62" + "\x35\x5e\x54\x58\x53\x4d\xdf\xbf", + .clen = 32 + 32, + }, { +#ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ + "\x01\x00" /* rta type */ +#else + .key = "\x00\x08" /* rta length */ + "\x00\x01" /* rta type */ +#endif + "\x00\x00\x00\x10" /* enc key length */ + "\x11\x22\x33\x44\x55\x66\x77\x88" + "\x99\xaa\xbb\xcc\xdd\xee\xff\x11" + "\x22\x33\x44\x55\x66\x77\x88\x99" + "\xaa\xbb\xcc\xdd\xee\xff\x11\x22" + "\x6c\x3e\xa0\x47\x76\x30\xce\x21" + "\xa2\xce\x33\x4a\xa7\x46\xc2\xcd", + .klen = 8 + 32 + 16, + .iv = "\x1f\x6b\xfb\xd6\x6b\x72\x2f\xc9" + "\xb6\x9f\x8c\x10\xa8\x96\x15\x64", + .assoc = "\xc7\x82\xdc\x4c\x09\x8c\x66\xcb" + "\xd9\xcd\x27\xd8\x25\x68\x2c\x81", + .alen = 16, + .ptext = "This is a 48-byte message (exactly 3 AES blocks)", + .plen = 48, + .ctext = "\xd0\xa0\x2b\x38\x36\x45\x17\x53" + "\xd4\x93\x66\x5d\x33\xf0\xe8\x86" + "\x2d\xea\x54\xcd\xb2\x93\xab\xc7" + "\x50\x69\x39\x27\x67\x72\xf8\xd5" + "\x02\x1c\x19\x21\x6b\xad\x52\x5c" + "\x85\x79\x69\x5d\x83\xba\x26\x84" + "\x68\xb9\x3e\x90\x38\xa0\x88\x01" + "\xe7\xc6\xce\x10\x31\x2f\x9b\x1d" + "\x24\x78\xfb\xbe\x02\xe0\x4f\x40" + "\x10\xbd\xaa\xc6\xa7\x79\xe0\x1a", + .clen = 48 + 32, + }, { +#ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ + "\x01\x00" /* rta type */ +#else + .key = "\x00\x08" /* rta length */ + "\x00\x01" /* rta type */ +#endif + "\x00\x00\x00\x10" /* enc key length */ + "\x11\x22\x33\x44\x55\x66\x77\x88" + "\x99\xaa\xbb\xcc\xdd\xee\xff\x11" + "\x22\x33\x44\x55\x66\x77\x88\x99" + "\xaa\xbb\xcc\xdd\xee\xff\x11\x22" + "\x56\xe4\x7a\x38\xc5\x59\x89\x74" + "\xbc\x46\x90\x3d\xba\x29\x03\x49", + .klen = 8 + 32 + 16, + .iv = "\x13\xe5\xf2\xef\x61\x97\x59\x35" + "\x9b\x36\x84\x46\x4e\x63\xd1\x41", + .assoc = "\x8c\xe8\x2e\xef\xbe\xa0\xda\x3c" + "\x44\x69\x9e\xd7\xdb\x51\xb7\xd9", + .alen = 16, + .ptext = "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf", + .plen = 64, + .ctext = "\xc3\x0e\x32\xff\xed\xc0\x77\x4e" + "\x6a\xff\x6a\xf0\x86\x9f\x71\xaa" + "\x0f\x3a\xf0\x7a\x9a\x31\xa9\xc6" + "\x84\xdb\x20\x7e\xb0\xef\x8e\x4e" + "\x35\x90\x7a\xa6\x32\xc3\xff\xdf" + "\x86\x8b\xb7\xb2\x9d\x3d\x46\xad" + "\x83\xce\x9f\x9a\x10\x2e\xe9\x9d" + "\x49\xa5\x3e\x87\xf4\xc3\xda\x55" + "\x7a\x1b\xd4\x3c\xdb\x17\x95\xe2" + "\xe0\x93\xec\xc9\x9f\xf7\xce\xd8" + "\x3f\x54\xe2\x49\x39\xe3\x71\x25" + "\x2b\x6c\xe9\x5d\xec\xec\x2b\x64", + .clen = 64 + 32, + }, { +#ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ + "\x01\x00" /* rta type */ +#else + .key = "\x00\x08" /* rta length */ + "\x00\x01" /* rta type */ +#endif + "\x00\x00\x00\x10" /* enc key length */ + "\x11\x22\x33\x44\x55\x66\x77\x88" + "\x99\xaa\xbb\xcc\xdd\xee\xff\x11" + "\x22\x33\x44\x55\x66\x77\x88\x99" + "\xaa\xbb\xcc\xdd\xee\xff\x11\x22" + "\x90\xd3\x82\xb4\x10\xee\xba\x7a" + "\xd9\x38\xc4\x6c\xec\x1a\x82\xbf", + .klen = 8 + 32 + 16, + .iv = "\xe4\x13\xa1\x15\xe9\x6b\xb8\x23" + "\x81\x7a\x94\x29\xab\xfd\xd2\x2c", + .assoc = "\x00\x00\x43\x21\x00\x00\x00\x01" + "\xe9\x6e\x8c\x08\xab\x46\x57\x63" + "\xfd\x09\x8d\x45\xdd\x3f\xf8\x93", + .alen = 24, + .ptext = "\x08\x00\x0e\xbd\xa7\x0a\x00\x00" + "\x8e\x9c\x08\x3d\xb9\x5b\x07\x00" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0e\x01", + .plen = 80, + .ctext = "\xf6\x63\xc2\x5d\x32\x5c\x18\xc6" + "\xa9\x45\x3e\x19\x4e\x12\x08\x49" + "\xa4\x87\x0b\x66\xcc\x6b\x99\x65" + "\x33\x00\x13\xb4\x89\x8d\xc8\x56" + "\xa4\x69\x9e\x52\x3a\x55\xdb\x08" + "\x0b\x59\xec\x3a\x8e\x4b\x7e\x52" + "\x77\x5b\x07\xd1\xdb\x34\xed\x9c" + "\x53\x8a\xb5\x0c\x55\x1b\x87\x4a" + "\xa2\x69\xad\xd0\x47\xad\x2d\x59" + "\x13\xac\x19\xb7\xcf\xba\xd4\xa6" + "\xbb\xd4\x0f\xbe\xa3\x3b\x4c\xb8" + "\x3a\xd2\xe1\x03\x86\xa5\x59\xb7" + "\x73\xc3\x46\x20\x2c\xb1\xef\x68" + "\xbb\x8a\x32\x7e\x12\x8c\x69\xcf", + .clen = 80 + 32, + }, { +#ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ + "\x01\x00" /* rta type */ +#else + .key = "\x00\x08" /* rta length */ + "\x00\x01" /* rta type */ +#endif + "\x00\x00\x00\x18" /* enc key length */ + "\x11\x22\x33\x44\x55\x66\x77\x88" + "\x99\xaa\xbb\xcc\xdd\xee\xff\x11" + "\x22\x33\x44\x55\x66\x77\x88\x99" + "\xaa\xbb\xcc\xdd\xee\xff\x11\x22" + "\x8e\x73\xb0\xf7\xda\x0e\x64\x52" + "\xc8\x10\xf3\x2b\x80\x90\x79\xe5" + "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", + .klen = 8 + 32 + 24, + .iv = "\x49\xca\x41\xc9\x6b\xbf\x6c\x98" + "\x38\x2f\xa7\x3d\x4d\x80\x49\xb0", + .assoc = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + .alen = 16, + .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" + "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" + "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" + "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" + "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + .plen = 64, + .ctext = "\x4f\x02\x1d\xb2\x43\xbc\x63\x3d" + "\x71\x78\x18\x3a\x9f\xa0\x71\xe8" + "\xb4\xd9\xad\xa9\xad\x7d\xed\xf4" + "\xe5\xe7\x38\x76\x3f\x69\x14\x5a" + "\x57\x1b\x24\x20\x12\xfb\x7a\xe0" + "\x7f\xa9\xba\xac\x3d\xf1\x02\xe0" + "\x08\xb0\xe2\x79\x88\x59\x88\x81" + "\xd9\x20\xa9\xe6\x4f\x56\x15\xcd" + "\x2f\xee\x5f\xdb\x66\xfe\x79\x09" + "\x61\x81\x31\xea\x5b\x3d\x8e\xfb" + "\xca\x71\x85\x93\xf7\x85\x55\x8b" + "\x7a\xe4\x94\xca\x8b\xba\x19\x33", + .clen = 64 + 32, + }, { +#ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ + "\x01\x00" /* rta type */ +#else + .key = "\x00\x08" /* rta length */ + "\x00\x01" /* rta type */ +#endif + "\x00\x00\x00\x20" /* enc key length */ + "\x11\x22\x33\x44\x55\x66\x77\x88" + "\x99\xaa\xbb\xcc\xdd\xee\xff\x11" + "\x22\x33\x44\x55\x66\x77\x88\x99" + "\xaa\xbb\xcc\xdd\xee\xff\x11\x22" + "\x60\x3d\xeb\x10\x15\xca\x71\xbe" + "\x2b\x73\xae\xf0\x85\x7d\x77\x81" + "\x1f\x35\x2c\x07\x3b\x61\x08\xd7" + "\x2d\x98\x10\xa3\x09\x14\xdf\xf4", + .klen = 8 + 32 + 32, + .iv = "\xdf\xab\xf2\x7c\xdc\xe0\x33\x4c" + "\xf9\x75\xaf\xf9\x2f\x60\x3a\x9b", + .assoc = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + .alen = 16, + .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" + "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" + "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" + "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" + "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + .plen = 64, + .ctext = "\xf5\x8c\x4c\x04\xd6\xe5\xf1\xba" + "\x77\x9e\xab\xfb\x5f\x7b\xfb\xd6" + "\x9c\xfc\x4e\x96\x7e\xdb\x80\x8d" + "\x67\x9f\x77\x7b\xc6\x70\x2c\x7d" + "\x39\xf2\x33\x69\xa9\xd9\xba\xcf" + "\xa5\x30\xe2\x63\x04\x23\x14\x61" + "\xb2\xeb\x05\xe2\xc3\x9b\xe9\xfc" + "\xda\x6c\x19\x07\x8c\x6a\x9d\x1b" + "\x24\x29\xed\xc2\x31\x49\xdb\xb1" + "\x8f\x74\xbd\x17\x92\x03\xbe\x8f" + "\xf3\x61\xde\x1c\xe9\xdb\xcd\xd0" + "\xcc\xce\xe9\x85\x57\xcf\x6f\x5f", + .clen = 64 + 32, + }, +}; + #endif /* _CRYPTO_TESTMGR_H */ diff --git a/crypto/xts.c b/crypto/xts.c index 11211003db7ed1a3647ba43e61ffac044bbc3612..ab117633d64e775520a6ab542282e4a839a8a714 100644 --- a/crypto/xts.c +++ b/crypto/xts.c @@ -1,8 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* XTS: as defined in IEEE1619/D16 * http://grouper.ieee.org/groups/1619/email/pdf00086.pdf - * (sector sizes which are not a multiple of 16 bytes are, - * however currently unsupported) * * Copyright (c) 2007 Rik Snel * @@ -34,6 +32,8 @@ struct xts_instance_ctx { struct rctx { le128 t; + struct scatterlist *tail; + struct scatterlist sg[2]; struct skcipher_request subreq; }; @@ -84,10 +84,11 @@ static int setkey(struct crypto_skcipher *parent, const u8 *key, * mutliple calls to the 'ecb(..)' instance, which usually would be slower than * just doing the gf128mul_x_ble() calls again. */ -static int xor_tweak(struct skcipher_request *req, bool second_pass) +static int xor_tweak(struct skcipher_request *req, bool second_pass, bool enc) { struct rctx *rctx = skcipher_request_ctx(req); struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + const bool cts = (req->cryptlen % XTS_BLOCK_SIZE); const int bs = XTS_BLOCK_SIZE; struct skcipher_walk w; le128 t = rctx->t; @@ -109,6 +110,20 @@ static int xor_tweak(struct skcipher_request *req, bool second_pass) wdst = w.dst.virt.addr; do { + if (unlikely(cts) && + w.total - w.nbytes + avail < 2 * XTS_BLOCK_SIZE) { + if (!enc) { + if (second_pass) + rctx->t = t; + gf128mul_x_ble(&t, &t); + } + le128_xor(wdst, &t, wsrc); + if (enc && second_pass) + gf128mul_x_ble(&rctx->t, &t); + skcipher_walk_done(&w, avail - bs); + return 0; + } + le128_xor(wdst++, &t, wsrc++); gf128mul_x_ble(&t, &t); } while ((avail -= bs) >= bs); @@ -119,17 +134,71 @@ static int xor_tweak(struct skcipher_request *req, bool second_pass) return err; } -static int xor_tweak_pre(struct skcipher_request *req) +static int xor_tweak_pre(struct skcipher_request *req, bool enc) { - return xor_tweak(req, false); + return xor_tweak(req, false, enc); } -static int xor_tweak_post(struct skcipher_request *req) +static int xor_tweak_post(struct skcipher_request *req, bool enc) { - return xor_tweak(req, true); + return xor_tweak(req, true, enc); } -static void crypt_done(struct crypto_async_request *areq, int err) +static void cts_done(struct crypto_async_request *areq, int err) +{ + struct skcipher_request *req = areq->data; + le128 b; + + if (!err) { + struct rctx *rctx = skcipher_request_ctx(req); + + scatterwalk_map_and_copy(&b, rctx->tail, 0, XTS_BLOCK_SIZE, 0); + le128_xor(&b, &rctx->t, &b); + scatterwalk_map_and_copy(&b, rctx->tail, 0, XTS_BLOCK_SIZE, 1); + } + + skcipher_request_complete(req, err); +} + +static int cts_final(struct skcipher_request *req, + int (*crypt)(struct skcipher_request *req)) +{ + struct priv *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); + int offset = req->cryptlen & ~(XTS_BLOCK_SIZE - 1); + struct rctx *rctx = skcipher_request_ctx(req); + struct skcipher_request *subreq = &rctx->subreq; + int tail = req->cryptlen % XTS_BLOCK_SIZE; + le128 b[2]; + int err; + + rctx->tail = scatterwalk_ffwd(rctx->sg, req->dst, + offset - XTS_BLOCK_SIZE); + + scatterwalk_map_and_copy(b, rctx->tail, 0, XTS_BLOCK_SIZE, 0); + memcpy(b + 1, b, tail); + scatterwalk_map_and_copy(b, req->src, offset, tail, 0); + + le128_xor(b, &rctx->t, b); + + scatterwalk_map_and_copy(b, rctx->tail, 0, XTS_BLOCK_SIZE + tail, 1); + + skcipher_request_set_tfm(subreq, ctx->child); + skcipher_request_set_callback(subreq, req->base.flags, cts_done, req); + skcipher_request_set_crypt(subreq, rctx->tail, rctx->tail, + XTS_BLOCK_SIZE, NULL); + + err = crypt(subreq); + if (err) + return err; + + scatterwalk_map_and_copy(b, rctx->tail, 0, XTS_BLOCK_SIZE, 0); + le128_xor(b, &rctx->t, b); + scatterwalk_map_and_copy(b, rctx->tail, 0, XTS_BLOCK_SIZE, 1); + + return 0; +} + +static void encrypt_done(struct crypto_async_request *areq, int err) { struct skcipher_request *req = areq->data; @@ -137,47 +206,90 @@ static void crypt_done(struct crypto_async_request *areq, int err) struct rctx *rctx = skcipher_request_ctx(req); rctx->subreq.base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; - err = xor_tweak_post(req); + err = xor_tweak_post(req, true); + + if (!err && unlikely(req->cryptlen % XTS_BLOCK_SIZE)) { + err = cts_final(req, crypto_skcipher_encrypt); + if (err == -EINPROGRESS) + return; + } } skcipher_request_complete(req, err); } -static void init_crypt(struct skcipher_request *req) +static void decrypt_done(struct crypto_async_request *areq, int err) +{ + struct skcipher_request *req = areq->data; + + if (!err) { + struct rctx *rctx = skcipher_request_ctx(req); + + rctx->subreq.base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + err = xor_tweak_post(req, false); + + if (!err && unlikely(req->cryptlen % XTS_BLOCK_SIZE)) { + err = cts_final(req, crypto_skcipher_decrypt); + if (err == -EINPROGRESS) + return; + } + } + + skcipher_request_complete(req, err); +} + +static int init_crypt(struct skcipher_request *req, crypto_completion_t compl) { struct priv *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); struct rctx *rctx = skcipher_request_ctx(req); struct skcipher_request *subreq = &rctx->subreq; + if (req->cryptlen < XTS_BLOCK_SIZE) + return -EINVAL; + skcipher_request_set_tfm(subreq, ctx->child); - skcipher_request_set_callback(subreq, req->base.flags, crypt_done, req); + skcipher_request_set_callback(subreq, req->base.flags, compl, req); skcipher_request_set_crypt(subreq, req->dst, req->dst, - req->cryptlen, NULL); + req->cryptlen & ~(XTS_BLOCK_SIZE - 1), NULL); /* calculate first value of T */ crypto_cipher_encrypt_one(ctx->tweak, (u8 *)&rctx->t, req->iv); + + return 0; } static int encrypt(struct skcipher_request *req) { struct rctx *rctx = skcipher_request_ctx(req); struct skcipher_request *subreq = &rctx->subreq; + int err; - init_crypt(req); - return xor_tweak_pre(req) ?: - crypto_skcipher_encrypt(subreq) ?: - xor_tweak_post(req); + err = init_crypt(req, encrypt_done) ?: + xor_tweak_pre(req, true) ?: + crypto_skcipher_encrypt(subreq) ?: + xor_tweak_post(req, true); + + if (err || likely((req->cryptlen % XTS_BLOCK_SIZE) == 0)) + return err; + + return cts_final(req, crypto_skcipher_encrypt); } static int decrypt(struct skcipher_request *req) { struct rctx *rctx = skcipher_request_ctx(req); struct skcipher_request *subreq = &rctx->subreq; + int err; + + err = init_crypt(req, decrypt_done) ?: + xor_tweak_pre(req, false) ?: + crypto_skcipher_decrypt(subreq) ?: + xor_tweak_post(req, false); + + if (err || likely((req->cryptlen % XTS_BLOCK_SIZE) == 0)) + return err; - init_crypt(req); - return xor_tweak_pre(req) ?: - crypto_skcipher_decrypt(subreq) ?: - xor_tweak_post(req); + return cts_final(req, crypto_skcipher_decrypt); } static int init_tfm(struct crypto_skcipher *tfm) diff --git a/drivers/Kconfig b/drivers/Kconfig index 61cf4ea2c229b3c03e2fcb5a890def6a15642d31..8befa53f43beb57babb2919b5e1bd0a0eda31e0f 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -30,8 +30,6 @@ source "drivers/block/Kconfig" source "drivers/nvme/Kconfig" -# misc before ide - BLK_DEV_SGIIOC4 depends on SGI_IOC4 - source "drivers/misc/Kconfig" source "drivers/ide/Kconfig" @@ -108,8 +106,6 @@ source "drivers/hid/Kconfig" source "drivers/usb/Kconfig" -source "drivers/uwb/Kconfig" - source "drivers/mmc/Kconfig" source "drivers/memstick/Kconfig" @@ -146,6 +142,8 @@ source "drivers/hv/Kconfig" source "drivers/xen/Kconfig" +source "drivers/greybus/Kconfig" + source "drivers/staging/Kconfig" source "drivers/platform/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 6d37564e783cb2d27f86a5c38b00891dee611cee..aaef17cc651287afb4b51fca89829b2efa743365 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -100,7 +100,6 @@ obj-$(CONFIG_ZORRO) += zorro/ obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/ obj-$(CONFIG_PARIDE) += block/paride/ obj-$(CONFIG_TC) += tc/ -obj-$(CONFIG_UWB) += uwb/ obj-$(CONFIG_USB_PHY) += usb/ obj-$(CONFIG_USB) += usb/ obj-$(CONFIG_USB_SUPPORT) += usb/ @@ -132,7 +131,6 @@ obj-y += mmc/ obj-$(CONFIG_MEMSTICK) += memstick/ obj-$(CONFIG_NEW_LEDS) += leds/ obj-$(CONFIG_INFINIBAND) += infiniband/ -obj-$(CONFIG_SGI_SN) += sn/ obj-y += firmware/ obj-$(CONFIG_CRYPTO) += crypto/ obj-$(CONFIG_SUPERH) += sh/ @@ -148,6 +146,7 @@ obj-$(CONFIG_BCMA) += bcma/ obj-$(CONFIG_VHOST_RING) += vhost/ obj-$(CONFIG_VHOST) += vhost/ obj-$(CONFIG_VLYNQ) += vlynq/ +obj-$(CONFIG_GREYBUS) += greybus/ obj-$(CONFIG_STAGING) += staging/ obj-y += platform/ diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 5f615897328987af48a04bf827659f83ba3dc939..ebe1e9e5fd81cb5a134d85c244fa81cba335d88c 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -323,7 +323,7 @@ config ACPI_NUMA bool "NUMA support" depends on NUMA depends on (X86 || IA64 || ARM64) - default y if IA64_GENERIC || IA64_SGI_SN2 || ARM64 + default y if IA64 || ARM64 config ACPI_CUSTOM_DSDT_FILE string "Custom DSDT Table file to include" diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index d696f165a50e6e815deef12dcc0b19d31fd22494..60bbc5090abec0a626d88dda38c3729b41cc2446 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -219,12 +219,13 @@ static void bsw_pwm_setup(struct lpss_private_data *pdata) } static const struct lpss_device_desc lpt_dev_desc = { - .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR, + .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR + | LPSS_SAVE_CTX, .prv_offset = 0x800, }; static const struct lpss_device_desc lpt_i2c_dev_desc = { - .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_LTR, + .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_LTR | LPSS_SAVE_CTX, .prv_offset = 0x800, }; @@ -236,7 +237,8 @@ static struct property_entry uart_properties[] = { }; static const struct lpss_device_desc lpt_uart_dev_desc = { - .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR, + .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR + | LPSS_SAVE_CTX, .clk_con_id = "baudclk", .prv_offset = 0x800, .setup = lpss_uart_setup, diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 24f065114d4240160301a22999a91dc37dca046f..2c4dda0787e849af8034710760393e2b0684e5cd 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -279,9 +279,13 @@ static int acpi_processor_get_info(struct acpi_device *device) } if (acpi_duplicate_processor_id(pr->acpi_id)) { - dev_err(&device->dev, - "Failed to get unique processor _UID (0x%x)\n", - pr->acpi_id); + if (pr->acpi_id == 0xff) + dev_info_once(&device->dev, + "Entry not well-defined, consider updating BIOS\n"); + else + dev_err(&device->dev, + "Failed to get unique processor _UID (0x%x)\n", + pr->acpi_id); return -ENODEV; } diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 13d513b81589207a4c9909e9577438310f4c5040..1ea52576f0a2e490c58cba27108b3eae5f9a8679 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -134,12 +134,12 @@ struct acpi_namespace_node { union acpi_operand_object *object; /* Interpreter object */ u8 descriptor_type; /* Differentiate object descriptor types */ u8 type; /* ACPI Type associated with this name */ - u8 flags; /* Miscellaneous flags */ - acpi_owner_id owner_id; /* Node creator */ + u16 flags; /* Miscellaneous flags */ union acpi_name_union name; /* ACPI Name, always 4 chars per ACPI spec */ struct acpi_namespace_node *parent; /* Parent node */ struct acpi_namespace_node *child; /* First child */ struct acpi_namespace_node *peer; /* First peer */ + acpi_owner_id owner_id; /* Node creator */ /* * The following fields are used by the ASL compiler and disassembler only diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index b2ef703d7df8b63361b7a00c8e2ddbd497aeadca..8def0e3d690fdaa69bb58fc78c59229df0412e52 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -153,8 +153,8 @@ struct acpi_object_method { } dispatch; u32 aml_length; - u8 thread_count; acpi_owner_id owner_id; + u8 thread_count; }; /* Flags for info_flags field above */ diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h index 8a4e6b4aaf2c3761ee92adac825c1b0248781fcf..218ff4c8b81715a28da6693de901d8144e40e9d4 100644 --- a/drivers/acpi/acpica/acstruct.h +++ b/drivers/acpi/acpica/acstruct.h @@ -167,9 +167,9 @@ struct acpi_evaluate_info { u32 return_flags; /* Used for return value analysis */ u32 return_btype; /* Bitmapped type of the returned object */ u16 param_count; /* Count of the input argument list */ + u16 node_flags; /* Same as Node->Flags */ u8 pass_number; /* Parser pass number */ u8 return_object_type; /* Object type of the returned object */ - u8 node_flags; /* Same as Node->Flags */ u8 flags; /* General flags */ }; diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 9022537567e9d2cd184d36ae01003c8608d203cc..601808be86d18e7a73ad4d731dd0eae164aefc8a 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -686,22 +686,26 @@ void acpi_ut_delete_address_lists(void); /* * utxferror - various error/warning output functions */ +ACPI_PRINTF_LIKE(5) void ACPI_INTERNAL_VAR_XFACE acpi_ut_predefined_warning(const char *module_name, u32 line_number, char *pathname, - u8 node_flags, const char *format, ...); + u16 node_flags, const char *format, ...); +ACPI_PRINTF_LIKE(5) void ACPI_INTERNAL_VAR_XFACE acpi_ut_predefined_info(const char *module_name, u32 line_number, - char *pathname, u8 node_flags, const char *format, ...); + char *pathname, + u16 node_flags, const char *format, ...); +ACPI_PRINTF_LIKE(5) void ACPI_INTERNAL_VAR_XFACE acpi_ut_predefined_bios_error(const char *module_name, u32 line_number, char *pathname, - u8 node_flags, const char *format, ...); + u16 node_flags, const char *format, ...); void acpi_ut_prefixed_namespace_error(const char *module_name, diff --git a/drivers/acpi/acpica/dbhistry.c b/drivers/acpi/acpica/dbhistry.c index 7809bd94a18ddc075e406334afe5ce6ab50d49c5..47d2e50598491964561c302b455c99b19481f8cb 100644 --- a/drivers/acpi/acpica/dbhistry.c +++ b/drivers/acpi/acpica/dbhistry.c @@ -121,7 +121,7 @@ void acpi_db_display_history(void) for (i = 0; i < acpi_gbl_num_history; i++) { if (acpi_gbl_history_buffer[history_index].command) { - acpi_os_printf("%3ld %s\n", + acpi_os_printf("%3u %s\n", acpi_gbl_history_buffer[history_index]. cmd_num, acpi_gbl_history_buffer[history_index]. diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c index 3e5f95390f0dd8a179c7e23751cf30a1d960e958..55a7e10998d87ed44f5716ab0fdc2d1b6538afe0 100644 --- a/drivers/acpi/acpica/dbinput.c +++ b/drivers/acpi/acpica/dbinput.c @@ -593,7 +593,7 @@ static u32 acpi_db_get_line(char *input_buffer) input_buffer)) { acpi_os_printf ("Buffer overflow while parsing input line (max %u characters)\n", - sizeof(acpi_gbl_db_parsed_buf)); + (u32)sizeof(acpi_gbl_db_parsed_buf)); return (0); } @@ -853,24 +853,24 @@ acpi_db_command_dispatch(char *input_buffer, if (param_count == 0) { acpi_os_printf - ("Current debug level for file output is: %8.8lX\n", + ("Current debug level for file output is: %8.8X\n", acpi_gbl_db_debug_level); acpi_os_printf - ("Current debug level for console output is: %8.8lX\n", + ("Current debug level for console output is: %8.8X\n", acpi_gbl_db_console_debug_level); } else if (param_count == 2) { temp = acpi_gbl_db_console_debug_level; acpi_gbl_db_console_debug_level = strtoul(acpi_gbl_db_args[1], NULL, 16); acpi_os_printf - ("Debug Level for console output was %8.8lX, now %8.8lX\n", + ("Debug Level for console output was %8.8X, now %8.8X\n", temp, acpi_gbl_db_console_debug_level); } else { temp = acpi_gbl_db_debug_level; acpi_gbl_db_debug_level = strtoul(acpi_gbl_db_args[1], NULL, 16); acpi_os_printf - ("Debug Level for file output was %8.8lX, now %8.8lX\n", + ("Debug Level for file output was %8.8X, now %8.8X\n", temp, acpi_gbl_db_debug_level); } break; diff --git a/drivers/acpi/acpica/dbmethod.c b/drivers/acpi/acpica/dbmethod.c index d8b7a0fe92ecd07bca1547ac26f58ea2a5e5e28e..76a15b6ffc5d3688ae5ee2b6a63b0e58178867e6 100644 --- a/drivers/acpi/acpica/dbmethod.c +++ b/drivers/acpi/acpica/dbmethod.c @@ -302,6 +302,10 @@ acpi_status acpi_db_disassemble_method(char *name) } status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id); + if (ACPI_FAILURE(status)) { + return (status); + } + walk_state->owner_id = obj_desc->method.owner_id; /* Push start scope on scope stack and make it current */ diff --git a/drivers/acpi/acpica/dbobject.c b/drivers/acpi/acpica/dbobject.c index d220168dca01a4fadf7df7380ccedc6a9a8cd41f..f9fc84bc3e84f8d0f078e58140b33541922a19fa 100644 --- a/drivers/acpi/acpica/dbobject.c +++ b/drivers/acpi/acpica/dbobject.c @@ -394,7 +394,6 @@ void acpi_db_decode_locals(struct acpi_walk_state *walk_state) u8 display_locals = FALSE; node = walk_state->method_node; - obj_desc = walk_state->method_desc; /* There are no locals for the module-level code case */ diff --git a/drivers/acpi/acpica/dbstats.c b/drivers/acpi/acpica/dbstats.c index bf620937c79b9c28f4ab5e43b2c13ed033256e88..3af88e70238c5c4fb5a505167ee718443e2ed4ed 100644 --- a/drivers/acpi/acpica/dbstats.c +++ b/drivers/acpi/acpica/dbstats.c @@ -341,17 +341,17 @@ acpi_status acpi_db_display_statistics(char *type_arg) "ACPI_TYPE", "NODES", "OBJECTS"); for (i = 0; i < ACPI_TYPE_NS_NODE_MAX; i++) { - acpi_os_printf("%16.16s % 10ld% 10ld\n", + acpi_os_printf("%16.16s %10u %10u\n", acpi_ut_get_type_name(i), acpi_gbl_node_type_count[i], acpi_gbl_obj_type_count[i]); } - acpi_os_printf("%16.16s % 10ld% 10ld\n", "Misc/Unknown", + acpi_os_printf("%16.16s %10u %10u\n", "Misc/Unknown", acpi_gbl_node_type_count_misc, acpi_gbl_obj_type_count_misc); - acpi_os_printf("%16.16s % 10ld% 10ld\n", "TOTALS:", + acpi_os_printf("%16.16s %10u %10u\n", "TOTALS:", acpi_gbl_num_nodes, acpi_gbl_num_objects); break; @@ -379,16 +379,14 @@ acpi_status acpi_db_display_statistics(char *type_arg) case CMD_STAT_MISC: acpi_os_printf("\nMiscellaneous Statistics:\n\n"); - acpi_os_printf("Calls to AcpiPsFind:.. ........% 7ld\n", + acpi_os_printf("%-28s: %7u\n", "Calls to AcpiPsFind", acpi_gbl_ps_find_count); - acpi_os_printf("Calls to AcpiNsLookup:..........% 7ld\n", + acpi_os_printf("%-28s: %7u\n", "Calls to AcpiNsLookup", acpi_gbl_ns_lookup_count); - acpi_os_printf("\n"); - - acpi_os_printf("Mutex usage:\n\n"); + acpi_os_printf("\nMutex usage:\n\n"); for (i = 0; i < ACPI_NUM_MUTEX; i++) { - acpi_os_printf("%-28s: % 7ld\n", + acpi_os_printf("%-28s: %7u\n", acpi_ut_get_mutex_name(i), acpi_gbl_mutex_info[i].use_count); } @@ -399,87 +397,87 @@ acpi_status acpi_db_display_statistics(char *type_arg) acpi_os_printf("\nInternal object sizes:\n\n"); acpi_os_printf("Common %3d\n", - sizeof(struct acpi_object_common)); + (u32)sizeof(struct acpi_object_common)); acpi_os_printf("Number %3d\n", - sizeof(struct acpi_object_integer)); + (u32)sizeof(struct acpi_object_integer)); acpi_os_printf("String %3d\n", - sizeof(struct acpi_object_string)); + (u32)sizeof(struct acpi_object_string)); acpi_os_printf("Buffer %3d\n", - sizeof(struct acpi_object_buffer)); + (u32)sizeof(struct acpi_object_buffer)); acpi_os_printf("Package %3d\n", - sizeof(struct acpi_object_package)); + (u32)sizeof(struct acpi_object_package)); acpi_os_printf("BufferField %3d\n", - sizeof(struct acpi_object_buffer_field)); + (u32)sizeof(struct acpi_object_buffer_field)); acpi_os_printf("Device %3d\n", - sizeof(struct acpi_object_device)); + (u32)sizeof(struct acpi_object_device)); acpi_os_printf("Event %3d\n", - sizeof(struct acpi_object_event)); + (u32)sizeof(struct acpi_object_event)); acpi_os_printf("Method %3d\n", - sizeof(struct acpi_object_method)); + (u32)sizeof(struct acpi_object_method)); acpi_os_printf("Mutex %3d\n", - sizeof(struct acpi_object_mutex)); + (u32)sizeof(struct acpi_object_mutex)); acpi_os_printf("Region %3d\n", - sizeof(struct acpi_object_region)); + (u32)sizeof(struct acpi_object_region)); acpi_os_printf("PowerResource %3d\n", - sizeof(struct acpi_object_power_resource)); + (u32)sizeof(struct acpi_object_power_resource)); acpi_os_printf("Processor %3d\n", - sizeof(struct acpi_object_processor)); + (u32)sizeof(struct acpi_object_processor)); acpi_os_printf("ThermalZone %3d\n", - sizeof(struct acpi_object_thermal_zone)); + (u32)sizeof(struct acpi_object_thermal_zone)); acpi_os_printf("RegionField %3d\n", - sizeof(struct acpi_object_region_field)); + (u32)sizeof(struct acpi_object_region_field)); acpi_os_printf("BankField %3d\n", - sizeof(struct acpi_object_bank_field)); + (u32)sizeof(struct acpi_object_bank_field)); acpi_os_printf("IndexField %3d\n", - sizeof(struct acpi_object_index_field)); + (u32)sizeof(struct acpi_object_index_field)); acpi_os_printf("Reference %3d\n", - sizeof(struct acpi_object_reference)); + (u32)sizeof(struct acpi_object_reference)); acpi_os_printf("Notify %3d\n", - sizeof(struct acpi_object_notify_handler)); + (u32)sizeof(struct acpi_object_notify_handler)); acpi_os_printf("AddressSpace %3d\n", - sizeof(struct acpi_object_addr_handler)); + (u32)sizeof(struct acpi_object_addr_handler)); acpi_os_printf("Extra %3d\n", - sizeof(struct acpi_object_extra)); + (u32)sizeof(struct acpi_object_extra)); acpi_os_printf("Data %3d\n", - sizeof(struct acpi_object_data)); + (u32)sizeof(struct acpi_object_data)); acpi_os_printf("\n"); acpi_os_printf("ParseObject %3d\n", - sizeof(struct acpi_parse_obj_common)); + (u32)sizeof(struct acpi_parse_obj_common)); acpi_os_printf("ParseObjectNamed %3d\n", - sizeof(struct acpi_parse_obj_named)); + (u32)sizeof(struct acpi_parse_obj_named)); acpi_os_printf("ParseObjectAsl %3d\n", - sizeof(struct acpi_parse_obj_asl)); + (u32)sizeof(struct acpi_parse_obj_asl)); acpi_os_printf("OperandObject %3d\n", - sizeof(union acpi_operand_object)); + (u32)sizeof(union acpi_operand_object)); acpi_os_printf("NamespaceNode %3d\n", - sizeof(struct acpi_namespace_node)); + (u32)sizeof(struct acpi_namespace_node)); acpi_os_printf("AcpiObject %3d\n", - sizeof(union acpi_object)); + (u32)sizeof(union acpi_object)); acpi_os_printf("\n"); acpi_os_printf("Generic State %3d\n", - sizeof(union acpi_generic_state)); + (u32)sizeof(union acpi_generic_state)); acpi_os_printf("Common State %3d\n", - sizeof(struct acpi_common_state)); + (u32)sizeof(struct acpi_common_state)); acpi_os_printf("Control State %3d\n", - sizeof(struct acpi_control_state)); + (u32)sizeof(struct acpi_control_state)); acpi_os_printf("Update State %3d\n", - sizeof(struct acpi_update_state)); + (u32)sizeof(struct acpi_update_state)); acpi_os_printf("Scope State %3d\n", - sizeof(struct acpi_scope_state)); + (u32)sizeof(struct acpi_scope_state)); acpi_os_printf("Parse Scope %3d\n", - sizeof(struct acpi_pscope_state)); + (u32)sizeof(struct acpi_pscope_state)); acpi_os_printf("Package State %3d\n", - sizeof(struct acpi_pkg_state)); + (u32)sizeof(struct acpi_pkg_state)); acpi_os_printf("Thread State %3d\n", - sizeof(struct acpi_thread_state)); + (u32)sizeof(struct acpi_thread_state)); acpi_os_printf("Result Values %3d\n", - sizeof(struct acpi_result_values)); + (u32)sizeof(struct acpi_result_values)); acpi_os_printf("Notify Info %3d\n", - sizeof(struct acpi_notify_info)); + (u32)sizeof(struct acpi_notify_info)); break; case CMD_STAT_STACK: diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 710488ec59e99f7819a7de1d685f87fe6a87b500..04a40d563dd6771edb5bcd7ad12c14eba8f3259a 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -644,17 +644,17 @@ ACPI_EXPORT_SYMBOL(acpi_get_gpe_status) * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 * gpe_number - GPE level within the GPE block * - * RETURN: None + * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED * * DESCRIPTION: Detect and dispatch a General Purpose Event to either a function * (e.g. EC) or method (e.g. _Lxx/_Exx) handler. * ******************************************************************************/ -void acpi_dispatch_gpe(acpi_handle gpe_device, u32 gpe_number) +u32 acpi_dispatch_gpe(acpi_handle gpe_device, u32 gpe_number) { ACPI_FUNCTION_TRACE(acpi_dispatch_gpe); - acpi_ev_detect_gpe(gpe_device, NULL, gpe_number); + return acpi_ev_detect_gpe(gpe_device, NULL, gpe_number); } ACPI_EXPORT_SYMBOL(acpi_dispatch_gpe) diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 6526b2deeaada44251d6869f07ae45791650fc6e..a9bc938a3b55743803241e8d0fe15c26ed177e95 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -94,7 +94,7 @@ static struct acpi_exdump_info acpi_ex_dump_method[9] = { "Parameter Count"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.sync_level), "Sync Level"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.mutex), "Mutex"}, - {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.owner_id), "Owner Id"}, + {ACPI_EXD_UINT16, ACPI_EXD_OFFSET(method.owner_id), "Owner Id"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.thread_count), "Thread Count"}, {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(method.aml_length), "Aml Length"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.aml_start), "Aml Start"} @@ -269,8 +269,8 @@ static struct acpi_exdump_info acpi_ex_dump_field_common[7] = { static struct acpi_exdump_info acpi_ex_dump_node[7] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_node), NULL}, - {ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET(flags), "Flags"}, - {ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET(owner_id), "Owner Id"}, + {ACPI_EXD_UINT16, ACPI_EXD_NSOFFSET(flags), "Flags"}, + {ACPI_EXD_UINT16, ACPI_EXD_NSOFFSET(owner_id), "Owner Id"}, {ACPI_EXD_LIST, ACPI_EXD_NSOFFSET(object), "Object List"}, {ACPI_EXD_NODE, ACPI_EXD_NSOFFSET(parent), "Parent"}, {ACPI_EXD_NODE, ACPI_EXD_NSOFFSET(child), "Child"}, diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 2566e2d4c78031b4194ada252878b0b88194d1e4..3f045b5953b2e85ac7c2345fc568f57418c234b2 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -598,7 +598,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, if (flags & ACPI_NS_PREFIX_MUST_EXIST) { acpi_os_printf(ACPI_MSG_BIOS_ERROR "Object does not exist: %4.4s\n", - &simple_name); + (char *)&simple_name); } #endif /* Name not found in ACPI namespace */ diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index 6eb63db72249b0291be099310163841f2b59340e..fe9b3639a87dcbf10bc7b622417ff464d64108e6 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -241,7 +241,7 @@ void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namesp node->type = (u8) type; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, - "%4.4s (%s) [Node %p Owner %X] added to %4.4s (%s) [Node %p]\n", + "%4.4s (%s) [Node %p Owner %3.3X] added to %4.4s (%s) [Node %p]\n", acpi_ut_get_node_name(node), acpi_ut_get_type_name(node->type), node, owner_id, acpi_ut_get_node_name(parent_node), diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index 1b12c172e115150e267d312413b4b7bdc6ce8ebe..9731d7cf1b83c1face62588ffce214a1a32986bc 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -197,7 +197,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, /* Now we can print out the pertinent information */ - acpi_os_printf(" %-12s %p %2.2X ", + acpi_os_printf(" %-12s %p %3.3X ", acpi_ut_get_type_name(type), this_node, this_node->owner_id); diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index 8d776256b21318827de8de97eb365ad1dc35df3d..663d85e0adba92fd2cd6f77f7608a9c01dca6bd6 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -126,7 +126,7 @@ static const struct acpi_repair_info acpi_ns_repairable_names[] = { #define ACPI_FDE_FIELD_COUNT 5 #define ACPI_FDE_BYTE_BUFFER_SIZE 5 -#define ACPI_FDE_DWORD_BUFFER_SIZE (ACPI_FDE_FIELD_COUNT * sizeof (u32)) +#define ACPI_FDE_DWORD_BUFFER_SIZE (ACPI_FDE_FIELD_COUNT * (u32) sizeof (u32)) /****************************************************************************** * diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index 91a4b984f224c71ced026462db951b08c2e478f1..309440010ab2adc8dab4e27856aee74ef39f6e84 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -750,6 +750,7 @@ acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index) if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } + acpi_ns_delete_namespace_by_owner(owner_id); acpi_ut_release_write_lock(&acpi_gbl_namespace_rw_lock); return_ACPI_STATUS(status); diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 01b1b36c8a8e2ac5798a633b2da1cd53d283e9d3..5b169b5f0f1a3a098c2061f788bb1718364619c7 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -158,7 +158,7 @@ acpi_debug_print(u32 requested_debug_level, * Display the module name, current line number, thread ID (if requested), * current procedure nesting level, and the current procedure name */ - acpi_os_printf("%9s-%04ld ", module_name, line_number); + acpi_os_printf("%9s-%04d ", module_name, line_number); #ifdef ACPI_APPLICATION /* @@ -177,7 +177,7 @@ acpi_debug_print(u32 requested_debug_level, fill_count = 0; } - acpi_os_printf("[%02ld] %*s", + acpi_os_printf("[%02d] %*s", acpi_gbl_nesting_level, acpi_gbl_nesting_level + 1, " "); acpi_os_printf("%s%*s: ", acpi_ut_trim_function_name(function_name), fill_count, diff --git a/drivers/acpi/acpica/uterror.c b/drivers/acpi/acpica/uterror.c index 075457341bad19bd8c7a4b2a251533e536dda003..918aca7c4db41d62e0ba9285647b4dd9600b03ef 100644 --- a/drivers/acpi/acpica/uterror.c +++ b/drivers/acpi/acpica/uterror.c @@ -39,7 +39,7 @@ void ACPI_INTERNAL_VAR_XFACE acpi_ut_predefined_warning(const char *module_name, u32 line_number, char *pathname, - u8 node_flags, const char *format, ...) + u16 node_flags, const char *format, ...) { va_list arg_list; @@ -81,7 +81,7 @@ acpi_ut_predefined_warning(const char *module_name, void ACPI_INTERNAL_VAR_XFACE acpi_ut_predefined_info(const char *module_name, u32 line_number, - char *pathname, u8 node_flags, const char *format, ...) + char *pathname, u16 node_flags, const char *format, ...) { va_list arg_list; @@ -124,7 +124,7 @@ void ACPI_INTERNAL_VAR_XFACE acpi_ut_predefined_bios_error(const char *module_name, u32 line_number, char *pathname, - u8 node_flags, const char *format, ...) + u16 node_flags, const char *format, ...) { va_list arg_list; diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c index 688c61a90725a51635f6cd8998ade2c48736205e..ad2b218039d0f9eee89225e014dbe921afac601d 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -65,13 +65,14 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = { {"Windows 2006 SP2", NULL, 0, ACPI_OSI_WIN_VISTA_SP2}, /* Windows Vista SP2 - Added 09/2010 */ {"Windows 2009", NULL, 0, ACPI_OSI_WIN_7}, /* Windows 7 and Server 2008 R2 - Added 09/2009 */ {"Windows 2012", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8 and Server 2012 - Added 08/2012 */ - {"Windows 2013", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8.1 and Server 2012 R2 - Added 01/2014 */ + {"Windows 2013", NULL, 0, ACPI_OSI_WIN_8_1}, /* Windows 8.1 and Server 2012 R2 - Added 01/2014 */ {"Windows 2015", NULL, 0, ACPI_OSI_WIN_10}, /* Windows 10 - Added 03/2015 */ {"Windows 2016", NULL, 0, ACPI_OSI_WIN_10_RS1}, /* Windows 10 version 1607 - Added 12/2017 */ {"Windows 2017", NULL, 0, ACPI_OSI_WIN_10_RS2}, /* Windows 10 version 1703 - Added 12/2017 */ {"Windows 2017.2", NULL, 0, ACPI_OSI_WIN_10_RS3}, /* Windows 10 version 1709 - Added 02/2018 */ {"Windows 2018", NULL, 0, ACPI_OSI_WIN_10_RS4}, /* Windows 10 version 1803 - Added 11/2018 */ {"Windows 2018.2", NULL, 0, ACPI_OSI_WIN_10_RS5}, /* Windows 10 version 1809 - Added 11/2018 */ + {"Windows 2019", NULL, 0, ACPI_OSI_WIN_10_19H1}, /* Windows 10 version 1903 - Added 08/2019 */ /* Feature Group Strings */ diff --git a/drivers/acpi/acpica/utownerid.c b/drivers/acpi/acpica/utownerid.c index 5eb8b76ce9d8db9a912d293b65c3ce3751ed72d4..d3525ef8ed28550eb05d0a45e90d3790612626b0 100644 --- a/drivers/acpi/acpica/utownerid.c +++ b/drivers/acpi/acpica/utownerid.c @@ -38,7 +38,7 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id *owner_id) if (*owner_id) { ACPI_ERROR((AE_INFO, - "Owner ID [0x%2.2X] already exists", *owner_id)); + "Owner ID [0x%3.3X] already exists", *owner_id)); return_ACPI_STATUS(AE_ALREADY_EXISTS); } @@ -88,14 +88,14 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id *owner_id) /* * Construct encoded ID from the index and bit position * - * Note: Last [j].k (bit 255) is never used and is marked + * Note: Last [j].k (bit 4095) is never used and is marked * permanently allocated (prevents +1 overflow) */ *owner_id = (acpi_owner_id)((k + 1) + ACPI_MUL_32(j)); ACPI_DEBUG_PRINT((ACPI_DB_VALUES, - "Allocated OwnerId: %2.2X\n", + "Allocated OwnerId: 0x%3.3X\n", (unsigned int)*owner_id)); goto exit; } @@ -116,7 +116,7 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id *owner_id) */ status = AE_OWNER_ID_LIMIT; ACPI_ERROR((AE_INFO, - "Could not allocate new OwnerId (255 max), AE_OWNER_ID_LIMIT")); + "Could not allocate new OwnerId (4095 max), AE_OWNER_ID_LIMIT")); exit: (void)acpi_ut_release_mutex(ACPI_MTX_CACHES); @@ -153,7 +153,7 @@ void acpi_ut_release_owner_id(acpi_owner_id *owner_id_ptr) /* Zero is not a valid owner_ID */ if (owner_id == 0) { - ACPI_ERROR((AE_INFO, "Invalid OwnerId: 0x%2.2X", owner_id)); + ACPI_ERROR((AE_INFO, "Invalid OwnerId: 0x%3.3X", owner_id)); return_VOID; } @@ -179,7 +179,7 @@ void acpi_ut_release_owner_id(acpi_owner_id *owner_id_ptr) acpi_gbl_owner_id_mask[index] ^= bit; } else { ACPI_ERROR((AE_INFO, - "Release of non-allocated OwnerId: 0x%2.2X", + "Attempted release of non-allocated OwnerId: 0x%3.3X", owner_id + 1)); } diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index a66e00fe31fec16774bbb795c50427183c137e27..777f6f7122b404a3bbdbd2712e023e1fc6fb2f0a 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -153,6 +153,7 @@ static void ghes_unmap(void __iomem *vaddr, enum fixed_addresses fixmap_idx) int ghes_estatus_pool_init(int num_ghes) { unsigned long addr, len; + int rc; ghes_estatus_pool = gen_pool_create(GHES_ESTATUS_POOL_MIN_ALLOC_ORDER, -1); if (!ghes_estatus_pool) @@ -164,7 +165,7 @@ int ghes_estatus_pool_init(int num_ghes) ghes_estatus_pool_size_request = PAGE_ALIGN(len); addr = (unsigned long)vmalloc(PAGE_ALIGN(len)); if (!addr) - return -ENOMEM; + goto err_pool_alloc; /* * New allocation must be visible in all pgd before it can be found by @@ -172,7 +173,19 @@ int ghes_estatus_pool_init(int num_ghes) */ vmalloc_sync_all(); - return gen_pool_add(ghes_estatus_pool, addr, PAGE_ALIGN(len), -1); + rc = gen_pool_add(ghes_estatus_pool, addr, PAGE_ALIGN(len), -1); + if (rc) + goto err_pool_add; + + return 0; + +err_pool_add: + vfree((void *)addr); + +err_pool_alloc: + gen_pool_destroy(ghes_estatus_pool); + + return -ENOMEM; } static int map_gen_v2(struct ghes *ghes) @@ -483,7 +496,7 @@ static void ghes_do_proc(struct ghes *ghes, int sev, sec_sev; struct acpi_hest_generic_data *gdata; guid_t *sec_type; - guid_t *fru_id = &NULL_UUID_LE; + const guid_t *fru_id = &guid_null; char *fru_text = ""; sev = ghes_severity(estatus->error_severity); diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 8569b79e8b581e894b129871a5fac2bc35994c62..5a7551d060f250b39b345646abd0a3299a515aa0 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -1256,12 +1256,12 @@ static int __init arm_smmu_v3_set_proximity(struct device *dev, smmu = (struct acpi_iort_smmu_v3 *)node->node_data; if (smmu->flags & ACPI_IORT_SMMU_V3_PXM_VALID) { - int node = acpi_map_pxm_to_node(smmu->pxm); + int dev_node = acpi_map_pxm_to_node(smmu->pxm); - if (node != NUMA_NO_NODE && !node_online(node)) + if (dev_node != NUMA_NO_NODE && !node_online(dev_node)) return -EINVAL; - set_dev_node(dev, node); + set_dev_node(dev, dev_node); pr_info("SMMU-v3[%llx] Mapped to Proximity domain %d\n", smmu->base_address, smmu->pxm); diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 15f103d7532b09d83ec9df1475bfba0a0dd7fe76..3b2525908dd8cfaed9074d7926d2036102e77f34 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -365,8 +365,10 @@ static int acpi_get_psd(struct cpc_desc *cpc_ptr, acpi_handle handle) union acpi_object *psd = NULL; struct acpi_psd_package *pdomain; - status = acpi_evaluate_object_typed(handle, "_PSD", NULL, &buffer, - ACPI_TYPE_PACKAGE); + status = acpi_evaluate_object_typed(handle, "_PSD", NULL, + &buffer, ACPI_TYPE_PACKAGE); + if (status == AE_NOT_FOUND) /* _PSD is optional */ + return 0; if (ACPI_FAILURE(status)) return -ENODEV; diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c index b2ef4c2ec955d5c737a69aac1cde444dcd351caf..fd66a736621cff9627b7c6bec47e2079f48de684 100644 --- a/drivers/acpi/custom_method.c +++ b/drivers/acpi/custom_method.c @@ -49,8 +49,10 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, if ((*ppos > max_size) || (*ppos + count > max_size) || (*ppos + count < count) || - (count > uncopied_bytes)) + (count > uncopied_bytes)) { + kfree(buf); return -EINVAL; + } if (copy_from_user(buf + (*ppos), user_buf, count)) { kfree(buf); @@ -70,6 +72,7 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE); } + kfree(buf); return count; } diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index f616b16c1f0be267aa5c116b14a35b095a5ac5d5..08bb9f2f2d2310367c9fde629aaa62e8955bf0e9 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -166,6 +166,10 @@ int acpi_device_set_power(struct acpi_device *device, int state) || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD)) return -EINVAL; + acpi_handle_debug(device->handle, "Power state change: %s -> %s\n", + acpi_power_state_string(device->power.state), + acpi_power_state_string(state)); + /* Make sure this is a valid target state */ /* There is a special case for D0 addressed below. */ @@ -497,7 +501,8 @@ acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev, goto out; mutex_lock(&acpi_pm_notifier_lock); - adev->wakeup.ws = wakeup_source_register(dev_name(&adev->dev)); + adev->wakeup.ws = wakeup_source_register(&adev->dev, + dev_name(&adev->dev)); adev->wakeup.context.dev = dev; adev->wakeup.context.func = func; adev->wakeup.flags.notifier_present = true; diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index c33756ed33049cd9e9eced123177c556f76874ee..da1e5c5ce15065dbddac0e6c0b6abe1bde43fe2d 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1048,24 +1049,6 @@ void acpi_ec_unblock_transactions(void) acpi_ec_start(first_ec, true); } -void acpi_ec_mark_gpe_for_wake(void) -{ - if (first_ec && !ec_no_wakeup) - acpi_mark_gpe_for_wake(NULL, first_ec->gpe); -} - -void acpi_ec_set_gpe_wake_mask(u8 action) -{ - if (first_ec && !ec_no_wakeup) - acpi_set_gpe_wake_mask(NULL, first_ec->gpe, action); -} - -void acpi_ec_dispatch_gpe(void) -{ - if (first_ec) - acpi_dispatch_gpe(NULL, first_ec->gpe); -} - /* -------------------------------------------------------------------------- Event Management -------------------------------------------------------------------------- */ @@ -1931,7 +1914,7 @@ static int acpi_ec_suspend(struct device *dev) struct acpi_ec *ec = acpi_driver_data(to_acpi_device(dev)); - if (acpi_sleep_no_ec_events() && ec_freeze_events) + if (!pm_suspend_no_platform() && ec_freeze_events) acpi_ec_disable_event(ec); return 0; } @@ -1948,8 +1931,7 @@ static int acpi_ec_suspend_noirq(struct device *dev) ec->reference_count >= 1) acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE); - if (acpi_sleep_no_ec_events()) - acpi_ec_enter_noirq(ec); + acpi_ec_enter_noirq(ec); return 0; } @@ -1958,8 +1940,7 @@ static int acpi_ec_resume_noirq(struct device *dev) { struct acpi_ec *ec = acpi_driver_data(to_acpi_device(dev)); - if (acpi_sleep_no_ec_events()) - acpi_ec_leave_noirq(ec); + acpi_ec_leave_noirq(ec); if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) && ec->reference_count >= 1) @@ -1976,7 +1957,35 @@ static int acpi_ec_resume(struct device *dev) acpi_ec_enable_event(ec); return 0; } -#endif + +void acpi_ec_mark_gpe_for_wake(void) +{ + if (first_ec && !ec_no_wakeup) + acpi_mark_gpe_for_wake(NULL, first_ec->gpe); +} +EXPORT_SYMBOL_GPL(acpi_ec_mark_gpe_for_wake); + +void acpi_ec_set_gpe_wake_mask(u8 action) +{ + if (pm_suspend_no_platform() && first_ec && !ec_no_wakeup) + acpi_set_gpe_wake_mask(NULL, first_ec->gpe, action); +} + +bool acpi_ec_dispatch_gpe(void) +{ + u32 ret; + + if (!first_ec) + return false; + + ret = acpi_dispatch_gpe(NULL, first_ec->gpe); + if (ret == ACPI_INTERRUPT_HANDLED) { + pm_pr_dbg("EC GPE dispatched\n"); + return true; + } + return false; +} +#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops acpi_ec_pm = { SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend_noirq, acpi_ec_resume_noirq) diff --git a/drivers/acpi/hmat/hmat.c b/drivers/acpi/hmat/hmat.c index 96b7d39a97c65db544a7e8ec32159f57c595d673..8f9a28a870b0c5a4315c683abe7a67b0da28a664 100644 --- a/drivers/acpi/hmat/hmat.c +++ b/drivers/acpi/hmat/hmat.c @@ -14,14 +14,18 @@ #include #include #include +#include +#include #include #include -static __initdata u8 hmat_revision; +static u8 hmat_revision; -static __initdata LIST_HEAD(targets); -static __initdata LIST_HEAD(initiators); -static __initdata LIST_HEAD(localities); +static LIST_HEAD(targets); +static LIST_HEAD(initiators); +static LIST_HEAD(localities); + +static DEFINE_MUTEX(target_lock); /* * The defined enum order is used to prioritize attributes to break ties when @@ -36,11 +40,19 @@ enum locality_types { static struct memory_locality *localities_types[4]; +struct target_cache { + struct list_head node; + struct node_cache_attrs cache_attrs; +}; + struct memory_target { struct list_head node; unsigned int memory_pxm; unsigned int processor_pxm; struct node_hmem_attrs hmem_attrs; + struct list_head caches; + struct node_cache_attrs cache_attrs; + bool registered; }; struct memory_initiator { @@ -53,7 +65,7 @@ struct memory_locality { struct acpi_hmat_locality *hmat_loc; }; -static __init struct memory_initiator *find_mem_initiator(unsigned int cpu_pxm) +static struct memory_initiator *find_mem_initiator(unsigned int cpu_pxm) { struct memory_initiator *initiator; @@ -63,7 +75,7 @@ static __init struct memory_initiator *find_mem_initiator(unsigned int cpu_pxm) return NULL; } -static __init struct memory_target *find_mem_target(unsigned int mem_pxm) +static struct memory_target *find_mem_target(unsigned int mem_pxm) { struct memory_target *target; @@ -96,9 +108,6 @@ static __init void alloc_memory_target(unsigned int mem_pxm) { struct memory_target *target; - if (pxm_to_node(mem_pxm) == NUMA_NO_NODE) - return; - target = find_mem_target(mem_pxm); if (target) return; @@ -110,6 +119,7 @@ static __init void alloc_memory_target(unsigned int mem_pxm) target->memory_pxm = mem_pxm; target->processor_pxm = PXM_INVAL; list_add_tail(&target->node, &targets); + INIT_LIST_HEAD(&target->caches); } static __init const char *hmat_data_type(u8 type) @@ -148,7 +158,7 @@ static __init const char *hmat_data_type_suffix(u8 type) } } -static __init u32 hmat_normalize(u16 entry, u64 base, u8 type) +static u32 hmat_normalize(u16 entry, u64 base, u8 type) { u32 value; @@ -183,7 +193,7 @@ static __init u32 hmat_normalize(u16 entry, u64 base, u8 type) return value; } -static __init void hmat_update_target_access(struct memory_target *target, +static void hmat_update_target_access(struct memory_target *target, u8 type, u32 value) { switch (type) { @@ -314,7 +324,8 @@ static __init int hmat_parse_cache(union acpi_subtable_headers *header, const unsigned long end) { struct acpi_hmat_cache *cache = (void *)header; - struct node_cache_attrs cache_attrs; + struct memory_target *target; + struct target_cache *tcache; u32 attrs; if (cache->header.length < sizeof(*cache)) { @@ -328,37 +339,47 @@ static __init int hmat_parse_cache(union acpi_subtable_headers *header, cache->memory_PD, cache->cache_size, attrs, cache->number_of_SMBIOShandles); - cache_attrs.size = cache->cache_size; - cache_attrs.level = (attrs & ACPI_HMAT_CACHE_LEVEL) >> 4; - cache_attrs.line_size = (attrs & ACPI_HMAT_CACHE_LINE_SIZE) >> 16; + target = find_mem_target(cache->memory_PD); + if (!target) + return 0; + + tcache = kzalloc(sizeof(*tcache), GFP_KERNEL); + if (!tcache) { + pr_notice_once("Failed to allocate HMAT cache info\n"); + return 0; + } + + tcache->cache_attrs.size = cache->cache_size; + tcache->cache_attrs.level = (attrs & ACPI_HMAT_CACHE_LEVEL) >> 4; + tcache->cache_attrs.line_size = (attrs & ACPI_HMAT_CACHE_LINE_SIZE) >> 16; switch ((attrs & ACPI_HMAT_CACHE_ASSOCIATIVITY) >> 8) { case ACPI_HMAT_CA_DIRECT_MAPPED: - cache_attrs.indexing = NODE_CACHE_DIRECT_MAP; + tcache->cache_attrs.indexing = NODE_CACHE_DIRECT_MAP; break; case ACPI_HMAT_CA_COMPLEX_CACHE_INDEXING: - cache_attrs.indexing = NODE_CACHE_INDEXED; + tcache->cache_attrs.indexing = NODE_CACHE_INDEXED; break; case ACPI_HMAT_CA_NONE: default: - cache_attrs.indexing = NODE_CACHE_OTHER; + tcache->cache_attrs.indexing = NODE_CACHE_OTHER; break; } switch ((attrs & ACPI_HMAT_WRITE_POLICY) >> 12) { case ACPI_HMAT_CP_WB: - cache_attrs.write_policy = NODE_CACHE_WRITE_BACK; + tcache->cache_attrs.write_policy = NODE_CACHE_WRITE_BACK; break; case ACPI_HMAT_CP_WT: - cache_attrs.write_policy = NODE_CACHE_WRITE_THROUGH; + tcache->cache_attrs.write_policy = NODE_CACHE_WRITE_THROUGH; break; case ACPI_HMAT_CP_NONE: default: - cache_attrs.write_policy = NODE_CACHE_WRITE_OTHER; + tcache->cache_attrs.write_policy = NODE_CACHE_WRITE_OTHER; break; } + list_add_tail(&tcache->node, &target->caches); - node_add_cache(pxm_to_node(cache->memory_PD), &cache_attrs); return 0; } @@ -435,7 +456,7 @@ static __init int srat_parse_mem_affinity(union acpi_subtable_headers *header, return 0; } -static __init u32 hmat_initiator_perf(struct memory_target *target, +static u32 hmat_initiator_perf(struct memory_target *target, struct memory_initiator *initiator, struct acpi_hmat_locality *hmat_loc) { @@ -473,7 +494,7 @@ static __init u32 hmat_initiator_perf(struct memory_target *target, hmat_loc->data_type); } -static __init bool hmat_update_best(u8 type, u32 value, u32 *best) +static bool hmat_update_best(u8 type, u32 value, u32 *best) { bool updated = false; @@ -517,7 +538,7 @@ static int initiator_cmp(void *priv, struct list_head *a, struct list_head *b) return ia->processor_pxm - ib->processor_pxm; } -static __init void hmat_register_target_initiators(struct memory_target *target) +static void hmat_register_target_initiators(struct memory_target *target) { static DECLARE_BITMAP(p_nodes, MAX_NUMNODES); struct memory_initiator *initiator; @@ -577,29 +598,89 @@ static __init void hmat_register_target_initiators(struct memory_target *target) } } -static __init void hmat_register_target_perf(struct memory_target *target) +static void hmat_register_target_cache(struct memory_target *target) +{ + unsigned mem_nid = pxm_to_node(target->memory_pxm); + struct target_cache *tcache; + + list_for_each_entry(tcache, &target->caches, node) + node_add_cache(mem_nid, &tcache->cache_attrs); +} + +static void hmat_register_target_perf(struct memory_target *target) { unsigned mem_nid = pxm_to_node(target->memory_pxm); node_set_perf_attrs(mem_nid, &target->hmem_attrs, 0); } -static __init void hmat_register_targets(void) +static void hmat_register_target(struct memory_target *target) { - struct memory_target *target; + int nid = pxm_to_node(target->memory_pxm); - list_for_each_entry(target, &targets, node) { + /* + * 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 + * the node being marked offline / unplugged, or if + * memory-only "hotplug" node is offline. + */ + if (nid == NUMA_NO_NODE || !node_online(nid)) + return; + + mutex_lock(&target_lock); + if (!target->registered) { hmat_register_target_initiators(target); + hmat_register_target_cache(target); hmat_register_target_perf(target); + target->registered = true; } + mutex_unlock(&target_lock); +} + +static void hmat_register_targets(void) +{ + struct memory_target *target; + + list_for_each_entry(target, &targets, node) + hmat_register_target(target); +} + +static int hmat_callback(struct notifier_block *self, + unsigned long action, void *arg) +{ + struct memory_target *target; + struct memory_notify *mnb = arg; + int pxm, nid = mnb->status_change_nid; + + if (nid == NUMA_NO_NODE || action != MEM_ONLINE) + return NOTIFY_OK; + + pxm = node_to_pxm(nid); + target = find_mem_target(pxm); + if (!target) + return NOTIFY_OK; + + hmat_register_target(target); + return NOTIFY_OK; } +static struct notifier_block hmat_callback_nb = { + .notifier_call = hmat_callback, + .priority = 2, +}; + static __init void hmat_free_structures(void) { struct memory_target *target, *tnext; struct memory_locality *loc, *lnext; struct memory_initiator *initiator, *inext; + struct target_cache *tcache, *cnext; list_for_each_entry_safe(target, tnext, &targets, node) { + list_for_each_entry_safe(tcache, cnext, &target->caches, node) { + list_del(&tcache->node); + kfree(tcache); + } list_del(&target->node); kfree(target); } @@ -658,6 +739,10 @@ static __init int hmat_init(void) } } hmat_register_targets(); + + /* Keep the table and structures if the notifier may use them */ + if (!register_hotmemory_notifier(&hmat_callback_nb)) + return 0; out_put: hmat_free_structures(); acpi_put_table(tbl); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index f4c2fe6be4f2d8a9bfe48fb880755771bbe823cd..afe6636f9ad39d33333c2aae9e3e0467b70f9b64 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -194,9 +194,6 @@ void acpi_ec_ecdt_probe(void); void acpi_ec_dsdt_probe(void); void acpi_ec_block_transactions(void); void acpi_ec_unblock_transactions(void); -void acpi_ec_mark_gpe_for_wake(void); -void acpi_ec_set_gpe_wake_mask(u8 action); -void acpi_ec_dispatch_gpe(void); int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, acpi_handle handle, acpi_ec_query_func func, void *data); @@ -204,6 +201,7 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit); #ifdef CONFIG_PM_SLEEP void acpi_ec_flush_work(void); +bool acpi_ec_dispatch_gpe(void); #endif @@ -212,11 +210,9 @@ void acpi_ec_flush_work(void); -------------------------------------------------------------------------- */ #ifdef CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT extern bool acpi_s2idle_wakeup(void); -extern bool acpi_sleep_no_ec_events(void); extern int acpi_sleep_init(void); #else static inline bool acpi_s2idle_wakeup(void) { return false; } -static inline bool acpi_sleep_no_ec_events(void) { return true; } static inline int acpi_sleep_init(void) { return -ENXIO; } #endif diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 9c0edf2fc0dd57df77d526e25d3f69dd3b2cd81b..2f9d0d20b83661af54500daf5d2771e55d0db284 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,7 @@ struct acpi_ioremap { static LIST_HEAD(acpi_ioremaps); static DEFINE_MUTEX(acpi_ioremap_lock); +#define acpi_ioremap_lock_held() lock_is_held(&acpi_ioremap_lock.dep_map) static void __init acpi_request_region (struct acpi_generic_address *gas, unsigned int length, char *desc) @@ -206,7 +208,7 @@ acpi_map_lookup(acpi_physical_address phys, acpi_size size) { struct acpi_ioremap *map; - list_for_each_entry_rcu(map, &acpi_ioremaps, list) + list_for_each_entry_rcu(map, &acpi_ioremaps, list, acpi_ioremap_lock_held()) if (map->phys <= phys && phys + size <= map->phys + map->size) return map; @@ -249,7 +251,7 @@ acpi_map_lookup_virt(void __iomem *virt, acpi_size size) { struct acpi_ioremap *map; - list_for_each_entry_rcu(map, &acpi_ioremaps, list) + list_for_each_entry_rcu(map, &acpi_ioremaps, list, acpi_ioremap_lock_held()) if (map->virt <= virt && virt + size <= map->virt + map->size) return map; diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index d2549ae65e1b6f049c0c68199010f0d652433c70..dea8a60e18a4c00929cb6f7c759615f075bcfe12 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -449,8 +449,10 @@ int acpi_pci_irq_enable(struct pci_dev *dev) * No IRQ known to the ACPI subsystem - maybe the BIOS / * driver reported one, then use it. Exit in any case. */ - if (!acpi_pci_irq_valid(dev, pin)) + if (!acpi_pci_irq_valid(dev, pin)) { + kfree(entry); return 0; + } if (acpi_isa_register_gsi(dev)) dev_warn(&dev->dev, "PCI INT %c: no GSI\n", diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index db11f7771ef1b9ed401c99fb047c275bd8f7079f..00a6da2121be30bd08de4bcbe2f9a6e9a12c4488 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -661,7 +661,7 @@ int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering, ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link %s is referenced\n", acpi_device_bid(link->device))); - return (link->irq.active); + return link->irq.active; } /* @@ -712,7 +712,7 @@ int acpi_pci_link_free_irq(acpi_handle handle) acpi_evaluate_object(link->device->handle, "_DIS", NULL, NULL); mutex_unlock(&acpi_link_lock); - return (link->irq.active); + return link->irq.active; } /* -------------------------------------------------------------------------- diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c index 1e7ac0bd0d3a090c42136e2b4fc213a31924516c..f31544d3656e3dfb400ce86d51ea46679eafde3b 100644 --- a/drivers/acpi/pptt.c +++ b/drivers/acpi/pptt.c @@ -540,6 +540,44 @@ static int find_acpi_cpu_topology_tag(unsigned int cpu, int level, int flag) return retval; } +/** + * check_acpi_cpu_flag() - Determine if CPU node has a flag set + * @cpu: Kernel logical CPU number + * @rev: The minimum PPTT revision defining the flag + * @flag: The flag itself + * + * Check the node representing a CPU for a given flag. + * + * Return: -ENOENT if the PPTT doesn't exist, the CPU cannot be found or + * the table revision isn't new enough. + * 1, any passed flag set + * 0, flag unset + */ +static int check_acpi_cpu_flag(unsigned int cpu, int rev, u32 flag) +{ + struct acpi_table_header *table; + acpi_status status; + u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu); + struct acpi_pptt_processor *cpu_node = NULL; + int ret = -ENOENT; + + status = acpi_get_table(ACPI_SIG_PPTT, 0, &table); + if (ACPI_FAILURE(status)) { + acpi_pptt_warn_missing(); + return ret; + } + + if (table->revision >= rev) + cpu_node = acpi_find_processor_node(table, acpi_cpu_id); + + if (cpu_node) + ret = (cpu_node->flags & flag) != 0; + + acpi_put_table(table); + + return ret; +} + /** * acpi_find_last_cache_level() - Determines the number of cache levels for a PE * @cpu: Kernel logical CPU number @@ -604,6 +642,20 @@ int cache_setup_acpi(unsigned int cpu) return status; } +/** + * acpi_pptt_cpu_is_thread() - Determine if CPU is a thread + * @cpu: Kernel logical CPU number + * + * Return: 1, a thread + * 0, not a thread + * -ENOENT ,if the PPTT doesn't exist, the CPU cannot be found or + * the table revision isn't new enough. + */ +int acpi_pptt_cpu_is_thread(unsigned int cpu) +{ + return check_acpi_cpu_flag(cpu, 2, ACPI_PPTT_ACPI_PROCESSOR_IS_THREAD); +} + /** * find_acpi_cpu_topology() - Determine a unique topology value for a given CPU * @cpu: Kernel logical CPU number @@ -664,7 +716,6 @@ int find_acpi_cpu_cache_topology(unsigned int cpu, int level) return ret; } - /** * find_acpi_cpu_topology_package() - Determine a unique CPU package value * @cpu: Kernel logical CPU number diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index aea8d674a33d106c07b143f0b1ef50b2b9bc7f0e..08da9c29f1e9a8fe722e5bfc7895357b5ec3277e 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -284,6 +284,29 @@ static int acpi_processor_stop(struct device *dev) return 0; } +bool acpi_processor_cpufreq_init; + +static int acpi_processor_notifier(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct cpufreq_policy *policy = data; + int cpu = policy->cpu; + + if (event == CPUFREQ_CREATE_POLICY) { + acpi_thermal_cpufreq_init(cpu); + acpi_processor_ppc_init(cpu); + } else if (event == CPUFREQ_REMOVE_POLICY) { + acpi_processor_ppc_exit(cpu); + acpi_thermal_cpufreq_exit(cpu); + } + + return 0; +} + +static struct notifier_block acpi_processor_notifier_block = { + .notifier_call = acpi_processor_notifier, +}; + /* * We keep the driver loaded even when ACPI is not running. * This is needed for the powernow-k8 driver, that works even without @@ -310,8 +333,12 @@ static int __init acpi_processor_driver_init(void) cpuhp_setup_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD, "acpi/cpu-drv:dead", NULL, acpi_soft_cpu_dead); - acpi_thermal_cpufreq_init(); - acpi_processor_ppc_init(); + if (!cpufreq_register_notifier(&acpi_processor_notifier_block, + CPUFREQ_POLICY_NOTIFIER)) { + acpi_processor_cpufreq_init = true; + acpi_processor_ignore_ppc_init(); + } + acpi_processor_throttling_init(); return 0; err: @@ -324,8 +351,12 @@ static void __exit acpi_processor_driver_exit(void) if (acpi_disabled) return; - acpi_processor_ppc_exit(); - acpi_thermal_cpufreq_exit(); + if (acpi_processor_cpufreq_init) { + cpufreq_unregister_notifier(&acpi_processor_notifier_block, + CPUFREQ_POLICY_NOTIFIER); + acpi_processor_cpufreq_init = false; + } + cpuhp_remove_state_nocalls(hp_online); cpuhp_remove_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD); driver_unregister(&acpi_processor_driver); diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index ee87cb6f6e5944f2cc843d1b9b56600d7edde6e6..2261713d1aec08ffe2f006ff8fd69c165b32a6de 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -50,57 +50,13 @@ module_param(ignore_ppc, int, 0644); MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \ "limited by BIOS, this should help"); -#define PPC_REGISTERED 1 -#define PPC_IN_USE 2 - -static int acpi_processor_ppc_status; - -static int acpi_processor_ppc_notifier(struct notifier_block *nb, - unsigned long event, void *data) -{ - struct cpufreq_policy *policy = data; - struct acpi_processor *pr; - unsigned int ppc = 0; - - if (ignore_ppc < 0) - ignore_ppc = 0; - - if (ignore_ppc) - return 0; - - if (event != CPUFREQ_ADJUST) - return 0; - - mutex_lock(&performance_mutex); - - pr = per_cpu(processors, policy->cpu); - if (!pr || !pr->performance) - goto out; - - ppc = (unsigned int)pr->performance_platform_limit; - - if (ppc >= pr->performance->state_count) - goto out; - - cpufreq_verify_within_limits(policy, 0, - pr->performance->states[ppc]. - core_frequency * 1000); - - out: - mutex_unlock(&performance_mutex); - - return 0; -} - -static struct notifier_block acpi_ppc_notifier_block = { - .notifier_call = acpi_processor_ppc_notifier, -}; +static bool acpi_processor_ppc_in_use; static int acpi_processor_get_platform_limit(struct acpi_processor *pr) { acpi_status status = 0; unsigned long long ppc = 0; - + int ret; if (!pr) return -EINVAL; @@ -112,7 +68,7 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr) status = acpi_evaluate_integer(pr->handle, "_PPC", NULL, &ppc); if (status != AE_NOT_FOUND) - acpi_processor_ppc_status |= PPC_IN_USE; + acpi_processor_ppc_in_use = true; if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PPC")); @@ -124,6 +80,17 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr) pr->performance_platform_limit = (int)ppc; + if (ppc >= pr->performance->state_count || + unlikely(!dev_pm_qos_request_active(&pr->perflib_req))) + return 0; + + ret = dev_pm_qos_update_request(&pr->perflib_req, + pr->performance->states[ppc].core_frequency * 1000); + if (ret < 0) { + pr_warn("Failed to update perflib freq constraint: CPU%d (%d)\n", + pr->id, ret); + } + return 0; } @@ -184,23 +151,32 @@ int acpi_processor_get_bios_limit(int cpu, unsigned int *limit) } EXPORT_SYMBOL(acpi_processor_get_bios_limit); -void acpi_processor_ppc_init(void) +void acpi_processor_ignore_ppc_init(void) { - if (!cpufreq_register_notifier - (&acpi_ppc_notifier_block, CPUFREQ_POLICY_NOTIFIER)) - acpi_processor_ppc_status |= PPC_REGISTERED; - else - printk(KERN_DEBUG - "Warning: Processor Platform Limit not supported.\n"); + if (ignore_ppc < 0) + ignore_ppc = 0; +} + +void acpi_processor_ppc_init(int cpu) +{ + struct acpi_processor *pr = per_cpu(processors, cpu); + int ret; + + ret = dev_pm_qos_add_request(get_cpu_device(cpu), + &pr->perflib_req, DEV_PM_QOS_MAX_FREQUENCY, + INT_MAX); + if (ret < 0) { + pr_err("Failed to add freq constraint for CPU%d (%d)\n", cpu, + ret); + return; + } } -void acpi_processor_ppc_exit(void) +void acpi_processor_ppc_exit(int cpu) { - if (acpi_processor_ppc_status & PPC_REGISTERED) - cpufreq_unregister_notifier(&acpi_ppc_notifier_block, - CPUFREQ_POLICY_NOTIFIER); + struct acpi_processor *pr = per_cpu(processors, cpu); - acpi_processor_ppc_status &= ~PPC_REGISTERED; + dev_pm_qos_remove_request(&pr->perflib_req); } static int acpi_processor_get_performance_control(struct acpi_processor *pr) @@ -477,7 +453,7 @@ int acpi_processor_notify_smm(struct module *calling_module) static int is_done = 0; int result; - if (!(acpi_processor_ppc_status & PPC_REGISTERED)) + if (!acpi_processor_cpufreq_init) return -EBUSY; if (!try_module_get(calling_module)) @@ -513,7 +489,7 @@ int acpi_processor_notify_smm(struct module *calling_module) * we can allow the cpufreq driver to be rmmod'ed. */ is_done = 1; - if (!(acpi_processor_ppc_status & PPC_IN_USE)) + if (!acpi_processor_ppc_in_use) module_put(calling_module); return 0; @@ -742,7 +718,7 @@ acpi_processor_register_performance(struct acpi_processor_performance { struct acpi_processor *pr; - if (!(acpi_processor_ppc_status & PPC_REGISTERED)) + if (!acpi_processor_cpufreq_init) return -EINVAL; mutex_lock(&performance_mutex); diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 50fb0107375e523a47acde7749d9b47c5384c283..ec2638f1df4faea14e10a0682887bdce2d3e91e1 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -35,7 +35,6 @@ ACPI_MODULE_NAME("processor_thermal"); #define CPUFREQ_THERMAL_MAX_STEP 3 static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg); -static unsigned int acpi_thermal_cpufreq_is_init = 0; #define reduction_pctg(cpu) \ per_cpu(cpufreq_thermal_reduction_pctg, phys_package_first_cpu(cpu)) @@ -61,35 +60,11 @@ static int phys_package_first_cpu(int cpu) static int cpu_has_cpufreq(unsigned int cpu) { struct cpufreq_policy policy; - if (!acpi_thermal_cpufreq_is_init || cpufreq_get_policy(&policy, cpu)) + if (!acpi_processor_cpufreq_init || cpufreq_get_policy(&policy, cpu)) return 0; return 1; } -static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb, - unsigned long event, void *data) -{ - struct cpufreq_policy *policy = data; - unsigned long max_freq = 0; - - if (event != CPUFREQ_ADJUST) - goto out; - - max_freq = ( - policy->cpuinfo.max_freq * - (100 - reduction_pctg(policy->cpu) * 20) - ) / 100; - - cpufreq_verify_within_limits(policy, 0, max_freq); - - out: - return 0; -} - -static struct notifier_block acpi_thermal_cpufreq_notifier_block = { - .notifier_call = acpi_thermal_cpufreq_notifier, -}; - static int cpufreq_get_max_state(unsigned int cpu) { if (!cpu_has_cpufreq(cpu)) @@ -108,7 +83,10 @@ static int cpufreq_get_cur_state(unsigned int cpu) static int cpufreq_set_cur_state(unsigned int cpu, int state) { - int i; + struct cpufreq_policy *policy; + struct acpi_processor *pr; + unsigned long max_freq; + int i, ret; if (!cpu_has_cpufreq(cpu)) return 0; @@ -121,33 +99,53 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state) * frequency. */ for_each_online_cpu(i) { - if (topology_physical_package_id(i) == + if (topology_physical_package_id(i) != topology_physical_package_id(cpu)) - cpufreq_update_policy(i); + continue; + + pr = per_cpu(processors, i); + + if (unlikely(!dev_pm_qos_request_active(&pr->thermal_req))) + continue; + + policy = cpufreq_cpu_get(i); + if (!policy) + return -EINVAL; + + max_freq = (policy->cpuinfo.max_freq * (100 - reduction_pctg(i) * 20)) / 100; + + cpufreq_cpu_put(policy); + + ret = dev_pm_qos_update_request(&pr->thermal_req, max_freq); + if (ret < 0) { + pr_warn("Failed to update thermal freq constraint: CPU%d (%d)\n", + pr->id, ret); + } } return 0; } -void acpi_thermal_cpufreq_init(void) +void acpi_thermal_cpufreq_init(int cpu) { - int i; - - i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block, - CPUFREQ_POLICY_NOTIFIER); - if (!i) - acpi_thermal_cpufreq_is_init = 1; + struct acpi_processor *pr = per_cpu(processors, cpu); + int ret; + + ret = dev_pm_qos_add_request(get_cpu_device(cpu), + &pr->thermal_req, DEV_PM_QOS_MAX_FREQUENCY, + INT_MAX); + if (ret < 0) { + pr_err("Failed to add freq constraint for CPU%d (%d)\n", cpu, + ret); + return; + } } -void acpi_thermal_cpufreq_exit(void) +void acpi_thermal_cpufreq_exit(int cpu) { - if (acpi_thermal_cpufreq_is_init) - cpufreq_unregister_notifier - (&acpi_thermal_cpufreq_notifier_block, - CPUFREQ_POLICY_NOTIFIER); + struct acpi_processor *pr = per_cpu(processors, cpu); - acpi_thermal_cpufreq_is_init = 0; + dev_pm_qos_remove_request(&pr->thermal_req); } - #else /* ! CONFIG_CPU_FREQ */ static int cpufreq_get_max_state(unsigned int cpu) { diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index ea3d700da3ca6bdbe1defcf412ede93b16e6ac96..3eacf474e1e39b07197c5f6975412f4116d22879 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -39,6 +39,12 @@ static const guid_t prp_guids[] = { /* External facing port GUID: efcc06cc-73ac-4bc3-bff0-76143807c389 */ GUID_INIT(0xefcc06cc, 0x73ac, 0x4bc3, 0xbf, 0xf0, 0x76, 0x14, 0x38, 0x07, 0xc3, 0x89), + /* Thunderbolt GUID for IMR_VALID: c44d002f-69f9-4e7d-a904-a7baabdf43f7 */ + GUID_INIT(0xc44d002f, 0x69f9, 0x4e7d, + 0xa9, 0x04, 0xa7, 0xba, 0xab, 0xdf, 0x43, 0xf7), + /* Thunderbolt GUID for WAKE_SUPPORTED: 6c501103-c189-4296-ba72-9bf5a26ebe5d */ + GUID_INIT(0x6c501103, 0xc189, 0x4296, + 0xba, 0x72, 0x9b, 0xf5, 0xa2, 0x6e, 0xbe, 0x5d), }; /* ACPI _DSD data subnodes GUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */ @@ -1210,7 +1216,7 @@ static struct fwnode_handle *acpi_graph_get_child_prop_value( /** - * acpi_graph_get_remote_enpoint - Parses and returns remote end of an endpoint + * acpi_graph_get_remote_endpoint - Parses and returns remote end of an endpoint * @fwnode: Endpoint firmware node pointing to a remote device * @endpoint: Firmware node of remote endpoint is filled here if not %NULL * diff --git a/drivers/acpi/sbshc.h b/drivers/acpi/sbshc.h index 06372a37df10f1da6e345f73020bbae53aa68c5d..c3522bb8279246861da743b7841492ef8b578d8c 100644 --- a/drivers/acpi/sbshc.h +++ b/drivers/acpi/sbshc.h @@ -15,8 +15,6 @@ enum acpi_smb_protocol { SMBUS_BLOCK_PROCESS_CALL = 0xd, }; -static const u8 SMBUS_PEC = 0x80; - enum acpi_sbs_device_addr { ACPI_SBS_CHARGER = 0x9, ACPI_SBS_MANAGER = 0xa, diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index f0fe7c15d657288d28a20f6b906c62f955c5fcda..9fa77d72ef27f52369a23f9ed99788705661bc3a 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -89,6 +89,10 @@ bool acpi_sleep_state_supported(u8 sleep_state) } #ifdef CONFIG_ACPI_SLEEP +static bool sleep_no_lps0 __read_mostly; +module_param(sleep_no_lps0, bool, 0644); +MODULE_PARM_DESC(sleep_no_lps0, "Do not use the special LPS0 device interface"); + static u32 acpi_target_sleep_state = ACPI_STATE_S0; u32 acpi_target_system_state(void) @@ -158,11 +162,11 @@ static int __init init_nvs_nosave(const struct dmi_system_id *d) return 0; } -static bool acpi_sleep_no_lps0; +static bool acpi_sleep_default_s3; -static int __init init_no_lps0(const struct dmi_system_id *d) +static int __init init_default_s3(const struct dmi_system_id *d) { - acpi_sleep_no_lps0 = true; + acpi_sleep_default_s3 = true; return 0; } @@ -363,7 +367,7 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = { * S0 Idle firmware interface. */ { - .callback = init_no_lps0, + .callback = init_default_s3, .ident = "Dell XPS13 9360", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), @@ -376,7 +380,7 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = { * https://bugzilla.kernel.org/show_bug.cgi?id=199057). */ { - .callback = init_no_lps0, + .callback = init_default_s3, .ident = "ThinkPad X1 Tablet(2016)", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), @@ -524,8 +528,9 @@ static void acpi_pm_end(void) acpi_sleep_tts_switch(acpi_target_sleep_state); } #else /* !CONFIG_ACPI_SLEEP */ +#define sleep_no_lps0 (1) #define acpi_target_sleep_state ACPI_STATE_S0 -#define acpi_sleep_no_lps0 (false) +#define acpi_sleep_default_s3 (1) static inline void acpi_sleep_dmi_check(void) {} #endif /* CONFIG_ACPI_SLEEP */ @@ -691,7 +696,6 @@ static const struct platform_suspend_ops acpi_suspend_ops_old = { .recover = acpi_pm_finish, }; -static bool s2idle_in_progress; static bool s2idle_wakeup; /* @@ -904,42 +908,43 @@ static int lps0_device_attach(struct acpi_device *adev, if (lps0_device_handle) return 0; - if (acpi_sleep_no_lps0) { - acpi_handle_info(adev->handle, - "Low Power S0 Idle interface disabled\n"); - return 0; - } - if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) return 0; guid_parse(ACPI_LPS0_DSM_UUID, &lps0_dsm_guid); /* Check if the _DSM is present and as expected. */ out_obj = acpi_evaluate_dsm(adev->handle, &lps0_dsm_guid, 1, 0, NULL); - if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) { - char bitmask = *(char *)out_obj->buffer.pointer; - - lps0_dsm_func_mask = bitmask; - lps0_device_handle = adev->handle; - /* - * Use suspend-to-idle by default if the default - * suspend mode was not set from the command line. - */ - if (mem_sleep_default > PM_SUSPEND_MEM) - mem_sleep_current = PM_SUSPEND_TO_IDLE; - - acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n", - bitmask); - - acpi_ec_mark_gpe_for_wake(); - } else { + if (!out_obj || out_obj->type != ACPI_TYPE_BUFFER) { acpi_handle_debug(adev->handle, "_DSM function 0 evaluation failed\n"); + return 0; } + + lps0_dsm_func_mask = *(char *)out_obj->buffer.pointer; + ACPI_FREE(out_obj); + acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n", + lps0_dsm_func_mask); + + lps0_device_handle = adev->handle; + lpi_device_get_constraints(); + /* + * Use suspend-to-idle by default if the default suspend mode was not + * set from the command line. + */ + if (mem_sleep_default > PM_SUSPEND_MEM && !acpi_sleep_default_s3) + mem_sleep_current = PM_SUSPEND_TO_IDLE; + + /* + * Some LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U, require the + * EC GPE to be enabled while suspended for certain wakeup devices to + * work, so mark it as wakeup-capable. + */ + acpi_ec_mark_gpe_for_wake(); + return 0; } @@ -951,98 +956,110 @@ static struct acpi_scan_handler lps0_handler = { static int acpi_s2idle_begin(void) { acpi_scan_lock_acquire(); - s2idle_in_progress = true; return 0; } static int acpi_s2idle_prepare(void) { - if (lps0_device_handle) { - acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF); - acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY); - + if (acpi_sci_irq_valid()) { + enable_irq_wake(acpi_sci_irq); acpi_ec_set_gpe_wake_mask(ACPI_GPE_ENABLE); } - if (acpi_sci_irq_valid()) - enable_irq_wake(acpi_sci_irq); - acpi_enable_wakeup_devices(ACPI_STATE_S0); /* Change the configuration of GPEs to avoid spurious wakeup. */ acpi_enable_all_wakeup_gpes(); acpi_os_wait_events_complete(); + + s2idle_wakeup = true; return 0; } -static void acpi_s2idle_wake(void) +static int acpi_s2idle_prepare_late(void) { - if (!lps0_device_handle) - return; + if (!lps0_device_handle || sleep_no_lps0) + return 0; if (pm_debug_messages_on) lpi_check_constraints(); + acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF); + acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY); + + return 0; +} + +static void acpi_s2idle_wake(void) +{ + /* + * If IRQD_WAKEUP_ARMED is set for the SCI at this point, the SCI has + * not triggered while suspended, so bail out. + */ + if (!acpi_sci_irq_valid() || + irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) + return; + /* - * If IRQD_WAKEUP_ARMED is not set for the SCI at this point, it means - * that the SCI has triggered while suspended, so cancel the wakeup in - * case it has not been a wakeup event (the GPEs will be checked later). + * If there are EC events to process, the wakeup may be a spurious one + * coming from the EC. */ - if (acpi_sci_irq_valid() && - !irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) { + if (acpi_ec_dispatch_gpe()) { + /* + * Cancel the wakeup and process all pending events in case + * there are any wakeup ones in there. + * + * Note that if any non-EC GPEs are active at this point, the + * SCI will retrigger after the rearming below, so no events + * should be missed by canceling the wakeup here. + */ pm_system_cancel_wakeup(); - s2idle_wakeup = true; /* - * On some platforms with the LPS0 _DSM device noirq resume - * takes too much time for EC wakeup events to survive, so look - * for them now. + * The EC driver uses the system workqueue and an additional + * special one, so those need to be flushed too. */ - acpi_ec_dispatch_gpe(); + acpi_os_wait_events_complete(); /* synchronize EC GPE processing */ + acpi_ec_flush_work(); + acpi_os_wait_events_complete(); /* synchronize Notify handling */ + + rearm_wake_irq(acpi_sci_irq); } } -static void acpi_s2idle_sync(void) +static void acpi_s2idle_restore_early(void) { - /* - * Process all pending events in case there are any wakeup ones. - * - * The EC driver uses the system workqueue and an additional special - * one, so those need to be flushed too. - */ - acpi_os_wait_events_complete(); /* synchronize SCI IRQ handling */ - acpi_ec_flush_work(); - acpi_os_wait_events_complete(); /* synchronize Notify handling */ - s2idle_wakeup = false; + if (!lps0_device_handle || sleep_no_lps0) + return; + + acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT); + acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON); } static void acpi_s2idle_restore(void) { + s2idle_wakeup = false; + acpi_enable_all_runtime_gpes(); acpi_disable_wakeup_devices(ACPI_STATE_S0); - if (acpi_sci_irq_valid()) - disable_irq_wake(acpi_sci_irq); - - if (lps0_device_handle) { + if (acpi_sci_irq_valid()) { acpi_ec_set_gpe_wake_mask(ACPI_GPE_DISABLE); - - acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT); - acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON); + disable_irq_wake(acpi_sci_irq); } } static void acpi_s2idle_end(void) { - s2idle_in_progress = false; acpi_scan_lock_release(); } static const struct platform_s2idle_ops acpi_s2idle_ops = { .begin = acpi_s2idle_begin, .prepare = acpi_s2idle_prepare, + .prepare_late = acpi_s2idle_prepare_late, .wake = acpi_s2idle_wake, - .sync = acpi_s2idle_sync, + .restore_early = acpi_s2idle_restore_early, .restore = acpi_s2idle_restore, .end = acpi_s2idle_end, }; @@ -1063,7 +1080,6 @@ static void acpi_sleep_suspend_setup(void) } #else /* !CONFIG_SUSPEND */ -#define s2idle_in_progress (false) #define s2idle_wakeup (false) #define lps0_device_handle (NULL) static inline void acpi_sleep_suspend_setup(void) {} @@ -1074,11 +1090,6 @@ bool acpi_s2idle_wakeup(void) return s2idle_wakeup; } -bool acpi_sleep_no_ec_events(void) -{ - return !s2idle_in_progress || !lps0_device_handle; -} - #ifdef CONFIG_PM_SLEEP static u32 saved_bm_rld; diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 00f12a86ecbd42fc5ca401bef64b2a03d8249c7f..d831a61e0010eaf69dd16c96f0983315cf0a0972 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -225,13 +225,9 @@ static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode) if (!tz) return -EINVAL; - if (!acpi_has_method(tz->device->handle, "_SCP")) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n")); + if (ACPI_FAILURE(acpi_execute_simple_method(tz->device->handle, + "_SCP", mode))) return -ENODEV; - } else if (ACPI_FAILURE(acpi_execute_simple_method(tz->device->handle, - "_SCP", mode))) { - return -ENODEV; - } return 0; } @@ -463,8 +459,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) break; } - if ((flag & ACPI_TRIPS_DEVICES) - && acpi_has_method(tz->device->handle, "_TZD")) { + if (flag & ACPI_TRIPS_DEVICES) { memset(&devices, 0, sizeof(devices)); status = acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &devices); diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index ba277cd5c7faf7d3f54577f7f1872a01082dce23..697a6b12d6b96ef4d0e7b974c4d888d97084cc07 100644 --- a/drivers/acpi/x86/utils.c +++ b/drivers/acpi/x86/utils.c @@ -69,11 +69,11 @@ static const struct always_present_id always_present_ids[] = { * after _SB.PCI0.GFX0.LCD.LCD1._ON gets called has passed * *and* _STA has been called at least 3 times since. */ - ENTRY("SYNA7500", "1", ICPU(INTEL_FAM6_HASWELL_ULT), { + ENTRY("SYNA7500", "1", ICPU(INTEL_FAM6_HASWELL_L), { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7130"), }), - ENTRY("SYNA7500", "1", ICPU(INTEL_FAM6_HASWELL_ULT), { + ENTRY("SYNA7500", "1", ICPU(INTEL_FAM6_HASWELL_L), { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7139"), }), diff --git a/drivers/amba/tegra-ahb.c b/drivers/amba/tegra-ahb.c index aa64eece77a66a08a9816505f9e341770385e196..57d3b2e2d007da5617f2b830f2b8d310f866caf4 100644 --- a/drivers/amba/tegra-ahb.c +++ b/drivers/amba/tegra-ahb.c @@ -134,22 +134,13 @@ static inline void gizmo_writel(struct tegra_ahb *ahb, u32 value, u32 offset) } #ifdef CONFIG_TEGRA_IOMMU_SMMU -static int tegra_ahb_match_by_smmu(struct device *dev, const void *data) -{ - struct tegra_ahb *ahb = dev_get_drvdata(dev); - const struct device_node *dn = data; - - return (ahb->dev->of_node == dn) ? 1 : 0; -} - int tegra_ahb_enable_smmu(struct device_node *dn) { struct device *dev; u32 val; struct tegra_ahb *ahb; - dev = driver_find_device(&tegra_ahb_driver.driver, NULL, dn, - tegra_ahb_match_by_smmu); + dev = driver_find_device_by_of_node(&tegra_ahb_driver.driver, dn); if (!dev) return -EPROBE_DEFER; ahb = dev_get_drvdata(dev); diff --git a/drivers/android/binder.c b/drivers/android/binder.c index f3cf51af833bf656acfdbccb472e8515abd355ea..d970a45e60382b606a678d22ec12f990f7bd0399 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -123,7 +123,7 @@ static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR | BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION; module_param_named(debug_mask, binder_debug_mask, uint, 0644); -static char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES; +char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES; module_param_named(devices, binder_devices_param, charp, 0444); static DECLARE_WAIT_QUEUE_HEAD(binder_user_error_wait); @@ -197,30 +197,8 @@ static inline void binder_stats_created(enum binder_stat_types type) atomic_inc(&binder_stats.obj_created[type]); } -struct binder_transaction_log_entry { - int debug_id; - int debug_id_done; - int call_type; - int from_proc; - int from_thread; - int target_handle; - int to_proc; - int to_thread; - int to_node; - int data_size; - int offsets_size; - int return_error_line; - uint32_t return_error; - uint32_t return_error_param; - const char *context_name; -}; -struct binder_transaction_log { - atomic_t cur; - bool full; - struct binder_transaction_log_entry entry[32]; -}; -static struct binder_transaction_log binder_transaction_log; -static struct binder_transaction_log binder_transaction_log_failed; +struct binder_transaction_log binder_transaction_log; +struct binder_transaction_log binder_transaction_log_failed; static struct binder_transaction_log_entry *binder_transaction_log_add( struct binder_transaction_log *log) @@ -502,6 +480,7 @@ struct binder_priority { * @inner_lock: can nest under outer_lock and/or node lock * @outer_lock: no nesting under innor or node lock * Lock order: 1) outer, 2) node, 3) inner + * @binderfs_entry: process-specific binderfs log file * * Bookkeeping structure for binder processes */ @@ -531,6 +510,7 @@ struct binder_proc { struct binder_context *context; spinlock_t inner_lock; spinlock_t outer_lock; + struct dentry *binderfs_entry; }; enum { @@ -5400,6 +5380,8 @@ static int binder_open(struct inode *nodp, struct file *filp) { struct binder_proc *proc; struct binder_device *binder_dev; + struct binderfs_info *info; + struct dentry *binder_binderfs_dir_entry_proc = NULL; binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d:%d\n", __func__, current->group_leader->pid, current->pid); @@ -5421,11 +5403,14 @@ static int binder_open(struct inode *nodp, struct file *filp) } /* binderfs stashes devices in i_private */ - if (is_binderfs_device(nodp)) + if (is_binderfs_device(nodp)) { binder_dev = nodp->i_private; - else + info = nodp->i_sb->s_fs_info; + binder_binderfs_dir_entry_proc = info->proc_log_dir; + } else { binder_dev = container_of(filp->private_data, struct binder_device, miscdev); + } proc->context = &binder_dev->context; binder_alloc_init(&proc->alloc); @@ -5456,6 +5441,35 @@ static int binder_open(struct inode *nodp, struct file *filp) &proc_fops); } + if (binder_binderfs_dir_entry_proc) { + char strbuf[11]; + struct dentry *binderfs_entry; + + snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); + /* + * Similar to debugfs, the process specific log file is shared + * between contexts. If the file has already been created for a + * process, the following binderfs_create_file() call will + * fail with error code EEXIST if another context of the same + * process invoked binder_open(). This is ok since same as + * debugfs, the log file will contain information on all + * contexts of a given PID. + */ + binderfs_entry = binderfs_create_file(binder_binderfs_dir_entry_proc, + strbuf, &proc_fops, (void *)(unsigned long)proc->pid); + if (!IS_ERR(binderfs_entry)) { + proc->binderfs_entry = binderfs_entry; + } else { + int error; + + error = PTR_ERR(binderfs_entry); + if (error != -EEXIST) { + pr_warn("Unable to create file %s in binderfs (error %d)\n", + strbuf, error); + } + } + } + return 0; } @@ -5495,6 +5509,12 @@ static int binder_release(struct inode *nodp, struct file *filp) struct binder_proc *proc = filp->private_data; debugfs_remove(proc->debugfs_entry); + + if (proc->binderfs_entry) { + binderfs_remove_file(proc->binderfs_entry); + proc->binderfs_entry = NULL; + } + binder_defer_work(proc, BINDER_DEFERRED_RELEASE); return 0; @@ -6086,7 +6106,7 @@ static void print_binder_proc_stats(struct seq_file *m, } -static int state_show(struct seq_file *m, void *unused) +int binder_state_show(struct seq_file *m, void *unused) { struct binder_proc *proc; struct binder_node *node; @@ -6125,7 +6145,7 @@ static int state_show(struct seq_file *m, void *unused) return 0; } -static int stats_show(struct seq_file *m, void *unused) +int binder_stats_show(struct seq_file *m, void *unused) { struct binder_proc *proc; @@ -6141,7 +6161,7 @@ static int stats_show(struct seq_file *m, void *unused) return 0; } -static int transactions_show(struct seq_file *m, void *unused) +int binder_transactions_show(struct seq_file *m, void *unused) { struct binder_proc *proc; @@ -6197,7 +6217,7 @@ static void print_binder_transaction_log_entry(struct seq_file *m, "\n" : " (incomplete)\n"); } -static int transaction_log_show(struct seq_file *m, void *unused) +int binder_transaction_log_show(struct seq_file *m, void *unused) { struct binder_transaction_log *log = m->private; unsigned int log_cur = atomic_read(&log->cur); @@ -6229,11 +6249,6 @@ const struct file_operations binder_fops = { .release = binder_release, }; -DEFINE_SHOW_ATTRIBUTE(state); -DEFINE_SHOW_ATTRIBUTE(stats); -DEFINE_SHOW_ATTRIBUTE(transactions); -DEFINE_SHOW_ATTRIBUTE(transaction_log); - static int __init init_binder_device(const char *name) { int ret; @@ -6287,30 +6302,31 @@ static int __init binder_init(void) 0444, binder_debugfs_dir_entry_root, NULL, - &state_fops); + &binder_state_fops); debugfs_create_file("stats", 0444, binder_debugfs_dir_entry_root, NULL, - &stats_fops); + &binder_stats_fops); debugfs_create_file("transactions", 0444, binder_debugfs_dir_entry_root, NULL, - &transactions_fops); + &binder_transactions_fops); debugfs_create_file("transaction_log", 0444, binder_debugfs_dir_entry_root, &binder_transaction_log, - &transaction_log_fops); + &binder_transaction_log_fops); debugfs_create_file("failed_transaction_log", 0444, binder_debugfs_dir_entry_root, &binder_transaction_log_failed, - &transaction_log_fops); + &binder_transaction_log_fops); } - if (strcmp(binder_devices_param, "") != 0) { + if (!IS_ENABLED(CONFIG_ANDROID_BINDERFS) && + strcmp(binder_devices_param, "") != 0) { /* * Copy the module_parameter string, because we don't want to * tokenize it in-place. diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index 045b3e42d98b8336a9d069a79f38f5803402072a..bd47f7f72075a9676e84380d7c2f9f875878ebca 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -35,15 +35,63 @@ struct binder_device { struct inode *binderfs_inode; }; +/** + * binderfs_mount_opts - mount options for binderfs + * @max: maximum number of allocatable binderfs binder devices + * @stats_mode: enable binder stats in binderfs. + */ +struct binderfs_mount_opts { + int max; + int stats_mode; +}; + +/** + * binderfs_info - information about a binderfs mount + * @ipc_ns: The ipc namespace the binderfs mount belongs to. + * @control_dentry: This records the dentry of this binderfs mount + * binder-control device. + * @root_uid: uid that needs to be used when a new binder device is + * created. + * @root_gid: gid that needs to be used when a new binder device is + * created. + * @mount_opts: The mount options in use. + * @device_count: The current number of allocated binder devices. + * @proc_log_dir: Pointer to the directory dentry containing process-specific + * logs. + */ +struct binderfs_info { + struct ipc_namespace *ipc_ns; + struct dentry *control_dentry; + kuid_t root_uid; + kgid_t root_gid; + struct binderfs_mount_opts mount_opts; + int device_count; + struct dentry *proc_log_dir; +}; + extern const struct file_operations binder_fops; +extern char *binder_devices_param; + #ifdef CONFIG_ANDROID_BINDERFS extern bool is_binderfs_device(const struct inode *inode); +extern struct dentry *binderfs_create_file(struct dentry *dir, const char *name, + const struct file_operations *fops, + void *data); +extern void binderfs_remove_file(struct dentry *dentry); #else static inline bool is_binderfs_device(const struct inode *inode) { return false; } +static inline struct dentry *binderfs_create_file(struct dentry *dir, + const char *name, + const struct file_operations *fops, + void *data) +{ + return NULL; +} +static inline void binderfs_remove_file(struct dentry *dentry) {} #endif #ifdef CONFIG_ANDROID_BINDERFS @@ -55,4 +103,42 @@ static inline int __init init_binderfs(void) } #endif +int binder_stats_show(struct seq_file *m, void *unused); +DEFINE_SHOW_ATTRIBUTE(binder_stats); + +int binder_state_show(struct seq_file *m, void *unused); +DEFINE_SHOW_ATTRIBUTE(binder_state); + +int binder_transactions_show(struct seq_file *m, void *unused); +DEFINE_SHOW_ATTRIBUTE(binder_transactions); + +int binder_transaction_log_show(struct seq_file *m, void *unused); +DEFINE_SHOW_ATTRIBUTE(binder_transaction_log); + +struct binder_transaction_log_entry { + int debug_id; + int debug_id_done; + int call_type; + int from_proc; + int from_thread; + int target_handle; + int to_proc; + int to_thread; + int to_node; + int data_size; + int offsets_size; + int return_error_line; + uint32_t return_error; + uint32_t return_error_param; + const char *context_name; +}; + +struct binder_transaction_log { + atomic_t cur; + bool full; + struct binder_transaction_log_entry entry[32]; +}; + +extern struct binder_transaction_log binder_transaction_log; +extern struct binder_transaction_log binder_transaction_log_failed; #endif /* _LINUX_BINDER_INTERNAL_H */ diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index e773f45d19d932dc1c8f997b5ea9ab50e4291c70..e2580e5316a2f5747f5db96d3cbbd907f7442822 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -48,45 +48,23 @@ static dev_t binderfs_dev; static DEFINE_MUTEX(binderfs_minors_mutex); static DEFINE_IDA(binderfs_minors); -/** - * binderfs_mount_opts - mount options for binderfs - * @max: maximum number of allocatable binderfs binder devices - */ -struct binderfs_mount_opts { - int max; -}; - enum { Opt_max, + Opt_stats_mode, Opt_err }; +enum binderfs_stats_mode { + STATS_NONE, + STATS_GLOBAL, +}; + static const match_table_t tokens = { { Opt_max, "max=%d" }, + { Opt_stats_mode, "stats=%s" }, { Opt_err, NULL } }; -/** - * binderfs_info - information about a binderfs mount - * @ipc_ns: The ipc namespace the binderfs mount belongs to. - * @control_dentry: This records the dentry of this binderfs mount - * binder-control device. - * @root_uid: uid that needs to be used when a new binder device is - * created. - * @root_gid: gid that needs to be used when a new binder device is - * created. - * @mount_opts: The mount options in use. - * @device_count: The current number of allocated binder devices. - */ -struct binderfs_info { - struct ipc_namespace *ipc_ns; - struct dentry *control_dentry; - kuid_t root_uid; - kgid_t root_gid; - struct binderfs_mount_opts mount_opts; - int device_count; -}; - static inline struct binderfs_info *BINDERFS_I(const struct inode *inode) { return inode->i_sb->s_fs_info; @@ -186,8 +164,7 @@ static int binderfs_binder_device_create(struct inode *ref_inode, req->major = MAJOR(binderfs_dev); req->minor = minor; - ret = copy_to_user(userp, req, sizeof(*req)); - if (ret) { + if (userp && copy_to_user(userp, req, sizeof(*req))) { ret = -EFAULT; goto err; } @@ -272,7 +249,7 @@ static void binderfs_evict_inode(struct inode *inode) clear_inode(inode); - if (!device) + if (!S_ISCHR(inode->i_mode) || !device) return; mutex_lock(&binderfs_minors_mutex); @@ -291,8 +268,9 @@ static void binderfs_evict_inode(struct inode *inode) static int binderfs_parse_mount_opts(char *data, struct binderfs_mount_opts *opts) { - char *p; + char *p, *stats; opts->max = BINDERFS_MAX_MINOR; + opts->stats_mode = STATS_NONE; while ((p = strsep(&data, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; @@ -312,6 +290,22 @@ static int binderfs_parse_mount_opts(char *data, opts->max = max_devices; break; + case Opt_stats_mode: + if (!capable(CAP_SYS_ADMIN)) + return -EINVAL; + + stats = match_strdup(&args[0]); + if (!stats) + return -ENOMEM; + + if (strcmp(stats, "global") != 0) { + kfree(stats); + return -EINVAL; + } + + opts->stats_mode = STATS_GLOBAL; + kfree(stats); + break; default: pr_err("Invalid mount options\n"); return -EINVAL; @@ -323,8 +317,21 @@ static int binderfs_parse_mount_opts(char *data, static int binderfs_remount(struct super_block *sb, int *flags, char *data) { + int prev_stats_mode, ret; struct binderfs_info *info = sb->s_fs_info; - return binderfs_parse_mount_opts(data, &info->mount_opts); + + prev_stats_mode = info->mount_opts.stats_mode; + ret = binderfs_parse_mount_opts(data, &info->mount_opts); + if (ret) + return ret; + + if (prev_stats_mode != info->mount_opts.stats_mode) { + pr_err("Binderfs stats mode cannot be changed during a remount\n"); + info->mount_opts.stats_mode = prev_stats_mode; + return -EINVAL; + } + + return 0; } static int binderfs_show_mount_opts(struct seq_file *seq, struct dentry *root) @@ -334,6 +341,8 @@ static int binderfs_show_mount_opts(struct seq_file *seq, struct dentry *root) info = root->d_sb->s_fs_info; if (info->mount_opts.max <= BINDERFS_MAX_MINOR) seq_printf(seq, ",max=%d", info->mount_opts.max); + if (info->mount_opts.stats_mode == STATS_GLOBAL) + seq_printf(seq, ",stats=global"); return 0; } @@ -462,11 +471,192 @@ static const struct inode_operations binderfs_dir_inode_operations = { .unlink = binderfs_unlink, }; +static struct inode *binderfs_make_inode(struct super_block *sb, int mode) +{ + struct inode *ret; + + ret = new_inode(sb); + if (ret) { + ret->i_ino = iunique(sb, BINDERFS_MAX_MINOR + INODE_OFFSET); + ret->i_mode = mode; + ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret); + } + return ret; +} + +static struct dentry *binderfs_create_dentry(struct dentry *parent, + const char *name) +{ + struct dentry *dentry; + + dentry = lookup_one_len(name, parent, strlen(name)); + if (IS_ERR(dentry)) + return dentry; + + /* Return error if the file/dir already exists. */ + if (d_really_is_positive(dentry)) { + dput(dentry); + return ERR_PTR(-EEXIST); + } + + return dentry; +} + +void binderfs_remove_file(struct dentry *dentry) +{ + struct inode *parent_inode; + + parent_inode = d_inode(dentry->d_parent); + inode_lock(parent_inode); + if (simple_positive(dentry)) { + dget(dentry); + simple_unlink(parent_inode, dentry); + d_delete(dentry); + dput(dentry); + } + inode_unlock(parent_inode); +} + +struct dentry *binderfs_create_file(struct dentry *parent, const char *name, + const struct file_operations *fops, + void *data) +{ + struct dentry *dentry; + struct inode *new_inode, *parent_inode; + struct super_block *sb; + + parent_inode = d_inode(parent); + inode_lock(parent_inode); + + dentry = binderfs_create_dentry(parent, name); + if (IS_ERR(dentry)) + goto out; + + sb = parent_inode->i_sb; + new_inode = binderfs_make_inode(sb, S_IFREG | 0444); + if (!new_inode) { + dput(dentry); + dentry = ERR_PTR(-ENOMEM); + goto out; + } + + new_inode->i_fop = fops; + new_inode->i_private = data; + d_instantiate(dentry, new_inode); + fsnotify_create(parent_inode, dentry); + +out: + inode_unlock(parent_inode); + return dentry; +} + +static struct dentry *binderfs_create_dir(struct dentry *parent, + const char *name) +{ + struct dentry *dentry; + struct inode *new_inode, *parent_inode; + struct super_block *sb; + + parent_inode = d_inode(parent); + inode_lock(parent_inode); + + dentry = binderfs_create_dentry(parent, name); + if (IS_ERR(dentry)) + goto out; + + sb = parent_inode->i_sb; + new_inode = binderfs_make_inode(sb, S_IFDIR | 0755); + if (!new_inode) { + dput(dentry); + dentry = ERR_PTR(-ENOMEM); + goto out; + } + + new_inode->i_fop = &simple_dir_operations; + new_inode->i_op = &simple_dir_inode_operations; + + set_nlink(new_inode, 2); + d_instantiate(dentry, new_inode); + inc_nlink(parent_inode); + fsnotify_mkdir(parent_inode, dentry); + +out: + inode_unlock(parent_inode); + return dentry; +} + +static int init_binder_logs(struct super_block *sb) +{ + struct dentry *binder_logs_root_dir, *dentry, *proc_log_dir; + struct binderfs_info *info; + int ret = 0; + + binder_logs_root_dir = binderfs_create_dir(sb->s_root, + "binder_logs"); + if (IS_ERR(binder_logs_root_dir)) { + ret = PTR_ERR(binder_logs_root_dir); + goto out; + } + + dentry = binderfs_create_file(binder_logs_root_dir, "stats", + &binder_stats_fops, NULL); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + dentry = binderfs_create_file(binder_logs_root_dir, "state", + &binder_state_fops, NULL); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + dentry = binderfs_create_file(binder_logs_root_dir, "transactions", + &binder_transactions_fops, NULL); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + dentry = binderfs_create_file(binder_logs_root_dir, + "transaction_log", + &binder_transaction_log_fops, + &binder_transaction_log); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + dentry = binderfs_create_file(binder_logs_root_dir, + "failed_transaction_log", + &binder_transaction_log_fops, + &binder_transaction_log_failed); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + proc_log_dir = binderfs_create_dir(binder_logs_root_dir, "proc"); + if (IS_ERR(proc_log_dir)) { + ret = PTR_ERR(proc_log_dir); + goto out; + } + info = sb->s_fs_info; + info->proc_log_dir = proc_log_dir; + +out: + return ret; +} + static int binderfs_fill_super(struct super_block *sb, void *data, int silent) { int ret; struct binderfs_info *info; struct inode *inode = NULL; + struct binderfs_device device_info = { 0 }; + const char *name; + size_t len; sb->s_blocksize = PAGE_SIZE; sb->s_blocksize_bits = PAGE_SHIFT; @@ -521,7 +711,25 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) if (!sb->s_root) return -ENOMEM; - return binderfs_binder_ctl_create(sb); + ret = binderfs_binder_ctl_create(sb); + if (ret) + return ret; + + name = binder_devices_param; + for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) { + strscpy(device_info.name, name, len + 1); + ret = binderfs_binder_device_create(inode, NULL, &device_info); + if (ret) + return ret; + name += len; + if (*name == ',') + name++; + } + + if (info->mount_opts.stats_mode == STATS_GLOBAL) + return init_binder_logs(sb); + + return 0; } static struct dentry *binderfs_mount(struct file_system_type *fs_type, @@ -553,6 +761,18 @@ static struct file_system_type binder_fs_type = { int __init init_binderfs(void) { int ret; + const char *name; + size_t len; + + /* Verify that the default binderfs device names are valid. */ + name = binder_devices_param; + for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) { + if (len > BINDERFS_MAX_NAME) + return -E2BIG; + name += len; + if (*name == ',') + name++; + } /* Allocate new major number for binderfs. */ ret = alloc_chrdev_region(&binderfs_dev, 0, BINDERFS_MAX_MINOR, diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c index 85357f27a66ba1df312bcffc6de00f99d1867cbd..753985c0151772193f122d90b46df56b2c2815ee 100644 --- a/drivers/ata/acard-ahci.c +++ b/drivers/ata/acard-ahci.c @@ -160,37 +160,6 @@ static int acard_ahci_pci_device_resume(struct pci_dev *pdev) } #endif -static int acard_ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) -{ - int rc; - - if (using_dac && - !dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) { - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); - if (rc) { - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, - "64-bit DMA enable failed\n"); - return rc; - } - } - } else { - rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, "32-bit DMA enable failed\n"); - return rc; - } - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, - "32-bit consistent DMA enable failed\n"); - return rc; - } - } - return 0; -} - static void acard_ahci_pci_print_info(struct ata_host *host) { struct pci_dev *pdev = to_pci_dev(host->dev); @@ -471,9 +440,12 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id } /* initialize adapter */ - rc = acard_ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64); - if (rc) + rc = dma_set_mask_and_coherent(&pdev->dev, + DMA_BIT_MASK((hpriv->cap & HOST_CAP_64) ? 64 : 32)); + if (rc) { + dev_err(&pdev->dev, "DMA enable failed\n"); return rc; + } rc = ahci_reset_controller(host); if (rc) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index f7652baa6337043c82ef88c361477d4d7a5ca4e3..dd92faf197d5ed81a8a7c0fcbc0d39a73be5b977 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -65,6 +65,12 @@ enum board_ids { board_ahci_sb700, /* for SB700 and SB800 */ board_ahci_vt8251, + /* + * board IDs for Intel chipsets that support more than 6 ports + * *and* end up needing the PCS quirk. + */ + board_ahci_pcs7, + /* aliases */ board_ahci_mcp_linux = board_ahci_mcp65, board_ahci_mcp67 = board_ahci_mcp65, @@ -220,6 +226,12 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_vt8251_ops, }, + [board_ahci_pcs7] = { + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, }; static const struct pci_device_id ahci_pci_tbl[] = { @@ -264,26 +276,26 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */ { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci_mobile }, /* PCH M RAID */ { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */ - { PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19b2), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19b3), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19b4), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19b5), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19b6), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19b7), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19bE), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19bF), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19c0), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19c1), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19c2), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19c3), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19c4), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19c5), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19c6), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19c7), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */ - { PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b0), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b1), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b2), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b3), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b4), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b5), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b6), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b7), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19bE), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19bF), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c0), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c1), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c2), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c3), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c4), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c5), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c6), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c7), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19cE), board_ahci_pcs7 }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19cF), board_ahci_pcs7 }, /* DNV AHCI */ { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */ { PCI_VDEVICE(INTEL, 0x1c03), board_ahci_mobile }, /* CPT M AHCI */ { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */ @@ -623,30 +635,6 @@ static void ahci_pci_save_initial_config(struct pci_dev *pdev, ahci_save_initial_config(&pdev->dev, hpriv); } -static int ahci_pci_reset_controller(struct ata_host *host) -{ - struct pci_dev *pdev = to_pci_dev(host->dev); - int rc; - - rc = ahci_reset_controller(host); - if (rc) - return rc; - - if (pdev->vendor == PCI_VENDOR_ID_INTEL) { - struct ahci_host_priv *hpriv = host->private_data; - u16 tmp16; - - /* configure PCS */ - pci_read_config_word(pdev, 0x92, &tmp16); - if ((tmp16 & hpriv->port_map) != hpriv->port_map) { - tmp16 |= hpriv->port_map; - pci_write_config_word(pdev, 0x92, tmp16); - } - } - - return 0; -} - static void ahci_pci_init_controller(struct ata_host *host) { struct ahci_host_priv *hpriv = host->private_data; @@ -849,7 +837,7 @@ static int ahci_pci_device_runtime_resume(struct device *dev) struct ata_host *host = pci_get_drvdata(pdev); int rc; - rc = ahci_pci_reset_controller(host); + rc = ahci_reset_controller(host); if (rc) return rc; ahci_pci_init_controller(host); @@ -884,7 +872,7 @@ static int ahci_pci_device_resume(struct device *dev) ahci_mcp89_apple_enable(pdev); if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { - rc = ahci_pci_reset_controller(host); + rc = ahci_reset_controller(host); if (rc) return rc; @@ -901,40 +889,23 @@ static int ahci_pci_device_resume(struct device *dev) static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) { + const int dma_bits = using_dac ? 64 : 32; int rc; /* * If the device fixup already set the dma_mask to some non-standard * value, don't extend it here. This happens on STA2X11, for example. + * + * XXX: manipulating the DMA mask from platform code is completely + * bogus, platform code should use dev->bus_dma_mask instead.. */ if (pdev->dma_mask && pdev->dma_mask < DMA_BIT_MASK(32)) return 0; - if (using_dac && - !dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) { - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); - if (rc) { - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, - "64-bit DMA enable failed\n"); - return rc; - } - } - } else { - rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, "32-bit DMA enable failed\n"); - return rc; - } - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, - "32-bit consistent DMA enable failed\n"); - return rc; - } - } - return 0; + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(dma_bits)); + if (rc) + dev_err(&pdev->dev, "DMA enable failed\n"); + return rc; } static void ahci_pci_print_info(struct ata_host *host) @@ -1619,6 +1590,34 @@ static void ahci_update_initial_lpm_policy(struct ata_port *ap, ap->target_lpm_policy = policy; } +static void ahci_intel_pcs_quirk(struct pci_dev *pdev, struct ahci_host_priv *hpriv) +{ + const struct pci_device_id *id = pci_match_id(ahci_pci_tbl, pdev); + u16 tmp16; + + /* + * Only apply the 6-port PCS quirk for known legacy platforms. + */ + if (!id || id->vendor != PCI_VENDOR_ID_INTEL) + return; + if (((enum board_ids) id->driver_data) < board_ahci_pcs7) + return; + + /* + * port_map is determined from PORTS_IMPL PCI register which is + * implemented as write or write-once register. If the register + * isn't programmed, ahci automatically generates it from number + * of ports, which is good enough for PCS programming. It is + * otherwise expected that platform firmware enables the ports + * before the OS boots. + */ + pci_read_config_word(pdev, PCS_6, &tmp16); + if ((tmp16 & hpriv->port_map) != hpriv->port_map) { + tmp16 |= hpriv->port_map; + pci_write_config_word(pdev, PCS_6, tmp16); + } +} + static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned int board_id = ent->driver_data; @@ -1731,6 +1730,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* save initial config */ ahci_pci_save_initial_config(pdev, hpriv); + /* + * If platform firmware failed to enable ports, try to enable + * them here. + */ + ahci_intel_pcs_quirk(pdev, hpriv); + /* prepare host */ if (hpriv->cap & HOST_CAP_NCQ) { pi.flags |= ATA_FLAG_NCQ; @@ -1840,7 +1845,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - rc = ahci_pci_reset_controller(host); + rc = ahci_reset_controller(host); if (rc) return rc; diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 0570629d719d8dc4c0f23bf75a407cc085b658f6..3dbf398c92eafa056f507d1f97669a8938bb69a2 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -247,6 +247,8 @@ enum { ATA_FLAG_ACPI_SATA | ATA_FLAG_AN, ICH_MAP = 0x90, /* ICH MAP register */ + PCS_6 = 0x92, /* 6 port PCS */ + PCS_7 = 0x94, /* 7+ port PCS (Denverton) */ /* em constants */ EM_MAX_SLOTS = 8, diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index e4c45d3cca79c1b021cd91acd45a139fe5b73408..bff369d9a1a7827cd0059180248167c2a349a9ff 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -175,7 +175,6 @@ struct ata_port_operations ahci_pmp_retry_srst_ops = { EXPORT_SYMBOL_GPL(ahci_pmp_retry_srst_ops); static bool ahci_em_messages __read_mostly = true; -EXPORT_SYMBOL_GPL(ahci_em_messages); module_param(ahci_em_messages, bool, 0444); /* add other LED protocol types when they become supported */ MODULE_PARM_DESC(ahci_em_messages, diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 4f115adb4ee83b3836f1d596e1350ce3785011d6..4ed682da52ae915e7e0662a189f3f29b95174458 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -3153,15 +3153,9 @@ void ata_pci_bmdma_init(struct ata_host *host) * ->sff_irq_clear method. Try to initialize bmdma_addr * regardless of dma masks. */ - rc = dma_set_mask(&pdev->dev, ATA_DMA_MASK); + rc = dma_set_mask_and_coherent(&pdev->dev, ATA_DMA_MASK); if (rc) ata_bmdma_nodma(host, "failed to set dma mask"); - if (!rc) { - rc = dma_set_coherent_mask(&pdev->dev, ATA_DMA_MASK); - if (rc) - ata_bmdma_nodma(host, - "failed to set consistent dma mask"); - } /* request and iomap DMA region */ rc = pcim_iomap_regions(pdev, 1 << 4, dev_driver_string(gdev)); diff --git a/drivers/ata/pata_atp867x.c b/drivers/ata/pata_atp867x.c index 2b9ed4ddef8ded6e1772eafda8f215547e4fcd3b..cfd0cf2cbca6caaaab2fd2b2d424375bb09a95a2 100644 --- a/drivers/ata/pata_atp867x.c +++ b/drivers/ata/pata_atp867x.c @@ -463,12 +463,7 @@ static int atp867x_ata_pci_sff_init_host(struct ata_host *host) atp867x_fixup(host); - rc = dma_set_mask(&pdev->dev, ATA_DMA_MASK); - if (rc) - return rc; - - rc = dma_set_coherent_mask(&pdev->dev, ATA_DMA_MASK); - return rc; + return dma_set_mask_and_coherent(&pdev->dev, ATA_DMA_MASK); } static int atp867x_init_one(struct pci_dev *pdev, diff --git a/drivers/ata/pata_buddha.c b/drivers/ata/pata_buddha.c index 11a8044ff633cf5ca1e619a184b1bd06874c0d4c..27d4c417fc60bb0f1f62dee3156cf4a373146e9b 100644 --- a/drivers/ata/pata_buddha.c +++ b/drivers/ata/pata_buddha.c @@ -18,7 +18,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -29,7 +31,7 @@ #include #define DRV_NAME "pata_buddha" -#define DRV_VERSION "0.1.0" +#define DRV_VERSION "0.1.1" #define BUDDHA_BASE1 0x800 #define BUDDHA_BASE2 0xa00 @@ -47,11 +49,11 @@ enum { BOARD_XSURF }; -static unsigned int buddha_bases[3] __initdata = { +static unsigned int buddha_bases[3] = { BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3 }; -static unsigned int xsurf_bases[2] __initdata = { +static unsigned int xsurf_bases[2] = { XSURF_BASE1, XSURF_BASE2 }; @@ -145,111 +147,151 @@ static struct ata_port_operations pata_xsurf_ops = { .set_mode = pata_buddha_set_mode, }; -static int __init pata_buddha_init_one(void) +static int pata_buddha_probe(struct zorro_dev *z, + const struct zorro_device_id *ent) { - struct zorro_dev *z = NULL; + static const char * const board_name[] = { + "Buddha", "Catweasel", "X-Surf" + }; + struct ata_host *host; + void __iomem *buddha_board; + unsigned long board; + unsigned int type = ent->driver_data; + unsigned int nr_ports = (type == BOARD_CATWEASEL) ? 3 : 2; + void *old_drvdata; + int i; + + dev_info(&z->dev, "%s IDE controller\n", board_name[type]); + + board = z->resource.start; + + if (type != BOARD_XSURF) { + if (!devm_request_mem_region(&z->dev, + board + BUDDHA_BASE1, + 0x800, DRV_NAME)) + return -ENXIO; + } else { + if (!devm_request_mem_region(&z->dev, + board + XSURF_BASE1, + 0x1000, DRV_NAME)) + return -ENXIO; + if (!devm_request_mem_region(&z->dev, + board + XSURF_BASE2, + 0x1000, DRV_NAME)) { + } + } + + /* Workaround for X-Surf: Save drvdata in case zorro8390 has set it */ + if (type == BOARD_XSURF) + old_drvdata = dev_get_drvdata(&z->dev); + + /* allocate host */ + host = ata_host_alloc(&z->dev, nr_ports); + if (type == BOARD_XSURF) + dev_set_drvdata(&z->dev, old_drvdata); + if (!host) + return -ENXIO; + + buddha_board = ZTWO_VADDR(board); + + /* enable the board IRQ on Buddha/Catweasel */ + if (type != BOARD_XSURF) + z_writeb(0, buddha_board + BUDDHA_IRQ_MR); - while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { - static const char *board_name[] - = { "Buddha", "Catweasel", "X-Surf" }; - struct ata_host *host; - void __iomem *buddha_board; - unsigned long board; - unsigned int type, nr_ports = 2; - int i; - - if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) { - type = BOARD_BUDDHA; - } else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) { - type = BOARD_CATWEASEL; - nr_ports++; - } else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) { - type = BOARD_XSURF; - } else - continue; - - dev_info(&z->dev, "%s IDE controller\n", board_name[type]); - - board = z->resource.start; + for (i = 0; i < nr_ports; i++) { + struct ata_port *ap = host->ports[i]; + void __iomem *base, *irqport; + unsigned long ctl = 0; if (type != BOARD_XSURF) { - if (!devm_request_mem_region(&z->dev, - board + BUDDHA_BASE1, - 0x800, DRV_NAME)) - continue; + ap->ops = &pata_buddha_ops; + base = buddha_board + buddha_bases[i]; + ctl = BUDDHA_CONTROL; + irqport = buddha_board + BUDDHA_IRQ + i * 0x40; } else { - if (!devm_request_mem_region(&z->dev, - board + XSURF_BASE1, - 0x1000, DRV_NAME)) - continue; - if (!devm_request_mem_region(&z->dev, - board + XSURF_BASE2, - 0x1000, DRV_NAME)) - continue; + ap->ops = &pata_xsurf_ops; + base = buddha_board + xsurf_bases[i]; + /* X-Surf has no CS1* (Control/AltStat) */ + irqport = buddha_board + XSURF_IRQ; } - /* allocate host */ - host = ata_host_alloc(&z->dev, nr_ports); - if (!host) - continue; - - buddha_board = ZTWO_VADDR(board); - - /* enable the board IRQ on Buddha/Catweasel */ - if (type != BOARD_XSURF) - z_writeb(0, buddha_board + BUDDHA_IRQ_MR); - - for (i = 0; i < nr_ports; i++) { - struct ata_port *ap = host->ports[i]; - void __iomem *base, *irqport; - unsigned long ctl = 0; - - if (type != BOARD_XSURF) { - ap->ops = &pata_buddha_ops; - base = buddha_board + buddha_bases[i]; - ctl = BUDDHA_CONTROL; - irqport = buddha_board + BUDDHA_IRQ + i * 0x40; - } else { - ap->ops = &pata_xsurf_ops; - base = buddha_board + xsurf_bases[i]; - /* X-Surf has no CS1* (Control/AltStat) */ - irqport = buddha_board + XSURF_IRQ; - } - - ap->pio_mask = ATA_PIO4; - ap->flags |= ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY; - - ap->ioaddr.data_addr = base; - ap->ioaddr.error_addr = base + 2 + 1 * 4; - ap->ioaddr.feature_addr = base + 2 + 1 * 4; - ap->ioaddr.nsect_addr = base + 2 + 2 * 4; - ap->ioaddr.lbal_addr = base + 2 + 3 * 4; - ap->ioaddr.lbam_addr = base + 2 + 4 * 4; - ap->ioaddr.lbah_addr = base + 2 + 5 * 4; - ap->ioaddr.device_addr = base + 2 + 6 * 4; - ap->ioaddr.status_addr = base + 2 + 7 * 4; - ap->ioaddr.command_addr = base + 2 + 7 * 4; - - if (ctl) { - ap->ioaddr.altstatus_addr = base + ctl; - ap->ioaddr.ctl_addr = base + ctl; - } - - ap->private_data = (void *)irqport; - - ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", board, - ctl ? board + buddha_bases[i] + ctl : 0); + ap->pio_mask = ATA_PIO4; + ap->flags |= ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY; + + ap->ioaddr.data_addr = base; + ap->ioaddr.error_addr = base + 2 + 1 * 4; + ap->ioaddr.feature_addr = base + 2 + 1 * 4; + ap->ioaddr.nsect_addr = base + 2 + 2 * 4; + ap->ioaddr.lbal_addr = base + 2 + 3 * 4; + ap->ioaddr.lbam_addr = base + 2 + 4 * 4; + ap->ioaddr.lbah_addr = base + 2 + 5 * 4; + ap->ioaddr.device_addr = base + 2 + 6 * 4; + ap->ioaddr.status_addr = base + 2 + 7 * 4; + ap->ioaddr.command_addr = base + 2 + 7 * 4; + + if (ctl) { + ap->ioaddr.altstatus_addr = base + ctl; + ap->ioaddr.ctl_addr = base + ctl; } - ata_host_activate(host, IRQ_AMIGA_PORTS, ata_sff_interrupt, - IRQF_SHARED, &pata_buddha_sht); + ap->private_data = (void *)irqport; + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", board, + ctl ? board + buddha_bases[i] + ctl : 0); } + ata_host_activate(host, IRQ_AMIGA_PORTS, ata_sff_interrupt, + IRQF_SHARED, &pata_buddha_sht); + return 0; } -module_init(pata_buddha_init_one); +static void pata_buddha_remove(struct zorro_dev *z) +{ + struct ata_host *host = dev_get_drvdata(&z->dev); + + ata_host_detach(host); +} + +static const struct zorro_device_id pata_buddha_zorro_tbl[] = { + { ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA, BOARD_BUDDHA}, + { ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL, BOARD_CATWEASEL}, + { 0 } +}; +MODULE_DEVICE_TABLE(zorro, pata_buddha_zorro_tbl); + +static struct zorro_driver pata_buddha_driver = { + .name = "pata_buddha", + .id_table = pata_buddha_zorro_tbl, + .probe = pata_buddha_probe, + .remove = pata_buddha_remove, +}; + +/* + * We cannot have a modalias for X-Surf boards, as it competes with the + * zorro8390 network driver. As a stopgap measure until we have proper + * MFD support for this board, we manually attach to it late after Zorro + * has enumerated its boards. + */ +static int __init pata_buddha_late_init(void) +{ + struct zorro_dev *z = NULL; + + /* Auto-bind to regular boards */ + zorro_register_driver(&pata_buddha_driver); + + /* Manually bind to all X-Surf boards */ + while ((z = zorro_find_device(ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF, z))) { + static struct zorro_device_id xsurf_ent = { + ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF, BOARD_XSURF + }; + + pata_buddha_probe(z, &xsurf_ent); + } + + return 0; +} +late_initcall(pata_buddha_late_init); MODULE_AUTHOR("Bartlomiej Zolnierkiewicz"); MODULE_DESCRIPTION("low-level driver for Buddha/Catweasel/X-Surf PATA"); diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 099a5c68a4c99863f0528b88a2aa2b7449000f21..9052148b306d9f157e5b2e22c04a8282add07c2d 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -155,14 +155,10 @@ static int cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return -ENODEV; } - if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) { printk(KERN_ERR DRV_NAME ": unable to configure DMA mask.\n"); return -ENODEV; } - if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32))) { - printk(KERN_ERR DRV_NAME ": unable to configure consistent DMA mask.\n"); - return -ENODEV; - } /* Map IO ports and initialize host accordingly */ iomap[0] = devm_ioport_map(&pdev->dev, cmd_port[0], 8); diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index b2fc023783b15c3338160d3a0370a4e494b5db6f..83974d5eb3871d15a6eb9a5513a6efb3d003a220 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -221,10 +221,7 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (rc) return rc; host->iomap = pcim_iomap_table(pdev); - rc = dma_set_mask(&pdev->dev, ATA_DMA_MASK); - if (rc) - return rc; - rc = dma_set_coherent_mask(&pdev->dev, ATA_DMA_MASK); + rc = dma_set_mask_and_coherent(&pdev->dev, ATA_DMA_MASK); if (rc) return rc; diff --git a/drivers/ata/pata_ninja32.c b/drivers/ata/pata_ninja32.c index 607db1f05f9a01563dc5611f0a2de354315f1289..f9255d6fd19406b8c009e0ca8ec2596decc818bb 100644 --- a/drivers/ata/pata_ninja32.c +++ b/drivers/ata/pata_ninja32.c @@ -123,10 +123,7 @@ static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id) return rc; host->iomap = pcim_iomap_table(dev); - rc = dma_set_mask(&dev->dev, ATA_DMA_MASK); - if (rc) - return rc; - rc = dma_set_coherent_mask(&dev->dev, ATA_DMA_MASK); + rc = dma_set_mask_and_coherent(&dev->dev, ATA_DMA_MASK); if (rc) return rc; pci_set_master(dev); diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index b656e15368554d4b84d65e2be3ce8020ba889fe2..de834fbb6dfe6eb301086667248a3a9d68ffa982 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -722,11 +722,7 @@ static int pdc2027x_init_one(struct pci_dev *pdev, return rc; host->iomap = pcim_iomap_table(pdev); - rc = dma_set_mask(&pdev->dev, ATA_DMA_MASK); - if (rc) - return rc; - - rc = dma_set_coherent_mask(&pdev->dev, ATA_DMA_MASK); + rc = dma_set_mask_and_coherent(&pdev->dev, ATA_DMA_MASK); if (rc) return rc; diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index c14071be4f55f2f5222f5599b7570bba6de4d430..7ab9aea3b6305dd9ba1aad6c2650d3cd7ebb4c5b 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -374,10 +374,7 @@ static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) host->iomap = pcim_iomap_table(pdev); /* Setup DMA masks */ - rc = dma_set_mask(&pdev->dev, ATA_DMA_MASK); - if (rc) - return rc; - rc = dma_set_coherent_mask(&pdev->dev, ATA_DMA_MASK); + rc = dma_set_mask_and_coherent(&pdev->dev, ATA_DMA_MASK); if (rc) return rc; pci_set_master(pdev); diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index c5bbb07aa7d9d781738c4534bde199bd098ce5bb..cb490531b62ec0be93f072d6f4c16d7fe45af117 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -572,23 +572,6 @@ static void adma_host_init(struct ata_host *host, unsigned int chip_id) adma_reset_engine(host->ports[port_no]); } -static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) -{ - int rc; - - rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, "32-bit DMA enable failed\n"); - return rc; - } - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, "32-bit consistent DMA enable failed\n"); - return rc; - } - return 0; -} - static int adma_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -619,9 +602,11 @@ static int adma_ata_init_one(struct pci_dev *pdev, host->iomap = pcim_iomap_table(pdev); mmio_base = host->iomap[ADMA_MMIO_BAR]; - rc = adma_set_dma_masks(pdev, mmio_base); - if (rc) + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (rc) { + dev_err(&pdev->dev, "32-bit DMA enable failed\n"); return rc; + } for (port_no = 0; port_no < ADMA_PORTS; ++port_no) { struct ata_port *ap = host->ports[port_no]; diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 790968497dfe86cd234c860b9eacf5b6683d615e..7f99e23bff88c31e02938ca8fd85bb10ef33cea8 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -862,18 +862,12 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } /* Set dma_mask. This devices doesn't support 64bit addressing. */ - rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (rc) { dev_err(&pdev->dev, "32-bit DMA enable failed\n"); return rc; } - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, "32-bit consistent DMA enable failed\n"); - return rc; - } - rc = init_controller(hpriv->mmio_base, hpriv->cached_hctl); if (rc) { dev_err(&pdev->dev, "failed to initialize controller\n"); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index da585d2bded655277d698e0285ffeae50b2b17c0..ad385a113391ea95279f65d117890c590b75dbd9 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -4314,38 +4314,6 @@ static struct pci_driver mv_pci_driver = { }; -/* move to PCI layer or libata core? */ -static int pci_go_64(struct pci_dev *pdev) -{ - int rc; - - if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) { - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); - if (rc) { - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, - "64-bit DMA enable failed\n"); - return rc; - } - } - } else { - rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, "32-bit DMA enable failed\n"); - return rc; - } - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, - "32-bit consistent DMA enable failed\n"); - return rc; - } - } - - return rc; -} - /** * mv_print_info - Dump key info to kernel log for perusal. * @host: ATA host to print info about @@ -4430,9 +4398,11 @@ static int mv_pci_init_one(struct pci_dev *pdev, host->iomap = pcim_iomap_table(pdev); hpriv->base = host->iomap[MV_PRIMARY_BAR]; - rc = pci_go_64(pdev); - if (rc) + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (rc) { + dev_err(&pdev->dev, "DMA enable failed\n"); return rc; + } rc = mv_create_dma_pools(hpriv, &pdev->dev); if (rc) diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index b44b4b64354c242e990d5bf010b37579dc2456f8..56946012d113a50af4b8bb24628596ac0f55b24d 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -1122,14 +1122,10 @@ static int nv_adma_port_start(struct ata_port *ap) /* * Now that the legacy PRD and padding buffer are allocated we can - * try to raise the DMA mask to allocate the CPB/APRD table. + * raise the DMA mask to allocate the CPB/APRD table. */ - rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); - if (rc) { - rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) - return rc; - } + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + pp->adma_dma_mask = *dev->dma_mask; mem = dmam_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ, diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index f4dfec3b6e424146a90c00b5d9a53146dca6bdf2..5fd464765ddcb5195c3fe731992d792b6912faf9 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -1230,10 +1230,7 @@ static int pdc_ata_init_one(struct pci_dev *pdev, /* initialize adapter */ pdc_host_init(host); - rc = dma_set_mask(&pdev->dev, ATA_DMA_MASK); - if (rc) - return rc; - rc = dma_set_coherent_mask(&pdev->dev, ATA_DMA_MASK); + rc = dma_set_mask_and_coherent(&pdev->dev, ATA_DMA_MASK); if (rc) return rc; diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 865e5c58bd94883dcc3b1d8758fe4a8792ab22e8..c53c5a47204db12815c6318beec17f0a7d92d42d 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -537,33 +537,13 @@ static void qs_host_init(struct ata_host *host, unsigned int chip_id) static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) { u32 bus_info = readl(mmio_base + QS_HID_HPHY); - int rc, have_64bit_bus = (bus_info & QS_HPHY_64BIT); - - if (have_64bit_bus && - !dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) { - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); - if (rc) { - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, - "64-bit DMA enable failed\n"); - return rc; - } - } - } else { - rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, "32-bit DMA enable failed\n"); - return rc; - } - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, - "32-bit consistent DMA enable failed\n"); - return rc; - } - } - return 0; + int dma_bits = (bus_info & QS_HPHY_64BIT) ? 64 : 32; + int rc; + + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(dma_bits)); + if (rc) + dev_err(&pdev->dev, "%d-bit DMA enable failed\n", dma_bits); + return rc; } static int qs_ata_init_one(struct pci_dev *pdev, diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 25b6a52be5abac7b575b43d324e385cbf034b06a..e6fbae2f645acf5f74dd48d52a209732fde879f5 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -757,10 +757,7 @@ static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return rc; host->iomap = pcim_iomap_table(pdev); - rc = dma_set_mask(&pdev->dev, ATA_DMA_MASK); - if (rc) - return rc; - rc = dma_set_coherent_mask(&pdev->dev, ATA_DMA_MASK); + rc = dma_set_mask_and_coherent(&pdev->dev, ATA_DMA_MASK); if (rc) return rc; diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 98aad820692198bd9b4704f74fc62226c3831357..7bef82de53ca972b877236c71aeae849ed8b59e0 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -1301,28 +1301,10 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) host->iomap = iomap; /* configure and activate the device */ - if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) { - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); - if (rc) { - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, - "64-bit DMA enable failed\n"); - return rc; - } - } - } else { - rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, "32-bit DMA enable failed\n"); - return rc; - } - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, - "32-bit consistent DMA enable failed\n"); - return rc; - } + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (rc) { + dev_err(&pdev->dev, "DMA enable failed\n"); + return rc; } /* Set max read request size to 4096. This slightly increases diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index b903d55c6c20d50c28724b45c00fd4b81c7361f7..f8552559db7f5c1962c892e12c92f790c5eb98c5 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -471,10 +471,7 @@ static int k2_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *en ata_port_pbar_desc(ap, 5, offset, "port"); } - rc = dma_set_mask(&pdev->dev, ATA_DMA_MASK); - if (rc) - return rc; - rc = dma_set_coherent_mask(&pdev->dev, ATA_DMA_MASK); + rc = dma_set_mask_and_coherent(&pdev->dev, ATA_DMA_MASK); if (rc) return rc; diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index ae8e374d0a77cc049e351b3e7813bd0c3af64858..2277ba0c9c7f4c527f2db952fe7ba5885631f2ba 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -1470,10 +1470,7 @@ static int pdc_sata_init_one(struct pci_dev *pdev, } /* configure and activate */ - rc = dma_set_mask(&pdev->dev, ATA_DMA_MASK); - if (rc) - return rc; - rc = dma_set_coherent_mask(&pdev->dev, ATA_DMA_MASK); + rc = dma_set_mask_and_coherent(&pdev->dev, ATA_DMA_MASK); if (rc) return rc; diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index fcb9245b184f53371032c8c2e96790f0fc1409a0..c7891cc84ea0bb7d4d3da77d1026d04d22556fa5 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -505,14 +505,7 @@ static int vt6421_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) for (i = 0; i < host->n_ports; i++) vt6421_init_addrs(host->ports[i]); - rc = dma_set_mask(&pdev->dev, ATA_DMA_MASK); - if (rc) - return rc; - rc = dma_set_coherent_mask(&pdev->dev, ATA_DMA_MASK); - if (rc) - return rc; - - return 0; + return dma_set_mask_and_coherent(&pdev->dev, ATA_DMA_MASK); } static int vt8251_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index fd401e9164ef4a4c4b11a1531e9f8843926ccc3f..8fa952cb9f7f4bf150db781f4d8ba1e09f5992d0 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -371,10 +371,7 @@ static int vsc_sata_init_one(struct pci_dev *pdev, /* * Use 32 bit DMA mask, because 64 bit address support is poor. */ - rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) - return rc; - rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (rc) return rc; diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 79b718430cd1e9124621e1aee9708c5ef150973f..b23d1e4bad33b20653b213047d815f388dfd0d47 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -1136,7 +1136,7 @@ DPRINTK("doing direct send\n"); /* @@@ well, this doesn't work anyway */ else put_dma(tx->index,eni_dev->dma,&j,(unsigned long) skb_frag_page(&skb_shinfo(skb)->frags[i]) + - skb_shinfo(skb)->frags[i].page_offset, + skb_frag_off(&skb_shinfo(skb)->frags[i]), skb_frag_size(&skb_shinfo(skb)->frags[i])); } if (skb->len & 3) { diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 211607986134dcfd3864c11ce4201967b6702707..70b00ae4ec383aa5584e6f52b80c549b587ca5e2 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -2580,10 +2580,9 @@ he_send(struct atm_vcc *vcc, struct sk_buff *skb) slot = 0; } - tpd->iovec[slot].addr = dma_map_single(&he_dev->pci_dev->dev, - (void *) page_address(frag->page) + frag->page_offset, - frag->size, DMA_TO_DEVICE); - tpd->iovec[slot].len = frag->size; + tpd->iovec[slot].addr = skb_frag_dma_map(&he_dev->pci_dev->dev, + frag, 0, skb_frag_size(frag), DMA_TO_DEVICE); + tpd->iovec[slot].len = skb_frag_size(frag); ++slot; } diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 5c4c6eeb505c526f3c356d1664a7e3da027b939e..c32f7dd9879ac59f2e48d47695e5c31d0afed2c4 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -516,9 +516,8 @@ struct geos_gpio_attr { static ssize_t geos_gpio_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct pci_dev *pdev = to_pci_dev(dev); struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr); - struct solos_card *card = pci_get_drvdata(pdev); + struct solos_card *card = dev_get_drvdata(dev); uint32_t data32; if (count != 1 && (count != 2 || buf[1] != '\n')) @@ -542,9 +541,8 @@ static ssize_t geos_gpio_store(struct device *dev, struct device_attribute *attr static ssize_t geos_gpio_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct pci_dev *pdev = to_pci_dev(dev); struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr); - struct solos_card *card = pci_get_drvdata(pdev); + struct solos_card *card = dev_get_drvdata(dev); uint32_t data32; data32 = ioread32(card->config_regs + GPIO_STATUS); @@ -556,9 +554,8 @@ static ssize_t geos_gpio_show(struct device *dev, struct device_attribute *attr, static ssize_t hardware_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct pci_dev *pdev = to_pci_dev(dev); struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr); - struct solos_card *card = pci_get_drvdata(pdev); + struct solos_card *card = dev_get_drvdata(dev); uint32_t data32; data32 = ioread32(card->config_regs + GPIO_STATUS); diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index 68489d1f00bb33a275100e280bd68341aa31c8d1..b8313a04422db69495d547cd10a8ef39c88510a1 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -97,7 +97,7 @@ config CFAG12864B say Y. You also need the ks0108 LCD Controller driver. For help about how to wire your LCD to the parallel port, - check Documentation/auxdisplay/cfag12864b + check Documentation/admin-guide/auxdisplay/cfag12864b.rst Depends on the x86 arch and the framebuffer support. diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index dc404492381d84efdd58a3e92f8f74fca852408e..28b92e3cc570c61e94120678032f9f378da9359a 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -202,7 +202,7 @@ config GENERIC_ARCH_TOPOLOGY help Enable support for architectures common topology code: e.g., parsing CPU capacity information from DT, usage of such information for - appropriate scaling, sysfs interface for changing capacity values at + appropriate scaling, sysfs interface for reading capacity values at runtime. endmenu diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 63c1e76739f12648c9face8e841d756d693dec01..1eb81f113786f3875d590ca4941e5eef7e14bb51 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -15,6 +15,11 @@ #include #include #include +#include +#include +#include +#include +#include DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE; @@ -174,7 +179,7 @@ init_cpu_capacity_callback(struct notifier_block *nb, if (!raw_capacity) return 0; - if (val != CPUFREQ_NOTIFY) + if (val != CPUFREQ_CREATE_POLICY) return 0; pr_debug("cpu_capacity: init cpu capacity for CPUs [%*pbl] (to_visit=%*pbl)\n", @@ -241,3 +246,296 @@ static void parsing_done_workfn(struct work_struct *work) #else core_initcall(free_raw_capacity); #endif + +#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV) +static int __init get_cpu_for_node(struct device_node *node) +{ + struct device_node *cpu_node; + int cpu; + + cpu_node = of_parse_phandle(node, "cpu", 0); + if (!cpu_node) + return -1; + + cpu = of_cpu_node_to_id(cpu_node); + if (cpu >= 0) + topology_parse_cpu_capacity(cpu_node, cpu); + else + pr_crit("Unable to find CPU node for %pOF\n", cpu_node); + + of_node_put(cpu_node); + return cpu; +} + +static int __init parse_core(struct device_node *core, int package_id, + int core_id) +{ + char name[10]; + bool leaf = true; + int i = 0; + int cpu; + struct device_node *t; + + do { + snprintf(name, sizeof(name), "thread%d", i); + t = of_get_child_by_name(core, name); + if (t) { + leaf = false; + cpu = get_cpu_for_node(t); + if (cpu >= 0) { + cpu_topology[cpu].package_id = package_id; + cpu_topology[cpu].core_id = core_id; + cpu_topology[cpu].thread_id = i; + } else { + pr_err("%pOF: Can't get CPU for thread\n", + t); + of_node_put(t); + return -EINVAL; + } + of_node_put(t); + } + i++; + } while (t); + + cpu = get_cpu_for_node(core); + if (cpu >= 0) { + if (!leaf) { + pr_err("%pOF: Core has both threads and CPU\n", + core); + return -EINVAL; + } + + cpu_topology[cpu].package_id = package_id; + cpu_topology[cpu].core_id = core_id; + } else if (leaf) { + pr_err("%pOF: Can't get CPU for leaf core\n", core); + return -EINVAL; + } + + return 0; +} + +static int __init parse_cluster(struct device_node *cluster, int depth) +{ + char name[10]; + bool leaf = true; + bool has_cores = false; + struct device_node *c; + static int package_id __initdata; + int core_id = 0; + int i, ret; + + /* + * First check for child clusters; we currently ignore any + * information about the nesting of clusters and present the + * scheduler with a flat list of them. + */ + i = 0; + do { + snprintf(name, sizeof(name), "cluster%d", i); + c = of_get_child_by_name(cluster, name); + if (c) { + leaf = false; + ret = parse_cluster(c, depth + 1); + of_node_put(c); + if (ret != 0) + return ret; + } + i++; + } while (c); + + /* Now check for cores */ + i = 0; + do { + snprintf(name, sizeof(name), "core%d", i); + c = of_get_child_by_name(cluster, name); + if (c) { + has_cores = true; + + if (depth == 0) { + pr_err("%pOF: cpu-map children should be clusters\n", + c); + of_node_put(c); + return -EINVAL; + } + + if (leaf) { + ret = parse_core(c, package_id, core_id++); + } else { + pr_err("%pOF: Non-leaf cluster with core %s\n", + cluster, name); + ret = -EINVAL; + } + + of_node_put(c); + if (ret != 0) + return ret; + } + i++; + } while (c); + + if (leaf && !has_cores) + pr_warn("%pOF: empty cluster\n", cluster); + + if (leaf) + package_id++; + + return 0; +} + +static int __init parse_dt_topology(void) +{ + struct device_node *cn, *map; + int ret = 0; + int cpu; + + cn = of_find_node_by_path("/cpus"); + if (!cn) { + pr_err("No CPU information found in DT\n"); + return 0; + } + + /* + * When topology is provided cpu-map is essentially a root + * cluster with restricted subnodes. + */ + map = of_get_child_by_name(cn, "cpu-map"); + if (!map) + goto out; + + ret = parse_cluster(map, 0); + if (ret != 0) + goto out_map; + + topology_normalize_cpu_scale(); + + /* + * Check that all cores are in the topology; the SMP code will + * only mark cores described in the DT as possible. + */ + for_each_possible_cpu(cpu) + if (cpu_topology[cpu].package_id == -1) + ret = -EINVAL; + +out_map: + of_node_put(map); +out: + of_node_put(cn); + return ret; +} +#endif + +/* + * cpu topology table + */ +struct cpu_topology cpu_topology[NR_CPUS]; +EXPORT_SYMBOL_GPL(cpu_topology); + +const struct cpumask *cpu_coregroup_mask(int cpu) +{ + const cpumask_t *core_mask = cpumask_of_node(cpu_to_node(cpu)); + + /* Find the smaller of NUMA, core or LLC siblings */ + if (cpumask_subset(&cpu_topology[cpu].core_sibling, core_mask)) { + /* not numa in package, lets use the package siblings */ + core_mask = &cpu_topology[cpu].core_sibling; + } + if (cpu_topology[cpu].llc_id != -1) { + if (cpumask_subset(&cpu_topology[cpu].llc_sibling, core_mask)) + core_mask = &cpu_topology[cpu].llc_sibling; + } + + return core_mask; +} + +void update_siblings_masks(unsigned int cpuid) +{ + struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid]; + int cpu; + + /* update core and thread sibling masks */ + for_each_online_cpu(cpu) { + cpu_topo = &cpu_topology[cpu]; + + if (cpuid_topo->llc_id == cpu_topo->llc_id) { + cpumask_set_cpu(cpu, &cpuid_topo->llc_sibling); + cpumask_set_cpu(cpuid, &cpu_topo->llc_sibling); + } + + if (cpuid_topo->package_id != cpu_topo->package_id) + continue; + + cpumask_set_cpu(cpuid, &cpu_topo->core_sibling); + cpumask_set_cpu(cpu, &cpuid_topo->core_sibling); + + if (cpuid_topo->core_id != cpu_topo->core_id) + continue; + + cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling); + cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling); + } +} + +static void clear_cpu_topology(int cpu) +{ + struct cpu_topology *cpu_topo = &cpu_topology[cpu]; + + cpumask_clear(&cpu_topo->llc_sibling); + cpumask_set_cpu(cpu, &cpu_topo->llc_sibling); + + cpumask_clear(&cpu_topo->core_sibling); + cpumask_set_cpu(cpu, &cpu_topo->core_sibling); + cpumask_clear(&cpu_topo->thread_sibling); + cpumask_set_cpu(cpu, &cpu_topo->thread_sibling); +} + +void __init reset_cpu_topology(void) +{ + unsigned int cpu; + + for_each_possible_cpu(cpu) { + struct cpu_topology *cpu_topo = &cpu_topology[cpu]; + + cpu_topo->thread_id = -1; + cpu_topo->core_id = -1; + cpu_topo->package_id = -1; + cpu_topo->llc_id = -1; + + clear_cpu_topology(cpu); + } +} + +void remove_cpu_topology(unsigned int cpu) +{ + int sibling; + + for_each_cpu(sibling, topology_core_cpumask(cpu)) + cpumask_clear_cpu(cpu, topology_core_cpumask(sibling)); + for_each_cpu(sibling, topology_sibling_cpumask(cpu)) + cpumask_clear_cpu(cpu, topology_sibling_cpumask(sibling)); + for_each_cpu(sibling, topology_llc_cpumask(cpu)) + cpumask_clear_cpu(cpu, topology_llc_cpumask(sibling)); + + clear_cpu_topology(cpu); +} + +__weak int __init parse_acpi_topology(void) +{ + return 0; +} + +#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV) +void __init init_cpu_topology(void) +{ + reset_cpu_topology(); + + /* + * Discard anything that was parsed if we hit an error so we + * don't use partial information. + */ + if (parse_acpi_topology()) + reset_cpu_topology(); + else if (of_have_populated_dt() && parse_dt_topology()) + reset_cpu_topology(); +} +#endif diff --git a/drivers/base/base.h b/drivers/base/base.h index b405436ee28e0873ee9646b0344e7e549eabf3a0..0d32544b6f91668c1d3493c875498b4f8e609cb5 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -165,6 +165,7 @@ static inline int devtmpfs_init(void) { return 0; } /* Device links support */ extern int device_links_read_lock(void); extern void device_links_read_unlock(int idx); +extern int device_links_read_lock_held(void); extern int device_links_check_suppliers(struct device *dev); extern void device_links_driver_bound(struct device *dev); extern void device_links_driver_cleanup(struct device *dev); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index df3cac739813fd7f85ef02da83504aa0e4d34d59..a1d1e82563244c4fc9e512222036651d21130fee 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -342,30 +342,6 @@ struct device *bus_find_device(struct bus_type *bus, } EXPORT_SYMBOL_GPL(bus_find_device); -static int match_name(struct device *dev, const void *data) -{ - const char *name = data; - - return sysfs_streq(name, dev_name(dev)); -} - -/** - * bus_find_device_by_name - device iterator for locating a particular device of a specific name - * @bus: bus type - * @start: Device to begin with - * @name: name of the device to match - * - * This is similar to the bus_find_device() function above, but it handles - * searching by a name automatically, no need to write another strcmp matching - * function. - */ -struct device *bus_find_device_by_name(struct bus_type *bus, - struct device *start, const char *name) -{ - return bus_find_device(bus, start, (void *)name, match_name); -} -EXPORT_SYMBOL_GPL(bus_find_device_by_name); - /** * subsys_find_device_by_id - find a device with a specific enumeration number * @subsys: subsystem diff --git a/drivers/base/core.c b/drivers/base/core.c index 1669d41fcddccde2cfbb35f1ccc7be37ef0b3dc0..2db62d98e39505b3466275d41bbb2c5a2cc9017e 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -68,6 +68,11 @@ void device_links_read_unlock(int idx) { srcu_read_unlock(&device_links_srcu, idx); } + +int device_links_read_lock_held(void) +{ + return srcu_read_lock_held(&device_links_srcu); +} #else /* !CONFIG_SRCU */ static DECLARE_RWSEM(device_links_lock); @@ -91,6 +96,13 @@ void device_links_read_unlock(int not_used) { up_read(&device_links_lock); } + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +int device_links_read_lock_held(void) +{ + return lockdep_is_held(&device_links_lock); +} +#endif #endif /* !CONFIG_SRCU */ /** @@ -124,6 +136,50 @@ static int device_is_dependent(struct device *dev, void *target) return ret; } +static void device_link_init_status(struct device_link *link, + struct device *consumer, + struct device *supplier) +{ + switch (supplier->links.status) { + case DL_DEV_PROBING: + switch (consumer->links.status) { + case DL_DEV_PROBING: + /* + * A consumer driver can create a link to a supplier + * that has not completed its probing yet as long as it + * knows that the supplier is already functional (for + * example, it has just acquired some resources from the + * supplier). + */ + link->status = DL_STATE_CONSUMER_PROBE; + break; + default: + link->status = DL_STATE_DORMANT; + break; + } + break; + case DL_DEV_DRIVER_BOUND: + switch (consumer->links.status) { + case DL_DEV_PROBING: + link->status = DL_STATE_CONSUMER_PROBE; + break; + case DL_DEV_DRIVER_BOUND: + link->status = DL_STATE_ACTIVE; + break; + default: + link->status = DL_STATE_AVAILABLE; + break; + } + break; + case DL_DEV_UNBINDING: + link->status = DL_STATE_SUPPLIER_UNBIND; + break; + default: + link->status = DL_STATE_DORMANT; + break; + } +} + static int device_reorder_to_tail(struct device *dev, void *not_used) { struct device_link *link; @@ -165,6 +221,13 @@ void device_pm_move_to_tail(struct device *dev) device_links_read_unlock(idx); } +#define DL_MANAGED_LINK_FLAGS (DL_FLAG_AUTOREMOVE_CONSUMER | \ + DL_FLAG_AUTOREMOVE_SUPPLIER | \ + DL_FLAG_AUTOPROBE_CONSUMER) + +#define DL_ADD_VALID_FLAGS (DL_MANAGED_LINK_FLAGS | DL_FLAG_STATELESS | \ + DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE) + /** * device_link_add - Create a link between two devices. * @consumer: Consumer end of the link. @@ -179,9 +242,9 @@ void device_pm_move_to_tail(struct device *dev) * of the link. If DL_FLAG_PM_RUNTIME is not set, DL_FLAG_RPM_ACTIVE will be * ignored. * - * If DL_FLAG_STATELESS is set in @flags, the link is not going to be managed by - * the driver core and, in particular, the caller of this function is expected - * to drop the reference to the link acquired by it directly. + * If DL_FLAG_STATELESS is set in @flags, the caller of this function is + * expected to release the link returned by it directly with the help of either + * device_link_del() or device_link_remove(). * * If that flag is not set, however, the caller of this function is handing the * management of the link over to the driver core entirely and its return value @@ -201,9 +264,16 @@ void device_pm_move_to_tail(struct device *dev) * be used to request the driver core to automaticall probe for a consmer * driver after successfully binding a driver to the supplier device. * - * The combination of DL_FLAG_STATELESS and either DL_FLAG_AUTOREMOVE_CONSUMER - * or DL_FLAG_AUTOREMOVE_SUPPLIER set in @flags at the same time is invalid and - * will cause NULL to be returned upfront. + * The combination of DL_FLAG_STATELESS and one of DL_FLAG_AUTOREMOVE_CONSUMER, + * DL_FLAG_AUTOREMOVE_SUPPLIER, or DL_FLAG_AUTOPROBE_CONSUMER set in @flags at + * the same time is invalid and will cause NULL to be returned upfront. + * However, if a device link between the given @consumer and @supplier pair + * exists already when this function is called for them, the existing link will + * be returned regardless of its current type and status (the link's flags may + * be modified then). The caller of this function is then expected to treat + * the link as though it has just been created, so (in particular) if + * DL_FLAG_STATELESS was passed in @flags, the link needs to be released + * explicitly when not needed any more (as stated above). * * A side effect of the link creation is re-ordering of dpm_list and the * devices_kset list by moving the consumer device and all devices depending @@ -219,11 +289,8 @@ struct device_link *device_link_add(struct device *consumer, { struct device_link *link; - if (!consumer || !supplier || - (flags & DL_FLAG_STATELESS && - flags & (DL_FLAG_AUTOREMOVE_CONSUMER | - DL_FLAG_AUTOREMOVE_SUPPLIER | - DL_FLAG_AUTOPROBE_CONSUMER)) || + if (!consumer || !supplier || flags & ~DL_ADD_VALID_FLAGS || + (flags & DL_FLAG_STATELESS && flags & DL_MANAGED_LINK_FLAGS) || (flags & DL_FLAG_AUTOPROBE_CONSUMER && flags & (DL_FLAG_AUTOREMOVE_CONSUMER | DL_FLAG_AUTOREMOVE_SUPPLIER))) @@ -236,6 +303,9 @@ struct device_link *device_link_add(struct device *consumer, } } + if (!(flags & DL_FLAG_STATELESS)) + flags |= DL_FLAG_MANAGED; + device_links_write_lock(); device_pm_lock(); @@ -262,15 +332,6 @@ struct device_link *device_link_add(struct device *consumer, if (link->consumer != consumer) continue; - /* - * Don't return a stateless link if the caller wants a stateful - * one and vice versa. - */ - if (WARN_ON((flags & DL_FLAG_STATELESS) != (link->flags & DL_FLAG_STATELESS))) { - link = NULL; - goto out; - } - if (flags & DL_FLAG_PM_RUNTIME) { if (!(link->flags & DL_FLAG_PM_RUNTIME)) { pm_runtime_new_link(consumer); @@ -281,6 +342,7 @@ struct device_link *device_link_add(struct device *consumer, } if (flags & DL_FLAG_STATELESS) { + link->flags |= DL_FLAG_STATELESS; kref_get(&link->kref); goto out; } @@ -299,6 +361,11 @@ struct device_link *device_link_add(struct device *consumer, link->flags &= ~(DL_FLAG_AUTOREMOVE_CONSUMER | DL_FLAG_AUTOREMOVE_SUPPLIER); } + if (!(link->flags & DL_FLAG_MANAGED)) { + kref_get(&link->kref); + link->flags |= DL_FLAG_MANAGED; + device_link_init_status(link, consumer, supplier); + } goto out; } @@ -325,48 +392,10 @@ struct device_link *device_link_add(struct device *consumer, kref_init(&link->kref); /* Determine the initial link state. */ - if (flags & DL_FLAG_STATELESS) { + if (flags & DL_FLAG_STATELESS) link->status = DL_STATE_NONE; - } else { - switch (supplier->links.status) { - case DL_DEV_PROBING: - switch (consumer->links.status) { - case DL_DEV_PROBING: - /* - * A consumer driver can create a link to a - * supplier that has not completed its probing - * yet as long as it knows that the supplier is - * already functional (for example, it has just - * acquired some resources from the supplier). - */ - link->status = DL_STATE_CONSUMER_PROBE; - break; - default: - link->status = DL_STATE_DORMANT; - break; - } - break; - case DL_DEV_DRIVER_BOUND: - switch (consumer->links.status) { - case DL_DEV_PROBING: - link->status = DL_STATE_CONSUMER_PROBE; - break; - case DL_DEV_DRIVER_BOUND: - link->status = DL_STATE_ACTIVE; - break; - default: - link->status = DL_STATE_AVAILABLE; - break; - } - break; - case DL_DEV_UNBINDING: - link->status = DL_STATE_SUPPLIER_UNBIND; - break; - default: - link->status = DL_STATE_DORMANT; - break; - } - } + else + device_link_init_status(link, consumer, supplier); /* * Some callers expect the link creation during consumer driver probe to @@ -528,7 +557,7 @@ static void device_links_missing_supplier(struct device *dev) * mark the link as "consumer probe in progress" to make the supplier removal * wait for us to complete (or bad things may happen). * - * Links with the DL_FLAG_STATELESS flag set are ignored. + * Links without the DL_FLAG_MANAGED flag set are ignored. */ int device_links_check_suppliers(struct device *dev) { @@ -538,7 +567,7 @@ int device_links_check_suppliers(struct device *dev) device_links_write_lock(); list_for_each_entry(link, &dev->links.suppliers, c_node) { - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; if (link->status != DL_STATE_AVAILABLE) { @@ -563,7 +592,7 @@ int device_links_check_suppliers(struct device *dev) * * Also change the status of @dev's links to suppliers to "active". * - * Links with the DL_FLAG_STATELESS flag set are ignored. + * Links without the DL_FLAG_MANAGED flag set are ignored. */ void device_links_driver_bound(struct device *dev) { @@ -572,7 +601,7 @@ void device_links_driver_bound(struct device *dev) device_links_write_lock(); list_for_each_entry(link, &dev->links.consumers, s_node) { - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; /* @@ -593,7 +622,7 @@ void device_links_driver_bound(struct device *dev) } list_for_each_entry(link, &dev->links.suppliers, c_node) { - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; WARN_ON(link->status != DL_STATE_CONSUMER_PROBE); @@ -605,6 +634,13 @@ void device_links_driver_bound(struct device *dev) device_links_write_unlock(); } +static void device_link_drop_managed(struct device_link *link) +{ + link->flags &= ~DL_FLAG_MANAGED; + WRITE_ONCE(link->status, DL_STATE_NONE); + kref_put(&link->kref, __device_link_del); +} + /** * __device_links_no_driver - Update links of a device without a driver. * @dev: Device without a drvier. @@ -615,18 +651,18 @@ void device_links_driver_bound(struct device *dev) * unless they already are in the "supplier unbind in progress" state in which * case they need not be updated. * - * Links with the DL_FLAG_STATELESS flag set are ignored. + * Links without the DL_FLAG_MANAGED flag set are ignored. */ static void __device_links_no_driver(struct device *dev) { struct device_link *link, *ln; list_for_each_entry_safe_reverse(link, ln, &dev->links.suppliers, c_node) { - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER) - __device_link_del(&link->kref); + device_link_drop_managed(link); else if (link->status == DL_STATE_CONSUMER_PROBE || link->status == DL_STATE_ACTIVE) WRITE_ONCE(link->status, DL_STATE_AVAILABLE); @@ -643,7 +679,7 @@ static void __device_links_no_driver(struct device *dev) * %__device_links_no_driver() to update links to suppliers for it as * appropriate. * - * Links with the DL_FLAG_STATELESS flag set are ignored. + * Links without the DL_FLAG_MANAGED flag set are ignored. */ void device_links_no_driver(struct device *dev) { @@ -652,7 +688,7 @@ void device_links_no_driver(struct device *dev) device_links_write_lock(); list_for_each_entry(link, &dev->links.consumers, s_node) { - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; /* @@ -680,7 +716,7 @@ void device_links_no_driver(struct device *dev) * invoke %__device_links_no_driver() to update links to suppliers for it as * appropriate. * - * Links with the DL_FLAG_STATELESS flag set are ignored. + * Links without the DL_FLAG_MANAGED flag set are ignored. */ void device_links_driver_cleanup(struct device *dev) { @@ -689,7 +725,7 @@ void device_links_driver_cleanup(struct device *dev) device_links_write_lock(); list_for_each_entry_safe(link, ln, &dev->links.consumers, s_node) { - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; WARN_ON(link->flags & DL_FLAG_AUTOREMOVE_CONSUMER); @@ -702,7 +738,7 @@ void device_links_driver_cleanup(struct device *dev) */ if (link->status == DL_STATE_SUPPLIER_UNBIND && link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER) - __device_link_del(&link->kref); + device_link_drop_managed(link); WRITE_ONCE(link->status, DL_STATE_DORMANT); } @@ -724,7 +760,7 @@ void device_links_driver_cleanup(struct device *dev) * * Return 'false' if there are no probing or active consumers. * - * Links with the DL_FLAG_STATELESS flag set are ignored. + * Links without the DL_FLAG_MANAGED flag set are ignored. */ bool device_links_busy(struct device *dev) { @@ -734,7 +770,7 @@ bool device_links_busy(struct device *dev) device_links_write_lock(); list_for_each_entry(link, &dev->links.consumers, s_node) { - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; if (link->status == DL_STATE_CONSUMER_PROBE @@ -764,7 +800,7 @@ bool device_links_busy(struct device *dev) * driver to unbind and start over (the consumer will not re-probe as we have * changed the state of the link already). * - * Links with the DL_FLAG_STATELESS flag set are ignored. + * Links without the DL_FLAG_MANAGED flag set are ignored. */ void device_links_unbind_consumers(struct device *dev) { @@ -776,7 +812,7 @@ void device_links_unbind_consumers(struct device *dev) list_for_each_entry(link, &dev->links.consumers, s_node) { enum device_link_state status; - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; status = link->status; @@ -2932,13 +2968,6 @@ struct device *device_create_with_groups(struct class *class, } EXPORT_SYMBOL_GPL(device_create_with_groups); -static int __match_devt(struct device *dev, const void *data) -{ - const dev_t *devt = data; - - return dev->devt == *devt; -} - /** * device_destroy - removes a device that was created with device_create() * @class: pointer to the struct class that this device was registered with @@ -2951,7 +2980,7 @@ void device_destroy(struct class *class, dev_t devt) { struct device *dev; - dev = class_find_device(class, NULL, &devt, __match_devt); + dev = class_find_device_by_devt(class, devt); if (dev) { put_device(dev); device_unregister(dev); @@ -3422,8 +3451,38 @@ void device_set_of_node_from_dev(struct device *dev, const struct device *dev2) } EXPORT_SYMBOL_GPL(device_set_of_node_from_dev); +int device_match_name(struct device *dev, const void *name) +{ + return sysfs_streq(dev_name(dev), name); +} +EXPORT_SYMBOL_GPL(device_match_name); + int device_match_of_node(struct device *dev, const void *np) { return dev->of_node == np; } EXPORT_SYMBOL_GPL(device_match_of_node); + +int device_match_fwnode(struct device *dev, const void *fwnode) +{ + return dev_fwnode(dev) == fwnode; +} +EXPORT_SYMBOL_GPL(device_match_fwnode); + +int device_match_devt(struct device *dev, const void *pdevt) +{ + return dev->devt == *(dev_t *)pdevt; +} +EXPORT_SYMBOL_GPL(device_match_devt); + +int device_match_acpi_dev(struct device *dev, const void *adev) +{ + return ACPI_COMPANION(dev) == adev; +} +EXPORT_SYMBOL(device_match_acpi_dev); + +int device_match_any(struct device *dev, const void *unused) +{ + return 1; +} +EXPORT_SYMBOL_GPL(device_match_any); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 994a9074742046edfed5afefe62011450e20669c..d811e60610d33ae952efacc2db3ce9fb47349a5e 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -554,9 +554,16 @@ static int really_probe(struct device *dev, struct device_driver *drv) goto probe_failed; } + if (device_add_groups(dev, drv->dev_groups)) { + dev_err(dev, "device_add_groups() failed\n"); + goto dev_groups_failed; + } + if (test_remove) { test_remove = false; + device_remove_groups(dev, drv->dev_groups); + if (dev->bus->remove) dev->bus->remove(dev); else if (drv->remove) @@ -584,6 +591,11 @@ static int really_probe(struct device *dev, struct device_driver *drv) drv->bus->name, __func__, dev_name(dev), drv->name); goto done; +dev_groups_failed: + if (dev->bus->remove) + dev->bus->remove(dev); + else if (drv->remove) + drv->remove(dev); probe_failed: if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, @@ -1114,6 +1126,8 @@ static void __device_release_driver(struct device *dev, struct device *parent) pm_runtime_put_sync(dev); + device_remove_groups(dev, drv->dev_groups); + if (dev->bus && dev->bus->remove) dev->bus->remove(dev); else if (drv->remove) diff --git a/drivers/base/devcon.c b/drivers/base/devcon.c index 09f28479b243ac93f1d9d149db3db1f6ca71799d..14e2178e09f835f8d7937adb0180dbcd63433907 100644 --- a/drivers/base/devcon.c +++ b/drivers/base/devcon.c @@ -12,9 +12,6 @@ static DEFINE_MUTEX(devcon_lock); static LIST_HEAD(devcon_list); -typedef void *(*devcon_match_fn_t)(struct device_connection *con, int ep, - void *data); - static void * fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id, void *data, devcon_match_fn_t match) @@ -60,6 +57,34 @@ fwnode_devcon_match(struct fwnode_handle *fwnode, const char *con_id, return NULL; } +/** + * fwnode_connection_find_match - Find connection from a device node + * @fwnode: Device node with the connection + * @con_id: Identifier for the connection + * @data: Data for the match function + * @match: Function to check and convert the connection description + * + * Find a connection with unique identifier @con_id between @fwnode and another + * device node. @match will be used to convert the connection description to + * data the caller is expecting to be returned. + */ +void *fwnode_connection_find_match(struct fwnode_handle *fwnode, + const char *con_id, void *data, + devcon_match_fn_t match) +{ + void *ret; + + if (!fwnode || !match) + return NULL; + + ret = fwnode_graph_devcon_match(fwnode, con_id, data, match); + if (ret) + return ret; + + return fwnode_devcon_match(fwnode, con_id, data, match); +} +EXPORT_SYMBOL_GPL(fwnode_connection_find_match); + /** * device_connection_find_match - Find physical connection to a device * @dev: Device with the connection @@ -83,15 +108,9 @@ void *device_connection_find_match(struct device *dev, const char *con_id, if (!match) return NULL; - if (fwnode) { - ret = fwnode_graph_devcon_match(fwnode, con_id, data, match); - if (ret) - return ret; - - ret = fwnode_devcon_match(fwnode, con_id, data, match); - if (ret) - return ret; - } + ret = fwnode_connection_find_match(fwnode, con_id, data, match); + if (ret) + return ret; mutex_lock(&devcon_lock); @@ -133,19 +152,13 @@ static struct bus_type *generic_match_buses[] = { NULL, }; -static int device_fwnode_match(struct device *dev, const void *fwnode) -{ - return dev_fwnode(dev) == fwnode; -} - static void *device_connection_fwnode_match(struct device_connection *con) { struct bus_type *bus; struct device *dev; for (bus = generic_match_buses[0]; bus; bus++) { - dev = bus_find_device(bus, NULL, (void *)con->fwnode, - device_fwnode_match); + dev = bus_find_device_by_fwnode(bus, con->fwnode); if (dev && !strncmp(dev_name(dev), con->id, strlen(con->id))) return dev; diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index f1a3353f349467eeabd2cc4680fb96337bbf0eec..e42d0b5143849f3f89e7a5077ffab9a19f8bdd3a 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -164,16 +164,7 @@ static struct class devcd_class = { static ssize_t devcd_readv(char *buffer, loff_t offset, size_t count, void *data, size_t datalen) { - if (offset > datalen) - return -EINVAL; - - if (offset + count > datalen) - count = datalen - offset; - - if (count) - memcpy(buffer, ((u8 *)data) + offset, count); - - return count; + return memory_read_from_buffer(buffer, count, &offset, data, datalen); } static void devcd_freev(void *data) @@ -323,7 +314,7 @@ void dev_coredumpm(struct device *dev, struct module *owner, EXPORT_SYMBOL_GPL(dev_coredumpm); /** - * dev_coredumpmsg - create device coredump that uses scatterlist as data + * dev_coredumpsg - create device coredump that uses scatterlist as data * parameter * @dev: the struct device for the crashed device * @table: the dump data diff --git a/drivers/base/platform.c b/drivers/base/platform.c index ec974ba9c0c4ca93a3b1cfcaf541c6e4a4a3bd9c..b6c6c7d97d5b2aa388baa153550ed7a4db3af022 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -39,25 +39,6 @@ struct device platform_bus = { }; EXPORT_SYMBOL_GPL(platform_bus); -/** - * arch_setup_pdev_archdata - Allow manipulation of archdata before its used - * @pdev: platform device - * - * This is called before platform_device_add() such that any pdev_archdata may - * be setup before the platform_notifier is called. So if a user needs to - * manipulate any relevant information in the pdev_archdata they can do: - * - * platform_device_alloc() - * ... manipulate ... - * platform_device_add() - * - * And if they don't care they can just call platform_device_register() and - * everything will just work out. - */ -void __weak arch_setup_pdev_archdata(struct platform_device *pdev) -{ -} - /** * platform_get_resource - get a resource for a device * @dev: platform device @@ -99,12 +80,7 @@ void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev, EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource); #endif /* CONFIG_HAS_IOMEM */ -/** - * platform_get_irq - get an IRQ for a device - * @dev: platform device - * @num: IRQ number index - */ -int platform_get_irq(struct platform_device *dev, unsigned int num) +static int __platform_get_irq(struct platform_device *dev, unsigned int num) { #ifdef CONFIG_SPARC /* sparc does not have irqs represented as IORESOURCE_IRQ resources */ @@ -168,8 +144,58 @@ int platform_get_irq(struct platform_device *dev, unsigned int num) return -ENXIO; #endif } + +/** + * platform_get_irq - get an IRQ for a device + * @dev: platform device + * @num: IRQ number index + * + * Gets an IRQ for a platform device and prints an error message if finding the + * IRQ fails. Device drivers should check the return value for errors so as to + * not pass a negative integer value to the request_irq() APIs. + * + * Example: + * int irq = platform_get_irq(pdev, 0); + * if (irq < 0) + * return irq; + * + * Return: IRQ number on success, negative error number on failure. + */ +int platform_get_irq(struct platform_device *dev, unsigned int num) +{ + int ret; + + ret = __platform_get_irq(dev, num); + if (ret < 0 && ret != -EPROBE_DEFER) + dev_err(&dev->dev, "IRQ index %u not found\n", num); + + return ret; +} EXPORT_SYMBOL_GPL(platform_get_irq); +/** + * platform_get_irq_optional - get an optional IRQ for a device + * @dev: platform device + * @num: IRQ number index + * + * Gets an IRQ for a platform device. Device drivers should check the return + * value for errors so as to not pass a negative integer value to the + * request_irq() APIs. This is the same as platform_get_irq(), except that it + * does not print an error message if an IRQ can not be obtained. + * + * Example: + * int irq = platform_get_irq_optional(pdev, 0); + * if (irq < 0) + * return irq; + * + * Return: IRQ number on success, negative error number on failure. + */ +int platform_get_irq_optional(struct platform_device *dev, unsigned int num) +{ + return __platform_get_irq(dev, num); +} +EXPORT_SYMBOL_GPL(platform_get_irq_optional); + /** * platform_irq_count - Count the number of IRQs a platform device uses * @dev: platform device @@ -180,7 +206,7 @@ int platform_irq_count(struct platform_device *dev) { int ret, nr = 0; - while ((ret = platform_get_irq(dev, nr)) >= 0) + while ((ret = __platform_get_irq(dev, nr)) >= 0) nr++; if (ret == -EPROBE_DEFER) @@ -233,7 +259,11 @@ int platform_get_irq_byname(struct platform_device *dev, const char *name) } r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name); - return r ? r->start : -ENXIO; + if (r) + return r->start; + + dev_err(&dev->dev, "IRQ %s not found\n", name); + return -ENXIO; } EXPORT_SYMBOL_GPL(platform_get_irq_byname); @@ -264,6 +294,20 @@ struct platform_object { char name[]; }; +/* + * Set up default DMA mask for platform devices if the they weren't + * previously set by the architecture / DT. + */ +static void setup_pdev_dma_masks(struct platform_device *pdev) +{ + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + if (!pdev->dma_mask) + pdev->dma_mask = DMA_BIT_MASK(32); + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dma_mask; +}; + /** * platform_device_put - destroy a platform device * @pdev: platform device to free @@ -310,7 +354,7 @@ struct platform_device *platform_device_alloc(const char *name, int id) pa->pdev.id = id; device_initialize(&pa->pdev.dev); pa->pdev.dev.release = platform_device_release; - arch_setup_pdev_archdata(&pa->pdev); + setup_pdev_dma_masks(&pa->pdev); } return pa ? &pa->pdev : NULL; @@ -512,7 +556,7 @@ EXPORT_SYMBOL_GPL(platform_device_del); int platform_device_register(struct platform_device *pdev) { device_initialize(&pdev->dev); - arch_setup_pdev_archdata(pdev); + setup_pdev_dma_masks(pdev); return platform_device_add(pdev); } EXPORT_SYMBOL_GPL(platform_device_register); @@ -1202,6 +1246,20 @@ struct bus_type platform_bus_type = { }; EXPORT_SYMBOL_GPL(platform_bus_type); +/** + * platform_find_device_by_driver - Find a platform device with a given + * driver. + * @start: The device to start the search from. + * @drv: The device driver to look for. + */ +struct device *platform_find_device_by_driver(struct device *start, + const struct device_driver *drv) +{ + return bus_find_device(&platform_bus_type, start, drv, + (void *)platform_match); +} +EXPORT_SYMBOL_GPL(platform_find_device_by_driver); + int __init platform_bus_init(void) { int error; diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index e1bb691cf8f14632ed40cf8d570578bf42616d91..ec5bb190b9d0c85b83517b6bc3c31cddc35170ac 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o wakeirq.o -obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o +obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o wakeup_stats.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o obj-$(CONFIG_HAVE_CLK) += clock_ops.o diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index b063bc41b0a9cd9ba54fcad80955683131a65f8f..cc85e87eaf05559ecbe5c0279d9b8f134a7bf880 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -149,29 +149,24 @@ static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev, return ret; } +static int genpd_runtime_suspend(struct device *dev); + /* * Get the generic PM domain for a particular struct device. * This validates the struct device pointer, the PM domain pointer, * and checks that the PM domain pointer is a real generic PM domain. * Any failure results in NULL being returned. */ -static struct generic_pm_domain *genpd_lookup_dev(struct device *dev) +static struct generic_pm_domain *dev_to_genpd_safe(struct device *dev) { - struct generic_pm_domain *genpd = NULL, *gpd; - if (IS_ERR_OR_NULL(dev) || IS_ERR_OR_NULL(dev->pm_domain)) return NULL; - mutex_lock(&gpd_list_lock); - list_for_each_entry(gpd, &gpd_list, gpd_list_node) { - if (&gpd->domain == dev->pm_domain) { - genpd = gpd; - break; - } - } - mutex_unlock(&gpd_list_lock); + /* A genpd's always have its ->runtime_suspend() callback assigned. */ + if (dev->pm_domain->ops.runtime_suspend == genpd_runtime_suspend) + return pd_to_genpd(dev->pm_domain); - return genpd; + return NULL; } /* @@ -385,8 +380,8 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state) unsigned int prev; int ret; - genpd = dev_to_genpd(dev); - if (IS_ERR(genpd)) + genpd = dev_to_genpd_safe(dev); + if (!genpd) return -ENODEV; if (unlikely(!genpd->set_performance_state)) @@ -1610,7 +1605,7 @@ static int genpd_remove_device(struct generic_pm_domain *genpd, */ int pm_genpd_remove_device(struct device *dev) { - struct generic_pm_domain *genpd = genpd_lookup_dev(dev); + struct generic_pm_domain *genpd = dev_to_genpd_safe(dev); if (!genpd) return -EINVAL; diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 1f48fd8823197b74f1e71c9ec8aa4bdd68472284..40657d602be67fe08d19185ad84179ece32969ca 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -717,7 +717,7 @@ static void async_resume_noirq(void *data, async_cookie_t cookie) put_device(dev); } -void dpm_noirq_resume_devices(pm_message_t state) +static void dpm_noirq_resume_devices(pm_message_t state) { struct device *dev; ktime_t starttime = ktime_get(); @@ -761,13 +761,6 @@ void dpm_noirq_resume_devices(pm_message_t state) trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false); } -void dpm_noirq_end(void) -{ - resume_device_irqs(); - device_wakeup_disarm_wake_irqs(); - cpuidle_resume(); -} - /** * dpm_resume_noirq - Execute "noirq resume" callbacks for all devices. * @state: PM transition of the system being carried out. @@ -778,7 +771,11 @@ void dpm_noirq_end(void) void dpm_resume_noirq(pm_message_t state) { dpm_noirq_resume_devices(state); - dpm_noirq_end(); + + resume_device_irqs(); + device_wakeup_disarm_wake_irqs(); + + cpuidle_resume(); } static pm_callback_t dpm_subsys_resume_early_cb(struct device *dev, @@ -1292,11 +1289,6 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a if (async_error) goto Complete; - if (pm_wakeup_pending()) { - async_error = -EBUSY; - goto Complete; - } - if (dev->power.syscore || dev->power.direct_complete) goto Complete; @@ -1363,14 +1355,7 @@ static int device_suspend_noirq(struct device *dev) return __device_suspend_noirq(dev, pm_transition, false); } -void dpm_noirq_begin(void) -{ - cpuidle_pause(); - device_wakeup_arm_wake_irqs(); - suspend_device_irqs(); -} - -int dpm_noirq_suspend_devices(pm_message_t state) +static int dpm_noirq_suspend_devices(pm_message_t state) { ktime_t starttime = ktime_get(); int error = 0; @@ -1427,7 +1412,11 @@ int dpm_suspend_noirq(pm_message_t state) { int ret; - dpm_noirq_begin(); + cpuidle_pause(); + + device_wakeup_arm_wake_irqs(); + suspend_device_irqs(); + ret = dpm_noirq_suspend_devices(state); if (ret) dpm_resume_noirq(resume_event(state)); diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index ec33fbdb919b3506219928a52267de1a6275aa8b..39a06a0cfdaa82cdf78f43c24dc2db6ea7236d33 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -149,3 +149,21 @@ static inline void device_pm_init(struct device *dev) device_pm_sleep_init(dev); pm_runtime_init(dev); } + +#ifdef CONFIG_PM_SLEEP + +/* drivers/base/power/wakeup_stats.c */ +extern int wakeup_source_sysfs_add(struct device *parent, + struct wakeup_source *ws); +extern void wakeup_source_sysfs_remove(struct wakeup_source *ws); + +extern int pm_wakeup_source_sysfs_add(struct device *parent); + +#else /* !CONFIG_PM_SLEEP */ + +static inline int pm_wakeup_source_sysfs_add(struct device *parent) +{ + return 0; +} + +#endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index b75335508d2c57834675a3e1878d3abd3b5f28a2..48616f358854a4562222877b5dd779e4d1434460 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -287,7 +287,8 @@ static int rpm_get_suppliers(struct device *dev) { struct device_link *link; - list_for_each_entry_rcu(link, &dev->links.suppliers, c_node) { + list_for_each_entry_rcu(link, &dev->links.suppliers, c_node, + device_links_read_lock_held()) { int retval; if (!(link->flags & DL_FLAG_PM_RUNTIME) || @@ -309,7 +310,8 @@ static void rpm_put_suppliers(struct device *dev) { struct device_link *link; - list_for_each_entry_rcu(link, &dev->links.suppliers, c_node) { + list_for_each_entry_rcu(link, &dev->links.suppliers, c_node, + device_links_read_lock_held()) { if (READ_ONCE(link->status) == DL_STATE_SUPPLIER_UNBIND) continue; @@ -1624,7 +1626,7 @@ void pm_runtime_remove(struct device *dev) * runtime PM references to the device, drop the usage counter of the device * (as many times as needed). * - * Links with the DL_FLAG_STATELESS flag set are ignored. + * Links with the DL_FLAG_MANAGED flag unset are ignored. * * Since the device is guaranteed to be runtime-active at the point this is * called, nothing else needs to be done here. @@ -1640,8 +1642,9 @@ void pm_runtime_clean_up_links(struct device *dev) idx = device_links_read_lock(); - list_for_each_entry_rcu(link, &dev->links.consumers, s_node) { - if (link->flags & DL_FLAG_STATELESS) + list_for_each_entry_rcu(link, &dev->links.consumers, s_node, + device_links_read_lock_held()) { + if (!(link->flags & DL_FLAG_MANAGED)) continue; while (refcount_dec_not_one(&link->rpm_active)) @@ -1662,7 +1665,8 @@ void pm_runtime_get_suppliers(struct device *dev) idx = device_links_read_lock(); - list_for_each_entry_rcu(link, &dev->links.suppliers, c_node) + list_for_each_entry_rcu(link, &dev->links.suppliers, c_node, + device_links_read_lock_held()) if (link->flags & DL_FLAG_PM_RUNTIME) { link->supplier_preactivated = true; refcount_inc(&link->rpm_active); @@ -1683,7 +1687,8 @@ void pm_runtime_put_suppliers(struct device *dev) idx = device_links_read_lock(); - list_for_each_entry_rcu(link, &dev->links.suppliers, c_node) + list_for_each_entry_rcu(link, &dev->links.suppliers, c_node, + device_links_read_lock_held()) if (link->supplier_preactivated) { link->supplier_preactivated = false; if (refcount_dec_not_one(&link->rpm_active)) diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 1b9c281cbe4126ebd4050dbabebae0291058c7a8..d7d82db2e4bc401fb5a35c8eaa11090aa39ce01a 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include "power.h" @@ -667,8 +668,13 @@ int dpm_sysfs_add(struct device *dev) if (rc) goto err_wakeup; } + rc = pm_wakeup_source_sysfs_add(dev); + if (rc) + goto err_latency; return 0; + err_latency: + sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_tolerance_attr_group); err_wakeup: sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group); err_runtime: diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index bfcdf5f195703a316a634068d7938e7a6da3e71a..06b3ce836a24ac71a7be585a1a65cfdcb323824f 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -73,22 +73,7 @@ static struct wakeup_source deleted_ws = { .lock = __SPIN_LOCK_UNLOCKED(deleted_ws.lock), }; -/** - * wakeup_source_prepare - Prepare a new wakeup source for initialization. - * @ws: Wakeup source to prepare. - * @name: Pointer to the name of the new wakeup source. - * - * Callers must ensure that the @name string won't be freed when @ws is still in - * use. - */ -void wakeup_source_prepare(struct wakeup_source *ws, const char *name) -{ - if (ws) { - memset(ws, 0, sizeof(*ws)); - ws->name = name; - } -} -EXPORT_SYMBOL_GPL(wakeup_source_prepare); +static DEFINE_IDA(wakeup_ida); /** * wakeup_source_create - Create a struct wakeup_source object. @@ -97,13 +82,31 @@ EXPORT_SYMBOL_GPL(wakeup_source_prepare); struct wakeup_source *wakeup_source_create(const char *name) { struct wakeup_source *ws; + const char *ws_name; + int id; - ws = kmalloc(sizeof(*ws), GFP_KERNEL); + ws = kzalloc(sizeof(*ws), GFP_KERNEL); if (!ws) - return NULL; + goto err_ws; + + ws_name = kstrdup_const(name, GFP_KERNEL); + if (!ws_name) + goto err_name; + ws->name = ws_name; + + id = ida_alloc(&wakeup_ida, GFP_KERNEL); + if (id < 0) + goto err_id; + ws->id = id; - wakeup_source_prepare(ws, name ? kstrdup_const(name, GFP_KERNEL) : NULL); return ws; + +err_id: + kfree_const(ws->name); +err_name: + kfree(ws); +err_ws: + return NULL; } EXPORT_SYMBOL_GPL(wakeup_source_create); @@ -135,6 +138,13 @@ static void wakeup_source_record(struct wakeup_source *ws) spin_unlock_irqrestore(&deleted_ws.lock, flags); } +static void wakeup_source_free(struct wakeup_source *ws) +{ + ida_free(&wakeup_ida, ws->id); + kfree_const(ws->name); + kfree(ws); +} + /** * wakeup_source_destroy - Destroy a struct wakeup_source object. * @ws: Wakeup source to destroy. @@ -148,8 +158,7 @@ void wakeup_source_destroy(struct wakeup_source *ws) __pm_relax(ws); wakeup_source_record(ws); - kfree_const(ws->name); - kfree(ws); + wakeup_source_free(ws); } EXPORT_SYMBOL_GPL(wakeup_source_destroy); @@ -201,16 +210,26 @@ EXPORT_SYMBOL_GPL(wakeup_source_remove); /** * wakeup_source_register - Create wakeup source and add it to the list. + * @dev: Device this wakeup source is associated with (or NULL if virtual). * @name: Name of the wakeup source to register. */ -struct wakeup_source *wakeup_source_register(const char *name) +struct wakeup_source *wakeup_source_register(struct device *dev, + const char *name) { struct wakeup_source *ws; + int ret; ws = wakeup_source_create(name); - if (ws) + if (ws) { + if (!dev || device_is_registered(dev)) { + ret = wakeup_source_sysfs_add(dev, ws); + if (ret) { + wakeup_source_free(ws); + return NULL; + } + } wakeup_source_add(ws); - + } return ws; } EXPORT_SYMBOL_GPL(wakeup_source_register); @@ -223,6 +242,7 @@ void wakeup_source_unregister(struct wakeup_source *ws) { if (ws) { wakeup_source_remove(ws); + wakeup_source_sysfs_remove(ws); wakeup_source_destroy(ws); } } @@ -266,7 +286,7 @@ int device_wakeup_enable(struct device *dev) if (pm_suspend_target_state != PM_SUSPEND_ON) dev_dbg(dev, "Suspicious %s() during system transition!\n", __func__); - ws = wakeup_source_register(dev_name(dev)); + ws = wakeup_source_register(dev, dev_name(dev)); if (!ws) return -ENOMEM; @@ -891,7 +911,7 @@ EXPORT_SYMBOL_GPL(pm_system_wakeup); void pm_system_cancel_wakeup(void) { - atomic_dec(&pm_abort_suspend); + atomic_dec_if_positive(&pm_abort_suspend); } void pm_wakeup_clear(bool reset) diff --git a/drivers/base/power/wakeup_stats.c b/drivers/base/power/wakeup_stats.c new file mode 100644 index 0000000000000000000000000000000000000000..c7734914d9144bc4d2591b137123159a244267f0 --- /dev/null +++ b/drivers/base/power/wakeup_stats.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Wakeup statistics in sysfs + * + * Copyright (c) 2019 Linux Foundation + * Copyright (c) 2019 Greg Kroah-Hartman + * Copyright (c) 2019 Google Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "power.h" + +static struct class *wakeup_class; + +#define wakeup_attr(_name) \ +static ssize_t _name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct wakeup_source *ws = dev_get_drvdata(dev); \ + \ + return sprintf(buf, "%lu\n", ws->_name); \ +} \ +static DEVICE_ATTR_RO(_name) + +wakeup_attr(active_count); +wakeup_attr(event_count); +wakeup_attr(wakeup_count); +wakeup_attr(expire_count); + +static ssize_t active_time_ms_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct wakeup_source *ws = dev_get_drvdata(dev); + ktime_t active_time = + ws->active ? ktime_sub(ktime_get(), ws->last_time) : 0; + + return sprintf(buf, "%lld\n", ktime_to_ms(active_time)); +} +static DEVICE_ATTR_RO(active_time_ms); + +static ssize_t total_time_ms_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct wakeup_source *ws = dev_get_drvdata(dev); + ktime_t active_time; + ktime_t total_time = ws->total_time; + + if (ws->active) { + active_time = ktime_sub(ktime_get(), ws->last_time); + total_time = ktime_add(total_time, active_time); + } + return sprintf(buf, "%lld\n", ktime_to_ms(total_time)); +} +static DEVICE_ATTR_RO(total_time_ms); + +static ssize_t max_time_ms_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct wakeup_source *ws = dev_get_drvdata(dev); + ktime_t active_time; + ktime_t max_time = ws->max_time; + + if (ws->active) { + active_time = ktime_sub(ktime_get(), ws->last_time); + if (active_time > max_time) + max_time = active_time; + } + return sprintf(buf, "%lld\n", ktime_to_ms(max_time)); +} +static DEVICE_ATTR_RO(max_time_ms); + +static ssize_t last_change_ms_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct wakeup_source *ws = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", ktime_to_ms(ws->last_time)); +} +static DEVICE_ATTR_RO(last_change_ms); + +static ssize_t name_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct wakeup_source *ws = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", ws->name); +} +static DEVICE_ATTR_RO(name); + +static ssize_t prevent_suspend_time_ms_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct wakeup_source *ws = dev_get_drvdata(dev); + ktime_t prevent_sleep_time = ws->prevent_sleep_time; + + if (ws->active && ws->autosleep_enabled) { + prevent_sleep_time = ktime_add(prevent_sleep_time, + ktime_sub(ktime_get(), ws->start_prevent_time)); + } + return sprintf(buf, "%lld\n", ktime_to_ms(prevent_sleep_time)); +} +static DEVICE_ATTR_RO(prevent_suspend_time_ms); + +static struct attribute *wakeup_source_attrs[] = { + &dev_attr_name.attr, + &dev_attr_active_count.attr, + &dev_attr_event_count.attr, + &dev_attr_wakeup_count.attr, + &dev_attr_expire_count.attr, + &dev_attr_active_time_ms.attr, + &dev_attr_total_time_ms.attr, + &dev_attr_max_time_ms.attr, + &dev_attr_last_change_ms.attr, + &dev_attr_prevent_suspend_time_ms.attr, + NULL, +}; +ATTRIBUTE_GROUPS(wakeup_source); + +static void device_create_release(struct device *dev) +{ + kfree(dev); +} + +static struct device *wakeup_source_device_create(struct device *parent, + struct wakeup_source *ws) +{ + struct device *dev = NULL; + int retval = -ENODEV; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + retval = -ENOMEM; + goto error; + } + + device_initialize(dev); + dev->devt = MKDEV(0, 0); + dev->class = wakeup_class; + dev->parent = parent; + dev->groups = wakeup_source_groups; + dev->release = device_create_release; + dev_set_drvdata(dev, ws); + device_set_pm_not_required(dev); + + retval = kobject_set_name(&dev->kobj, "wakeup%d", ws->id); + if (retval) + goto error; + + retval = device_add(dev); + if (retval) + goto error; + + return dev; + +error: + put_device(dev); + return ERR_PTR(retval); +} + +/** + * wakeup_source_sysfs_add - Add wakeup_source attributes to sysfs. + * @parent: Device given wakeup source is associated with (or NULL if virtual). + * @ws: Wakeup source to be added in sysfs. + */ +int wakeup_source_sysfs_add(struct device *parent, struct wakeup_source *ws) +{ + struct device *dev; + + dev = wakeup_source_device_create(parent, ws); + if (IS_ERR(dev)) + return PTR_ERR(dev); + ws->dev = dev; + + return 0; +} + +/** + * pm_wakeup_source_sysfs_add - Add wakeup_source attributes to sysfs + * for a device if they're missing. + * @parent: Device given wakeup source is associated with + */ +int pm_wakeup_source_sysfs_add(struct device *parent) +{ + if (!parent->power.wakeup || parent->power.wakeup->dev) + return 0; + + return wakeup_source_sysfs_add(parent, parent->power.wakeup); +} + +/** + * wakeup_source_sysfs_remove - Remove wakeup_source attributes from sysfs. + * @ws: Wakeup source to be removed from sysfs. + */ +void wakeup_source_sysfs_remove(struct wakeup_source *ws) +{ + device_unregister(ws->dev); +} + +static int __init wakeup_sources_sysfs_init(void) +{ + wakeup_class = class_create(THIS_MODULE, "wakeup"); + + return PTR_ERR_OR_ZERO(wakeup_class); +} +postcore_initcall(wakeup_sources_sysfs_init); diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index e5e1b3a01b1a3e9099f5f745bc0e3a04320d2ed2..e72843fe41dfeea565b2c0dc2722688561670228 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -588,14 +588,6 @@ void regmap_debugfs_init(struct regmap *map, const char *name) } map->debugfs = debugfs_create_dir(name, regmap_debugfs_root); - if (!map->debugfs) { - dev_warn(map->dev, - "Failed to create %s debugfs directory\n", name); - - kfree(map->debugfs_name); - map->debugfs_name = NULL; - return; - } debugfs_create_file("name", 0400, map->debugfs, map, ®map_name_fops); @@ -672,10 +664,6 @@ void regmap_debugfs_initcall(void) struct regmap_debugfs_node *node, *tmp; regmap_debugfs_root = debugfs_create_dir("regmap", NULL); - if (!regmap_debugfs_root) { - pr_warn("regmap: Failed to create debugfs root\n"); - return; - } mutex_lock(®map_debugfs_early_lock); list_for_each_entry_safe(node, tmp, ®map_debugfs_early_list, link) { diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index c9dc70ceca5f104a9c329f0d01fd7bd6a5c9bed7..3d64c9331a82aa61cdab5be03fca8c5c08b4aea6 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -370,7 +370,6 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) if (ret < 0) { dev_err(map->dev, "IRQ thread failed to resume: %d\n", ret); - pm_runtime_put(map->dev); goto exit; } } @@ -425,8 +424,6 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) dev_err(map->dev, "Failed to read IRQ status %d\n", ret); - if (chip->runtime_pm) - pm_runtime_put(map->dev); goto exit; } } @@ -478,8 +475,6 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) dev_err(map->dev, "Failed to read IRQ status: %d\n", ret); - if (chip->runtime_pm) - pm_runtime_put(map->dev); goto exit; } } @@ -513,10 +508,10 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) } } +exit: if (chip->runtime_pm) pm_runtime_put(map->dev); -exit: if (chip->handle_post_irq) chip->handle_post_irq(chip->irq_drv_data); diff --git a/drivers/base/soc.c b/drivers/base/soc.c index 10b280f30217bcc6ec72cea2d7ca9612fc299293..7c0c5ca5953d20b63b849ec537ba999a328f212a 100644 --- a/drivers/base/soc.c +++ b/drivers/base/soc.c @@ -33,6 +33,7 @@ static struct bus_type soc_bus_type = { static DEVICE_ATTR(machine, S_IRUGO, soc_info_get, NULL); static DEVICE_ATTR(family, S_IRUGO, soc_info_get, NULL); +static DEVICE_ATTR(serial_number, S_IRUGO, soc_info_get, NULL); static DEVICE_ATTR(soc_id, S_IRUGO, soc_info_get, NULL); static DEVICE_ATTR(revision, S_IRUGO, soc_info_get, NULL); @@ -57,6 +58,9 @@ static umode_t soc_attribute_mode(struct kobject *kobj, if ((attr == &dev_attr_revision.attr) && (soc_dev->attr->revision != NULL)) return attr->mode; + if ((attr == &dev_attr_serial_number.attr) + && (soc_dev->attr->serial_number != NULL)) + return attr->mode; if ((attr == &dev_attr_soc_id.attr) && (soc_dev->attr->soc_id != NULL)) return attr->mode; @@ -77,6 +81,8 @@ static ssize_t soc_info_get(struct device *dev, return sprintf(buf, "%s\n", soc_dev->attr->family); if (attr == &dev_attr_revision) return sprintf(buf, "%s\n", soc_dev->attr->revision); + if (attr == &dev_attr_serial_number) + return sprintf(buf, "%s\n", soc_dev->attr->serial_number); if (attr == &dev_attr_soc_id) return sprintf(buf, "%s\n", soc_dev->attr->soc_id); @@ -87,6 +93,7 @@ static ssize_t soc_info_get(struct device *dev, static struct attribute *soc_attr[] = { &dev_attr_machine.attr, &dev_attr_family.attr, + &dev_attr_serial_number.attr, &dev_attr_soc_id.attr, &dev_attr_revision.attr, NULL, @@ -157,6 +164,7 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr out1: return ERR_PTR(ret); } +EXPORT_SYMBOL_GPL(soc_device_register); /* Ensure soc_dev->attr is freed prior to calling soc_device_unregister. */ void soc_device_unregister(struct soc_device *soc_dev) @@ -166,6 +174,7 @@ void soc_device_unregister(struct soc_device *soc_dev) device_unregister(&soc_dev->dev); early_soc_dev_attr = NULL; } +EXPORT_SYMBOL_GPL(soc_device_unregister); static int __init soc_bus_register(void) { diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index e7b3aa3bd55addce693e796f8c8c289f3ee1dfff..a1f3f0994f9f9c9e3f3e7582ff37971f74a41984 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -51,7 +51,7 @@ EXPORT_SYMBOL_GPL(is_software_node); static struct swnode * software_node_to_swnode(const struct software_node *node) { - struct swnode *swnode; + struct swnode *swnode = NULL; struct kobject *k; if (!node) @@ -620,6 +620,43 @@ static const struct fwnode_operations software_node_ops = { /* -------------------------------------------------------------------------- */ +/** + * software_node_find_by_name - Find software node by name + * @parent: Parent of the software node + * @name: Name of the software node + * + * The function will find a node that is child of @parent and that is named + * @name. If no node is found, the function returns NULL. + * + * NOTE: you will need to drop the reference with fwnode_handle_put() after use. + */ +const struct software_node * +software_node_find_by_name(const struct software_node *parent, const char *name) +{ + struct swnode *swnode = NULL; + struct kobject *k; + + if (!name) + return NULL; + + spin_lock(&swnode_kset->list_lock); + + list_for_each_entry(k, &swnode_kset->list, entry) { + swnode = kobj_to_swnode(k); + if (parent == swnode->node->parent && swnode->node->name && + !strcmp(name, swnode->node->name)) { + kobject_get(&swnode->kobj); + break; + } + swnode = NULL; + } + + spin_unlock(&swnode_kset->list_lock); + + return swnode ? swnode->node : NULL; +} +EXPORT_SYMBOL_GPL(software_node_find_by_name); + static int software_node_register_properties(struct software_node *node, const struct property_entry *properties) diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c index 27e9686b6d3a3bb499da4e724ce05d344ab24e86..87760aa60446e93e0e2f1f856a82366e87c75685 100644 --- a/drivers/bcma/driver_mips.c +++ b/drivers/bcma/driver_mips.c @@ -59,22 +59,6 @@ static inline void mips_write32(struct bcma_drv_mips *mcore, bcma_write32(mcore->core, offset, value); } -static const u32 ipsflag_irq_mask[] = { - 0, - BCMA_MIPS_IPSFLAG_IRQ1, - BCMA_MIPS_IPSFLAG_IRQ2, - BCMA_MIPS_IPSFLAG_IRQ3, - BCMA_MIPS_IPSFLAG_IRQ4, -}; - -static const u32 ipsflag_irq_shift[] = { - 0, - BCMA_MIPS_IPSFLAG_IRQ1_SHIFT, - BCMA_MIPS_IPSFLAG_IRQ2_SHIFT, - BCMA_MIPS_IPSFLAG_IRQ3_SHIFT, - BCMA_MIPS_IPSFLAG_IRQ4_SHIFT, -}; - static u32 bcma_core_mips_irqflag(struct bcma_device *dev) { u32 flag; diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index f499a469e66d08d7dfcb50e123c82fc920f32ea9..12b2cc9a3fbe8a1050133582e7f553b599fbcbbf 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -78,7 +78,7 @@ static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u16 device, u8 address) v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD); } - v = BCMA_CORE_PCI_MDIODATA_START; + v |= BCMA_CORE_PCI_MDIODATA_START; v |= BCMA_CORE_PCI_MDIODATA_READ; v |= BCMA_CORE_PCI_MDIODATA_TA; @@ -121,7 +121,7 @@ static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u16 device, v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD); } - v = BCMA_CORE_PCI_MDIODATA_START; + v |= BCMA_CORE_PCI_MDIODATA_START; v |= BCMA_CORE_PCI_MDIODATA_WRITE; v |= BCMA_CORE_PCI_MDIODATA_TA; v |= data; diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index f52239feb4cb2585757eb3448f3da363059b0544..69c10a7b7c617b0155637c42e53821693445b826 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -260,8 +260,7 @@ static void bcma_host_pci_remove(struct pci_dev *dev) #ifdef CONFIG_PM_SLEEP static int bcma_host_pci_suspend(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct bcma_bus *bus = pci_get_drvdata(pdev); + struct bcma_bus *bus = dev_get_drvdata(dev); bus->mapped_core = NULL; @@ -270,8 +269,7 @@ static int bcma_host_pci_suspend(struct device *dev) static int bcma_host_pci_resume(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct bcma_bus *bus = pci_get_drvdata(pdev); + struct bcma_bus *bus = dev_get_drvdata(dev); return bcma_bus_resume(bus); } diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index 206edd3ba668de63dcbe3b928c9dc7a16b0025cd..bd2c923a658670a185f7b55caa56c711faaba578 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -222,7 +222,7 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) { u16 v, o; int i; - u16 pwr_info_offset[] = { + static const u16 pwr_info_offset[] = { SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1, SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3 }; @@ -578,9 +578,11 @@ int bcma_sprom_get(struct bcma_bus *bus) { u16 offset = BCMA_CC_SPROM; u16 *sprom; - size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4, - SSB_SPROMSIZE_WORDS_R10, - SSB_SPROMSIZE_WORDS_R11, }; + static const size_t sprom_sizes[] = { + SSB_SPROMSIZE_WORDS_R4, + SSB_SPROMSIZE_WORDS_R10, + SSB_SPROMSIZE_WORDS_R11, + }; int i, err = 0; if (!bus->drv_cc.core) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 0469aceaa230778896d02dbde35e3270aa494992..485865fd0412e40d041e861506bb3ac11a3a91e3 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3780,7 +3780,7 @@ static int compat_getdrvprm(int drive, v.native_format = UDP->native_format; mutex_unlock(&floppy_mutex); - if (copy_from_user(arg, &v, sizeof(struct compat_floppy_drive_params))) + if (copy_to_user(arg, &v, sizeof(struct compat_floppy_drive_params))) return -EFAULT; return 0; } @@ -3816,7 +3816,7 @@ static int compat_getdrvstat(int drive, bool poll, v.bufblocks = UDRS->bufblocks; mutex_unlock(&floppy_mutex); - if (copy_from_user(arg, &v, sizeof(struct compat_floppy_drive_struct))) + if (copy_to_user(arg, &v, sizeof(struct compat_floppy_drive_struct))) return -EFAULT; return 0; Eintr: diff --git a/drivers/block/loop.c b/drivers/block/loop.c index ab7ca5989097ac70372f77f4fb60964a98c98177..1410fa89365389a62f42782b3ef89dfb23fa1600 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1755,6 +1755,7 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode, case LOOP_SET_FD: case LOOP_CHANGE_FD: case LOOP_SET_BLOCK_SIZE: + case LOOP_SET_DIRECT_IO: err = lo_ioctl(bdev, mode, cmd, arg); break; default: diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index e21d2ded732b735c13f7ebbd02533ed081afe0ca..a8e3815295fe590ba7f14c213b142e1eae69bdbb 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -108,6 +108,7 @@ struct nbd_device { struct nbd_config *config; struct mutex config_lock; struct gendisk *disk; + struct workqueue_struct *recv_workq; struct list_head list; struct task_struct *task_recv; @@ -121,6 +122,7 @@ struct nbd_cmd { struct mutex lock; int index; int cookie; + int retries; blk_status_t status; unsigned long flags; u32 cmd_cookie; @@ -138,7 +140,6 @@ static struct dentry *nbd_dbg_dir; static unsigned int nbds_max = 16; static int max_part = 16; -static struct workqueue_struct *recv_workqueue; static int part_shift; static int nbd_dev_dbg_init(struct nbd_device *nbd); @@ -344,6 +345,22 @@ static void sock_shutdown(struct nbd_device *nbd) dev_warn(disk_to_dev(nbd->disk), "shutting down sockets\n"); } +static u32 req_to_nbd_cmd_type(struct request *req) +{ + switch (req_op(req)) { + case REQ_OP_DISCARD: + return NBD_CMD_TRIM; + case REQ_OP_FLUSH: + return NBD_CMD_FLUSH; + case REQ_OP_WRITE: + return NBD_CMD_WRITE; + case REQ_OP_READ: + return NBD_CMD_READ; + default: + return U32_MAX; + } +} + static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req, bool reserved) { @@ -357,8 +374,10 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req, } config = nbd->config; - if (!mutex_trylock(&cmd->lock)) + if (!mutex_trylock(&cmd->lock)) { + nbd_config_put(nbd); return BLK_EH_RESET_TIMER; + } if (config->num_connections > 1) { dev_err_ratelimited(nbd_to_dev(nbd), @@ -389,10 +408,25 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req, nbd_config_put(nbd); return BLK_EH_DONE; } - } else { - dev_err_ratelimited(nbd_to_dev(nbd), - "Connection timed out\n"); } + + if (!nbd->tag_set.timeout) { + /* + * Userspace sets timeout=0 to disable socket disconnection, + * so just warn and reset the timer. + */ + cmd->retries++; + dev_info(nbd_to_dev(nbd), "Possible stuck request %p: control (%s@%llu,%uB). Runtime %u seconds\n", + req, nbdcmd_to_ascii(req_to_nbd_cmd_type(req)), + (unsigned long long)blk_rq_pos(req) << 9, + blk_rq_bytes(req), (req->timeout / HZ) * cmd->retries); + + mutex_unlock(&cmd->lock); + nbd_config_put(nbd); + return BLK_EH_RESET_TIMER; + } + + dev_err_ratelimited(nbd_to_dev(nbd), "Connection timed out\n"); set_bit(NBD_TIMEDOUT, &config->runtime_flags); cmd->status = BLK_STS_IOERR; mutex_unlock(&cmd->lock); @@ -480,22 +514,9 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) iov_iter_kvec(&from, WRITE, &iov, 1, sizeof(request)); - switch (req_op(req)) { - case REQ_OP_DISCARD: - type = NBD_CMD_TRIM; - break; - case REQ_OP_FLUSH: - type = NBD_CMD_FLUSH; - break; - case REQ_OP_WRITE: - type = NBD_CMD_WRITE; - break; - case REQ_OP_READ: - type = NBD_CMD_READ; - break; - default: + type = req_to_nbd_cmd_type(req); + if (type == U32_MAX) return -EIO; - } if (rq_data_dir(req) == WRITE && (config->flags & NBD_FLAG_READ_ONLY)) { @@ -526,6 +547,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) } cmd->index = index; cmd->cookie = nsock->cookie; + cmd->retries = 0; request.type = htonl(type | nbd_cmd_flags); if (type != NBD_CMD_FLUSH) { request.from = cpu_to_be64((u64)blk_rq_pos(req) << 9); @@ -1036,7 +1058,7 @@ static int nbd_reconnect_socket(struct nbd_device *nbd, unsigned long arg) /* We take the tx_mutex in an error path in the recv_work, so we * need to queue_work outside of the tx_mutex. */ - queue_work(recv_workqueue, &args->work); + queue_work(nbd->recv_workq, &args->work); atomic_inc(&config->live_connections); wake_up(&config->conn_wait); @@ -1137,6 +1159,10 @@ static void nbd_config_put(struct nbd_device *nbd) kfree(nbd->config); nbd->config = NULL; + if (nbd->recv_workq) + destroy_workqueue(nbd->recv_workq); + nbd->recv_workq = NULL; + nbd->tag_set.timeout = 0; nbd->disk->queue->limits.discard_granularity = 0; nbd->disk->queue->limits.discard_alignment = 0; @@ -1165,6 +1191,14 @@ static int nbd_start_device(struct nbd_device *nbd) return -EINVAL; } + nbd->recv_workq = alloc_workqueue("knbd%d-recv", + WQ_MEM_RECLAIM | WQ_HIGHPRI | + WQ_UNBOUND, 0, nbd->index); + if (!nbd->recv_workq) { + dev_err(disk_to_dev(nbd->disk), "Could not allocate knbd recv work queue.\n"); + return -ENOMEM; + } + blk_mq_update_nr_hw_queues(&nbd->tag_set, config->num_connections); nbd->task_recv = current; @@ -1195,7 +1229,7 @@ static int nbd_start_device(struct nbd_device *nbd) INIT_WORK(&args->work, recv_work); args->nbd = nbd; args->index = i; - queue_work(recv_workqueue, &args->work); + queue_work(nbd->recv_workq, &args->work); } nbd_size_update(nbd); return error; @@ -1215,8 +1249,10 @@ static int nbd_start_device_ioctl(struct nbd_device *nbd, struct block_device *b mutex_unlock(&nbd->config_lock); ret = wait_event_interruptible(config->recv_wq, atomic_read(&config->recv_threads) == 0); - if (ret) + if (ret) { sock_shutdown(nbd); + flush_workqueue(nbd->recv_workq); + } mutex_lock(&nbd->config_lock); nbd_bdev_reset(bdev); /* user requested, ignore socket errors */ @@ -1246,6 +1282,13 @@ static bool nbd_is_valid_blksize(unsigned long blksize) return true; } +static void nbd_set_cmd_timeout(struct nbd_device *nbd, u64 timeout) +{ + nbd->tag_set.timeout = timeout * HZ; + if (timeout) + blk_queue_rq_timeout(nbd->disk->queue, timeout * HZ); +} + /* Must be called with config_lock held */ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, unsigned int cmd, unsigned long arg) @@ -1276,10 +1319,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, nbd_size_set(nbd, config->blksize, arg); return 0; case NBD_SET_TIMEOUT: - if (arg) { - nbd->tag_set.timeout = arg * HZ; - blk_queue_rq_timeout(nbd->disk->queue, arg * HZ); - } + nbd_set_cmd_timeout(nbd, arg); return 0; case NBD_SET_FLAGS: @@ -1799,11 +1839,9 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info) if (ret) goto out; - if (info->attrs[NBD_ATTR_TIMEOUT]) { - u64 timeout = nla_get_u64(info->attrs[NBD_ATTR_TIMEOUT]); - nbd->tag_set.timeout = timeout * HZ; - blk_queue_rq_timeout(nbd->disk->queue, timeout * HZ); - } + if (info->attrs[NBD_ATTR_TIMEOUT]) + nbd_set_cmd_timeout(nbd, + nla_get_u64(info->attrs[NBD_ATTR_TIMEOUT])); if (info->attrs[NBD_ATTR_DEAD_CONN_TIMEOUT]) { config->dead_conn_timeout = nla_get_u64(info->attrs[NBD_ATTR_DEAD_CONN_TIMEOUT]); @@ -1875,6 +1913,12 @@ static void nbd_disconnect_and_put(struct nbd_device *nbd) nbd_disconnect(nbd); nbd_clear_sock(nbd); mutex_unlock(&nbd->config_lock); + /* + * Make sure recv thread has finished, so it does not drop the last + * config ref and try to destroy the workqueue from inside the work + * queue. + */ + flush_workqueue(nbd->recv_workq); if (test_and_clear_bit(NBD_HAS_CONFIG_REF, &nbd->config->runtime_flags)) nbd_config_put(nbd); @@ -1971,11 +2015,9 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info) if (ret) goto out; - if (info->attrs[NBD_ATTR_TIMEOUT]) { - u64 timeout = nla_get_u64(info->attrs[NBD_ATTR_TIMEOUT]); - nbd->tag_set.timeout = timeout * HZ; - blk_queue_rq_timeout(nbd->disk->queue, timeout * HZ); - } + if (info->attrs[NBD_ATTR_TIMEOUT]) + nbd_set_cmd_timeout(nbd, + nla_get_u64(info->attrs[NBD_ATTR_TIMEOUT])); if (info->attrs[NBD_ATTR_DEAD_CONN_TIMEOUT]) { config->dead_conn_timeout = nla_get_u64(info->attrs[NBD_ATTR_DEAD_CONN_TIMEOUT]); @@ -2261,20 +2303,12 @@ static int __init nbd_init(void) if (nbds_max > 1UL << (MINORBITS - part_shift)) return -EINVAL; - recv_workqueue = alloc_workqueue("knbd-recv", - WQ_MEM_RECLAIM | WQ_HIGHPRI | - WQ_UNBOUND, 0); - if (!recv_workqueue) - return -ENOMEM; - if (register_blkdev(NBD_MAJOR, "nbd")) { - destroy_workqueue(recv_workqueue); + if (register_blkdev(NBD_MAJOR, "nbd")) return -EIO; - } if (genl_register_family(&nbd_genl_family)) { unregister_blkdev(NBD_MAJOR, "nbd"); - destroy_workqueue(recv_workqueue); return -EINVAL; } nbd_dbg_init(); @@ -2316,7 +2350,6 @@ static void __exit nbd_cleanup(void) idr_destroy(&nbd_index_idr); genl_unregister_family(&nbd_genl_family); - destroy_workqueue(recv_workqueue); unregister_blkdev(NBD_MAJOR, "nbd"); } diff --git a/drivers/block/null_blk.h b/drivers/block/null_blk.h index a1b9929bd911926c94d4c86b886c4da629a5ef58..a235c45e22a70c7bb046bb1d897b74adba595727 100644 --- a/drivers/block/null_blk.h +++ b/drivers/block/null_blk.h @@ -2,6 +2,9 @@ #ifndef __BLK_NULL_BLK_H #define __BLK_NULL_BLK_H +#undef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -90,13 +93,13 @@ int null_zone_init(struct nullb_device *dev); void null_zone_exit(struct nullb_device *dev); int null_zone_report(struct gendisk *disk, sector_t sector, struct blk_zone *zones, unsigned int *nr_zones); -void null_zone_write(struct nullb_cmd *cmd, sector_t sector, - unsigned int nr_sectors); -void null_zone_reset(struct nullb_cmd *cmd, sector_t sector); +blk_status_t null_handle_zoned(struct nullb_cmd *cmd, + enum req_opf op, sector_t sector, + sector_t nr_sectors); #else static inline int null_zone_init(struct nullb_device *dev) { - pr_err("null_blk: CONFIG_BLK_DEV_ZONED not enabled\n"); + pr_err("CONFIG_BLK_DEV_ZONED not enabled\n"); return -EINVAL; } static inline void null_zone_exit(struct nullb_device *dev) {} @@ -106,10 +109,11 @@ static inline int null_zone_report(struct gendisk *disk, sector_t sector, { return -EOPNOTSUPP; } -static inline void null_zone_write(struct nullb_cmd *cmd, sector_t sector, - unsigned int nr_sectors) +static inline blk_status_t null_handle_zoned(struct nullb_cmd *cmd, + enum req_opf op, sector_t sector, + sector_t nr_sectors) { + return BLK_STS_NOTSUPP; } -static inline void null_zone_reset(struct nullb_cmd *cmd, sector_t sector) {} #endif /* CONFIG_BLK_DEV_ZONED */ #endif /* __NULL_BLK_H */ diff --git a/drivers/block/null_blk_main.c b/drivers/block/null_blk_main.c index 99328ded60d124695fe7fd307b7420d2e94bb8a6..0e7da5015ccd5f8a7d6314d24eb8bfd52b15d4c9 100644 --- a/drivers/block/null_blk_main.c +++ b/drivers/block/null_blk_main.c @@ -141,8 +141,8 @@ static int g_bs = 512; module_param_named(bs, g_bs, int, 0444); MODULE_PARM_DESC(bs, "Block size (in bytes)"); -static int nr_devices = 1; -module_param(nr_devices, int, 0444); +static unsigned int nr_devices = 1; +module_param(nr_devices, uint, 0444); MODULE_PARM_DESC(nr_devices, "Number of devices to register"); static bool g_blocking; @@ -1133,93 +1133,61 @@ static void null_restart_queue_async(struct nullb *nullb) blk_mq_start_stopped_hw_queues(q, true); } -static blk_status_t null_handle_cmd(struct nullb_cmd *cmd) +static inline blk_status_t null_handle_throttled(struct nullb_cmd *cmd) { struct nullb_device *dev = cmd->nq->dev; struct nullb *nullb = dev->nullb; - int err = 0; + blk_status_t sts = BLK_STS_OK; + struct request *rq = cmd->rq; - if (test_bit(NULLB_DEV_FL_THROTTLED, &dev->flags)) { - struct request *rq = cmd->rq; - - if (!hrtimer_active(&nullb->bw_timer)) - hrtimer_restart(&nullb->bw_timer); - - if (atomic_long_sub_return(blk_rq_bytes(rq), - &nullb->cur_bytes) < 0) { - null_stop_queue(nullb); - /* race with timer */ - if (atomic_long_read(&nullb->cur_bytes) > 0) - null_restart_queue_async(nullb); - /* requeue request */ - return BLK_STS_DEV_RESOURCE; - } - } + if (!hrtimer_active(&nullb->bw_timer)) + hrtimer_restart(&nullb->bw_timer); - if (nullb->dev->badblocks.shift != -1) { - int bad_sectors; - sector_t sector, size, first_bad; - bool is_flush = true; - - if (dev->queue_mode == NULL_Q_BIO && - bio_op(cmd->bio) != REQ_OP_FLUSH) { - is_flush = false; - sector = cmd->bio->bi_iter.bi_sector; - size = bio_sectors(cmd->bio); - } - if (dev->queue_mode != NULL_Q_BIO && - req_op(cmd->rq) != REQ_OP_FLUSH) { - is_flush = false; - sector = blk_rq_pos(cmd->rq); - size = blk_rq_sectors(cmd->rq); - } - if (!is_flush && badblocks_check(&nullb->dev->badblocks, sector, - size, &first_bad, &bad_sectors)) { - cmd->error = BLK_STS_IOERR; - goto out; - } + if (atomic_long_sub_return(blk_rq_bytes(rq), &nullb->cur_bytes) < 0) { + null_stop_queue(nullb); + /* race with timer */ + if (atomic_long_read(&nullb->cur_bytes) > 0) + null_restart_queue_async(nullb); + /* requeue request */ + sts = BLK_STS_DEV_RESOURCE; } + return sts; +} - if (dev->memory_backed) { - if (dev->queue_mode == NULL_Q_BIO) { - if (bio_op(cmd->bio) == REQ_OP_FLUSH) - err = null_handle_flush(nullb); - else - err = null_handle_bio(cmd); - } else { - if (req_op(cmd->rq) == REQ_OP_FLUSH) - err = null_handle_flush(nullb); - else - err = null_handle_rq(cmd); - } - } - cmd->error = errno_to_blk_status(err); +static inline blk_status_t null_handle_badblocks(struct nullb_cmd *cmd, + sector_t sector, + sector_t nr_sectors) +{ + struct badblocks *bb = &cmd->nq->dev->badblocks; + sector_t first_bad; + int bad_sectors; - if (!cmd->error && dev->zoned) { - sector_t sector; - unsigned int nr_sectors; - enum req_opf op; + if (badblocks_check(bb, sector, nr_sectors, &first_bad, &bad_sectors)) + return BLK_STS_IOERR; - if (dev->queue_mode == NULL_Q_BIO) { - op = bio_op(cmd->bio); - sector = cmd->bio->bi_iter.bi_sector; - nr_sectors = cmd->bio->bi_iter.bi_size >> 9; - } else { - op = req_op(cmd->rq); - sector = blk_rq_pos(cmd->rq); - nr_sectors = blk_rq_sectors(cmd->rq); - } + return BLK_STS_OK; +} - if (op == REQ_OP_WRITE) - null_zone_write(cmd, sector, nr_sectors); - else if (op == REQ_OP_ZONE_RESET) - null_zone_reset(cmd, sector); - } -out: +static inline blk_status_t null_handle_memory_backed(struct nullb_cmd *cmd, + enum req_opf op) +{ + struct nullb_device *dev = cmd->nq->dev; + int err; + + if (dev->queue_mode == NULL_Q_BIO) + err = null_handle_bio(cmd); + else + err = null_handle_rq(cmd); + + return errno_to_blk_status(err); +} + +static inline void nullb_complete_cmd(struct nullb_cmd *cmd) +{ /* Complete IO by inline, softirq or timer */ - switch (dev->irqmode) { + switch (cmd->nq->dev->irqmode) { case NULL_IRQ_SOFTIRQ: - switch (dev->queue_mode) { + switch (cmd->nq->dev->queue_mode) { case NULL_Q_MQ: blk_mq_complete_request(cmd->rq); break; @@ -1238,6 +1206,40 @@ static blk_status_t null_handle_cmd(struct nullb_cmd *cmd) null_cmd_end_timer(cmd); break; } +} + +static blk_status_t null_handle_cmd(struct nullb_cmd *cmd, sector_t sector, + sector_t nr_sectors, enum req_opf op) +{ + struct nullb_device *dev = cmd->nq->dev; + struct nullb *nullb = dev->nullb; + blk_status_t sts; + + if (test_bit(NULLB_DEV_FL_THROTTLED, &dev->flags)) { + sts = null_handle_throttled(cmd); + if (sts != BLK_STS_OK) + return sts; + } + + if (op == REQ_OP_FLUSH) { + cmd->error = errno_to_blk_status(null_handle_flush(nullb)); + goto out; + } + + if (nullb->dev->badblocks.shift != -1) { + cmd->error = null_handle_badblocks(cmd, sector, nr_sectors); + if (cmd->error != BLK_STS_OK) + goto out; + } + + if (dev->memory_backed) + cmd->error = null_handle_memory_backed(cmd, op); + + if (!cmd->error && dev->zoned) + cmd->error = null_handle_zoned(cmd, op, sector, nr_sectors); + +out: + nullb_complete_cmd(cmd); return BLK_STS_OK; } @@ -1280,6 +1282,8 @@ static struct nullb_queue *nullb_to_queue(struct nullb *nullb) static blk_qc_t null_queue_bio(struct request_queue *q, struct bio *bio) { + sector_t sector = bio->bi_iter.bi_sector; + sector_t nr_sectors = bio_sectors(bio); struct nullb *nullb = q->queuedata; struct nullb_queue *nq = nullb_to_queue(nullb); struct nullb_cmd *cmd; @@ -1287,7 +1291,7 @@ static blk_qc_t null_queue_bio(struct request_queue *q, struct bio *bio) cmd = alloc_cmd(nq, 1); cmd->bio = bio; - null_handle_cmd(cmd); + null_handle_cmd(cmd, sector, nr_sectors, bio_op(bio)); return BLK_QC_T_NONE; } @@ -1311,7 +1315,7 @@ static bool should_requeue_request(struct request *rq) static enum blk_eh_timer_return null_timeout_rq(struct request *rq, bool res) { - pr_info("null: rq %p timed out\n", rq); + pr_info("rq %p timed out\n", rq); blk_mq_complete_request(rq); return BLK_EH_DONE; } @@ -1321,6 +1325,8 @@ static blk_status_t null_queue_rq(struct blk_mq_hw_ctx *hctx, { struct nullb_cmd *cmd = blk_mq_rq_to_pdu(bd->rq); struct nullb_queue *nq = hctx->driver_data; + sector_t nr_sectors = blk_rq_sectors(bd->rq); + sector_t sector = blk_rq_pos(bd->rq); might_sleep_if(hctx->flags & BLK_MQ_F_BLOCKING); @@ -1349,7 +1355,7 @@ static blk_status_t null_queue_rq(struct blk_mq_hw_ctx *hctx, if (should_timeout_request(bd->rq)) return BLK_STS_OK; - return null_handle_cmd(cmd); + return null_handle_cmd(cmd, sector, nr_sectors, req_op(bd->rq)); } static const struct blk_mq_ops null_mq_ops = { @@ -1688,6 +1694,9 @@ static int null_add_dev(struct nullb_device *dev) blk_queue_chunk_sectors(nullb->q, dev->zone_size_sects); nullb->q->limits.zoned = BLK_ZONED_HM; + blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, nullb->q); + blk_queue_required_elevator_features(nullb->q, + ELEVATOR_F_ZBD_SEQ_WRITE); } nullb->q->queuedata = nullb; @@ -1739,28 +1748,28 @@ static int __init null_init(void) struct nullb_device *dev; if (g_bs > PAGE_SIZE) { - pr_warn("null_blk: invalid block size\n"); - pr_warn("null_blk: defaults block size to %lu\n", PAGE_SIZE); + pr_warn("invalid block size\n"); + pr_warn("defaults block size to %lu\n", PAGE_SIZE); g_bs = PAGE_SIZE; } if (!is_power_of_2(g_zone_size)) { - pr_err("null_blk: zone_size must be power-of-two\n"); + pr_err("zone_size must be power-of-two\n"); return -EINVAL; } if (g_home_node != NUMA_NO_NODE && g_home_node >= nr_online_nodes) { - pr_err("null_blk: invalid home_node value\n"); + pr_err("invalid home_node value\n"); g_home_node = NUMA_NO_NODE; } if (g_queue_mode == NULL_Q_RQ) { - pr_err("null_blk: legacy IO path no longer available\n"); + pr_err("legacy IO path no longer available\n"); return -EINVAL; } if (g_queue_mode == NULL_Q_MQ && g_use_per_node_hctx) { if (g_submit_queues != nr_online_nodes) { - pr_warn("null_blk: submit_queues param is set to %u.\n", + pr_warn("submit_queues param is set to %u.\n", nr_online_nodes); g_submit_queues = nr_online_nodes; } @@ -1803,7 +1812,7 @@ static int __init null_init(void) } } - pr_info("null: module loaded\n"); + pr_info("module loaded\n"); return 0; err_dev: diff --git a/drivers/block/null_blk_zoned.c b/drivers/block/null_blk_zoned.c index cb28d93f2bd145a1b7a867dd33cf571d708f76ae..eabc116832a7ea47f22d4634926b521ce7206002 100644 --- a/drivers/block/null_blk_zoned.c +++ b/drivers/block/null_blk_zoned.c @@ -17,7 +17,7 @@ int null_zone_init(struct nullb_device *dev) unsigned int i; if (!is_power_of_2(dev->zone_size)) { - pr_err("null_blk: zone_size must be power-of-two\n"); + pr_err("zone_size must be power-of-two\n"); return -EINVAL; } @@ -31,7 +31,7 @@ int null_zone_init(struct nullb_device *dev) if (dev->zone_nr_conv >= dev->nr_zones) { dev->zone_nr_conv = dev->nr_zones - 1; - pr_info("null_blk: changed the number of conventional zones to %u", + pr_info("changed the number of conventional zones to %u", dev->zone_nr_conv); } @@ -84,7 +84,7 @@ int null_zone_report(struct gendisk *disk, sector_t sector, return 0; } -void null_zone_write(struct nullb_cmd *cmd, sector_t sector, +static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector, unsigned int nr_sectors) { struct nullb_device *dev = cmd->nq->dev; @@ -95,14 +95,12 @@ void null_zone_write(struct nullb_cmd *cmd, sector_t sector, case BLK_ZONE_COND_FULL: /* Cannot write to a full zone */ cmd->error = BLK_STS_IOERR; - break; + return BLK_STS_IOERR; case BLK_ZONE_COND_EMPTY: case BLK_ZONE_COND_IMP_OPEN: /* Writes must be at the write pointer position */ - if (sector != zone->wp) { - cmd->error = BLK_STS_IOERR; - break; - } + if (sector != zone->wp) + return BLK_STS_IOERR; if (zone->cond == BLK_ZONE_COND_EMPTY) zone->cond = BLK_ZONE_COND_IMP_OPEN; @@ -115,22 +113,51 @@ void null_zone_write(struct nullb_cmd *cmd, sector_t sector, break; default: /* Invalid zone condition */ - cmd->error = BLK_STS_IOERR; - break; + return BLK_STS_IOERR; } + return BLK_STS_OK; } -void null_zone_reset(struct nullb_cmd *cmd, sector_t sector) +static blk_status_t null_zone_reset(struct nullb_cmd *cmd, sector_t sector) { struct nullb_device *dev = cmd->nq->dev; unsigned int zno = null_zone_no(dev, sector); struct blk_zone *zone = &dev->zones[zno]; + size_t i; + + switch (req_op(cmd->rq)) { + case REQ_OP_ZONE_RESET_ALL: + for (i = 0; i < dev->nr_zones; i++) { + if (zone[i].type == BLK_ZONE_TYPE_CONVENTIONAL) + continue; + zone[i].cond = BLK_ZONE_COND_EMPTY; + zone[i].wp = zone[i].start; + } + break; + case REQ_OP_ZONE_RESET: + if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL) + return BLK_STS_IOERR; - if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL) { - cmd->error = BLK_STS_IOERR; - return; + zone->cond = BLK_ZONE_COND_EMPTY; + zone->wp = zone->start; + break; + default: + cmd->error = BLK_STS_NOTSUPP; + break; } + return BLK_STS_OK; +} - zone->cond = BLK_ZONE_COND_EMPTY; - zone->wp = zone->start; +blk_status_t null_handle_zoned(struct nullb_cmd *cmd, enum req_opf op, + sector_t sector, sector_t nr_sectors) +{ + switch (op) { + case REQ_OP_WRITE: + return null_zone_write(cmd, sector, nr_sectors); + case REQ_OP_ZONE_RESET: + case REQ_OP_ZONE_RESET_ALL: + return null_zone_reset(cmd, sector); + default: + return BLK_STS_OK; + } } diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 001dbdcbf35572891ad3981d6f3c74c475065475..636bfea2de6fa2f2ffccbc6272169d88ea6491b9 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -314,8 +314,8 @@ static void pcd_init_units(void) disk->queue = blk_mq_init_sq_queue(&cd->tag_set, &pcd_mq_ops, 1, BLK_MQ_F_SHOULD_MERGE); if (IS_ERR(disk->queue)) { - put_disk(disk); disk->queue = NULL; + put_disk(disk); continue; } @@ -723,9 +723,9 @@ static int pcd_detect(void) k = 0; if (pcd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */ cd = pcd; - if (pi_init(cd->pi, 1, -1, -1, -1, -1, -1, pcd_buffer, - PI_PCD, verbose, cd->name)) { - if (!pcd_probe(cd, -1, id) && cd->disk) { + if (cd->disk && pi_init(cd->pi, 1, -1, -1, -1, -1, -1, + pcd_buffer, PI_PCD, verbose, cd->name)) { + if (!pcd_probe(cd, -1, id)) { cd->present = 1; k++; } else @@ -736,11 +736,13 @@ static int pcd_detect(void) int *conf = *drives[unit]; if (!conf[D_PRT]) continue; + if (!cd->disk) + continue; if (!pi_init(cd->pi, 0, conf[D_PRT], conf[D_MOD], conf[D_UNI], conf[D_PRO], conf[D_DLY], pcd_buffer, PI_PCD, verbose, cd->name)) continue; - if (!pcd_probe(cd, conf[D_SLV], id) && cd->disk) { + if (!pcd_probe(cd, conf[D_SLV], id)) { cd->present = 1; k++; } else diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 1e9c50a7256cd88d7c8910430cd54875889be854..6b7d4cab36874e5b38bd665a49de7a5427cc04b8 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -300,8 +300,8 @@ static void __init pf_init_units(void) disk->queue = blk_mq_init_sq_queue(&pf->tag_set, &pf_mq_ops, 1, BLK_MQ_F_SHOULD_MERGE); if (IS_ERR(disk->queue)) { - put_disk(disk); disk->queue = NULL; + put_disk(disk); continue; } diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index 124ef0a3e1dd0cc3fac12503c9228ec84ebf1ad3..2d2e6d862068105f21b4e5d0ca673ce097d0e15d 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -23,6 +23,7 @@ #define BDADDR_BCM43430A0 (&(bdaddr_t) {{0xac, 0x1f, 0x12, 0xa0, 0x43, 0x43}}) #define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}}) #define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}}) +#define BDADDR_BCM4345C5 (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0xc5, 0x45, 0x43}}) #define BDADDR_BCM43341B (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0x1b, 0x34, 0x43}}) int btbcm_check_bdaddr(struct hci_dev *hdev) @@ -73,6 +74,7 @@ int btbcm_check_bdaddr(struct hci_dev *hdev) !bacmp(&bda->bdaddr, BDADDR_BCM2076B1) || !bacmp(&bda->bdaddr, BDADDR_BCM4324B3) || !bacmp(&bda->bdaddr, BDADDR_BCM4330B1) || + !bacmp(&bda->bdaddr, BDADDR_BCM4345C5) || !bacmp(&bda->bdaddr, BDADDR_BCM43430A0) || !bacmp(&bda->bdaddr, BDADDR_BCM43341B)) { bt_dev_info(hdev, "BCM: Using default device address (%pMR)", @@ -332,6 +334,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = { { 0x2122, "BCM4343A0" }, /* 001.001.034 */ { 0x2209, "BCM43430A1" }, /* 001.002.009 */ { 0x6119, "BCM4345C0" }, /* 003.001.025 */ + { 0x6606, "BCM4345C5" }, /* 003.006.006 */ { 0x230f, "BCM4356A2" }, /* 001.003.015 */ { 0x220e, "BCM20702A1" }, /* 001.002.014 */ { 0x4217, "BCM4329B1" }, /* 002.002.023 */ diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index 0875470a7806f8658c45b2b4a15f6e2b029bf0c2..8cc21ad7cf29d88b35979af0abaf79956d375f53 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -106,8 +106,9 @@ int qca_send_pre_shutdown_cmd(struct hci_dev *hdev) bt_dev_dbg(hdev, "QCA pre shutdown cmd"); - skb = __hci_cmd_sync(hdev, QCA_PRE_SHUTDOWN_CMD, 0, - NULL, HCI_INIT_TIMEOUT); + skb = __hci_cmd_sync_ev(hdev, QCA_PRE_SHUTDOWN_CMD, 0, + NULL, HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { err = PTR_ERR(skb); bt_dev_err(hdev, "QCA preshutdown_cmd failed (%d)", err); diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c index 4f75a9b61d095c45cc362c55be72fc8834633661..bf3c02be69305cbaffb91c07217c0b003e5d1282 100644 --- a/drivers/bluetooth/btrtl.c +++ b/drivers/bluetooth/btrtl.c @@ -178,6 +178,27 @@ static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev, return &ic_id_table[i]; } +static struct sk_buff *btrtl_read_local_version(struct hci_dev *hdev) +{ + struct sk_buff *skb; + + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + rtl_dev_err(hdev, "HCI_OP_READ_LOCAL_VERSION failed (%ld)", + PTR_ERR(skb)); + return skb; + } + + if (skb->len != sizeof(struct hci_rp_read_local_version)) { + rtl_dev_err(hdev, "HCI_OP_READ_LOCAL_VERSION event length mismatch"); + kfree_skb(skb); + return ERR_PTR(-EIO); + } + + return skb; +} + static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) { struct rtl_rom_version_evt *rom_version; @@ -186,19 +207,19 @@ static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) /* Read RTL ROM version command */ skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { - rtl_dev_err(hdev, "Read ROM version failed (%ld)\n", + rtl_dev_err(hdev, "Read ROM version failed (%ld)", PTR_ERR(skb)); return PTR_ERR(skb); } if (skb->len != sizeof(*rom_version)) { - rtl_dev_err(hdev, "RTL version event length mismatch\n"); + rtl_dev_err(hdev, "version event length mismatch"); kfree_skb(skb); return -EIO; } rom_version = (struct rtl_rom_version_evt *)skb->data; - rtl_dev_info(hdev, "rom_version status=%x version=%x\n", + rtl_dev_info(hdev, "rom_version status=%x version=%x", rom_version->status, rom_version->version); *version = rom_version->version; @@ -242,7 +263,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, fwptr = btrtl_dev->fw_data + btrtl_dev->fw_len - sizeof(extension_sig); if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) { - rtl_dev_err(hdev, "extension section signature mismatch\n"); + rtl_dev_err(hdev, "extension section signature mismatch"); return -EINVAL; } @@ -263,7 +284,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, break; if (length == 0) { - rtl_dev_err(hdev, "found instruction with length 0\n"); + rtl_dev_err(hdev, "found instruction with length 0"); return -EINVAL; } @@ -276,7 +297,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, } if (project_id < 0) { - rtl_dev_err(hdev, "failed to find version instruction\n"); + rtl_dev_err(hdev, "failed to find version instruction"); return -EINVAL; } @@ -287,13 +308,13 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, } if (i >= ARRAY_SIZE(project_id_to_lmp_subver)) { - rtl_dev_err(hdev, "unknown project id %d\n", project_id); + rtl_dev_err(hdev, "unknown project id %d", project_id); return -EINVAL; } if (btrtl_dev->ic_info->lmp_subver != project_id_to_lmp_subver[i].lmp_subver) { - rtl_dev_err(hdev, "firmware is for %x but this is a %x\n", + rtl_dev_err(hdev, "firmware is for %x but this is a %x", project_id_to_lmp_subver[i].lmp_subver, btrtl_dev->ic_info->lmp_subver); return -EINVAL; @@ -301,7 +322,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, epatch_info = (struct rtl_epatch_header *)btrtl_dev->fw_data; if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) { - rtl_dev_err(hdev, "bad EPATCH signature\n"); + rtl_dev_err(hdev, "bad EPATCH signature"); return -EINVAL; } @@ -368,6 +389,8 @@ static int rtl_download_firmware(struct hci_dev *hdev, int frag_len = RTL_FRAG_LEN; int ret = 0; int i; + struct sk_buff *skb; + struct hci_rp_read_local_version *rp; dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL); if (!dl_cmd) @@ -378,7 +401,11 @@ static int rtl_download_firmware(struct hci_dev *hdev, BT_DBG("download fw (%d/%d)", i, frag_num); - dl_cmd->index = i; + if (i > 0x7f) + dl_cmd->index = (i & 0x7f) + 1; + else + dl_cmd->index = i; + if (i == (frag_num - 1)) { dl_cmd->index |= 0x80; /* data end */ frag_len = fw_len % RTL_FRAG_LEN; @@ -389,14 +416,14 @@ static int rtl_download_firmware(struct hci_dev *hdev, skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { - rtl_dev_err(hdev, "download fw command failed (%ld)\n", + rtl_dev_err(hdev, "download fw command failed (%ld)", PTR_ERR(skb)); ret = -PTR_ERR(skb); goto out; } if (skb->len != sizeof(struct rtl_download_response)) { - rtl_dev_err(hdev, "download fw event length mismatch\n"); + rtl_dev_err(hdev, "download fw event length mismatch"); kfree_skb(skb); ret = -EIO; goto out; @@ -406,6 +433,18 @@ static int rtl_download_firmware(struct hci_dev *hdev, data += RTL_FRAG_LEN; } + skb = btrtl_read_local_version(hdev); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + rtl_dev_err(hdev, "read local version failed"); + goto out; + } + + rp = (struct hci_rp_read_local_version *)skb->data; + rtl_dev_info(hdev, "fw version 0x%04x%04x", + __le16_to_cpu(rp->hci_rev), __le16_to_cpu(rp->lmp_subver)); + kfree_skb(skb); + out: kfree(dl_cmd); return ret; @@ -416,7 +455,7 @@ static int rtl_load_file(struct hci_dev *hdev, const char *name, u8 **buff) const struct firmware *fw; int ret; - rtl_dev_info(hdev, "rtl: loading %s\n", name); + rtl_dev_info(hdev, "loading %s", name); ret = request_firmware(&fw, name, &hdev->dev); if (ret < 0) return ret; @@ -440,7 +479,7 @@ static int btrtl_setup_rtl8723a(struct hci_dev *hdev, * (which is only for RTL8723B and newer). */ if (!memcmp(btrtl_dev->fw_data, RTL_EPATCH_SIGNATURE, 8)) { - rtl_dev_err(hdev, "unexpected EPATCH signature!\n"); + rtl_dev_err(hdev, "unexpected EPATCH signature!"); return -EINVAL; } @@ -475,7 +514,7 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev, fw_data = tbuff; } - rtl_dev_info(hdev, "cfg_sz %d, total sz %d\n", btrtl_dev->cfg_len, ret); + rtl_dev_info(hdev, "cfg_sz %d, total sz %d", btrtl_dev->cfg_len, ret); ret = rtl_download_firmware(hdev, fw_data, ret); @@ -484,27 +523,6 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev, return ret; } -static struct sk_buff *btrtl_read_local_version(struct hci_dev *hdev) -{ - struct sk_buff *skb; - - skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, - HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - rtl_dev_err(hdev, "HCI_OP_READ_LOCAL_VERSION failed (%ld)\n", - PTR_ERR(skb)); - return skb; - } - - if (skb->len != sizeof(struct hci_rp_read_local_version)) { - rtl_dev_err(hdev, "HCI_OP_READ_LOCAL_VERSION event length mismatch\n"); - kfree_skb(skb); - return ERR_PTR(-EIO); - } - - return skb; -} - void btrtl_free(struct btrtl_device_info *btrtl_dev) { kfree(btrtl_dev->fw_data); @@ -537,7 +555,7 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev, } resp = (struct hci_rp_read_local_version *)skb->data; - rtl_dev_info(hdev, "rtl: examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x lmp_subver=%04x\n", + rtl_dev_info(hdev, "examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x lmp_subver=%04x", resp->hci_ver, resp->hci_rev, resp->lmp_ver, resp->lmp_subver); @@ -550,7 +568,7 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev, hdev->bus); if (!btrtl_dev->ic_info) { - rtl_dev_info(hdev, "rtl: unknown IC info, lmp subver %04x, hci rev %04x, hci ver %04x", + rtl_dev_info(hdev, "unknown IC info, lmp subver %04x, hci rev %04x, hci ver %04x", lmp_subver, hci_rev, hci_ver); return btrtl_dev; } @@ -564,7 +582,7 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev, btrtl_dev->fw_len = rtl_load_file(hdev, btrtl_dev->ic_info->fw_name, &btrtl_dev->fw_data); if (btrtl_dev->fw_len < 0) { - rtl_dev_err(hdev, "firmware file %s not found\n", + rtl_dev_err(hdev, "firmware file %s not found", btrtl_dev->ic_info->fw_name); ret = btrtl_dev->fw_len; goto err_free; @@ -582,7 +600,7 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev, &btrtl_dev->cfg_data); if (btrtl_dev->ic_info->config_needed && btrtl_dev->cfg_len <= 0) { - rtl_dev_err(hdev, "mandatory config file %s not found\n", + rtl_dev_err(hdev, "mandatory config file %s not found", btrtl_dev->ic_info->cfg_name); ret = btrtl_dev->cfg_len; goto err_free; @@ -608,7 +626,7 @@ int btrtl_download_firmware(struct hci_dev *hdev, * to a different value. */ if (!btrtl_dev->ic_info) { - rtl_dev_info(hdev, "rtl: assuming no firmware upload needed\n"); + rtl_dev_info(hdev, "assuming no firmware upload needed"); return 0; } @@ -622,7 +640,7 @@ int btrtl_download_firmware(struct hci_dev *hdev, case RTL_ROM_LMP_8822B: return btrtl_setup_rtl8723b(hdev, btrtl_dev); default: - rtl_dev_info(hdev, "rtl: assuming no firmware upload needed\n"); + rtl_dev_info(hdev, "assuming no firmware upload needed"); return 0; } } @@ -641,6 +659,11 @@ int btrtl_setup_realtek(struct hci_dev *hdev) btrtl_free(btrtl_dev); + /* Enable controller to do both LE scan and BR/EDR inquiry + * simultaneously. + */ + set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); + return ret; } EXPORT_SYMBOL_GPL(btrtl_setup_realtek); @@ -714,18 +737,18 @@ int btrtl_get_uart_settings(struct hci_dev *hdev, total_data_len = btrtl_dev->cfg_len - sizeof(*config); if (total_data_len <= 0) { - rtl_dev_warn(hdev, "no config loaded\n"); + rtl_dev_warn(hdev, "no config loaded"); return -EINVAL; } config = (struct rtl_vendor_config *)btrtl_dev->cfg_data; if (le32_to_cpu(config->signature) != RTL_CONFIG_MAGIC) { - rtl_dev_err(hdev, "invalid config magic\n"); + rtl_dev_err(hdev, "invalid config magic"); return -EINVAL; } if (total_data_len < le16_to_cpu(config->total_len)) { - rtl_dev_err(hdev, "config is too short\n"); + rtl_dev_err(hdev, "config is too short"); return -EINVAL; } @@ -735,7 +758,7 @@ int btrtl_get_uart_settings(struct hci_dev *hdev, switch (le16_to_cpu(entry->offset)) { case 0xc: if (entry->len < sizeof(*device_baudrate)) { - rtl_dev_err(hdev, "invalid UART config entry\n"); + rtl_dev_err(hdev, "invalid UART config entry"); return -EINVAL; } @@ -752,7 +775,7 @@ int btrtl_get_uart_settings(struct hci_dev *hdev, break; default: - rtl_dev_dbg(hdev, "skipping config entry 0x%x (len %u)\n", + rtl_dev_dbg(hdev, "skipping config entry 0x%x (len %u)", le16_to_cpu(entry->offset), entry->len); break; }; @@ -761,13 +784,13 @@ int btrtl_get_uart_settings(struct hci_dev *hdev, } if (!found) { - rtl_dev_err(hdev, "no UART config entry found\n"); + rtl_dev_err(hdev, "no UART config entry found"); return -ENOENT; } - rtl_dev_dbg(hdev, "device baudrate = 0x%08x\n", *device_baudrate); - rtl_dev_dbg(hdev, "controller baudrate = %u\n", *controller_baudrate); - rtl_dev_dbg(hdev, "flow control %d\n", *flow_control); + rtl_dev_dbg(hdev, "device baudrate = 0x%08x", *device_baudrate); + rtl_dev_dbg(hdev, "controller baudrate = %u", *controller_baudrate); + rtl_dev_dbg(hdev, "flow control %d", *flow_control); return 0; } diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index ba41490543040a723bbdb868626225be0612846d..a9c35ebb30f86963009cbf76b30d6582215a15a0 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -438,6 +438,7 @@ static const struct dmi_system_id btusb_needs_reset_resume_table[] = { #define BTUSB_OOB_WAKE_ENABLED 11 #define BTUSB_HW_RESET_ACTIVE 12 #define BTUSB_TX_WAIT_VND_EVT 13 +#define BTUSB_WAKEUP_DISABLE 14 struct btusb_data { struct hci_dev *hdev; @@ -526,6 +527,36 @@ static void btusb_intel_cmd_timeout(struct hci_dev *hdev) gpiod_set_value_cansleep(reset_gpio, 0); } +static void btusb_rtl_cmd_timeout(struct hci_dev *hdev) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + struct gpio_desc *reset_gpio = data->reset_gpio; + + if (++data->cmd_timeout_cnt < 5) + return; + + if (!reset_gpio) { + bt_dev_err(hdev, "No gpio to reset Realtek device, ignoring"); + return; + } + + /* Toggle the hard reset line. The Realtek device is going to + * yank itself off the USB and then replug. The cleanup is handled + * correctly on the way out (standard USB disconnect), and the new + * device is detected cleanly and bound to the driver again like + * it should be. + */ + if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) { + bt_dev_err(hdev, "last reset failed? Not resetting again"); + return; + } + + bt_dev_err(hdev, "Reset Realtek device via gpio"); + gpiod_set_value_cansleep(reset_gpio, 0); + msleep(200); + gpiod_set_value_cansleep(reset_gpio, 1); +} + static inline void btusb_free_frags(struct btusb_data *data) { unsigned long flags; @@ -1174,6 +1205,13 @@ static int btusb_open(struct hci_dev *hdev) data->intf->needs_remote_wakeup = 1; + /* Disable device remote wakeup when host is suspended + * For Realtek chips, global suspend without + * SET_FEATURE (DEVICE_REMOTE_WAKEUP) can save more power in device. + */ + if (test_bit(BTUSB_WAKEUP_DISABLE, &data->flags)) + device_wakeup_disable(&data->udev->dev); + if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags)) goto done; @@ -1237,6 +1275,11 @@ static int btusb_close(struct hci_dev *hdev) goto failed; data->intf->needs_remote_wakeup = 0; + + /* Enable remote wake up for auto-suspend */ + if (test_bit(BTUSB_WAKEUP_DISABLE, &data->flags)) + data->intf->needs_remote_wakeup = 1; + usb_autopm_put_interface(data->intf); failed: @@ -3768,12 +3811,13 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_REALTEK) { hdev->setup = btrtl_setup_realtek; hdev->shutdown = btrtl_shutdown_realtek; + hdev->cmd_timeout = btusb_rtl_cmd_timeout; - /* Realtek devices lose their updated firmware over suspend, - * but the USB hub doesn't notice any status change. - * Explicitly request a device reset on resume. + /* Realtek devices lose their updated firmware over global + * suspend that means host doesn't send SET_FEATURE + * (DEVICE_REMOTE_WAKEUP) */ - interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME; + set_bit(BTUSB_WAKEUP_DISABLE, &data->flags); } #endif @@ -3947,6 +3991,19 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message) enable_irq(data->oob_wake_irq); } + /* For global suspend, Realtek devices lose the loaded fw + * in them. But for autosuspend, firmware should remain. + * Actually, it depends on whether the usb host sends + * set feature (enable wakeup) or not. + */ + if (test_bit(BTUSB_WAKEUP_DISABLE, &data->flags)) { + if (PMSG_IS_AUTO(message) && + device_can_wakeup(&data->udev->dev)) + data->udev->do_remote_wakeup = 1; + else if (!PMSG_IS_AUTO(message)) + data->udev->reset_resume = 1; + } + return 0; } diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index ae2624fce913471bf4c8b4a25f90fcffc0a8b965..7646636f2d183d5c38cdf8d5412afd2373d9886d 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -260,7 +260,7 @@ static int bcm_gpio_set_power(struct bcm_device *dev, bool powered) } /* wait for device to power on and come out of reset */ - usleep_range(10000, 20000); + usleep_range(100000, 120000); dev->res_enabled = powered; @@ -824,6 +824,21 @@ static int bcm_resume(struct device *dev) } #endif +/* Some firmware reports an IRQ which does not work (wrong pin in fw table?) */ +static const struct dmi_system_id bcm_broken_irq_dmi_table[] = { + { + .ident = "Meegopad T08", + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, + "To be filled by OEM."), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "T3 MRD"), + DMI_EXACT_MATCH(DMI_BOARD_VERSION, "V1.1"), + }, + }, + { } +}; + +#ifdef CONFIG_ACPI static const struct acpi_gpio_params first_gpio = { 0, 0, false }; static const struct acpi_gpio_params second_gpio = { 1, 0, false }; static const struct acpi_gpio_params third_gpio = { 2, 0, false }; @@ -842,21 +857,6 @@ static const struct acpi_gpio_mapping acpi_bcm_int_first_gpios[] = { { }, }; -/* Some firmware reports an IRQ which does not work (wrong pin in fw table?) */ -static const struct dmi_system_id bcm_broken_irq_dmi_table[] = { - { - .ident = "Meegopad T08", - .matches = { - DMI_EXACT_MATCH(DMI_BOARD_VENDOR, - "To be filled by OEM."), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "T3 MRD"), - DMI_EXACT_MATCH(DMI_BOARD_VERSION, "V1.1"), - }, - }, - { } -}; - -#ifdef CONFIG_ACPI static int bcm_resource(struct acpi_resource *ares, void *data) { struct bcm_device *dev = data; @@ -1419,6 +1419,7 @@ static void bcm_serdev_remove(struct serdev_device *serdev) #ifdef CONFIG_OF static const struct of_device_id bcm_bluetooth_of_match[] = { { .compatible = "brcm,bcm20702a1" }, + { .compatible = "brcm,bcm4345c5" }, { .compatible = "brcm,bcm4330-bt" }, { .compatible = "brcm,bcm43438-bt" }, { }, diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 31dec435767be3757adcfeadad1ce2cfbcad620a..e3164c200eac5ae0ebd84a6e69b1ec14adeafea9 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -504,26 +504,7 @@ static int qca_open(struct hci_uart *hu) qca->tx_ibs_state = HCI_IBS_TX_ASLEEP; qca->rx_ibs_state = HCI_IBS_RX_ASLEEP; - /* clocks actually on, but we start votes off */ - qca->tx_vote = false; - qca->rx_vote = false; - qca->flags = 0; - - qca->ibs_sent_wacks = 0; - qca->ibs_sent_slps = 0; - qca->ibs_sent_wakes = 0; - qca->ibs_recv_wacks = 0; - qca->ibs_recv_slps = 0; - qca->ibs_recv_wakes = 0; qca->vote_last_jif = jiffies; - qca->vote_on_ms = 0; - qca->vote_off_ms = 0; - qca->votes_on = 0; - qca->votes_off = 0; - qca->tx_votes_on = 0; - qca->tx_votes_off = 0; - qca->rx_votes_on = 0; - qca->rx_votes_off = 0; hu->priv = qca; @@ -1263,6 +1244,11 @@ static int qca_setup(struct hci_uart *hu) /* Patch downloading has to be done without IBS mode */ clear_bit(QCA_IBS_ENABLED, &qca->flags); + /* Enable controller to do both LE scan and BR/EDR inquiry + * simultaneously. + */ + set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); + if (qca_is_wcn399x(soc_type)) { bt_dev_info(hdev, "setting up wcn3990"); @@ -1328,7 +1314,7 @@ static int qca_setup(struct hci_uart *hu) return ret; } -static struct hci_uart_proto qca_proto = { +static const struct hci_uart_proto qca_proto = { .id = HCI_UART_QCA, .name = "QCA", .manufacturer = 29, @@ -1391,6 +1377,8 @@ static int qca_power_off(struct hci_dev *hdev) /* Perform pre shutdown command */ qca_send_pre_shutdown_cmd(hdev); + usleep_range(8000, 10000); + qca_power_shutdown(hu); return 0; } diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 1851112ccc294bcbd36d0fd8c016477c3f95d0cd..6b331061d34b895a7fd96a84e94cabf24c816685 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -29,6 +29,16 @@ config BRCMSTB_GISB_ARB arbiter. This driver provides timeout and target abort error handling and internal bus master decoding. +config MOXTET + tristate "CZ.NIC Turris Mox module configuration bus" + depends on SPI_MASTER && OF + help + Say yes here to add support for the module configuration bus found + on CZ.NIC's Turris Mox. This is needed for the ability to discover + the order in which the modules are connected and to get/set some of + their settings. For example the GPIOs on Mox SFP module are + configured through this bus. + config HISILICON_LPC bool "Support for ISA I/O space on HiSilicon Hip06/7" depends on ARM64 && (ARCH_HISI || COMPILE_TEST) diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index ca300b1914ce24170a4862ea422b526acfeafd4d..16b43d3468c674653c1f422df4849fb6d7e9785d 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_ARM_CCI) += arm-cci.o obj-$(CONFIG_HISILICON_LPC) += hisi_lpc.o obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o +obj-$(CONFIG_MOXTET) += moxtet.o # DPAA2 fsl-mc bus obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/ diff --git a/drivers/bus/fsl-mc/fsl-mc-allocator.c b/drivers/bus/fsl-mc/fsl-mc-allocator.c index 8ad77246f3221fc2e34fb98fa21c95f84099684e..cc7bb900f5249860658a839ae1a79383c018c791 100644 --- a/drivers/bus/fsl-mc/fsl-mc-allocator.c +++ b/drivers/bus/fsl-mc/fsl-mc-allocator.c @@ -330,7 +330,6 @@ void fsl_mc_object_free(struct fsl_mc_device *mc_adev) fsl_mc_resource_free(resource); - device_link_del(mc_adev->consumer_link); mc_adev->consumer_link = NULL; } EXPORT_SYMBOL_GPL(fsl_mc_object_free); diff --git a/drivers/bus/fsl-mc/mc-io.c b/drivers/bus/fsl-mc/mc-io.c index 3ae574a58ccee5369d249cfb603521b32b1093e8..d9629fc13a15538115abb0fc46702087c0d401d7 100644 --- a/drivers/bus/fsl-mc/mc-io.c +++ b/drivers/bus/fsl-mc/mc-io.c @@ -255,7 +255,6 @@ void fsl_mc_portal_free(struct fsl_mc_io *mc_io) fsl_destroy_mc_io(mc_io); fsl_mc_resource_free(resource); - device_link_del(dpmcp_dev->consumer_link); dpmcp_dev->consumer_link = NULL; } EXPORT_SYMBOL_GPL(fsl_mc_portal_free); diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c index db74334ca5ef003ed587c5cccb63363abb30750d..28bb65a5613fd282dc735b5c516d9d2dabc302cd 100644 --- a/drivers/bus/imx-weim.c +++ b/drivers/bus/imx-weim.c @@ -19,6 +19,8 @@ struct imx_weim_devtype { unsigned int cs_count; unsigned int cs_regs_count; unsigned int cs_stride; + unsigned int wcr_offset; + unsigned int wcr_bcm; }; static const struct imx_weim_devtype imx1_weim_devtype = { @@ -37,6 +39,8 @@ static const struct imx_weim_devtype imx50_weim_devtype = { .cs_count = 4, .cs_regs_count = 6, .cs_stride = 0x18, + .wcr_offset = 0x90, + .wcr_bcm = BIT(0), }; static const struct imx_weim_devtype imx51_weim_devtype = { @@ -72,7 +76,7 @@ static const struct of_device_id weim_id_table[] = { }; MODULE_DEVICE_TABLE(of, weim_id_table); -static int __init imx_weim_gpr_setup(struct platform_device *pdev) +static int imx_weim_gpr_setup(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct property *prop; @@ -122,10 +126,10 @@ static int __init imx_weim_gpr_setup(struct platform_device *pdev) } /* Parse and set the timing for this device. */ -static int __init weim_timing_setup(struct device *dev, - struct device_node *np, void __iomem *base, - const struct imx_weim_devtype *devtype, - struct cs_timing_state *ts) +static int weim_timing_setup(struct device *dev, + struct device_node *np, void __iomem *base, + const struct imx_weim_devtype *devtype, + struct cs_timing_state *ts) { u32 cs_idx, value[MAX_CS_REGS_COUNT]; int i, ret; @@ -183,8 +187,7 @@ static int __init weim_timing_setup(struct device *dev, return 0; } -static int __init weim_parse_dt(struct platform_device *pdev, - void __iomem *base) +static int weim_parse_dt(struct platform_device *pdev, void __iomem *base) { const struct of_device_id *of_id = of_match_device(weim_id_table, &pdev->dev); @@ -192,6 +195,7 @@ static int __init weim_parse_dt(struct platform_device *pdev, struct device_node *child; int ret, have_child = 0; struct cs_timing_state ts = {}; + u32 reg; if (devtype == &imx50_weim_devtype) { ret = imx_weim_gpr_setup(pdev); @@ -199,6 +203,17 @@ static int __init weim_parse_dt(struct platform_device *pdev, return ret; } + if (of_property_read_bool(pdev->dev.of_node, "fsl,burst-clk-enable")) { + if (devtype->wcr_bcm) { + reg = readl(base + devtype->wcr_offset); + writel(reg | devtype->wcr_bcm, + base + devtype->wcr_offset); + } else { + dev_err(&pdev->dev, "burst clk mode not supported.\n"); + return -EINVAL; + } + } + for_each_available_child_of_node(pdev->dev.of_node, child) { ret = weim_timing_setup(&pdev->dev, child, base, devtype, &ts); if (ret) @@ -217,7 +232,7 @@ static int __init weim_parse_dt(struct platform_device *pdev, return ret; } -static int __init weim_probe(struct platform_device *pdev) +static int weim_probe(struct platform_device *pdev) { struct resource *res; struct clk *clk; @@ -254,8 +269,9 @@ static struct platform_driver weim_driver = { .name = "imx-weim", .of_match_table = weim_id_table, }, + .probe = weim_probe, }; -module_platform_driver_probe(weim_driver, weim_probe); +module_platform_driver(weim_driver); MODULE_AUTHOR("Freescale Semiconductor Inc."); MODULE_DESCRIPTION("i.MX EIM Controller Driver"); diff --git a/drivers/bus/moxtet.c b/drivers/bus/moxtet.c new file mode 100644 index 0000000000000000000000000000000000000000..36cf13eee6b8ba9af71747cc6bd2e0e7eab0a01b --- /dev/null +++ b/drivers/bus/moxtet.c @@ -0,0 +1,885 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Turris Mox module configuration bus driver + * + * Copyright (C) 2019 Marek Behun + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * @name: module name for sysfs + * @hwirq_base: base index for IRQ for this module (-1 if no IRQs) + * @nirqs: how many interrupts does the shift register provide + * @desc: module description for kernel log + */ +static const struct { + const char *name; + int hwirq_base; + int nirqs; + const char *desc; +} mox_module_table[] = { + /* do not change order of this array! */ + { NULL, 0, 0, NULL }, + { "sfp", -1, 0, "MOX D (SFP cage)" }, + { "pci", MOXTET_IRQ_PCI, 1, "MOX B (Mini-PCIe)" }, + { "topaz", MOXTET_IRQ_TOPAZ, 1, "MOX C (4 port switch)" }, + { "peridot", MOXTET_IRQ_PERIDOT(0), 1, "MOX E (8 port switch)" }, + { "usb3", MOXTET_IRQ_USB3, 2, "MOX F (USB 3.0)" }, + { "pci-bridge", -1, 0, "MOX G (Mini-PCIe bridge)" }, +}; + +static inline bool mox_module_known(unsigned int id) +{ + return id >= TURRIS_MOX_MODULE_FIRST && id <= TURRIS_MOX_MODULE_LAST; +} + +static inline const char *mox_module_name(unsigned int id) +{ + if (mox_module_known(id)) + return mox_module_table[id].name; + else + return "unknown"; +} + +#define DEF_MODULE_ATTR(name, fmt, ...) \ +static ssize_t \ +module_##name##_show(struct device *dev, struct device_attribute *a, \ + char *buf) \ +{ \ + struct moxtet_device *mdev = to_moxtet_device(dev); \ + return sprintf(buf, (fmt), __VA_ARGS__); \ +} \ +static DEVICE_ATTR_RO(module_##name) + +DEF_MODULE_ATTR(id, "0x%x\n", mdev->id); +DEF_MODULE_ATTR(name, "%s\n", mox_module_name(mdev->id)); +DEF_MODULE_ATTR(description, "%s\n", + mox_module_known(mdev->id) ? mox_module_table[mdev->id].desc + : ""); + +static struct attribute *moxtet_dev_attrs[] = { + &dev_attr_module_id.attr, + &dev_attr_module_name.attr, + &dev_attr_module_description.attr, + NULL, +}; + +static const struct attribute_group moxtet_dev_group = { + .attrs = moxtet_dev_attrs, +}; + +static const struct attribute_group *moxtet_dev_groups[] = { + &moxtet_dev_group, + NULL, +}; + +static int moxtet_match(struct device *dev, struct device_driver *drv) +{ + struct moxtet_device *mdev = to_moxtet_device(dev); + struct moxtet_driver *tdrv = to_moxtet_driver(drv); + const enum turris_mox_module_id *t; + + if (of_driver_match_device(dev, drv)) + return 1; + + if (!tdrv->id_table) + return 0; + + for (t = tdrv->id_table; *t; ++t) + if (*t == mdev->id) + return 1; + + return 0; +} + +struct bus_type moxtet_bus_type = { + .name = "moxtet", + .dev_groups = moxtet_dev_groups, + .match = moxtet_match, +}; +EXPORT_SYMBOL_GPL(moxtet_bus_type); + +int __moxtet_register_driver(struct module *owner, + struct moxtet_driver *mdrv) +{ + mdrv->driver.owner = owner; + mdrv->driver.bus = &moxtet_bus_type; + return driver_register(&mdrv->driver); +} +EXPORT_SYMBOL_GPL(__moxtet_register_driver); + +static int moxtet_dev_check(struct device *dev, void *data) +{ + struct moxtet_device *mdev = to_moxtet_device(dev); + struct moxtet_device *new_dev = data; + + if (mdev->moxtet == new_dev->moxtet && mdev->id == new_dev->id && + mdev->idx == new_dev->idx) + return -EBUSY; + return 0; +} + +static void moxtet_dev_release(struct device *dev) +{ + struct moxtet_device *mdev = to_moxtet_device(dev); + + put_device(mdev->moxtet->dev); + kfree(mdev); +} + +static struct moxtet_device * +moxtet_alloc_device(struct moxtet *moxtet) +{ + struct moxtet_device *dev; + + if (!get_device(moxtet->dev)) + return NULL; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + put_device(moxtet->dev); + return NULL; + } + + dev->moxtet = moxtet; + dev->dev.parent = moxtet->dev; + dev->dev.bus = &moxtet_bus_type; + dev->dev.release = moxtet_dev_release; + + device_initialize(&dev->dev); + + return dev; +} + +static int moxtet_add_device(struct moxtet_device *dev) +{ + static DEFINE_MUTEX(add_mutex); + int ret; + + if (dev->idx >= TURRIS_MOX_MAX_MODULES || dev->id > 0xf) + return -EINVAL; + + dev_set_name(&dev->dev, "moxtet-%s.%u", mox_module_name(dev->id), + dev->idx); + + mutex_lock(&add_mutex); + + ret = bus_for_each_dev(&moxtet_bus_type, NULL, dev, + moxtet_dev_check); + if (ret) + goto done; + + ret = device_add(&dev->dev); + if (ret < 0) + dev_err(dev->moxtet->dev, "can't add %s, status %d\n", + dev_name(dev->moxtet->dev), ret); + +done: + mutex_unlock(&add_mutex); + return ret; +} + +static int __unregister(struct device *dev, void *null) +{ + if (dev->of_node) { + of_node_clear_flag(dev->of_node, OF_POPULATED); + of_node_put(dev->of_node); + } + + device_unregister(dev); + + return 0; +} + +static struct moxtet_device * +of_register_moxtet_device(struct moxtet *moxtet, struct device_node *nc) +{ + struct moxtet_device *dev; + u32 val; + int ret; + + dev = moxtet_alloc_device(moxtet); + if (!dev) { + dev_err(moxtet->dev, + "Moxtet device alloc error for %pOF\n", nc); + return ERR_PTR(-ENOMEM); + } + + ret = of_property_read_u32(nc, "reg", &val); + if (ret) { + dev_err(moxtet->dev, "%pOF has no valid 'reg' property (%d)\n", + nc, ret); + goto err_put; + } + + dev->idx = val; + + if (dev->idx >= TURRIS_MOX_MAX_MODULES) { + dev_err(moxtet->dev, "%pOF Moxtet address 0x%x out of range\n", + nc, dev->idx); + ret = -EINVAL; + goto err_put; + } + + dev->id = moxtet->modules[dev->idx]; + + if (!dev->id) { + dev_err(moxtet->dev, "%pOF Moxtet address 0x%x is empty\n", nc, + dev->idx); + ret = -ENODEV; + goto err_put; + } + + of_node_get(nc); + dev->dev.of_node = nc; + + ret = moxtet_add_device(dev); + if (ret) { + dev_err(moxtet->dev, + "Moxtet device register error for %pOF\n", nc); + of_node_put(nc); + goto err_put; + } + + return dev; + +err_put: + put_device(&dev->dev); + return ERR_PTR(ret); +} + +static void of_register_moxtet_devices(struct moxtet *moxtet) +{ + struct moxtet_device *dev; + struct device_node *nc; + + if (!moxtet->dev->of_node) + return; + + for_each_available_child_of_node(moxtet->dev->of_node, nc) { + if (of_node_test_and_set_flag(nc, OF_POPULATED)) + continue; + dev = of_register_moxtet_device(moxtet, nc); + if (IS_ERR(dev)) { + dev_warn(moxtet->dev, + "Failed to create Moxtet device for %pOF\n", + nc); + of_node_clear_flag(nc, OF_POPULATED); + } + } +} + +static void +moxtet_register_devices_from_topology(struct moxtet *moxtet) +{ + struct moxtet_device *dev; + int i, ret; + + for (i = 0; i < moxtet->count; ++i) { + dev = moxtet_alloc_device(moxtet); + if (!dev) { + dev_err(moxtet->dev, "Moxtet device %u alloc error\n", + i); + continue; + } + + dev->idx = i; + dev->id = moxtet->modules[i]; + + ret = moxtet_add_device(dev); + if (ret && ret != -EBUSY) { + put_device(&dev->dev); + dev_err(moxtet->dev, + "Moxtet device %u register error: %i\n", i, + ret); + } + } +} + +/* + * @nsame: how many modules with same id are already in moxtet->modules + */ +static int moxtet_set_irq(struct moxtet *moxtet, int idx, int id, int nsame) +{ + int i, first; + struct moxtet_irqpos *pos; + + first = mox_module_table[id].hwirq_base + + nsame * mox_module_table[id].nirqs; + + if (first + mox_module_table[id].nirqs > MOXTET_NIRQS) + return -EINVAL; + + for (i = 0; i < mox_module_table[id].nirqs; ++i) { + pos = &moxtet->irq.position[first + i]; + pos->idx = idx; + pos->bit = i; + moxtet->irq.exists |= BIT(first + i); + } + + return 0; +} + +static int moxtet_find_topology(struct moxtet *moxtet) +{ + u8 buf[TURRIS_MOX_MAX_MODULES]; + int cnts[TURRIS_MOX_MODULE_LAST]; + int i, ret; + + memset(cnts, 0, sizeof(cnts)); + + ret = spi_read(to_spi_device(moxtet->dev), buf, TURRIS_MOX_MAX_MODULES); + if (ret < 0) + return ret; + + if (buf[0] == TURRIS_MOX_CPU_ID_EMMC) { + dev_info(moxtet->dev, "Found MOX A (eMMC CPU) module\n"); + } else if (buf[0] == TURRIS_MOX_CPU_ID_SD) { + dev_info(moxtet->dev, "Found MOX A (CPU) module\n"); + } else { + dev_err(moxtet->dev, "Invalid Turris MOX A CPU module 0x%02x\n", + buf[0]); + return -ENODEV; + } + + moxtet->count = 0; + + for (i = 1; i < TURRIS_MOX_MAX_MODULES; ++i) { + int id; + + if (buf[i] == 0xff) + break; + + id = buf[i] & 0xf; + + moxtet->modules[i-1] = id; + ++moxtet->count; + + if (mox_module_known(id)) { + dev_info(moxtet->dev, "Found %s module\n", + mox_module_table[id].desc); + + if (moxtet_set_irq(moxtet, i-1, id, cnts[id]++) < 0) + dev_err(moxtet->dev, + " Cannot set IRQ for module %s\n", + mox_module_table[id].desc); + } else { + dev_warn(moxtet->dev, + "Unknown Moxtet module found (ID 0x%02x)\n", + id); + } + } + + return 0; +} + +static int moxtet_spi_read(struct moxtet *moxtet, u8 *buf) +{ + struct spi_transfer xfer = { + .rx_buf = buf, + .tx_buf = moxtet->tx, + .len = moxtet->count + 1 + }; + int ret; + + mutex_lock(&moxtet->lock); + + ret = spi_sync_transfer(to_spi_device(moxtet->dev), &xfer, 1); + + mutex_unlock(&moxtet->lock); + + return ret; +} + +int moxtet_device_read(struct device *dev) +{ + struct moxtet_device *mdev = to_moxtet_device(dev); + struct moxtet *moxtet = mdev->moxtet; + u8 buf[TURRIS_MOX_MAX_MODULES]; + int ret; + + if (mdev->idx >= moxtet->count) + return -EINVAL; + + ret = moxtet_spi_read(moxtet, buf); + if (ret < 0) + return ret; + + return buf[mdev->idx + 1] >> 4; +} +EXPORT_SYMBOL_GPL(moxtet_device_read); + +int moxtet_device_write(struct device *dev, u8 val) +{ + struct moxtet_device *mdev = to_moxtet_device(dev); + struct moxtet *moxtet = mdev->moxtet; + int ret; + + if (mdev->idx >= moxtet->count) + return -EINVAL; + + mutex_lock(&moxtet->lock); + + moxtet->tx[moxtet->count - mdev->idx] = val; + + ret = spi_write(to_spi_device(moxtet->dev), moxtet->tx, + moxtet->count + 1); + + mutex_unlock(&moxtet->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(moxtet_device_write); + +int moxtet_device_written(struct device *dev) +{ + struct moxtet_device *mdev = to_moxtet_device(dev); + struct moxtet *moxtet = mdev->moxtet; + + if (mdev->idx >= moxtet->count) + return -EINVAL; + + return moxtet->tx[moxtet->count - mdev->idx]; +} +EXPORT_SYMBOL_GPL(moxtet_device_written); + +#ifdef CONFIG_DEBUG_FS +static int moxtet_debug_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + + return nonseekable_open(inode, file); +} + +static ssize_t input_read(struct file *file, char __user *buf, size_t len, + loff_t *ppos) +{ + struct moxtet *moxtet = file->private_data; + u8 bin[TURRIS_MOX_MAX_MODULES]; + u8 hex[sizeof(buf) * 2 + 1]; + int ret, n; + + ret = moxtet_spi_read(moxtet, bin); + if (ret < 0) + return ret; + + n = moxtet->count + 1; + bin2hex(hex, bin, n); + + hex[2*n] = '\n'; + + return simple_read_from_buffer(buf, len, ppos, hex, 2*n + 1); +} + +static const struct file_operations input_fops = { + .owner = THIS_MODULE, + .open = moxtet_debug_open, + .read = input_read, + .llseek = no_llseek, +}; + +static ssize_t output_read(struct file *file, char __user *buf, size_t len, + loff_t *ppos) +{ + struct moxtet *moxtet = file->private_data; + u8 hex[TURRIS_MOX_MAX_MODULES * 2 + 1]; + u8 *p = hex; + int i; + + mutex_lock(&moxtet->lock); + + for (i = 0; i < moxtet->count; ++i) + p = hex_byte_pack(p, moxtet->tx[moxtet->count - i]); + + mutex_unlock(&moxtet->lock); + + *p++ = '\n'; + + return simple_read_from_buffer(buf, len, ppos, hex, p - hex); +} + +static ssize_t output_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct moxtet *moxtet = file->private_data; + u8 bin[TURRIS_MOX_MAX_MODULES]; + u8 hex[sizeof(bin) * 2 + 1]; + ssize_t res; + loff_t dummy = 0; + int err, i; + + if (len > 2 * moxtet->count + 1 || len < 2 * moxtet->count) + return -EINVAL; + + res = simple_write_to_buffer(hex, sizeof(hex), &dummy, buf, len); + if (res < 0) + return res; + + if (len % 2 == 1 && hex[len - 1] != '\n') + return -EINVAL; + + err = hex2bin(bin, hex, moxtet->count); + if (err < 0) + return -EINVAL; + + mutex_lock(&moxtet->lock); + + for (i = 0; i < moxtet->count; ++i) + moxtet->tx[moxtet->count - i] = bin[i]; + + err = spi_write(to_spi_device(moxtet->dev), moxtet->tx, + moxtet->count + 1); + + mutex_unlock(&moxtet->lock); + + return err < 0 ? err : len; +} + +static const struct file_operations output_fops = { + .owner = THIS_MODULE, + .open = moxtet_debug_open, + .read = output_read, + .write = output_write, + .llseek = no_llseek, +}; + +static int moxtet_register_debugfs(struct moxtet *moxtet) +{ + struct dentry *root, *entry; + + root = debugfs_create_dir("moxtet", NULL); + + if (IS_ERR(root)) + return PTR_ERR(root); + + entry = debugfs_create_file_unsafe("input", 0444, root, moxtet, + &input_fops); + if (IS_ERR(entry)) + goto err_remove; + + entry = debugfs_create_file_unsafe("output", 0644, root, moxtet, + &output_fops); + if (IS_ERR(entry)) + goto err_remove; + + moxtet->debugfs_root = root; + + return 0; +err_remove: + debugfs_remove_recursive(root); + return PTR_ERR(entry); +} + +static void moxtet_unregister_debugfs(struct moxtet *moxtet) +{ + debugfs_remove_recursive(moxtet->debugfs_root); +} +#else +static inline int moxtet_register_debugfs(struct moxtet *moxtet) +{ + return 0; +} + +static inline void moxtet_unregister_debugfs(struct moxtet *moxtet) +{ +} +#endif + +static int moxtet_irq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + struct moxtet *moxtet = d->host_data; + + if (hw >= MOXTET_NIRQS || !(moxtet->irq.exists & BIT(hw))) { + dev_err(moxtet->dev, "Invalid hw irq number\n"); + return -EINVAL; + } + + irq_set_chip_data(irq, d->host_data); + irq_set_chip_and_handler(irq, &moxtet->irq.chip, handle_level_irq); + + return 0; +} + +static int moxtet_irq_domain_xlate(struct irq_domain *d, + struct device_node *ctrlr, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + struct moxtet *moxtet = d->host_data; + int irq; + + if (WARN_ON(intsize < 1)) + return -EINVAL; + + irq = intspec[0]; + + if (irq >= MOXTET_NIRQS || !(moxtet->irq.exists & BIT(irq))) + return -EINVAL; + + *out_hwirq = irq; + *out_type = IRQ_TYPE_NONE; + return 0; +} + +static const struct irq_domain_ops moxtet_irq_domain = { + .map = moxtet_irq_domain_map, + .xlate = moxtet_irq_domain_xlate, +}; + +static void moxtet_irq_mask(struct irq_data *d) +{ + struct moxtet *moxtet = irq_data_get_irq_chip_data(d); + + moxtet->irq.masked |= BIT(d->hwirq); +} + +static void moxtet_irq_unmask(struct irq_data *d) +{ + struct moxtet *moxtet = irq_data_get_irq_chip_data(d); + + moxtet->irq.masked &= ~BIT(d->hwirq); +} + +static void moxtet_irq_print_chip(struct irq_data *d, struct seq_file *p) +{ + struct moxtet *moxtet = irq_data_get_irq_chip_data(d); + struct moxtet_irqpos *pos = &moxtet->irq.position[d->hwirq]; + int id; + + id = moxtet->modules[pos->idx]; + + seq_printf(p, " moxtet-%s.%i#%i", mox_module_name(id), pos->idx, + pos->bit); +} + +static const struct irq_chip moxtet_irq_chip = { + .name = "moxtet", + .irq_mask = moxtet_irq_mask, + .irq_unmask = moxtet_irq_unmask, + .irq_print_chip = moxtet_irq_print_chip, +}; + +static int moxtet_irq_read(struct moxtet *moxtet, unsigned long *map) +{ + struct moxtet_irqpos *pos = moxtet->irq.position; + u8 buf[TURRIS_MOX_MAX_MODULES]; + int i, ret; + + ret = moxtet_spi_read(moxtet, buf); + if (ret < 0) + return ret; + + *map = 0; + + for_each_set_bit(i, &moxtet->irq.exists, MOXTET_NIRQS) { + if (!(buf[pos[i].idx + 1] & BIT(4 + pos[i].bit))) + set_bit(i, map); + } + + return 0; +} + +static irqreturn_t moxtet_irq_thread_fn(int irq, void *data) +{ + struct moxtet *moxtet = data; + unsigned long set; + int nhandled = 0, i, sub_irq, ret; + + ret = moxtet_irq_read(moxtet, &set); + if (ret < 0) + goto out; + + set &= ~moxtet->irq.masked; + + do { + for_each_set_bit(i, &set, MOXTET_NIRQS) { + sub_irq = irq_find_mapping(moxtet->irq.domain, i); + handle_nested_irq(sub_irq); + dev_dbg(moxtet->dev, "%i irq\n", i); + ++nhandled; + } + + ret = moxtet_irq_read(moxtet, &set); + if (ret < 0) + goto out; + + set &= ~moxtet->irq.masked; + } while (set); + +out: + return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); +} + +static void moxtet_irq_free(struct moxtet *moxtet) +{ + int i, irq; + + for (i = 0; i < MOXTET_NIRQS; ++i) { + if (moxtet->irq.exists & BIT(i)) { + irq = irq_find_mapping(moxtet->irq.domain, i); + irq_dispose_mapping(irq); + } + } + + irq_domain_remove(moxtet->irq.domain); +} + +static int moxtet_irq_setup(struct moxtet *moxtet) +{ + int i, ret; + + moxtet->irq.domain = irq_domain_add_simple(moxtet->dev->of_node, + MOXTET_NIRQS, 0, + &moxtet_irq_domain, moxtet); + if (moxtet->irq.domain == NULL) { + dev_err(moxtet->dev, "Could not add IRQ domain\n"); + return -ENOMEM; + } + + for (i = 0; i < MOXTET_NIRQS; ++i) + if (moxtet->irq.exists & BIT(i)) + irq_create_mapping(moxtet->irq.domain, i); + + moxtet->irq.chip = moxtet_irq_chip; + moxtet->irq.masked = ~0; + + ret = request_threaded_irq(moxtet->dev_irq, NULL, moxtet_irq_thread_fn, + IRQF_ONESHOT, "moxtet", moxtet); + if (ret < 0) + goto err_free; + + return 0; + +err_free: + moxtet_irq_free(moxtet); + return ret; +} + +static int moxtet_probe(struct spi_device *spi) +{ + struct moxtet *moxtet; + int ret; + + ret = spi_setup(spi); + if (ret < 0) + return ret; + + moxtet = devm_kzalloc(&spi->dev, sizeof(struct moxtet), + GFP_KERNEL); + if (!moxtet) + return -ENOMEM; + + moxtet->dev = &spi->dev; + spi_set_drvdata(spi, moxtet); + + mutex_init(&moxtet->lock); + + moxtet->dev_irq = of_irq_get(moxtet->dev->of_node, 0); + if (moxtet->dev_irq == -EPROBE_DEFER) + return -EPROBE_DEFER; + + if (moxtet->dev_irq <= 0) { + dev_err(moxtet->dev, "No IRQ resource found\n"); + return -ENXIO; + } + + ret = moxtet_find_topology(moxtet); + if (ret < 0) + return ret; + + if (moxtet->irq.exists) { + ret = moxtet_irq_setup(moxtet); + if (ret < 0) + return ret; + } + + of_register_moxtet_devices(moxtet); + moxtet_register_devices_from_topology(moxtet); + + ret = moxtet_register_debugfs(moxtet); + if (ret < 0) + dev_warn(moxtet->dev, "Failed creating debugfs entries: %i\n", + ret); + + return 0; +} + +static int moxtet_remove(struct spi_device *spi) +{ + struct moxtet *moxtet = spi_get_drvdata(spi); + + free_irq(moxtet->dev_irq, moxtet); + + moxtet_irq_free(moxtet); + + moxtet_unregister_debugfs(moxtet); + + device_for_each_child(moxtet->dev, NULL, __unregister); + + mutex_destroy(&moxtet->lock); + + return 0; +} + +static const struct of_device_id moxtet_dt_ids[] = { + { .compatible = "cznic,moxtet" }, + {}, +}; +MODULE_DEVICE_TABLE(of, moxtet_dt_ids); + +static struct spi_driver moxtet_spi_driver = { + .driver = { + .name = "moxtet", + .of_match_table = moxtet_dt_ids, + }, + .probe = moxtet_probe, + .remove = moxtet_remove, +}; + +static int __init moxtet_init(void) +{ + int ret; + + ret = bus_register(&moxtet_bus_type); + if (ret < 0) { + pr_err("moxtet bus registration failed: %d\n", ret); + goto error; + } + + ret = spi_register_driver(&moxtet_spi_driver); + if (ret < 0) { + pr_err("moxtet spi driver registration failed: %d\n", ret); + goto error_bus; + } + + return 0; + +error_bus: + bus_unregister(&moxtet_bus_type); +error: + return ret; +} +postcore_initcall_sync(moxtet_init); + +static void __exit moxtet_exit(void) +{ + spi_unregister_driver(&moxtet_spi_driver); + bus_unregister(&moxtet_bus_type); +} +module_exit(moxtet_exit); + +MODULE_AUTHOR("Marek Behun "); +MODULE_DESCRIPTION("CZ.NIC's Turris Mox module configuration bus"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c index 1b76d958590275daa6b9c2f8c69ecd2d51655da7..be79d6c6a4e458bc330467af1c0e150125526242 100644 --- a/drivers/bus/sunxi-rsb.c +++ b/drivers/bus/sunxi-rsb.c @@ -651,10 +651,8 @@ static int sunxi_rsb_probe(struct platform_device *pdev) return PTR_ERR(rsb->regs); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "failed to retrieve irq: %d\n", irq); + if (irq < 0) return irq; - } rsb->clk = devm_clk_get(dev, NULL); if (IS_ERR(rsb->clk)) { diff --git a/drivers/bus/uniphier-system-bus.c b/drivers/bus/uniphier-system-bus.c index e845c1a93f2106eca5eda8f3438b68c8a10118de..f70dedace20b4ec4c06535453d419f7d00b9e1c2 100644 --- a/drivers/bus/uniphier-system-bus.c +++ b/drivers/bus/uniphier-system-bus.c @@ -176,7 +176,6 @@ static int uniphier_system_bus_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct uniphier_system_bus_priv *priv; - struct resource *regs; const __be32 *ranges; u32 cells, addr, size; u64 paddr; @@ -186,8 +185,7 @@ static int uniphier_system_bus_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->membase = devm_ioremap_resource(dev, regs); + priv->membase = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->membase)) return PTR_ERR(priv->membase); diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 3e866885a40513596148b9c5a5a0db5add1c42ff..df0fc997dc3e302e5a184924bc7fb8f6d4b10585 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -26,28 +26,6 @@ config DEVKMEM kind of kernel debugging operations. When in doubt, say "N". -config SGI_SNSC - bool "SGI Altix system controller communication support" - depends on (IA64_SGI_SN2 || IA64_GENERIC) - help - If you have an SGI Altix and you want to enable system - controller communication from user space (you want this!), - say Y. Otherwise, say N. - -config SGI_TIOCX - bool "SGI TIO CX driver support" - depends on (IA64_SGI_SN2 || IA64_GENERIC) - help - If you have an SGI Altix and you have fpga devices attached - to your TIO, say Y here, otherwise say N. - -config SGI_MBCS - tristate "SGI FPGA Core Services driver support" - depends on SGI_TIOCX - help - If you have an SGI Altix with an attached SABrick - say Y or M here, otherwise say N. - source "drivers/tty/serial/Kconfig" source "drivers/tty/serdev/Kconfig" @@ -573,3 +551,12 @@ config RANDOM_TRUST_CPU has not installed a hidden back door to compromise the CPU's random number generation facilities. This can also be configured at boot with "random.trust_cpu=on/off". + +config RANDOM_TRUST_BOOTLOADER + bool "Trust the bootloader to initialize Linux's CRNG" + help + Some bootloaders can provide entropy to increase the kernel's initial + device randomness. Say Y here to assume the entropy provided by the + booloader is trustworthy so it will be added to the kernel's entropy + pool. Otherwise, say N here so it will be regarded as device input that + only mixes the entropy pool. \ No newline at end of file diff --git a/drivers/char/Makefile b/drivers/char/Makefile index fbea7dd129326c806e11c342c7a1c6cad6d2bff6..7c5ea6f9df14555a59dffdf52d48ac42f2aa10ed 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -9,11 +9,9 @@ obj-y += misc.o obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o -obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o obj-$(CONFIG_MSPEC) += mspec.o obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o obj-$(CONFIG_IBM_BSR) += bsr.o -obj-$(CONFIG_SGI_MBCS) += mbcs.o obj-$(CONFIG_PRINTER) += lp.o diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 6231714ef3c8f95ec99769db5a2e75731e29dee3..812d6aa6e013676479133cba5e8936aad04cb8e8 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -111,14 +111,14 @@ config AGP_VIA config AGP_I460 tristate "Intel 460GX chipset support" - depends on AGP && (IA64_DIG || IA64_GENERIC) + depends on AGP && IA64 help This option gives you AGP GART support for the Intel 460GX chipset for IA64 processors. config AGP_HP_ZX1 tristate "HP ZX1 chipset AGP support" - depends on AGP && (IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB || IA64_GENERIC) + depends on AGP && IA64 help This option gives you AGP GART support for the HP ZX1 chipset for IA64 processors. @@ -150,13 +150,6 @@ config AGP_EFFICEON This option gives you AGP support for the Transmeta Efficeon series processors with integrated northbridges. -config AGP_SGI_TIOCA - tristate "SGI TIO chipset AGP support" - depends on AGP && (IA64_SGI_SN2 || IA64_GENERIC) - help - This option gives you AGP GART support for the SGI TIO chipset - for IA64 processors. - config INTEL_GTT tristate depends on X86 && PCI diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile index 4a786ffd9dee80ae0a1195003a2133dd73f254fe..cb2497d157f613046f420f08a5c7d4059d819489 100644 --- a/drivers/char/agp/Makefile +++ b/drivers/char/agp/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_AGP_I460) += i460-agp.o obj-$(CONFIG_AGP_INTEL) += intel-agp.o obj-$(CONFIG_INTEL_GTT) += intel-gtt.o obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o -obj-$(CONFIG_AGP_SGI_TIOCA) += sgi-agp.o obj-$(CONFIG_AGP_SIS) += sis-agp.o obj-$(CONFIG_AGP_SWORKS) += sworks-agp.o obj-$(CONFIG_AGP_UNINORTH) += uninorth-agp.o diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c deleted file mode 100644 index e7d5bdc02d93d75daa05be0aabf370d073325028..0000000000000000000000000000000000000000 --- a/drivers/char/agp/sgi-agp.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2003-2005 Silicon Graphics, Inc. All Rights Reserved. - */ - -/* - * SGI TIOCA AGPGART routines. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "agp.h" - -extern int agp_memory_reserved; -extern uint32_t tioca_gart_found; -extern struct list_head tioca_list; -static struct agp_bridge_data **sgi_tioca_agp_bridges; - -/* - * The aperature size and related information is set up at TIOCA init time. - * Values for this table will be extracted and filled in at - * sgi_tioca_fetch_size() time. - */ - -static struct aper_size_info_fixed sgi_tioca_sizes[] = { - {0, 0, 0}, -}; - -static struct page *sgi_tioca_alloc_page(struct agp_bridge_data *bridge) -{ - struct page *page; - int nid; - struct tioca_kernel *info = - (struct tioca_kernel *)bridge->dev_private_data; - - nid = info->ca_closest_node; - page = alloc_pages_node(nid, GFP_KERNEL, 0); - if (!page) - return NULL; - - get_page(page); - atomic_inc(&agp_bridge->current_memory_agp); - return page; -} - -/* - * Flush GART tlb's. Cannot selectively flush based on memory so the mem - * arg is ignored. - */ - -static void sgi_tioca_tlbflush(struct agp_memory *mem) -{ - tioca_tlbflush(mem->bridge->dev_private_data); -} - -/* - * Given an address of a host physical page, turn it into a valid gart - * entry. - */ -static unsigned long -sgi_tioca_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr, - int type) -{ - return tioca_physpage_to_gart(addr); -} - -static void sgi_tioca_agp_enable(struct agp_bridge_data *bridge, u32 mode) -{ - tioca_fastwrite_enable(bridge->dev_private_data); -} - -/* - * sgi_tioca_configure() doesn't have anything to do since the base CA driver - * has alreay set up the GART. - */ - -static int sgi_tioca_configure(void) -{ - return 0; -} - -/* - * Determine gfx aperature size. This has already been determined by the - * CA driver init, so just need to set agp_bridge values accordingly. - */ - -static int sgi_tioca_fetch_size(void) -{ - struct tioca_kernel *info = - (struct tioca_kernel *)agp_bridge->dev_private_data; - - sgi_tioca_sizes[0].size = info->ca_gfxap_size / MB(1); - sgi_tioca_sizes[0].num_entries = info->ca_gfxgart_entries; - - return sgi_tioca_sizes[0].size; -} - -static int sgi_tioca_create_gatt_table(struct agp_bridge_data *bridge) -{ - struct tioca_kernel *info = - (struct tioca_kernel *)bridge->dev_private_data; - - bridge->gatt_table_real = (u32 *) info->ca_gfxgart; - bridge->gatt_table = bridge->gatt_table_real; - bridge->gatt_bus_addr = info->ca_gfxgart_base; - - return 0; -} - -static int sgi_tioca_free_gatt_table(struct agp_bridge_data *bridge) -{ - return 0; -} - -static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start, - int type) -{ - int num_entries; - size_t i; - off_t j; - void *temp; - struct agp_bridge_data *bridge; - u64 *table; - - bridge = mem->bridge; - if (!bridge) - return -EINVAL; - - table = (u64 *)bridge->gatt_table; - - temp = bridge->current_size; - - switch (bridge->driver->size_type) { - case U8_APER_SIZE: - num_entries = A_SIZE_8(temp)->num_entries; - break; - case U16_APER_SIZE: - num_entries = A_SIZE_16(temp)->num_entries; - break; - case U32_APER_SIZE: - num_entries = A_SIZE_32(temp)->num_entries; - break; - case FIXED_APER_SIZE: - num_entries = A_SIZE_FIX(temp)->num_entries; - break; - case LVL2_APER_SIZE: - return -EINVAL; - default: - num_entries = 0; - break; - } - - num_entries -= agp_memory_reserved / PAGE_SIZE; - if (num_entries < 0) - num_entries = 0; - - if (type != 0 || mem->type != 0) { - return -EINVAL; - } - - if ((pg_start + mem->page_count) > num_entries) - return -EINVAL; - - j = pg_start; - - while (j < (pg_start + mem->page_count)) { - if (table[j]) - return -EBUSY; - j++; - } - - if (!mem->is_flushed) { - bridge->driver->cache_flush(); - mem->is_flushed = true; - } - - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - table[j] = - bridge->driver->mask_memory(bridge, - page_to_phys(mem->pages[i]), - mem->type); - } - - bridge->driver->tlb_flush(mem); - return 0; -} - -static int sgi_tioca_remove_memory(struct agp_memory *mem, off_t pg_start, - int type) -{ - size_t i; - struct agp_bridge_data *bridge; - u64 *table; - - bridge = mem->bridge; - if (!bridge) - return -EINVAL; - - if (type != 0 || mem->type != 0) { - return -EINVAL; - } - - table = (u64 *)bridge->gatt_table; - - for (i = pg_start; i < (mem->page_count + pg_start); i++) { - table[i] = 0; - } - - bridge->driver->tlb_flush(mem); - return 0; -} - -static void sgi_tioca_cache_flush(void) -{ -} - -/* - * Cleanup. Nothing to do as the CA driver owns the GART. - */ - -static void sgi_tioca_cleanup(void) -{ -} - -static struct agp_bridge_data *sgi_tioca_find_bridge(struct pci_dev *pdev) -{ - struct agp_bridge_data *bridge; - - list_for_each_entry(bridge, &agp_bridges, list) { - if (bridge->dev->bus == pdev->bus) - break; - } - return bridge; -} - -const struct agp_bridge_driver sgi_tioca_driver = { - .owner = THIS_MODULE, - .size_type = U16_APER_SIZE, - .configure = sgi_tioca_configure, - .fetch_size = sgi_tioca_fetch_size, - .cleanup = sgi_tioca_cleanup, - .tlb_flush = sgi_tioca_tlbflush, - .mask_memory = sgi_tioca_mask_memory, - .agp_enable = sgi_tioca_agp_enable, - .cache_flush = sgi_tioca_cache_flush, - .create_gatt_table = sgi_tioca_create_gatt_table, - .free_gatt_table = sgi_tioca_free_gatt_table, - .insert_memory = sgi_tioca_insert_memory, - .remove_memory = sgi_tioca_remove_memory, - .alloc_by_type = agp_generic_alloc_by_type, - .free_by_type = agp_generic_free_by_type, - .agp_alloc_page = sgi_tioca_alloc_page, - .agp_destroy_page = agp_generic_destroy_page, - .agp_type_to_mask_type = agp_generic_type_to_mask_type, - .cant_use_aperture = true, - .needs_scratch_page = false, - .num_aperture_sizes = 1, -}; - -static int agp_sgi_init(void) -{ - unsigned int j; - struct tioca_kernel *info; - struct pci_dev *pdev = NULL; - - if (tioca_gart_found) - printk(KERN_INFO PFX "SGI TIO CA GART driver initialized.\n"); - else - return 0; - - sgi_tioca_agp_bridges = kmalloc_array(tioca_gart_found, - sizeof(struct agp_bridge_data *), - GFP_KERNEL); - if (!sgi_tioca_agp_bridges) - return -ENOMEM; - - j = 0; - list_for_each_entry(info, &tioca_list, ca_list) { - if (list_empty(info->ca_devices)) - continue; - list_for_each_entry(pdev, info->ca_devices, bus_list) { - u8 cap_ptr; - - if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8)) - continue; - cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); - if (!cap_ptr) - continue; - } - sgi_tioca_agp_bridges[j] = agp_alloc_bridge(); - printk(KERN_INFO PFX "bridge %d = 0x%p\n", j, - sgi_tioca_agp_bridges[j]); - if (sgi_tioca_agp_bridges[j]) { - sgi_tioca_agp_bridges[j]->dev = pdev; - sgi_tioca_agp_bridges[j]->dev_private_data = info; - sgi_tioca_agp_bridges[j]->driver = &sgi_tioca_driver; - sgi_tioca_agp_bridges[j]->gart_bus_addr = - info->ca_gfxap_base; - sgi_tioca_agp_bridges[j]->mode = (0x7D << 24) | /* 126 requests */ - (0x1 << 9) | /* SBA supported */ - (0x1 << 5) | /* 64-bit addresses supported */ - (0x1 << 4) | /* FW supported */ - (0x1 << 3) | /* AGP 3.0 mode */ - 0x2; /* 8x transfer only */ - sgi_tioca_agp_bridges[j]->current_size = - sgi_tioca_agp_bridges[j]->previous_size = - (void *)&sgi_tioca_sizes[0]; - agp_add_bridge(sgi_tioca_agp_bridges[j]); - } - j++; - } - - agp_find_bridge = &sgi_tioca_find_bridge; - return 0; -} - -static void agp_sgi_cleanup(void) -{ - kfree(sgi_tioca_agp_bridges); - sgi_tioca_agp_bridges = NULL; -} - -module_init(agp_sgi_init); -module_exit(agp_sgi_cleanup); - -MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c index 433426242b875c7297573e7985afabcdb569d25c..e55705745d5e42bf2b368ae231cfa5247bf2e628 100644 --- a/drivers/char/hw_random/atmel-rng.c +++ b/drivers/char/hw_random/atmel-rng.c @@ -86,7 +86,7 @@ static int atmel_trng_probe(struct platform_device *pdev) trng->rng.name = pdev->name; trng->rng.read = atmel_trng_read; - ret = hwrng_register(&trng->rng); + ret = devm_hwrng_register(&pdev->dev, &trng->rng); if (ret) goto err_register; @@ -103,7 +103,6 @@ static int atmel_trng_remove(struct platform_device *pdev) { struct atmel_trng *trng = platform_get_drvdata(pdev); - hwrng_unregister(&trng->rng); atmel_trng_disable(trng); clk_disable_unprepare(trng->clk); diff --git a/drivers/char/hw_random/cavium-rng-vf.c b/drivers/char/hw_random/cavium-rng-vf.c index 2d1352b67168b96fb70fe13729f8dfb84262828e..3de4a6a443ef98ac3369228593147afd7cd1b862 100644 --- a/drivers/char/hw_random/cavium-rng-vf.c +++ b/drivers/char/hw_random/cavium-rng-vf.c @@ -67,7 +67,7 @@ static int cavium_rng_probe_vf(struct pci_dev *pdev, pci_set_drvdata(pdev, rng); - ret = hwrng_register(&rng->ops); + ret = devm_hwrng_register(&pdev->dev, &rng->ops); if (ret) { dev_err(&pdev->dev, "Error registering device as HWRNG.\n"); return ret; @@ -76,14 +76,6 @@ static int cavium_rng_probe_vf(struct pci_dev *pdev, return 0; } -/* Remove the VF */ -static void cavium_rng_remove_vf(struct pci_dev *pdev) -{ - struct cavium_rng *rng; - - rng = pci_get_drvdata(pdev); - hwrng_unregister(&rng->ops); -} static const struct pci_device_id cavium_rng_vf_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa033), 0, 0, 0}, @@ -95,7 +87,6 @@ static struct pci_driver cavium_rng_vf_driver = { .name = "cavium_rng_vf", .id_table = cavium_rng_vf_id_table, .probe = cavium_rng_probe_vf, - .remove = cavium_rng_remove_vf, }; module_pci_driver(cavium_rng_vf_driver); diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 9044d31ab1a19cef76b2aa7fafc620ffdd0206c4..bdab5d9af8d219896a22879f3edfcee5ca08b4eb 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -421,7 +422,9 @@ static int hwrng_fillfn(void *unused) { long rc; - while (!kthread_should_stop()) { + set_freezable(); + + while (!kthread_freezable_should_stop(NULL)) { struct hwrng *rng; rng = get_current_rng(); diff --git a/drivers/char/hw_random/exynos-trng.c b/drivers/char/hw_random/exynos-trng.c index 94235761955cea743952d6b8cd49ec87d57a0bfc..b4b52ab23b6b1cea2a77acc07ce6c0d1b647183a 100644 --- a/drivers/char/hw_random/exynos-trng.c +++ b/drivers/char/hw_random/exynos-trng.c @@ -153,7 +153,7 @@ static int exynos_trng_probe(struct platform_device *pdev) goto err_clock; } - ret = hwrng_register(&trng->rng); + ret = devm_hwrng_register(&pdev->dev, &trng->rng); if (ret) { dev_err(&pdev->dev, "Could not register hwrng device.\n"); goto err_register; @@ -179,7 +179,6 @@ static int exynos_trng_remove(struct platform_device *pdev) { struct exynos_trng_dev *trng = platform_get_drvdata(pdev); - hwrng_unregister(&trng->rng); clk_disable_unprepare(trng->clk); pm_runtime_put_sync(&pdev->dev); diff --git a/drivers/char/hw_random/imx-rngc.c b/drivers/char/hw_random/imx-rngc.c index 69f537980004978fba432784d6e54490c796b4b9..30cf00f8e9a09ad3c57b0c4190080cd38311f669 100644 --- a/drivers/char/hw_random/imx-rngc.c +++ b/drivers/char/hw_random/imx-rngc.c @@ -196,7 +196,6 @@ static int imx_rngc_init(struct hwrng *rng) static int imx_rngc_probe(struct platform_device *pdev) { struct imx_rngc *rngc; - struct resource *res; int ret; int irq; @@ -204,8 +203,7 @@ static int imx_rngc_probe(struct platform_device *pdev) if (!rngc) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - rngc->base = devm_ioremap_resource(&pdev->dev, res); + rngc->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(rngc->base)) return PTR_ERR(rngc->base); diff --git a/drivers/char/hw_random/mxc-rnga.c b/drivers/char/hw_random/mxc-rnga.c index ea2bf18b1fbb17bd763a49a0ca2eb80caa27a33c..025083c838f5d95ed64e7a33244b2c336ef15221 100644 --- a/drivers/char/hw_random/mxc-rnga.c +++ b/drivers/char/hw_random/mxc-rnga.c @@ -134,7 +134,6 @@ static void mxc_rnga_cleanup(struct hwrng *rng) static int __init mxc_rnga_probe(struct platform_device *pdev) { int err; - struct resource *res; struct mxc_rng *mxc_rng; mxc_rng = devm_kzalloc(&pdev->dev, sizeof(*mxc_rng), GFP_KERNEL); @@ -158,8 +157,7 @@ static int __init mxc_rnga_probe(struct platform_device *pdev) if (err) return err; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mxc_rng->mem = devm_ioremap_resource(&pdev->dev, res); + mxc_rng->mem = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mxc_rng->mem)) { err = PTR_ERR(mxc_rng->mem); goto err_ioremap; diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index d4cab105796facc0ff31207e77883bc4560a0eef..73e408146420d5573099942520870a8078f0986e 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -768,7 +768,7 @@ static int n2rng_probe(struct platform_device *op) np->hwrng.data_read = n2rng_data_read; np->hwrng.priv = (unsigned long) np; - err = hwrng_register(&np->hwrng); + err = devm_hwrng_register(&op->dev, &np->hwrng); if (err) goto out_hvapi_unregister; @@ -793,8 +793,6 @@ static int n2rng_remove(struct platform_device *op) cancel_delayed_work_sync(&np->work); - hwrng_unregister(&np->hwrng); - sun4v_hvapi_unregister(HV_GRP_RNG); return 0; diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c index fc0f6b0cb80da04e1bea95c653f60b89013a9b68..74ed29f42e4fe70eafa0f2e58df3922f1b26dc29 100644 --- a/drivers/char/hw_random/nomadik-rng.c +++ b/drivers/char/hw_random/nomadik-rng.c @@ -57,7 +57,7 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id) if (!base) goto out_release; nmk_rng.priv = (unsigned long)base; - ret = hwrng_register(&nmk_rng); + ret = devm_hwrng_register(&dev->dev, &nmk_rng); if (ret) goto out_release; return 0; @@ -71,7 +71,6 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id) static int nmk_rng_remove(struct amba_device *dev) { - hwrng_unregister(&nmk_rng); amba_release_regions(dev); clk_disable(rng_clk); return 0; diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index e9b6ac61fb7f64953e988c130d53f518ca3e7ab0..b27f39688b5e71de16650bb7a67c29a54b7539dd 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -500,7 +500,7 @@ static int omap_rng_probe(struct platform_device *pdev) if (ret) goto err_register; - ret = hwrng_register(&priv->rng); + ret = devm_hwrng_register(&pdev->dev, &priv->rng); if (ret) goto err_register; @@ -525,7 +525,6 @@ static int omap_rng_remove(struct platform_device *pdev) { struct omap_rng_dev *priv = platform_get_drvdata(pdev); - hwrng_unregister(&priv->rng); priv->pdata->cleanup(priv); diff --git a/drivers/char/hw_random/powernv-rng.c b/drivers/char/hw_random/powernv-rng.c index f2e8272e276a23bf28a4c1db82e2f8e0dafbebcd..8da1d7917bdc45d78f2b0afef6c69cd31a6c2746 100644 --- a/drivers/char/hw_random/powernv-rng.c +++ b/drivers/char/hw_random/powernv-rng.c @@ -33,18 +33,11 @@ static struct hwrng powernv_hwrng = { .read = powernv_rng_read, }; -static int powernv_rng_remove(struct platform_device *pdev) -{ - hwrng_unregister(&powernv_hwrng); - - return 0; -} - static int powernv_rng_probe(struct platform_device *pdev) { int rc; - rc = hwrng_register(&powernv_hwrng); + rc = devm_hwrng_register(&pdev->dev, &powernv_hwrng); if (rc) { /* We only register one device, ignore any others */ if (rc == -EEXIST) @@ -70,7 +63,6 @@ static struct platform_driver powernv_rng_driver = { .of_match_table = powernv_rng_match, }, .probe = powernv_rng_probe, - .remove = powernv_rng_remove, }; module_platform_driver(powernv_rng_driver); diff --git a/drivers/char/hw_random/st-rng.c b/drivers/char/hw_random/st-rng.c index bd6a98b3479b79fea87d1c10fd774e4754da87a6..863448360a7dacf4bb6076ab5347a6a3280ac6ed 100644 --- a/drivers/char/hw_random/st-rng.c +++ b/drivers/char/hw_random/st-rng.c @@ -102,7 +102,7 @@ static int st_rng_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, ddata); - ret = hwrng_register(&ddata->ops); + ret = devm_hwrng_register(&pdev->dev, &ddata->ops); if (ret) { dev_err(&pdev->dev, "Failed to register HW RNG\n"); clk_disable_unprepare(clk); @@ -118,8 +118,6 @@ static int st_rng_remove(struct platform_device *pdev) { struct st_rng_data *ddata = dev_get_drvdata(&pdev->dev); - hwrng_unregister(&ddata->ops); - clk_disable_unprepare(ddata->clk); return 0; diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c index ccd1f6e0696bfd777aea5ae87b26e7ddd4a941c5..e262445fed5f5353460e8dd0a3f7553f7d7bfafe 100644 --- a/drivers/char/hw_random/timeriomem-rng.c +++ b/drivers/char/hw_random/timeriomem-rng.c @@ -117,9 +117,9 @@ static int timeriomem_rng_probe(struct platform_device *pdev) if (!res) return -ENXIO; - if (res->start % 4 != 0 || resource_size(res) != 4) { + if (res->start % 4 != 0 || resource_size(res) < 4) { dev_err(&pdev->dev, - "address must be four bytes wide and aligned\n"); + "address must be at least four bytes wide and 32-bit aligned\n"); return -EINVAL; } diff --git a/drivers/char/hw_random/xgene-rng.c b/drivers/char/hw_random/xgene-rng.c index 8c6f9f63da5e8e6805e8b3b90f0cf65bbcdb867b..7e568db87ae29a782dffc84c3dece7ee6a291004 100644 --- a/drivers/char/hw_random/xgene-rng.c +++ b/drivers/char/hw_random/xgene-rng.c @@ -361,7 +361,7 @@ static int xgene_rng_probe(struct platform_device *pdev) xgene_rng_func.priv = (unsigned long) ctx; - rc = hwrng_register(&xgene_rng_func); + rc = devm_hwrng_register(&pdev->dev, &xgene_rng_func); if (rc) { dev_err(&pdev->dev, "RNG registering failed error %d\n", rc); if (!IS_ERR(ctx->clk)) @@ -375,7 +375,6 @@ static int xgene_rng_probe(struct platform_device *pdev) rc); if (!IS_ERR(ctx->clk)) clk_disable_unprepare(ctx->clk); - hwrng_unregister(&xgene_rng_func); return rc; } @@ -392,7 +391,6 @@ static int xgene_rng_remove(struct platform_device *pdev) dev_err(&pdev->dev, "RNG init wakeup failed error %d\n", rc); if (!IS_ERR(ctx->clk)) clk_disable_unprepare(ctx->clk); - hwrng_unregister(&xgene_rng_func); return rc; } diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c deleted file mode 100644 index 0a31b60bee7b8e181c2ae5de68f84c143d278f52..0000000000000000000000000000000000000000 --- a/drivers/char/mbcs.c +++ /dev/null @@ -1,831 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * MOATB Core Services driver. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "mbcs.h" - -#define MBCS_DEBUG 0 -#if MBCS_DEBUG -#define DBG(fmt...) printk(KERN_ALERT fmt) -#else -#define DBG(fmt...) -#endif -static DEFINE_MUTEX(mbcs_mutex); -static int mbcs_major; - -static LIST_HEAD(soft_list); - -/* - * file operations - */ -static const struct file_operations mbcs_ops = { - .owner = THIS_MODULE, - .open = mbcs_open, - .llseek = mbcs_sram_llseek, - .read = mbcs_sram_read, - .write = mbcs_sram_write, - .mmap = mbcs_gscr_mmap, -}; - -struct mbcs_callback_arg { - int minor; - struct cx_dev *cx_dev; -}; - -static inline void mbcs_getdma_init(struct getdma *gdma) -{ - memset(gdma, 0, sizeof(struct getdma)); - gdma->DoneIntEnable = 1; -} - -static inline void mbcs_putdma_init(struct putdma *pdma) -{ - memset(pdma, 0, sizeof(struct putdma)); - pdma->DoneIntEnable = 1; -} - -static inline void mbcs_algo_init(struct algoblock *algo_soft) -{ - memset(algo_soft, 0, sizeof(struct algoblock)); -} - -static inline void mbcs_getdma_set(void *mmr, - uint64_t hostAddr, - uint64_t localAddr, - uint64_t localRamSel, - uint64_t numPkts, - uint64_t amoEnable, - uint64_t intrEnable, - uint64_t peerIO, - uint64_t amoHostDest, - uint64_t amoModType, uint64_t intrHostDest, - uint64_t intrVector) -{ - union dma_control rdma_control; - union dma_amo_dest amo_dest; - union intr_dest intr_dest; - union dma_localaddr local_addr; - union dma_hostaddr host_addr; - - rdma_control.dma_control_reg = 0; - amo_dest.dma_amo_dest_reg = 0; - intr_dest.intr_dest_reg = 0; - local_addr.dma_localaddr_reg = 0; - host_addr.dma_hostaddr_reg = 0; - - host_addr.dma_sys_addr = hostAddr; - MBCS_MMR_SET(mmr, MBCS_RD_DMA_SYS_ADDR, host_addr.dma_hostaddr_reg); - - local_addr.dma_ram_addr = localAddr; - local_addr.dma_ram_sel = localRamSel; - MBCS_MMR_SET(mmr, MBCS_RD_DMA_LOC_ADDR, local_addr.dma_localaddr_reg); - - rdma_control.dma_op_length = numPkts; - rdma_control.done_amo_en = amoEnable; - rdma_control.done_int_en = intrEnable; - rdma_control.pio_mem_n = peerIO; - MBCS_MMR_SET(mmr, MBCS_RD_DMA_CTRL, rdma_control.dma_control_reg); - - amo_dest.dma_amo_sys_addr = amoHostDest; - amo_dest.dma_amo_mod_type = amoModType; - MBCS_MMR_SET(mmr, MBCS_RD_DMA_AMO_DEST, amo_dest.dma_amo_dest_reg); - - intr_dest.address = intrHostDest; - intr_dest.int_vector = intrVector; - MBCS_MMR_SET(mmr, MBCS_RD_DMA_INT_DEST, intr_dest.intr_dest_reg); - -} - -static inline void mbcs_putdma_set(void *mmr, - uint64_t hostAddr, - uint64_t localAddr, - uint64_t localRamSel, - uint64_t numPkts, - uint64_t amoEnable, - uint64_t intrEnable, - uint64_t peerIO, - uint64_t amoHostDest, - uint64_t amoModType, - uint64_t intrHostDest, uint64_t intrVector) -{ - union dma_control wdma_control; - union dma_amo_dest amo_dest; - union intr_dest intr_dest; - union dma_localaddr local_addr; - union dma_hostaddr host_addr; - - wdma_control.dma_control_reg = 0; - amo_dest.dma_amo_dest_reg = 0; - intr_dest.intr_dest_reg = 0; - local_addr.dma_localaddr_reg = 0; - host_addr.dma_hostaddr_reg = 0; - - host_addr.dma_sys_addr = hostAddr; - MBCS_MMR_SET(mmr, MBCS_WR_DMA_SYS_ADDR, host_addr.dma_hostaddr_reg); - - local_addr.dma_ram_addr = localAddr; - local_addr.dma_ram_sel = localRamSel; - MBCS_MMR_SET(mmr, MBCS_WR_DMA_LOC_ADDR, local_addr.dma_localaddr_reg); - - wdma_control.dma_op_length = numPkts; - wdma_control.done_amo_en = amoEnable; - wdma_control.done_int_en = intrEnable; - wdma_control.pio_mem_n = peerIO; - MBCS_MMR_SET(mmr, MBCS_WR_DMA_CTRL, wdma_control.dma_control_reg); - - amo_dest.dma_amo_sys_addr = amoHostDest; - amo_dest.dma_amo_mod_type = amoModType; - MBCS_MMR_SET(mmr, MBCS_WR_DMA_AMO_DEST, amo_dest.dma_amo_dest_reg); - - intr_dest.address = intrHostDest; - intr_dest.int_vector = intrVector; - MBCS_MMR_SET(mmr, MBCS_WR_DMA_INT_DEST, intr_dest.intr_dest_reg); - -} - -static inline void mbcs_algo_set(void *mmr, - uint64_t amoHostDest, - uint64_t amoModType, - uint64_t intrHostDest, - uint64_t intrVector, uint64_t algoStepCount) -{ - union dma_amo_dest amo_dest; - union intr_dest intr_dest; - union algo_step step; - - step.algo_step_reg = 0; - intr_dest.intr_dest_reg = 0; - amo_dest.dma_amo_dest_reg = 0; - - amo_dest.dma_amo_sys_addr = amoHostDest; - amo_dest.dma_amo_mod_type = amoModType; - MBCS_MMR_SET(mmr, MBCS_ALG_AMO_DEST, amo_dest.dma_amo_dest_reg); - - intr_dest.address = intrHostDest; - intr_dest.int_vector = intrVector; - MBCS_MMR_SET(mmr, MBCS_ALG_INT_DEST, intr_dest.intr_dest_reg); - - step.alg_step_cnt = algoStepCount; - MBCS_MMR_SET(mmr, MBCS_ALG_STEP, step.algo_step_reg); -} - -static inline int mbcs_getdma_start(struct mbcs_soft *soft) -{ - void *mmr_base; - struct getdma *gdma; - uint64_t numPkts; - union cm_control cm_control; - - mmr_base = soft->mmr_base; - gdma = &soft->getdma; - - /* check that host address got setup */ - if (!gdma->hostAddr) - return -1; - - numPkts = - (gdma->bytes + (MBCS_CACHELINE_SIZE - 1)) / MBCS_CACHELINE_SIZE; - - /* program engine */ - mbcs_getdma_set(mmr_base, tiocx_dma_addr(gdma->hostAddr), - gdma->localAddr, - (gdma->localAddr < MB2) ? 0 : - (gdma->localAddr < MB4) ? 1 : - (gdma->localAddr < MB6) ? 2 : 3, - numPkts, - gdma->DoneAmoEnable, - gdma->DoneIntEnable, - gdma->peerIO, - gdma->amoHostDest, - gdma->amoModType, - gdma->intrHostDest, gdma->intrVector); - - /* start engine */ - cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); - cm_control.rd_dma_go = 1; - MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg); - - return 0; - -} - -static inline int mbcs_putdma_start(struct mbcs_soft *soft) -{ - void *mmr_base; - struct putdma *pdma; - uint64_t numPkts; - union cm_control cm_control; - - mmr_base = soft->mmr_base; - pdma = &soft->putdma; - - /* check that host address got setup */ - if (!pdma->hostAddr) - return -1; - - numPkts = - (pdma->bytes + (MBCS_CACHELINE_SIZE - 1)) / MBCS_CACHELINE_SIZE; - - /* program engine */ - mbcs_putdma_set(mmr_base, tiocx_dma_addr(pdma->hostAddr), - pdma->localAddr, - (pdma->localAddr < MB2) ? 0 : - (pdma->localAddr < MB4) ? 1 : - (pdma->localAddr < MB6) ? 2 : 3, - numPkts, - pdma->DoneAmoEnable, - pdma->DoneIntEnable, - pdma->peerIO, - pdma->amoHostDest, - pdma->amoModType, - pdma->intrHostDest, pdma->intrVector); - - /* start engine */ - cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); - cm_control.wr_dma_go = 1; - MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg); - - return 0; - -} - -static inline int mbcs_algo_start(struct mbcs_soft *soft) -{ - struct algoblock *algo_soft = &soft->algo; - void *mmr_base = soft->mmr_base; - union cm_control cm_control; - - if (mutex_lock_interruptible(&soft->algolock)) - return -ERESTARTSYS; - - atomic_set(&soft->algo_done, 0); - - mbcs_algo_set(mmr_base, - algo_soft->amoHostDest, - algo_soft->amoModType, - algo_soft->intrHostDest, - algo_soft->intrVector, algo_soft->algoStepCount); - - /* start algorithm */ - cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); - cm_control.alg_done_int_en = 1; - cm_control.alg_go = 1; - MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg); - - mutex_unlock(&soft->algolock); - - return 0; -} - -static inline ssize_t -do_mbcs_sram_dmawrite(struct mbcs_soft *soft, uint64_t hostAddr, - size_t len, loff_t * off) -{ - int rv = 0; - - if (mutex_lock_interruptible(&soft->dmawritelock)) - return -ERESTARTSYS; - - atomic_set(&soft->dmawrite_done, 0); - - soft->putdma.hostAddr = hostAddr; - soft->putdma.localAddr = *off; - soft->putdma.bytes = len; - - if (mbcs_putdma_start(soft) < 0) { - DBG(KERN_ALERT "do_mbcs_sram_dmawrite: " - "mbcs_putdma_start failed\n"); - rv = -EAGAIN; - goto dmawrite_exit; - } - - if (wait_event_interruptible(soft->dmawrite_queue, - atomic_read(&soft->dmawrite_done))) { - rv = -ERESTARTSYS; - goto dmawrite_exit; - } - - rv = len; - *off += len; - -dmawrite_exit: - mutex_unlock(&soft->dmawritelock); - - return rv; -} - -static inline ssize_t -do_mbcs_sram_dmaread(struct mbcs_soft *soft, uint64_t hostAddr, - size_t len, loff_t * off) -{ - int rv = 0; - - if (mutex_lock_interruptible(&soft->dmareadlock)) - return -ERESTARTSYS; - - atomic_set(&soft->dmawrite_done, 0); - - soft->getdma.hostAddr = hostAddr; - soft->getdma.localAddr = *off; - soft->getdma.bytes = len; - - if (mbcs_getdma_start(soft) < 0) { - DBG(KERN_ALERT "mbcs_strategy: mbcs_getdma_start failed\n"); - rv = -EAGAIN; - goto dmaread_exit; - } - - if (wait_event_interruptible(soft->dmaread_queue, - atomic_read(&soft->dmaread_done))) { - rv = -ERESTARTSYS; - goto dmaread_exit; - } - - rv = len; - *off += len; - -dmaread_exit: - mutex_unlock(&soft->dmareadlock); - - return rv; -} - -static int mbcs_open(struct inode *ip, struct file *fp) -{ - struct mbcs_soft *soft; - int minor; - - mutex_lock(&mbcs_mutex); - minor = iminor(ip); - - /* Nothing protects access to this list... */ - list_for_each_entry(soft, &soft_list, list) { - if (soft->nasid == minor) { - fp->private_data = soft->cxdev; - mutex_unlock(&mbcs_mutex); - return 0; - } - } - - mutex_unlock(&mbcs_mutex); - return -ENODEV; -} - -static ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off) -{ - struct cx_dev *cx_dev = fp->private_data; - struct mbcs_soft *soft = cx_dev->soft; - uint64_t hostAddr; - int rv = 0; - - hostAddr = __get_dma_pages(GFP_KERNEL, get_order(len)); - if (hostAddr == 0) - return -ENOMEM; - - rv = do_mbcs_sram_dmawrite(soft, hostAddr, len, off); - if (rv < 0) - goto exit; - - if (copy_to_user(buf, (void *)hostAddr, len)) - rv = -EFAULT; - - exit: - free_pages(hostAddr, get_order(len)); - - return rv; -} - -static ssize_t -mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * off) -{ - struct cx_dev *cx_dev = fp->private_data; - struct mbcs_soft *soft = cx_dev->soft; - uint64_t hostAddr; - int rv = 0; - - hostAddr = __get_dma_pages(GFP_KERNEL, get_order(len)); - if (hostAddr == 0) - return -ENOMEM; - - if (copy_from_user((void *)hostAddr, buf, len)) { - rv = -EFAULT; - goto exit; - } - - rv = do_mbcs_sram_dmaread(soft, hostAddr, len, off); - - exit: - free_pages(hostAddr, get_order(len)); - - return rv; -} - -static loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence) -{ - return generic_file_llseek_size(filp, off, whence, MAX_LFS_FILESIZE, - MBCS_SRAM_SIZE); -} - -static uint64_t mbcs_pioaddr(struct mbcs_soft *soft, uint64_t offset) -{ - uint64_t mmr_base; - - mmr_base = (uint64_t) (soft->mmr_base + offset); - - return mmr_base; -} - -static void mbcs_debug_pioaddr_set(struct mbcs_soft *soft) -{ - soft->debug_addr = mbcs_pioaddr(soft, MBCS_DEBUG_START); -} - -static void mbcs_gscr_pioaddr_set(struct mbcs_soft *soft) -{ - soft->gscr_addr = mbcs_pioaddr(soft, MBCS_GSCR_START); -} - -static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma) -{ - struct cx_dev *cx_dev = fp->private_data; - struct mbcs_soft *soft = cx_dev->soft; - - if (vma->vm_pgoff != 0) - return -EINVAL; - - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - - /* Remap-pfn-range will mark the range VM_IO */ - if (remap_pfn_range(vma, - vma->vm_start, - __pa(soft->gscr_addr) >> PAGE_SHIFT, - PAGE_SIZE, - vma->vm_page_prot)) - return -EAGAIN; - - return 0; -} - -/** - * mbcs_completion_intr_handler - Primary completion handler. - * @irq: irq - * @arg: soft struct for device - * - */ -static irqreturn_t -mbcs_completion_intr_handler(int irq, void *arg) -{ - struct mbcs_soft *soft = (struct mbcs_soft *)arg; - void *mmr_base; - union cm_status cm_status; - union cm_control cm_control; - - mmr_base = soft->mmr_base; - cm_status.cm_status_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_STATUS); - - if (cm_status.rd_dma_done) { - /* stop dma-read engine, clear status */ - cm_control.cm_control_reg = - MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); - cm_control.rd_dma_clr = 1; - MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, - cm_control.cm_control_reg); - atomic_set(&soft->dmaread_done, 1); - wake_up(&soft->dmaread_queue); - } - if (cm_status.wr_dma_done) { - /* stop dma-write engine, clear status */ - cm_control.cm_control_reg = - MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); - cm_control.wr_dma_clr = 1; - MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, - cm_control.cm_control_reg); - atomic_set(&soft->dmawrite_done, 1); - wake_up(&soft->dmawrite_queue); - } - if (cm_status.alg_done) { - /* clear status */ - cm_control.cm_control_reg = - MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); - cm_control.alg_done_clr = 1; - MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, - cm_control.cm_control_reg); - atomic_set(&soft->algo_done, 1); - wake_up(&soft->algo_queue); - } - - return IRQ_HANDLED; -} - -/** - * mbcs_intr_alloc - Allocate interrupts. - * @dev: device pointer - * - */ -static int mbcs_intr_alloc(struct cx_dev *dev) -{ - struct sn_irq_info *sn_irq; - struct mbcs_soft *soft; - struct getdma *getdma; - struct putdma *putdma; - struct algoblock *algo; - - soft = dev->soft; - getdma = &soft->getdma; - putdma = &soft->putdma; - algo = &soft->algo; - - soft->get_sn_irq = NULL; - soft->put_sn_irq = NULL; - soft->algo_sn_irq = NULL; - - sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1); - if (sn_irq == NULL) - return -EAGAIN; - soft->get_sn_irq = sn_irq; - getdma->intrHostDest = sn_irq->irq_xtalkaddr; - getdma->intrVector = sn_irq->irq_irq; - if (request_irq(sn_irq->irq_irq, - (void *)mbcs_completion_intr_handler, IRQF_SHARED, - "MBCS get intr", (void *)soft)) { - tiocx_irq_free(soft->get_sn_irq); - return -EAGAIN; - } - - sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1); - if (sn_irq == NULL) { - free_irq(soft->get_sn_irq->irq_irq, soft); - tiocx_irq_free(soft->get_sn_irq); - return -EAGAIN; - } - soft->put_sn_irq = sn_irq; - putdma->intrHostDest = sn_irq->irq_xtalkaddr; - putdma->intrVector = sn_irq->irq_irq; - if (request_irq(sn_irq->irq_irq, - (void *)mbcs_completion_intr_handler, IRQF_SHARED, - "MBCS put intr", (void *)soft)) { - tiocx_irq_free(soft->put_sn_irq); - free_irq(soft->get_sn_irq->irq_irq, soft); - tiocx_irq_free(soft->get_sn_irq); - return -EAGAIN; - } - - sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1); - if (sn_irq == NULL) { - free_irq(soft->put_sn_irq->irq_irq, soft); - tiocx_irq_free(soft->put_sn_irq); - free_irq(soft->get_sn_irq->irq_irq, soft); - tiocx_irq_free(soft->get_sn_irq); - return -EAGAIN; - } - soft->algo_sn_irq = sn_irq; - algo->intrHostDest = sn_irq->irq_xtalkaddr; - algo->intrVector = sn_irq->irq_irq; - if (request_irq(sn_irq->irq_irq, - (void *)mbcs_completion_intr_handler, IRQF_SHARED, - "MBCS algo intr", (void *)soft)) { - tiocx_irq_free(soft->algo_sn_irq); - free_irq(soft->put_sn_irq->irq_irq, soft); - tiocx_irq_free(soft->put_sn_irq); - free_irq(soft->get_sn_irq->irq_irq, soft); - tiocx_irq_free(soft->get_sn_irq); - return -EAGAIN; - } - - return 0; -} - -/** - * mbcs_intr_dealloc - Remove interrupts. - * @dev: device pointer - * - */ -static void mbcs_intr_dealloc(struct cx_dev *dev) -{ - struct mbcs_soft *soft; - - soft = dev->soft; - - free_irq(soft->get_sn_irq->irq_irq, soft); - tiocx_irq_free(soft->get_sn_irq); - free_irq(soft->put_sn_irq->irq_irq, soft); - tiocx_irq_free(soft->put_sn_irq); - free_irq(soft->algo_sn_irq->irq_irq, soft); - tiocx_irq_free(soft->algo_sn_irq); -} - -static inline int mbcs_hw_init(struct mbcs_soft *soft) -{ - void *mmr_base = soft->mmr_base; - union cm_control cm_control; - union cm_req_timeout cm_req_timeout; - uint64_t err_stat; - - cm_req_timeout.cm_req_timeout_reg = - MBCS_MMR_GET(mmr_base, MBCS_CM_REQ_TOUT); - - cm_req_timeout.time_out = MBCS_CM_CONTROL_REQ_TOUT_MASK; - MBCS_MMR_SET(mmr_base, MBCS_CM_REQ_TOUT, - cm_req_timeout.cm_req_timeout_reg); - - mbcs_gscr_pioaddr_set(soft); - mbcs_debug_pioaddr_set(soft); - - /* clear errors */ - err_stat = MBCS_MMR_GET(mmr_base, MBCS_CM_ERR_STAT); - MBCS_MMR_SET(mmr_base, MBCS_CM_CLR_ERR_STAT, err_stat); - MBCS_MMR_ZERO(mmr_base, MBCS_CM_ERROR_DETAIL1); - - /* enable interrupts */ - /* turn off 2^23 (INT_EN_PIO_REQ_ADDR_INV) */ - MBCS_MMR_SET(mmr_base, MBCS_CM_ERR_INT_EN, 0x3ffffff7e00ffUL); - - /* arm status regs and clear engines */ - cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); - cm_control.rearm_stat_regs = 1; - cm_control.alg_clr = 1; - cm_control.wr_dma_clr = 1; - cm_control.rd_dma_clr = 1; - - MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg); - - return 0; -} - -static ssize_t show_algo(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct cx_dev *cx_dev = to_cx_dev(dev); - struct mbcs_soft *soft = cx_dev->soft; - uint64_t debug0; - - /* - * By convention, the first debug register contains the - * algorithm number and revision. - */ - debug0 = *(uint64_t *) soft->debug_addr; - - return sprintf(buf, "0x%x 0x%x\n", - upper_32_bits(debug0), lower_32_bits(debug0)); -} - -static ssize_t store_algo(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - int n; - struct cx_dev *cx_dev = to_cx_dev(dev); - struct mbcs_soft *soft = cx_dev->soft; - - if (count <= 0) - return 0; - - n = simple_strtoul(buf, NULL, 0); - - if (n == 1) { - mbcs_algo_start(soft); - if (wait_event_interruptible(soft->algo_queue, - atomic_read(&soft->algo_done))) - return -ERESTARTSYS; - } - - return count; -} - -DEVICE_ATTR(algo, 0644, show_algo, store_algo); - -/** - * mbcs_probe - Initialize for device - * @dev: device pointer - * @device_id: id table pointer - * - */ -static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id) -{ - struct mbcs_soft *soft; - - dev->soft = NULL; - - soft = kzalloc(sizeof(struct mbcs_soft), GFP_KERNEL); - if (soft == NULL) - return -ENOMEM; - - soft->nasid = dev->cx_id.nasid; - list_add(&soft->list, &soft_list); - soft->mmr_base = (void *)tiocx_swin_base(dev->cx_id.nasid); - dev->soft = soft; - soft->cxdev = dev; - - init_waitqueue_head(&soft->dmawrite_queue); - init_waitqueue_head(&soft->dmaread_queue); - init_waitqueue_head(&soft->algo_queue); - - mutex_init(&soft->dmawritelock); - mutex_init(&soft->dmareadlock); - mutex_init(&soft->algolock); - - mbcs_getdma_init(&soft->getdma); - mbcs_putdma_init(&soft->putdma); - mbcs_algo_init(&soft->algo); - - mbcs_hw_init(soft); - - /* Allocate interrupts */ - mbcs_intr_alloc(dev); - - device_create_file(&dev->dev, &dev_attr_algo); - - return 0; -} - -static int mbcs_remove(struct cx_dev *dev) -{ - if (dev->soft) { - mbcs_intr_dealloc(dev); - kfree(dev->soft); - } - - device_remove_file(&dev->dev, &dev_attr_algo); - - return 0; -} - -static const struct cx_device_id mbcs_id_table[] = { - { - .part_num = MBCS_PART_NUM, - .mfg_num = MBCS_MFG_NUM, - }, - { - .part_num = MBCS_PART_NUM_ALG0, - .mfg_num = MBCS_MFG_NUM, - }, - {0, 0} -}; - -MODULE_DEVICE_TABLE(cx, mbcs_id_table); - -static struct cx_drv mbcs_driver = { - .name = DEVICE_NAME, - .id_table = mbcs_id_table, - .probe = mbcs_probe, - .remove = mbcs_remove, -}; - -static void __exit mbcs_exit(void) -{ - unregister_chrdev(mbcs_major, DEVICE_NAME); - cx_driver_unregister(&mbcs_driver); -} - -static int __init mbcs_init(void) -{ - int rv; - - if (!ia64_platform_is("sn2")) - return -ENODEV; - - // Put driver into chrdevs[]. Get major number. - rv = register_chrdev(mbcs_major, DEVICE_NAME, &mbcs_ops); - if (rv < 0) { - DBG(KERN_ALERT "mbcs_init: can't get major number. %d\n", rv); - return rv; - } - mbcs_major = rv; - - return cx_driver_register(&mbcs_driver); -} - -module_init(mbcs_init); -module_exit(mbcs_exit); - -MODULE_AUTHOR("Bruce Losure "); -MODULE_DESCRIPTION("Driver for MOATB Core Services"); -MODULE_LICENSE("GPL"); diff --git a/drivers/char/mbcs.h b/drivers/char/mbcs.h deleted file mode 100644 index 1a36884c48b526d786b306d647a5e43df7d74ecb..0000000000000000000000000000000000000000 --- a/drivers/char/mbcs.h +++ /dev/null @@ -1,553 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef __MBCS_H__ -#define __MBCS_H__ - -/* - * General macros - */ -#define MB (1024*1024) -#define MB2 (2*MB) -#define MB4 (4*MB) -#define MB6 (6*MB) - -/* - * Offsets and masks - */ -#define MBCS_CM_ID 0x0000 /* Identification */ -#define MBCS_CM_STATUS 0x0008 /* Status */ -#define MBCS_CM_ERROR_DETAIL1 0x0010 /* Error Detail1 */ -#define MBCS_CM_ERROR_DETAIL2 0x0018 /* Error Detail2 */ -#define MBCS_CM_CONTROL 0x0020 /* Control */ -#define MBCS_CM_REQ_TOUT 0x0028 /* Request Time-out */ -#define MBCS_CM_ERR_INT_DEST 0x0038 /* Error Interrupt Destination */ -#define MBCS_CM_TARG_FL 0x0050 /* Target Flush */ -#define MBCS_CM_ERR_STAT 0x0060 /* Error Status */ -#define MBCS_CM_CLR_ERR_STAT 0x0068 /* Clear Error Status */ -#define MBCS_CM_ERR_INT_EN 0x0070 /* Error Interrupt Enable */ -#define MBCS_RD_DMA_SYS_ADDR 0x0100 /* Read DMA System Address */ -#define MBCS_RD_DMA_LOC_ADDR 0x0108 /* Read DMA Local Address */ -#define MBCS_RD_DMA_CTRL 0x0110 /* Read DMA Control */ -#define MBCS_RD_DMA_AMO_DEST 0x0118 /* Read DMA AMO Destination */ -#define MBCS_RD_DMA_INT_DEST 0x0120 /* Read DMA Interrupt Destination */ -#define MBCS_RD_DMA_AUX_STAT 0x0130 /* Read DMA Auxiliary Status */ -#define MBCS_WR_DMA_SYS_ADDR 0x0200 /* Write DMA System Address */ -#define MBCS_WR_DMA_LOC_ADDR 0x0208 /* Write DMA Local Address */ -#define MBCS_WR_DMA_CTRL 0x0210 /* Write DMA Control */ -#define MBCS_WR_DMA_AMO_DEST 0x0218 /* Write DMA AMO Destination */ -#define MBCS_WR_DMA_INT_DEST 0x0220 /* Write DMA Interrupt Destination */ -#define MBCS_WR_DMA_AUX_STAT 0x0230 /* Write DMA Auxiliary Status */ -#define MBCS_ALG_AMO_DEST 0x0300 /* Algorithm AMO Destination */ -#define MBCS_ALG_INT_DEST 0x0308 /* Algorithm Interrupt Destination */ -#define MBCS_ALG_OFFSETS 0x0310 -#define MBCS_ALG_STEP 0x0318 /* Algorithm Step */ - -#define MBCS_GSCR_START 0x0000000 -#define MBCS_DEBUG_START 0x0100000 -#define MBCS_RAM0_START 0x0200000 -#define MBCS_RAM1_START 0x0400000 -#define MBCS_RAM2_START 0x0600000 - -#define MBCS_CM_CONTROL_REQ_TOUT_MASK 0x0000000000ffffffUL -//#define PIO_BASE_ADDR_BASE_OFFSET_MASK 0x00fffffffff00000UL - -#define MBCS_SRAM_SIZE (1024*1024) -#define MBCS_CACHELINE_SIZE 128 - -/* - * MMR get's and put's - */ -#define MBCS_MMR_ADDR(mmr_base, offset)((uint64_t *)(mmr_base + offset)) -#define MBCS_MMR_SET(mmr_base, offset, value) { \ - uint64_t *mbcs_mmr_set_u64p, readback; \ - mbcs_mmr_set_u64p = (uint64_t *)(mmr_base + offset); \ - *mbcs_mmr_set_u64p = value; \ - readback = *mbcs_mmr_set_u64p; \ -} -#define MBCS_MMR_GET(mmr_base, offset) *(uint64_t *)(mmr_base + offset) -#define MBCS_MMR_ZERO(mmr_base, offset) MBCS_MMR_SET(mmr_base, offset, 0) - -/* - * MBCS mmr structures - */ -union cm_id { - uint64_t cm_id_reg; - struct { - uint64_t always_one:1, // 0 - mfg_id:11, // 11:1 - part_num:16, // 27:12 - bitstream_rev:8, // 35:28 - :28; // 63:36 - }; -}; - -union cm_status { - uint64_t cm_status_reg; - struct { - uint64_t pending_reads:8, // 7:0 - pending_writes:8, // 15:8 - ice_rsp_credits:8, // 23:16 - ice_req_credits:8, // 31:24 - cm_req_credits:8, // 39:32 - :1, // 40 - rd_dma_in_progress:1, // 41 - rd_dma_done:1, // 42 - :1, // 43 - wr_dma_in_progress:1, // 44 - wr_dma_done:1, // 45 - alg_waiting:1, // 46 - alg_pipe_running:1, // 47 - alg_done:1, // 48 - :3, // 51:49 - pending_int_reqs:8, // 59:52 - :3, // 62:60 - alg_half_speed_sel:1; // 63 - }; -}; - -union cm_error_detail1 { - uint64_t cm_error_detail1_reg; - struct { - uint64_t packet_type:4, // 3:0 - source_id:2, // 5:4 - data_size:2, // 7:6 - tnum:8, // 15:8 - byte_enable:8, // 23:16 - gfx_cred:8, // 31:24 - read_type:2, // 33:32 - pio_or_memory:1, // 34 - head_cw_error:1, // 35 - :12, // 47:36 - head_error_bit:1, // 48 - data_error_bit:1, // 49 - :13, // 62:50 - valid:1; // 63 - }; -}; - -union cm_error_detail2 { - uint64_t cm_error_detail2_reg; - struct { - uint64_t address:56, // 55:0 - :8; // 63:56 - }; -}; - -union cm_control { - uint64_t cm_control_reg; - struct { - uint64_t cm_id:2, // 1:0 - :2, // 3:2 - max_trans:5, // 8:4 - :3, // 11:9 - address_mode:1, // 12 - :7, // 19:13 - credit_limit:8, // 27:20 - :5, // 32:28 - rearm_stat_regs:1, // 33 - prescalar_byp:1, // 34 - force_gap_war:1, // 35 - rd_dma_go:1, // 36 - wr_dma_go:1, // 37 - alg_go:1, // 38 - rd_dma_clr:1, // 39 - wr_dma_clr:1, // 40 - alg_clr:1, // 41 - :2, // 43:42 - alg_wait_step:1, // 44 - alg_done_amo_en:1, // 45 - alg_done_int_en:1, // 46 - :1, // 47 - alg_sram0_locked:1, // 48 - alg_sram1_locked:1, // 49 - alg_sram2_locked:1, // 50 - alg_done_clr:1, // 51 - :12; // 63:52 - }; -}; - -union cm_req_timeout { - uint64_t cm_req_timeout_reg; - struct { - uint64_t time_out:24, // 23:0 - :40; // 63:24 - }; -}; - -union intr_dest { - uint64_t intr_dest_reg; - struct { - uint64_t address:56, // 55:0 - int_vector:8; // 63:56 - }; -}; - -union cm_error_status { - uint64_t cm_error_status_reg; - struct { - uint64_t ecc_sbe:1, // 0 - ecc_mbe:1, // 1 - unsupported_req:1, // 2 - unexpected_rsp:1, // 3 - bad_length:1, // 4 - bad_datavalid:1, // 5 - buffer_overflow:1, // 6 - request_timeout:1, // 7 - :8, // 15:8 - head_inv_data_size:1, // 16 - rsp_pactype_inv:1, // 17 - head_sb_err:1, // 18 - missing_head:1, // 19 - head_inv_rd_type:1, // 20 - head_cmd_err_bit:1, // 21 - req_addr_align_inv:1, // 22 - pio_req_addr_inv:1, // 23 - req_range_dsize_inv:1, // 24 - early_term:1, // 25 - early_tail:1, // 26 - missing_tail:1, // 27 - data_flit_sb_err:1, // 28 - cm2hcm_req_cred_of:1, // 29 - cm2hcm_rsp_cred_of:1, // 30 - rx_bad_didn:1, // 31 - rd_dma_err_rsp:1, // 32 - rd_dma_tnum_tout:1, // 33 - rd_dma_multi_tnum_tou:1, // 34 - wr_dma_err_rsp:1, // 35 - wr_dma_tnum_tout:1, // 36 - wr_dma_multi_tnum_tou:1, // 37 - alg_data_overflow:1, // 38 - alg_data_underflow:1, // 39 - ram0_access_conflict:1, // 40 - ram1_access_conflict:1, // 41 - ram2_access_conflict:1, // 42 - ram0_perr:1, // 43 - ram1_perr:1, // 44 - ram2_perr:1, // 45 - int_gen_rsp_err:1, // 46 - int_gen_tnum_tout:1, // 47 - rd_dma_prog_err:1, // 48 - wr_dma_prog_err:1, // 49 - :14; // 63:50 - }; -}; - -union cm_clr_error_status { - uint64_t cm_clr_error_status_reg; - struct { - uint64_t clr_ecc_sbe:1, // 0 - clr_ecc_mbe:1, // 1 - clr_unsupported_req:1, // 2 - clr_unexpected_rsp:1, // 3 - clr_bad_length:1, // 4 - clr_bad_datavalid:1, // 5 - clr_buffer_overflow:1, // 6 - clr_request_timeout:1, // 7 - :8, // 15:8 - clr_head_inv_data_siz:1, // 16 - clr_rsp_pactype_inv:1, // 17 - clr_head_sb_err:1, // 18 - clr_missing_head:1, // 19 - clr_head_inv_rd_type:1, // 20 - clr_head_cmd_err_bit:1, // 21 - clr_req_addr_align_in:1, // 22 - clr_pio_req_addr_inv:1, // 23 - clr_req_range_dsize_i:1, // 24 - clr_early_term:1, // 25 - clr_early_tail:1, // 26 - clr_missing_tail:1, // 27 - clr_data_flit_sb_err:1, // 28 - clr_cm2hcm_req_cred_o:1, // 29 - clr_cm2hcm_rsp_cred_o:1, // 30 - clr_rx_bad_didn:1, // 31 - clr_rd_dma_err_rsp:1, // 32 - clr_rd_dma_tnum_tout:1, // 33 - clr_rd_dma_multi_tnum:1, // 34 - clr_wr_dma_err_rsp:1, // 35 - clr_wr_dma_tnum_tout:1, // 36 - clr_wr_dma_multi_tnum:1, // 37 - clr_alg_data_overflow:1, // 38 - clr_alg_data_underflo:1, // 39 - clr_ram0_access_confl:1, // 40 - clr_ram1_access_confl:1, // 41 - clr_ram2_access_confl:1, // 42 - clr_ram0_perr:1, // 43 - clr_ram1_perr:1, // 44 - clr_ram2_perr:1, // 45 - clr_int_gen_rsp_err:1, // 46 - clr_int_gen_tnum_tout:1, // 47 - clr_rd_dma_prog_err:1, // 48 - clr_wr_dma_prog_err:1, // 49 - :14; // 63:50 - }; -}; - -union cm_error_intr_enable { - uint64_t cm_error_intr_enable_reg; - struct { - uint64_t int_en_ecc_sbe:1, // 0 - int_en_ecc_mbe:1, // 1 - int_en_unsupported_re:1, // 2 - int_en_unexpected_rsp:1, // 3 - int_en_bad_length:1, // 4 - int_en_bad_datavalid:1, // 5 - int_en_buffer_overflo:1, // 6 - int_en_request_timeou:1, // 7 - :8, // 15:8 - int_en_head_inv_data_:1, // 16 - int_en_rsp_pactype_in:1, // 17 - int_en_head_sb_err:1, // 18 - int_en_missing_head:1, // 19 - int_en_head_inv_rd_ty:1, // 20 - int_en_head_cmd_err_b:1, // 21 - int_en_req_addr_align:1, // 22 - int_en_pio_req_addr_i:1, // 23 - int_en_req_range_dsiz:1, // 24 - int_en_early_term:1, // 25 - int_en_early_tail:1, // 26 - int_en_missing_tail:1, // 27 - int_en_data_flit_sb_e:1, // 28 - int_en_cm2hcm_req_cre:1, // 29 - int_en_cm2hcm_rsp_cre:1, // 30 - int_en_rx_bad_didn:1, // 31 - int_en_rd_dma_err_rsp:1, // 32 - int_en_rd_dma_tnum_to:1, // 33 - int_en_rd_dma_multi_t:1, // 34 - int_en_wr_dma_err_rsp:1, // 35 - int_en_wr_dma_tnum_to:1, // 36 - int_en_wr_dma_multi_t:1, // 37 - int_en_alg_data_overf:1, // 38 - int_en_alg_data_under:1, // 39 - int_en_ram0_access_co:1, // 40 - int_en_ram1_access_co:1, // 41 - int_en_ram2_access_co:1, // 42 - int_en_ram0_perr:1, // 43 - int_en_ram1_perr:1, // 44 - int_en_ram2_perr:1, // 45 - int_en_int_gen_rsp_er:1, // 46 - int_en_int_gen_tnum_t:1, // 47 - int_en_rd_dma_prog_er:1, // 48 - int_en_wr_dma_prog_er:1, // 49 - :14; // 63:50 - }; -}; - -struct cm_mmr { - union cm_id id; - union cm_status status; - union cm_error_detail1 err_detail1; - union cm_error_detail2 err_detail2; - union cm_control control; - union cm_req_timeout req_timeout; - uint64_t reserved1[1]; - union intr_dest int_dest; - uint64_t reserved2[2]; - uint64_t targ_flush; - uint64_t reserved3[1]; - union cm_error_status err_status; - union cm_clr_error_status clr_err_status; - union cm_error_intr_enable int_enable; -}; - -union dma_hostaddr { - uint64_t dma_hostaddr_reg; - struct { - uint64_t dma_sys_addr:56, // 55:0 - :8; // 63:56 - }; -}; - -union dma_localaddr { - uint64_t dma_localaddr_reg; - struct { - uint64_t dma_ram_addr:21, // 20:0 - dma_ram_sel:2, // 22:21 - :41; // 63:23 - }; -}; - -union dma_control { - uint64_t dma_control_reg; - struct { - uint64_t dma_op_length:16, // 15:0 - :18, // 33:16 - done_amo_en:1, // 34 - done_int_en:1, // 35 - :1, // 36 - pio_mem_n:1, // 37 - :26; // 63:38 - }; -}; - -union dma_amo_dest { - uint64_t dma_amo_dest_reg; - struct { - uint64_t dma_amo_sys_addr:56, // 55:0 - dma_amo_mod_type:3, // 58:56 - :5; // 63:59 - }; -}; - -union rdma_aux_status { - uint64_t rdma_aux_status_reg; - struct { - uint64_t op_num_pacs_left:17, // 16:0 - :5, // 21:17 - lrsp_buff_empty:1, // 22 - :17, // 39:23 - pending_reqs_left:6, // 45:40 - :18; // 63:46 - }; -}; - -struct rdma_mmr { - union dma_hostaddr host_addr; - union dma_localaddr local_addr; - union dma_control control; - union dma_amo_dest amo_dest; - union intr_dest intr_dest; - union rdma_aux_status aux_status; -}; - -union wdma_aux_status { - uint64_t wdma_aux_status_reg; - struct { - uint64_t op_num_pacs_left:17, // 16:0 - :4, // 20:17 - lreq_buff_empty:1, // 21 - :18, // 39:22 - pending_reqs_left:6, // 45:40 - :18; // 63:46 - }; -}; - -struct wdma_mmr { - union dma_hostaddr host_addr; - union dma_localaddr local_addr; - union dma_control control; - union dma_amo_dest amo_dest; - union intr_dest intr_dest; - union wdma_aux_status aux_status; -}; - -union algo_step { - uint64_t algo_step_reg; - struct { - uint64_t alg_step_cnt:16, // 15:0 - :48; // 63:16 - }; -}; - -struct algo_mmr { - union dma_amo_dest amo_dest; - union intr_dest intr_dest; - union { - uint64_t algo_offset_reg; - struct { - uint64_t sram0_offset:7, // 6:0 - reserved0:1, // 7 - sram1_offset:7, // 14:8 - reserved1:1, // 15 - sram2_offset:7, // 22:16 - reserved2:14; // 63:23 - }; - } sram_offset; - union algo_step step; -}; - -struct mbcs_mmr { - struct cm_mmr cm; - uint64_t reserved1[17]; - struct rdma_mmr rdDma; - uint64_t reserved2[25]; - struct wdma_mmr wrDma; - uint64_t reserved3[25]; - struct algo_mmr algo; - uint64_t reserved4[156]; -}; - -/* - * defines - */ -#define DEVICE_NAME "mbcs" -#define MBCS_PART_NUM 0xfff0 -#define MBCS_PART_NUM_ALG0 0xf001 -#define MBCS_MFG_NUM 0x1 - -struct algoblock { - uint64_t amoHostDest; - uint64_t amoModType; - uint64_t intrHostDest; - uint64_t intrVector; - uint64_t algoStepCount; -}; - -struct getdma { - uint64_t hostAddr; - uint64_t localAddr; - uint64_t bytes; - uint64_t DoneAmoEnable; - uint64_t DoneIntEnable; - uint64_t peerIO; - uint64_t amoHostDest; - uint64_t amoModType; - uint64_t intrHostDest; - uint64_t intrVector; -}; - -struct putdma { - uint64_t hostAddr; - uint64_t localAddr; - uint64_t bytes; - uint64_t DoneAmoEnable; - uint64_t DoneIntEnable; - uint64_t peerIO; - uint64_t amoHostDest; - uint64_t amoModType; - uint64_t intrHostDest; - uint64_t intrVector; -}; - -struct mbcs_soft { - struct list_head list; - struct cx_dev *cxdev; - int major; - int nasid; - void *mmr_base; - wait_queue_head_t dmawrite_queue; - wait_queue_head_t dmaread_queue; - wait_queue_head_t algo_queue; - struct sn_irq_info *get_sn_irq; - struct sn_irq_info *put_sn_irq; - struct sn_irq_info *algo_sn_irq; - struct getdma getdma; - struct putdma putdma; - struct algoblock algo; - uint64_t gscr_addr; // pio addr - uint64_t ram0_addr; // pio addr - uint64_t ram1_addr; // pio addr - uint64_t ram2_addr; // pio addr - uint64_t debug_addr; // pio addr - atomic_t dmawrite_done; - atomic_t dmaread_done; - atomic_t algo_done; - struct mutex dmawritelock; - struct mutex dmareadlock; - struct mutex algolock; -}; - -static int mbcs_open(struct inode *ip, struct file *fp); -static ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len, - loff_t * off); -static ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len, - loff_t * off); -static loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence); -static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma); - -#endif // __MBCS_H__ diff --git a/drivers/char/mem.c b/drivers/char/mem.c index b08dc50f9f26026730c5eb12ee8e4be47012c2f8..9eb564c002f66e221646c5225e69ff71b38f913e 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -97,6 +97,13 @@ void __weak unxlate_dev_mem_ptr(phys_addr_t phys, void *addr) } #endif +static inline bool should_stop_iteration(void) +{ + if (need_resched()) + cond_resched(); + return fatal_signal_pending(current); +} + /* * This funcion reads the *physical* memory. The f_pos points directly to the * memory location. @@ -175,6 +182,8 @@ static ssize_t read_mem(struct file *file, char __user *buf, p += sz; count -= sz; read += sz; + if (should_stop_iteration()) + break; } kfree(bounce); @@ -251,6 +260,8 @@ static ssize_t write_mem(struct file *file, const char __user *buf, p += sz; count -= sz; written += sz; + if (should_stop_iteration()) + break; } *ppos += written; @@ -468,6 +479,10 @@ static ssize_t read_kmem(struct file *file, char __user *buf, read += sz; low_count -= sz; count -= sz; + if (should_stop_iteration()) { + count = 0; + break; + } } } @@ -492,6 +507,8 @@ static ssize_t read_kmem(struct file *file, char __user *buf, buf += sz; read += sz; p += sz; + if (should_stop_iteration()) + break; } free_page((unsigned long)kbuf); } @@ -544,6 +561,8 @@ static ssize_t do_write_kmem(unsigned long p, const char __user *buf, p += sz; count -= sz; written += sz; + if (should_stop_iteration()) + break; } *ppos += written; @@ -595,6 +614,8 @@ static ssize_t write_kmem(struct file *file, const char __user *buf, buf += sz; virtr += sz; p += sz; + if (should_stop_iteration()) + break; } free_page((unsigned long)kbuf); } diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index e75c9df7c2d80b8404a335caf1363174a28bf36b..a9d9f074fbd65f2853d2294dbc6b5e9d04ddc0c7 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c @@ -9,11 +9,8 @@ * * This driver exports the SN special memory (mspec) facility to user * processes. - * There are three types of memory made available thru this driver: - * fetchops, uncached and cached. - * - * Fetchops are atomic memory operations that are implemented in the - * memory controller on SGI SN hardware. + * There are two types of memory made available thru this driver: + * uncached and cached. * * Uncached are used for memory write combining feature of the ia64 * cpu. @@ -46,16 +43,8 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#define FETCHOP_ID "SGI Fetchop," #define CACHED_ID "Cached," #define UNCACHED_ID "Uncached" #define REVISION "4.0" @@ -65,17 +54,10 @@ * Page types allocated by the device. */ enum mspec_page_type { - MSPEC_FETCHOP = 1, - MSPEC_CACHED, + MSPEC_CACHED = 2, MSPEC_UNCACHED }; -#ifdef CONFIG_SGI_SN -static int is_sn2; -#else -#define is_sn2 0 -#endif - /* * One of these structures is allocated when an mspec region is mmaped. The * structure is pointed to by the vma->vm_private_data field in the vma struct. @@ -96,39 +78,6 @@ struct vma_data { unsigned long maddr[0]; /* Array of MSPEC addresses. */ }; -/* used on shub2 to clear FOP cache in the HUB */ -static unsigned long scratch_page[MAX_NUMNODES]; -#define SH2_AMO_CACHE_ENTRIES 4 - -static inline int -mspec_zero_block(unsigned long addr, int len) -{ - int status; - - if (is_sn2) { - if (is_shub2()) { - int nid; - void *p; - int i; - - nid = nasid_to_cnodeid(get_node_number(__pa(addr))); - p = (void *)TO_AMO(scratch_page[nid]); - - for (i=0; i < SH2_AMO_CACHE_ENTRIES; i++) { - FETCHOP_LOAD_OP(p, FETCHOP_LOAD); - p += FETCHOP_VAR_SIZE; - } - } - - status = bte_copy(0, addr & ~__IA64_UNCACHED_OFFSET, len, - BTE_WACQUIRE | BTE_ZERO_FILL, NULL); - } else { - memset((char *) addr, 0, len); - status = 0; - } - return status; -} - /* * mspec_open * @@ -173,11 +122,8 @@ mspec_close(struct vm_area_struct *vma) */ my_page = vdata->maddr[index]; vdata->maddr[index] = 0; - if (!mspec_zero_block(my_page, PAGE_SIZE)) - uncached_free_page(my_page, 1); - else - printk(KERN_WARNING "mspec_close(): " - "failed to zero page %ld\n", my_page); + memset((char *)my_page, 0, PAGE_SIZE); + uncached_free_page(my_page, 1); } kvfree(vdata); @@ -213,11 +159,7 @@ mspec_fault(struct vm_fault *vmf) spin_unlock(&vdata->lock); } - if (vdata->type == MSPEC_FETCHOP) - paddr = TO_AMO(maddr); - else - paddr = maddr & ~__IA64_UNCACHED_OFFSET; - + paddr = maddr & ~__IA64_UNCACHED_OFFSET; pfn = paddr >> PAGE_SHIFT; return vmf_insert_pfn(vmf->vma, vmf->address, pfn); @@ -269,19 +211,13 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma, vma->vm_private_data = vdata; vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; - if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED) + if (vdata->type == MSPEC_UNCACHED) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_ops = &mspec_vm_ops; return 0; } -static int -fetchop_mmap(struct file *file, struct vm_area_struct *vma) -{ - return mspec_mmap(file, vma, MSPEC_FETCHOP); -} - static int cached_mmap(struct file *file, struct vm_area_struct *vma) { @@ -294,18 +230,6 @@ uncached_mmap(struct file *file, struct vm_area_struct *vma) return mspec_mmap(file, vma, MSPEC_UNCACHED); } -static const struct file_operations fetchop_fops = { - .owner = THIS_MODULE, - .mmap = fetchop_mmap, - .llseek = noop_llseek, -}; - -static struct miscdevice fetchop_miscdev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "sgi_fetchop", - .fops = &fetchop_fops -}; - static const struct file_operations cached_fops = { .owner = THIS_MODULE, .mmap = cached_mmap, @@ -339,89 +263,32 @@ static int __init mspec_init(void) { int ret; - int nid; - - /* - * The fetchop device only works on SN2 hardware, uncached and cached - * memory drivers should both be valid on all ia64 hardware - */ -#ifdef CONFIG_SGI_SN - if (ia64_platform_is("sn2")) { - is_sn2 = 1; - if (is_shub2()) { - ret = -ENOMEM; - for_each_node_state(nid, N_ONLINE) { - int actual_nid; - int nasid; - unsigned long phys; - - scratch_page[nid] = uncached_alloc_page(nid, 1); - if (scratch_page[nid] == 0) - goto free_scratch_pages; - phys = __pa(scratch_page[nid]); - nasid = get_node_number(phys); - actual_nid = nasid_to_cnodeid(nasid); - if (actual_nid != nid) - goto free_scratch_pages; - } - } - ret = misc_register(&fetchop_miscdev); - if (ret) { - printk(KERN_ERR - "%s: failed to register device %i\n", - FETCHOP_ID, ret); - goto free_scratch_pages; - } - } -#endif ret = misc_register(&cached_miscdev); if (ret) { printk(KERN_ERR "%s: failed to register device %i\n", CACHED_ID, ret); - if (is_sn2) - misc_deregister(&fetchop_miscdev); - goto free_scratch_pages; + return ret; } ret = misc_register(&uncached_miscdev); if (ret) { printk(KERN_ERR "%s: failed to register device %i\n", UNCACHED_ID, ret); misc_deregister(&cached_miscdev); - if (is_sn2) - misc_deregister(&fetchop_miscdev); - goto free_scratch_pages; + return ret; } - printk(KERN_INFO "%s %s initialized devices: %s %s %s\n", - MSPEC_BASENAME, REVISION, is_sn2 ? FETCHOP_ID : "", - CACHED_ID, UNCACHED_ID); + printk(KERN_INFO "%s %s initialized devices: %s %s\n", + MSPEC_BASENAME, REVISION, CACHED_ID, UNCACHED_ID); return 0; - - free_scratch_pages: - for_each_node(nid) { - if (scratch_page[nid] != 0) - uncached_free_page(scratch_page[nid], 1); - } - return ret; } static void __exit mspec_exit(void) { - int nid; - misc_deregister(&uncached_miscdev); misc_deregister(&cached_miscdev); - if (is_sn2) { - misc_deregister(&fetchop_miscdev); - - for_each_node(nid) { - if (scratch_page[nid] != 0) - uncached_free_page(scratch_page[nid], 1); - } - } } module_init(mspec_init); diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index f0a8adca1eeea9259c48147824e76123a7f86993..c86f18aa8985c9f89ef0c13ce08840c47db3d02e 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -737,7 +737,7 @@ static int pp_release(struct inode *inode, struct file *file) "negotiated back to compatibility mode because user-space forgot\n"); } - if (pp->flags & PP_CLAIMED) { + if ((pp->flags & PP_CLAIMED) && pp->pdev) { struct ieee1284_info *info; info = &pp->pdev->port->ieee1284; diff --git a/drivers/char/random.c b/drivers/char/random.c index 5d5ea4ce144293e3e99cc7b7bcc68250cf12df5b..d3beed084c0a56456da01da13cb127b7236d3e0b 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -327,6 +327,7 @@ #include #include #include +#include #include #include #include @@ -2439,9 +2440,24 @@ void add_hwgenerator_randomness(const char *buffer, size_t count, * We'll be woken up again once below random_write_wakeup_thresh, * or when the calling thread is about to terminate. */ - wait_event_interruptible(random_write_wait, kthread_should_stop() || + wait_event_freezable(random_write_wait, + kthread_should_stop() || ENTROPY_BITS(&input_pool) <= random_write_wakeup_bits); mix_pool_bytes(poolp, buffer, count); credit_entropy_bits(poolp, entropy); } EXPORT_SYMBOL_GPL(add_hwgenerator_randomness); + +/* Handle random seed passed by bootloader. + * If the seed is trustworthy, it would be regarded as hardware RNGs. Otherwise + * it would be regarded as device data. + * The decision is controlled by CONFIG_RANDOM_TRUST_BOOTLOADER. + */ +void add_bootloader_randomness(const void *buf, unsigned int size) +{ + if (IS_ENABLED(CONFIG_RANDOM_TRUST_BOOTLOADER)) + add_hwgenerator_randomness(buf, size, size * 8); + else + add_device_randomness(buf, size); +} +EXPORT_SYMBOL_GPL(add_bootloader_randomness); \ No newline at end of file diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c deleted file mode 100644 index 5918ea7499bb15b40ac05dc98d71a919fbac1881..0000000000000000000000000000000000000000 --- a/drivers/char/snsc.c +++ /dev/null @@ -1,469 +0,0 @@ -/* - * SN Platform system controller communication support - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2004, 2006 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * System controller communication driver - * - * This driver allows a user process to communicate with the system - * controller (a.k.a. "IRouter") network in an SGI SN system. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "snsc.h" - -#define SYSCTL_BASENAME "snsc" - -#define SCDRV_BUFSZ 2048 -#define SCDRV_TIMEOUT 1000 - -static DEFINE_MUTEX(scdrv_mutex); -static irqreturn_t -scdrv_interrupt(int irq, void *subch_data) -{ - struct subch_data_s *sd = subch_data; - unsigned long flags; - int status; - - spin_lock_irqsave(&sd->sd_rlock, flags); - spin_lock(&sd->sd_wlock); - status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch); - - if (status > 0) { - if (status & SAL_IROUTER_INTR_RECV) { - wake_up(&sd->sd_rq); - } - if (status & SAL_IROUTER_INTR_XMIT) { - ia64_sn_irtr_intr_disable - (sd->sd_nasid, sd->sd_subch, - SAL_IROUTER_INTR_XMIT); - wake_up(&sd->sd_wq); - } - } - spin_unlock(&sd->sd_wlock); - spin_unlock_irqrestore(&sd->sd_rlock, flags); - return IRQ_HANDLED; -} - -/* - * scdrv_open - * - * Reserve a subchannel for system controller communication. - */ - -static int -scdrv_open(struct inode *inode, struct file *file) -{ - struct sysctl_data_s *scd; - struct subch_data_s *sd; - int rv; - - /* look up device info for this device file */ - scd = container_of(inode->i_cdev, struct sysctl_data_s, scd_cdev); - - /* allocate memory for subchannel data */ - sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL); - if (sd == NULL) { - printk("%s: couldn't allocate subchannel data\n", - __func__); - return -ENOMEM; - } - - /* initialize subch_data_s fields */ - sd->sd_nasid = scd->scd_nasid; - sd->sd_subch = ia64_sn_irtr_open(scd->scd_nasid); - - if (sd->sd_subch < 0) { - kfree(sd); - printk("%s: couldn't allocate subchannel\n", __func__); - return -EBUSY; - } - - spin_lock_init(&sd->sd_rlock); - spin_lock_init(&sd->sd_wlock); - init_waitqueue_head(&sd->sd_rq); - init_waitqueue_head(&sd->sd_wq); - sema_init(&sd->sd_rbs, 1); - sema_init(&sd->sd_wbs, 1); - - file->private_data = sd; - - /* hook this subchannel up to the system controller interrupt */ - mutex_lock(&scdrv_mutex); - rv = request_irq(SGI_UART_VECTOR, scdrv_interrupt, - IRQF_SHARED, SYSCTL_BASENAME, sd); - if (rv) { - ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch); - kfree(sd); - printk("%s: irq request failed (%d)\n", __func__, rv); - mutex_unlock(&scdrv_mutex); - return -EBUSY; - } - mutex_unlock(&scdrv_mutex); - return 0; -} - -/* - * scdrv_release - * - * Release a previously-reserved subchannel. - */ - -static int -scdrv_release(struct inode *inode, struct file *file) -{ - struct subch_data_s *sd = (struct subch_data_s *) file->private_data; - int rv; - - /* free the interrupt */ - free_irq(SGI_UART_VECTOR, sd); - - /* ask SAL to close the subchannel */ - rv = ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch); - - kfree(sd); - return rv; -} - -/* - * scdrv_read - * - * Called to read bytes from the open IRouter pipe. - * - */ - -static inline int -read_status_check(struct subch_data_s *sd, int *len) -{ - return ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch, sd->sd_rb, len); -} - -static ssize_t -scdrv_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos) -{ - int status; - int len; - unsigned long flags; - struct subch_data_s *sd = (struct subch_data_s *) file->private_data; - - /* try to get control of the read buffer */ - if (down_trylock(&sd->sd_rbs)) { - /* somebody else has it now; - * if we're non-blocking, then exit... - */ - if (file->f_flags & O_NONBLOCK) { - return -EAGAIN; - } - /* ...or if we want to block, then do so here */ - if (down_interruptible(&sd->sd_rbs)) { - /* something went wrong with wait */ - return -ERESTARTSYS; - } - } - - /* anything to read? */ - len = CHUNKSIZE; - spin_lock_irqsave(&sd->sd_rlock, flags); - status = read_status_check(sd, &len); - - /* if not, and we're blocking I/O, loop */ - while (status < 0) { - DECLARE_WAITQUEUE(wait, current); - - if (file->f_flags & O_NONBLOCK) { - spin_unlock_irqrestore(&sd->sd_rlock, flags); - up(&sd->sd_rbs); - return -EAGAIN; - } - - len = CHUNKSIZE; - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&sd->sd_rq, &wait); - spin_unlock_irqrestore(&sd->sd_rlock, flags); - - schedule_timeout(msecs_to_jiffies(SCDRV_TIMEOUT)); - - remove_wait_queue(&sd->sd_rq, &wait); - if (signal_pending(current)) { - /* wait was interrupted */ - up(&sd->sd_rbs); - return -ERESTARTSYS; - } - - spin_lock_irqsave(&sd->sd_rlock, flags); - status = read_status_check(sd, &len); - } - spin_unlock_irqrestore(&sd->sd_rlock, flags); - - if (len > 0) { - /* we read something in the last read_status_check(); copy - * it out to user space - */ - if (count < len) { - pr_debug("%s: only accepting %d of %d bytes\n", - __func__, (int) count, len); - } - len = min((int) count, len); - if (copy_to_user(buf, sd->sd_rb, len)) - len = -EFAULT; - } - - /* release the read buffer and wake anyone who might be - * waiting for it - */ - up(&sd->sd_rbs); - - /* return the number of characters read in */ - return len; -} - -/* - * scdrv_write - * - * Writes a chunk of an IRouter packet (or other system controller data) - * to the system controller. - * - */ -static inline int -write_status_check(struct subch_data_s *sd, int count) -{ - return ia64_sn_irtr_send(sd->sd_nasid, sd->sd_subch, sd->sd_wb, count); -} - -static ssize_t -scdrv_write(struct file *file, const char __user *buf, - size_t count, loff_t *f_pos) -{ - unsigned long flags; - int status; - struct subch_data_s *sd = (struct subch_data_s *) file->private_data; - - /* try to get control of the write buffer */ - if (down_trylock(&sd->sd_wbs)) { - /* somebody else has it now; - * if we're non-blocking, then exit... - */ - if (file->f_flags & O_NONBLOCK) { - return -EAGAIN; - } - /* ...or if we want to block, then do so here */ - if (down_interruptible(&sd->sd_wbs)) { - /* something went wrong with wait */ - return -ERESTARTSYS; - } - } - - count = min((int) count, CHUNKSIZE); - if (copy_from_user(sd->sd_wb, buf, count)) { - up(&sd->sd_wbs); - return -EFAULT; - } - - /* try to send the buffer */ - spin_lock_irqsave(&sd->sd_wlock, flags); - status = write_status_check(sd, count); - - /* if we failed, and we want to block, then loop */ - while (status <= 0) { - DECLARE_WAITQUEUE(wait, current); - - if (file->f_flags & O_NONBLOCK) { - spin_unlock_irqrestore(&sd->sd_wlock, flags); - up(&sd->sd_wbs); - return -EAGAIN; - } - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&sd->sd_wq, &wait); - spin_unlock_irqrestore(&sd->sd_wlock, flags); - - schedule_timeout(msecs_to_jiffies(SCDRV_TIMEOUT)); - - remove_wait_queue(&sd->sd_wq, &wait); - if (signal_pending(current)) { - /* wait was interrupted */ - up(&sd->sd_wbs); - return -ERESTARTSYS; - } - - spin_lock_irqsave(&sd->sd_wlock, flags); - status = write_status_check(sd, count); - } - spin_unlock_irqrestore(&sd->sd_wlock, flags); - - /* release the write buffer and wake anyone who's waiting for it */ - up(&sd->sd_wbs); - - /* return the number of characters accepted (should be the complete - * "chunk" as requested) - */ - if ((status >= 0) && (status < count)) { - pr_debug("Didn't accept the full chunk; %d of %d\n", - status, (int) count); - } - return status; -} - -static __poll_t -scdrv_poll(struct file *file, struct poll_table_struct *wait) -{ - __poll_t mask = 0; - int status = 0; - struct subch_data_s *sd = (struct subch_data_s *) file->private_data; - unsigned long flags; - - poll_wait(file, &sd->sd_rq, wait); - poll_wait(file, &sd->sd_wq, wait); - - spin_lock_irqsave(&sd->sd_rlock, flags); - spin_lock(&sd->sd_wlock); - status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch); - spin_unlock(&sd->sd_wlock); - spin_unlock_irqrestore(&sd->sd_rlock, flags); - - if (status > 0) { - if (status & SAL_IROUTER_INTR_RECV) { - mask |= EPOLLIN | EPOLLRDNORM; - } - if (status & SAL_IROUTER_INTR_XMIT) { - mask |= EPOLLOUT | EPOLLWRNORM; - } - } - - return mask; -} - -static const struct file_operations scdrv_fops = { - .owner = THIS_MODULE, - .read = scdrv_read, - .write = scdrv_write, - .poll = scdrv_poll, - .open = scdrv_open, - .release = scdrv_release, - .llseek = noop_llseek, -}; - -static struct class *snsc_class; - -/* - * scdrv_init - * - * Called at boot time to initialize the system controller communication - * facility. - */ -int __init -scdrv_init(void) -{ - geoid_t geoid; - cnodeid_t cnode; - char devname[32]; - char *devnamep; - struct sysctl_data_s *scd; - void *salbuf; - dev_t first_dev, dev; - nasid_t event_nasid; - - if (!ia64_platform_is("sn2")) - return -ENODEV; - - event_nasid = ia64_sn_get_console_nasid(); - - snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME); - if (IS_ERR(snsc_class)) { - printk("%s: failed to allocate class\n", __func__); - return PTR_ERR(snsc_class); - } - - if (alloc_chrdev_region(&first_dev, 0, num_cnodes, - SYSCTL_BASENAME) < 0) { - printk("%s: failed to register SN system controller device\n", - __func__); - return -ENODEV; - } - - for (cnode = 0; cnode < num_cnodes; cnode++) { - geoid = cnodeid_get_geoid(cnode); - devnamep = devname; - format_module_id(devnamep, geo_module(geoid), - MODULE_FORMAT_BRIEF); - devnamep = devname + strlen(devname); - sprintf(devnamep, "^%d#%d", geo_slot(geoid), - geo_slab(geoid)); - - /* allocate sysctl device data */ - scd = kzalloc(sizeof (struct sysctl_data_s), - GFP_KERNEL); - if (!scd) { - printk("%s: failed to allocate device info" - "for %s/%s\n", __func__, - SYSCTL_BASENAME, devname); - continue; - } - - /* initialize sysctl device data fields */ - scd->scd_nasid = cnodeid_to_nasid(cnode); - if (!(salbuf = kmalloc(SCDRV_BUFSZ, GFP_KERNEL))) { - printk("%s: failed to allocate driver buffer" - "(%s%s)\n", __func__, - SYSCTL_BASENAME, devname); - kfree(scd); - continue; - } - - if (ia64_sn_irtr_init(scd->scd_nasid, salbuf, - SCDRV_BUFSZ) < 0) { - printk - ("%s: failed to initialize SAL for" - " system controller communication" - " (%s/%s): outdated PROM?\n", - __func__, SYSCTL_BASENAME, devname); - kfree(scd); - kfree(salbuf); - continue; - } - - dev = first_dev + cnode; - cdev_init(&scd->scd_cdev, &scdrv_fops); - if (cdev_add(&scd->scd_cdev, dev, 1)) { - printk("%s: failed to register system" - " controller device (%s%s)\n", - __func__, SYSCTL_BASENAME, devname); - kfree(scd); - kfree(salbuf); - continue; - } - - device_create(snsc_class, NULL, dev, NULL, - "%s", devname); - - ia64_sn_irtr_intr_enable(scd->scd_nasid, - 0 /*ignored */ , - SAL_IROUTER_INTR_RECV); - - /* on the console nasid, prepare to receive - * system controller environmental events - */ - if(scd->scd_nasid == event_nasid) { - scdrv_event_init(scd); - } - } - return 0; -} -device_initcall(scdrv_init); diff --git a/drivers/char/snsc.h b/drivers/char/snsc.h deleted file mode 100644 index e8c52c882b210aa87b0f76ddaa2ac3e714eb1c53..0000000000000000000000000000000000000000 --- a/drivers/char/snsc.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * SN Platform system controller communication support - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2004-2006 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * This file contains macros and data types for communication with the - * system controllers in SGI SN systems. - */ - -#ifndef _SN_SYSCTL_H_ -#define _SN_SYSCTL_H_ - -#include -#include -#include -#include -#include -#include -#include - -#define CHUNKSIZE 127 - -/* This structure is used to track an open subchannel. */ -struct subch_data_s { - nasid_t sd_nasid; /* node on which the subchannel was opened */ - int sd_subch; /* subchannel number */ - spinlock_t sd_rlock; /* monitor lock for rsv */ - spinlock_t sd_wlock; /* monitor lock for wsv */ - wait_queue_head_t sd_rq; /* wait queue for readers */ - wait_queue_head_t sd_wq; /* wait queue for writers */ - struct semaphore sd_rbs; /* semaphore for read buffer */ - struct semaphore sd_wbs; /* semaphore for write buffer */ - - char sd_rb[CHUNKSIZE]; /* read buffer */ - char sd_wb[CHUNKSIZE]; /* write buffer */ -}; - -struct sysctl_data_s { - struct cdev scd_cdev; /* Character device info */ - nasid_t scd_nasid; /* Node on which subchannels are opened. */ -}; - - -/* argument types */ -#define IR_ARG_INT 0x00 /* 4-byte integer (big-endian) */ -#define IR_ARG_ASCII 0x01 /* null-terminated ASCII string */ -#define IR_ARG_UNKNOWN 0x80 /* unknown data type. The low - * 7 bits will contain the data - * length. */ -#define IR_ARG_UNKNOWN_LENGTH_MASK 0x7f - - -/* system controller event codes */ -#define EV_CLASS_MASK 0xf000ul -#define EV_SEVERITY_MASK 0x0f00ul -#define EV_COMPONENT_MASK 0x00fful - -#define EV_CLASS_POWER 0x1000ul -#define EV_CLASS_FAN 0x2000ul -#define EV_CLASS_TEMP 0x3000ul -#define EV_CLASS_ENV 0x4000ul -#define EV_CLASS_TEST_FAULT 0x5000ul -#define EV_CLASS_TEST_WARNING 0x6000ul -#define EV_CLASS_PWRD_NOTIFY 0x8000ul - -/* ENV class codes */ -#define ENV_PWRDN_PEND 0x4101ul - -#define EV_SEVERITY_POWER_STABLE 0x0000ul -#define EV_SEVERITY_POWER_LOW_WARNING 0x0100ul -#define EV_SEVERITY_POWER_HIGH_WARNING 0x0200ul -#define EV_SEVERITY_POWER_HIGH_FAULT 0x0300ul -#define EV_SEVERITY_POWER_LOW_FAULT 0x0400ul - -#define EV_SEVERITY_FAN_STABLE 0x0000ul -#define EV_SEVERITY_FAN_WARNING 0x0100ul -#define EV_SEVERITY_FAN_FAULT 0x0200ul - -#define EV_SEVERITY_TEMP_STABLE 0x0000ul -#define EV_SEVERITY_TEMP_ADVISORY 0x0100ul -#define EV_SEVERITY_TEMP_CRITICAL 0x0200ul -#define EV_SEVERITY_TEMP_FAULT 0x0300ul - -void scdrv_event_init(struct sysctl_data_s *); - -#endif /* _SN_SYSCTL_H_ */ diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c deleted file mode 100644 index e452673dff66128f33505e96b4b7e007038ddb78..0000000000000000000000000000000000000000 --- a/drivers/char/snsc_event.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * SN Platform system controller communication support - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2004-2006 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * System controller event handler - * - * These routines deal with environmental events arriving from the - * system controllers. - */ - -#include -#include -#include -#include -#include -#include -#include "snsc.h" - -static struct subch_data_s *event_sd; - -void scdrv_event(unsigned long); -DECLARE_TASKLET(sn_sysctl_event, scdrv_event, 0); - -/* - * scdrv_event_interrupt - * - * Pull incoming environmental events off the physical link to the - * system controller and put them in a temporary holding area in SAL. - * Schedule scdrv_event() to move them along to their ultimate - * destination. - */ -static irqreturn_t -scdrv_event_interrupt(int irq, void *subch_data) -{ - struct subch_data_s *sd = subch_data; - unsigned long flags; - int status; - - spin_lock_irqsave(&sd->sd_rlock, flags); - status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch); - - if ((status > 0) && (status & SAL_IROUTER_INTR_RECV)) { - tasklet_schedule(&sn_sysctl_event); - } - spin_unlock_irqrestore(&sd->sd_rlock, flags); - return IRQ_HANDLED; -} - - -/* - * scdrv_parse_event - * - * Break an event (as read from SAL) into useful pieces so we can decide - * what to do with it. - */ -static int -scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc) -{ - char *desc_end; - - /* record event source address */ - *src = get_unaligned_be32(event); - event += 4; /* move on to event code */ - - /* record the system controller's event code */ - *code = get_unaligned_be32(event); - event += 4; /* move on to event arguments */ - - /* how many arguments are in the packet? */ - if (*event++ != 2) { - /* if not 2, give up */ - return -1; - } - - /* parse out the ESP code */ - if (*event++ != IR_ARG_INT) { - /* not an integer argument, so give up */ - return -1; - } - *esp_code = get_unaligned_be32(event); - event += 4; - - /* parse out the event description */ - if (*event++ != IR_ARG_ASCII) { - /* not an ASCII string, so give up */ - return -1; - } - event[CHUNKSIZE-1] = '\0'; /* ensure this string ends! */ - event += 2; /* skip leading CR/LF */ - desc_end = desc + sprintf(desc, "%s", event); - - /* strip trailing CR/LF (if any) */ - for (desc_end--; - (desc_end != desc) && ((*desc_end == 0xd) || (*desc_end == 0xa)); - desc_end--) { - *desc_end = '\0'; - } - - return 0; -} - - -/* - * scdrv_event_severity - * - * Figure out how urgent a message we should write to the console/syslog - * via printk. - */ -static char * -scdrv_event_severity(int code) -{ - int ev_class = (code & EV_CLASS_MASK); - int ev_severity = (code & EV_SEVERITY_MASK); - char *pk_severity = KERN_NOTICE; - - switch (ev_class) { - case EV_CLASS_POWER: - switch (ev_severity) { - case EV_SEVERITY_POWER_LOW_WARNING: - case EV_SEVERITY_POWER_HIGH_WARNING: - pk_severity = KERN_WARNING; - break; - case EV_SEVERITY_POWER_HIGH_FAULT: - case EV_SEVERITY_POWER_LOW_FAULT: - pk_severity = KERN_ALERT; - break; - } - break; - case EV_CLASS_FAN: - switch (ev_severity) { - case EV_SEVERITY_FAN_WARNING: - pk_severity = KERN_WARNING; - break; - case EV_SEVERITY_FAN_FAULT: - pk_severity = KERN_CRIT; - break; - } - break; - case EV_CLASS_TEMP: - switch (ev_severity) { - case EV_SEVERITY_TEMP_ADVISORY: - pk_severity = KERN_WARNING; - break; - case EV_SEVERITY_TEMP_CRITICAL: - pk_severity = KERN_CRIT; - break; - case EV_SEVERITY_TEMP_FAULT: - pk_severity = KERN_ALERT; - break; - } - break; - case EV_CLASS_ENV: - pk_severity = KERN_ALERT; - break; - case EV_CLASS_TEST_FAULT: - pk_severity = KERN_ALERT; - break; - case EV_CLASS_TEST_WARNING: - pk_severity = KERN_WARNING; - break; - case EV_CLASS_PWRD_NOTIFY: - pk_severity = KERN_ALERT; - break; - } - - return pk_severity; -} - - -/* - * scdrv_dispatch_event - * - * Do the right thing with an incoming event. That's often nothing - * more than printing it to the system log. For power-down notifications - * we start a graceful shutdown. - */ -static void -scdrv_dispatch_event(char *event, int len) -{ - static int snsc_shutting_down = 0; - int code, esp_code, src, class; - char desc[CHUNKSIZE]; - char *severity; - - if (scdrv_parse_event(event, &src, &code, &esp_code, desc) < 0) { - /* ignore uninterpretible event */ - return; - } - - /* how urgent is the message? */ - severity = scdrv_event_severity(code); - - class = (code & EV_CLASS_MASK); - - if (class == EV_CLASS_PWRD_NOTIFY || code == ENV_PWRDN_PEND) { - if (snsc_shutting_down) - return; - - snsc_shutting_down = 1; - - /* give a message for each type of event */ - if (class == EV_CLASS_PWRD_NOTIFY) - printk(KERN_NOTICE "Power off indication received." - " Sending SIGPWR to init...\n"); - else if (code == ENV_PWRDN_PEND) - printk(KERN_CRIT "WARNING: Shutting down the system" - " due to a critical environmental condition." - " Sending SIGPWR to init...\n"); - - /* give a SIGPWR signal to init proc */ - kill_cad_pid(SIGPWR, 0); - } else { - /* print to system log */ - printk("%s|$(0x%x)%s\n", severity, esp_code, desc); - } -} - - -/* - * scdrv_event - * - * Called as a tasklet when an event arrives from the L1. Read the event - * from where it's temporarily stored in SAL and call scdrv_dispatch_event() - * to send it on its way. Keep trying to read events until SAL indicates - * that there are no more immediately available. - */ -void -scdrv_event(unsigned long dummy) -{ - int status; - int len; - unsigned long flags; - struct subch_data_s *sd = event_sd; - - /* anything to read? */ - len = CHUNKSIZE; - spin_lock_irqsave(&sd->sd_rlock, flags); - status = ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch, - sd->sd_rb, &len); - - while (!(status < 0)) { - spin_unlock_irqrestore(&sd->sd_rlock, flags); - scdrv_dispatch_event(sd->sd_rb, len); - len = CHUNKSIZE; - spin_lock_irqsave(&sd->sd_rlock, flags); - status = ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch, - sd->sd_rb, &len); - } - spin_unlock_irqrestore(&sd->sd_rlock, flags); -} - - -/* - * scdrv_event_init - * - * Sets up a system controller subchannel to begin receiving event - * messages. This is sort of a specialized version of scdrv_open() - * in drivers/char/sn_sysctl.c. - */ -void -scdrv_event_init(struct sysctl_data_s *scd) -{ - int rv; - - event_sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL); - if (event_sd == NULL) { - printk(KERN_WARNING "%s: couldn't allocate subchannel info" - " for event monitoring\n", __func__); - return; - } - - /* initialize subch_data_s fields */ - event_sd->sd_nasid = scd->scd_nasid; - spin_lock_init(&event_sd->sd_rlock); - - /* ask the system controllers to send events to this node */ - event_sd->sd_subch = ia64_sn_sysctl_event_init(scd->scd_nasid); - - if (event_sd->sd_subch < 0) { - kfree(event_sd); - printk(KERN_WARNING "%s: couldn't open event subchannel\n", - __func__); - return; - } - - /* hook event subchannel up to the system controller interrupt */ - rv = request_irq(SGI_UART_VECTOR, scdrv_event_interrupt, - IRQF_SHARED, "system controller events", event_sd); - if (rv) { - printk(KERN_WARNING "%s: irq request failed (%d)\n", - __func__, rv); - ia64_sn_irtr_close(event_sd->sd_nasid, event_sd->sd_subch); - kfree(event_sd); - return; - } -} diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index 0bdc602f0d48d9d8d61597108ecc6bf18ef42804..98f3150e00483fa3b047d7489c4e240080427c62 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -373,7 +373,7 @@ static int tosh_get_machine_id(void __iomem *bios) value. This has been verified on a Satellite Pro 430CDT, Tecra 750CDT, Tecra 780DVD and Satellite 310CDT. */ #if TOSH_DEBUG - printk("toshiba: debugging ID ebx=0x%04x\n", regs.ebx); + pr_debug("toshiba: debugging ID ebx=0x%04x\n", regs.ebx); #endif bx = 0xe6f5; @@ -417,7 +417,7 @@ static int tosh_probe(void) for (i=0;i<7;i++) { if (readb(bios+0xe010+i)!=signature[i]) { - printk("toshiba: not a supported Toshiba laptop\n"); + pr_err("toshiba: not a supported Toshiba laptop\n"); iounmap(bios); return -ENODEV; } @@ -433,7 +433,7 @@ static int tosh_probe(void) /* if this is not a Toshiba laptop carry flag is set and ah=0x86 */ if ((flag==1) || ((regs.eax & 0xff00)==0x8600)) { - printk("toshiba: not a supported Toshiba laptop\n"); + pr_err("toshiba: not a supported Toshiba laptop\n"); iounmap(bios); return -ENODEV; } @@ -486,7 +486,7 @@ static int __init toshiba_init(void) if (tosh_probe()) return -ENODEV; - printk(KERN_INFO "Toshiba System Management Mode driver v" TOSH_VERSION "\n"); + pr_info("Toshiba System Management Mode driver v" TOSH_VERSION "\n"); /* set the port to use for Fn status if not specified as a parameter */ if (tosh_fn==0x00) diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 88a3c06fc153e087640460a4c52713377729a1b5..9c37047f4b5625b8ea3fd5b3b93796729d1b4bdc 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -164,6 +164,11 @@ config TCG_VTPM_PROXY /dev/vtpmX and a server-side file descriptor on which the vTPM can receive commands. +config TCG_FTPM_TEE + tristate "TEE based fTPM Interface" + depends on TEE && OPTEE + help + This driver proxies for firmware TPM running in TEE. source "drivers/char/tpm/st33zp24/Kconfig" endif # TCG_TPM diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index a01c4cab902a662bd842427e2708bbbfd8fbc660..c354cdff9c625fad7f813a269924053de0293a32 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -33,3 +33,4 @@ obj-$(CONFIG_TCG_TIS_ST33ZP24) += st33zp24/ obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o obj-$(CONFIG_TCG_CRB) += tpm_crb.o obj-$(CONFIG_TCG_VTPM_PROXY) += tpm_vtpm_proxy.o +obj-$(CONFIG_TCG_FTPM_TEE) += tpm_ftpm_tee.o diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 4838c6a9f0f2c702e932066fba62d7a336a87f36..3d6d394a866188107f48495298dfe5a43d8e93f0 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -287,12 +287,9 @@ static void tpm_devs_release(struct device *dev) * @dev: device to which the chip is associated. * * Issues a TPM2_Shutdown command prior to loss of power, as required by the - * TPM 2.0 spec. - * Then, calls bus- and device- specific shutdown code. + * TPM 2.0 spec. Then, calls bus- and device- specific shutdown code. * - * XXX: This codepath relies on the fact that sysfs is not enabled for - * TPM2: sysfs uses an implicit lock on chip->ops, so this could race if TPM2 - * has sysfs support enabled before TPM sysfs's implicit locking is fixed. + * Return: always 0 (i.e. success) */ static int tpm_class_shutdown(struct device *dev) { diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index d9caedda075b2f5e690b5a34f086e1902ac774b4..edfa89160010c5cf29e1d2d4e76016323a45e306 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -329,16 +329,9 @@ static const struct attribute_group tpm_dev_group = { void tpm_sysfs_add_device(struct tpm_chip *chip) { - /* XXX: If you wish to remove this restriction, you must first update - * tpm_sysfs to explicitly lock chip->ops. - */ if (chip->flags & TPM_CHIP_FLAG_TPM2) return; - /* The sysfs routines rely on an implicit tpm_try_get_ops, device_del - * is called before ops is null'd and the sysfs core synchronizes this - * removal so that no callbacks are running or can run again - */ WARN_ON(chip->groups_cnt != 0); chip->groups[chip->groups_cnt++] = &tpm_dev_group; } diff --git a/drivers/char/tpm/tpm_ftpm_tee.c b/drivers/char/tpm/tpm_ftpm_tee.c new file mode 100644 index 0000000000000000000000000000000000000000..6640a14dbe48cf137f2ed5212e699888730cfebd --- /dev/null +++ b/drivers/char/tpm/tpm_ftpm_tee.c @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Microsoft Corporation + * + * Implements a firmware TPM as described here: + * https://www.microsoft.com/en-us/research/publication/ftpm-software-implementation-tpm-chip/ + * + * A reference implementation is available here: + * https://github.com/microsoft/ms-tpm-20-ref/tree/master/Samples/ARM32-FirmwareTPM/optee_ta/fTPM + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "tpm.h" +#include "tpm_ftpm_tee.h" + +/* + * TA_FTPM_UUID: BC50D971-D4C9-42C4-82CB-343FB7F37896 + * + * Randomly generated, and must correspond to the GUID on the TA side. + * Defined here in the reference implementation: + * https://github.com/microsoft/ms-tpm-20-ref/blob/master/Samples/ARM32-FirmwareTPM/optee_ta/fTPM/include/fTPM.h#L42 + */ +static const uuid_t ftpm_ta_uuid = + UUID_INIT(0xBC50D971, 0xD4C9, 0x42C4, + 0x82, 0xCB, 0x34, 0x3F, 0xB7, 0xF3, 0x78, 0x96); + +/** + * ftpm_tee_tpm_op_recv - retrieve fTPM response. + * @chip: the tpm_chip description as specified in driver/char/tpm/tpm.h. + * @buf: the buffer to store data. + * @count: the number of bytes to read. + * + * Return: + * In case of success the number of bytes received. + * On failure, -errno. + */ +static int ftpm_tee_tpm_op_recv(struct tpm_chip *chip, u8 *buf, size_t count) +{ + struct ftpm_tee_private *pvt_data = dev_get_drvdata(chip->dev.parent); + size_t len; + + len = pvt_data->resp_len; + if (count < len) { + dev_err(&chip->dev, + "%s: Invalid size in recv: count=%zd, resp_len=%zd\n", + __func__, count, len); + return -EIO; + } + + memcpy(buf, pvt_data->resp_buf, len); + pvt_data->resp_len = 0; + + return len; +} + +/** + * ftpm_tee_tpm_op_send - send TPM commands through the TEE shared memory. + * @chip: the tpm_chip description as specified in driver/char/tpm/tpm.h + * @buf: the buffer to send. + * @len: the number of bytes to send. + * + * Return: + * In case of success, returns 0. + * On failure, -errno + */ +static int ftpm_tee_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t len) +{ + struct ftpm_tee_private *pvt_data = dev_get_drvdata(chip->dev.parent); + size_t resp_len; + int rc; + u8 *temp_buf; + struct tpm_header *resp_header; + struct tee_ioctl_invoke_arg transceive_args; + struct tee_param command_params[4]; + struct tee_shm *shm = pvt_data->shm; + + if (len > MAX_COMMAND_SIZE) { + dev_err(&chip->dev, + "%s: len=%zd exceeds MAX_COMMAND_SIZE supported by fTPM TA\n", + __func__, len); + return -EIO; + } + + memset(&transceive_args, 0, sizeof(transceive_args)); + memset(command_params, 0, sizeof(command_params)); + pvt_data->resp_len = 0; + + /* Invoke FTPM_OPTEE_TA_SUBMIT_COMMAND function of fTPM TA */ + transceive_args = (struct tee_ioctl_invoke_arg) { + .func = FTPM_OPTEE_TA_SUBMIT_COMMAND, + .session = pvt_data->session, + .num_params = 4, + }; + + /* Fill FTPM_OPTEE_TA_SUBMIT_COMMAND parameters */ + command_params[0] = (struct tee_param) { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT, + .u.memref = { + .shm = shm, + .size = len, + .shm_offs = 0, + }, + }; + + temp_buf = tee_shm_get_va(shm, 0); + if (IS_ERR(temp_buf)) { + dev_err(&chip->dev, "%s: tee_shm_get_va failed for transmit\n", + __func__); + return PTR_ERR(temp_buf); + } + memset(temp_buf, 0, (MAX_COMMAND_SIZE + MAX_RESPONSE_SIZE)); + memcpy(temp_buf, buf, len); + + command_params[1] = (struct tee_param) { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT, + .u.memref = { + .shm = shm, + .size = MAX_RESPONSE_SIZE, + .shm_offs = MAX_COMMAND_SIZE, + }, + }; + + rc = tee_client_invoke_func(pvt_data->ctx, &transceive_args, + command_params); + if ((rc < 0) || (transceive_args.ret != 0)) { + dev_err(&chip->dev, "%s: SUBMIT_COMMAND invoke error: 0x%x\n", + __func__, transceive_args.ret); + return (rc < 0) ? rc : transceive_args.ret; + } + + temp_buf = tee_shm_get_va(shm, command_params[1].u.memref.shm_offs); + if (IS_ERR(temp_buf)) { + dev_err(&chip->dev, "%s: tee_shm_get_va failed for receive\n", + __func__); + return PTR_ERR(temp_buf); + } + + resp_header = (struct tpm_header *)temp_buf; + resp_len = be32_to_cpu(resp_header->length); + + /* sanity check resp_len */ + if (resp_len < TPM_HEADER_SIZE) { + dev_err(&chip->dev, "%s: tpm response header too small\n", + __func__); + return -EIO; + } + if (resp_len > MAX_RESPONSE_SIZE) { + dev_err(&chip->dev, + "%s: resp_len=%zd exceeds MAX_RESPONSE_SIZE\n", + __func__, resp_len); + return -EIO; + } + + /* sanity checks look good, cache the response */ + memcpy(pvt_data->resp_buf, temp_buf, resp_len); + pvt_data->resp_len = resp_len; + + return 0; +} + +static void ftpm_tee_tpm_op_cancel(struct tpm_chip *chip) +{ + /* not supported */ +} + +static u8 ftpm_tee_tpm_op_status(struct tpm_chip *chip) +{ + return 0; +} + +static bool ftpm_tee_tpm_req_canceled(struct tpm_chip *chip, u8 status) +{ + return 0; +} + +static const struct tpm_class_ops ftpm_tee_tpm_ops = { + .flags = TPM_OPS_AUTO_STARTUP, + .recv = ftpm_tee_tpm_op_recv, + .send = ftpm_tee_tpm_op_send, + .cancel = ftpm_tee_tpm_op_cancel, + .status = ftpm_tee_tpm_op_status, + .req_complete_mask = 0, + .req_complete_val = 0, + .req_canceled = ftpm_tee_tpm_req_canceled, +}; + +/* + * Check whether this driver supports the fTPM TA in the TEE instance + * represented by the params (ver/data) to this function. + */ +static int ftpm_tee_match(struct tee_ioctl_version_data *ver, const void *data) +{ + /* + * Currently this driver only support GP Complaint OPTEE based fTPM TA + */ + if ((ver->impl_id == TEE_IMPL_ID_OPTEE) && + (ver->gen_caps & TEE_GEN_CAP_GP)) + return 1; + else + return 0; +} + +/** + * ftpm_tee_probe - initialize the fTPM + * @pdev: the platform_device description. + * + * Return: + * On success, 0. On failure, -errno. + */ +static int ftpm_tee_probe(struct platform_device *pdev) +{ + int rc; + struct tpm_chip *chip; + struct device *dev = &pdev->dev; + struct ftpm_tee_private *pvt_data = NULL; + struct tee_ioctl_open_session_arg sess_arg; + + pvt_data = devm_kzalloc(dev, sizeof(struct ftpm_tee_private), + GFP_KERNEL); + if (!pvt_data) + return -ENOMEM; + + dev_set_drvdata(dev, pvt_data); + + /* Open context with TEE driver */ + pvt_data->ctx = tee_client_open_context(NULL, ftpm_tee_match, NULL, + NULL); + if (IS_ERR(pvt_data->ctx)) { + if (PTR_ERR(pvt_data->ctx) == -ENOENT) + return -EPROBE_DEFER; + dev_err(dev, "%s: tee_client_open_context failed\n", __func__); + return PTR_ERR(pvt_data->ctx); + } + + /* Open a session with fTPM TA */ + memset(&sess_arg, 0, sizeof(sess_arg)); + memcpy(sess_arg.uuid, ftpm_ta_uuid.b, TEE_IOCTL_UUID_LEN); + sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC; + sess_arg.num_params = 0; + + rc = tee_client_open_session(pvt_data->ctx, &sess_arg, NULL); + if ((rc < 0) || (sess_arg.ret != 0)) { + dev_err(dev, "%s: tee_client_open_session failed, err=%x\n", + __func__, sess_arg.ret); + rc = -EINVAL; + goto out_tee_session; + } + pvt_data->session = sess_arg.session; + + /* Allocate dynamic shared memory with fTPM TA */ + pvt_data->shm = tee_shm_alloc(pvt_data->ctx, + MAX_COMMAND_SIZE + MAX_RESPONSE_SIZE, + TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); + if (IS_ERR(pvt_data->shm)) { + dev_err(dev, "%s: tee_shm_alloc failed\n", __func__); + rc = -ENOMEM; + goto out_shm_alloc; + } + + /* Allocate new struct tpm_chip instance */ + chip = tpm_chip_alloc(dev, &ftpm_tee_tpm_ops); + if (IS_ERR(chip)) { + dev_err(dev, "%s: tpm_chip_alloc failed\n", __func__); + rc = PTR_ERR(chip); + goto out_chip_alloc; + } + + pvt_data->chip = chip; + pvt_data->chip->flags |= TPM_CHIP_FLAG_TPM2; + + /* Create a character device for the fTPM */ + rc = tpm_chip_register(pvt_data->chip); + if (rc) { + dev_err(dev, "%s: tpm_chip_register failed with rc=%d\n", + __func__, rc); + goto out_chip; + } + + return 0; + +out_chip: + put_device(&pvt_data->chip->dev); +out_chip_alloc: + tee_shm_free(pvt_data->shm); +out_shm_alloc: + tee_client_close_session(pvt_data->ctx, pvt_data->session); +out_tee_session: + tee_client_close_context(pvt_data->ctx); + + return rc; +} + +/** + * ftpm_tee_remove - remove the TPM device + * @pdev: the platform_device description. + * + * Return: + * 0 always. + */ +static int ftpm_tee_remove(struct platform_device *pdev) +{ + struct ftpm_tee_private *pvt_data = dev_get_drvdata(&pdev->dev); + + /* Release the chip */ + tpm_chip_unregister(pvt_data->chip); + + /* frees chip */ + put_device(&pvt_data->chip->dev); + + /* Free the shared memory pool */ + tee_shm_free(pvt_data->shm); + + /* close the existing session with fTPM TA*/ + tee_client_close_session(pvt_data->ctx, pvt_data->session); + + /* close the context with TEE driver */ + tee_client_close_context(pvt_data->ctx); + + /* memory allocated with devm_kzalloc() is freed automatically */ + + return 0; +} + +static const struct of_device_id of_ftpm_tee_ids[] = { + { .compatible = "microsoft,ftpm" }, + { } +}; +MODULE_DEVICE_TABLE(of, of_ftpm_tee_ids); + +static struct platform_driver ftpm_tee_driver = { + .driver = { + .name = "ftpm-tee", + .of_match_table = of_match_ptr(of_ftpm_tee_ids), + }, + .probe = ftpm_tee_probe, + .remove = ftpm_tee_remove, +}; + +module_platform_driver(ftpm_tee_driver); + +MODULE_AUTHOR("Thirupathaiah Annapureddy "); +MODULE_DESCRIPTION("TPM Driver for fTPM TA in TEE"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/char/tpm/tpm_ftpm_tee.h b/drivers/char/tpm/tpm_ftpm_tee.h new file mode 100644 index 0000000000000000000000000000000000000000..f98daa7bf68cf6c78e3249cd391cfc15bf3c9963 --- /dev/null +++ b/drivers/char/tpm/tpm_ftpm_tee.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Microsoft Corporation + */ + +#ifndef __TPM_FTPM_TEE_H__ +#define __TPM_FTPM_TEE_H__ + +#include +#include +#include + +/* The TAFs ID implemented in this TA */ +#define FTPM_OPTEE_TA_SUBMIT_COMMAND (0) +#define FTPM_OPTEE_TA_EMULATE_PPI (1) + +/* max. buffer size supported by fTPM */ +#define MAX_COMMAND_SIZE 4096 +#define MAX_RESPONSE_SIZE 4096 + +/** + * struct ftpm_tee_private - fTPM's private data + * @chip: struct tpm_chip instance registered with tpm framework. + * @state: internal state + * @session: fTPM TA session identifier. + * @resp_len: cached response buffer length. + * @resp_buf: cached response buffer. + * @ctx: TEE context handler. + * @shm: Memory pool shared with fTPM TA in TEE. + */ +struct ftpm_tee_private { + struct tpm_chip *chip; + u32 session; + size_t resp_len; + u8 resp_buf[MAX_RESPONSE_SIZE]; + struct tee_context *ctx; + struct tee_shm *shm; +}; + +#endif /* __TPM_FTPM_TEE_H__ */ diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index c3181ea9f27132e4013c6a1c86612d296a803c3d..270f43acbb77d485939c13c55026b9a942110bb1 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -980,6 +980,8 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, goto out_err; } + tpm_chip_start(chip); + chip->flags |= TPM_CHIP_FLAG_IRQ; if (irq) { tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED, irq); @@ -989,6 +991,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, } else { tpm_tis_probe_irq(chip, intmask); } + tpm_chip_stop(chip); } rc = tpm_chip_register(chip); diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c index a2287c770d5c07408365b89a49450c554f48d55a..886f7c5df51a919cadb74d1161438a7607554105 100644 --- a/drivers/clk/clk-scmi.c +++ b/drivers/clk/clk-scmi.c @@ -69,7 +69,7 @@ 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, 0, rate); + return clk->handle->clk_ops->rate_set(clk->handle, clk->id, rate); } static int scmi_clk_enable(struct clk_hw *hw) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 1c46babeb09330e8e2a98060ad310fabba65aa2d..ca99e9db657587995dcd83efb49b194b91fa3be7 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2510,6 +2510,12 @@ static int clk_core_set_parent_nolock(struct clk_core *core, return ret; } +int clk_hw_set_parent(struct clk_hw *hw, struct clk_hw *parent) +{ + return clk_core_set_parent_nolock(hw->core, parent->core); +} +EXPORT_SYMBOL_GPL(clk_hw_set_parent); + /** * clk_set_parent - switch the parent of a mux clk * @clk: the mux clk whose input we are switching diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig index 0eaf418482800d5593586c1cfa290ea1fc07e178..1ac0c7990392d74f7c62726b6bb94f66f56545a3 100644 --- a/drivers/clk/imx/Kconfig +++ b/drivers/clk/imx/Kconfig @@ -14,6 +14,12 @@ config CLK_IMX8MM help Build the driver for i.MX8MM CCM Clock Driver +config CLK_IMX8MN + bool "IMX8MN CCM Clock Driver" + depends on ARCH_MXC && ARM64 + help + Build the driver for i.MX8MN CCM Clock Driver + config CLK_IMX8MQ bool "IMX8MQ CCM Clock Driver" depends on ARCH_MXC && ARM64 diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 05641c64b31740566621a9b0ef7d858430d2b6ee..77a3d714f1d59986395f7e6e694e204a4739a4d3 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_MXC_CLK_SCU) += \ clk-lpcg-scu.o obj-$(CONFIG_CLK_IMX8MM) += clk-imx8mm.o +obj-$(CONFIG_CLK_IMX8MN) += clk-imx8mn.o obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o obj-$(CONFIG_CLK_IMX8QXP) += clk-imx8qxp.o clk-imx8qxp-lpcg.o diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 6b8e75df994d387d47af89d7d19449aef72a0a16..43fa9c361fcb9021fa095819e1387dbb0d77f901 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -26,23 +26,6 @@ static u32 share_count_dcss; static u32 share_count_pdm; static u32 share_count_nand; -#define PLL_1416X_RATE(_rate, _m, _p, _s) \ - { \ - .rate = (_rate), \ - .mdiv = (_m), \ - .pdiv = (_p), \ - .sdiv = (_s), \ - } - -#define PLL_1443X_RATE(_rate, _m, _p, _s, _k) \ - { \ - .rate = (_rate), \ - .mdiv = (_m), \ - .pdiv = (_p), \ - .sdiv = (_s), \ - .kdiv = (_k), \ - } - static const struct imx_pll14xx_rate_table imx8mm_pll1416x_tbl[] = { PLL_1416X_RATE(1800000000U, 225, 3, 0), PLL_1416X_RATE(1600000000U, 200, 3, 0), diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c new file mode 100644 index 0000000000000000000000000000000000000000..07481a53e33611d1414542e7c551143a1d9f47db --- /dev/null +++ b/drivers/clk/imx/clk-imx8mn.c @@ -0,0 +1,636 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018-2019 NXP. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static u32 share_count_sai2; +static u32 share_count_sai3; +static u32 share_count_sai5; +static u32 share_count_sai6; +static u32 share_count_sai7; +static u32 share_count_disp; +static u32 share_count_pdm; +static u32 share_count_nand; + +enum { + ARM_PLL, + GPU_PLL, + VPU_PLL, + SYS_PLL1, + SYS_PLL2, + SYS_PLL3, + DRAM_PLL, + AUDIO_PLL1, + AUDIO_PLL2, + VIDEO_PLL2, + NR_PLLS, +}; + +static const struct imx_pll14xx_rate_table imx8mn_pll1416x_tbl[] = { + PLL_1416X_RATE(1800000000U, 225, 3, 0), + PLL_1416X_RATE(1600000000U, 200, 3, 0), + PLL_1416X_RATE(1200000000U, 300, 3, 1), + PLL_1416X_RATE(1000000000U, 250, 3, 1), + PLL_1416X_RATE(800000000U, 200, 3, 1), + PLL_1416X_RATE(750000000U, 250, 2, 2), + PLL_1416X_RATE(700000000U, 350, 3, 2), + PLL_1416X_RATE(600000000U, 300, 3, 2), +}; + +static const struct imx_pll14xx_rate_table imx8mn_audiopll_tbl[] = { + PLL_1443X_RATE(786432000U, 655, 5, 2, 23593), + PLL_1443X_RATE(722534400U, 301, 5, 1, 3670), +}; + +static const struct imx_pll14xx_rate_table imx8mn_videopll_tbl[] = { + PLL_1443X_RATE(650000000U, 325, 3, 2, 0), + PLL_1443X_RATE(594000000U, 198, 2, 2, 0), +}; + +static const struct imx_pll14xx_rate_table imx8mn_drampll_tbl[] = { + PLL_1443X_RATE(650000000U, 325, 3, 2, 0), +}; + +static struct imx_pll14xx_clk imx8mn_audio_pll = { + .type = PLL_1443X, + .rate_table = imx8mn_audiopll_tbl, +}; + +static struct imx_pll14xx_clk imx8mn_video_pll = { + .type = PLL_1443X, + .rate_table = imx8mn_videopll_tbl, +}; + +static struct imx_pll14xx_clk imx8mn_dram_pll = { + .type = PLL_1443X, + .rate_table = imx8mn_drampll_tbl, +}; + +static struct imx_pll14xx_clk imx8mn_arm_pll = { + .type = PLL_1416X, + .rate_table = imx8mn_pll1416x_tbl, +}; + +static struct imx_pll14xx_clk imx8mn_gpu_pll = { + .type = PLL_1416X, + .rate_table = imx8mn_pll1416x_tbl, +}; + +static struct imx_pll14xx_clk imx8mn_vpu_pll = { + .type = PLL_1416X, + .rate_table = imx8mn_pll1416x_tbl, +}; + +static struct imx_pll14xx_clk imx8mn_sys_pll = { + .type = PLL_1416X, + .rate_table = imx8mn_pll1416x_tbl, +}; + +static const char * const pll_ref_sels[] = { "osc_24m", "dummy", "dummy", "dummy", }; +static const char * const audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", }; +static const char * const audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", }; +static const char * const video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", }; +static const char * const dram_pll_bypass_sels[] = {"dram_pll", "dram_pll_ref_sel", }; +static const char * const gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", }; +static const char * const vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", }; +static const char * const arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", }; +static const char * const sys_pll1_bypass_sels[] = {"sys_pll1", "sys_pll1_ref_sel", }; +static const char * const sys_pll2_bypass_sels[] = {"sys_pll2", "sys_pll2_ref_sel", }; +static const char * const sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", }; + +static const char * const imx8mn_a53_sels[] = {"osc_24m", "arm_pll_out", "sys_pll2_500m", + "sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m", + "audio_pll1_out", "sys_pll3_out", }; + +static const char * const imx8mn_gpu_core_sels[] = {"osc_24m", "gpu_pll_out", "sys_pll1_800m", + "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", }; + +static const char * const imx8mn_gpu_shader_sels[] = {"osc_24m", "gpu_pll_out", "sys_pll1_800m", + "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", }; + +static const char * const imx8mn_main_axi_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll1_800m", + "sys_pll2_250m", "sys_pll2_1000m", "audio_pll1_out", + "video_pll1_out", "sys_pll1_100m",}; + +static const char * const imx8mn_enet_axi_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll1_800m", + "sys_pll2_250m", "sys_pll2_200m", "audio_pll1_out", + "video_pll1_out", "sys_pll3_out", }; + +static const char * const imx8mn_nand_usdhc_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll1_800m", + "sys_pll2_200m", "sys_pll1_133m", "sys_pll3_out", + "sys_pll2_250m", "audio_pll1_out", }; + +static const char * const imx8mn_disp_axi_sels[] = {"osc_24m", "sys_pll2_1000m", "sys_pll1_800m", + "sys_pll3_out", "sys_pll1_40m", "audio_pll2_out", + "clk_ext1", "clk_ext4", }; + +static const char * const imx8mn_disp_apb_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll1_800m", + "sys_pll3_out", "sys1_pll_40m", "audio_pll2_out", + "clk_ext1", "clk_ext3", }; + +static const char * const imx8mn_usb_bus_sels[] = {"osc_24m", "sys_pll2_500m", "sys_pll1_800m", + "sys_pll2_100m", "sys_pll2_200m", "clk_ext2", + "clk_ext4", "audio_pll2_out", }; + +static const char * const imx8mn_gpu_axi_sels[] = {"osc_24m", "sys_pll1_800m", "gpu_pll_out", + "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", }; + +static const char * const imx8mn_gpu_ahb_sels[] = {"osc_24m", "sys_pll1_800m", "gpu_pll_out", + "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", }; + +static const char * const imx8mn_noc_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_1000m", "sys_pll2_500m", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", }; + +static const char * const imx8mn_ahb_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_800m", + "sys_pll1_400m", "sys_pll2_125m", "sys_pll3_out", + "audio_pll1_out", "video_pll1_out", }; + +static const char * const imx8mn_audio_ahb_sels[] = {"osc_24m", "sys_pll2_500m", "sys_pll1_800m", + "sys_pll2_1000m", "sys_pll2_166m", "sys_pll3_out", + "audio_pll1_out", "video_pll1_out", }; + +static const char * const imx8mn_dram_alt_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll1_100m", + "sys_pll2_500m", "sys_pll2_1000m", "sys_pll3_out", + "audio_pll1_out", "sys_pll1_266m", }; + +static const char * const imx8mn_dram_apb_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", + "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_250m", "audio_pll2_out", }; + +static const char * const imx8mn_disp_pixel_sels[] = {"osc_24m", "video_pll1_out", "audio_pll2_out", + "audio_pll1_out", "sys_pll1_800m", "sys_pll2_1000m", + "sys_pll3_out", "clk_ext4", }; + +static const char * const imx8mn_sai2_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", + "video_pll1_out", "sys_pll1_133m", "osc_hdmi", + "clk_ext3", "clk_ext4", }; + +static const char * const imx8mn_sai3_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", + "video_pll1_out", "sys_pll1_133m", "osc_hdmi", + "clk_ext3", "clk_ext4", }; + +static const char * const imx8mn_sai5_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", + "video_pll1_out", "sys_pll1_133m", "osc_hdmi", + "clk_ext2", "clk_ext3", }; + +static const char * const imx8mn_sai6_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", + "video_pll1_out", "sys_pll1_133m", "osc_hdmi", + "clk_ext3", "clk_ext4", }; + +static const char * const imx8mn_sai7_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", + "video_pll1_out", "sys_pll1_133m", "osc_hdmi", + "clk_ext3", "clk_ext4", }; + +static const char * const imx8mn_spdif1_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", + "video_pll1_out", "sys_pll1_133m", "osc_hdmi", + "clk_ext2", "clk_ext3", }; + +static const char * const imx8mn_enet_ref_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_50m", + "sys_pll2_100m", "sys_pll1_160m", "audio_pll1_out", + "video_pll1_out", "clk_ext4", }; + +static const char * const imx8mn_enet_timer_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_out", + "clk_ext1", "clk_ext2", "clk_ext3", + "clk_ext4", "video_pll1_out", }; + +static const char * const imx8mn_enet_phy_sels[] = {"osc_24m", "sys_pll2_50m", "sys_pll2_125m", + "sys_pll2_200m", "sys_pll2_500m", "video_pll1_out", + "audio_pll2_out", }; + +static const char * const imx8mn_nand_sels[] = {"osc_24m", "sys_pll2_500m", "audio_pll1_out", + "sys_pll1_400m", "audio_pll2_out", "sys_pll3_out", + "sys_pll2_250m", "video_pll1_out", }; + +static const char * const imx8mn_qspi_sels[] = {"osc_24m", "sys1_pll_400m", "sys_pll1_800m", + "sys2_pll_500m", "audio_pll2_out", "sys1_pll_266m", + "sys3_pll2_out", "sys1_pll_100m", }; + +static const char * const imx8mn_usdhc1_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m", + "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m", + "audio_pll2_out", "sys_pll1_100m", }; + +static const char * const imx8mn_usdhc2_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m", + "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m", + "audio_pll2_out", "sys_pll1_100m", }; + +static const char * const imx8mn_i2c1_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m", + "sys_pll3_out", "audio_pll1_out", "video_pll1_out", + "audio_pll2_out", "sys_pll1_133m", }; + +static const char * const imx8mn_i2c2_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m", + "sys_pll3_out", "audio_pll1_out", "video_pll1_out", + "audio_pll2_out", "sys_pll1_133m", }; + +static const char * const imx8mn_i2c3_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m", + "sys_pll3_out", "audio_pll1_out", "video_pll1_out", + "audio_pll2_out", "sys_pll1_133m", }; + +static const char * const imx8mn_i2c4_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m", + "sys_pll3_out", "audio_pll1_out", "video_pll1_out", + "audio_pll2_out", "sys_pll1_133m", }; + +static const char * const imx8mn_uart1_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m", + "sys_pll2_100m", "sys_pll3_out", "clk_ext2", + "clk_ext4", "audio_pll2_out", }; + +static const char * const imx8mn_uart2_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m", + "sys_pll2_100m", "sys_pll3_out", "clk_ext2", + "clk_ext3", "audio_pll2_out", }; + +static const char * const imx8mn_uart3_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m", + "sys_pll2_100m", "sys_pll3_out", "clk_ext2", + "clk_ext4", "audio_pll2_out", }; + +static const char * const imx8mn_uart4_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m", + "sys_pll2_100m", "sys_pll3_out", "clk_ext2", + "clk_ext3", "audio_pll2_out", }; + +static const char * const imx8mn_usb_core_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m", + "sys_pll2_100m", "sys_pll2_200m", "clk_ext2", + "clk_ext3", "audio_pll2_out", }; + +static const char * const imx8mn_usb_phy_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m", + "sys_pll2_100m", "sys_pll2_200m", "clk_ext2", + "clk_ext3", "audio_pll2_out", }; + +static const char * const imx8mn_ecspi1_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", + "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_250m", "audio_pll2_out", }; + +static const char * const imx8mn_ecspi2_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", + "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_250m", "audio_pll2_out", }; + +static const char * const imx8mn_pwm1_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m", + "sys_pll1_40m", "sys_pll3_out", "clk_ext1", + "sys_pll1_80m", "video_pll1_out", }; + +static const char * const imx8mn_pwm2_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m", + "sys_pll1_40m", "sys_pll3_out", "clk_ext1", + "sys_pll1_80m", "video_pll1_out", }; + +static const char * const imx8mn_pwm3_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m", + "sys_pll1_40m", "sys3_pll2_out", "clk_ext2", + "sys_pll1_80m", "video_pll1_out", }; + +static const char * const imx8mn_pwm4_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m", + "sys_pll1_40m", "sys_pll3_out", "clk_ext2", + "sys_pll1_80m", "video_pll1_out", }; + +static const char * const imx8mn_wdog_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_160m", + "vpu_pll_out", "sys_pll2_125m", "sys_pll3_out", + "sys_pll1_80m", "sys_pll2_166m", }; + +static const char * const imx8mn_wrclk_sels[] = {"osc_24m", "sys_pll1_40m", "vpu_pll_out", + "sys_pll3_out", "sys_pll2_200m", "sys_pll1_266m", + "sys_pll2_500m", "sys_pll1_100m", }; + +static const char * const imx8mn_dsi_core_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_250m", + "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out", + "audio_pll2_out", "video_pll1_out", }; + +static const char * const imx8mn_dsi_phy_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_100m", + "sys_pll1_800m", "sys_pll2_1000m", "clk_ext2", + "audio_pll2_out", "video_pll1_out", }; + +static const char * const imx8mn_dsi_dbi_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_100m", + "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out", + "audio_pll2_out", "video_pll1_out", }; + +static const char * const imx8mn_usdhc3_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m", + "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m", + "audio_pll2_clk", "sys_pll1_100m", }; + +static const char * const imx8mn_camera_pixel_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_250m", + "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out", + "audio_pll2_out", "video_pll1_out", }; + +static const char * const imx8mn_csi1_phy_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll2_100m", + "sys_pll1_800m", "sys_pll2_1000m", "clk_ext2", + "audio_pll2_out", "video_pll1_out", }; + +static const char * const imx8mn_csi2_phy_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll2_100m", + "sys_pll1_800m", "sys_pll2_1000m", "clk_ext2", + "audio_pll2_out", "video_pll1_out", }; + +static const char * const imx8mn_csi2_esc_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_80m", + "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out", + "clk_ext3", "audio_pll2_out", }; + +static const char * const imx8mn_ecspi3_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", + "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_250m", "audio_pll2_out", }; + +static const char * const imx8mn_pdm_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_out", + "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out", + "clk_ext3", "audio_pll2_out", }; + +static const char * const imx8mn_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", }; + +static const char * const imx8mn_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m", + "sys_pll1_200m", "audio_pll2_clk", "vpu_pll", + "sys_pll1_80m", }; +static const char * const imx8mn_clko2_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_400m", + "sys_pll2_166m", "sys_pll3_out", "audio_pll1_out", + "video_pll1_out", "osc_32k", }; + +static struct clk *clks[IMX8MN_CLK_END]; +static struct clk_onecell_data clk_data; + +static int imx8mn_clocks_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + void __iomem *base; + int ret; + + clks[IMX8MN_CLK_DUMMY] = imx_clk_fixed("dummy", 0); + clks[IMX8MN_CLK_24M] = of_clk_get_by_name(np, "osc_24m"); + clks[IMX8MN_CLK_32K] = of_clk_get_by_name(np, "osc_32k"); + clks[IMX8MN_CLK_EXT1] = of_clk_get_by_name(np, "clk_ext1"); + clks[IMX8MN_CLK_EXT2] = of_clk_get_by_name(np, "clk_ext2"); + clks[IMX8MN_CLK_EXT3] = of_clk_get_by_name(np, "clk_ext3"); + clks[IMX8MN_CLK_EXT4] = of_clk_get_by_name(np, "clk_ext4"); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx8mn-anatop"); + base = of_iomap(np, 0); + if (WARN_ON(!base)) { + ret = -ENOMEM; + goto unregister_clks; + } + + clks[IMX8MN_AUDIO_PLL1_REF_SEL] = imx_clk_mux("audio_pll1_ref_sel", base + 0x0, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MN_AUDIO_PLL2_REF_SEL] = imx_clk_mux("audio_pll2_ref_sel", base + 0x14, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MN_VIDEO_PLL1_REF_SEL] = imx_clk_mux("video_pll1_ref_sel", base + 0x28, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MN_DRAM_PLL_REF_SEL] = imx_clk_mux("dram_pll_ref_sel", base + 0x50, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MN_GPU_PLL_REF_SEL] = imx_clk_mux("gpu_pll_ref_sel", base + 0x64, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MN_VPU_PLL_REF_SEL] = imx_clk_mux("vpu_pll_ref_sel", base + 0x74, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MN_ARM_PLL_REF_SEL] = imx_clk_mux("arm_pll_ref_sel", base + 0x84, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MN_SYS_PLL1_REF_SEL] = imx_clk_mux("sys_pll1_ref_sel", base + 0x94, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MN_SYS_PLL2_REF_SEL] = imx_clk_mux("sys_pll2_ref_sel", base + 0x104, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MN_SYS_PLL3_REF_SEL] = imx_clk_mux("sys_pll3_ref_sel", base + 0x114, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + + clks[IMX8MN_AUDIO_PLL1] = imx_clk_pll14xx("audio_pll1", "audio_pll1_ref_sel", base, &imx8mn_audio_pll); + clks[IMX8MN_AUDIO_PLL2] = imx_clk_pll14xx("audio_pll2", "audio_pll2_ref_sel", base + 0x14, &imx8mn_audio_pll); + clks[IMX8MN_VIDEO_PLL1] = imx_clk_pll14xx("video_pll1", "video_pll1_ref_sel", base + 0x28, &imx8mn_video_pll); + clks[IMX8MN_DRAM_PLL] = imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", base + 0x50, &imx8mn_dram_pll); + clks[IMX8MN_GPU_PLL] = imx_clk_pll14xx("gpu_pll", "gpu_pll_ref_sel", base + 0x64, &imx8mn_gpu_pll); + clks[IMX8MN_VPU_PLL] = imx_clk_pll14xx("vpu_pll", "vpu_pll_ref_sel", base + 0x74, &imx8mn_vpu_pll); + clks[IMX8MN_ARM_PLL] = imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", base + 0x84, &imx8mn_arm_pll); + clks[IMX8MN_SYS_PLL1] = imx_clk_pll14xx("sys_pll1", "sys_pll1_ref_sel", base + 0x94, &imx8mn_sys_pll); + clks[IMX8MN_SYS_PLL2] = imx_clk_pll14xx("sys_pll2", "sys_pll2_ref_sel", base + 0x104, &imx8mn_sys_pll); + clks[IMX8MN_SYS_PLL3] = imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", base + 0x114, &imx8mn_sys_pll); + + /* PLL bypass out */ + clks[IMX8MN_AUDIO_PLL1_BYPASS] = imx_clk_mux_flags("audio_pll1_bypass", base, 4, 1, audio_pll1_bypass_sels, ARRAY_SIZE(audio_pll1_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MN_AUDIO_PLL2_BYPASS] = imx_clk_mux_flags("audio_pll2_bypass", base + 0x14, 4, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MN_VIDEO_PLL1_BYPASS] = imx_clk_mux_flags("video_pll1_bypass", base + 0x28, 4, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MN_DRAM_PLL_BYPASS] = imx_clk_mux_flags("dram_pll_bypass", base + 0x50, 4, 1, dram_pll_bypass_sels, ARRAY_SIZE(dram_pll_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MN_GPU_PLL_BYPASS] = imx_clk_mux_flags("gpu_pll_bypass", base + 0x64, 4, 1, gpu_pll_bypass_sels, ARRAY_SIZE(gpu_pll_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MN_VPU_PLL_BYPASS] = imx_clk_mux_flags("vpu_pll_bypass", base + 0x74, 4, 1, vpu_pll_bypass_sels, ARRAY_SIZE(vpu_pll_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MN_ARM_PLL_BYPASS] = imx_clk_mux_flags("arm_pll_bypass", base + 0x84, 4, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MN_SYS_PLL1_BYPASS] = imx_clk_mux_flags("sys_pll1_bypass", base + 0x94, 4, 1, sys_pll1_bypass_sels, ARRAY_SIZE(sys_pll1_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MN_SYS_PLL2_BYPASS] = imx_clk_mux_flags("sys_pll2_bypass", base + 0x104, 4, 1, sys_pll2_bypass_sels, ARRAY_SIZE(sys_pll2_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MN_SYS_PLL3_BYPASS] = imx_clk_mux_flags("sys_pll3_bypass", base + 0x114, 4, 1, sys_pll3_bypass_sels, ARRAY_SIZE(sys_pll3_bypass_sels), CLK_SET_RATE_PARENT); + + /* unbypass all the plls */ + clk_set_parent(clks[IMX8MN_AUDIO_PLL1_BYPASS], clks[IMX8MN_AUDIO_PLL1]); + clk_set_parent(clks[IMX8MN_AUDIO_PLL2_BYPASS], clks[IMX8MN_AUDIO_PLL2]); + clk_set_parent(clks[IMX8MN_VIDEO_PLL1_BYPASS], clks[IMX8MN_VIDEO_PLL1]); + clk_set_parent(clks[IMX8MN_DRAM_PLL_BYPASS], clks[IMX8MN_DRAM_PLL]); + clk_set_parent(clks[IMX8MN_GPU_PLL_BYPASS], clks[IMX8MN_GPU_PLL]); + clk_set_parent(clks[IMX8MN_VPU_PLL_BYPASS], clks[IMX8MN_VPU_PLL]); + clk_set_parent(clks[IMX8MN_ARM_PLL_BYPASS], clks[IMX8MN_ARM_PLL]); + clk_set_parent(clks[IMX8MN_SYS_PLL1_BYPASS], clks[IMX8MN_SYS_PLL1]); + clk_set_parent(clks[IMX8MN_SYS_PLL2_BYPASS], clks[IMX8MN_SYS_PLL2]); + clk_set_parent(clks[IMX8MN_SYS_PLL3_BYPASS], clks[IMX8MN_SYS_PLL3]); + + /* PLL out gate */ + clks[IMX8MN_AUDIO_PLL1_OUT] = imx_clk_gate("audio_pll1_out", "audio_pll1_bypass", base, 13); + clks[IMX8MN_AUDIO_PLL2_OUT] = imx_clk_gate("audio_pll2_out", "audio_pll2_bypass", base + 0x14, 13); + clks[IMX8MN_VIDEO_PLL1_OUT] = imx_clk_gate("video_pll1_out", "video_pll1_bypass", base + 0x28, 13); + clks[IMX8MN_DRAM_PLL_OUT] = imx_clk_gate("dram_pll_out", "dram_pll_bypass", base + 0x50, 13); + clks[IMX8MN_GPU_PLL_OUT] = imx_clk_gate("gpu_pll_out", "gpu_pll_bypass", base + 0x64, 13); + clks[IMX8MN_VPU_PLL_OUT] = imx_clk_gate("vpu_pll_out", "vpu_pll_bypass", base + 0x74, 13); + clks[IMX8MN_ARM_PLL_OUT] = imx_clk_gate("arm_pll_out", "arm_pll_bypass", base + 0x84, 13); + clks[IMX8MN_SYS_PLL1_OUT] = imx_clk_gate("sys_pll1_out", "sys_pll1_bypass", base + 0x94, 13); + clks[IMX8MN_SYS_PLL2_OUT] = imx_clk_gate("sys_pll2_out", "sys_pll2_bypass", base + 0x104, 13); + clks[IMX8MN_SYS_PLL3_OUT] = imx_clk_gate("sys_pll3_out", "sys_pll3_bypass", base + 0x114, 13); + + /* SYS PLL fixed output */ + clks[IMX8MN_SYS_PLL1_40M] = imx_clk_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20); + clks[IMX8MN_SYS_PLL1_80M] = imx_clk_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10); + clks[IMX8MN_SYS_PLL1_100M] = imx_clk_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8); + clks[IMX8MN_SYS_PLL1_133M] = imx_clk_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6); + clks[IMX8MN_SYS_PLL1_160M] = imx_clk_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5); + clks[IMX8MN_SYS_PLL1_200M] = imx_clk_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4); + clks[IMX8MN_SYS_PLL1_266M] = imx_clk_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3); + clks[IMX8MN_SYS_PLL1_400M] = imx_clk_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2); + clks[IMX8MN_SYS_PLL1_800M] = imx_clk_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1); + + clks[IMX8MN_SYS_PLL2_50M] = imx_clk_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20); + clks[IMX8MN_SYS_PLL2_100M] = imx_clk_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10); + clks[IMX8MN_SYS_PLL2_125M] = imx_clk_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8); + clks[IMX8MN_SYS_PLL2_166M] = imx_clk_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6); + clks[IMX8MN_SYS_PLL2_200M] = imx_clk_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5); + clks[IMX8MN_SYS_PLL2_250M] = imx_clk_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4); + clks[IMX8MN_SYS_PLL2_333M] = imx_clk_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3); + clks[IMX8MN_SYS_PLL2_500M] = imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2); + clks[IMX8MN_SYS_PLL2_1000M] = imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1); + + np = dev->of_node; + base = devm_platform_ioremap_resource(pdev, 0); + if (WARN_ON(IS_ERR(base))) { + ret = PTR_ERR(base); + goto unregister_clks; + } + + /* CORE */ + clks[IMX8MN_CLK_A53_SRC] = imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mn_a53_sels, ARRAY_SIZE(imx8mn_a53_sels)); + clks[IMX8MN_CLK_GPU_CORE_SRC] = imx_clk_mux2("gpu_core_src", base + 0x8180, 24, 3, imx8mn_gpu_core_sels, ARRAY_SIZE(imx8mn_gpu_core_sels)); + clks[IMX8MN_CLK_GPU_SHADER_SRC] = imx_clk_mux2("gpu_shader_src", base + 0x8200, 24, 3, imx8mn_gpu_shader_sels, ARRAY_SIZE(imx8mn_gpu_shader_sels)); + clks[IMX8MN_CLK_A53_CG] = imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28); + clks[IMX8MN_CLK_GPU_CORE_CG] = imx_clk_gate3("gpu_core_cg", "gpu_core_src", base + 0x8180, 28); + clks[IMX8MN_CLK_GPU_SHADER_CG] = imx_clk_gate3("gpu_shader_cg", "gpu_shader_src", base + 0x8200, 28); + + clks[IMX8MN_CLK_A53_DIV] = imx_clk_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3); + clks[IMX8MN_CLK_GPU_CORE_DIV] = imx_clk_divider2("gpu_core_div", "gpu_core_cg", base + 0x8180, 0, 3); + clks[IMX8MN_CLK_GPU_SHADER_DIV] = imx_clk_divider2("gpu_shader_div", "gpu_shader_cg", base + 0x8200, 0, 3); + + /* BUS */ + clks[IMX8MN_CLK_MAIN_AXI] = imx8m_clk_composite_critical("main_axi", imx8mn_main_axi_sels, base + 0x8800); + clks[IMX8MN_CLK_ENET_AXI] = imx8m_clk_composite("enet_axi", imx8mn_enet_axi_sels, base + 0x8880); + clks[IMX8MN_CLK_NAND_USDHC_BUS] = imx8m_clk_composite("nand_usdhc_bus", imx8mn_nand_usdhc_sels, base + 0x8900); + clks[IMX8MN_CLK_DISP_AXI] = imx8m_clk_composite("disp_axi", imx8mn_disp_axi_sels, base + 0x8a00); + clks[IMX8MN_CLK_DISP_APB] = imx8m_clk_composite("disp_apb", imx8mn_disp_apb_sels, base + 0x8a80); + clks[IMX8MN_CLK_USB_BUS] = imx8m_clk_composite("usb_bus", imx8mn_usb_bus_sels, base + 0x8b80); + clks[IMX8MN_CLK_GPU_AXI] = imx8m_clk_composite("gpu_axi", imx8mn_gpu_axi_sels, base + 0x8c00); + clks[IMX8MN_CLK_GPU_AHB] = imx8m_clk_composite("gpu_ahb", imx8mn_gpu_ahb_sels, base + 0x8c80); + clks[IMX8MN_CLK_NOC] = imx8m_clk_composite_critical("noc", imx8mn_noc_sels, base + 0x8d00); + + clks[IMX8MN_CLK_AHB] = imx8m_clk_composite_critical("ahb", imx8mn_ahb_sels, base + 0x9000); + clks[IMX8MN_CLK_AUDIO_AHB] = imx8m_clk_composite("audio_ahb", imx8mn_audio_ahb_sels, base + 0x9100); + clks[IMX8MN_CLK_IPG_ROOT] = imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1); + clks[IMX8MN_CLK_IPG_AUDIO_ROOT] = imx_clk_divider2("ipg_audio_root", "audio_ahb", base + 0x9180, 0, 1); + clks[IMX8MN_CLK_DRAM_CORE] = imx_clk_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mn_dram_core_sels, ARRAY_SIZE(imx8mn_dram_core_sels), CLK_IS_CRITICAL); + clks[IMX8MN_CLK_DRAM_ALT] = imx8m_clk_composite("dram_alt", imx8mn_dram_alt_sels, base + 0xa000); + clks[IMX8MN_CLK_DRAM_APB] = imx8m_clk_composite_critical("dram_apb", imx8mn_dram_apb_sels, base + 0xa080); + clks[IMX8MN_CLK_DISP_PIXEL] = imx8m_clk_composite("disp_pixel", imx8mn_disp_pixel_sels, base + 0xa500); + clks[IMX8MN_CLK_SAI2] = imx8m_clk_composite("sai2", imx8mn_sai2_sels, base + 0xa600); + clks[IMX8MN_CLK_SAI3] = imx8m_clk_composite("sai3", imx8mn_sai3_sels, base + 0xa680); + clks[IMX8MN_CLK_SAI5] = imx8m_clk_composite("sai5", imx8mn_sai5_sels, base + 0xa780); + clks[IMX8MN_CLK_SAI6] = imx8m_clk_composite("sai6", imx8mn_sai6_sels, base + 0xa800); + clks[IMX8MN_CLK_SPDIF1] = imx8m_clk_composite("spdif1", imx8mn_spdif1_sels, base + 0xa880); + clks[IMX8MN_CLK_ENET_REF] = imx8m_clk_composite("enet_ref", imx8mn_enet_ref_sels, base + 0xa980); + clks[IMX8MN_CLK_ENET_TIMER] = imx8m_clk_composite("enet_timer", imx8mn_enet_timer_sels, base + 0xaa00); + clks[IMX8MN_CLK_ENET_PHY_REF] = imx8m_clk_composite("enet_phy", imx8mn_enet_phy_sels, base + 0xaa80); + clks[IMX8MN_CLK_NAND] = imx8m_clk_composite("nand", imx8mn_nand_sels, base + 0xab00); + clks[IMX8MN_CLK_QSPI] = imx8m_clk_composite("qspi", imx8mn_qspi_sels, base + 0xab80); + clks[IMX8MN_CLK_USDHC1] = imx8m_clk_composite("usdhc1", imx8mn_usdhc1_sels, base + 0xac00); + clks[IMX8MN_CLK_USDHC2] = imx8m_clk_composite("usdhc2", imx8mn_usdhc2_sels, base + 0xac80); + clks[IMX8MN_CLK_I2C1] = imx8m_clk_composite("i2c1", imx8mn_i2c1_sels, base + 0xad00); + clks[IMX8MN_CLK_I2C2] = imx8m_clk_composite("i2c2", imx8mn_i2c2_sels, base + 0xad80); + clks[IMX8MN_CLK_I2C3] = imx8m_clk_composite("i2c3", imx8mn_i2c3_sels, base + 0xae00); + clks[IMX8MN_CLK_I2C4] = imx8m_clk_composite("i2c4", imx8mn_i2c4_sels, base + 0xae80); + clks[IMX8MN_CLK_UART1] = imx8m_clk_composite("uart1", imx8mn_uart1_sels, base + 0xaf00); + clks[IMX8MN_CLK_UART2] = imx8m_clk_composite("uart2", imx8mn_uart2_sels, base + 0xaf80); + clks[IMX8MN_CLK_UART3] = imx8m_clk_composite("uart3", imx8mn_uart3_sels, base + 0xb000); + clks[IMX8MN_CLK_UART4] = imx8m_clk_composite("uart4", imx8mn_uart4_sels, base + 0xb080); + clks[IMX8MN_CLK_USB_CORE_REF] = imx8m_clk_composite("usb_core_ref", imx8mn_usb_core_sels, base + 0xb100); + clks[IMX8MN_CLK_USB_PHY_REF] = imx8m_clk_composite("usb_phy_ref", imx8mn_usb_phy_sels, base + 0xb180); + clks[IMX8MN_CLK_ECSPI1] = imx8m_clk_composite("ecspi1", imx8mn_ecspi1_sels, base + 0xb280); + clks[IMX8MN_CLK_ECSPI2] = imx8m_clk_composite("ecspi2", imx8mn_ecspi2_sels, base + 0xb300); + clks[IMX8MN_CLK_PWM1] = imx8m_clk_composite("pwm1", imx8mn_pwm1_sels, base + 0xb380); + clks[IMX8MN_CLK_PWM2] = imx8m_clk_composite("pwm2", imx8mn_pwm2_sels, base + 0xb400); + clks[IMX8MN_CLK_PWM3] = imx8m_clk_composite("pwm3", imx8mn_pwm3_sels, base + 0xb480); + clks[IMX8MN_CLK_PWM4] = imx8m_clk_composite("pwm4", imx8mn_pwm4_sels, base + 0xb500); + clks[IMX8MN_CLK_WDOG] = imx8m_clk_composite("wdog", imx8mn_wdog_sels, base + 0xb900); + clks[IMX8MN_CLK_WRCLK] = imx8m_clk_composite("wrclk", imx8mn_wrclk_sels, base + 0xb980); + clks[IMX8MN_CLK_CLKO1] = imx8m_clk_composite("clko1", imx8mn_clko1_sels, base + 0xba00); + clks[IMX8MN_CLK_CLKO2] = imx8m_clk_composite("clko2", imx8mn_clko2_sels, base + 0xba80); + clks[IMX8MN_CLK_DSI_CORE] = imx8m_clk_composite("dsi_core", imx8mn_dsi_core_sels, base + 0xbb00); + clks[IMX8MN_CLK_DSI_PHY_REF] = imx8m_clk_composite("dsi_phy_ref", imx8mn_dsi_phy_sels, base + 0xbb80); + clks[IMX8MN_CLK_DSI_DBI] = imx8m_clk_composite("dsi_dbi", imx8mn_dsi_dbi_sels, base + 0xbc00); + clks[IMX8MN_CLK_USDHC3] = imx8m_clk_composite("usdhc3", imx8mn_usdhc3_sels, base + 0xbc80); + clks[IMX8MN_CLK_CAMERA_PIXEL] = imx8m_clk_composite("camera_pixel", imx8mn_camera_pixel_sels, base + 0xbd00); + clks[IMX8MN_CLK_CSI1_PHY_REF] = imx8m_clk_composite("csi1_phy_ref", imx8mn_csi1_phy_sels, base + 0xbd80); + clks[IMX8MN_CLK_CSI2_PHY_REF] = imx8m_clk_composite("csi2_phy_ref", imx8mn_csi2_phy_sels, base + 0xbf00); + clks[IMX8MN_CLK_CSI2_ESC] = imx8m_clk_composite("csi2_esc", imx8mn_csi2_esc_sels, base + 0xbf80); + clks[IMX8MN_CLK_ECSPI3] = imx8m_clk_composite("ecspi3", imx8mn_ecspi3_sels, base + 0xc180); + clks[IMX8MN_CLK_PDM] = imx8m_clk_composite("pdm", imx8mn_pdm_sels, base + 0xc200); + clks[IMX8MN_CLK_SAI7] = imx8m_clk_composite("sai7", imx8mn_sai7_sels, base + 0xc300); + + clks[IMX8MN_CLK_ECSPI1_ROOT] = imx_clk_gate4("ecspi1_root_clk", "ecspi1", base + 0x4070, 0); + clks[IMX8MN_CLK_ECSPI2_ROOT] = imx_clk_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0); + clks[IMX8MN_CLK_ECSPI3_ROOT] = imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0); + clks[IMX8MN_CLK_ENET1_ROOT] = imx_clk_gate4("enet1_root_clk", "enet_axi", base + 0x40a0, 0); + clks[IMX8MN_CLK_GPIO1_ROOT] = imx_clk_gate4("gpio1_root_clk", "ipg_root", base + 0x40b0, 0); + clks[IMX8MN_CLK_GPIO2_ROOT] = imx_clk_gate4("gpio2_root_clk", "ipg_root", base + 0x40c0, 0); + clks[IMX8MN_CLK_GPIO3_ROOT] = imx_clk_gate4("gpio3_root_clk", "ipg_root", base + 0x40d0, 0); + clks[IMX8MN_CLK_GPIO4_ROOT] = imx_clk_gate4("gpio4_root_clk", "ipg_root", base + 0x40e0, 0); + clks[IMX8MN_CLK_GPIO5_ROOT] = imx_clk_gate4("gpio5_root_clk", "ipg_root", base + 0x40f0, 0); + clks[IMX8MN_CLK_I2C1_ROOT] = imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0); + clks[IMX8MN_CLK_I2C2_ROOT] = imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0); + clks[IMX8MN_CLK_I2C3_ROOT] = imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0); + clks[IMX8MN_CLK_I2C4_ROOT] = imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0); + clks[IMX8MN_CLK_MU_ROOT] = imx_clk_gate4("mu_root_clk", "ipg_root", base + 0x4210, 0); + clks[IMX8MN_CLK_OCOTP_ROOT] = imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0); + clks[IMX8MN_CLK_PWM1_ROOT] = imx_clk_gate4("pwm1_root_clk", "pwm1", base + 0x4280, 0); + clks[IMX8MN_CLK_PWM2_ROOT] = imx_clk_gate4("pwm2_root_clk", "pwm2", base + 0x4290, 0); + clks[IMX8MN_CLK_PWM3_ROOT] = imx_clk_gate4("pwm3_root_clk", "pwm3", base + 0x42a0, 0); + clks[IMX8MN_CLK_PWM4_ROOT] = imx_clk_gate4("pwm4_root_clk", "pwm4", base + 0x42b0, 0); + clks[IMX8MN_CLK_QSPI_ROOT] = imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0); + clks[IMX8MN_CLK_NAND_ROOT] = imx_clk_gate2_shared2("nand_root_clk", "nand", base + 0x4300, 0, &share_count_nand); + clks[IMX8MN_CLK_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_bus", base + 0x4300, 0, &share_count_nand); + clks[IMX8MN_CLK_SAI2_ROOT] = imx_clk_gate2_shared2("sai2_root_clk", "sai2", base + 0x4340, 0, &share_count_sai2); + clks[IMX8MN_CLK_SAI2_IPG] = imx_clk_gate2_shared2("sai2_ipg_clk", "ipg_audio_root", base + 0x4340, 0, &share_count_sai2); + clks[IMX8MN_CLK_SAI3_ROOT] = imx_clk_gate2_shared2("sai3_root_clk", "sai3", base + 0x4350, 0, &share_count_sai3); + clks[IMX8MN_CLK_SAI3_IPG] = imx_clk_gate2_shared2("sai3_ipg_clk", "ipg_audio_root", base + 0x4350, 0, &share_count_sai3); + clks[IMX8MN_CLK_SAI5_ROOT] = imx_clk_gate2_shared2("sai5_root_clk", "sai5", base + 0x4370, 0, &share_count_sai5); + clks[IMX8MN_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5); + clks[IMX8MN_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6); + clks[IMX8MN_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6); + clks[IMX8MN_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0); + clks[IMX8MN_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0); + clks[IMX8MN_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0); + clks[IMX8MN_CLK_UART4_ROOT] = imx_clk_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0); + clks[IMX8MN_CLK_USB1_CTRL_ROOT] = imx_clk_gate4("usb1_ctrl_root_clk", "usb_core_ref", base + 0x44d0, 0); + clks[IMX8MN_CLK_GPU_CORE_ROOT] = imx_clk_gate4("gpu_core_root_clk", "gpu_core_div", base + 0x44f0, 0); + clks[IMX8MN_CLK_USDHC1_ROOT] = imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0); + clks[IMX8MN_CLK_USDHC2_ROOT] = imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0); + clks[IMX8MN_CLK_WDOG1_ROOT] = imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0); + clks[IMX8MN_CLK_WDOG2_ROOT] = imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0); + clks[IMX8MN_CLK_WDOG3_ROOT] = imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0); + clks[IMX8MN_CLK_GPU_BUS_ROOT] = imx_clk_gate4("gpu_root_clk", "gpu_axi", base + 0x4570, 0); + clks[IMX8MN_CLK_ASRC_ROOT] = imx_clk_gate4("asrc_root_clk", "audio_ahb", base + 0x4580, 0); + clks[IMX8MN_CLK_PDM_ROOT] = imx_clk_gate2_shared2("pdm_root_clk", "pdm", base + 0x45b0, 0, &share_count_pdm); + clks[IMX8MN_CLK_PDM_IPG] = imx_clk_gate2_shared2("pdm_ipg_clk", "ipg_audio_root", base + 0x45b0, 0, &share_count_pdm); + clks[IMX8MN_CLK_DISP_AXI_ROOT] = imx_clk_gate2_shared2("disp_axi_root_clk", "disp_axi", base + 0x45d0, 0, &share_count_disp); + clks[IMX8MN_CLK_DISP_APB_ROOT] = imx_clk_gate2_shared2("disp_apb_root_clk", "disp_apb", base + 0x45d0, 0, &share_count_disp); + clks[IMX8MN_CLK_CAMERA_PIXEL_ROOT] = imx_clk_gate2_shared2("camera_pixel_clk", "camera_pixel", base + 0x45d0, 0, &share_count_disp); + clks[IMX8MN_CLK_DISP_PIXEL_ROOT] = imx_clk_gate2_shared2("disp_pixel_clk", "disp_pixel", base + 0x45d0, 0, &share_count_disp); + clks[IMX8MN_CLK_USDHC3_ROOT] = imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0); + clks[IMX8MN_CLK_TMU_ROOT] = imx_clk_gate4("tmu_root_clk", "ipg_root", base + 0x4620, 0); + clks[IMX8MN_CLK_SDMA1_ROOT] = imx_clk_gate4("sdma1_clk", "ipg_root", base + 0x43a0, 0); + clks[IMX8MN_CLK_SDMA2_ROOT] = imx_clk_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0); + clks[IMX8MN_CLK_SDMA3_ROOT] = imx_clk_gate4("sdma3_clk", "ipg_audio_root", base + 0x45f0, 0); + clks[IMX8MN_CLK_SAI7_ROOT] = imx_clk_gate2_shared2("sai7_root_clk", "sai7", base + 0x4650, 0, &share_count_sai7); + + clks[IMX8MN_CLK_DRAM_ALT_ROOT] = imx_clk_fixed_factor("dram_alt_root", "dram_alt", 1, 4); + + clks[IMX8MN_CLK_ARM] = imx_clk_cpu("arm", "arm_a53_div", + clks[IMX8MN_CLK_A53_DIV], + clks[IMX8MN_CLK_A53_SRC], + clks[IMX8MN_ARM_PLL_OUT], + clks[IMX8MN_CLK_24M]); + + imx_check_clocks(clks, ARRAY_SIZE(clks)); + + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + if (ret < 0) { + dev_err(dev, "failed to register clks for i.MX8MN\n"); + goto unregister_clks; + } + + return 0; + +unregister_clks: + imx_unregister_clocks(clks, ARRAY_SIZE(clks)); + + return ret; +} + +static const struct of_device_id imx8mn_clk_of_match[] = { + { .compatible = "fsl,imx8mn-ccm" }, + { /* Sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, imx8mn_clk_of_match); + +static struct platform_driver imx8mn_clk_driver = { + .probe = imx8mn_clocks_probe, + .driver = { + .name = "imx8mn-ccm", + .of_match_table = of_match_ptr(imx8mn_clk_of_match), + }, +}; +module_platform_driver(imx8mn_clk_driver); diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.c b/drivers/clk/imx/clk-imx8qxp-lpcg.c index fb6edf1b8aa2688bc1ce7e2e2555698d8c01a583..c0aff7ca6374c951537e669e8b970309f4e7e167 100644 --- a/drivers/clk/imx/clk-imx8qxp-lpcg.c +++ b/drivers/clk/imx/clk-imx8qxp-lpcg.c @@ -72,6 +72,11 @@ static const struct imx8qxp_lpcg_data imx8qxp_lpcg_adma[] = { { IMX_ADMA_LPCG_I2C2_CLK, "i2c2_lpcg_clk", "i2c2_clk", 0, ADMA_LPI2C_2_LPCG, 0, 0, }, { IMX_ADMA_LPCG_I2C3_IPG_CLK, "i2c3_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_3_LPCG, 16, 0, }, { IMX_ADMA_LPCG_I2C3_CLK, "i2c3_lpcg_clk", "i2c3_clk", 0, ADMA_LPI2C_3_LPCG, 0, 0, }, + + { IMX_ADMA_LPCG_DSP_CORE_CLK, "dsp_lpcg_core_clk", "dma_ipg_clk_root", 0, ADMA_HIFI_LPCG, 28, 0, }, + { IMX_ADMA_LPCG_DSP_IPG_CLK, "dsp_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_HIFI_LPCG, 20, 0, }, + { IMX_ADMA_LPCG_DSP_ADB_CLK, "dsp_lpcg_adb_clk", "dma_ipg_clk_root", 0, ADMA_HIFI_LPCG, 16, 0, }, + { IMX_ADMA_LPCG_OCRAM_IPG_CLK, "ocram_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_OCRAM_LPCG, 16, 0, }, }; static const struct imx8qxp_ss_lpcg imx8qxp_ss_adma = { diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c index f628071f6605e3f3dd18b9db8cd82cbaec6f82ff..cfc05e43c3430d58a26e291480f7a09e622e3781 100644 --- a/drivers/clk/imx/clk.c +++ b/drivers/clk/imx/clk.c @@ -14,6 +14,14 @@ DEFINE_SPINLOCK(imx_ccm_lock); +void imx_unregister_clocks(struct clk *clks[], unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) + clk_unregister(clks[i]); +} + void __init imx_mmdc_mask_handshake(void __iomem *ccm_base, unsigned int chn) { diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index d94d9cb079d3970e38e0f745d39b8e3311bcb25a..bb4ec1b33fafeaed073bd0b7b697768c75f9bb31 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -12,6 +12,7 @@ void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count); void imx_register_uart_clocks(struct clk ** const clks[]); void imx_register_uart_clocks_hws(struct clk_hw ** const hws[]); void imx_mmdc_mask_handshake(void __iomem *ccm_base, unsigned int chn); +void imx_unregister_clocks(struct clk *clks[], unsigned int count); extern void imx_cscmr1_fixup(u32 *val); @@ -153,6 +154,23 @@ enum imx_pllv3_type { struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name, const char *parent_name, void __iomem *base, u32 div_mask); +#define PLL_1416X_RATE(_rate, _m, _p, _s) \ + { \ + .rate = (_rate), \ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + } + +#define PLL_1443X_RATE(_rate, _m, _p, _s, _k) \ + { \ + .rate = (_rate), \ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + .kdiv = (_k), \ + } + struct clk_hw *imx_clk_pllv4(const char *name, const char *parent_name, void __iomem *base); diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index a6b20e123e0cc16ddc802c51c0efb356d5c70da7..dabeb435d06784205399a84d75f9faa883de0466 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -1,7 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -config COMMON_CLK_MESON_INPUT - tristate - config COMMON_CLK_MESON_REGMAP tristate select REGMAP @@ -33,13 +30,15 @@ config COMMON_CLK_MESON_VID_PLL_DIV config COMMON_CLK_MESON_AO_CLKC tristate select COMMON_CLK_MESON_REGMAP - select COMMON_CLK_MESON_INPUT select RESET_CONTROLLER config COMMON_CLK_MESON_EE_CLKC tristate select COMMON_CLK_MESON_REGMAP - select COMMON_CLK_MESON_INPUT + +config COMMON_CLK_MESON_CPU_DYNDIV + tristate + select COMMON_CLK_MESON_REGMAP config COMMON_CLK_MESON8B bool @@ -86,7 +85,6 @@ config COMMON_CLK_AXG config COMMON_CLK_AXG_AUDIO tristate "Meson AXG Audio Clock Controller Driver" depends on ARCH_MESON - select COMMON_CLK_MESON_INPUT select COMMON_CLK_MESON_REGMAP select COMMON_CLK_MESON_PHASE select COMMON_CLK_MESON_SCLK_DIV @@ -104,6 +102,7 @@ config COMMON_CLK_G12A select COMMON_CLK_MESON_PLL select COMMON_CLK_MESON_AO_CLKC select COMMON_CLK_MESON_EE_CLKC + select COMMON_CLK_MESON_CPU_DYNDIV select MFD_SYSCON help Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2 diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index bc35a4efd6b77c7de2f2a1fde2358fade29fef9a..3939f218587abfb324d32a81768eddabfca2d3c9 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -2,9 +2,9 @@ # Amlogic clock drivers obj-$(CONFIG_COMMON_CLK_MESON_AO_CLKC) += meson-aoclk.o +obj-$(CONFIG_COMMON_CLK_MESON_CPU_DYNDIV) += clk-cpu-dyndiv.o obj-$(CONFIG_COMMON_CLK_MESON_DUALDIV) += clk-dualdiv.o obj-$(CONFIG_COMMON_CLK_MESON_EE_CLKC) += meson-eeclk.o -obj-$(CONFIG_COMMON_CLK_MESON_INPUT) += clk-input.o obj-$(CONFIG_COMMON_CLK_MESON_MPLL) += clk-mpll.o obj-$(CONFIG_COMMON_CLK_MESON_PHASE) += clk-phase.o obj-$(CONFIG_COMMON_CLK_MESON_PLL) += clk-pll.o diff --git a/drivers/clk/meson/axg-aoclk.c b/drivers/clk/meson/axg-aoclk.c index 0086f31288eb8621bc38a0c4a104cd2c664079ed..b488b40c9d0e3f56bd94d0a7145abd475a263d3d 100644 --- a/drivers/clk/meson/axg-aoclk.c +++ b/drivers/clk/meson/axg-aoclk.c @@ -18,8 +18,6 @@ #include "clk-regmap.h" #include "clk-dualdiv.h" -#define IN_PREFIX "ao-in-" - /* * AO Configuration Clock registers offsets * Register offsets from the data sheet must be multiplied by 4. @@ -42,7 +40,9 @@ static struct clk_regmap axg_aoclk_##_name = { \ .hw.init = &(struct clk_init_data) { \ .name = "axg_ao_" #_name, \ .ops = &clk_regmap_gate_ops, \ - .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk" }, \ + .parent_data = &(const struct clk_parent_data) { \ + .fw_name = "mpeg-clk", \ + }, \ .num_parents = 1, \ .flags = CLK_IGNORE_UNUSED, \ }, \ @@ -64,7 +64,9 @@ static struct clk_regmap axg_aoclk_cts_oscin = { .hw.init = &(struct clk_init_data){ .name = "cts_oscin", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -77,7 +79,9 @@ static struct clk_regmap axg_aoclk_32k_pre = { .hw.init = &(struct clk_init_data){ .name = "axg_ao_32k_pre", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "cts_oscin" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_aoclk_cts_oscin.hw + }, .num_parents = 1, }, }; @@ -124,7 +128,9 @@ static struct clk_regmap axg_aoclk_32k_div = { .hw.init = &(struct clk_init_data){ .name = "axg_ao_32k_div", .ops = &meson_clk_dualdiv_ops, - .parent_names = (const char *[]){ "axg_ao_32k_pre" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_aoclk_32k_pre.hw + }, .num_parents = 1, }, }; @@ -139,8 +145,10 @@ static struct clk_regmap axg_aoclk_32k_sel = { .hw.init = &(struct clk_init_data){ .name = "axg_ao_32k_sel", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "axg_ao_32k_div", - "axg_ao_32k_pre" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_aoclk_32k_div.hw, + &axg_aoclk_32k_pre.hw, + }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, @@ -154,7 +162,9 @@ static struct clk_regmap axg_aoclk_32k = { .hw.init = &(struct clk_init_data){ .name = "axg_ao_32k", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "axg_ao_32k_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_aoclk_32k_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -170,8 +180,10 @@ static struct clk_regmap axg_aoclk_cts_rtc_oscin = { .hw.init = &(struct clk_init_data){ .name = "axg_ao_cts_rtc_oscin", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "axg_ao_32k", - IN_PREFIX "ext_32k-0" }, + .parent_data = (const struct clk_parent_data []) { + { .hw = &axg_aoclk_32k.hw }, + { .fw_name = "ext_32k-0", }, + }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, @@ -187,8 +199,10 @@ static struct clk_regmap axg_aoclk_clk81 = { .hw.init = &(struct clk_init_data){ .name = "axg_ao_clk81", .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk", - "axg_ao_cts_rtc_oscin"}, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "mpeg-clk", }, + { .hw = &axg_aoclk_cts_rtc_oscin.hw }, + }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, @@ -203,8 +217,10 @@ static struct clk_regmap axg_aoclk_saradc_mux = { .hw.init = &(struct clk_init_data){ .name = "axg_ao_saradc_mux", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal", - "axg_ao_clk81" }, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &axg_aoclk_clk81.hw }, + }, .num_parents = 2, }, }; @@ -218,7 +234,9 @@ static struct clk_regmap axg_aoclk_saradc_div = { .hw.init = &(struct clk_init_data){ .name = "axg_ao_saradc_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "axg_ao_saradc_mux" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_aoclk_saradc_mux.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -232,7 +250,9 @@ static struct clk_regmap axg_aoclk_saradc_gate = { .hw.init = &(struct clk_init_data){ .name = "axg_ao_saradc_gate", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "axg_ao_saradc_div" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_aoclk_saradc_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -290,12 +310,6 @@ static const struct clk_hw_onecell_data axg_aoclk_onecell_data = { .num = NR_CLKS, }; -static const struct meson_aoclk_input axg_aoclk_inputs[] = { - { .name = "xtal", .required = true }, - { .name = "mpeg-clk", .required = true }, - { .name = "ext-32k-0", .required = false }, -}; - static const struct meson_aoclk_data axg_aoclkc_data = { .reset_reg = AO_RTI_GEN_CNTL_REG0, .num_reset = ARRAY_SIZE(axg_aoclk_reset), @@ -303,9 +317,6 @@ static const struct meson_aoclk_data axg_aoclkc_data = { .num_clks = ARRAY_SIZE(axg_aoclk_regmap), .clks = axg_aoclk_regmap, .hw_data = &axg_aoclk_onecell_data, - .inputs = axg_aoclk_inputs, - .num_inputs = ARRAY_SIZE(axg_aoclk_inputs), - .input_prefix = IN_PREFIX, }; static const struct of_device_id axg_aoclkc_match_table[] = { diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c index 8028ff6f661075168f6e41afde073f0082d1d932..741df7e955ca0785c72e9ae13018c8bb025c3797 100644 --- a/drivers/clk/meson/axg-audio.c +++ b/drivers/clk/meson/axg-audio.c @@ -15,7 +15,6 @@ #include #include "axg-audio.h" -#include "clk-input.h" #include "clk-regmap.h" #include "clk-phase.h" #include "sclk-div.h" @@ -24,7 +23,7 @@ #define AUD_SLV_SCLK_COUNT 10 #define AUD_SLV_LRCLK_COUNT 10 -#define AUD_GATE(_name, _reg, _bit, _pname, _iflags) \ +#define AUD_GATE(_name, _reg, _bit, _phws, _iflags) \ struct clk_regmap aud_##_name = { \ .data = &(struct clk_regmap_gate_data){ \ .offset = (_reg), \ @@ -33,13 +32,13 @@ struct clk_regmap aud_##_name = { \ .hw.init = &(struct clk_init_data) { \ .name = "aud_"#_name, \ .ops = &clk_regmap_gate_ops, \ - .parent_names = (const char *[]){ _pname }, \ + .parent_hws = (const struct clk_hw *[]) { &_phws.hw }, \ .num_parents = 1, \ .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \ }, \ } -#define AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pnames, _iflags) \ +#define AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pdata, _iflags) \ struct clk_regmap aud_##_name = { \ .data = &(struct clk_regmap_mux_data){ \ .offset = (_reg), \ @@ -50,13 +49,13 @@ struct clk_regmap aud_##_name = { \ .hw.init = &(struct clk_init_data){ \ .name = "aud_"#_name, \ .ops = &clk_regmap_mux_ops, \ - .parent_names = (_pnames), \ - .num_parents = ARRAY_SIZE(_pnames), \ + .parent_data = _pdata, \ + .num_parents = ARRAY_SIZE(_pdata), \ .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \ }, \ } -#define AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) \ +#define AUD_DIV(_name, _reg, _shift, _width, _dflags, _phws, _iflags) \ struct clk_regmap aud_##_name = { \ .data = &(struct clk_regmap_div_data){ \ .offset = (_reg), \ @@ -67,15 +66,27 @@ struct clk_regmap aud_##_name = { \ .hw.init = &(struct clk_init_data){ \ .name = "aud_"#_name, \ .ops = &clk_regmap_divider_ops, \ - .parent_names = (const char *[]) { _pname }, \ + .parent_hws = (const struct clk_hw *[]) { &_phws.hw }, \ .num_parents = 1, \ .flags = (_iflags), \ }, \ } #define AUD_PCLK_GATE(_name, _bit) \ - AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "audio_pclk", 0) - +struct clk_regmap aud_##_name = { \ + .data = &(struct clk_regmap_gate_data){ \ + .offset = (AUDIO_CLK_GATE_EN), \ + .bit_idx = (_bit), \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = "aud_"#_name, \ + .ops = &clk_regmap_gate_ops, \ + .parent_data = &(const struct clk_parent_data) { \ + .fw_name = "pclk", \ + }, \ + .num_parents = 1, \ + }, \ +} /* Audio peripheral clocks */ static AUD_PCLK_GATE(ddr_arb, 0); static AUD_PCLK_GATE(pdm, 1); @@ -100,14 +111,20 @@ static AUD_PCLK_GATE(power_detect, 19); static AUD_PCLK_GATE(spdifout_b, 21); /* Audio Master Clocks */ -static const char * const mst_mux_parent_names[] = { - "aud_mst_in0", "aud_mst_in1", "aud_mst_in2", "aud_mst_in3", - "aud_mst_in4", "aud_mst_in5", "aud_mst_in6", "aud_mst_in7", +static const struct clk_parent_data mst_mux_parent_data[] = { + { .fw_name = "mst_in0", }, + { .fw_name = "mst_in1", }, + { .fw_name = "mst_in2", }, + { .fw_name = "mst_in3", }, + { .fw_name = "mst_in4", }, + { .fw_name = "mst_in5", }, + { .fw_name = "mst_in6", }, + { .fw_name = "mst_in7", }, }; #define AUD_MST_MUX(_name, _reg, _flag) \ AUD_MUX(_name##_sel, _reg, 0x7, 24, _flag, \ - mst_mux_parent_names, CLK_SET_RATE_PARENT) + mst_mux_parent_data, 0) #define AUD_MST_MCLK_MUX(_name, _reg) \ AUD_MST_MUX(_name, _reg, CLK_MUX_ROUND_CLOSEST) @@ -129,7 +146,7 @@ static AUD_MST_MCLK_MUX(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); #define AUD_MST_DIV(_name, _reg, _flag) \ AUD_DIV(_name##_div, _reg, 0, 16, _flag, \ - "aud_"#_name"_sel", CLK_SET_RATE_PARENT) \ + aud_##_name##_sel, CLK_SET_RATE_PARENT) \ #define AUD_MST_MCLK_DIV(_name, _reg) \ AUD_MST_DIV(_name, _reg, CLK_DIVIDER_ROUND_CLOSEST) @@ -150,7 +167,7 @@ static AUD_MST_SYS_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); static AUD_MST_MCLK_DIV(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); #define AUD_MST_MCLK_GATE(_name, _reg) \ - AUD_GATE(_name, _reg, 31, "aud_"#_name"_div", \ + AUD_GATE(_name, _reg, 31, aud_##_name##_div, \ CLK_SET_RATE_PARENT) static AUD_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL); @@ -168,7 +185,7 @@ static AUD_MST_MCLK_GATE(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); /* Sample Clocks */ #define AUD_MST_SCLK_PRE_EN(_name, _reg) \ AUD_GATE(mst_##_name##_sclk_pre_en, _reg, 31, \ - "aud_mst_"#_name"_mclk", 0) + aud_mst_##_name##_mclk, 0) static AUD_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0); static AUD_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0); @@ -178,7 +195,7 @@ static AUD_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0); static AUD_MST_SCLK_PRE_EN(f, AUDIO_MST_F_SCLK_CTRL0); #define AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width, \ - _hi_shift, _hi_width, _pname, _iflags) \ + _hi_shift, _hi_width, _phws, _iflags) \ struct clk_regmap aud_##_name = { \ .data = &(struct meson_sclk_div_data) { \ .div = { \ @@ -195,7 +212,7 @@ struct clk_regmap aud_##_name = { \ .hw.init = &(struct clk_init_data) { \ .name = "aud_"#_name, \ .ops = &meson_sclk_div_ops, \ - .parent_names = (const char *[]) { _pname }, \ + .parent_hws = (const struct clk_hw *[]) { &_phws.hw }, \ .num_parents = 1, \ .flags = (_iflags), \ }, \ @@ -203,7 +220,7 @@ struct clk_regmap aud_##_name = { \ #define AUD_MST_SCLK_DIV(_name, _reg) \ AUD_SCLK_DIV(mst_##_name##_sclk_div, _reg, 20, 10, 0, 0, \ - "aud_mst_"#_name"_sclk_pre_en", \ + aud_mst_##_name##_sclk_pre_en, \ CLK_SET_RATE_PARENT) static AUD_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); @@ -214,8 +231,8 @@ static AUD_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); static AUD_MST_SCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); #define AUD_MST_SCLK_POST_EN(_name, _reg) \ - AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30, \ - "aud_mst_"#_name"_sclk_div", CLK_SET_RATE_PARENT) + AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30, \ + aud_mst_##_name##_sclk_div, CLK_SET_RATE_PARENT) static AUD_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0); static AUD_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0); @@ -224,8 +241,8 @@ static AUD_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0); static AUD_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0); static AUD_MST_SCLK_POST_EN(f, AUDIO_MST_F_SCLK_CTRL0); -#define AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \ - _pname, _iflags) \ +#define AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \ + _phws, _iflags) \ struct clk_regmap aud_##_name = { \ .data = &(struct meson_clk_triphase_data) { \ .ph0 = { \ @@ -247,7 +264,7 @@ struct clk_regmap aud_##_name = { \ .hw.init = &(struct clk_init_data) { \ .name = "aud_"#_name, \ .ops = &meson_clk_triphase_ops, \ - .parent_names = (const char *[]) { _pname }, \ + .parent_hws = (const struct clk_hw *[]) { &_phws.hw }, \ .num_parents = 1, \ .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \ }, \ @@ -255,7 +272,7 @@ struct clk_regmap aud_##_name = { \ #define AUD_MST_SCLK(_name, _reg) \ AUD_TRIPHASE(mst_##_name##_sclk, _reg, 1, 0, 2, 4, \ - "aud_mst_"#_name"_sclk_post_en", CLK_SET_RATE_PARENT) + aud_mst_##_name##_sclk_post_en, CLK_SET_RATE_PARENT) static AUD_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1); static AUD_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1); @@ -266,7 +283,7 @@ static AUD_MST_SCLK(f, AUDIO_MST_F_SCLK_CTRL1); #define AUD_MST_LRCLK_DIV(_name, _reg) \ AUD_SCLK_DIV(mst_##_name##_lrclk_div, _reg, 0, 10, 10, 10, \ - "aud_mst_"#_name"_sclk_post_en", 0) \ + aud_mst_##_name##_sclk_post_en, 0) \ static AUD_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); static AUD_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); @@ -277,7 +294,7 @@ static AUD_MST_LRCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); #define AUD_MST_LRCLK(_name, _reg) \ AUD_TRIPHASE(mst_##_name##_lrclk, _reg, 1, 1, 3, 5, \ - "aud_mst_"#_name"_lrclk_div", CLK_SET_RATE_PARENT) + aud_mst_##_name##_lrclk_div, CLK_SET_RATE_PARENT) static AUD_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1); static AUD_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1); @@ -286,19 +303,29 @@ static AUD_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1); static AUD_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1); static AUD_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1); -static const char * const tdm_sclk_parent_names[] = { - "aud_mst_a_sclk", "aud_mst_b_sclk", "aud_mst_c_sclk", - "aud_mst_d_sclk", "aud_mst_e_sclk", "aud_mst_f_sclk", - "aud_slv_sclk0", "aud_slv_sclk1", "aud_slv_sclk2", - "aud_slv_sclk3", "aud_slv_sclk4", "aud_slv_sclk5", - "aud_slv_sclk6", "aud_slv_sclk7", "aud_slv_sclk8", - "aud_slv_sclk9" +static const struct clk_parent_data tdm_sclk_parent_data[] = { + { .hw = &aud_mst_a_sclk.hw, }, + { .hw = &aud_mst_b_sclk.hw, }, + { .hw = &aud_mst_c_sclk.hw, }, + { .hw = &aud_mst_d_sclk.hw, }, + { .hw = &aud_mst_e_sclk.hw, }, + { .hw = &aud_mst_f_sclk.hw, }, + { .fw_name = "slv_sclk0", }, + { .fw_name = "slv_sclk1", }, + { .fw_name = "slv_sclk2", }, + { .fw_name = "slv_sclk3", }, + { .fw_name = "slv_sclk4", }, + { .fw_name = "slv_sclk5", }, + { .fw_name = "slv_sclk6", }, + { .fw_name = "slv_sclk7", }, + { .fw_name = "slv_sclk8", }, + { .fw_name = "slv_sclk9", }, }; #define AUD_TDM_SCLK_MUX(_name, _reg) \ AUD_MUX(tdm##_name##_sclk_sel, _reg, 0xf, 24, \ CLK_MUX_ROUND_CLOSEST, \ - tdm_sclk_parent_names, 0) + tdm_sclk_parent_data, 0) static AUD_TDM_SCLK_MUX(in_a, AUDIO_CLK_TDMIN_A_CTRL); static AUD_TDM_SCLK_MUX(in_b, AUDIO_CLK_TDMIN_B_CTRL); @@ -310,7 +337,7 @@ static AUD_TDM_SCLK_MUX(out_c, AUDIO_CLK_TDMOUT_C_CTRL); #define AUD_TDM_SCLK_PRE_EN(_name, _reg) \ AUD_GATE(tdm##_name##_sclk_pre_en, _reg, 31, \ - "aud_tdm"#_name"_sclk_sel", CLK_SET_RATE_PARENT) + aud_tdm##_name##_sclk_sel, CLK_SET_RATE_PARENT) static AUD_TDM_SCLK_PRE_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); static AUD_TDM_SCLK_PRE_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); @@ -322,7 +349,7 @@ static AUD_TDM_SCLK_PRE_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); #define AUD_TDM_SCLK_POST_EN(_name, _reg) \ AUD_GATE(tdm##_name##_sclk_post_en, _reg, 30, \ - "aud_tdm"#_name"_sclk_pre_en", CLK_SET_RATE_PARENT) + aud_tdm##_name##_sclk_pre_en, CLK_SET_RATE_PARENT) static AUD_TDM_SCLK_POST_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); static AUD_TDM_SCLK_POST_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); @@ -344,8 +371,9 @@ static AUD_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); .hw.init = &(struct clk_init_data) { \ .name = "aud_tdm"#_name"_sclk", \ .ops = &meson_clk_phase_ops, \ - .parent_names = (const char *[]) \ - { "aud_tdm"#_name"_sclk_post_en" }, \ + .parent_hws = (const struct clk_hw *[]) { \ + &aud_tdm##_name##_sclk_post_en.hw \ + }, \ .num_parents = 1, \ .flags = CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT, \ }, \ @@ -359,19 +387,29 @@ static AUD_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); static AUD_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); static AUD_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); -static const char * const tdm_lrclk_parent_names[] = { - "aud_mst_a_lrclk", "aud_mst_b_lrclk", "aud_mst_c_lrclk", - "aud_mst_d_lrclk", "aud_mst_e_lrclk", "aud_mst_f_lrclk", - "aud_slv_lrclk0", "aud_slv_lrclk1", "aud_slv_lrclk2", - "aud_slv_lrclk3", "aud_slv_lrclk4", "aud_slv_lrclk5", - "aud_slv_lrclk6", "aud_slv_lrclk7", "aud_slv_lrclk8", - "aud_slv_lrclk9" +static const struct clk_parent_data tdm_lrclk_parent_data[] = { + { .hw = &aud_mst_a_lrclk.hw, }, + { .hw = &aud_mst_b_lrclk.hw, }, + { .hw = &aud_mst_c_lrclk.hw, }, + { .hw = &aud_mst_d_lrclk.hw, }, + { .hw = &aud_mst_e_lrclk.hw, }, + { .hw = &aud_mst_f_lrclk.hw, }, + { .fw_name = "slv_lrclk0", }, + { .fw_name = "slv_lrclk1", }, + { .fw_name = "slv_lrclk2", }, + { .fw_name = "slv_lrclk3", }, + { .fw_name = "slv_lrclk4", }, + { .fw_name = "slv_lrclk5", }, + { .fw_name = "slv_lrclk6", }, + { .fw_name = "slv_lrclk7", }, + { .fw_name = "slv_lrclk8", }, + { .fw_name = "slv_lrclk9", }, }; -#define AUD_TDM_LRLCK(_name, _reg) \ - AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \ - CLK_MUX_ROUND_CLOSEST, \ - tdm_lrclk_parent_names, 0) +#define AUD_TDM_LRLCK(_name, _reg) \ + AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \ + CLK_MUX_ROUND_CLOSEST, \ + tdm_lrclk_parent_data, 0) static AUD_TDM_LRLCK(in_a, AUDIO_CLK_TDMIN_A_CTRL); static AUD_TDM_LRLCK(in_b, AUDIO_CLK_TDMIN_B_CTRL); @@ -386,39 +424,51 @@ static AUD_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); AUD_MUX(tdm_##_name, _reg, 0x7, _shift, 0, _parents, \ CLK_SET_RATE_NO_REPARENT) -static const char * const mclk_pad_ctrl_parent_names[] = { - "aud_mst_a_mclk", "aud_mst_b_mclk", "aud_mst_c_mclk", - "aud_mst_d_mclk", "aud_mst_e_mclk", "aud_mst_f_mclk", +static const struct clk_parent_data mclk_pad_ctrl_parent_data[] = { + { .hw = &aud_mst_a_mclk.hw }, + { .hw = &aud_mst_b_mclk.hw }, + { .hw = &aud_mst_c_mclk.hw }, + { .hw = &aud_mst_d_mclk.hw }, + { .hw = &aud_mst_e_mclk.hw }, + { .hw = &aud_mst_f_mclk.hw }, }; static AUD_TDM_PAD_CTRL(mclk_pad_0, AUDIO_MST_PAD_CTRL0, 0, - mclk_pad_ctrl_parent_names); + mclk_pad_ctrl_parent_data); static AUD_TDM_PAD_CTRL(mclk_pad_1, AUDIO_MST_PAD_CTRL0, 4, - mclk_pad_ctrl_parent_names); - -static const char * const lrclk_pad_ctrl_parent_names[] = { - "aud_mst_a_lrclk", "aud_mst_b_lrclk", "aud_mst_c_lrclk", - "aud_mst_d_lrclk", "aud_mst_e_lrclk", "aud_mst_f_lrclk", + mclk_pad_ctrl_parent_data); + +static const struct clk_parent_data lrclk_pad_ctrl_parent_data[] = { + { .hw = &aud_mst_a_lrclk.hw }, + { .hw = &aud_mst_b_lrclk.hw }, + { .hw = &aud_mst_c_lrclk.hw }, + { .hw = &aud_mst_d_lrclk.hw }, + { .hw = &aud_mst_e_lrclk.hw }, + { .hw = &aud_mst_f_lrclk.hw }, }; static AUD_TDM_PAD_CTRL(lrclk_pad_0, AUDIO_MST_PAD_CTRL1, 16, - lrclk_pad_ctrl_parent_names); + lrclk_pad_ctrl_parent_data); static AUD_TDM_PAD_CTRL(lrclk_pad_1, AUDIO_MST_PAD_CTRL1, 20, - lrclk_pad_ctrl_parent_names); + lrclk_pad_ctrl_parent_data); static AUD_TDM_PAD_CTRL(lrclk_pad_2, AUDIO_MST_PAD_CTRL1, 24, - lrclk_pad_ctrl_parent_names); - -static const char * const sclk_pad_ctrl_parent_names[] = { - "aud_mst_a_sclk", "aud_mst_b_sclk", "aud_mst_c_sclk", - "aud_mst_d_sclk", "aud_mst_e_sclk", "aud_mst_f_sclk", + lrclk_pad_ctrl_parent_data); + +static const struct clk_parent_data sclk_pad_ctrl_parent_data[] = { + { .hw = &aud_mst_a_sclk.hw }, + { .hw = &aud_mst_b_sclk.hw }, + { .hw = &aud_mst_c_sclk.hw }, + { .hw = &aud_mst_d_sclk.hw }, + { .hw = &aud_mst_e_sclk.hw }, + { .hw = &aud_mst_f_sclk.hw }, }; static AUD_TDM_PAD_CTRL(sclk_pad_0, AUDIO_MST_PAD_CTRL1, 0, - sclk_pad_ctrl_parent_names); + sclk_pad_ctrl_parent_data); static AUD_TDM_PAD_CTRL(sclk_pad_1, AUDIO_MST_PAD_CTRL1, 4, - sclk_pad_ctrl_parent_names); + sclk_pad_ctrl_parent_data); static AUD_TDM_PAD_CTRL(sclk_pad_2, AUDIO_MST_PAD_CTRL1, 8, - sclk_pad_ctrl_parent_names); + sclk_pad_ctrl_parent_data); /* * Array of all clocks provided by this provider @@ -868,54 +918,6 @@ static int devm_clk_get_enable(struct device *dev, char *id) return 0; } -static int axg_register_clk_hw_input(struct device *dev, - const char *name) -{ - char *clk_name; - struct clk_hw *hw; - int err = 0; - - clk_name = kasprintf(GFP_KERNEL, "aud_%s", name); - if (!clk_name) - return -ENOMEM; - - hw = meson_clk_hw_register_input(dev, name, clk_name, 0); - if (IS_ERR(hw)) { - /* It is ok if an input clock is missing */ - if (PTR_ERR(hw) == -ENOENT) { - dev_dbg(dev, "%s not provided", name); - } else { - err = PTR_ERR(hw); - if (err != -EPROBE_DEFER) - dev_err(dev, "failed to get %s clock", name); - } - } - - kfree(clk_name); - return err; -} - -static int axg_register_clk_hw_inputs(struct device *dev, - const char *basename, - unsigned int count) -{ - char *name; - int i, ret; - - for (i = 0; i < count; i++) { - name = kasprintf(GFP_KERNEL, "%s%d", basename, i); - if (!name) - return -ENOMEM; - - ret = axg_register_clk_hw_input(dev, name); - kfree(name); - if (ret) - return ret; - } - - return 0; -} - static const struct regmap_config axg_audio_regmap_cfg = { .reg_bits = 32, .val_bits = 32, @@ -963,29 +965,6 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) return ret; } - /* Register the peripheral input clock */ - hw = meson_clk_hw_register_input(dev, "pclk", "audio_pclk", 0); - if (IS_ERR(hw)) - return PTR_ERR(hw); - - /* Register optional input master clocks */ - ret = axg_register_clk_hw_inputs(dev, "mst_in", - AUD_MST_IN_COUNT); - if (ret) - return ret; - - /* Register optional input slave sclks */ - ret = axg_register_clk_hw_inputs(dev, "slv_sclk", - AUD_SLV_SCLK_COUNT); - if (ret) - return ret; - - /* Register optional input slave lrclks */ - ret = axg_register_clk_hw_inputs(dev, "slv_lrclk", - AUD_SLV_LRCLK_COUNT); - if (ret) - return ret; - /* Populate regmap for the regmap backed clocks */ for (i = 0; i < ARRAY_SIZE(aud_clk_regmaps); i++) aud_clk_regmaps[i]->map = map; diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 3ddd0efc9ee0b7a2d233888e1650361929511f86..13fc0006f63d82f4de17a376ecafe9344907e93f 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -14,7 +14,6 @@ #include #include -#include "clk-input.h" #include "clk-regmap.h" #include "clk-pll.h" #include "clk-mpll.h" @@ -59,7 +58,9 @@ static struct clk_regmap axg_fixed_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -74,7 +75,9 @@ static struct clk_regmap axg_fixed_pll = { .hw.init = &(struct clk_init_data){ .name = "fixed_pll", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "fixed_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_fixed_pll_dco.hw + }, .num_parents = 1, /* * This clock won't ever change at runtime so @@ -114,7 +117,9 @@ static struct clk_regmap axg_sys_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "sys_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -129,7 +134,9 @@ static struct clk_regmap axg_sys_pll = { .hw.init = &(struct clk_init_data){ .name = "sys_pll", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "sys_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_sys_pll_dco.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -215,7 +222,9 @@ static struct clk_regmap axg_gp0_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -230,7 +239,9 @@ static struct clk_regmap axg_gp0_pll = { .hw.init = &(struct clk_init_data){ .name = "gp0_pll", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "gp0_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_gp0_pll_dco.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -284,7 +295,9 @@ static struct clk_regmap axg_hifi_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "hifi_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -299,7 +312,9 @@ static struct clk_regmap axg_hifi_pll = { .hw.init = &(struct clk_init_data){ .name = "hifi_pll", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "hifi_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_hifi_pll_dco.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -311,7 +326,7 @@ static struct clk_fixed_factor axg_fclk_div2_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div2_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { &axg_fixed_pll.hw }, .num_parents = 1, }, }; @@ -324,7 +339,9 @@ static struct clk_regmap axg_fclk_div2 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div2", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div2_div" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_fclk_div2_div.hw + }, .num_parents = 1, .flags = CLK_IS_CRITICAL, }, @@ -336,7 +353,7 @@ static struct clk_fixed_factor axg_fclk_div3_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div3_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { &axg_fixed_pll.hw }, .num_parents = 1, }, }; @@ -349,7 +366,9 @@ static struct clk_regmap axg_fclk_div3 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div3", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div3_div" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_fclk_div3_div.hw + }, .num_parents = 1, /* * FIXME: @@ -372,7 +391,7 @@ static struct clk_fixed_factor axg_fclk_div4_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div4_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { &axg_fixed_pll.hw }, .num_parents = 1, }, }; @@ -385,7 +404,9 @@ static struct clk_regmap axg_fclk_div4 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div4", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div4_div" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_fclk_div4_div.hw + }, .num_parents = 1, }, }; @@ -396,7 +417,7 @@ static struct clk_fixed_factor axg_fclk_div5_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div5_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { &axg_fixed_pll.hw }, .num_parents = 1, }, }; @@ -409,7 +430,9 @@ static struct clk_regmap axg_fclk_div5 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div5", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div5_div" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_fclk_div5_div.hw + }, .num_parents = 1, }, }; @@ -420,7 +443,9 @@ static struct clk_fixed_factor axg_fclk_div7_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div7_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_fixed_pll.hw + }, .num_parents = 1, }, }; @@ -433,7 +458,9 @@ static struct clk_regmap axg_fclk_div7 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div7", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div7_div" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_fclk_div7_div.hw + }, .num_parents = 1, }, }; @@ -447,7 +474,9 @@ static struct clk_regmap axg_mpll_prediv = { .hw.init = &(struct clk_init_data){ .name = "mpll_prediv", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_fixed_pll.hw + }, .num_parents = 1, }, }; @@ -480,7 +509,9 @@ static struct clk_regmap axg_mpll0_div = { .hw.init = &(struct clk_init_data){ .name = "mpll0_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "mpll_prediv" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpll_prediv.hw + }, .num_parents = 1, }, }; @@ -493,7 +524,9 @@ static struct clk_regmap axg_mpll0 = { .hw.init = &(struct clk_init_data){ .name = "mpll0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpll0_div" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpll0_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -527,7 +560,9 @@ static struct clk_regmap axg_mpll1_div = { .hw.init = &(struct clk_init_data){ .name = "mpll1_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "mpll_prediv" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpll_prediv.hw + }, .num_parents = 1, }, }; @@ -540,7 +575,9 @@ static struct clk_regmap axg_mpll1 = { .hw.init = &(struct clk_init_data){ .name = "mpll1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpll1_div" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpll1_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -579,7 +616,9 @@ static struct clk_regmap axg_mpll2_div = { .hw.init = &(struct clk_init_data){ .name = "mpll2_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "mpll_prediv" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpll_prediv.hw + }, .num_parents = 1, }, }; @@ -592,7 +631,9 @@ static struct clk_regmap axg_mpll2 = { .hw.init = &(struct clk_init_data){ .name = "mpll2", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpll2_div" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpll2_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -626,7 +667,9 @@ static struct clk_regmap axg_mpll3_div = { .hw.init = &(struct clk_init_data){ .name = "mpll3_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "mpll_prediv" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpll_prediv.hw + }, .num_parents = 1, }, }; @@ -639,7 +682,9 @@ static struct clk_regmap axg_mpll3 = { .hw.init = &(struct clk_init_data){ .name = "mpll3", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpll3_div" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpll3_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -702,7 +747,9 @@ static struct clk_regmap axg_pcie_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "pcie_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -717,7 +764,9 @@ static struct clk_regmap axg_pcie_pll_od = { .hw.init = &(struct clk_init_data){ .name = "pcie_pll_od", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "pcie_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_pcie_pll_dco.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -733,7 +782,9 @@ static struct clk_regmap axg_pcie_pll = { .hw.init = &(struct clk_init_data){ .name = "pcie_pll", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "pcie_pll_od" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_pcie_pll_od.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -750,7 +801,7 @@ static struct clk_regmap axg_pcie_mux = { .hw.init = &(struct clk_init_data){ .name = "pcie_mux", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "pcie_pll" }, + .parent_hws = (const struct clk_hw *[]) { &axg_pcie_pll.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -767,7 +818,7 @@ static struct clk_regmap axg_pcie_ref = { .hw.init = &(struct clk_init_data){ .name = "pcie_ref", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "pcie_mux" }, + .parent_hws = (const struct clk_hw *[]) { &axg_pcie_mux.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -781,7 +832,7 @@ static struct clk_regmap axg_pcie_cml_en0 = { .hw.init = &(struct clk_init_data) { .name = "pcie_cml_en0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "pcie_ref" }, + .parent_hws = (const struct clk_hw *[]) { &axg_pcie_ref.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -796,16 +847,21 @@ static struct clk_regmap axg_pcie_cml_en1 = { .hw.init = &(struct clk_init_data) { .name = "pcie_cml_en1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "pcie_ref" }, + .parent_hws = (const struct clk_hw *[]) { &axg_pcie_ref.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; -static const char * const clk81_parent_names[] = { - IN_PREFIX "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", - "fclk_div3", "fclk_div5" +static const struct clk_parent_data clk81_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &axg_fclk_div7.hw }, + { .hw = &axg_mpll1.hw }, + { .hw = &axg_mpll2.hw }, + { .hw = &axg_fclk_div4.hw }, + { .hw = &axg_fclk_div3.hw }, + { .hw = &axg_fclk_div5.hw }, }; static struct clk_regmap axg_mpeg_clk_sel = { @@ -818,8 +874,8 @@ static struct clk_regmap axg_mpeg_clk_sel = { .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_names = clk81_parent_names, - .num_parents = ARRAY_SIZE(clk81_parent_names), + .parent_data = clk81_parent_data, + .num_parents = ARRAY_SIZE(clk81_parent_data), }, }; @@ -832,7 +888,9 @@ static struct clk_regmap axg_mpeg_clk_div = { .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "mpeg_clk_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpeg_clk_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -846,15 +904,20 @@ static struct clk_regmap axg_clk81 = { .hw.init = &(struct clk_init_data){ .name = "clk81", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpeg_clk_div" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpeg_clk_div.hw + }, .num_parents = 1, .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), }, }; -static const char * const axg_sd_emmc_clk0_parent_names[] = { - IN_PREFIX "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", - +static const struct clk_parent_data axg_sd_emmc_clk0_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &axg_fclk_div2.hw }, + { .hw = &axg_fclk_div3.hw }, + { .hw = &axg_fclk_div5.hw }, + { .hw = &axg_fclk_div7.hw }, /* * Following these parent clocks, we should also have had mpll2, mpll3 * and gp0_pll but these clocks are too precious to be used here. All @@ -873,8 +936,8 @@ static struct clk_regmap axg_sd_emmc_b_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_names = axg_sd_emmc_clk0_parent_names, - .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_names), + .parent_data = axg_sd_emmc_clk0_parent_data, + .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_data), .flags = CLK_SET_RATE_PARENT, }, }; @@ -889,7 +952,9 @@ static struct clk_regmap axg_sd_emmc_b_clk0_div = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_sd_emmc_b_clk0_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -903,7 +968,9 @@ static struct clk_regmap axg_sd_emmc_b_clk0 = { .hw.init = &(struct clk_init_data){ .name = "sd_emmc_b_clk0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_sd_emmc_b_clk0_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -919,8 +986,8 @@ static struct clk_regmap axg_sd_emmc_c_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_names = axg_sd_emmc_clk0_parent_names, - .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_names), + .parent_data = axg_sd_emmc_clk0_parent_data, + .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_data), .flags = CLK_SET_RATE_PARENT, }, }; @@ -935,7 +1002,9 @@ static struct clk_regmap axg_sd_emmc_c_clk0_div = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_sd_emmc_c_clk0_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -949,7 +1018,9 @@ static struct clk_regmap axg_sd_emmc_c_clk0 = { .hw.init = &(struct clk_init_data){ .name = "sd_emmc_c_clk0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_sd_emmc_c_clk0_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -957,9 +1028,18 @@ static struct clk_regmap axg_sd_emmc_c_clk0 = { static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, }; -static const char * const gen_clk_parent_names[] = { - IN_PREFIX "xtal", "hifi_pll", "mpll0", "mpll1", "mpll2", "mpll3", - "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "gp0_pll", +static const struct clk_parent_data gen_clk_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &axg_hifi_pll.hw }, + { .hw = &axg_mpll0.hw }, + { .hw = &axg_mpll1.hw }, + { .hw = &axg_mpll2.hw }, + { .hw = &axg_mpll3.hw }, + { .hw = &axg_fclk_div4.hw }, + { .hw = &axg_fclk_div3.hw }, + { .hw = &axg_fclk_div5.hw }, + { .hw = &axg_fclk_div7.hw }, + { .hw = &axg_gp0_pll.hw }, }; static struct clk_regmap axg_gen_clk_sel = { @@ -978,8 +1058,8 @@ static struct clk_regmap axg_gen_clk_sel = { * hifi_pll, mpll0, mpll1, mpll2, mpll3, fdiv4, * fdiv3, fdiv5, [cts_msr_clk], fdiv7, gp0_pll */ - .parent_names = gen_clk_parent_names, - .num_parents = ARRAY_SIZE(gen_clk_parent_names), + .parent_data = gen_clk_parent_data, + .num_parents = ARRAY_SIZE(gen_clk_parent_data), }, }; @@ -992,7 +1072,9 @@ static struct clk_regmap axg_gen_clk_div = { .hw.init = &(struct clk_init_data){ .name = "gen_clk_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "gen_clk_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_gen_clk_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1006,12 +1088,17 @@ static struct clk_regmap axg_gen_clk = { .hw.init = &(struct clk_init_data){ .name = "gen_clk", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "gen_clk_div" }, + .parent_hws = (const struct clk_hw *[]) { + &axg_gen_clk_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; +#define MESON_GATE(_name, _reg, _bit) \ + MESON_PCLK(_name, _reg, _bit, &axg_clk81.hw) + /* Everything Else (EE) domain gates */ static MESON_GATE(axg_ddr, HHI_GCLK_MPEG0, 0); static MESON_GATE(axg_audio_locker, HHI_GCLK_MPEG0, 2); diff --git a/drivers/clk/meson/clk-cpu-dyndiv.c b/drivers/clk/meson/clk-cpu-dyndiv.c new file mode 100644 index 0000000000000000000000000000000000000000..36976927fe827fc87fbed800d39abfc76e5c9495 --- /dev/null +++ b/drivers/clk/meson/clk-cpu-dyndiv.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Neil Armstrong + */ + +#include +#include + +#include "clk-regmap.h" +#include "clk-cpu-dyndiv.h" + +static inline struct meson_clk_cpu_dyndiv_data * +meson_clk_cpu_dyndiv_data(struct clk_regmap *clk) +{ + return (struct meson_clk_cpu_dyndiv_data *)clk->data; +} + +static unsigned long meson_clk_cpu_dyndiv_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_cpu_dyndiv_data *data = meson_clk_cpu_dyndiv_data(clk); + + return divider_recalc_rate(hw, prate, + meson_parm_read(clk->map, &data->div), + NULL, 0, data->div.width); +} + +static long meson_clk_cpu_dyndiv_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *prate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_cpu_dyndiv_data *data = meson_clk_cpu_dyndiv_data(clk); + + return divider_round_rate(hw, rate, prate, NULL, data->div.width, 0); +} + +static int meson_clk_cpu_dyndiv_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_cpu_dyndiv_data *data = meson_clk_cpu_dyndiv_data(clk); + unsigned int val; + int ret; + + ret = divider_get_val(rate, parent_rate, NULL, data->div.width, 0); + if (ret < 0) + return ret; + + val = (unsigned int)ret << data->div.shift; + + /* Write the SYS_CPU_DYN_ENABLE bit before changing the divider */ + meson_parm_write(clk->map, &data->dyn, 1); + + /* Update the divider while removing the SYS_CPU_DYN_ENABLE bit */ + return regmap_update_bits(clk->map, data->div.reg_off, + SETPMASK(data->div.width, data->div.shift) | + SETPMASK(data->dyn.width, data->dyn.shift), + val); +}; + +const struct clk_ops meson_clk_cpu_dyndiv_ops = { + .recalc_rate = meson_clk_cpu_dyndiv_recalc_rate, + .round_rate = meson_clk_cpu_dyndiv_round_rate, + .set_rate = meson_clk_cpu_dyndiv_set_rate, +}; +EXPORT_SYMBOL_GPL(meson_clk_cpu_dyndiv_ops); + +MODULE_DESCRIPTION("Amlogic CPU Dynamic Clock divider"); +MODULE_AUTHOR("Neil Armstrong "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/clk-cpu-dyndiv.h b/drivers/clk/meson/clk-cpu-dyndiv.h new file mode 100644 index 0000000000000000000000000000000000000000..f4908404792ec05f33fdd0841116ef2cec360fd2 --- /dev/null +++ b/drivers/clk/meson/clk-cpu-dyndiv.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Neil Armstrong + */ + +#ifndef __MESON_CLK_CPU_DYNDIV_H +#define __MESON_CLK_CPU_DYNDIV_H + +#include +#include "parm.h" + +struct meson_clk_cpu_dyndiv_data { + struct parm div; + struct parm dyn; +}; + +extern const struct clk_ops meson_clk_cpu_dyndiv_ops; + +#endif /* __MESON_CLK_CPU_DYNDIV_H */ diff --git a/drivers/clk/meson/clk-input.c b/drivers/clk/meson/clk-input.c deleted file mode 100644 index 086226e9dba640f173110da556cffb69784d1d81..0000000000000000000000000000000000000000 --- a/drivers/clk/meson/clk-input.c +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR MIT) -/* - * Copyright (c) 2018 BayLibre, SAS. - * Author: Jerome Brunet - */ - -#include -#include -#include -#include -#include "clk-input.h" - -static const struct clk_ops meson_clk_no_ops = {}; - -struct clk_hw *meson_clk_hw_register_input(struct device *dev, - const char *of_name, - const char *clk_name, - unsigned long flags) -{ - struct clk *parent_clk = devm_clk_get(dev, of_name); - struct clk_init_data init; - const char *parent_name; - struct clk_hw *hw; - int ret; - - if (IS_ERR(parent_clk)) - return (struct clk_hw *)parent_clk; - - hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); - if (!hw) - return ERR_PTR(-ENOMEM); - - parent_name = __clk_get_name(parent_clk); - init.name = clk_name; - init.ops = &meson_clk_no_ops; - init.flags = flags; - init.parent_names = &parent_name; - init.num_parents = 1; - hw->init = &init; - - ret = devm_clk_hw_register(dev, hw); - - return ret ? ERR_PTR(ret) : hw; -} -EXPORT_SYMBOL_GPL(meson_clk_hw_register_input); - -MODULE_DESCRIPTION("Amlogic clock input helper"); -MODULE_AUTHOR("Jerome Brunet "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/clk-input.h b/drivers/clk/meson/clk-input.h deleted file mode 100644 index 4a541b9685a66933d3aa8b40e3fc5d37abb1f621..0000000000000000000000000000000000000000 --- a/drivers/clk/meson/clk-input.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2019 BayLibre, SAS. - * Author: Jerome Brunet - */ - -#ifndef __MESON_CLK_INPUT_H -#define __MESON_CLK_INPUT_H - -#include - -struct device; - -struct clk_hw *meson_clk_hw_register_input(struct device *dev, - const char *of_name, - const char *clk_name, - unsigned long flags); - -#endif /* __MESON_CLK_INPUT_H */ diff --git a/drivers/clk/meson/clk-regmap.h b/drivers/clk/meson/clk-regmap.h index 1dd0abe3ba91a48f2fb290f5958a6b8d81f68348..c4a39604cffdd32a5904f21a429b0dee378610e3 100644 --- a/drivers/clk/meson/clk-regmap.h +++ b/drivers/clk/meson/clk-regmap.h @@ -111,7 +111,7 @@ clk_get_regmap_mux_data(struct clk_regmap *clk) extern const struct clk_ops clk_regmap_mux_ops; extern const struct clk_ops clk_regmap_mux_ro_ops; -#define __MESON_GATE(_name, _reg, _bit, _ops) \ +#define __MESON_PCLK(_name, _reg, _bit, _ops, _pname) \ struct clk_regmap _name = { \ .data = &(struct clk_regmap_gate_data){ \ .offset = (_reg), \ @@ -120,15 +120,15 @@ struct clk_regmap _name = { \ .hw.init = &(struct clk_init_data) { \ .name = #_name, \ .ops = _ops, \ - .parent_names = (const char *[]){ "clk81" }, \ + .parent_hws = (const struct clk_hw *[]) { _pname }, \ .num_parents = 1, \ .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ }, \ } -#define MESON_GATE(_name, _reg, _bit) \ - __MESON_GATE(_name, _reg, _bit, &clk_regmap_gate_ops) +#define MESON_PCLK(_name, _reg, _bit, _pname) \ + __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ops, _pname) -#define MESON_GATE_RO(_name, _reg, _bit) \ - __MESON_GATE(_name, _reg, _bit, &clk_regmap_gate_ro_ops) +#define MESON_PCLK_RO(_name, _reg, _bit, _pname) \ + __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ro_ops, _pname) #endif /* __CLK_REGMAP_H */ diff --git a/drivers/clk/meson/g12a-aoclk.c b/drivers/clk/meson/g12a-aoclk.c index 1994e735396b53aae310390405f8b04a95499101..62499563e4f5a5f2942cbcadaf624376c82ff9e9 100644 --- a/drivers/clk/meson/g12a-aoclk.c +++ b/drivers/clk/meson/g12a-aoclk.c @@ -18,8 +18,6 @@ #include "clk-regmap.h" #include "clk-dualdiv.h" -#define IN_PREFIX "ao-in-" - /* * AO Configuration Clock registers offsets * Register offsets from the data sheet must be multiplied by 4. @@ -51,7 +49,9 @@ static struct clk_regmap g12a_aoclk_##_name = { \ .hw.init = &(struct clk_init_data) { \ .name = "g12a_ao_" #_name, \ .ops = &clk_regmap_gate_ops, \ - .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk" }, \ + .parent_data = &(const struct clk_parent_data) { \ + .fw_name = "mpeg-clk", \ + }, \ .num_parents = 1, \ .flags = CLK_IGNORE_UNUSED, \ }, \ @@ -81,7 +81,9 @@ static struct clk_regmap g12a_aoclk_cts_oscin = { .hw.init = &(struct clk_init_data){ .name = "cts_oscin", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -106,7 +108,9 @@ static struct clk_regmap g12a_aoclk_32k_by_oscin_pre = { .hw.init = &(struct clk_init_data){ .name = "g12a_ao_32k_by_oscin_pre", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "cts_oscin" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_aoclk_cts_oscin.hw + }, .num_parents = 1, }, }; @@ -143,7 +147,9 @@ static struct clk_regmap g12a_aoclk_32k_by_oscin_div = { .hw.init = &(struct clk_init_data){ .name = "g12a_ao_32k_by_oscin_div", .ops = &meson_clk_dualdiv_ops, - .parent_names = (const char *[]){ "g12a_ao_32k_by_oscin_pre" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_aoclk_32k_by_oscin_pre.hw + }, .num_parents = 1, }, }; @@ -158,8 +164,10 @@ static struct clk_regmap g12a_aoclk_32k_by_oscin_sel = { .hw.init = &(struct clk_init_data){ .name = "g12a_ao_32k_by_oscin_sel", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "g12a_ao_32k_by_oscin_div", - "g12a_ao_32k_by_oscin_pre" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_aoclk_32k_by_oscin_div.hw, + &g12a_aoclk_32k_by_oscin_pre.hw, + }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, @@ -173,7 +181,9 @@ static struct clk_regmap g12a_aoclk_32k_by_oscin = { .hw.init = &(struct clk_init_data){ .name = "g12a_ao_32k_by_oscin", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "g12a_ao_32k_by_oscin_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_aoclk_32k_by_oscin_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -189,7 +199,9 @@ static struct clk_regmap g12a_aoclk_cec_pre = { .hw.init = &(struct clk_init_data){ .name = "g12a_ao_cec_pre", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "cts_oscin" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_aoclk_cts_oscin.hw + }, .num_parents = 1, }, }; @@ -226,7 +238,9 @@ static struct clk_regmap g12a_aoclk_cec_div = { .hw.init = &(struct clk_init_data){ .name = "g12a_ao_cec_div", .ops = &meson_clk_dualdiv_ops, - .parent_names = (const char *[]){ "g12a_ao_cec_pre" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_aoclk_cec_pre.hw + }, .num_parents = 1, }, }; @@ -241,8 +255,10 @@ static struct clk_regmap g12a_aoclk_cec_sel = { .hw.init = &(struct clk_init_data){ .name = "g12a_ao_cec_sel", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "g12a_ao_cec_div", - "g12a_ao_cec_pre" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_aoclk_cec_div.hw, + &g12a_aoclk_cec_pre.hw, + }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, @@ -256,7 +272,9 @@ static struct clk_regmap g12a_aoclk_cec = { .hw.init = &(struct clk_init_data){ .name = "g12a_ao_cec", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "g12a_ao_cec_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_aoclk_cec_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -272,8 +290,10 @@ static struct clk_regmap g12a_aoclk_cts_rtc_oscin = { .hw.init = &(struct clk_init_data){ .name = "g12a_ao_cts_rtc_oscin", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "g12a_ao_32k_by_oscin", - IN_PREFIX "ext_32k-0" }, + .parent_data = (const struct clk_parent_data []) { + { .hw = &g12a_aoclk_32k_by_oscin.hw }, + { .fw_name = "ext-32k-0", }, + }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, @@ -289,8 +309,10 @@ static struct clk_regmap g12a_aoclk_clk81 = { .hw.init = &(struct clk_init_data){ .name = "g12a_ao_clk81", .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk", - "g12a_ao_cts_rtc_oscin"}, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "mpeg-clk", }, + { .hw = &g12a_aoclk_cts_rtc_oscin.hw }, + }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, @@ -305,8 +327,10 @@ static struct clk_regmap g12a_aoclk_saradc_mux = { .hw.init = &(struct clk_init_data){ .name = "g12a_ao_saradc_mux", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal", - "g12a_ao_clk81" }, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_aoclk_clk81.hw }, + }, .num_parents = 2, }, }; @@ -320,7 +344,9 @@ static struct clk_regmap g12a_aoclk_saradc_div = { .hw.init = &(struct clk_init_data){ .name = "g12a_ao_saradc_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "g12a_ao_saradc_mux" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_aoclk_saradc_mux.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -334,7 +360,9 @@ static struct clk_regmap g12a_aoclk_saradc_gate = { .hw.init = &(struct clk_init_data){ .name = "g12a_ao_saradc_gate", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "g12a_ao_saradc_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_aoclk_saradc_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -417,12 +445,6 @@ static const struct clk_hw_onecell_data g12a_aoclk_onecell_data = { .num = NR_CLKS, }; -static const struct meson_aoclk_input g12a_aoclk_inputs[] = { - { .name = "xtal", .required = true }, - { .name = "mpeg-clk", .required = true }, - { .name = "ext-32k-0", .required = false }, -}; - static const struct meson_aoclk_data g12a_aoclkc_data = { .reset_reg = AO_RTI_GEN_CNTL_REG0, .num_reset = ARRAY_SIZE(g12a_aoclk_reset), @@ -430,9 +452,6 @@ static const struct meson_aoclk_data g12a_aoclkc_data = { .num_clks = ARRAY_SIZE(g12a_aoclk_regmap), .clks = g12a_aoclk_regmap, .hw_data = &g12a_aoclk_onecell_data, - .inputs = g12a_aoclk_inputs, - .num_inputs = ARRAY_SIZE(g12a_aoclk_inputs), - .input_prefix = IN_PREFIX, }; static const struct of_device_id g12a_aoclkc_match_table[] = { diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index db1c4ed9d54e64248318ae635fc6638974a57846..c3f0ffc3280dee1d1ded704b6a96c2f8702958ab 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -14,11 +14,12 @@ #include #include #include +#include -#include "clk-input.h" #include "clk-mpll.h" #include "clk-pll.h" #include "clk-regmap.h" +#include "clk-cpu-dyndiv.h" #include "vid-pll-div.h" #include "meson-eeclk.h" #include "g12a.h" @@ -61,7 +62,9 @@ static struct clk_regmap g12a_fixed_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -76,7 +79,9 @@ static struct clk_regmap g12a_fixed_pll = { .hw.init = &(struct clk_init_data){ .name = "fixed_pll", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "fixed_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fixed_pll_dco.hw + }, .num_parents = 1, /* * This clock won't ever change at runtime so @@ -85,16 +90,9 @@ static struct clk_regmap g12a_fixed_pll = { }, }; -/* - * Internal sys pll emulation configuration parameters - */ -static const struct reg_sequence g12a_sys_init_regs[] = { - { .reg = HHI_SYS_PLL_CNTL1, .def = 0x00000000 }, - { .reg = HHI_SYS_PLL_CNTL2, .def = 0x00000000 }, - { .reg = HHI_SYS_PLL_CNTL3, .def = 0x48681c00 }, - { .reg = HHI_SYS_PLL_CNTL4, .def = 0x88770290 }, - { .reg = HHI_SYS_PLL_CNTL5, .def = 0x39272000 }, - { .reg = HHI_SYS_PLL_CNTL6, .def = 0x56540000 }, +static const struct pll_mult_range g12a_sys_pll_mult_range = { + .min = 128, + .max = 250, }; static struct clk_regmap g12a_sys_pll_dco = { @@ -124,14 +122,17 @@ static struct clk_regmap g12a_sys_pll_dco = { .shift = 29, .width = 1, }, - .init_regs = g12a_sys_init_regs, - .init_count = ARRAY_SIZE(g12a_sys_init_regs), + .range = &g12a_sys_pll_mult_range, }, .hw.init = &(struct clk_init_data){ .name = "sys_pll_dco", - .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, + /* This clock feeds the CPU, avoid disabling it */ + .flags = CLK_IS_CRITICAL, }, }; @@ -144,9 +145,12 @@ static struct clk_regmap g12a_sys_pll = { }, .hw.init = &(struct clk_init_data){ .name = "sys_pll", - .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "sys_pll_dco" }, + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sys_pll_dco.hw + }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -177,12 +181,17 @@ static struct clk_regmap g12b_sys1_pll_dco = { .shift = 29, .width = 1, }, + .range = &g12a_sys_pll_mult_range, }, .hw.init = &(struct clk_init_data){ .name = "sys1_pll_dco", - .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, + /* This clock feeds the CPU, avoid disabling it */ + .flags = CLK_IS_CRITICAL, }, }; @@ -195,9 +204,12 @@ static struct clk_regmap g12b_sys1_pll = { }, .hw.init = &(struct clk_init_data){ .name = "sys1_pll", - .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "sys1_pll_dco" }, + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_sys1_pll_dco.hw + }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -209,7 +221,7 @@ static struct clk_regmap g12a_sys_pll_div16_en = { .hw.init = &(struct clk_init_data) { .name = "sys_pll_div16_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "sys_pll" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_sys_pll.hw }, .num_parents = 1, /* * This clock is used to debug the sys_pll range @@ -226,7 +238,9 @@ static struct clk_regmap g12b_sys1_pll_div16_en = { .hw.init = &(struct clk_init_data) { .name = "sys1_pll_div16_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "sys1_pll" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_sys1_pll.hw + }, .num_parents = 1, /* * This clock is used to debug the sys_pll range @@ -241,7 +255,9 @@ static struct clk_fixed_factor g12a_sys_pll_div16 = { .hw.init = &(struct clk_init_data){ .name = "sys_pll_div16", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "sys_pll_div16_en" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sys_pll_div16_en.hw + }, .num_parents = 1, }, }; @@ -252,11 +268,75 @@ static struct clk_fixed_factor g12b_sys1_pll_div16 = { .hw.init = &(struct clk_init_data){ .name = "sys1_pll_div16", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "sys1_pll_div16_en" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_sys1_pll_div16_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_fclk_div2_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fclk_div2_div.hw + }, .num_parents = 1, }, }; +static struct clk_fixed_factor g12a_fclk_div3_div = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 20, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fclk_div3_div.hw + }, + .num_parents = 1, + /* + * This clock is used by the resident firmware and is required + * by the platform to operate correctly. + * Until the following condition are met, we need this clock to + * be marked as critical: + * a) Mark the clock used by a firmware resource, if possible + * b) CCF has a clock hand-off mechanism to make the sure the + * clock stays on until the proper driver comes along + */ + .flags = CLK_IS_CRITICAL, + }, +}; + /* Datasheet names this field as "premux0" */ static struct clk_regmap g12a_cpu_clk_premux0 = { .data = &(struct clk_regmap_mux_data){ @@ -266,26 +346,61 @@ static struct clk_regmap g12a_cpu_clk_premux0 = { }, .hw.init = &(struct clk_init_data){ .name = "cpu_clk_dyn0_sel", - .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal", - "fclk_div2", - "fclk_div3" }, + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div3.hw }, + }, .num_parents = 3, + /* This sub-tree is used a parking clock */ + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +/* Datasheet names this field as "premux1" */ +static struct clk_regmap g12a_cpu_clk_premux1 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x3, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div3.hw }, + }, + .num_parents = 3, + /* This sub-tree is used a parking clock */ + .flags = CLK_SET_RATE_NO_REPARENT }, }; /* Datasheet names this field as "mux0_divn_tcnt" */ static struct clk_regmap g12a_cpu_clk_mux0_div = { - .data = &(struct clk_regmap_div_data){ - .offset = HHI_SYS_CPU_CLK_CNTL0, - .shift = 4, - .width = 6, + .data = &(struct meson_clk_cpu_dyndiv_data){ + .div = { + .reg_off = HHI_SYS_CPU_CLK_CNTL0, + .shift = 4, + .width = 6, + }, + .dyn = { + .reg_off = HHI_SYS_CPU_CLK_CNTL0, + .shift = 26, + .width = 1, + }, }, .hw.init = &(struct clk_init_data){ .name = "cpu_clk_dyn0_div", - .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "cpu_clk_dyn0_sel" }, + .ops = &meson_clk_cpu_dyndiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_premux0.hw + }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -298,27 +413,13 @@ static struct clk_regmap g12a_cpu_clk_postmux0 = { }, .hw.init = &(struct clk_init_data){ .name = "cpu_clk_dyn0", - .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "cpu_clk_dyn0_sel", - "cpu_clk_dyn0_div" }, + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_premux0.hw, + &g12a_cpu_clk_mux0_div.hw, + }, .num_parents = 2, - }, -}; - -/* Datasheet names this field as "premux1" */ -static struct clk_regmap g12a_cpu_clk_premux1 = { - .data = &(struct clk_regmap_mux_data){ - .offset = HHI_SYS_CPU_CLK_CNTL0, - .mask = 0x3, - .shift = 16, - }, - .hw.init = &(struct clk_init_data){ - .name = "cpu_clk_dyn1_sel", - .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal", - "fclk_div2", - "fclk_div3" }, - .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -332,7 +433,9 @@ static struct clk_regmap g12a_cpu_clk_mux1_div = { .hw.init = &(struct clk_init_data){ .name = "cpu_clk_dyn1_div", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "cpu_clk_dyn1_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_premux1.hw + }, .num_parents = 1, }, }; @@ -346,10 +449,14 @@ static struct clk_regmap g12a_cpu_clk_postmux1 = { }, .hw.init = &(struct clk_init_data){ .name = "cpu_clk_dyn1", - .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "cpu_clk_dyn1_sel", - "cpu_clk_dyn1_div" }, + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_premux1.hw, + &g12a_cpu_clk_mux1_div.hw, + }, .num_parents = 2, + /* This sub-tree is used a parking clock */ + .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -362,10 +469,13 @@ static struct clk_regmap g12a_cpu_clk_dyn = { }, .hw.init = &(struct clk_init_data){ .name = "cpu_clk_dyn", - .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "cpu_clk_dyn0", - "cpu_clk_dyn1" }, + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_postmux0.hw, + &g12a_cpu_clk_postmux1.hw, + }, .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -378,10 +488,13 @@ static struct clk_regmap g12a_cpu_clk = { }, .hw.init = &(struct clk_init_data){ .name = "cpu_clk", - .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "cpu_clk_dyn", - "sys_pll" }, + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_dyn.hw, + &g12a_sys_pll.hw, + }, .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -394,10 +507,13 @@ static struct clk_regmap g12b_cpu_clk = { }, .hw.init = &(struct clk_init_data){ .name = "cpu_clk", - .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "cpu_clk_dyn", - "sys1_pll" }, + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_dyn.hw, + &g12b_sys1_pll.hw + }, .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -410,26 +526,38 @@ static struct clk_regmap g12b_cpub_clk_premux0 = { }, .hw.init = &(struct clk_init_data){ .name = "cpub_clk_dyn0_sel", - .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal", - "fclk_div2", - "fclk_div3" }, + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div3.hw }, + }, .num_parents = 3, }, }; /* Datasheet names this field as "mux0_divn_tcnt" */ static struct clk_regmap g12b_cpub_clk_mux0_div = { - .data = &(struct clk_regmap_div_data){ - .offset = HHI_SYS_CPUB_CLK_CNTL, - .shift = 4, - .width = 6, + .data = &(struct meson_clk_cpu_dyndiv_data){ + .div = { + .reg_off = HHI_SYS_CPUB_CLK_CNTL, + .shift = 4, + .width = 6, + }, + .dyn = { + .reg_off = HHI_SYS_CPUB_CLK_CNTL, + .shift = 26, + .width = 1, + }, }, .hw.init = &(struct clk_init_data){ .name = "cpub_clk_dyn0_div", - .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "cpub_clk_dyn0_sel" }, + .ops = &meson_clk_cpu_dyndiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_premux0.hw + }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -442,10 +570,13 @@ static struct clk_regmap g12b_cpub_clk_postmux0 = { }, .hw.init = &(struct clk_init_data){ .name = "cpub_clk_dyn0", - .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "cpub_clk_dyn0_sel", - "cpub_clk_dyn0_div" }, + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_premux0.hw, + &g12b_cpub_clk_mux0_div.hw + }, .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -458,11 +589,15 @@ static struct clk_regmap g12b_cpub_clk_premux1 = { }, .hw.init = &(struct clk_init_data){ .name = "cpub_clk_dyn1_sel", - .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal", - "fclk_div2", - "fclk_div3" }, + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div3.hw }, + }, .num_parents = 3, + /* This sub-tree is used a parking clock */ + .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -476,7 +611,9 @@ static struct clk_regmap g12b_cpub_clk_mux1_div = { .hw.init = &(struct clk_init_data){ .name = "cpub_clk_dyn1_div", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "cpub_clk_dyn1_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_premux1.hw + }, .num_parents = 1, }, }; @@ -490,10 +627,14 @@ static struct clk_regmap g12b_cpub_clk_postmux1 = { }, .hw.init = &(struct clk_init_data){ .name = "cpub_clk_dyn1", - .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "cpub_clk_dyn1_sel", - "cpub_clk_dyn1_div" }, + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_premux1.hw, + &g12b_cpub_clk_mux1_div.hw + }, .num_parents = 2, + /* This sub-tree is used a parking clock */ + .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -506,10 +647,13 @@ static struct clk_regmap g12b_cpub_clk_dyn = { }, .hw.init = &(struct clk_init_data){ .name = "cpub_clk_dyn", - .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "cpub_clk_dyn0", - "cpub_clk_dyn1" }, + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_postmux0.hw, + &g12b_cpub_clk_postmux1.hw + }, .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -522,13 +666,227 @@ static struct clk_regmap g12b_cpub_clk = { }, .hw.init = &(struct clk_init_data){ .name = "cpub_clk", - .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "cpub_clk_dyn", - "sys_pll" }, + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_dyn.hw, + &g12a_sys_pll.hw + }, .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, }, }; +static int g12a_cpu_clk_mux_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + if (event == POST_RATE_CHANGE || event == PRE_RATE_CHANGE) { + /* Wait for clock propagation before/after changing the mux */ + udelay(100); + return NOTIFY_OK; + } + + return NOTIFY_DONE; +} + +static struct notifier_block g12a_cpu_clk_mux_nb = { + .notifier_call = g12a_cpu_clk_mux_notifier_cb, +}; + +struct g12a_cpu_clk_postmux_nb_data { + struct notifier_block nb; + struct clk_hw *xtal; + struct clk_hw *cpu_clk_dyn; + struct clk_hw *cpu_clk_postmux0; + struct clk_hw *cpu_clk_postmux1; + struct clk_hw *cpu_clk_premux1; +}; + +static int g12a_cpu_clk_postmux_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct g12a_cpu_clk_postmux_nb_data *nb_data = + container_of(nb, struct g12a_cpu_clk_postmux_nb_data, nb); + + switch (event) { + case PRE_RATE_CHANGE: + /* + * This notifier means cpu_clk_postmux0 clock will be changed + * to feed cpu_clk, this is the current path : + * cpu_clk + * \- cpu_clk_dyn + * \- cpu_clk_postmux0 + * \- cpu_clk_muxX_div + * \- cpu_clk_premux0 + * \- fclk_div3 or fclk_div2 + * OR + * \- cpu_clk_premux0 + * \- fclk_div3 or fclk_div2 + */ + + /* Setup cpu_clk_premux1 to xtal */ + clk_hw_set_parent(nb_data->cpu_clk_premux1, + nb_data->xtal); + + /* Setup cpu_clk_postmux1 to bypass divider */ + clk_hw_set_parent(nb_data->cpu_clk_postmux1, + nb_data->cpu_clk_premux1); + + /* Switch to parking clk on cpu_clk_postmux1 */ + clk_hw_set_parent(nb_data->cpu_clk_dyn, + nb_data->cpu_clk_postmux1); + + /* + * Now, cpu_clk is 24MHz in the current path : + * cpu_clk + * \- cpu_clk_dyn + * \- cpu_clk_postmux1 + * \- cpu_clk_premux1 + * \- xtal + */ + + udelay(100); + + return NOTIFY_OK; + + case POST_RATE_CHANGE: + /* + * The cpu_clk_postmux0 has ben updated, now switch back + * cpu_clk_dyn to cpu_clk_postmux0 and take the changes + * in account. + */ + + /* Configure cpu_clk_dyn back to cpu_clk_postmux0 */ + clk_hw_set_parent(nb_data->cpu_clk_dyn, + nb_data->cpu_clk_postmux0); + + /* + * new path : + * cpu_clk + * \- cpu_clk_dyn + * \- cpu_clk_postmux0 + * \- cpu_clk_muxX_div + * \- cpu_clk_premux0 + * \- fclk_div3 or fclk_div2 + * OR + * \- cpu_clk_premux0 + * \- fclk_div3 or fclk_div2 + */ + + udelay(100); + + return NOTIFY_OK; + + default: + return NOTIFY_DONE; + } +} + +static struct g12a_cpu_clk_postmux_nb_data g12a_cpu_clk_postmux0_nb_data = { + .cpu_clk_dyn = &g12a_cpu_clk_dyn.hw, + .cpu_clk_postmux0 = &g12a_cpu_clk_postmux0.hw, + .cpu_clk_postmux1 = &g12a_cpu_clk_postmux1.hw, + .cpu_clk_premux1 = &g12a_cpu_clk_premux1.hw, + .nb.notifier_call = g12a_cpu_clk_postmux_notifier_cb, +}; + +static struct g12a_cpu_clk_postmux_nb_data g12b_cpub_clk_postmux0_nb_data = { + .cpu_clk_dyn = &g12b_cpub_clk_dyn.hw, + .cpu_clk_postmux0 = &g12b_cpub_clk_postmux0.hw, + .cpu_clk_postmux1 = &g12b_cpub_clk_postmux1.hw, + .cpu_clk_premux1 = &g12b_cpub_clk_premux1.hw, + .nb.notifier_call = g12a_cpu_clk_postmux_notifier_cb, +}; + +struct g12a_sys_pll_nb_data { + struct notifier_block nb; + struct clk_hw *sys_pll; + struct clk_hw *cpu_clk; + struct clk_hw *cpu_clk_dyn; +}; + +static int g12a_sys_pll_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct g12a_sys_pll_nb_data *nb_data = + container_of(nb, struct g12a_sys_pll_nb_data, nb); + + switch (event) { + case PRE_RATE_CHANGE: + /* + * This notifier means sys_pll clock will be changed + * to feed cpu_clk, this the current path : + * cpu_clk + * \- sys_pll + * \- sys_pll_dco + */ + + /* Configure cpu_clk to use cpu_clk_dyn */ + clk_hw_set_parent(nb_data->cpu_clk, + nb_data->cpu_clk_dyn); + + /* + * Now, cpu_clk uses the dyn path + * cpu_clk + * \- cpu_clk_dyn + * \- cpu_clk_dynX + * \- cpu_clk_dynX_sel + * \- cpu_clk_dynX_div + * \- xtal/fclk_div2/fclk_div3 + * \- xtal/fclk_div2/fclk_div3 + */ + + udelay(100); + + return NOTIFY_OK; + + case POST_RATE_CHANGE: + /* + * The sys_pll has ben updated, now switch back cpu_clk to + * sys_pll + */ + + /* Configure cpu_clk to use sys_pll */ + clk_hw_set_parent(nb_data->cpu_clk, + nb_data->sys_pll); + + udelay(100); + + /* new path : + * cpu_clk + * \- sys_pll + * \- sys_pll_dco + */ + + return NOTIFY_OK; + + default: + return NOTIFY_DONE; + } +} + +static struct g12a_sys_pll_nb_data g12a_sys_pll_nb_data = { + .sys_pll = &g12a_sys_pll.hw, + .cpu_clk = &g12a_cpu_clk.hw, + .cpu_clk_dyn = &g12a_cpu_clk_dyn.hw, + .nb.notifier_call = g12a_sys_pll_notifier_cb, +}; + +/* G12B first CPU cluster uses sys1_pll */ +static struct g12a_sys_pll_nb_data g12b_cpu_clk_sys1_pll_nb_data = { + .sys_pll = &g12b_sys1_pll.hw, + .cpu_clk = &g12b_cpu_clk.hw, + .cpu_clk_dyn = &g12a_cpu_clk_dyn.hw, + .nb.notifier_call = g12a_sys_pll_notifier_cb, +}; + +/* G12B second CPU cluster uses sys_pll */ +static struct g12a_sys_pll_nb_data g12b_cpub_clk_sys_pll_nb_data = { + .sys_pll = &g12a_sys_pll.hw, + .cpu_clk = &g12b_cpub_clk.hw, + .cpu_clk_dyn = &g12b_cpub_clk_dyn.hw, + .nb.notifier_call = g12a_sys_pll_notifier_cb, +}; + static struct clk_regmap g12a_cpu_clk_div16_en = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_SYS_CPU_CLK_CNTL1, @@ -537,7 +895,9 @@ static struct clk_regmap g12a_cpu_clk_div16_en = { .hw.init = &(struct clk_init_data) { .name = "cpu_clk_div16_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "cpu_clk" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk.hw + }, .num_parents = 1, /* * This clock is used to debug the cpu_clk range @@ -554,7 +914,9 @@ static struct clk_regmap g12b_cpub_clk_div16_en = { .hw.init = &(struct clk_init_data) { .name = "cpub_clk_div16_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "cpub_clk" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk.hw + }, .num_parents = 1, /* * This clock is used to debug the cpu_clk range @@ -569,7 +931,9 @@ static struct clk_fixed_factor g12a_cpu_clk_div16 = { .hw.init = &(struct clk_init_data){ .name = "cpu_clk_div16", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpu_clk_div16_en" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_div16_en.hw + }, .num_parents = 1, }, }; @@ -580,7 +944,9 @@ static struct clk_fixed_factor g12b_cpub_clk_div16 = { .hw.init = &(struct clk_init_data){ .name = "cpub_clk_div16", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpub_clk_div16_en" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_div16_en.hw + }, .num_parents = 1, }, }; @@ -595,7 +961,7 @@ static struct clk_regmap g12a_cpu_clk_apb_div = { .hw.init = &(struct clk_init_data){ .name = "cpu_clk_apb_div", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "cpu_clk" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_cpu_clk.hw }, .num_parents = 1, }, }; @@ -608,7 +974,9 @@ static struct clk_regmap g12a_cpu_clk_apb = { .hw.init = &(struct clk_init_data) { .name = "cpu_clk_apb", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "cpu_clk_apb_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_apb_div.hw + }, .num_parents = 1, /* * This clock is set by the ROM monitor code, @@ -627,7 +995,7 @@ static struct clk_regmap g12a_cpu_clk_atb_div = { .hw.init = &(struct clk_init_data){ .name = "cpu_clk_atb_div", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "cpu_clk" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_cpu_clk.hw }, .num_parents = 1, }, }; @@ -640,7 +1008,9 @@ static struct clk_regmap g12a_cpu_clk_atb = { .hw.init = &(struct clk_init_data) { .name = "cpu_clk_atb", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "cpu_clk_atb_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_atb_div.hw + }, .num_parents = 1, /* * This clock is set by the ROM monitor code, @@ -659,7 +1029,7 @@ static struct clk_regmap g12a_cpu_clk_axi_div = { .hw.init = &(struct clk_init_data){ .name = "cpu_clk_axi_div", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "cpu_clk" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_cpu_clk.hw }, .num_parents = 1, }, }; @@ -672,7 +1042,9 @@ static struct clk_regmap g12a_cpu_clk_axi = { .hw.init = &(struct clk_init_data) { .name = "cpu_clk_axi", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "cpu_clk_axi_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_axi_div.hw + }, .num_parents = 1, /* * This clock is set by the ROM monitor code, @@ -691,7 +1063,17 @@ static struct clk_regmap g12a_cpu_clk_trace_div = { .hw.init = &(struct clk_init_data){ .name = "cpu_clk_trace_div", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "cpu_clk" }, + .parent_data = &(const struct clk_parent_data) { + /* + * Note: + * G12A and G12B have different cpu_clks (with + * different struct clk_hw). We fallback to the global + * naming string mechanism so cpu_clk_trace_div picks + * up the appropriate one. + */ + .name = "cpu_clk", + .index = -1, + }, .num_parents = 1, }, }; @@ -704,7 +1086,9 @@ static struct clk_regmap g12a_cpu_clk_trace = { .hw.init = &(struct clk_init_data) { .name = "cpu_clk_trace", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "cpu_clk_trace_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_trace_div.hw + }, .num_parents = 1, /* * This clock is set by the ROM monitor code, @@ -719,7 +1103,9 @@ static struct clk_fixed_factor g12b_cpub_clk_div2 = { .hw.init = &(struct clk_init_data){ .name = "cpub_clk_div2", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpub_clk" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk.hw + }, .num_parents = 1, }, }; @@ -730,7 +1116,9 @@ static struct clk_fixed_factor g12b_cpub_clk_div3 = { .hw.init = &(struct clk_init_data){ .name = "cpub_clk_div3", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpub_clk" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk.hw + }, .num_parents = 1, }, }; @@ -741,7 +1129,9 @@ static struct clk_fixed_factor g12b_cpub_clk_div4 = { .hw.init = &(struct clk_init_data){ .name = "cpub_clk_div4", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpub_clk" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk.hw + }, .num_parents = 1, }, }; @@ -752,7 +1142,9 @@ static struct clk_fixed_factor g12b_cpub_clk_div5 = { .hw.init = &(struct clk_init_data){ .name = "cpub_clk_div5", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpub_clk" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk.hw + }, .num_parents = 1, }, }; @@ -763,7 +1155,9 @@ static struct clk_fixed_factor g12b_cpub_clk_div6 = { .hw.init = &(struct clk_init_data){ .name = "cpub_clk_div6", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpub_clk" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk.hw + }, .num_parents = 1, }, }; @@ -774,7 +1168,9 @@ static struct clk_fixed_factor g12b_cpub_clk_div7 = { .hw.init = &(struct clk_init_data){ .name = "cpub_clk_div7", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpub_clk" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk.hw + }, .num_parents = 1, }, }; @@ -785,7 +1181,9 @@ static struct clk_fixed_factor g12b_cpub_clk_div8 = { .hw.init = &(struct clk_init_data){ .name = "cpub_clk_div8", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpub_clk" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk.hw + }, .num_parents = 1, }, }; @@ -801,13 +1199,15 @@ static struct clk_regmap g12b_cpub_clk_apb_sel = { .hw.init = &(struct clk_init_data){ .name = "cpub_clk_apb_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "cpub_clk_div2", - "cpub_clk_div3", - "cpub_clk_div4", - "cpub_clk_div5", - "cpub_clk_div6", - "cpub_clk_div7", - "cpub_clk_div8" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_div2.hw, + &g12b_cpub_clk_div3.hw, + &g12b_cpub_clk_div4.hw, + &g12b_cpub_clk_div5.hw, + &g12b_cpub_clk_div6.hw, + &g12b_cpub_clk_div7.hw, + &g12b_cpub_clk_div8.hw + }, .num_parents = 7, }, }; @@ -821,7 +1221,9 @@ static struct clk_regmap g12b_cpub_clk_apb = { .hw.init = &(struct clk_init_data) { .name = "cpub_clk_apb", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "cpub_clk_apb_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_apb_sel.hw + }, .num_parents = 1, /* * This clock is set by the ROM monitor code, @@ -840,13 +1242,15 @@ static struct clk_regmap g12b_cpub_clk_atb_sel = { .hw.init = &(struct clk_init_data){ .name = "cpub_clk_atb_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "cpub_clk_div2", - "cpub_clk_div3", - "cpub_clk_div4", - "cpub_clk_div5", - "cpub_clk_div6", - "cpub_clk_div7", - "cpub_clk_div8" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_div2.hw, + &g12b_cpub_clk_div3.hw, + &g12b_cpub_clk_div4.hw, + &g12b_cpub_clk_div5.hw, + &g12b_cpub_clk_div6.hw, + &g12b_cpub_clk_div7.hw, + &g12b_cpub_clk_div8.hw + }, .num_parents = 7, }, }; @@ -860,7 +1264,9 @@ static struct clk_regmap g12b_cpub_clk_atb = { .hw.init = &(struct clk_init_data) { .name = "cpub_clk_atb", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "cpub_clk_atb_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_atb_sel.hw + }, .num_parents = 1, /* * This clock is set by the ROM monitor code, @@ -879,13 +1285,15 @@ static struct clk_regmap g12b_cpub_clk_axi_sel = { .hw.init = &(struct clk_init_data){ .name = "cpub_clk_axi_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "cpub_clk_div2", - "cpub_clk_div3", - "cpub_clk_div4", - "cpub_clk_div5", - "cpub_clk_div6", - "cpub_clk_div7", - "cpub_clk_div8" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_div2.hw, + &g12b_cpub_clk_div3.hw, + &g12b_cpub_clk_div4.hw, + &g12b_cpub_clk_div5.hw, + &g12b_cpub_clk_div6.hw, + &g12b_cpub_clk_div7.hw, + &g12b_cpub_clk_div8.hw + }, .num_parents = 7, }, }; @@ -899,7 +1307,9 @@ static struct clk_regmap g12b_cpub_clk_axi = { .hw.init = &(struct clk_init_data) { .name = "cpub_clk_axi", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "cpub_clk_axi_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_axi_sel.hw + }, .num_parents = 1, /* * This clock is set by the ROM monitor code, @@ -918,13 +1328,15 @@ static struct clk_regmap g12b_cpub_clk_trace_sel = { .hw.init = &(struct clk_init_data){ .name = "cpub_clk_trace_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "cpub_clk_div2", - "cpub_clk_div3", - "cpub_clk_div4", - "cpub_clk_div5", - "cpub_clk_div6", - "cpub_clk_div7", - "cpub_clk_div8" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_div2.hw, + &g12b_cpub_clk_div3.hw, + &g12b_cpub_clk_div4.hw, + &g12b_cpub_clk_div5.hw, + &g12b_cpub_clk_div6.hw, + &g12b_cpub_clk_div7.hw, + &g12b_cpub_clk_div8.hw + }, .num_parents = 7, }, }; @@ -938,7 +1350,9 @@ static struct clk_regmap g12b_cpub_clk_trace = { .hw.init = &(struct clk_init_data) { .name = "cpub_clk_trace", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "cpub_clk_trace_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_trace_sel.hw + }, .num_parents = 1, /* * This clock is set by the ROM monitor code, @@ -1003,7 +1417,9 @@ static struct clk_regmap g12a_gp0_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -1019,7 +1435,9 @@ static struct clk_regmap g12a_gp0_pll = { .hw.init = &(struct clk_init_data){ .name = "gp0_pll", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "gp0_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_gp0_pll_dco.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1077,7 +1495,9 @@ static struct clk_regmap g12a_hifi_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "hifi_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -1093,7 +1513,9 @@ static struct clk_regmap g12a_hifi_pll = { .hw.init = &(struct clk_init_data){ .name = "hifi_pll", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "hifi_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_hifi_pll_dco.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1164,7 +1586,9 @@ static struct clk_regmap g12a_pcie_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "pcie_pll_dco", .ops = &meson_clk_pcie_pll_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -1175,7 +1599,9 @@ static struct clk_fixed_factor g12a_pcie_pll_dco_div2 = { .hw.init = &(struct clk_init_data){ .name = "pcie_pll_dco_div2", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "pcie_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_pcie_pll_dco.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1193,7 +1619,9 @@ static struct clk_regmap g12a_pcie_pll_od = { .hw.init = &(struct clk_init_data){ .name = "pcie_pll_od", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "pcie_pll_dco_div2" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_pcie_pll_dco_div2.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1205,7 +1633,9 @@ static struct clk_fixed_factor g12a_pcie_pll = { .hw.init = &(struct clk_init_data){ .name = "pcie_pll_pll", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "pcie_pll_od" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_pcie_pll_od.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1247,7 +1677,9 @@ static struct clk_regmap g12a_hdmi_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, /* * Display directly handle hdmi pll registers ATM, we need @@ -1267,7 +1699,9 @@ static struct clk_regmap g12a_hdmi_pll_od = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_od", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "hdmi_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_hdmi_pll_dco.hw + }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, }, @@ -1283,7 +1717,9 @@ static struct clk_regmap g12a_hdmi_pll_od2 = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_od2", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "hdmi_pll_od" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_hdmi_pll_od.hw + }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, }, @@ -1299,77 +1735,21 @@ static struct clk_regmap g12a_hdmi_pll = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "hdmi_pll_od2" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_hdmi_pll_od2.hw + }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, }, }; -static struct clk_fixed_factor g12a_fclk_div2_div = { - .mult = 1, - .div = 2, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div2_div", - .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, - .num_parents = 1, - }, -}; - -static struct clk_regmap g12a_fclk_div2 = { - .data = &(struct clk_regmap_gate_data){ - .offset = HHI_FIX_PLL_CNTL1, - .bit_idx = 24, - }, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div2", - .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div2_div" }, - .num_parents = 1, - }, -}; - -static struct clk_fixed_factor g12a_fclk_div3_div = { - .mult = 1, - .div = 3, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div3_div", - .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, - .num_parents = 1, - }, -}; - -static struct clk_regmap g12a_fclk_div3 = { - .data = &(struct clk_regmap_gate_data){ - .offset = HHI_FIX_PLL_CNTL1, - .bit_idx = 20, - }, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div3", - .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div3_div" }, - .num_parents = 1, - /* - * This clock is used by the resident firmware and is required - * by the platform to operate correctly. - * Until the following condition are met, we need this clock to - * be marked as critical: - * a) Mark the clock used by a firmware resource, if possible - * b) CCF has a clock hand-off mechanism to make the sure the - * clock stays on until the proper driver comes along - */ - .flags = CLK_IS_CRITICAL, - }, -}; - static struct clk_fixed_factor g12a_fclk_div4_div = { .mult = 1, .div = 4, .hw.init = &(struct clk_init_data){ .name = "fclk_div4_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, .num_parents = 1, }, }; @@ -1382,7 +1762,9 @@ static struct clk_regmap g12a_fclk_div4 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div4", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div4_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fclk_div4_div.hw + }, .num_parents = 1, }, }; @@ -1393,7 +1775,7 @@ static struct clk_fixed_factor g12a_fclk_div5_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div5_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, .num_parents = 1, }, }; @@ -1406,7 +1788,9 @@ static struct clk_regmap g12a_fclk_div5 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div5", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div5_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fclk_div5_div.hw + }, .num_parents = 1, }, }; @@ -1417,7 +1801,7 @@ static struct clk_fixed_factor g12a_fclk_div7_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div7_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, .num_parents = 1, }, }; @@ -1430,7 +1814,9 @@ static struct clk_regmap g12a_fclk_div7 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div7", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div7_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fclk_div7_div.hw + }, .num_parents = 1, }, }; @@ -1441,7 +1827,9 @@ static struct clk_fixed_factor g12a_fclk_div2p5_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div2p5_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fixed_pll_dco.hw + }, .num_parents = 1, }, }; @@ -1454,7 +1842,9 @@ static struct clk_regmap g12a_fclk_div2p5 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div2p5", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div2p5_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fclk_div2p5_div.hw + }, .num_parents = 1, }, }; @@ -1465,7 +1855,9 @@ static struct clk_fixed_factor g12a_mpll_50m_div = { .hw.init = &(struct clk_init_data){ .name = "mpll_50m_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fixed_pll_dco.hw + }, .num_parents = 1, }, }; @@ -1479,8 +1871,10 @@ static struct clk_regmap g12a_mpll_50m = { .hw.init = &(struct clk_init_data){ .name = "mpll_50m", .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal", - "mpll_50m_div" }, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_mpll_50m_div.hw }, + }, .num_parents = 2, }, }; @@ -1491,7 +1885,9 @@ static struct clk_fixed_factor g12a_mpll_prediv = { .hw.init = &(struct clk_init_data){ .name = "mpll_prediv", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fixed_pll_dco.hw + }, .num_parents = 1, }, }; @@ -1529,7 +1925,9 @@ static struct clk_regmap g12a_mpll0_div = { .hw.init = &(struct clk_init_data){ .name = "mpll0_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "mpll_prediv" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mpll_prediv.hw + }, .num_parents = 1, }, }; @@ -1542,7 +1940,7 @@ static struct clk_regmap g12a_mpll0 = { .hw.init = &(struct clk_init_data){ .name = "mpll0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpll0_div" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_mpll0_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1581,7 +1979,9 @@ static struct clk_regmap g12a_mpll1_div = { .hw.init = &(struct clk_init_data){ .name = "mpll1_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "mpll_prediv" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mpll_prediv.hw + }, .num_parents = 1, }, }; @@ -1594,7 +1994,7 @@ static struct clk_regmap g12a_mpll1 = { .hw.init = &(struct clk_init_data){ .name = "mpll1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpll1_div" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_mpll1_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1633,7 +2033,9 @@ static struct clk_regmap g12a_mpll2_div = { .hw.init = &(struct clk_init_data){ .name = "mpll2_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "mpll_prediv" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mpll_prediv.hw + }, .num_parents = 1, }, }; @@ -1646,7 +2048,7 @@ static struct clk_regmap g12a_mpll2 = { .hw.init = &(struct clk_init_data){ .name = "mpll2", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpll2_div" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_mpll2_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1685,7 +2087,9 @@ static struct clk_regmap g12a_mpll3_div = { .hw.init = &(struct clk_init_data){ .name = "mpll3_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "mpll_prediv" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mpll_prediv.hw + }, .num_parents = 1, }, }; @@ -1698,16 +2102,21 @@ static struct clk_regmap g12a_mpll3 = { .hw.init = &(struct clk_init_data){ .name = "mpll3", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpll3_div" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_mpll3_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; -static const char * const clk81_parent_names[] = { - IN_PREFIX "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", - "fclk_div3", "fclk_div5" +static const struct clk_parent_data clk81_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div7.hw }, + { .hw = &g12a_mpll1.hw }, + { .hw = &g12a_mpll2.hw }, + { .hw = &g12a_fclk_div4.hw }, + { .hw = &g12a_fclk_div3.hw }, + { .hw = &g12a_fclk_div5.hw }, }; static struct clk_regmap g12a_mpeg_clk_sel = { @@ -1720,8 +2129,8 @@ static struct clk_regmap g12a_mpeg_clk_sel = { .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_names = clk81_parent_names, - .num_parents = ARRAY_SIZE(clk81_parent_names), + .parent_data = clk81_parent_data, + .num_parents = ARRAY_SIZE(clk81_parent_data), }, }; @@ -1734,7 +2143,9 @@ static struct clk_regmap g12a_mpeg_clk_div = { .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "mpeg_clk_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mpeg_clk_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1748,15 +2159,20 @@ static struct clk_regmap g12a_clk81 = { .hw.init = &(struct clk_init_data){ .name = "clk81", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpeg_clk_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mpeg_clk_div.hw + }, .num_parents = 1, .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), }, }; -static const char * const g12a_sd_emmc_clk0_parent_names[] = { - IN_PREFIX "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", - +static const struct clk_parent_data g12a_sd_emmc_clk0_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div3.hw }, + { .hw = &g12a_fclk_div5.hw }, + { .hw = &g12a_fclk_div7.hw }, /* * Following these parent clocks, we should also have had mpll2, mpll3 * and gp0_pll but these clocks are too precious to be used here. All @@ -1775,8 +2191,8 @@ static struct clk_regmap g12a_sd_emmc_a_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_a_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_sd_emmc_clk0_parent_names, - .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_names), + .parent_data = g12a_sd_emmc_clk0_parent_data, + .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_data), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1790,7 +2206,9 @@ static struct clk_regmap g12a_sd_emmc_a_clk0_div = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_a_clk0_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "sd_emmc_a_clk0_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sd_emmc_a_clk0_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1804,7 +2222,9 @@ static struct clk_regmap g12a_sd_emmc_a_clk0 = { .hw.init = &(struct clk_init_data){ .name = "sd_emmc_a_clk0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "sd_emmc_a_clk0_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sd_emmc_a_clk0_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1820,8 +2240,8 @@ static struct clk_regmap g12a_sd_emmc_b_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_sd_emmc_clk0_parent_names, - .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_names), + .parent_data = g12a_sd_emmc_clk0_parent_data, + .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_data), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1835,7 +2255,9 @@ static struct clk_regmap g12a_sd_emmc_b_clk0_div = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sd_emmc_b_clk0_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1849,7 +2271,9 @@ static struct clk_regmap g12a_sd_emmc_b_clk0 = { .hw.init = &(struct clk_init_data){ .name = "sd_emmc_b_clk0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sd_emmc_b_clk0_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1865,8 +2289,8 @@ static struct clk_regmap g12a_sd_emmc_c_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_sd_emmc_clk0_parent_names, - .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_names), + .parent_data = g12a_sd_emmc_clk0_parent_data, + .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_data), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1880,7 +2304,9 @@ static struct clk_regmap g12a_sd_emmc_c_clk0_div = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sd_emmc_c_clk0_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1894,17 +2320,89 @@ static struct clk_regmap g12a_sd_emmc_c_clk0 = { .hw.init = &(struct clk_init_data){ .name = "sd_emmc_c_clk0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sd_emmc_c_clk0_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; +/* Video Clocks */ + +static struct clk_regmap g12a_vid_pll_div = { + .data = &(struct meson_vid_pll_div_data){ + .val = { + .reg_off = HHI_VID_PLL_CLK_DIV, + .shift = 0, + .width = 15, + }, + .sel = { + .reg_off = HHI_VID_PLL_CLK_DIV, + .shift = 16, + .width = 2, + }, + }, + .hw.init = &(struct clk_init_data) { + .name = "vid_pll_div", + .ops = &meson_vid_pll_div_ro_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_hdmi_pll.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static const struct clk_hw *g12a_vid_pll_parent_hws[] = { + &g12a_vid_pll_div.hw, + &g12a_hdmi_pll.hw, +}; + +static struct clk_regmap g12a_vid_pll_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_PLL_CLK_DIV, + .mask = 0x1, + .shift = 18, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_sel", + .ops = &clk_regmap_mux_ops, + /* + * bit 18 selects from 2 possible parents: + * vid_pll_div or hdmi_pll + */ + .parent_hws = g12a_vid_pll_parent_hws, + .num_parents = ARRAY_SIZE(g12a_vid_pll_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_vid_pll = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_PLL_CLK_DIV, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vid_pll", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vid_pll_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + /* VPU Clock */ -static const char * const g12a_vpu_parent_names[] = { - "fclk_div3", "fclk_div4", "fclk_div5", "fclk_div7", - "mpll1", "vid_pll", "hifi_pll", "gp0_pll", +static const struct clk_hw *g12a_vpu_parent_hws[] = { + &g12a_fclk_div3.hw, + &g12a_fclk_div4.hw, + &g12a_fclk_div5.hw, + &g12a_fclk_div7.hw, + &g12a_mpll1.hw, + &g12a_vid_pll.hw, + &g12a_hifi_pll.hw, + &g12a_gp0_pll.hw, }; static struct clk_regmap g12a_vpu_0_sel = { @@ -1916,8 +2414,8 @@ static struct clk_regmap g12a_vpu_0_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_0_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_vpu_parent_names, - .num_parents = ARRAY_SIZE(g12a_vpu_parent_names), + .parent_hws = g12a_vpu_parent_hws, + .num_parents = ARRAY_SIZE(g12a_vpu_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -1931,7 +2429,7 @@ static struct clk_regmap g12a_vpu_0_div = { .hw.init = &(struct clk_init_data){ .name = "vpu_0_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vpu_0_sel" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vpu_0_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1945,7 +2443,7 @@ static struct clk_regmap g12a_vpu_0 = { .hw.init = &(struct clk_init_data) { .name = "vpu_0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vpu_0_div" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vpu_0_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1960,8 +2458,8 @@ static struct clk_regmap g12a_vpu_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_1_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_vpu_parent_names, - .num_parents = ARRAY_SIZE(g12a_vpu_parent_names), + .parent_hws = g12a_vpu_parent_hws, + .num_parents = ARRAY_SIZE(g12a_vpu_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -1975,7 +2473,7 @@ static struct clk_regmap g12a_vpu_1_div = { .hw.init = &(struct clk_init_data){ .name = "vpu_1_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vpu_1_sel" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vpu_1_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1989,7 +2487,7 @@ static struct clk_regmap g12a_vpu_1 = { .hw.init = &(struct clk_init_data) { .name = "vpu_1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vpu_1_div" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vpu_1_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2008,7 +2506,10 @@ static struct clk_regmap g12a_vpu = { * bit 31 selects from 2 possible parents: * vpu_0 or vpu_1 */ - .parent_names = (const char *[]){ "vpu_0", "vpu_1" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vpu_0.hw, + &g12a_vpu_1.hw, + }, .num_parents = 2, .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -2016,9 +2517,14 @@ static struct clk_regmap g12a_vpu = { /* VDEC clocks */ -static const char * const g12a_vdec_parent_names[] = { - "fclk_div2p5", "fclk_div3", "fclk_div4", "fclk_div5", "fclk_div7", - "hifi_pll", "gp0_pll", +static const struct clk_hw *g12a_vdec_parent_hws[] = { + &g12a_fclk_div2p5.hw, + &g12a_fclk_div3.hw, + &g12a_fclk_div4.hw, + &g12a_fclk_div5.hw, + &g12a_fclk_div7.hw, + &g12a_hifi_pll.hw, + &g12a_gp0_pll.hw, }; static struct clk_regmap g12a_vdec_1_sel = { @@ -2031,8 +2537,8 @@ static struct clk_regmap g12a_vdec_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_1_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_vdec_parent_names, - .num_parents = ARRAY_SIZE(g12a_vdec_parent_names), + .parent_hws = g12a_vdec_parent_hws, + .num_parents = ARRAY_SIZE(g12a_vdec_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2047,7 +2553,9 @@ static struct clk_regmap g12a_vdec_1_div = { .hw.init = &(struct clk_init_data){ .name = "vdec_1_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vdec_1_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vdec_1_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2061,7 +2569,9 @@ static struct clk_regmap g12a_vdec_1 = { .hw.init = &(struct clk_init_data) { .name = "vdec_1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vdec_1_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vdec_1_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2077,8 +2587,8 @@ static struct clk_regmap g12a_vdec_hevcf_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_hevcf_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_vdec_parent_names, - .num_parents = ARRAY_SIZE(g12a_vdec_parent_names), + .parent_hws = g12a_vdec_parent_hws, + .num_parents = ARRAY_SIZE(g12a_vdec_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2093,7 +2603,9 @@ static struct clk_regmap g12a_vdec_hevcf_div = { .hw.init = &(struct clk_init_data){ .name = "vdec_hevcf_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vdec_hevcf_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vdec_hevcf_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2107,7 +2619,9 @@ static struct clk_regmap g12a_vdec_hevcf = { .hw.init = &(struct clk_init_data) { .name = "vdec_hevcf", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vdec_hevcf_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vdec_hevcf_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2123,8 +2637,8 @@ static struct clk_regmap g12a_vdec_hevc_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_hevc_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_vdec_parent_names, - .num_parents = ARRAY_SIZE(g12a_vdec_parent_names), + .parent_hws = g12a_vdec_parent_hws, + .num_parents = ARRAY_SIZE(g12a_vdec_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2139,7 +2653,9 @@ static struct clk_regmap g12a_vdec_hevc_div = { .hw.init = &(struct clk_init_data){ .name = "vdec_hevc_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vdec_hevc_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vdec_hevc_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2153,7 +2669,9 @@ static struct clk_regmap g12a_vdec_hevc = { .hw.init = &(struct clk_init_data) { .name = "vdec_hevc", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vdec_hevc_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vdec_hevc_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2161,9 +2679,15 @@ static struct clk_regmap g12a_vdec_hevc = { /* VAPB Clock */ -static const char * const g12a_vapb_parent_names[] = { - "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", - "mpll1", "vid_pll", "mpll2", "fclk_div2p5", +static const struct clk_hw *g12a_vapb_parent_hws[] = { + &g12a_fclk_div4.hw, + &g12a_fclk_div3.hw, + &g12a_fclk_div5.hw, + &g12a_fclk_div7.hw, + &g12a_mpll1.hw, + &g12a_vid_pll.hw, + &g12a_mpll2.hw, + &g12a_fclk_div2p5.hw, }; static struct clk_regmap g12a_vapb_0_sel = { @@ -2175,8 +2699,8 @@ static struct clk_regmap g12a_vapb_0_sel = { .hw.init = &(struct clk_init_data){ .name = "vapb_0_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_vapb_parent_names, - .num_parents = ARRAY_SIZE(g12a_vapb_parent_names), + .parent_hws = g12a_vapb_parent_hws, + .num_parents = ARRAY_SIZE(g12a_vapb_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -2190,7 +2714,9 @@ static struct clk_regmap g12a_vapb_0_div = { .hw.init = &(struct clk_init_data){ .name = "vapb_0_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vapb_0_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vapb_0_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2204,7 +2730,9 @@ static struct clk_regmap g12a_vapb_0 = { .hw.init = &(struct clk_init_data) { .name = "vapb_0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vapb_0_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vapb_0_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2219,8 +2747,8 @@ static struct clk_regmap g12a_vapb_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vapb_1_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_vapb_parent_names, - .num_parents = ARRAY_SIZE(g12a_vapb_parent_names), + .parent_hws = g12a_vapb_parent_hws, + .num_parents = ARRAY_SIZE(g12a_vapb_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -2234,7 +2762,9 @@ static struct clk_regmap g12a_vapb_1_div = { .hw.init = &(struct clk_init_data){ .name = "vapb_1_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vapb_1_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vapb_1_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2248,7 +2778,9 @@ static struct clk_regmap g12a_vapb_1 = { .hw.init = &(struct clk_init_data) { .name = "vapb_1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vapb_1_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vapb_1_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2267,7 +2799,10 @@ static struct clk_regmap g12a_vapb_sel = { * bit 31 selects from 2 possible parents: * vapb_0 or vapb_1 */ - .parent_names = (const char *[]){ "vapb_0", "vapb_1" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vapb_0.hw, + &g12a_vapb_1.hw, + }, .num_parents = 2, .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -2281,75 +2816,21 @@ static struct clk_regmap g12a_vapb = { .hw.init = &(struct clk_init_data) { .name = "vapb", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vapb_sel" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vapb_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, }; -/* Video Clocks */ - -static struct clk_regmap g12a_vid_pll_div = { - .data = &(struct meson_vid_pll_div_data){ - .val = { - .reg_off = HHI_VID_PLL_CLK_DIV, - .shift = 0, - .width = 15, - }, - .sel = { - .reg_off = HHI_VID_PLL_CLK_DIV, - .shift = 16, - .width = 2, - }, - }, - .hw.init = &(struct clk_init_data) { - .name = "vid_pll_div", - .ops = &meson_vid_pll_div_ro_ops, - .parent_names = (const char *[]){ "hdmi_pll" }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, - }, -}; - -static const char * const g12a_vid_pll_parent_names[] = { "vid_pll_div", - "hdmi_pll" }; - -static struct clk_regmap g12a_vid_pll_sel = { - .data = &(struct clk_regmap_mux_data){ - .offset = HHI_VID_PLL_CLK_DIV, - .mask = 0x1, - .shift = 18, - }, - .hw.init = &(struct clk_init_data){ - .name = "vid_pll_sel", - .ops = &clk_regmap_mux_ops, - /* - * bit 18 selects from 2 possible parents: - * vid_pll_div or hdmi_pll - */ - .parent_names = g12a_vid_pll_parent_names, - .num_parents = ARRAY_SIZE(g12a_vid_pll_parent_names), - .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, - }, -}; - -static struct clk_regmap g12a_vid_pll = { - .data = &(struct clk_regmap_gate_data){ - .offset = HHI_VID_PLL_CLK_DIV, - .bit_idx = 19, - }, - .hw.init = &(struct clk_init_data) { - .name = "vid_pll", - .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vid_pll_sel" }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, - }, -}; - -static const char * const g12a_vclk_parent_names[] = { - "vid_pll", "gp0_pll", "hifi_pll", "mpll1", "fclk_div3", "fclk_div4", - "fclk_div5", "fclk_div7" +static const struct clk_hw *g12a_vclk_parent_hws[] = { + &g12a_vid_pll.hw, + &g12a_gp0_pll.hw, + &g12a_hifi_pll.hw, + &g12a_mpll1.hw, + &g12a_fclk_div3.hw, + &g12a_fclk_div4.hw, + &g12a_fclk_div5.hw, + &g12a_fclk_div7.hw, }; static struct clk_regmap g12a_vclk_sel = { @@ -2361,8 +2842,8 @@ static struct clk_regmap g12a_vclk_sel = { .hw.init = &(struct clk_init_data){ .name = "vclk_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_vclk_parent_names, - .num_parents = ARRAY_SIZE(g12a_vclk_parent_names), + .parent_hws = g12a_vclk_parent_hws, + .num_parents = ARRAY_SIZE(g12a_vclk_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -2376,8 +2857,8 @@ static struct clk_regmap g12a_vclk2_sel = { .hw.init = &(struct clk_init_data){ .name = "vclk2_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_vclk_parent_names, - .num_parents = ARRAY_SIZE(g12a_vclk_parent_names), + .parent_hws = g12a_vclk_parent_hws, + .num_parents = ARRAY_SIZE(g12a_vclk_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -2390,7 +2871,7 @@ static struct clk_regmap g12a_vclk_input = { .hw.init = &(struct clk_init_data) { .name = "vclk_input", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk_sel" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2404,7 +2885,7 @@ static struct clk_regmap g12a_vclk2_input = { .hw.init = &(struct clk_init_data) { .name = "vclk2_input", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk2_sel" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2419,7 +2900,9 @@ static struct clk_regmap g12a_vclk_div = { .hw.init = &(struct clk_init_data){ .name = "vclk_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vclk_input" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk_input.hw + }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE, }, @@ -2434,7 +2917,9 @@ static struct clk_regmap g12a_vclk2_div = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vclk2_input" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk2_input.hw + }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE, }, @@ -2448,7 +2933,7 @@ static struct clk_regmap g12a_vclk = { .hw.init = &(struct clk_init_data) { .name = "vclk", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk_div" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2462,7 +2947,7 @@ static struct clk_regmap g12a_vclk2 = { .hw.init = &(struct clk_init_data) { .name = "vclk2", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk2_div" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2476,7 +2961,7 @@ static struct clk_regmap g12a_vclk_div1 = { .hw.init = &(struct clk_init_data) { .name = "vclk_div1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2490,7 +2975,7 @@ static struct clk_regmap g12a_vclk_div2_en = { .hw.init = &(struct clk_init_data) { .name = "vclk_div2_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2504,7 +2989,7 @@ static struct clk_regmap g12a_vclk_div4_en = { .hw.init = &(struct clk_init_data) { .name = "vclk_div4_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2518,7 +3003,7 @@ static struct clk_regmap g12a_vclk_div6_en = { .hw.init = &(struct clk_init_data) { .name = "vclk_div6_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2532,7 +3017,7 @@ static struct clk_regmap g12a_vclk_div12_en = { .hw.init = &(struct clk_init_data) { .name = "vclk_div12_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2546,7 +3031,7 @@ static struct clk_regmap g12a_vclk2_div1 = { .hw.init = &(struct clk_init_data) { .name = "vclk2_div1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk2" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2560,7 +3045,7 @@ static struct clk_regmap g12a_vclk2_div2_en = { .hw.init = &(struct clk_init_data) { .name = "vclk2_div2_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk2" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2574,7 +3059,7 @@ static struct clk_regmap g12a_vclk2_div4_en = { .hw.init = &(struct clk_init_data) { .name = "vclk2_div4_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk2" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2588,7 +3073,7 @@ static struct clk_regmap g12a_vclk2_div6_en = { .hw.init = &(struct clk_init_data) { .name = "vclk2_div6_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk2" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2602,7 +3087,7 @@ static struct clk_regmap g12a_vclk2_div12_en = { .hw.init = &(struct clk_init_data) { .name = "vclk2_div12_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk2" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2614,7 +3099,9 @@ static struct clk_fixed_factor g12a_vclk_div2 = { .hw.init = &(struct clk_init_data){ .name = "vclk_div2", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk_div2_en" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk_div2_en.hw + }, .num_parents = 1, }, }; @@ -2625,7 +3112,9 @@ static struct clk_fixed_factor g12a_vclk_div4 = { .hw.init = &(struct clk_init_data){ .name = "vclk_div4", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk_div4_en" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk_div4_en.hw + }, .num_parents = 1, }, }; @@ -2636,7 +3125,9 @@ static struct clk_fixed_factor g12a_vclk_div6 = { .hw.init = &(struct clk_init_data){ .name = "vclk_div6", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk_div6_en" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk_div6_en.hw + }, .num_parents = 1, }, }; @@ -2647,7 +3138,9 @@ static struct clk_fixed_factor g12a_vclk_div12 = { .hw.init = &(struct clk_init_data){ .name = "vclk_div12", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk_div12_en" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk_div12_en.hw + }, .num_parents = 1, }, }; @@ -2658,7 +3151,9 @@ static struct clk_fixed_factor g12a_vclk2_div2 = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div2", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk2_div2_en" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk2_div2_en.hw + }, .num_parents = 1, }, }; @@ -2669,7 +3164,9 @@ static struct clk_fixed_factor g12a_vclk2_div4 = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div4", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk2_div4_en" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk2_div4_en.hw + }, .num_parents = 1, }, }; @@ -2680,7 +3177,9 @@ static struct clk_fixed_factor g12a_vclk2_div6 = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div6", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk2_div6_en" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk2_div6_en.hw + }, .num_parents = 1, }, }; @@ -2691,16 +3190,25 @@ static struct clk_fixed_factor g12a_vclk2_div12 = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div12", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk2_div12_en" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk2_div12_en.hw + }, .num_parents = 1, }, }; static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; -static const char * const g12a_cts_parent_names[] = { - "vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6", - "vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4", - "vclk2_div6", "vclk2_div12" +static const struct clk_hw *g12a_cts_parent_hws[] = { + &g12a_vclk_div1.hw, + &g12a_vclk_div2.hw, + &g12a_vclk_div4.hw, + &g12a_vclk_div6.hw, + &g12a_vclk_div12.hw, + &g12a_vclk2_div1.hw, + &g12a_vclk2_div2.hw, + &g12a_vclk2_div4.hw, + &g12a_vclk2_div6.hw, + &g12a_vclk2_div12.hw, }; static struct clk_regmap g12a_cts_enci_sel = { @@ -2713,8 +3221,8 @@ static struct clk_regmap g12a_cts_enci_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_enci_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_cts_parent_names, - .num_parents = ARRAY_SIZE(g12a_cts_parent_names), + .parent_hws = g12a_cts_parent_hws, + .num_parents = ARRAY_SIZE(g12a_cts_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -2729,8 +3237,8 @@ static struct clk_regmap g12a_cts_encp_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_encp_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_cts_parent_names, - .num_parents = ARRAY_SIZE(g12a_cts_parent_names), + .parent_hws = g12a_cts_parent_hws, + .num_parents = ARRAY_SIZE(g12a_cts_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -2745,18 +3253,25 @@ static struct clk_regmap g12a_cts_vdac_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_vdac_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_cts_parent_names, - .num_parents = ARRAY_SIZE(g12a_cts_parent_names), + .parent_hws = g12a_cts_parent_hws, + .num_parents = ARRAY_SIZE(g12a_cts_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; /* TOFIX: add support for cts_tcon */ static u32 mux_table_hdmi_tx_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; -static const char * const g12a_cts_hdmi_tx_parent_names[] = { - "vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6", - "vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4", - "vclk2_div6", "vclk2_div12" +static const struct clk_hw *g12a_cts_hdmi_tx_parent_hws[] = { + &g12a_vclk_div1.hw, + &g12a_vclk_div2.hw, + &g12a_vclk_div4.hw, + &g12a_vclk_div6.hw, + &g12a_vclk_div12.hw, + &g12a_vclk2_div1.hw, + &g12a_vclk2_div2.hw, + &g12a_vclk2_div4.hw, + &g12a_vclk2_div6.hw, + &g12a_vclk2_div12.hw, }; static struct clk_regmap g12a_hdmi_tx_sel = { @@ -2769,8 +3284,8 @@ static struct clk_regmap g12a_hdmi_tx_sel = { .hw.init = &(struct clk_init_data){ .name = "hdmi_tx_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_cts_hdmi_tx_parent_names, - .num_parents = ARRAY_SIZE(g12a_cts_hdmi_tx_parent_names), + .parent_hws = g12a_cts_hdmi_tx_parent_hws, + .num_parents = ARRAY_SIZE(g12a_cts_hdmi_tx_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -2783,7 +3298,9 @@ static struct clk_regmap g12a_cts_enci = { .hw.init = &(struct clk_init_data) { .name = "cts_enci", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "cts_enci_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cts_enci_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2797,7 +3314,9 @@ static struct clk_regmap g12a_cts_encp = { .hw.init = &(struct clk_init_data) { .name = "cts_encp", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "cts_encp_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cts_encp_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2811,7 +3330,9 @@ static struct clk_regmap g12a_cts_vdac = { .hw.init = &(struct clk_init_data) { .name = "cts_vdac", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "cts_vdac_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cts_vdac_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2825,7 +3346,9 @@ static struct clk_regmap g12a_hdmi_tx = { .hw.init = &(struct clk_init_data) { .name = "hdmi_tx", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "hdmi_tx_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_hdmi_tx_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2833,8 +3356,11 @@ static struct clk_regmap g12a_hdmi_tx = { /* HDMI Clocks */ -static const char * const g12a_hdmi_parent_names[] = { - IN_PREFIX "xtal", "fclk_div4", "fclk_div3", "fclk_div5" +static const struct clk_parent_data g12a_hdmi_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div4.hw }, + { .hw = &g12a_fclk_div3.hw }, + { .hw = &g12a_fclk_div5.hw }, }; static struct clk_regmap g12a_hdmi_sel = { @@ -2847,8 +3373,8 @@ static struct clk_regmap g12a_hdmi_sel = { .hw.init = &(struct clk_init_data){ .name = "hdmi_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_hdmi_parent_names, - .num_parents = ARRAY_SIZE(g12a_hdmi_parent_names), + .parent_data = g12a_hdmi_parent_data, + .num_parents = ARRAY_SIZE(g12a_hdmi_parent_data), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -2862,7 +3388,7 @@ static struct clk_regmap g12a_hdmi_div = { .hw.init = &(struct clk_init_data){ .name = "hdmi_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "hdmi_sel" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_hdmi_sel.hw }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE, }, @@ -2876,7 +3402,7 @@ static struct clk_regmap g12a_hdmi = { .hw.init = &(struct clk_init_data) { .name = "hdmi", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "hdmi_div" }, + .parent_hws = (const struct clk_hw *[]) { &g12a_hdmi_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2886,10 +3412,15 @@ static struct clk_regmap g12a_hdmi = { * The MALI IP is clocked by two identical clocks (mali_0 and mali_1) * muxed by a glitch-free switch. */ - -static const char * const g12a_mali_0_1_parent_names[] = { - IN_PREFIX "xtal", "gp0_pll", "hihi_pll", "fclk_div2p5", - "fclk_div3", "fclk_div4", "fclk_div5", "fclk_div7" +static const struct clk_parent_data g12a_mali_0_1_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &g12a_gp0_pll.hw }, + { .hw = &g12a_hifi_pll.hw }, + { .hw = &g12a_fclk_div2p5.hw }, + { .hw = &g12a_fclk_div3.hw }, + { .hw = &g12a_fclk_div4.hw }, + { .hw = &g12a_fclk_div5.hw }, + { .hw = &g12a_fclk_div7.hw }, }; static struct clk_regmap g12a_mali_0_sel = { @@ -2901,7 +3432,7 @@ static struct clk_regmap g12a_mali_0_sel = { .hw.init = &(struct clk_init_data){ .name = "mali_0_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_mali_0_1_parent_names, + .parent_data = g12a_mali_0_1_parent_data, .num_parents = 8, .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -2916,7 +3447,9 @@ static struct clk_regmap g12a_mali_0_div = { .hw.init = &(struct clk_init_data){ .name = "mali_0_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "mali_0_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mali_0_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -2930,7 +3463,9 @@ static struct clk_regmap g12a_mali_0 = { .hw.init = &(struct clk_init_data){ .name = "mali_0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mali_0_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mali_0_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2945,7 +3480,7 @@ static struct clk_regmap g12a_mali_1_sel = { .hw.init = &(struct clk_init_data){ .name = "mali_1_sel", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_mali_0_1_parent_names, + .parent_data = g12a_mali_0_1_parent_data, .num_parents = 8, .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -2960,7 +3495,9 @@ static struct clk_regmap g12a_mali_1_div = { .hw.init = &(struct clk_init_data){ .name = "mali_1_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "mali_1_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mali_1_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -2974,14 +3511,17 @@ static struct clk_regmap g12a_mali_1 = { .hw.init = &(struct clk_init_data){ .name = "mali_1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mali_1_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mali_1_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const char * const g12a_mali_parent_names[] = { - "mali_0", "mali_1" +static const struct clk_hw *g12a_mali_parent_hws[] = { + &g12a_mali_0.hw, + &g12a_mali_1.hw, }; static struct clk_regmap g12a_mali = { @@ -2993,7 +3533,7 @@ static struct clk_regmap g12a_mali = { .hw.init = &(struct clk_init_data){ .name = "mali", .ops = &clk_regmap_mux_ops, - .parent_names = g12a_mali_parent_names, + .parent_hws = g12a_mali_parent_hws, .num_parents = 2, .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -3008,7 +3548,9 @@ static struct clk_regmap g12a_ts_div = { .hw.init = &(struct clk_init_data){ .name = "ts_div", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -3021,11 +3563,19 @@ static struct clk_regmap g12a_ts = { .hw.init = &(struct clk_init_data){ .name = "ts", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "ts_div" }, + .parent_hws = (const struct clk_hw *[]) { + &g12a_ts_div.hw + }, .num_parents = 1, }, }; +#define MESON_GATE(_name, _reg, _bit) \ + MESON_PCLK(_name, _reg, _bit, &g12a_clk81.hw) + +#define MESON_GATE_RO(_name, _reg, _bit) \ + MESON_PCLK_RO(_name, _reg, _bit, &g12a_clk81.hw) + /* Everything Else (EE) domain gates */ static MESON_GATE(g12a_ddr, HHI_GCLK_MPEG0, 0); static MESON_GATE(g12a_dos, HHI_GCLK_MPEG0, 1); @@ -3792,28 +4342,210 @@ static const struct reg_sequence g12a_init_regs[] = { { .reg = HHI_MPLL_CNTL0, .def = 0x00000543 }, }; -static const struct meson_eeclkc_data g12a_clkc_data = { - .regmap_clks = g12a_clk_regmaps, - .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps), - .hw_onecell_data = &g12a_hw_onecell_data, - .init_regs = g12a_init_regs, - .init_count = ARRAY_SIZE(g12a_init_regs), -}; - -static const struct meson_eeclkc_data g12b_clkc_data = { - .regmap_clks = g12a_clk_regmaps, - .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps), - .hw_onecell_data = &g12b_hw_onecell_data +static int meson_g12a_dvfs_setup_common(struct platform_device *pdev, + struct clk_hw **hws) +{ + const char *notifier_clk_name; + struct clk *notifier_clk; + struct clk_hw *xtal; + int ret; + + xtal = clk_hw_get_parent_by_index(hws[CLKID_CPU_CLK_DYN1_SEL], 0); + + /* Setup clock notifier for cpu_clk_postmux0 */ + g12a_cpu_clk_postmux0_nb_data.xtal = xtal; + notifier_clk_name = clk_hw_get_name(&g12a_cpu_clk_postmux0.hw); + notifier_clk = __clk_lookup(notifier_clk_name); + ret = clk_notifier_register(notifier_clk, + &g12a_cpu_clk_postmux0_nb_data.nb); + if (ret) { + dev_err(&pdev->dev, "failed to register the cpu_clk_postmux0 notifier\n"); + return ret; + } + + /* Setup clock notifier for cpu_clk_dyn mux */ + notifier_clk_name = clk_hw_get_name(&g12a_cpu_clk_dyn.hw); + notifier_clk = __clk_lookup(notifier_clk_name); + ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); + if (ret) { + dev_err(&pdev->dev, "failed to register the cpu_clk_dyn notifier\n"); + return ret; + } + + return 0; +} + +static int meson_g12b_dvfs_setup(struct platform_device *pdev) +{ + struct clk_hw **hws = g12b_hw_onecell_data.hws; + const char *notifier_clk_name; + struct clk *notifier_clk; + struct clk_hw *xtal; + int ret; + + ret = meson_g12a_dvfs_setup_common(pdev, hws); + if (ret) + return ret; + + xtal = clk_hw_get_parent_by_index(hws[CLKID_CPU_CLK_DYN1_SEL], 0); + + /* Setup clock notifier for cpu_clk mux */ + notifier_clk_name = clk_hw_get_name(&g12b_cpu_clk.hw); + notifier_clk = __clk_lookup(notifier_clk_name); + ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); + if (ret) { + dev_err(&pdev->dev, "failed to register the cpu_clk notifier\n"); + return ret; + } + + /* Setup clock notifier for sys1_pll */ + notifier_clk_name = clk_hw_get_name(&g12b_sys1_pll.hw); + notifier_clk = __clk_lookup(notifier_clk_name); + ret = clk_notifier_register(notifier_clk, + &g12b_cpu_clk_sys1_pll_nb_data.nb); + if (ret) { + dev_err(&pdev->dev, "failed to register the sys1_pll notifier\n"); + return ret; + } + + /* Add notifiers for the second CPU cluster */ + + /* Setup clock notifier for cpub_clk_postmux0 */ + g12b_cpub_clk_postmux0_nb_data.xtal = xtal; + notifier_clk_name = clk_hw_get_name(&g12b_cpub_clk_postmux0.hw); + notifier_clk = __clk_lookup(notifier_clk_name); + ret = clk_notifier_register(notifier_clk, + &g12b_cpub_clk_postmux0_nb_data.nb); + if (ret) { + dev_err(&pdev->dev, "failed to register the cpub_clk_postmux0 notifier\n"); + return ret; + } + + /* Setup clock notifier for cpub_clk_dyn mux */ + notifier_clk_name = clk_hw_get_name(&g12b_cpub_clk_dyn.hw); + notifier_clk = __clk_lookup(notifier_clk_name); + ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); + if (ret) { + dev_err(&pdev->dev, "failed to register the cpub_clk_dyn notifier\n"); + return ret; + } + + /* Setup clock notifier for cpub_clk mux */ + notifier_clk_name = clk_hw_get_name(&g12b_cpub_clk.hw); + notifier_clk = __clk_lookup(notifier_clk_name); + ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); + if (ret) { + dev_err(&pdev->dev, "failed to register the cpub_clk notifier\n"); + return ret; + } + + /* Setup clock notifier for sys_pll */ + notifier_clk_name = clk_hw_get_name(&g12a_sys_pll.hw); + notifier_clk = __clk_lookup(notifier_clk_name); + ret = clk_notifier_register(notifier_clk, + &g12b_cpub_clk_sys_pll_nb_data.nb); + if (ret) { + dev_err(&pdev->dev, "failed to register the sys_pll notifier\n"); + return ret; + } + + return 0; +} + +static int meson_g12a_dvfs_setup(struct platform_device *pdev) +{ + struct clk_hw **hws = g12a_hw_onecell_data.hws; + const char *notifier_clk_name; + struct clk *notifier_clk; + int ret; + + ret = meson_g12a_dvfs_setup_common(pdev, hws); + if (ret) + return ret; + + /* Setup clock notifier for cpu_clk mux */ + notifier_clk_name = clk_hw_get_name(&g12a_cpu_clk.hw); + notifier_clk = __clk_lookup(notifier_clk_name); + ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); + if (ret) { + dev_err(&pdev->dev, "failed to register the cpu_clk notifier\n"); + return ret; + } + + /* Setup clock notifier for sys_pll */ + notifier_clk_name = clk_hw_get_name(&g12a_sys_pll.hw); + notifier_clk = __clk_lookup(notifier_clk_name); + ret = clk_notifier_register(notifier_clk, &g12a_sys_pll_nb_data.nb); + if (ret) { + dev_err(&pdev->dev, "failed to register the sys_pll notifier\n"); + return ret; + } + + return 0; +} + +struct meson_g12a_data { + const struct meson_eeclkc_data eeclkc_data; + int (*dvfs_setup)(struct platform_device *pdev); +}; + +static int meson_g12a_probe(struct platform_device *pdev) +{ + const struct meson_eeclkc_data *eeclkc_data; + const struct meson_g12a_data *g12a_data; + int ret; + + eeclkc_data = of_device_get_match_data(&pdev->dev); + if (!eeclkc_data) + return -EINVAL; + + ret = meson_eeclkc_probe(pdev); + if (ret) + return ret; + + g12a_data = container_of(eeclkc_data, struct meson_g12a_data, + eeclkc_data); + + if (g12a_data->dvfs_setup) + return g12a_data->dvfs_setup(pdev); + + return 0; +} + +static const struct meson_g12a_data g12a_clkc_data = { + .eeclkc_data = { + .regmap_clks = g12a_clk_regmaps, + .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps), + .hw_onecell_data = &g12a_hw_onecell_data, + .init_regs = g12a_init_regs, + .init_count = ARRAY_SIZE(g12a_init_regs), + }, + .dvfs_setup = meson_g12a_dvfs_setup, +}; + +static const struct meson_g12a_data g12b_clkc_data = { + .eeclkc_data = { + .regmap_clks = g12a_clk_regmaps, + .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps), + .hw_onecell_data = &g12b_hw_onecell_data, + }, + .dvfs_setup = meson_g12b_dvfs_setup, }; static const struct of_device_id clkc_match_table[] = { - { .compatible = "amlogic,g12a-clkc", .data = &g12a_clkc_data }, - { .compatible = "amlogic,g12b-clkc", .data = &g12b_clkc_data }, + { + .compatible = "amlogic,g12a-clkc", + .data = &g12a_clkc_data.eeclkc_data + }, + { + .compatible = "amlogic,g12b-clkc", + .data = &g12b_clkc_data.eeclkc_data + }, {} }; static struct platform_driver g12a_driver = { - .probe = meson_eeclkc_probe, + .probe = meson_g12a_probe, .driver = { .name = "g12a-clkc", .of_match_table = clkc_match_table, diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h index c8aed31fbe1715c4e2077a61c9e1a71493388a88..559a34cfdfeb876cd12e1039a6554a473142315c 100644 --- a/drivers/clk/meson/g12a.h +++ b/drivers/clk/meson/g12a.h @@ -216,7 +216,6 @@ #define CLKID_CPUB_CLK_DYN1_DIV 221 #define CLKID_CPUB_CLK_DYN1 222 #define CLKID_CPUB_CLK_DYN 223 -#define CLKID_CPUB_CLK 224 #define CLKID_CPUB_CLK_DIV16_EN 225 #define CLKID_CPUB_CLK_DIV16 226 #define CLKID_CPUB_CLK_DIV2 227 diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index 449f6ac189d86ea59fcb0d66ea0efe4d40dea9ac..e940861a396b591c190da58042b108f2e81ac9e8 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -11,8 +11,6 @@ #include "clk-regmap.h" #include "clk-dualdiv.h" -#define IN_PREFIX "ao-in-" - /* AO Configuration Clock registers offsets */ #define AO_RTI_PWR_CNTL_REG1 0x0c #define AO_RTI_PWR_CNTL_REG0 0x10 @@ -31,7 +29,9 @@ static struct clk_regmap _name##_ao = { \ .hw.init = &(struct clk_init_data) { \ .name = #_name "_ao", \ .ops = &clk_regmap_gate_ops, \ - .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk" }, \ + .parent_data = &(const struct clk_parent_data) { \ + .fw_name = "mpeg-clk", \ + }, \ .num_parents = 1, \ .flags = CLK_IGNORE_UNUSED, \ }, \ @@ -52,7 +52,9 @@ static struct clk_regmap ao_cts_oscin = { .hw.init = &(struct clk_init_data){ .name = "ao_cts_oscin", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -65,7 +67,7 @@ static struct clk_regmap ao_32k_pre = { .hw.init = &(struct clk_init_data){ .name = "ao_32k_pre", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "ao_cts_oscin" }, + .parent_hws = (const struct clk_hw *[]) { &ao_cts_oscin.hw }, .num_parents = 1, }, }; @@ -112,7 +114,7 @@ static struct clk_regmap ao_32k_div = { .hw.init = &(struct clk_init_data){ .name = "ao_32k_div", .ops = &meson_clk_dualdiv_ops, - .parent_names = (const char *[]){ "ao_32k_pre" }, + .parent_hws = (const struct clk_hw *[]) { &ao_32k_pre.hw }, .num_parents = 1, }, }; @@ -127,8 +129,10 @@ static struct clk_regmap ao_32k_sel = { .hw.init = &(struct clk_init_data){ .name = "ao_32k_sel", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "ao_32k_div", - "ao_32k_pre" }, + .parent_hws = (const struct clk_hw *[]) { + &ao_32k_div.hw, + &ao_32k_pre.hw + }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, @@ -142,7 +146,7 @@ static struct clk_regmap ao_32k = { .hw.init = &(struct clk_init_data){ .name = "ao_32k", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "ao_32k_sel" }, + .parent_hws = (const struct clk_hw *[]) { &ao_32k_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -159,10 +163,12 @@ static struct clk_regmap ao_cts_rtc_oscin = { .hw.init = &(struct clk_init_data){ .name = "ao_cts_rtc_oscin", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ IN_PREFIX "ext-32k-0", - IN_PREFIX "ext-32k-1", - IN_PREFIX "ext-32k-2", - "ao_32k" }, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "ext-32k-0", }, + { .fw_name = "ext-32k-1", }, + { .fw_name = "ext-32k-2", }, + { .hw = &ao_32k.hw }, + }, .num_parents = 4, .flags = CLK_SET_RATE_PARENT, }, @@ -178,8 +184,10 @@ static struct clk_regmap ao_clk81 = { .hw.init = &(struct clk_init_data){ .name = "ao_clk81", .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk", - "ao_cts_rtc_oscin" }, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "mpeg-clk", }, + { .hw = &ao_cts_rtc_oscin.hw }, + }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, @@ -208,8 +216,10 @@ static struct clk_regmap ao_cts_cec = { * Until CCF gets fixed, adding this fake parent that won't * ever be registered should work around the problem */ - .parent_names = (const char *[]){ "fixme", - "ao_cts_rtc_oscin" }, + .parent_data = (const struct clk_parent_data []) { + { .name = "fixme", .index = -1, }, + { .hw = &ao_cts_rtc_oscin.hw }, + }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, @@ -261,14 +271,6 @@ static const struct clk_hw_onecell_data gxbb_aoclk_onecell_data = { .num = NR_CLKS, }; -static const struct meson_aoclk_input gxbb_aoclk_inputs[] = { - { .name = "xtal", .required = true, }, - { .name = "mpeg-clk", .required = true, }, - {. name = "ext-32k-0", .required = false, }, - {. name = "ext-32k-1", .required = false, }, - {. name = "ext-32k-2", .required = false, }, -}; - static const struct meson_aoclk_data gxbb_aoclkc_data = { .reset_reg = AO_RTI_GEN_CNTL_REG0, .num_reset = ARRAY_SIZE(gxbb_aoclk_reset), @@ -276,9 +278,6 @@ static const struct meson_aoclk_data gxbb_aoclkc_data = { .num_clks = ARRAY_SIZE(gxbb_aoclk), .clks = gxbb_aoclk, .hw_data = &gxbb_aoclk_onecell_data, - .inputs = gxbb_aoclk_inputs, - .num_inputs = ARRAY_SIZE(gxbb_aoclk_inputs), - .input_prefix = IN_PREFIX, }; static const struct of_device_id gxbb_aoclkc_match_table[] = { diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index dab16d9b1af8b442eed369771e38117c06f48864..7cfb998eeb3e0e05234f041ce0bb6938dc7db1f9 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -10,15 +10,12 @@ #include #include "gxbb.h" -#include "clk-input.h" #include "clk-regmap.h" #include "clk-pll.h" #include "clk-mpll.h" #include "meson-eeclk.h" #include "vid-pll-div.h" -#define IN_PREFIX "ee-in-" - static DEFINE_SPINLOCK(meson_clk_lock); static const struct pll_params_table gxbb_gp0_pll_params_table[] = { @@ -121,7 +118,9 @@ static struct clk_regmap gxbb_fixed_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -136,7 +135,9 @@ static struct clk_regmap gxbb_fixed_pll = { .hw.init = &(struct clk_init_data){ .name = "fixed_pll", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "fixed_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_fixed_pll_dco.hw + }, .num_parents = 1, /* * This clock won't ever change at runtime so @@ -151,7 +152,9 @@ static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_pre_mult", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -192,7 +195,9 @@ static struct clk_regmap gxbb_hdmi_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "hdmi_pll_pre_mult" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_hdmi_pll_pre_mult.hw + }, .num_parents = 1, /* * Display directly handle hdmi pll registers ATM, we need @@ -244,7 +249,9 @@ static struct clk_regmap gxl_hdmi_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, /* * Display directly handle hdmi pll registers ATM, we need @@ -264,7 +271,9 @@ static struct clk_regmap gxbb_hdmi_pll_od = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_od", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "hdmi_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_hdmi_pll_dco.hw + }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, }, @@ -280,7 +289,9 @@ static struct clk_regmap gxbb_hdmi_pll_od2 = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_od2", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "hdmi_pll_od" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_hdmi_pll_od.hw + }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, }, @@ -296,7 +307,9 @@ static struct clk_regmap gxbb_hdmi_pll = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "hdmi_pll_od2" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_hdmi_pll_od2.hw + }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, }, @@ -312,7 +325,9 @@ static struct clk_regmap gxl_hdmi_pll_od = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_od", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "hdmi_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &gxl_hdmi_pll_dco.hw + }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, }, @@ -328,7 +343,9 @@ static struct clk_regmap gxl_hdmi_pll_od2 = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_od2", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "hdmi_pll_od" }, + .parent_hws = (const struct clk_hw *[]) { + &gxl_hdmi_pll_od.hw + }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, }, @@ -344,7 +361,9 @@ static struct clk_regmap gxl_hdmi_pll = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "hdmi_pll_od2" }, + .parent_hws = (const struct clk_hw *[]) { + &gxl_hdmi_pll_od2.hw + }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, }, @@ -381,7 +400,9 @@ static struct clk_regmap gxbb_sys_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "sys_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -396,7 +417,9 @@ static struct clk_regmap gxbb_sys_pll = { .hw.init = &(struct clk_init_data){ .name = "sys_pll", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "sys_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sys_pll_dco.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -442,7 +465,9 @@ static struct clk_regmap gxbb_gp0_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -494,7 +519,9 @@ static struct clk_regmap gxl_gp0_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, .num_parents = 1, }, }; @@ -509,7 +536,17 @@ static struct clk_regmap gxbb_gp0_pll = { .hw.init = &(struct clk_init_data){ .name = "gp0_pll", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "gp0_pll_dco" }, + .parent_data = &(const struct clk_parent_data) { + /* + * Note: + * GXL and GXBB have different gp0_pll_dco (with + * different struct clk_hw). We fallback to the global + * naming string mechanism so gp0_pll picks up the + * appropriate one. + */ + .name = "gp0_pll_dco", + .index = -1, + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -521,7 +558,9 @@ static struct clk_fixed_factor gxbb_fclk_div2_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div2_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_fixed_pll.hw + }, .num_parents = 1, }, }; @@ -534,7 +573,9 @@ static struct clk_regmap gxbb_fclk_div2 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div2", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div2_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_fclk_div2_div.hw + }, .num_parents = 1, .flags = CLK_IS_CRITICAL, }, @@ -546,7 +587,7 @@ static struct clk_fixed_factor gxbb_fclk_div3_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div3_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_fixed_pll.hw }, .num_parents = 1, }, }; @@ -559,7 +600,9 @@ static struct clk_regmap gxbb_fclk_div3 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div3", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div3_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_fclk_div3_div.hw + }, .num_parents = 1, /* * FIXME: @@ -582,7 +625,7 @@ static struct clk_fixed_factor gxbb_fclk_div4_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div4_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_fixed_pll.hw }, .num_parents = 1, }, }; @@ -595,7 +638,9 @@ static struct clk_regmap gxbb_fclk_div4 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div4", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div4_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_fclk_div4_div.hw + }, .num_parents = 1, }, }; @@ -606,7 +651,7 @@ static struct clk_fixed_factor gxbb_fclk_div5_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div5_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_fixed_pll.hw }, .num_parents = 1, }, }; @@ -619,7 +664,9 @@ static struct clk_regmap gxbb_fclk_div5 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div5", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div5_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_fclk_div5_div.hw + }, .num_parents = 1, }, }; @@ -630,7 +677,7 @@ static struct clk_fixed_factor gxbb_fclk_div7_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div7_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_fixed_pll.hw }, .num_parents = 1, }, }; @@ -643,7 +690,9 @@ static struct clk_regmap gxbb_fclk_div7 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div7", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div7_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_fclk_div7_div.hw + }, .num_parents = 1, }, }; @@ -657,7 +706,7 @@ static struct clk_regmap gxbb_mpll_prediv = { .hw.init = &(struct clk_init_data){ .name = "mpll_prediv", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_fixed_pll.hw }, .num_parents = 1, }, }; @@ -684,7 +733,9 @@ static struct clk_regmap gxbb_mpll0_div = { .hw.init = &(struct clk_init_data){ .name = "mpll0_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "mpll_prediv" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mpll_prediv.hw + }, .num_parents = 1, }, }; @@ -697,7 +748,7 @@ static struct clk_regmap gxbb_mpll0 = { .hw.init = &(struct clk_init_data){ .name = "mpll0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpll0_div" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_mpll0_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -725,7 +776,9 @@ static struct clk_regmap gxbb_mpll1_div = { .hw.init = &(struct clk_init_data){ .name = "mpll1_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "mpll_prediv" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mpll_prediv.hw + }, .num_parents = 1, }, }; @@ -738,7 +791,7 @@ static struct clk_regmap gxbb_mpll1 = { .hw.init = &(struct clk_init_data){ .name = "mpll1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpll1_div" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_mpll1_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -766,7 +819,9 @@ static struct clk_regmap gxbb_mpll2_div = { .hw.init = &(struct clk_init_data){ .name = "mpll2_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "mpll_prediv" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mpll_prediv.hw + }, .num_parents = 1, }, }; @@ -779,16 +834,21 @@ static struct clk_regmap gxbb_mpll2 = { .hw.init = &(struct clk_init_data){ .name = "mpll2", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpll2_div" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_mpll2_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; -static const char * const clk81_parent_names[] = { - IN_PREFIX "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", - "fclk_div3", "fclk_div5" +static const struct clk_parent_data clk81_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &gxbb_fclk_div7.hw }, + { .hw = &gxbb_mpll1.hw }, + { .hw = &gxbb_mpll2.hw }, + { .hw = &gxbb_fclk_div4.hw }, + { .hw = &gxbb_fclk_div3.hw }, + { .hw = &gxbb_fclk_div5.hw }, }; static struct clk_regmap gxbb_mpeg_clk_sel = { @@ -806,8 +866,8 @@ static struct clk_regmap gxbb_mpeg_clk_sel = { * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, * fclk_div4, fclk_div3, fclk_div5 */ - .parent_names = clk81_parent_names, - .num_parents = ARRAY_SIZE(clk81_parent_names), + .parent_data = clk81_parent_data, + .num_parents = ARRAY_SIZE(clk81_parent_data), }, }; @@ -820,7 +880,9 @@ static struct clk_regmap gxbb_mpeg_clk_div = { .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "mpeg_clk_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mpeg_clk_sel.hw + }, .num_parents = 1, }, }; @@ -834,7 +896,9 @@ static struct clk_regmap gxbb_clk81 = { .hw.init = &(struct clk_init_data){ .name = "clk81", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpeg_clk_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mpeg_clk_div.hw + }, .num_parents = 1, .flags = CLK_IS_CRITICAL, }, @@ -850,7 +914,10 @@ static struct clk_regmap gxbb_sar_adc_clk_sel = { .name = "sar_adc_clk_sel", .ops = &clk_regmap_mux_ops, /* NOTE: The datasheet doesn't list the parents for bit 10 */ - .parent_names = (const char *[]){ IN_PREFIX "xtal", "clk81", }, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &gxbb_clk81.hw }, + }, .num_parents = 2, }, }; @@ -864,7 +931,9 @@ static struct clk_regmap gxbb_sar_adc_clk_div = { .hw.init = &(struct clk_init_data){ .name = "sar_adc_clk_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "sar_adc_clk_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sar_adc_clk_sel.hw + }, .num_parents = 1, }, }; @@ -877,7 +946,9 @@ static struct clk_regmap gxbb_sar_adc_clk = { .hw.init = &(struct clk_init_data){ .name = "sar_adc_clk", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "sar_adc_clk_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sar_adc_clk_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -888,9 +959,15 @@ static struct clk_regmap gxbb_sar_adc_clk = { * muxed by a glitch-free switch. */ -static const char * const gxbb_mali_0_1_parent_names[] = { - IN_PREFIX "xtal", "gp0_pll", "mpll2", "mpll1", "fclk_div7", - "fclk_div4", "fclk_div3", "fclk_div5" +static const struct clk_parent_data gxbb_mali_0_1_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &gxbb_gp0_pll.hw }, + { .hw = &gxbb_mpll2.hw }, + { .hw = &gxbb_mpll1.hw }, + { .hw = &gxbb_fclk_div7.hw }, + { .hw = &gxbb_fclk_div4.hw }, + { .hw = &gxbb_fclk_div3.hw }, + { .hw = &gxbb_fclk_div5.hw }, }; static struct clk_regmap gxbb_mali_0_sel = { @@ -907,7 +984,7 @@ static struct clk_regmap gxbb_mali_0_sel = { * xtal, gp0_pll, mpll2, mpll1, fclk_div7, * fclk_div4, fclk_div3, fclk_div5 */ - .parent_names = gxbb_mali_0_1_parent_names, + .parent_data = gxbb_mali_0_1_parent_data, .num_parents = 8, .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -922,7 +999,9 @@ static struct clk_regmap gxbb_mali_0_div = { .hw.init = &(struct clk_init_data){ .name = "mali_0_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "mali_0_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mali_0_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -936,7 +1015,9 @@ static struct clk_regmap gxbb_mali_0 = { .hw.init = &(struct clk_init_data){ .name = "mali_0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mali_0_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mali_0_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -956,7 +1037,7 @@ static struct clk_regmap gxbb_mali_1_sel = { * xtal, gp0_pll, mpll2, mpll1, fclk_div7, * fclk_div4, fclk_div3, fclk_div5 */ - .parent_names = gxbb_mali_0_1_parent_names, + .parent_data = gxbb_mali_0_1_parent_data, .num_parents = 8, .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -971,7 +1052,9 @@ static struct clk_regmap gxbb_mali_1_div = { .hw.init = &(struct clk_init_data){ .name = "mali_1_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "mali_1_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mali_1_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -985,14 +1068,17 @@ static struct clk_regmap gxbb_mali_1 = { .hw.init = &(struct clk_init_data){ .name = "mali_1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mali_1_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mali_1_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const char * const gxbb_mali_parent_names[] = { - "mali_0", "mali_1" +static const struct clk_hw *gxbb_mali_parent_hws[] = { + &gxbb_mali_0.hw, + &gxbb_mali_1.hw, }; static struct clk_regmap gxbb_mali = { @@ -1004,7 +1090,7 @@ static struct clk_regmap gxbb_mali = { .hw.init = &(struct clk_init_data){ .name = "mali", .ops = &clk_regmap_mux_ops, - .parent_names = gxbb_mali_parent_names, + .parent_hws = gxbb_mali_parent_hws, .num_parents = 2, .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -1021,7 +1107,11 @@ static struct clk_regmap gxbb_cts_amclk_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_amclk_sel", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mpll0.hw, + &gxbb_mpll1.hw, + &gxbb_mpll2.hw, + }, .num_parents = 3, }, }; @@ -1036,7 +1126,9 @@ static struct clk_regmap gxbb_cts_amclk_div = { .hw.init = &(struct clk_init_data){ .name = "cts_amclk_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "cts_amclk_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_cts_amclk_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1050,7 +1142,9 @@ static struct clk_regmap gxbb_cts_amclk = { .hw.init = &(struct clk_init_data){ .name = "cts_amclk", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "cts_amclk_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_cts_amclk_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1067,7 +1161,11 @@ static struct clk_regmap gxbb_cts_mclk_i958_sel = { .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_sel", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mpll0.hw, + &gxbb_mpll1.hw, + &gxbb_mpll2.hw, + }, .num_parents = 3, }, }; @@ -1082,7 +1180,9 @@ static struct clk_regmap gxbb_cts_mclk_i958_div = { .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "cts_mclk_i958_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_cts_mclk_i958_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1096,7 +1196,9 @@ static struct clk_regmap gxbb_cts_mclk_i958 = { .hw.init = &(struct clk_init_data){ .name = "cts_mclk_i958", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "cts_mclk_i958_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_cts_mclk_i958_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1111,7 +1213,10 @@ static struct clk_regmap gxbb_cts_i958 = { .hw.init = &(struct clk_init_data){ .name = "cts_i958", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "cts_amclk", "cts_mclk_i958" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_cts_amclk.hw, + &gxbb_cts_mclk_i958.hw + }, .num_parents = 2, /* *The parent is specific to origin of the audio data. Let the @@ -1121,6 +1226,33 @@ static struct clk_regmap gxbb_cts_i958 = { }, }; +static const struct clk_parent_data gxbb_32k_clk_parent_data[] = { + { .fw_name = "xtal", }, + /* + * FIXME: This clock is provided by the ao clock controller but the + * clock is not yet part of the binding of this controller, so string + * name must be use to set this parent. + */ + { .name = "cts_slow_oscin", .index = -1 }, + { .hw = &gxbb_fclk_div3.hw }, + { .hw = &gxbb_fclk_div5.hw }, +}; + +static struct clk_regmap gxbb_32k_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_32K_CLK_CNTL, + .mask = 0x3, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "32k_clk_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = gxbb_32k_clk_parent_data, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static struct clk_regmap gxbb_32k_clk_div = { .data = &(struct clk_regmap_div_data){ .offset = HHI_32K_CLK_CNTL, @@ -1130,7 +1262,9 @@ static struct clk_regmap gxbb_32k_clk_div = { .hw.init = &(struct clk_init_data){ .name = "32k_clk_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "32k_clk_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_32k_clk_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_DIVIDER_ROUND_CLOSEST, }, @@ -1144,34 +1278,20 @@ static struct clk_regmap gxbb_32k_clk = { .hw.init = &(struct clk_init_data){ .name = "32k_clk", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "32k_clk_div" }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static const char * const gxbb_32k_clk_parent_names[] = { - IN_PREFIX "xtal", "cts_slow_oscin", "fclk_div3", "fclk_div5" -}; - -static struct clk_regmap gxbb_32k_clk_sel = { - .data = &(struct clk_regmap_mux_data){ - .offset = HHI_32K_CLK_CNTL, - .mask = 0x3, - .shift = 16, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_32k_clk_div.hw }, - .hw.init = &(struct clk_init_data){ - .name = "32k_clk_sel", - .ops = &clk_regmap_mux_ops, - .parent_names = gxbb_32k_clk_parent_names, - .num_parents = 4, + .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const char * const gxbb_sd_emmc_clk0_parent_names[] = { - IN_PREFIX "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", - +static const struct clk_parent_data gxbb_sd_emmc_clk0_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &gxbb_fclk_div2.hw }, + { .hw = &gxbb_fclk_div3.hw }, + { .hw = &gxbb_fclk_div5.hw }, + { .hw = &gxbb_fclk_div7.hw }, /* * Following these parent clocks, we should also have had mpll2, mpll3 * and gp0_pll but these clocks are too precious to be used here. All @@ -1190,8 +1310,8 @@ static struct clk_regmap gxbb_sd_emmc_a_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_a_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_names = gxbb_sd_emmc_clk0_parent_names, - .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), + .parent_data = gxbb_sd_emmc_clk0_parent_data, + .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_data), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1206,7 +1326,9 @@ static struct clk_regmap gxbb_sd_emmc_a_clk0_div = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_a_clk0_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "sd_emmc_a_clk0_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sd_emmc_a_clk0_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1220,7 +1342,9 @@ static struct clk_regmap gxbb_sd_emmc_a_clk0 = { .hw.init = &(struct clk_init_data){ .name = "sd_emmc_a_clk0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "sd_emmc_a_clk0_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sd_emmc_a_clk0_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1236,8 +1360,8 @@ static struct clk_regmap gxbb_sd_emmc_b_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_names = gxbb_sd_emmc_clk0_parent_names, - .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), + .parent_data = gxbb_sd_emmc_clk0_parent_data, + .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_data), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1252,7 +1376,9 @@ static struct clk_regmap gxbb_sd_emmc_b_clk0_div = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sd_emmc_b_clk0_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1266,7 +1392,9 @@ static struct clk_regmap gxbb_sd_emmc_b_clk0 = { .hw.init = &(struct clk_init_data){ .name = "sd_emmc_b_clk0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sd_emmc_b_clk0_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1282,8 +1410,8 @@ static struct clk_regmap gxbb_sd_emmc_c_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_names = gxbb_sd_emmc_clk0_parent_names, - .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), + .parent_data = gxbb_sd_emmc_clk0_parent_data, + .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_data), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1298,7 +1426,9 @@ static struct clk_regmap gxbb_sd_emmc_c_clk0_div = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sd_emmc_c_clk0_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1312,7 +1442,9 @@ static struct clk_regmap gxbb_sd_emmc_c_clk0 = { .hw.init = &(struct clk_init_data){ .name = "sd_emmc_c_clk0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sd_emmc_c_clk0_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1320,8 +1452,11 @@ static struct clk_regmap gxbb_sd_emmc_c_clk0 = { /* VPU Clock */ -static const char * const gxbb_vpu_parent_names[] = { - "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" +static const struct clk_hw *gxbb_vpu_parent_hws[] = { + &gxbb_fclk_div4.hw, + &gxbb_fclk_div3.hw, + &gxbb_fclk_div5.hw, + &gxbb_fclk_div7.hw, }; static struct clk_regmap gxbb_vpu_0_sel = { @@ -1337,8 +1472,8 @@ static struct clk_regmap gxbb_vpu_0_sel = { * bits 9:10 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, */ - .parent_names = gxbb_vpu_parent_names, - .num_parents = ARRAY_SIZE(gxbb_vpu_parent_names), + .parent_hws = gxbb_vpu_parent_hws, + .num_parents = ARRAY_SIZE(gxbb_vpu_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -1352,7 +1487,7 @@ static struct clk_regmap gxbb_vpu_0_div = { .hw.init = &(struct clk_init_data){ .name = "vpu_0_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vpu_0_sel" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vpu_0_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1366,7 +1501,7 @@ static struct clk_regmap gxbb_vpu_0 = { .hw.init = &(struct clk_init_data) { .name = "vpu_0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vpu_0_div" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vpu_0_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1385,8 +1520,8 @@ static struct clk_regmap gxbb_vpu_1_sel = { * bits 25:26 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, */ - .parent_names = gxbb_vpu_parent_names, - .num_parents = ARRAY_SIZE(gxbb_vpu_parent_names), + .parent_hws = gxbb_vpu_parent_hws, + .num_parents = ARRAY_SIZE(gxbb_vpu_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -1400,7 +1535,7 @@ static struct clk_regmap gxbb_vpu_1_div = { .hw.init = &(struct clk_init_data){ .name = "vpu_1_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vpu_1_sel" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vpu_1_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1414,7 +1549,7 @@ static struct clk_regmap gxbb_vpu_1 = { .hw.init = &(struct clk_init_data) { .name = "vpu_1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vpu_1_div" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vpu_1_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1433,7 +1568,10 @@ static struct clk_regmap gxbb_vpu = { * bit 31 selects from 2 possible parents: * vpu_0 or vpu_1 */ - .parent_names = (const char *[]){ "vpu_0", "vpu_1" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vpu_0.hw, + &gxbb_vpu_1.hw + }, .num_parents = 2, .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -1441,8 +1579,11 @@ static struct clk_regmap gxbb_vpu = { /* VAPB Clock */ -static const char * const gxbb_vapb_parent_names[] = { - "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" +static const struct clk_hw *gxbb_vapb_parent_hws[] = { + &gxbb_fclk_div4.hw, + &gxbb_fclk_div3.hw, + &gxbb_fclk_div5.hw, + &gxbb_fclk_div7.hw, }; static struct clk_regmap gxbb_vapb_0_sel = { @@ -1458,8 +1599,8 @@ static struct clk_regmap gxbb_vapb_0_sel = { * bits 9:10 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, */ - .parent_names = gxbb_vapb_parent_names, - .num_parents = ARRAY_SIZE(gxbb_vapb_parent_names), + .parent_hws = gxbb_vapb_parent_hws, + .num_parents = ARRAY_SIZE(gxbb_vapb_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -1473,7 +1614,9 @@ static struct clk_regmap gxbb_vapb_0_div = { .hw.init = &(struct clk_init_data){ .name = "vapb_0_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vapb_0_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vapb_0_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1487,7 +1630,9 @@ static struct clk_regmap gxbb_vapb_0 = { .hw.init = &(struct clk_init_data) { .name = "vapb_0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vapb_0_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vapb_0_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1506,8 +1651,8 @@ static struct clk_regmap gxbb_vapb_1_sel = { * bits 25:26 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, */ - .parent_names = gxbb_vapb_parent_names, - .num_parents = ARRAY_SIZE(gxbb_vapb_parent_names), + .parent_hws = gxbb_vapb_parent_hws, + .num_parents = ARRAY_SIZE(gxbb_vapb_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -1521,7 +1666,9 @@ static struct clk_regmap gxbb_vapb_1_div = { .hw.init = &(struct clk_init_data){ .name = "vapb_1_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vapb_1_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vapb_1_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1535,7 +1682,9 @@ static struct clk_regmap gxbb_vapb_1 = { .hw.init = &(struct clk_init_data) { .name = "vapb_1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vapb_1_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vapb_1_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1554,7 +1703,10 @@ static struct clk_regmap gxbb_vapb_sel = { * bit 31 selects from 2 possible parents: * vapb_0 or vapb_1 */ - .parent_names = (const char *[]){ "vapb_0", "vapb_1" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vapb_0.hw, + &gxbb_vapb_1.hw + }, .num_parents = 2, .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -1568,7 +1720,7 @@ static struct clk_regmap gxbb_vapb = { .hw.init = &(struct clk_init_data) { .name = "vapb", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vapb_sel" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vapb_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1592,13 +1744,33 @@ static struct clk_regmap gxbb_vid_pll_div = { .hw.init = &(struct clk_init_data) { .name = "vid_pll_div", .ops = &meson_vid_pll_div_ro_ops, - .parent_names = (const char *[]){ "hdmi_pll" }, + .parent_data = &(const struct clk_parent_data) { + /* + * Note: + * GXL and GXBB have different hdmi_plls (with + * different struct clk_hw). We fallback to the global + * naming string mechanism so vid_pll_div picks up the + * appropriate one. + */ + .name = "hdmi_pll", + .index = -1, + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, }, }; -static const char * const gxbb_vid_pll_parent_names[] = { "vid_pll_div", "hdmi_pll" }; +static const struct clk_parent_data gxbb_vid_pll_parent_data[] = { + { .hw = &gxbb_vid_pll_div.hw }, + /* + * Note: + * GXL and GXBB have different hdmi_plls (with + * different struct clk_hw). We fallback to the global + * naming string mechanism so vid_pll_div picks up the + * appropriate one. + */ + { .name = "hdmi_pll", .index = -1 }, +}; static struct clk_regmap gxbb_vid_pll_sel = { .data = &(struct clk_regmap_mux_data){ @@ -1613,8 +1785,8 @@ static struct clk_regmap gxbb_vid_pll_sel = { * bit 18 selects from 2 possible parents: * vid_pll_div or hdmi_pll */ - .parent_names = gxbb_vid_pll_parent_names, - .num_parents = ARRAY_SIZE(gxbb_vid_pll_parent_names), + .parent_data = gxbb_vid_pll_parent_data, + .num_parents = ARRAY_SIZE(gxbb_vid_pll_parent_data), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -1627,15 +1799,22 @@ static struct clk_regmap gxbb_vid_pll = { .hw.init = &(struct clk_init_data) { .name = "vid_pll", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vid_pll_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vid_pll_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, }; -static const char * const gxbb_vclk_parent_names[] = { - "vid_pll", "fclk_div4", "fclk_div3", "fclk_div5", "vid_pll", - "fclk_div7", "mpll1", +static const struct clk_hw *gxbb_vclk_parent_hws[] = { + &gxbb_vid_pll.hw, + &gxbb_fclk_div4.hw, + &gxbb_fclk_div3.hw, + &gxbb_fclk_div5.hw, + &gxbb_vid_pll.hw, + &gxbb_fclk_div7.hw, + &gxbb_mpll1.hw, }; static struct clk_regmap gxbb_vclk_sel = { @@ -1652,8 +1831,8 @@ static struct clk_regmap gxbb_vclk_sel = { * vid_pll, fclk_div4, fclk_div3, fclk_div5, * vid_pll, fclk_div7, mp1 */ - .parent_names = gxbb_vclk_parent_names, - .num_parents = ARRAY_SIZE(gxbb_vclk_parent_names), + .parent_hws = gxbb_vclk_parent_hws, + .num_parents = ARRAY_SIZE(gxbb_vclk_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -1672,8 +1851,8 @@ static struct clk_regmap gxbb_vclk2_sel = { * vid_pll, fclk_div4, fclk_div3, fclk_div5, * vid_pll, fclk_div7, mp1 */ - .parent_names = gxbb_vclk_parent_names, - .num_parents = ARRAY_SIZE(gxbb_vclk_parent_names), + .parent_hws = gxbb_vclk_parent_hws, + .num_parents = ARRAY_SIZE(gxbb_vclk_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -1686,7 +1865,7 @@ static struct clk_regmap gxbb_vclk_input = { .hw.init = &(struct clk_init_data) { .name = "vclk_input", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk_sel" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1700,7 +1879,7 @@ static struct clk_regmap gxbb_vclk2_input = { .hw.init = &(struct clk_init_data) { .name = "vclk2_input", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk2_sel" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1715,7 +1894,9 @@ static struct clk_regmap gxbb_vclk_div = { .hw.init = &(struct clk_init_data){ .name = "vclk_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vclk_input" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk_input.hw + }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE, }, @@ -1730,7 +1911,9 @@ static struct clk_regmap gxbb_vclk2_div = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vclk2_input" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk2_input.hw + }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE, }, @@ -1744,7 +1927,7 @@ static struct clk_regmap gxbb_vclk = { .hw.init = &(struct clk_init_data) { .name = "vclk", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk_div" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1758,7 +1941,7 @@ static struct clk_regmap gxbb_vclk2 = { .hw.init = &(struct clk_init_data) { .name = "vclk2", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk2_div" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1772,7 +1955,7 @@ static struct clk_regmap gxbb_vclk_div1 = { .hw.init = &(struct clk_init_data) { .name = "vclk_div1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1786,7 +1969,7 @@ static struct clk_regmap gxbb_vclk_div2_en = { .hw.init = &(struct clk_init_data) { .name = "vclk_div2_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1800,7 +1983,7 @@ static struct clk_regmap gxbb_vclk_div4_en = { .hw.init = &(struct clk_init_data) { .name = "vclk_div4_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1814,7 +1997,7 @@ static struct clk_regmap gxbb_vclk_div6_en = { .hw.init = &(struct clk_init_data) { .name = "vclk_div6_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1828,7 +2011,7 @@ static struct clk_regmap gxbb_vclk_div12_en = { .hw.init = &(struct clk_init_data) { .name = "vclk_div12_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1842,7 +2025,7 @@ static struct clk_regmap gxbb_vclk2_div1 = { .hw.init = &(struct clk_init_data) { .name = "vclk2_div1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk2" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1856,7 +2039,7 @@ static struct clk_regmap gxbb_vclk2_div2_en = { .hw.init = &(struct clk_init_data) { .name = "vclk2_div2_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk2" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1870,7 +2053,7 @@ static struct clk_regmap gxbb_vclk2_div4_en = { .hw.init = &(struct clk_init_data) { .name = "vclk2_div4_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk2" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1884,7 +2067,7 @@ static struct clk_regmap gxbb_vclk2_div6_en = { .hw.init = &(struct clk_init_data) { .name = "vclk2_div6_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk2" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1898,7 +2081,7 @@ static struct clk_regmap gxbb_vclk2_div12_en = { .hw.init = &(struct clk_init_data) { .name = "vclk2_div12_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vclk2" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -1910,7 +2093,9 @@ static struct clk_fixed_factor gxbb_vclk_div2 = { .hw.init = &(struct clk_init_data){ .name = "vclk_div2", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk_div2_en" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk_div2_en.hw + }, .num_parents = 1, }, }; @@ -1921,7 +2106,9 @@ static struct clk_fixed_factor gxbb_vclk_div4 = { .hw.init = &(struct clk_init_data){ .name = "vclk_div4", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk_div4_en" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk_div4_en.hw + }, .num_parents = 1, }, }; @@ -1932,7 +2119,9 @@ static struct clk_fixed_factor gxbb_vclk_div6 = { .hw.init = &(struct clk_init_data){ .name = "vclk_div6", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk_div6_en" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk_div6_en.hw + }, .num_parents = 1, }, }; @@ -1943,7 +2132,9 @@ static struct clk_fixed_factor gxbb_vclk_div12 = { .hw.init = &(struct clk_init_data){ .name = "vclk_div12", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk_div12_en" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk_div12_en.hw + }, .num_parents = 1, }, }; @@ -1954,7 +2145,9 @@ static struct clk_fixed_factor gxbb_vclk2_div2 = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div2", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk2_div2_en" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk2_div2_en.hw + }, .num_parents = 1, }, }; @@ -1965,7 +2158,9 @@ static struct clk_fixed_factor gxbb_vclk2_div4 = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div4", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk2_div4_en" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk2_div4_en.hw + }, .num_parents = 1, }, }; @@ -1976,7 +2171,9 @@ static struct clk_fixed_factor gxbb_vclk2_div6 = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div6", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk2_div6_en" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk2_div6_en.hw + }, .num_parents = 1, }, }; @@ -1987,16 +2184,25 @@ static struct clk_fixed_factor gxbb_vclk2_div12 = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div12", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk2_div12_en" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk2_div12_en.hw + }, .num_parents = 1, }, }; static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; -static const char * const gxbb_cts_parent_names[] = { - "vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6", - "vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4", - "vclk2_div6", "vclk2_div12" +static const struct clk_hw *gxbb_cts_parent_hws[] = { + &gxbb_vclk_div1.hw, + &gxbb_vclk_div2.hw, + &gxbb_vclk_div4.hw, + &gxbb_vclk_div6.hw, + &gxbb_vclk_div12.hw, + &gxbb_vclk2_div1.hw, + &gxbb_vclk2_div2.hw, + &gxbb_vclk2_div4.hw, + &gxbb_vclk2_div6.hw, + &gxbb_vclk2_div12.hw, }; static struct clk_regmap gxbb_cts_enci_sel = { @@ -2009,8 +2215,8 @@ static struct clk_regmap gxbb_cts_enci_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_enci_sel", .ops = &clk_regmap_mux_ops, - .parent_names = gxbb_cts_parent_names, - .num_parents = ARRAY_SIZE(gxbb_cts_parent_names), + .parent_hws = gxbb_cts_parent_hws, + .num_parents = ARRAY_SIZE(gxbb_cts_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -2025,8 +2231,8 @@ static struct clk_regmap gxbb_cts_encp_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_encp_sel", .ops = &clk_regmap_mux_ops, - .parent_names = gxbb_cts_parent_names, - .num_parents = ARRAY_SIZE(gxbb_cts_parent_names), + .parent_hws = gxbb_cts_parent_hws, + .num_parents = ARRAY_SIZE(gxbb_cts_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -2041,18 +2247,25 @@ static struct clk_regmap gxbb_cts_vdac_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_vdac_sel", .ops = &clk_regmap_mux_ops, - .parent_names = gxbb_cts_parent_names, - .num_parents = ARRAY_SIZE(gxbb_cts_parent_names), + .parent_hws = gxbb_cts_parent_hws, + .num_parents = ARRAY_SIZE(gxbb_cts_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; /* TOFIX: add support for cts_tcon */ static u32 mux_table_hdmi_tx_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; -static const char * const gxbb_cts_hdmi_tx_parent_names[] = { - "vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6", - "vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4", - "vclk2_div6", "vclk2_div12" +static const struct clk_hw *gxbb_cts_hdmi_tx_parent_hws[] = { + &gxbb_vclk_div1.hw, + &gxbb_vclk_div2.hw, + &gxbb_vclk_div4.hw, + &gxbb_vclk_div6.hw, + &gxbb_vclk_div12.hw, + &gxbb_vclk2_div1.hw, + &gxbb_vclk2_div2.hw, + &gxbb_vclk2_div4.hw, + &gxbb_vclk2_div6.hw, + &gxbb_vclk2_div12.hw, }; static struct clk_regmap gxbb_hdmi_tx_sel = { @@ -2071,8 +2284,8 @@ static struct clk_regmap gxbb_hdmi_tx_sel = { * vclk2_div1, vclk2_div2, vclk2_div4, vclk2_div6, vclk2_div12, * cts_tcon */ - .parent_names = gxbb_cts_hdmi_tx_parent_names, - .num_parents = ARRAY_SIZE(gxbb_cts_hdmi_tx_parent_names), + .parent_hws = gxbb_cts_hdmi_tx_parent_hws, + .num_parents = ARRAY_SIZE(gxbb_cts_hdmi_tx_parent_hws), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -2085,7 +2298,9 @@ static struct clk_regmap gxbb_cts_enci = { .hw.init = &(struct clk_init_data) { .name = "cts_enci", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "cts_enci_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_cts_enci_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2099,7 +2314,9 @@ static struct clk_regmap gxbb_cts_encp = { .hw.init = &(struct clk_init_data) { .name = "cts_encp", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "cts_encp_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_cts_encp_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2113,7 +2330,9 @@ static struct clk_regmap gxbb_cts_vdac = { .hw.init = &(struct clk_init_data) { .name = "cts_vdac", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "cts_vdac_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_cts_vdac_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2127,7 +2346,9 @@ static struct clk_regmap gxbb_hdmi_tx = { .hw.init = &(struct clk_init_data) { .name = "hdmi_tx", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "hdmi_tx_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_hdmi_tx_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2135,8 +2356,11 @@ static struct clk_regmap gxbb_hdmi_tx = { /* HDMI Clocks */ -static const char * const gxbb_hdmi_parent_names[] = { - IN_PREFIX "xtal", "fclk_div4", "fclk_div3", "fclk_div5" +static const struct clk_parent_data gxbb_hdmi_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &gxbb_fclk_div4.hw }, + { .hw = &gxbb_fclk_div3.hw }, + { .hw = &gxbb_fclk_div5.hw }, }; static struct clk_regmap gxbb_hdmi_sel = { @@ -2149,8 +2373,8 @@ static struct clk_regmap gxbb_hdmi_sel = { .hw.init = &(struct clk_init_data){ .name = "hdmi_sel", .ops = &clk_regmap_mux_ops, - .parent_names = gxbb_hdmi_parent_names, - .num_parents = ARRAY_SIZE(gxbb_hdmi_parent_names), + .parent_data = gxbb_hdmi_parent_data, + .num_parents = ARRAY_SIZE(gxbb_hdmi_parent_data), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -2164,7 +2388,7 @@ static struct clk_regmap gxbb_hdmi_div = { .hw.init = &(struct clk_init_data){ .name = "hdmi_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "hdmi_sel" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_hdmi_sel.hw }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE, }, @@ -2178,7 +2402,7 @@ static struct clk_regmap gxbb_hdmi = { .hw.init = &(struct clk_init_data) { .name = "hdmi", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "hdmi_div" }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_hdmi_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, @@ -2186,8 +2410,11 @@ static struct clk_regmap gxbb_hdmi = { /* VDEC clocks */ -static const char * const gxbb_vdec_parent_names[] = { - "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" +static const struct clk_hw *gxbb_vdec_parent_hws[] = { + &gxbb_fclk_div4.hw, + &gxbb_fclk_div3.hw, + &gxbb_fclk_div5.hw, + &gxbb_fclk_div7.hw, }; static struct clk_regmap gxbb_vdec_1_sel = { @@ -2200,8 +2427,8 @@ static struct clk_regmap gxbb_vdec_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_1_sel", .ops = &clk_regmap_mux_ops, - .parent_names = gxbb_vdec_parent_names, - .num_parents = ARRAY_SIZE(gxbb_vdec_parent_names), + .parent_hws = gxbb_vdec_parent_hws, + .num_parents = ARRAY_SIZE(gxbb_vdec_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2216,7 +2443,9 @@ static struct clk_regmap gxbb_vdec_1_div = { .hw.init = &(struct clk_init_data){ .name = "vdec_1_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vdec_1_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vdec_1_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2230,7 +2459,9 @@ static struct clk_regmap gxbb_vdec_1 = { .hw.init = &(struct clk_init_data) { .name = "vdec_1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vdec_1_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vdec_1_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2246,8 +2477,8 @@ static struct clk_regmap gxbb_vdec_hevc_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_hevc_sel", .ops = &clk_regmap_mux_ops, - .parent_names = gxbb_vdec_parent_names, - .num_parents = ARRAY_SIZE(gxbb_vdec_parent_names), + .parent_hws = gxbb_vdec_parent_hws, + .num_parents = ARRAY_SIZE(gxbb_vdec_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2262,7 +2493,9 @@ static struct clk_regmap gxbb_vdec_hevc_div = { .hw.init = &(struct clk_init_data){ .name = "vdec_hevc_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vdec_hevc_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vdec_hevc_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2276,7 +2509,9 @@ static struct clk_regmap gxbb_vdec_hevc = { .hw.init = &(struct clk_init_data) { .name = "vdec_hevc", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vdec_hevc_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vdec_hevc_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2284,9 +2519,18 @@ static struct clk_regmap gxbb_vdec_hevc = { static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, }; -static const char * const gen_clk_parent_names[] = { - IN_PREFIX "xtal", "vdec_1", "vdec_hevc", "mpll0", "mpll1", "mpll2", - "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "gp0_pll", +static const struct clk_parent_data gen_clk_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &gxbb_vdec_1.hw }, + { .hw = &gxbb_vdec_hevc.hw }, + { .hw = &gxbb_mpll0.hw }, + { .hw = &gxbb_mpll1.hw }, + { .hw = &gxbb_mpll2.hw }, + { .hw = &gxbb_fclk_div4.hw }, + { .hw = &gxbb_fclk_div3.hw }, + { .hw = &gxbb_fclk_div5.hw }, + { .hw = &gxbb_fclk_div7.hw }, + { .hw = &gxbb_gp0_pll.hw }, }; static struct clk_regmap gxbb_gen_clk_sel = { @@ -2305,8 +2549,8 @@ static struct clk_regmap gxbb_gen_clk_sel = { * vid_pll, vid2_pll (hevc), mpll0, mpll1, mpll2, fdiv4, * fdiv3, fdiv5, [cts_msr_clk], fdiv7, gp0_pll */ - .parent_names = gen_clk_parent_names, - .num_parents = ARRAY_SIZE(gen_clk_parent_names), + .parent_data = gen_clk_parent_data, + .num_parents = ARRAY_SIZE(gen_clk_parent_data), }, }; @@ -2319,7 +2563,9 @@ static struct clk_regmap gxbb_gen_clk_div = { .hw.init = &(struct clk_init_data){ .name = "gen_clk_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "gen_clk_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_gen_clk_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2333,12 +2579,17 @@ static struct clk_regmap gxbb_gen_clk = { .hw.init = &(struct clk_init_data){ .name = "gen_clk", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "gen_clk_div" }, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_gen_clk_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; +#define MESON_GATE(_name, _reg, _bit) \ + MESON_PCLK(_name, _reg, _bit, &gxbb_clk81.hw) + /* Everything Else (EE) domain gates */ static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0); static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1); diff --git a/drivers/clk/meson/meson-aoclk.c b/drivers/clk/meson/meson-aoclk.c index b67951909e04955730cddb6d0f252a95980f867d..bf8bea675d2437611a8d4b569a739f641bb38f2e 100644 --- a/drivers/clk/meson/meson-aoclk.c +++ b/drivers/clk/meson/meson-aoclk.c @@ -17,8 +17,6 @@ #include #include "meson-aoclk.h" -#include "clk-input.h" - static int meson_aoclk_do_reset(struct reset_controller_dev *rcdev, unsigned long id) { @@ -33,37 +31,6 @@ static const struct reset_control_ops meson_aoclk_reset_ops = { .reset = meson_aoclk_do_reset, }; -static int meson_aoclkc_register_inputs(struct device *dev, - struct meson_aoclk_data *data) -{ - struct clk_hw *hw; - char *str; - int i; - - for (i = 0; i < data->num_inputs; i++) { - const struct meson_aoclk_input *in = &data->inputs[i]; - - str = kasprintf(GFP_KERNEL, "%s%s", data->input_prefix, - in->name); - if (!str) - return -ENOMEM; - - hw = meson_clk_hw_register_input(dev, in->name, str, 0); - kfree(str); - - if (IS_ERR(hw)) { - if (!in->required && PTR_ERR(hw) == -ENOENT) - continue; - else if (PTR_ERR(hw) != -EPROBE_DEFER) - dev_err(dev, "failed to register input %s\n", - in->name); - return PTR_ERR(hw); - } - } - - return 0; -} - int meson_aoclkc_probe(struct platform_device *pdev) { struct meson_aoclk_reset_controller *rstc; @@ -86,10 +53,6 @@ int meson_aoclkc_probe(struct platform_device *pdev) return PTR_ERR(regmap); } - ret = meson_aoclkc_register_inputs(dev, data); - if (ret) - return ret; - /* Reset Controller */ rstc->data = data; rstc->regmap = regmap; diff --git a/drivers/clk/meson/meson-aoclk.h b/drivers/clk/meson/meson-aoclk.h index 999cde3868f7f38982c2a7bebe12b8ee352551ec..605b43855a6998dd07e6fdd5735ebf4fb070d9c0 100644 --- a/drivers/clk/meson/meson-aoclk.h +++ b/drivers/clk/meson/meson-aoclk.h @@ -18,20 +18,12 @@ #include "clk-regmap.h" -struct meson_aoclk_input { - const char *name; - bool required; -}; - struct meson_aoclk_data { const unsigned int reset_reg; const int num_reset; const unsigned int *reset; const int num_clks; struct clk_regmap **clks; - const int num_inputs; - const struct meson_aoclk_input *inputs; - const char *input_prefix; const struct clk_hw_onecell_data *hw_data; }; diff --git a/drivers/clk/meson/meson-eeclk.c b/drivers/clk/meson/meson-eeclk.c index 6ba2094be257772d3328ab0ffdfd4dfcbb2a0ea2..a7cb1e7aedc463f83df2008a47aedd39bd53cfd6 100644 --- a/drivers/clk/meson/meson-eeclk.c +++ b/drivers/clk/meson/meson-eeclk.c @@ -10,7 +10,6 @@ #include #include -#include "clk-input.h" #include "clk-regmap.h" #include "meson-eeclk.h" @@ -18,7 +17,6 @@ int meson_eeclkc_probe(struct platform_device *pdev) { const struct meson_eeclkc_data *data; struct device *dev = &pdev->dev; - struct clk_hw *input; struct regmap *map; int ret, i; @@ -37,14 +35,6 @@ int meson_eeclkc_probe(struct platform_device *pdev) if (data->init_count) regmap_multi_reg_write(map, data->init_regs, data->init_count); - input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0); - if (IS_ERR(input)) { - ret = PTR_ERR(input); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get input clock"); - return ret; - } - /* Populate regmap for the regmap backed clocks */ for (i = 0; i < data->regmap_clk_num; i++) data->regmap_clks[i]->map = map; diff --git a/drivers/clk/meson/meson-eeclk.h b/drivers/clk/meson/meson-eeclk.h index 9ab5d6fa7ccb26adf3084bad886e9e7f4670f83b..77316207bde19c623f613678cc024425b878e144 100644 --- a/drivers/clk/meson/meson-eeclk.h +++ b/drivers/clk/meson/meson-eeclk.h @@ -10,8 +10,6 @@ #include #include "clk-regmap.h" -#define IN_PREFIX "ee-in-" - struct platform_device; struct meson_eeclkc_data { diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 537219fa573ea330f4323991c290d50a2459c7f2..67e6691e080c111ce8784818aa1aac9a4284ea2b 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -97,7 +97,9 @@ static struct clk_regmap meson8b_fixed_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_xtal.hw + }, .num_parents = 1, }, }; @@ -112,7 +114,9 @@ static struct clk_regmap meson8b_fixed_pll = { .hw.init = &(struct clk_init_data){ .name = "fixed_pll", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "fixed_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fixed_pll_dco.hw + }, .num_parents = 1, /* * This clock won't ever change at runtime so @@ -158,7 +162,9 @@ static struct clk_regmap meson8b_hdmi_pll_dco = { /* sometimes also called "HPLL" or "HPLL PLL" */ .name = "hdmi_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_xtal.hw + }, .num_parents = 1, }, }; @@ -173,7 +179,9 @@ static struct clk_regmap meson8b_hdmi_pll_lvds_out = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_lvds_out", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "hdmi_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_hdmi_pll_dco.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -189,7 +197,9 @@ static struct clk_regmap meson8b_hdmi_pll_hdmi_out = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_hdmi_out", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "hdmi_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_hdmi_pll_dco.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -227,7 +237,9 @@ static struct clk_regmap meson8b_sys_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "sys_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_xtal.hw + }, .num_parents = 1, }, }; @@ -242,7 +254,9 @@ static struct clk_regmap meson8b_sys_pll = { .hw.init = &(struct clk_init_data){ .name = "sys_pll", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "sys_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_sys_pll_dco.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -254,7 +268,9 @@ static struct clk_fixed_factor meson8b_fclk_div2_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div2_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fixed_pll.hw + }, .num_parents = 1, }, }; @@ -267,7 +283,9 @@ static struct clk_regmap meson8b_fclk_div2 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div2", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div2_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fclk_div2_div.hw + }, .num_parents = 1, /* * FIXME: Ethernet with a RGMII PHYs is not working if @@ -285,7 +303,9 @@ static struct clk_fixed_factor meson8b_fclk_div3_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div3_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fixed_pll.hw + }, .num_parents = 1, }, }; @@ -298,7 +318,9 @@ static struct clk_regmap meson8b_fclk_div3 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div3", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div3_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fclk_div3_div.hw + }, .num_parents = 1, }, }; @@ -309,7 +331,9 @@ static struct clk_fixed_factor meson8b_fclk_div4_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div4_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fixed_pll.hw + }, .num_parents = 1, }, }; @@ -322,7 +346,9 @@ static struct clk_regmap meson8b_fclk_div4 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div4", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div4_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fclk_div4_div.hw + }, .num_parents = 1, }, }; @@ -333,7 +359,9 @@ static struct clk_fixed_factor meson8b_fclk_div5_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div5_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fixed_pll.hw + }, .num_parents = 1, }, }; @@ -346,7 +374,9 @@ static struct clk_regmap meson8b_fclk_div5 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div5", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div5_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fclk_div5_div.hw + }, .num_parents = 1, }, }; @@ -357,7 +387,9 @@ static struct clk_fixed_factor meson8b_fclk_div7_div = { .hw.init = &(struct clk_init_data){ .name = "fclk_div7_div", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fixed_pll.hw + }, .num_parents = 1, }, }; @@ -370,7 +402,9 @@ static struct clk_regmap meson8b_fclk_div7 = { .hw.init = &(struct clk_init_data){ .name = "fclk_div7", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div7_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fclk_div7_div.hw + }, .num_parents = 1, }, }; @@ -384,7 +418,9 @@ static struct clk_regmap meson8b_mpll_prediv = { .hw.init = &(struct clk_init_data){ .name = "mpll_prediv", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fixed_pll.hw + }, .num_parents = 1, }, }; @@ -416,7 +452,9 @@ static struct clk_regmap meson8b_mpll0_div = { .hw.init = &(struct clk_init_data){ .name = "mpll0_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "mpll_prediv" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mpll_prediv.hw + }, .num_parents = 1, }, }; @@ -429,7 +467,9 @@ static struct clk_regmap meson8b_mpll0 = { .hw.init = &(struct clk_init_data){ .name = "mpll0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpll0_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mpll0_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -457,7 +497,9 @@ static struct clk_regmap meson8b_mpll1_div = { .hw.init = &(struct clk_init_data){ .name = "mpll1_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "mpll_prediv" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mpll_prediv.hw + }, .num_parents = 1, }, }; @@ -470,7 +512,9 @@ static struct clk_regmap meson8b_mpll1 = { .hw.init = &(struct clk_init_data){ .name = "mpll1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpll1_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mpll1_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -498,7 +542,9 @@ static struct clk_regmap meson8b_mpll2_div = { .hw.init = &(struct clk_init_data){ .name = "mpll2_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "mpll_prediv" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mpll_prediv.hw + }, .num_parents = 1, }, }; @@ -511,7 +557,9 @@ static struct clk_regmap meson8b_mpll2 = { .hw.init = &(struct clk_init_data){ .name = "mpll2", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpll2_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mpll2_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -533,8 +581,11 @@ static struct clk_regmap meson8b_mpeg_clk_sel = { * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, * fclk_div4, fclk_div3, fclk_div5 */ - .parent_names = (const char *[]){ "fclk_div3", "fclk_div4", - "fclk_div5" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fclk_div3.hw, + &meson8b_fclk_div4.hw, + &meson8b_fclk_div5.hw, + }, .num_parents = 3, }, }; @@ -548,7 +599,9 @@ static struct clk_regmap meson8b_mpeg_clk_div = { .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "mpeg_clk_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mpeg_clk_sel.hw + }, .num_parents = 1, }, }; @@ -561,7 +614,9 @@ static struct clk_regmap meson8b_clk81 = { .hw.init = &(struct clk_init_data){ .name = "clk81", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mpeg_clk_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mpeg_clk_div.hw + }, .num_parents = 1, .flags = CLK_IS_CRITICAL, }, @@ -576,7 +631,10 @@ static struct clk_regmap meson8b_cpu_in_sel = { .hw.init = &(struct clk_init_data){ .name = "cpu_in_sel", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "xtal", "sys_pll" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_xtal.hw, + &meson8b_sys_pll.hw, + }, .num_parents = 2, .flags = (CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), @@ -589,7 +647,9 @@ static struct clk_fixed_factor meson8b_cpu_in_div2 = { .hw.init = &(struct clk_init_data){ .name = "cpu_in_div2", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpu_in_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_in_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -601,7 +661,9 @@ static struct clk_fixed_factor meson8b_cpu_in_div3 = { .hw.init = &(struct clk_init_data){ .name = "cpu_in_div3", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpu_in_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_in_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -630,7 +692,9 @@ static struct clk_regmap meson8b_cpu_scale_div = { .hw.init = &(struct clk_init_data){ .name = "cpu_scale_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "cpu_in_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_in_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -649,13 +713,15 @@ static struct clk_regmap meson8b_cpu_scale_out_sel = { .ops = &clk_regmap_mux_ops, /* * NOTE: We are skipping the parent with value 0x2 (which is - * "cpu_in_div3") because it results in a duty cycle of 33% - * which makes the system unstable and can result in a lockup - * of the whole system. + * meson8b_cpu_in_div3) because it results in a duty cycle of + * 33% which makes the system unstable and can result in a + * lockup of the whole system. */ - .parent_names = (const char *[]) { "cpu_in_sel", - "cpu_in_div2", - "cpu_scale_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_in_sel.hw, + &meson8b_cpu_in_div2.hw, + &meson8b_cpu_scale_div.hw, + }, .num_parents = 3, .flags = CLK_SET_RATE_PARENT, }, @@ -670,8 +736,10 @@ static struct clk_regmap meson8b_cpu_clk = { .hw.init = &(struct clk_init_data){ .name = "cpu_clk", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "xtal", - "cpu_scale_out_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_xtal.hw, + &meson8b_cpu_scale_out_sel.hw, + }, .num_parents = 2, .flags = (CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | @@ -690,8 +758,13 @@ static struct clk_regmap meson8b_nand_clk_sel = { .name = "nand_clk_sel", .ops = &clk_regmap_mux_ops, /* FIXME all other parents are unknown: */ - .parent_names = (const char *[]){ "fclk_div4", "fclk_div3", - "fclk_div5", "fclk_div7", "xtal" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fclk_div4.hw, + &meson8b_fclk_div3.hw, + &meson8b_fclk_div5.hw, + &meson8b_fclk_div7.hw, + &meson8b_xtal.hw, + }, .num_parents = 5, .flags = CLK_SET_RATE_PARENT, }, @@ -707,7 +780,9 @@ static struct clk_regmap meson8b_nand_clk_div = { .hw.init = &(struct clk_init_data){ .name = "nand_clk_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "nand_clk_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_nand_clk_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -721,7 +796,9 @@ static struct clk_regmap meson8b_nand_clk_gate = { .hw.init = &(struct clk_init_data){ .name = "nand_clk_gate", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "nand_clk_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_nand_clk_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -733,7 +810,9 @@ static struct clk_fixed_factor meson8b_cpu_clk_div2 = { .hw.init = &(struct clk_init_data){ .name = "cpu_clk_div2", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpu_clk" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk.hw + }, .num_parents = 1, }, }; @@ -744,7 +823,9 @@ static struct clk_fixed_factor meson8b_cpu_clk_div3 = { .hw.init = &(struct clk_init_data){ .name = "cpu_clk_div3", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpu_clk" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk.hw + }, .num_parents = 1, }, }; @@ -755,7 +836,9 @@ static struct clk_fixed_factor meson8b_cpu_clk_div4 = { .hw.init = &(struct clk_init_data){ .name = "cpu_clk_div4", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpu_clk" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk.hw + }, .num_parents = 1, }, }; @@ -766,7 +849,9 @@ static struct clk_fixed_factor meson8b_cpu_clk_div5 = { .hw.init = &(struct clk_init_data){ .name = "cpu_clk_div5", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpu_clk" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk.hw + }, .num_parents = 1, }, }; @@ -777,7 +862,9 @@ static struct clk_fixed_factor meson8b_cpu_clk_div6 = { .hw.init = &(struct clk_init_data){ .name = "cpu_clk_div6", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpu_clk" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk.hw + }, .num_parents = 1, }, }; @@ -788,7 +875,9 @@ static struct clk_fixed_factor meson8b_cpu_clk_div7 = { .hw.init = &(struct clk_init_data){ .name = "cpu_clk_div7", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpu_clk" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk.hw + }, .num_parents = 1, }, }; @@ -799,7 +888,9 @@ static struct clk_fixed_factor meson8b_cpu_clk_div8 = { .hw.init = &(struct clk_init_data){ .name = "cpu_clk_div8", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "cpu_clk" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk.hw + }, .num_parents = 1, }, }; @@ -815,13 +906,15 @@ static struct clk_regmap meson8b_apb_clk_sel = { .hw.init = &(struct clk_init_data){ .name = "apb_clk_sel", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "cpu_clk_div2", - "cpu_clk_div3", - "cpu_clk_div4", - "cpu_clk_div5", - "cpu_clk_div6", - "cpu_clk_div7", - "cpu_clk_div8", }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk_div2.hw, + &meson8b_cpu_clk_div3.hw, + &meson8b_cpu_clk_div4.hw, + &meson8b_cpu_clk_div5.hw, + &meson8b_cpu_clk_div6.hw, + &meson8b_cpu_clk_div7.hw, + &meson8b_cpu_clk_div8.hw, + }, .num_parents = 7, }, }; @@ -835,7 +928,9 @@ static struct clk_regmap meson8b_apb_clk_gate = { .hw.init = &(struct clk_init_data){ .name = "apb_clk_dis", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "apb_clk_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_apb_clk_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -850,13 +945,15 @@ static struct clk_regmap meson8b_periph_clk_sel = { .hw.init = &(struct clk_init_data){ .name = "periph_clk_sel", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "cpu_clk_div2", - "cpu_clk_div3", - "cpu_clk_div4", - "cpu_clk_div5", - "cpu_clk_div6", - "cpu_clk_div7", - "cpu_clk_div8", }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk_div2.hw, + &meson8b_cpu_clk_div3.hw, + &meson8b_cpu_clk_div4.hw, + &meson8b_cpu_clk_div5.hw, + &meson8b_cpu_clk_div6.hw, + &meson8b_cpu_clk_div7.hw, + &meson8b_cpu_clk_div8.hw, + }, .num_parents = 7, }, }; @@ -870,7 +967,9 @@ static struct clk_regmap meson8b_periph_clk_gate = { .hw.init = &(struct clk_init_data){ .name = "periph_clk_dis", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "periph_clk_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_periph_clk_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -887,13 +986,15 @@ static struct clk_regmap meson8b_axi_clk_sel = { .hw.init = &(struct clk_init_data){ .name = "axi_clk_sel", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "cpu_clk_div2", - "cpu_clk_div3", - "cpu_clk_div4", - "cpu_clk_div5", - "cpu_clk_div6", - "cpu_clk_div7", - "cpu_clk_div8", }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk_div2.hw, + &meson8b_cpu_clk_div3.hw, + &meson8b_cpu_clk_div4.hw, + &meson8b_cpu_clk_div5.hw, + &meson8b_cpu_clk_div6.hw, + &meson8b_cpu_clk_div7.hw, + &meson8b_cpu_clk_div8.hw, + }, .num_parents = 7, }, }; @@ -907,7 +1008,9 @@ static struct clk_regmap meson8b_axi_clk_gate = { .hw.init = &(struct clk_init_data){ .name = "axi_clk_dis", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "axi_clk_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_axi_clk_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -922,13 +1025,15 @@ static struct clk_regmap meson8b_l2_dram_clk_sel = { .hw.init = &(struct clk_init_data){ .name = "l2_dram_clk_sel", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "cpu_clk_div2", - "cpu_clk_div3", - "cpu_clk_div4", - "cpu_clk_div5", - "cpu_clk_div6", - "cpu_clk_div7", - "cpu_clk_div8", }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk_div2.hw, + &meson8b_cpu_clk_div3.hw, + &meson8b_cpu_clk_div4.hw, + &meson8b_cpu_clk_div5.hw, + &meson8b_cpu_clk_div6.hw, + &meson8b_cpu_clk_div7.hw, + &meson8b_cpu_clk_div8.hw, + }, .num_parents = 7, }, }; @@ -942,7 +1047,9 @@ static struct clk_regmap meson8b_l2_dram_clk_gate = { .hw.init = &(struct clk_init_data){ .name = "l2_dram_clk_dis", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "l2_dram_clk_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_l2_dram_clk_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -963,7 +1070,9 @@ static struct clk_regmap meson8b_vid_pll_in_sel = { * Meson8b: hdmi_pll_dco * Meson8m2: vid2_pll */ - .parent_names = (const char *[]){ "hdmi_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_hdmi_pll_dco.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -977,7 +1086,9 @@ static struct clk_regmap meson8b_vid_pll_in_en = { .hw.init = &(struct clk_init_data){ .name = "vid_pll_in_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "vid_pll_in_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vid_pll_in_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -992,7 +1103,9 @@ static struct clk_regmap meson8b_vid_pll_pre_div = { .hw.init = &(struct clk_init_data){ .name = "vid_pll_pre_div", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "vid_pll_in_en" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vid_pll_in_en.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1007,7 +1120,9 @@ static struct clk_regmap meson8b_vid_pll_post_div = { .hw.init = &(struct clk_init_data){ .name = "vid_pll_post_div", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "vid_pll_pre_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vid_pll_pre_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1023,8 +1138,10 @@ static struct clk_regmap meson8b_vid_pll = { .name = "vid_pll", .ops = &clk_regmap_mux_ro_ops, /* TODO: parent 0x2 is vid_pll_pre_div_mult7_div2 */ - .parent_names = (const char *[]){ "vid_pll_pre_div", - "vid_pll_post_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vid_pll_pre_div.hw, + &meson8b_vid_pll_post_div.hw, + }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, @@ -1039,15 +1156,22 @@ static struct clk_regmap meson8b_vid_pll_final_div = { .hw.init = &(struct clk_init_data){ .name = "vid_pll_final_div", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "vid_pll" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vid_pll.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const char * const meson8b_vclk_mux_parents[] = { - "vid_pll_final_div", "fclk_div4", "fclk_div3", "fclk_div5", - "vid_pll_final_div", "fclk_div7", "mpll1" +static const struct clk_hw *meson8b_vclk_mux_parent_hws[] = { + &meson8b_vid_pll_final_div.hw, + &meson8b_fclk_div4.hw, + &meson8b_fclk_div3.hw, + &meson8b_fclk_div5.hw, + &meson8b_vid_pll_final_div.hw, + &meson8b_fclk_div7.hw, + &meson8b_mpll1.hw, }; static struct clk_regmap meson8b_vclk_in_sel = { @@ -1059,8 +1183,8 @@ static struct clk_regmap meson8b_vclk_in_sel = { .hw.init = &(struct clk_init_data){ .name = "vclk_in_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_names = meson8b_vclk_mux_parents, - .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parents), + .parent_hws = meson8b_vclk_mux_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1073,7 +1197,9 @@ static struct clk_regmap meson8b_vclk_in_en = { .hw.init = &(struct clk_init_data){ .name = "vclk_in_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "vclk_in_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_in_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1087,7 +1213,9 @@ static struct clk_regmap meson8b_vclk_div1_gate = { .hw.init = &(struct clk_init_data){ .name = "vclk_div1_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "vclk_in_en" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_in_en.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1099,7 +1227,9 @@ static struct clk_fixed_factor meson8b_vclk_div2_div = { .hw.init = &(struct clk_init_data){ .name = "vclk_div2", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk_in_en" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_in_en.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, } @@ -1113,7 +1243,9 @@ static struct clk_regmap meson8b_vclk_div2_div_gate = { .hw.init = &(struct clk_init_data){ .name = "vclk_div2_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "vclk_div2" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_div2_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1125,7 +1257,9 @@ static struct clk_fixed_factor meson8b_vclk_div4_div = { .hw.init = &(struct clk_init_data){ .name = "vclk_div4", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk_in_en" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_in_en.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, } @@ -1139,7 +1273,9 @@ static struct clk_regmap meson8b_vclk_div4_div_gate = { .hw.init = &(struct clk_init_data){ .name = "vclk_div4_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "vclk_div4" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_div4_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1151,7 +1287,9 @@ static struct clk_fixed_factor meson8b_vclk_div6_div = { .hw.init = &(struct clk_init_data){ .name = "vclk_div6", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk_in_en" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_in_en.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, } @@ -1165,7 +1303,9 @@ static struct clk_regmap meson8b_vclk_div6_div_gate = { .hw.init = &(struct clk_init_data){ .name = "vclk_div6_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "vclk_div6" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_div6_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1177,7 +1317,9 @@ static struct clk_fixed_factor meson8b_vclk_div12_div = { .hw.init = &(struct clk_init_data){ .name = "vclk_div12", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk_in_en" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_in_en.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, } @@ -1191,7 +1333,9 @@ static struct clk_regmap meson8b_vclk_div12_div_gate = { .hw.init = &(struct clk_init_data){ .name = "vclk_div12_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "vclk_div12" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_div12_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1206,8 +1350,8 @@ static struct clk_regmap meson8b_vclk2_in_sel = { .hw.init = &(struct clk_init_data){ .name = "vclk2_in_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_names = meson8b_vclk_mux_parents, - .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parents), + .parent_hws = meson8b_vclk_mux_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1220,7 +1364,9 @@ static struct clk_regmap meson8b_vclk2_clk_in_en = { .hw.init = &(struct clk_init_data){ .name = "vclk2_in_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "vclk2_in_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_in_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1234,7 +1380,9 @@ static struct clk_regmap meson8b_vclk2_div1_gate = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div1_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "vclk2_in_en" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_clk_in_en.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1246,7 +1394,9 @@ static struct clk_fixed_factor meson8b_vclk2_div2_div = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div2", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk2_in_en" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_clk_in_en.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, } @@ -1260,7 +1410,9 @@ static struct clk_regmap meson8b_vclk2_div2_div_gate = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div2_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "vclk2_div2" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_div2_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1272,7 +1424,9 @@ static struct clk_fixed_factor meson8b_vclk2_div4_div = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div4", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk2_in_en" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_clk_in_en.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, } @@ -1286,7 +1440,9 @@ static struct clk_regmap meson8b_vclk2_div4_div_gate = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div4_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "vclk2_div4" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_div4_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1298,7 +1454,9 @@ static struct clk_fixed_factor meson8b_vclk2_div6_div = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div6", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk2_in_en" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_clk_in_en.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, } @@ -1312,7 +1470,9 @@ static struct clk_regmap meson8b_vclk2_div6_div_gate = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div6_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "vclk2_div6" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_div6_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1324,7 +1484,9 @@ static struct clk_fixed_factor meson8b_vclk2_div12_div = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div12", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "vclk2_in_en" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_clk_in_en.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, } @@ -1338,15 +1500,20 @@ static struct clk_regmap meson8b_vclk2_div12_div_gate = { .hw.init = &(struct clk_init_data){ .name = "vclk2_div12_en", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "vclk2_div12" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_div12_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const char * const meson8b_vclk_enc_mux_parents[] = { - "vclk_div1_en", "vclk_div2_en", "vclk_div4_en", "vclk_div6_en", - "vclk_div12_en", +static const struct clk_hw *meson8b_vclk_enc_mux_parent_hws[] = { + &meson8b_vclk_div1_gate.hw, + &meson8b_vclk_div2_div_gate.hw, + &meson8b_vclk_div4_div_gate.hw, + &meson8b_vclk_div6_div_gate.hw, + &meson8b_vclk_div12_div_gate.hw, }; static struct clk_regmap meson8b_cts_enct_sel = { @@ -1358,8 +1525,8 @@ static struct clk_regmap meson8b_cts_enct_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_enct_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_names = meson8b_vclk_enc_mux_parents, - .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parents), + .parent_hws = meson8b_vclk_enc_mux_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1372,7 +1539,9 @@ static struct clk_regmap meson8b_cts_enct = { .hw.init = &(struct clk_init_data){ .name = "cts_enct", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "cts_enct_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_enct_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1387,8 +1556,8 @@ static struct clk_regmap meson8b_cts_encp_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_encp_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_names = meson8b_vclk_enc_mux_parents, - .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parents), + .parent_hws = meson8b_vclk_enc_mux_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1401,7 +1570,9 @@ static struct clk_regmap meson8b_cts_encp = { .hw.init = &(struct clk_init_data){ .name = "cts_encp", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "cts_encp_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_encp_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1416,8 +1587,8 @@ static struct clk_regmap meson8b_cts_enci_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_enci_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_names = meson8b_vclk_enc_mux_parents, - .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parents), + .parent_hws = meson8b_vclk_enc_mux_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1430,7 +1601,9 @@ static struct clk_regmap meson8b_cts_enci = { .hw.init = &(struct clk_init_data){ .name = "cts_enci", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "cts_enci_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_enci_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1445,8 +1618,8 @@ static struct clk_regmap meson8b_hdmi_tx_pixel_sel = { .hw.init = &(struct clk_init_data){ .name = "hdmi_tx_pixel_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_names = meson8b_vclk_enc_mux_parents, - .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parents), + .parent_hws = meson8b_vclk_enc_mux_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1459,15 +1632,20 @@ static struct clk_regmap meson8b_hdmi_tx_pixel = { .hw.init = &(struct clk_init_data){ .name = "hdmi_tx_pixel", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "hdmi_tx_pixel_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_hdmi_tx_pixel_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const char * const meson8b_vclk2_enc_mux_parents[] = { - "vclk2_div1_en", "vclk2_div2_en", "vclk2_div4_en", "vclk2_div6_en", - "vclk2_div12_en", +static const struct clk_hw *meson8b_vclk2_enc_mux_parent_hws[] = { + &meson8b_vclk2_div1_gate.hw, + &meson8b_vclk2_div2_div_gate.hw, + &meson8b_vclk2_div4_div_gate.hw, + &meson8b_vclk2_div6_div_gate.hw, + &meson8b_vclk2_div12_div_gate.hw, }; static struct clk_regmap meson8b_cts_encl_sel = { @@ -1479,8 +1657,8 @@ static struct clk_regmap meson8b_cts_encl_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_encl_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_names = meson8b_vclk2_enc_mux_parents, - .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parents), + .parent_hws = meson8b_vclk2_enc_mux_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1493,7 +1671,9 @@ static struct clk_regmap meson8b_cts_encl = { .hw.init = &(struct clk_init_data){ .name = "cts_encl", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "cts_encl_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_encl_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1508,8 +1688,8 @@ static struct clk_regmap meson8b_cts_vdac0_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_vdac0_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_names = meson8b_vclk2_enc_mux_parents, - .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parents), + .parent_hws = meson8b_vclk2_enc_mux_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1522,7 +1702,9 @@ static struct clk_regmap meson8b_cts_vdac0 = { .hw.init = &(struct clk_init_data){ .name = "cts_vdac0", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "cts_vdac0_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_vdac0_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1539,7 +1721,9 @@ static struct clk_regmap meson8b_hdmi_sys_sel = { .name = "hdmi_sys_sel", .ops = &clk_regmap_mux_ro_ops, /* FIXME: all other parents are unknown */ - .parent_names = (const char *[]){ "xtal" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_xtal.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -1554,7 +1738,9 @@ static struct clk_regmap meson8b_hdmi_sys_div = { .hw.init = &(struct clk_init_data){ .name = "hdmi_sys_div", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "hdmi_sys_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_hdmi_sys_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1568,7 +1754,9 @@ static struct clk_regmap meson8b_hdmi_sys = { .hw.init = &(struct clk_init_data) { .name = "hdmi_sys", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "hdmi_sys_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_hdmi_sys_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1579,9 +1767,14 @@ static struct clk_regmap meson8b_hdmi_sys = { * muxed by a glitch-free switch on Meson8b and Meson8m2. Meson8 only * has mali_0 and no glitch-free mux. */ -static const char * const meson8b_mali_0_1_parent_names[] = { - "xtal", "mpll2", "mpll1", "fclk_div7", "fclk_div4", "fclk_div3", - "fclk_div5" +static const struct clk_hw *meson8b_mali_0_1_parent_hws[] = { + &meson8b_xtal.hw, + &meson8b_mpll2.hw, + &meson8b_mpll1.hw, + &meson8b_fclk_div7.hw, + &meson8b_fclk_div4.hw, + &meson8b_fclk_div3.hw, + &meson8b_fclk_div5.hw, }; static u32 meson8b_mali_0_1_mux_table[] = { 0, 2, 3, 4, 5, 6, 7 }; @@ -1596,8 +1789,8 @@ static struct clk_regmap meson8b_mali_0_sel = { .hw.init = &(struct clk_init_data){ .name = "mali_0_sel", .ops = &clk_regmap_mux_ops, - .parent_names = meson8b_mali_0_1_parent_names, - .num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_names), + .parent_hws = meson8b_mali_0_1_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_hws), /* * Don't propagate rate changes up because the only changeable * parents are mpll1 and mpll2 but we need those for audio and @@ -1617,7 +1810,9 @@ static struct clk_regmap meson8b_mali_0_div = { .hw.init = &(struct clk_init_data){ .name = "mali_0_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "mali_0_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mali_0_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1631,7 +1826,9 @@ static struct clk_regmap meson8b_mali_0 = { .hw.init = &(struct clk_init_data){ .name = "mali_0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mali_0_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mali_0_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1647,8 +1844,8 @@ static struct clk_regmap meson8b_mali_1_sel = { .hw.init = &(struct clk_init_data){ .name = "mali_1_sel", .ops = &clk_regmap_mux_ops, - .parent_names = meson8b_mali_0_1_parent_names, - .num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_names), + .parent_hws = meson8b_mali_0_1_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_hws), /* * Don't propagate rate changes up because the only changeable * parents are mpll1 and mpll2 but we need those for audio and @@ -1668,7 +1865,9 @@ static struct clk_regmap meson8b_mali_1_div = { .hw.init = &(struct clk_init_data){ .name = "mali_1_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "mali_1_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mali_1_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1682,7 +1881,9 @@ static struct clk_regmap meson8b_mali_1 = { .hw.init = &(struct clk_init_data){ .name = "mali_1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "mali_1_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mali_1_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1697,7 +1898,10 @@ static struct clk_regmap meson8b_mali = { .hw.init = &(struct clk_init_data){ .name = "mali", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "mali_0", "mali_1" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mali_0.hw, + &meson8b_mali_1.hw, + }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, @@ -1740,7 +1944,9 @@ static struct clk_regmap meson8m2_gp_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "gp_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_xtal.hw + }, .num_parents = 1, }, }; @@ -1755,18 +1961,26 @@ static struct clk_regmap meson8m2_gp_pll = { .hw.init = &(struct clk_init_data){ .name = "gp_pll", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "gp_pll_dco" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8m2_gp_pll_dco.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const char * const meson8b_vpu_0_1_parent_names[] = { - "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" +static const struct clk_hw *meson8b_vpu_0_1_parent_hws[] = { + &meson8b_fclk_div4.hw, + &meson8b_fclk_div3.hw, + &meson8b_fclk_div5.hw, + &meson8b_fclk_div7.hw, }; -static const char * const mmeson8m2_vpu_0_1_parent_names[] = { - "fclk_div4", "fclk_div3", "fclk_div5", "gp_pll" +static const struct clk_hw *mmeson8m2_vpu_0_1_parent_hws[] = { + &meson8b_fclk_div4.hw, + &meson8b_fclk_div3.hw, + &meson8b_fclk_div5.hw, + &meson8m2_gp_pll.hw, }; static struct clk_regmap meson8b_vpu_0_sel = { @@ -1778,8 +1992,8 @@ static struct clk_regmap meson8b_vpu_0_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_0_sel", .ops = &clk_regmap_mux_ops, - .parent_names = meson8b_vpu_0_1_parent_names, - .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_names), + .parent_hws = meson8b_vpu_0_1_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1793,8 +2007,8 @@ static struct clk_regmap meson8m2_vpu_0_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_0_sel", .ops = &clk_regmap_mux_ops, - .parent_names = mmeson8m2_vpu_0_1_parent_names, - .num_parents = ARRAY_SIZE(mmeson8m2_vpu_0_1_parent_names), + .parent_hws = mmeson8m2_vpu_0_1_parent_hws, + .num_parents = ARRAY_SIZE(mmeson8m2_vpu_0_1_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1808,7 +2022,17 @@ static struct clk_regmap meson8b_vpu_0_div = { .hw.init = &(struct clk_init_data){ .name = "vpu_0_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vpu_0_sel" }, + .parent_data = &(const struct clk_parent_data) { + /* + * Note: + * meson8b and meson8m2 have different vpu_0_sels (with + * different struct clk_hw). We fallback to the global + * naming string mechanism so vpu_0_div picks up the + * appropriate one. + */ + .name = "vpu_0_sel", + .index = -1, + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1822,7 +2046,9 @@ static struct clk_regmap meson8b_vpu_0 = { .hw.init = &(struct clk_init_data) { .name = "vpu_0", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vpu_0_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vpu_0_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1837,8 +2063,8 @@ static struct clk_regmap meson8b_vpu_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_1_sel", .ops = &clk_regmap_mux_ops, - .parent_names = meson8b_vpu_0_1_parent_names, - .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_names), + .parent_hws = meson8b_vpu_0_1_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1852,8 +2078,8 @@ static struct clk_regmap meson8m2_vpu_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_1_sel", .ops = &clk_regmap_mux_ops, - .parent_names = mmeson8m2_vpu_0_1_parent_names, - .num_parents = ARRAY_SIZE(mmeson8m2_vpu_0_1_parent_names), + .parent_hws = mmeson8m2_vpu_0_1_parent_hws, + .num_parents = ARRAY_SIZE(mmeson8m2_vpu_0_1_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1867,7 +2093,17 @@ static struct clk_regmap meson8b_vpu_1_div = { .hw.init = &(struct clk_init_data){ .name = "vpu_1_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vpu_1_sel" }, + .parent_data = &(const struct clk_parent_data) { + /* + * Note: + * meson8b and meson8m2 have different vpu_1_sels (with + * different struct clk_hw). We fallback to the global + * naming string mechanism so vpu_1_div picks up the + * appropriate one. + */ + .name = "vpu_1_sel", + .index = -1, + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1881,7 +2117,9 @@ static struct clk_regmap meson8b_vpu_1 = { .hw.init = &(struct clk_init_data) { .name = "vpu_1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vpu_1_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vpu_1_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1896,14 +2134,22 @@ static struct clk_regmap meson8b_vpu = { .hw.init = &(struct clk_init_data){ .name = "vpu", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "vpu_0", "vpu_1" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vpu_0.hw, + &meson8b_vpu_1.hw, + }, .num_parents = 2, .flags = CLK_SET_RATE_NO_REPARENT, }, }; -static const char * const meson8b_vdec_parent_names[] = { - "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "mpll2", "mpll1" +static const struct clk_hw *meson8b_vdec_parent_hws[] = { + &meson8b_fclk_div4.hw, + &meson8b_fclk_div3.hw, + &meson8b_fclk_div5.hw, + &meson8b_fclk_div7.hw, + &meson8b_mpll2.hw, + &meson8b_mpll1.hw, }; static struct clk_regmap meson8b_vdec_1_sel = { @@ -1916,8 +2162,8 @@ static struct clk_regmap meson8b_vdec_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_1_sel", .ops = &clk_regmap_mux_ops, - .parent_names = meson8b_vdec_parent_names, - .num_parents = ARRAY_SIZE(meson8b_vdec_parent_names), + .parent_hws = meson8b_vdec_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_vdec_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1932,7 +2178,9 @@ static struct clk_regmap meson8b_vdec_1_1_div = { .hw.init = &(struct clk_init_data){ .name = "vdec_1_1_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vdec_1_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_1_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1946,7 +2194,9 @@ static struct clk_regmap meson8b_vdec_1_1 = { .hw.init = &(struct clk_init_data) { .name = "vdec_1_1", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vdec_1_1_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_1_1_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1962,7 +2212,9 @@ static struct clk_regmap meson8b_vdec_1_2_div = { .hw.init = &(struct clk_init_data){ .name = "vdec_1_2_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vdec_1_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_1_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1976,7 +2228,9 @@ static struct clk_regmap meson8b_vdec_1_2 = { .hw.init = &(struct clk_init_data) { .name = "vdec_1_2", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vdec_1_2_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_1_2_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1992,7 +2246,10 @@ static struct clk_regmap meson8b_vdec_1 = { .hw.init = &(struct clk_init_data){ .name = "vdec_1", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "vdec_1_1", "vdec_1_2" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_1_1.hw, + &meson8b_vdec_1_2.hw, + }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, @@ -2008,8 +2265,8 @@ static struct clk_regmap meson8b_vdec_hcodec_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_hcodec_sel", .ops = &clk_regmap_mux_ops, - .parent_names = meson8b_vdec_parent_names, - .num_parents = ARRAY_SIZE(meson8b_vdec_parent_names), + .parent_hws = meson8b_vdec_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_vdec_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2024,7 +2281,9 @@ static struct clk_regmap meson8b_vdec_hcodec_div = { .hw.init = &(struct clk_init_data){ .name = "vdec_hcodec_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vdec_hcodec_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_hcodec_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2038,7 +2297,9 @@ static struct clk_regmap meson8b_vdec_hcodec = { .hw.init = &(struct clk_init_data) { .name = "vdec_hcodec", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vdec_hcodec_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_hcodec_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2054,8 +2315,8 @@ static struct clk_regmap meson8b_vdec_2_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_2_sel", .ops = &clk_regmap_mux_ops, - .parent_names = meson8b_vdec_parent_names, - .num_parents = ARRAY_SIZE(meson8b_vdec_parent_names), + .parent_hws = meson8b_vdec_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_vdec_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2070,7 +2331,9 @@ static struct clk_regmap meson8b_vdec_2_div = { .hw.init = &(struct clk_init_data){ .name = "vdec_2_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vdec_2_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_2_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2084,7 +2347,9 @@ static struct clk_regmap meson8b_vdec_2 = { .hw.init = &(struct clk_init_data) { .name = "vdec_2", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vdec_2_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_2_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2100,8 +2365,8 @@ static struct clk_regmap meson8b_vdec_hevc_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_hevc_sel", .ops = &clk_regmap_mux_ops, - .parent_names = meson8b_vdec_parent_names, - .num_parents = ARRAY_SIZE(meson8b_vdec_parent_names), + .parent_hws = meson8b_vdec_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_vdec_parent_hws), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2116,7 +2381,9 @@ static struct clk_regmap meson8b_vdec_hevc_div = { .hw.init = &(struct clk_init_data){ .name = "vdec_hevc_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "vdec_hevc_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_hevc_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2130,7 +2397,9 @@ static struct clk_regmap meson8b_vdec_hevc_en = { .hw.init = &(struct clk_init_data) { .name = "vdec_hevc_en", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "vdec_hevc_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_hevc_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2147,15 +2416,19 @@ static struct clk_regmap meson8b_vdec_hevc = { .name = "vdec_hevc", .ops = &clk_regmap_mux_ops, /* TODO: The second parent is currently unknown */ - .parent_names = (const char *[]){ "vdec_hevc_en" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_hevc_en.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; /* TODO: the clock at index 0 is "DDR_PLL" which we don't support yet */ -static const char * const meson8b_cts_amclk_parent_names[] = { - "mpll0", "mpll1", "mpll2" +static const struct clk_hw *meson8b_cts_amclk_parent_hws[] = { + &meson8b_mpll0.hw, + &meson8b_mpll1.hw, + &meson8b_mpll2.hw }; static u32 meson8b_cts_amclk_mux_table[] = { 1, 2, 3 }; @@ -2171,8 +2444,8 @@ static struct clk_regmap meson8b_cts_amclk_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_amclk_sel", .ops = &clk_regmap_mux_ops, - .parent_names = meson8b_cts_amclk_parent_names, - .num_parents = ARRAY_SIZE(meson8b_cts_amclk_parent_names), + .parent_hws = meson8b_cts_amclk_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_cts_amclk_parent_hws), }, }; @@ -2186,7 +2459,9 @@ static struct clk_regmap meson8b_cts_amclk_div = { .hw.init = &(struct clk_init_data){ .name = "cts_amclk_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "cts_amclk_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_amclk_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2200,15 +2475,19 @@ static struct clk_regmap meson8b_cts_amclk = { .hw.init = &(struct clk_init_data){ .name = "cts_amclk", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "cts_amclk_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_amclk_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; /* TODO: the clock at index 0 is "DDR_PLL" which we don't support yet */ -static const char * const meson8b_cts_mclk_i958_parent_names[] = { - "mpll0", "mpll1", "mpll2" +static const struct clk_hw *meson8b_cts_mclk_i958_parent_hws[] = { + &meson8b_mpll0.hw, + &meson8b_mpll1.hw, + &meson8b_mpll2.hw }; static u32 meson8b_cts_mclk_i958_mux_table[] = { 1, 2, 3 }; @@ -2224,8 +2503,8 @@ static struct clk_regmap meson8b_cts_mclk_i958_sel = { .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_sel", .ops = &clk_regmap_mux_ops, - .parent_names = meson8b_cts_mclk_i958_parent_names, - .num_parents = ARRAY_SIZE(meson8b_cts_mclk_i958_parent_names), + .parent_hws = meson8b_cts_mclk_i958_parent_hws, + .num_parents = ARRAY_SIZE(meson8b_cts_mclk_i958_parent_hws), }, }; @@ -2239,7 +2518,9 @@ static struct clk_regmap meson8b_cts_mclk_i958_div = { .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_div", .ops = &clk_regmap_divider_ops, - .parent_names = (const char *[]){ "cts_mclk_i958_sel" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_mclk_i958_sel.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2253,7 +2534,9 @@ static struct clk_regmap meson8b_cts_mclk_i958 = { .hw.init = &(struct clk_init_data){ .name = "cts_mclk_i958", .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "cts_mclk_i958_div" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_mclk_i958_div.hw + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -2268,8 +2551,10 @@ static struct clk_regmap meson8b_cts_i958 = { .hw.init = &(struct clk_init_data){ .name = "cts_i958", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "cts_amclk", - "cts_mclk_i958" }, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_amclk.hw, + &meson8b_cts_mclk_i958.hw + }, .num_parents = 2, /* * The parent is specific to origin of the audio data. Let the @@ -2279,6 +2564,9 @@ static struct clk_regmap meson8b_cts_i958 = { }, }; +#define MESON_GATE(_name, _reg, _bit) \ + MESON_PCLK(_name, _reg, _bit, &meson8b_clk81.hw) + /* Everything Else (EE) domain gates */ static MESON_GATE(meson8b_ddr, HHI_GCLK_MPEG0, 0); diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index c3fd632af1190d3cf1e32fa34ec1346724bdc3df..a32bfaeb7e613af452aaac836189c623109c09e8 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ #include @@ -12,23 +12,13 @@ #include #include #include +#include #include #define CLK_RPMH_ARC_EN_OFFSET 0 #define CLK_RPMH_VRM_EN_OFFSET 4 -#define BCM_TCS_CMD_COMMIT_MASK 0x40000000 -#define BCM_TCS_CMD_VALID_SHIFT 29 -#define BCM_TCS_CMD_VOTE_MASK 0x3fff -#define BCM_TCS_CMD_VOTE_SHIFT 0 - -#define BCM_TCS_CMD(valid, vote) \ - (BCM_TCS_CMD_COMMIT_MASK | \ - ((valid) << BCM_TCS_CMD_VALID_SHIFT) | \ - ((vote & BCM_TCS_CMD_VOTE_MASK) \ - << BCM_TCS_CMD_VOTE_SHIFT)) - /** * struct bcm_db - Auxiliary data pertaining to each Bus Clock Manager(BCM) * @unit: divisor used to convert Hz value to an RPMh msg @@ -269,7 +259,7 @@ static int clk_rpmh_bcm_send_cmd(struct clk_rpmh *c, bool enable) } cmd.addr = c->res_addr; - cmd.data = BCM_TCS_CMD(enable, cmd_state); + cmd.data = BCM_TCS_CMD(1, enable, 0, cmd_state); ret = rpmh_write_async(c->dev, RPMH_ACTIVE_ONLY_STATE, &cmd, 1); if (ret) { diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 5e9317dc3d39794d79eee244996bc225d8801e03..a642c23b2fba9d6bfb3ffa97e052c7b9182e53c4 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -429,7 +429,7 @@ config ATMEL_ST config ATMEL_TCB_CLKSRC bool "Atmel TC Block timer driver" if COMPILE_TEST - depends on HAS_IOMEM + depends on ARM && HAS_IOMEM select TIMER_OF if OF help Support for Timer Counter Blocks on Atmel SoCs. diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c index 8e12b11e81b096b77c8bcc6c9eca0cc0a3c5c240..9039df4f90e2bd6caa58ee6848c8a48ebec7d365 100644 --- a/drivers/clocksource/em_sti.c +++ b/drivers/clocksource/em_sti.c @@ -291,10 +291,8 @@ static int em_sti_probe(struct platform_device *pdev) platform_set_drvdata(pdev, p); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "failed to get irq\n"); + if (irq < 0) return irq; - } /* map memory, let base point to the STI instance */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index ba2c79e6a0ee74d5a9a48278dfb561c978e81356..2317d4e3daaffc2de01105f2b43cccc159ca5c20 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -22,6 +22,7 @@ #include static struct clock_event_device __percpu *hv_clock_event; +static u64 hv_sched_clock_offset __ro_after_init; /* * If false, we're using the old mechanism for stimer0 interrupts @@ -212,19 +213,17 @@ EXPORT_SYMBOL_GPL(hv_stimer_global_cleanup); struct clocksource *hyperv_cs; EXPORT_SYMBOL_GPL(hyperv_cs); -#ifdef CONFIG_HYPERV_TSCPAGE - -static struct ms_hyperv_tsc_page *tsc_pg; +static struct ms_hyperv_tsc_page tsc_pg __aligned(PAGE_SIZE); struct ms_hyperv_tsc_page *hv_get_tsc_page(void) { - return tsc_pg; + return &tsc_pg; } EXPORT_SYMBOL_GPL(hv_get_tsc_page); -static u64 notrace read_hv_sched_clock_tsc(void) +static u64 notrace read_hv_clock_tsc(struct clocksource *arg) { - u64 current_tick = hv_read_tsc_page(tsc_pg); + u64 current_tick = hv_read_tsc_page(&tsc_pg); if (current_tick == U64_MAX) hv_get_time_ref_count(current_tick); @@ -232,9 +231,9 @@ static u64 notrace read_hv_sched_clock_tsc(void) return current_tick; } -static u64 read_hv_clock_tsc(struct clocksource *arg) +static u64 read_hv_sched_clock_tsc(void) { - return read_hv_sched_clock_tsc(); + return read_hv_clock_tsc(NULL) - hv_sched_clock_offset; } static struct clocksource hyperv_cs_tsc = { @@ -244,9 +243,8 @@ static struct clocksource hyperv_cs_tsc = { .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -#endif -static u64 notrace read_hv_sched_clock_msr(void) +static u64 notrace read_hv_clock_msr(struct clocksource *arg) { u64 current_tick; /* @@ -258,9 +256,9 @@ static u64 notrace read_hv_sched_clock_msr(void) return current_tick; } -static u64 read_hv_clock_msr(struct clocksource *arg) +static u64 read_hv_sched_clock_msr(void) { - return read_hv_sched_clock_msr(); + return read_hv_clock_msr(NULL) - hv_sched_clock_offset; } static struct clocksource hyperv_cs_msr = { @@ -271,7 +269,6 @@ static struct clocksource hyperv_cs_msr = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -#ifdef CONFIG_HYPERV_TSCPAGE static bool __init hv_init_tsc_clocksource(void) { u64 tsc_msr; @@ -280,12 +277,8 @@ static bool __init hv_init_tsc_clocksource(void) if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE)) return false; - tsc_pg = vmalloc(PAGE_SIZE); - if (!tsc_pg) - return false; - hyperv_cs = &hyperv_cs_tsc; - phys_addr = page_to_phys(vmalloc_to_page(tsc_pg)); + phys_addr = virt_to_phys(&tsc_pg); /* * The Hyper-V TLFS specifies to preserve the value of reserved @@ -302,17 +295,11 @@ static bool __init hv_init_tsc_clocksource(void) hv_set_clocksource_vdso(hyperv_cs_tsc); clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100); - /* sched_clock_register is needed on ARM64 but is a no-op on x86 */ - sched_clock_register(read_hv_sched_clock_tsc, 64, HV_CLOCK_HZ); + hv_sched_clock_offset = hyperv_cs->read(hyperv_cs); + hv_setup_sched_clock(read_hv_sched_clock_tsc); + return true; } -#else -static bool __init hv_init_tsc_clocksource(void) -{ - return false; -} -#endif - void __init hv_init_clocksource(void) { @@ -333,7 +320,7 @@ void __init hv_init_clocksource(void) hyperv_cs = &hyperv_cs_msr; clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100); - /* sched_clock_register is needed on ARM64 but is a no-op on x86 */ - sched_clock_register(read_hv_sched_clock_msr, 64, HV_CLOCK_HZ); + hv_sched_clock_offset = hyperv_cs->read(hyperv_cs); + hv_setup_sched_clock(read_hv_sched_clock_msr); } EXPORT_SYMBOL_GPL(hv_init_clocksource); diff --git a/drivers/clocksource/renesas-ostm.c b/drivers/clocksource/renesas-ostm.c index 61d5f3b539ce23df60f43bc914fb8a45e915202a..37c39b901bb12b38e2d6bf2d6c69848ed4b12efd 100644 --- a/drivers/clocksource/renesas-ostm.c +++ b/drivers/clocksource/renesas-ostm.c @@ -221,7 +221,7 @@ static int __init ostm_init(struct device_node *np) } rate = clk_get_rate(ostm_clk); - ostm->ticks_per_jiffy = (rate + HZ / 2) / HZ; + ostm->ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ); /* * First probed device will be used as system clocksource. Any diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 55d3e03f2cd4fefa02ed8be70aa96c7472687eeb..ef773db080e903002b693b41b961a2d48e0f5e53 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -776,11 +776,8 @@ static int sh_cmt_register_clockevent(struct sh_cmt_channel *ch, int ret; irq = platform_get_irq(ch->cmt->pdev, ch->index); - if (irq < 0) { - dev_err(&ch->cmt->pdev->dev, "ch%u: failed to get irq\n", - ch->index); + if (irq < 0) return irq; - } ret = request_irq(irq, sh_cmt_interrupt, IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, @@ -921,12 +918,24 @@ static const struct platform_device_id sh_cmt_id_table[] = { MODULE_DEVICE_TABLE(platform, sh_cmt_id_table); static const struct of_device_id sh_cmt_of_table[] __maybe_unused = { - { .compatible = "renesas,cmt-48", .data = &sh_cmt_info[SH_CMT_48BIT] }, + { + /* deprecated, preserved for backward compatibility */ + .compatible = "renesas,cmt-48", + .data = &sh_cmt_info[SH_CMT_48BIT] + }, { /* deprecated, preserved for backward compatibility */ .compatible = "renesas,cmt-48-gen2", .data = &sh_cmt_info[SH_CMT0_RCAR_GEN2] }, + { + .compatible = "renesas,r8a7740-cmt1", + .data = &sh_cmt_info[SH_CMT_48BIT] + }, + { + .compatible = "renesas,sh73a0-cmt1", + .data = &sh_cmt_info[SH_CMT_48BIT] + }, { .compatible = "renesas,rcar-gen2-cmt0", .data = &sh_cmt_info[SH_CMT0_RCAR_GEN2] diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index 49f1c805fc9598edf5d7021b435419b40e24b64f..8c4f3753b36ecbec88cb4be5091264e44f6a1934 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -462,11 +462,8 @@ static int sh_tmu_channel_setup(struct sh_tmu_channel *ch, unsigned int index, ch->base = tmu->mapbase + 8 + ch->index * 12; ch->irq = platform_get_irq(tmu->pdev, index); - if (ch->irq < 0) { - dev_err(&tmu->pdev->dev, "ch%u: failed to get irq\n", - ch->index); + if (ch->irq < 0) return ch->irq; - } ch->cs_enabled = false; ch->enable_count = 0; diff --git a/drivers/clocksource/timer-atmel-tcb.c b/drivers/clocksource/timer-atmel-tcb.c index 6ed31f9def7eb2aff31441e203ddd7b85bd1bd8a..7427b07495a89785d3459f73e0a34305ceeaa2f6 100644 --- a/drivers/clocksource/timer-atmel-tcb.c +++ b/drivers/clocksource/timer-atmel-tcb.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -125,6 +126,18 @@ static u64 notrace tc_sched_clock_read32(void) return tc_get_cycles32(&clksrc); } +static struct delay_timer tc_delay_timer; + +static unsigned long tc_delay_timer_read(void) +{ + return tc_get_cycles(&clksrc); +} + +static unsigned long notrace tc_delay_timer_read32(void) +{ + return tc_get_cycles32(&clksrc); +} + #ifdef CONFIG_GENERIC_CLOCKEVENTS struct tc_clkevt_device { @@ -432,6 +445,7 @@ static int __init tcb_clksrc_init(struct device_node *node) /* setup ony 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; } else { /* we have three clocks no matter what the * underlying platform supports. @@ -444,6 +458,7 @@ static int __init tcb_clksrc_init(struct device_node *node) /* setup both channel 0 & 1 */ tcb_setup_dual_chan(&tc, best_divisor_idx); tc_sched_clock = tc_sched_clock_read; + tc_delay_timer.read_current_timer = tc_delay_timer_read; } /* and away we go! */ @@ -458,6 +473,9 @@ static int __init tcb_clksrc_init(struct device_node *node) sched_clock_register(tc_sched_clock, 32, divided_rate); + tc_delay_timer.freq = divided_rate; + register_current_timer_delay(&tc_delay_timer); + return 0; err_unregister_clksrc: diff --git a/drivers/clocksource/timer-imx-sysctr.c b/drivers/clocksource/timer-imx-sysctr.c index fd7d68066efb5414c0b7294069bdac142d691319..b7c80a368a1b1a544fb17c2f4212bf2875555977 100644 --- a/drivers/clocksource/timer-imx-sysctr.c +++ b/drivers/clocksource/timer-imx-sysctr.c @@ -20,6 +20,8 @@ #define SYS_CTR_EN 0x1 #define SYS_CTR_IRQ_MASK 0x2 +#define SYS_CTR_CLK_DIV 0x3 + static void __iomem *sys_ctr_base; static u32 cmpcr; @@ -134,6 +136,9 @@ static int __init sysctr_timer_init(struct device_node *np) if (ret) return ret; + /* system counter clock is divided by 3 internally */ + to_sysctr.of_clk.rate /= SYS_CTR_CLK_DIV; + sys_ctr_base = timer_of_base(&to_sysctr); cmpcr = readl(sys_ctr_base + CMPCR); cmpcr &= ~SYS_CTR_EN; diff --git a/drivers/clocksource/timer-npcm7xx.c b/drivers/clocksource/timer-npcm7xx.c index 8a30da7f083b09ad2d5d15a338853a0a8bc23662..9780ffd8010e686697a57eded89aa2d1d02d826c 100644 --- a/drivers/clocksource/timer-npcm7xx.c +++ b/drivers/clocksource/timer-npcm7xx.c @@ -32,7 +32,7 @@ #define NPCM7XX_Tx_INTEN BIT(29) #define NPCM7XX_Tx_COUNTEN BIT(30) #define NPCM7XX_Tx_ONESHOT 0x0 -#define NPCM7XX_Tx_OPER GENMASK(27, 3) +#define NPCM7XX_Tx_OPER GENMASK(28, 27) #define NPCM7XX_Tx_MIN_PRESCALE 0x1 #define NPCM7XX_Tx_TDR_MASK_BITS 24 #define NPCM7XX_Tx_MAX_CNT 0xFFFFFF @@ -84,8 +84,6 @@ static int npcm7xx_timer_oneshot(struct clock_event_device *evt) val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0); val &= ~NPCM7XX_Tx_OPER; - - val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0); val |= NPCM7XX_START_ONESHOT_Tx; writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0); @@ -97,12 +95,11 @@ static int npcm7xx_timer_periodic(struct clock_event_device *evt) struct timer_of *to = to_timer_of(evt); u32 val; + writel(timer_of_period(to), timer_of_base(to) + NPCM7XX_REG_TICR0); + val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0); val &= ~NPCM7XX_Tx_OPER; - - writel(timer_of_period(to), timer_of_base(to) + NPCM7XX_REG_TICR0); val |= NPCM7XX_START_PERIODIC_Tx; - writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0); return 0; diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c index 80542289fae7b34de7a7137d21a33a38f673e993..d8c2bd4391d027acf9f4609153a39514e7043f3a 100644 --- a/drivers/clocksource/timer-of.c +++ b/drivers/clocksource/timer-of.c @@ -113,8 +113,10 @@ static __init int timer_of_clk_init(struct device_node *np, of_clk->clk = of_clk->name ? of_clk_get_by_name(np, of_clk->name) : of_clk_get(np, of_clk->index); if (IS_ERR(of_clk->clk)) { - pr_err("Failed to get clock for %pOF\n", np); - return PTR_ERR(of_clk->clk); + ret = PTR_ERR(of_clk->clk); + if (ret != -EPROBE_DEFER) + pr_err("Failed to get clock for %pOF\n", np); + goto out; } ret = clk_prepare_enable(of_clk->clk); diff --git a/drivers/clocksource/timer-probe.c b/drivers/clocksource/timer-probe.c index dda1946e84dd4f52f0555aad4ab1a81bf4fa7c03..ee9574da53c059a86ed7942aaea24d96074e0faa 100644 --- a/drivers/clocksource/timer-probe.c +++ b/drivers/clocksource/timer-probe.c @@ -29,7 +29,9 @@ void __init timer_probe(void) ret = init_func_ret(np); if (ret) { - pr_err("Failed to initialize '%pOF': %d\n", np, ret); + if (ret != -EPROBE_DEFER) + pr_err("Failed to initialize '%pOF': %d\n", np, + ret); continue; } diff --git a/drivers/clocksource/timer-riscv.c b/drivers/clocksource/timer-riscv.c index 09e031176bc6bae860133bb478d7fb5428b25469..470c7ef02ea478a4d034f7e03b3477d41dffe455 100644 --- a/drivers/clocksource/timer-riscv.c +++ b/drivers/clocksource/timer-riscv.c @@ -2,6 +2,10 @@ /* * Copyright (C) 2012 Regents of the University of California * Copyright (C) 2017 SiFive + * + * All RISC-V systems have a timer attached to every hart. These timers can be + * read from the "time" and "timeh" CSRs, and can use the SBI to setup + * events. */ #include #include @@ -12,19 +16,6 @@ #include #include -/* - * All RISC-V systems have a timer attached to every hart. These timers can be - * read by the 'rdcycle' pseudo instruction, and can use the SBI to setup - * events. In order to abstract the architecture-specific timer reading and - * setting functions away from the clock event insertion code, we provide - * function pointers to the clockevent subsystem that perform two basic - * operations: rdtime() reads the timer on the current CPU, and - * next_event(delta) sets the next timer event to 'delta' cycles in the future. - * As the timers are inherently a per-cpu resource, these callbacks perform - * operations on the current hart. There is guaranteed to be exactly one timer - * per hart on all RISC-V systems. - */ - static int riscv_clock_next_event(unsigned long delta, struct clock_event_device *ce) { diff --git a/drivers/clocksource/timer-sun4i.c b/drivers/clocksource/timer-sun4i.c index 65f38f6ca7141980a188056b33c353221b713e83..0ba8155b8287d540352c5c777c14dc98c6ec8089 100644 --- a/drivers/clocksource/timer-sun4i.c +++ b/drivers/clocksource/timer-sun4i.c @@ -219,5 +219,9 @@ static int __init sun4i_timer_init(struct device_node *node) } TIMER_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer", sun4i_timer_init); +TIMER_OF_DECLARE(sun8i_a23, "allwinner,sun8i-a23-timer", + sun4i_timer_init); +TIMER_OF_DECLARE(sun8i_v3s, "allwinner,sun8i-v3s-timer", + sun4i_timer_init); TIMER_OF_DECLARE(suniv, "allwinner,suniv-f1c100s-timer", sun4i_timer_init); diff --git a/drivers/counter/ftm-quaddec.c b/drivers/counter/ftm-quaddec.c index 68a9b73934575cae82e4f41664b788b7352ba3a2..4046aa9f9234472522525387c1331baddde8a30d 100644 --- a/drivers/counter/ftm-quaddec.c +++ b/drivers/counter/ftm-quaddec.c @@ -100,16 +100,18 @@ static void ftm_quaddec_init(struct ftm_quaddec *ftm) ftm_set_write_protection(ftm); } -static void ftm_quaddec_disable(struct ftm_quaddec *ftm) +static void ftm_quaddec_disable(void *ftm) { - ftm_clear_write_protection(ftm); - ftm_write(ftm, FTM_MODE, 0); - ftm_write(ftm, FTM_QDCTRL, 0); + struct ftm_quaddec *ftm_qua = ftm; + + ftm_clear_write_protection(ftm_qua); + ftm_write(ftm_qua, FTM_MODE, 0); + ftm_write(ftm_qua, FTM_QDCTRL, 0); /* * This is enough to disable the counter. No clock has been * selected by writing to FTM_SC in init() */ - ftm_set_write_protection(ftm); + ftm_set_write_protection(ftm_qua); } static int ftm_quaddec_get_prescaler(struct counter_device *counter, @@ -317,20 +319,13 @@ static int ftm_quaddec_probe(struct platform_device *pdev) ftm_quaddec_init(ftm); - ret = counter_register(&ftm->counter); + ret = devm_add_action_or_reset(&pdev->dev, ftm_quaddec_disable, ftm); if (ret) - ftm_quaddec_disable(ftm); - - return ret; -} + return ret; -static int ftm_quaddec_remove(struct platform_device *pdev) -{ - struct ftm_quaddec *ftm = platform_get_drvdata(pdev); - - counter_unregister(&ftm->counter); - - ftm_quaddec_disable(ftm); + ret = devm_counter_register(&pdev->dev, &ftm->counter); + if (ret) + return ret; return 0; } @@ -346,7 +341,6 @@ static struct platform_driver ftm_quaddec_driver = { .of_match_table = ftm_quaddec_match, }, .probe = ftm_quaddec_probe, - .remove = ftm_quaddec_remove, }; module_platform_driver(ftm_quaddec_driver); diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 56c31a78c692052ca6fe86137d63409d8d0db38d..a905796f7f856516ea6299b5ff83b098e2f0e015 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -19,6 +19,18 @@ config ACPI_CPPC_CPUFREQ If in doubt, say N. +config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM + tristate "Allwinner nvmem based SUN50I CPUFreq driver" + depends on ARCH_SUNXI + depends on NVMEM_SUNXI_SID + select PM_OPP + help + This adds the nvmem based CPUFreq driver for Allwinner + h6 SoC. + + To compile this driver as a module, choose M here: the + module will be called sun50i-cpufreq-nvmem. + config ARM_ARMADA_37XX_CPUFREQ tristate "Armada 37xx CPUFreq support" depends on ARCH_MVEBU && CPUFREQ_DT @@ -120,8 +132,8 @@ config ARM_OMAP2PLUS_CPUFREQ depends on ARCH_OMAP2PLUS default ARCH_OMAP2PLUS -config ARM_QCOM_CPUFREQ_KRYO - tristate "Qualcomm Kryo based CPUFreq" +config ARM_QCOM_CPUFREQ_NVMEM + tristate "Qualcomm nvmem based CPUFreq" depends on ARM64 depends on QCOM_QFPROM depends on QCOM_SMEM diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index d28709da43de5249c66999fe7d589473c5720928..93d52a112cab2d3023420ccfdbf82fe0d05255f1 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -67,7 +67,7 @@ obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o -obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o +obj-$(CONFIG_ARM_QCOM_CPUFREQ_NVMEM) += qcom-cpufreq-nvmem.o obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ) += raspberrypi-cpufreq.o obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o @@ -83,6 +83,7 @@ obj-$(CONFIG_ARM_SCMI_CPUFREQ) += scmi-cpufreq.o obj-$(CONFIG_ARM_SCPI_CPUFREQ) += scpi-cpufreq.o obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o obj-$(CONFIG_ARM_STI_CPUFREQ) += sti-cpufreq.o +obj-$(CONFIG_ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM) += sun50i-cpufreq-nvmem.o obj-$(CONFIG_ARM_TANGO_CPUFREQ) += tango-cpufreq.o obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o diff --git a/drivers/cpufreq/armada-8k-cpufreq.c b/drivers/cpufreq/armada-8k-cpufreq.c index 988ebc326bdbb02c6d29c804e32455d43cd3d539..39e34f5066d3dfc54853356b1b4a6e57c67ad151 100644 --- a/drivers/cpufreq/armada-8k-cpufreq.c +++ b/drivers/cpufreq/armada-8k-cpufreq.c @@ -136,6 +136,8 @@ static int __init armada_8k_cpufreq_init(void) nb_cpus = num_possible_cpus(); freq_tables = kcalloc(nb_cpus, sizeof(*freq_tables), GFP_KERNEL); + if (!freq_tables) + return -ENOMEM; cpumask_copy(&cpus, cpu_possible_mask); /* diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index 03dc4244ab000fe4f30c20ca3a69c4eab2f2ce31..bca8d1f47fd2c0dd8fd496604466a58dd34e2492 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -101,12 +101,15 @@ static const struct of_device_id whitelist[] __initconst = { * platforms using "operating-points-v2" property. */ static const struct of_device_id blacklist[] __initconst = { + { .compatible = "allwinner,sun50i-h6", }, + { .compatible = "calxeda,highbank", }, { .compatible = "calxeda,ecx-2000", }, { .compatible = "fsl,imx7d", }, { .compatible = "fsl,imx8mq", }, { .compatible = "fsl,imx8mm", }, + { .compatible = "fsl,imx8mn", }, { .compatible = "marvell,armadaxp", }, @@ -117,12 +120,14 @@ static const struct of_device_id blacklist[] __initconst = { { .compatible = "mediatek,mt817x", }, { .compatible = "mediatek,mt8173", }, { .compatible = "mediatek,mt8176", }, + { .compatible = "mediatek,mt8183", }, { .compatible = "nvidia,tegra124", }, { .compatible = "nvidia,tegra210", }, { .compatible = "qcom,apq8096", }, { .compatible = "qcom,msm8996", }, + { .compatible = "qcom,qcs404", }, { .compatible = "st,stih407", }, { .compatible = "st,stih410", }, diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 642fc08b6c8213013fa4b51cdf442ef304eaedef..f9de9dece70ff250847abdb53e161a8840cc8f2b 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1268,7 +1268,17 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy) DEV_PM_QOS_MAX_FREQUENCY); dev_pm_qos_remove_notifier(dev, &policy->nb_min, DEV_PM_QOS_MIN_FREQUENCY); - dev_pm_qos_remove_request(policy->max_freq_req); + + if (policy->max_freq_req) { + /* + * CPUFREQ_CREATE_POLICY notification is sent only after + * successfully adding max_freq_req request. + */ + blocking_notifier_call_chain(&cpufreq_policy_notifier_list, + CPUFREQ_REMOVE_POLICY, policy); + dev_pm_qos_remove_request(policy->max_freq_req); + } + dev_pm_qos_remove_request(policy->min_freq_req); kfree(policy->min_freq_req); @@ -1393,6 +1403,9 @@ static int cpufreq_online(unsigned int cpu) ret); goto out_destroy_policy; } + + blocking_notifier_call_chain(&cpufreq_policy_notifier_list, + CPUFREQ_CREATE_POLICY, policy); } if (cpufreq_driver->get && has_target()) { @@ -1810,8 +1823,8 @@ void cpufreq_suspend(void) } if (cpufreq_driver->suspend && cpufreq_driver->suspend(policy)) - pr_err("%s: Failed to suspend driver: %p\n", __func__, - policy); + pr_err("%s: Failed to suspend driver: %s\n", __func__, + cpufreq_driver->name); } suspend: @@ -2149,7 +2162,7 @@ int cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { - int ret = -EINVAL; + int ret; down_write(&policy->rwsem); @@ -2356,15 +2369,13 @@ EXPORT_SYMBOL(cpufreq_get_policy); * @policy: Policy object to modify. * @new_policy: New policy data. * - * Pass @new_policy to the cpufreq driver's ->verify() callback, run the - * installed policy notifiers for it with the CPUFREQ_ADJUST value, pass it to - * the driver's ->verify() callback again and run the notifiers for it again - * with the CPUFREQ_NOTIFY value. Next, copy the min and max parameters - * of @new_policy to @policy and either invoke the driver's ->setpolicy() - * callback (if present) or carry out a governor update for @policy. That is, - * run the current governor's ->limits() callback (if the governor field in - * @new_policy points to the same object as the one in @policy) or replace the - * governor for @policy with the new one stored in @new_policy. + * Pass @new_policy to the cpufreq driver's ->verify() callback. Next, copy the + * min and max parameters of @new_policy to @policy and either invoke the + * driver's ->setpolicy() callback (if present) or carry out a governor update + * for @policy. That is, run the current governor's ->limits() callback (if the + * governor field in @new_policy points to the same object as the one in + * @policy) or replace the governor for @policy with the new one stored in + * @new_policy. * * The cpuinfo part of @policy is not updated by this function. */ @@ -2392,26 +2403,6 @@ int cpufreq_set_policy(struct cpufreq_policy *policy, if (ret) return ret; - /* - * The notifier-chain shall be removed once all the users of - * CPUFREQ_ADJUST are moved to use the QoS framework. - */ - /* adjust if necessary - all reasons */ - blocking_notifier_call_chain(&cpufreq_policy_notifier_list, - CPUFREQ_ADJUST, new_policy); - - /* - * verify the cpu speed can be set within this limit, which might be - * different to the first one - */ - ret = cpufreq_driver->verify(new_policy); - if (ret) - return ret; - - /* notification of the new policy */ - blocking_notifier_call_chain(&cpufreq_policy_notifier_list, - CPUFREQ_NOTIFY, new_policy); - policy->min = new_policy->min; policy->max = new_policy->max; trace_cpu_frequency_limits(policy); diff --git a/drivers/cpufreq/imx-cpufreq-dt.c b/drivers/cpufreq/imx-cpufreq-dt.c index 4f85f3112784f77b2781e2a4432191148b1cebb4..35db14cf31026a73728ad54ba11cdf007f6b3645 100644 --- a/drivers/cpufreq/imx-cpufreq-dt.c +++ b/drivers/cpufreq/imx-cpufreq-dt.c @@ -16,6 +16,7 @@ #define OCOTP_CFG3_SPEED_GRADE_SHIFT 8 #define OCOTP_CFG3_SPEED_GRADE_MASK (0x3 << 8) +#define IMX8MN_OCOTP_CFG3_SPEED_GRADE_MASK (0xf << 8) #define OCOTP_CFG3_MKT_SEGMENT_SHIFT 6 #define OCOTP_CFG3_MKT_SEGMENT_MASK (0x3 << 6) @@ -34,7 +35,12 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev) if (ret) return ret; - speed_grade = (cell_value & OCOTP_CFG3_SPEED_GRADE_MASK) >> OCOTP_CFG3_SPEED_GRADE_SHIFT; + if (of_machine_is_compatible("fsl,imx8mn")) + speed_grade = (cell_value & IMX8MN_OCOTP_CFG3_SPEED_GRADE_MASK) + >> OCOTP_CFG3_SPEED_GRADE_SHIFT; + else + speed_grade = (cell_value & OCOTP_CFG3_SPEED_GRADE_MASK) + >> OCOTP_CFG3_SPEED_GRADE_SHIFT; mkt_segment = (cell_value & OCOTP_CFG3_MKT_SEGMENT_MASK) >> OCOTP_CFG3_MKT_SEGMENT_SHIFT; /* diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index cc27d4c59dca8324b6b0a28c688e7e3793d026cb..9f02de9a1b4743ea7d01c2a3ff9f85e0cb81a997 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -1085,6 +1086,47 @@ static ssize_t store_no_turbo(struct kobject *a, struct kobj_attribute *b, return count; } +static struct cpufreq_driver intel_pstate; + +static void update_qos_request(enum dev_pm_qos_req_type type) +{ + int max_state, turbo_max, freq, i, perf_pct; + struct dev_pm_qos_request *req; + struct cpufreq_policy *policy; + + for_each_possible_cpu(i) { + struct cpudata *cpu = all_cpu_data[i]; + + policy = cpufreq_cpu_get(i); + if (!policy) + continue; + + req = policy->driver_data; + cpufreq_cpu_put(policy); + + if (!req) + continue; + + if (hwp_active) + intel_pstate_get_hwp_max(i, &turbo_max, &max_state); + else + turbo_max = cpu->pstate.turbo_pstate; + + if (type == DEV_PM_QOS_MIN_FREQUENCY) { + perf_pct = global.min_perf_pct; + } else { + req++; + perf_pct = global.max_perf_pct; + } + + freq = DIV_ROUND_UP(turbo_max * perf_pct, 100); + freq *= cpu->pstate.scaling; + + if (dev_pm_qos_update_request(req, freq) < 0) + pr_warn("Failed to update freq constraint: CPU%d\n", i); + } +} + static ssize_t store_max_perf_pct(struct kobject *a, struct kobj_attribute *b, const char *buf, size_t count) { @@ -1108,7 +1150,10 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct kobj_attribute *b, mutex_unlock(&intel_pstate_limits_lock); - intel_pstate_update_policies(); + if (intel_pstate_driver == &intel_pstate) + intel_pstate_update_policies(); + else + update_qos_request(DEV_PM_QOS_MAX_FREQUENCY); mutex_unlock(&intel_pstate_driver_lock); @@ -1139,7 +1184,10 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct kobj_attribute *b, mutex_unlock(&intel_pstate_limits_lock); - intel_pstate_update_policies(); + if (intel_pstate_driver == &intel_pstate) + intel_pstate_update_policies(); + else + update_qos_request(DEV_PM_QOS_MIN_FREQUENCY); mutex_unlock(&intel_pstate_driver_lock); @@ -1867,22 +1915,22 @@ static const struct pstate_funcs knl_funcs = { (unsigned long)&policy } static const struct x86_cpu_id intel_pstate_cpu_ids[] = { - ICPU(INTEL_FAM6_SANDYBRIDGE, core_funcs), + ICPU(INTEL_FAM6_SANDYBRIDGE, core_funcs), ICPU(INTEL_FAM6_SANDYBRIDGE_X, core_funcs), ICPU(INTEL_FAM6_ATOM_SILVERMONT, silvermont_funcs), ICPU(INTEL_FAM6_IVYBRIDGE, core_funcs), - ICPU(INTEL_FAM6_HASWELL_CORE, core_funcs), - ICPU(INTEL_FAM6_BROADWELL_CORE, core_funcs), + ICPU(INTEL_FAM6_HASWELL, core_funcs), + ICPU(INTEL_FAM6_BROADWELL, core_funcs), ICPU(INTEL_FAM6_IVYBRIDGE_X, core_funcs), ICPU(INTEL_FAM6_HASWELL_X, core_funcs), - ICPU(INTEL_FAM6_HASWELL_ULT, core_funcs), - ICPU(INTEL_FAM6_HASWELL_GT3E, core_funcs), - ICPU(INTEL_FAM6_BROADWELL_GT3E, core_funcs), + ICPU(INTEL_FAM6_HASWELL_L, core_funcs), + ICPU(INTEL_FAM6_HASWELL_G, core_funcs), + ICPU(INTEL_FAM6_BROADWELL_G, core_funcs), ICPU(INTEL_FAM6_ATOM_AIRMONT, airmont_funcs), - ICPU(INTEL_FAM6_SKYLAKE_MOBILE, core_funcs), + ICPU(INTEL_FAM6_SKYLAKE_L, core_funcs), ICPU(INTEL_FAM6_BROADWELL_X, core_funcs), - ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, core_funcs), - ICPU(INTEL_FAM6_BROADWELL_XEON_D, core_funcs), + ICPU(INTEL_FAM6_SKYLAKE, core_funcs), + ICPU(INTEL_FAM6_BROADWELL_D, core_funcs), ICPU(INTEL_FAM6_XEON_PHI_KNL, knl_funcs), ICPU(INTEL_FAM6_XEON_PHI_KNM, knl_funcs), ICPU(INTEL_FAM6_ATOM_GOLDMONT, core_funcs), @@ -1893,20 +1941,20 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = { MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids); static const struct x86_cpu_id intel_pstate_cpu_oob_ids[] __initconst = { - ICPU(INTEL_FAM6_BROADWELL_XEON_D, core_funcs), + ICPU(INTEL_FAM6_BROADWELL_D, core_funcs), ICPU(INTEL_FAM6_BROADWELL_X, core_funcs), ICPU(INTEL_FAM6_SKYLAKE_X, core_funcs), {} }; static const struct x86_cpu_id intel_pstate_cpu_ee_disable_ids[] = { - ICPU(INTEL_FAM6_KABYLAKE_DESKTOP, core_funcs), + ICPU(INTEL_FAM6_KABYLAKE, core_funcs), {} }; static const struct x86_cpu_id intel_pstate_hwp_boost_ids[] = { ICPU(INTEL_FAM6_SKYLAKE_X, core_funcs), - ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, core_funcs), + ICPU(INTEL_FAM6_SKYLAKE, core_funcs), {} }; @@ -2332,8 +2380,16 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy, static int intel_cpufreq_cpu_init(struct cpufreq_policy *policy) { - int ret = __intel_pstate_cpu_init(policy); + int max_state, turbo_max, min_freq, max_freq, ret; + struct dev_pm_qos_request *req; + struct cpudata *cpu; + struct device *dev; + + dev = get_cpu_device(policy->cpu); + if (!dev) + return -ENODEV; + ret = __intel_pstate_cpu_init(policy); if (ret) return ret; @@ -2342,7 +2398,63 @@ static int intel_cpufreq_cpu_init(struct cpufreq_policy *policy) /* This reflects the intel_pstate_get_cpu_pstates() setting. */ policy->cur = policy->cpuinfo.min_freq; + req = kcalloc(2, sizeof(*req), GFP_KERNEL); + if (!req) { + ret = -ENOMEM; + goto pstate_exit; + } + + cpu = all_cpu_data[policy->cpu]; + + if (hwp_active) + intel_pstate_get_hwp_max(policy->cpu, &turbo_max, &max_state); + else + turbo_max = cpu->pstate.turbo_pstate; + + 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; + + ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_MIN_FREQUENCY, + min_freq); + if (ret < 0) { + dev_err(dev, "Failed to add min-freq constraint (%d)\n", ret); + goto free_req; + } + + ret = dev_pm_qos_add_request(dev, req + 1, DEV_PM_QOS_MAX_FREQUENCY, + max_freq); + if (ret < 0) { + dev_err(dev, "Failed to add max-freq constraint (%d)\n", ret); + goto remove_min_req; + } + + policy->driver_data = req; + return 0; + +remove_min_req: + dev_pm_qos_remove_request(req); +free_req: + kfree(req); +pstate_exit: + intel_pstate_exit_perf_limits(policy); + + return ret; +} + +static int intel_cpufreq_cpu_exit(struct cpufreq_policy *policy) +{ + struct dev_pm_qos_request *req; + + req = policy->driver_data; + + dev_pm_qos_remove_request(req + 1); + dev_pm_qos_remove_request(req); + kfree(req); + + return intel_pstate_cpu_exit(policy); } static struct cpufreq_driver intel_cpufreq = { @@ -2351,7 +2463,7 @@ static struct cpufreq_driver intel_cpufreq = { .target = intel_cpufreq_target, .fast_switch = intel_cpufreq_fast_switch, .init = intel_cpufreq_cpu_init, - .exit = intel_pstate_cpu_exit, + .exit = intel_cpufreq_cpu_exit, .stop_cpu = intel_cpufreq_stop_cpu, .update_limits = intel_pstate_update_limits, .name = "intel_cpufreq", @@ -2624,7 +2736,7 @@ static inline void intel_pstate_request_control_from_smm(void) {} static const struct x86_cpu_id hwp_support_ids[] __initconst = { ICPU_HWP(INTEL_FAM6_BROADWELL_X, INTEL_PSTATE_HWP_BROADWELL), - ICPU_HWP(INTEL_FAM6_BROADWELL_XEON_D, INTEL_PSTATE_HWP_BROADWELL), + ICPU_HWP(INTEL_FAM6_BROADWELL_D, INTEL_PSTATE_HWP_BROADWELL), ICPU_HWP(X86_MODEL_ANY, 0), {} }; diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c index f14f3a85f2f7659fb8ce5460d3516d9a972ce0f4..0c98dd08273d0ab4405adfde78644462887485db 100644 --- a/drivers/cpufreq/mediatek-cpufreq.c +++ b/drivers/cpufreq/mediatek-cpufreq.c @@ -338,7 +338,7 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) goto out_free_resources; } - proc_reg = regulator_get_exclusive(cpu_dev, "proc"); + proc_reg = regulator_get_optional(cpu_dev, "proc"); if (IS_ERR(proc_reg)) { if (PTR_ERR(proc_reg) == -EPROBE_DEFER) pr_warn("proc regulator for cpu%d not ready, retry.\n", @@ -535,6 +535,8 @@ static const struct of_device_id mtk_cpufreq_machines[] __initconst = { { .compatible = "mediatek,mt817x", }, { .compatible = "mediatek,mt8173", }, { .compatible = "mediatek,mt8176", }, + { .compatible = "mediatek,mt8183", }, + { .compatible = "mediatek,mt8516", }, { } }; diff --git a/drivers/cpufreq/ppc_cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c index b83f36febf037e509c13690a3fbb6c0a067234f0..c58abb4cca3a254b028bec292a888099e8e7c7b0 100644 --- a/drivers/cpufreq/ppc_cbe_cpufreq.c +++ b/drivers/cpufreq/ppc_cbe_cpufreq.c @@ -110,6 +110,13 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) #endif policy->freq_table = cbe_freqs; + cbe_cpufreq_pmi_policy_init(policy); + return 0; +} + +static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy) +{ + cbe_cpufreq_pmi_policy_exit(policy); return 0; } @@ -129,6 +136,7 @@ static struct cpufreq_driver cbe_cpufreq_driver = { .verify = cpufreq_generic_frequency_table_verify, .target_index = cbe_cpufreq_target, .init = cbe_cpufreq_cpu_init, + .exit = cbe_cpufreq_cpu_exit, .name = "cbe-cpufreq", .flags = CPUFREQ_CONST_LOOPS, }; @@ -139,15 +147,24 @@ static struct cpufreq_driver cbe_cpufreq_driver = { static int __init cbe_cpufreq_init(void) { + int ret; + if (!machine_is(cell)) return -ENODEV; - return cpufreq_register_driver(&cbe_cpufreq_driver); + cbe_cpufreq_pmi_init(); + + ret = cpufreq_register_driver(&cbe_cpufreq_driver); + if (ret) + cbe_cpufreq_pmi_exit(); + + return ret; } static void __exit cbe_cpufreq_exit(void) { cpufreq_unregister_driver(&cbe_cpufreq_driver); + cbe_cpufreq_pmi_exit(); } module_init(cbe_cpufreq_init); diff --git a/drivers/cpufreq/ppc_cbe_cpufreq.h b/drivers/cpufreq/ppc_cbe_cpufreq.h index 9d973519d669169b70c76e144a8c083bf880a818..00cd8633b0d9df96f9381ca6c65342919f030b85 100644 --- a/drivers/cpufreq/ppc_cbe_cpufreq.h +++ b/drivers/cpufreq/ppc_cbe_cpufreq.h @@ -20,6 +20,14 @@ int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode); #if IS_ENABLED(CONFIG_CPU_FREQ_CBE_PMI) extern bool cbe_cpufreq_has_pmi; +void cbe_cpufreq_pmi_policy_init(struct cpufreq_policy *policy); +void cbe_cpufreq_pmi_policy_exit(struct cpufreq_policy *policy); +void cbe_cpufreq_pmi_init(void); +void cbe_cpufreq_pmi_exit(void); #else #define cbe_cpufreq_has_pmi (0) +static inline void cbe_cpufreq_pmi_policy_init(struct cpufreq_policy *policy) {} +static inline void cbe_cpufreq_pmi_policy_exit(struct cpufreq_policy *policy) {} +static inline void cbe_cpufreq_pmi_init(void) {} +static inline void cbe_cpufreq_pmi_exit(void) {} #endif diff --git a/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c b/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c index 97c8ee4614b7d408eca9116d3f76704e31b34978..bc9dd30395c402893d2ca71a5b78a96888c3526e 100644 --- a/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c +++ b/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -24,8 +25,6 @@ #include "ppc_cbe_cpufreq.h" -static u8 pmi_slow_mode_limit[MAX_CBE]; - bool cbe_cpufreq_has_pmi = false; EXPORT_SYMBOL_GPL(cbe_cpufreq_has_pmi); @@ -65,64 +64,89 @@ EXPORT_SYMBOL_GPL(cbe_cpufreq_set_pmode_pmi); static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg) { + struct cpufreq_policy *policy; + struct dev_pm_qos_request *req; u8 node, slow_mode; + int cpu, ret; BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE); node = pmi_msg.data1; slow_mode = pmi_msg.data2; - pmi_slow_mode_limit[node] = slow_mode; + cpu = cbe_node_to_cpu(node); pr_debug("cbe_handle_pmi: node: %d max_freq: %d\n", node, slow_mode); -} - -static int pmi_notifier(struct notifier_block *nb, - unsigned long event, void *data) -{ - struct cpufreq_policy *policy = data; - struct cpufreq_frequency_table *cbe_freqs = policy->freq_table; - u8 node; - - /* Should this really be called for CPUFREQ_ADJUST and CPUFREQ_NOTIFY - * policy events?) - */ - node = cbe_cpu_to_node(policy->cpu); - - pr_debug("got notified, event=%lu, node=%u\n", event, node); - if (pmi_slow_mode_limit[node] != 0) { - pr_debug("limiting node %d to slow mode %d\n", - node, pmi_slow_mode_limit[node]); + policy = cpufreq_cpu_get(cpu); + if (!policy) { + pr_warn("cpufreq policy not found cpu%d\n", cpu); + return; + } - cpufreq_verify_within_limits(policy, 0, + req = policy->driver_data; - cbe_freqs[pmi_slow_mode_limit[node]].frequency); - } + ret = dev_pm_qos_update_request(req, + policy->freq_table[slow_mode].frequency); + if (ret < 0) + pr_warn("Failed to update freq constraint: %d\n", ret); + else + pr_debug("limiting node %d to slow mode %d\n", node, slow_mode); - return 0; + cpufreq_cpu_put(policy); } -static struct notifier_block pmi_notifier_block = { - .notifier_call = pmi_notifier, -}; - static struct pmi_handler cbe_pmi_handler = { .type = PMI_TYPE_FREQ_CHANGE, .handle_pmi_message = cbe_cpufreq_handle_pmi, }; +void cbe_cpufreq_pmi_policy_init(struct cpufreq_policy *policy) +{ + struct dev_pm_qos_request *req; + int ret; + + if (!cbe_cpufreq_has_pmi) + return; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return; + + ret = dev_pm_qos_add_request(get_cpu_device(policy->cpu), req, + DEV_PM_QOS_MAX_FREQUENCY, + policy->freq_table[0].frequency); + if (ret < 0) { + pr_err("Failed to add freq constraint (%d)\n", ret); + kfree(req); + return; + } + policy->driver_data = req; +} +EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_policy_init); -static int __init cbe_cpufreq_pmi_init(void) +void cbe_cpufreq_pmi_policy_exit(struct cpufreq_policy *policy) { - cbe_cpufreq_has_pmi = pmi_register_handler(&cbe_pmi_handler) == 0; + struct dev_pm_qos_request *req = policy->driver_data; - if (!cbe_cpufreq_has_pmi) - return -ENODEV; + if (cbe_cpufreq_has_pmi) { + dev_pm_qos_remove_request(req); + kfree(req); + } +} +EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_policy_exit); - cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); +void cbe_cpufreq_pmi_init(void) +{ + if (!pmi_register_handler(&cbe_pmi_handler)) + cbe_cpufreq_has_pmi = true; +} +EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_init); - return 0; +void cbe_cpufreq_pmi_exit(void) +{ + pmi_unregister_handler(&cbe_pmi_handler); + cbe_cpufreq_has_pmi = false; } -device_initcall(cbe_cpufreq_pmi_init); +EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_exit); diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c index 4b0b50403901b7c67c56d33cff1438b6ca0ba86a..a9ae2f84a4efcf07694dea83480883ac2c648d50 100644 --- a/drivers/cpufreq/qcom-cpufreq-hw.c +++ b/drivers/cpufreq/qcom-cpufreq-hw.c @@ -20,6 +20,7 @@ #define LUT_VOLT GENMASK(11, 0) #define LUT_ROW_SIZE 32 #define CLK_HW_DIV 2 +#define LUT_TURBO_IND 1 /* Register offsets */ #define REG_ENABLE 0x0 @@ -34,9 +35,12 @@ static int qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy, unsigned int index) { void __iomem *perf_state_reg = policy->driver_data; + unsigned long freq = policy->freq_table[index].frequency; writel_relaxed(index, perf_state_reg); + arch_set_freq_scale(policy->related_cpus, freq, + policy->cpuinfo.max_freq); return 0; } @@ -63,6 +67,7 @@ static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy, { void __iomem *perf_state_reg = policy->driver_data; int index; + unsigned long freq; index = policy->cached_resolved_idx; if (index < 0) @@ -70,16 +75,19 @@ static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy, writel_relaxed(index, perf_state_reg); - return policy->freq_table[index].frequency; + freq = policy->freq_table[index].frequency; + arch_set_freq_scale(policy->related_cpus, freq, + policy->cpuinfo.max_freq); + + return freq; } static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev, struct cpufreq_policy *policy, void __iomem *base) { - u32 data, src, lval, i, core_count, prev_cc = 0, prev_freq = 0, freq; + u32 data, src, lval, i, core_count, prev_freq = 0, freq; u32 volt; - unsigned int max_cores = cpumask_weight(policy->cpus); struct cpufreq_frequency_table *table; table = kcalloc(LUT_MAX_ENTRIES + 1, sizeof(*table), GFP_KERNEL); @@ -102,12 +110,12 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev, else freq = cpu_hw_rate / 1000; - if (freq != prev_freq && core_count == max_cores) { + if (freq != prev_freq && core_count != LUT_TURBO_IND) { table[i].frequency = freq; dev_pm_opp_add(cpu_dev, freq * 1000, volt); dev_dbg(cpu_dev, "index=%d freq=%d, core_count %d\n", i, freq, core_count); - } else { + } else if (core_count == LUT_TURBO_IND) { table[i].frequency = CPUFREQ_ENTRY_INVALID; } @@ -115,14 +123,14 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev, * Two of the same frequencies with the same core counts means * end of table */ - if (i > 0 && prev_freq == freq && prev_cc == core_count) { + if (i > 0 && prev_freq == freq) { struct cpufreq_frequency_table *prev = &table[i - 1]; /* * Only treat the last frequency that might be a boost * as the boost frequency */ - if (prev_cc != max_cores) { + if (prev->frequency == CPUFREQ_ENTRY_INVALID) { prev->frequency = prev_freq; prev->flags = CPUFREQ_BOOST_FREQ; dev_pm_opp_add(cpu_dev, prev_freq * 1000, volt); @@ -131,7 +139,6 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev, break; } - prev_cc = core_count; prev_freq = freq; } diff --git a/drivers/cpufreq/qcom-cpufreq-kryo.c b/drivers/cpufreq/qcom-cpufreq-kryo.c deleted file mode 100644 index dd64dcf89c74c26a3d93924e2906a631757c292b..0000000000000000000000000000000000000000 --- a/drivers/cpufreq/qcom-cpufreq-kryo.c +++ /dev/null @@ -1,249 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. - */ - -/* - * In Certain QCOM SoCs like apq8096 and msm8996 that have KRYO processors, - * the CPU frequency subset and voltage value of each OPP varies - * based on the silicon variant in use. Qualcomm Process Voltage Scaling Tables - * defines the voltage and frequency value based on the msm-id in SMEM - * and speedbin blown in the efuse combination. - * The qcom-cpufreq-kryo driver reads the msm-id and efuse value from the SoC - * to provide the OPP framework with required information. - * This is used to determine the voltage and frequency value for each OPP of - * operating-points-v2 table when it is parsed by the OPP framework. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MSM_ID_SMEM 137 - -enum _msm_id { - MSM8996V3 = 0xF6ul, - APQ8096V3 = 0x123ul, - MSM8996SG = 0x131ul, - APQ8096SG = 0x138ul, -}; - -enum _msm8996_version { - MSM8996_V3, - MSM8996_SG, - NUM_OF_MSM8996_VERSIONS, -}; - -static struct platform_device *cpufreq_dt_pdev, *kryo_cpufreq_pdev; - -static enum _msm8996_version qcom_cpufreq_kryo_get_msm_id(void) -{ - size_t len; - u32 *msm_id; - enum _msm8996_version version; - - msm_id = qcom_smem_get(QCOM_SMEM_HOST_ANY, MSM_ID_SMEM, &len); - if (IS_ERR(msm_id)) - return NUM_OF_MSM8996_VERSIONS; - - /* The first 4 bytes are format, next to them is the actual msm-id */ - msm_id++; - - switch ((enum _msm_id)*msm_id) { - case MSM8996V3: - case APQ8096V3: - version = MSM8996_V3; - break; - case MSM8996SG: - case APQ8096SG: - version = MSM8996_SG; - break; - default: - version = NUM_OF_MSM8996_VERSIONS; - } - - return version; -} - -static int qcom_cpufreq_kryo_probe(struct platform_device *pdev) -{ - struct opp_table **opp_tables; - enum _msm8996_version msm8996_version; - struct nvmem_cell *speedbin_nvmem; - struct device_node *np; - struct device *cpu_dev; - unsigned cpu; - u8 *speedbin; - u32 versions; - size_t len; - int ret; - - cpu_dev = get_cpu_device(0); - if (!cpu_dev) - return -ENODEV; - - msm8996_version = qcom_cpufreq_kryo_get_msm_id(); - if (NUM_OF_MSM8996_VERSIONS == msm8996_version) { - dev_err(cpu_dev, "Not Snapdragon 820/821!"); - return -ENODEV; - } - - np = dev_pm_opp_of_get_opp_desc_node(cpu_dev); - if (!np) - return -ENOENT; - - ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu"); - if (!ret) { - of_node_put(np); - return -ENOENT; - } - - speedbin_nvmem = of_nvmem_cell_get(np, NULL); - of_node_put(np); - if (IS_ERR(speedbin_nvmem)) { - if (PTR_ERR(speedbin_nvmem) != -EPROBE_DEFER) - dev_err(cpu_dev, "Could not get nvmem cell: %ld\n", - PTR_ERR(speedbin_nvmem)); - return PTR_ERR(speedbin_nvmem); - } - - speedbin = nvmem_cell_read(speedbin_nvmem, &len); - nvmem_cell_put(speedbin_nvmem); - if (IS_ERR(speedbin)) - return PTR_ERR(speedbin); - - switch (msm8996_version) { - case MSM8996_V3: - versions = 1 << (unsigned int)(*speedbin); - break; - case MSM8996_SG: - versions = 1 << ((unsigned int)(*speedbin) + 4); - break; - default: - BUG(); - break; - } - kfree(speedbin); - - opp_tables = kcalloc(num_possible_cpus(), sizeof(*opp_tables), GFP_KERNEL); - if (!opp_tables) - return -ENOMEM; - - for_each_possible_cpu(cpu) { - cpu_dev = get_cpu_device(cpu); - if (NULL == cpu_dev) { - ret = -ENODEV; - goto free_opp; - } - - opp_tables[cpu] = dev_pm_opp_set_supported_hw(cpu_dev, - &versions, 1); - if (IS_ERR(opp_tables[cpu])) { - ret = PTR_ERR(opp_tables[cpu]); - dev_err(cpu_dev, "Failed to set supported hardware\n"); - goto free_opp; - } - } - - cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1, - NULL, 0); - if (!IS_ERR(cpufreq_dt_pdev)) { - platform_set_drvdata(pdev, opp_tables); - return 0; - } - - ret = PTR_ERR(cpufreq_dt_pdev); - dev_err(cpu_dev, "Failed to register platform device\n"); - -free_opp: - for_each_possible_cpu(cpu) { - if (IS_ERR_OR_NULL(opp_tables[cpu])) - break; - dev_pm_opp_put_supported_hw(opp_tables[cpu]); - } - kfree(opp_tables); - - return ret; -} - -static int qcom_cpufreq_kryo_remove(struct platform_device *pdev) -{ - struct opp_table **opp_tables = platform_get_drvdata(pdev); - unsigned int cpu; - - platform_device_unregister(cpufreq_dt_pdev); - - for_each_possible_cpu(cpu) - dev_pm_opp_put_supported_hw(opp_tables[cpu]); - - kfree(opp_tables); - - return 0; -} - -static struct platform_driver qcom_cpufreq_kryo_driver = { - .probe = qcom_cpufreq_kryo_probe, - .remove = qcom_cpufreq_kryo_remove, - .driver = { - .name = "qcom-cpufreq-kryo", - }, -}; - -static const struct of_device_id qcom_cpufreq_kryo_match_list[] __initconst = { - { .compatible = "qcom,apq8096", }, - { .compatible = "qcom,msm8996", }, - {} -}; - -/* - * Since the driver depends on smem and nvmem drivers, which may - * return EPROBE_DEFER, all the real activity is done in the probe, - * which may be defered as well. The init here is only registering - * the driver and the platform device. - */ -static int __init qcom_cpufreq_kryo_init(void) -{ - struct device_node *np = of_find_node_by_path("/"); - const struct of_device_id *match; - int ret; - - if (!np) - return -ENODEV; - - match = of_match_node(qcom_cpufreq_kryo_match_list, np); - of_node_put(np); - if (!match) - return -ENODEV; - - ret = platform_driver_register(&qcom_cpufreq_kryo_driver); - if (unlikely(ret < 0)) - return ret; - - kryo_cpufreq_pdev = platform_device_register_simple( - "qcom-cpufreq-kryo", -1, NULL, 0); - ret = PTR_ERR_OR_ZERO(kryo_cpufreq_pdev); - if (0 == ret) - return 0; - - platform_driver_unregister(&qcom_cpufreq_kryo_driver); - return ret; -} -module_init(qcom_cpufreq_kryo_init); - -static void __exit qcom_cpufreq_kryo_exit(void) -{ - platform_device_unregister(kryo_cpufreq_pdev); - platform_driver_unregister(&qcom_cpufreq_kryo_driver); -} -module_exit(qcom_cpufreq_kryo_exit); - -MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Kryo CPUfreq driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c new file mode 100644 index 0000000000000000000000000000000000000000..f0d2d5035413bac89134e9e72ef64d33acc0bcd2 --- /dev/null +++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +/* + * In Certain QCOM SoCs like apq8096 and msm8996 that have KRYO processors, + * the CPU frequency subset and voltage value of each OPP varies + * based on the silicon variant in use. Qualcomm Process Voltage Scaling Tables + * defines the voltage and frequency value based on the msm-id in SMEM + * and speedbin blown in the efuse combination. + * The qcom-cpufreq-nvmem driver reads the msm-id and efuse value from the SoC + * to provide the OPP framework with required information. + * This is used to determine the voltage and frequency value for each OPP of + * operating-points-v2 table when it is parsed by the OPP framework. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSM_ID_SMEM 137 + +enum _msm_id { + MSM8996V3 = 0xF6ul, + APQ8096V3 = 0x123ul, + MSM8996SG = 0x131ul, + APQ8096SG = 0x138ul, +}; + +enum _msm8996_version { + MSM8996_V3, + MSM8996_SG, + NUM_OF_MSM8996_VERSIONS, +}; + +struct qcom_cpufreq_drv; + +struct qcom_cpufreq_match_data { + int (*get_version)(struct device *cpu_dev, + struct nvmem_cell *speedbin_nvmem, + struct qcom_cpufreq_drv *drv); + const char **genpd_names; +}; + +struct qcom_cpufreq_drv { + struct opp_table **opp_tables; + struct opp_table **genpd_opp_tables; + u32 versions; + const struct qcom_cpufreq_match_data *data; +}; + +static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev; + +static enum _msm8996_version qcom_cpufreq_get_msm_id(void) +{ + size_t len; + u32 *msm_id; + enum _msm8996_version version; + + msm_id = qcom_smem_get(QCOM_SMEM_HOST_ANY, MSM_ID_SMEM, &len); + if (IS_ERR(msm_id)) + return NUM_OF_MSM8996_VERSIONS; + + /* The first 4 bytes are format, next to them is the actual msm-id */ + msm_id++; + + switch ((enum _msm_id)*msm_id) { + case MSM8996V3: + case APQ8096V3: + version = MSM8996_V3; + break; + case MSM8996SG: + case APQ8096SG: + version = MSM8996_SG; + break; + default: + version = NUM_OF_MSM8996_VERSIONS; + } + + return version; +} + +static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev, + struct nvmem_cell *speedbin_nvmem, + struct qcom_cpufreq_drv *drv) +{ + size_t len; + u8 *speedbin; + enum _msm8996_version msm8996_version; + + msm8996_version = qcom_cpufreq_get_msm_id(); + if (NUM_OF_MSM8996_VERSIONS == msm8996_version) { + dev_err(cpu_dev, "Not Snapdragon 820/821!"); + return -ENODEV; + } + + speedbin = nvmem_cell_read(speedbin_nvmem, &len); + if (IS_ERR(speedbin)) + return PTR_ERR(speedbin); + + switch (msm8996_version) { + case MSM8996_V3: + drv->versions = 1 << (unsigned int)(*speedbin); + break; + case MSM8996_SG: + drv->versions = 1 << ((unsigned int)(*speedbin) + 4); + break; + default: + BUG(); + break; + } + + kfree(speedbin); + return 0; +} + +static const struct qcom_cpufreq_match_data match_data_kryo = { + .get_version = qcom_cpufreq_kryo_name_version, +}; + +static const char *qcs404_genpd_names[] = { "cpr", NULL }; + +static const struct qcom_cpufreq_match_data match_data_qcs404 = { + .genpd_names = qcs404_genpd_names, +}; + +static int qcom_cpufreq_probe(struct platform_device *pdev) +{ + struct qcom_cpufreq_drv *drv; + struct nvmem_cell *speedbin_nvmem; + struct device_node *np; + struct device *cpu_dev; + unsigned cpu; + const struct of_device_id *match; + int ret; + + cpu_dev = get_cpu_device(0); + if (!cpu_dev) + return -ENODEV; + + np = dev_pm_opp_of_get_opp_desc_node(cpu_dev); + if (!np) + return -ENOENT; + + ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu"); + if (!ret) { + of_node_put(np); + return -ENOENT; + } + + drv = kzalloc(sizeof(*drv), GFP_KERNEL); + if (!drv) + return -ENOMEM; + + match = pdev->dev.platform_data; + drv->data = match->data; + if (!drv->data) { + ret = -ENODEV; + goto free_drv; + } + + if (drv->data->get_version) { + speedbin_nvmem = of_nvmem_cell_get(np, NULL); + if (IS_ERR(speedbin_nvmem)) { + if (PTR_ERR(speedbin_nvmem) != -EPROBE_DEFER) + dev_err(cpu_dev, + "Could not get nvmem cell: %ld\n", + PTR_ERR(speedbin_nvmem)); + ret = PTR_ERR(speedbin_nvmem); + goto free_drv; + } + + ret = drv->data->get_version(cpu_dev, speedbin_nvmem, drv); + if (ret) { + nvmem_cell_put(speedbin_nvmem); + goto free_drv; + } + nvmem_cell_put(speedbin_nvmem); + } + of_node_put(np); + + drv->opp_tables = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tables), + GFP_KERNEL); + if (!drv->opp_tables) { + ret = -ENOMEM; + goto free_drv; + } + + drv->genpd_opp_tables = kcalloc(num_possible_cpus(), + sizeof(*drv->genpd_opp_tables), + GFP_KERNEL); + if (!drv->genpd_opp_tables) { + ret = -ENOMEM; + goto free_opp; + } + + for_each_possible_cpu(cpu) { + cpu_dev = get_cpu_device(cpu); + if (NULL == cpu_dev) { + ret = -ENODEV; + goto free_genpd_opp; + } + + if (drv->data->get_version) { + drv->opp_tables[cpu] = + dev_pm_opp_set_supported_hw(cpu_dev, + &drv->versions, 1); + if (IS_ERR(drv->opp_tables[cpu])) { + ret = PTR_ERR(drv->opp_tables[cpu]); + dev_err(cpu_dev, + "Failed to set supported hardware\n"); + goto free_genpd_opp; + } + } + + if (drv->data->genpd_names) { + drv->genpd_opp_tables[cpu] = + dev_pm_opp_attach_genpd(cpu_dev, + drv->data->genpd_names, + NULL); + if (IS_ERR(drv->genpd_opp_tables[cpu])) { + ret = PTR_ERR(drv->genpd_opp_tables[cpu]); + if (ret != -EPROBE_DEFER) + dev_err(cpu_dev, + "Could not attach to pm_domain: %d\n", + ret); + goto free_genpd_opp; + } + } + } + + cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1, + NULL, 0); + if (!IS_ERR(cpufreq_dt_pdev)) { + platform_set_drvdata(pdev, drv); + return 0; + } + + ret = PTR_ERR(cpufreq_dt_pdev); + dev_err(cpu_dev, "Failed to register platform device\n"); + +free_genpd_opp: + for_each_possible_cpu(cpu) { + if (IS_ERR_OR_NULL(drv->genpd_opp_tables[cpu])) + break; + dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]); + } + kfree(drv->genpd_opp_tables); +free_opp: + for_each_possible_cpu(cpu) { + if (IS_ERR_OR_NULL(drv->opp_tables[cpu])) + break; + dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]); + } + kfree(drv->opp_tables); +free_drv: + kfree(drv); + + return ret; +} + +static int qcom_cpufreq_remove(struct platform_device *pdev) +{ + struct qcom_cpufreq_drv *drv = platform_get_drvdata(pdev); + unsigned int cpu; + + platform_device_unregister(cpufreq_dt_pdev); + + for_each_possible_cpu(cpu) { + if (drv->opp_tables[cpu]) + dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]); + if (drv->genpd_opp_tables[cpu]) + dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]); + } + + kfree(drv->opp_tables); + kfree(drv->genpd_opp_tables); + kfree(drv); + + return 0; +} + +static struct platform_driver qcom_cpufreq_driver = { + .probe = qcom_cpufreq_probe, + .remove = qcom_cpufreq_remove, + .driver = { + .name = "qcom-cpufreq-nvmem", + }, +}; + +static const struct of_device_id qcom_cpufreq_match_list[] __initconst = { + { .compatible = "qcom,apq8096", .data = &match_data_kryo }, + { .compatible = "qcom,msm8996", .data = &match_data_kryo }, + { .compatible = "qcom,qcs404", .data = &match_data_qcs404 }, + {}, +}; + +/* + * Since the driver depends on smem and nvmem drivers, which may + * return EPROBE_DEFER, all the real activity is done in the probe, + * which may be defered as well. The init here is only registering + * the driver and the platform device. + */ +static int __init qcom_cpufreq_init(void) +{ + struct device_node *np = of_find_node_by_path("/"); + const struct of_device_id *match; + int ret; + + if (!np) + return -ENODEV; + + match = of_match_node(qcom_cpufreq_match_list, np); + of_node_put(np); + if (!match) + return -ENODEV; + + ret = platform_driver_register(&qcom_cpufreq_driver); + if (unlikely(ret < 0)) + return ret; + + cpufreq_pdev = platform_device_register_data(NULL, "qcom-cpufreq-nvmem", + -1, match, sizeof(*match)); + ret = PTR_ERR_OR_ZERO(cpufreq_pdev); + if (0 == ret) + return 0; + + platform_driver_unregister(&qcom_cpufreq_driver); + return ret; +} +module_init(qcom_cpufreq_init); + +static void __exit qcom_cpufreq_exit(void) +{ + platform_device_unregister(cpufreq_pdev); + platform_driver_unregister(&qcom_cpufreq_driver); +} +module_exit(qcom_cpufreq_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. CPUfreq driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cpufreq/sun50i-cpufreq-nvmem.c b/drivers/cpufreq/sun50i-cpufreq-nvmem.c new file mode 100644 index 0000000000000000000000000000000000000000..eca32e443716c58aa330e14d3f251acb8ff8e52a --- /dev/null +++ b/drivers/cpufreq/sun50i-cpufreq-nvmem.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Allwinner CPUFreq nvmem based driver + * + * The sun50i-cpufreq-nvmem driver reads the efuse value from the SoC to + * provide the OPP framework with required information. + * + * Copyright (C) 2019 Yangtao Li + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include + +#define MAX_NAME_LEN 7 + +#define NVMEM_MASK 0x7 +#define NVMEM_SHIFT 5 + +static struct platform_device *cpufreq_dt_pdev, *sun50i_cpufreq_pdev; + +/** + * sun50i_cpufreq_get_efuse() - Parse and return efuse value present on SoC + * @versions: Set to the value parsed from efuse + * + * Returns 0 if success. + */ +static int sun50i_cpufreq_get_efuse(u32 *versions) +{ + struct nvmem_cell *speedbin_nvmem; + struct device_node *np; + struct device *cpu_dev; + u32 *speedbin, efuse_value; + size_t len; + int ret; + + cpu_dev = get_cpu_device(0); + if (!cpu_dev) + return -ENODEV; + + np = dev_pm_opp_of_get_opp_desc_node(cpu_dev); + if (!np) + return -ENOENT; + + ret = of_device_is_compatible(np, + "allwinner,sun50i-h6-operating-points"); + if (!ret) { + of_node_put(np); + return -ENOENT; + } + + speedbin_nvmem = of_nvmem_cell_get(np, NULL); + of_node_put(np); + if (IS_ERR(speedbin_nvmem)) { + if (PTR_ERR(speedbin_nvmem) != -EPROBE_DEFER) + pr_err("Could not get nvmem cell: %ld\n", + PTR_ERR(speedbin_nvmem)); + return PTR_ERR(speedbin_nvmem); + } + + speedbin = nvmem_cell_read(speedbin_nvmem, &len); + nvmem_cell_put(speedbin_nvmem); + if (IS_ERR(speedbin)) + return PTR_ERR(speedbin); + + efuse_value = (*speedbin >> NVMEM_SHIFT) & NVMEM_MASK; + switch (efuse_value) { + case 0b0001: + *versions = 1; + break; + case 0b0011: + *versions = 2; + break; + default: + /* + * For other situations, we treat it as bin0. + * This vf table can be run for any good cpu. + */ + *versions = 0; + break; + } + + kfree(speedbin); + return 0; +}; + +static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev) +{ + struct opp_table **opp_tables; + char name[MAX_NAME_LEN]; + unsigned int cpu; + u32 speed = 0; + int ret; + + opp_tables = kcalloc(num_possible_cpus(), sizeof(*opp_tables), + GFP_KERNEL); + if (!opp_tables) + return -ENOMEM; + + ret = sun50i_cpufreq_get_efuse(&speed); + if (ret) + return ret; + + snprintf(name, MAX_NAME_LEN, "speed%d", speed); + + for_each_possible_cpu(cpu) { + struct device *cpu_dev = get_cpu_device(cpu); + + if (!cpu_dev) { + ret = -ENODEV; + goto free_opp; + } + + opp_tables[cpu] = dev_pm_opp_set_prop_name(cpu_dev, name); + if (IS_ERR(opp_tables[cpu])) { + ret = PTR_ERR(opp_tables[cpu]); + pr_err("Failed to set prop name\n"); + goto free_opp; + } + } + + cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1, + NULL, 0); + if (!IS_ERR(cpufreq_dt_pdev)) { + platform_set_drvdata(pdev, opp_tables); + return 0; + } + + ret = PTR_ERR(cpufreq_dt_pdev); + pr_err("Failed to register platform device\n"); + +free_opp: + for_each_possible_cpu(cpu) { + if (IS_ERR_OR_NULL(opp_tables[cpu])) + break; + dev_pm_opp_put_prop_name(opp_tables[cpu]); + } + kfree(opp_tables); + + return ret; +} + +static int sun50i_cpufreq_nvmem_remove(struct platform_device *pdev) +{ + struct opp_table **opp_tables = platform_get_drvdata(pdev); + unsigned int cpu; + + platform_device_unregister(cpufreq_dt_pdev); + + for_each_possible_cpu(cpu) + dev_pm_opp_put_prop_name(opp_tables[cpu]); + + kfree(opp_tables); + + return 0; +} + +static struct platform_driver sun50i_cpufreq_driver = { + .probe = sun50i_cpufreq_nvmem_probe, + .remove = sun50i_cpufreq_nvmem_remove, + .driver = { + .name = "sun50i-cpufreq-nvmem", + }, +}; + +static const struct of_device_id sun50i_cpufreq_match_list[] = { + { .compatible = "allwinner,sun50i-h6" }, + {} +}; + +static const struct of_device_id *sun50i_cpufreq_match_node(void) +{ + const struct of_device_id *match; + struct device_node *np; + + np = of_find_node_by_path("/"); + match = of_match_node(sun50i_cpufreq_match_list, np); + of_node_put(np); + + return match; +} + +/* + * Since the driver depends on nvmem drivers, which may return EPROBE_DEFER, + * all the real activity is done in the probe, which may be defered as well. + * The init here is only registering the driver and the platform device. + */ +static int __init sun50i_cpufreq_init(void) +{ + const struct of_device_id *match; + int ret; + + match = sun50i_cpufreq_match_node(); + if (!match) + return -ENODEV; + + ret = platform_driver_register(&sun50i_cpufreq_driver); + if (unlikely(ret < 0)) + return ret; + + sun50i_cpufreq_pdev = + platform_device_register_simple("sun50i-cpufreq-nvmem", + -1, NULL, 0); + ret = PTR_ERR_OR_ZERO(sun50i_cpufreq_pdev); + if (ret == 0) + return 0; + + platform_driver_unregister(&sun50i_cpufreq_driver); + return ret; +} +module_init(sun50i_cpufreq_init); + +static void __exit sun50i_cpufreq_exit(void) +{ + platform_device_unregister(sun50i_cpufreq_pdev); + platform_driver_unregister(&sun50i_cpufreq_driver); +} +module_exit(sun50i_cpufreq_exit); + +MODULE_DESCRIPTION("Sun50i-h6 cpufreq driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c index 2ad1ae17932d27b429506597eec9bbf35270611f..aeaa883a8c9d5e4084277cc4b28ea8e26208b190 100644 --- a/drivers/cpufreq/ti-cpufreq.c +++ b/drivers/cpufreq/ti-cpufreq.c @@ -77,6 +77,7 @@ static unsigned long dra7_efuse_xlate(struct ti_cpufreq_data *opp_data, case DRA7_EFUSE_HAS_ALL_MPU_OPP: case DRA7_EFUSE_HAS_HIGH_MPU_OPP: calculated_efuse |= DRA7_EFUSE_HIGH_MPU_OPP; + /* Fall through */ case DRA7_EFUSE_HAS_OD_MPU_OPP: calculated_efuse |= DRA7_EFUSE_OD_MPU_OPP; } diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index a4ac31e4a58c3b6004003403f783b254529bad7b..88727b7c0d592cb50c92f085b624a7b659313b27 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig @@ -33,6 +33,17 @@ config CPU_IDLE_GOV_TEO Some workloads benefit from using it and it generally should be safe to use. Say Y here if you are not happy with the alternatives. +config CPU_IDLE_GOV_HALTPOLL + bool "Haltpoll governor (for virtualized systems)" + depends on KVM_GUEST + help + This governor implements haltpoll idle state selection, to be + used in conjunction with the haltpoll cpuidle driver, allowing + for polling for a certain amount of time before entering idle + state. + + Some virtualized workloads benefit from using it. + config DT_IDLE_STATES bool @@ -51,6 +62,15 @@ depends on PPC source "drivers/cpuidle/Kconfig.powerpc" endmenu +config HALTPOLL_CPUIDLE + tristate "Halt poll cpuidle driver" + depends on X86 && KVM_GUEST + default y + help + This option enables halt poll cpuidle driver, which allows to poll + before halting in the guest (more efficient than polling in the + host via halt_poll_ns for some scenarios). + endif config ARCH_NEEDS_CPU_IDLE_COUPLED diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm index 48cb3d4bb7d1344afb921e1b53d7b1fcb32ad162..d8530475493cb552e308021b449aaab3d12c5382 100644 --- a/drivers/cpuidle/Kconfig.arm +++ b/drivers/cpuidle/Kconfig.arm @@ -13,6 +13,16 @@ config ARM_CPUIDLE initialized by calling the CPU operations init idle hook provided by architecture code. +config ARM_PSCI_CPUIDLE + bool "PSCI CPU idle Driver" + depends on ARM_PSCI_FW + select DT_IDLE_STATES + select CPU_IDLE_MULTIPLE_DRIVERS + help + Select this to enable PSCI firmware based CPUidle driver for ARM. + It provides an idle driver that is capable of detecting and + managing idle states through the PSCI firmware interface. + config ARM_BIG_LITTLE_CPUIDLE bool "Support for ARM big.LITTLE processors" depends on ARCH_VEXPRESS_TC2_PM || ARCH_EXYNOS diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index 9d7176cee3d376195a6bbe7ebbe67956e4a5ca52..ee70d5cc5b996b446bb130dd8ee47dae63c4c23d 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile @@ -7,6 +7,7 @@ obj-y += cpuidle.o driver.o governor.o sysfs.o governors/ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o obj-$(CONFIG_DT_IDLE_STATES) += dt_idle_states.o obj-$(CONFIG_ARCH_HAS_CPU_RELAX) += poll_state.o +obj-$(CONFIG_HALTPOLL_CPUIDLE) += cpuidle-haltpoll.o ################################################################################## # ARM SoC drivers @@ -20,6 +21,7 @@ obj-$(CONFIG_ARM_U8500_CPUIDLE) += cpuidle-ux500.o obj-$(CONFIG_ARM_AT91_CPUIDLE) += cpuidle-at91.o obj-$(CONFIG_ARM_EXYNOS_CPUIDLE) += cpuidle-exynos.o obj-$(CONFIG_ARM_CPUIDLE) += cpuidle-arm.o +obj-$(CONFIG_ARM_PSCI_CPUIDLE) += cpuidle-psci.o ############################################################################### # MIPS drivers diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c index 5bcd82c35dcf72fa92c49409aeb975852ff65e9d..9e5156d3962769e54f6742ea5f72a30f2bd565b7 100644 --- a/drivers/cpuidle/cpuidle-arm.c +++ b/drivers/cpuidle/cpuidle-arm.c @@ -15,7 +15,6 @@ #include #include #include -#include #include @@ -106,11 +105,17 @@ static int __init arm_idle_init_cpu(int cpu) ret = arm_cpuidle_init(cpu); /* - * Allow the initialization to continue for other CPUs, if the reported - * failure is a HW misconfiguration/breakage (-ENXIO). + * Allow the initialization to continue for other CPUs, if the + * reported failure is a HW misconfiguration/breakage (-ENXIO). + * + * Some platforms do not support idle operations + * (arm_cpuidle_init() returning -EOPNOTSUPP), we should + * not flag this case as an error, it is a valid + * configuration. */ if (ret) { - pr_err("CPU %d failed to init idle CPU ops\n", cpu); + if (ret != -EOPNOTSUPP) + pr_err("CPU %d failed to init idle CPU ops\n", cpu); ret = ret == -ENXIO ? 0 : ret; goto out_kfree_drv; } diff --git a/drivers/cpuidle/cpuidle-haltpoll.c b/drivers/cpuidle/cpuidle-haltpoll.c new file mode 100644 index 0000000000000000000000000000000000000000..932390b028f1df148d8f96bd6a5b1b6b36fcec72 --- /dev/null +++ b/drivers/cpuidle/cpuidle-haltpoll.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cpuidle driver for haltpoll governor. + * + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Authors: Marcelo Tosatti + */ + +#include +#include +#include +#include +#include +#include +#include + +static struct cpuidle_device __percpu *haltpoll_cpuidle_devices; +static enum cpuhp_state haltpoll_hp_state; + +static int default_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + if (current_clr_polling_and_test()) { + local_irq_enable(); + return index; + } + default_idle(); + return index; +} + +static struct cpuidle_driver haltpoll_driver = { + .name = "haltpoll", + .governor = "haltpoll", + .states = { + { /* entry 0 is for polling */ }, + { + .enter = default_enter_idle, + .exit_latency = 1, + .target_residency = 1, + .power_usage = -1, + .name = "haltpoll idle", + .desc = "default architecture idle", + }, + }, + .safe_state_index = 0, + .state_count = 2, +}; + +static int haltpoll_cpu_online(unsigned int cpu) +{ + struct cpuidle_device *dev; + + dev = per_cpu_ptr(haltpoll_cpuidle_devices, cpu); + if (!dev->registered) { + dev->cpu = cpu; + if (cpuidle_register_device(dev)) { + pr_notice("cpuidle_register_device %d failed!\n", cpu); + return -EIO; + } + arch_haltpoll_enable(cpu); + } + + return 0; +} + +static int haltpoll_cpu_offline(unsigned int cpu) +{ + struct cpuidle_device *dev; + + dev = per_cpu_ptr(haltpoll_cpuidle_devices, cpu); + if (dev->registered) { + arch_haltpoll_disable(cpu); + cpuidle_unregister_device(dev); + } + + return 0; +} + +static void haltpoll_uninit(void) +{ + if (haltpoll_hp_state) + cpuhp_remove_state(haltpoll_hp_state); + cpuidle_unregister_driver(&haltpoll_driver); + + free_percpu(haltpoll_cpuidle_devices); + haltpoll_cpuidle_devices = NULL; +} + +static int __init haltpoll_init(void) +{ + int ret; + struct cpuidle_driver *drv = &haltpoll_driver; + + cpuidle_poll_state_init(drv); + + if (!kvm_para_available() || + !kvm_para_has_hint(KVM_HINTS_REALTIME)) + return -ENODEV; + + ret = cpuidle_register_driver(drv); + if (ret < 0) + return ret; + + haltpoll_cpuidle_devices = alloc_percpu(struct cpuidle_device); + if (haltpoll_cpuidle_devices == NULL) { + cpuidle_unregister_driver(drv); + return -ENOMEM; + } + + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "cpuidle/haltpoll:online", + haltpoll_cpu_online, haltpoll_cpu_offline); + if (ret < 0) { + haltpoll_uninit(); + } else { + haltpoll_hp_state = ret; + ret = 0; + } + + return ret; +} + +static void __exit haltpoll_exit(void) +{ + haltpoll_uninit(); +} + +module_init(haltpoll_init); +module_exit(haltpoll_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Marcelo Tosatti "); diff --git a/drivers/cpuidle/cpuidle-psci.c b/drivers/cpuidle/cpuidle-psci.c new file mode 100644 index 0000000000000000000000000000000000000000..f3c1a2396f989e29a9251106484d762ccca97aec --- /dev/null +++ b/drivers/cpuidle/cpuidle-psci.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * PSCI CPU idle driver. + * + * Copyright (C) 2019 ARM Ltd. + * Author: Lorenzo Pieralisi + */ + +#define pr_fmt(fmt) "CPUidle PSCI: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "dt_idle_states.h" + +static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state); + +static int psci_enter_idle_state(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int idx) +{ + u32 *state = __this_cpu_read(psci_power_state); + + return CPU_PM_CPU_IDLE_ENTER_PARAM(psci_cpu_suspend_enter, + idx, state[idx - 1]); +} + +static struct cpuidle_driver psci_idle_driver __initdata = { + .name = "psci_idle", + .owner = THIS_MODULE, + /* + * PSCI idle states relies on architectural WFI to + * be represented as state index 0. + */ + .states[0] = { + .enter = psci_enter_idle_state, + .exit_latency = 1, + .target_residency = 1, + .power_usage = UINT_MAX, + .name = "WFI", + .desc = "ARM WFI", + } +}; + +static const struct of_device_id psci_idle_state_match[] __initconst = { + { .compatible = "arm,idle-state", + .data = psci_enter_idle_state }, + { }, +}; + +static int __init psci_dt_parse_state_node(struct device_node *np, u32 *state) +{ + int err = of_property_read_u32(np, "arm,psci-suspend-param", state); + + if (err) { + pr_warn("%pOF missing arm,psci-suspend-param property\n", np); + return err; + } + + if (!psci_power_state_is_valid(*state)) { + pr_warn("Invalid PSCI power state %#x\n", *state); + return -EINVAL; + } + + return 0; +} + +static int __init psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu) +{ + int i, ret = 0, count = 0; + u32 *psci_states; + struct device_node *state_node; + + /* Count idle states */ + while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states", + count))) { + count++; + of_node_put(state_node); + } + + if (!count) + return -ENODEV; + + psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL); + if (!psci_states) + return -ENOMEM; + + for (i = 0; i < count; i++) { + state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i); + ret = psci_dt_parse_state_node(state_node, &psci_states[i]); + of_node_put(state_node); + + if (ret) + goto free_mem; + + pr_debug("psci-power-state %#x index %d\n", psci_states[i], i); + } + + /* Idle states parsed correctly, initialize per-cpu pointer */ + per_cpu(psci_power_state, cpu) = psci_states; + return 0; + +free_mem: + kfree(psci_states); + return ret; +} + +static __init int psci_cpu_init_idle(unsigned int cpu) +{ + struct device_node *cpu_node; + int ret; + + /* + * If the PSCI cpu_suspend function hook has not been initialized + * idle states must not be enabled, so bail out + */ + if (!psci_ops.cpu_suspend) + return -EOPNOTSUPP; + + cpu_node = of_cpu_device_node_get(cpu); + if (!cpu_node) + return -ENODEV; + + ret = psci_dt_cpu_init_idle(cpu_node, cpu); + + of_node_put(cpu_node); + + return ret; +} + +static int __init psci_idle_init_cpu(int cpu) +{ + struct cpuidle_driver *drv; + struct device_node *cpu_node; + const char *enable_method; + int ret = 0; + + cpu_node = of_cpu_device_node_get(cpu); + if (!cpu_node) + return -ENODEV; + + /* + * Check whether the enable-method for the cpu is PSCI, fail + * if it is not. + */ + enable_method = of_get_property(cpu_node, "enable-method", NULL); + if (!enable_method || (strcmp(enable_method, "psci"))) + ret = -ENODEV; + + of_node_put(cpu_node); + if (ret) + return ret; + + drv = kmemdup(&psci_idle_driver, sizeof(*drv), GFP_KERNEL); + if (!drv) + return -ENOMEM; + + drv->cpumask = (struct cpumask *)cpumask_of(cpu); + + /* + * Initialize idle states data, starting at index 1, since + * by default idle state 0 is the quiescent state reached + * by the cpu by executing the wfi instruction. + * + * If no DT idle states are detected (ret == 0) let the driver + * initialization fail accordingly since there is no reason to + * initialize the idle driver if only wfi is supported, the + * default archictectural back-end already executes wfi + * on idle entry. + */ + ret = dt_init_idle_driver(drv, psci_idle_state_match, 1); + if (ret <= 0) { + ret = ret ? : -ENODEV; + goto out_kfree_drv; + } + + /* + * Initialize PSCI idle states. + */ + ret = psci_cpu_init_idle(cpu); + if (ret) { + pr_err("CPU %d failed to PSCI idle\n", cpu); + goto out_kfree_drv; + } + + ret = cpuidle_register(drv, NULL); + if (ret) + goto out_kfree_drv; + + return 0; + +out_kfree_drv: + kfree(drv); + return ret; +} + +/* + * psci_idle_init - Initializes PSCI cpuidle driver + * + * Initializes PSCI cpuidle driver for all CPUs, if any CPU fails + * to register cpuidle driver then rollback to cancel all CPUs + * registration. + */ +static int __init psci_idle_init(void) +{ + int cpu, ret; + struct cpuidle_driver *drv; + struct cpuidle_device *dev; + + for_each_possible_cpu(cpu) { + ret = psci_idle_init_cpu(cpu); + if (ret) + goto out_fail; + } + + return 0; + +out_fail: + while (--cpu >= 0) { + dev = per_cpu(cpuidle_devices, cpu); + drv = cpuidle_get_cpu_driver(dev); + cpuidle_unregister(drv); + kfree(drv); + } + + return ret; +} +device_initcall(psci_idle_init); diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 0f4b7c45df3e103cba0a5a617b782cee522a44be..0895b988fa92246d655b35d3af6e11f237f243e3 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -361,6 +361,36 @@ void cpuidle_reflect(struct cpuidle_device *dev, int index) cpuidle_curr_governor->reflect(dev, index); } +/** + * cpuidle_poll_time - return amount of time to poll for, + * governors can override dev->poll_limit_ns if necessary + * + * @drv: the cpuidle driver tied with the cpu + * @dev: the cpuidle device + * + */ +u64 cpuidle_poll_time(struct cpuidle_driver *drv, + struct cpuidle_device *dev) +{ + int i; + u64 limit_ns; + + if (dev->poll_limit_ns) + return dev->poll_limit_ns; + + limit_ns = TICK_NSEC; + for (i = 1; i < drv->state_count; i++) { + if (drv->states[i].disabled || dev->states_usage[i].disable) + continue; + + limit_ns = (u64)drv->states[i].target_residency * NSEC_PER_USEC; + } + + dev->poll_limit_ns = limit_ns; + + return dev->poll_limit_ns; +} + /** * cpuidle_install_idle_handler - installs the cpuidle idle loop handler */ diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h index d6613101af9246ee112df42c36a5abd2d63ceb56..9f336af17fa6038abe7b939b6c4718fd6965c540 100644 --- a/drivers/cpuidle/cpuidle.h +++ b/drivers/cpuidle/cpuidle.h @@ -9,6 +9,7 @@ /* For internal use only */ extern char param_governor[]; extern struct cpuidle_governor *cpuidle_curr_governor; +extern struct cpuidle_governor *cpuidle_prev_governor; extern struct list_head cpuidle_governors; extern struct list_head cpuidle_detected_devices; extern struct mutex cpuidle_lock; @@ -22,6 +23,7 @@ extern void cpuidle_install_idle_handler(void); extern void cpuidle_uninstall_idle_handler(void); /* governors */ +extern struct cpuidle_governor *cpuidle_find_governor(const char *str); extern int cpuidle_switch_governor(struct cpuidle_governor *gov); /* sysfs */ diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index dc32f34e68d9379dceee6f04795fe81473a8f9ca..80c1a830d99178c8906e66e044dbe445798b9ab6 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -254,12 +254,25 @@ static void __cpuidle_unregister_driver(struct cpuidle_driver *drv) */ int cpuidle_register_driver(struct cpuidle_driver *drv) { + struct cpuidle_governor *gov; int ret; spin_lock(&cpuidle_driver_lock); ret = __cpuidle_register_driver(drv); spin_unlock(&cpuidle_driver_lock); + if (!ret && !strlen(param_governor) && drv->governor && + (cpuidle_get_driver() == drv)) { + mutex_lock(&cpuidle_lock); + gov = cpuidle_find_governor(drv->governor); + if (gov) { + cpuidle_prev_governor = cpuidle_curr_governor; + if (cpuidle_switch_governor(gov) < 0) + cpuidle_prev_governor = NULL; + } + mutex_unlock(&cpuidle_lock); + } + return ret; } EXPORT_SYMBOL_GPL(cpuidle_register_driver); @@ -274,9 +287,21 @@ EXPORT_SYMBOL_GPL(cpuidle_register_driver); */ void cpuidle_unregister_driver(struct cpuidle_driver *drv) { + bool enabled = (cpuidle_get_driver() == drv); + spin_lock(&cpuidle_driver_lock); __cpuidle_unregister_driver(drv); spin_unlock(&cpuidle_driver_lock); + + if (!enabled) + return; + + mutex_lock(&cpuidle_lock); + if (cpuidle_prev_governor) { + if (!cpuidle_switch_governor(cpuidle_prev_governor)) + cpuidle_prev_governor = NULL; + } + mutex_unlock(&cpuidle_lock); } EXPORT_SYMBOL_GPL(cpuidle_unregister_driver); diff --git a/drivers/cpuidle/governor.c b/drivers/cpuidle/governor.c index 2e3e14192beee760b1341261b4b3da6ed1ff0d98..e9801f26c73270c6665a117a60b1e45d32186217 100644 --- a/drivers/cpuidle/governor.c +++ b/drivers/cpuidle/governor.c @@ -20,14 +20,15 @@ char param_governor[CPUIDLE_NAME_LEN]; LIST_HEAD(cpuidle_governors); struct cpuidle_governor *cpuidle_curr_governor; +struct cpuidle_governor *cpuidle_prev_governor; /** - * __cpuidle_find_governor - finds a governor of the specified name + * cpuidle_find_governor - finds a governor of the specified name * @str: the name * * Must be called with cpuidle_lock acquired. */ -static struct cpuidle_governor * __cpuidle_find_governor(const char *str) +struct cpuidle_governor *cpuidle_find_governor(const char *str) { struct cpuidle_governor *gov; @@ -87,7 +88,7 @@ int cpuidle_register_governor(struct cpuidle_governor *gov) return -ENODEV; mutex_lock(&cpuidle_lock); - if (__cpuidle_find_governor(gov->name) == NULL) { + if (cpuidle_find_governor(gov->name) == NULL) { ret = 0; list_add_tail(&gov->governor_list, &cpuidle_governors); if (!cpuidle_curr_governor || diff --git a/drivers/cpuidle/governors/Makefile b/drivers/cpuidle/governors/Makefile index 42f44cc610dda5f6745d5a69051272171f0b36b7..63abb5393a4d6bb8f80584f9021b89d325966118 100644 --- a/drivers/cpuidle/governors/Makefile +++ b/drivers/cpuidle/governors/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_CPU_IDLE_GOV_LADDER) += ladder.o obj-$(CONFIG_CPU_IDLE_GOV_MENU) += menu.o obj-$(CONFIG_CPU_IDLE_GOV_TEO) += teo.o +obj-$(CONFIG_CPU_IDLE_GOV_HALTPOLL) += haltpoll.o diff --git a/drivers/cpuidle/governors/haltpoll.c b/drivers/cpuidle/governors/haltpoll.c new file mode 100644 index 0000000000000000000000000000000000000000..7a703d2e006403cc73cd443a326c5adcb3bf58c9 --- /dev/null +++ b/drivers/cpuidle/governors/haltpoll.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * haltpoll.c - haltpoll idle governor + * + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Authors: Marcelo Tosatti + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned int guest_halt_poll_ns __read_mostly = 200000; +module_param(guest_halt_poll_ns, uint, 0644); + +/* division factor to shrink halt_poll_ns */ +static unsigned int guest_halt_poll_shrink __read_mostly = 2; +module_param(guest_halt_poll_shrink, uint, 0644); + +/* multiplication factor to grow per-cpu poll_limit_ns */ +static unsigned int guest_halt_poll_grow __read_mostly = 2; +module_param(guest_halt_poll_grow, uint, 0644); + +/* value in us to start growing per-cpu halt_poll_ns */ +static unsigned int guest_halt_poll_grow_start __read_mostly = 50000; +module_param(guest_halt_poll_grow_start, uint, 0644); + +/* allow shrinking guest halt poll */ +static bool guest_halt_poll_allow_shrink __read_mostly = true; +module_param(guest_halt_poll_allow_shrink, bool, 0644); + +/** + * haltpoll_select - selects the next idle state to enter + * @drv: cpuidle driver containing state data + * @dev: the CPU + * @stop_tick: indication on whether or not to stop the tick + */ +static int haltpoll_select(struct cpuidle_driver *drv, + struct cpuidle_device *dev, + bool *stop_tick) +{ + int latency_req = cpuidle_governor_latency_req(dev->cpu); + + if (!drv->state_count || latency_req == 0) { + *stop_tick = false; + return 0; + } + + if (dev->poll_limit_ns == 0) + return 1; + + /* Last state was poll? */ + if (dev->last_state_idx == 0) { + /* Halt if no event occurred on poll window */ + if (dev->poll_time_limit == true) + return 1; + + *stop_tick = false; + /* Otherwise, poll again */ + return 0; + } + + *stop_tick = false; + /* Last state was halt: poll */ + return 0; +} + +static void adjust_poll_limit(struct cpuidle_device *dev, unsigned int block_us) +{ + unsigned int val; + u64 block_ns = block_us*NSEC_PER_USEC; + + /* Grow cpu_halt_poll_us if + * cpu_halt_poll_us < block_ns < guest_halt_poll_us + */ + if (block_ns > dev->poll_limit_ns && block_ns <= guest_halt_poll_ns) { + val = dev->poll_limit_ns * guest_halt_poll_grow; + + if (val < guest_halt_poll_grow_start) + val = guest_halt_poll_grow_start; + if (val > guest_halt_poll_ns) + val = guest_halt_poll_ns; + + dev->poll_limit_ns = val; + } else if (block_ns > guest_halt_poll_ns && + guest_halt_poll_allow_shrink) { + unsigned int shrink = guest_halt_poll_shrink; + + val = dev->poll_limit_ns; + if (shrink == 0) + val = 0; + else + val /= shrink; + dev->poll_limit_ns = val; + } +} + +/** + * haltpoll_reflect - update variables and update poll time + * @dev: the CPU + * @index: the index of actual entered state + */ +static void haltpoll_reflect(struct cpuidle_device *dev, int index) +{ + dev->last_state_idx = index; + + if (index != 0) + adjust_poll_limit(dev, dev->last_residency); +} + +/** + * haltpoll_enable_device - scans a CPU's states and does setup + * @drv: cpuidle driver + * @dev: the CPU + */ +static int haltpoll_enable_device(struct cpuidle_driver *drv, + struct cpuidle_device *dev) +{ + dev->poll_limit_ns = 0; + + return 0; +} + +static struct cpuidle_governor haltpoll_governor = { + .name = "haltpoll", + .rating = 9, + .enable = haltpoll_enable_device, + .select = haltpoll_select, + .reflect = haltpoll_reflect, +}; + +static int __init init_haltpoll(void) +{ + if (kvm_para_available()) + return cpuidle_register_governor(&haltpoll_governor); + + return 0; +} + +postcore_initcall(init_haltpoll); diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index f0dddc66af26087b8d0c380fab157946058bc612..428eeb832fe7cd32cd8fc5fee37c7f980f70586c 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -38,7 +38,6 @@ struct ladder_device_state { struct ladder_device { struct ladder_device_state states[CPUIDLE_STATE_MAX]; - int last_state_idx; }; static DEFINE_PER_CPU(struct ladder_device, ladder_devices); @@ -49,12 +48,13 @@ static DEFINE_PER_CPU(struct ladder_device, ladder_devices); * @old_idx: the current state index * @new_idx: the new target state index */ -static inline void ladder_do_selection(struct ladder_device *ldev, +static inline void ladder_do_selection(struct cpuidle_device *dev, + struct ladder_device *ldev, int old_idx, int new_idx) { ldev->states[old_idx].stats.promotion_count = 0; ldev->states[old_idx].stats.demotion_count = 0; - ldev->last_state_idx = new_idx; + dev->last_state_idx = new_idx; } /** @@ -68,13 +68,13 @@ static int ladder_select_state(struct cpuidle_driver *drv, { struct ladder_device *ldev = this_cpu_ptr(&ladder_devices); struct ladder_device_state *last_state; - int last_residency, last_idx = ldev->last_state_idx; + int last_residency, last_idx = dev->last_state_idx; int first_idx = drv->states[0].flags & CPUIDLE_FLAG_POLLING ? 1 : 0; int latency_req = cpuidle_governor_latency_req(dev->cpu); /* Special case when user has set very strict latency requirement */ if (unlikely(latency_req == 0)) { - ladder_do_selection(ldev, last_idx, 0); + ladder_do_selection(dev, ldev, last_idx, 0); return 0; } @@ -91,7 +91,7 @@ static int ladder_select_state(struct cpuidle_driver *drv, last_state->stats.promotion_count++; last_state->stats.demotion_count = 0; if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) { - ladder_do_selection(ldev, last_idx, last_idx + 1); + ladder_do_selection(dev, ldev, last_idx, last_idx + 1); return last_idx + 1; } } @@ -107,7 +107,7 @@ static int ladder_select_state(struct cpuidle_driver *drv, if (drv->states[i].exit_latency <= latency_req) break; } - ladder_do_selection(ldev, last_idx, i); + ladder_do_selection(dev, ldev, last_idx, i); return i; } @@ -116,7 +116,7 @@ static int ladder_select_state(struct cpuidle_driver *drv, last_state->stats.demotion_count++; last_state->stats.promotion_count = 0; if (last_state->stats.demotion_count >= last_state->threshold.demotion_count) { - ladder_do_selection(ldev, last_idx, last_idx - 1); + ladder_do_selection(dev, ldev, last_idx, last_idx - 1); return last_idx - 1; } } @@ -139,7 +139,7 @@ static int ladder_enable_device(struct cpuidle_driver *drv, struct ladder_device_state *lstate; struct cpuidle_state *state; - ldev->last_state_idx = first_idx; + dev->last_state_idx = first_idx; for (i = first_idx; i < drv->state_count; i++) { state = &drv->states[i]; @@ -167,9 +167,8 @@ static int ladder_enable_device(struct cpuidle_driver *drv, */ static void ladder_reflect(struct cpuidle_device *dev, int index) { - struct ladder_device *ldev = this_cpu_ptr(&ladder_devices); if (index > 0) - ldev->last_state_idx = index; + dev->last_state_idx = index; } static struct cpuidle_governor ladder_governor = { diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index e9a28c7846d674a46a336d3685da0588e5421a0f..e5a5d0c8d66b1629a69f5e0a5c46f249fd49bf20 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -117,7 +117,6 @@ */ struct menu_device { - int last_state_idx; int needs_update; int tick_wakeup; @@ -302,9 +301,10 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, !drv->states[0].disabled && !dev->states_usage[0].disable)) { /* * In this case state[0] will be used no matter what, so return - * it right away and keep the tick running. + * it right away and keep the tick running if state[0] is a + * polling one. */ - *stop_tick = false; + *stop_tick = !(drv->states[0].flags & CPUIDLE_FLAG_POLLING); return 0; } @@ -395,16 +395,9 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, return idx; } - if (s->exit_latency > latency_req) { - /* - * If we break out of the loop for latency reasons, use - * the target residency of the selected state as the - * expected idle duration so that the tick is retained - * as long as that target residency is low enough. - */ - predicted_us = drv->states[idx].target_residency; + if (s->exit_latency > latency_req) break; - } + idx = i; } @@ -455,7 +448,7 @@ static void menu_reflect(struct cpuidle_device *dev, int index) { struct menu_device *data = this_cpu_ptr(&menu_devices); - data->last_state_idx = index; + dev->last_state_idx = index; data->needs_update = 1; data->tick_wakeup = tick_nohz_idle_got_tick(); } @@ -468,7 +461,7 @@ static void menu_reflect(struct cpuidle_device *dev, int index) static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct menu_device *data = this_cpu_ptr(&menu_devices); - int last_idx = data->last_state_idx; + int last_idx = dev->last_state_idx; struct cpuidle_state *target = &drv->states[last_idx]; unsigned int measured_us; unsigned int new_factor; diff --git a/drivers/cpuidle/governors/teo.c b/drivers/cpuidle/governors/teo.c index 7d05efdbd3c665871d23579d96d35a4d7a2fdd37..b5a0e498f7989791192f79e72e166eb5ed862a85 100644 --- a/drivers/cpuidle/governors/teo.c +++ b/drivers/cpuidle/governors/teo.c @@ -96,7 +96,6 @@ struct teo_idle_state { * @time_span_ns: Time between idle state selection and post-wakeup update. * @sleep_length_ns: Time till the closest timer event (at the selection time). * @states: Idle states data corresponding to this CPU. - * @last_state: Idle state entered by the CPU last time. * @interval_idx: Index of the most recent saved idle interval. * @intervals: Saved idle duration values. */ @@ -104,7 +103,6 @@ struct teo_cpu { u64 time_span_ns; u64 sleep_length_ns; struct teo_idle_state states[CPUIDLE_STATE_MAX]; - int last_state; int interval_idx; unsigned int intervals[INTERVALS]; }; @@ -125,12 +123,15 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) if (cpu_data->time_span_ns >= cpu_data->sleep_length_ns) { /* - * One of the safety nets has triggered or this was a timer - * wakeup (or equivalent). + * One of the safety nets has triggered or the wakeup was close + * enough to the closest timer event expected at the idle state + * selection time to be discarded. */ - measured_us = sleep_length_us; + measured_us = UINT_MAX; } else { - unsigned int lat = drv->states[cpu_data->last_state].exit_latency; + unsigned int lat; + + lat = drv->states[dev->last_state_idx].exit_latency; measured_us = ktime_to_us(cpu_data->time_span_ns); /* @@ -188,15 +189,6 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) cpu_data->states[idx_timer].hits = hits; } - /* - * If the total time span between idle state selection and the "reflect" - * callback is greater than or equal to the sleep length determined at - * the idle state selection time, the wakeup is likely to be due to a - * timer event. - */ - if (cpu_data->time_span_ns >= cpu_data->sleep_length_ns) - measured_us = UINT_MAX; - /* * Save idle duration values corresponding to non-timer wakeups for * pattern detection. @@ -242,12 +234,12 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); int latency_req = cpuidle_governor_latency_req(dev->cpu); unsigned int duration_us, count; - int max_early_idx, idx, i; + int max_early_idx, constraint_idx, idx, i; ktime_t delta_tick; - if (cpu_data->last_state >= 0) { + if (dev->last_state_idx >= 0) { teo_update(drv, dev); - cpu_data->last_state = -1; + dev->last_state_idx = -1; } cpu_data->time_span_ns = local_clock(); @@ -257,6 +249,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, count = 0; max_early_idx = -1; + constraint_idx = drv->state_count; idx = -1; for (i = 0; i < drv->state_count; i++) { @@ -286,16 +279,8 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, if (s->target_residency > duration_us) break; - if (s->exit_latency > latency_req) { - /* - * If we break out of the loop for latency reasons, use - * the target residency of the selected state as the - * expected idle duration to avoid stopping the tick - * as long as that target residency is low enough. - */ - duration_us = drv->states[idx].target_residency; - goto refine; - } + if (s->exit_latency > latency_req && constraint_idx > i) + constraint_idx = i; idx = i; @@ -321,7 +306,13 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, duration_us = drv->states[idx].target_residency; } -refine: + /* + * If there is a latency constraint, it may be necessary to use a + * shallower idle state than the one selected so far. + */ + if (constraint_idx < idx) + idx = constraint_idx; + if (idx < 0) { idx = 0; /* No states enabled. Must use 0. */ } else if (idx > 0) { @@ -331,13 +322,12 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, /* * Count and sum the most recent idle duration values less than - * the target residency of the state selected so far, find the - * max. + * the current expected idle duration value. */ for (i = 0; i < INTERVALS; i++) { unsigned int val = cpu_data->intervals[i]; - if (val >= drv->states[idx].target_residency) + if (val >= duration_us) continue; count++; @@ -356,8 +346,10 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * would be too shallow. */ if (!(tick_nohz_tick_stopped() && avg_us < TICK_USEC)) { - idx = teo_find_shallower_state(drv, dev, idx, avg_us); duration_us = avg_us; + if (drv->states[idx].target_residency > avg_us) + idx = teo_find_shallower_state(drv, dev, + idx, avg_us); } } } @@ -394,7 +386,7 @@ static void teo_reflect(struct cpuidle_device *dev, int state) { struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); - cpu_data->last_state = state; + dev->last_state_idx = state; /* * If the wakeup was not "natural", but triggered by one of the safety * nets, assume that the CPU might have been idle for the entire sleep diff --git a/drivers/cpuidle/poll_state.c b/drivers/cpuidle/poll_state.c index 02b9315a9e9680e8b077968931fa410c23e44b0f..c8fa5f41dfc4cfdc5c0a33d091f748f747ad1b31 100644 --- a/drivers/cpuidle/poll_state.c +++ b/drivers/cpuidle/poll_state.c @@ -20,16 +20,9 @@ static int __cpuidle poll_idle(struct cpuidle_device *dev, local_irq_enable(); if (!current_set_polling_and_test()) { unsigned int loop_count = 0; - u64 limit = TICK_NSEC; - int i; + u64 limit; - for (i = 1; i < drv->state_count; i++) { - if (drv->states[i].disabled || dev->states_usage[i].disable) - continue; - - limit = (u64)drv->states[i].target_residency * NSEC_PER_USEC; - break; - } + limit = cpuidle_poll_time(drv, dev); while (!need_resched()) { cpu_relax(); diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index eb20adb5de2349c059d328bb24d75696b2e1890e..2bb2683b493cf7a1769146a6d19ecb3d7f748f7b 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -334,6 +334,7 @@ struct cpuidle_state_kobj { struct cpuidle_state_usage *state_usage; struct completion kobj_unregister; struct kobject kobj; + struct cpuidle_device *device; }; #ifdef CONFIG_SUSPEND @@ -391,6 +392,7 @@ static inline void cpuidle_remove_s2idle_attr_group(struct cpuidle_state_kobj *k #define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj) #define kobj_to_state(k) (kobj_to_state_obj(k)->state) #define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage) +#define kobj_to_device(k) (kobj_to_state_obj(k)->device) #define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr) static ssize_t cpuidle_state_show(struct kobject *kobj, struct attribute *attr, @@ -414,10 +416,14 @@ static ssize_t cpuidle_state_store(struct kobject *kobj, struct attribute *attr, struct cpuidle_state *state = kobj_to_state(kobj); struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj); struct cpuidle_state_attr *cattr = attr_to_stateattr(attr); + struct cpuidle_device *dev = kobj_to_device(kobj); if (cattr->store) ret = cattr->store(state, state_usage, buf, size); + /* reset poll time cache */ + dev->poll_limit_ns = 0; + return ret; } @@ -468,6 +474,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device) } kobj->state = &drv->states[i]; kobj->state_usage = &device->states_usage[i]; + kobj->device = device; init_completion(&kobj->kobj_unregister); ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 603413f28fa35b5ac53959b8069d10e1d5ca8108..1fb622f2a87d93e0cd508f3b89a41e5212c534f1 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -27,7 +27,7 @@ config CRYPTO_DEV_PADLOCK_AES tristate "PadLock driver for AES algorithm" depends on CRYPTO_DEV_PADLOCK select CRYPTO_BLKCIPHER - select CRYPTO_AES + select CRYPTO_LIB_AES help Use VIA PadLock for AES algorithm. @@ -145,12 +145,32 @@ config CRYPTO_SHA512_S390 It is available as of z10. +config CRYPTO_SHA3_256_S390 + tristate "SHA3_224 and SHA3_256 digest algorithm" + depends on S390 + select CRYPTO_HASH + help + This is the s390 hardware accelerated implementation of the + SHA3_256 secure hash standard. + + It is available as of z14. + +config CRYPTO_SHA3_512_S390 + tristate "SHA3_384 and SHA3_512 digest algorithm" + depends on S390 + select CRYPTO_HASH + help + This is the s390 hardware accelerated implementation of the + SHA3_512 secure hash standard. + + It is available as of z14. + config CRYPTO_DES_S390 tristate "DES and Triple DES cipher algorithms" depends on S390 select CRYPTO_ALGAPI select CRYPTO_BLKCIPHER - select CRYPTO_DES + select CRYPTO_LIB_DES help This is the s390 hardware accelerated implementation of the DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). @@ -189,12 +209,12 @@ config S390_PRNG It is available as of z9. config CRYPTO_GHASH_S390 - tristate "GHASH digest algorithm" + tristate "GHASH hash function" depends on S390 select CRYPTO_HASH help - This is the s390 hardware accelerated implementation of the - GHASH message digest algorithm for GCM (Galois/Counter Mode). + This is the s390 hardware accelerated implementation of GHASH, + the hash function used in GCM (Galois/Counter mode). It is available as of z196. @@ -214,8 +234,8 @@ config CRYPTO_CRC32_S390 config CRYPTO_DEV_MARVELL_CESA tristate "Marvell's Cryptographic Engine driver" depends on PLAT_ORION || ARCH_MVEBU - select CRYPTO_AES - select CRYPTO_DES + select CRYPTO_LIB_AES + select CRYPTO_LIB_DES select CRYPTO_BLKCIPHER select CRYPTO_HASH select SRAM @@ -227,7 +247,7 @@ config CRYPTO_DEV_MARVELL_CESA config CRYPTO_DEV_NIAGARA2 tristate "Niagara2 Stream Processing Unit driver" - select CRYPTO_DES + select CRYPTO_LIB_DES select CRYPTO_BLKCIPHER select CRYPTO_HASH select CRYPTO_MD5 @@ -244,7 +264,7 @@ config CRYPTO_DEV_NIAGARA2 config CRYPTO_DEV_HIFN_795X tristate "Driver HIFN 795x crypto accelerator chips" - select CRYPTO_DES + select CRYPTO_LIB_DES select CRYPTO_BLKCIPHER select HW_RANDOM if CRYPTO_DEV_HIFN_795X_RNG depends on PCI @@ -300,7 +320,7 @@ config CRYPTO_DEV_TALITOS2 config CRYPTO_DEV_IXP4XX tristate "Driver for IXP4xx crypto hardware acceleration" depends on ARCH_IXP4XX && IXP4XX_QMGR && IXP4XX_NPE - select CRYPTO_DES + select CRYPTO_LIB_DES select CRYPTO_AEAD select CRYPTO_AUTHENC select CRYPTO_BLKCIPHER @@ -312,7 +332,7 @@ config CRYPTO_DEV_PPC4XX depends on PPC && 4xx select CRYPTO_HASH select CRYPTO_AEAD - select CRYPTO_AES + select CRYPTO_LIB_AES select CRYPTO_CCM select CRYPTO_CTR select CRYPTO_GCM @@ -366,7 +386,7 @@ config CRYPTO_DEV_OMAP_AES config CRYPTO_DEV_OMAP_DES tristate "Support for OMAP DES/3DES hw engine" depends on ARCH_OMAP2PLUS - select CRYPTO_DES + select CRYPTO_LIB_DES select CRYPTO_BLKCIPHER select CRYPTO_ENGINE help @@ -384,7 +404,7 @@ config CRYPTO_DEV_PICOXCELL select CRYPTO_AES select CRYPTO_AUTHENC select CRYPTO_BLKCIPHER - select CRYPTO_DES + select CRYPTO_LIB_DES select CRYPTO_CBC select CRYPTO_ECB select CRYPTO_SEQIV @@ -393,7 +413,7 @@ config CRYPTO_DEV_PICOXCELL Picochip picoXcell SoC devices. Select this for IPSEC ESP offload and for 3gpp Layer 2 ciphering support. - Saying m here will build a module named pipcoxcell_crypto. + Saying m here will build a module named picoxcell_crypto. config CRYPTO_DEV_SAHARA tristate "Support for SAHARA crypto accelerator" @@ -497,7 +517,7 @@ config CRYPTO_DEV_ATMEL_AES config CRYPTO_DEV_ATMEL_TDES tristate "Support for Atmel DES/TDES hw accelerator" depends on ARCH_AT91 || COMPILE_TEST - select CRYPTO_DES + select CRYPTO_LIB_DES select CRYPTO_BLKCIPHER help Some Atmel processors have DES/TDES hw accelerator. @@ -595,7 +615,7 @@ config CRYPTO_DEV_QCE depends on ARCH_QCOM || COMPILE_TEST depends on HAS_IOMEM select CRYPTO_AES - select CRYPTO_DES + select CRYPTO_LIB_DES select CRYPTO_ECB select CRYPTO_CBC select CRYPTO_XTS @@ -643,7 +663,7 @@ config CRYPTO_DEV_SUN4I_SS select CRYPTO_MD5 select CRYPTO_SHA1 select CRYPTO_AES - select CRYPTO_DES + select CRYPTO_LIB_DES select CRYPTO_BLKCIPHER help Some Allwinner SoC have a crypto accelerator named @@ -666,7 +686,7 @@ config CRYPTO_DEV_ROCKCHIP tristate "Rockchip's Cryptographic Engine driver" depends on OF && ARCH_ROCKCHIP select CRYPTO_AES - select CRYPTO_DES + select CRYPTO_LIB_DES select CRYPTO_MD5 select CRYPTO_SHA1 select CRYPTO_SHA256 @@ -703,7 +723,7 @@ config CRYPTO_DEV_BCM_SPU depends on MAILBOX default m select CRYPTO_AUTHENC - select CRYPTO_DES + select CRYPTO_LIB_DES select CRYPTO_MD5 select CRYPTO_SHA1 select CRYPTO_SHA256 @@ -717,12 +737,11 @@ source "drivers/crypto/stm32/Kconfig" config CRYPTO_DEV_SAFEXCEL tristate "Inside Secure's SafeXcel cryptographic engine driver" - depends on OF - depends on (ARM64 && ARCH_MVEBU) || (COMPILE_TEST && 64BIT) - select CRYPTO_AES + depends on OF || PCI || COMPILE_TEST + select CRYPTO_LIB_AES select CRYPTO_AUTHENC select CRYPTO_BLKCIPHER - select CRYPTO_DES + select CRYPTO_LIB_DES select CRYPTO_HASH select CRYPTO_HMAC select CRYPTO_MD5 @@ -730,10 +749,11 @@ config CRYPTO_DEV_SAFEXCEL select CRYPTO_SHA256 select CRYPTO_SHA512 help - This driver interfaces with the SafeXcel EIP-197 cryptographic engine - designed by Inside Secure. Select this if you want to use CBC/ECB - chain mode, AES cipher mode and SHA1/SHA224/SHA256/SHA512 hash - algorithms. + This driver interfaces with the SafeXcel EIP-97 and EIP-197 cryptographic + engines designed by Inside Secure. It currently accelerates DES, 3DES and + AES block ciphers in ECB and CBC mode, as well as SHA1, SHA224, SHA256, + SHA384 and SHA512 hash algorithms for both basic hash and HMAC. + Additionally, it accelerates combined AES-CBC/HMAC-SHA AEAD operations. config CRYPTO_DEV_ARTPEC6 tristate "Support for Axis ARTPEC-6/7 hardware crypto acceleration." @@ -760,7 +780,7 @@ config CRYPTO_DEV_CCREE default n select CRYPTO_HASH select CRYPTO_BLKCIPHER - select CRYPTO_DES + select CRYPTO_LIB_DES select CRYPTO_AEAD select CRYPTO_AUTHENC select CRYPTO_SHA1 diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c index cbfc607282f48238b932d62be7a257d0cfa4a021..a42f8619589d3949426863044b5e844e651e685b 100644 --- a/drivers/crypto/amcc/crypto4xx_alg.c +++ b/drivers/crypto/amcc/crypto4xx_alg.c @@ -527,28 +527,20 @@ static int crypto4xx_aes_gcm_validate_keylen(unsigned int keylen) static int crypto4xx_compute_gcm_hash_key_sw(__le32 *hash_start, const u8 *key, unsigned int keylen) { - struct crypto_cipher *aes_tfm = NULL; + struct crypto_aes_ctx ctx; uint8_t src[16] = { 0 }; - int rc = 0; - - aes_tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_NEED_FALLBACK); - if (IS_ERR(aes_tfm)) { - rc = PTR_ERR(aes_tfm); - pr_warn("could not load aes cipher driver: %d\n", rc); - return rc; - } + int rc; - rc = crypto_cipher_setkey(aes_tfm, key, keylen); + rc = aes_expandkey(&ctx, key, keylen); if (rc) { - pr_err("setkey() failed: %d\n", rc); - goto out; + pr_err("aes_expandkey() failed: %d\n", rc); + return rc; } - crypto_cipher_encrypt_one(aes_tfm, src, src); + aes_encrypt(&ctx, src, src); crypto4xx_memcpy_to_le32(hash_start, src, 16); -out: - crypto_free_cipher(aes_tfm); - return rc; + memzero_explicit(&ctx, sizeof(ctx)); + return 0; } int crypto4xx_setkey_aes_gcm(struct crypto_aead *cipher, diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 2b7af44c7b85309cde6402eddeadcdf3415a5e7b..026f193556f9df8b759dc90be596206c556ebcef 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -2673,7 +2673,6 @@ static int atmel_aes_probe(struct platform_device *pdev) /* Get the IRQ */ aes_dd->irq = platform_get_irq(pdev, 0); if (aes_dd->irq < 0) { - dev_err(dev, "no IRQ resource info\n"); err = aes_dd->irq; goto res_err; } diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c index dc876fab2882f3f88f858b5c56c419df5c23b42c..1d3355913b4092696d71a7fdca8eca9197ead350 100644 --- a/drivers/crypto/atmel-i2c.c +++ b/drivers/crypto/atmel-i2c.c @@ -21,6 +21,18 @@ #include #include "atmel-i2c.h" +static const struct { + u8 value; + const char *error_text; +} error_list[] = { + { 0x01, "CheckMac or Verify miscompare" }, + { 0x03, "Parse Error" }, + { 0x05, "ECC Fault" }, + { 0x0F, "Execution Error" }, + { 0xEE, "Watchdog about to expire" }, + { 0xFF, "CRC or other communication error" }, +}; + /** * atmel_i2c_checksum() - Generate 16-bit CRC as required by ATMEL ECC. * CRC16 verification of the count, opcode, param1, param2 and data bytes. diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h index 21860b99c3e35b8ce4985162714bf995e9af5ff8..63b97b104f16f580db069a788335dc2f706f5b85 100644 --- a/drivers/crypto/atmel-i2c.h +++ b/drivers/crypto/atmel-i2c.h @@ -62,18 +62,6 @@ struct atmel_i2c_cmd { #define STATUS_NOERR 0x00 #define STATUS_WAKE_SUCCESSFUL 0x11 -static const struct { - u8 value; - const char *error_text; -} error_list[] = { - { 0x01, "CheckMac or Verify miscompare" }, - { 0x03, "Parse Error" }, - { 0x05, "ECC Fault" }, - { 0x0F, "Execution Error" }, - { 0xEE, "Watchdog about to expire" }, - { 0xFF, "CRC or other communication error" }, -}; - /* Definitions for eeprom organization */ #define CONFIG_ZONE 0 diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index ab0cfe748931a6a1c70d4530eb44b70008bcb44c..84cb8748a79595d4310c5bcfb4fc07a01f361628 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -2779,7 +2779,6 @@ static int atmel_sha_probe(struct platform_device *pdev) /* Get the IRQ */ sha_dd->irq = platform_get_irq(pdev, 0); if (sha_dd->irq < 0) { - dev_err(dev, "no IRQ resource info\n"); err = sha_dd->irq; goto res_err; } diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c index ea0d2068ea4f3c3d922d340ce15ace2ab787d156..c96c14e7dab1c0ae89fd026bb733155cf761659c 100644 --- a/drivers/crypto/atmel-sha204a.c +++ b/drivers/crypto/atmel-sha204a.c @@ -109,7 +109,7 @@ static int atmel_sha204a_probe(struct i2c_client *client, i2c_priv->hwrng.read = atmel_sha204a_rng_read; i2c_priv->hwrng.quality = 1024; - ret = hwrng_register(&i2c_priv->hwrng); + ret = devm_hwrng_register(&client->dev, &i2c_priv->hwrng); if (ret) dev_warn(&client->dev, "failed to register RNG (%d)\n", ret); @@ -127,7 +127,6 @@ static int atmel_sha204a_remove(struct i2c_client *client) if (i2c_priv->hwrng.priv) kfree((void *)i2c_priv->hwrng.priv); - hwrng_unregister(&i2c_priv->hwrng); return 0; } diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c index fa76620281e803aae994f7a28241a3e8505e94e5..1a6c86ae6148097e9d286f617d9bf56a557319fc 100644 --- a/drivers/crypto/atmel-tdes.c +++ b/drivers/crypto/atmel-tdes.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include @@ -773,22 +773,12 @@ static void atmel_tdes_dma_cleanup(struct atmel_tdes_dev *dd) static int atmel_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int keylen) { - u32 tmp[DES_EXPKEY_WORDS]; - int err; - struct crypto_tfm *ctfm = crypto_ablkcipher_tfm(tfm); - struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx(tfm); + int err; - if (keylen != DES_KEY_SIZE) { - crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - err = des_ekey(tmp, key); - if (err == 0 && (ctfm->crt_flags & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) { - ctfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; - return -EINVAL; - } + err = verify_ablkcipher_des_key(tfm, key); + if (err) + return err; memcpy(ctx->key, key, keylen); ctx->keylen = keylen; @@ -800,15 +790,11 @@ static int atmel_tdes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int keylen) { struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx(tfm); - u32 flags; int err; - flags = crypto_ablkcipher_get_flags(tfm); - err = __des3_verify_key(&flags, key); - if (unlikely(err)) { - crypto_ablkcipher_set_flags(tfm, flags); + err = verify_ablkcipher_des3_key(tfm, key); + if (err) return err; - } memcpy(ctx->key, key, keylen); ctx->keylen = keylen; @@ -1281,7 +1267,6 @@ static int atmel_tdes_probe(struct platform_device *pdev) /* Get the IRQ */ tdes_dd->irq = platform_get_irq(pdev, 0); if (tdes_dd->irq < 0) { - dev_err(dev, "no IRQ resource info\n"); err = tdes_dd->irq; goto res_err; } diff --git a/drivers/crypto/axis/artpec6_crypto.c b/drivers/crypto/axis/artpec6_crypto.c index 80fa04ef215f98364fa9e5d7a6e80959e2c4c0ae..4b20606983a43c7fe59bf0119e2d458594d619bb 100644 --- a/drivers/crypto/axis/artpec6_crypto.c +++ b/drivers/crypto/axis/artpec6_crypto.c @@ -2854,7 +2854,6 @@ static int artpec6_crypto_probe(struct platform_device *pdev) struct artpec6_crypto *ac; struct device *dev = &pdev->dev; void __iomem *base; - struct resource *res; int irq; int err; @@ -2867,8 +2866,7 @@ static int artpec6_crypto_probe(struct platform_device *pdev) variant = (enum artpec6_crypto_variant)match->data; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/drivers/crypto/bcm/cipher.c b/drivers/crypto/bcm/cipher.c index 869602fcfd965a609a8b721bbecebc9a1c1a6711..f85356a48e7ea0ceb9aa5df83872c7ec8dc8722c 100644 --- a/drivers/crypto/bcm/cipher.c +++ b/drivers/crypto/bcm/cipher.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -1802,24 +1802,13 @@ static int des_setkey(struct crypto_ablkcipher *cipher, const u8 *key, unsigned int keylen) { struct iproc_ctx_s *ctx = crypto_ablkcipher_ctx(cipher); - u32 tmp[DES_EXPKEY_WORDS]; - - if (keylen == DES_KEY_SIZE) { - if (des_ekey(tmp, key) == 0) { - if (crypto_ablkcipher_get_flags(cipher) & - CRYPTO_TFM_REQ_FORBID_WEAK_KEYS) { - u32 flags = CRYPTO_TFM_RES_WEAK_KEY; + int err; - crypto_ablkcipher_set_flags(cipher, flags); - return -EINVAL; - } - } + err = verify_ablkcipher_des_key(cipher, key); + if (err) + return err; - ctx->cipher_type = CIPHER_TYPE_DES; - } else { - crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } + ctx->cipher_type = CIPHER_TYPE_DES; return 0; } @@ -1827,23 +1816,13 @@ static int threedes_setkey(struct crypto_ablkcipher *cipher, const u8 *key, unsigned int keylen) { struct iproc_ctx_s *ctx = crypto_ablkcipher_ctx(cipher); + int err; - if (keylen == (DES_KEY_SIZE * 3)) { - u32 flags; - int ret; - - flags = crypto_ablkcipher_get_flags(cipher); - ret = __des3_verify_key(&flags, key); - if (unlikely(ret)) { - crypto_ablkcipher_set_flags(cipher, flags); - return ret; - } + err = verify_ablkcipher_des3_key(cipher, key); + if (err) + return err; - ctx->cipher_type = CIPHER_TYPE_3DES; - } else { - crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } + ctx->cipher_type = CIPHER_TYPE_3DES; return 0; } @@ -2629,6 +2608,19 @@ static int aead_need_fallback(struct aead_request *req) return 1; } + /* + * RFC4106 and RFC4543 cannot handle the case where AAD is other than + * 16 or 20 bytes long. So use fallback in this case. + */ + if (ctx->cipher.mode == CIPHER_MODE_GCM && + ctx->cipher.alg == CIPHER_ALG_AES && + rctx->iv_ctr_len == GCM_RFC4106_IV_SIZE && + req->assoclen != 16 && req->assoclen != 20) { + flow_log("RFC4106/RFC4543 needs fallback for assoclen" + " other than 16 or 20 bytes\n"); + return 1; + } + payload_len = req->cryptlen; if (spu->spu_type == SPU_TYPE_SPUM) payload_len += req->assoclen; @@ -2855,40 +2847,16 @@ static int aead_authenc_setkey(struct crypto_aead *cipher, switch (ctx->alg->cipher_info.alg) { case CIPHER_ALG_DES: - if (ctx->enckeylen == DES_KEY_SIZE) { - u32 tmp[DES_EXPKEY_WORDS]; - u32 flags = CRYPTO_TFM_RES_WEAK_KEY; - - if (des_ekey(tmp, keys.enckey) == 0) { - if (crypto_aead_get_flags(cipher) & - CRYPTO_TFM_REQ_FORBID_WEAK_KEYS) { - crypto_aead_set_flags(cipher, flags); - return -EINVAL; - } - } + if (verify_aead_des_key(cipher, keys.enckey, keys.enckeylen)) + return -EINVAL; - ctx->cipher_type = CIPHER_TYPE_DES; - } else { - goto badkey; - } + ctx->cipher_type = CIPHER_TYPE_DES; break; case CIPHER_ALG_3DES: - if (ctx->enckeylen == (DES_KEY_SIZE * 3)) { - u32 flags; - - flags = crypto_aead_get_flags(cipher); - ret = __des3_verify_key(&flags, keys.enckey); - if (unlikely(ret)) { - crypto_aead_set_flags(cipher, flags); - return ret; - } - - ctx->cipher_type = CIPHER_TYPE_3DES; - } else { - crypto_aead_set_flags(cipher, - CRYPTO_TFM_RES_BAD_KEY_LEN); + if (verify_aead_des3_key(cipher, keys.enckey, keys.enckeylen)) return -EINVAL; - } + + ctx->cipher_type = CIPHER_TYPE_3DES; break; case CIPHER_ALG_AES: switch (ctx->enckeylen) { diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig index 3720ddabb50796dd16e8db4a426c99e99a1ba414..137ed3df0c74d585e184657c4a7f8011b5f4c7fb 100644 --- a/drivers/crypto/caam/Kconfig +++ b/drivers/crypto/caam/Kconfig @@ -98,7 +98,7 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API select CRYPTO_AEAD select CRYPTO_AUTHENC select CRYPTO_BLKCIPHER - select CRYPTO_DES + select CRYPTO_LIB_DES help Selecting this will offload crypto for users of the scatterlist crypto API (such as the linux native IPSec @@ -111,6 +111,7 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI select CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC select CRYPTO_AUTHENC select CRYPTO_BLKCIPHER + select CRYPTO_DES help Selecting this will use CAAM Queue Interface (QI) for sending & receiving crypto jobs to/from CAAM. This gives better performance @@ -161,6 +162,7 @@ config CRYPTO_DEV_FSL_DPAA2_CAAM select CRYPTO_AUTHENC select CRYPTO_AEAD select CRYPTO_HASH + select CRYPTO_DES help CAAM driver for QorIQ Data Path Acceleration Architecture 2. It handles DPSECI DPAA2 objects that sit on the Management Complex diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile index 9ab4e81ea21ea3947b5f0c76058ce78286a224fe..68d5cc0f28e2955e419a18d2830c77971f6b50ac 100644 --- a/drivers/crypto/caam/Makefile +++ b/drivers/crypto/caam/Makefile @@ -30,3 +30,4 @@ endif obj-$(CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM) += dpaa2_caam.o dpaa2_caam-y := caamalg_qi2.o dpseci.o +dpaa2_caam-$(CONFIG_DEBUG_FS) += dpseci-debugfs.o diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 43f18253e5b6fe1152c89c4cba03831dc5de7871..2912006b946b018f13af84322342633cd4284ff7 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -74,7 +74,7 @@ #define CHACHAPOLY_DESC_JOB_IO_LEN (AEAD_DESC_JOB_IO_LEN + CAAM_CMD_SZ * 6) -#define DESC_MAX_USED_BYTES (CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN) +#define DESC_MAX_USED_BYTES (CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN_MIN) #define DESC_MAX_USED_LEN (DESC_MAX_USED_BYTES / CAAM_CMD_SZ) struct caam_alg_entry { @@ -205,6 +205,18 @@ static int aead_set_sh_desc(struct crypto_aead *aead) ctx->cdata.keylen - CTR_RFC3686_NONCE_SIZE); } + /* + * In case |user key| > |derived key|, using DKP + * would result in invalid opcodes (last bytes of user key) in + * the resulting descriptor. Use DKP instead => both + * virtual and dma key addresses are needed. + */ + ctx->adata.key_virt = ctx->key; + ctx->adata.key_dma = ctx->key_dma; + + ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; + ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; + data_len[0] = ctx->adata.keylen_pad; data_len[1] = ctx->cdata.keylen; @@ -221,16 +233,6 @@ static int aead_set_sh_desc(struct crypto_aead *aead) ARRAY_SIZE(data_len)) < 0) return -EINVAL; - if (inl_mask & 1) - ctx->adata.key_virt = ctx->key; - else - ctx->adata.key_dma = ctx->key_dma; - - if (inl_mask & 2) - ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; - else - ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; - ctx->adata.key_inline = !!(inl_mask & 1); ctx->cdata.key_inline = !!(inl_mask & 2); @@ -253,16 +255,6 @@ static int aead_set_sh_desc(struct crypto_aead *aead) ARRAY_SIZE(data_len)) < 0) return -EINVAL; - if (inl_mask & 1) - ctx->adata.key_virt = ctx->key; - else - ctx->adata.key_dma = ctx->key_dma; - - if (inl_mask & 2) - ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; - else - ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; - ctx->adata.key_inline = !!(inl_mask & 1); ctx->cdata.key_inline = !!(inl_mask & 2); @@ -287,16 +279,6 @@ static int aead_set_sh_desc(struct crypto_aead *aead) ARRAY_SIZE(data_len)) < 0) return -EINVAL; - if (inl_mask & 1) - ctx->adata.key_virt = ctx->key; - else - ctx->adata.key_dma = ctx->key_dma; - - if (inl_mask & 2) - ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; - else - ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; - ctx->adata.key_inline = !!(inl_mask & 1); ctx->cdata.key_inline = !!(inl_mask & 2); @@ -376,6 +358,11 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) static int gcm_setauthsize(struct crypto_aead *authenc, unsigned int authsize) { struct caam_ctx *ctx = crypto_aead_ctx(authenc); + int err; + + err = crypto_gcm_check_authsize(authsize); + if (err) + return err; ctx->authsize = authsize; gcm_set_sh_desc(authenc); @@ -439,6 +426,11 @@ static int rfc4106_setauthsize(struct crypto_aead *authenc, unsigned int authsize) { struct caam_ctx *ctx = crypto_aead_ctx(authenc); + int err; + + err = crypto_rfc4106_check_authsize(authsize); + if (err) + return err; ctx->authsize = authsize; rfc4106_set_sh_desc(authenc); @@ -503,6 +495,9 @@ static int rfc4543_setauthsize(struct crypto_aead *authenc, { struct caam_ctx *ctx = crypto_aead_ctx(authenc); + if (authsize != 16) + return -EINVAL; + ctx->authsize = authsize; rfc4543_set_sh_desc(authenc); @@ -633,33 +628,17 @@ static int des3_aead_setkey(struct crypto_aead *aead, const u8 *key, unsigned int keylen) { struct crypto_authenc_keys keys; - u32 flags; int err; err = crypto_authenc_extractkeys(&keys, key, keylen); if (unlikely(err)) - goto badkey; - - err = -EINVAL; - if (keys.enckeylen != DES3_EDE_KEY_SIZE) - goto badkey; - - flags = crypto_aead_get_flags(aead); - err = __des3_verify_key(&flags, keys.enckey); - if (unlikely(err)) { - crypto_aead_set_flags(aead, flags); - goto out; - } + return err; - err = aead_setkey(aead, key, keylen); + err = verify_aead_des3_key(aead, keys.enckey, keys.enckeylen) ?: + aead_setkey(aead, key, keylen); -out: memzero_explicit(&keys, sizeof(keys)); return err; - -badkey: - crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); - goto out; } static int gcm_setkey(struct crypto_aead *aead, @@ -667,6 +646,13 @@ static int gcm_setkey(struct crypto_aead *aead, { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; + int err; + + err = aes_check_keylen(keylen); + if (err) { + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); + return err; + } print_hex_dump_debug("key in @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); @@ -683,9 +669,13 @@ static int rfc4106_setkey(struct crypto_aead *aead, { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; + int err; - if (keylen < 4) - return -EINVAL; + err = aes_check_keylen(keylen - 4); + if (err) { + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); + return err; + } print_hex_dump_debug("key in @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); @@ -707,9 +697,13 @@ static int rfc4543_setkey(struct crypto_aead *aead, { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; + int err; - if (keylen < 4) - return -EINVAL; + err = aes_check_keylen(keylen - 4); + if (err) { + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); + return err; + } print_hex_dump_debug("key in @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); @@ -727,7 +721,7 @@ static int rfc4543_setkey(struct crypto_aead *aead, } static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, - unsigned int keylen) + unsigned int keylen, const u32 ctx1_iv_off) { struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); struct caam_skcipher_alg *alg = @@ -736,30 +730,10 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, struct device *jrdev = ctx->jrdev; unsigned int ivsize = crypto_skcipher_ivsize(skcipher); u32 *desc; - u32 ctx1_iv_off = 0; - const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == - OP_ALG_AAI_CTR_MOD128); const bool is_rfc3686 = alg->caam.rfc3686; print_hex_dump_debug("key in @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); - /* - * AES-CTR needs to load IV in CONTEXT1 reg - * at an offset of 128bits (16bytes) - * CONTEXT1[255:128] = IV - */ - if (ctr_mode) - ctx1_iv_off = 16; - - /* - * RFC3686 specific: - * | CONTEXT1[255:128] = {NONCE, IV, COUNTER} - * | *key = {KEY, NONCE} - */ - if (is_rfc3686) { - ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; - keylen -= CTR_RFC3686_NONCE_SIZE; - } ctx->cdata.keylen = keylen; ctx->cdata.key_virt = key; @@ -782,25 +756,86 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, return 0; } -static int des_skcipher_setkey(struct crypto_skcipher *skcipher, +static int aes_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, unsigned int keylen) { - u32 tmp[DES3_EDE_EXPKEY_WORDS]; - struct crypto_tfm *tfm = crypto_skcipher_tfm(skcipher); + int err; - if (keylen == DES3_EDE_KEY_SIZE && - __des3_ede_setkey(tmp, &tfm->crt_flags, key, DES3_EDE_KEY_SIZE)) { - return -EINVAL; + err = aes_check_keylen(keylen); + if (err) { + crypto_skcipher_set_flags(skcipher, + CRYPTO_TFM_RES_BAD_KEY_LEN); + return err; } - if (!des_ekey(tmp, key) && (crypto_skcipher_get_flags(skcipher) & - CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) { + return skcipher_setkey(skcipher, key, keylen, 0); +} + +static int rfc3686_skcipher_setkey(struct crypto_skcipher *skcipher, + const u8 *key, unsigned int keylen) +{ + u32 ctx1_iv_off; + int err; + + /* + * RFC3686 specific: + * | CONTEXT1[255:128] = {NONCE, IV, COUNTER} + * | *key = {KEY, NONCE} + */ + ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; + keylen -= CTR_RFC3686_NONCE_SIZE; + + err = aes_check_keylen(keylen); + if (err) { crypto_skcipher_set_flags(skcipher, - CRYPTO_TFM_RES_WEAK_KEY); - return -EINVAL; + CRYPTO_TFM_RES_BAD_KEY_LEN); + return err; } - return skcipher_setkey(skcipher, key, keylen); + return skcipher_setkey(skcipher, key, keylen, ctx1_iv_off); +} + +static int ctr_skcipher_setkey(struct crypto_skcipher *skcipher, + const u8 *key, unsigned int keylen) +{ + u32 ctx1_iv_off; + int err; + + /* + * AES-CTR needs to load IV in CONTEXT1 reg + * at an offset of 128bits (16bytes) + * CONTEXT1[255:128] = IV + */ + ctx1_iv_off = 16; + + err = aes_check_keylen(keylen); + if (err) { + crypto_skcipher_set_flags(skcipher, + CRYPTO_TFM_RES_BAD_KEY_LEN); + return err; + } + + return skcipher_setkey(skcipher, key, keylen, ctx1_iv_off); +} + +static int arc4_skcipher_setkey(struct crypto_skcipher *skcipher, + const u8 *key, unsigned int keylen) +{ + return skcipher_setkey(skcipher, key, keylen, 0); +} + +static int des_skcipher_setkey(struct crypto_skcipher *skcipher, + const u8 *key, unsigned int keylen) +{ + return verify_skcipher_des_key(skcipher, key) ?: + skcipher_setkey(skcipher, key, keylen, 0); +} + +static int des3_skcipher_setkey(struct crypto_skcipher *skcipher, + const u8 *key, unsigned int keylen) +{ + return verify_skcipher_des3_key(skcipher, key) ?: + skcipher_setkey(skcipher, key, keylen, 0); } static int xts_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, @@ -930,19 +965,20 @@ static void aead_encrypt_done(struct device *jrdev, u32 *desc, u32 err, { struct aead_request *req = context; struct aead_edesc *edesc; + int ecode = 0; dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); edesc = container_of(desc, struct aead_edesc, hw_desc[0]); if (err) - caam_jr_strstatus(jrdev, err); + ecode = caam_jr_strstatus(jrdev, err); aead_unmap(jrdev, edesc, req); kfree(edesc); - aead_request_complete(req, err); + aead_request_complete(req, ecode); } static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err, @@ -950,25 +986,20 @@ static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err, { struct aead_request *req = context; struct aead_edesc *edesc; + int ecode = 0; dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); edesc = container_of(desc, struct aead_edesc, hw_desc[0]); if (err) - caam_jr_strstatus(jrdev, err); + ecode = caam_jr_strstatus(jrdev, err); aead_unmap(jrdev, edesc, req); - /* - * verify hw auth check passed else return -EBADMSG - */ - if ((err & JRSTA_CCBERR_ERRID_MASK) == JRSTA_CCBERR_ERRID_ICVCHK) - err = -EBADMSG; - kfree(edesc); - aead_request_complete(req, err); + aead_request_complete(req, ecode); } static void skcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, @@ -978,13 +1009,14 @@ static void skcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, struct skcipher_edesc *edesc; struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); int ivsize = crypto_skcipher_ivsize(skcipher); + int ecode = 0; dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); edesc = container_of(desc, struct skcipher_edesc, hw_desc[0]); if (err) - caam_jr_strstatus(jrdev, err); + ecode = caam_jr_strstatus(jrdev, err); skcipher_unmap(jrdev, edesc, req); @@ -993,10 +1025,9 @@ static void skcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, * ciphertext block (CBC mode) or last counter (CTR mode). * This is used e.g. by the CTS mode. */ - if (ivsize) { + if (ivsize && !ecode) { memcpy(req->iv, (u8 *)edesc->sec4_sg + edesc->sec4_sg_bytes, ivsize); - print_hex_dump_debug("dstiv @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->iv, edesc->src_nents > 1 ? 100 : ivsize, 1); @@ -1008,7 +1039,7 @@ static void skcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, kfree(edesc); - skcipher_request_complete(req, err); + skcipher_request_complete(req, ecode); } static void skcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, @@ -1018,12 +1049,13 @@ static void skcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, struct skcipher_edesc *edesc; struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); int ivsize = crypto_skcipher_ivsize(skcipher); + int ecode = 0; dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); edesc = container_of(desc, struct skcipher_edesc, hw_desc[0]); if (err) - caam_jr_strstatus(jrdev, err); + ecode = caam_jr_strstatus(jrdev, err); skcipher_unmap(jrdev, edesc, req); @@ -1032,7 +1064,7 @@ static void skcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, * ciphertext block (CBC mode) or last counter (CTR mode). * This is used e.g. by the CTS mode. */ - if (ivsize) { + if (ivsize && !ecode) { memcpy(req->iv, (u8 *)edesc->sec4_sg + edesc->sec4_sg_bytes, ivsize); @@ -1047,7 +1079,7 @@ static void skcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, kfree(edesc); - skcipher_request_complete(req, err); + skcipher_request_complete(req, ecode); } /* @@ -1525,10 +1557,7 @@ static int chachapoly_decrypt(struct aead_request *req) static int ipsec_gcm_encrypt(struct aead_request *req) { - if (req->assoclen < 8) - return -EINVAL; - - return gcm_encrypt(req); + return crypto_ipsec_check_assoclen(req->assoclen) ? : gcm_encrypt(req); } static int aead_encrypt(struct aead_request *req) @@ -1602,10 +1631,7 @@ static int gcm_decrypt(struct aead_request *req) static int ipsec_gcm_decrypt(struct aead_request *req) { - if (req->assoclen < 8) - return -EINVAL; - - return gcm_decrypt(req); + return crypto_ipsec_check_assoclen(req->assoclen) ? : gcm_decrypt(req); } static int aead_decrypt(struct aead_request *req) @@ -1817,6 +1843,9 @@ static int skcipher_encrypt(struct skcipher_request *req) u32 *desc; int ret = 0; + if (!req->cryptlen) + return 0; + /* allocate extended descriptor */ edesc = skcipher_edesc_alloc(req, DESC_JOB_IO_LEN * CAAM_CMD_SZ); if (IS_ERR(edesc)) @@ -1851,6 +1880,9 @@ static int skcipher_decrypt(struct skcipher_request *req) u32 *desc; int ret = 0; + if (!req->cryptlen) + return 0; + /* allocate extended descriptor */ edesc = skcipher_edesc_alloc(req, DESC_JOB_IO_LEN * CAAM_CMD_SZ); if (IS_ERR(edesc)) @@ -1883,7 +1915,7 @@ static struct caam_skcipher_alg driver_algs[] = { .cra_driver_name = "cbc-aes-caam", .cra_blocksize = AES_BLOCK_SIZE, }, - .setkey = skcipher_setkey, + .setkey = aes_skcipher_setkey, .encrypt = skcipher_encrypt, .decrypt = skcipher_decrypt, .min_keysize = AES_MIN_KEY_SIZE, @@ -1899,7 +1931,7 @@ static struct caam_skcipher_alg driver_algs[] = { .cra_driver_name = "cbc-3des-caam", .cra_blocksize = DES3_EDE_BLOCK_SIZE, }, - .setkey = des_skcipher_setkey, + .setkey = des3_skcipher_setkey, .encrypt = skcipher_encrypt, .decrypt = skcipher_decrypt, .min_keysize = DES3_EDE_KEY_SIZE, @@ -1931,7 +1963,7 @@ static struct caam_skcipher_alg driver_algs[] = { .cra_driver_name = "ctr-aes-caam", .cra_blocksize = 1, }, - .setkey = skcipher_setkey, + .setkey = ctr_skcipher_setkey, .encrypt = skcipher_encrypt, .decrypt = skcipher_decrypt, .min_keysize = AES_MIN_KEY_SIZE, @@ -1949,7 +1981,7 @@ static struct caam_skcipher_alg driver_algs[] = { .cra_driver_name = "rfc3686-ctr-aes-caam", .cra_blocksize = 1, }, - .setkey = skcipher_setkey, + .setkey = rfc3686_skcipher_setkey, .encrypt = skcipher_encrypt, .decrypt = skcipher_decrypt, .min_keysize = AES_MIN_KEY_SIZE + @@ -2003,7 +2035,7 @@ static struct caam_skcipher_alg driver_algs[] = { .cra_driver_name = "ecb-aes-caam", .cra_blocksize = AES_BLOCK_SIZE, }, - .setkey = skcipher_setkey, + .setkey = aes_skcipher_setkey, .encrypt = skcipher_encrypt, .decrypt = skcipher_decrypt, .min_keysize = AES_MIN_KEY_SIZE, @@ -2018,7 +2050,7 @@ static struct caam_skcipher_alg driver_algs[] = { .cra_driver_name = "ecb-des3-caam", .cra_blocksize = DES3_EDE_BLOCK_SIZE, }, - .setkey = des_skcipher_setkey, + .setkey = des3_skcipher_setkey, .encrypt = skcipher_encrypt, .decrypt = skcipher_decrypt, .min_keysize = DES3_EDE_KEY_SIZE, @@ -2033,7 +2065,7 @@ static struct caam_skcipher_alg driver_algs[] = { .cra_driver_name = "ecb-arc4-caam", .cra_blocksize = ARC4_BLOCK_SIZE, }, - .setkey = skcipher_setkey, + .setkey = arc4_skcipher_setkey, .encrypt = skcipher_encrypt, .decrypt = skcipher_decrypt, .min_keysize = ARC4_MIN_KEY_SIZE, diff --git a/drivers/crypto/caam/caamalg_desc.c b/drivers/crypto/caam/caamalg_desc.c index 72531837571ec46eac3a6028f4cc8c4acc07fcda..aa9ccca670450161da8ecba423ac22a9b1a59404 100644 --- a/drivers/crypto/caam/caamalg_desc.c +++ b/drivers/crypto/caam/caamalg_desc.c @@ -503,6 +503,7 @@ void cnstr_shdsc_aead_givencap(u32 * const desc, struct alginfo *cdata, const bool is_qi, int era) { u32 geniv, moveiv; + u32 *wait_cmd; /* Note: Context registers are saved. */ init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce, era); @@ -598,6 +599,14 @@ void cnstr_shdsc_aead_givencap(u32 * const desc, struct alginfo *cdata, /* Will read cryptlen */ append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + + /* + * Wait for IV transfer (ofifo -> class2) to finish before starting + * ciphertext transfer (ofifo -> external memory). + */ + wait_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_NIFP); + set_jump_tgt_here(desc, wait_cmd); + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | KEY_VLF | FIFOLD_TYPE_MSG1OUT2 | FIFOLD_TYPE_LASTBOTH); append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); @@ -843,13 +852,16 @@ EXPORT_SYMBOL(cnstr_shdsc_gcm_decap); * @ivsize: initialization vector size * @icvsize: integrity check value (ICV) size (truncated or full) * @is_qi: true when called from caam/qi + * + * Input sequence: AAD | PTXT + * Output sequence: AAD | CTXT | ICV + * AAD length (assoclen), which includes the IV length, is available in Math3. */ void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata, unsigned int ivsize, unsigned int icvsize, const bool is_qi) { - u32 *key_jump_cmd; - + u32 *key_jump_cmd, *zero_cryptlen_jump_cmd, *skip_instructions; init_sh_desc(desc, HDR_SHARE_SERIAL); /* Skip key loading if it is loaded due to sharing */ @@ -892,24 +904,26 @@ void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata, append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, ivsize); append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - /* Read assoc data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); + /* Skip AAD */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); - /* Skip IV */ - append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_SKIP); + /* Read cryptlen and set this value into VARSEQOUTLEN */ + append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG3, CAAM_CMD_SZ); - /* Will read cryptlen bytes */ - append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + /* If cryptlen is ZERO jump to AAD command */ + zero_cryptlen_jump_cmd = append_jump(desc, JUMP_TEST_ALL | + JUMP_COND_MATH_Z); - /* Workaround for erratum A-005473 (simultaneous SEQ FIFO skips) */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG); + /* Read AAD data */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | + FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); - /* Skip assoc data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); + /* Workaround for erratum A-005473 (simultaneous SEQ FIFO skips) */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA); - /* cryptlen = seqoutlen - assoclen */ - append_math_sub(desc, VARSEQOUTLEN, VARSEQINLEN, REG0, CAAM_CMD_SZ); + /* Skip IV */ + append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_SKIP); + append_math_add(desc, VARSEQINLEN, VARSEQOUTLEN, REG0, CAAM_CMD_SZ); /* Write encrypted data */ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); @@ -918,6 +932,18 @@ void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata, append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); + /* Jump instructions to avoid double reading of AAD */ + skip_instructions = append_jump(desc, JUMP_TEST_ALL); + + /* There is no input data, cryptlen = 0 */ + set_jump_tgt_here(desc, zero_cryptlen_jump_cmd); + + /* Read AAD */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | + FIFOLD_TYPE_AAD | FIFOLD_TYPE_LAST1); + + set_jump_tgt_here(desc, skip_instructions); + /* Write ICV */ append_seq_store(desc, icvsize, LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_CONTEXT); diff --git a/drivers/crypto/caam/caamalg_desc.h b/drivers/crypto/caam/caamalg_desc.h index da4a4ee60c80051cf5a45e3017c7b60ef9621735..f2893393ba5e770b505fa11f945d2b23f2d13c75 100644 --- a/drivers/crypto/caam/caamalg_desc.h +++ b/drivers/crypto/caam/caamalg_desc.h @@ -12,7 +12,7 @@ #define DESC_AEAD_BASE (4 * CAAM_CMD_SZ) #define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 11 * CAAM_CMD_SZ) #define DESC_AEAD_DEC_LEN (DESC_AEAD_BASE + 15 * CAAM_CMD_SZ) -#define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 7 * CAAM_CMD_SZ) +#define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 8 * CAAM_CMD_SZ) #define DESC_QI_AEAD_ENC_LEN (DESC_AEAD_ENC_LEN + 3 * CAAM_CMD_SZ) #define DESC_QI_AEAD_DEC_LEN (DESC_AEAD_DEC_LEN + 3 * CAAM_CMD_SZ) #define DESC_QI_AEAD_GIVENC_LEN (DESC_AEAD_GIVENC_LEN + 3 * CAAM_CMD_SZ) @@ -31,7 +31,7 @@ #define DESC_QI_GCM_DEC_LEN (DESC_GCM_DEC_LEN + 3 * CAAM_CMD_SZ) #define DESC_RFC4106_BASE (3 * CAAM_CMD_SZ) -#define DESC_RFC4106_ENC_LEN (DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ) +#define DESC_RFC4106_ENC_LEN (DESC_RFC4106_BASE + 16 * CAAM_CMD_SZ) #define DESC_RFC4106_DEC_LEN (DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ) #define DESC_QI_RFC4106_ENC_LEN (DESC_RFC4106_ENC_LEN + 5 * CAAM_CMD_SZ) #define DESC_QI_RFC4106_DEC_LEN (DESC_RFC4106_DEC_LEN + 5 * CAAM_CMD_SZ) diff --git a/drivers/crypto/caam/caamalg_qi.c b/drivers/crypto/caam/caamalg_qi.c index 32f0f8a72067fd232b3322e536350830515a175a..8e3449670d2f0517a0a9ae1ca2e6b0eb3a59db80 100644 --- a/drivers/crypto/caam/caamalg_qi.c +++ b/drivers/crypto/caam/caamalg_qi.c @@ -105,6 +105,18 @@ static int aead_set_sh_desc(struct crypto_aead *aead) ctx->cdata.keylen - CTR_RFC3686_NONCE_SIZE); } + /* + * In case |user key| > |derived key|, using DKP would result + * in invalid opcodes (last bytes of user key) in the resulting + * descriptor. Use DKP instead => both virtual and dma key + * addresses are needed. + */ + ctx->adata.key_virt = ctx->key; + ctx->adata.key_dma = ctx->key_dma; + + ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; + ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; + data_len[0] = ctx->adata.keylen_pad; data_len[1] = ctx->cdata.keylen; @@ -118,16 +130,6 @@ static int aead_set_sh_desc(struct crypto_aead *aead) ARRAY_SIZE(data_len)) < 0) return -EINVAL; - if (inl_mask & 1) - ctx->adata.key_virt = ctx->key; - else - ctx->adata.key_dma = ctx->key_dma; - - if (inl_mask & 2) - ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; - else - ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; - ctx->adata.key_inline = !!(inl_mask & 1); ctx->cdata.key_inline = !!(inl_mask & 2); @@ -143,16 +145,6 @@ static int aead_set_sh_desc(struct crypto_aead *aead) ARRAY_SIZE(data_len)) < 0) return -EINVAL; - if (inl_mask & 1) - ctx->adata.key_virt = ctx->key; - else - ctx->adata.key_dma = ctx->key_dma; - - if (inl_mask & 2) - ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; - else - ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; - ctx->adata.key_inline = !!(inl_mask & 1); ctx->cdata.key_inline = !!(inl_mask & 2); @@ -171,16 +163,6 @@ static int aead_set_sh_desc(struct crypto_aead *aead) ARRAY_SIZE(data_len)) < 0) return -EINVAL; - if (inl_mask & 1) - ctx->adata.key_virt = ctx->key; - else - ctx->adata.key_dma = ctx->key_dma; - - if (inl_mask & 2) - ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; - else - ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; - ctx->adata.key_inline = !!(inl_mask & 1); ctx->cdata.key_inline = !!(inl_mask & 2); @@ -252,11 +234,10 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key, dma_sync_single_for_device(jrdev->parent, ctx->key_dma, ctx->adata.keylen_pad + keys.enckeylen, ctx->dir); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, - ctx->adata.keylen_pad + keys.enckeylen, 1); -#endif + + print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, + ctx->adata.keylen_pad + keys.enckeylen, 1); skip_split_key: ctx->cdata.keylen = keys.enckeylen; @@ -296,33 +277,17 @@ static int des3_aead_setkey(struct crypto_aead *aead, const u8 *key, unsigned int keylen) { struct crypto_authenc_keys keys; - u32 flags; int err; err = crypto_authenc_extractkeys(&keys, key, keylen); if (unlikely(err)) - goto badkey; - - err = -EINVAL; - if (keys.enckeylen != DES3_EDE_KEY_SIZE) - goto badkey; - - flags = crypto_aead_get_flags(aead); - err = __des3_verify_key(&flags, keys.enckey); - if (unlikely(err)) { - crypto_aead_set_flags(aead, flags); - goto out; - } + return err; - err = aead_setkey(aead, key, keylen); + err = verify_aead_des3_key(aead, keys.enckey, keys.enckeylen) ?: + aead_setkey(aead, key, keylen); -out: memzero_explicit(&keys, sizeof(keys)); return err; - -badkey: - crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); - goto out; } static int gcm_set_sh_desc(struct crypto_aead *aead) @@ -371,6 +336,11 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) static int gcm_setauthsize(struct crypto_aead *authenc, unsigned int authsize) { struct caam_ctx *ctx = crypto_aead_ctx(authenc); + int err; + + err = crypto_gcm_check_authsize(authsize); + if (err) + return err; ctx->authsize = authsize; gcm_set_sh_desc(authenc); @@ -385,6 +355,12 @@ static int gcm_setkey(struct crypto_aead *aead, struct device *jrdev = ctx->jrdev; int ret; + ret = aes_check_keylen(keylen); + if (ret) { + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); + return ret; + } + print_hex_dump_debug("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); @@ -466,6 +442,11 @@ static int rfc4106_setauthsize(struct crypto_aead *authenc, unsigned int authsize) { struct caam_ctx *ctx = crypto_aead_ctx(authenc); + int err; + + err = crypto_rfc4106_check_authsize(authsize); + if (err) + return err; ctx->authsize = authsize; rfc4106_set_sh_desc(authenc); @@ -480,8 +461,11 @@ static int rfc4106_setkey(struct crypto_aead *aead, struct device *jrdev = ctx->jrdev; int ret; - if (keylen < 4) - return -EINVAL; + ret = aes_check_keylen(keylen - 4); + if (ret) { + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); + return ret; + } print_hex_dump_debug("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); @@ -569,6 +553,9 @@ static int rfc4543_setauthsize(struct crypto_aead *authenc, { struct caam_ctx *ctx = crypto_aead_ctx(authenc); + if (authsize != 16) + return -EINVAL; + ctx->authsize = authsize; rfc4543_set_sh_desc(authenc); @@ -582,8 +569,11 @@ static int rfc4543_setkey(struct crypto_aead *aead, struct device *jrdev = ctx->jrdev; int ret; - if (keylen < 4) - return -EINVAL; + ret = aes_check_keylen(keylen - 4); + if (ret) { + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); + return ret; + } print_hex_dump_debug("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); @@ -624,7 +614,7 @@ static int rfc4543_setkey(struct crypto_aead *aead, } static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, - unsigned int keylen) + unsigned int keylen, const u32 ctx1_iv_off) { struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); struct caam_skcipher_alg *alg = @@ -632,33 +622,12 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, skcipher); struct device *jrdev = ctx->jrdev; unsigned int ivsize = crypto_skcipher_ivsize(skcipher); - u32 ctx1_iv_off = 0; - const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == - OP_ALG_AAI_CTR_MOD128); const bool is_rfc3686 = alg->caam.rfc3686; int ret = 0; print_hex_dump_debug("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); - /* - * AES-CTR needs to load IV in CONTEXT1 reg - * at an offset of 128bits (16bytes) - * CONTEXT1[255:128] = IV - */ - if (ctr_mode) - ctx1_iv_off = 16; - - /* - * RFC3686 specific: - * | CONTEXT1[255:128] = {NONCE, IV, COUNTER} - * | *key = {KEY, NONCE} - */ - if (is_rfc3686) { - ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; - keylen -= CTR_RFC3686_NONCE_SIZE; - } - ctx->cdata.keylen = keylen; ctx->cdata.key_virt = key; ctx->cdata.key_inline = true; @@ -694,11 +663,80 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, return -EINVAL; } +static int aes_skcipher_setkey(struct crypto_skcipher *skcipher, + const u8 *key, unsigned int keylen) +{ + int err; + + err = aes_check_keylen(keylen); + if (err) { + crypto_skcipher_set_flags(skcipher, + CRYPTO_TFM_RES_BAD_KEY_LEN); + return err; + } + + return skcipher_setkey(skcipher, key, keylen, 0); +} + +static int rfc3686_skcipher_setkey(struct crypto_skcipher *skcipher, + const u8 *key, unsigned int keylen) +{ + u32 ctx1_iv_off; + int err; + + /* + * RFC3686 specific: + * | CONTEXT1[255:128] = {NONCE, IV, COUNTER} + * | *key = {KEY, NONCE} + */ + ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; + keylen -= CTR_RFC3686_NONCE_SIZE; + + err = aes_check_keylen(keylen); + if (err) { + crypto_skcipher_set_flags(skcipher, + CRYPTO_TFM_RES_BAD_KEY_LEN); + return err; + } + + return skcipher_setkey(skcipher, key, keylen, ctx1_iv_off); +} + +static int ctr_skcipher_setkey(struct crypto_skcipher *skcipher, + const u8 *key, unsigned int keylen) +{ + u32 ctx1_iv_off; + int err; + + /* + * AES-CTR needs to load IV in CONTEXT1 reg + * at an offset of 128bits (16bytes) + * CONTEXT1[255:128] = IV + */ + ctx1_iv_off = 16; + + err = aes_check_keylen(keylen); + if (err) { + crypto_skcipher_set_flags(skcipher, + CRYPTO_TFM_RES_BAD_KEY_LEN); + return err; + } + + return skcipher_setkey(skcipher, key, keylen, ctx1_iv_off); +} + static int des3_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, unsigned int keylen) { - return unlikely(des3_verify_key(skcipher, key)) ?: - skcipher_setkey(skcipher, key, keylen); + return verify_skcipher_des3_key(skcipher, key) ?: + skcipher_setkey(skcipher, key, keylen, 0); +} + +static int des_skcipher_setkey(struct crypto_skcipher *skcipher, + const u8 *key, unsigned int keylen) +{ + return verify_skcipher_des_key(skcipher, key) ?: + skcipher_setkey(skcipher, key, keylen, 0); } static int xts_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, @@ -884,20 +922,8 @@ static void aead_done(struct caam_drv_req *drv_req, u32 status) qidev = caam_ctx->qidev; - if (unlikely(status)) { - u32 ssrc = status & JRSTA_SSRC_MASK; - u8 err_id = status & JRSTA_CCBERR_ERRID_MASK; - - caam_jr_strstatus(qidev, status); - /* - * verify hw auth check passed else return -EBADMSG - */ - if (ssrc == JRSTA_SSRC_CCB_ERROR && - err_id == JRSTA_CCBERR_ERRID_ICVCHK) - ecode = -EBADMSG; - else - ecode = -EIO; - } + if (unlikely(status)) + ecode = caam_jr_strstatus(qidev, status); edesc = container_of(drv_req, typeof(*edesc), drv_req); aead_unmap(qidev, edesc, aead_req); @@ -1168,18 +1194,14 @@ static int aead_decrypt(struct aead_request *req) static int ipsec_gcm_encrypt(struct aead_request *req) { - if (req->assoclen < 8) - return -EINVAL; - - return aead_crypt(req, true); + return crypto_ipsec_check_assoclen(req->assoclen) ? : aead_crypt(req, + true); } static int ipsec_gcm_decrypt(struct aead_request *req) { - if (req->assoclen < 8) - return -EINVAL; - - return aead_crypt(req, false); + return crypto_ipsec_check_assoclen(req->assoclen) ? : aead_crypt(req, + false); } static void skcipher_done(struct caam_drv_req *drv_req, u32 status) @@ -1190,13 +1212,14 @@ static void skcipher_done(struct caam_drv_req *drv_req, u32 status) struct caam_ctx *caam_ctx = crypto_skcipher_ctx(skcipher); struct device *qidev = caam_ctx->qidev; int ivsize = crypto_skcipher_ivsize(skcipher); + int ecode = 0; dev_dbg(qidev, "%s %d: status 0x%x\n", __func__, __LINE__, status); edesc = container_of(drv_req, typeof(*edesc), drv_req); if (status) - caam_jr_strstatus(qidev, status); + ecode = caam_jr_strstatus(qidev, status); print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->iv, @@ -1212,10 +1235,12 @@ static void skcipher_done(struct caam_drv_req *drv_req, u32 status) * ciphertext block (CBC mode) or last counter (CTR mode). * This is used e.g. by the CTS mode. */ - memcpy(req->iv, (u8 *)&edesc->sgt[0] + edesc->qm_sg_bytes, ivsize); + if (!ecode) + memcpy(req->iv, (u8 *)&edesc->sgt[0] + edesc->qm_sg_bytes, + ivsize); qi_cache_free(edesc); - skcipher_request_complete(req, status); + skcipher_request_complete(req, ecode); } static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req, @@ -1377,6 +1402,9 @@ static inline int skcipher_crypt(struct skcipher_request *req, bool encrypt) struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); int ret; + if (!req->cryptlen) + return 0; + if (unlikely(caam_congested)) return -EAGAIN; @@ -1414,7 +1442,7 @@ static struct caam_skcipher_alg driver_algs[] = { .cra_driver_name = "cbc-aes-caam-qi", .cra_blocksize = AES_BLOCK_SIZE, }, - .setkey = skcipher_setkey, + .setkey = aes_skcipher_setkey, .encrypt = skcipher_encrypt, .decrypt = skcipher_decrypt, .min_keysize = AES_MIN_KEY_SIZE, @@ -1446,7 +1474,7 @@ static struct caam_skcipher_alg driver_algs[] = { .cra_driver_name = "cbc-des-caam-qi", .cra_blocksize = DES_BLOCK_SIZE, }, - .setkey = skcipher_setkey, + .setkey = des_skcipher_setkey, .encrypt = skcipher_encrypt, .decrypt = skcipher_decrypt, .min_keysize = DES_KEY_SIZE, @@ -1462,7 +1490,7 @@ static struct caam_skcipher_alg driver_algs[] = { .cra_driver_name = "ctr-aes-caam-qi", .cra_blocksize = 1, }, - .setkey = skcipher_setkey, + .setkey = ctr_skcipher_setkey, .encrypt = skcipher_encrypt, .decrypt = skcipher_decrypt, .min_keysize = AES_MIN_KEY_SIZE, @@ -1480,7 +1508,7 @@ static struct caam_skcipher_alg driver_algs[] = { .cra_driver_name = "rfc3686-ctr-aes-caam-qi", .cra_blocksize = 1, }, - .setkey = skcipher_setkey, + .setkey = rfc3686_skcipher_setkey, .encrypt = skcipher_encrypt, .decrypt = skcipher_decrypt, .min_keysize = AES_MIN_KEY_SIZE + @@ -2523,10 +2551,9 @@ int caam_qi_algapi_init(struct device *ctrldev) unsigned int md_limit = SHA512_DIGEST_SIZE; bool registered = false; - if (caam_dpaa2) { - dev_info(ctrldev, "caam/qi frontend driver not suitable for DPAA 2.x, aborting...\n"); - return -ENODEV; - } + /* Make sure this runs only on (DPAA 1.x) QI */ + if (!priv->qi_present || caam_dpaa2) + return 0; /* * Register crypto algorithms the device supports. diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c index 06bf32c32cbd62f08a9bf2d25f30f0534a61e070..3443f6d6dd832fe2ad6ae40b2126db327a240ac6 100644 --- a/drivers/crypto/caam/caamalg_qi2.c +++ b/drivers/crypto/caam/caamalg_qi2.c @@ -15,6 +15,7 @@ #include "key_gen.h" #include "caamalg_desc.h" #include "caamhash_desc.h" +#include "dpseci-debugfs.h" #include #include #include @@ -198,6 +199,18 @@ static int aead_set_sh_desc(struct crypto_aead *aead) ctx->cdata.keylen - CTR_RFC3686_NONCE_SIZE); } + /* + * In case |user key| > |derived key|, using DKP would result + * in invalid opcodes (last bytes of user key) in the resulting + * descriptor. Use DKP instead => both virtual and dma key + * addresses are needed. + */ + ctx->adata.key_virt = ctx->key; + ctx->adata.key_dma = ctx->key_dma; + + ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; + ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; + data_len[0] = ctx->adata.keylen_pad; data_len[1] = ctx->cdata.keylen; @@ -209,16 +222,6 @@ static int aead_set_sh_desc(struct crypto_aead *aead) ARRAY_SIZE(data_len)) < 0) return -EINVAL; - if (inl_mask & 1) - ctx->adata.key_virt = ctx->key; - else - ctx->adata.key_dma = ctx->key_dma; - - if (inl_mask & 2) - ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; - else - ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; - ctx->adata.key_inline = !!(inl_mask & 1); ctx->cdata.key_inline = !!(inl_mask & 2); @@ -247,16 +250,6 @@ static int aead_set_sh_desc(struct crypto_aead *aead) ARRAY_SIZE(data_len)) < 0) return -EINVAL; - if (inl_mask & 1) - ctx->adata.key_virt = ctx->key; - else - ctx->adata.key_dma = ctx->key_dma; - - if (inl_mask & 2) - ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; - else - ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; - ctx->adata.key_inline = !!(inl_mask & 1); ctx->cdata.key_inline = !!(inl_mask & 2); @@ -329,7 +322,6 @@ static int des3_aead_setkey(struct crypto_aead *aead, const u8 *key, unsigned int keylen) { struct crypto_authenc_keys keys; - u32 flags; int err; err = crypto_authenc_extractkeys(&keys, key, keylen); @@ -340,14 +332,8 @@ static int des3_aead_setkey(struct crypto_aead *aead, const u8 *key, if (keys.enckeylen != DES3_EDE_KEY_SIZE) goto badkey; - flags = crypto_aead_get_flags(aead); - err = __des3_verify_key(&flags, keys.enckey); - if (unlikely(err)) { - crypto_aead_set_flags(aead, flags); - goto out; - } - - err = aead_setkey(aead, key, keylen); + err = crypto_des3_ede_verify_key(crypto_aead_tfm(aead), keys.enckey) ?: + aead_setkey(aead, key, keylen); out: memzero_explicit(&keys, sizeof(keys)); @@ -719,6 +705,11 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) static int gcm_setauthsize(struct crypto_aead *authenc, unsigned int authsize) { struct caam_ctx *ctx = crypto_aead_ctx(authenc); + int err; + + err = crypto_gcm_check_authsize(authsize); + if (err) + return err; ctx->authsize = authsize; gcm_set_sh_desc(authenc); @@ -731,7 +722,13 @@ static int gcm_setkey(struct crypto_aead *aead, { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *dev = ctx->dev; + int ret; + ret = aes_check_keylen(keylen); + if (ret) { + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); + return ret; + } print_hex_dump_debug("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); @@ -805,6 +802,11 @@ static int rfc4106_setauthsize(struct crypto_aead *authenc, unsigned int authsize) { struct caam_ctx *ctx = crypto_aead_ctx(authenc); + int err; + + err = crypto_rfc4106_check_authsize(authsize); + if (err) + return err; ctx->authsize = authsize; rfc4106_set_sh_desc(authenc); @@ -817,9 +819,13 @@ static int rfc4106_setkey(struct crypto_aead *aead, { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *dev = ctx->dev; + int ret; - if (keylen < 4) - return -EINVAL; + ret = aes_check_keylen(keylen - 4); + if (ret) { + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); + return ret; + } print_hex_dump_debug("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); @@ -900,6 +906,9 @@ static int rfc4543_setauthsize(struct crypto_aead *authenc, { struct caam_ctx *ctx = crypto_aead_ctx(authenc); + if (authsize != 16) + return -EINVAL; + ctx->authsize = authsize; rfc4543_set_sh_desc(authenc); @@ -911,9 +920,13 @@ static int rfc4543_setkey(struct crypto_aead *aead, { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *dev = ctx->dev; + int ret; - if (keylen < 4) - return -EINVAL; + ret = aes_check_keylen(keylen - 4); + if (ret) { + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); + return ret; + } print_hex_dump_debug("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); @@ -931,7 +944,7 @@ static int rfc4543_setkey(struct crypto_aead *aead, } static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, - unsigned int keylen) + unsigned int keylen, const u32 ctx1_iv_off) { struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); struct caam_skcipher_alg *alg = @@ -941,34 +954,11 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, struct caam_flc *flc; unsigned int ivsize = crypto_skcipher_ivsize(skcipher); u32 *desc; - u32 ctx1_iv_off = 0; - const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == - OP_ALG_AAI_CTR_MOD128) && - ((ctx->cdata.algtype & OP_ALG_ALGSEL_MASK) != - OP_ALG_ALGSEL_CHACHA20); const bool is_rfc3686 = alg->caam.rfc3686; print_hex_dump_debug("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); - /* - * AES-CTR needs to load IV in CONTEXT1 reg - * at an offset of 128bits (16bytes) - * CONTEXT1[255:128] = IV - */ - if (ctr_mode) - ctx1_iv_off = 16; - - /* - * RFC3686 specific: - * | CONTEXT1[255:128] = {NONCE, IV, COUNTER} - * | *key = {KEY, NONCE} - */ - if (is_rfc3686) { - ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; - keylen -= CTR_RFC3686_NONCE_SIZE; - } - ctx->cdata.keylen = keylen; ctx->cdata.key_virt = key; ctx->cdata.key_inline = true; @@ -996,11 +986,92 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, return 0; } +static int aes_skcipher_setkey(struct crypto_skcipher *skcipher, + const u8 *key, unsigned int keylen) +{ + int err; + + err = aes_check_keylen(keylen); + if (err) { + crypto_skcipher_set_flags(skcipher, + CRYPTO_TFM_RES_BAD_KEY_LEN); + return err; + } + + return skcipher_setkey(skcipher, key, keylen, 0); +} + +static int rfc3686_skcipher_setkey(struct crypto_skcipher *skcipher, + const u8 *key, unsigned int keylen) +{ + u32 ctx1_iv_off; + int err; + + /* + * RFC3686 specific: + * | CONTEXT1[255:128] = {NONCE, IV, COUNTER} + * | *key = {KEY, NONCE} + */ + ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; + keylen -= CTR_RFC3686_NONCE_SIZE; + + err = aes_check_keylen(keylen); + if (err) { + crypto_skcipher_set_flags(skcipher, + CRYPTO_TFM_RES_BAD_KEY_LEN); + return err; + } + + return skcipher_setkey(skcipher, key, keylen, ctx1_iv_off); +} + +static int ctr_skcipher_setkey(struct crypto_skcipher *skcipher, + const u8 *key, unsigned int keylen) +{ + u32 ctx1_iv_off; + int err; + + /* + * AES-CTR needs to load IV in CONTEXT1 reg + * at an offset of 128bits (16bytes) + * CONTEXT1[255:128] = IV + */ + ctx1_iv_off = 16; + + err = aes_check_keylen(keylen); + if (err) { + crypto_skcipher_set_flags(skcipher, + CRYPTO_TFM_RES_BAD_KEY_LEN); + return err; + } + + return skcipher_setkey(skcipher, key, keylen, ctx1_iv_off); +} + +static int chacha20_skcipher_setkey(struct crypto_skcipher *skcipher, + const u8 *key, unsigned int keylen) +{ + if (keylen != CHACHA_KEY_SIZE) { + crypto_skcipher_set_flags(skcipher, + CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + + return skcipher_setkey(skcipher, key, keylen, 0); +} + +static int des_skcipher_setkey(struct crypto_skcipher *skcipher, + const u8 *key, unsigned int keylen) +{ + return verify_skcipher_des_key(skcipher, key) ?: + skcipher_setkey(skcipher, key, keylen, 0); +} + static int des3_skcipher_setkey(struct crypto_skcipher *skcipher, - const u8 *key, unsigned int keylen) + const u8 *key, unsigned int keylen) { - return unlikely(des3_verify_key(skcipher, key)) ?: - skcipher_setkey(skcipher, key, keylen); + return verify_skcipher_des3_key(skcipher, key) ?: + skcipher_setkey(skcipher, key, keylen, 0); } static int xts_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, @@ -1227,10 +1298,8 @@ static void aead_encrypt_done(void *cbk_ctx, u32 status) dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); - if (unlikely(status)) { - caam_qi2_strstatus(ctx->dev, status); - ecode = -EIO; - } + if (unlikely(status)) + ecode = caam_qi2_strstatus(ctx->dev, status); aead_unmap(ctx->dev, edesc, req); qi_cache_free(edesc); @@ -1250,17 +1319,8 @@ static void aead_decrypt_done(void *cbk_ctx, u32 status) dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); - if (unlikely(status)) { - caam_qi2_strstatus(ctx->dev, status); - /* - * verify hw auth check passed else return -EBADMSG - */ - if ((status & JRSTA_CCBERR_ERRID_MASK) == - JRSTA_CCBERR_ERRID_ICVCHK) - ecode = -EBADMSG; - else - ecode = -EIO; - } + if (unlikely(status)) + ecode = caam_qi2_strstatus(ctx->dev, status); aead_unmap(ctx->dev, edesc, req); qi_cache_free(edesc); @@ -1325,18 +1385,12 @@ static int aead_decrypt(struct aead_request *req) static int ipsec_gcm_encrypt(struct aead_request *req) { - if (req->assoclen < 8) - return -EINVAL; - - return aead_encrypt(req); + return crypto_ipsec_check_assoclen(req->assoclen) ? : aead_encrypt(req); } static int ipsec_gcm_decrypt(struct aead_request *req) { - if (req->assoclen < 8) - return -EINVAL; - - return aead_decrypt(req); + return crypto_ipsec_check_assoclen(req->assoclen) ? : aead_decrypt(req); } static void skcipher_encrypt_done(void *cbk_ctx, u32 status) @@ -1352,10 +1406,8 @@ static void skcipher_encrypt_done(void *cbk_ctx, u32 status) dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); - if (unlikely(status)) { - caam_qi2_strstatus(ctx->dev, status); - ecode = -EIO; - } + if (unlikely(status)) + ecode = caam_qi2_strstatus(ctx->dev, status); print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->iv, @@ -1371,7 +1423,9 @@ static void skcipher_encrypt_done(void *cbk_ctx, u32 status) * ciphertext block (CBC mode) or last counter (CTR mode). * This is used e.g. by the CTS mode. */ - memcpy(req->iv, (u8 *)&edesc->sgt[0] + edesc->qm_sg_bytes, ivsize); + if (!ecode) + memcpy(req->iv, (u8 *)&edesc->sgt[0] + edesc->qm_sg_bytes, + ivsize); qi_cache_free(edesc); skcipher_request_complete(req, ecode); @@ -1390,10 +1444,8 @@ static void skcipher_decrypt_done(void *cbk_ctx, u32 status) dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); - if (unlikely(status)) { - caam_qi2_strstatus(ctx->dev, status); - ecode = -EIO; - } + if (unlikely(status)) + ecode = caam_qi2_strstatus(ctx->dev, status); print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->iv, @@ -1409,7 +1461,9 @@ static void skcipher_decrypt_done(void *cbk_ctx, u32 status) * ciphertext block (CBC mode) or last counter (CTR mode). * This is used e.g. by the CTS mode. */ - memcpy(req->iv, (u8 *)&edesc->sgt[0] + edesc->qm_sg_bytes, ivsize); + if (!ecode) + memcpy(req->iv, (u8 *)&edesc->sgt[0] + edesc->qm_sg_bytes, + ivsize); qi_cache_free(edesc); skcipher_request_complete(req, ecode); @@ -1423,6 +1477,9 @@ static int skcipher_encrypt(struct skcipher_request *req) struct caam_request *caam_req = skcipher_request_ctx(req); int ret; + if (!req->cryptlen) + return 0; + /* allocate extended descriptor */ edesc = skcipher_edesc_alloc(req); if (IS_ERR(edesc)) @@ -1451,6 +1508,8 @@ static int skcipher_decrypt(struct skcipher_request *req) struct caam_request *caam_req = skcipher_request_ctx(req); int ret; + if (!req->cryptlen) + return 0; /* allocate extended descriptor */ edesc = skcipher_edesc_alloc(req); if (IS_ERR(edesc)) @@ -1545,7 +1604,7 @@ static struct caam_skcipher_alg driver_algs[] = { .cra_driver_name = "cbc-aes-caam-qi2", .cra_blocksize = AES_BLOCK_SIZE, }, - .setkey = skcipher_setkey, + .setkey = aes_skcipher_setkey, .encrypt = skcipher_encrypt, .decrypt = skcipher_decrypt, .min_keysize = AES_MIN_KEY_SIZE, @@ -1577,7 +1636,7 @@ static struct caam_skcipher_alg driver_algs[] = { .cra_driver_name = "cbc-des-caam-qi2", .cra_blocksize = DES_BLOCK_SIZE, }, - .setkey = skcipher_setkey, + .setkey = des_skcipher_setkey, .encrypt = skcipher_encrypt, .decrypt = skcipher_decrypt, .min_keysize = DES_KEY_SIZE, @@ -1593,7 +1652,7 @@ static struct caam_skcipher_alg driver_algs[] = { .cra_driver_name = "ctr-aes-caam-qi2", .cra_blocksize = 1, }, - .setkey = skcipher_setkey, + .setkey = ctr_skcipher_setkey, .encrypt = skcipher_encrypt, .decrypt = skcipher_decrypt, .min_keysize = AES_MIN_KEY_SIZE, @@ -1611,7 +1670,7 @@ static struct caam_skcipher_alg driver_algs[] = { .cra_driver_name = "rfc3686-ctr-aes-caam-qi2", .cra_blocksize = 1, }, - .setkey = skcipher_setkey, + .setkey = rfc3686_skcipher_setkey, .encrypt = skcipher_encrypt, .decrypt = skcipher_decrypt, .min_keysize = AES_MIN_KEY_SIZE + @@ -1650,7 +1709,7 @@ static struct caam_skcipher_alg driver_algs[] = { .cra_driver_name = "chacha20-caam-qi2", .cra_blocksize = 1, }, - .setkey = skcipher_setkey, + .setkey = chacha20_skcipher_setkey, .encrypt = skcipher_encrypt, .decrypt = skcipher_decrypt, .min_keysize = CHACHA_KEY_SIZE, @@ -2918,6 +2977,7 @@ enum hash_optype { /** * caam_hash_ctx - ahash per-session context * @flc: Flow Contexts array + * @key: authentication key * @flc_dma: I/O virtual addresses of the Flow Contexts * @dev: dpseci device * @ctx_len: size of Context Register @@ -2925,6 +2985,7 @@ enum hash_optype { */ struct caam_hash_ctx { struct caam_flc flc[HASH_NUM_OP]; + u8 key[CAAM_MAX_HASH_BLOCK_SIZE] ____cacheline_aligned; dma_addr_t flc_dma[HASH_NUM_OP]; struct device *dev; int ctx_len; @@ -3094,10 +3155,7 @@ static void split_key_sh_done(void *cbk_ctx, u32 err) dev_dbg(res->dev, "%s %d: err 0x%x\n", __func__, __LINE__, err); - if (err) - caam_qi2_strstatus(res->dev, err); - - res->err = err; + res->err = err ? caam_qi2_strstatus(res->dev, err) : 0; complete(&res->completion); } @@ -3228,6 +3286,19 @@ static int ahash_setkey(struct crypto_ahash *ahash, const u8 *key, ctx->adata.key_virt = key; ctx->adata.key_inline = true; + /* + * In case |user key| > |derived key|, using DKP would result + * in invalid opcodes (last bytes of user key) in the resulting + * descriptor. Use DKP instead => both virtual and dma key + * addresses are needed. + */ + if (keylen > ctx->adata.keylen_pad) { + memcpy(ctx->key, key, keylen); + dma_sync_single_for_device(ctx->dev, ctx->adata.key_dma, + ctx->adata.keylen_pad, + DMA_TO_DEVICE); + } + ret = ahash_set_sh_desc(ahash); kfree(hashed_key); return ret; @@ -3282,10 +3353,8 @@ static void ahash_done(void *cbk_ctx, u32 status) dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); - if (unlikely(status)) { - caam_qi2_strstatus(ctx->dev, status); - ecode = -EIO; - } + if (unlikely(status)) + ecode = caam_qi2_strstatus(ctx->dev, status); ahash_unmap_ctx(ctx->dev, edesc, req, DMA_FROM_DEVICE); memcpy(req->result, state->caam_ctx, digestsize); @@ -3310,10 +3379,8 @@ static void ahash_done_bi(void *cbk_ctx, u32 status) dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); - if (unlikely(status)) { - caam_qi2_strstatus(ctx->dev, status); - ecode = -EIO; - } + if (unlikely(status)) + ecode = caam_qi2_strstatus(ctx->dev, status); ahash_unmap_ctx(ctx->dev, edesc, req, DMA_BIDIRECTIONAL); switch_buf(state); @@ -3343,10 +3410,8 @@ static void ahash_done_ctx_src(void *cbk_ctx, u32 status) dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); - if (unlikely(status)) { - caam_qi2_strstatus(ctx->dev, status); - ecode = -EIO; - } + if (unlikely(status)) + ecode = caam_qi2_strstatus(ctx->dev, status); ahash_unmap_ctx(ctx->dev, edesc, req, DMA_BIDIRECTIONAL); memcpy(req->result, state->caam_ctx, digestsize); @@ -3371,10 +3436,8 @@ static void ahash_done_ctx_dst(void *cbk_ctx, u32 status) dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); - if (unlikely(status)) { - caam_qi2_strstatus(ctx->dev, status); - ecode = -EIO; - } + if (unlikely(status)) + ecode = caam_qi2_strstatus(ctx->dev, status); ahash_unmap_ctx(ctx->dev, edesc, req, DMA_FROM_DEVICE); switch_buf(state); @@ -4466,11 +4529,27 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) ctx->dev = caam_hash->dev; + if (alg->setkey) { + ctx->adata.key_dma = dma_map_single_attrs(ctx->dev, ctx->key, + ARRAY_SIZE(ctx->key), + DMA_TO_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); + if (dma_mapping_error(ctx->dev, ctx->adata.key_dma)) { + dev_err(ctx->dev, "unable to map key\n"); + return -ENOMEM; + } + } + dma_addr = dma_map_single_attrs(ctx->dev, ctx->flc, sizeof(ctx->flc), DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); if (dma_mapping_error(ctx->dev, dma_addr)) { dev_err(ctx->dev, "unable to map shared descriptors\n"); + if (ctx->adata.key_dma) + dma_unmap_single_attrs(ctx->dev, ctx->adata.key_dma, + ARRAY_SIZE(ctx->key), + DMA_TO_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); return -ENOMEM; } @@ -4496,6 +4575,10 @@ static void caam_hash_cra_exit(struct crypto_tfm *tfm) dma_unmap_single_attrs(ctx->dev, ctx->flc_dma[0], sizeof(ctx->flc), DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); + if (ctx->adata.key_dma) + dma_unmap_single_attrs(ctx->dev, ctx->adata.key_dma, + ARRAY_SIZE(ctx->key), DMA_TO_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); } static struct caam_hash_alg *caam_hash_alloc(struct device *dev, @@ -4700,7 +4783,7 @@ static void dpaa2_caam_process_fd(struct dpaa2_caam_priv *priv, fd_err = dpaa2_fd_get_ctrl(fd) & FD_CTRL_ERR_MASK; if (unlikely(fd_err)) - dev_err(priv->dev, "FD error: %08x\n", fd_err); + dev_err_ratelimited(priv->dev, "FD error: %08x\n", fd_err); /* * FD[ADDR] is guaranteed to be valid, irrespective of errors reported @@ -5098,6 +5181,8 @@ static int dpaa2_caam_probe(struct fsl_mc_device *dpseci_dev) goto err_bind; } + dpaa2_dpseci_debugfs_init(priv); + /* register crypto algorithms the device supports */ for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { struct caam_skcipher_alg *t_alg = driver_algs + i; @@ -5265,6 +5350,8 @@ static int __cold dpaa2_caam_remove(struct fsl_mc_device *ls_dev) dev = &ls_dev->dev; priv = dev_get_drvdata(dev); + dpaa2_dpseci_debugfs_exit(priv); + for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) { struct caam_aead_alg *t_alg = driver_aeads + i; diff --git a/drivers/crypto/caam/caamalg_qi2.h b/drivers/crypto/caam/caamalg_qi2.h index be5085451053be4fcd554ddb0158960b52a2d207..706736776b47ac9bef61edfb180ba1fea00d47da 100644 --- a/drivers/crypto/caam/caamalg_qi2.h +++ b/drivers/crypto/caam/caamalg_qi2.h @@ -10,12 +10,13 @@ #include #include #include +#include #include "dpseci.h" #include "desc_constr.h" #define DPAA2_CAAM_STORE_SIZE 16 /* NAPI weight *must* be a multiple of the store size. */ -#define DPAA2_CAAM_NAPI_WEIGHT 64 +#define DPAA2_CAAM_NAPI_WEIGHT 512 /* The congestion entrance threshold was chosen so that on LS2088 * we support the maximum throughput for the available memory @@ -64,6 +65,7 @@ struct dpaa2_caam_priv { struct iommu_domain *domain; struct dpaa2_caam_priv_per_cpu __percpu *ppriv; + struct dentry *dfs_root; }; /** @@ -90,33 +92,6 @@ struct dpaa2_caam_priv_per_cpu { struct dpaa2_io *dpio; }; -/* - * The CAAM QI hardware constructs a job descriptor which points - * to shared descriptor (as pointed by context_a of FQ to CAAM). - * When the job descriptor is executed by deco, the whole job - * descriptor together with shared descriptor gets loaded in - * deco buffer which is 64 words long (each 32-bit). - * - * The job descriptor constructed by QI hardware has layout: - * - * HEADER (1 word) - * Shdesc ptr (1 or 2 words) - * SEQ_OUT_PTR (1 word) - * Out ptr (1 or 2 words) - * Out length (1 word) - * SEQ_IN_PTR (1 word) - * In ptr (1 or 2 words) - * In length (1 word) - * - * The shdesc ptr is used to fetch shared descriptor contents - * into deco buffer. - * - * Apart from shdesc contents, the total number of words that - * get loaded in deco buffer are '8' or '11'. The remaining words - * in deco buffer can be used for storing shared descriptor. - */ -#define MAX_SDLEN ((CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN) / CAAM_CMD_SZ) - /* Length of a single buffer in the QI driver memory cache */ #define CAAM_QI_MEMCACHE_SIZE 512 diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index e4ac5d591ad689af5a3bc574b43aa9e8c4ebdf62..65399cb2a77057c91399a76ee72666ab159ceaf3 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -95,8 +95,8 @@ struct caam_hash_ctx { dma_addr_t sh_desc_update_first_dma; dma_addr_t sh_desc_fin_dma; dma_addr_t sh_desc_digest_dma; - dma_addr_t key_dma; enum dma_data_direction dir; + enum dma_data_direction key_dir; struct device *jrdev; int ctx_len; struct alginfo adata; @@ -282,13 +282,10 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash) struct device *jrdev = ctx->jrdev; u32 *desc; - /* key is loaded from memory for UPDATE and FINALIZE states */ - ctx->adata.key_dma = ctx->key_dma; - /* shared descriptor for ahash_update */ desc = ctx->sh_desc_update; cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_UPDATE, - ctx->ctx_len, ctx->ctx_len, 0); + ctx->ctx_len, ctx->ctx_len); dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma, desc_bytes(desc), ctx->dir); print_hex_dump_debug("axcbc update shdesc@" __stringify(__LINE__)" : ", @@ -298,7 +295,7 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash) /* shared descriptor for ahash_{final,finup} */ desc = ctx->sh_desc_fin; cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_FINALIZE, - digestsize, ctx->ctx_len, 0); + digestsize, ctx->ctx_len); dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, desc_bytes(desc), ctx->dir); print_hex_dump_debug("axcbc finup shdesc@" __stringify(__LINE__)" : ", @@ -311,7 +308,7 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash) /* shared descriptor for first invocation of ahash_update */ desc = ctx->sh_desc_update_first; cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_INIT, ctx->ctx_len, - ctx->ctx_len, ctx->key_dma); + ctx->ctx_len); dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, desc_bytes(desc), ctx->dir); print_hex_dump_debug("axcbc update first shdesc@" __stringify(__LINE__) @@ -321,7 +318,7 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash) /* shared descriptor for ahash_digest */ desc = ctx->sh_desc_digest; cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_INITFINAL, - digestsize, ctx->ctx_len, 0); + digestsize, ctx->ctx_len); dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, desc_bytes(desc), ctx->dir); print_hex_dump_debug("axcbc digest shdesc@" __stringify(__LINE__)" : ", @@ -340,7 +337,7 @@ static int acmac_set_sh_desc(struct crypto_ahash *ahash) /* shared descriptor for ahash_update */ desc = ctx->sh_desc_update; cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_UPDATE, - ctx->ctx_len, ctx->ctx_len, 0); + ctx->ctx_len, ctx->ctx_len); dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma, desc_bytes(desc), ctx->dir); print_hex_dump_debug("acmac update shdesc@" __stringify(__LINE__)" : ", @@ -350,7 +347,7 @@ static int acmac_set_sh_desc(struct crypto_ahash *ahash) /* shared descriptor for ahash_{final,finup} */ desc = ctx->sh_desc_fin; cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_FINALIZE, - digestsize, ctx->ctx_len, 0); + digestsize, ctx->ctx_len); dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, desc_bytes(desc), ctx->dir); print_hex_dump_debug("acmac finup shdesc@" __stringify(__LINE__)" : ", @@ -360,7 +357,7 @@ static int acmac_set_sh_desc(struct crypto_ahash *ahash) /* shared descriptor for first invocation of ahash_update */ desc = ctx->sh_desc_update_first; cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_INIT, ctx->ctx_len, - ctx->ctx_len, 0); + ctx->ctx_len); dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, desc_bytes(desc), ctx->dir); print_hex_dump_debug("acmac update first shdesc@" __stringify(__LINE__) @@ -370,7 +367,7 @@ static int acmac_set_sh_desc(struct crypto_ahash *ahash) /* shared descriptor for ahash_digest */ desc = ctx->sh_desc_digest; cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_INITFINAL, - digestsize, ctx->ctx_len, 0); + digestsize, ctx->ctx_len); dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, desc_bytes(desc), ctx->dir); print_hex_dump_debug("acmac digest shdesc@" __stringify(__LINE__)" : ", @@ -480,6 +477,18 @@ static int ahash_setkey(struct crypto_ahash *ahash, goto bad_free_key; memcpy(ctx->key, key, keylen); + + /* + * In case |user key| > |derived key|, using DKP + * would result in invalid opcodes (last bytes of user key) in + * the resulting descriptor. Use DKP instead => both + * virtual and dma key addresses are needed. + */ + if (keylen > ctx->adata.keylen_pad) + dma_sync_single_for_device(ctx->jrdev, + ctx->adata.key_dma, + ctx->adata.keylen_pad, + DMA_TO_DEVICE); } else { ret = gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, key, keylen, CAAM_MAX_HASH_KEY_SIZE); @@ -501,8 +510,14 @@ static int axcbc_setkey(struct crypto_ahash *ahash, const u8 *key, struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); struct device *jrdev = ctx->jrdev; + if (keylen != AES_KEYSIZE_128) { + crypto_ahash_set_flags(ahash, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + memcpy(ctx->key, key, keylen); - dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, DMA_TO_DEVICE); + dma_sync_single_for_device(jrdev, ctx->adata.key_dma, keylen, + DMA_TO_DEVICE); ctx->adata.keylen = keylen; print_hex_dump_debug("axcbc ctx.key@" __stringify(__LINE__)" : ", @@ -515,6 +530,13 @@ static int acmac_setkey(struct crypto_ahash *ahash, const u8 *key, unsigned int keylen) { struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + int err; + + err = aes_check_keylen(keylen); + if (err) { + crypto_ahash_set_flags(ahash, CRYPTO_TFM_RES_BAD_KEY_LEN); + return err; + } /* key is immediate data for all cmac shared descriptors */ ctx->adata.key_virt = key; @@ -538,7 +560,7 @@ struct ahash_edesc { dma_addr_t sec4_sg_dma; int src_nents; int sec4_sg_bytes; - u32 hw_desc[DESC_JOB_IO_LEN / sizeof(u32)] ____cacheline_aligned; + u32 hw_desc[DESC_JOB_IO_LEN_MAX / sizeof(u32)] ____cacheline_aligned; struct sec4_sg_entry sec4_sg[0]; }; @@ -584,12 +606,13 @@ static void ahash_done(struct device *jrdev, u32 *desc, u32 err, int digestsize = crypto_ahash_digestsize(ahash); struct caam_hash_state *state = ahash_request_ctx(req); struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + int ecode = 0; dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); edesc = container_of(desc, struct ahash_edesc, hw_desc[0]); if (err) - caam_jr_strstatus(jrdev, err); + ecode = caam_jr_strstatus(jrdev, err); ahash_unmap_ctx(jrdev, edesc, req, digestsize, DMA_FROM_DEVICE); memcpy(req->result, state->caam_ctx, digestsize); @@ -599,7 +622,7 @@ static void ahash_done(struct device *jrdev, u32 *desc, u32 err, DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, ctx->ctx_len, 1); - req->base.complete(&req->base, err); + req->base.complete(&req->base, ecode); } static void ahash_done_bi(struct device *jrdev, u32 *desc, u32 err, @@ -611,12 +634,13 @@ static void ahash_done_bi(struct device *jrdev, u32 *desc, u32 err, struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); struct caam_hash_state *state = ahash_request_ctx(req); int digestsize = crypto_ahash_digestsize(ahash); + int ecode = 0; dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); edesc = container_of(desc, struct ahash_edesc, hw_desc[0]); if (err) - caam_jr_strstatus(jrdev, err); + ecode = caam_jr_strstatus(jrdev, err); ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_BIDIRECTIONAL); switch_buf(state); @@ -630,7 +654,7 @@ static void ahash_done_bi(struct device *jrdev, u32 *desc, u32 err, DUMP_PREFIX_ADDRESS, 16, 4, req->result, digestsize, 1); - req->base.complete(&req->base, err); + req->base.complete(&req->base, ecode); } static void ahash_done_ctx_src(struct device *jrdev, u32 *desc, u32 err, @@ -642,12 +666,13 @@ static void ahash_done_ctx_src(struct device *jrdev, u32 *desc, u32 err, int digestsize = crypto_ahash_digestsize(ahash); struct caam_hash_state *state = ahash_request_ctx(req); struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + int ecode = 0; dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); edesc = container_of(desc, struct ahash_edesc, hw_desc[0]); if (err) - caam_jr_strstatus(jrdev, err); + ecode = caam_jr_strstatus(jrdev, err); ahash_unmap_ctx(jrdev, edesc, req, digestsize, DMA_BIDIRECTIONAL); memcpy(req->result, state->caam_ctx, digestsize); @@ -657,7 +682,7 @@ static void ahash_done_ctx_src(struct device *jrdev, u32 *desc, u32 err, DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, ctx->ctx_len, 1); - req->base.complete(&req->base, err); + req->base.complete(&req->base, ecode); } static void ahash_done_ctx_dst(struct device *jrdev, u32 *desc, u32 err, @@ -669,12 +694,13 @@ static void ahash_done_ctx_dst(struct device *jrdev, u32 *desc, u32 err, struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); struct caam_hash_state *state = ahash_request_ctx(req); int digestsize = crypto_ahash_digestsize(ahash); + int ecode = 0; dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); edesc = container_of(desc, struct ahash_edesc, hw_desc[0]); if (err) - caam_jr_strstatus(jrdev, err); + ecode = caam_jr_strstatus(jrdev, err); ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_FROM_DEVICE); switch_buf(state); @@ -688,7 +714,7 @@ static void ahash_done_ctx_dst(struct device *jrdev, u32 *desc, u32 err, DUMP_PREFIX_ADDRESS, 16, 4, req->result, digestsize, 1); - req->base.complete(&req->base, err); + req->base.complete(&req->base, ecode); } /* @@ -1812,40 +1838,50 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) if (is_xcbc_aes(caam_hash->alg_type)) { ctx->dir = DMA_TO_DEVICE; + ctx->key_dir = DMA_BIDIRECTIONAL; ctx->adata.algtype = OP_TYPE_CLASS1_ALG | caam_hash->alg_type; ctx->ctx_len = 48; - - ctx->key_dma = dma_map_single_attrs(ctx->jrdev, ctx->key, - ARRAY_SIZE(ctx->key), - DMA_BIDIRECTIONAL, - DMA_ATTR_SKIP_CPU_SYNC); - if (dma_mapping_error(ctx->jrdev, ctx->key_dma)) { - dev_err(ctx->jrdev, "unable to map key\n"); - caam_jr_free(ctx->jrdev); - return -ENOMEM; - } } else if (is_cmac_aes(caam_hash->alg_type)) { ctx->dir = DMA_TO_DEVICE; + ctx->key_dir = DMA_NONE; ctx->adata.algtype = OP_TYPE_CLASS1_ALG | caam_hash->alg_type; ctx->ctx_len = 32; } else { - ctx->dir = priv->era >= 6 ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE; + if (priv->era >= 6) { + ctx->dir = DMA_BIDIRECTIONAL; + ctx->key_dir = alg->setkey ? DMA_TO_DEVICE : DMA_NONE; + } else { + ctx->dir = DMA_TO_DEVICE; + ctx->key_dir = DMA_NONE; + } ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam_hash->alg_type; ctx->ctx_len = runninglen[(ctx->adata.algtype & OP_ALG_ALGSEL_SUBMASK) >> OP_ALG_ALGSEL_SHIFT]; } + if (ctx->key_dir != DMA_NONE) { + ctx->adata.key_dma = dma_map_single_attrs(ctx->jrdev, ctx->key, + ARRAY_SIZE(ctx->key), + ctx->key_dir, + DMA_ATTR_SKIP_CPU_SYNC); + if (dma_mapping_error(ctx->jrdev, ctx->adata.key_dma)) { + dev_err(ctx->jrdev, "unable to map key\n"); + caam_jr_free(ctx->jrdev); + return -ENOMEM; + } + } + dma_addr = dma_map_single_attrs(ctx->jrdev, ctx->sh_desc_update, offsetof(struct caam_hash_ctx, key), ctx->dir, DMA_ATTR_SKIP_CPU_SYNC); if (dma_mapping_error(ctx->jrdev, dma_addr)) { dev_err(ctx->jrdev, "unable to map shared descriptors\n"); - if (is_xcbc_aes(caam_hash->alg_type)) - dma_unmap_single_attrs(ctx->jrdev, ctx->key_dma, + if (ctx->key_dir != DMA_NONE) + dma_unmap_single_attrs(ctx->jrdev, ctx->adata.key_dma, ARRAY_SIZE(ctx->key), - DMA_BIDIRECTIONAL, + ctx->key_dir, DMA_ATTR_SKIP_CPU_SYNC); caam_jr_free(ctx->jrdev); @@ -1878,9 +1914,9 @@ static void caam_hash_cra_exit(struct crypto_tfm *tfm) dma_unmap_single_attrs(ctx->jrdev, ctx->sh_desc_update_dma, offsetof(struct caam_hash_ctx, key), ctx->dir, DMA_ATTR_SKIP_CPU_SYNC); - if (is_xcbc_aes(ctx->adata.algtype)) - dma_unmap_single_attrs(ctx->jrdev, ctx->key_dma, - ARRAY_SIZE(ctx->key), DMA_BIDIRECTIONAL, + if (ctx->key_dir != DMA_NONE) + dma_unmap_single_attrs(ctx->jrdev, ctx->adata.key_dma, + ARRAY_SIZE(ctx->key), ctx->key_dir, DMA_ATTR_SKIP_CPU_SYNC); caam_jr_free(ctx->jrdev); } @@ -1971,7 +2007,7 @@ int caam_algapi_hash_init(struct device *ctrldev) * is not present. */ if (!md_inst) - return -ENODEV; + return 0; /* Limit digest size based on LP256 */ if (md_vid == CHA_VER_VID_MD_LP256) diff --git a/drivers/crypto/caam/caamhash_desc.c b/drivers/crypto/caam/caamhash_desc.c index 71d018343ee453f595d2bba88e668f04b63672e0..78383d77da99dc61b70c8950863a925446c182f1 100644 --- a/drivers/crypto/caam/caamhash_desc.c +++ b/drivers/crypto/caam/caamhash_desc.c @@ -83,10 +83,9 @@ EXPORT_SYMBOL(cnstr_shdsc_ahash); * @state: algorithm state OP_ALG_AS_{INIT, FINALIZE, INITFINALIZE, UPDATE} * @digestsize: algorithm's digest size * @ctx_len: size of Context Register - * @key_dma: I/O Virtual Address of the key */ void cnstr_shdsc_sk_hash(u32 * const desc, struct alginfo *adata, u32 state, - int digestsize, int ctx_len, dma_addr_t key_dma) + int digestsize, int ctx_len) { u32 *skip_key_load; @@ -136,7 +135,7 @@ void cnstr_shdsc_sk_hash(u32 * const desc, struct alginfo *adata, u32 state, LDST_SRCDST_BYTE_CONTEXT); if (is_xcbc_aes(adata->algtype) && state == OP_ALG_AS_INIT) /* Save K1 */ - append_fifo_store(desc, key_dma, adata->keylen, + append_fifo_store(desc, adata->key_dma, adata->keylen, LDST_CLASS_1_CCB | FIFOST_TYPE_KEY_KEK); } EXPORT_SYMBOL(cnstr_shdsc_sk_hash); diff --git a/drivers/crypto/caam/caamhash_desc.h b/drivers/crypto/caam/caamhash_desc.h index 6947ee1f200c2a224681eff7ea289b386fb73266..4f369b8cb6aee72346e24372346a3c9e42fdab63 100644 --- a/drivers/crypto/caam/caamhash_desc.h +++ b/drivers/crypto/caam/caamhash_desc.h @@ -25,5 +25,5 @@ void cnstr_shdsc_ahash(u32 * const desc, struct alginfo *adata, u32 state, int digestsize, int ctx_len, bool import_ctx, int era); void cnstr_shdsc_sk_hash(u32 * const desc, struct alginfo *adata, u32 state, - int digestsize, int ctx_len, dma_addr_t key_dma); + int digestsize, int ctx_len); #endif /* _CAAMHASH_DESC_H_ */ diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c index 80574106af29b19ce91b381d17a1677093c1831c..83f96d4f86e03614be5e87e3c09e6dc9b2c40f5d 100644 --- a/drivers/crypto/caam/caampkc.c +++ b/drivers/crypto/caam/caampkc.c @@ -17,18 +17,29 @@ #include "sg_sw_sec4.h" #include "caampkc.h" -#define DESC_RSA_PUB_LEN (2 * CAAM_CMD_SZ + sizeof(struct rsa_pub_pdb)) +#define DESC_RSA_PUB_LEN (2 * CAAM_CMD_SZ + SIZEOF_RSA_PUB_PDB) #define DESC_RSA_PRIV_F1_LEN (2 * CAAM_CMD_SZ + \ - sizeof(struct rsa_priv_f1_pdb)) + SIZEOF_RSA_PRIV_F1_PDB) #define DESC_RSA_PRIV_F2_LEN (2 * CAAM_CMD_SZ + \ - sizeof(struct rsa_priv_f2_pdb)) + SIZEOF_RSA_PRIV_F2_PDB) #define DESC_RSA_PRIV_F3_LEN (2 * CAAM_CMD_SZ + \ - sizeof(struct rsa_priv_f3_pdb)) + SIZEOF_RSA_PRIV_F3_PDB) #define CAAM_RSA_MAX_INPUT_SIZE 512 /* for a 4096-bit modulus */ /* buffer filled with zeros, used for padding */ static u8 *zero_buffer; +/* + * variable used to avoid double free of resources in case + * algorithm registration was unsuccessful + */ +static bool init_done; + +struct caam_akcipher_alg { + struct akcipher_alg akcipher; + bool registered; +}; + static void rsa_io_unmap(struct device *dev, struct rsa_edesc *edesc, struct akcipher_request *req) { @@ -107,9 +118,10 @@ static void rsa_pub_done(struct device *dev, u32 *desc, u32 err, void *context) { struct akcipher_request *req = context; struct rsa_edesc *edesc; + int ecode = 0; if (err) - caam_jr_strstatus(dev, err); + ecode = caam_jr_strstatus(dev, err); edesc = container_of(desc, struct rsa_edesc, hw_desc[0]); @@ -117,7 +129,7 @@ static void rsa_pub_done(struct device *dev, u32 *desc, u32 err, void *context) rsa_io_unmap(dev, edesc, req); kfree(edesc); - akcipher_request_complete(req, err); + akcipher_request_complete(req, ecode); } static void rsa_priv_f1_done(struct device *dev, u32 *desc, u32 err, @@ -125,9 +137,10 @@ static void rsa_priv_f1_done(struct device *dev, u32 *desc, u32 err, { struct akcipher_request *req = context; struct rsa_edesc *edesc; + int ecode = 0; if (err) - caam_jr_strstatus(dev, err); + ecode = caam_jr_strstatus(dev, err); edesc = container_of(desc, struct rsa_edesc, hw_desc[0]); @@ -135,7 +148,7 @@ static void rsa_priv_f1_done(struct device *dev, u32 *desc, u32 err, rsa_io_unmap(dev, edesc, req); kfree(edesc); - akcipher_request_complete(req, err); + akcipher_request_complete(req, ecode); } static void rsa_priv_f2_done(struct device *dev, u32 *desc, u32 err, @@ -143,9 +156,10 @@ static void rsa_priv_f2_done(struct device *dev, u32 *desc, u32 err, { struct akcipher_request *req = context; struct rsa_edesc *edesc; + int ecode = 0; if (err) - caam_jr_strstatus(dev, err); + ecode = caam_jr_strstatus(dev, err); edesc = container_of(desc, struct rsa_edesc, hw_desc[0]); @@ -153,7 +167,7 @@ static void rsa_priv_f2_done(struct device *dev, u32 *desc, u32 err, rsa_io_unmap(dev, edesc, req); kfree(edesc); - akcipher_request_complete(req, err); + akcipher_request_complete(req, ecode); } static void rsa_priv_f3_done(struct device *dev, u32 *desc, u32 err, @@ -161,9 +175,10 @@ static void rsa_priv_f3_done(struct device *dev, u32 *desc, u32 err, { struct akcipher_request *req = context; struct rsa_edesc *edesc; + int ecode = 0; if (err) - caam_jr_strstatus(dev, err); + ecode = caam_jr_strstatus(dev, err); edesc = container_of(desc, struct rsa_edesc, hw_desc[0]); @@ -171,7 +186,7 @@ static void rsa_priv_f3_done(struct device *dev, u32 *desc, u32 err, rsa_io_unmap(dev, edesc, req); kfree(edesc); - akcipher_request_complete(req, err); + akcipher_request_complete(req, ecode); } /** @@ -867,7 +882,7 @@ static int caam_rsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, return ret; /* Copy key in DMA zone */ - rsa_key->e = kzalloc(raw_key.e_sz, GFP_DMA | GFP_KERNEL); + rsa_key->e = kmemdup(raw_key.e, raw_key.e_sz, GFP_DMA | GFP_KERNEL); if (!rsa_key->e) goto err; @@ -889,8 +904,6 @@ static int caam_rsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, rsa_key->e_sz = raw_key.e_sz; rsa_key->n_sz = raw_key.n_sz; - memcpy(rsa_key->e, raw_key.e, raw_key.e_sz); - return 0; err: caam_rsa_free_key(rsa_key); @@ -971,11 +984,11 @@ static int caam_rsa_set_priv_key(struct crypto_akcipher *tfm, const void *key, return ret; /* Copy key in DMA zone */ - rsa_key->d = kzalloc(raw_key.d_sz, GFP_DMA | GFP_KERNEL); + rsa_key->d = kmemdup(raw_key.d, raw_key.d_sz, GFP_DMA | GFP_KERNEL); if (!rsa_key->d) goto err; - rsa_key->e = kzalloc(raw_key.e_sz, GFP_DMA | GFP_KERNEL); + rsa_key->e = kmemdup(raw_key.e, raw_key.e_sz, GFP_DMA | GFP_KERNEL); if (!rsa_key->e) goto err; @@ -998,9 +1011,6 @@ static int caam_rsa_set_priv_key(struct crypto_akcipher *tfm, const void *key, rsa_key->e_sz = raw_key.e_sz; rsa_key->n_sz = raw_key.n_sz; - memcpy(rsa_key->d, raw_key.d, raw_key.d_sz); - memcpy(rsa_key->e, raw_key.e, raw_key.e_sz); - caam_rsa_set_priv_key_form(ctx, &raw_key); return 0; @@ -1053,22 +1063,24 @@ static void caam_rsa_exit_tfm(struct crypto_akcipher *tfm) caam_jr_free(ctx->dev); } -static struct akcipher_alg caam_rsa = { - .encrypt = caam_rsa_enc, - .decrypt = caam_rsa_dec, - .set_pub_key = caam_rsa_set_pub_key, - .set_priv_key = caam_rsa_set_priv_key, - .max_size = caam_rsa_max_size, - .init = caam_rsa_init_tfm, - .exit = caam_rsa_exit_tfm, - .reqsize = sizeof(struct caam_rsa_req_ctx), - .base = { - .cra_name = "rsa", - .cra_driver_name = "rsa-caam", - .cra_priority = 3000, - .cra_module = THIS_MODULE, - .cra_ctxsize = sizeof(struct caam_rsa_ctx), - }, +static struct caam_akcipher_alg caam_rsa = { + .akcipher = { + .encrypt = caam_rsa_enc, + .decrypt = caam_rsa_dec, + .set_pub_key = caam_rsa_set_pub_key, + .set_priv_key = caam_rsa_set_priv_key, + .max_size = caam_rsa_max_size, + .init = caam_rsa_init_tfm, + .exit = caam_rsa_exit_tfm, + .reqsize = sizeof(struct caam_rsa_req_ctx), + .base = { + .cra_name = "rsa", + .cra_driver_name = "rsa-caam", + .cra_priority = 3000, + .cra_module = THIS_MODULE, + .cra_ctxsize = sizeof(struct caam_rsa_ctx), + }, + } }; /* Public Key Cryptography module initialization handler */ @@ -1077,6 +1089,7 @@ int caam_pkc_init(struct device *ctrldev) struct caam_drv_private *priv = dev_get_drvdata(ctrldev); u32 pk_inst; int err; + init_done = false; /* Determine public key hardware accelerator presence. */ if (priv->era < 10) @@ -1095,12 +1108,15 @@ int caam_pkc_init(struct device *ctrldev) if (!zero_buffer) return -ENOMEM; - err = crypto_register_akcipher(&caam_rsa); + err = crypto_register_akcipher(&caam_rsa.akcipher); + if (err) { kfree(zero_buffer); dev_warn(ctrldev, "%s alg registration failed\n", - caam_rsa.base.cra_driver_name); + caam_rsa.akcipher.base.cra_driver_name); } else { + init_done = true; + caam_rsa.registered = true; dev_info(ctrldev, "caam pkc algorithms registered in /proc/crypto\n"); } @@ -1109,6 +1125,11 @@ int caam_pkc_init(struct device *ctrldev) void caam_pkc_exit(void) { + if (!init_done) + return; + + if (caam_rsa.registered) + crypto_unregister_akcipher(&caam_rsa.akcipher); + kfree(zero_buffer); - crypto_unregister_akcipher(&caam_rsa); } diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index 561bcb5351840a0422244753850d3ce2a3d4bc4c..e8baacaabe07fbd245ac76456eb9da9ffce84167 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -53,7 +53,7 @@ L1_CACHE_BYTES) /* length of descriptors */ -#define DESC_JOB_O_LEN (CAAM_CMD_SZ * 2 + CAAM_PTR_SZ * 2) +#define DESC_JOB_O_LEN (CAAM_CMD_SZ * 2 + CAAM_PTR_SZ_MAX * 2) #define DESC_RNG_LEN (3 * CAAM_CMD_SZ) /* Buffer, its dma address and lock */ @@ -80,6 +80,12 @@ struct caam_rng_ctx { static struct caam_rng_ctx *rng_ctx; +/* + * Variable used to avoid double free of resources in case + * algorithm registration was unsuccessful + */ +static bool init_done; + static inline void rng_unmap_buf(struct device *jrdev, struct buf_data *bd) { if (bd->addr) @@ -296,6 +302,9 @@ static struct hwrng caam_rng = { void caam_rng_exit(void) { + if (!init_done) + return; + caam_jr_free(rng_ctx->jrdev); hwrng_unregister(&caam_rng); kfree(rng_ctx); @@ -307,6 +316,7 @@ int caam_rng_init(struct device *ctrldev) u32 rng_inst; struct caam_drv_private *priv = dev_get_drvdata(ctrldev); int err; + init_done = false; /* Check for an instantiated RNG before registration */ if (priv->era < 10) @@ -333,7 +343,12 @@ int caam_rng_init(struct device *ctrldev) goto free_rng_ctx; dev_info(dev, "registering rng-caam\n"); - return hwrng_register(&caam_rng); + + err = hwrng_register(&caam_rng); + if (!err) { + init_done = true; + return err; + } free_rng_ctx: kfree(rng_ctx); diff --git a/drivers/crypto/caam/compat.h b/drivers/crypto/caam/compat.h index 8639b2df0371dc8b91e24a4740b290ded1478467..60e2a54c19f1121a6df809e1163b826c7a9ce06b 100644 --- a/drivers/crypto/caam/compat.h +++ b/drivers/crypto/caam/compat.h @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 4e43ca4d3656961496347014b3380fedada2123e..db22777d59b4685d4702be36589900044369c81f 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -25,16 +25,6 @@ EXPORT_SYMBOL(caam_dpaa2); #include "qi.h" #endif -/* - * i.MX targets tend to have clock control subsystems that can - * enable/disable clocking to our device. - */ -static inline struct clk *caam_drv_identify_clk(struct device *dev, - char *clk_name) -{ - return caam_imx ? devm_clk_get(dev, clk_name) : NULL; -} - /* * Descriptor to instantiate RNG State Handle 0 in normal mode and * load the JDKEK, TDKEK and TDSK registers @@ -107,7 +97,12 @@ static inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc, int i; - if (ctrlpriv->virt_en == 1) { + if (ctrlpriv->virt_en == 1 || + /* + * Apparently on i.MX8MQ it doesn't matter if virt_en == 1 + * and the following steps should be performed regardless + */ + of_machine_is_compatible("fsl,imx8mq")) { clrsetbits_32(&ctrl->deco_rsr, 0, DECORSR_JR0); while (!(rd_reg32(&ctrl->deco_rsr) & DECORSR_VALID) && @@ -342,13 +337,6 @@ static int caam_remove(struct platform_device *pdev) /* Unmap controller region */ iounmap(ctrl); - /* shut clocks off before finalizing shutdown */ - clk_disable_unprepare(ctrlpriv->caam_ipg); - if (ctrlpriv->caam_mem) - clk_disable_unprepare(ctrlpriv->caam_mem); - clk_disable_unprepare(ctrlpriv->caam_aclk); - if (ctrlpriv->caam_emi_slow) - clk_disable_unprepare(ctrlpriv->caam_emi_slow); return 0; } @@ -497,20 +485,99 @@ static const struct of_device_id caam_match[] = { }; MODULE_DEVICE_TABLE(of, caam_match); +struct caam_imx_data { + const struct clk_bulk_data *clks; + int num_clks; +}; + +static const struct clk_bulk_data caam_imx6_clks[] = { + { .id = "ipg" }, + { .id = "mem" }, + { .id = "aclk" }, + { .id = "emi_slow" }, +}; + +static const struct caam_imx_data caam_imx6_data = { + .clks = caam_imx6_clks, + .num_clks = ARRAY_SIZE(caam_imx6_clks), +}; + +static const struct clk_bulk_data caam_imx7_clks[] = { + { .id = "ipg" }, + { .id = "aclk" }, +}; + +static const struct caam_imx_data caam_imx7_data = { + .clks = caam_imx7_clks, + .num_clks = ARRAY_SIZE(caam_imx7_clks), +}; + +static const struct clk_bulk_data caam_imx6ul_clks[] = { + { .id = "ipg" }, + { .id = "mem" }, + { .id = "aclk" }, +}; + +static const struct caam_imx_data caam_imx6ul_data = { + .clks = caam_imx6ul_clks, + .num_clks = ARRAY_SIZE(caam_imx6ul_clks), +}; + +static const struct soc_device_attribute caam_imx_soc_table[] = { + { .soc_id = "i.MX6UL", .data = &caam_imx6ul_data }, + { .soc_id = "i.MX6*", .data = &caam_imx6_data }, + { .soc_id = "i.MX7*", .data = &caam_imx7_data }, + { .soc_id = "i.MX8MQ", .data = &caam_imx7_data }, + { .family = "Freescale i.MX" }, + { /* sentinel */ } +}; + +static void disable_clocks(void *data) +{ + struct caam_drv_private *ctrlpriv = data; + + clk_bulk_disable_unprepare(ctrlpriv->num_clks, ctrlpriv->clks); +} + +static int init_clocks(struct device *dev, const struct caam_imx_data *data) +{ + struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); + int ret; + + ctrlpriv->num_clks = data->num_clks; + ctrlpriv->clks = devm_kmemdup(dev, data->clks, + data->num_clks * sizeof(data->clks[0]), + GFP_KERNEL); + if (!ctrlpriv->clks) + return -ENOMEM; + + ret = devm_clk_bulk_get(dev, ctrlpriv->num_clks, ctrlpriv->clks); + if (ret) { + dev_err(dev, + "Failed to request all necessary clocks\n"); + return ret; + } + + ret = clk_bulk_prepare_enable(ctrlpriv->num_clks, ctrlpriv->clks); + if (ret) { + dev_err(dev, + "Failed to prepare/enable all necessary clocks\n"); + return ret; + } + + return devm_add_action_or_reset(dev, disable_clocks, ctrlpriv); +} + /* Probe routine for CAAM top (controller) level */ static int caam_probe(struct platform_device *pdev) { int ret, ring, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN; u64 caam_id; - static const struct soc_device_attribute imx_soc[] = { - {.family = "Freescale i.MX"}, - {}, - }; + const struct soc_device_attribute *imx_soc_match; struct device *dev; struct device_node *nprop, *np; struct caam_ctrl __iomem *ctrl; struct caam_drv_private *ctrlpriv; - struct clk *clk; #ifdef CONFIG_DEBUG_FS struct caam_perfmon *perfmon; #endif @@ -527,103 +594,68 @@ static int caam_probe(struct platform_device *pdev) dev_set_drvdata(dev, ctrlpriv); nprop = pdev->dev.of_node; - caam_imx = (bool)soc_device_match(imx_soc); + imx_soc_match = soc_device_match(caam_imx_soc_table); + caam_imx = (bool)imx_soc_match; - /* Enable clocking */ - clk = caam_drv_identify_clk(&pdev->dev, "ipg"); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - dev_err(&pdev->dev, - "can't identify CAAM ipg clk: %d\n", ret); - return ret; - } - ctrlpriv->caam_ipg = clk; - - if (!of_machine_is_compatible("fsl,imx7d") && - !of_machine_is_compatible("fsl,imx7s") && - !of_machine_is_compatible("fsl,imx7ulp")) { - clk = caam_drv_identify_clk(&pdev->dev, "mem"); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - dev_err(&pdev->dev, - "can't identify CAAM mem clk: %d\n", ret); - return ret; + if (imx_soc_match) { + if (!imx_soc_match->data) { + dev_err(dev, "No clock data provided for i.MX SoC"); + return -EINVAL; } - ctrlpriv->caam_mem = clk; - } - clk = caam_drv_identify_clk(&pdev->dev, "aclk"); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - dev_err(&pdev->dev, - "can't identify CAAM aclk clk: %d\n", ret); - return ret; - } - ctrlpriv->caam_aclk = clk; - - if (!of_machine_is_compatible("fsl,imx6ul") && - !of_machine_is_compatible("fsl,imx7d") && - !of_machine_is_compatible("fsl,imx7s") && - !of_machine_is_compatible("fsl,imx7ulp")) { - clk = caam_drv_identify_clk(&pdev->dev, "emi_slow"); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - dev_err(&pdev->dev, - "can't identify CAAM emi_slow clk: %d\n", ret); + ret = init_clocks(dev, imx_soc_match->data); + if (ret) return ret; - } - ctrlpriv->caam_emi_slow = clk; - } - - ret = clk_prepare_enable(ctrlpriv->caam_ipg); - if (ret < 0) { - dev_err(&pdev->dev, "can't enable CAAM ipg clock: %d\n", ret); - return ret; - } - - if (ctrlpriv->caam_mem) { - ret = clk_prepare_enable(ctrlpriv->caam_mem); - if (ret < 0) { - dev_err(&pdev->dev, "can't enable CAAM secure mem clock: %d\n", - ret); - goto disable_caam_ipg; - } } - ret = clk_prepare_enable(ctrlpriv->caam_aclk); - if (ret < 0) { - dev_err(&pdev->dev, "can't enable CAAM aclk clock: %d\n", ret); - goto disable_caam_mem; - } - - if (ctrlpriv->caam_emi_slow) { - ret = clk_prepare_enable(ctrlpriv->caam_emi_slow); - if (ret < 0) { - dev_err(&pdev->dev, "can't enable CAAM emi slow clock: %d\n", - ret); - goto disable_caam_aclk; - } - } /* Get configuration properties from device tree */ /* First, get register page */ ctrl = of_iomap(nprop, 0); - if (ctrl == NULL) { + if (!ctrl) { dev_err(dev, "caam: of_iomap() failed\n"); - ret = -ENOMEM; - goto disable_caam_emi_slow; + return -ENOMEM; } caam_little_end = !(bool)(rd_reg32(&ctrl->perfmon.status) & (CSTA_PLEND | CSTA_ALT_PLEND)); - - /* Finding the page size for using the CTPR_MS register */ comp_params = rd_reg32(&ctrl->perfmon.comp_parms_ms); - pg_size = (comp_params & CTPR_MS_PG_SZ_MASK) >> CTPR_MS_PG_SZ_SHIFT; + if (comp_params & CTPR_MS_PS && rd_reg32(&ctrl->mcr) & MCFGR_LONG_PTR) + caam_ptr_sz = sizeof(u64); + else + caam_ptr_sz = sizeof(u32); + caam_dpaa2 = !!(comp_params & CTPR_MS_DPAA2); + ctrlpriv->qi_present = !!(comp_params & CTPR_MS_QI_MASK); + +#ifdef CONFIG_CAAM_QI + /* If (DPAA 1.x) QI present, check whether dependencies are available */ + if (ctrlpriv->qi_present && !caam_dpaa2) { + ret = qman_is_probed(); + if (!ret) { + ret = -EPROBE_DEFER; + goto iounmap_ctrl; + } else if (ret < 0) { + dev_err(dev, "failing probe due to qman probe error\n"); + ret = -ENODEV; + goto iounmap_ctrl; + } + + ret = qman_portals_probed(); + if (!ret) { + ret = -EPROBE_DEFER; + goto iounmap_ctrl; + } else if (ret < 0) { + dev_err(dev, "failing probe due to qman portals probe error\n"); + ret = -ENODEV; + goto iounmap_ctrl; + } + } +#endif /* Allocating the BLOCK_OFFSET based on the supported page size on * the platform */ + pg_size = (comp_params & CTPR_MS_PG_SZ_MASK) >> CTPR_MS_PG_SZ_SHIFT; if (pg_size == 0) BLOCK_OFFSET = PG_SIZE_4K; else @@ -648,7 +680,6 @@ static int caam_probe(struct platform_device *pdev) * In case of SoCs with Management Complex, MC f/w performs * the configuration. */ - caam_dpaa2 = !!(comp_params & CTPR_MS_DPAA2); np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-mc"); ctrlpriv->mc_en = !!np; of_node_put(np); @@ -688,16 +719,7 @@ static int caam_probe(struct platform_device *pdev) JRSTART_JR1_START | JRSTART_JR2_START | JRSTART_JR3_START); - if (sizeof(dma_addr_t) == sizeof(u64)) { - if (caam_dpaa2) - ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(49)); - else if (of_device_is_compatible(nprop, "fsl,sec-v5.0")) - ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); - else - ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36)); - } else { - ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); - } + ret = dma_set_mask_and_coherent(dev, caam_get_dma_mask(dev)); if (ret) { dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret); goto iounmap_ctrl; @@ -719,7 +741,6 @@ static int caam_probe(struct platform_device *pdev) #endif /* Check to see if (DPAA 1.x) QI present. If so, enable */ - ctrlpriv->qi_present = !!(comp_params & CTPR_MS_QI_MASK); if (ctrlpriv->qi_present && !caam_dpaa2) { ctrlpriv->qi = (struct caam_queue_if __iomem __force *) ((__force uint8_t *)ctrl + @@ -908,16 +929,6 @@ static int caam_probe(struct platform_device *pdev) #endif iounmap_ctrl: iounmap(ctrl); -disable_caam_emi_slow: - if (ctrlpriv->caam_emi_slow) - clk_disable_unprepare(ctrlpriv->caam_emi_slow); -disable_caam_aclk: - clk_disable_unprepare(ctrlpriv->caam_aclk); -disable_caam_mem: - if (ctrlpriv->caam_mem) - clk_disable_unprepare(ctrlpriv->caam_mem); -disable_caam_ipg: - clk_disable_unprepare(ctrlpriv->caam_ipg); return ret; } diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h index 5988a26a2441a5841ebe35026bcf6e94a72c3b29..62ce6421bb3fe7ba5e6a213d60ae88d9df53b09e 100644 --- a/drivers/crypto/caam/desc_constr.h +++ b/drivers/crypto/caam/desc_constr.h @@ -14,9 +14,41 @@ #define IMMEDIATE (1 << 23) #define CAAM_CMD_SZ sizeof(u32) -#define CAAM_PTR_SZ sizeof(dma_addr_t) +#define CAAM_PTR_SZ caam_ptr_sz +#define CAAM_PTR_SZ_MAX sizeof(dma_addr_t) +#define CAAM_PTR_SZ_MIN sizeof(u32) #define CAAM_DESC_BYTES_MAX (CAAM_CMD_SZ * MAX_CAAM_DESCSIZE) -#define DESC_JOB_IO_LEN (CAAM_CMD_SZ * 5 + CAAM_PTR_SZ * 3) +#define __DESC_JOB_IO_LEN(n) (CAAM_CMD_SZ * 5 + (n) * 3) +#define DESC_JOB_IO_LEN __DESC_JOB_IO_LEN(CAAM_PTR_SZ) +#define DESC_JOB_IO_LEN_MAX __DESC_JOB_IO_LEN(CAAM_PTR_SZ_MAX) +#define DESC_JOB_IO_LEN_MIN __DESC_JOB_IO_LEN(CAAM_PTR_SZ_MIN) + +/* + * The CAAM QI hardware constructs a job descriptor which points + * to shared descriptor (as pointed by context_a of FQ to CAAM). + * When the job descriptor is executed by deco, the whole job + * descriptor together with shared descriptor gets loaded in + * deco buffer which is 64 words long (each 32-bit). + * + * The job descriptor constructed by QI hardware has layout: + * + * HEADER (1 word) + * Shdesc ptr (1 or 2 words) + * SEQ_OUT_PTR (1 word) + * Out ptr (1 or 2 words) + * Out length (1 word) + * SEQ_IN_PTR (1 word) + * In ptr (1 or 2 words) + * In length (1 word) + * + * The shdesc ptr is used to fetch shared descriptor contents + * into deco buffer. + * + * Apart from shdesc contents, the total number of words that + * get loaded in deco buffer are '8' or '11'. The remaining words + * in deco buffer can be used for storing shared descriptor. + */ +#define MAX_SDLEN ((CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN_MIN) / CAAM_CMD_SZ) #ifdef DEBUG #define PRINT_POS do { printk(KERN_DEBUG "%02d: %s\n", desc_len(desc),\ @@ -37,6 +69,7 @@ (LDOFF_ENABLE_AUTO_NFIFO << LDST_OFFSET_SHIFT)) extern bool caam_little_end; +extern size_t caam_ptr_sz; /* * HW fetches 4 S/G table entries at a time, irrespective of how many entries @@ -103,9 +136,15 @@ static inline void init_job_desc_pdb(u32 * const desc, u32 options, static inline void append_ptr(u32 * const desc, dma_addr_t ptr) { - dma_addr_t *offset = (dma_addr_t *)desc_end(desc); + if (caam_ptr_sz == sizeof(dma_addr_t)) { + dma_addr_t *offset = (dma_addr_t *)desc_end(desc); - *offset = cpu_to_caam_dma(ptr); + *offset = cpu_to_caam_dma(ptr); + } else { + u32 *offset = (u32 *)desc_end(desc); + + *offset = cpu_to_caam_dma(ptr); + } (*desc) = cpu_to_caam32(caam32_to_cpu(*desc) + CAAM_PTR_SZ / CAAM_CMD_SZ); @@ -457,8 +496,8 @@ do { \ * functions where it is used. * @keylen: length of the provided algorithm key, in bytes * @keylen_pad: padded length of the provided algorithm key, in bytes - * @key: address where algorithm key resides; virtual address if key_inline - * is true, dma (bus) address if key_inline is false. + * @key_dma: dma (bus) address where algorithm key resides + * @key_virt: virtual address where algorithm key resides * @key_inline: true - key can be inlined in the descriptor; false - key is * referenced by the descriptor */ @@ -466,10 +505,8 @@ struct alginfo { u32 algtype; unsigned int keylen; unsigned int keylen_pad; - union { - dma_addr_t key_dma; - const void *key_virt; - }; + dma_addr_t key_dma; + const void *key_virt; bool key_inline; }; @@ -535,14 +572,26 @@ static inline void append_proto_dkp(u32 * const desc, struct alginfo *adata) if (adata->key_inline) { int words; - append_operation(desc, OP_TYPE_UNI_PROTOCOL | protid | - OP_PCL_DKP_SRC_IMM | OP_PCL_DKP_DST_IMM | - adata->keylen); - append_data(desc, adata->key_virt, adata->keylen); + if (adata->keylen > adata->keylen_pad) { + append_operation(desc, OP_TYPE_UNI_PROTOCOL | protid | + OP_PCL_DKP_SRC_PTR | + OP_PCL_DKP_DST_IMM | adata->keylen); + append_ptr(desc, adata->key_dma); + + words = (ALIGN(adata->keylen_pad, CAAM_CMD_SZ) - + CAAM_PTR_SZ) / CAAM_CMD_SZ; + } else { + append_operation(desc, OP_TYPE_UNI_PROTOCOL | protid | + OP_PCL_DKP_SRC_IMM | + OP_PCL_DKP_DST_IMM | adata->keylen); + append_data(desc, adata->key_virt, adata->keylen); + + words = (ALIGN(adata->keylen_pad, CAAM_CMD_SZ) - + ALIGN(adata->keylen, CAAM_CMD_SZ)) / + CAAM_CMD_SZ; + } /* Reserve space in descriptor buffer for the derived key */ - words = (ALIGN(adata->keylen_pad, CAAM_CMD_SZ) - - ALIGN(adata->keylen, CAAM_CMD_SZ)) / CAAM_CMD_SZ; if (words) (*desc) = cpu_to_caam32(caam32_to_cpu(*desc) + words); } else { diff --git a/drivers/crypto/caam/dpseci-debugfs.c b/drivers/crypto/caam/dpseci-debugfs.c new file mode 100644 index 0000000000000000000000000000000000000000..c5bfc923abd811f5b1d6e49c198e891e07b83051 --- /dev/null +++ b/drivers/crypto/caam/dpseci-debugfs.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* Copyright 2019 NXP */ + +#include +#include +#include +#include "dpseci-debugfs.h" + +static int dpseci_dbg_fqs_show(struct seq_file *file, void *offset) +{ + struct dpaa2_caam_priv *priv = (struct dpaa2_caam_priv *)file->private; + u32 fqid, fcnt, bcnt; + int i, err; + + seq_printf(file, "FQ stats for %s:\n", dev_name(priv->dev)); + seq_printf(file, "%s%16s%16s\n", + "Rx-VFQID", + "Pending frames", + "Pending bytes"); + + for (i = 0; i < priv->num_pairs; i++) { + fqid = priv->rx_queue_attr[i].fqid; + err = dpaa2_io_query_fq_count(NULL, fqid, &fcnt, &bcnt); + if (err) + continue; + + seq_printf(file, "%5d%16u%16u\n", fqid, fcnt, bcnt); + } + + seq_printf(file, "%s%16s%16s\n", + "Tx-VFQID", + "Pending frames", + "Pending bytes"); + + for (i = 0; i < priv->num_pairs; i++) { + fqid = priv->tx_queue_attr[i].fqid; + err = dpaa2_io_query_fq_count(NULL, fqid, &fcnt, &bcnt); + if (err) + continue; + + seq_printf(file, "%5d%16u%16u\n", fqid, fcnt, bcnt); + } + + return 0; +} + +static int dpseci_dbg_fqs_open(struct inode *inode, struct file *file) +{ + int err; + struct dpaa2_caam_priv *priv; + + priv = (struct dpaa2_caam_priv *)inode->i_private; + + err = single_open(file, dpseci_dbg_fqs_show, priv); + if (err < 0) + dev_err(priv->dev, "single_open() failed\n"); + + return err; +} + +static const struct file_operations dpseci_dbg_fq_ops = { + .open = dpseci_dbg_fqs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void dpaa2_dpseci_debugfs_init(struct dpaa2_caam_priv *priv) +{ + priv->dfs_root = debugfs_create_dir(dev_name(priv->dev), NULL); + + debugfs_create_file("fq_stats", 0444, priv->dfs_root, priv, + &dpseci_dbg_fq_ops); +} + +void dpaa2_dpseci_debugfs_exit(struct dpaa2_caam_priv *priv) +{ + debugfs_remove_recursive(priv->dfs_root); +} diff --git a/drivers/crypto/caam/dpseci-debugfs.h b/drivers/crypto/caam/dpseci-debugfs.h new file mode 100644 index 0000000000000000000000000000000000000000..bc22af7bec377944ec768a1b5a8f468d8ba1dd14 --- /dev/null +++ b/drivers/crypto/caam/dpseci-debugfs.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* Copyright 2019 NXP */ + +#ifndef DPSECI_DEBUGFS_H +#define DPSECI_DEBUGFS_H + +#include +#include "caamalg_qi2.h" + +#ifdef CONFIG_DEBUG_FS +void dpaa2_dpseci_debugfs_init(struct dpaa2_caam_priv *priv); +void dpaa2_dpseci_debugfs_exit(struct dpaa2_caam_priv *priv); +#else +static inline void dpaa2_dpseci_debugfs_init(struct dpaa2_caam_priv *priv) {} +static inline void dpaa2_dpseci_debugfs_exit(struct dpaa2_caam_priv *priv) {} +#endif /* CONFIG_DEBUG_FS */ + +#endif /* DPSECI_DEBUGFS_H */ diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c index 4f0d45865aa2d2cbcd91db042f8857655bf13082..17c6108b6d412eea0f2f2be7ff1f3ba77cab4dfd 100644 --- a/drivers/crypto/caam/error.c +++ b/drivers/crypto/caam/error.c @@ -56,6 +56,9 @@ EXPORT_SYMBOL(caam_little_end); bool caam_imx; EXPORT_SYMBOL(caam_imx); +size_t caam_ptr_sz; +EXPORT_SYMBOL(caam_ptr_sz); + static const struct { u8 value; const char *error_text; @@ -118,6 +121,7 @@ static const struct { u8 value; const char *error_text; } qi_error_list[] = { + { 0x00, "No error" }, { 0x1F, "Job terminated by FQ or ICID flush" }, { 0x20, "FD format error"}, { 0x21, "FD command format error"}, @@ -210,8 +214,8 @@ static const char * const rng_err_id_list[] = { "Secure key generation", }; -static void report_ccb_status(struct device *jrdev, const u32 status, - const char *error) +static int report_ccb_status(struct device *jrdev, const u32 status, + const char *error) { u8 cha_id = (status & JRSTA_CCBERR_CHAID_MASK) >> JRSTA_CCBERR_CHAID_SHIFT; @@ -247,22 +251,27 @@ static void report_ccb_status(struct device *jrdev, const u32 status, * CCB ICV check failures are part of normal operation life; * we leave the upper layers to do what they want with them. */ - if (err_id != JRSTA_CCBERR_ERRID_ICVCHK) - dev_err(jrdev, "%08x: %s: %s %d: %s%s: %s%s\n", - status, error, idx_str, idx, - cha_str, cha_err_code, - err_str, err_err_code); + if (err_id == JRSTA_CCBERR_ERRID_ICVCHK) + return -EBADMSG; + + dev_err_ratelimited(jrdev, "%08x: %s: %s %d: %s%s: %s%s\n", status, + error, idx_str, idx, cha_str, cha_err_code, + err_str, err_err_code); + + return -EINVAL; } -static void report_jump_status(struct device *jrdev, const u32 status, - const char *error) +static int report_jump_status(struct device *jrdev, const u32 status, + const char *error) { dev_err(jrdev, "%08x: %s: %s() not implemented\n", status, error, __func__); + + return -EINVAL; } -static void report_deco_status(struct device *jrdev, const u32 status, - const char *error) +static int report_deco_status(struct device *jrdev, const u32 status, + const char *error) { u8 err_id = status & JRSTA_DECOERR_ERROR_MASK; u8 idx = (status & JRSTA_DECOERR_INDEX_MASK) >> @@ -288,10 +297,12 @@ static void report_deco_status(struct device *jrdev, const u32 status, dev_err(jrdev, "%08x: %s: %s %d: %s%s\n", status, error, idx_str, idx, err_str, err_err_code); + + return -EINVAL; } -static void report_qi_status(struct device *qidev, const u32 status, - const char *error) +static int report_qi_status(struct device *qidev, const u32 status, + const char *error) { u8 err_id = status & JRSTA_QIERR_ERROR_MASK; const char *err_str = "unidentified error value 0x"; @@ -309,27 +320,33 @@ static void report_qi_status(struct device *qidev, const u32 status, dev_err(qidev, "%08x: %s: %s%s\n", status, error, err_str, err_err_code); + + return -EINVAL; } -static void report_jr_status(struct device *jrdev, const u32 status, - const char *error) +static int report_jr_status(struct device *jrdev, const u32 status, + const char *error) { dev_err(jrdev, "%08x: %s: %s() not implemented\n", status, error, __func__); + + return -EINVAL; } -static void report_cond_code_status(struct device *jrdev, const u32 status, - const char *error) +static int report_cond_code_status(struct device *jrdev, const u32 status, + const char *error) { dev_err(jrdev, "%08x: %s: %s() not implemented\n", status, error, __func__); + + return -EINVAL; } -void caam_strstatus(struct device *jrdev, u32 status, bool qi_v2) +int caam_strstatus(struct device *jrdev, u32 status, bool qi_v2) { static const struct stat_src { - void (*report_ssed)(struct device *jrdev, const u32 status, - const char *error); + int (*report_ssed)(struct device *jrdev, const u32 status, + const char *error); const char *error; } status_src[16] = { { NULL, "No error" }, @@ -357,11 +374,14 @@ void caam_strstatus(struct device *jrdev, u32 status, bool qi_v2) * Otherwise print the error source name. */ if (status_src[ssrc].report_ssed) - status_src[ssrc].report_ssed(jrdev, status, error); - else if (error) + return status_src[ssrc].report_ssed(jrdev, status, error); + + if (error) dev_err(jrdev, "%d: %s\n", ssrc, error); else dev_err(jrdev, "%d: unknown error source\n", ssrc); + + return -EINVAL; } EXPORT_SYMBOL(caam_strstatus); diff --git a/drivers/crypto/caam/error.h b/drivers/crypto/caam/error.h index d9726e66edbf97a1339b2ee507731205c94dae17..16809fa8fec7c25423678b34d623b5019b6aa63a 100644 --- a/drivers/crypto/caam/error.h +++ b/drivers/crypto/caam/error.h @@ -12,7 +12,7 @@ #define CAAM_ERROR_STR_MAX 302 -void caam_strstatus(struct device *dev, u32 status, bool qi_v2); +int caam_strstatus(struct device *dev, u32 status, bool qi_v2); #define caam_jr_strstatus(jrdev, status) caam_strstatus(jrdev, status, false) #define caam_qi2_strstatus(qidev, status) caam_strstatus(qidev, status, true) diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h index 6af84bbc612c7c36629c30ac758271b149e0e9d1..731b06becd9c912b9ce783a94cd63857957053dd 100644 --- a/drivers/crypto/caam/intern.h +++ b/drivers/crypto/caam/intern.h @@ -10,6 +10,8 @@ #ifndef INTERN_H #define INTERN_H +#include "ctrl.h" + /* Currently comes from Kconfig param as a ^2 (driver-required) */ #define JOBR_DEPTH (1 << CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE) @@ -53,10 +55,11 @@ struct caam_drv_private_jr { spinlock_t inplock ____cacheline_aligned; /* Input ring index lock */ u32 inpring_avail; /* Number of free entries in input ring */ int head; /* entinfo (s/w ring) head index */ - dma_addr_t *inpring; /* Base of input ring, alloc DMA-safe */ + void *inpring; /* Base of input ring, alloc + * DMA-safe */ int out_ring_read_index; /* Output index "tail" */ int tail; /* entinfo (s/w ring) tail index */ - struct jr_outentry *outring; /* Base of output ring, DMA-safe */ + void *outring; /* Base of output ring, DMA-safe */ }; /* @@ -92,11 +95,8 @@ struct caam_drv_private { Handles of the RNG4 block are initialized by this driver */ - struct clk *caam_ipg; - struct clk *caam_mem; - struct clk *caam_aclk; - struct clk *caam_emi_slow; - + struct clk_bulk_data *clks; + int num_clks; /* * debugfs entries for developer view into driver/device * variables at runtime. @@ -215,4 +215,22 @@ DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u32_ro, caam_debugfs_u32_get, NULL, "%llu\n"); DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u64_ro, caam_debugfs_u64_get, NULL, "%llu\n"); #endif +static inline u64 caam_get_dma_mask(struct device *dev) +{ + struct device_node *nprop = dev->of_node; + + if (caam_ptr_sz != sizeof(u64)) + return DMA_BIT_MASK(32); + + if (caam_dpaa2) + return DMA_BIT_MASK(49); + + if (of_device_is_compatible(nprop, "fsl,sec-v5.0-job-ring") || + of_device_is_compatible(nprop, "fsl,sec-v5.0")) + return DMA_BIT_MASK(40); + + return DMA_BIT_MASK(36); +} + + #endif /* INTERN_H */ diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index cea811fed320b7a2efa95484c2a38f40ef2e2fb1..fc97cde2705950683200471b80bb34121747cd38 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -108,25 +108,12 @@ static int caam_reset_hw_jr(struct device *dev) static int caam_jr_shutdown(struct device *dev) { struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); - dma_addr_t inpbusaddr, outbusaddr; int ret; ret = caam_reset_hw_jr(dev); tasklet_kill(&jrp->irqtask); - /* Release interrupt */ - free_irq(jrp->irq, dev); - - /* Free rings */ - inpbusaddr = rd_reg64(&jrp->rregs->inpring_base); - outbusaddr = rd_reg64(&jrp->rregs->outring_base); - dma_free_coherent(dev, sizeof(dma_addr_t) * JOBR_DEPTH, - jrp->inpring, inpbusaddr); - dma_free_coherent(dev, sizeof(struct jr_outentry) * JOBR_DEPTH, - jrp->outring, outbusaddr); - kfree(jrp->entinfo); - return ret; } @@ -159,7 +146,6 @@ static int caam_jr_remove(struct platform_device *pdev) ret = caam_jr_shutdown(jrdev); if (ret) dev_err(jrdev, "Failed to shut down job ring\n"); - irq_dispose_mapping(jrpriv->irq); return ret; } @@ -224,7 +210,7 @@ static void caam_jr_dequeue(unsigned long devarg) for (i = 0; CIRC_CNT(head, tail + i, JOBR_DEPTH) >= 1; i++) { sw_idx = (tail + i) & (JOBR_DEPTH - 1); - if (jrp->outring[hw_idx].desc == + if (jr_outentry_desc(jrp->outring, hw_idx) == caam_dma_to_cpu(jrp->entinfo[sw_idx].desc_addr_dma)) break; /* found */ } @@ -233,7 +219,8 @@ static void caam_jr_dequeue(unsigned long devarg) /* Unmap just-run descriptor so we can post-process */ dma_unmap_single(dev, - caam_dma_to_cpu(jrp->outring[hw_idx].desc), + caam_dma_to_cpu(jr_outentry_desc(jrp->outring, + hw_idx)), jrp->entinfo[sw_idx].desc_size, DMA_TO_DEVICE); @@ -244,7 +231,8 @@ static void caam_jr_dequeue(unsigned long devarg) usercall = jrp->entinfo[sw_idx].callbk; userarg = jrp->entinfo[sw_idx].cbkarg; userdesc = jrp->entinfo[sw_idx].desc_addr_virt; - userstatus = caam32_to_cpu(jrp->outring[hw_idx].jrstatus); + userstatus = caam32_to_cpu(jr_outentry_jrstatus(jrp->outring, + hw_idx)); /* * Make sure all information from the job has been obtained @@ -399,7 +387,7 @@ int caam_jr_enqueue(struct device *dev, u32 *desc, head_entry->cbkarg = areq; head_entry->desc_addr_dma = desc_dma; - jrp->inpring[head] = cpu_to_caam_dma(desc_dma); + jr_inpentry_set(jrp->inpring, head, cpu_to_caam_dma(desc_dma)); /* * Guarantee that the descriptor's DMA address has been written to @@ -441,35 +429,26 @@ static int caam_jr_init(struct device *dev) jrp = dev_get_drvdata(dev); - tasklet_init(&jrp->irqtask, caam_jr_dequeue, (unsigned long)dev); - - /* Connect job ring interrupt handler. */ - error = request_irq(jrp->irq, caam_jr_interrupt, IRQF_SHARED, - dev_name(dev), dev); - if (error) { - dev_err(dev, "can't connect JobR %d interrupt (%d)\n", - jrp->ridx, jrp->irq); - goto out_kill_deq; - } - error = caam_reset_hw_jr(dev); if (error) - goto out_free_irq; + return error; - error = -ENOMEM; - jrp->inpring = dma_alloc_coherent(dev, sizeof(*jrp->inpring) * - JOBR_DEPTH, &inpbusaddr, GFP_KERNEL); + jrp->inpring = dmam_alloc_coherent(dev, SIZEOF_JR_INPENTRY * + JOBR_DEPTH, &inpbusaddr, + GFP_KERNEL); if (!jrp->inpring) - goto out_free_irq; + return -ENOMEM; - jrp->outring = dma_alloc_coherent(dev, sizeof(*jrp->outring) * - JOBR_DEPTH, &outbusaddr, GFP_KERNEL); + jrp->outring = dmam_alloc_coherent(dev, SIZEOF_JR_OUTENTRY * + JOBR_DEPTH, &outbusaddr, + GFP_KERNEL); if (!jrp->outring) - goto out_free_inpring; + return -ENOMEM; - jrp->entinfo = kcalloc(JOBR_DEPTH, sizeof(*jrp->entinfo), GFP_KERNEL); + jrp->entinfo = devm_kcalloc(dev, JOBR_DEPTH, sizeof(*jrp->entinfo), + GFP_KERNEL); if (!jrp->entinfo) - goto out_free_outring; + return -ENOMEM; for (i = 0; i < JOBR_DEPTH; i++) jrp->entinfo[i].desc_addr_dma = !0; @@ -493,22 +472,24 @@ static int caam_jr_init(struct device *dev) (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) | (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT)); - return 0; + tasklet_init(&jrp->irqtask, caam_jr_dequeue, (unsigned long)dev); + + /* Connect job ring interrupt handler. */ + error = devm_request_irq(dev, jrp->irq, caam_jr_interrupt, IRQF_SHARED, + dev_name(dev), dev); + if (error) { + dev_err(dev, "can't connect JobR %d interrupt (%d)\n", + jrp->ridx, jrp->irq); + tasklet_kill(&jrp->irqtask); + } -out_free_outring: - dma_free_coherent(dev, sizeof(struct jr_outentry) * JOBR_DEPTH, - jrp->outring, outbusaddr); -out_free_inpring: - dma_free_coherent(dev, sizeof(dma_addr_t) * JOBR_DEPTH, - jrp->inpring, inpbusaddr); - dev_err(dev, "can't allocate job rings for %d\n", jrp->ridx); -out_free_irq: - free_irq(jrp->irq, dev); -out_kill_deq: - tasklet_kill(&jrp->irqtask); return error; } +static void caam_jr_irq_dispose_mapping(void *data) +{ + irq_dispose_mapping((unsigned long)data); +} /* * Probe routine for each detected JobR subsystem. @@ -520,6 +501,7 @@ static int caam_jr_probe(struct platform_device *pdev) struct caam_job_ring __iomem *ctrl; struct caam_drv_private_jr *jrpriv; static int total_jobrs; + struct resource *r; int error; jrdev = &pdev->dev; @@ -535,45 +517,43 @@ static int caam_jr_probe(struct platform_device *pdev) nprop = pdev->dev.of_node; /* Get configuration properties from device tree */ /* First, get register page */ - ctrl = of_iomap(nprop, 0); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(jrdev, "platform_get_resource() failed\n"); + return -ENOMEM; + } + + ctrl = devm_ioremap(jrdev, r->start, resource_size(r)); if (!ctrl) { - dev_err(jrdev, "of_iomap() failed\n"); + dev_err(jrdev, "devm_ioremap() failed\n"); return -ENOMEM; } jrpriv->rregs = (struct caam_job_ring __iomem __force *)ctrl; - if (sizeof(dma_addr_t) == sizeof(u64)) { - if (caam_dpaa2) - error = dma_set_mask_and_coherent(jrdev, - DMA_BIT_MASK(49)); - else if (of_device_is_compatible(nprop, - "fsl,sec-v5.0-job-ring")) - error = dma_set_mask_and_coherent(jrdev, - DMA_BIT_MASK(40)); - else - error = dma_set_mask_and_coherent(jrdev, - DMA_BIT_MASK(36)); - } else { - error = dma_set_mask_and_coherent(jrdev, DMA_BIT_MASK(32)); - } + error = dma_set_mask_and_coherent(jrdev, caam_get_dma_mask(jrdev)); if (error) { dev_err(jrdev, "dma_set_mask_and_coherent failed (%d)\n", error); - iounmap(ctrl); return error; } /* Identify the interrupt */ jrpriv->irq = irq_of_parse_and_map(nprop, 0); + if (!jrpriv->irq) { + dev_err(jrdev, "irq_of_parse_and_map failed\n"); + return -EINVAL; + } + + error = devm_add_action_or_reset(jrdev, caam_jr_irq_dispose_mapping, + (void *)(unsigned long)jrpriv->irq); + if (error) + return error; /* Now do the platform independent part */ error = caam_jr_init(jrdev); /* now turn on hardware */ - if (error) { - irq_dispose_mapping(jrpriv->irq); - iounmap(ctrl); + if (error) return error; - } jrpriv->dev = jrdev; spin_lock(&driver_data.jr_alloc_lock); diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c index 48dd3536060d4cf831c7ff55b95f37a70debc15a..5a851ddc48fbed2cd706956eb5a90fe2f2803b2c 100644 --- a/drivers/crypto/caam/key_gen.c +++ b/drivers/crypto/caam/key_gen.c @@ -15,13 +15,14 @@ void split_key_done(struct device *dev, u32 *desc, u32 err, void *context) { struct split_key_result *res = context; + int ecode = 0; dev_dbg(dev, "%s %d: err 0x%x\n", __func__, __LINE__, err); if (err) - caam_jr_strstatus(dev, err); + ecode = caam_jr_strstatus(dev, err); - res->err = err; + res->err = ecode; complete(&res->completion); } @@ -47,18 +48,20 @@ int gen_split_key(struct device *jrdev, u8 *key_out, u32 *desc; struct split_key_result result; dma_addr_t dma_addr; + unsigned int local_max; int ret = -ENOMEM; adata->keylen = split_key_len(adata->algtype & OP_ALG_ALGSEL_MASK); adata->keylen_pad = split_key_pad_len(adata->algtype & OP_ALG_ALGSEL_MASK); + local_max = max(keylen, adata->keylen_pad); dev_dbg(jrdev, "split keylen %d split keylen padded %d\n", adata->keylen, adata->keylen_pad); print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key_in, keylen, 1); - if (adata->keylen_pad > max_keylen) + if (local_max > max_keylen) return -EINVAL; desc = kmalloc(CAAM_CMD_SZ * 6 + CAAM_PTR_SZ * 2, GFP_KERNEL | GFP_DMA); @@ -69,8 +72,7 @@ int gen_split_key(struct device *jrdev, u8 *key_out, memcpy(key_out, key_in, keylen); - dma_addr = dma_map_single(jrdev, key_out, adata->keylen_pad, - DMA_BIDIRECTIONAL); + dma_addr = dma_map_single(jrdev, key_out, local_max, DMA_BIDIRECTIONAL); if (dma_mapping_error(jrdev, dma_addr)) { dev_err(jrdev, "unable to map key memory\n"); goto out_free; @@ -116,7 +118,7 @@ int gen_split_key(struct device *jrdev, u8 *key_out, adata->keylen_pad, 1); } - dma_unmap_single(jrdev, dma_addr, adata->keylen_pad, DMA_BIDIRECTIONAL); + dma_unmap_single(jrdev, dma_addr, local_max, DMA_BIDIRECTIONAL); out_free: kfree(desc); return ret; diff --git a/drivers/crypto/caam/pdb.h b/drivers/crypto/caam/pdb.h index 810f0bef0652b38c299d2c5888c1e90265090a73..68c1fd5dee5df0d49db8f949c7f30fe56150ede4 100644 --- a/drivers/crypto/caam/pdb.h +++ b/drivers/crypto/caam/pdb.h @@ -512,7 +512,9 @@ struct rsa_pub_pdb { dma_addr_t n_dma; dma_addr_t e_dma; u32 f_len; -} __packed; +}; + +#define SIZEOF_RSA_PUB_PDB (2 * sizeof(u32) + 4 * caam_ptr_sz) /** * RSA Decrypt PDB - Private Key Form #1 @@ -528,7 +530,9 @@ struct rsa_priv_f1_pdb { dma_addr_t f_dma; dma_addr_t n_dma; dma_addr_t d_dma; -} __packed; +}; + +#define SIZEOF_RSA_PRIV_F1_PDB (sizeof(u32) + 4 * caam_ptr_sz) /** * RSA Decrypt PDB - Private Key Form #2 @@ -554,7 +558,9 @@ struct rsa_priv_f2_pdb { dma_addr_t tmp1_dma; dma_addr_t tmp2_dma; u32 p_q_len; -} __packed; +}; + +#define SIZEOF_RSA_PRIV_F2_PDB (2 * sizeof(u32) + 7 * caam_ptr_sz) /** * RSA Decrypt PDB - Private Key Form #3 @@ -586,6 +592,8 @@ struct rsa_priv_f3_pdb { dma_addr_t tmp1_dma; dma_addr_t tmp2_dma; u32 p_q_len; -} __packed; +}; + +#define SIZEOF_RSA_PRIV_F3_PDB (2 * sizeof(u32) + 9 * caam_ptr_sz) #endif diff --git a/drivers/crypto/caam/pkc_desc.c b/drivers/crypto/caam/pkc_desc.c index 2a8d87ea94bf46d24f813790110a33d61342bbaf..0d5ee762e036ab589627e5af9accc2b59906b678 100644 --- a/drivers/crypto/caam/pkc_desc.c +++ b/drivers/crypto/caam/pkc_desc.c @@ -13,7 +13,7 @@ /* Descriptor for RSA Public operation */ void init_rsa_pub_desc(u32 *desc, struct rsa_pub_pdb *pdb) { - init_job_desc_pdb(desc, 0, sizeof(*pdb)); + init_job_desc_pdb(desc, 0, SIZEOF_RSA_PUB_PDB); append_cmd(desc, pdb->sgf); append_ptr(desc, pdb->f_dma); append_ptr(desc, pdb->g_dma); @@ -26,7 +26,7 @@ void init_rsa_pub_desc(u32 *desc, struct rsa_pub_pdb *pdb) /* Descriptor for RSA Private operation - Private Key Form #1 */ void init_rsa_priv_f1_desc(u32 *desc, struct rsa_priv_f1_pdb *pdb) { - init_job_desc_pdb(desc, 0, sizeof(*pdb)); + init_job_desc_pdb(desc, 0, SIZEOF_RSA_PRIV_F1_PDB); append_cmd(desc, pdb->sgf); append_ptr(desc, pdb->g_dma); append_ptr(desc, pdb->f_dma); @@ -39,7 +39,7 @@ void init_rsa_priv_f1_desc(u32 *desc, struct rsa_priv_f1_pdb *pdb) /* Descriptor for RSA Private operation - Private Key Form #2 */ void init_rsa_priv_f2_desc(u32 *desc, struct rsa_priv_f2_pdb *pdb) { - init_job_desc_pdb(desc, 0, sizeof(*pdb)); + init_job_desc_pdb(desc, 0, SIZEOF_RSA_PRIV_F2_PDB); append_cmd(desc, pdb->sgf); append_ptr(desc, pdb->g_dma); append_ptr(desc, pdb->f_dma); @@ -56,7 +56,7 @@ void init_rsa_priv_f2_desc(u32 *desc, struct rsa_priv_f2_pdb *pdb) /* Descriptor for RSA Private operation - Private Key Form #3 */ void init_rsa_priv_f3_desc(u32 *desc, struct rsa_priv_f3_pdb *pdb) { - init_job_desc_pdb(desc, 0, sizeof(*pdb)); + init_job_desc_pdb(desc, 0, SIZEOF_RSA_PRIV_F3_PDB); append_cmd(desc, pdb->sgf); append_ptr(desc, pdb->g_dma); append_ptr(desc, pdb->f_dma); diff --git a/drivers/crypto/caam/qi.c b/drivers/crypto/caam/qi.c index 0fe618e3804a91c176d97c90165ae50beb80c98f..378f627e1d64f624694221e2fbbe197a49f80209 100644 --- a/drivers/crypto/caam/qi.c +++ b/drivers/crypto/caam/qi.c @@ -163,7 +163,10 @@ static void caam_fq_ern_cb(struct qman_portal *qm, struct qman_fq *fq, dma_unmap_single(drv_req->drv_ctx->qidev, qm_fd_addr(fd), sizeof(drv_req->fd_sgt), DMA_BIDIRECTIONAL); - drv_req->cbk(drv_req, -EIO); + if (fd->status) + drv_req->cbk(drv_req, be32_to_cpu(fd->status)); + else + drv_req->cbk(drv_req, JRSTA_SSRC_QI); } static struct qman_fq *create_caam_req_fq(struct device *qidev, @@ -574,8 +577,9 @@ static enum qman_cb_dqrr_result caam_rsp_fq_dqrr_cb(struct qman_portal *p, if (ssrc != JRSTA_SSRC_CCB_ERROR || err_id != JRSTA_CCBERR_ERRID_ICVCHK) - dev_err(qidev, "Error: %#x in CAAM response FD\n", - status); + dev_err_ratelimited(qidev, + "Error: %#x in CAAM response FD\n", + status); } if (unlikely(qm_fd_get_format(fd) != qm_fd_compound)) { diff --git a/drivers/crypto/caam/qi.h b/drivers/crypto/caam/qi.h index f93c9c7ed430c976bf7269f58fe8c3721db7d26f..db0549549e3bd6966ec9a1a92a719e5ce94357de 100644 --- a/drivers/crypto/caam/qi.h +++ b/drivers/crypto/caam/qi.h @@ -14,32 +14,6 @@ #include "desc.h" #include "desc_constr.h" -/* - * CAAM hardware constructs a job descriptor which points to a shared descriptor - * (as pointed by context_a of to-CAAM FQ). - * When the job descriptor is executed by DECO, the whole job descriptor - * together with shared descriptor gets loaded in DECO buffer, which is - * 64 words (each 32-bit) long. - * - * The job descriptor constructed by CAAM hardware has the following layout: - * - * HEADER (1 word) - * Shdesc ptr (1 or 2 words) - * SEQ_OUT_PTR (1 word) - * Out ptr (1 or 2 words) - * Out length (1 word) - * SEQ_IN_PTR (1 word) - * In ptr (1 or 2 words) - * In length (1 word) - * - * The shdesc ptr is used to fetch shared descriptor contents into DECO buffer. - * - * Apart from shdesc contents, the total number of words that get loaded in DECO - * buffer are '8' or '11'. The remaining words in DECO buffer can be used for - * storing shared descriptor. - */ -#define MAX_SDLEN ((CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN) / CAAM_CMD_SZ) - /* Length of a single buffer in the QI driver memory cache */ #define CAAM_QI_MEMCACHE_SIZE 768 diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h index 8591914d5c51b73de69f9832c4bf272eeaff4efc..05127b70527d7f372e5de0d37c6cba6cfb3b8fe5 100644 --- a/drivers/crypto/caam/regs.h +++ b/drivers/crypto/caam/regs.h @@ -12,6 +12,7 @@ #include #include #include +#include /* * Architecture-specific register access methods @@ -70,6 +71,7 @@ extern bool caam_little_end; extern bool caam_imx; +extern size_t caam_ptr_sz; #define caam_to_cpu(len) \ static inline u##len caam##len ## _to_cpu(u##len val) \ @@ -137,46 +139,38 @@ static inline void clrsetbits_32(void __iomem *reg, u32 clear, u32 set) * base + 0x0000 : least-significant 32 bits * base + 0x0004 : most-significant 32 bits */ -#ifdef CONFIG_64BIT static inline void wr_reg64(void __iomem *reg, u64 data) { - if (caam_little_end) - iowrite64(data, reg); - else + if (caam_little_end) { + if (caam_imx) { + iowrite32(data >> 32, (u32 __iomem *)(reg)); + iowrite32(data, (u32 __iomem *)(reg) + 1); + } else { + iowrite64(data, reg); + } + } else { iowrite64be(data, reg); + } } static inline u64 rd_reg64(void __iomem *reg) { - if (caam_little_end) - return ioread64(reg); - else - return ioread64be(reg); -} + if (caam_little_end) { + if (caam_imx) { + u32 low, high; -#else /* CONFIG_64BIT */ -static inline void wr_reg64(void __iomem *reg, u64 data) -{ - if (!caam_imx && caam_little_end) { - wr_reg32((u32 __iomem *)(reg) + 1, data >> 32); - wr_reg32((u32 __iomem *)(reg), data); + high = ioread32(reg); + low = ioread32(reg + sizeof(u32)); + + return low + ((u64)high << 32); + } else { + return ioread64(reg); + } } else { - wr_reg32((u32 __iomem *)(reg), data >> 32); - wr_reg32((u32 __iomem *)(reg) + 1, data); + return ioread64be(reg); } } -static inline u64 rd_reg64(void __iomem *reg) -{ - if (!caam_imx && caam_little_end) - return ((u64)rd_reg32((u32 __iomem *)(reg) + 1) << 32 | - (u64)rd_reg32((u32 __iomem *)(reg))); - - return ((u64)rd_reg32((u32 __iomem *)(reg)) << 32 | - (u64)rd_reg32((u32 __iomem *)(reg) + 1)); -} -#endif /* CONFIG_64BIT */ - static inline u64 cpu_to_caam_dma64(dma_addr_t value) { if (caam_imx) @@ -195,22 +189,89 @@ static inline u64 caam_dma64_to_cpu(u64 value) return caam64_to_cpu(value); } -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -#define cpu_to_caam_dma(value) cpu_to_caam_dma64(value) -#define caam_dma_to_cpu(value) caam_dma64_to_cpu(value) -#else -#define cpu_to_caam_dma(value) cpu_to_caam32(value) -#define caam_dma_to_cpu(value) caam32_to_cpu(value) -#endif /* CONFIG_ARCH_DMA_ADDR_T_64BIT */ +static inline u64 cpu_to_caam_dma(u64 value) +{ + if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && + caam_ptr_sz == sizeof(u64)) + return cpu_to_caam_dma64(value); + else + return cpu_to_caam32(value); +} + +static inline u64 caam_dma_to_cpu(u64 value) +{ + if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && + caam_ptr_sz == sizeof(u64)) + return caam_dma64_to_cpu(value); + else + return caam32_to_cpu(value); +} /* * jr_outentry * Represents each entry in a JobR output ring */ -struct jr_outentry { - dma_addr_t desc;/* Pointer to completed descriptor */ - u32 jrstatus; /* Status for completed descriptor */ -} __packed; + +static inline void jr_outentry_get(void *outring, int hw_idx, dma_addr_t *desc, + u32 *jrstatus) +{ + + if (caam_ptr_sz == sizeof(u32)) { + struct { + u32 desc; + u32 jrstatus; + } __packed *outentry = outring; + + *desc = outentry[hw_idx].desc; + *jrstatus = outentry[hw_idx].jrstatus; + } else { + struct { + dma_addr_t desc;/* Pointer to completed descriptor */ + u32 jrstatus; /* Status for completed descriptor */ + } __packed *outentry = outring; + + *desc = outentry[hw_idx].desc; + *jrstatus = outentry[hw_idx].jrstatus; + } +} + +#define SIZEOF_JR_OUTENTRY (caam_ptr_sz + sizeof(u32)) + +static inline dma_addr_t jr_outentry_desc(void *outring, int hw_idx) +{ + dma_addr_t desc; + u32 unused; + + jr_outentry_get(outring, hw_idx, &desc, &unused); + + return desc; +} + +static inline u32 jr_outentry_jrstatus(void *outring, int hw_idx) +{ + dma_addr_t unused; + u32 jrstatus; + + jr_outentry_get(outring, hw_idx, &unused, &jrstatus); + + return jrstatus; +} + +static inline void jr_inpentry_set(void *inpring, int hw_idx, dma_addr_t val) +{ + if (caam_ptr_sz == sizeof(u32)) { + u32 *inpentry = inpring; + + inpentry[hw_idx] = val; + } else { + dma_addr_t *inpentry = inpring; + + inpentry[hw_idx] = val; + } +} + +#define SIZEOF_JR_INPENTRY caam_ptr_sz + /* Version registers (Era 10+) e80-eff */ struct version_regs { @@ -338,6 +399,7 @@ struct caam_perfmon { u32 cha_rev_ls; /* CRNR - CHA Rev No. Least significant half*/ #define CTPR_MS_QI_SHIFT 25 #define CTPR_MS_QI_MASK (0x1ull << CTPR_MS_QI_SHIFT) +#define CTPR_MS_PS BIT(17) #define CTPR_MS_DPAA2 BIT(13) #define CTPR_MS_VIRT_EN_INCL 0x00000001 #define CTPR_MS_VIRT_EN_POR 0x00000002 @@ -641,6 +703,7 @@ struct caam_job_ring { #define JRSTA_SSRC_CCB_ERROR 0x20000000 #define JRSTA_SSRC_JUMP_HALT_USER 0x30000000 #define JRSTA_SSRC_DECO 0x40000000 +#define JRSTA_SSRC_QI 0x50000000 #define JRSTA_SSRC_JRERROR 0x60000000 #define JRSTA_SSRC_JUMP_HALT_CC 0x70000000 diff --git a/drivers/crypto/cavium/cpt/cptvf_algs.c b/drivers/crypto/cavium/cpt/cptvf_algs.c index ff3cb1f8f2b62dd4d37f327286e0f3a7fe03fcca..596ce28b957d3130020853fd58d678105b06ab49 100644 --- a/drivers/crypto/cavium/cpt/cptvf_algs.c +++ b/drivers/crypto/cavium/cpt/cptvf_algs.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -322,31 +322,15 @@ static int cvm_cfb_aes_setkey(struct crypto_ablkcipher *cipher, const u8 *key, static int cvm_cbc_des3_setkey(struct crypto_ablkcipher *cipher, const u8 *key, u32 keylen) { - u32 flags = crypto_ablkcipher_get_flags(cipher); - int err; - - err = __des3_verify_key(&flags, key); - if (unlikely(err)) { - crypto_ablkcipher_set_flags(cipher, flags); - return err; - } - - return cvm_setkey(cipher, key, keylen, DES3_CBC); + return verify_ablkcipher_des3_key(cipher, key) ?: + cvm_setkey(cipher, key, keylen, DES3_CBC); } static int cvm_ecb_des3_setkey(struct crypto_ablkcipher *cipher, const u8 *key, u32 keylen) { - u32 flags = crypto_ablkcipher_get_flags(cipher); - int err; - - err = __des3_verify_key(&flags, key); - if (unlikely(err)) { - crypto_ablkcipher_set_flags(cipher, flags); - return err; - } - - return cvm_setkey(cipher, key, keylen, DES3_ECB); + return verify_ablkcipher_des3_key(cipher, key) ?: + cvm_setkey(cipher, key, keylen, DES3_ECB); } static int cvm_enc_dec_init(struct crypto_tfm *tfm) diff --git a/drivers/crypto/cavium/nitrox/Kconfig b/drivers/crypto/cavium/nitrox/Kconfig index dab162af41b8a42df89ec46d18a6831e5b5e7bb7..7b1e751bb9cda09a8b4aa84e7b980ca6df838e79 100644 --- a/drivers/crypto/cavium/nitrox/Kconfig +++ b/drivers/crypto/cavium/nitrox/Kconfig @@ -6,7 +6,7 @@ config CRYPTO_DEV_NITROX tristate select CRYPTO_BLKCIPHER select CRYPTO_AES - select CRYPTO_DES + select CRYPTO_LIB_DES select FW_LOADER config CRYPTO_DEV_NITROX_CNN55XX diff --git a/drivers/crypto/cavium/nitrox/nitrox_csr.h b/drivers/crypto/cavium/nitrox/nitrox_csr.h index a2a452642b3865a93db67fe2c0f53a7985524d92..1c8715ae0488a17e3acb0f14208f798221960410 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_csr.h +++ b/drivers/crypto/cavium/nitrox/nitrox_csr.h @@ -40,9 +40,77 @@ #define EMU_FUSE_MAPX(_i) (0x1402708 + ((_i) * 0x40000)) /* UCD registers */ +#define UCD_SE_EID_UCODE_BLOCK_NUMX(_i) (0x12C0000 + ((_i) * 0x1000)) +#define UCD_AE_EID_UCODE_BLOCK_NUMX(_i) (0x12C0008 + ((_i) * 0x800)) #define UCD_UCODE_LOAD_BLOCK_NUM 0x12C0010 #define UCD_UCODE_LOAD_IDX_DATAX(_i) (0x12C0018 + ((_i) * 0x20)) -#define UCD_SE_EID_UCODE_BLOCK_NUMX(_i) (0x12C0000 + ((_i) * 0x1000)) +#define UCD_SE_CNTX(_i) (0x12C0040 + ((_i) * 0x1000)) +#define UCD_AE_CNTX(_i) (0x12C0048 + ((_i) * 0x800)) + +/* AQM registers */ +#define AQM_CTL 0x1300000 +#define AQM_INT 0x1300008 +#define AQM_DBELL_OVF_LO 0x1300010 +#define AQM_DBELL_OVF_HI 0x1300018 +#define AQM_DBELL_OVF_LO_W1S 0x1300020 +#define AQM_DBELL_OVF_LO_ENA_W1C 0x1300028 +#define AQM_DBELL_OVF_LO_ENA_W1S 0x1300030 +#define AQM_DBELL_OVF_HI_W1S 0x1300038 +#define AQM_DBELL_OVF_HI_ENA_W1C 0x1300040 +#define AQM_DBELL_OVF_HI_ENA_W1S 0x1300048 +#define AQM_DMA_RD_ERR_LO 0x1300050 +#define AQM_DMA_RD_ERR_HI 0x1300058 +#define AQM_DMA_RD_ERR_LO_W1S 0x1300060 +#define AQM_DMA_RD_ERR_LO_ENA_W1C 0x1300068 +#define AQM_DMA_RD_ERR_LO_ENA_W1S 0x1300070 +#define AQM_DMA_RD_ERR_HI_W1S 0x1300078 +#define AQM_DMA_RD_ERR_HI_ENA_W1C 0x1300080 +#define AQM_DMA_RD_ERR_HI_ENA_W1S 0x1300088 +#define AQM_EXEC_NA_LO 0x1300090 +#define AQM_EXEC_NA_HI 0x1300098 +#define AQM_EXEC_NA_LO_W1S 0x13000A0 +#define AQM_EXEC_NA_LO_ENA_W1C 0x13000A8 +#define AQM_EXEC_NA_LO_ENA_W1S 0x13000B0 +#define AQM_EXEC_NA_HI_W1S 0x13000B8 +#define AQM_EXEC_NA_HI_ENA_W1C 0x13000C0 +#define AQM_EXEC_NA_HI_ENA_W1S 0x13000C8 +#define AQM_EXEC_ERR_LO 0x13000D0 +#define AQM_EXEC_ERR_HI 0x13000D8 +#define AQM_EXEC_ERR_LO_W1S 0x13000E0 +#define AQM_EXEC_ERR_LO_ENA_W1C 0x13000E8 +#define AQM_EXEC_ERR_LO_ENA_W1S 0x13000F0 +#define AQM_EXEC_ERR_HI_W1S 0x13000F8 +#define AQM_EXEC_ERR_HI_ENA_W1C 0x1300100 +#define AQM_EXEC_ERR_HI_ENA_W1S 0x1300108 +#define AQM_ECC_INT 0x1300110 +#define AQM_ECC_INT_W1S 0x1300118 +#define AQM_ECC_INT_ENA_W1C 0x1300120 +#define AQM_ECC_INT_ENA_W1S 0x1300128 +#define AQM_ECC_CTL 0x1300130 +#define AQM_BIST_STATUS 0x1300138 +#define AQM_CMD_INF_THRX(x) (0x1300400 + ((x) * 0x8)) +#define AQM_CMD_INFX(x) (0x1300800 + ((x) * 0x8)) +#define AQM_GRP_EXECMSK_LOX(x) (0x1300C00 + ((x) * 0x10)) +#define AQM_GRP_EXECMSK_HIX(x) (0x1300C08 + ((x) * 0x10)) +#define AQM_ACTIVITY_STAT_LO 0x1300C80 +#define AQM_ACTIVITY_STAT_HI 0x1300C88 +#define AQM_Q_CMD_PROCX(x) (0x1301000 + ((x) * 0x8)) +#define AQM_PERF_CTL_LO 0x1301400 +#define AQM_PERF_CTL_HI 0x1301408 +#define AQM_PERF_CNT 0x1301410 + +#define AQMQ_DRBLX(x) (0x20000 + ((x) * 0x40000)) +#define AQMQ_QSZX(x) (0x20008 + ((x) * 0x40000)) +#define AQMQ_BADRX(x) (0x20010 + ((x) * 0x40000)) +#define AQMQ_NXT_CMDX(x) (0x20018 + ((x) * 0x40000)) +#define AQMQ_CMD_CNTX(x) (0x20020 + ((x) * 0x40000)) +#define AQMQ_CMP_THRX(x) (0x20028 + ((x) * 0x40000)) +#define AQMQ_CMP_CNTX(x) (0x20030 + ((x) * 0x40000)) +#define AQMQ_TIM_LDX(x) (0x20038 + ((x) * 0x40000)) +#define AQMQ_TIMERX(x) (0x20040 + ((x) * 0x40000)) +#define AQMQ_ENX(x) (0x20048 + ((x) * 0x40000)) +#define AQMQ_ACTIVITY_STATX(x) (0x20050 + ((x) * 0x40000)) +#define AQM_VF_CMP_STATX(x) (0x28000 + ((x) * 0x40000)) /* NPS core registers */ #define NPS_CORE_GBL_VFCFG 0x1000000 @@ -134,6 +202,171 @@ /* PEM registers */ #define PEM0_INT 0x1080428 +/** + * struct ucd_core_eid_ucode_block_num - Core Eid to Ucode Blk Mapping Registers + * @ucode_len: Ucode length identifier 32KB or 64KB + * @ucode_blk: Ucode Block Number + */ +union ucd_core_eid_ucode_block_num { + u64 value; + struct { +#if (defined(__BIG_ENDIAN_BITFIELD)) + u64 raz_4_63 : 60; + u64 ucode_len : 1; + u64 ucode_blk : 3; +#else + u64 ucode_blk : 3; + u64 ucode_len : 1; + u64 raz_4_63 : 60; +#endif + }; +}; + +/** + * struct aqm_grp_execmsk_lo - Available AE engines for the group + * @exec_0_to_39: AE engines 0 to 39 status + */ +union aqm_grp_execmsk_lo { + u64 value; + struct { +#if (defined(__BIG_ENDIAN_BITFIELD)) + u64 raz_40_63 : 24; + u64 exec_0_to_39 : 40; +#else + u64 exec_0_to_39 : 40; + u64 raz_40_63 : 24; +#endif + }; +}; + +/** + * struct aqm_grp_execmsk_hi - Available AE engines for the group + * @exec_40_to_79: AE engines 40 to 79 status + */ +union aqm_grp_execmsk_hi { + u64 value; + struct { +#if (defined(__BIG_ENDIAN_BITFIELD)) + u64 raz_40_63 : 24; + u64 exec_40_to_79 : 40; +#else + u64 exec_40_to_79 : 40; + u64 raz_40_63 : 24; +#endif + }; +}; + +/** + * struct aqmq_drbl - AQM Queue Doorbell Counter Registers + * @dbell_count: Doorbell Counter + */ +union aqmq_drbl { + u64 value; + struct { +#if (defined(__BIG_ENDIAN_BITFIELD)) + u64 raz_32_63 : 32; + u64 dbell_count : 32; +#else + u64 dbell_count : 32; + u64 raz_32_63 : 32; +#endif + }; +}; + +/** + * struct aqmq_qsz - AQM Queue Host Queue Size Registers + * @host_queue_size: Size, in numbers of 'aqmq_command_s' command + * of the Host Ring. + */ +union aqmq_qsz { + u64 value; + struct { +#if (defined(__BIG_ENDIAN_BITFIELD)) + u64 raz_32_63 : 32; + u64 host_queue_size : 32; +#else + u64 host_queue_size : 32; + u64 raz_32_63 : 32; +#endif + }; +}; + +/** + * struct aqmq_cmp_thr - AQM Queue Commands Completed Threshold Registers + * @commands_completed_threshold: Count of 'aqmq_command_s' commands executed + * by AE engines for which completion interrupt is asserted. + */ +union aqmq_cmp_thr { + u64 value; + struct { +#if (defined(__BIG_ENDIAN_BITFIELD)) + u64 raz_32_63 : 32; + u64 commands_completed_threshold : 32; +#else + u64 commands_completed_threshold : 32; + u64 raz_32_63 : 32; +#endif + }; +}; + +/** + * struct aqmq_cmp_cnt - AQM Queue Commands Completed Count Registers + * @resend: Bit to request completion interrupt Resend. + * @completion_status: Command completion status of the ring. + * @commands_completed_count: Count of 'aqmq_command_s' commands executed by + * AE engines. + */ +union aqmq_cmp_cnt { + u64 value; + struct { +#if (defined(__BIG_ENDIAN_BITFIELD)) + u64 raz_34_63 : 30; + u64 resend : 1; + u64 completion_status : 1; + u64 commands_completed_count : 32; +#else + u64 commands_completed_count : 32; + u64 completion_status : 1; + u64 resend : 1; + u64 raz_34_63 : 30; +#endif + }; +}; + +/** + * struct aqmq_en - AQM Queue Enable Registers + * @queue_status: 1 = AQMQ is enabled, 0 = AQMQ is disabled + */ +union aqmq_en { + u64 value; + struct { +#if (defined(__BIG_ENDIAN_BITFIELD)) + u64 raz_1_63 : 63; + u64 queue_enable : 1; +#else + u64 queue_enable : 1; + u64 raz_1_63 : 63; +#endif + }; +}; + +/** + * struct aqmq_activity_stat - AQM Queue Activity Status Registers + * @queue_active: 1 = AQMQ is active, 0 = AQMQ is quiescent + */ +union aqmq_activity_stat { + u64 value; + struct { +#if (defined(__BIG_ENDIAN_BITFIELD)) + u64 raz_1_63 : 63; + u64 queue_active : 1; +#else + u64 queue_active : 1; + u64 raz_1_63 : 63; +#endif + }; +}; + /** * struct emu_fuse_map - EMU Fuse Map Registers * @ae_fuse: Fuse settings for AE 19..0 diff --git a/drivers/crypto/cavium/nitrox/nitrox_debugfs.c b/drivers/crypto/cavium/nitrox/nitrox_debugfs.c index 848ec93d4333d0bb04bd89c78f1616a27d4407c0..16f7d0bd1303203c2d273737b7254d047b12ef7a 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_debugfs.c +++ b/drivers/crypto/cavium/nitrox/nitrox_debugfs.c @@ -9,7 +9,8 @@ static int firmware_show(struct seq_file *s, void *v) { struct nitrox_device *ndev = s->private; - seq_printf(s, "Version: %s\n", ndev->hw.fw_name); + seq_printf(s, "Version: %s\n", ndev->hw.fw_name[0]); + seq_printf(s, "Version: %s\n", ndev->hw.fw_name[1]); return 0; } diff --git a/drivers/crypto/cavium/nitrox/nitrox_dev.h b/drivers/crypto/cavium/nitrox/nitrox_dev.h index 0338877b828f9844336fd0ee260390787291b315..2217a2736c8e47dc2f625d4ed51d226ee6270eb2 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_dev.h +++ b/drivers/crypto/cavium/nitrox/nitrox_dev.h @@ -10,6 +10,10 @@ #define VERSION_LEN 32 /* Maximum queues in PF mode */ #define MAX_PF_QUEUES 64 +/* Maximum device queues */ +#define MAX_DEV_QUEUES (MAX_PF_QUEUES) +/* Maximum UCD Blocks */ +#define CNN55XX_MAX_UCD_BLOCKS 8 /** * struct nitrox_cmdq - NITROX command queue @@ -74,7 +78,7 @@ struct nitrox_cmdq { */ struct nitrox_hw { char partname[IFNAMSIZ * 2]; - char fw_name[VERSION_LEN]; + char fw_name[CNN55XX_MAX_UCD_BLOCKS][VERSION_LEN]; int freq; u16 vendor_id; @@ -206,6 +210,7 @@ enum vf_mode { * @mode: Device mode PF/VF * @ctx_pool: DMA pool for crypto context * @pkt_inq: Packet input rings + * @aqmq: AQM command queues * @qvec: MSI-X queue vectors information * @iov: SR-IOV informatin * @num_vecs: number of MSI-X vectors @@ -232,6 +237,7 @@ struct nitrox_device { struct dma_pool *ctx_pool; struct nitrox_cmdq *pkt_inq; + struct nitrox_cmdq *aqmq[MAX_DEV_QUEUES] ____cacheline_aligned_in_smp; struct nitrox_q_vector *qvec; struct nitrox_iov iov; diff --git a/drivers/crypto/cavium/nitrox/nitrox_hal.c b/drivers/crypto/cavium/nitrox/nitrox_hal.c index 3f0df60267a9f25329788615cc0118a92d16d2ef..34a2f4f30a7e02d5339554ac605d7842cfa5b3a8 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_hal.c +++ b/drivers/crypto/cavium/nitrox/nitrox_hal.c @@ -241,12 +241,12 @@ void nitrox_config_pkt_solicit_ports(struct nitrox_device *ndev) } /** - * enable_nps_interrupts - enable NPS interrutps + * enable_nps_core_interrupts - enable NPS core interrutps * @ndev: NITROX device. * - * This includes NPS core, packet in and slc interrupts. + * This includes NPS core interrupts. */ -static void enable_nps_interrupts(struct nitrox_device *ndev) +static void enable_nps_core_interrupts(struct nitrox_device *ndev) { union nps_core_int_ena_w1s core_int; @@ -258,18 +258,9 @@ static void enable_nps_interrupts(struct nitrox_device *ndev) core_int.s.npco_dma_malform = 1; core_int.s.host_nps_wr_err = 1; nitrox_write_csr(ndev, NPS_CORE_INT_ENA_W1S, core_int.value); - - /* NPS packet in ring interrupts */ - nitrox_write_csr(ndev, NPS_PKT_IN_RERR_LO_ENA_W1S, (~0ULL)); - nitrox_write_csr(ndev, NPS_PKT_IN_RERR_HI_ENA_W1S, (~0ULL)); - nitrox_write_csr(ndev, NPS_PKT_IN_ERR_TYPE_ENA_W1S, (~0ULL)); - /* NPS packet slc port interrupts */ - nitrox_write_csr(ndev, NPS_PKT_SLC_RERR_HI_ENA_W1S, (~0ULL)); - nitrox_write_csr(ndev, NPS_PKT_SLC_RERR_LO_ENA_W1S, (~0ULL)); - nitrox_write_csr(ndev, NPS_PKT_SLC_ERR_TYPE_ENA_W1S, (~0uLL)); } -void nitrox_config_nps_unit(struct nitrox_device *ndev) +void nitrox_config_nps_core_unit(struct nitrox_device *ndev) { union nps_core_gbl_vfcfg core_gbl_vfcfg; @@ -281,12 +272,149 @@ void nitrox_config_nps_unit(struct nitrox_device *ndev) core_gbl_vfcfg.s.ilk_disable = 1; core_gbl_vfcfg.s.cfg = __NDEV_MODE_PF; nitrox_write_csr(ndev, NPS_CORE_GBL_VFCFG, core_gbl_vfcfg.value); + + /* enable nps core interrupts */ + enable_nps_core_interrupts(ndev); +} + +/** + * enable_nps_pkt_interrupts - enable NPS packet interrutps + * @ndev: NITROX device. + * + * This includes NPS packet in and slc interrupts. + */ +static void enable_nps_pkt_interrupts(struct nitrox_device *ndev) +{ + /* NPS packet in ring interrupts */ + nitrox_write_csr(ndev, NPS_PKT_IN_RERR_LO_ENA_W1S, (~0ULL)); + nitrox_write_csr(ndev, NPS_PKT_IN_RERR_HI_ENA_W1S, (~0ULL)); + nitrox_write_csr(ndev, NPS_PKT_IN_ERR_TYPE_ENA_W1S, (~0ULL)); + /* NPS packet slc port interrupts */ + nitrox_write_csr(ndev, NPS_PKT_SLC_RERR_HI_ENA_W1S, (~0ULL)); + nitrox_write_csr(ndev, NPS_PKT_SLC_RERR_LO_ENA_W1S, (~0ULL)); + nitrox_write_csr(ndev, NPS_PKT_SLC_ERR_TYPE_ENA_W1S, (~0uLL)); +} + +void nitrox_config_nps_pkt_unit(struct nitrox_device *ndev) +{ /* config input and solicit ports */ nitrox_config_pkt_input_rings(ndev); nitrox_config_pkt_solicit_ports(ndev); - /* enable interrupts */ - enable_nps_interrupts(ndev); + /* enable nps packet interrupts */ + enable_nps_pkt_interrupts(ndev); +} + +static void reset_aqm_ring(struct nitrox_device *ndev, int ring) +{ + union aqmq_en aqmq_en_reg; + union aqmq_activity_stat activity_stat; + union aqmq_cmp_cnt cmp_cnt; + int max_retries = MAX_CSR_RETRIES; + u64 offset; + + /* step 1: disable the queue */ + offset = AQMQ_ENX(ring); + aqmq_en_reg.value = 0; + aqmq_en_reg.queue_enable = 0; + nitrox_write_csr(ndev, offset, aqmq_en_reg.value); + + /* step 2: wait for AQMQ_ACTIVITY_STATX[QUEUE_ACTIVE] to clear */ + usleep_range(100, 150); + offset = AQMQ_ACTIVITY_STATX(ring); + do { + activity_stat.value = nitrox_read_csr(ndev, offset); + if (!activity_stat.queue_active) + break; + udelay(50); + } while (max_retries--); + + /* step 3: clear commands completed count */ + offset = AQMQ_CMP_CNTX(ring); + cmp_cnt.value = nitrox_read_csr(ndev, offset); + nitrox_write_csr(ndev, offset, cmp_cnt.value); + usleep_range(50, 100); +} + +void enable_aqm_ring(struct nitrox_device *ndev, int ring) +{ + union aqmq_en aqmq_en_reg; + u64 offset; + + offset = AQMQ_ENX(ring); + aqmq_en_reg.value = 0; + aqmq_en_reg.queue_enable = 1; + nitrox_write_csr(ndev, offset, aqmq_en_reg.value); + usleep_range(50, 100); +} + +void nitrox_config_aqm_rings(struct nitrox_device *ndev) +{ + int ring; + + for (ring = 0; ring < ndev->nr_queues; ring++) { + struct nitrox_cmdq *cmdq = ndev->aqmq[ring]; + union aqmq_drbl drbl; + union aqmq_qsz qsize; + union aqmq_cmp_thr cmp_thr; + u64 offset; + + /* steps 1 - 3 */ + reset_aqm_ring(ndev, ring); + + /* step 4: clear doorbell count of ring */ + offset = AQMQ_DRBLX(ring); + drbl.value = 0; + drbl.dbell_count = 0xFFFFFFFF; + nitrox_write_csr(ndev, offset, drbl.value); + + /* step 5: configure host ring details */ + + /* set host address for next command of ring */ + offset = AQMQ_NXT_CMDX(ring); + nitrox_write_csr(ndev, offset, 0ULL); + + /* set host address of ring base */ + offset = AQMQ_BADRX(ring); + nitrox_write_csr(ndev, offset, cmdq->dma); + + /* set ring size */ + offset = AQMQ_QSZX(ring); + qsize.value = 0; + qsize.host_queue_size = ndev->qlen; + nitrox_write_csr(ndev, offset, qsize.value); + + /* set command completion threshold */ + offset = AQMQ_CMP_THRX(ring); + cmp_thr.value = 0; + cmp_thr.commands_completed_threshold = 1; + nitrox_write_csr(ndev, offset, cmp_thr.value); + + /* step 6: enable the queue */ + enable_aqm_ring(ndev, ring); + } +} + +static void enable_aqm_interrupts(struct nitrox_device *ndev) +{ + /* clear interrupt enable bits */ + nitrox_write_csr(ndev, AQM_DBELL_OVF_LO_ENA_W1S, (~0ULL)); + nitrox_write_csr(ndev, AQM_DBELL_OVF_HI_ENA_W1S, (~0ULL)); + nitrox_write_csr(ndev, AQM_DMA_RD_ERR_LO_ENA_W1S, (~0ULL)); + nitrox_write_csr(ndev, AQM_DMA_RD_ERR_HI_ENA_W1S, (~0ULL)); + nitrox_write_csr(ndev, AQM_EXEC_NA_LO_ENA_W1S, (~0ULL)); + nitrox_write_csr(ndev, AQM_EXEC_NA_HI_ENA_W1S, (~0ULL)); + nitrox_write_csr(ndev, AQM_EXEC_ERR_LO_ENA_W1S, (~0ULL)); + nitrox_write_csr(ndev, AQM_EXEC_ERR_HI_ENA_W1S, (~0ULL)); +} + +void nitrox_config_aqm_unit(struct nitrox_device *ndev) +{ + /* config aqm command queues */ + nitrox_config_aqm_rings(ndev); + + /* enable aqm interrupts */ + enable_aqm_interrupts(ndev); } void nitrox_config_pom_unit(struct nitrox_device *ndev) diff --git a/drivers/crypto/cavium/nitrox/nitrox_hal.h b/drivers/crypto/cavium/nitrox/nitrox_hal.h index d6606418ba3822f93a7d6ab9057718997fd79f33..48b0af0390998c9a7e37a414634b6741d37c66d5 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_hal.h +++ b/drivers/crypto/cavium/nitrox/nitrox_hal.h @@ -4,10 +4,13 @@ #include "nitrox_dev.h" +void nitrox_config_aqm_rings(struct nitrox_device *ndev); +void nitrox_config_aqm_unit(struct nitrox_device *ndev); void nitrox_config_emu_unit(struct nitrox_device *ndev); void nitrox_config_pkt_input_rings(struct nitrox_device *ndev); void nitrox_config_pkt_solicit_ports(struct nitrox_device *ndev); -void nitrox_config_nps_unit(struct nitrox_device *ndev); +void nitrox_config_nps_core_unit(struct nitrox_device *ndev); +void nitrox_config_nps_pkt_unit(struct nitrox_device *ndev); void nitrox_config_pom_unit(struct nitrox_device *ndev); void nitrox_config_rand_unit(struct nitrox_device *ndev); void nitrox_config_efl_unit(struct nitrox_device *ndev); @@ -15,6 +18,7 @@ void nitrox_config_bmi_unit(struct nitrox_device *ndev); void nitrox_config_bmo_unit(struct nitrox_device *ndev); void nitrox_config_lbc_unit(struct nitrox_device *ndev); void invalidate_lbc(struct nitrox_device *ndev); +void enable_aqm_ring(struct nitrox_device *ndev, int qno); void enable_pkt_input_ring(struct nitrox_device *ndev, int ring); void enable_pkt_solicit_port(struct nitrox_device *ndev, int port); void config_nps_core_vfcfg_mode(struct nitrox_device *ndev, enum vf_mode mode); diff --git a/drivers/crypto/cavium/nitrox/nitrox_lib.c b/drivers/crypto/cavium/nitrox/nitrox_lib.c index 4ace9bcd603a45ee165a90af729052fdc0d8e8c1..5cbc64b851b993b8452236222ddce1b165b62b2a 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_lib.c +++ b/drivers/crypto/cavium/nitrox/nitrox_lib.c @@ -19,6 +19,8 @@ /* packet inuput ring alignments */ #define PKTIN_Q_ALIGN_BYTES 16 +/* AQM Queue input alignments */ +#define AQM_Q_ALIGN_BYTES 32 static int nitrox_cmdq_init(struct nitrox_cmdq *cmdq, int align_bytes) { @@ -57,11 +59,15 @@ static void nitrox_cmdq_reset(struct nitrox_cmdq *cmdq) static void nitrox_cmdq_cleanup(struct nitrox_cmdq *cmdq) { - struct nitrox_device *ndev = cmdq->ndev; + struct nitrox_device *ndev; + + if (!cmdq) + return; if (!cmdq->unalign_base) return; + ndev = cmdq->ndev; cancel_work_sync(&cmdq->backlog_qflush); dma_free_coherent(DEV(ndev), cmdq->qsize, @@ -78,6 +84,57 @@ static void nitrox_cmdq_cleanup(struct nitrox_cmdq *cmdq) cmdq->instr_size = 0; } +static void nitrox_free_aqm_queues(struct nitrox_device *ndev) +{ + int i; + + for (i = 0; i < ndev->nr_queues; i++) { + nitrox_cmdq_cleanup(ndev->aqmq[i]); + kzfree(ndev->aqmq[i]); + ndev->aqmq[i] = NULL; + } +} + +static int nitrox_alloc_aqm_queues(struct nitrox_device *ndev) +{ + int i, err; + + for (i = 0; i < ndev->nr_queues; i++) { + struct nitrox_cmdq *cmdq; + u64 offset; + + cmdq = kzalloc_node(sizeof(*cmdq), GFP_KERNEL, ndev->node); + if (!cmdq) { + err = -ENOMEM; + goto aqmq_fail; + } + + cmdq->ndev = ndev; + cmdq->qno = i; + cmdq->instr_size = sizeof(struct aqmq_command_s); + + /* AQM Queue Doorbell Counter Register Address */ + offset = AQMQ_DRBLX(i); + cmdq->dbell_csr_addr = NITROX_CSR_ADDR(ndev, offset); + /* AQM Queue Commands Completed Count Register Address */ + offset = AQMQ_CMD_CNTX(i); + cmdq->compl_cnt_csr_addr = NITROX_CSR_ADDR(ndev, offset); + + err = nitrox_cmdq_init(cmdq, AQM_Q_ALIGN_BYTES); + if (err) { + kzfree(cmdq); + goto aqmq_fail; + } + ndev->aqmq[i] = cmdq; + } + + return 0; + +aqmq_fail: + nitrox_free_aqm_queues(ndev); + return err; +} + static void nitrox_free_pktin_queues(struct nitrox_device *ndev) { int i; @@ -222,6 +279,12 @@ int nitrox_common_sw_init(struct nitrox_device *ndev) if (err) destroy_crypto_dma_pool(ndev); + err = nitrox_alloc_aqm_queues(ndev); + if (err) { + nitrox_free_pktin_queues(ndev); + destroy_crypto_dma_pool(ndev); + } + return err; } @@ -231,6 +294,7 @@ int nitrox_common_sw_init(struct nitrox_device *ndev) */ void nitrox_common_sw_cleanup(struct nitrox_device *ndev) { + nitrox_free_aqm_queues(ndev); nitrox_free_pktin_queues(ndev); destroy_crypto_dma_pool(ndev); } diff --git a/drivers/crypto/cavium/nitrox/nitrox_main.c b/drivers/crypto/cavium/nitrox/nitrox_main.c index fe825d0ef9cafe41ea7bb2fa6c8d67246da255cb..bc924980e10c036c03ce3bb4785c4a0698800963 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_main.c +++ b/drivers/crypto/cavium/nitrox/nitrox_main.c @@ -17,12 +17,17 @@ #define CNN55XX_DEV_ID 0x12 #define UCODE_HLEN 48 -#define SE_GROUP 0 +#define DEFAULT_SE_GROUP 0 +#define DEFAULT_AE_GROUP 0 -#define DRIVER_VERSION "1.1" +#define DRIVER_VERSION "1.2" +#define CNN55XX_UCD_BLOCK_SIZE 32768 +#define CNN55XX_MAX_UCODE_SIZE (CNN55XX_UCD_BLOCK_SIZE * 2) #define FW_DIR "cavium/" /* SE microcode */ #define SE_FW FW_DIR "cnn55xx_se.fw" +/* AE microcode */ +#define AE_FW FW_DIR "cnn55xx_ae.fw" static const char nitrox_driver_name[] = "CNN55XX"; @@ -72,10 +77,10 @@ struct ucode { /** * write_to_ucd_unit - Write Firmware to NITROX UCD unit */ -static void write_to_ucd_unit(struct nitrox_device *ndev, - struct ucode *ucode) +static void write_to_ucd_unit(struct nitrox_device *ndev, u32 ucode_size, + u64 *ucode_data, int block_num) { - u32 code_size = be32_to_cpu(ucode->code_size) * 2; + u32 code_size; u64 offset, data; int i = 0; @@ -96,11 +101,12 @@ static void write_to_ucd_unit(struct nitrox_device *ndev, /* set the block number */ offset = UCD_UCODE_LOAD_BLOCK_NUM; - nitrox_write_csr(ndev, offset, 0); + nitrox_write_csr(ndev, offset, block_num); + code_size = ucode_size; code_size = roundup(code_size, 8); while (code_size) { - data = ucode->code[i]; + data = ucode_data[i]; /* write 8 bytes at a time */ offset = UCD_UCODE_LOAD_IDX_DATAX(i); nitrox_write_csr(ndev, offset, data); @@ -108,29 +114,74 @@ static void write_to_ucd_unit(struct nitrox_device *ndev, i++; } - /* put all SE cores in group 0 */ - offset = POM_GRP_EXECMASKX(SE_GROUP); - nitrox_write_csr(ndev, offset, (~0ULL)); - - for (i = 0; i < ndev->hw.se_cores; i++) { - /* - * write block number and firware length - * bit:<2:0> block number - * bit:3 is set SE uses 32KB microcode - * bit:3 is clear SE uses 64KB microcode - */ - offset = UCD_SE_EID_UCODE_BLOCK_NUMX(i); - nitrox_write_csr(ndev, offset, 0x8); - } usleep_range(300, 400); } -static int nitrox_load_fw(struct nitrox_device *ndev, const char *fw_name) +static int nitrox_load_fw(struct nitrox_device *ndev) { const struct firmware *fw; + const char *fw_name; struct ucode *ucode; - int ret; + u64 *ucode_data; + u64 offset; + union ucd_core_eid_ucode_block_num core_2_eid_val; + union aqm_grp_execmsk_lo aqm_grp_execmask_lo; + union aqm_grp_execmsk_hi aqm_grp_execmask_hi; + u32 ucode_size; + int ret, i = 0; + + fw_name = SE_FW; + dev_info(DEV(ndev), "Loading firmware \"%s\"\n", fw_name); + + ret = request_firmware(&fw, fw_name, DEV(ndev)); + if (ret < 0) { + dev_err(DEV(ndev), "failed to get firmware %s\n", fw_name); + return ret; + } + + ucode = (struct ucode *)fw->data; + + ucode_size = be32_to_cpu(ucode->code_size) * 2; + if (!ucode_size || ucode_size > CNN55XX_MAX_UCODE_SIZE) { + dev_err(DEV(ndev), "Invalid ucode size: %u for firmware %s\n", + ucode_size, fw_name); + release_firmware(fw); + return -EINVAL; + } + ucode_data = ucode->code; + + /* copy the firmware version */ + memcpy(&ndev->hw.fw_name[0][0], ucode->version, (VERSION_LEN - 2)); + ndev->hw.fw_name[0][VERSION_LEN - 1] = '\0'; + + /* Load SE Firmware on UCD Block 0 */ + write_to_ucd_unit(ndev, ucode_size, ucode_data, 0); + release_firmware(fw); + + /* put all SE cores in DEFAULT_SE_GROUP */ + offset = POM_GRP_EXECMASKX(DEFAULT_SE_GROUP); + nitrox_write_csr(ndev, offset, (~0ULL)); + + /* write block number and firmware length + * bit:<2:0> block number + * bit:3 is set SE uses 32KB microcode + * bit:3 is clear SE uses 64KB microcode + */ + core_2_eid_val.value = 0ULL; + core_2_eid_val.ucode_blk = 0; + if (ucode_size <= CNN55XX_UCD_BLOCK_SIZE) + core_2_eid_val.ucode_len = 1; + else + core_2_eid_val.ucode_len = 0; + + for (i = 0; i < ndev->hw.se_cores; i++) { + offset = UCD_SE_EID_UCODE_BLOCK_NUMX(i); + nitrox_write_csr(ndev, offset, core_2_eid_val.value); + } + + + fw_name = AE_FW; dev_info(DEV(ndev), "Loading firmware \"%s\"\n", fw_name); ret = request_firmware(&fw, fw_name, DEV(ndev)); @@ -140,13 +191,50 @@ static int nitrox_load_fw(struct nitrox_device *ndev, const char *fw_name) } ucode = (struct ucode *)fw->data; + + ucode_size = be32_to_cpu(ucode->code_size) * 2; + if (!ucode_size || ucode_size > CNN55XX_MAX_UCODE_SIZE) { + dev_err(DEV(ndev), "Invalid ucode size: %u for firmware %s\n", + ucode_size, fw_name); + release_firmware(fw); + return -EINVAL; + } + ucode_data = ucode->code; + /* copy the firmware version */ - memcpy(ndev->hw.fw_name, ucode->version, (VERSION_LEN - 2)); - ndev->hw.fw_name[VERSION_LEN - 1] = '\0'; + memcpy(&ndev->hw.fw_name[1][0], ucode->version, (VERSION_LEN - 2)); + ndev->hw.fw_name[1][VERSION_LEN - 1] = '\0'; + + /* Load AE Firmware on UCD Block 2 */ + write_to_ucd_unit(ndev, ucode_size, ucode_data, 2); - write_to_ucd_unit(ndev, ucode); release_firmware(fw); + /* put all AE cores in DEFAULT_AE_GROUP */ + offset = AQM_GRP_EXECMSK_LOX(DEFAULT_AE_GROUP); + aqm_grp_execmask_lo.exec_0_to_39 = 0xFFFFFFFFFFULL; + nitrox_write_csr(ndev, offset, aqm_grp_execmask_lo.value); + offset = AQM_GRP_EXECMSK_HIX(DEFAULT_AE_GROUP); + aqm_grp_execmask_hi.exec_40_to_79 = 0xFFFFFFFFFFULL; + nitrox_write_csr(ndev, offset, aqm_grp_execmask_hi.value); + + /* write block number and firmware length + * bit:<2:0> block number + * bit:3 is set SE uses 32KB microcode + * bit:3 is clear SE uses 64KB microcode + */ + core_2_eid_val.value = 0ULL; + core_2_eid_val.ucode_blk = 0; + if (ucode_size <= CNN55XX_UCD_BLOCK_SIZE) + core_2_eid_val.ucode_len = 1; + else + core_2_eid_val.ucode_len = 0; + + for (i = 0; i < ndev->hw.ae_cores; i++) { + offset = UCD_AE_EID_UCODE_BLOCK_NUMX(i); + nitrox_write_csr(ndev, offset, core_2_eid_val.value); + } + return 0; } @@ -299,7 +387,9 @@ static int nitrox_pf_hw_init(struct nitrox_device *ndev) /* get cores information */ nitrox_get_hwinfo(ndev); - nitrox_config_nps_unit(ndev); + nitrox_config_nps_core_unit(ndev); + nitrox_config_aqm_unit(ndev); + nitrox_config_nps_pkt_unit(ndev); nitrox_config_pom_unit(ndev); nitrox_config_efl_unit(ndev); /* configure IO units */ @@ -309,8 +399,8 @@ static int nitrox_pf_hw_init(struct nitrox_device *ndev) nitrox_config_lbc_unit(ndev); nitrox_config_rand_unit(ndev); - /* load firmware on SE cores */ - err = nitrox_load_fw(ndev, SE_FW); + /* load firmware on cores */ + err = nitrox_load_fw(ndev); if (err) return err; diff --git a/drivers/crypto/cavium/nitrox/nitrox_req.h b/drivers/crypto/cavium/nitrox/nitrox_req.h index efdbd0fc3e3bf3f2ac6694e8df3d59d0ef16a8d3..f69ba02c4d2561a2e1d983409ca4b42ce02549d1 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_req.h +++ b/drivers/crypto/cavium/nitrox/nitrox_req.h @@ -399,6 +399,36 @@ struct nps_pkt_instr { u64 fdata[2]; }; +/** + * struct aqmq_command_s - The 32 byte command for AE processing. + * @opcode: Request opcode + * @param1: Request control parameter 1 + * @param2: Request control parameter 2 + * @dlen: Input length + * @dptr: Input pointer points to buffer in remote host + * @rptr: Result pointer points to buffer in remote host + * @grp: AQM Group (0..7) + * @cptr: Context pointer + */ +struct aqmq_command_s { + __be16 opcode; + __be16 param1; + __be16 param2; + __be16 dlen; + __be64 dptr; + __be64 rptr; + union { + __be64 word3; +#if defined(__BIG_ENDIAN_BITFIELD) + u64 grp : 3; + u64 cptr : 61; +#else + u64 cptr : 61; + u64 grp : 3; +#endif + }; +}; + /** * struct ctx_hdr - Book keeping data about the crypto context * @pool: Pool used to allocate crypto context diff --git a/drivers/crypto/cavium/nitrox/nitrox_skcipher.c b/drivers/crypto/cavium/nitrox/nitrox_skcipher.c index 7e4a5e69085e9d334d7110e4ef73a32bc56904e4..3cdce1f0f257cf3cc454e63c63339a2de0c52272 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_skcipher.c +++ b/drivers/crypto/cavium/nitrox/nitrox_skcipher.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include "nitrox_dev.h" @@ -257,7 +257,7 @@ static int nitrox_aes_decrypt(struct skcipher_request *skreq) static int nitrox_3des_setkey(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen) { - return unlikely(des3_verify_key(cipher, key)) ?: + return verify_skcipher_des3_key(cipher, key) ?: nitrox_skcipher_setkey(cipher, 0, key, keylen); } diff --git a/drivers/crypto/cavium/nitrox/nitrox_sriov.c b/drivers/crypto/cavium/nitrox/nitrox_sriov.c index bf439d8256ba0c841152096d939411506b23abd7..43287f8471d1d6b83aa12678ee01ac323d4c8e95 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_sriov.c +++ b/drivers/crypto/cavium/nitrox/nitrox_sriov.c @@ -109,6 +109,9 @@ static int nitrox_pf_reinit(struct nitrox_device *ndev) return err; } + /* configure the AQM queues */ + nitrox_config_aqm_rings(ndev); + /* configure the packet queues */ nitrox_config_pkt_input_rings(ndev); nitrox_config_pkt_solicit_ports(ndev); diff --git a/drivers/crypto/cavium/zip/zip_main.c b/drivers/crypto/cavium/zip/zip_main.c index a8447a3cf3665b586cfd0c92a3cd6b083781a277..194624b4855bd24ff4c0a445e7ebe6fe038ebb9c 100644 --- a/drivers/crypto/cavium/zip/zip_main.c +++ b/drivers/crypto/cavium/zip/zip_main.c @@ -593,6 +593,7 @@ static const struct file_operations zip_stats_fops = { .owner = THIS_MODULE, .open = zip_stats_open, .read = seq_read, + .release = single_release, }; static int zip_clear_open(struct inode *inode, struct file *file) @@ -604,6 +605,7 @@ static const struct file_operations zip_clear_fops = { .owner = THIS_MODULE, .open = zip_clear_open, .read = seq_read, + .release = single_release, }; static int zip_regs_open(struct inode *inode, struct file *file) @@ -615,6 +617,7 @@ static const struct file_operations zip_regs_fops = { .owner = THIS_MODULE, .open = zip_regs_open, .read = seq_read, + .release = single_release, }; /* Root directory for thunderx_zip debugfs entry */ diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig index 48f3edc1e3fb2fd170b4a18489c47e8ba3d6b8ed..8fec733f567f5ced722524dddd225b269b491d33 100644 --- a/drivers/crypto/ccp/Kconfig +++ b/drivers/crypto/ccp/Kconfig @@ -30,6 +30,7 @@ config CRYPTO_DEV_CCP_CRYPTO select CRYPTO_BLKCIPHER select CRYPTO_AUTHENC select CRYPTO_RSA + select CRYPTO_LIB_AES help Support for using the cryptographic API with the AMD Cryptographic Coprocessor. This module supports offload of SHA and AES algorithms. @@ -45,3 +46,11 @@ config CRYPTO_DEV_SP_PSP management commands in Secure Encrypted Virtualization (SEV) mode, along with software-based Trusted Execution Environment (TEE) to enable third-party trusted applications. + +config CRYPTO_DEV_CCP_DEBUGFS + bool "Enable CCP Internals in DebugFS" + default n + depends on CRYPTO_DEV_SP_CCP + help + Expose CCP device information such as operation statistics, feature + information, and descriptor queue contents. diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile index 51d1c0cf66c737a046a5ac9b7fc6f7b57548985c..6b86f1e6d634a9d46940998e4a5c7cea45506485 100644 --- a/drivers/crypto/ccp/Makefile +++ b/drivers/crypto/ccp/Makefile @@ -5,8 +5,8 @@ ccp-$(CONFIG_CRYPTO_DEV_SP_CCP) += ccp-dev.o \ ccp-ops.o \ ccp-dev-v3.o \ ccp-dev-v5.o \ - ccp-dmaengine.o \ - ccp-debugfs.o + ccp-dmaengine.o +ccp-$(CONFIG_CRYPTO_DEV_CCP_DEBUGFS) += ccp-debugfs.o ccp-$(CONFIG_PCI) += sp-pci.o ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += psp-dev.o diff --git a/drivers/crypto/ccp/ccp-crypto-aes-cmac.c b/drivers/crypto/ccp/ccp-crypto-aes-cmac.c index bb7219d36b2ca929b53c5edc2ab5c99b1330be92..32f19f402073728104d7c82ac78a765be8d95b73 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes-cmac.c +++ b/drivers/crypto/ccp/ccp-crypto-aes-cmac.c @@ -261,6 +261,7 @@ static int ccp_aes_cmac_setkey(struct crypto_ahash *tfm, const u8 *key, ccp_crypto_ahash_alg(crypto_ahash_tfm(tfm)); u64 k0_hi, k0_lo, k1_hi, k1_lo, k2_hi, k2_lo; u64 rb_hi = 0x00, rb_lo = 0x87; + struct crypto_aes_ctx aes; __be64 *gk; int ret; @@ -284,14 +285,14 @@ static int ccp_aes_cmac_setkey(struct crypto_ahash *tfm, const u8 *key, ctx->u.aes.key_len = 0; /* Set the key for the AES cipher used to generate the keys */ - ret = crypto_cipher_setkey(ctx->u.aes.tfm_cipher, key, key_len); + ret = aes_expandkey(&aes, key, key_len); if (ret) return ret; /* Encrypt a block of zeroes - use key area in context */ memset(ctx->u.aes.key, 0, sizeof(ctx->u.aes.key)); - crypto_cipher_encrypt_one(ctx->u.aes.tfm_cipher, ctx->u.aes.key, - ctx->u.aes.key); + aes_encrypt(&aes, ctx->u.aes.key, ctx->u.aes.key); + memzero_explicit(&aes, sizeof(aes)); /* Generate K1 and K2 */ k0_hi = be64_to_cpu(*((__be64 *)ctx->u.aes.key)); @@ -336,32 +337,15 @@ static int ccp_aes_cmac_cra_init(struct crypto_tfm *tfm) { struct ccp_ctx *ctx = crypto_tfm_ctx(tfm); struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); - struct crypto_cipher *cipher_tfm; ctx->complete = ccp_aes_cmac_complete; ctx->u.aes.key_len = 0; crypto_ahash_set_reqsize(ahash, sizeof(struct ccp_aes_cmac_req_ctx)); - cipher_tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_NEED_FALLBACK); - if (IS_ERR(cipher_tfm)) { - pr_warn("could not load aes cipher driver\n"); - return PTR_ERR(cipher_tfm); - } - ctx->u.aes.tfm_cipher = cipher_tfm; - return 0; } -static void ccp_aes_cmac_cra_exit(struct crypto_tfm *tfm) -{ - struct ccp_ctx *ctx = crypto_tfm_ctx(tfm); - - if (ctx->u.aes.tfm_cipher) - crypto_free_cipher(ctx->u.aes.tfm_cipher); - ctx->u.aes.tfm_cipher = NULL; -} - int ccp_register_aes_cmac_algs(struct list_head *head) { struct ccp_crypto_ahash_alg *ccp_alg; @@ -401,7 +385,6 @@ int ccp_register_aes_cmac_algs(struct list_head *head) base->cra_ctxsize = sizeof(struct ccp_ctx); base->cra_priority = CCP_CRA_PRIORITY; base->cra_init = ccp_aes_cmac_cra_init; - base->cra_exit = ccp_aes_cmac_cra_exit; base->cra_module = THIS_MODULE; ret = crypto_register_ahash(alg); diff --git a/drivers/crypto/ccp/ccp-crypto-aes-xts.c b/drivers/crypto/ccp/ccp-crypto-aes-xts.c index 783ba75e06187273aaaa02f0c068f9841662fc0a..8e4a531f4f707896657d67b3bb10b1a5c8b8cd0f 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes-xts.c +++ b/drivers/crypto/ccp/ccp-crypto-aes-xts.c @@ -116,9 +116,6 @@ static int ccp_aes_xts_crypt(struct ablkcipher_request *req, if (!ctx->u.aes.key_len) return -EINVAL; - if (req->nbytes & (AES_BLOCK_SIZE - 1)) - return -EINVAL; - if (!req->info) return -EINVAL; diff --git a/drivers/crypto/ccp/ccp-crypto-des3.c b/drivers/crypto/ccp/ccp-crypto-des3.c index 5f05f834c7cd3b86bfaf524abf73c0202f6d60d4..d2c49b2f03232755d1556cfdb127e4cc0c554d16 100644 --- a/drivers/crypto/ccp/ccp-crypto-des3.c +++ b/drivers/crypto/ccp/ccp-crypto-des3.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include "ccp-crypto.h" @@ -39,11 +39,10 @@ static int ccp_des3_setkey(struct crypto_ablkcipher *tfm, const u8 *key, struct ccp_ctx *ctx = crypto_tfm_ctx(crypto_ablkcipher_tfm(tfm)); struct ccp_crypto_ablkcipher_alg *alg = ccp_crypto_ablkcipher_alg(crypto_ablkcipher_tfm(tfm)); - u32 *flags = &tfm->base.crt_flags; int err; - err = __des3_verify_key(flags, key); - if (unlikely(err)) + err = verify_ablkcipher_des3_key(tfm, key); + if (err) return err; /* It's not clear that there is any support for a keysize of 112. diff --git a/drivers/crypto/ccp/ccp-crypto-main.c b/drivers/crypto/ccp/ccp-crypto-main.c index 8180964908298774c2fff6b021d9bd3fe68aa88b..8ee4cb45a3f381444bf55e046f26868792b51e5b 100644 --- a/drivers/crypto/ccp/ccp-crypto-main.c +++ b/drivers/crypto/ccp/ccp-crypto-main.c @@ -405,8 +405,10 @@ static int ccp_crypto_init(void) int ret; ret = ccp_present(); - if (ret) + if (ret) { + pr_err("Cannot load: there are no available CCPs\n"); return ret; + } spin_lock_init(&req_queue_lock); INIT_LIST_HEAD(&req_queue.cmds); diff --git a/drivers/crypto/ccp/ccp-crypto.h b/drivers/crypto/ccp/ccp-crypto.h index 622b34c176431d61aa938522b1c5e545fa60b757..9015b5da6ba386c90401d35e3e3d79e17a6a07ed 100644 --- a/drivers/crypto/ccp/ccp-crypto.h +++ b/drivers/crypto/ccp/ccp-crypto.h @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -24,6 +23,10 @@ #include #include +/* We want the module name in front of our messages */ +#undef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define CCP_LOG_LEVEL KERN_INFO #define CCP_CRA_PRIORITY 300 @@ -87,9 +90,6 @@ struct ccp_aes_ctx { /* Fallback cipher for XTS with unsupported unit sizes */ struct crypto_sync_skcipher *tfm_skcipher; - /* Cipher used to generate CMAC K1/K2 keys */ - struct crypto_cipher *tfm_cipher; - enum ccp_engine engine; enum ccp_aes_type type; enum ccp_aes_mode mode; diff --git a/drivers/crypto/ccp/ccp-dev-v3.c b/drivers/crypto/ccp/ccp-dev-v3.c index 2b7d47ed5c74638900e2b39115734f978036bd17..0186b3df4c87770d018c2392cb6f427e98266c24 100644 --- a/drivers/crypto/ccp/ccp-dev-v3.c +++ b/drivers/crypto/ccp/ccp-dev-v3.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include @@ -379,7 +378,7 @@ static int ccp_init(struct ccp_device *ccp) /* Find available queues */ ccp->qim = 0; qmr = ioread32(ccp->io_regs + Q_MASK_REG); - for (i = 0; i < MAX_HW_QUEUES; i++) { + for (i = 0; (i < MAX_HW_QUEUES) && (ccp->cmd_q_count < ccp->max_q_count); i++) { if (!(qmr & (1 << i))) continue; diff --git a/drivers/crypto/ccp/ccp-dev-v5.c b/drivers/crypto/ccp/ccp-dev-v5.c index 217e41bbadaf3feb152b8d0f407f40e88884a475..57eb53b8ac21730abe9622d4913af07e53f5d80a 100644 --- a/drivers/crypto/ccp/ccp-dev-v5.c +++ b/drivers/crypto/ccp/ccp-dev-v5.c @@ -2,16 +2,13 @@ /* * AMD Cryptographic Coprocessor (CCP) driver * - * Copyright (C) 2016,2017 Advanced Micro Devices, Inc. + * Copyright (C) 2016,2019 Advanced Micro Devices, Inc. * * Author: Gary R Hook */ -#include #include -#include #include -#include #include #include #include @@ -792,8 +789,7 @@ static int ccp5_init(struct ccp_device *ccp) /* Find available queues */ qmr = ioread32(ccp->io_regs + Q_MASK_REG); - for (i = 0; i < MAX_HW_QUEUES; i++) { - + for (i = 0; (i < MAX_HW_QUEUES) && (ccp->cmd_q_count < ccp->max_q_count); i++) { if (!(qmr & (1 << i))) continue; @@ -806,6 +802,7 @@ static int ccp5_init(struct ccp_device *ccp) if (!dma_pool) { dev_err(dev, "unable to allocate dma pool\n"); ret = -ENOMEM; + goto e_pool; } cmd_q = &ccp->cmd_q[ccp->cmd_q_count]; @@ -819,9 +816,9 @@ static int ccp5_init(struct ccp_device *ccp) /* Page alignment satisfies our needs for N <= 128 */ BUILD_BUG_ON(COMMANDS_PER_QUEUE > 128); cmd_q->qsize = Q_SIZE(Q_DESC_SIZE); - cmd_q->qbase = dma_alloc_coherent(dev, cmd_q->qsize, - &cmd_q->qbase_dma, - GFP_KERNEL); + cmd_q->qbase = dmam_alloc_coherent(dev, cmd_q->qsize, + &cmd_q->qbase_dma, + GFP_KERNEL); if (!cmd_q->qbase) { dev_err(dev, "unable to allocate command queue\n"); ret = -ENOMEM; @@ -970,8 +967,10 @@ static int ccp5_init(struct ccp_device *ccp) if (ret) goto e_hwrng; +#ifdef CONFIG_CRYPTO_DEV_CCP_DEBUGFS /* Set up debugfs entries */ ccp5_debugfs_setup(ccp); +#endif return 0; @@ -995,7 +994,6 @@ static int ccp5_init(struct ccp_device *ccp) static void ccp5_destroy(struct ccp_device *ccp) { - struct device *dev = ccp->dev; struct ccp_cmd_queue *cmd_q; struct ccp_cmd *cmd; unsigned int i; @@ -1009,11 +1007,13 @@ static void ccp5_destroy(struct ccp_device *ccp) /* Remove this device from the list of available units first */ ccp_del_device(ccp); +#ifdef CONFIG_CRYPTO_DEV_CCP_DEBUGFS /* We're in the process of tearing down the entire driver; * when all the devices are gone clean up debugfs */ if (ccp_present()) ccp5_debugfs_destroy(); +#endif /* Disable and clear interrupts */ ccp5_disable_queue_interrupts(ccp); @@ -1036,12 +1036,6 @@ static void ccp5_destroy(struct ccp_device *ccp) sp_free_ccp_irq(ccp->sp, ccp); - for (i = 0; i < ccp->cmd_q_count; i++) { - cmd_q = &ccp->cmd_q[i]; - dma_free_coherent(dev, cmd_q->qsize, cmd_q->qbase, - cmd_q->qbase_dma); - } - /* Flush the cmd and backlog queue */ while (!list_empty(&ccp->cmd)) { /* Invoke the callback directly with an error code */ diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c index edefa669153f49c4df1591431c24d4180d3f4b7c..73acf0fdb7932b3929f6aaffa2e19c60db1273d4 100644 --- a/drivers/crypto/ccp/ccp-dev.c +++ b/drivers/crypto/ccp/ccp-dev.c @@ -2,12 +2,13 @@ /* * AMD Cryptographic Coprocessor (CCP) driver * - * Copyright (C) 2013,2017 Advanced Micro Devices, Inc. + * Copyright (C) 2013,2019 Advanced Micro Devices, Inc. * * Author: Tom Lendacky * Author: Gary R Hook */ +#include #include #include #include @@ -19,6 +20,7 @@ #include #include #include +#include #ifdef CONFIG_X86 #include #endif @@ -26,6 +28,19 @@ #include "ccp-dev.h" +#define MAX_CCPS 32 + +/* Limit CCP use to a specifed number of queues per device */ +static unsigned int nqueues = 0; +module_param(nqueues, uint, 0444); +MODULE_PARM_DESC(nqueues, "Number of queues per CCP (minimum 1; default: all available)"); + +/* Limit the maximum number of configured CCPs */ +static atomic_t dev_count = ATOMIC_INIT(0); +static unsigned int max_devs = MAX_CCPS; +module_param(max_devs, uint, 0444); +MODULE_PARM_DESC(max_devs, "Maximum number of CCPs to enable (default: all; 0 disables all CCPs)"); + struct ccp_tasklet_data { struct completion completion; struct ccp_cmd *cmd; @@ -594,12 +609,24 @@ int ccp_dev_init(struct sp_device *sp) struct ccp_device *ccp; int ret; + /* + * Check how many we have so far, and stop after reaching + * that number + */ + if (atomic_inc_return(&dev_count) > max_devs) + return 0; /* don't fail the load */ + ret = -ENOMEM; ccp = ccp_alloc_struct(sp); if (!ccp) goto e_err; sp->ccp_data = ccp; + if (!nqueues || (nqueues > MAX_HW_QUEUES)) + ccp->max_q_count = MAX_HW_QUEUES; + else + ccp->max_q_count = nqueues; + ccp->vdata = (struct ccp_vdata *)sp->dev_vdata->ccp_vdata; if (!ccp->vdata || !ccp->vdata->version) { ret = -ENODEV; diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h index 5e624920fd99e207f1f4174dab510a9426a3eb13..3f68262d9ab4a21643acb0d304494dab4be3f1e8 100644 --- a/drivers/crypto/ccp/ccp-dev.h +++ b/drivers/crypto/ccp/ccp-dev.h @@ -12,11 +12,11 @@ #define __CCP_DEV_H__ #include -#include #include #include #include #include +#include #include #include #include @@ -379,6 +379,7 @@ struct ccp_device { */ struct ccp_cmd_queue cmd_q[MAX_HW_QUEUES]; unsigned int cmd_q_count; + unsigned int max_q_count; /* Support for the CCP True RNG */ diff --git a/drivers/crypto/ccp/ccp-dmaengine.c b/drivers/crypto/ccp/ccp-dmaengine.c index 7f22a45bbc1129688c818f93eb5de92d5ac23e29..a54f9367a58084eddc486e31f751a99334a7bb01 100644 --- a/drivers/crypto/ccp/ccp-dmaengine.c +++ b/drivers/crypto/ccp/ccp-dmaengine.c @@ -2,13 +2,14 @@ /* * AMD Cryptographic Coprocessor (CCP) driver * - * Copyright (C) 2016,2017 Advanced Micro Devices, Inc. + * Copyright (C) 2016,2019 Advanced Micro Devices, Inc. * * Author: Gary R Hook */ #include #include +#include #include #include #include @@ -35,6 +36,10 @@ static unsigned int dma_chan_attr = CCP_DMA_DFLT; module_param(dma_chan_attr, uint, 0444); MODULE_PARM_DESC(dma_chan_attr, "Set DMA channel visibility: 0 (default) = device defaults, 1 = make private, 2 = make public"); +static unsigned int dmaengine = 1; +module_param(dmaengine, uint, 0444); +MODULE_PARM_DESC(dmaengine, "Register services with the DMA subsystem (any non-zero value, default: 1)"); + static unsigned int ccp_get_dma_chan_attr(struct ccp_device *ccp) { switch (dma_chan_attr) { @@ -637,6 +642,9 @@ int ccp_dmaengine_register(struct ccp_device *ccp) unsigned int i; int ret; + if (!dmaengine) + return 0; + ccp->ccp_dma_chan = devm_kcalloc(ccp->dev, ccp->cmd_q_count, sizeof(*(ccp->ccp_dma_chan)), GFP_KERNEL); @@ -740,6 +748,9 @@ void ccp_dmaengine_unregister(struct ccp_device *ccp) { struct dma_device *dma_dev = &ccp->dma_dev; + if (!dmaengine) + return; + dma_async_device_unregister(dma_dev); kmem_cache_destroy(ccp->dma_desc_cache); diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c index 9bc3c62157d7dc500b3b00c3d4d74bd37d5fd531..c8da8eb160da08e41f98fd3ac02d9535eb94c5d2 100644 --- a/drivers/crypto/ccp/ccp-ops.c +++ b/drivers/crypto/ccp/ccp-ops.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include @@ -150,14 +149,13 @@ static int ccp_init_dm_workarea(struct ccp_dm_workarea *wa, if (len <= CCP_DMAPOOL_MAX_SIZE) { wa->dma_pool = cmd_q->dma_pool; - wa->address = dma_pool_alloc(wa->dma_pool, GFP_KERNEL, + wa->address = dma_pool_zalloc(wa->dma_pool, GFP_KERNEL, &wa->dma.address); if (!wa->address) return -ENOMEM; wa->dma.length = CCP_DMAPOOL_MAX_SIZE; - memset(wa->address, 0, CCP_DMAPOOL_MAX_SIZE); } else { wa->address = kzalloc(len, GFP_KERNEL); if (!wa->address) @@ -455,8 +453,8 @@ static int ccp_copy_from_sb(struct ccp_cmd_queue *cmd_q, return ccp_copy_to_from_sb(cmd_q, wa, jobid, sb, byte_swap, true); } -static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q, - struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_aes_engine *aes = &cmd->u.aes; struct ccp_dm_workarea key, ctx; @@ -611,8 +609,8 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q, return ret; } -static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, - struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_aes_engine *aes = &cmd->u.aes; struct ccp_dm_workarea key, ctx, final_wa, tag; @@ -894,7 +892,8 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, return ret; } -static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_aes_engine *aes = &cmd->u.aes; struct ccp_dm_workarea key, ctx; @@ -904,12 +903,6 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) bool in_place = false; int ret; - if (aes->mode == CCP_AES_MODE_CMAC) - return ccp_run_aes_cmac_cmd(cmd_q, cmd); - - if (aes->mode == CCP_AES_MODE_GCM) - return ccp_run_aes_gcm_cmd(cmd_q, cmd); - if (!((aes->key_len == AES_KEYSIZE_128) || (aes->key_len == AES_KEYSIZE_192) || (aes->key_len == AES_KEYSIZE_256))) @@ -1076,8 +1069,8 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) return ret; } -static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, - struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_xts_aes_engine *xts = &cmd->u.xts; struct ccp_dm_workarea key, ctx; @@ -1276,7 +1269,8 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, return ret; } -static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_des3_engine *des3 = &cmd->u.des3; @@ -1472,7 +1466,8 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) return ret; } -static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_sha_engine *sha = &cmd->u.sha; struct ccp_dm_workarea ctx; @@ -1816,7 +1811,8 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) return ret; } -static int ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_rsa_engine *rsa = &cmd->u.rsa; struct ccp_dm_workarea exp, src, dst; @@ -1947,8 +1943,8 @@ static int ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) return ret; } -static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q, - struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_passthru_engine *pt = &cmd->u.passthru; struct ccp_dm_workarea mask; @@ -2079,7 +2075,8 @@ static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q, return ret; } -static int ccp_run_passthru_nomap_cmd(struct ccp_cmd_queue *cmd_q, +static noinline_for_stack int +ccp_run_passthru_nomap_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_passthru_nomap_engine *pt = &cmd->u.passthru_nomap; @@ -2420,7 +2417,8 @@ static int ccp_run_ecc_pm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) return ret; } -static int ccp_run_ecc_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_ecc_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_ecc_engine *ecc = &cmd->u.ecc; @@ -2457,7 +2455,17 @@ int ccp_run_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) switch (cmd->engine) { case CCP_ENGINE_AES: - ret = ccp_run_aes_cmd(cmd_q, cmd); + switch (cmd->u.aes.mode) { + case CCP_AES_MODE_CMAC: + ret = ccp_run_aes_cmac_cmd(cmd_q, cmd); + break; + case CCP_AES_MODE_GCM: + ret = ccp_run_aes_gcm_cmd(cmd_q, cmd); + break; + default: + ret = ccp_run_aes_cmd(cmd_q, cmd); + break; + } break; case CCP_ENGINE_XTS_AES_128: ret = ccp_run_xts_aes_cmd(cmd_q, cmd); diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h index c5e06c92d40e9eb1c89796ede42ed036b7a5ac5c..82a084f0299011cd9a59722b362d225db490c077 100644 --- a/drivers/crypto/ccp/psp-dev.h +++ b/drivers/crypto/ccp/psp-dev.h @@ -11,7 +11,6 @@ #define __PSP_DEV_H__ #include -#include #include #include #include diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h index 8abe9ea7e76f759d975ba1cb9770f3e9b0ec7b97..53c12562d31e9bef3a0700de9c44035a104b4ddf 100644 --- a/drivers/crypto/ccp/sp-dev.h +++ b/drivers/crypto/ccp/sp-dev.h @@ -13,7 +13,6 @@ #define __SP_DEV_H__ #include -#include #include #include #include diff --git a/drivers/crypto/ccp/sp-platform.c b/drivers/crypto/ccp/sp-platform.c index 1b45236e371617f770e1663995ad96248978f389..831aac1393a2f048a82cde6354603766699107e9 100644 --- a/drivers/crypto/ccp/sp-platform.c +++ b/drivers/crypto/ccp/sp-platform.c @@ -125,7 +125,6 @@ static int sp_platform_probe(struct platform_device *pdev) struct sp_platform *sp_platform; struct device *dev = &pdev->dev; enum dev_dma_attr attr; - struct resource *ior; int ret; ret = -ENOMEM; @@ -146,8 +145,7 @@ static int sp_platform_probe(struct platform_device *pdev) goto e_err; } - ior = platform_get_resource(pdev, IORESOURCE_MEM, 0); - sp->io_map = devm_ioremap_resource(dev, ior); + sp->io_map = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(sp->io_map)) { ret = PTR_ERR(sp->io_map); goto e_err; diff --git a/drivers/crypto/ccree/Makefile b/drivers/crypto/ccree/Makefile index 145e50bdbf16c2d8526df204e1b90570c9861094..5cfda508ee41b6238d07cfa193bfe9ae46d911e3 100644 --- a/drivers/crypto/ccree/Makefile +++ b/drivers/crypto/ccree/Makefile @@ -2,7 +2,7 @@ # Copyright (C) 2012-2019 ARM Limited (or its affiliates). obj-$(CONFIG_CRYPTO_DEV_CCREE) := ccree.o -ccree-y := cc_driver.o cc_buffer_mgr.o cc_request_mgr.o cc_cipher.o cc_hash.o cc_aead.o cc_ivgen.o cc_sram_mgr.o +ccree-y := cc_driver.o cc_buffer_mgr.o cc_request_mgr.o cc_cipher.o cc_hash.o cc_aead.o cc_sram_mgr.o ccree-$(CONFIG_CRYPTO_FIPS) += cc_fips.o ccree-$(CONFIG_DEBUG_FS) += cc_debugfs.o ccree-$(CONFIG_PM) += cc_pm.o diff --git a/drivers/crypto/ccree/cc_aead.c b/drivers/crypto/ccree/cc_aead.c index 7aa4cbe19a86f523ca390d0943b75a8c27e36876..d3e8faa03f1560c8561f2e39a93a393b25b3241c 100644 --- a/drivers/crypto/ccree/cc_aead.c +++ b/drivers/crypto/ccree/cc_aead.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include "cc_driver.h" #include "cc_buffer_mgr.h" @@ -236,31 +236,17 @@ static void cc_aead_complete(struct device *dev, void *cc_req, int err) /* In case of payload authentication failure, MUST NOT * revealed the decrypted message --> zero its memory. */ - cc_zero_sgl(areq->dst, areq_ctx->cryptlen); + sg_zero_buffer(areq->dst, sg_nents(areq->dst), + areq->cryptlen, 0); err = -EBADMSG; } - } else { /*ENCRYPT*/ - if (areq_ctx->is_icv_fragmented) { - u32 skip = areq->cryptlen + areq_ctx->dst_offset; - - cc_copy_sg_portion(dev, areq_ctx->mac_buf, - areq_ctx->dst_sgl, skip, - (skip + ctx->authsize), - CC_SG_FROM_BUF); - } + /*ENCRYPT*/ + } else if (areq_ctx->is_icv_fragmented) { + u32 skip = areq->cryptlen + areq_ctx->dst_offset; - /* If an IV was generated, copy it back to the user provided - * buffer. - */ - if (areq_ctx->backup_giv) { - if (ctx->cipher_mode == DRV_CIPHER_CTR) - memcpy(areq_ctx->backup_giv, areq_ctx->ctr_iv + - CTR_RFC3686_NONCE_SIZE, - CTR_RFC3686_IV_SIZE); - else if (ctx->cipher_mode == DRV_CIPHER_CCM) - memcpy(areq_ctx->backup_giv, areq_ctx->ctr_iv + - CCM_BLOCK_IV_OFFSET, CCM_BLOCK_IV_SIZE); - } + cc_copy_sg_portion(dev, areq_ctx->mac_buf, areq_ctx->dst_sgl, + skip, (skip + ctx->authsize), + CC_SG_FROM_BUF); } done: aead_request_complete(areq, err); @@ -663,33 +649,17 @@ static int cc_des3_aead_setkey(struct crypto_aead *aead, const u8 *key, unsigned int keylen) { struct crypto_authenc_keys keys; - u32 flags; int err; err = crypto_authenc_extractkeys(&keys, key, keylen); if (unlikely(err)) - goto badkey; - - err = -EINVAL; - if (keys.enckeylen != DES3_EDE_KEY_SIZE) - goto badkey; + return err; - flags = crypto_aead_get_flags(aead); - err = __des3_verify_key(&flags, keys.enckey); - if (unlikely(err)) { - crypto_aead_set_flags(aead, flags); - goto out; - } - - err = cc_aead_setkey(aead, key, keylen); + err = verify_aead_des3_key(aead, keys.enckey, keys.enckeylen) ?: + cc_aead_setkey(aead, key, keylen); -out: memzero_explicit(&keys, sizeof(keys)); return err; - -badkey: - crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); - goto out; } static int cc_rfc4309_ccm_setkey(struct crypto_aead *tfm, const u8 *key, @@ -1975,9 +1945,8 @@ static int cc_proc_aead(struct aead_request *req, */ memcpy(areq_ctx->ctr_iv, ctx->ctr_nonce, CTR_RFC3686_NONCE_SIZE); - if (!areq_ctx->backup_giv) /*User none-generated IV*/ - memcpy(areq_ctx->ctr_iv + CTR_RFC3686_NONCE_SIZE, - req->iv, CTR_RFC3686_IV_SIZE); + memcpy(areq_ctx->ctr_iv + CTR_RFC3686_NONCE_SIZE, req->iv, + CTR_RFC3686_IV_SIZE); /* Initialize counter portion of counter block */ *(__be32 *)(areq_ctx->ctr_iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) = cpu_to_be32(1); @@ -2023,40 +1992,6 @@ static int cc_proc_aead(struct aead_request *req, goto exit; } - /* do we need to generate IV? */ - if (areq_ctx->backup_giv) { - /* set the DMA mapped IV address*/ - if (ctx->cipher_mode == DRV_CIPHER_CTR) { - cc_req.ivgen_dma_addr[0] = - areq_ctx->gen_ctx.iv_dma_addr + - CTR_RFC3686_NONCE_SIZE; - cc_req.ivgen_dma_addr_len = 1; - } else if (ctx->cipher_mode == DRV_CIPHER_CCM) { - /* In ccm, the IV needs to exist both inside B0 and - * inside the counter.It is also copied to iv_dma_addr - * for other reasons (like returning it to the user). - * So, using 3 (identical) IV outputs. - */ - cc_req.ivgen_dma_addr[0] = - areq_ctx->gen_ctx.iv_dma_addr + - CCM_BLOCK_IV_OFFSET; - cc_req.ivgen_dma_addr[1] = - sg_dma_address(&areq_ctx->ccm_adata_sg) + - CCM_B0_OFFSET + CCM_BLOCK_IV_OFFSET; - cc_req.ivgen_dma_addr[2] = - sg_dma_address(&areq_ctx->ccm_adata_sg) + - CCM_CTR_COUNT_0_OFFSET + CCM_BLOCK_IV_OFFSET; - cc_req.ivgen_dma_addr_len = 3; - } else { - cc_req.ivgen_dma_addr[0] = - areq_ctx->gen_ctx.iv_dma_addr; - cc_req.ivgen_dma_addr_len = 1; - } - - /* set the IV size (8/16 B long)*/ - cc_req.ivgen_size = crypto_aead_ivsize(tfm); - } - /* STAT_PHASE_2: Create sequence */ /* Load MLLI tables to SRAM if necessary */ @@ -2107,7 +2042,6 @@ static int cc_aead_encrypt(struct aead_request *req) /* No generated IV required */ areq_ctx->backup_iv = req->iv; areq_ctx->assoclen = req->assoclen; - areq_ctx->backup_giv = NULL; areq_ctx->is_gcm4543 = false; areq_ctx->plaintext_authenticate_only = false; @@ -2139,7 +2073,6 @@ static int cc_rfc4309_ccm_encrypt(struct aead_request *req) /* No generated IV required */ areq_ctx->backup_iv = req->iv; areq_ctx->assoclen = req->assoclen; - areq_ctx->backup_giv = NULL; areq_ctx->is_gcm4543 = true; cc_proc_rfc4309_ccm(req); @@ -2161,7 +2094,6 @@ static int cc_aead_decrypt(struct aead_request *req) /* No generated IV required */ areq_ctx->backup_iv = req->iv; areq_ctx->assoclen = req->assoclen; - areq_ctx->backup_giv = NULL; areq_ctx->is_gcm4543 = false; areq_ctx->plaintext_authenticate_only = false; @@ -2191,7 +2123,6 @@ static int cc_rfc4309_ccm_decrypt(struct aead_request *req) /* No generated IV required */ areq_ctx->backup_iv = req->iv; areq_ctx->assoclen = req->assoclen; - areq_ctx->backup_giv = NULL; areq_ctx->is_gcm4543 = true; cc_proc_rfc4309_ccm(req); @@ -2311,8 +2242,6 @@ static int cc_rfc4106_gcm_encrypt(struct aead_request *req) /* No generated IV required */ areq_ctx->backup_iv = req->iv; areq_ctx->assoclen = req->assoclen; - areq_ctx->backup_giv = NULL; - areq_ctx->plaintext_authenticate_only = false; cc_proc_rfc4_gcm(req); @@ -2328,9 +2257,16 @@ static int cc_rfc4106_gcm_encrypt(struct aead_request *req) static int cc_rfc4543_gcm_encrypt(struct aead_request *req) { /* Very similar to cc_aead_encrypt() above. */ - + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); + struct device *dev = drvdata_to_dev(ctx->drvdata); struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - int rc; + int rc = -EINVAL; + + if (!valid_assoclen(req)) { + dev_err(dev, "invalid Assoclen:%u\n", req->assoclen); + goto out; + } memset(areq_ctx, 0, sizeof(*areq_ctx)); @@ -2340,7 +2276,6 @@ static int cc_rfc4543_gcm_encrypt(struct aead_request *req) /* No generated IV required */ areq_ctx->backup_iv = req->iv; areq_ctx->assoclen = req->assoclen; - areq_ctx->backup_giv = NULL; cc_proc_rfc4_gcm(req); areq_ctx->is_gcm4543 = true; @@ -2348,7 +2283,7 @@ static int cc_rfc4543_gcm_encrypt(struct aead_request *req) rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_ENCRYPT); if (rc != -EINPROGRESS && rc != -EBUSY) req->iv = areq_ctx->backup_iv; - +out: return rc; } @@ -2372,8 +2307,6 @@ static int cc_rfc4106_gcm_decrypt(struct aead_request *req) /* No generated IV required */ areq_ctx->backup_iv = req->iv; areq_ctx->assoclen = req->assoclen; - areq_ctx->backup_giv = NULL; - areq_ctx->plaintext_authenticate_only = false; cc_proc_rfc4_gcm(req); @@ -2389,9 +2322,16 @@ static int cc_rfc4106_gcm_decrypt(struct aead_request *req) static int cc_rfc4543_gcm_decrypt(struct aead_request *req) { /* Very similar to cc_aead_decrypt() above. */ - + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); + struct device *dev = drvdata_to_dev(ctx->drvdata); struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - int rc; + int rc = -EINVAL; + + if (!valid_assoclen(req)) { + dev_err(dev, "invalid Assoclen:%u\n", req->assoclen); + goto out; + } memset(areq_ctx, 0, sizeof(*areq_ctx)); @@ -2401,7 +2341,6 @@ static int cc_rfc4543_gcm_decrypt(struct aead_request *req) /* No generated IV required */ areq_ctx->backup_iv = req->iv; areq_ctx->assoclen = req->assoclen; - areq_ctx->backup_giv = NULL; cc_proc_rfc4_gcm(req); areq_ctx->is_gcm4543 = true; @@ -2409,7 +2348,7 @@ static int cc_rfc4543_gcm_decrypt(struct aead_request *req) rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_DECRYPT); if (rc != -EINPROGRESS && rc != -EBUSY) req->iv = areq_ctx->backup_iv; - +out: return rc; } diff --git a/drivers/crypto/ccree/cc_aead.h b/drivers/crypto/ccree/cc_aead.h index e51724b96c564b3b2c8df103ae8f87519741a20b..f12169b57f9d9ada69e2bfb04f66f7f601888b65 100644 --- a/drivers/crypto/ccree/cc_aead.h +++ b/drivers/crypto/ccree/cc_aead.h @@ -65,8 +65,7 @@ struct aead_req_ctx { unsigned int hw_iv_size ____cacheline_aligned; /* used to prevent cache coherence problem */ u8 backup_mac[MAX_MAC_SIZE]; - u8 *backup_iv; /*store iv for generated IV flow*/ - u8 *backup_giv; /*store iv for rfc3686(ctr) flow*/ + u8 *backup_iv; /* store orig iv */ u32 assoclen; /* internal assoclen */ dma_addr_t mac_buf_dma_addr; /* internal ICV DMA buffer */ /* buffer for internal ccm configurations */ diff --git a/drivers/crypto/ccree/cc_buffer_mgr.c b/drivers/crypto/ccree/cc_buffer_mgr.c index c81ad33f91159c59b11ca9c33a482be60ea818e0..a72586eccd81816571ddf17c8b07748cc9e5c50b 100644 --- a/drivers/crypto/ccree/cc_buffer_mgr.c +++ b/drivers/crypto/ccree/cc_buffer_mgr.c @@ -99,27 +99,6 @@ static unsigned int cc_get_sgl_nents(struct device *dev, return nents; } -/** - * cc_zero_sgl() - Zero scatter scatter list data. - * - * @sgl: - */ -void cc_zero_sgl(struct scatterlist *sgl, u32 data_len) -{ - struct scatterlist *current_sg = sgl; - int sg_index = 0; - - while (sg_index <= data_len) { - if (!current_sg) { - /* reached the end of the sgl --> just return back */ - return; - } - memset(sg_virt(current_sg), 0, current_sg->length); - sg_index += current_sg->length; - current_sg = sg_next(current_sg); - } -} - /** * cc_copy_sg_portion() - Copy scatter list data, * from to_skip to end, to dest and vice versa diff --git a/drivers/crypto/ccree/cc_buffer_mgr.h b/drivers/crypto/ccree/cc_buffer_mgr.h index a726016bdbc19c9c89dd311a11ee0c4f68b14381..af434872c6ff7ec75a8e974ee657aaff8885b43f 100644 --- a/drivers/crypto/ccree/cc_buffer_mgr.h +++ b/drivers/crypto/ccree/cc_buffer_mgr.h @@ -66,6 +66,4 @@ void cc_unmap_hash_request(struct device *dev, void *ctx, void cc_copy_sg_portion(struct device *dev, u8 *dest, struct scatterlist *sg, u32 to_skip, u32 end, enum cc_sg_cpy_direct direct); -void cc_zero_sgl(struct scatterlist *sgl, u32 data_len); - #endif /*__BUFFER_MGR_H__*/ diff --git a/drivers/crypto/ccree/cc_cipher.c b/drivers/crypto/ccree/cc_cipher.c index 5b58226ea24df6b23f43c48a4611eb224d0419fb..254b48797799408b668832d4d8988d066fc42444 100644 --- a/drivers/crypto/ccree/cc_cipher.c +++ b/drivers/crypto/ccree/cc_cipher.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include @@ -116,10 +116,6 @@ static int validate_data_size(struct cc_cipher_ctx *ctx_p, case S_DIN_to_AES: switch (ctx_p->cipher_mode) { case DRV_CIPHER_XTS: - if (size >= AES_BLOCK_SIZE && - IS_ALIGNED(size, AES_BLOCK_SIZE)) - return 0; - break; case DRV_CIPHER_CBC_CTS: if (size >= AES_BLOCK_SIZE) return 0; @@ -411,16 +407,9 @@ static int cc_cipher_setkey(struct crypto_skcipher *sktfm, const u8 *key, * HW does the expansion on its own. */ if (ctx_p->flow_mode == S_DIN_to_DES) { - u32 tmp[DES3_EDE_EXPKEY_WORDS]; - if (keylen == DES3_EDE_KEY_SIZE && - __des3_ede_setkey(tmp, &tfm->crt_flags, key, - DES3_EDE_KEY_SIZE)) { - dev_dbg(dev, "weak 3DES key"); - return -EINVAL; - } else if (!des_ekey(tmp, key) && - (crypto_tfm_get_flags(tfm) & - CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) { - tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; + if ((keylen == DES3_EDE_KEY_SIZE && + verify_skcipher_des3_key(sktfm, key)) || + verify_skcipher_des_key(sktfm, key)) { dev_dbg(dev, "weak DES key"); return -EINVAL; } @@ -945,7 +934,7 @@ static const struct cc_alg_template skcipher_algs[] = { { .name = "xts(paes)", .driver_name = "xts-paes-ccree", - .blocksize = AES_BLOCK_SIZE, + .blocksize = 1, .template_skcipher = { .setkey = cc_cipher_sethkey, .encrypt = cc_cipher_encrypt, @@ -963,7 +952,7 @@ static const struct cc_alg_template skcipher_algs[] = { { .name = "xts512(paes)", .driver_name = "xts-paes-du512-ccree", - .blocksize = AES_BLOCK_SIZE, + .blocksize = 1, .template_skcipher = { .setkey = cc_cipher_sethkey, .encrypt = cc_cipher_encrypt, @@ -982,7 +971,7 @@ static const struct cc_alg_template skcipher_algs[] = { { .name = "xts4096(paes)", .driver_name = "xts-paes-du4096-ccree", - .blocksize = AES_BLOCK_SIZE, + .blocksize = 1, .template_skcipher = { .setkey = cc_cipher_sethkey, .encrypt = cc_cipher_encrypt, @@ -1203,7 +1192,7 @@ static const struct cc_alg_template skcipher_algs[] = { { .name = "xts(aes)", .driver_name = "xts-aes-ccree", - .blocksize = AES_BLOCK_SIZE, + .blocksize = 1, .template_skcipher = { .setkey = cc_cipher_setkey, .encrypt = cc_cipher_encrypt, @@ -1220,7 +1209,7 @@ static const struct cc_alg_template skcipher_algs[] = { { .name = "xts512(aes)", .driver_name = "xts-aes-du512-ccree", - .blocksize = AES_BLOCK_SIZE, + .blocksize = 1, .template_skcipher = { .setkey = cc_cipher_setkey, .encrypt = cc_cipher_encrypt, @@ -1238,7 +1227,7 @@ static const struct cc_alg_template skcipher_algs[] = { { .name = "xts4096(aes)", .driver_name = "xts-aes-du4096-ccree", - .blocksize = AES_BLOCK_SIZE, + .blocksize = 1, .template_skcipher = { .setkey = cc_cipher_setkey, .encrypt = cc_cipher_encrypt, diff --git a/drivers/crypto/ccree/cc_driver.c b/drivers/crypto/ccree/cc_driver.c index 980aa04b655b67f5b0eda536421c5298a32a5d1e..8b8eee513c279815223d05c731066476184653c8 100644 --- a/drivers/crypto/ccree/cc_driver.c +++ b/drivers/crypto/ccree/cc_driver.c @@ -22,7 +22,6 @@ #include "cc_cipher.h" #include "cc_aead.h" #include "cc_hash.h" -#include "cc_ivgen.h" #include "cc_sram_mgr.h" #include "cc_pm.h" #include "cc_fips.h" @@ -339,10 +338,8 @@ static int init_cc_resources(struct platform_device *plat_dev) /* Then IRQ */ new_drvdata->irq = platform_get_irq(plat_dev, 0); - if (new_drvdata->irq < 0) { - dev_err(dev, "Failed getting IRQ resource\n"); + if (new_drvdata->irq < 0) return new_drvdata->irq; - } init_completion(&new_drvdata->hw_queue_avail); @@ -421,7 +418,7 @@ static int init_cc_resources(struct platform_device *plat_dev) } break; default: - dev_err(dev, "Unsupported engines configration.\n"); + dev_err(dev, "Unsupported engines configuration.\n"); rc = -EINVAL; goto post_clk_err; } @@ -503,17 +500,11 @@ static int init_cc_resources(struct platform_device *plat_dev) goto post_buf_mgr_err; } - rc = cc_ivgen_init(new_drvdata); - if (rc) { - dev_err(dev, "cc_ivgen_init failed\n"); - goto post_buf_mgr_err; - } - /* Allocate crypto algs */ rc = cc_cipher_alloc(new_drvdata); if (rc) { dev_err(dev, "cc_cipher_alloc failed\n"); - goto post_ivgen_err; + goto post_buf_mgr_err; } /* hash must be allocated before aead since hash exports APIs */ @@ -544,8 +535,6 @@ static int init_cc_resources(struct platform_device *plat_dev) cc_hash_free(new_drvdata); post_cipher_err: cc_cipher_free(new_drvdata); -post_ivgen_err: - cc_ivgen_fini(new_drvdata); post_buf_mgr_err: cc_buffer_mgr_fini(new_drvdata); post_req_mgr_err: @@ -577,7 +566,6 @@ static void cleanup_cc_resources(struct platform_device *plat_dev) cc_aead_free(drvdata); cc_hash_free(drvdata); cc_cipher_free(drvdata); - cc_ivgen_fini(drvdata); cc_pm_fini(drvdata); cc_buffer_mgr_fini(drvdata); cc_req_mgr_fini(drvdata); diff --git a/drivers/crypto/ccree/cc_driver.h b/drivers/crypto/ccree/cc_driver.h index 7cd99380bf1ff9abe175f374f9ad77062cfc1f2b..ab31d4a68c808dc8eb2dba72b341811585250e15 100644 --- a/drivers/crypto/ccree/cc_driver.h +++ b/drivers/crypto/ccree/cc_driver.h @@ -126,15 +126,6 @@ struct cc_cpp_req { struct cc_crypto_req { void (*user_cb)(struct device *dev, void *req, int err); void *user_arg; - dma_addr_t ivgen_dma_addr[CC_MAX_IVGEN_DMA_ADDRESSES]; - /* For the first 'ivgen_dma_addr_len' addresses of this array, - * generated IV would be placed in it by send_request(). - * Same generated IV for all addresses! - */ - /* Amount of 'ivgen_dma_addr' elements to be filled. */ - unsigned int ivgen_dma_addr_len; - /* The generated IV size required, 8/16 B allowed. */ - unsigned int ivgen_size; struct completion seq_compl; /* request completion */ struct cc_cpp_req cpp; }; @@ -158,7 +149,6 @@ struct cc_drvdata { void *aead_handle; void *request_mgr_handle; void *fips_handle; - void *ivgen_handle; void *sram_mgr_handle; void *debugfs; struct clk *clk; diff --git a/drivers/crypto/ccree/cc_fips.c b/drivers/crypto/ccree/cc_fips.c index 5ad3ffb7acaa8973a9f9fcc09c87c6eb8878f339..4c8bce33abcfe7f49fb2cff9cfaac692ad3fc5f0 100644 --- a/drivers/crypto/ccree/cc_fips.c +++ b/drivers/crypto/ccree/cc_fips.c @@ -3,6 +3,7 @@ #include #include +#include #include "cc_driver.h" #include "cc_fips.h" @@ -11,6 +12,8 @@ static void fips_dsr(unsigned long devarg); struct cc_fips_handle { struct tasklet_struct tasklet; + struct notifier_block nb; + struct cc_drvdata *drvdata; }; /* The function called once at driver entry point to check @@ -21,7 +24,13 @@ static bool cc_get_tee_fips_status(struct cc_drvdata *drvdata) u32 reg; reg = cc_ioread(drvdata, CC_REG(GPR_HOST)); - return (reg == (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)); + /* Did the TEE report status? */ + if (reg & CC_FIPS_SYNC_TEE_STATUS) + /* Yes. Is it OK? */ + return (reg & CC_FIPS_SYNC_MODULE_OK); + + /* No. It's either not in use or will be reported later */ + return true; } /* @@ -40,6 +49,21 @@ void cc_set_ree_fips_status(struct cc_drvdata *drvdata, bool status) cc_iowrite(drvdata, CC_REG(HOST_GPR0), val); } +/* Push REE side FIPS test failure to TEE side */ +static int cc_ree_fips_failure(struct notifier_block *nb, unsigned long unused1, + void *unused2) +{ + struct cc_fips_handle *fips_h = + container_of(nb, struct cc_fips_handle, nb); + struct cc_drvdata *drvdata = fips_h->drvdata; + struct device *dev = drvdata_to_dev(drvdata); + + cc_set_ree_fips_status(drvdata, false); + dev_info(dev, "Notifying TEE of FIPS test failure...\n"); + + return NOTIFY_OK; +} + void cc_fips_fini(struct cc_drvdata *drvdata) { struct cc_fips_handle *fips_h = drvdata->fips_handle; @@ -47,6 +71,8 @@ void cc_fips_fini(struct cc_drvdata *drvdata) if (drvdata->hw_rev < CC_HW_REV_712 || !fips_h) return; + atomic_notifier_chain_unregister(&fips_fail_notif_chain, &fips_h->nb); + /* Kill tasklet */ tasklet_kill(&fips_h->tasklet); drvdata->fips_handle = NULL; @@ -118,6 +144,9 @@ int cc_fips_init(struct cc_drvdata *p_drvdata) dev_dbg(dev, "Initializing fips tasklet\n"); tasklet_init(&fips_h->tasklet, fips_dsr, (unsigned long)p_drvdata); + fips_h->drvdata = p_drvdata; + fips_h->nb.notifier_call = cc_ree_fips_failure; + atomic_notifier_chain_register(&fips_fail_notif_chain, &fips_h->nb); cc_tee_handle_fips_error(p_drvdata); diff --git a/drivers/crypto/ccree/cc_hash.c b/drivers/crypto/ccree/cc_hash.c index a6abe4e3bb0e78977fefe8664d64d25224a8f2fe..bc71bdf44a9ff195ee4d64b72e5fd8a1fff940e7 100644 --- a/drivers/crypto/ccree/cc_hash.c +++ b/drivers/crypto/ccree/cc_hash.c @@ -25,27 +25,27 @@ struct cc_hash_handle { struct list_head hash_list; }; -static const u32 digest_len_init[] = { +static const u32 cc_digest_len_init[] = { 0x00000040, 0x00000000, 0x00000000, 0x00000000 }; -static const u32 md5_init[] = { +static const u32 cc_md5_init[] = { SHA1_H3, SHA1_H2, SHA1_H1, SHA1_H0 }; -static const u32 sha1_init[] = { +static const u32 cc_sha1_init[] = { SHA1_H4, SHA1_H3, SHA1_H2, SHA1_H1, SHA1_H0 }; -static const u32 sha224_init[] = { +static const u32 cc_sha224_init[] = { SHA224_H7, SHA224_H6, SHA224_H5, SHA224_H4, SHA224_H3, SHA224_H2, SHA224_H1, SHA224_H0 }; -static const u32 sha256_init[] = { +static const u32 cc_sha256_init[] = { SHA256_H7, SHA256_H6, SHA256_H5, SHA256_H4, SHA256_H3, SHA256_H2, SHA256_H1, SHA256_H0 }; -static const u32 digest_len_sha512_init[] = { +static const u32 cc_digest_len_sha512_init[] = { 0x00000080, 0x00000000, 0x00000000, 0x00000000 }; -static u64 sha384_init[] = { +static u64 cc_sha384_init[] = { SHA384_H7, SHA384_H6, SHA384_H5, SHA384_H4, SHA384_H3, SHA384_H2, SHA384_H1, SHA384_H0 }; -static u64 sha512_init[] = { +static u64 cc_sha512_init[] = { SHA512_H7, SHA512_H6, SHA512_H5, SHA512_H4, SHA512_H3, SHA512_H2, SHA512_H1, SHA512_H0 }; -static const u32 sm3_init[] = { +static const u32 cc_sm3_init[] = { SM3_IVH, SM3_IVG, SM3_IVF, SM3_IVE, SM3_IVD, SM3_IVC, SM3_IVB, SM3_IVA }; @@ -144,10 +144,11 @@ static void cc_init_req(struct device *dev, struct ahash_req_ctx *state, if (ctx->hash_mode == DRV_HASH_SHA512 || ctx->hash_mode == DRV_HASH_SHA384) memcpy(state->digest_bytes_len, - digest_len_sha512_init, + cc_digest_len_sha512_init, ctx->hash_len); else - memcpy(state->digest_bytes_len, digest_len_init, + memcpy(state->digest_bytes_len, + cc_digest_len_init, ctx->hash_len); } @@ -1873,26 +1874,26 @@ int cc_init_hash_sram(struct cc_drvdata *drvdata) int rc = 0; /* Copy-to-sram digest-len */ - cc_set_sram_desc(digest_len_init, sram_buff_ofs, - ARRAY_SIZE(digest_len_init), larval_seq, + cc_set_sram_desc(cc_digest_len_init, sram_buff_ofs, + ARRAY_SIZE(cc_digest_len_init), larval_seq, &larval_seq_len); rc = send_request_init(drvdata, larval_seq, larval_seq_len); if (rc) goto init_digest_const_err; - sram_buff_ofs += sizeof(digest_len_init); + sram_buff_ofs += sizeof(cc_digest_len_init); larval_seq_len = 0; if (large_sha_supported) { /* Copy-to-sram digest-len for sha384/512 */ - cc_set_sram_desc(digest_len_sha512_init, sram_buff_ofs, - ARRAY_SIZE(digest_len_sha512_init), + cc_set_sram_desc(cc_digest_len_sha512_init, sram_buff_ofs, + ARRAY_SIZE(cc_digest_len_sha512_init), larval_seq, &larval_seq_len); rc = send_request_init(drvdata, larval_seq, larval_seq_len); if (rc) goto init_digest_const_err; - sram_buff_ofs += sizeof(digest_len_sha512_init); + sram_buff_ofs += sizeof(cc_digest_len_sha512_init); larval_seq_len = 0; } @@ -1900,64 +1901,64 @@ int cc_init_hash_sram(struct cc_drvdata *drvdata) hash_handle->larval_digest_sram_addr = sram_buff_ofs; /* Copy-to-sram initial SHA* digests */ - cc_set_sram_desc(md5_init, sram_buff_ofs, ARRAY_SIZE(md5_init), + cc_set_sram_desc(cc_md5_init, sram_buff_ofs, ARRAY_SIZE(cc_md5_init), larval_seq, &larval_seq_len); rc = send_request_init(drvdata, larval_seq, larval_seq_len); if (rc) goto init_digest_const_err; - sram_buff_ofs += sizeof(md5_init); + sram_buff_ofs += sizeof(cc_md5_init); larval_seq_len = 0; - cc_set_sram_desc(sha1_init, sram_buff_ofs, - ARRAY_SIZE(sha1_init), larval_seq, + cc_set_sram_desc(cc_sha1_init, sram_buff_ofs, + ARRAY_SIZE(cc_sha1_init), larval_seq, &larval_seq_len); rc = send_request_init(drvdata, larval_seq, larval_seq_len); if (rc) goto init_digest_const_err; - sram_buff_ofs += sizeof(sha1_init); + sram_buff_ofs += sizeof(cc_sha1_init); larval_seq_len = 0; - cc_set_sram_desc(sha224_init, sram_buff_ofs, - ARRAY_SIZE(sha224_init), larval_seq, + cc_set_sram_desc(cc_sha224_init, sram_buff_ofs, + ARRAY_SIZE(cc_sha224_init), larval_seq, &larval_seq_len); rc = send_request_init(drvdata, larval_seq, larval_seq_len); if (rc) goto init_digest_const_err; - sram_buff_ofs += sizeof(sha224_init); + sram_buff_ofs += sizeof(cc_sha224_init); larval_seq_len = 0; - cc_set_sram_desc(sha256_init, sram_buff_ofs, - ARRAY_SIZE(sha256_init), larval_seq, + cc_set_sram_desc(cc_sha256_init, sram_buff_ofs, + ARRAY_SIZE(cc_sha256_init), larval_seq, &larval_seq_len); rc = send_request_init(drvdata, larval_seq, larval_seq_len); if (rc) goto init_digest_const_err; - sram_buff_ofs += sizeof(sha256_init); + sram_buff_ofs += sizeof(cc_sha256_init); larval_seq_len = 0; if (sm3_supported) { - cc_set_sram_desc(sm3_init, sram_buff_ofs, - ARRAY_SIZE(sm3_init), larval_seq, + cc_set_sram_desc(cc_sm3_init, sram_buff_ofs, + ARRAY_SIZE(cc_sm3_init), larval_seq, &larval_seq_len); rc = send_request_init(drvdata, larval_seq, larval_seq_len); if (rc) goto init_digest_const_err; - sram_buff_ofs += sizeof(sm3_init); + sram_buff_ofs += sizeof(cc_sm3_init); larval_seq_len = 0; } if (large_sha_supported) { - cc_set_sram_desc((u32 *)sha384_init, sram_buff_ofs, - (ARRAY_SIZE(sha384_init) * 2), larval_seq, + cc_set_sram_desc((u32 *)cc_sha384_init, sram_buff_ofs, + (ARRAY_SIZE(cc_sha384_init) * 2), larval_seq, &larval_seq_len); rc = send_request_init(drvdata, larval_seq, larval_seq_len); if (rc) goto init_digest_const_err; - sram_buff_ofs += sizeof(sha384_init); + sram_buff_ofs += sizeof(cc_sha384_init); larval_seq_len = 0; - cc_set_sram_desc((u32 *)sha512_init, sram_buff_ofs, - (ARRAY_SIZE(sha512_init) * 2), larval_seq, + cc_set_sram_desc((u32 *)cc_sha512_init, sram_buff_ofs, + (ARRAY_SIZE(cc_sha512_init) * 2), larval_seq, &larval_seq_len); rc = send_request_init(drvdata, larval_seq, larval_seq_len); if (rc) @@ -1986,8 +1987,8 @@ static void __init cc_swap_dwords(u32 *buf, unsigned long size) */ void __init cc_hash_global_init(void) { - cc_swap_dwords((u32 *)&sha384_init, (ARRAY_SIZE(sha384_init) * 2)); - cc_swap_dwords((u32 *)&sha512_init, (ARRAY_SIZE(sha512_init) * 2)); + cc_swap_dwords((u32 *)&cc_sha384_init, (ARRAY_SIZE(cc_sha384_init) * 2)); + cc_swap_dwords((u32 *)&cc_sha512_init, (ARRAY_SIZE(cc_sha512_init) * 2)); } int cc_hash_alloc(struct cc_drvdata *drvdata) @@ -2006,18 +2007,18 @@ int cc_hash_alloc(struct cc_drvdata *drvdata) INIT_LIST_HEAD(&hash_handle->hash_list); drvdata->hash_handle = hash_handle; - sram_size_to_alloc = sizeof(digest_len_init) + - sizeof(md5_init) + - sizeof(sha1_init) + - sizeof(sha224_init) + - sizeof(sha256_init); + sram_size_to_alloc = sizeof(cc_digest_len_init) + + sizeof(cc_md5_init) + + sizeof(cc_sha1_init) + + sizeof(cc_sha224_init) + + sizeof(cc_sha256_init); if (drvdata->hw_rev >= CC_HW_REV_713) - sram_size_to_alloc += sizeof(sm3_init); + sram_size_to_alloc += sizeof(cc_sm3_init); if (drvdata->hw_rev >= CC_HW_REV_712) - sram_size_to_alloc += sizeof(digest_len_sha512_init) + - sizeof(sha384_init) + sizeof(sha512_init); + sram_size_to_alloc += sizeof(cc_digest_len_sha512_init) + + sizeof(cc_sha384_init) + sizeof(cc_sha512_init); sram_buff = cc_sram_alloc(drvdata, sram_size_to_alloc); if (sram_buff == NULL_SRAM_ADDR) { @@ -2258,22 +2259,22 @@ static const void *cc_larval_digest(struct device *dev, u32 mode) { switch (mode) { case DRV_HASH_MD5: - return md5_init; + return cc_md5_init; case DRV_HASH_SHA1: - return sha1_init; + return cc_sha1_init; case DRV_HASH_SHA224: - return sha224_init; + return cc_sha224_init; case DRV_HASH_SHA256: - return sha256_init; + return cc_sha256_init; case DRV_HASH_SHA384: - return sha384_init; + return cc_sha384_init; case DRV_HASH_SHA512: - return sha512_init; + return cc_sha512_init; case DRV_HASH_SM3: - return sm3_init; + return cc_sm3_init; default: dev_err(dev, "Invalid hash mode (%d)\n", mode); - return md5_init; + return cc_md5_init; } } @@ -2301,40 +2302,40 @@ cc_sram_addr_t cc_larval_digest_addr(void *drvdata, u32 mode) return (hash_handle->larval_digest_sram_addr); case DRV_HASH_SHA1: return (hash_handle->larval_digest_sram_addr + - sizeof(md5_init)); + sizeof(cc_md5_init)); case DRV_HASH_SHA224: return (hash_handle->larval_digest_sram_addr + - sizeof(md5_init) + - sizeof(sha1_init)); + sizeof(cc_md5_init) + + sizeof(cc_sha1_init)); case DRV_HASH_SHA256: return (hash_handle->larval_digest_sram_addr + - sizeof(md5_init) + - sizeof(sha1_init) + - sizeof(sha224_init)); + sizeof(cc_md5_init) + + sizeof(cc_sha1_init) + + sizeof(cc_sha224_init)); case DRV_HASH_SM3: return (hash_handle->larval_digest_sram_addr + - sizeof(md5_init) + - sizeof(sha1_init) + - sizeof(sha224_init) + - sizeof(sha256_init)); + sizeof(cc_md5_init) + + sizeof(cc_sha1_init) + + sizeof(cc_sha224_init) + + sizeof(cc_sha256_init)); case DRV_HASH_SHA384: addr = (hash_handle->larval_digest_sram_addr + - sizeof(md5_init) + - sizeof(sha1_init) + - sizeof(sha224_init) + - sizeof(sha256_init)); + sizeof(cc_md5_init) + + sizeof(cc_sha1_init) + + sizeof(cc_sha224_init) + + sizeof(cc_sha256_init)); if (sm3_supported) - addr += sizeof(sm3_init); + addr += sizeof(cc_sm3_init); return addr; case DRV_HASH_SHA512: addr = (hash_handle->larval_digest_sram_addr + - sizeof(md5_init) + - sizeof(sha1_init) + - sizeof(sha224_init) + - sizeof(sha256_init) + - sizeof(sha384_init)); + sizeof(cc_md5_init) + + sizeof(cc_sha1_init) + + sizeof(cc_sha224_init) + + sizeof(cc_sha256_init) + + sizeof(cc_sha384_init)); if (sm3_supported) - addr += sizeof(sm3_init); + addr += sizeof(cc_sm3_init); return addr; default: dev_err(dev, "Invalid hash mode (%d)\n", mode); @@ -2360,7 +2361,7 @@ cc_digest_len_addr(void *drvdata, u32 mode) #if (CC_DEV_SHA_MAX > 256) case DRV_HASH_SHA384: case DRV_HASH_SHA512: - return digest_len_addr + sizeof(digest_len_init); + return digest_len_addr + sizeof(cc_digest_len_init); #endif default: return digest_len_addr; /*to avoid kernel crash*/ diff --git a/drivers/crypto/ccree/cc_ivgen.c b/drivers/crypto/ccree/cc_ivgen.c deleted file mode 100644 index 99dc69383e2079d179b4b4e2ff13fd8e864c4837..0000000000000000000000000000000000000000 --- a/drivers/crypto/ccree/cc_ivgen.c +++ /dev/null @@ -1,276 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2012-2019 ARM Limited (or its affiliates). */ - -#include -#include "cc_driver.h" -#include "cc_ivgen.h" -#include "cc_request_mgr.h" -#include "cc_sram_mgr.h" -#include "cc_buffer_mgr.h" - -/* The max. size of pool *MUST* be <= SRAM total size */ -#define CC_IVPOOL_SIZE 1024 -/* The first 32B fraction of pool are dedicated to the - * next encryption "key" & "IV" for pool regeneration - */ -#define CC_IVPOOL_META_SIZE (CC_AES_IV_SIZE + AES_KEYSIZE_128) -#define CC_IVPOOL_GEN_SEQ_LEN 4 - -/** - * struct cc_ivgen_ctx -IV pool generation context - * @pool: the start address of the iv-pool resides in internal RAM - * @ctr_key_dma: address of pool's encryption key material in internal RAM - * @ctr_iv_dma: address of pool's counter iv in internal RAM - * @next_iv_ofs: the offset to the next available IV in pool - * @pool_meta: virt. address of the initial enc. key/IV - * @pool_meta_dma: phys. address of the initial enc. key/IV - */ -struct cc_ivgen_ctx { - cc_sram_addr_t pool; - cc_sram_addr_t ctr_key; - cc_sram_addr_t ctr_iv; - u32 next_iv_ofs; - u8 *pool_meta; - dma_addr_t pool_meta_dma; -}; - -/*! - * Generates CC_IVPOOL_SIZE of random bytes by - * encrypting 0's using AES128-CTR. - * - * \param ivgen iv-pool context - * \param iv_seq IN/OUT array to the descriptors sequence - * \param iv_seq_len IN/OUT pointer to the sequence length - */ -static int cc_gen_iv_pool(struct cc_ivgen_ctx *ivgen_ctx, - struct cc_hw_desc iv_seq[], unsigned int *iv_seq_len) -{ - unsigned int idx = *iv_seq_len; - - if ((*iv_seq_len + CC_IVPOOL_GEN_SEQ_LEN) > CC_IVPOOL_SEQ_LEN) { - /* The sequence will be longer than allowed */ - return -EINVAL; - } - /* Setup key */ - hw_desc_init(&iv_seq[idx]); - set_din_sram(&iv_seq[idx], ivgen_ctx->ctr_key, AES_KEYSIZE_128); - set_setup_mode(&iv_seq[idx], SETUP_LOAD_KEY0); - set_cipher_config0(&iv_seq[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_flow_mode(&iv_seq[idx], S_DIN_to_AES); - set_key_size_aes(&iv_seq[idx], CC_AES_128_BIT_KEY_SIZE); - set_cipher_mode(&iv_seq[idx], DRV_CIPHER_CTR); - idx++; - - /* Setup cipher state */ - hw_desc_init(&iv_seq[idx]); - set_din_sram(&iv_seq[idx], ivgen_ctx->ctr_iv, CC_AES_IV_SIZE); - set_cipher_config0(&iv_seq[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_flow_mode(&iv_seq[idx], S_DIN_to_AES); - set_setup_mode(&iv_seq[idx], SETUP_LOAD_STATE1); - set_key_size_aes(&iv_seq[idx], CC_AES_128_BIT_KEY_SIZE); - set_cipher_mode(&iv_seq[idx], DRV_CIPHER_CTR); - idx++; - - /* Perform dummy encrypt to skip first block */ - hw_desc_init(&iv_seq[idx]); - set_din_const(&iv_seq[idx], 0, CC_AES_IV_SIZE); - set_dout_sram(&iv_seq[idx], ivgen_ctx->pool, CC_AES_IV_SIZE); - set_flow_mode(&iv_seq[idx], DIN_AES_DOUT); - idx++; - - /* Generate IV pool */ - hw_desc_init(&iv_seq[idx]); - set_din_const(&iv_seq[idx], 0, CC_IVPOOL_SIZE); - set_dout_sram(&iv_seq[idx], ivgen_ctx->pool, CC_IVPOOL_SIZE); - set_flow_mode(&iv_seq[idx], DIN_AES_DOUT); - idx++; - - *iv_seq_len = idx; /* Update sequence length */ - - /* queue ordering assures pool readiness */ - ivgen_ctx->next_iv_ofs = CC_IVPOOL_META_SIZE; - - return 0; -} - -/*! - * Generates the initial pool in SRAM. - * This function should be invoked when resuming driver. - * - * \param drvdata - * - * \return int Zero for success, negative value otherwise. - */ -int cc_init_iv_sram(struct cc_drvdata *drvdata) -{ - struct cc_ivgen_ctx *ivgen_ctx = drvdata->ivgen_handle; - struct cc_hw_desc iv_seq[CC_IVPOOL_SEQ_LEN]; - unsigned int iv_seq_len = 0; - int rc; - - /* Generate initial enc. key/iv */ - get_random_bytes(ivgen_ctx->pool_meta, CC_IVPOOL_META_SIZE); - - /* The first 32B reserved for the enc. Key/IV */ - ivgen_ctx->ctr_key = ivgen_ctx->pool; - ivgen_ctx->ctr_iv = ivgen_ctx->pool + AES_KEYSIZE_128; - - /* Copy initial enc. key and IV to SRAM at a single descriptor */ - hw_desc_init(&iv_seq[iv_seq_len]); - set_din_type(&iv_seq[iv_seq_len], DMA_DLLI, ivgen_ctx->pool_meta_dma, - CC_IVPOOL_META_SIZE, NS_BIT); - set_dout_sram(&iv_seq[iv_seq_len], ivgen_ctx->pool, - CC_IVPOOL_META_SIZE); - set_flow_mode(&iv_seq[iv_seq_len], BYPASS); - iv_seq_len++; - - /* Generate initial pool */ - rc = cc_gen_iv_pool(ivgen_ctx, iv_seq, &iv_seq_len); - if (rc) - return rc; - - /* Fire-and-forget */ - return send_request_init(drvdata, iv_seq, iv_seq_len); -} - -/*! - * Free iv-pool and ivgen context. - * - * \param drvdata - */ -void cc_ivgen_fini(struct cc_drvdata *drvdata) -{ - struct cc_ivgen_ctx *ivgen_ctx = drvdata->ivgen_handle; - struct device *device = &drvdata->plat_dev->dev; - - if (!ivgen_ctx) - return; - - if (ivgen_ctx->pool_meta) { - memset(ivgen_ctx->pool_meta, 0, CC_IVPOOL_META_SIZE); - dma_free_coherent(device, CC_IVPOOL_META_SIZE, - ivgen_ctx->pool_meta, - ivgen_ctx->pool_meta_dma); - } - - ivgen_ctx->pool = NULL_SRAM_ADDR; -} - -/*! - * Allocates iv-pool and maps resources. - * This function generates the first IV pool. - * - * \param drvdata Driver's private context - * - * \return int Zero for success, negative value otherwise. - */ -int cc_ivgen_init(struct cc_drvdata *drvdata) -{ - struct cc_ivgen_ctx *ivgen_ctx; - struct device *device = &drvdata->plat_dev->dev; - int rc; - - /* Allocate "this" context */ - ivgen_ctx = devm_kzalloc(device, sizeof(*ivgen_ctx), GFP_KERNEL); - if (!ivgen_ctx) - return -ENOMEM; - - drvdata->ivgen_handle = ivgen_ctx; - - /* Allocate pool's header for initial enc. key/IV */ - ivgen_ctx->pool_meta = dma_alloc_coherent(device, CC_IVPOOL_META_SIZE, - &ivgen_ctx->pool_meta_dma, - GFP_KERNEL); - if (!ivgen_ctx->pool_meta) { - dev_err(device, "Not enough memory to allocate DMA of pool_meta (%u B)\n", - CC_IVPOOL_META_SIZE); - rc = -ENOMEM; - goto out; - } - /* Allocate IV pool in SRAM */ - ivgen_ctx->pool = cc_sram_alloc(drvdata, CC_IVPOOL_SIZE); - if (ivgen_ctx->pool == NULL_SRAM_ADDR) { - dev_err(device, "SRAM pool exhausted\n"); - rc = -ENOMEM; - goto out; - } - - return cc_init_iv_sram(drvdata); - -out: - cc_ivgen_fini(drvdata); - return rc; -} - -/*! - * Acquires 16 Bytes IV from the iv-pool - * - * \param drvdata Driver private context - * \param iv_out_dma Array of physical IV out addresses - * \param iv_out_dma_len Length of iv_out_dma array (additional elements - * of iv_out_dma array are ignore) - * \param iv_out_size May be 8 or 16 bytes long - * \param iv_seq IN/OUT array to the descriptors sequence - * \param iv_seq_len IN/OUT pointer to the sequence length - * - * \return int Zero for success, negative value otherwise. - */ -int cc_get_iv(struct cc_drvdata *drvdata, dma_addr_t iv_out_dma[], - unsigned int iv_out_dma_len, unsigned int iv_out_size, - struct cc_hw_desc iv_seq[], unsigned int *iv_seq_len) -{ - struct cc_ivgen_ctx *ivgen_ctx = drvdata->ivgen_handle; - unsigned int idx = *iv_seq_len; - struct device *dev = drvdata_to_dev(drvdata); - unsigned int t; - - if (iv_out_size != CC_AES_IV_SIZE && - iv_out_size != CTR_RFC3686_IV_SIZE) { - return -EINVAL; - } - if ((iv_out_dma_len + 1) > CC_IVPOOL_SEQ_LEN) { - /* The sequence will be longer than allowed */ - return -EINVAL; - } - - /* check that number of generated IV is limited to max dma address - * iv buffer size - */ - if (iv_out_dma_len > CC_MAX_IVGEN_DMA_ADDRESSES) { - /* The sequence will be longer than allowed */ - return -EINVAL; - } - - for (t = 0; t < iv_out_dma_len; t++) { - /* Acquire IV from pool */ - hw_desc_init(&iv_seq[idx]); - set_din_sram(&iv_seq[idx], (ivgen_ctx->pool + - ivgen_ctx->next_iv_ofs), - iv_out_size); - set_dout_dlli(&iv_seq[idx], iv_out_dma[t], iv_out_size, - NS_BIT, 0); - set_flow_mode(&iv_seq[idx], BYPASS); - idx++; - } - - /* Bypass operation is proceeded by crypto sequence, hence must - * assure bypass-write-transaction by a memory barrier - */ - hw_desc_init(&iv_seq[idx]); - set_din_no_dma(&iv_seq[idx], 0, 0xfffff0); - set_dout_no_dma(&iv_seq[idx], 0, 0, 1); - idx++; - - *iv_seq_len = idx; /* update seq length */ - - /* Update iv index */ - ivgen_ctx->next_iv_ofs += iv_out_size; - - if ((CC_IVPOOL_SIZE - ivgen_ctx->next_iv_ofs) < CC_AES_IV_SIZE) { - dev_dbg(dev, "Pool exhausted, regenerating iv-pool\n"); - /* pool is drained -regenerate it! */ - return cc_gen_iv_pool(ivgen_ctx, iv_seq, iv_seq_len); - } - - return 0; -} diff --git a/drivers/crypto/ccree/cc_ivgen.h b/drivers/crypto/ccree/cc_ivgen.h deleted file mode 100644 index a9f5e8bba4f183c40f84d5e9e8b602f6ceb3bd15..0000000000000000000000000000000000000000 --- a/drivers/crypto/ccree/cc_ivgen.h +++ /dev/null @@ -1,55 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2019 ARM Limited (or its affiliates). */ - -#ifndef __CC_IVGEN_H__ -#define __CC_IVGEN_H__ - -#include "cc_hw_queue_defs.h" - -#define CC_IVPOOL_SEQ_LEN 8 - -/*! - * Allocates iv-pool and maps resources. - * This function generates the first IV pool. - * - * \param drvdata Driver's private context - * - * \return int Zero for success, negative value otherwise. - */ -int cc_ivgen_init(struct cc_drvdata *drvdata); - -/*! - * Free iv-pool and ivgen context. - * - * \param drvdata - */ -void cc_ivgen_fini(struct cc_drvdata *drvdata); - -/*! - * Generates the initial pool in SRAM. - * This function should be invoked when resuming DX driver. - * - * \param drvdata - * - * \return int Zero for success, negative value otherwise. - */ -int cc_init_iv_sram(struct cc_drvdata *drvdata); - -/*! - * Acquires 16 Bytes IV from the iv-pool - * - * \param drvdata Driver private context - * \param iv_out_dma Array of physical IV out addresses - * \param iv_out_dma_len Length of iv_out_dma array (additional elements of - * iv_out_dma array are ignore) - * \param iv_out_size May be 8 or 16 bytes long - * \param iv_seq IN/OUT array to the descriptors sequence - * \param iv_seq_len IN/OUT pointer to the sequence length - * - * \return int Zero for success, negative value otherwise. - */ -int cc_get_iv(struct cc_drvdata *drvdata, dma_addr_t iv_out_dma[], - unsigned int iv_out_dma_len, unsigned int iv_out_size, - struct cc_hw_desc iv_seq[], unsigned int *iv_seq_len); - -#endif /*__CC_IVGEN_H__*/ diff --git a/drivers/crypto/ccree/cc_pm.c b/drivers/crypto/ccree/cc_pm.c index 899a52f05b7a5dd076416964f4f66864e8db7485..dbc508fb719b6966f77292989b08fcc7faff8043 100644 --- a/drivers/crypto/ccree/cc_pm.c +++ b/drivers/crypto/ccree/cc_pm.c @@ -8,7 +8,6 @@ #include "cc_buffer_mgr.h" #include "cc_request_mgr.h" #include "cc_sram_mgr.h" -#include "cc_ivgen.h" #include "cc_hash.h" #include "cc_pm.h" #include "cc_fips.h" @@ -73,7 +72,6 @@ int cc_pm_resume(struct device *dev) /* must be after the queue resuming as it uses the HW queue*/ cc_init_hash_sram(drvdata); - cc_init_iv_sram(drvdata); return 0; } diff --git a/drivers/crypto/ccree/cc_request_mgr.c b/drivers/crypto/ccree/cc_request_mgr.c index 0bc6ccb0b899f3937bf9b5bfaf9e1864c6db74ea..a947d5a2cf35d9190a92bde7685efbb864f6a766 100644 --- a/drivers/crypto/ccree/cc_request_mgr.c +++ b/drivers/crypto/ccree/cc_request_mgr.c @@ -6,7 +6,6 @@ #include "cc_driver.h" #include "cc_buffer_mgr.h" #include "cc_request_mgr.h" -#include "cc_ivgen.h" #include "cc_pm.h" #define CC_MAX_POLL_ITER 10 @@ -281,36 +280,12 @@ static int cc_queues_status(struct cc_drvdata *drvdata, static int cc_do_send_request(struct cc_drvdata *drvdata, struct cc_crypto_req *cc_req, struct cc_hw_desc *desc, unsigned int len, - bool add_comp, bool ivgen) + bool add_comp) { struct cc_req_mgr_handle *req_mgr_h = drvdata->request_mgr_handle; unsigned int used_sw_slots; - unsigned int iv_seq_len = 0; unsigned int total_seq_len = len; /*initial sequence length*/ - struct cc_hw_desc iv_seq[CC_IVPOOL_SEQ_LEN]; struct device *dev = drvdata_to_dev(drvdata); - int rc; - - if (ivgen) { - dev_dbg(dev, "Acquire IV from pool into %d DMA addresses %pad, %pad, %pad, IV-size=%u\n", - cc_req->ivgen_dma_addr_len, - &cc_req->ivgen_dma_addr[0], - &cc_req->ivgen_dma_addr[1], - &cc_req->ivgen_dma_addr[2], - cc_req->ivgen_size); - - /* Acquire IV from pool */ - rc = cc_get_iv(drvdata, cc_req->ivgen_dma_addr, - cc_req->ivgen_dma_addr_len, - cc_req->ivgen_size, iv_seq, &iv_seq_len); - - if (rc) { - dev_err(dev, "Failed to generate IV (rc=%d)\n", rc); - return rc; - } - - total_seq_len += iv_seq_len; - } used_sw_slots = ((req_mgr_h->req_queue_head - req_mgr_h->req_queue_tail) & @@ -334,8 +309,6 @@ static int cc_do_send_request(struct cc_drvdata *drvdata, wmb(); /* STAT_PHASE_4: Push sequence */ - if (ivgen) - enqueue_seq(drvdata, iv_seq, iv_seq_len); enqueue_seq(drvdata, desc, len); @@ -380,8 +353,6 @@ static void cc_proc_backlog(struct cc_drvdata *drvdata) struct cc_bl_item *bli; struct cc_crypto_req *creq; void *req; - bool ivgen; - unsigned int total_len; struct device *dev = drvdata_to_dev(drvdata); int rc; @@ -406,12 +377,9 @@ static void cc_proc_backlog(struct cc_drvdata *drvdata) bli->notif = true; } - ivgen = !!creq->ivgen_dma_addr_len; - total_len = bli->len + (ivgen ? CC_IVPOOL_SEQ_LEN : 0); - spin_lock(&mgr->hw_lock); - rc = cc_queues_status(drvdata, mgr, total_len); + rc = cc_queues_status(drvdata, mgr, bli->len); if (rc) { /* * There is still not room in the FIFO for @@ -423,7 +391,7 @@ static void cc_proc_backlog(struct cc_drvdata *drvdata) } rc = cc_do_send_request(drvdata, &bli->creq, bli->desc, - bli->len, false, ivgen); + bli->len, false); spin_unlock(&mgr->hw_lock); @@ -447,8 +415,6 @@ int cc_send_request(struct cc_drvdata *drvdata, struct cc_crypto_req *cc_req, { int rc; struct cc_req_mgr_handle *mgr = drvdata->request_mgr_handle; - bool ivgen = !!cc_req->ivgen_dma_addr_len; - unsigned int total_len = len + (ivgen ? CC_IVPOOL_SEQ_LEN : 0); struct device *dev = drvdata_to_dev(drvdata); bool backlog_ok = req->flags & CRYPTO_TFM_REQ_MAY_BACKLOG; gfp_t flags = cc_gfp_flags(req); @@ -461,7 +427,7 @@ int cc_send_request(struct cc_drvdata *drvdata, struct cc_crypto_req *cc_req, } spin_lock_bh(&mgr->hw_lock); - rc = cc_queues_status(drvdata, mgr, total_len); + rc = cc_queues_status(drvdata, mgr, len); #ifdef CC_DEBUG_FORCE_BACKLOG if (backlog_ok) @@ -486,8 +452,7 @@ int cc_send_request(struct cc_drvdata *drvdata, struct cc_crypto_req *cc_req, } if (!rc) - rc = cc_do_send_request(drvdata, cc_req, desc, len, false, - ivgen); + rc = cc_do_send_request(drvdata, cc_req, desc, len, false); spin_unlock_bh(&mgr->hw_lock); return rc; @@ -527,7 +492,7 @@ int cc_send_sync_request(struct cc_drvdata *drvdata, reinit_completion(&drvdata->hw_queue_avail); } - rc = cc_do_send_request(drvdata, cc_req, desc, len, true, false); + rc = cc_do_send_request(drvdata, cc_req, desc, len, true); spin_unlock_bh(&mgr->hw_lock); if (rc != -EINPROGRESS) { diff --git a/drivers/crypto/chelsio/Kconfig b/drivers/crypto/chelsio/Kconfig index 4b9b37a130d3503e835bccf6c67d1d0f37e9dea8..250150560e687bfed3efd06ac9121cd7e2a67d4c 100644 --- a/drivers/crypto/chelsio/Kconfig +++ b/drivers/crypto/chelsio/Kconfig @@ -2,6 +2,7 @@ config CRYPTO_DEV_CHELSIO tristate "Chelsio Crypto Co-processor Driver" depends on CHELSIO_T4 + select CRYPTO_LIB_AES select CRYPTO_SHA1 select CRYPTO_SHA256 select CRYPTO_SHA512 diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index 177f572b95890c842a574a69fabfd40ddb2c33c9..38ee38b37ae6fae3f1a9460adbc79ec64a1cb86c 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -1023,22 +1023,21 @@ static int chcr_update_tweak(struct ablkcipher_request *req, u8 *iv, struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); struct ablk_ctx *ablkctx = ABLK_CTX(c_ctx(tfm)); struct chcr_blkcipher_req_ctx *reqctx = ablkcipher_request_ctx(req); - struct crypto_cipher *cipher; + struct crypto_aes_ctx aes; int ret, i; u8 *key; unsigned int keylen; int round = reqctx->last_req_len / AES_BLOCK_SIZE; int round8 = round / 8; - cipher = ablkctx->aes_generic; memcpy(iv, reqctx->iv, AES_BLOCK_SIZE); keylen = ablkctx->enckey_len / 2; key = ablkctx->key + keylen; - ret = crypto_cipher_setkey(cipher, key, keylen); + ret = aes_expandkey(&aes, key, keylen); if (ret) - goto out; - crypto_cipher_encrypt_one(cipher, iv, iv); + return ret; + aes_encrypt(&aes, iv, iv); for (i = 0; i < round8; i++) gf128mul_x8_ble((le128 *)iv, (le128 *)iv); @@ -1046,9 +1045,10 @@ static int chcr_update_tweak(struct ablkcipher_request *req, u8 *iv, gf128mul_x_ble((le128 *)iv, (le128 *)iv); if (!isfinal) - crypto_cipher_decrypt_one(cipher, iv, iv); -out: - return ret; + aes_decrypt(&aes, iv, iv); + + memzero_explicit(&aes, sizeof(aes)); + return 0; } static int chcr_update_cipher_iv(struct ablkcipher_request *req, @@ -1411,16 +1411,6 @@ static int chcr_cra_init(struct crypto_tfm *tfm) return PTR_ERR(ablkctx->sw_cipher); } - if (get_cryptoalg_subtype(tfm) == CRYPTO_ALG_SUB_TYPE_XTS) { - /* To update tweak*/ - ablkctx->aes_generic = crypto_alloc_cipher("aes-generic", 0, 0); - if (IS_ERR(ablkctx->aes_generic)) { - pr_err("failed to allocate aes cipher for tweak\n"); - return PTR_ERR(ablkctx->aes_generic); - } - } else - ablkctx->aes_generic = NULL; - tfm->crt_ablkcipher.reqsize = sizeof(struct chcr_blkcipher_req_ctx); return chcr_device_init(crypto_tfm_ctx(tfm)); } @@ -1451,8 +1441,6 @@ static void chcr_cra_exit(struct crypto_tfm *tfm) struct ablk_ctx *ablkctx = ABLK_CTX(ctx); crypto_free_sync_skcipher(ablkctx->sw_cipher); - if (ablkctx->aes_generic) - crypto_free_cipher(ablkctx->aes_generic); } static int get_alg_config(struct algo_param *params, @@ -3364,9 +3352,9 @@ static int chcr_gcm_setkey(struct crypto_aead *aead, const u8 *key, { struct chcr_aead_ctx *aeadctx = AEAD_CTX(a_ctx(aead)); struct chcr_gcm_ctx *gctx = GCM_CTX(aeadctx); - struct crypto_cipher *cipher; unsigned int ck_size; int ret = 0, key_ctx_size = 0; + struct crypto_aes_ctx aes; aeadctx->enckey_len = 0; crypto_aead_clear_flags(aeadctx->sw_cipher, CRYPTO_TFM_REQ_MASK); @@ -3409,23 +3397,15 @@ static int chcr_gcm_setkey(struct crypto_aead *aead, const u8 *key, /* Calculate the H = CIPH(K, 0 repeated 16 times). * It will go in key context */ - cipher = crypto_alloc_cipher("aes-generic", 0, 0); - if (IS_ERR(cipher)) { - aeadctx->enckey_len = 0; - ret = -ENOMEM; - goto out; - } - - ret = crypto_cipher_setkey(cipher, key, keylen); + ret = aes_expandkey(&aes, key, keylen); if (ret) { aeadctx->enckey_len = 0; - goto out1; + goto out; } memset(gctx->ghash_h, 0, AEAD_H_SIZE); - crypto_cipher_encrypt_one(cipher, gctx->ghash_h, gctx->ghash_h); + aes_encrypt(&aes, gctx->ghash_h, gctx->ghash_h); + memzero_explicit(&aes, sizeof(aes)); -out1: - crypto_free_cipher(cipher); out: return ret; } diff --git a/drivers/crypto/chelsio/chcr_algo.h b/drivers/crypto/chelsio/chcr_algo.h index ee20dd899e831883e6f38521050dc625b1ed793e..d1e6b51df0cecb052abcf64ab23af3aae77a77fb 100644 --- a/drivers/crypto/chelsio/chcr_algo.h +++ b/drivers/crypto/chelsio/chcr_algo.h @@ -333,26 +333,26 @@ struct phys_sge_pairs { }; -static const u32 sha1_init[SHA1_DIGEST_SIZE / 4] = { +static const u32 chcr_sha1_init[SHA1_DIGEST_SIZE / 4] = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4, }; -static const u32 sha224_init[SHA256_DIGEST_SIZE / 4] = { +static const u32 chcr_sha224_init[SHA256_DIGEST_SIZE / 4] = { SHA224_H0, SHA224_H1, SHA224_H2, SHA224_H3, SHA224_H4, SHA224_H5, SHA224_H6, SHA224_H7, }; -static const u32 sha256_init[SHA256_DIGEST_SIZE / 4] = { +static const u32 chcr_sha256_init[SHA256_DIGEST_SIZE / 4] = { SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3, SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7, }; -static const u64 sha384_init[SHA512_DIGEST_SIZE / 8] = { +static const u64 chcr_sha384_init[SHA512_DIGEST_SIZE / 8] = { SHA384_H0, SHA384_H1, SHA384_H2, SHA384_H3, SHA384_H4, SHA384_H5, SHA384_H6, SHA384_H7, }; -static const u64 sha512_init[SHA512_DIGEST_SIZE / 8] = { +static const u64 chcr_sha512_init[SHA512_DIGEST_SIZE / 8] = { SHA512_H0, SHA512_H1, SHA512_H2, SHA512_H3, SHA512_H4, SHA512_H5, SHA512_H6, SHA512_H7, }; @@ -362,21 +362,21 @@ static inline void copy_hash_init_values(char *key, int digestsize) u8 i; __be32 *dkey = (__be32 *)key; u64 *ldkey = (u64 *)key; - __be64 *sha384 = (__be64 *)sha384_init; - __be64 *sha512 = (__be64 *)sha512_init; + __be64 *sha384 = (__be64 *)chcr_sha384_init; + __be64 *sha512 = (__be64 *)chcr_sha512_init; switch (digestsize) { case SHA1_DIGEST_SIZE: for (i = 0; i < SHA1_INIT_STATE; i++) - dkey[i] = cpu_to_be32(sha1_init[i]); + dkey[i] = cpu_to_be32(chcr_sha1_init[i]); break; case SHA224_DIGEST_SIZE: for (i = 0; i < SHA224_INIT_STATE; i++) - dkey[i] = cpu_to_be32(sha224_init[i]); + dkey[i] = cpu_to_be32(chcr_sha224_init[i]); break; case SHA256_DIGEST_SIZE: for (i = 0; i < SHA256_INIT_STATE; i++) - dkey[i] = cpu_to_be32(sha256_init[i]); + dkey[i] = cpu_to_be32(chcr_sha256_init[i]); break; case SHA384_DIGEST_SIZE: for (i = 0; i < SHA384_INIT_STATE; i++) diff --git a/drivers/crypto/chelsio/chcr_crypto.h b/drivers/crypto/chelsio/chcr_crypto.h index 655606f2e4d09f089d27ed607da95fad94fe6983..993c97e70565ef84e5b92a9d645727b9e9b8ad0f 100644 --- a/drivers/crypto/chelsio/chcr_crypto.h +++ b/drivers/crypto/chelsio/chcr_crypto.h @@ -172,7 +172,6 @@ static inline struct chcr_context *h_ctx(struct crypto_ahash *tfm) struct ablk_ctx { struct crypto_sync_skcipher *sw_cipher; - struct crypto_cipher *aes_generic; __be32 key_ctx_hdr; unsigned int enckey_len; unsigned char ciph_mode; diff --git a/drivers/crypto/chelsio/chcr_ipsec.c b/drivers/crypto/chelsio/chcr_ipsec.c index f429aae72542f1e5b8f0b773ded5b4c95b7d9792..24355680f30addbf183b961d4ea12633be6906f0 100644 --- a/drivers/crypto/chelsio/chcr_ipsec.c +++ b/drivers/crypto/chelsio/chcr_ipsec.c @@ -132,11 +132,11 @@ static inline int chcr_ipsec_setauthsize(struct xfrm_state *x, static inline int chcr_ipsec_setkey(struct xfrm_state *x, struct ipsec_sa_entry *sa_entry) { - struct crypto_cipher *cipher; int keylen = (x->aead->alg_key_len + 7) / 8; unsigned char *key = x->aead->alg_key; int ck_size, key_ctx_size = 0; unsigned char ghash_h[AEAD_H_SIZE]; + struct crypto_aes_ctx aes; int ret = 0; if (keylen > 3) { @@ -170,26 +170,19 @@ static inline int chcr_ipsec_setkey(struct xfrm_state *x, /* Calculate the H = CIPH(K, 0 repeated 16 times). * It will go in key context */ - cipher = crypto_alloc_cipher("aes-generic", 0, 0); - if (IS_ERR(cipher)) { - sa_entry->enckey_len = 0; - ret = -ENOMEM; - goto out; - } - - ret = crypto_cipher_setkey(cipher, key, keylen); + ret = aes_expandkey(&aes, key, keylen); if (ret) { sa_entry->enckey_len = 0; - goto out1; + goto out; } memset(ghash_h, 0, AEAD_H_SIZE); - crypto_cipher_encrypt_one(cipher, ghash_h, ghash_h); + aes_encrypt(&aes, ghash_h, ghash_h); + memzero_explicit(&aes, sizeof(aes)); + memcpy(sa_entry->key + (DIV_ROUND_UP(sa_entry->enckey_len, 16) * 16), ghash_h, AEAD_H_SIZE); sa_entry->kctx_len = ((DIV_ROUND_UP(sa_entry->enckey_len, 16)) << 4) + AEAD_H_SIZE; -out1: - crypto_free_cipher(cipher); out: return ret; } diff --git a/drivers/crypto/chelsio/chtls/chtls_hw.c b/drivers/crypto/chelsio/chtls/chtls_hw.c index f2424f4c5f78636f8cc1aad75c8e2f5935894d3e..2a34035d3cfbce68d10eed93ac0be512148bd378 100644 --- a/drivers/crypto/chelsio/chtls/chtls_hw.c +++ b/drivers/crypto/chelsio/chtls/chtls_hw.c @@ -213,8 +213,8 @@ static int chtls_key_info(struct chtls_sock *csk, unsigned char key[AES_KEYSIZE_128]; struct tls12_crypto_info_aes_gcm_128 *gcm_ctx; unsigned char ghash_h[AEAD_H_SIZE]; - struct crypto_cipher *cipher; int ck_size, key_ctx_size; + struct crypto_aes_ctx aes; int ret; gcm_ctx = (struct tls12_crypto_info_aes_gcm_128 *) @@ -234,18 +234,13 @@ static int chtls_key_info(struct chtls_sock *csk, /* Calculate the H = CIPH(K, 0 repeated 16 times). * It will go in key context */ - cipher = crypto_alloc_cipher("aes", 0, 0); - if (IS_ERR(cipher)) { - ret = -ENOMEM; - goto out; - } - - ret = crypto_cipher_setkey(cipher, key, keylen); + ret = aes_expandkey(&aes, key, keylen); if (ret) - goto out1; + return ret; memset(ghash_h, 0, AEAD_H_SIZE); - crypto_cipher_encrypt_one(cipher, ghash_h, ghash_h); + aes_encrypt(&aes, ghash_h, ghash_h); + memzero_explicit(&aes, sizeof(aes)); csk->tlshws.keylen = key_ctx_size; /* Copy the Key context */ @@ -269,10 +264,7 @@ static int chtls_key_info(struct chtls_sock *csk, /* erase key info from driver */ memset(gcm_ctx->key, 0, keylen); -out1: - crypto_free_cipher(cipher); -out: - return ret; + return 0; } static void chtls_set_scmd(struct chtls_sock *csk) diff --git a/drivers/crypto/chelsio/chtls/chtls_io.c b/drivers/crypto/chelsio/chtls/chtls_io.c index 551bca6fef242904d39400a6d958ac1f829c270a..c70cb5f272cf05a8c7ab962976e9bc324ea57c91 100644 --- a/drivers/crypto/chelsio/chtls/chtls_io.c +++ b/drivers/crypto/chelsio/chtls/chtls_io.c @@ -1134,7 +1134,9 @@ int chtls_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) } /* Update the skb. */ if (merge) { - skb_shinfo(skb)->frags[i - 1].size += copy; + skb_frag_size_add( + &skb_shinfo(skb)->frags[i - 1], + copy); } else { skb_fill_page_desc(skb, i, page, off, copy); if (off + copy < pg_size) { @@ -1247,7 +1249,7 @@ int chtls_sendpage(struct sock *sk, struct page *page, i = skb_shinfo(skb)->nr_frags; if (skb_can_coalesce(skb, i, page, offset)) { - skb_shinfo(skb)->frags[i - 1].size += copy; + skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); } else if (i < MAX_SKB_FRAGS) { get_page(page); skb_fill_page_desc(skb, i, page, offset, copy); diff --git a/drivers/crypto/chelsio/chtls/chtls_main.c b/drivers/crypto/chelsio/chtls/chtls_main.c index 635bb4b447fb4ab65977a9bfcafd7bd71cec38f9..e6df5b95ed47b51d1ad46927d995d78528d6baf5 100644 --- a/drivers/crypto/chelsio/chtls/chtls_main.c +++ b/drivers/crypto/chelsio/chtls/chtls_main.c @@ -474,7 +474,8 @@ static int chtls_getsockopt(struct sock *sk, int level, int optname, struct tls_context *ctx = tls_get_ctx(sk); if (level != SOL_TLS) - return ctx->getsockopt(sk, level, optname, optval, optlen); + return ctx->sk_proto->getsockopt(sk, level, + optname, optval, optlen); return do_chtls_getsockopt(sk, optval, optlen); } @@ -541,7 +542,8 @@ static int chtls_setsockopt(struct sock *sk, int level, int optname, struct tls_context *ctx = tls_get_ctx(sk); if (level != SOL_TLS) - return ctx->setsockopt(sk, level, optname, optval, optlen); + return ctx->sk_proto->setsockopt(sk, level, + optname, optval, optlen); return do_chtls_setsockopt(sk, optname, optval, optlen); } diff --git a/drivers/crypto/exynos-rng.c b/drivers/crypto/exynos-rng.c index 2cfabb99cb6ebfb5f9bfea8a595ae29b8b483ec6..cbd8ca6e52ee49e6defec1f9bb1db1eb32f7b2fc 100644 --- a/drivers/crypto/exynos-rng.c +++ b/drivers/crypto/exynos-rng.c @@ -268,7 +268,6 @@ static struct rng_alg exynos_rng_alg = { static int exynos_rng_probe(struct platform_device *pdev) { struct exynos_rng_dev *rng; - struct resource *res; int ret; if (exynos_rng_dev) @@ -289,8 +288,7 @@ static int exynos_rng_probe(struct platform_device *pdev) return PTR_ERR(rng->clk); } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - rng->mem = devm_ioremap_resource(&pdev->dev, res); + rng->mem = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(rng->mem)) return PTR_ERR(rng->mem); diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index 5c3f02e4aecea6b8247efb7b08601f419d3acd75..a18e62df68d990e4831d70560ece896ad54d5786 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c @@ -21,7 +21,7 @@ #include #include -#include +#include static char hifn_pll_ref[sizeof("extNNN")] = "ext"; module_param_string(hifn_pll_ref, hifn_pll_ref, sizeof(hifn_pll_ref), 0444); @@ -1939,25 +1939,13 @@ static void hifn_flush(struct hifn_device *dev) static int hifn_setkey(struct crypto_ablkcipher *cipher, const u8 *key, unsigned int len) { - struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); - struct hifn_context *ctx = crypto_tfm_ctx(tfm); + struct hifn_context *ctx = crypto_ablkcipher_ctx(cipher); struct hifn_device *dev = ctx->dev; + int err; - if (len > HIFN_MAX_CRYPT_KEY_LENGTH) { - crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -1; - } - - if (len == HIFN_DES_KEY_LENGTH) { - u32 tmp[DES_EXPKEY_WORDS]; - int ret = des_ekey(tmp, key); - - if (unlikely(ret == 0) && - (tfm->crt_flags & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) { - tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; - return -EINVAL; - } - } + err = verify_ablkcipher_des_key(cipher, key); + if (err) + return err; dev->flags &= ~HIFN_FLAG_OLD_KEY; @@ -1972,15 +1960,11 @@ static int hifn_des3_setkey(struct crypto_ablkcipher *cipher, const u8 *key, { struct hifn_context *ctx = crypto_ablkcipher_ctx(cipher); struct hifn_device *dev = ctx->dev; - u32 flags; int err; - flags = crypto_ablkcipher_get_flags(cipher); - err = __des3_verify_key(&flags, key); - if (unlikely(err)) { - crypto_ablkcipher_set_flags(cipher, flags); + err = verify_ablkcipher_des3_key(cipher, key); + if (err) return err; - } dev->flags &= ~HIFN_FLAG_OLD_KEY; diff --git a/drivers/crypto/hisilicon/Kconfig b/drivers/crypto/hisilicon/Kconfig index 8ca9c503bcb0de8309663e8ca7690817212993df..ebaf91e0146d17058e2ae8d344fdfda03044880b 100644 --- a/drivers/crypto/hisilicon/Kconfig +++ b/drivers/crypto/hisilicon/Kconfig @@ -4,6 +4,7 @@ config CRYPTO_DEV_HISI_SEC tristate "Support for Hisilicon SEC crypto block cipher accelerator" select CRYPTO_BLKCIPHER select CRYPTO_ALGAPI + select CRYPTO_LIB_DES select SG_SPLIT depends on ARM64 || COMPILE_TEST depends on HAS_IOMEM @@ -12,3 +13,27 @@ config CRYPTO_DEV_HISI_SEC To compile this as a module, choose M here: the module will be called hisi_sec. + +config CRYPTO_DEV_HISI_QM + tristate + depends on ARM64 && PCI && PCI_MSI + help + HiSilicon accelerator engines use a common queue management + interface. Specific engine driver may use this module. + +config CRYPTO_HISI_SGL + tristate + depends on ARM64 + help + HiSilicon accelerator engines use a common hardware scatterlist + interface for data format. Specific engine driver may use this + module. + +config CRYPTO_DEV_HISI_ZIP + tristate "Support for HiSilicon ZIP accelerator" + depends on ARM64 && PCI && PCI_MSI + select CRYPTO_DEV_HISI_QM + select CRYPTO_HISI_SGL + select SG_SPLIT + help + Support for HiSilicon ZIP Driver diff --git a/drivers/crypto/hisilicon/Makefile b/drivers/crypto/hisilicon/Makefile index 463f46ace1820e26131f29d6028e8cd26dfe71a1..45a2797411268e18b1bbe76cbe6ffd3bcf80cbf3 100644 --- a/drivers/crypto/hisilicon/Makefile +++ b/drivers/crypto/hisilicon/Makefile @@ -1,2 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_CRYPTO_DEV_HISI_SEC) += sec/ +obj-$(CONFIG_CRYPTO_DEV_HISI_QM) += qm.o +obj-$(CONFIG_CRYPTO_HISI_SGL) += sgl.o +obj-$(CONFIG_CRYPTO_DEV_HISI_ZIP) += zip/ diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c new file mode 100644 index 0000000000000000000000000000000000000000..f975c393a6037fb071f3e71e17de5e239f784349 --- /dev/null +++ b/drivers/crypto/hisilicon/qm.c @@ -0,0 +1,1913 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019 HiSilicon Limited. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qm.h" + +/* eq/aeq irq enable */ +#define QM_VF_AEQ_INT_SOURCE 0x0 +#define QM_VF_AEQ_INT_MASK 0x4 +#define QM_VF_EQ_INT_SOURCE 0x8 +#define QM_VF_EQ_INT_MASK 0xc +#define QM_IRQ_NUM_V1 1 +#define QM_IRQ_NUM_PF_V2 4 +#define QM_IRQ_NUM_VF_V2 2 + +#define QM_EQ_EVENT_IRQ_VECTOR 0 +#define QM_AEQ_EVENT_IRQ_VECTOR 1 +#define QM_ABNORMAL_EVENT_IRQ_VECTOR 3 + +/* mailbox */ +#define QM_MB_CMD_SQC 0x0 +#define QM_MB_CMD_CQC 0x1 +#define QM_MB_CMD_EQC 0x2 +#define QM_MB_CMD_AEQC 0x3 +#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_SEND_BASE 0x300 +#define QM_MB_EVENT_SHIFT 8 +#define QM_MB_BUSY_SHIFT 13 +#define QM_MB_OP_SHIFT 14 +#define QM_MB_CMD_DATA_ADDR_L 0x304 +#define QM_MB_CMD_DATA_ADDR_H 0x308 + +/* sqc shift */ +#define QM_SQ_HOP_NUM_SHIFT 0 +#define QM_SQ_PAGE_SIZE_SHIFT 4 +#define QM_SQ_BUF_SIZE_SHIFT 8 +#define QM_SQ_SQE_SIZE_SHIFT 12 +#define QM_SQ_PRIORITY_SHIFT 0 +#define QM_SQ_ORDERS_SHIFT 4 +#define QM_SQ_TYPE_SHIFT 8 + +#define QM_SQ_TYPE_MASK GENMASK(3, 0) + +/* cqc shift */ +#define QM_CQ_HOP_NUM_SHIFT 0 +#define QM_CQ_PAGE_SIZE_SHIFT 4 +#define QM_CQ_BUF_SIZE_SHIFT 8 +#define QM_CQ_CQE_SIZE_SHIFT 12 +#define QM_CQ_PHASE_SHIFT 0 +#define QM_CQ_FLAG_SHIFT 1 + +#define QM_CQE_PHASE(cqe) ((cqe)->w7 & 0x1) +#define QM_QC_CQE_SIZE 4 + +/* eqc shift */ +#define QM_EQE_AEQE_SIZE (2UL << 12) +#define QM_EQC_PHASE_SHIFT 16 + +#define QM_EQE_PHASE(eqe) (((eqe)->dw0 >> 16) & 0x1) +#define QM_EQE_CQN_MASK GENMASK(15, 0) + +#define QM_AEQE_PHASE(aeqe) (((aeqe)->dw0 >> 16) & 0x1) +#define QM_AEQE_TYPE_SHIFT 17 + +#define QM_DOORBELL_CMD_SQ 0 +#define QM_DOORBELL_CMD_CQ 1 +#define QM_DOORBELL_CMD_EQ 2 +#define QM_DOORBELL_CMD_AEQ 3 + +#define QM_DOORBELL_BASE_V1 0x340 +#define QM_DB_CMD_SHIFT_V1 16 +#define QM_DB_INDEX_SHIFT_V1 32 +#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_DB_CMD_SHIFT_V2 12 +#define QM_DB_RAND_SHIFT_V2 16 +#define QM_DB_INDEX_SHIFT_V2 32 +#define QM_DB_PRIORITY_SHIFT_V2 48 + +#define QM_MEM_START_INIT 0x100040 +#define QM_MEM_INIT_DONE 0x100044 +#define QM_VFT_CFG_RDY 0x10006c +#define QM_VFT_CFG_OP_WR 0x100058 +#define QM_VFT_CFG_TYPE 0x10005c +#define QM_SQC_VFT 0x0 +#define QM_CQC_VFT 0x1 +#define QM_VFT_CFG 0x100060 +#define QM_VFT_CFG_OP_ENABLE 0x100054 + +#define QM_VFT_CFG_DATA_L 0x100064 +#define QM_VFT_CFG_DATA_H 0x100068 +#define QM_SQC_VFT_BUF_SIZE (7ULL << 8) +#define QM_SQC_VFT_SQC_SIZE (5ULL << 12) +#define QM_SQC_VFT_INDEX_NUMBER (1ULL << 16) +#define QM_SQC_VFT_START_SQN_SHIFT 28 +#define QM_SQC_VFT_VALID (1ULL << 44) +#define QM_SQC_VFT_SQN_SHIFT 45 +#define QM_CQC_VFT_BUF_SIZE (7ULL << 8) +#define QM_CQC_VFT_SQC_SIZE (5ULL << 12) +#define QM_CQC_VFT_INDEX_NUMBER (1ULL << 16) +#define QM_CQC_VFT_VALID (1ULL << 28) + +#define QM_SQC_VFT_BASE_SHIFT_V2 28 +#define QM_SQC_VFT_BASE_MASK_V2 GENMASK(5, 0) +#define QM_SQC_VFT_NUM_SHIFT_V2 45 +#define QM_SQC_VFT_NUM_MASK_v2 GENMASK(9, 0) + +#define QM_DFX_CNT_CLR_CE 0x100118 + +#define QM_ABNORMAL_INT_SOURCE 0x100000 +#define QM_ABNORMAL_INT_MASK 0x100004 +#define QM_ABNORMAL_INT_MASK_VALUE 0x1fff +#define QM_ABNORMAL_INT_STATUS 0x100008 +#define QM_ABNORMAL_INF00 0x100010 +#define QM_FIFO_OVERFLOW_TYPE 0xc0 +#define QM_FIFO_OVERFLOW_TYPE_SHIFT 6 +#define QM_FIFO_OVERFLOW_VF 0x3f +#define QM_ABNORMAL_INF01 0x100014 +#define QM_DB_TIMEOUT_TYPE 0xc0 +#define QM_DB_TIMEOUT_TYPE_SHIFT 6 +#define QM_DB_TIMEOUT_VF 0x3f +#define QM_RAS_CE_ENABLE 0x1000ec +#define QM_RAS_FE_ENABLE 0x1000f0 +#define QM_RAS_NFE_ENABLE 0x1000f4 +#define QM_RAS_CE_THRESHOLD 0x1000f8 +#define QM_RAS_CE_TIMES_PER_IRQ 1 +#define QM_RAS_MSI_INT_SEL 0x1040f4 + +#define QM_CACHE_WB_START 0x204 +#define QM_CACHE_WB_DONE 0x208 + +#define PCI_BAR_2 2 +#define QM_SQE_DATA_ALIGN_MASK GENMASK(6, 0) +#define QMC_ALIGN(sz) ALIGN(sz, 32) + +#define QM_DBG_TMP_BUF_LEN 22 + +#define QM_MK_CQC_DW3_V1(hop_num, pg_sz, buf_sz, cqe_sz) \ + (((hop_num) << QM_CQ_HOP_NUM_SHIFT) | \ + ((pg_sz) << QM_CQ_PAGE_SIZE_SHIFT) | \ + ((buf_sz) << QM_CQ_BUF_SIZE_SHIFT) | \ + ((cqe_sz) << QM_CQ_CQE_SIZE_SHIFT)) + +#define QM_MK_CQC_DW3_V2(cqe_sz) \ + ((QM_Q_DEPTH - 1) | ((cqe_sz) << QM_CQ_CQE_SIZE_SHIFT)) + +#define QM_MK_SQC_W13(priority, orders, alg_type) \ + (((priority) << QM_SQ_PRIORITY_SHIFT) | \ + ((orders) << QM_SQ_ORDERS_SHIFT) | \ + (((alg_type) & QM_SQ_TYPE_MASK) << QM_SQ_TYPE_SHIFT)) + +#define QM_MK_SQC_DW3_V1(hop_num, pg_sz, buf_sz, sqe_sz) \ + (((hop_num) << QM_SQ_HOP_NUM_SHIFT) | \ + ((pg_sz) << QM_SQ_PAGE_SIZE_SHIFT) | \ + ((buf_sz) << QM_SQ_BUF_SIZE_SHIFT) | \ + ((u32)ilog2(sqe_sz) << QM_SQ_SQE_SIZE_SHIFT)) + +#define QM_MK_SQC_DW3_V2(sqe_sz) \ + ((QM_Q_DEPTH - 1) | ((u32)ilog2(sqe_sz) << QM_SQ_SQE_SIZE_SHIFT)) + +#define INIT_QC_COMMON(qc, base, pasid) do { \ + (qc)->head = 0; \ + (qc)->tail = 0; \ + (qc)->base_l = lower_32_bits(base); \ + (qc)->base_h = upper_32_bits(base); \ + (qc)->dw3 = 0; \ + (qc)->w8 = 0; \ + (qc)->rsvd0 = 0; \ + (qc)->pasid = pasid; \ + (qc)->w11 = 0; \ + (qc)->rsvd1 = 0; \ +} while (0) + +enum vft_type { + SQC_VFT = 0, + CQC_VFT, +}; + +struct qm_cqe { + __le32 rsvd0; + __le16 cmd_id; + __le16 rsvd1; + __le16 sq_head; + __le16 sq_num; + __le16 rsvd2; + __le16 w7; +}; + +struct qm_eqe { + __le32 dw0; +}; + +struct qm_aeqe { + __le32 dw0; +}; + +struct qm_sqc { + __le16 head; + __le16 tail; + __le32 base_l; + __le32 base_h; + __le32 dw3; + __le16 w8; + __le16 rsvd0; + __le16 pasid; + __le16 w11; + __le16 cq_num; + __le16 w13; + __le32 rsvd1; +}; + +struct qm_cqc { + __le16 head; + __le16 tail; + __le32 base_l; + __le32 base_h; + __le32 dw3; + __le16 w8; + __le16 rsvd0; + __le16 pasid; + __le16 w11; + __le32 dw6; + __le32 rsvd1; +}; + +struct qm_eqc { + __le16 head; + __le16 tail; + __le32 base_l; + __le32 base_h; + __le32 dw3; + __le32 rsvd[2]; + __le32 dw6; +}; + +struct qm_aeqc { + __le16 head; + __le16 tail; + __le32 base_l; + __le32 base_h; + __le32 dw3; + __le32 rsvd[2]; + __le32 dw6; +}; + +struct qm_mailbox { + __le16 w0; + __le16 queue_num; + __le32 base_l; + __le32 base_h; + __le32 rsvd; +}; + +struct qm_doorbell { + __le16 queue_num; + __le16 cmd; + __le16 index; + __le16 priority; +}; + +struct hisi_qm_hw_ops { + int (*get_vft)(struct hisi_qm *qm, u32 *base, u32 *number); + void (*qm_db)(struct hisi_qm *qm, u16 qn, + u8 cmd, u16 index, u8 priority); + u32 (*get_irq_num)(struct hisi_qm *qm); + int (*debug_init)(struct hisi_qm *qm); + void (*hw_error_init)(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe, + u32 msi); + pci_ers_result_t (*hw_error_handle)(struct hisi_qm *qm); +}; + +static const char * const qm_debug_file_name[] = { + [CURRENT_Q] = "current_q", + [CLEAR_ENABLE] = "clear_enable", +}; + +struct hisi_qm_hw_error { + u32 int_msk; + const char *msg; +}; + +static const struct hisi_qm_hw_error qm_hw_error[] = { + { .int_msk = BIT(0), .msg = "qm_axi_rresp" }, + { .int_msk = BIT(1), .msg = "qm_axi_bresp" }, + { .int_msk = BIT(2), .msg = "qm_ecc_mbit" }, + { .int_msk = BIT(3), .msg = "qm_ecc_1bit" }, + { .int_msk = BIT(4), .msg = "qm_acc_get_task_timeout" }, + { .int_msk = BIT(5), .msg = "qm_acc_do_task_timeout" }, + { .int_msk = BIT(6), .msg = "qm_acc_wb_not_ready_timeout" }, + { .int_msk = BIT(7), .msg = "qm_sq_cq_vf_invalid" }, + { .int_msk = BIT(8), .msg = "qm_cq_vf_invalid" }, + { .int_msk = BIT(9), .msg = "qm_sq_vf_invalid" }, + { .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" }, + { /* sentinel */ } +}; + +static const char * const qm_db_timeout[] = { + "sq", "cq", "eq", "aeq", +}; + +static const char * const qm_fifo_overflow[] = { + "cq", "eq", "aeq", +}; + +/* return 0 mailbox ready, -ETIMEDOUT hardware timeout */ +static int qm_wait_mb_ready(struct hisi_qm *qm) +{ + u32 val; + + return readl_relaxed_poll_timeout(qm->io_base + QM_MB_CMD_SEND_BASE, + val, !((val >> QM_MB_BUSY_SHIFT) & + 0x1), 10, 1000); +} + +/* 128 bit should be written to hardware at one time to trigger a mailbox */ +static void qm_mb_write(struct hisi_qm *qm, const void *src) +{ + void __iomem *fun_base = qm->io_base + QM_MB_CMD_SEND_BASE; + unsigned long tmp0 = 0, tmp1 = 0; + + asm volatile("ldp %0, %1, %3\n" + "stp %0, %1, %2\n" + "dsb sy\n" + : "=&r" (tmp0), + "=&r" (tmp1), + "+Q" (*((char *)fun_base)) + : "Q" (*((char *)src)) + : "memory"); +} + +static int qm_mb(struct hisi_qm *qm, u8 cmd, dma_addr_t dma_addr, u16 queue, + bool op) +{ + struct qm_mailbox mailbox; + int ret = 0; + + dev_dbg(&qm->pdev->dev, "QM mailbox request to q%u: %u-%llx\n", + queue, cmd, (unsigned long long)dma_addr); + + mailbox.w0 = cmd | + (op ? 0x1 << QM_MB_OP_SHIFT : 0) | + (0x1 << QM_MB_BUSY_SHIFT); + mailbox.queue_num = queue; + mailbox.base_l = lower_32_bits(dma_addr); + mailbox.base_h = upper_32_bits(dma_addr); + mailbox.rsvd = 0; + + mutex_lock(&qm->mailbox_lock); + + if (unlikely(qm_wait_mb_ready(qm))) { + ret = -EBUSY; + dev_err(&qm->pdev->dev, "QM mailbox is busy to start!\n"); + goto busy_unlock; + } + + qm_mb_write(qm, &mailbox); + + if (unlikely(qm_wait_mb_ready(qm))) { + ret = -EBUSY; + dev_err(&qm->pdev->dev, "QM mailbox operation timeout!\n"); + goto busy_unlock; + } + +busy_unlock: + mutex_unlock(&qm->mailbox_lock); + + return ret; +} + +static void qm_db_v1(struct hisi_qm *qm, u16 qn, u8 cmd, u16 index, u8 priority) +{ + u64 doorbell; + + doorbell = qn | ((u64)cmd << QM_DB_CMD_SHIFT_V1) | + ((u64)index << QM_DB_INDEX_SHIFT_V1) | + ((u64)priority << QM_DB_PRIORITY_SHIFT_V1); + + writeq(doorbell, qm->io_base + QM_DOORBELL_BASE_V1); +} + +static void qm_db_v2(struct hisi_qm *qm, u16 qn, u8 cmd, u16 index, u8 priority) +{ + u64 doorbell; + u64 dbase; + u16 randata = 0; + + if (cmd == QM_DOORBELL_CMD_SQ || cmd == QM_DOORBELL_CMD_CQ) + dbase = QM_DOORBELL_SQ_CQ_BASE_V2; + else + dbase = 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); +} + +static void qm_db(struct hisi_qm *qm, u16 qn, u8 cmd, u16 index, u8 priority) +{ + dev_dbg(&qm->pdev->dev, "QM doorbell request: qn=%u, cmd=%u, index=%u\n", + qn, cmd, index); + + qm->ops->qm_db(qm, qn, cmd, index, priority); +} + +static int qm_dev_mem_reset(struct hisi_qm *qm) +{ + u32 val; + + writel(0x1, qm->io_base + QM_MEM_START_INIT); + return readl_relaxed_poll_timeout(qm->io_base + QM_MEM_INIT_DONE, val, + val & BIT(0), 10, 1000); +} + +static u32 qm_get_irq_num_v1(struct hisi_qm *qm) +{ + return QM_IRQ_NUM_V1; +} + +static u32 qm_get_irq_num_v2(struct hisi_qm *qm) +{ + if (qm->fun_type == QM_HW_PF) + return QM_IRQ_NUM_PF_V2; + else + return QM_IRQ_NUM_VF_V2; +} + +static struct hisi_qp *qm_to_hisi_qp(struct hisi_qm *qm, struct qm_eqe *eqe) +{ + u16 cqn = eqe->dw0 & QM_EQE_CQN_MASK; + + return qm->qp_array[cqn]; +} + +static void qm_cq_head_update(struct hisi_qp *qp) +{ + if (qp->qp_status.cq_head == QM_Q_DEPTH - 1) { + qp->qp_status.cqc_phase = !qp->qp_status.cqc_phase; + qp->qp_status.cq_head = 0; + } else { + qp->qp_status.cq_head++; + } +} + +static void qm_poll_qp(struct hisi_qp *qp, struct hisi_qm *qm) +{ + struct qm_cqe *cqe = qp->cqe + qp->qp_status.cq_head; + + if (qp->req_cb) { + while (QM_CQE_PHASE(cqe) == qp->qp_status.cqc_phase) { + dma_rmb(); + qp->req_cb(qp, qp->sqe + qm->sqe_size * cqe->sq_head); + qm_cq_head_update(qp); + cqe = qp->cqe + qp->qp_status.cq_head; + qm_db(qm, qp->qp_id, QM_DOORBELL_CMD_CQ, + qp->qp_status.cq_head, 0); + atomic_dec(&qp->qp_status.used); + } + + /* set c_flag */ + qm_db(qm, qp->qp_id, QM_DOORBELL_CMD_CQ, + qp->qp_status.cq_head, 1); + } +} + +static void qm_qp_work_func(struct work_struct *work) +{ + struct hisi_qp *qp; + + qp = container_of(work, struct hisi_qp, work); + qm_poll_qp(qp, qp->qm); +} + +static irqreturn_t qm_irq_handler(int irq, void *data) +{ + struct hisi_qm *qm = data; + struct qm_eqe *eqe = qm->eqe + qm->status.eq_head; + struct hisi_qp *qp; + int eqe_num = 0; + + while (QM_EQE_PHASE(eqe) == qm->status.eqc_phase) { + eqe_num++; + qp = qm_to_hisi_qp(qm, eqe); + if (qp) + queue_work(qp->wq, &qp->work); + + if (qm->status.eq_head == QM_Q_DEPTH - 1) { + qm->status.eqc_phase = !qm->status.eqc_phase; + eqe = qm->eqe; + qm->status.eq_head = 0; + } else { + eqe++; + qm->status.eq_head++; + } + + if (eqe_num == QM_Q_DEPTH / 2 - 1) { + eqe_num = 0; + qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0); + } + } + + qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0); + + return IRQ_HANDLED; +} + +static irqreturn_t qm_irq(int irq, void *data) +{ + struct hisi_qm *qm = data; + + if (readl(qm->io_base + QM_VF_EQ_INT_SOURCE)) + return qm_irq_handler(irq, data); + + dev_err(&qm->pdev->dev, "invalid int source\n"); + qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0); + + return IRQ_NONE; +} + +static irqreturn_t qm_aeq_irq(int irq, void *data) +{ + struct hisi_qm *qm = data; + struct qm_aeqe *aeqe = qm->aeqe + qm->status.aeq_head; + u32 type; + + if (!readl(qm->io_base + QM_VF_AEQ_INT_SOURCE)) + return IRQ_NONE; + + while (QM_AEQE_PHASE(aeqe) == qm->status.aeqc_phase) { + type = aeqe->dw0 >> QM_AEQE_TYPE_SHIFT; + if (type < ARRAY_SIZE(qm_fifo_overflow)) + dev_err(&qm->pdev->dev, "%s overflow\n", + qm_fifo_overflow[type]); + else + dev_err(&qm->pdev->dev, "unknown error type %d\n", + type); + + if (qm->status.aeq_head == QM_Q_DEPTH - 1) { + qm->status.aeqc_phase = !qm->status.aeqc_phase; + aeqe = qm->aeqe; + qm->status.aeq_head = 0; + } else { + aeqe++; + qm->status.aeq_head++; + } + + qm_db(qm, 0, QM_DOORBELL_CMD_AEQ, qm->status.aeq_head, 0); + } + + return IRQ_HANDLED; +} + +static irqreturn_t qm_abnormal_irq(int irq, void *data) +{ + const struct hisi_qm_hw_error *err = qm_hw_error; + struct hisi_qm *qm = data; + struct device *dev = &qm->pdev->dev; + u32 error_status, tmp; + + /* read err sts */ + tmp = readl(qm->io_base + QM_ABNORMAL_INT_STATUS); + error_status = qm->msi_mask & tmp; + + while (err->msg) { + if (err->int_msk & error_status) + dev_err(dev, "%s [error status=0x%x] found\n", + err->msg, err->int_msk); + + err++; + } + + /* clear err sts */ + writel(error_status, qm->io_base + QM_ABNORMAL_INT_SOURCE); + + return IRQ_HANDLED; +} + +static int qm_irq_register(struct hisi_qm *qm) +{ + struct pci_dev *pdev = qm->pdev; + int ret; + + ret = request_irq(pci_irq_vector(pdev, QM_EQ_EVENT_IRQ_VECTOR), + qm_irq, IRQF_SHARED, qm->dev_name, qm); + if (ret) + return ret; + + if (qm->ver == QM_HW_V2) { + ret = request_irq(pci_irq_vector(pdev, QM_AEQ_EVENT_IRQ_VECTOR), + qm_aeq_irq, IRQF_SHARED, qm->dev_name, qm); + if (ret) + goto err_aeq_irq; + + if (qm->fun_type == QM_HW_PF) { + ret = request_irq(pci_irq_vector(pdev, + QM_ABNORMAL_EVENT_IRQ_VECTOR), + qm_abnormal_irq, IRQF_SHARED, + qm->dev_name, qm); + if (ret) + goto err_abonormal_irq; + } + } + + return 0; + +err_abonormal_irq: + free_irq(pci_irq_vector(pdev, QM_AEQ_EVENT_IRQ_VECTOR), qm); +err_aeq_irq: + free_irq(pci_irq_vector(pdev, QM_EQ_EVENT_IRQ_VECTOR), qm); + return ret; +} + +static void qm_irq_unregister(struct hisi_qm *qm) +{ + struct pci_dev *pdev = qm->pdev; + + free_irq(pci_irq_vector(pdev, QM_EQ_EVENT_IRQ_VECTOR), qm); + + if (qm->ver == QM_HW_V2) { + free_irq(pci_irq_vector(pdev, QM_AEQ_EVENT_IRQ_VECTOR), qm); + + if (qm->fun_type == QM_HW_PF) + free_irq(pci_irq_vector(pdev, + QM_ABNORMAL_EVENT_IRQ_VECTOR), qm); + } +} + +static void qm_init_qp_status(struct hisi_qp *qp) +{ + struct hisi_qp_status *qp_status = &qp->qp_status; + + qp_status->sq_tail = 0; + qp_status->cq_head = 0; + qp_status->cqc_phase = 1; + qp_status->flags = 0; +} + +static void qm_vft_data_cfg(struct hisi_qm *qm, enum vft_type type, u32 base, + u32 number) +{ + u64 tmp = 0; + + if (number > 0) { + switch (type) { + case SQC_VFT: + switch (qm->ver) { + case QM_HW_V1: + tmp = QM_SQC_VFT_BUF_SIZE | + QM_SQC_VFT_SQC_SIZE | + QM_SQC_VFT_INDEX_NUMBER | + QM_SQC_VFT_VALID | + (u64)base << QM_SQC_VFT_START_SQN_SHIFT; + break; + case QM_HW_V2: + tmp = (u64)base << QM_SQC_VFT_START_SQN_SHIFT | + QM_SQC_VFT_VALID | + (u64)(number - 1) << QM_SQC_VFT_SQN_SHIFT; + break; + case QM_HW_UNKNOWN: + break; + } + break; + case CQC_VFT: + switch (qm->ver) { + case QM_HW_V1: + tmp = QM_CQC_VFT_BUF_SIZE | + QM_CQC_VFT_SQC_SIZE | + QM_CQC_VFT_INDEX_NUMBER | + QM_CQC_VFT_VALID; + break; + case QM_HW_V2: + tmp = QM_CQC_VFT_VALID; + break; + case QM_HW_UNKNOWN: + break; + } + break; + } + } + + writel(lower_32_bits(tmp), qm->io_base + QM_VFT_CFG_DATA_L); + writel(upper_32_bits(tmp), qm->io_base + QM_VFT_CFG_DATA_H); +} + +static int qm_set_vft_common(struct hisi_qm *qm, enum vft_type type, + u32 fun_num, u32 base, u32 number) +{ + unsigned int val; + int ret; + + ret = readl_relaxed_poll_timeout(qm->io_base + QM_VFT_CFG_RDY, val, + val & BIT(0), 10, 1000); + if (ret) + return ret; + + writel(0x0, qm->io_base + QM_VFT_CFG_OP_WR); + writel(type, qm->io_base + QM_VFT_CFG_TYPE); + writel(fun_num, qm->io_base + QM_VFT_CFG); + + qm_vft_data_cfg(qm, type, base, number); + + writel(0x0, qm->io_base + QM_VFT_CFG_RDY); + writel(0x1, qm->io_base + QM_VFT_CFG_OP_ENABLE); + + return readl_relaxed_poll_timeout(qm->io_base + QM_VFT_CFG_RDY, val, + val & BIT(0), 10, 1000); +} + +/* The config should be conducted after qm_dev_mem_reset() */ +static int qm_set_sqc_cqc_vft(struct hisi_qm *qm, u32 fun_num, u32 base, + u32 number) +{ + int ret, i; + + for (i = SQC_VFT; i <= CQC_VFT; i++) { + ret = qm_set_vft_common(qm, i, fun_num, base, number); + if (ret) + return ret; + } + + return 0; +} + +static int qm_get_vft_v2(struct hisi_qm *qm, u32 *base, u32 *number) +{ + u64 sqc_vft; + int ret; + + ret = qm_mb(qm, QM_MB_CMD_SQC_VFT_V2, 0, 0, 1); + if (ret) + return ret; + + sqc_vft = readl(qm->io_base + QM_MB_CMD_DATA_ADDR_L) | + ((u64)readl(qm->io_base + QM_MB_CMD_DATA_ADDR_H) << 32); + *base = QM_SQC_VFT_BASE_MASK_V2 & (sqc_vft >> QM_SQC_VFT_BASE_SHIFT_V2); + *number = (QM_SQC_VFT_NUM_MASK_v2 & + (sqc_vft >> QM_SQC_VFT_NUM_SHIFT_V2)) + 1; + + return 0; +} + +static struct hisi_qm *file_to_qm(struct debugfs_file *file) +{ + struct qm_debug *debug = file->debug; + + return container_of(debug, struct hisi_qm, debug); +} + +static u32 current_q_read(struct debugfs_file *file) +{ + struct hisi_qm *qm = file_to_qm(file); + + return readl(qm->io_base + QM_DFX_SQE_CNT_VF_SQN) >> QM_DFX_QN_SHIFT; +} + +static int current_q_write(struct debugfs_file *file, u32 val) +{ + struct hisi_qm *qm = file_to_qm(file); + u32 tmp; + + if (val >= qm->debug.curr_qm_qp_num) + return -EINVAL; + + tmp = val << QM_DFX_QN_SHIFT | + (readl(qm->io_base + QM_DFX_SQE_CNT_VF_SQN) & CURRENT_FUN_MASK); + writel(tmp, qm->io_base + QM_DFX_SQE_CNT_VF_SQN); + + tmp = val << QM_DFX_QN_SHIFT | + (readl(qm->io_base + QM_DFX_CQE_CNT_VF_CQN) & CURRENT_FUN_MASK); + writel(tmp, qm->io_base + QM_DFX_CQE_CNT_VF_CQN); + + return 0; +} + +static u32 clear_enable_read(struct debugfs_file *file) +{ + struct hisi_qm *qm = file_to_qm(file); + + return readl(qm->io_base + QM_DFX_CNT_CLR_CE); +} + +/* rd_clr_ctrl 1 enable read clear, otherwise 0 disable it */ +static int clear_enable_write(struct debugfs_file *file, u32 rd_clr_ctrl) +{ + struct hisi_qm *qm = file_to_qm(file); + + if (rd_clr_ctrl > 1) + return -EINVAL; + + writel(rd_clr_ctrl, qm->io_base + QM_DFX_CNT_CLR_CE); + + return 0; +} + +static ssize_t qm_debug_read(struct file *filp, char __user *buf, + size_t count, loff_t *pos) +{ + struct debugfs_file *file = filp->private_data; + enum qm_debug_file index = file->index; + char tbuf[QM_DBG_TMP_BUF_LEN]; + u32 val; + int ret; + + mutex_lock(&file->lock); + switch (index) { + case CURRENT_Q: + val = current_q_read(file); + break; + case CLEAR_ENABLE: + val = clear_enable_read(file); + break; + default: + mutex_unlock(&file->lock); + return -EINVAL; + } + mutex_unlock(&file->lock); + ret = sprintf(tbuf, "%u\n", val); + return simple_read_from_buffer(buf, count, pos, tbuf, ret); +} + +static ssize_t qm_debug_write(struct file *filp, const char __user *buf, + size_t count, loff_t *pos) +{ + struct debugfs_file *file = filp->private_data; + enum qm_debug_file index = file->index; + unsigned long val; + char tbuf[QM_DBG_TMP_BUF_LEN]; + int len, ret; + + if (*pos != 0) + return 0; + + if (count >= QM_DBG_TMP_BUF_LEN) + return -ENOSPC; + + len = simple_write_to_buffer(tbuf, QM_DBG_TMP_BUF_LEN - 1, pos, buf, + count); + if (len < 0) + return len; + + tbuf[len] = '\0'; + if (kstrtoul(tbuf, 0, &val)) + return -EFAULT; + + mutex_lock(&file->lock); + switch (index) { + 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; + +err_input: + mutex_unlock(&file->lock); + return ret; +} + +static const struct file_operations qm_debug_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = qm_debug_read, + .write = qm_debug_write, +}; + +struct qm_dfx_registers { + char *reg_name; + u64 reg_offset; +}; + +#define CNT_CYC_REGS_NUM 10 +static struct qm_dfx_registers qm_dfx_regs[] = { + /* XXX_CNT are reading clear register */ + {"QM_ECC_1BIT_CNT ", 0x104000ull}, + {"QM_ECC_MBIT_CNT ", 0x104008ull}, + {"QM_DFX_MB_CNT ", 0x104018ull}, + {"QM_DFX_DB_CNT ", 0x104028ull}, + {"QM_DFX_SQE_CNT ", 0x104038ull}, + {"QM_DFX_CQE_CNT ", 0x104048ull}, + {"QM_DFX_SEND_SQE_TO_ACC_CNT ", 0x104050ull}, + {"QM_DFX_WB_SQE_FROM_ACC_CNT ", 0x104058ull}, + {"QM_DFX_ACC_FINISH_CNT ", 0x104060ull}, + {"QM_DFX_CQE_ERR_CNT ", 0x1040b4ull}, + {"QM_DFX_FUNS_ACTIVE_ST ", 0x200ull}, + {"QM_ECC_1BIT_INF ", 0x104004ull}, + {"QM_ECC_MBIT_INF ", 0x10400cull}, + {"QM_DFX_ACC_RDY_VLD0 ", 0x1040a0ull}, + {"QM_DFX_ACC_RDY_VLD1 ", 0x1040a4ull}, + {"QM_DFX_AXI_RDY_VLD ", 0x1040a8ull}, + {"QM_DFX_FF_ST0 ", 0x1040c8ull}, + {"QM_DFX_FF_ST1 ", 0x1040ccull}, + {"QM_DFX_FF_ST2 ", 0x1040d0ull}, + {"QM_DFX_FF_ST3 ", 0x1040d4ull}, + {"QM_DFX_FF_ST4 ", 0x1040d8ull}, + {"QM_DFX_FF_ST5 ", 0x1040dcull}, + {"QM_DFX_FF_ST6 ", 0x1040e0ull}, + {"QM_IN_IDLE_ST ", 0x1040e4ull}, + { NULL, 0} +}; + +static struct qm_dfx_registers qm_vf_dfx_regs[] = { + {"QM_DFX_FUNS_ACTIVE_ST ", 0x200ull}, + { NULL, 0} +}; + +static int qm_regs_show(struct seq_file *s, void *unused) +{ + struct hisi_qm *qm = s->private; + struct qm_dfx_registers *regs; + u32 val; + + if (qm->fun_type == QM_HW_PF) + regs = qm_dfx_regs; + else + regs = qm_vf_dfx_regs; + + while (regs->reg_name) { + val = readl(qm->io_base + regs->reg_offset); + seq_printf(s, "%s= 0x%08x\n", regs->reg_name, val); + regs++; + } + + return 0; +} + +static int qm_regs_open(struct inode *inode, struct file *file) +{ + return single_open(file, qm_regs_show, inode->i_private); +} + +static const struct file_operations qm_regs_fops = { + .owner = THIS_MODULE, + .open = qm_regs_open, + .read = seq_read, + .release = single_release, +}; + +static int qm_create_debugfs_file(struct hisi_qm *qm, enum qm_debug_file index) +{ + struct dentry *qm_d = qm->debug.qm_d, *tmp; + struct debugfs_file *file = qm->debug.files + index; + + tmp = debugfs_create_file(qm_debug_file_name[index], 0600, qm_d, file, + &qm_debug_fops); + if (IS_ERR(tmp)) + return -ENOENT; + + file->index = index; + mutex_init(&file->lock); + file->debug = &qm->debug; + + return 0; +} + +static void qm_hw_error_init_v1(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe, + u32 msi) +{ + dev_info(&qm->pdev->dev, + "QM v%d does not support hw error handle\n", qm->ver); + + writel(QM_ABNORMAL_INT_MASK_VALUE, qm->io_base + QM_ABNORMAL_INT_MASK); +} + +static void qm_hw_error_init_v2(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe, + u32 msi) +{ + u32 irq_enable = ce | nfe | fe | msi; + u32 irq_unmask = ~irq_enable; + + qm->error_mask = ce | nfe | fe; + qm->msi_mask = msi; + + /* configure error type */ + writel(ce, qm->io_base + QM_RAS_CE_ENABLE); + writel(QM_RAS_CE_TIMES_PER_IRQ, qm->io_base + QM_RAS_CE_THRESHOLD); + writel(nfe, qm->io_base + QM_RAS_NFE_ENABLE); + writel(fe, qm->io_base + QM_RAS_FE_ENABLE); + + /* use RAS irq default, so only set QM_RAS_MSI_INT_SEL for MSI */ + writel(msi, qm->io_base + QM_RAS_MSI_INT_SEL); + + irq_unmask &= readl(qm->io_base + QM_ABNORMAL_INT_MASK); + writel(irq_unmask, qm->io_base + QM_ABNORMAL_INT_MASK); +} + +static void qm_log_hw_error(struct hisi_qm *qm, u32 error_status) +{ + const struct hisi_qm_hw_error *err = qm_hw_error; + struct device *dev = &qm->pdev->dev; + u32 reg_val, type, vf_num; + + while (err->msg) { + if (err->int_msk & error_status) { + dev_err(dev, "%s [error status=0x%x] found\n", + err->msg, err->int_msk); + + if (error_status & QM_DB_TIMEOUT) { + reg_val = readl(qm->io_base + + QM_ABNORMAL_INF01); + type = (reg_val & QM_DB_TIMEOUT_TYPE) >> + QM_DB_TIMEOUT_TYPE_SHIFT; + vf_num = reg_val & QM_DB_TIMEOUT_VF; + dev_err(dev, "qm %s doorbell timeout in function %u\n", + qm_db_timeout[type], vf_num); + } + + if (error_status & QM_OF_FIFO_OF) { + reg_val = readl(qm->io_base + + QM_ABNORMAL_INF00); + type = (reg_val & QM_FIFO_OVERFLOW_TYPE) >> + QM_FIFO_OVERFLOW_TYPE_SHIFT; + vf_num = reg_val & QM_FIFO_OVERFLOW_VF; + + if (type < ARRAY_SIZE(qm_fifo_overflow)) + dev_err(dev, "qm %s fifo overflow in function %u\n", + qm_fifo_overflow[type], + vf_num); + else + dev_err(dev, "unknown error type\n"); + } + } + err++; + } +} + +static pci_ers_result_t qm_hw_error_handle_v2(struct hisi_qm *qm) +{ + u32 error_status, tmp; + + /* read err sts */ + tmp = readl(qm->io_base + QM_ABNORMAL_INT_STATUS); + error_status = qm->error_mask & tmp; + + if (error_status) { + qm_log_hw_error(qm, error_status); + + /* clear err sts */ + writel(error_status, qm->io_base + QM_ABNORMAL_INT_SOURCE); + + return PCI_ERS_RESULT_NEED_RESET; + } + + return PCI_ERS_RESULT_RECOVERED; +} + +static const struct hisi_qm_hw_ops qm_hw_ops_v1 = { + .qm_db = qm_db_v1, + .get_irq_num = qm_get_irq_num_v1, + .hw_error_init = qm_hw_error_init_v1, +}; + +static const struct hisi_qm_hw_ops qm_hw_ops_v2 = { + .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_handle = qm_hw_error_handle_v2, +}; + +static void *qm_get_avail_sqe(struct hisi_qp *qp) +{ + struct hisi_qp_status *qp_status = &qp->qp_status; + u16 sq_tail = qp_status->sq_tail; + + if (unlikely(atomic_read(&qp->qp_status.used) == QM_Q_DEPTH)) + return NULL; + + return qp->sqe + sq_tail * qp->qm->sqe_size; +} + +/** + * hisi_qm_create_qp() - Create a queue pair from qm. + * @qm: The qm we create a qp from. + * @alg_type: Accelerator specific algorithm type in sqc. + * + * return created qp, -EBUSY if all qps in qm allocated, -ENOMEM if allocating + * qp memory fails. + */ +struct hisi_qp *hisi_qm_create_qp(struct hisi_qm *qm, u8 alg_type) +{ + struct device *dev = &qm->pdev->dev; + struct hisi_qp *qp; + int qp_id, ret; + + qp = kzalloc(sizeof(*qp), GFP_KERNEL); + if (!qp) + return ERR_PTR(-ENOMEM); + + write_lock(&qm->qps_lock); + + qp_id = find_first_zero_bit(qm->qp_bitmap, qm->qp_num); + if (qp_id >= qm->qp_num) { + write_unlock(&qm->qps_lock); + dev_info(&qm->pdev->dev, "QM all queues are busy!\n"); + ret = -EBUSY; + goto err_free_qp; + } + set_bit(qp_id, qm->qp_bitmap); + qm->qp_array[qp_id] = qp; + + write_unlock(&qm->qps_lock); + + qp->qm = qm; + + if (qm->use_dma_api) { + qp->qdma.size = qm->sqe_size * QM_Q_DEPTH + + sizeof(struct qm_cqe) * QM_Q_DEPTH; + qp->qdma.va = dma_alloc_coherent(dev, qp->qdma.size, + &qp->qdma.dma, GFP_KERNEL); + if (!qp->qdma.va) { + ret = -ENOMEM; + goto err_clear_bit; + } + + dev_dbg(dev, "allocate qp dma buf(va=%pK, dma=%pad, size=%zx)\n", + qp->qdma.va, &qp->qdma.dma, qp->qdma.size); + } + + qp->qp_id = qp_id; + qp->alg_type = alg_type; + INIT_WORK(&qp->work, qm_qp_work_func); + qp->wq = alloc_workqueue("hisi_qm", WQ_UNBOUND | WQ_HIGHPRI | + WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 0); + if (!qp->wq) { + ret = -EFAULT; + goto err_free_qp_mem; + } + + return qp; + +err_free_qp_mem: + if (qm->use_dma_api) + dma_free_coherent(dev, qp->qdma.size, qp->qdma.va, + qp->qdma.dma); +err_clear_bit: + write_lock(&qm->qps_lock); + qm->qp_array[qp_id] = NULL; + clear_bit(qp_id, qm->qp_bitmap); + write_unlock(&qm->qps_lock); +err_free_qp: + kfree(qp); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(hisi_qm_create_qp); + +/** + * hisi_qm_release_qp() - Release a qp back to its qm. + * @qp: The qp we want to release. + * + * This function releases the resource of a qp. + */ +void hisi_qm_release_qp(struct hisi_qp *qp) +{ + struct hisi_qm *qm = qp->qm; + struct qm_dma *qdma = &qp->qdma; + struct device *dev = &qm->pdev->dev; + + if (qm->use_dma_api && qdma->va) + dma_free_coherent(dev, qdma->size, qdma->va, qdma->dma); + + write_lock(&qm->qps_lock); + qm->qp_array[qp->qp_id] = NULL; + clear_bit(qp->qp_id, qm->qp_bitmap); + write_unlock(&qm->qps_lock); + + kfree(qp); +} +EXPORT_SYMBOL_GPL(hisi_qm_release_qp); + +static int qm_qp_ctx_cfg(struct hisi_qp *qp, int qp_id, int pasid) +{ + struct hisi_qm *qm = qp->qm; + struct device *dev = &qm->pdev->dev; + enum qm_hw_ver ver = qm->ver; + struct qm_sqc *sqc; + struct qm_cqc *cqc; + dma_addr_t sqc_dma; + dma_addr_t cqc_dma; + int ret; + + qm_init_qp_status(qp); + + sqc = kzalloc(sizeof(struct qm_sqc), GFP_KERNEL); + if (!sqc) + return -ENOMEM; + sqc_dma = dma_map_single(dev, sqc, sizeof(struct qm_sqc), + DMA_TO_DEVICE); + if (dma_mapping_error(dev, sqc_dma)) { + kfree(sqc); + return -ENOMEM; + } + + INIT_QC_COMMON(sqc, qp->sqe_dma, pasid); + if (ver == QM_HW_V1) { + sqc->dw3 = QM_MK_SQC_DW3_V1(0, 0, 0, qm->sqe_size); + sqc->w8 = QM_Q_DEPTH - 1; + } else if (ver == QM_HW_V2) { + sqc->dw3 = QM_MK_SQC_DW3_V2(qm->sqe_size); + sqc->w8 = 0; /* rand_qc */ + } + sqc->cq_num = qp_id; + sqc->w13 = QM_MK_SQC_W13(0, 1, qp->alg_type); + + ret = qm_mb(qm, QM_MB_CMD_SQC, sqc_dma, qp_id, 0); + dma_unmap_single(dev, sqc_dma, sizeof(struct qm_sqc), DMA_TO_DEVICE); + kfree(sqc); + if (ret) + return ret; + + cqc = kzalloc(sizeof(struct qm_cqc), GFP_KERNEL); + if (!cqc) + return -ENOMEM; + cqc_dma = dma_map_single(dev, cqc, sizeof(struct qm_cqc), + DMA_TO_DEVICE); + if (dma_mapping_error(dev, cqc_dma)) { + kfree(cqc); + return -ENOMEM; + } + + INIT_QC_COMMON(cqc, qp->cqe_dma, pasid); + if (ver == QM_HW_V1) { + cqc->dw3 = QM_MK_CQC_DW3_V1(0, 0, 0, 4); + cqc->w8 = QM_Q_DEPTH - 1; + } else if (ver == QM_HW_V2) { + cqc->dw3 = QM_MK_CQC_DW3_V2(4); + cqc->w8 = 0; + } + cqc->dw6 = 1 << QM_CQ_PHASE_SHIFT | 1 << QM_CQ_FLAG_SHIFT; + + ret = qm_mb(qm, QM_MB_CMD_CQC, cqc_dma, qp_id, 0); + dma_unmap_single(dev, cqc_dma, sizeof(struct qm_cqc), DMA_TO_DEVICE); + kfree(cqc); + + return ret; +} + +/** + * hisi_qm_start_qp() - Start a qp into running. + * @qp: The qp we want to start to run. + * @arg: Accelerator specific argument. + * + * After this function, qp can receive request from user. Return qp_id if + * successful, Return -EBUSY if failed. + */ +int hisi_qm_start_qp(struct hisi_qp *qp, unsigned long arg) +{ + struct hisi_qm *qm = qp->qm; + struct device *dev = &qm->pdev->dev; + enum qm_hw_ver ver = qm->ver; + int qp_id = qp->qp_id; + int pasid = arg; + size_t off = 0; + int ret; + +#define QP_INIT_BUF(qp, type, size) do { \ + (qp)->type = ((qp)->qdma.va + (off)); \ + (qp)->type##_dma = (qp)->qdma.dma + (off); \ + off += (size); \ +} while (0) + + if (!qp->qdma.dma) { + dev_err(dev, "cannot get qm dma buffer\n"); + return -EINVAL; + } + + /* sq need 128 bytes alignment */ + if (qp->qdma.dma & QM_SQE_DATA_ALIGN_MASK) { + dev_err(dev, "qm sq is not aligned to 128 byte\n"); + return -EINVAL; + } + + QP_INIT_BUF(qp, sqe, qm->sqe_size * QM_Q_DEPTH); + QP_INIT_BUF(qp, cqe, sizeof(struct qm_cqe) * QM_Q_DEPTH); + + dev_dbg(dev, "init qp buffer(v%d):\n" + " sqe (%pK, %lx)\n" + " cqe (%pK, %lx)\n", + ver, qp->sqe, (unsigned long)qp->sqe_dma, + qp->cqe, (unsigned long)qp->cqe_dma); + + ret = qm_qp_ctx_cfg(qp, qp_id, pasid); + if (ret) + return ret; + + dev_dbg(dev, "queue %d started\n", qp_id); + + return qp_id; +} +EXPORT_SYMBOL_GPL(hisi_qm_start_qp); + +/** + * hisi_qm_stop_qp() - Stop a qp in qm. + * @qp: The qp we want to stop. + * + * This function is reverse of hisi_qm_start_qp. Return 0 if successful. + */ +int hisi_qm_stop_qp(struct hisi_qp *qp) +{ + struct device *dev = &qp->qm->pdev->dev; + int i = 0; + + /* it is stopped */ + if (test_bit(QP_STOP, &qp->qp_status.flags)) + return 0; + + while (atomic_read(&qp->qp_status.used)) { + i++; + msleep(20); + if (i == 10) { + dev_err(dev, "Cannot drain out data for stopping, Force to stop!\n"); + return 0; + } + } + + set_bit(QP_STOP, &qp->qp_status.flags); + + dev_dbg(dev, "stop queue %u!", qp->qp_id); + + return 0; +} +EXPORT_SYMBOL_GPL(hisi_qm_stop_qp); + +/** + * hisi_qp_send() - Queue up a task in the hardware queue. + * @qp: The qp in which to put the message. + * @msg: The message. + * + * This function will return -EBUSY if qp is currently full, and -EAGAIN + * if qp related qm is resetting. + */ +int hisi_qp_send(struct hisi_qp *qp, const void *msg) +{ + struct hisi_qp_status *qp_status = &qp->qp_status; + u16 sq_tail = qp_status->sq_tail; + u16 sq_tail_next = (sq_tail + 1) % QM_Q_DEPTH; + void *sqe = qm_get_avail_sqe(qp); + + if (unlikely(test_bit(QP_STOP, &qp->qp_status.flags))) { + dev_info(&qp->qm->pdev->dev, "QP is stopped or resetting\n"); + return -EAGAIN; + } + + if (!sqe) + return -EBUSY; + + memcpy(sqe, msg, qp->qm->sqe_size); + + qm_db(qp->qm, qp->qp_id, QM_DOORBELL_CMD_SQ, sq_tail_next, 0); + atomic_inc(&qp->qp_status.used); + qp_status->sq_tail = sq_tail_next; + + return 0; +} +EXPORT_SYMBOL_GPL(hisi_qp_send); + +static void hisi_qm_cache_wb(struct hisi_qm *qm) +{ + unsigned int val; + + if (qm->ver == QM_HW_V2) { + writel(0x1, qm->io_base + QM_CACHE_WB_START); + if (readl_relaxed_poll_timeout(qm->io_base + QM_CACHE_WB_DONE, + val, val & BIT(0), 10, 1000)) + dev_err(&qm->pdev->dev, "QM writeback sqc cache fail!\n"); + } +} + +/** + * hisi_qm_init() - Initialize configures about qm. + * @qm: The qm needing init. + * + * This function init qm, then we can call hisi_qm_start to put qm into work. + */ +int hisi_qm_init(struct hisi_qm *qm) +{ + struct pci_dev *pdev = qm->pdev; + struct device *dev = &pdev->dev; + unsigned int num_vec; + int ret; + + switch (qm->ver) { + case QM_HW_V1: + qm->ops = &qm_hw_ops_v1; + break; + case QM_HW_V2: + qm->ops = &qm_hw_ops_v2; + break; + default: + return -EINVAL; + } + + ret = pci_enable_device_mem(pdev); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable device mem!\n"); + return ret; + } + + ret = pci_request_mem_regions(pdev, qm->dev_name); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request mem regions!\n"); + goto err_disable_pcidev; + } + + qm->io_base = ioremap(pci_resource_start(pdev, PCI_BAR_2), + pci_resource_len(qm->pdev, PCI_BAR_2)); + if (!qm->io_base) { + ret = -EIO; + goto err_release_mem_regions; + } + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (ret < 0) + goto err_iounmap; + pci_set_master(pdev); + + if (!qm->ops->get_irq_num) { + ret = -EOPNOTSUPP; + goto err_iounmap; + } + 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; + } + + ret = qm_irq_register(qm); + if (ret) + goto err_free_irq_vectors; + + mutex_init(&qm->mailbox_lock); + rwlock_init(&qm->qps_lock); + + dev_dbg(dev, "init qm %s with %s\n", pdev->is_physfn ? "pf" : "vf", + qm->use_dma_api ? "dma api" : "iommu api"); + + return 0; + +err_free_irq_vectors: + pci_free_irq_vectors(pdev); +err_iounmap: + iounmap(qm->io_base); +err_release_mem_regions: + pci_release_mem_regions(pdev); +err_disable_pcidev: + pci_disable_device(pdev); + + return ret; +} +EXPORT_SYMBOL_GPL(hisi_qm_init); + +/** + * hisi_qm_uninit() - Uninitialize qm. + * @qm: The qm needed uninit. + * + * This function uninits qm related device resources. + */ +void hisi_qm_uninit(struct hisi_qm *qm) +{ + struct pci_dev *pdev = qm->pdev; + struct device *dev = &pdev->dev; + + if (qm->use_dma_api && qm->qdma.va) { + 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); + pci_free_irq_vectors(pdev); + iounmap(qm->io_base); + pci_release_mem_regions(pdev); + pci_disable_device(pdev); +} +EXPORT_SYMBOL_GPL(hisi_qm_uninit); + +/** + * hisi_qm_get_vft() - Get vft from a qm. + * @qm: The qm we want to get its vft. + * @base: The base number of queue in vft. + * @number: The number of queues in vft. + * + * We can allocate multiple queues to a qm by configuring virtual function + * table. We get related configures by this function. Normally, we call this + * function in VF driver to get the queue information. + * + * qm hw v1 does not support this interface. + */ +int hisi_qm_get_vft(struct hisi_qm *qm, u32 *base, u32 *number) +{ + if (!base || !number) + return -EINVAL; + + if (!qm->ops->get_vft) { + dev_err(&qm->pdev->dev, "Don't support vft read!\n"); + return -EINVAL; + } + + return qm->ops->get_vft(qm, base, number); +} +EXPORT_SYMBOL_GPL(hisi_qm_get_vft); + +/** + * hisi_qm_set_vft() - Set "virtual function table" for a qm. + * @fun_num: Number of operated function. + * @qm: The qm in which to set vft, alway in a PF. + * @base: The base number of queue in vft. + * @number: The number of queues in vft. 0 means invalid vft. + * + * This function is alway called in PF driver, it is used to assign queues + * among PF and VFs. + * + * Assign queues A~B to PF: hisi_qm_set_vft(qm, 0, A, B - A + 1) + * Assign queues A~B to VF: hisi_qm_set_vft(qm, 2, A, B - A + 1) + * (VF function number 0x2) + */ +int hisi_qm_set_vft(struct hisi_qm *qm, u32 fun_num, u32 base, + u32 number) +{ + u32 max_q_num = qm->ctrl_qp_num; + + if (base >= max_q_num || number > max_q_num || + (base + number) > max_q_num) + return -EINVAL; + + return qm_set_sqc_cqc_vft(qm, fun_num, base, number); +} +EXPORT_SYMBOL_GPL(hisi_qm_set_vft); + +static void qm_init_eq_aeq_status(struct hisi_qm *qm) +{ + struct hisi_qm_status *status = &qm->status; + + status->eq_head = 0; + status->aeq_head = 0; + status->eqc_phase = 1; + status->aeqc_phase = 1; +} + +static int qm_eq_ctx_cfg(struct hisi_qm *qm) +{ + struct device *dev = &qm->pdev->dev; + struct qm_eqc *eqc; + struct qm_aeqc *aeqc; + dma_addr_t eqc_dma; + dma_addr_t aeqc_dma; + int ret; + + qm_init_eq_aeq_status(qm); + + eqc = kzalloc(sizeof(struct qm_eqc), GFP_KERNEL); + if (!eqc) + return -ENOMEM; + eqc_dma = dma_map_single(dev, eqc, sizeof(struct qm_eqc), + DMA_TO_DEVICE); + if (dma_mapping_error(dev, eqc_dma)) { + kfree(eqc); + return -ENOMEM; + } + + eqc->base_l = lower_32_bits(qm->eqe_dma); + eqc->base_h = upper_32_bits(qm->eqe_dma); + if (qm->ver == QM_HW_V1) + eqc->dw3 = QM_EQE_AEQE_SIZE; + eqc->dw6 = (QM_Q_DEPTH - 1) | (1 << QM_EQC_PHASE_SHIFT); + ret = qm_mb(qm, QM_MB_CMD_EQC, eqc_dma, 0, 0); + dma_unmap_single(dev, eqc_dma, sizeof(struct qm_eqc), DMA_TO_DEVICE); + kfree(eqc); + if (ret) + return ret; + + aeqc = kzalloc(sizeof(struct qm_aeqc), GFP_KERNEL); + if (!aeqc) + return -ENOMEM; + aeqc_dma = dma_map_single(dev, aeqc, sizeof(struct qm_aeqc), + DMA_TO_DEVICE); + if (dma_mapping_error(dev, aeqc_dma)) { + kfree(aeqc); + return -ENOMEM; + } + + aeqc->base_l = lower_32_bits(qm->aeqe_dma); + aeqc->base_h = upper_32_bits(qm->aeqe_dma); + aeqc->dw6 = (QM_Q_DEPTH - 1) | (1 << QM_EQC_PHASE_SHIFT); + + ret = qm_mb(qm, QM_MB_CMD_AEQC, aeqc_dma, 0, 0); + dma_unmap_single(dev, aeqc_dma, sizeof(struct qm_aeqc), DMA_TO_DEVICE); + kfree(aeqc); + + return ret; +} + +static int __hisi_qm_start(struct hisi_qm *qm) +{ + struct pci_dev *pdev = qm->pdev; + struct device *dev = &pdev->dev; + size_t off = 0; + int ret; + +#define QM_INIT_BUF(qm, type, num) do { \ + (qm)->type = ((qm)->qdma.va + (off)); \ + (qm)->type##_dma = (qm)->qdma.dma + (off); \ + off += QMC_ALIGN(sizeof(struct qm_##type) * (num)); \ +} while (0) + + WARN_ON(!qm->qdma.dma); + + if (qm->qp_num == 0) + return -EINVAL; + + if (qm->fun_type == QM_HW_PF) { + ret = qm_dev_mem_reset(qm); + if (ret) + return ret; + + ret = hisi_qm_set_vft(qm, 0, qm->qp_base, qm->qp_num); + if (ret) + return ret; + } + + QM_INIT_BUF(qm, eqe, QM_Q_DEPTH); + QM_INIT_BUF(qm, aeqe, QM_Q_DEPTH); + QM_INIT_BUF(qm, sqc, qm->qp_num); + QM_INIT_BUF(qm, cqc, qm->qp_num); + + dev_dbg(dev, "init qm buffer:\n" + " eqe (%pK, %lx)\n" + " aeqe (%pK, %lx)\n" + " sqc (%pK, %lx)\n" + " cqc (%pK, %lx)\n", + qm->eqe, (unsigned long)qm->eqe_dma, + qm->aeqe, (unsigned long)qm->aeqe_dma, + qm->sqc, (unsigned long)qm->sqc_dma, + qm->cqc, (unsigned long)qm->cqc_dma); + + ret = qm_eq_ctx_cfg(qm); + if (ret) + return ret; + + ret = qm_mb(qm, QM_MB_CMD_SQC_BT, qm->sqc_dma, 0, 0); + if (ret) + return ret; + + ret = qm_mb(qm, QM_MB_CMD_CQC_BT, qm->cqc_dma, 0, 0); + if (ret) + return ret; + + writel(0x0, qm->io_base + QM_VF_EQ_INT_MASK); + writel(0x0, qm->io_base + QM_VF_AEQ_INT_MASK); + + return 0; +} + +/** + * hisi_qm_start() - start qm + * @qm: The qm to be started. + * + * This function starts a qm, then we can allocate qp from this qm. + */ +int hisi_qm_start(struct hisi_qm *qm) +{ + struct device *dev = &qm->pdev->dev; + + dev_dbg(dev, "qm start with %d queue pairs\n", qm->qp_num); + + if (!qm->qp_num) { + dev_err(dev, "qp_num should not be 0\n"); + return -EINVAL; + } + + if (!qm->qp_bitmap) { + qm->qp_bitmap = devm_kcalloc(dev, BITS_TO_LONGS(qm->qp_num), + sizeof(long), GFP_KERNEL); + qm->qp_array = devm_kcalloc(dev, qm->qp_num, + sizeof(struct hisi_qp *), + GFP_KERNEL); + if (!qm->qp_bitmap || !qm->qp_array) + return -ENOMEM; + } + + if (!qm->use_dma_api) { + dev_dbg(&qm->pdev->dev, "qm delay start\n"); + return 0; + } else if (!qm->qdma.va) { + qm->qdma.size = QMC_ALIGN(sizeof(struct qm_eqe) * QM_Q_DEPTH) + + QMC_ALIGN(sizeof(struct qm_aeqe) * QM_Q_DEPTH) + + QMC_ALIGN(sizeof(struct qm_sqc) * qm->qp_num) + + QMC_ALIGN(sizeof(struct qm_cqc) * qm->qp_num); + qm->qdma.va = dma_alloc_coherent(dev, qm->qdma.size, + &qm->qdma.dma, GFP_KERNEL); + dev_dbg(dev, "allocate qm dma buf(va=%pK, dma=%pad, size=%zx)\n", + qm->qdma.va, &qm->qdma.dma, qm->qdma.size); + if (!qm->qdma.va) + return -ENOMEM; + } + + return __hisi_qm_start(qm); +} +EXPORT_SYMBOL_GPL(hisi_qm_start); + +/** + * hisi_qm_stop() - Stop a qm. + * @qm: The qm which will be stopped. + * + * This function stops qm and its qps, then qm can not accept request. + * Related resources are not released at this state, we can use hisi_qm_start + * to let qm start again. + */ +int hisi_qm_stop(struct hisi_qm *qm) +{ + struct device *dev; + struct hisi_qp *qp; + int ret = 0, i; + + if (!qm || !qm->pdev) { + WARN_ON(1); + return -EINVAL; + } + + dev = &qm->pdev->dev; + + /* Mask eq and aeq irq */ + writel(0x1, qm->io_base + QM_VF_EQ_INT_MASK); + writel(0x1, qm->io_base + QM_VF_AEQ_INT_MASK); + + /* Stop all qps belong to this qm */ + for (i = 0; i < qm->qp_num; i++) { + qp = qm->qp_array[i]; + if (qp) { + ret = hisi_qm_stop_qp(qp); + if (ret < 0) { + dev_err(dev, "Failed to stop qp%d!\n", i); + return -EBUSY; + } + } + } + + if (qm->fun_type == QM_HW_PF) { + ret = hisi_qm_set_vft(qm, 0, 0, 0); + if (ret < 0) + dev_err(dev, "Failed to set vft!\n"); + } + + return ret; +} +EXPORT_SYMBOL_GPL(hisi_qm_stop); + +/** + * hisi_qm_debug_init() - Initialize qm related debugfs files. + * @qm: The qm for which we want to add debugfs files. + * + * Create qm related debugfs files. + */ +int hisi_qm_debug_init(struct hisi_qm *qm) +{ + struct dentry *qm_d, *qm_regs; + int i, ret; + + qm_d = debugfs_create_dir("qm", qm->debug.debug_root); + if (IS_ERR(qm_d)) + return -ENOENT; + qm->debug.qm_d = qm_d; + + /* only show this in PF */ + if (qm->fun_type == QM_HW_PF) + for (i = CURRENT_Q; i < DEBUG_FILE_NUM; i++) + if (qm_create_debugfs_file(qm, i)) { + ret = -ENOENT; + goto failed_to_create; + } + + qm_regs = debugfs_create_file("qm_regs", 0444, qm->debug.qm_d, qm, + &qm_regs_fops); + if (IS_ERR(qm_regs)) { + ret = -ENOENT; + goto failed_to_create; + } + + return 0; + +failed_to_create: + debugfs_remove_recursive(qm_d); + return ret; +} +EXPORT_SYMBOL_GPL(hisi_qm_debug_init); + +/** + * hisi_qm_debug_regs_clear() - clear qm debug related registers. + * @qm: The qm for which we want to clear its debug registers. + */ +void hisi_qm_debug_regs_clear(struct hisi_qm *qm) +{ + struct qm_dfx_registers *regs; + int i; + + /* 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); + + /* + * these registers are reading and clearing, so clear them after + * reading them. + */ + writel(0x1, qm->io_base + QM_DFX_CNT_CLR_CE); + + regs = qm_dfx_regs; + for (i = 0; i < CNT_CYC_REGS_NUM; i++) { + readl(qm->io_base + regs->reg_offset); + regs++; + } + + writel(0x0, qm->io_base + QM_DFX_CNT_CLR_CE); +} +EXPORT_SYMBOL_GPL(hisi_qm_debug_regs_clear); + +/** + * hisi_qm_hw_error_init() - Configure qm hardware error report method. + * @qm: The qm which we want to configure. + * @ce: Bit mask of correctable error configure. + * @nfe: Bit mask of non-fatal error configure. + * @fe: Bit mask of fatal error configure. + * @msi: Bit mask of error reported by message signal interrupt. + * + * Hardware errors of qm can be reported either by RAS interrupts which will + * be handled by UEFI and then PCIe AER or by device MSI. User can configure + * each error to use either of above two methods. For RAS interrupts, we can + * configure an error as one of correctable error, non-fatal error or + * fatal error. + * + * Bits indicating errors can be configured to ce, nfe, fe and msi to enable + * related report methods. Error report will be masked if related error bit + * does not configure. + */ +void hisi_qm_hw_error_init(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe, + u32 msi) +{ + if (!qm->ops->hw_error_init) { + dev_err(&qm->pdev->dev, "QM version %d doesn't support hw error handling!\n", + qm->ver); + return; + } + + qm->ops->hw_error_init(qm, ce, nfe, fe, msi); +} +EXPORT_SYMBOL_GPL(hisi_qm_hw_error_init); + +/** + * hisi_qm_hw_error_handle() - Handle qm non-fatal hardware errors. + * @qm: The qm which has non-fatal hardware errors. + * + * Accelerators use this function to handle qm non-fatal hardware errors. + */ +int hisi_qm_hw_error_handle(struct hisi_qm *qm) +{ + if (!qm->ops->hw_error_handle) { + dev_err(&qm->pdev->dev, "QM version %d doesn't support hw error report!\n", + qm->ver); + return PCI_ERS_RESULT_NONE; + } + + return qm->ops->hw_error_handle(qm); +} +EXPORT_SYMBOL_GPL(hisi_qm_hw_error_handle); + +/** + * hisi_qm_get_hw_version() - Get hardware version of a qm. + * @pdev: The device which hardware version we want to get. + * + * This function gets the hardware version of a qm. Return QM_HW_UNKNOWN + * if the hardware version is not supported. + */ +enum qm_hw_ver hisi_qm_get_hw_version(struct pci_dev *pdev) +{ + switch (pdev->revision) { + case QM_HW_V1: + case QM_HW_V2: + return pdev->revision; + default: + return QM_HW_UNKNOWN; + } +} +EXPORT_SYMBOL_GPL(hisi_qm_get_hw_version); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Zhou Wang "); +MODULE_DESCRIPTION("HiSilicon Accelerator queue manager driver"); diff --git a/drivers/crypto/hisilicon/qm.h b/drivers/crypto/hisilicon/qm.h new file mode 100644 index 0000000000000000000000000000000000000000..70e672ae86bf5ccee9c18f41387008227c2451f6 --- /dev/null +++ b/drivers/crypto/hisilicon/qm.h @@ -0,0 +1,215 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2019 HiSilicon Limited. */ +#ifndef HISI_ACC_QM_H +#define HISI_ACC_QM_H + +#include +#include +#include +#include + +/* qm user domain */ +#define QM_ARUSER_M_CFG_1 0x100088 +#define AXUSER_SNOOP_ENABLE BIT(30) +#define AXUSER_CMD_TYPE GENMASK(14, 12) +#define AXUSER_CMD_SMMU_NORMAL 1 +#define AXUSER_NS BIT(6) +#define AXUSER_NO BIT(5) +#define AXUSER_FP BIT(4) +#define AXUSER_SSV BIT(0) +#define AXUSER_BASE (AXUSER_SNOOP_ENABLE | \ + FIELD_PREP(AXUSER_CMD_TYPE, \ + AXUSER_CMD_SMMU_NORMAL) | \ + AXUSER_NS | AXUSER_NO | AXUSER_FP) +#define QM_ARUSER_M_CFG_ENABLE 0x100090 +#define ARUSER_M_CFG_ENABLE 0xfffffffe +#define QM_AWUSER_M_CFG_1 0x100098 +#define QM_AWUSER_M_CFG_ENABLE 0x1000a0 +#define AWUSER_M_CFG_ENABLE 0xfffffffe +#define QM_WUSER_M_CFG_ENABLE 0x1000a8 +#define WUSER_M_CFG_ENABLE 0xffffffff + +/* qm cache */ +#define QM_CACHE_CTL 0x100050 +#define SQC_CACHE_ENABLE BIT(0) +#define CQC_CACHE_ENABLE BIT(1) +#define SQC_CACHE_WB_ENABLE BIT(4) +#define SQC_CACHE_WB_THRD GENMASK(10, 5) +#define CQC_CACHE_WB_ENABLE BIT(11) +#define CQC_CACHE_WB_THRD GENMASK(17, 12) +#define QM_AXI_M_CFG 0x1000ac +#define AXI_M_CFG 0xffff +#define QM_AXI_M_CFG_ENABLE 0x1000b0 +#define AXI_M_CFG_ENABLE 0xffffffff +#define QM_PEH_AXUSER_CFG 0x1000cc +#define QM_PEH_AXUSER_CFG_ENABLE 0x1000d0 +#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) +#define QM_ECC_1BIT BIT(3) +#define QM_ACC_GET_TASK_TIMEOUT BIT(4) +#define QM_ACC_DO_TASK_TIMEOUT BIT(5) +#define QM_ACC_WB_NOT_READY_TIMEOUT BIT(6) +#define QM_SQ_CQ_VF_INVALID BIT(7) +#define QM_CQ_VF_INVALID BIT(8) +#define QM_SQ_VF_INVALID BIT(9) +#define QM_DB_TIMEOUT BIT(10) +#define QM_OF_FIFO_OF BIT(11) +#define QM_DB_RANDOM_INVALID BIT(12) + +#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) +#define QM_BASE_CE QM_ECC_1BIT + +#define QM_Q_DEPTH 1024 + +enum qp_state { + QP_STOP, +}; + +enum qm_hw_ver { + QM_HW_UNKNOWN = -1, + QM_HW_V1 = 0x20, + QM_HW_V2 = 0x21, +}; + +enum qm_fun_type { + QM_HW_PF, + QM_HW_VF, +}; + +enum qm_debug_file { + CURRENT_Q, + CLEAR_ENABLE, + DEBUG_FILE_NUM, +}; + +struct debugfs_file { + enum qm_debug_file index; + struct mutex lock; + struct qm_debug *debug; +}; + +struct qm_debug { + u32 curr_qm_qp_num; + struct dentry *debug_root; + struct dentry *qm_d; + struct debugfs_file files[DEBUG_FILE_NUM]; +}; + +struct qm_dma { + void *va; + dma_addr_t dma; + size_t size; +}; + +struct hisi_qm_status { + u32 eq_head; + bool eqc_phase; + u32 aeq_head; + bool aeqc_phase; + unsigned long flags; +}; + +struct hisi_qm { + enum qm_hw_ver ver; + enum qm_fun_type fun_type; + const char *dev_name; + struct pci_dev *pdev; + void __iomem *io_base; + u32 sqe_size; + u32 qp_base; + u32 qp_num; + u32 ctrl_qp_num; + + struct qm_dma qdma; + struct qm_sqc *sqc; + struct qm_cqc *cqc; + struct qm_eqe *eqe; + struct qm_aeqe *aeqe; + dma_addr_t sqc_dma; + dma_addr_t cqc_dma; + dma_addr_t eqe_dma; + dma_addr_t aeqe_dma; + + struct hisi_qm_status status; + + rwlock_t qps_lock; + unsigned long *qp_bitmap; + struct hisi_qp **qp_array; + + struct mutex mailbox_lock; + + const struct hisi_qm_hw_ops *ops; + + struct qm_debug debug; + + u32 error_mask; + u32 msi_mask; + + bool use_dma_api; +}; + +struct hisi_qp_status { + atomic_t used; + u16 sq_tail; + u16 cq_head; + bool cqc_phase; + unsigned long flags; +}; + +struct hisi_qp_ops { + int (*fill_sqe)(void *sqe, void *q_parm, void *d_parm); +}; + +struct hisi_qp { + u32 qp_id; + u8 alg_type; + u8 req_type; + + struct qm_dma qdma; + void *sqe; + struct qm_cqe *cqe; + dma_addr_t sqe_dma; + dma_addr_t cqe_dma; + + struct hisi_qp_status qp_status; + struct hisi_qp_ops *hw_ops; + void *qp_ctx; + void (*req_cb)(struct hisi_qp *qp, void *data); + struct work_struct work; + struct workqueue_struct *wq; + + struct hisi_qm *qm; +}; + +int hisi_qm_init(struct hisi_qm *qm); +void hisi_qm_uninit(struct hisi_qm *qm); +int hisi_qm_start(struct hisi_qm *qm); +int hisi_qm_stop(struct hisi_qm *qm); +struct hisi_qp *hisi_qm_create_qp(struct hisi_qm *qm, u8 alg_type); +int hisi_qm_start_qp(struct hisi_qp *qp, unsigned long arg); +int hisi_qm_stop_qp(struct hisi_qp *qp); +void hisi_qm_release_qp(struct hisi_qp *qp); +int hisi_qp_send(struct hisi_qp *qp, const void *msg); +int hisi_qm_get_vft(struct hisi_qm *qm, u32 *base, u32 *number); +int hisi_qm_set_vft(struct hisi_qm *qm, u32 fun_num, u32 base, u32 number); +int hisi_qm_debug_init(struct hisi_qm *qm); +void hisi_qm_hw_error_init(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe, + u32 msi); +int hisi_qm_hw_error_handle(struct hisi_qm *qm); +enum qm_hw_ver hisi_qm_get_hw_version(struct pci_dev *pdev); +void hisi_qm_debug_regs_clear(struct hisi_qm *qm); +#endif diff --git a/drivers/crypto/hisilicon/sec/sec_algs.c b/drivers/crypto/hisilicon/sec/sec_algs.c index 02768af0dccdd4f6e1285dde4ac5febd580379ce..e0508ea160f17c930a7445b6fe685fbdf844a687 100644 --- a/drivers/crypto/hisilicon/sec/sec_algs.c +++ b/drivers/crypto/hisilicon/sec/sec_algs.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include @@ -347,25 +347,21 @@ static int sec_alg_skcipher_setkey_aes_xts(struct crypto_skcipher *tfm, static int sec_alg_skcipher_setkey_des_ecb(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen) { - if (keylen != DES_KEY_SIZE) - return -EINVAL; - - return sec_alg_skcipher_setkey(tfm, key, keylen, SEC_C_DES_ECB_64); + return verify_skcipher_des_key(tfm, key) ?: + sec_alg_skcipher_setkey(tfm, key, keylen, SEC_C_DES_ECB_64); } static int sec_alg_skcipher_setkey_des_cbc(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen) { - if (keylen != DES_KEY_SIZE) - return -EINVAL; - - return sec_alg_skcipher_setkey(tfm, key, keylen, SEC_C_DES_CBC_64); + return verify_skcipher_des_key(tfm, key) ?: + sec_alg_skcipher_setkey(tfm, key, keylen, SEC_C_DES_CBC_64); } static int sec_alg_skcipher_setkey_3des_ecb(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen) { - return unlikely(des3_verify_key(tfm, key)) ?: + return verify_skcipher_des3_key(tfm, key) ?: sec_alg_skcipher_setkey(tfm, key, keylen, SEC_C_3DES_ECB_192_3KEY); } @@ -373,7 +369,7 @@ static int sec_alg_skcipher_setkey_3des_ecb(struct crypto_skcipher *tfm, static int sec_alg_skcipher_setkey_3des_cbc(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen) { - return unlikely(des3_verify_key(tfm, key)) ?: + return verify_skcipher_des3_key(tfm, key) ?: sec_alg_skcipher_setkey(tfm, key, keylen, SEC_C_3DES_CBC_192_3KEY); } diff --git a/drivers/crypto/hisilicon/sgl.c b/drivers/crypto/hisilicon/sgl.c new file mode 100644 index 0000000000000000000000000000000000000000..e083d172b618d4d0f00b2de73c81f9e6fc01486b --- /dev/null +++ b/drivers/crypto/hisilicon/sgl.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019 HiSilicon Limited. */ +#include +#include +#include "./sgl.h" + +#define HISI_ACC_SGL_SGE_NR_MIN 1 +#define HISI_ACC_SGL_SGE_NR_MAX 255 +#define HISI_ACC_SGL_SGE_NR_DEF 10 +#define HISI_ACC_SGL_NR_MAX 256 +#define HISI_ACC_SGL_ALIGN_SIZE 64 + +static int acc_sgl_sge_set(const char *val, const struct kernel_param *kp) +{ + int ret; + u32 n; + + if (!val) + return -EINVAL; + + ret = kstrtou32(val, 10, &n); + if (ret != 0 || n > HISI_ACC_SGL_SGE_NR_MAX || n == 0) + return -EINVAL; + + return param_set_int(val, kp); +} + +static const struct kernel_param_ops acc_sgl_sge_ops = { + .set = acc_sgl_sge_set, + .get = param_get_int, +}; + +static u32 acc_sgl_sge_nr = HISI_ACC_SGL_SGE_NR_DEF; +module_param_cb(acc_sgl_sge_nr, &acc_sgl_sge_ops, &acc_sgl_sge_nr, 0444); +MODULE_PARM_DESC(acc_sgl_sge_nr, "Number of sge in sgl(1-255)"); + +struct acc_hw_sge { + dma_addr_t buf; + void *page_ctrl; + __le32 len; + __le32 pad; + __le32 pad0; + __le32 pad1; +}; + +/* use default sgl head size 64B */ +struct hisi_acc_hw_sgl { + dma_addr_t next_dma; + __le16 entry_sum_in_chain; + __le16 entry_sum_in_sgl; + __le16 entry_length_in_sgl; + __le16 pad0; + __le64 pad1[5]; + struct hisi_acc_hw_sgl *next; + struct acc_hw_sge sge_entries[]; +} __aligned(1); + +/** + * hisi_acc_create_sgl_pool() - Create a hw sgl pool. + * @dev: The device which hw sgl pool belongs to. + * @pool: Pointer of pool. + * @count: Count of hisi_acc_hw_sgl in pool. + * + * This function creates a hw sgl pool, after this user can get hw sgl memory + * from it. + */ +int hisi_acc_create_sgl_pool(struct device *dev, + struct hisi_acc_sgl_pool *pool, u32 count) +{ + u32 sgl_size; + u32 size; + + if (!dev || !pool || !count) + return -EINVAL; + + sgl_size = sizeof(struct acc_hw_sge) * acc_sgl_sge_nr + + sizeof(struct hisi_acc_hw_sgl); + size = sgl_size * count; + + pool->sgl = dma_alloc_coherent(dev, size, &pool->sgl_dma, GFP_KERNEL); + if (!pool->sgl) + return -ENOMEM; + + pool->size = size; + pool->count = count; + pool->sgl_size = sgl_size; + + return 0; +} +EXPORT_SYMBOL_GPL(hisi_acc_create_sgl_pool); + +/** + * hisi_acc_free_sgl_pool() - Free a hw sgl pool. + * @dev: The device which hw sgl pool belongs to. + * @pool: Pointer of pool. + * + * This function frees memory of a hw sgl pool. + */ +void hisi_acc_free_sgl_pool(struct device *dev, struct hisi_acc_sgl_pool *pool) +{ + dma_free_coherent(dev, pool->size, pool->sgl, pool->sgl_dma); + memset(pool, 0, sizeof(struct hisi_acc_sgl_pool)); +} +EXPORT_SYMBOL_GPL(hisi_acc_free_sgl_pool); + +struct hisi_acc_hw_sgl *acc_get_sgl(struct hisi_acc_sgl_pool *pool, u32 index, + dma_addr_t *hw_sgl_dma) +{ + if (!pool || !hw_sgl_dma || index >= pool->count || !pool->sgl) + return ERR_PTR(-EINVAL); + + *hw_sgl_dma = pool->sgl_dma + pool->sgl_size * index; + return (void *)pool->sgl + pool->sgl_size * index; +} + +void acc_put_sgl(struct hisi_acc_sgl_pool *pool, u32 index) {} + +static void sg_map_to_hw_sg(struct scatterlist *sgl, + struct acc_hw_sge *hw_sge) +{ + hw_sge->buf = sgl->dma_address; + hw_sge->len = sgl->dma_length; +} + +static void inc_hw_sgl_sge(struct hisi_acc_hw_sgl *hw_sgl) +{ + hw_sgl->entry_sum_in_sgl++; +} + +static void update_hw_sgl_sum_sge(struct hisi_acc_hw_sgl *hw_sgl, u16 sum) +{ + hw_sgl->entry_sum_in_chain = sum; +} + +/** + * hisi_acc_sg_buf_map_to_hw_sgl - Map a scatterlist to a hw sgl. + * @dev: The device which hw sgl belongs to. + * @sgl: Scatterlist which will be mapped to hw sgl. + * @pool: Pool which hw sgl memory will be allocated in. + * @index: Index of hisi_acc_hw_sgl in pool. + * @hw_sgl_dma: The dma address of allocated hw sgl. + * + * This function builds hw sgl according input sgl, user can use hw_sgl_dma + * as src/dst in its BD. Only support single hw sgl currently. + */ +struct hisi_acc_hw_sgl * +hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev, + struct scatterlist *sgl, + struct hisi_acc_sgl_pool *pool, + u32 index, dma_addr_t *hw_sgl_dma) +{ + struct hisi_acc_hw_sgl *curr_hw_sgl; + dma_addr_t curr_sgl_dma = 0; + struct acc_hw_sge *curr_hw_sge; + struct scatterlist *sg; + int sg_n = sg_nents(sgl); + int i, ret; + + if (!dev || !sgl || !pool || !hw_sgl_dma || sg_n > acc_sgl_sge_nr) + return ERR_PTR(-EINVAL); + + ret = dma_map_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL); + if (!ret) + return ERR_PTR(-EINVAL); + + curr_hw_sgl = acc_get_sgl(pool, index, &curr_sgl_dma); + if (!curr_hw_sgl) { + ret = -ENOMEM; + goto err_unmap_sg; + } + curr_hw_sgl->entry_length_in_sgl = acc_sgl_sge_nr; + curr_hw_sge = curr_hw_sgl->sge_entries; + + for_each_sg(sgl, sg, sg_n, i) { + sg_map_to_hw_sg(sg, curr_hw_sge); + inc_hw_sgl_sge(curr_hw_sgl); + curr_hw_sge++; + } + + update_hw_sgl_sum_sge(curr_hw_sgl, acc_sgl_sge_nr); + *hw_sgl_dma = curr_sgl_dma; + + return curr_hw_sgl; + +err_unmap_sg: + dma_unmap_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(hisi_acc_sg_buf_map_to_hw_sgl); + +/** + * hisi_acc_sg_buf_unmap() - Unmap allocated hw sgl. + * @dev: The device which hw sgl belongs to. + * @sgl: Related scatterlist. + * @hw_sgl: Virtual address of hw sgl. + * @hw_sgl_dma: DMA address of hw sgl. + * @pool: Pool which hw sgl is allocated in. + * + * This function unmaps allocated hw sgl. + */ +void hisi_acc_sg_buf_unmap(struct device *dev, struct scatterlist *sgl, + struct hisi_acc_hw_sgl *hw_sgl) +{ + dma_unmap_sg(dev, sgl, sg_nents(sgl), DMA_BIDIRECTIONAL); + + hw_sgl->entry_sum_in_chain = 0; + hw_sgl->entry_sum_in_sgl = 0; + hw_sgl->entry_length_in_sgl = 0; +} +EXPORT_SYMBOL_GPL(hisi_acc_sg_buf_unmap); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Zhou Wang "); +MODULE_DESCRIPTION("HiSilicon Accelerator SGL support"); diff --git a/drivers/crypto/hisilicon/sgl.h b/drivers/crypto/hisilicon/sgl.h new file mode 100644 index 0000000000000000000000000000000000000000..3ac8871c7acf2a2385c77bd6b4d584d81f550da6 --- /dev/null +++ b/drivers/crypto/hisilicon/sgl.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2019 HiSilicon Limited. */ +#ifndef HISI_ACC_SGL_H +#define HISI_ACC_SGL_H + +struct hisi_acc_sgl_pool { + struct hisi_acc_hw_sgl *sgl; + dma_addr_t sgl_dma; + size_t size; + u32 count; + size_t sgl_size; +}; + +struct hisi_acc_hw_sgl * +hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev, + struct scatterlist *sgl, + struct hisi_acc_sgl_pool *pool, + u32 index, dma_addr_t *hw_sgl_dma); +void hisi_acc_sg_buf_unmap(struct device *dev, struct scatterlist *sgl, + struct hisi_acc_hw_sgl *hw_sgl); +int hisi_acc_create_sgl_pool(struct device *dev, struct hisi_acc_sgl_pool *pool, + u32 count); +void hisi_acc_free_sgl_pool(struct device *dev, struct hisi_acc_sgl_pool *pool); +#endif diff --git a/drivers/crypto/hisilicon/zip/Makefile b/drivers/crypto/hisilicon/zip/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a936f099ee22eadfbf5a9cb8fcea2049a30255ef --- /dev/null +++ b/drivers/crypto/hisilicon/zip/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_CRYPTO_DEV_HISI_ZIP) += hisi_zip.o +hisi_zip-objs = zip_main.o zip_crypto.o diff --git a/drivers/crypto/hisilicon/zip/zip.h b/drivers/crypto/hisilicon/zip/zip.h new file mode 100644 index 0000000000000000000000000000000000000000..ffb00d987d024d3028326040d051f4e4416a50e5 --- /dev/null +++ b/drivers/crypto/hisilicon/zip/zip.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2019 HiSilicon Limited. */ +#ifndef HISI_ZIP_H +#define HISI_ZIP_H + +#undef pr_fmt +#define pr_fmt(fmt) "hisi_zip: " fmt + +#include +#include "../qm.h" +#include "../sgl.h" + +/* hisi_zip_sqe dw3 */ +#define HZIP_BD_STATUS_M GENMASK(7, 0) +/* hisi_zip_sqe dw9 */ +#define HZIP_REQ_TYPE_M GENMASK(7, 0) +#define HZIP_ALG_TYPE_ZLIB 0x02 +#define HZIP_ALG_TYPE_GZIP 0x03 +#define HZIP_BUF_TYPE_M GENMASK(11, 8) +#define HZIP_PBUFFER 0x0 +#define HZIP_SGL 0x1 + +enum hisi_zip_error_type { + /* negative compression */ + HZIP_NC_ERR = 0x0d, +}; + +struct hisi_zip_ctrl; + +struct hisi_zip { + struct hisi_qm qm; + struct list_head list; + struct hisi_zip_ctrl *ctrl; +}; + +struct hisi_zip_sqe { + u32 consumed; + u32 produced; + u32 comp_data_length; + u32 dw3; + u32 input_data_length; + u32 lba_l; + u32 lba_h; + u32 dw7; + u32 dw8; + u32 dw9; + u32 dw10; + u32 priv_info; + u32 dw12; + u32 tag; + u32 dest_avail_out; + u32 rsvd0; + u32 comp_head_addr_l; + u32 comp_head_addr_h; + 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 rsvd1[4]; +}; + +struct hisi_zip *find_zip_device(int node); +int hisi_zip_register_to_crypto(void); +void hisi_zip_unregister_from_crypto(void); +#endif diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c new file mode 100644 index 0000000000000000000000000000000000000000..5a3f84dcdcde7a113b75036bc87226e735a3d58e --- /dev/null +++ b/drivers/crypto/hisilicon/zip/zip_crypto.c @@ -0,0 +1,653 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019 HiSilicon Limited. */ +#include +#include +#include +#include +#include "zip.h" + +#define HZIP_ZLIB_HEAD_SIZE 2 +#define HZIP_GZIP_HEAD_SIZE 10 + +#define GZIP_HEAD_FHCRC_BIT BIT(1) +#define GZIP_HEAD_FEXTRA_BIT BIT(2) +#define GZIP_HEAD_FNAME_BIT BIT(3) +#define GZIP_HEAD_FCOMMENT_BIT BIT(4) + +#define GZIP_HEAD_FLG_SHIFT 3 +#define GZIP_HEAD_FEXTRA_SHIFT 10 +#define GZIP_HEAD_FEXTRA_XLEN 2 +#define GZIP_HEAD_FHCRC_SIZE 2 + +#define HZIP_CTX_Q_NUM 2 +#define HZIP_GZIP_HEAD_BUF 256 +#define HZIP_ALG_PRIORITY 300 + +static const u8 zlib_head[HZIP_ZLIB_HEAD_SIZE] = {0x78, 0x9c}; +static const u8 gzip_head[HZIP_GZIP_HEAD_SIZE] = {0x1f, 0x8b, 0x08, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x03}; +enum hisi_zip_alg_type { + HZIP_ALG_TYPE_COMP = 0, + HZIP_ALG_TYPE_DECOMP = 1, +}; + +#define COMP_NAME_TO_TYPE(alg_name) \ + (!strcmp((alg_name), "zlib-deflate") ? HZIP_ALG_TYPE_ZLIB : \ + !strcmp((alg_name), "gzip") ? HZIP_ALG_TYPE_GZIP : 0) \ + +#define TO_HEAD_SIZE(req_type) \ + (((req_type) == HZIP_ALG_TYPE_ZLIB) ? sizeof(zlib_head) : \ + ((req_type) == HZIP_ALG_TYPE_GZIP) ? sizeof(gzip_head) : 0) \ + +#define TO_HEAD(req_type) \ + (((req_type) == HZIP_ALG_TYPE_ZLIB) ? zlib_head : \ + ((req_type) == HZIP_ALG_TYPE_GZIP) ? gzip_head : 0) \ + +struct hisi_zip_req { + struct acomp_req *req; + struct scatterlist *src; + struct scatterlist *dst; + size_t slen; + size_t dlen; + struct hisi_acc_hw_sgl *hw_src; + struct hisi_acc_hw_sgl *hw_dst; + dma_addr_t dma_src; + dma_addr_t dma_dst; + int req_id; +}; + +struct hisi_zip_req_q { + struct hisi_zip_req *q; + unsigned long *req_bitmap; + rwlock_t req_lock; + u16 size; +}; + +struct hisi_zip_qp_ctx { + struct hisi_qp *qp; + struct hisi_zip_sqe zip_sqe; + struct hisi_zip_req_q req_q; + struct hisi_acc_sgl_pool sgl_pool; + struct hisi_zip *zip_dev; + struct hisi_zip_ctx *ctx; +}; + +struct hisi_zip_ctx { +#define QPC_COMP 0 +#define QPC_DECOMP 1 + struct hisi_zip_qp_ctx qp_ctx[HZIP_CTX_Q_NUM]; +}; + +static void hisi_zip_config_buf_type(struct hisi_zip_sqe *sqe, u8 buf_type) +{ + u32 val; + + 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) +{ + sqe->tag = tag; +} + +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) +{ + memset(sqe, 0, sizeof(struct hisi_zip_sqe)); + + sqe->input_data_length = slen; + sqe->dw9 = FIELD_PREP(HZIP_REQ_TYPE_M, req_type); + sqe->dest_avail_out = dlen; + 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); +} + +static int hisi_zip_create_qp(struct hisi_qm *qm, struct hisi_zip_qp_ctx *ctx, + int alg_type, int req_type) +{ + struct hisi_qp *qp; + int ret; + + qp = hisi_qm_create_qp(qm, alg_type); + if (IS_ERR(qp)) + return PTR_ERR(qp); + + qp->req_type = req_type; + qp->qp_ctx = ctx; + ctx->qp = qp; + + ret = hisi_qm_start_qp(qp, 0); + if (ret < 0) + goto err_release_qp; + + return 0; + +err_release_qp: + hisi_qm_release_qp(qp); + return ret; +} + +static void hisi_zip_release_qp(struct hisi_zip_qp_ctx *ctx) +{ + hisi_qm_stop_qp(ctx->qp); + hisi_qm_release_qp(ctx->qp); +} + +static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type) +{ + struct hisi_zip *hisi_zip; + struct hisi_qm *qm; + int ret, i, j; + + /* find the proper zip device */ + hisi_zip = find_zip_device(cpu_to_node(smp_processor_id())); + if (!hisi_zip) { + pr_err("Failed to find a proper ZIP device!\n"); + return -ENODEV; + } + qm = &hisi_zip->qm; + + for (i = 0; i < HZIP_CTX_Q_NUM; i++) { + /* alg_type = 0 for compress, 1 for decompress in hw sqe */ + ret = hisi_zip_create_qp(qm, &hisi_zip_ctx->qp_ctx[i], i, + req_type); + if (ret) + goto err; + + hisi_zip_ctx->qp_ctx[i].zip_dev = hisi_zip; + } + + return 0; +err: + for (j = i - 1; j >= 0; j--) + hisi_zip_release_qp(&hisi_zip_ctx->qp_ctx[j]); + + return ret; +} + +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; +} + +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 int hisi_zip_create_req_q(struct hisi_zip_ctx *ctx) +{ + struct hisi_zip_req_q *req_q; + int i, ret; + + for (i = 0; i < HZIP_CTX_Q_NUM; i++) { + req_q = &ctx->qp_ctx[i].req_q; + req_q->size = QM_Q_DEPTH; + + req_q->req_bitmap = kcalloc(BITS_TO_LONGS(req_q->size), + sizeof(long), GFP_KERNEL); + if (!req_q->req_bitmap) { + ret = -ENOMEM; + if (i == 0) + return ret; + + goto err_free_loop0; + } + rwlock_init(&req_q->req_lock); + + req_q->q = kcalloc(req_q->size, sizeof(struct hisi_zip_req), + GFP_KERNEL); + if (!req_q->q) { + ret = -ENOMEM; + if (i == 0) + goto err_free_bitmap; + else + goto err_free_loop1; + } + } + + return 0; + +err_free_loop1: + kfree(ctx->qp_ctx[QPC_DECOMP].req_q.req_bitmap); +err_free_loop0: + kfree(ctx->qp_ctx[QPC_COMP].req_q.q); +err_free_bitmap: + kfree(ctx->qp_ctx[QPC_COMP].req_q.req_bitmap); + return ret; +} + +static void hisi_zip_release_req_q(struct hisi_zip_ctx *ctx) +{ + int i; + + for (i = 0; i < HZIP_CTX_Q_NUM; i++) { + kfree(ctx->qp_ctx[i].req_q.q); + kfree(ctx->qp_ctx[i].req_q.req_bitmap); + } +} + +static int hisi_zip_create_sgl_pool(struct hisi_zip_ctx *ctx) +{ + struct hisi_zip_qp_ctx *tmp; + int i, ret; + + for (i = 0; i < HZIP_CTX_Q_NUM; i++) { + tmp = &ctx->qp_ctx[i]; + ret = hisi_acc_create_sgl_pool(&tmp->qp->qm->pdev->dev, + &tmp->sgl_pool, + QM_Q_DEPTH << 1); + if (ret < 0) { + if (i == 1) + goto err_free_sgl_pool0; + return -ENOMEM; + } + } + + return 0; + +err_free_sgl_pool0: + hisi_acc_free_sgl_pool(&ctx->qp_ctx[QPC_COMP].qp->qm->pdev->dev, + &ctx->qp_ctx[QPC_COMP].sgl_pool); + return -ENOMEM; +} + +static void hisi_zip_release_sgl_pool(struct hisi_zip_ctx *ctx) +{ + int i; + + for (i = 0; i < HZIP_CTX_Q_NUM; i++) + hisi_acc_free_sgl_pool(&ctx->qp_ctx[i].qp->qm->pdev->dev, + &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; + + if (qp_ctx->qp->alg_type == HZIP_ALG_TYPE_COMP) + kfree(req->dst); + else + kfree(req->src); + + 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_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; + + 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); + err = -EIO; + } + dlen = sqe->produced; + + hisi_acc_sg_buf_unmap(dev, req->src, req->hw_src); + hisi_acc_sg_buf_unmap(dev, 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 *)) +{ + int i; + + for (i = 0; i < HZIP_CTX_Q_NUM; i++) + ctx->qp_ctx[i].qp->req_cb = fn; +} + +static int hisi_zip_acomp_init(struct crypto_acomp *tfm) +{ + const char *alg_name = crypto_tfm_alg_name(&tfm->base); + struct hisi_zip_ctx *ctx = crypto_tfm_ctx(&tfm->base); + int ret; + + ret = hisi_zip_ctx_init(ctx, COMP_NAME_TO_TYPE(alg_name)); + if (ret) + return ret; + + ret = hisi_zip_create_req_q(ctx); + if (ret) + goto err_ctx_exit; + + ret = hisi_zip_create_sgl_pool(ctx); + if (ret) + goto err_release_req_q; + + hisi_zip_set_acomp_cb(ctx, hisi_zip_acomp_cb); + + return 0; + +err_release_req_q: + hisi_zip_release_req_q(ctx); +err_ctx_exit: + hisi_zip_ctx_exit(ctx); + return ret; +} + +static void hisi_zip_acomp_exit(struct crypto_acomp *tfm) +{ + struct hisi_zip_ctx *ctx = crypto_tfm_ctx(&tfm->base); + + hisi_zip_set_acomp_cb(ctx, NULL); + hisi_zip_release_sgl_pool(ctx); + hisi_zip_release_req_q(ctx); + 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) + return -ENOMEM; + + return head_size; +} + +static size_t 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 size_t get_comp_head_size(struct scatterlist *src, u8 req_type) +{ + switch (req_type) { + case HZIP_ALG_TYPE_ZLIB: + return TO_HEAD_SIZE(HZIP_ALG_TYPE_ZLIB); + case HZIP_ALG_TYPE_GZIP: + return get_gzip_head_size(src); + default: + pr_err("request type does not support!\n"); + return -EINVAL; + } +} + +static int get_sg_skip_bytes(struct scatterlist *sgl, size_t bytes, + size_t remains, struct scatterlist **out) +{ +#define SPLIT_NUM 2 + size_t split_sizes[SPLIT_NUM]; + int out_mapped_nents[SPLIT_NUM]; + + split_sizes[0] = bytes; + split_sizes[1] = remains; + + return sg_split(sgl, 0, 0, SPLIT_NUM, split_sizes, out, + out_mapped_nents, GFP_KERNEL); +} + +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; + struct scatterlist *out[2]; + struct scatterlist *sgl; + size_t len; + int ret, req_id; + + /* + * remove/add zlib/gzip head, as hardware operations do not include + * comp head. so split req->src to get sgl without heads in acomp, or + * add comp head to req->dst ahead of that hardware output compressed + * data in sgl splited from req->dst without comp head. + */ + if (is_comp) { + sgl = req->dst; + len = req->dlen - head_size; + } else { + sgl = req->src; + len = req->slen - head_size; + } + + ret = get_sg_skip_bytes(sgl, head_size, len, out); + if (ret) + return ERR_PTR(ret); + + /* sgl for comp head is useless, so free it now */ + kfree(out[0]); + + 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"); + kfree(out[1]); + return ERR_PTR(-EBUSY); + } + 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->src = req->src; + req_cache->dst = out[1]; + req_cache->slen = req->slen; + req_cache->dlen = req->dlen - head_size; + } else { + req_cache->src = out[1]; + req_cache->dst = req->dst; + req_cache->slen = req->slen - head_size; + req_cache->dlen = req->dlen; + } + + 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 hisi_zip_sqe *zip_sqe = &qp_ctx->zip_sqe; + struct hisi_qp *qp = qp_ctx->qp; + struct device *dev = &qp->qm->pdev->dev; + struct hisi_acc_sgl_pool *pool = &qp_ctx->sgl_pool; + dma_addr_t input; + dma_addr_t output; + int ret; + + if (!req->src || !req->slen || !req->dst || !req->dlen) + return -EINVAL; + + req->hw_src = hisi_acc_sg_buf_map_to_hw_sgl(dev, req->src, pool, + req->req_id << 1, &input); + if (IS_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, req->dst, pool, + (req->req_id << 1) + 1, + &output); + if (IS_ERR(req->hw_dst)) { + ret = PTR_ERR(req->hw_dst); + goto err_unmap_input; + } + req->dma_dst = output; + + hisi_zip_fill_sqe(zip_sqe, qp->req_type, input, output, req->slen, + req->dlen); + hisi_zip_config_buf_type(zip_sqe, HZIP_SGL); + hisi_zip_config_tag(zip_sqe, req->req_id); + + /* send command to start a task */ + ret = hisi_qp_send(qp, zip_sqe); + if (ret < 0) + goto err_unmap_output; + + return -EINPROGRESS; + +err_unmap_output: + hisi_acc_sg_buf_unmap(dev, req->dst, req->hw_dst); +err_unmap_input: + hisi_acc_sg_buf_unmap(dev, 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[QPC_COMP]; + struct hisi_zip_req *req; + size_t 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) + return -ENOMEM; + + 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) + 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[QPC_DECOMP]; + struct hisi_zip_req *req; + size_t head_size; + int ret; + + head_size = get_comp_head_size(acomp_req->src, qp_ctx->qp->req_type); + + 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) + 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, + .compress = hisi_zip_acompress, + .decompress = hisi_zip_adecompress, + .base = { + .cra_name = "zlib-deflate", + .cra_driver_name = "hisi-zlib-acomp", + .cra_module = THIS_MODULE, + .cra_priority = HZIP_ALG_PRIORITY, + .cra_ctxsize = sizeof(struct hisi_zip_ctx), + } +}; + +static struct acomp_alg hisi_zip_acomp_gzip = { + .init = hisi_zip_acomp_init, + .exit = hisi_zip_acomp_exit, + .compress = hisi_zip_acompress, + .decompress = hisi_zip_adecompress, + .base = { + .cra_name = "gzip", + .cra_driver_name = "hisi-gzip-acomp", + .cra_module = THIS_MODULE, + .cra_priority = HZIP_ALG_PRIORITY, + .cra_ctxsize = sizeof(struct hisi_zip_ctx), + } +}; + +int hisi_zip_register_to_crypto(void) +{ + int ret = 0; + + ret = crypto_register_acomp(&hisi_zip_acomp_zlib); + if (ret) { + pr_err("Zlib acomp algorithm registration failed\n"); + return ret; + } + + ret = crypto_register_acomp(&hisi_zip_acomp_gzip); + if (ret) { + pr_err("Gzip acomp algorithm registration failed\n"); + crypto_unregister_acomp(&hisi_zip_acomp_zlib); + } + + return ret; +} + +void hisi_zip_unregister_from_crypto(void) +{ + 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 new file mode 100644 index 0000000000000000000000000000000000000000..6e0ca75585d44586184af430f32cae52774440fa --- /dev/null +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -0,0 +1,1013 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019 HiSilicon Limited. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "zip.h" + +#define PCI_DEVICE_ID_ZIP_PF 0xa250 +#define PCI_DEVICE_ID_ZIP_VF 0xa251 + +#define HZIP_VF_NUM 63 +#define HZIP_QUEUE_NUM_V1 4096 +#define HZIP_QUEUE_NUM_V2 1024 + +#define HZIP_CLOCK_GATE_CTRL 0x301004 +#define COMP0_ENABLE BIT(0) +#define COMP1_ENABLE BIT(1) +#define DECOMP0_ENABLE BIT(2) +#define DECOMP1_ENABLE BIT(3) +#define DECOMP2_ENABLE BIT(4) +#define DECOMP3_ENABLE BIT(5) +#define DECOMP4_ENABLE BIT(6) +#define DECOMP5_ENABLE BIT(7) +#define ALL_COMP_DECOMP_EN (COMP0_ENABLE | COMP1_ENABLE | \ + DECOMP0_ENABLE | DECOMP1_ENABLE | \ + DECOMP2_ENABLE | DECOMP3_ENABLE | \ + DECOMP4_ENABLE | DECOMP5_ENABLE) +#define DECOMP_CHECK_ENABLE BIT(16) +#define HZIP_FSM_MAX_CNT 0x301008 + +#define HZIP_PORT_ARCA_CHE_0 0x301040 +#define HZIP_PORT_ARCA_CHE_1 0x301044 +#define HZIP_PORT_AWCA_CHE_0 0x301060 +#define HZIP_PORT_AWCA_CHE_1 0x301064 +#define CACHE_ALL_EN 0xffffffff + +#define HZIP_BD_RUSER_32_63 0x301110 +#define HZIP_SGL_RUSER_32_63 0x30111c +#define HZIP_DATA_RUSER_32_63 0x301128 +#define HZIP_DATA_WUSER_32_63 0x301134 +#define HZIP_BD_WUSER_32_63 0x301140 + +#define HZIP_QM_IDEL_STATUS 0x3040e4 + +#define HZIP_CORE_DEBUG_COMP_0 0x302000 +#define HZIP_CORE_DEBUG_COMP_1 0x303000 +#define HZIP_CORE_DEBUG_DECOMP_0 0x304000 +#define HZIP_CORE_DEBUG_DECOMP_1 0x305000 +#define HZIP_CORE_DEBUG_DECOMP_2 0x306000 +#define HZIP_CORE_DEBUG_DECOMP_3 0x307000 +#define HZIP_CORE_DEBUG_DECOMP_4 0x308000 +#define HZIP_CORE_DEBUG_DECOMP_5 0x309000 + +#define HZIP_CORE_INT_SOURCE 0x3010A0 +#define HZIP_CORE_INT_MASK 0x3010A4 +#define HZIP_CORE_INT_STATUS 0x3010AC +#define HZIP_CORE_INT_STATUS_M_ECC BIT(1) +#define HZIP_CORE_SRAM_ECC_ERR_INFO 0x301148 +#define SRAM_ECC_ERR_NUM_SHIFT 16 +#define SRAM_ECC_ERR_ADDR_SHIFT 24 +#define HZIP_CORE_INT_DISABLE 0x000007FF +#define HZIP_COMP_CORE_NUM 2 +#define HZIP_DECOMP_CORE_NUM 6 +#define HZIP_CORE_NUM (HZIP_COMP_CORE_NUM + \ + HZIP_DECOMP_CORE_NUM) +#define HZIP_SQE_SIZE 128 +#define HZIP_SQ_SIZE (HZIP_SQE_SIZE * QM_Q_DEPTH) +#define HZIP_PF_DEF_Q_NUM 64 +#define HZIP_PF_DEF_Q_BASE 0 + +#define HZIP_SOFT_CTRL_CNT_CLR_CE 0x301000 +#define SOFT_CTRL_CNT_CLR_CE_BIT BIT(0) + +#define HZIP_NUMA_DISTANCE 100 +#define HZIP_BUF_SIZE 22 + +static const char hisi_zip_name[] = "hisi_zip"; +static struct dentry *hzip_debugfs_root; +LIST_HEAD(hisi_zip_list); +DEFINE_MUTEX(hisi_zip_list_lock); + +#ifdef CONFIG_NUMA +static struct hisi_zip *find_zip_device_numa(int node) +{ + struct hisi_zip *zip = NULL; + struct hisi_zip *hisi_zip; + int min_distance = HZIP_NUMA_DISTANCE; + struct device *dev; + + list_for_each_entry(hisi_zip, &hisi_zip_list, list) { + dev = &hisi_zip->qm.pdev->dev; + if (node_distance(dev->numa_node, node) < min_distance) { + zip = hisi_zip; + min_distance = node_distance(dev->numa_node, node); + } + } + + return zip; +} +#endif + +struct hisi_zip *find_zip_device(int node) +{ + struct hisi_zip *zip = NULL; + + mutex_lock(&hisi_zip_list_lock); +#ifdef CONFIG_NUMA + zip = find_zip_device_numa(node); +#else + zip = list_first_entry(&hisi_zip_list, struct hisi_zip, list); +#endif + mutex_unlock(&hisi_zip_list_lock); + + return zip; +} + +struct hisi_zip_hw_error { + u32 int_msk; + const char *msg; +}; + +static const struct hisi_zip_hw_error zip_hw_error[] = { + { .int_msk = BIT(0), .msg = "zip_ecc_1bitt_err" }, + { .int_msk = BIT(1), .msg = "zip_ecc_2bit_err" }, + { .int_msk = BIT(2), .msg = "zip_axi_rresp_err" }, + { .int_msk = BIT(3), .msg = "zip_axi_bresp_err" }, + { .int_msk = BIT(4), .msg = "zip_src_addr_parse_err" }, + { .int_msk = BIT(5), .msg = "zip_dst_addr_parse_err" }, + { .int_msk = BIT(6), .msg = "zip_pre_in_addr_err" }, + { .int_msk = BIT(7), .msg = "zip_pre_in_data_err" }, + { .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" }, + { /* 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", +}; + +struct ctrl_debug_file { + enum ctrl_debug_file_index index; + spinlock_t lock; + struct hisi_zip_ctrl *ctrl; +}; + +/* + * One ZIP controller has one PF and multiple VFs, some global configurations + * which PF has need this structure. + * + * Just relevant for PF. + */ +struct hisi_zip_ctrl { + u32 num_vfs; + struct hisi_zip *hisi_zip; + struct dentry *debug_root; + struct ctrl_debug_file files[HZIP_DEBUG_FILE_NUM]; +}; + +enum { + HZIP_COMP_CORE0, + HZIP_COMP_CORE1, + HZIP_DECOMP_CORE0, + HZIP_DECOMP_CORE1, + HZIP_DECOMP_CORE2, + HZIP_DECOMP_CORE3, + HZIP_DECOMP_CORE4, + HZIP_DECOMP_CORE5, +}; + +static const u64 core_offsets[] = { + [HZIP_COMP_CORE0] = 0x302000, + [HZIP_COMP_CORE1] = 0x303000, + [HZIP_DECOMP_CORE0] = 0x304000, + [HZIP_DECOMP_CORE1] = 0x305000, + [HZIP_DECOMP_CORE2] = 0x306000, + [HZIP_DECOMP_CORE3] = 0x307000, + [HZIP_DECOMP_CORE4] = 0x308000, + [HZIP_DECOMP_CORE5] = 0x309000, +}; + +static struct debugfs_reg32 hzip_dfx_regs[] = { + {"HZIP_GET_BD_NUM ", 0x00ull}, + {"HZIP_GET_RIGHT_BD ", 0x04ull}, + {"HZIP_GET_ERROR_BD ", 0x08ull}, + {"HZIP_DONE_BD_NUM ", 0x0cull}, + {"HZIP_WORK_CYCLE ", 0x10ull}, + {"HZIP_IDLE_CYCLE ", 0x18ull}, + {"HZIP_MAX_DELAY ", 0x20ull}, + {"HZIP_MIN_DELAY ", 0x24ull}, + {"HZIP_AVG_DELAY ", 0x28ull}, + {"HZIP_MEM_VISIBLE_DATA ", 0x30ull}, + {"HZIP_MEM_VISIBLE_ADDR ", 0x34ull}, + {"HZIP_COMSUMED_BYTE ", 0x38ull}, + {"HZIP_PRODUCED_BYTE ", 0x40ull}, + {"HZIP_COMP_INF ", 0x70ull}, + {"HZIP_PRE_OUT ", 0x78ull}, + {"HZIP_BD_RD ", 0x7cull}, + {"HZIP_BD_WR ", 0x80ull}, + {"HZIP_GET_BD_AXI_ERR_NUM ", 0x84ull}, + {"HZIP_GET_BD_PARSE_ERR_NUM ", 0x88ull}, + {"HZIP_ADD_BD_AXI_ERR_NUM ", 0x8cull}, + {"HZIP_DECOMP_STF_RELOAD_CURR_ST ", 0x94ull}, + {"HZIP_DECOMP_LZ77_CURR_ST ", 0x9cull}, +}; + +static int pf_q_num_set(const char *val, const struct kernel_param *kp) +{ + struct pci_dev *pdev = pci_get_device(PCI_VENDOR_ID_HUAWEI, + PCI_DEVICE_ID_ZIP_PF, NULL); + u32 n, q_num; + u8 rev_id; + int ret; + + if (!val) + return -EINVAL; + + if (!pdev) { + q_num = min_t(u32, HZIP_QUEUE_NUM_V1, HZIP_QUEUE_NUM_V2); + pr_info("No device found currently, suppose queue number is %d\n", + q_num); + } else { + rev_id = pdev->revision; + switch (rev_id) { + case QM_HW_V1: + q_num = HZIP_QUEUE_NUM_V1; + break; + case QM_HW_V2: + q_num = HZIP_QUEUE_NUM_V2; + break; + default: + return -EINVAL; + } + } + + ret = kstrtou32(val, 10, &n); + if (ret != 0 || n > q_num || n == 0) + return -EINVAL; + + return param_set_int(val, kp); +} + +static const struct kernel_param_ops pf_q_num_ops = { + .set = pf_q_num_set, + .get = param_get_int, +}; + +static u32 pf_q_num = HZIP_PF_DEF_Q_NUM; +module_param_cb(pf_q_num, &pf_q_num_ops, &pf_q_num, 0444); +MODULE_PARM_DESC(pf_q_num, "Number of queues in PF(v1 1-4096, v2 1-1024)"); + +static int uacce_mode; +module_param(uacce_mode, int, 0); + +static const struct pci_device_id hisi_zip_dev_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, PCI_DEVICE_ID_ZIP_PF) }, + { PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, PCI_DEVICE_ID_ZIP_VF) }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, hisi_zip_dev_ids); + +static inline void hisi_zip_add_to_list(struct hisi_zip *hisi_zip) +{ + mutex_lock(&hisi_zip_list_lock); + list_add_tail(&hisi_zip->list, &hisi_zip_list); + mutex_unlock(&hisi_zip_list_lock); +} + +static inline void hisi_zip_remove_from_list(struct hisi_zip *hisi_zip) +{ + mutex_lock(&hisi_zip_list_lock); + list_del(&hisi_zip->list); + mutex_unlock(&hisi_zip_list_lock); +} + +static void hisi_zip_set_user_domain_and_cache(struct hisi_zip *hisi_zip) +{ + void __iomem *base = hisi_zip->qm.io_base; + + /* qm user domain */ + writel(AXUSER_BASE, base + QM_ARUSER_M_CFG_1); + writel(ARUSER_M_CFG_ENABLE, base + QM_ARUSER_M_CFG_ENABLE); + writel(AXUSER_BASE, base + QM_AWUSER_M_CFG_1); + writel(AWUSER_M_CFG_ENABLE, base + QM_AWUSER_M_CFG_ENABLE); + writel(WUSER_M_CFG_ENABLE, base + QM_WUSER_M_CFG_ENABLE); + + /* qm cache */ + writel(AXI_M_CFG, base + QM_AXI_M_CFG); + writel(AXI_M_CFG_ENABLE, base + QM_AXI_M_CFG_ENABLE); + /* disable FLR triggered by BME(bus master enable) */ + writel(PEH_AXUSER_CFG, base + QM_PEH_AXUSER_CFG); + writel(PEH_AXUSER_CFG_ENABLE, base + QM_PEH_AXUSER_CFG_ENABLE); + + /* cache */ + writel(CACHE_ALL_EN, base + HZIP_PORT_ARCA_CHE_0); + writel(CACHE_ALL_EN, base + HZIP_PORT_ARCA_CHE_1); + writel(CACHE_ALL_EN, base + HZIP_PORT_AWCA_CHE_0); + writel(CACHE_ALL_EN, base + HZIP_PORT_AWCA_CHE_1); + + /* user domain configurations */ + writel(AXUSER_BASE, base + HZIP_BD_RUSER_32_63); + writel(AXUSER_BASE, base + HZIP_SGL_RUSER_32_63); + writel(AXUSER_BASE, base + HZIP_BD_WUSER_32_63); + writel(AXUSER_BASE, base + HZIP_DATA_RUSER_32_63); + writel(AXUSER_BASE, base + HZIP_DATA_WUSER_32_63); + + /* let's open all compression/decompression cores */ + writel(DECOMP_CHECK_ENABLE | ALL_COMP_DECOMP_EN, + base + HZIP_CLOCK_GATE_CTRL); + + /* enable sqc writeback */ + writel(SQC_CACHE_ENABLE | CQC_CACHE_ENABLE | SQC_CACHE_WB_ENABLE | + CQC_CACHE_WB_ENABLE | FIELD_PREP(SQC_CACHE_WB_THRD, 1) | + FIELD_PREP(CQC_CACHE_WB_THRD, 1), base + QM_CACHE_CTL); +} + +static void hisi_zip_hw_error_set_state(struct hisi_zip *hisi_zip, bool state) +{ + struct hisi_qm *qm = &hisi_zip->qm; + + if (qm->ver == QM_HW_V1) { + writel(HZIP_CORE_INT_DISABLE, qm->io_base + HZIP_CORE_INT_MASK); + dev_info(&qm->pdev->dev, "ZIP v%d does not support hw error handle\n", + qm->ver); + return; + } + + if (state) { + /* clear ZIP hw error source if having */ + writel(HZIP_CORE_INT_DISABLE, hisi_zip->qm.io_base + + HZIP_CORE_INT_SOURCE); + /* enable ZIP hw error interrupts */ + writel(0, hisi_zip->qm.io_base + HZIP_CORE_INT_MASK); + } else { + /* disable ZIP hw error interrupts */ + writel(HZIP_CORE_INT_DISABLE, + hisi_zip->qm.io_base + HZIP_CORE_INT_MASK); + } +} + +static inline struct hisi_qm *file_to_qm(struct ctrl_debug_file *file) +{ + struct hisi_zip *hisi_zip = file->ctrl->hisi_zip; + + 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); + struct hisi_zip_ctrl *ctrl = file->ctrl; + u32 vfq_num; + u32 tmp; + + if (val > ctrl->num_vfs) + return -EINVAL; + + /* Calculate 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) / ctrl->num_vfs; + if (val == ctrl->num_vfs) + qm->debug.curr_qm_qp_num = qm->ctrl_qp_num - + qm->qp_num - (ctrl->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 clear_enable_read(struct ctrl_debug_file *file) +{ + struct hisi_qm *qm = file_to_qm(file); + + return readl(qm->io_base + HZIP_SOFT_CTRL_CNT_CLR_CE) & + SOFT_CTRL_CNT_CLR_CE_BIT; +} + +static int clear_enable_write(struct ctrl_debug_file *file, u32 val) +{ + struct hisi_qm *qm = file_to_qm(file); + u32 tmp; + + if (val != 1 && val != 0) + return -EINVAL; + + tmp = (readl(qm->io_base + HZIP_SOFT_CTRL_CNT_CLR_CE) & + ~SOFT_CTRL_CNT_CLR_CE_BIT) | val; + writel(tmp, qm->io_base + HZIP_SOFT_CTRL_CNT_CLR_CE); + + return 0; +} + +static ssize_t ctrl_debug_read(struct file *filp, char __user *buf, + size_t count, loff_t *pos) +{ + struct ctrl_debug_file *file = filp->private_data; + char tbuf[HZIP_BUF_SIZE]; + u32 val; + int ret; + + 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; + default: + spin_unlock_irq(&file->lock); + return -EINVAL; + } + spin_unlock_irq(&file->lock); + ret = sprintf(tbuf, "%u\n", val); + return simple_read_from_buffer(buf, count, pos, tbuf, ret); +} + +static ssize_t ctrl_debug_write(struct file *filp, const char __user *buf, + size_t count, loff_t *pos) +{ + struct ctrl_debug_file *file = filp->private_data; + char tbuf[HZIP_BUF_SIZE]; + unsigned long val; + int len, ret; + + if (*pos != 0) + return 0; + + if (count >= HZIP_BUF_SIZE) + return -ENOSPC; + + len = simple_write_to_buffer(tbuf, HZIP_BUF_SIZE - 1, pos, buf, count); + if (len < 0) + return len; + + tbuf[len] = '\0'; + if (kstrtoul(tbuf, 0, &val)) + return -EFAULT; + + 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) + goto err_input; + break; + default: + ret = -EINVAL; + goto err_input; + } + spin_unlock_irq(&file->lock); + + return count; + +err_input: + spin_unlock_irq(&file->lock); + return ret; +} + +static const struct file_operations ctrl_debug_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = ctrl_debug_read, + .write = ctrl_debug_write, +}; + +static int hisi_zip_core_debug_init(struct hisi_zip_ctrl *ctrl) +{ + struct hisi_zip *hisi_zip = ctrl->hisi_zip; + struct hisi_qm *qm = &hisi_zip->qm; + struct device *dev = &qm->pdev->dev; + struct debugfs_regset32 *regset; + struct dentry *tmp_d, *tmp; + char buf[HZIP_BUF_SIZE]; + int i; + + for (i = 0; i < HZIP_CORE_NUM; i++) { + if (i < HZIP_COMP_CORE_NUM) + sprintf(buf, "comp_core%d", i); + else + sprintf(buf, "decomp_core%d", i - HZIP_COMP_CORE_NUM); + + tmp_d = debugfs_create_dir(buf, ctrl->debug_root); + if (!tmp_d) + return -ENOENT; + + regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL); + if (!regset) + return -ENOENT; + + regset->regs = hzip_dfx_regs; + regset->nregs = ARRAY_SIZE(hzip_dfx_regs); + regset->base = qm->io_base + core_offsets[i]; + + tmp = debugfs_create_regset32("regs", 0444, tmp_d, regset); + if (!tmp) + return -ENOENT; + } + + return 0; +} + +static int hisi_zip_ctrl_debug_init(struct hisi_zip_ctrl *ctrl) +{ + struct dentry *tmp; + int i; + + for (i = HZIP_CURRENT_QM; i < HZIP_DEBUG_FILE_NUM; i++) { + spin_lock_init(&ctrl->files[i].lock); + ctrl->files[i].ctrl = ctrl; + ctrl->files[i].index = i; + + tmp = debugfs_create_file(ctrl_debug_file_name[i], 0600, + ctrl->debug_root, ctrl->files + i, + &ctrl_debug_fops); + if (!tmp) + return -ENOENT; + } + + return hisi_zip_core_debug_init(ctrl); +} + +static int hisi_zip_debugfs_init(struct hisi_zip *hisi_zip) +{ + struct hisi_qm *qm = &hisi_zip->qm; + struct device *dev = &qm->pdev->dev; + struct dentry *dev_d; + int ret; + + dev_d = debugfs_create_dir(dev_name(dev), hzip_debugfs_root); + if (!dev_d) + return -ENOENT; + + qm->debug.debug_root = dev_d; + ret = hisi_qm_debug_init(qm); + if (ret) + goto failed_to_create; + + if (qm->fun_type == QM_HW_PF) { + hisi_zip->ctrl->debug_root = dev_d; + ret = hisi_zip_ctrl_debug_init(hisi_zip->ctrl); + if (ret) + goto failed_to_create; + } + + return 0; + +failed_to_create: + debugfs_remove_recursive(hzip_debugfs_root); + return ret; +} + +static void hisi_zip_debug_regs_clear(struct hisi_zip *hisi_zip) +{ + struct hisi_qm *qm = &hisi_zip->qm; + + writel(0x0, qm->io_base + QM_DFX_MB_CNT_VF); + writel(0x0, qm->io_base + QM_DFX_DB_CNT_VF); + writel(0x0, qm->io_base + HZIP_SOFT_CTRL_CNT_CLR_CE); + + hisi_qm_debug_regs_clear(qm); +} + +static void hisi_zip_debugfs_exit(struct hisi_zip *hisi_zip) +{ + struct hisi_qm *qm = &hisi_zip->qm; + + debugfs_remove_recursive(qm->debug.debug_root); + + if (qm->fun_type == QM_HW_PF) + hisi_zip_debug_regs_clear(hisi_zip); +} + +static void hisi_zip_hw_error_init(struct hisi_zip *hisi_zip) +{ + hisi_qm_hw_error_init(&hisi_zip->qm, QM_BASE_CE, + QM_BASE_NFE | QM_ACC_WB_NOT_READY_TIMEOUT, 0, + QM_DB_RANDOM_INVALID); + hisi_zip_hw_error_set_state(hisi_zip, true); +} + +static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip) +{ + struct hisi_qm *qm = &hisi_zip->qm; + struct hisi_zip_ctrl *ctrl; + + ctrl = devm_kzalloc(&qm->pdev->dev, sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return -ENOMEM; + + hisi_zip->ctrl = ctrl; + ctrl->hisi_zip = hisi_zip; + + switch (qm->ver) { + case QM_HW_V1: + qm->ctrl_qp_num = HZIP_QUEUE_NUM_V1; + break; + + case QM_HW_V2: + qm->ctrl_qp_num = HZIP_QUEUE_NUM_V2; + break; + + default: + return -EINVAL; + } + + hisi_zip_set_user_domain_and_cache(hisi_zip); + hisi_zip_hw_error_init(hisi_zip); + hisi_zip_debug_regs_clear(hisi_zip); + + return 0; +} + +static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct hisi_zip *hisi_zip; + enum qm_hw_ver rev_id; + struct hisi_qm *qm; + int ret; + + rev_id = hisi_qm_get_hw_version(pdev); + if (rev_id == QM_HW_UNKNOWN) + return -EINVAL; + + hisi_zip = devm_kzalloc(&pdev->dev, sizeof(*hisi_zip), GFP_KERNEL); + if (!hisi_zip) + return -ENOMEM; + pci_set_drvdata(pdev, hisi_zip); + + qm = &hisi_zip->qm; + qm->pdev = pdev; + qm->ver = rev_id; + + qm->sqe_size = HZIP_SQE_SIZE; + qm->dev_name = hisi_zip_name; + qm->fun_type = (pdev->device == PCI_DEVICE_ID_ZIP_PF) ? QM_HW_PF : + QM_HW_VF; + switch (uacce_mode) { + case 0: + qm->use_dma_api = true; + break; + case 1: + qm->use_dma_api = false; + break; + case 2: + qm->use_dma_api = true; + break; + default: + return -EINVAL; + } + + ret = hisi_qm_init(qm); + if (ret) { + dev_err(&pdev->dev, "Failed to init qm!\n"); + return ret; + } + + if (qm->fun_type == QM_HW_PF) { + ret = hisi_zip_pf_probe_init(hisi_zip); + if (ret) + return ret; + + qm->qp_base = HZIP_PF_DEF_Q_BASE; + qm->qp_num = pf_q_num; + } else if (qm->fun_type == QM_HW_VF) { + /* + * have no way to get qm configure in VM in v1 hardware, + * so currently force PF to uses HZIP_PF_DEF_Q_NUM, and force + * to trigger only one VF in v1 hardware. + * + * v2 hardware has no such problem. + */ + if (qm->ver == QM_HW_V1) { + qm->qp_base = HZIP_PF_DEF_Q_NUM; + qm->qp_num = HZIP_QUEUE_NUM_V1 - HZIP_PF_DEF_Q_NUM; + } else if (qm->ver == QM_HW_V2) + /* v2 starts to support get vft by mailbox */ + hisi_qm_get_vft(qm, &qm->qp_base, &qm->qp_num); + } + + ret = hisi_qm_start(qm); + if (ret) + goto err_qm_uninit; + + ret = hisi_zip_debugfs_init(hisi_zip); + if (ret) + dev_err(&pdev->dev, "Failed to init debugfs (%d)!\n", ret); + + hisi_zip_add_to_list(hisi_zip); + + return 0; + +err_qm_uninit: + hisi_qm_uninit(qm); + return ret; +} + +/* Currently we only support equal assignment */ +static int hisi_zip_vf_q_assign(struct hisi_zip *hisi_zip, int num_vfs) +{ + struct hisi_qm *qm = &hisi_zip->qm; + u32 qp_num = qm->qp_num; + u32 q_base = qp_num; + u32 q_num, remain_q_num, i; + int ret; + + if (!num_vfs) + return -EINVAL; + + remain_q_num = qm->ctrl_qp_num - qp_num; + if (remain_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); + if (ret) + return ret; + q_base += q_num; + } + + return 0; +} + +static int hisi_zip_clear_vft_config(struct hisi_zip *hisi_zip) +{ + struct hisi_zip_ctrl *ctrl = hisi_zip->ctrl; + struct hisi_qm *qm = &hisi_zip->qm; + u32 i, num_vfs = ctrl->num_vfs; + int ret; + + for (i = 1; i <= num_vfs; i++) { + ret = hisi_qm_set_vft(qm, i, 0, 0); + if (ret) + return ret; + } + + ctrl->num_vfs = 0; + + return 0; +} + +static int hisi_zip_sriov_enable(struct pci_dev *pdev, int max_vfs) +{ +#ifdef CONFIG_PCI_IOV + struct hisi_zip *hisi_zip = pci_get_drvdata(pdev); + int pre_existing_vfs, num_vfs, ret; + + pre_existing_vfs = pci_num_vf(pdev); + + if (pre_existing_vfs) { + dev_err(&pdev->dev, + "Can't enable VF. Please disable pre-enabled VFs!\n"); + return 0; + } + + num_vfs = min_t(int, max_vfs, HZIP_VF_NUM); + + ret = hisi_zip_vf_q_assign(hisi_zip, num_vfs); + if (ret) { + dev_err(&pdev->dev, "Can't assign queues for VF!\n"); + return ret; + } + + hisi_zip->ctrl->num_vfs = num_vfs; + + ret = pci_enable_sriov(pdev, num_vfs); + if (ret) { + dev_err(&pdev->dev, "Can't enable VF!\n"); + hisi_zip_clear_vft_config(hisi_zip); + return ret; + } + + return num_vfs; +#else + return 0; +#endif +} + +static int hisi_zip_sriov_disable(struct pci_dev *pdev) +{ + struct hisi_zip *hisi_zip = pci_get_drvdata(pdev); + + if (pci_vfs_assigned(pdev)) { + dev_err(&pdev->dev, + "Can't disable VFs while VFs are assigned!\n"); + return -EPERM; + } + + /* remove in hisi_zip_pci_driver will be called to free VF resources */ + pci_disable_sriov(pdev); + + return hisi_zip_clear_vft_config(hisi_zip); +} + +static int hisi_zip_sriov_configure(struct pci_dev *pdev, int num_vfs) +{ + if (num_vfs == 0) + return hisi_zip_sriov_disable(pdev); + else + return hisi_zip_sriov_enable(pdev, num_vfs); +} + +static void hisi_zip_remove(struct pci_dev *pdev) +{ + struct hisi_zip *hisi_zip = pci_get_drvdata(pdev); + struct hisi_qm *qm = &hisi_zip->qm; + + if (qm->fun_type == QM_HW_PF && hisi_zip->ctrl->num_vfs != 0) + hisi_zip_sriov_disable(pdev); + + hisi_zip_debugfs_exit(hisi_zip); + hisi_qm_stop(qm); + + if (qm->fun_type == QM_HW_PF) + hisi_zip_hw_error_set_state(hisi_zip, false); + + hisi_qm_uninit(qm); + hisi_zip_remove_from_list(hisi_zip); +} + +static void hisi_zip_log_hw_error(struct hisi_zip *hisi_zip, u32 err_sts) +{ + const struct hisi_zip_hw_error *err = zip_hw_error; + struct device *dev = &hisi_zip->qm.pdev->dev; + u32 err_val; + + while (err->msg) { + if (err->int_msk & err_sts) { + dev_warn(dev, "%s [error status=0x%x] found\n", + err->msg, err->int_msk); + + if (HZIP_CORE_INT_STATUS_M_ECC & err->int_msk) { + err_val = readl(hisi_zip->qm.io_base + + HZIP_CORE_SRAM_ECC_ERR_INFO); + dev_warn(dev, "hisi-zip multi ecc sram num=0x%x\n", + ((err_val >> SRAM_ECC_ERR_NUM_SHIFT) & + 0xFF)); + dev_warn(dev, "hisi-zip multi ecc sram addr=0x%x\n", + (err_val >> SRAM_ECC_ERR_ADDR_SHIFT)); + } + } + err++; + } +} + +static pci_ers_result_t hisi_zip_hw_error_handle(struct hisi_zip *hisi_zip) +{ + u32 err_sts; + + /* read err sts */ + err_sts = readl(hisi_zip->qm.io_base + HZIP_CORE_INT_STATUS); + + if (err_sts) { + hisi_zip_log_hw_error(hisi_zip, err_sts); + /* clear error interrupts */ + writel(err_sts, hisi_zip->qm.io_base + HZIP_CORE_INT_SOURCE); + + return PCI_ERS_RESULT_NEED_RESET; + } + + return PCI_ERS_RESULT_RECOVERED; +} + +static pci_ers_result_t hisi_zip_process_hw_error(struct pci_dev *pdev) +{ + struct hisi_zip *hisi_zip = pci_get_drvdata(pdev); + struct device *dev = &pdev->dev; + pci_ers_result_t qm_ret, zip_ret; + + if (!hisi_zip) { + dev_err(dev, + "Can't recover ZIP-error occurred during device init\n"); + return PCI_ERS_RESULT_NONE; + } + + qm_ret = hisi_qm_hw_error_handle(&hisi_zip->qm); + + zip_ret = hisi_zip_hw_error_handle(hisi_zip); + + return (qm_ret == PCI_ERS_RESULT_NEED_RESET || + zip_ret == PCI_ERS_RESULT_NEED_RESET) ? + PCI_ERS_RESULT_NEED_RESET : PCI_ERS_RESULT_RECOVERED; +} + +static pci_ers_result_t hisi_zip_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + if (pdev->is_virtfn) + return PCI_ERS_RESULT_NONE; + + dev_info(&pdev->dev, "PCI error detected, state(=%d)!!\n", state); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + + return hisi_zip_process_hw_error(pdev); +} + +static const struct pci_error_handlers hisi_zip_err_handler = { + .error_detected = hisi_zip_error_detected, +}; + +static struct pci_driver hisi_zip_pci_driver = { + .name = "hisi_zip", + .id_table = hisi_zip_dev_ids, + .probe = hisi_zip_probe, + .remove = hisi_zip_remove, + .sriov_configure = hisi_zip_sriov_configure, + .err_handler = &hisi_zip_err_handler, +}; + +static void hisi_zip_register_debugfs(void) +{ + if (!debugfs_initialized()) + return; + + hzip_debugfs_root = debugfs_create_dir("hisi_zip", NULL); + if (IS_ERR_OR_NULL(hzip_debugfs_root)) + hzip_debugfs_root = NULL; +} + +static void hisi_zip_unregister_debugfs(void) +{ + debugfs_remove_recursive(hzip_debugfs_root); +} + +static int __init hisi_zip_init(void) +{ + int ret; + + hisi_zip_register_debugfs(); + + ret = pci_register_driver(&hisi_zip_pci_driver); + if (ret < 0) { + pr_err("Failed to register pci driver.\n"); + goto err_pci; + } + + if (uacce_mode == 0 || uacce_mode == 2) { + ret = hisi_zip_register_to_crypto(); + if (ret < 0) { + pr_err("Failed to register driver to crypto.\n"); + goto err_crypto; + } + } + + return 0; + +err_crypto: + pci_unregister_driver(&hisi_zip_pci_driver); +err_pci: + hisi_zip_unregister_debugfs(); + + return ret; +} + +static void __exit hisi_zip_exit(void) +{ + if (uacce_mode == 0 || uacce_mode == 2) + hisi_zip_unregister_from_crypto(); + pci_unregister_driver(&hisi_zip_pci_driver); + hisi_zip_unregister_debugfs(); +} + +module_init(hisi_zip_init); +module_exit(hisi_zip_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Zhou Wang "); +MODULE_DESCRIPTION("Driver for HiSilicon ZIP accelerator"); diff --git a/drivers/crypto/img-hash.c b/drivers/crypto/img-hash.c index d27c812c3d8d227ce3c6d00c724ea4e04932a389..fe4cc8babe1c7d510c5eed0f9462059d623d124b 100644 --- a/drivers/crypto/img-hash.c +++ b/drivers/crypto/img-hash.c @@ -958,9 +958,7 @@ static int img_hash_probe(struct platform_device *pdev) crypto_init_queue(&hdev->queue, IMG_HASH_QUEUE_LENGTH); /* Register bank */ - hash_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - hdev->io_base = devm_ioremap_resource(dev, hash_res); + 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); @@ -980,7 +978,6 @@ static int img_hash_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(dev, "no IRQ resource info\n"); err = irq; goto res_err; } diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c index df43a2c6933b7fbba757cf2602e0001ed63d01e1..b456b85f46d37224cb9c971450a094cf2671ece8 100644 --- a/drivers/crypto/inside-secure/safexcel.c +++ b/drivers/crypto/inside-secure/safexcel.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -27,62 +28,205 @@ static u32 max_rings = EIP197_MAX_RINGS; module_param(max_rings, uint, 0644); MODULE_PARM_DESC(max_rings, "Maximum number of rings to use."); -static void eip197_trc_cache_init(struct safexcel_crypto_priv *priv) +static void eip197_trc_cache_setupvirt(struct safexcel_crypto_priv *priv) { - u32 val, htable_offset; - int i, cs_rc_max, cs_ht_wc, cs_trc_rec_wc, cs_trc_lg_rec_wc; - - if (priv->version == EIP197B) { - cs_rc_max = EIP197B_CS_RC_MAX; - cs_ht_wc = EIP197B_CS_HT_WC; - cs_trc_rec_wc = EIP197B_CS_TRC_REC_WC; - cs_trc_lg_rec_wc = EIP197B_CS_TRC_LG_REC_WC; - } else { - cs_rc_max = EIP197D_CS_RC_MAX; - cs_ht_wc = EIP197D_CS_HT_WC; - cs_trc_rec_wc = EIP197D_CS_TRC_REC_WC; - cs_trc_lg_rec_wc = EIP197D_CS_TRC_LG_REC_WC; + int i; + + /* + * Map all interfaces/rings to register index 0 + * so they can share contexts. Without this, the EIP197 will + * assume each interface/ring to be in its own memory domain + * i.e. have its own subset of UNIQUE memory addresses. + * Which would cause records with the SAME memory address to + * use DIFFERENT cache buffers, causing both poor cache utilization + * AND serious coherence/invalidation issues. + */ + for (i = 0; i < 4; i++) + writel(0, priv->base + EIP197_FLUE_IFC_LUT(i)); + + /* + * Initialize other virtualization regs for cache + * These may not be in their reset state ... + */ + for (i = 0; i < priv->config.rings; i++) { + writel(0, priv->base + EIP197_FLUE_CACHEBASE_LO(i)); + writel(0, priv->base + EIP197_FLUE_CACHEBASE_HI(i)); + writel(EIP197_FLUE_CONFIG_MAGIC, + priv->base + EIP197_FLUE_CONFIG(i)); } + writel(0, priv->base + EIP197_FLUE_OFFSETS); + writel(0, priv->base + EIP197_FLUE_ARC4_OFFSET); +} - /* Enable the record cache memory access */ - val = readl(priv->base + EIP197_CS_RAM_CTRL); - val &= ~EIP197_TRC_ENABLE_MASK; - val |= EIP197_TRC_ENABLE_0; - writel(val, priv->base + EIP197_CS_RAM_CTRL); +static void eip197_trc_cache_banksel(struct safexcel_crypto_priv *priv, + u32 addrmid, int *actbank) +{ + u32 val; + int curbank; + + curbank = addrmid >> 16; + if (curbank != *actbank) { + val = readl(priv->base + EIP197_CS_RAM_CTRL); + val = (val & ~EIP197_CS_BANKSEL_MASK) | + (curbank << EIP197_CS_BANKSEL_OFS); + writel(val, priv->base + EIP197_CS_RAM_CTRL); + *actbank = curbank; + } +} - /* Clear all ECC errors */ - writel(0, priv->base + EIP197_TRC_ECCCTRL); +static u32 eip197_trc_cache_probe(struct safexcel_crypto_priv *priv, + int maxbanks, u32 probemask) +{ + u32 val, addrhi, addrlo, addrmid; + int actbank; /* - * Make sure the cache memory is accessible by taking record cache into - * reset. + * And probe the actual size of the physically attached cache data RAM + * Using a binary subdivision algorithm downto 32 byte cache lines. */ - val = readl(priv->base + EIP197_TRC_PARAMS); - val |= EIP197_TRC_PARAMS_SW_RESET; - val &= ~EIP197_TRC_PARAMS_DATA_ACCESS; - writel(val, priv->base + EIP197_TRC_PARAMS); + addrhi = 1 << (16 + maxbanks); + addrlo = 0; + actbank = min(maxbanks - 1, 0); + while ((addrhi - addrlo) > 32) { + /* write marker to lowest address in top half */ + addrmid = (addrhi + addrlo) >> 1; + eip197_trc_cache_banksel(priv, addrmid, &actbank); + writel((addrmid | (addrlo << 16)) & probemask, + priv->base + EIP197_CLASSIFICATION_RAMS + + (addrmid & 0xffff)); + + /* write marker to lowest address in bottom half */ + eip197_trc_cache_banksel(priv, addrlo, &actbank); + writel((addrlo | (addrhi << 16)) & probemask, + priv->base + EIP197_CLASSIFICATION_RAMS + + (addrlo & 0xffff)); + + /* read back marker from top half */ + eip197_trc_cache_banksel(priv, addrmid, &actbank); + val = readl(priv->base + EIP197_CLASSIFICATION_RAMS + + (addrmid & 0xffff)); + + if (val == ((addrmid | (addrlo << 16)) & probemask)) { + /* read back correct, continue with top half */ + addrlo = addrmid; + } else { + /* not read back correct, continue with bottom half */ + addrhi = addrmid; + } + } + return addrhi; +} + +static void eip197_trc_cache_clear(struct safexcel_crypto_priv *priv, + int cs_rc_max, int cs_ht_wc) +{ + int i; + u32 htable_offset, val, offset; - /* Clear all records */ + /* Clear all records in administration RAM */ for (i = 0; i < cs_rc_max; i++) { - u32 val, offset = EIP197_CLASSIFICATION_RAMS + i * EIP197_CS_RC_SIZE; + offset = EIP197_CLASSIFICATION_RAMS + i * EIP197_CS_RC_SIZE; writel(EIP197_CS_RC_NEXT(EIP197_RC_NULL) | EIP197_CS_RC_PREV(EIP197_RC_NULL), priv->base + offset); - val = EIP197_CS_RC_NEXT(i+1) | EIP197_CS_RC_PREV(i-1); + val = EIP197_CS_RC_NEXT(i + 1) | EIP197_CS_RC_PREV(i - 1); if (i == 0) val |= EIP197_CS_RC_PREV(EIP197_RC_NULL); else if (i == cs_rc_max - 1) val |= EIP197_CS_RC_NEXT(EIP197_RC_NULL); - writel(val, priv->base + offset + sizeof(u32)); + writel(val, priv->base + offset + 4); + /* must also initialize the address key due to ECC! */ + writel(0, priv->base + offset + 8); + writel(0, priv->base + offset + 12); } /* Clear the hash table entries */ htable_offset = cs_rc_max * EIP197_CS_RC_SIZE; for (i = 0; i < cs_ht_wc; i++) writel(GENMASK(29, 0), - priv->base + EIP197_CLASSIFICATION_RAMS + htable_offset + i * sizeof(u32)); + priv->base + EIP197_CLASSIFICATION_RAMS + + htable_offset + i * sizeof(u32)); +} + +static void eip197_trc_cache_init(struct safexcel_crypto_priv *priv) +{ + u32 val, dsize, asize; + int cs_rc_max, cs_ht_wc, cs_trc_rec_wc, cs_trc_lg_rec_wc; + int cs_rc_abs_max, cs_ht_sz; + int maxbanks; + + /* Setup (dummy) virtualization for cache */ + eip197_trc_cache_setupvirt(priv); + + /* + * Enable the record cache memory access and + * probe the bank select width + */ + val = readl(priv->base + EIP197_CS_RAM_CTRL); + val &= ~EIP197_TRC_ENABLE_MASK; + val |= EIP197_TRC_ENABLE_0 | EIP197_CS_BANKSEL_MASK; + writel(val, priv->base + EIP197_CS_RAM_CTRL); + val = readl(priv->base + EIP197_CS_RAM_CTRL); + maxbanks = ((val&EIP197_CS_BANKSEL_MASK)>>EIP197_CS_BANKSEL_OFS) + 1; + + /* Clear all ECC errors */ + writel(0, priv->base + EIP197_TRC_ECCCTRL); + + /* + * Make sure the cache memory is accessible by taking record cache into + * reset. Need data memory access here, not admin access. + */ + val = readl(priv->base + EIP197_TRC_PARAMS); + val |= EIP197_TRC_PARAMS_SW_RESET | EIP197_TRC_PARAMS_DATA_ACCESS; + writel(val, priv->base + EIP197_TRC_PARAMS); + + /* Probed data RAM size in bytes */ + dsize = eip197_trc_cache_probe(priv, maxbanks, 0xffffffff); + + /* + * Now probe the administration RAM size pretty much the same way + * Except that only the lower 30 bits are writable and we don't need + * bank selects + */ + val = readl(priv->base + EIP197_TRC_PARAMS); + /* admin access now */ + val &= ~(EIP197_TRC_PARAMS_DATA_ACCESS | EIP197_CS_BANKSEL_MASK); + writel(val, priv->base + EIP197_TRC_PARAMS); + + /* Probed admin RAM size in admin words */ + asize = eip197_trc_cache_probe(priv, 0, 0xbfffffff) >> 4; + + /* Clear any ECC errors detected while probing! */ + writel(0, priv->base + EIP197_TRC_ECCCTRL); + + /* + * Determine optimal configuration from RAM sizes + * Note that we assume that the physical RAM configuration is sane + * Therefore, we don't do any parameter error checking here ... + */ + + /* For now, just use a single record format covering everything */ + cs_trc_rec_wc = EIP197_CS_TRC_REC_WC; + cs_trc_lg_rec_wc = EIP197_CS_TRC_REC_WC; + + /* + * Step #1: How many records will physically fit? + * Hard upper limit is 1023! + */ + cs_rc_abs_max = min_t(uint, ((dsize >> 2) / cs_trc_lg_rec_wc), 1023); + /* Step #2: Need at least 2 words in the admin RAM per record */ + cs_rc_max = min_t(uint, cs_rc_abs_max, (asize >> 1)); + /* Step #3: Determine log2 of hash table size */ + cs_ht_sz = __fls(asize - cs_rc_max) - 2; + /* Step #4: determine current size of hash table in dwords */ + cs_ht_wc = 16<> 4)); + + /* Clear the cache RAMs */ + eip197_trc_cache_clear(priv, cs_rc_max, cs_ht_wc); /* Disable the record cache memory access */ val = readl(priv->base + EIP197_CS_RAM_CTRL); @@ -102,119 +246,231 @@ static void eip197_trc_cache_init(struct safexcel_crypto_priv *priv) /* Configure the record cache #2 */ val = EIP197_TRC_PARAMS_RC_SZ_LARGE(cs_trc_lg_rec_wc) | EIP197_TRC_PARAMS_BLK_TIMER_SPEED(1) | - EIP197_TRC_PARAMS_HTABLE_SZ(2); + EIP197_TRC_PARAMS_HTABLE_SZ(cs_ht_sz); writel(val, priv->base + EIP197_TRC_PARAMS); + + dev_info(priv->dev, "TRC init: %dd,%da (%dr,%dh)\n", + dsize, asize, cs_rc_max, cs_ht_wc + cs_ht_wc); } -static void eip197_write_firmware(struct safexcel_crypto_priv *priv, - const struct firmware *fw, int pe, u32 ctrl, - u32 prog_en) +static void eip197_init_firmware(struct safexcel_crypto_priv *priv) { - const u32 *data = (const u32 *)fw->data; + int pe, i; u32 val; - int i; - /* Reset the engine to make its program memory accessible */ - writel(EIP197_PE_ICE_x_CTRL_SW_RESET | - EIP197_PE_ICE_x_CTRL_CLR_ECC_CORR | - EIP197_PE_ICE_x_CTRL_CLR_ECC_NON_CORR, - EIP197_PE(priv) + ctrl); + for (pe = 0; pe < priv->config.pes; pe++) { + /* Configure the token FIFO's */ + writel(3, EIP197_PE(priv) + EIP197_PE_ICE_PUTF_CTRL(pe)); + writel(0, EIP197_PE(priv) + EIP197_PE_ICE_PPTF_CTRL(pe)); - /* Enable access to the program memory */ - writel(prog_en, EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe)); + /* Clear the ICE scratchpad memory */ + val = readl(EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL(pe)); + val |= EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_TIMER | + EIP197_PE_ICE_SCRATCH_CTRL_TIMER_EN | + EIP197_PE_ICE_SCRATCH_CTRL_SCRATCH_ACCESS | + EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_ACCESS; + writel(val, EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL(pe)); + + /* clear the scratchpad RAM using 32 bit writes only */ + for (i = 0; i < EIP197_NUM_OF_SCRATCH_BLOCKS; i++) + writel(0, EIP197_PE(priv) + + EIP197_PE_ICE_SCRATCH_RAM(pe) + (i << 2)); + + /* Reset the IFPP engine to make its program mem accessible */ + writel(EIP197_PE_ICE_x_CTRL_SW_RESET | + EIP197_PE_ICE_x_CTRL_CLR_ECC_CORR | + EIP197_PE_ICE_x_CTRL_CLR_ECC_NON_CORR, + EIP197_PE(priv) + EIP197_PE_ICE_FPP_CTRL(pe)); + + /* Reset the IPUE engine to make its program mem accessible */ + writel(EIP197_PE_ICE_x_CTRL_SW_RESET | + EIP197_PE_ICE_x_CTRL_CLR_ECC_CORR | + EIP197_PE_ICE_x_CTRL_CLR_ECC_NON_CORR, + EIP197_PE(priv) + EIP197_PE_ICE_PUE_CTRL(pe)); + + /* Enable access to all IFPP program memories */ + writel(EIP197_PE_ICE_RAM_CTRL_FPP_PROG_EN, + EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe)); + } + +} + +static int eip197_write_firmware(struct safexcel_crypto_priv *priv, + const struct firmware *fw) +{ + const u32 *data = (const u32 *)fw->data; + int i; /* Write the firmware */ for (i = 0; i < fw->size / sizeof(u32); i++) writel(be32_to_cpu(data[i]), priv->base + EIP197_CLASSIFICATION_RAMS + i * sizeof(u32)); - /* Disable access to the program memory */ - writel(0, EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe)); + /* Exclude final 2 NOPs from size */ + return i - EIP197_FW_TERMINAL_NOPS; +} + +/* + * If FW is actual production firmware, then poll for its initialization + * to complete and check if it is good for the HW, otherwise just return OK. + */ +static bool poll_fw_ready(struct safexcel_crypto_priv *priv, int fpp) +{ + int pe, pollcnt; + u32 base, pollofs; - /* Release engine from reset */ - val = readl(EIP197_PE(priv) + ctrl); - val &= ~EIP197_PE_ICE_x_CTRL_SW_RESET; - writel(val, EIP197_PE(priv) + ctrl); + if (fpp) + pollofs = EIP197_FW_FPP_READY; + else + pollofs = EIP197_FW_PUE_READY; + + for (pe = 0; pe < priv->config.pes; pe++) { + base = EIP197_PE_ICE_SCRATCH_RAM(pe); + pollcnt = EIP197_FW_START_POLLCNT; + while (pollcnt && + (readl_relaxed(EIP197_PE(priv) + base + + pollofs) != 1)) { + pollcnt--; + } + if (!pollcnt) { + dev_err(priv->dev, "FW(%d) for PE %d failed to start\n", + fpp, pe); + return false; + } + } + return true; +} + +static bool eip197_start_firmware(struct safexcel_crypto_priv *priv, + int ipuesz, int ifppsz, int minifw) +{ + int pe; + u32 val; + + for (pe = 0; pe < priv->config.pes; pe++) { + /* Disable access to all program memory */ + writel(0, EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe)); + + /* Start IFPP microengines */ + if (minifw) + val = 0; + else + val = EIP197_PE_ICE_UENG_START_OFFSET((ifppsz - 1) & + EIP197_PE_ICE_UENG_INIT_ALIGN_MASK) | + EIP197_PE_ICE_UENG_DEBUG_RESET; + writel(val, EIP197_PE(priv) + EIP197_PE_ICE_FPP_CTRL(pe)); + + /* Start IPUE microengines */ + if (minifw) + val = 0; + else + val = EIP197_PE_ICE_UENG_START_OFFSET((ipuesz - 1) & + EIP197_PE_ICE_UENG_INIT_ALIGN_MASK) | + EIP197_PE_ICE_UENG_DEBUG_RESET; + writel(val, EIP197_PE(priv) + EIP197_PE_ICE_PUE_CTRL(pe)); + } + + /* For miniFW startup, there is no initialization, so always succeed */ + if (minifw) + return true; + + /* Wait until all the firmwares have properly started up */ + if (!poll_fw_ready(priv, 1)) + return false; + if (!poll_fw_ready(priv, 0)) + return false; + + return true; } static int eip197_load_firmwares(struct safexcel_crypto_priv *priv) { const char *fw_name[] = {"ifpp.bin", "ipue.bin"}; const struct firmware *fw[FW_NB]; - char fw_path[31], *dir = NULL; + char fw_path[37], *dir = NULL; int i, j, ret = 0, pe; - u32 val; + int ipuesz, ifppsz, minifw = 0; - switch (priv->version) { - case EIP197B: - dir = "eip197b"; - break; - case EIP197D: + if (priv->version == EIP197D_MRVL) dir = "eip197d"; - break; - default: - /* No firmware is required */ - return 0; - } + else if (priv->version == EIP197B_MRVL || + priv->version == EIP197_DEVBRD) + dir = "eip197b"; + else + return -ENODEV; +retry_fw: for (i = 0; i < FW_NB; i++) { - snprintf(fw_path, 31, "inside-secure/%s/%s", dir, fw_name[i]); - ret = request_firmware(&fw[i], fw_path, priv->dev); + snprintf(fw_path, 37, "inside-secure/%s/%s", dir, fw_name[i]); + ret = firmware_request_nowarn(&fw[i], fw_path, priv->dev); if (ret) { - if (priv->version != EIP197B) + if (minifw || priv->version != EIP197B_MRVL) goto release_fw; /* Fallback to the old firmware location for the * EIP197b. */ - ret = request_firmware(&fw[i], fw_name[i], priv->dev); - if (ret) { - dev_err(priv->dev, - "Failed to request firmware %s (%d)\n", - fw_name[i], ret); + ret = firmware_request_nowarn(&fw[i], fw_name[i], + priv->dev); + if (ret) goto release_fw; - } } } - for (pe = 0; pe < priv->config.pes; pe++) { - /* Clear the scratchpad memory */ - val = readl(EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL(pe)); - val |= EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_TIMER | - EIP197_PE_ICE_SCRATCH_CTRL_TIMER_EN | - EIP197_PE_ICE_SCRATCH_CTRL_SCRATCH_ACCESS | - EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_ACCESS; - writel(val, EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL(pe)); + eip197_init_firmware(priv); + + ifppsz = eip197_write_firmware(priv, fw[FW_IFPP]); - memset_io(EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_RAM(pe), 0, - EIP197_NUM_OF_SCRATCH_BLOCKS * sizeof(u32)); + /* Enable access to IPUE program memories */ + for (pe = 0; pe < priv->config.pes; pe++) + writel(EIP197_PE_ICE_RAM_CTRL_PUE_PROG_EN, + EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe)); - eip197_write_firmware(priv, fw[FW_IFPP], pe, - EIP197_PE_ICE_FPP_CTRL(pe), - EIP197_PE_ICE_RAM_CTRL_FPP_PROG_EN); + ipuesz = eip197_write_firmware(priv, fw[FW_IPUE]); - eip197_write_firmware(priv, fw[FW_IPUE], pe, - EIP197_PE_ICE_PUE_CTRL(pe), - EIP197_PE_ICE_RAM_CTRL_PUE_PROG_EN); + if (eip197_start_firmware(priv, ipuesz, ifppsz, minifw)) { + dev_dbg(priv->dev, "Firmware loaded successfully\n"); + return 0; } + ret = -ENODEV; + release_fw: for (j = 0; j < i; j++) release_firmware(fw[j]); + if (!minifw) { + /* Retry with minifw path */ + dev_dbg(priv->dev, "Firmware set not (fully) present or init failed, falling back to BCLA mode\n"); + dir = "eip197_minifw"; + minifw = 1; + goto retry_fw; + } + + dev_dbg(priv->dev, "Firmware load failed.\n"); + return ret; } static int safexcel_hw_setup_cdesc_rings(struct safexcel_crypto_priv *priv) { - u32 hdw, cd_size_rnd, val; - int i; - - hdw = readl(EIP197_HIA_AIC_G(priv) + EIP197_HIA_OPTIONS); - hdw &= GENMASK(27, 25); - hdw >>= 25; - - cd_size_rnd = (priv->config.cd_size + (BIT(hdw) - 1)) >> hdw; + u32 cd_size_rnd, val; + int i, cd_fetch_cnt; + + cd_size_rnd = (priv->config.cd_size + + (BIT(priv->hwconfig.hwdataw) - 1)) >> + priv->hwconfig.hwdataw; + /* determine number of CD's we can fetch into the CD FIFO as 1 block */ + if (priv->flags & SAFEXCEL_HW_EIP197) { + /* EIP197: try to fetch enough in 1 go to keep all pipes busy */ + cd_fetch_cnt = (1 << priv->hwconfig.hwcfsize) / cd_size_rnd; + cd_fetch_cnt = min_t(uint, cd_fetch_cnt, + (priv->config.pes * EIP197_FETCH_DEPTH)); + } else { + /* for the EIP97, just fetch all that fits minus 1 */ + cd_fetch_cnt = ((1 << priv->hwconfig.hwcfsize) / + cd_size_rnd) - 1; + } for (i = 0; i < priv->config.rings; i++) { /* ring base address */ @@ -226,8 +482,9 @@ static int safexcel_hw_setup_cdesc_rings(struct safexcel_crypto_priv *priv) writel(EIP197_xDR_DESC_MODE_64BIT | (priv->config.cd_offset << 16) | priv->config.cd_size, EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_DESC_SIZE); - writel(((EIP197_FETCH_COUNT * (cd_size_rnd << hdw)) << 16) | - (EIP197_FETCH_COUNT * priv->config.cd_offset), + writel(((cd_fetch_cnt * + (cd_size_rnd << priv->hwconfig.hwdataw)) << 16) | + (cd_fetch_cnt * priv->config.cd_offset), EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_CFG); /* Configure DMA tx control */ @@ -245,14 +502,23 @@ static int safexcel_hw_setup_cdesc_rings(struct safexcel_crypto_priv *priv) static int safexcel_hw_setup_rdesc_rings(struct safexcel_crypto_priv *priv) { - u32 hdw, rd_size_rnd, val; - int i; - - hdw = readl(EIP197_HIA_AIC_G(priv) + EIP197_HIA_OPTIONS); - hdw &= GENMASK(27, 25); - hdw >>= 25; - - rd_size_rnd = (priv->config.rd_size + (BIT(hdw) - 1)) >> hdw; + u32 rd_size_rnd, val; + int i, rd_fetch_cnt; + + /* determine number of RD's we can fetch into the FIFO as one block */ + rd_size_rnd = (EIP197_RD64_FETCH_SIZE + + (BIT(priv->hwconfig.hwdataw) - 1)) >> + priv->hwconfig.hwdataw; + if (priv->flags & SAFEXCEL_HW_EIP197) { + /* EIP197: try to fetch enough in 1 go to keep all pipes busy */ + rd_fetch_cnt = (1 << priv->hwconfig.hwrfsize) / rd_size_rnd; + rd_fetch_cnt = min_t(uint, rd_fetch_cnt, + (priv->config.pes * EIP197_FETCH_DEPTH)); + } else { + /* for the EIP97, just fetch all that fits minus 1 */ + rd_fetch_cnt = ((1 << priv->hwconfig.hwrfsize) / + rd_size_rnd) - 1; + } for (i = 0; i < priv->config.rings; i++) { /* ring base address */ @@ -265,8 +531,9 @@ static int safexcel_hw_setup_rdesc_rings(struct safexcel_crypto_priv *priv) priv->config.rd_size, EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_DESC_SIZE); - writel(((EIP197_FETCH_COUNT * (rd_size_rnd << hdw)) << 16) | - (EIP197_FETCH_COUNT * priv->config.rd_offset), + writel(((rd_fetch_cnt * + (rd_size_rnd << priv->hwconfig.hwdataw)) << 16) | + (rd_fetch_cnt * priv->config.rd_offset), EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_CFG); /* Configure DMA tx control */ @@ -291,23 +558,21 @@ static int safexcel_hw_setup_rdesc_rings(struct safexcel_crypto_priv *priv) static int safexcel_hw_init(struct safexcel_crypto_priv *priv) { - u32 version, val; + u32 val; int i, ret, pe; - /* Determine endianess and configure byte swap */ - version = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_VERSION); - val = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); + dev_dbg(priv->dev, "HW init: using %d pipe(s) and %d ring(s)\n", + priv->config.pes, priv->config.rings); - if ((version & 0xffff) == EIP197_HIA_VERSION_BE) - val |= EIP197_MST_CTRL_BYTE_SWAP; - else if (((version >> 16) & 0xffff) == EIP197_HIA_VERSION_LE) - val |= (EIP197_MST_CTRL_NO_BYTE_SWAP >> 24); - - /* For EIP197 set maximum number of TX commands to 2^5 = 32 */ - if (priv->version == EIP197B || priv->version == EIP197D) + /* + * For EIP197's only set maximum number of TX commands to 2^5 = 32 + * Skip for the EIP97 as it does not have this field. + */ + if (priv->flags & SAFEXCEL_HW_EIP197) { + val = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); val |= EIP197_MST_CTRL_TX_MAX_CMD(5); - - writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); + writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); + } /* Configure wr/rd cache values */ writel(EIP197_MST_CTRL_RD_CACHE(RD_CACHE_4BITS) | @@ -330,11 +595,10 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv) writel(EIP197_DxE_THR_CTRL_RESET_PE, EIP197_HIA_DFE_THR(priv) + EIP197_HIA_DFE_THR_CTRL(pe)); - if (priv->version == EIP197B || priv->version == EIP197D) { - /* Reset HIA input interface arbiter */ + if (priv->flags & SAFEXCEL_HW_EIP197) + /* Reset HIA input interface arbiter (EIP197 only) */ writel(EIP197_HIA_RA_PE_CTRL_RESET, EIP197_HIA_AIC(priv) + EIP197_HIA_RA_PE_CTRL(pe)); - } /* DMA transfer size to use */ val = EIP197_HIA_DFE_CFG_DIS_DEBUG; @@ -357,12 +621,11 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv) EIP197_PE_IN_xBUF_THRES_MAX(7), EIP197_PE(priv) + EIP197_PE_IN_TBUF_THRES(pe)); - if (priv->version == EIP197B || priv->version == EIP197D) { + if (priv->flags & SAFEXCEL_HW_EIP197) /* enable HIA input interface arbiter and rings */ writel(EIP197_HIA_RA_PE_CTRL_EN | GENMASK(priv->config.rings - 1, 0), EIP197_HIA_AIC(priv) + EIP197_HIA_RA_PE_CTRL(pe)); - } /* Data Store Engine configuration */ @@ -381,10 +644,10 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv) EIP197_HIA_DxE_CFG_MAX_DATA_SIZE(8); val |= EIP197_HIA_DxE_CFG_DATA_CACHE_CTRL(WR_CACHE_3BITS); val |= EIP197_HIA_DSE_CFG_ALWAYS_BUFFERABLE; - /* FIXME: instability issues can occur for EIP97 but disabling it impact - * performances. + /* FIXME: instability issues can occur for EIP97 but disabling + * it impacts performance. */ - if (priv->version == EIP197B || priv->version == EIP197D) + if (priv->flags & SAFEXCEL_HW_EIP197) val |= EIP197_HIA_DSE_CFG_EN_SINGLE_WR; writel(val, EIP197_HIA_DSE(priv) + EIP197_HIA_DSE_CFG(pe)); @@ -400,21 +663,15 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv) /* Token & context configuration */ val = EIP197_PE_EIP96_TOKEN_CTRL_CTX_UPDATES | - EIP197_PE_EIP96_TOKEN_CTRL_REUSE_CTX | - EIP197_PE_EIP96_TOKEN_CTRL_POST_REUSE_CTX; + EIP197_PE_EIP96_TOKEN_CTRL_NO_TOKEN_WAIT | + EIP197_PE_EIP96_TOKEN_CTRL_ENABLE_TIMEOUT; writel(val, EIP197_PE(priv) + EIP197_PE_EIP96_TOKEN_CTRL(pe)); - /* H/W capabilities selection */ - val = EIP197_FUNCTION_RSVD; - val |= EIP197_PROTOCOL_ENCRYPT_ONLY | EIP197_PROTOCOL_HASH_ONLY; - val |= EIP197_PROTOCOL_ENCRYPT_HASH | EIP197_PROTOCOL_HASH_DECRYPT; - val |= EIP197_ALG_DES_ECB | EIP197_ALG_DES_CBC; - val |= EIP197_ALG_3DES_ECB | EIP197_ALG_3DES_CBC; - val |= EIP197_ALG_AES_ECB | EIP197_ALG_AES_CBC; - val |= EIP197_ALG_MD5 | EIP197_ALG_HMAC_MD5; - val |= EIP197_ALG_SHA1 | EIP197_ALG_HMAC_SHA1; - val |= EIP197_ALG_SHA2 | EIP197_ALG_HMAC_SHA2; - writel(val, EIP197_PE(priv) + EIP197_PE_EIP96_FUNCTION_EN(pe)); + /* H/W capabilities selection: just enable everything */ + writel(EIP197_FUNCTION_ALL, + EIP197_PE(priv) + EIP197_PE_EIP96_FUNCTION_EN(pe)); + writel(EIP197_FUNCTION_ALL, + EIP197_PE(priv) + EIP197_PE_EIP96_FUNCTION2_EN(pe)); } /* Command Descriptor Rings prepare */ @@ -479,8 +736,9 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv) /* Clear any HIA interrupt */ writel(GENMASK(30, 20), EIP197_HIA_AIC_G(priv) + EIP197_HIA_AIC_G_ACK); - if (priv->version == EIP197B || priv->version == EIP197D) { + if (priv->flags & SAFEXCEL_HW_EIP197) { eip197_trc_cache_init(priv); + priv->flags |= EIP197_TRC_CACHE; ret = eip197_load_firmwares(priv); if (ret) @@ -589,16 +847,32 @@ void safexcel_dequeue(struct safexcel_crypto_priv *priv, int ring) inline int safexcel_rdesc_check_errors(struct safexcel_crypto_priv *priv, struct safexcel_result_desc *rdesc) { - if (likely(!rdesc->result_data.error_code)) + if (likely((!rdesc->descriptor_overflow) && + (!rdesc->buffer_overflow) && + (!rdesc->result_data.error_code))) return 0; - if (rdesc->result_data.error_code & 0x407f) { - /* Fatal error (bits 0-7, 14) */ + if (rdesc->descriptor_overflow) + dev_err(priv->dev, "Descriptor overflow detected"); + + if (rdesc->buffer_overflow) + dev_err(priv->dev, "Buffer overflow detected"); + + if (rdesc->result_data.error_code & 0x4066) { + /* Fatal error (bits 1,2,5,6 & 14) */ dev_err(priv->dev, - "cipher: result: result descriptor error (0x%x)\n", + "result descriptor error (%x)", rdesc->result_data.error_code); + return -EIO; + } else if (rdesc->result_data.error_code & + (BIT(7) | BIT(4) | BIT(3) | BIT(0))) { + /* + * Give priority over authentication fails: + * Blocksize, length & overflow errors, + * something wrong with the input! + */ return -EINVAL; - } else if (rdesc->result_data.error_code == BIT(9)) { + } else if (rdesc->result_data.error_code & BIT(9)) { /* Authentication failed */ return -EBADMSG; } @@ -711,7 +985,8 @@ static inline void safexcel_handle_result_descriptor(struct safexcel_crypto_priv ndesc = ctx->handle_result(priv, ring, req, &should_complete, &ret); if (ndesc < 0) { - dev_err(priv->dev, "failed to handle result (%d)", ndesc); + dev_err(priv->dev, "failed to handle result (%d)\n", + ndesc); goto acknowledge; } @@ -783,7 +1058,7 @@ static irqreturn_t safexcel_irq_ring(int irq, void *data) * reinitialized. This should not happen under * normal circumstances. */ - dev_err(priv->dev, "RDR: fatal error."); + dev_err(priv->dev, "RDR: fatal error.\n"); } else if (likely(stat & EIP197_xDR_THRESH)) { rc = IRQ_WAKE_THREAD; } @@ -813,23 +1088,45 @@ static irqreturn_t safexcel_irq_ring_thread(int irq, void *data) return IRQ_HANDLED; } -static int safexcel_request_ring_irq(struct platform_device *pdev, const char *name, +static int safexcel_request_ring_irq(void *pdev, int irqid, + int is_pci_dev, irq_handler_t handler, irq_handler_t threaded_handler, struct safexcel_ring_irq_data *ring_irq_priv) { - int ret, irq = platform_get_irq_byname(pdev, name); + int ret, irq; + struct device *dev; + + if (IS_ENABLED(CONFIG_PCI) && is_pci_dev) { + struct pci_dev *pci_pdev = pdev; + + dev = &pci_pdev->dev; + irq = pci_irq_vector(pci_pdev, irqid); + if (irq < 0) { + dev_err(dev, "unable to get device MSI IRQ %d (err %d)\n", + irqid, irq); + return irq; + } + } else if (IS_ENABLED(CONFIG_OF)) { + struct platform_device *plf_pdev = pdev; + char irq_name[6] = {0}; /* "ringX\0" */ + + snprintf(irq_name, 6, "ring%d", irqid); + dev = &plf_pdev->dev; + irq = platform_get_irq_byname(plf_pdev, irq_name); - if (irq < 0) { - dev_err(&pdev->dev, "unable to get IRQ '%s'\n", name); - return irq; + if (irq < 0) { + dev_err(dev, "unable to get IRQ '%s' (err %d)\n", + irq_name, irq); + return irq; + } } - ret = devm_request_threaded_irq(&pdev->dev, irq, handler, + ret = devm_request_threaded_irq(dev, irq, handler, threaded_handler, IRQF_ONESHOT, - dev_name(&pdev->dev), ring_irq_priv); + dev_name(dev), ring_irq_priv); if (ret) { - dev_err(&pdev->dev, "unable to request IRQ %d\n", irq); + dev_err(dev, "unable to request IRQ %d\n", irq); return ret; } @@ -843,6 +1140,9 @@ static struct safexcel_alg_template *safexcel_algs[] = { &safexcel_alg_cbc_des3_ede, &safexcel_alg_ecb_aes, &safexcel_alg_cbc_aes, + &safexcel_alg_cfb_aes, + &safexcel_alg_ofb_aes, + &safexcel_alg_ctr_aes, &safexcel_alg_md5, &safexcel_alg_sha1, &safexcel_alg_sha224, @@ -860,6 +1160,15 @@ static struct safexcel_alg_template *safexcel_algs[] = { &safexcel_alg_authenc_hmac_sha256_cbc_aes, &safexcel_alg_authenc_hmac_sha384_cbc_aes, &safexcel_alg_authenc_hmac_sha512_cbc_aes, + &safexcel_alg_authenc_hmac_sha1_cbc_des3_ede, + &safexcel_alg_authenc_hmac_sha1_ctr_aes, + &safexcel_alg_authenc_hmac_sha224_ctr_aes, + &safexcel_alg_authenc_hmac_sha256_ctr_aes, + &safexcel_alg_authenc_hmac_sha384_ctr_aes, + &safexcel_alg_authenc_hmac_sha512_ctr_aes, + &safexcel_alg_xts_aes, + &safexcel_alg_gcm, + &safexcel_alg_ccm, }; static int safexcel_register_algorithms(struct safexcel_crypto_priv *priv) @@ -869,7 +1178,10 @@ static int safexcel_register_algorithms(struct safexcel_crypto_priv *priv) for (i = 0; i < ARRAY_SIZE(safexcel_algs); i++) { safexcel_algs[i]->priv = priv; - if (!(safexcel_algs[i]->engines & priv->version)) + /* Do we have all required base algorithms available? */ + if ((safexcel_algs[i]->algo_mask & priv->hwconfig.algo_flags) != + safexcel_algs[i]->algo_mask) + /* No, so don't register this ciphersuite */ continue; if (safexcel_algs[i]->type == SAFEXCEL_ALG_TYPE_SKCIPHER) @@ -887,7 +1199,10 @@ static int safexcel_register_algorithms(struct safexcel_crypto_priv *priv) fail: for (j = 0; j < i; j++) { - if (!(safexcel_algs[j]->engines & priv->version)) + /* Do we have all required base algorithms available? */ + if ((safexcel_algs[j]->algo_mask & priv->hwconfig.algo_flags) != + safexcel_algs[j]->algo_mask) + /* No, so don't unregister this ciphersuite */ continue; if (safexcel_algs[j]->type == SAFEXCEL_ALG_TYPE_SKCIPHER) @@ -906,7 +1221,10 @@ static void safexcel_unregister_algorithms(struct safexcel_crypto_priv *priv) int i; for (i = 0; i < ARRAY_SIZE(safexcel_algs); i++) { - if (!(safexcel_algs[i]->engines & priv->version)) + /* Do we have all required base algorithms available? */ + if ((safexcel_algs[i]->algo_mask & priv->hwconfig.algo_flags) != + safexcel_algs[i]->algo_mask) + /* No, so don't unregister this ciphersuite */ continue; if (safexcel_algs[i]->type == SAFEXCEL_ALG_TYPE_SKCIPHER) @@ -925,22 +1243,20 @@ static void safexcel_configure(struct safexcel_crypto_priv *priv) val = readl(EIP197_HIA_AIC_G(priv) + EIP197_HIA_OPTIONS); /* Read number of PEs from the engine */ - switch (priv->version) { - case EIP197B: - case EIP197D: + if (priv->flags & SAFEXCEL_HW_EIP197) + /* Wider field width for all EIP197 type engines */ mask = EIP197_N_PES_MASK; - break; - default: + else + /* Narrow field width for EIP97 type engine */ mask = EIP97_N_PES_MASK; - } + priv->config.pes = (val >> EIP197_N_PES_OFFSET) & mask; + priv->config.rings = min_t(u32, val & GENMASK(3, 0), max_rings); + val = (val & GENMASK(27, 25)) >> 25; mask = BIT(val) - 1; - val = readl(EIP197_HIA_AIC_G(priv) + EIP197_HIA_OPTIONS); - priv->config.rings = min_t(u32, val & GENMASK(3, 0), max_rings); - priv->config.cd_size = (sizeof(struct safexcel_command_desc) / sizeof(u32)); priv->config.cd_offset = (priv->config.cd_size + mask) & ~mask; @@ -952,9 +1268,7 @@ static void safexcel_init_register_offsets(struct safexcel_crypto_priv *priv) { struct safexcel_register_offsets *offsets = &priv->offsets; - switch (priv->version) { - case EIP197B: - case EIP197D: + if (priv->flags & SAFEXCEL_HW_EIP197) { offsets->hia_aic = EIP197_HIA_AIC_BASE; offsets->hia_aic_g = EIP197_HIA_AIC_G_BASE; offsets->hia_aic_r = EIP197_HIA_AIC_R_BASE; @@ -965,8 +1279,8 @@ static void safexcel_init_register_offsets(struct safexcel_crypto_priv *priv) offsets->hia_dse_thr = EIP197_HIA_DSE_THR_BASE; offsets->hia_gen_cfg = EIP197_HIA_GEN_CFG_BASE; offsets->pe = EIP197_PE_BASE; - break; - case EIP97IES: + offsets->global = EIP197_GLOBAL_BASE; + } else { offsets->hia_aic = EIP97_HIA_AIC_BASE; offsets->hia_aic_g = EIP97_HIA_AIC_G_BASE; offsets->hia_aic_r = EIP97_HIA_AIC_R_BASE; @@ -977,135 +1291,213 @@ static void safexcel_init_register_offsets(struct safexcel_crypto_priv *priv) offsets->hia_dse_thr = EIP97_HIA_DSE_THR_BASE; offsets->hia_gen_cfg = EIP97_HIA_GEN_CFG_BASE; offsets->pe = EIP97_PE_BASE; - break; + offsets->global = EIP97_GLOBAL_BASE; } } -static int safexcel_probe(struct platform_device *pdev) +/* + * Generic part of probe routine, shared by platform and PCI driver + * + * Assumes IO resources have been mapped, private data mem has been allocated, + * clocks have been enabled, device pointer has been assigned etc. + * + */ +static int safexcel_probe_generic(void *pdev, + struct safexcel_crypto_priv *priv, + int is_pci_dev) { - struct device *dev = &pdev->dev; - struct resource *res; - struct safexcel_crypto_priv *priv; - int i, ret; + struct device *dev = priv->dev; + u32 peid, version, mask, val, hiaopt; + int i, ret, hwctg; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) + priv->context_pool = dmam_pool_create("safexcel-context", dev, + sizeof(struct safexcel_context_record), + 1, 0); + if (!priv->context_pool) return -ENOMEM; - priv->dev = dev; - priv->version = (enum safexcel_eip_version)of_device_get_match_data(dev); - - if (priv->version == EIP197B || priv->version == EIP197D) - priv->flags |= EIP197_TRC_CACHE; + /* + * First try the EIP97 HIA version regs + * For the EIP197, this is guaranteed to NOT return any of the test + * values + */ + version = readl(priv->base + EIP97_HIA_AIC_BASE + EIP197_HIA_VERSION); + + mask = 0; /* do not swap */ + if (EIP197_REG_LO16(version) == EIP197_HIA_VERSION_LE) { + priv->hwconfig.hiaver = EIP197_VERSION_MASK(version); + } else if (EIP197_REG_HI16(version) == EIP197_HIA_VERSION_BE) { + /* read back byte-swapped, so complement byte swap bits */ + mask = EIP197_MST_CTRL_BYTE_SWAP_BITS; + priv->hwconfig.hiaver = EIP197_VERSION_SWAP(version); + } else { + /* So it wasn't an EIP97 ... maybe it's an EIP197? */ + version = readl(priv->base + EIP197_HIA_AIC_BASE + + EIP197_HIA_VERSION); + if (EIP197_REG_LO16(version) == EIP197_HIA_VERSION_LE) { + priv->hwconfig.hiaver = EIP197_VERSION_MASK(version); + priv->flags |= SAFEXCEL_HW_EIP197; + } else if (EIP197_REG_HI16(version) == + EIP197_HIA_VERSION_BE) { + /* read back byte-swapped, so complement swap bits */ + mask = EIP197_MST_CTRL_BYTE_SWAP_BITS; + priv->hwconfig.hiaver = EIP197_VERSION_SWAP(version); + priv->flags |= SAFEXCEL_HW_EIP197; + } else { + return -ENODEV; + } + } + /* Now initialize the reg offsets based on the probing info so far */ safexcel_init_register_offsets(priv); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->base = devm_ioremap_resource(dev, res); - if (IS_ERR(priv->base)) { - dev_err(dev, "failed to get resource\n"); - return PTR_ERR(priv->base); + /* + * If the version was read byte-swapped, we need to flip the device + * swapping Keep in mind here, though, that what we write will also be + * byte-swapped ... + */ + if (mask) { + val = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); + val = val ^ (mask >> 24); /* toggle byte swap bits */ + writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); } - priv->clk = devm_clk_get(&pdev->dev, NULL); - ret = PTR_ERR_OR_ZERO(priv->clk); - /* The clock isn't mandatory */ - if (ret != -ENOENT) { - if (ret) - return ret; - - ret = clk_prepare_enable(priv->clk); - if (ret) { - dev_err(dev, "unable to enable clk (%d)\n", ret); - return ret; - } + /* + * We're not done probing yet! We may fall through to here if no HIA + * was found at all. So, with the endianness presumably correct now and + * the offsets setup, *really* probe for the EIP97/EIP197. + */ + version = readl(EIP197_GLOBAL(priv) + EIP197_VERSION); + if (((priv->flags & SAFEXCEL_HW_EIP197) && + (EIP197_REG_LO16(version) != EIP197_VERSION_LE)) || + ((!(priv->flags & SAFEXCEL_HW_EIP197) && + (EIP197_REG_LO16(version) != EIP97_VERSION_LE)))) { + /* + * We did not find the device that matched our initial probing + * (or our initial probing failed) Report appropriate error. + */ + return -ENODEV; } - priv->reg_clk = devm_clk_get(&pdev->dev, "reg"); - ret = PTR_ERR_OR_ZERO(priv->reg_clk); - /* The clock isn't mandatory */ - if (ret != -ENOENT) { - if (ret) - goto err_core_clk; + priv->hwconfig.hwver = EIP197_VERSION_MASK(version); + hwctg = version >> 28; + peid = version & 255; - ret = clk_prepare_enable(priv->reg_clk); - if (ret) { - dev_err(dev, "unable to enable reg clk (%d)\n", ret); - goto err_core_clk; - } + /* Detect EIP96 packet engine and version */ + version = readl(EIP197_PE(priv) + EIP197_PE_EIP96_VERSION(0)); + if (EIP197_REG_LO16(version) != EIP96_VERSION_LE) { + dev_err(dev, "EIP%d: EIP96 not detected.\n", peid); + return -ENODEV; + } + priv->hwconfig.pever = EIP197_VERSION_MASK(version); + + hiaopt = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_OPTIONS); + + if (priv->flags & SAFEXCEL_HW_EIP197) { + /* EIP197 */ + priv->hwconfig.hwdataw = (hiaopt >> EIP197_HWDATAW_OFFSET) & + EIP197_HWDATAW_MASK; + priv->hwconfig.hwcfsize = ((hiaopt >> EIP197_CFSIZE_OFFSET) & + EIP197_CFSIZE_MASK) + + EIP197_CFSIZE_ADJUST; + priv->hwconfig.hwrfsize = ((hiaopt >> EIP197_RFSIZE_OFFSET) & + EIP197_RFSIZE_MASK) + + EIP197_RFSIZE_ADJUST; + } else { + /* EIP97 */ + priv->hwconfig.hwdataw = (hiaopt >> EIP197_HWDATAW_OFFSET) & + EIP97_HWDATAW_MASK; + priv->hwconfig.hwcfsize = (hiaopt >> EIP97_CFSIZE_OFFSET) & + EIP97_CFSIZE_MASK; + priv->hwconfig.hwrfsize = (hiaopt >> EIP97_RFSIZE_OFFSET) & + EIP97_RFSIZE_MASK; } - ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); - if (ret) - goto err_reg_clk; + /* Get supported algorithms from EIP96 transform engine */ + priv->hwconfig.algo_flags = readl(EIP197_PE(priv) + + EIP197_PE_EIP96_OPTIONS(0)); - priv->context_pool = dmam_pool_create("safexcel-context", dev, - sizeof(struct safexcel_context_record), - 1, 0); - if (!priv->context_pool) { - ret = -ENOMEM; - goto err_reg_clk; - } + /* Print single info line describing what we just detected */ + dev_info(priv->dev, "EIP%d:%x(%d)-HIA:%x(%d,%d,%d),PE:%x,alg:%08x\n", + peid, priv->hwconfig.hwver, hwctg, priv->hwconfig.hiaver, + priv->hwconfig.hwdataw, priv->hwconfig.hwcfsize, + priv->hwconfig.hwrfsize, priv->hwconfig.pever, + priv->hwconfig.algo_flags); safexcel_configure(priv); + if (IS_ENABLED(CONFIG_PCI) && priv->version == EIP197_DEVBRD) { + /* + * Request MSI vectors for global + 1 per ring - + * or just 1 for older dev images + */ + struct pci_dev *pci_pdev = pdev; + + ret = pci_alloc_irq_vectors(pci_pdev, + priv->config.rings + 1, + priv->config.rings + 1, + PCI_IRQ_MSI | PCI_IRQ_MSIX); + if (ret < 0) { + dev_err(dev, "Failed to allocate PCI MSI interrupts\n"); + return ret; + } + } + + /* Register the ring IRQ handlers and configure the rings */ priv->ring = devm_kcalloc(dev, priv->config.rings, sizeof(*priv->ring), GFP_KERNEL); - if (!priv->ring) { - ret = -ENOMEM; - goto err_reg_clk; - } + if (!priv->ring) + return -ENOMEM; for (i = 0; i < priv->config.rings; i++) { - char irq_name[6] = {0}; /* "ringX\0" */ - char wq_name[9] = {0}; /* "wq_ringX\0" */ + char wq_name[9] = {0}; int irq; struct safexcel_ring_irq_data *ring_irq; ret = safexcel_init_ring_descriptors(priv, &priv->ring[i].cdr, &priv->ring[i].rdr); - if (ret) - goto err_reg_clk; + if (ret) { + dev_err(dev, "Failed to initialize rings\n"); + return ret; + } priv->ring[i].rdr_req = devm_kcalloc(dev, EIP197_DEFAULT_RING_SIZE, sizeof(priv->ring[i].rdr_req), GFP_KERNEL); - if (!priv->ring[i].rdr_req) { - ret = -ENOMEM; - goto err_reg_clk; - } + if (!priv->ring[i].rdr_req) + return -ENOMEM; ring_irq = devm_kzalloc(dev, sizeof(*ring_irq), GFP_KERNEL); - if (!ring_irq) { - ret = -ENOMEM; - goto err_reg_clk; - } + if (!ring_irq) + return -ENOMEM; ring_irq->priv = priv; ring_irq->ring = i; - snprintf(irq_name, 6, "ring%d", i); - irq = safexcel_request_ring_irq(pdev, irq_name, safexcel_irq_ring, + irq = safexcel_request_ring_irq(pdev, + EIP197_IRQ_NUMBER(i, is_pci_dev), + is_pci_dev, + safexcel_irq_ring, safexcel_irq_ring_thread, ring_irq); if (irq < 0) { - ret = irq; - goto err_reg_clk; + dev_err(dev, "Failed to get IRQ ID for ring %d\n", i); + return irq; } priv->ring[i].work_data.priv = priv; priv->ring[i].work_data.ring = i; - INIT_WORK(&priv->ring[i].work_data.work, safexcel_dequeue_work); + INIT_WORK(&priv->ring[i].work_data.work, + safexcel_dequeue_work); snprintf(wq_name, 9, "wq_ring%d", i); - priv->ring[i].workqueue = create_singlethread_workqueue(wq_name); - if (!priv->ring[i].workqueue) { - ret = -ENOMEM; - goto err_reg_clk; - } + priv->ring[i].workqueue = + create_singlethread_workqueue(wq_name); + if (!priv->ring[i].workqueue) + return -ENOMEM; priv->ring[i].requests = 0; priv->ring[i].busy = false; @@ -1117,28 +1509,21 @@ static int safexcel_probe(struct platform_device *pdev) spin_lock_init(&priv->ring[i].queue_lock); } - platform_set_drvdata(pdev, priv); atomic_set(&priv->ring_used, 0); ret = safexcel_hw_init(priv); if (ret) { - dev_err(dev, "EIP h/w init failed (%d)\n", ret); - goto err_reg_clk; + dev_err(dev, "HW init failed (%d)\n", ret); + return ret; } ret = safexcel_register_algorithms(priv); if (ret) { dev_err(dev, "Failed to register algorithms (%d)\n", ret); - goto err_reg_clk; + return ret; } return 0; - -err_reg_clk: - clk_disable_unprepare(priv->reg_clk); -err_core_clk: - clk_disable_unprepare(priv->clk); - return ret; } static void safexcel_hw_reset_rings(struct safexcel_crypto_priv *priv) @@ -1160,6 +1545,76 @@ static void safexcel_hw_reset_rings(struct safexcel_crypto_priv *priv) } } +#if IS_ENABLED(CONFIG_OF) +/* for Device Tree platform driver */ + +static int safexcel_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct safexcel_crypto_priv *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + priv->version = (enum safexcel_eip_version)of_device_get_match_data(dev); + + platform_set_drvdata(pdev, priv); + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) { + dev_err(dev, "failed to get resource\n"); + return PTR_ERR(priv->base); + } + + priv->clk = devm_clk_get(&pdev->dev, NULL); + ret = PTR_ERR_OR_ZERO(priv->clk); + /* The clock isn't mandatory */ + if (ret != -ENOENT) { + if (ret) + return ret; + + ret = clk_prepare_enable(priv->clk); + if (ret) { + dev_err(dev, "unable to enable clk (%d)\n", ret); + return ret; + } + } + + priv->reg_clk = devm_clk_get(&pdev->dev, "reg"); + ret = PTR_ERR_OR_ZERO(priv->reg_clk); + /* The clock isn't mandatory */ + if (ret != -ENOENT) { + if (ret) + goto err_core_clk; + + ret = clk_prepare_enable(priv->reg_clk); + if (ret) { + dev_err(dev, "unable to enable reg clk (%d)\n", ret); + goto err_core_clk; + } + } + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (ret) + goto err_reg_clk; + + /* Generic EIP97/EIP197 device probing */ + ret = safexcel_probe_generic(pdev, priv, 0); + if (ret) + goto err_reg_clk; + + return 0; + +err_reg_clk: + clk_disable_unprepare(priv->reg_clk); +err_core_clk: + clk_disable_unprepare(priv->clk); + return ret; +} + static int safexcel_remove(struct platform_device *pdev) { struct safexcel_crypto_priv *priv = platform_get_drvdata(pdev); @@ -1179,30 +1634,28 @@ static int safexcel_remove(struct platform_device *pdev) static const struct of_device_id safexcel_of_match_table[] = { { .compatible = "inside-secure,safexcel-eip97ies", - .data = (void *)EIP97IES, + .data = (void *)EIP97IES_MRVL, }, { .compatible = "inside-secure,safexcel-eip197b", - .data = (void *)EIP197B, + .data = (void *)EIP197B_MRVL, }, { .compatible = "inside-secure,safexcel-eip197d", - .data = (void *)EIP197D, + .data = (void *)EIP197D_MRVL, }, + /* For backward compatibility and intended for generic use */ { - /* Deprecated. Kept for backward compatibility. */ .compatible = "inside-secure,safexcel-eip97", - .data = (void *)EIP97IES, + .data = (void *)EIP97IES_MRVL, }, { - /* Deprecated. Kept for backward compatibility. */ .compatible = "inside-secure,safexcel-eip197", - .data = (void *)EIP197B, + .data = (void *)EIP197B_MRVL, }, {}, }; - static struct platform_driver crypto_safexcel = { .probe = safexcel_probe, .remove = safexcel_remove, @@ -1211,10 +1664,166 @@ static struct platform_driver crypto_safexcel = { .of_match_table = safexcel_of_match_table, }, }; -module_platform_driver(crypto_safexcel); +#endif + +#if IS_ENABLED(CONFIG_PCI) +/* PCIE devices - i.e. Inside Secure development boards */ + +static int safexcel_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct device *dev = &pdev->dev; + struct safexcel_crypto_priv *priv; + void __iomem *pciebase; + int rc; + u32 val; + + dev_dbg(dev, "Probing PCIE device: vendor %04x, device %04x, subv %04x, subdev %04x, ctxt %lx\n", + ent->vendor, ent->device, ent->subvendor, + ent->subdevice, ent->driver_data); + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + priv->version = (enum safexcel_eip_version)ent->driver_data; + + pci_set_drvdata(pdev, priv); + + /* enable the device */ + rc = pcim_enable_device(pdev); + if (rc) { + dev_err(dev, "Failed to enable PCI device\n"); + return rc; + } + + /* take ownership of PCI BAR0 */ + rc = pcim_iomap_regions(pdev, 1, "crypto_safexcel"); + if (rc) { + dev_err(dev, "Failed to map IO region for BAR0\n"); + return rc; + } + priv->base = pcim_iomap_table(pdev)[0]; + + if (priv->version == EIP197_DEVBRD) { + dev_dbg(dev, "Device identified as FPGA based development board - applying HW reset\n"); + + rc = pcim_iomap_regions(pdev, 4, "crypto_safexcel"); + if (rc) { + dev_err(dev, "Failed to map IO region for BAR4\n"); + return rc; + } + + pciebase = pcim_iomap_table(pdev)[2]; + val = readl(pciebase + EIP197_XLX_IRQ_BLOCK_ID_ADDR); + if ((val >> 16) == EIP197_XLX_IRQ_BLOCK_ID_VALUE) { + dev_dbg(dev, "Detected Xilinx PCIE IRQ block version %d, multiple MSI support enabled\n", + (val & 0xff)); + + /* Setup MSI identity map mapping */ + writel(EIP197_XLX_USER_VECT_LUT0_IDENT, + pciebase + EIP197_XLX_USER_VECT_LUT0_ADDR); + writel(EIP197_XLX_USER_VECT_LUT1_IDENT, + pciebase + EIP197_XLX_USER_VECT_LUT1_ADDR); + writel(EIP197_XLX_USER_VECT_LUT2_IDENT, + pciebase + EIP197_XLX_USER_VECT_LUT2_ADDR); + writel(EIP197_XLX_USER_VECT_LUT3_IDENT, + pciebase + EIP197_XLX_USER_VECT_LUT3_ADDR); + + /* Enable all device interrupts */ + writel(GENMASK(31, 0), + pciebase + EIP197_XLX_USER_INT_ENB_MSK); + } else { + dev_err(dev, "Unrecognised IRQ block identifier %x\n", + val); + return -ENODEV; + } + + /* HW reset FPGA dev board */ + /* assert reset */ + writel(1, priv->base + EIP197_XLX_GPIO_BASE); + wmb(); /* maintain strict ordering for accesses here */ + /* deassert reset */ + writel(0, priv->base + EIP197_XLX_GPIO_BASE); + wmb(); /* maintain strict ordering for accesses here */ + } + + /* enable bus mastering */ + pci_set_master(pdev); + + /* Generic EIP97/EIP197 device probing */ + rc = safexcel_probe_generic(pdev, priv, 1); + return rc; +} + +void safexcel_pci_remove(struct pci_dev *pdev) +{ + struct safexcel_crypto_priv *priv = pci_get_drvdata(pdev); + int i; + + safexcel_unregister_algorithms(priv); + + for (i = 0; i < priv->config.rings; i++) + destroy_workqueue(priv->ring[i].workqueue); + + safexcel_hw_reset_rings(priv); +} + +static const struct pci_device_id safexcel_pci_ids[] = { + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_XILINX, 0x9038, + 0x16ae, 0xc522), + .driver_data = EIP197_DEVBRD, + }, + {}, +}; + +MODULE_DEVICE_TABLE(pci, safexcel_pci_ids); + +static struct pci_driver safexcel_pci_driver = { + .name = "crypto-safexcel", + .id_table = safexcel_pci_ids, + .probe = safexcel_pci_probe, + .remove = safexcel_pci_remove, +}; +#endif + +static int __init safexcel_init(void) +{ + int rc; + +#if IS_ENABLED(CONFIG_OF) + /* Register platform driver */ + platform_driver_register(&crypto_safexcel); +#endif + +#if IS_ENABLED(CONFIG_PCI) + /* Register PCI driver */ + rc = pci_register_driver(&safexcel_pci_driver); +#endif + + return 0; +} + +static void __exit safexcel_exit(void) +{ +#if IS_ENABLED(CONFIG_OF) + /* Unregister platform driver */ + platform_driver_unregister(&crypto_safexcel); +#endif + +#if IS_ENABLED(CONFIG_PCI) + /* Unregister PCI driver if successfully registered before */ + pci_unregister_driver(&safexcel_pci_driver); +#endif +} + +module_init(safexcel_init); +module_exit(safexcel_exit); MODULE_AUTHOR("Antoine Tenart "); MODULE_AUTHOR("Ofer Heifetz "); MODULE_AUTHOR("Igal Liberman "); -MODULE_DESCRIPTION("Support for SafeXcel cryptographic engine EIP197"); +MODULE_DESCRIPTION("Support for SafeXcel cryptographic engines: EIP97 & EIP197"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/crypto/inside-secure/safexcel.h b/drivers/crypto/inside-secure/safexcel.h index e0c202f3367415211e8079e767cf49a022dbc9b4..930cc48a6f859553f888bad9f61ec15d1264e428 100644 --- a/drivers/crypto/inside-secure/safexcel.h +++ b/drivers/crypto/inside-secure/safexcel.h @@ -14,14 +14,23 @@ #include #include -#define EIP197_HIA_VERSION_LE 0xca35 -#define EIP197_HIA_VERSION_BE 0x35ca +#define EIP197_HIA_VERSION_BE 0xca35 +#define EIP197_HIA_VERSION_LE 0x35ca +#define EIP97_VERSION_LE 0x9e61 +#define EIP197_VERSION_LE 0x3ac5 +#define EIP96_VERSION_LE 0x9f60 +#define EIP197_REG_LO16(reg) (reg & 0xffff) +#define EIP197_REG_HI16(reg) ((reg >> 16) & 0xffff) +#define EIP197_VERSION_MASK(reg) ((reg >> 16) & 0xfff) +#define EIP197_VERSION_SWAP(reg) (((reg & 0xf0) << 4) | \ + ((reg >> 4) & 0xf0) | \ + ((reg >> 12) & 0xf)) /* Static configuration */ #define EIP197_DEFAULT_RING_SIZE 400 -#define EIP197_MAX_TOKENS 8 +#define EIP197_MAX_TOKENS 18 #define EIP197_MAX_RINGS 4 -#define EIP197_FETCH_COUNT 1 +#define EIP197_FETCH_DEPTH 2 #define EIP197_MAX_BATCH_SZ 64 #define EIP197_GFP_FLAGS(base) ((base).flags & CRYPTO_TFM_REQ_MAY_SLEEP ? \ @@ -38,6 +47,27 @@ char __##name##_desc[size] CRYPTO_MINALIGN_ATTR; \ struct type##_request *name = (void *)__##name##_desc +/* Xilinx dev board base offsets */ +#define EIP197_XLX_GPIO_BASE 0x200000 +#define EIP197_XLX_IRQ_BLOCK_ID_ADDR 0x2000 +#define EIP197_XLX_IRQ_BLOCK_ID_VALUE 0x1fc2 +#define EIP197_XLX_USER_INT_ENB_MSK 0x2004 +#define EIP197_XLX_USER_INT_ENB_SET 0x2008 +#define EIP197_XLX_USER_INT_ENB_CLEAR 0x200c +#define EIP197_XLX_USER_INT_BLOCK 0x2040 +#define EIP197_XLX_USER_INT_PEND 0x2048 +#define EIP197_XLX_USER_VECT_LUT0_ADDR 0x2080 +#define EIP197_XLX_USER_VECT_LUT0_IDENT 0x03020100 +#define EIP197_XLX_USER_VECT_LUT1_ADDR 0x2084 +#define EIP197_XLX_USER_VECT_LUT1_IDENT 0x07060504 +#define EIP197_XLX_USER_VECT_LUT2_ADDR 0x2088 +#define EIP197_XLX_USER_VECT_LUT2_IDENT 0x0b0a0908 +#define EIP197_XLX_USER_VECT_LUT3_ADDR 0x208c +#define EIP197_XLX_USER_VECT_LUT3_IDENT 0x0f0e0d0c + +/* Helper defines for probe function */ +#define EIP197_IRQ_NUMBER(i, is_pci) (i + is_pci) + /* Register base offsets */ #define EIP197_HIA_AIC(priv) ((priv)->base + (priv)->offsets.hia_aic) #define EIP197_HIA_AIC_G(priv) ((priv)->base + (priv)->offsets.hia_aic_g) @@ -49,6 +79,7 @@ #define EIP197_HIA_DSE_THR(priv) ((priv)->base + (priv)->offsets.hia_dse_thr) #define EIP197_HIA_GEN_CFG(priv) ((priv)->base + (priv)->offsets.hia_gen_cfg) #define EIP197_PE(priv) ((priv)->base + (priv)->offsets.pe) +#define EIP197_GLOBAL(priv) ((priv)->base + (priv)->offsets.global) /* EIP197 base offsets */ #define EIP197_HIA_AIC_BASE 0x90000 @@ -61,6 +92,7 @@ #define EIP197_HIA_DSE_THR_BASE 0x8d040 #define EIP197_HIA_GEN_CFG_BASE 0xf0000 #define EIP197_PE_BASE 0xa0000 +#define EIP197_GLOBAL_BASE 0xf0000 /* EIP97 base offsets */ #define EIP97_HIA_AIC_BASE 0x0 @@ -73,6 +105,7 @@ #define EIP97_HIA_DSE_THR_BASE 0xf600 #define EIP97_HIA_GEN_CFG_BASE 0x10000 #define EIP97_PE_BASE 0x10000 +#define EIP97_GLOBAL_BASE 0x10000 /* CDR/RDR register offsets */ #define EIP197_HIA_xDR_OFF(priv, r) (EIP197_HIA_AIC_xDR(priv) + (r) * 0x1000) @@ -115,16 +148,22 @@ #define EIP197_PE_IN_TBUF_THRES(n) (0x0100 + (0x2000 * (n))) #define EIP197_PE_ICE_SCRATCH_RAM(n) (0x0800 + (0x2000 * (n))) #define EIP197_PE_ICE_PUE_CTRL(n) (0x0c80 + (0x2000 * (n))) +#define EIP197_PE_ICE_PUTF_CTRL(n) (0x0d00 + (0x2000 * (n))) #define EIP197_PE_ICE_SCRATCH_CTRL(n) (0x0d04 + (0x2000 * (n))) #define EIP197_PE_ICE_FPP_CTRL(n) (0x0d80 + (0x2000 * (n))) +#define EIP197_PE_ICE_PPTF_CTRL(n) (0x0e00 + (0x2000 * (n))) #define EIP197_PE_ICE_RAM_CTRL(n) (0x0ff0 + (0x2000 * (n))) #define EIP197_PE_EIP96_TOKEN_CTRL(n) (0x1000 + (0x2000 * (n))) #define EIP197_PE_EIP96_FUNCTION_EN(n) (0x1004 + (0x2000 * (n))) #define EIP197_PE_EIP96_CONTEXT_CTRL(n) (0x1008 + (0x2000 * (n))) #define EIP197_PE_EIP96_CONTEXT_STAT(n) (0x100c + (0x2000 * (n))) +#define EIP197_PE_EIP96_FUNCTION2_EN(n) (0x1030 + (0x2000 * (n))) +#define EIP197_PE_EIP96_OPTIONS(n) (0x13f8 + (0x2000 * (n))) +#define EIP197_PE_EIP96_VERSION(n) (0x13fc + (0x2000 * (n))) #define EIP197_PE_OUT_DBUF_THRES(n) (0x1c00 + (0x2000 * (n))) #define EIP197_PE_OUT_TBUF_THRES(n) (0x1d00 + (0x2000 * (n))) #define EIP197_MST_CTRL 0xfff4 +#define EIP197_VERSION 0xfffc /* EIP197-specific registers, no indirection */ #define EIP197_CLASSIFICATION_RAMS 0xe0000 @@ -139,6 +178,12 @@ #define EIP197_TRC_ECCADMINSTAT 0xf0838 #define EIP197_TRC_ECCDATASTAT 0xf083c #define EIP197_TRC_ECCDATA 0xf0840 +#define EIP197_FLUE_CACHEBASE_LO(n) (0xf6000 + (32 * (n))) +#define EIP197_FLUE_CACHEBASE_HI(n) (0xf6004 + (32 * (n))) +#define EIP197_FLUE_CONFIG(n) (0xf6010 + (32 * (n))) +#define EIP197_FLUE_OFFSETS 0xf6808 +#define EIP197_FLUE_ARC4_OFFSET 0xf680c +#define EIP197_FLUE_IFC_LUT(n) (0xf6820 + (4 * (n))) #define EIP197_CS_RAM_CTRL 0xf7ff0 /* EIP197_HIA_xDR_DESC_SIZE */ @@ -186,6 +231,19 @@ #define EIP197_N_PES_OFFSET 4 #define EIP197_N_PES_MASK GENMASK(4, 0) #define EIP97_N_PES_MASK GENMASK(2, 0) +#define EIP197_HWDATAW_OFFSET 25 +#define EIP197_HWDATAW_MASK GENMASK(3, 0) +#define EIP97_HWDATAW_MASK GENMASK(2, 0) +#define EIP197_CFSIZE_OFFSET 9 +#define EIP197_CFSIZE_ADJUST 4 +#define EIP97_CFSIZE_OFFSET 8 +#define EIP197_CFSIZE_MASK GENMASK(3, 0) +#define EIP97_CFSIZE_MASK GENMASK(4, 0) +#define EIP197_RFSIZE_OFFSET 12 +#define EIP197_RFSIZE_ADJUST 4 +#define EIP97_RFSIZE_OFFSET 12 +#define EIP197_RFSIZE_MASK GENMASK(3, 0) +#define EIP97_RFSIZE_MASK GENMASK(4, 0) /* EIP197_HIA_AIC_R_ENABLE_CTRL */ #define EIP197_CDR_IRQ(n) BIT((n) * 2) @@ -207,6 +265,11 @@ #define EIP197_DxE_THR_CTRL_EN BIT(30) #define EIP197_DxE_THR_CTRL_RESET_PE BIT(31) +/* EIP197_PE_ICE_PUE/FPP_CTRL */ +#define EIP197_PE_ICE_UENG_START_OFFSET(n) ((n) << 16) +#define EIP197_PE_ICE_UENG_INIT_ALIGN_MASK 0x7ff0 +#define EIP197_PE_ICE_UENG_DEBUG_RESET BIT(3) + /* EIP197_HIA_AIC_G_ENABLED_STAT */ #define EIP197_G_IRQ_DFE(n) BIT((n) << 1) #define EIP197_G_IRQ_DSE(n) BIT(((n) << 1) + 1) @@ -223,6 +286,7 @@ #define EIP197_MST_CTRL_TX_MAX_CMD(n) (((n) & 0xf) << 20) #define EIP197_MST_CTRL_BYTE_SWAP BIT(24) #define EIP197_MST_CTRL_NO_BYTE_SWAP BIT(25) +#define EIP197_MST_CTRL_BYTE_SWAP_BITS GENMASK(25, 24) /* EIP197_PE_IN_DBUF/TBUF_THRES */ #define EIP197_PE_IN_xBUF_THRES_MIN(n) ((n) << 8) @@ -252,45 +316,20 @@ /* EIP197_PE_EIP96_TOKEN_CTRL */ #define EIP197_PE_EIP96_TOKEN_CTRL_CTX_UPDATES BIT(16) -#define EIP197_PE_EIP96_TOKEN_CTRL_REUSE_CTX BIT(19) -#define EIP197_PE_EIP96_TOKEN_CTRL_POST_REUSE_CTX BIT(20) +#define EIP197_PE_EIP96_TOKEN_CTRL_NO_TOKEN_WAIT BIT(17) +#define EIP197_PE_EIP96_TOKEN_CTRL_ENABLE_TIMEOUT BIT(22) /* EIP197_PE_EIP96_FUNCTION_EN */ -#define EIP197_FUNCTION_RSVD (BIT(6) | BIT(15) | BIT(20) | BIT(23)) -#define EIP197_PROTOCOL_HASH_ONLY BIT(0) -#define EIP197_PROTOCOL_ENCRYPT_ONLY BIT(1) -#define EIP197_PROTOCOL_HASH_ENCRYPT BIT(2) -#define EIP197_PROTOCOL_HASH_DECRYPT BIT(3) -#define EIP197_PROTOCOL_ENCRYPT_HASH BIT(4) -#define EIP197_PROTOCOL_DECRYPT_HASH BIT(5) -#define EIP197_ALG_ARC4 BIT(7) -#define EIP197_ALG_AES_ECB BIT(8) -#define EIP197_ALG_AES_CBC BIT(9) -#define EIP197_ALG_AES_CTR_ICM BIT(10) -#define EIP197_ALG_AES_OFB BIT(11) -#define EIP197_ALG_AES_CFB BIT(12) -#define EIP197_ALG_DES_ECB BIT(13) -#define EIP197_ALG_DES_CBC BIT(14) -#define EIP197_ALG_DES_OFB BIT(16) -#define EIP197_ALG_DES_CFB BIT(17) -#define EIP197_ALG_3DES_ECB BIT(18) -#define EIP197_ALG_3DES_CBC BIT(19) -#define EIP197_ALG_3DES_OFB BIT(21) -#define EIP197_ALG_3DES_CFB BIT(22) -#define EIP197_ALG_MD5 BIT(24) -#define EIP197_ALG_HMAC_MD5 BIT(25) -#define EIP197_ALG_SHA1 BIT(26) -#define EIP197_ALG_HMAC_SHA1 BIT(27) -#define EIP197_ALG_SHA2 BIT(28) -#define EIP197_ALG_HMAC_SHA2 BIT(29) -#define EIP197_ALG_AES_XCBC_MAC BIT(30) -#define EIP197_ALG_GCM_HASH BIT(31) +#define EIP197_FUNCTION_ALL 0xffffffff /* EIP197_PE_EIP96_CONTEXT_CTRL */ #define EIP197_CONTEXT_SIZE(n) (n) #define EIP197_ADDRESS_MODE BIT(8) #define EIP197_CONTROL_MODE BIT(9) +/* EIP197_FLUE_CONFIG */ +#define EIP197_FLUE_CONFIG_MAGIC 0xc7000004 + /* Context Control */ struct safexcel_context_record { u32 control0; @@ -320,6 +359,7 @@ struct safexcel_context_record { #define CONTEXT_CONTROL_CRYPTO_ALG_AES192 (0x6 << 17) #define CONTEXT_CONTROL_CRYPTO_ALG_AES256 (0x7 << 17) #define CONTEXT_CONTROL_DIGEST_PRECOMPUTED (0x1 << 21) +#define CONTEXT_CONTROL_DIGEST_XCM (0x2 << 21) #define CONTEXT_CONTROL_DIGEST_HMAC (0x3 << 21) #define CONTEXT_CONTROL_CRYPTO_ALG_MD5 (0x0 << 23) #define CONTEXT_CONTROL_CRYPTO_ALG_SHA1 (0x2 << 23) @@ -327,12 +367,21 @@ struct safexcel_context_record { #define CONTEXT_CONTROL_CRYPTO_ALG_SHA256 (0x3 << 23) #define CONTEXT_CONTROL_CRYPTO_ALG_SHA384 (0x6 << 23) #define CONTEXT_CONTROL_CRYPTO_ALG_SHA512 (0x5 << 23) +#define CONTEXT_CONTROL_CRYPTO_ALG_GHASH (0x4 << 23) +#define CONTEXT_CONTROL_CRYPTO_ALG_XCBC128 (0x1 << 23) +#define CONTEXT_CONTROL_CRYPTO_ALG_XCBC192 (0x2 << 23) +#define CONTEXT_CONTROL_CRYPTO_ALG_XCBC256 (0x3 << 23) #define CONTEXT_CONTROL_INV_FR (0x5 << 24) #define CONTEXT_CONTROL_INV_TR (0x6 << 24) /* control1 */ #define CONTEXT_CONTROL_CRYPTO_MODE_ECB (0 << 0) #define CONTEXT_CONTROL_CRYPTO_MODE_CBC (1 << 0) +#define CONTEXT_CONTROL_CRYPTO_MODE_OFB (4 << 0) +#define CONTEXT_CONTROL_CRYPTO_MODE_CFB (5 << 0) +#define CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD (6 << 0) +#define CONTEXT_CONTROL_CRYPTO_MODE_XTS (7 << 0) +#define CONTEXT_CONTROL_CRYPTO_MODE_XCM ((6 << 0) | BIT(17)) #define CONTEXT_CONTROL_IV0 BIT(5) #define CONTEXT_CONTROL_IV1 BIT(6) #define CONTEXT_CONTROL_IV2 BIT(7) @@ -342,6 +391,9 @@ struct safexcel_context_record { #define CONTEXT_CONTROL_CRYPTO_STORE BIT(12) #define CONTEXT_CONTROL_HASH_STORE BIT(19) +#define EIP197_XCM_MODE_GCM 1 +#define EIP197_XCM_MODE_CCM 2 + /* The hash counter given to the engine in the context has a granularity of * 64 bits. */ @@ -352,6 +404,8 @@ struct safexcel_context_record { #define EIP197_TRC_ENABLE_1 BIT(5) #define EIP197_TRC_ENABLE_2 BIT(6) #define EIP197_TRC_ENABLE_MASK GENMASK(6, 4) +#define EIP197_CS_BANKSEL_MASK GENMASK(14, 12) +#define EIP197_CS_BANKSEL_OFS 12 /* EIP197_TRC_PARAMS */ #define EIP197_TRC_PARAMS_SW_RESET BIT(0) @@ -369,19 +423,11 @@ struct safexcel_context_record { #define EIP197_TRC_PARAMS2_RC_SZ_SMALL(n) ((n) << 18) /* Cache helpers */ -#define EIP197B_CS_RC_MAX 52 -#define EIP197D_CS_RC_MAX 96 +#define EIP197_CS_TRC_REC_WC 64 #define EIP197_CS_RC_SIZE (4 * sizeof(u32)) #define EIP197_CS_RC_NEXT(x) (x) #define EIP197_CS_RC_PREV(x) ((x) << 10) #define EIP197_RC_NULL 0x3ff -#define EIP197B_CS_TRC_REC_WC 59 -#define EIP197D_CS_TRC_REC_WC 64 -#define EIP197B_CS_TRC_LG_REC_WC 73 -#define EIP197D_CS_TRC_LG_REC_WC 80 -#define EIP197B_CS_HT_WC 64 -#define EIP197D_CS_HT_WC 256 - /* Result data */ struct result_data_desc { @@ -423,6 +469,14 @@ struct safexcel_result_desc { struct result_data_desc result_data; } __packed; +/* + * The EIP(1)97 only needs to fetch the descriptor part of + * the result descriptor, not the result token part! + */ +#define EIP197_RD64_FETCH_SIZE ((sizeof(struct safexcel_result_desc) -\ + sizeof(struct result_data_desc)) /\ + sizeof(u32)) + struct safexcel_token { u32 packet_length:17; u8 stat:2; @@ -442,6 +496,7 @@ struct safexcel_token { #define EIP197_TOKEN_OPCODE_INSERT 0x2 #define EIP197_TOKEN_OPCODE_NOOP EIP197_TOKEN_OPCODE_INSERT #define EIP197_TOKEN_OPCODE_RETRIEVE 0x4 +#define EIP197_TOKEN_OPCODE_INSERT_REMRES 0xa #define EIP197_TOKEN_OPCODE_VERIFY 0xd #define EIP197_TOKEN_OPCODE_CTX_ACCESS 0xe #define EIP197_TOKEN_OPCODE_BYPASS GENMASK(3, 0) @@ -455,10 +510,11 @@ static inline void eip197_noop_token(struct safexcel_token *token) /* Instructions */ #define EIP197_TOKEN_INS_INSERT_HASH_DIGEST 0x1c #define EIP197_TOKEN_INS_ORIGIN_IV0 0x14 +#define EIP197_TOKEN_INS_ORIGIN_TOKEN 0x1b #define EIP197_TOKEN_INS_ORIGIN_LEN(x) ((x) << 5) #define EIP197_TOKEN_INS_TYPE_OUTPUT BIT(5) #define EIP197_TOKEN_INS_TYPE_HASH BIT(6) -#define EIP197_TOKEN_INS_TYPE_CRYTO BIT(7) +#define EIP197_TOKEN_INS_TYPE_CRYPTO BIT(7) #define EIP197_TOKEN_INS_LAST BIT(8) /* Processing Engine Control Data */ @@ -509,6 +565,11 @@ struct safexcel_command_desc { * Internal structures & functions */ +#define EIP197_FW_TERMINAL_NOPS 2 +#define EIP197_FW_START_POLLCNT 16 +#define EIP197_FW_PUE_READY 0x14 +#define EIP197_FW_FPP_READY 0x18 + enum eip197_fw { FW_IFPP = 0, FW_IPUE, @@ -581,10 +642,42 @@ struct safexcel_ring { struct crypto_async_request *backlog; }; +/* EIP integration context flags */ enum safexcel_eip_version { - EIP97IES = BIT(0), - EIP197B = BIT(1), - EIP197D = BIT(2), + /* Platform (EIP integration context) specifier */ + EIP97IES_MRVL, + EIP197B_MRVL, + EIP197D_MRVL, + EIP197_DEVBRD +}; + +/* Priority we use for advertising our algorithms */ +#define SAFEXCEL_CRA_PRIORITY 300 + +/* EIP algorithm presence flags */ +enum safexcel_eip_algorithms { + SAFEXCEL_ALG_BC0 = BIT(5), + SAFEXCEL_ALG_SM4 = BIT(6), + SAFEXCEL_ALG_SM3 = BIT(7), + SAFEXCEL_ALG_CHACHA20 = BIT(8), + SAFEXCEL_ALG_POLY1305 = BIT(9), + SAFEXCEL_SEQMASK_256 = BIT(10), + SAFEXCEL_SEQMASK_384 = BIT(11), + SAFEXCEL_ALG_AES = BIT(12), + SAFEXCEL_ALG_AES_XFB = BIT(13), + SAFEXCEL_ALG_DES = BIT(15), + SAFEXCEL_ALG_DES_XFB = BIT(16), + SAFEXCEL_ALG_ARC4 = BIT(18), + SAFEXCEL_ALG_AES_XTS = BIT(20), + SAFEXCEL_ALG_WIRELESS = BIT(21), + SAFEXCEL_ALG_MD5 = BIT(22), + SAFEXCEL_ALG_SHA1 = BIT(23), + SAFEXCEL_ALG_SHA2_256 = BIT(25), + SAFEXCEL_ALG_SHA2_512 = BIT(26), + SAFEXCEL_ALG_XCBC_MAC = BIT(27), + SAFEXCEL_ALG_CBC_MAC_ALL = BIT(29), + SAFEXCEL_ALG_GHASH = BIT(30), + SAFEXCEL_ALG_SHA3 = BIT(31), }; struct safexcel_register_offsets { @@ -598,10 +691,22 @@ struct safexcel_register_offsets { u32 hia_dse_thr; u32 hia_gen_cfg; u32 pe; + u32 global; }; enum safexcel_flags { - EIP197_TRC_CACHE = BIT(0), + EIP197_TRC_CACHE = BIT(0), + SAFEXCEL_HW_EIP197 = BIT(1), +}; + +struct safexcel_hwconfig { + enum safexcel_eip_algorithms algo_flags; + int hwver; + int hiaver; + int pever; + int hwdataw; + int hwcfsize; + int hwrfsize; }; struct safexcel_crypto_priv { @@ -613,6 +718,7 @@ struct safexcel_crypto_priv { enum safexcel_eip_version version; struct safexcel_register_offsets offsets; + struct safexcel_hwconfig hwconfig; u32 flags; /* context DMA pool */ @@ -637,14 +743,16 @@ struct safexcel_context { bool exit_inv; }; +#define HASH_CACHE_SIZE SHA512_BLOCK_SIZE + struct safexcel_ahash_export_state { - u64 len[2]; - u64 processed[2]; + u64 len; + u64 processed; u32 digest; u32 state[SHA512_DIGEST_SIZE / sizeof(u32)]; - u8 cache[SHA512_BLOCK_SIZE << 1]; + u8 cache[HASH_CACHE_SIZE]; }; /* @@ -655,7 +763,7 @@ struct safexcel_ahash_export_state { struct safexcel_alg_template { struct safexcel_crypto_priv *priv; enum safexcel_alg_type type; - u32 engines; + enum safexcel_eip_algorithms algo_mask; union { struct skcipher_alg skcipher; struct aead_alg aead; @@ -716,6 +824,9 @@ extern struct safexcel_alg_template safexcel_alg_ecb_des3_ede; extern struct safexcel_alg_template safexcel_alg_cbc_des3_ede; extern struct safexcel_alg_template safexcel_alg_ecb_aes; extern struct safexcel_alg_template safexcel_alg_cbc_aes; +extern struct safexcel_alg_template safexcel_alg_cfb_aes; +extern struct safexcel_alg_template safexcel_alg_ofb_aes; +extern struct safexcel_alg_template safexcel_alg_ctr_aes; extern struct safexcel_alg_template safexcel_alg_md5; extern struct safexcel_alg_template safexcel_alg_sha1; extern struct safexcel_alg_template safexcel_alg_sha224; @@ -733,5 +844,14 @@ extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha224_cbc_aes; extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha256_cbc_aes; extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha384_cbc_aes; extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha512_cbc_aes; +extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_cbc_des3_ede; +extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_ctr_aes; +extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha224_ctr_aes; +extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha256_ctr_aes; +extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha384_ctr_aes; +extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha512_ctr_aes; +extern struct safexcel_alg_template safexcel_alg_xts_aes; +extern struct safexcel_alg_template safexcel_alg_gcm; +extern struct safexcel_alg_template safexcel_alg_ccm; #endif diff --git a/drivers/crypto/inside-secure/safexcel_cipher.c b/drivers/crypto/inside-secure/safexcel_cipher.c index 8cdbdbe356815efbc0deb2d978a52a4a6ccc50cc..ef51f8c2b473ba8c914a1d6258c7602697e96676 100644 --- a/drivers/crypto/inside-secure/safexcel_cipher.c +++ b/drivers/crypto/inside-secure/safexcel_cipher.c @@ -12,8 +12,12 @@ #include #include #include -#include +#include +#include +#include +#include #include +#include #include #include #include @@ -38,15 +42,19 @@ struct safexcel_cipher_ctx { u32 mode; enum safexcel_cipher_alg alg; bool aead; + int xcm; /* 0=authenc, 1=GCM, 2 reserved for CCM */ - __le32 key[8]; - unsigned int key_len; + __le32 key[16]; + u32 nonce; + unsigned int key_len, xts; /* All the below is AEAD specific */ u32 hash_alg; u32 state_sz; u32 ipad[SHA512_DIGEST_SIZE / sizeof(u32)]; u32 opad[SHA512_DIGEST_SIZE / sizeof(u32)]; + + struct crypto_cipher *hkaes; }; struct safexcel_cipher_req { @@ -54,16 +62,47 @@ struct safexcel_cipher_req { /* Number of result descriptors associated to the request */ unsigned int rdescs; bool needs_inv; + int nr_src, nr_dst; }; -static void safexcel_skcipher_token(struct safexcel_cipher_ctx *ctx, u8 *iv, - struct safexcel_command_desc *cdesc, - u32 length) +static void safexcel_cipher_token(struct safexcel_cipher_ctx *ctx, u8 *iv, + struct safexcel_command_desc *cdesc) { - struct safexcel_token *token; - u32 offset = 0, block_sz = 0; + u32 block_sz = 0; + + if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD) { + cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD; + + /* 32 bit nonce */ + cdesc->control_data.token[0] = ctx->nonce; + /* 64 bit IV part */ + memcpy(&cdesc->control_data.token[1], iv, 8); + /* 32 bit counter, start at 1 (big endian!) */ + cdesc->control_data.token[3] = cpu_to_be32(1); + + return; + } else if (ctx->xcm == EIP197_XCM_MODE_GCM) { + cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD; + + /* 96 bit IV part */ + memcpy(&cdesc->control_data.token[0], iv, 12); + /* 32 bit counter, start at 1 (big endian!) */ + cdesc->control_data.token[3] = cpu_to_be32(1); + + return; + } else if (ctx->xcm == EIP197_XCM_MODE_CCM) { + cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD; + + /* Variable length IV part */ + memcpy(&cdesc->control_data.token[0], iv, 15 - iv[0]); + /* Start variable length counter at 0 */ + memset((u8 *)&cdesc->control_data.token[0] + 15 - iv[0], + 0, iv[0] + 1); - if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) { + return; + } + + if (ctx->mode != CONTEXT_CONTROL_CRYPTO_MODE_ECB) { switch (ctx->alg) { case SAFEXCEL_DES: block_sz = DES_BLOCK_SIZE; @@ -78,39 +117,28 @@ static void safexcel_skcipher_token(struct safexcel_cipher_ctx *ctx, u8 *iv, cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD; break; } - - offset = block_sz / sizeof(u32); memcpy(cdesc->control_data.token, iv, block_sz); } +} + +static void safexcel_skcipher_token(struct safexcel_cipher_ctx *ctx, u8 *iv, + struct safexcel_command_desc *cdesc, + u32 length) +{ + struct safexcel_token *token; + + safexcel_cipher_token(ctx, iv, cdesc); - token = (struct safexcel_token *)(cdesc->control_data.token + offset); + /* skip over worst case IV of 4 dwords, no need to be exact */ + token = (struct safexcel_token *)(cdesc->control_data.token + 4); token[0].opcode = EIP197_TOKEN_OPCODE_DIRECTION; token[0].packet_length = length; token[0].stat = EIP197_TOKEN_STAT_LAST_PACKET | EIP197_TOKEN_STAT_LAST_HASH; token[0].instructions = EIP197_TOKEN_INS_LAST | - EIP197_TOKEN_INS_TYPE_CRYTO | + EIP197_TOKEN_INS_TYPE_CRYPTO | EIP197_TOKEN_INS_TYPE_OUTPUT; - - if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) { - u32 last = (EIP197_MAX_TOKENS - 1) - offset; - - token[last].opcode = EIP197_TOKEN_OPCODE_CTX_ACCESS; - token[last].packet_length = EIP197_TOKEN_DIRECTION_EXTERNAL | - EIP197_TOKEN_EXEC_IF_SUCCESSFUL| - EIP197_TOKEN_CTX_OFFSET(0x2); - token[last].stat = EIP197_TOKEN_STAT_LAST_HASH | - EIP197_TOKEN_STAT_LAST_PACKET; - token[last].instructions = - EIP197_TOKEN_INS_ORIGIN_LEN(block_sz / sizeof(u32)) | - EIP197_TOKEN_INS_ORIGIN_IV0; - - /* Store the updated IV values back in the internal context - * registers. - */ - cdesc->control_data.control1 |= CONTEXT_CONTROL_CRYPTO_STORE; - } } static void safexcel_aead_token(struct safexcel_cipher_ctx *ctx, u8 *iv, @@ -119,53 +147,123 @@ static void safexcel_aead_token(struct safexcel_cipher_ctx *ctx, u8 *iv, u32 cryptlen, u32 assoclen, u32 digestsize) { struct safexcel_token *token; - unsigned offset = 0; - if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) { - offset = AES_BLOCK_SIZE / sizeof(u32); - memcpy(cdesc->control_data.token, iv, AES_BLOCK_SIZE); + safexcel_cipher_token(ctx, iv, cdesc); - cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD; + if (direction == SAFEXCEL_ENCRYPT) { + /* align end of instruction sequence to end of token */ + token = (struct safexcel_token *)(cdesc->control_data.token + + EIP197_MAX_TOKENS - 13); + + token[12].opcode = EIP197_TOKEN_OPCODE_INSERT; + token[12].packet_length = digestsize; + token[12].stat = EIP197_TOKEN_STAT_LAST_HASH | + EIP197_TOKEN_STAT_LAST_PACKET; + token[12].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT | + EIP197_TOKEN_INS_INSERT_HASH_DIGEST; + } else { + cryptlen -= digestsize; + + /* align end of instruction sequence to end of token */ + token = (struct safexcel_token *)(cdesc->control_data.token + + EIP197_MAX_TOKENS - 14); + + token[12].opcode = EIP197_TOKEN_OPCODE_RETRIEVE; + token[12].packet_length = digestsize; + token[12].stat = EIP197_TOKEN_STAT_LAST_HASH | + EIP197_TOKEN_STAT_LAST_PACKET; + token[12].instructions = EIP197_TOKEN_INS_INSERT_HASH_DIGEST; + + token[13].opcode = EIP197_TOKEN_OPCODE_VERIFY; + token[13].packet_length = digestsize | + EIP197_TOKEN_HASH_RESULT_VERIFY; + token[13].stat = EIP197_TOKEN_STAT_LAST_HASH | + EIP197_TOKEN_STAT_LAST_PACKET; + token[13].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT; } - token = (struct safexcel_token *)(cdesc->control_data.token + offset); + token[6].opcode = EIP197_TOKEN_OPCODE_DIRECTION; + token[6].packet_length = assoclen; + + if (likely(cryptlen)) { + token[6].instructions = EIP197_TOKEN_INS_TYPE_HASH; + + token[10].opcode = EIP197_TOKEN_OPCODE_DIRECTION; + token[10].packet_length = cryptlen; + token[10].stat = EIP197_TOKEN_STAT_LAST_HASH; + token[10].instructions = EIP197_TOKEN_INS_LAST | + EIP197_TOKEN_INS_TYPE_CRYPTO | + EIP197_TOKEN_INS_TYPE_HASH | + EIP197_TOKEN_INS_TYPE_OUTPUT; + } else if (ctx->xcm != EIP197_XCM_MODE_CCM) { + token[6].stat = EIP197_TOKEN_STAT_LAST_HASH; + token[6].instructions = EIP197_TOKEN_INS_LAST | + EIP197_TOKEN_INS_TYPE_HASH; + } - if (direction == SAFEXCEL_DECRYPT) - cryptlen -= digestsize; + if (!ctx->xcm) + return; - token[0].opcode = EIP197_TOKEN_OPCODE_DIRECTION; - token[0].packet_length = assoclen; - token[0].instructions = EIP197_TOKEN_INS_TYPE_HASH | - EIP197_TOKEN_INS_TYPE_OUTPUT; + token[8].opcode = EIP197_TOKEN_OPCODE_INSERT_REMRES; + token[8].packet_length = 0; + token[8].instructions = AES_BLOCK_SIZE; - token[1].opcode = EIP197_TOKEN_OPCODE_DIRECTION; - token[1].packet_length = cryptlen; - token[1].stat = EIP197_TOKEN_STAT_LAST_HASH; - token[1].instructions = EIP197_TOKEN_INS_LAST | - EIP197_TOKEN_INS_TYPE_CRYTO | - EIP197_TOKEN_INS_TYPE_HASH | - EIP197_TOKEN_INS_TYPE_OUTPUT; + token[9].opcode = EIP197_TOKEN_OPCODE_INSERT; + token[9].packet_length = AES_BLOCK_SIZE; + token[9].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT | + EIP197_TOKEN_INS_TYPE_CRYPTO; - if (direction == SAFEXCEL_ENCRYPT) { - token[2].opcode = EIP197_TOKEN_OPCODE_INSERT; - token[2].packet_length = digestsize; - token[2].stat = EIP197_TOKEN_STAT_LAST_HASH | - EIP197_TOKEN_STAT_LAST_PACKET; - token[2].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT | - EIP197_TOKEN_INS_INSERT_HASH_DIGEST; + if (ctx->xcm == EIP197_XCM_MODE_GCM) { + token[6].instructions = EIP197_TOKEN_INS_LAST | + EIP197_TOKEN_INS_TYPE_HASH; } else { - token[2].opcode = EIP197_TOKEN_OPCODE_RETRIEVE; - token[2].packet_length = digestsize; - token[2].stat = EIP197_TOKEN_STAT_LAST_HASH | - EIP197_TOKEN_STAT_LAST_PACKET; - token[2].instructions = EIP197_TOKEN_INS_INSERT_HASH_DIGEST; - - token[3].opcode = EIP197_TOKEN_OPCODE_VERIFY; - token[3].packet_length = digestsize | - EIP197_TOKEN_HASH_RESULT_VERIFY; - token[3].stat = EIP197_TOKEN_STAT_LAST_HASH | - EIP197_TOKEN_STAT_LAST_PACKET; - token[3].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT; + u8 *cbcmaciv = (u8 *)&token[1]; + u32 *aadlen = (u32 *)&token[5]; + + /* Construct IV block B0 for the CBC-MAC */ + token[0].opcode = EIP197_TOKEN_OPCODE_INSERT; + token[0].packet_length = AES_BLOCK_SIZE + + ((assoclen > 0) << 1); + token[0].instructions = EIP197_TOKEN_INS_ORIGIN_TOKEN | + EIP197_TOKEN_INS_TYPE_HASH; + /* Variable length IV part */ + memcpy(cbcmaciv, iv, 15 - iv[0]); + /* fixup flags byte */ + cbcmaciv[0] |= ((assoclen > 0) << 6) | ((digestsize - 2) << 2); + /* Clear upper bytes of variable message length to 0 */ + memset(cbcmaciv + 15 - iv[0], 0, iv[0] - 1); + /* insert lower 2 bytes of message length */ + cbcmaciv[14] = cryptlen >> 8; + cbcmaciv[15] = cryptlen & 255; + + if (assoclen) { + *aadlen = cpu_to_le32(cpu_to_be16(assoclen)); + assoclen += 2; + } + + token[6].instructions = EIP197_TOKEN_INS_TYPE_HASH; + + /* Align AAD data towards hash engine */ + token[7].opcode = EIP197_TOKEN_OPCODE_INSERT; + assoclen &= 15; + token[7].packet_length = assoclen ? 16 - assoclen : 0; + + if (likely(cryptlen)) { + token[7].instructions = EIP197_TOKEN_INS_TYPE_HASH; + + /* Align crypto data towards hash engine */ + token[10].stat = 0; + + token[11].opcode = EIP197_TOKEN_OPCODE_INSERT; + cryptlen &= 15; + token[11].packet_length = cryptlen ? 16 - cryptlen : 0; + token[11].stat = EIP197_TOKEN_STAT_LAST_HASH; + token[11].instructions = EIP197_TOKEN_INS_TYPE_HASH; + } else { + token[7].stat = EIP197_TOKEN_STAT_LAST_HASH; + token[7].instructions = EIP197_TOKEN_INS_LAST | + EIP197_TOKEN_INS_TYPE_HASH; + } } } @@ -178,7 +276,7 @@ static int safexcel_skcipher_aes_setkey(struct crypto_skcipher *ctfm, struct crypto_aes_ctx aes; int ret, i; - ret = crypto_aes_expand_key(&aes, key, len); + ret = aes_expandkey(&aes, key, len); if (ret) { crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN); return ret; @@ -202,22 +300,49 @@ static int safexcel_skcipher_aes_setkey(struct crypto_skcipher *ctfm, return 0; } -static int safexcel_aead_aes_setkey(struct crypto_aead *ctfm, const u8 *key, - unsigned int len) +static int safexcel_aead_setkey(struct crypto_aead *ctfm, const u8 *key, + unsigned int len) { struct crypto_tfm *tfm = crypto_aead_tfm(ctfm); struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); struct safexcel_ahash_export_state istate, ostate; struct safexcel_crypto_priv *priv = ctx->priv; struct crypto_authenc_keys keys; + struct crypto_aes_ctx aes; + int err = -EINVAL; if (crypto_authenc_extractkeys(&keys, key, len) != 0) goto badkey; - if (keys.enckeylen > sizeof(ctx->key)) - goto badkey; + if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD) { + /* Minimum keysize is minimum AES key size + nonce size */ + if (keys.enckeylen < (AES_MIN_KEY_SIZE + + CTR_RFC3686_NONCE_SIZE)) + goto badkey; + /* last 4 bytes of key are the nonce! */ + ctx->nonce = *(u32 *)(keys.enckey + keys.enckeylen - + CTR_RFC3686_NONCE_SIZE); + /* exclude the nonce here */ + keys.enckeylen -= CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD; + } /* Encryption key */ + switch (ctx->alg) { + case SAFEXCEL_3DES: + err = verify_aead_des3_key(ctfm, keys.enckey, keys.enckeylen); + if (unlikely(err)) + goto badkey_expflags; + break; + case SAFEXCEL_AES: + err = aes_expandkey(&aes, keys.enckey, keys.enckeylen); + if (unlikely(err)) + goto badkey; + break; + default: + dev_err(priv->dev, "aead: unsupported cipher algorithm\n"); + goto badkey; + } + if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma && memcmp(ctx->key, keys.enckey, keys.enckeylen)) ctx->base.needs_inv = true; @@ -274,8 +399,9 @@ static int safexcel_aead_aes_setkey(struct crypto_aead *ctfm, const u8 *key, badkey: crypto_aead_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN); +badkey_expflags: memzero_explicit(&keys, sizeof(keys)); - return -EINVAL; + return err; } static int safexcel_context_control(struct safexcel_cipher_ctx *ctx, @@ -284,59 +410,78 @@ static int safexcel_context_control(struct safexcel_cipher_ctx *ctx, struct safexcel_command_desc *cdesc) { struct safexcel_crypto_priv *priv = ctx->priv; - int ctrl_size; + int ctrl_size = ctx->key_len / sizeof(u32); + + cdesc->control_data.control1 = ctx->mode; if (ctx->aead) { + /* Take in account the ipad+opad digests */ + if (ctx->xcm) { + ctrl_size += ctx->state_sz / sizeof(u32); + cdesc->control_data.control0 = + CONTEXT_CONTROL_KEY_EN | + CONTEXT_CONTROL_DIGEST_XCM | + ctx->hash_alg | + CONTEXT_CONTROL_SIZE(ctrl_size); + } else { + ctrl_size += ctx->state_sz / sizeof(u32) * 2; + cdesc->control_data.control0 = + CONTEXT_CONTROL_KEY_EN | + CONTEXT_CONTROL_DIGEST_HMAC | + ctx->hash_alg | + CONTEXT_CONTROL_SIZE(ctrl_size); + } if (sreq->direction == SAFEXCEL_ENCRYPT) - cdesc->control_data.control0 |= CONTEXT_CONTROL_TYPE_ENCRYPT_HASH_OUT; + cdesc->control_data.control0 |= + (ctx->xcm == EIP197_XCM_MODE_CCM) ? + CONTEXT_CONTROL_TYPE_HASH_ENCRYPT_OUT : + CONTEXT_CONTROL_TYPE_ENCRYPT_HASH_OUT; + else - cdesc->control_data.control0 |= CONTEXT_CONTROL_TYPE_HASH_DECRYPT_IN; + cdesc->control_data.control0 |= + (ctx->xcm == EIP197_XCM_MODE_CCM) ? + CONTEXT_CONTROL_TYPE_DECRYPT_HASH_IN : + CONTEXT_CONTROL_TYPE_HASH_DECRYPT_IN; } else { - cdesc->control_data.control0 |= CONTEXT_CONTROL_TYPE_CRYPTO_OUT; - - /* The decryption control type is a combination of the - * encryption type and CONTEXT_CONTROL_TYPE_NULL_IN, for all - * types. - */ - if (sreq->direction == SAFEXCEL_DECRYPT) - cdesc->control_data.control0 |= CONTEXT_CONTROL_TYPE_NULL_IN; + if (sreq->direction == SAFEXCEL_ENCRYPT) + cdesc->control_data.control0 = + CONTEXT_CONTROL_TYPE_CRYPTO_OUT | + CONTEXT_CONTROL_KEY_EN | + CONTEXT_CONTROL_SIZE(ctrl_size); + else + cdesc->control_data.control0 = + CONTEXT_CONTROL_TYPE_CRYPTO_IN | + CONTEXT_CONTROL_KEY_EN | + CONTEXT_CONTROL_SIZE(ctrl_size); } - cdesc->control_data.control0 |= CONTEXT_CONTROL_KEY_EN; - cdesc->control_data.control1 |= ctx->mode; - - if (ctx->aead) - cdesc->control_data.control0 |= CONTEXT_CONTROL_DIGEST_HMAC | - ctx->hash_alg; - if (ctx->alg == SAFEXCEL_DES) { - cdesc->control_data.control0 |= CONTEXT_CONTROL_CRYPTO_ALG_DES; + cdesc->control_data.control0 |= + CONTEXT_CONTROL_CRYPTO_ALG_DES; } else if (ctx->alg == SAFEXCEL_3DES) { - cdesc->control_data.control0 |= CONTEXT_CONTROL_CRYPTO_ALG_3DES; + cdesc->control_data.control0 |= + CONTEXT_CONTROL_CRYPTO_ALG_3DES; } else if (ctx->alg == SAFEXCEL_AES) { - switch (ctx->key_len) { + switch (ctx->key_len >> ctx->xts) { case AES_KEYSIZE_128: - cdesc->control_data.control0 |= CONTEXT_CONTROL_CRYPTO_ALG_AES128; + cdesc->control_data.control0 |= + CONTEXT_CONTROL_CRYPTO_ALG_AES128; break; case AES_KEYSIZE_192: - cdesc->control_data.control0 |= CONTEXT_CONTROL_CRYPTO_ALG_AES192; + cdesc->control_data.control0 |= + CONTEXT_CONTROL_CRYPTO_ALG_AES192; break; case AES_KEYSIZE_256: - cdesc->control_data.control0 |= CONTEXT_CONTROL_CRYPTO_ALG_AES256; + cdesc->control_data.control0 |= + CONTEXT_CONTROL_CRYPTO_ALG_AES256; break; default: dev_err(priv->dev, "aes keysize not supported: %u\n", - ctx->key_len); + ctx->key_len >> ctx->xts); return -EINVAL; } } - ctrl_size = ctx->key_len / sizeof(u32); - if (ctx->aead) - /* Take in account the ipad+opad digests */ - ctrl_size += ctx->state_sz / sizeof(u32) * 2; - cdesc->control_data.control0 |= CONTEXT_CONTROL_SIZE(ctrl_size); - return 0; } @@ -348,6 +493,9 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin struct safexcel_cipher_req *sreq, bool *should_complete, int *ret) { + struct skcipher_request *areq = skcipher_request_cast(async); + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(areq); + struct safexcel_cipher_ctx *ctx = crypto_skcipher_ctx(skcipher); struct safexcel_result_desc *rdesc; int ndesc = 0; @@ -374,10 +522,22 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin safexcel_complete(priv, ring); if (src == dst) { - dma_unmap_sg(priv->dev, src, sg_nents(src), DMA_BIDIRECTIONAL); + dma_unmap_sg(priv->dev, src, sreq->nr_src, DMA_BIDIRECTIONAL); } else { - dma_unmap_sg(priv->dev, src, sg_nents(src), DMA_TO_DEVICE); - dma_unmap_sg(priv->dev, dst, sg_nents(dst), DMA_FROM_DEVICE); + dma_unmap_sg(priv->dev, src, sreq->nr_src, DMA_TO_DEVICE); + dma_unmap_sg(priv->dev, dst, sreq->nr_dst, DMA_FROM_DEVICE); + } + + /* + * Update IV in req from last crypto output word for CBC modes + */ + if ((!ctx->aead) && (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) && + (sreq->direction == SAFEXCEL_ENCRYPT)) { + /* For encrypt take the last output word */ + sg_pcopy_to_buffer(dst, sreq->nr_dst, areq->iv, + crypto_skcipher_ivsize(skcipher), + (cryptlen - + crypto_skcipher_ivsize(skcipher))); } *should_complete = true; @@ -392,53 +552,105 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring, unsigned int digestsize, u8 *iv, int *commands, int *results) { + struct skcipher_request *areq = skcipher_request_cast(base); + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(areq); struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(base->tfm); struct safexcel_crypto_priv *priv = ctx->priv; struct safexcel_command_desc *cdesc; + struct safexcel_command_desc *first_cdesc = NULL; struct safexcel_result_desc *rdesc, *first_rdesc = NULL; struct scatterlist *sg; - unsigned int totlen = cryptlen + assoclen; - int nr_src, nr_dst, n_cdesc = 0, n_rdesc = 0, queued = totlen; - int i, ret = 0; + unsigned int totlen; + unsigned int totlen_src = cryptlen + assoclen; + unsigned int totlen_dst = totlen_src; + int n_cdesc = 0, n_rdesc = 0; + int queued, i, ret = 0; + bool first = true; + + sreq->nr_src = sg_nents_for_len(src, totlen_src); + + if (ctx->aead) { + /* + * AEAD has auth tag appended to output for encrypt and + * removed from the output for decrypt! + */ + if (sreq->direction == SAFEXCEL_DECRYPT) + totlen_dst -= digestsize; + else + totlen_dst += digestsize; + + memcpy(ctx->base.ctxr->data + ctx->key_len / sizeof(u32), + ctx->ipad, ctx->state_sz); + if (!ctx->xcm) + memcpy(ctx->base.ctxr->data + (ctx->key_len + + ctx->state_sz) / sizeof(u32), ctx->opad, + ctx->state_sz); + } else if ((ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) && + (sreq->direction == SAFEXCEL_DECRYPT)) { + /* + * Save IV from last crypto input word for CBC modes in decrypt + * direction. Need to do this first in case of inplace operation + * as it will be overwritten. + */ + sg_pcopy_to_buffer(src, sreq->nr_src, areq->iv, + crypto_skcipher_ivsize(skcipher), + (totlen_src - + crypto_skcipher_ivsize(skcipher))); + } + + sreq->nr_dst = sg_nents_for_len(dst, totlen_dst); + + /* + * Remember actual input length, source buffer length may be + * updated in case of inline operation below. + */ + totlen = totlen_src; + queued = totlen_src; if (src == dst) { - nr_src = dma_map_sg(priv->dev, src, sg_nents(src), - DMA_BIDIRECTIONAL); - nr_dst = nr_src; - if (!nr_src) + sreq->nr_src = max(sreq->nr_src, sreq->nr_dst); + sreq->nr_dst = sreq->nr_src; + if (unlikely((totlen_src || totlen_dst) && + (sreq->nr_src <= 0))) { + dev_err(priv->dev, "In-place buffer not large enough (need %d bytes)!", + max(totlen_src, totlen_dst)); return -EINVAL; + } + dma_map_sg(priv->dev, src, sreq->nr_src, DMA_BIDIRECTIONAL); } else { - nr_src = dma_map_sg(priv->dev, src, sg_nents(src), - DMA_TO_DEVICE); - if (!nr_src) + if (unlikely(totlen_src && (sreq->nr_src <= 0))) { + dev_err(priv->dev, "Source buffer not large enough (need %d bytes)!", + totlen_src); return -EINVAL; + } + dma_map_sg(priv->dev, src, sreq->nr_src, DMA_TO_DEVICE); - nr_dst = dma_map_sg(priv->dev, dst, sg_nents(dst), - DMA_FROM_DEVICE); - if (!nr_dst) { - dma_unmap_sg(priv->dev, src, nr_src, DMA_TO_DEVICE); + if (unlikely(totlen_dst && (sreq->nr_dst <= 0))) { + dev_err(priv->dev, "Dest buffer not large enough (need %d bytes)!", + totlen_dst); + dma_unmap_sg(priv->dev, src, sreq->nr_src, + DMA_TO_DEVICE); return -EINVAL; } + dma_map_sg(priv->dev, dst, sreq->nr_dst, DMA_FROM_DEVICE); } memcpy(ctx->base.ctxr->data, ctx->key, ctx->key_len); - if (ctx->aead) { - memcpy(ctx->base.ctxr->data + ctx->key_len / sizeof(u32), - ctx->ipad, ctx->state_sz); - memcpy(ctx->base.ctxr->data + (ctx->key_len + ctx->state_sz) / sizeof(u32), - ctx->opad, ctx->state_sz); - } + /* The EIP cannot deal with zero length input packets! */ + if (totlen == 0) + totlen = 1; /* command descriptors */ - for_each_sg(src, sg, nr_src, i) { + for_each_sg(src, sg, sreq->nr_src, i) { int len = sg_dma_len(sg); /* Do not overflow the request */ if (queued - len < 0) len = queued; - cdesc = safexcel_add_cdesc(priv, ring, !n_cdesc, !(queued - len), + cdesc = safexcel_add_cdesc(priv, ring, !n_cdesc, + !(queued - len), sg_dma_address(sg), len, totlen, ctx->base.ctxr_dma); if (IS_ERR(cdesc)) { @@ -449,14 +661,7 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring, n_cdesc++; if (n_cdesc == 1) { - safexcel_context_control(ctx, base, sreq, cdesc); - if (ctx->aead) - safexcel_aead_token(ctx, iv, cdesc, - sreq->direction, cryptlen, - assoclen, digestsize); - else - safexcel_skcipher_token(ctx, iv, cdesc, - cryptlen); + first_cdesc = cdesc; } queued -= len; @@ -464,23 +669,83 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring, break; } + if (unlikely(!n_cdesc)) { + /* + * Special case: zero length input buffer. + * The engine always needs the 1st command descriptor, however! + */ + first_cdesc = safexcel_add_cdesc(priv, ring, 1, 1, 0, 0, totlen, + ctx->base.ctxr_dma); + n_cdesc = 1; + } + + /* Add context control words and token to first command descriptor */ + safexcel_context_control(ctx, base, sreq, first_cdesc); + if (ctx->aead) + safexcel_aead_token(ctx, iv, first_cdesc, + sreq->direction, cryptlen, + assoclen, digestsize); + else + safexcel_skcipher_token(ctx, iv, first_cdesc, + cryptlen); + /* result descriptors */ - for_each_sg(dst, sg, nr_dst, i) { - bool first = !i, last = sg_is_last(sg); + for_each_sg(dst, sg, sreq->nr_dst, i) { + bool last = (i == sreq->nr_dst - 1); u32 len = sg_dma_len(sg); - rdesc = safexcel_add_rdesc(priv, ring, first, last, - sg_dma_address(sg), len); + /* only allow the part of the buffer we know we need */ + if (len > totlen_dst) + len = totlen_dst; + if (unlikely(!len)) + break; + totlen_dst -= len; + + /* skip over AAD space in buffer - not written */ + if (assoclen) { + if (assoclen >= len) { + assoclen -= len; + continue; + } + rdesc = safexcel_add_rdesc(priv, ring, first, last, + sg_dma_address(sg) + + assoclen, + len - assoclen); + assoclen = 0; + } else { + rdesc = safexcel_add_rdesc(priv, ring, first, last, + sg_dma_address(sg), + len); + } if (IS_ERR(rdesc)) { /* No space left in the result descriptor ring */ ret = PTR_ERR(rdesc); goto rdesc_rollback; } - if (first) + if (first) { first_rdesc = rdesc; + first = false; + } n_rdesc++; } + if (unlikely(first)) { + /* + * Special case: AEAD decrypt with only AAD data. + * In this case there is NO output data from the engine, + * but the engine still needs a result descriptor! + * Create a dummy one just for catching the result token. + */ + rdesc = safexcel_add_rdesc(priv, ring, true, true, 0, 0); + if (IS_ERR(rdesc)) { + /* No space left in the result descriptor ring */ + ret = PTR_ERR(rdesc); + goto rdesc_rollback; + } + first_rdesc = rdesc; + n_rdesc = 1; + } + safexcel_rdr_req_set(priv, ring, first_rdesc, base); *commands = n_cdesc; @@ -495,10 +760,10 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring, safexcel_ring_rollback_wptr(priv, &priv->ring[ring].cdr); if (src == dst) { - dma_unmap_sg(priv->dev, src, nr_src, DMA_BIDIRECTIONAL); + dma_unmap_sg(priv->dev, src, sreq->nr_src, DMA_BIDIRECTIONAL); } else { - dma_unmap_sg(priv->dev, src, nr_src, DMA_TO_DEVICE); - dma_unmap_sg(priv->dev, dst, nr_dst, DMA_FROM_DEVICE); + dma_unmap_sg(priv->dev, src, sreq->nr_src, DMA_TO_DEVICE); + dma_unmap_sg(priv->dev, dst, sreq->nr_dst, DMA_FROM_DEVICE); } return ret; @@ -570,7 +835,6 @@ static int safexcel_skcipher_handle_result(struct safexcel_crypto_priv *priv, { struct skcipher_request *req = skcipher_request_cast(async); struct safexcel_cipher_req *sreq = skcipher_request_ctx(req); - struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(async->tfm); int err; if (sreq->needs_inv) { @@ -581,24 +845,6 @@ static int safexcel_skcipher_handle_result(struct safexcel_crypto_priv *priv, err = safexcel_handle_req_result(priv, ring, async, req->src, req->dst, req->cryptlen, sreq, should_complete, ret); - - if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) { - u32 block_sz = 0; - - switch (ctx->alg) { - case SAFEXCEL_DES: - block_sz = DES_BLOCK_SIZE; - break; - case SAFEXCEL_3DES: - block_sz = DES3_EDE_BLOCK_SIZE; - break; - case SAFEXCEL_AES: - block_sz = AES_BLOCK_SIZE; - break; - } - - memcpy(req->iv, ctx->base.ctxr->data, block_sz); - } } return err; @@ -656,12 +902,22 @@ static int safexcel_skcipher_send(struct crypto_async_request *async, int ring, BUG_ON(!(priv->flags & EIP197_TRC_CACHE) && sreq->needs_inv); - if (sreq->needs_inv) + if (sreq->needs_inv) { ret = safexcel_cipher_send_inv(async, ring, commands, results); - else + } else { + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + u8 input_iv[AES_BLOCK_SIZE]; + + /* + * Save input IV in case of CBC decrypt mode + * Will be overwritten with output IV prior to use! + */ + memcpy(input_iv, req->iv, crypto_skcipher_ivsize(skcipher)); + ret = safexcel_send_req(async, ring, sreq, req->src, - req->dst, req->cryptlen, 0, 0, req->iv, + req->dst, req->cryptlen, 0, 0, input_iv, commands, results); + } sreq->rdescs = *results; return ret; @@ -756,8 +1012,7 @@ static int safexcel_aead_exit_inv(struct crypto_tfm *tfm) static int safexcel_queue_req(struct crypto_async_request *base, struct safexcel_cipher_req *sreq, - enum safexcel_cipher_direction dir, u32 mode, - enum safexcel_cipher_alg alg) + enum safexcel_cipher_direction dir) { struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(base->tfm); struct safexcel_crypto_priv *priv = ctx->priv; @@ -765,8 +1020,6 @@ static int safexcel_queue_req(struct crypto_async_request *base, sreq->needs_inv = false; sreq->direction = dir; - ctx->alg = alg; - ctx->mode = mode; if (ctx->base.ctxr) { if (priv->flags & EIP197_TRC_CACHE && ctx->base.needs_inv) { @@ -794,18 +1047,16 @@ static int safexcel_queue_req(struct crypto_async_request *base, return ret; } -static int safexcel_ecb_aes_encrypt(struct skcipher_request *req) +static int safexcel_encrypt(struct skcipher_request *req) { return safexcel_queue_req(&req->base, skcipher_request_ctx(req), - SAFEXCEL_ENCRYPT, CONTEXT_CONTROL_CRYPTO_MODE_ECB, - SAFEXCEL_AES); + SAFEXCEL_ENCRYPT); } -static int safexcel_ecb_aes_decrypt(struct skcipher_request *req) +static int safexcel_decrypt(struct skcipher_request *req) { return safexcel_queue_req(&req->base, skcipher_request_ctx(req), - SAFEXCEL_DECRYPT, CONTEXT_CONTROL_CRYPTO_MODE_ECB, - SAFEXCEL_AES); + SAFEXCEL_DECRYPT); } static int safexcel_skcipher_cra_init(struct crypto_tfm *tfm) @@ -879,104 +1130,234 @@ static void safexcel_aead_cra_exit(struct crypto_tfm *tfm) } } +static int safexcel_skcipher_aes_ecb_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_skcipher_cra_init(tfm); + ctx->alg = SAFEXCEL_AES; + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_ECB; + return 0; +} + struct safexcel_alg_template safexcel_alg_ecb_aes = { .type = SAFEXCEL_ALG_TYPE_SKCIPHER, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_AES, .alg.skcipher = { .setkey = safexcel_skcipher_aes_setkey, - .encrypt = safexcel_ecb_aes_encrypt, - .decrypt = safexcel_ecb_aes_decrypt, + .encrypt = safexcel_encrypt, + .decrypt = safexcel_decrypt, .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .base = { .cra_name = "ecb(aes)", .cra_driver_name = "safexcel-ecb-aes", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), .cra_alignmask = 0, - .cra_init = safexcel_skcipher_cra_init, + .cra_init = safexcel_skcipher_aes_ecb_cra_init, .cra_exit = safexcel_skcipher_cra_exit, .cra_module = THIS_MODULE, }, }, }; -static int safexcel_cbc_aes_encrypt(struct skcipher_request *req) +static int safexcel_skcipher_aes_cbc_cra_init(struct crypto_tfm *tfm) { - return safexcel_queue_req(&req->base, skcipher_request_ctx(req), - SAFEXCEL_ENCRYPT, CONTEXT_CONTROL_CRYPTO_MODE_CBC, - SAFEXCEL_AES); -} + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); -static int safexcel_cbc_aes_decrypt(struct skcipher_request *req) -{ - return safexcel_queue_req(&req->base, skcipher_request_ctx(req), - SAFEXCEL_DECRYPT, CONTEXT_CONTROL_CRYPTO_MODE_CBC, - SAFEXCEL_AES); + safexcel_skcipher_cra_init(tfm); + ctx->alg = SAFEXCEL_AES; + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CBC; + return 0; } struct safexcel_alg_template safexcel_alg_cbc_aes = { .type = SAFEXCEL_ALG_TYPE_SKCIPHER, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_AES, .alg.skcipher = { .setkey = safexcel_skcipher_aes_setkey, - .encrypt = safexcel_cbc_aes_encrypt, - .decrypt = safexcel_cbc_aes_decrypt, + .encrypt = safexcel_encrypt, + .decrypt = safexcel_decrypt, .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, .base = { .cra_name = "cbc(aes)", .cra_driver_name = "safexcel-cbc-aes", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), .cra_alignmask = 0, - .cra_init = safexcel_skcipher_cra_init, + .cra_init = safexcel_skcipher_aes_cbc_cra_init, .cra_exit = safexcel_skcipher_cra_exit, .cra_module = THIS_MODULE, }, }, }; -static int safexcel_cbc_des_encrypt(struct skcipher_request *req) +static int safexcel_skcipher_aes_cfb_cra_init(struct crypto_tfm *tfm) { - return safexcel_queue_req(&req->base, skcipher_request_ctx(req), - SAFEXCEL_ENCRYPT, CONTEXT_CONTROL_CRYPTO_MODE_CBC, - SAFEXCEL_DES); + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_skcipher_cra_init(tfm); + ctx->alg = SAFEXCEL_AES; + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CFB; + return 0; } -static int safexcel_cbc_des_decrypt(struct skcipher_request *req) +struct safexcel_alg_template safexcel_alg_cfb_aes = { + .type = SAFEXCEL_ALG_TYPE_SKCIPHER, + .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_AES_XFB, + .alg.skcipher = { + .setkey = safexcel_skcipher_aes_setkey, + .encrypt = safexcel_encrypt, + .decrypt = safexcel_decrypt, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .base = { + .cra_name = "cfb(aes)", + .cra_driver_name = "safexcel-cfb-aes", + .cra_priority = SAFEXCEL_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), + .cra_alignmask = 0, + .cra_init = safexcel_skcipher_aes_cfb_cra_init, + .cra_exit = safexcel_skcipher_cra_exit, + .cra_module = THIS_MODULE, + }, + }, +}; + +static int safexcel_skcipher_aes_ofb_cra_init(struct crypto_tfm *tfm) { - return safexcel_queue_req(&req->base, skcipher_request_ctx(req), - SAFEXCEL_DECRYPT, CONTEXT_CONTROL_CRYPTO_MODE_CBC, - SAFEXCEL_DES); + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_skcipher_cra_init(tfm); + ctx->alg = SAFEXCEL_AES; + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_OFB; + return 0; } -static int safexcel_des_setkey(struct crypto_skcipher *ctfm, const u8 *key, - unsigned int len) +struct safexcel_alg_template safexcel_alg_ofb_aes = { + .type = SAFEXCEL_ALG_TYPE_SKCIPHER, + .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_AES_XFB, + .alg.skcipher = { + .setkey = safexcel_skcipher_aes_setkey, + .encrypt = safexcel_encrypt, + .decrypt = safexcel_decrypt, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .base = { + .cra_name = "ofb(aes)", + .cra_driver_name = "safexcel-ofb-aes", + .cra_priority = SAFEXCEL_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), + .cra_alignmask = 0, + .cra_init = safexcel_skcipher_aes_ofb_cra_init, + .cra_exit = safexcel_skcipher_cra_exit, + .cra_module = THIS_MODULE, + }, + }, +}; + +static int safexcel_skcipher_aesctr_setkey(struct crypto_skcipher *ctfm, + const u8 *key, unsigned int len) { struct crypto_tfm *tfm = crypto_skcipher_tfm(ctfm); struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); - u32 tmp[DES_EXPKEY_WORDS]; - int ret; + struct safexcel_crypto_priv *priv = ctx->priv; + struct crypto_aes_ctx aes; + int ret, i; + unsigned int keylen; - if (len != DES_KEY_SIZE) { + /* last 4 bytes of key are the nonce! */ + ctx->nonce = *(u32 *)(key + len - CTR_RFC3686_NONCE_SIZE); + /* exclude the nonce here */ + keylen = len - CTR_RFC3686_NONCE_SIZE; + ret = aes_expandkey(&aes, key, keylen); + if (ret) { crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; + return ret; } - ret = des_ekey(tmp, key); - if (!ret && (tfm->crt_flags & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) { - tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; - return -EINVAL; + if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) { + for (i = 0; i < keylen / sizeof(u32); i++) { + if (ctx->key[i] != cpu_to_le32(aes.key_enc[i])) { + ctx->base.needs_inv = true; + break; + } + } } + for (i = 0; i < keylen / sizeof(u32); i++) + ctx->key[i] = cpu_to_le32(aes.key_enc[i]); + + ctx->key_len = keylen; + + memzero_explicit(&aes, sizeof(aes)); + return 0; +} + +static int safexcel_skcipher_aes_ctr_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_skcipher_cra_init(tfm); + ctx->alg = SAFEXCEL_AES; + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD; + return 0; +} + +struct safexcel_alg_template safexcel_alg_ctr_aes = { + .type = SAFEXCEL_ALG_TYPE_SKCIPHER, + .algo_mask = SAFEXCEL_ALG_AES, + .alg.skcipher = { + .setkey = safexcel_skcipher_aesctr_setkey, + .encrypt = safexcel_encrypt, + .decrypt = safexcel_decrypt, + /* Add nonce size */ + .min_keysize = AES_MIN_KEY_SIZE + CTR_RFC3686_NONCE_SIZE, + .max_keysize = AES_MAX_KEY_SIZE + CTR_RFC3686_NONCE_SIZE, + .ivsize = CTR_RFC3686_IV_SIZE, + .base = { + .cra_name = "rfc3686(ctr(aes))", + .cra_driver_name = "safexcel-ctr-aes", + .cra_priority = SAFEXCEL_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), + .cra_alignmask = 0, + .cra_init = safexcel_skcipher_aes_ctr_cra_init, + .cra_exit = safexcel_skcipher_cra_exit, + .cra_module = THIS_MODULE, + }, + }, +}; + +static int safexcel_des_setkey(struct crypto_skcipher *ctfm, const u8 *key, + unsigned int len) +{ + struct safexcel_cipher_ctx *ctx = crypto_skcipher_ctx(ctfm); + int ret; + + ret = verify_skcipher_des_key(ctfm, key); + if (ret) + return ret; + /* if context exits and key changed, need to invalidate it */ if (ctx->base.ctxr_dma) if (memcmp(ctx->key, key, len)) @@ -988,94 +1369,85 @@ static int safexcel_des_setkey(struct crypto_skcipher *ctfm, const u8 *key, return 0; } +static int safexcel_skcipher_des_cbc_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_skcipher_cra_init(tfm); + ctx->alg = SAFEXCEL_DES; + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CBC; + return 0; +} + struct safexcel_alg_template safexcel_alg_cbc_des = { .type = SAFEXCEL_ALG_TYPE_SKCIPHER, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_DES, .alg.skcipher = { .setkey = safexcel_des_setkey, - .encrypt = safexcel_cbc_des_encrypt, - .decrypt = safexcel_cbc_des_decrypt, + .encrypt = safexcel_encrypt, + .decrypt = safexcel_decrypt, .min_keysize = DES_KEY_SIZE, .max_keysize = DES_KEY_SIZE, .ivsize = DES_BLOCK_SIZE, .base = { .cra_name = "cbc(des)", .cra_driver_name = "safexcel-cbc-des", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), .cra_alignmask = 0, - .cra_init = safexcel_skcipher_cra_init, + .cra_init = safexcel_skcipher_des_cbc_cra_init, .cra_exit = safexcel_skcipher_cra_exit, .cra_module = THIS_MODULE, }, }, }; -static int safexcel_ecb_des_encrypt(struct skcipher_request *req) +static int safexcel_skcipher_des_ecb_cra_init(struct crypto_tfm *tfm) { - return safexcel_queue_req(&req->base, skcipher_request_ctx(req), - SAFEXCEL_ENCRYPT, CONTEXT_CONTROL_CRYPTO_MODE_ECB, - SAFEXCEL_DES); -} + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); -static int safexcel_ecb_des_decrypt(struct skcipher_request *req) -{ - return safexcel_queue_req(&req->base, skcipher_request_ctx(req), - SAFEXCEL_DECRYPT, CONTEXT_CONTROL_CRYPTO_MODE_ECB, - SAFEXCEL_DES); + safexcel_skcipher_cra_init(tfm); + ctx->alg = SAFEXCEL_DES; + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_ECB; + return 0; } struct safexcel_alg_template safexcel_alg_ecb_des = { .type = SAFEXCEL_ALG_TYPE_SKCIPHER, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_DES, .alg.skcipher = { .setkey = safexcel_des_setkey, - .encrypt = safexcel_ecb_des_encrypt, - .decrypt = safexcel_ecb_des_decrypt, + .encrypt = safexcel_encrypt, + .decrypt = safexcel_decrypt, .min_keysize = DES_KEY_SIZE, .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, .base = { .cra_name = "ecb(des)", .cra_driver_name = "safexcel-ecb-des", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), .cra_alignmask = 0, - .cra_init = safexcel_skcipher_cra_init, + .cra_init = safexcel_skcipher_des_ecb_cra_init, .cra_exit = safexcel_skcipher_cra_exit, .cra_module = THIS_MODULE, }, }, }; -static int safexcel_cbc_des3_ede_encrypt(struct skcipher_request *req) -{ - return safexcel_queue_req(&req->base, skcipher_request_ctx(req), - SAFEXCEL_ENCRYPT, CONTEXT_CONTROL_CRYPTO_MODE_CBC, - SAFEXCEL_3DES); -} - -static int safexcel_cbc_des3_ede_decrypt(struct skcipher_request *req) -{ - return safexcel_queue_req(&req->base, skcipher_request_ctx(req), - SAFEXCEL_DECRYPT, CONTEXT_CONTROL_CRYPTO_MODE_CBC, - SAFEXCEL_3DES); -} - -static int safexcel_des3_ede_setkey(struct crypto_skcipher *ctfm, - const u8 *key, unsigned int len) +static int safexcel_des3_ede_setkey(struct crypto_skcipher *ctfm, + const u8 *key, unsigned int len) { struct safexcel_cipher_ctx *ctx = crypto_skcipher_ctx(ctfm); int err; - err = des3_verify_key(ctfm, key); - if (unlikely(err)) + err = verify_skcipher_des3_key(ctfm, key); + if (err) return err; /* if context exits and key changed, need to invalidate it */ @@ -1091,66 +1463,71 @@ static int safexcel_des3_ede_setkey(struct crypto_skcipher *ctfm, return 0; } +static int safexcel_skcipher_des3_cbc_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_skcipher_cra_init(tfm); + ctx->alg = SAFEXCEL_3DES; + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CBC; + return 0; +} + struct safexcel_alg_template safexcel_alg_cbc_des3_ede = { .type = SAFEXCEL_ALG_TYPE_SKCIPHER, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_DES, .alg.skcipher = { .setkey = safexcel_des3_ede_setkey, - .encrypt = safexcel_cbc_des3_ede_encrypt, - .decrypt = safexcel_cbc_des3_ede_decrypt, + .encrypt = safexcel_encrypt, + .decrypt = safexcel_decrypt, .min_keysize = DES3_EDE_KEY_SIZE, .max_keysize = DES3_EDE_KEY_SIZE, .ivsize = DES3_EDE_BLOCK_SIZE, .base = { .cra_name = "cbc(des3_ede)", .cra_driver_name = "safexcel-cbc-des3_ede", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), .cra_alignmask = 0, - .cra_init = safexcel_skcipher_cra_init, + .cra_init = safexcel_skcipher_des3_cbc_cra_init, .cra_exit = safexcel_skcipher_cra_exit, .cra_module = THIS_MODULE, }, }, }; -static int safexcel_ecb_des3_ede_encrypt(struct skcipher_request *req) +static int safexcel_skcipher_des3_ecb_cra_init(struct crypto_tfm *tfm) { - return safexcel_queue_req(&req->base, skcipher_request_ctx(req), - SAFEXCEL_ENCRYPT, CONTEXT_CONTROL_CRYPTO_MODE_ECB, - SAFEXCEL_3DES); -} + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); -static int safexcel_ecb_des3_ede_decrypt(struct skcipher_request *req) -{ - return safexcel_queue_req(&req->base, skcipher_request_ctx(req), - SAFEXCEL_DECRYPT, CONTEXT_CONTROL_CRYPTO_MODE_ECB, - SAFEXCEL_3DES); + safexcel_skcipher_cra_init(tfm); + ctx->alg = SAFEXCEL_3DES; + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_ECB; + return 0; } struct safexcel_alg_template safexcel_alg_ecb_des3_ede = { .type = SAFEXCEL_ALG_TYPE_SKCIPHER, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_DES, .alg.skcipher = { .setkey = safexcel_des3_ede_setkey, - .encrypt = safexcel_ecb_des3_ede_encrypt, - .decrypt = safexcel_ecb_des3_ede_decrypt, + .encrypt = safexcel_encrypt, + .decrypt = safexcel_decrypt, .min_keysize = DES3_EDE_KEY_SIZE, .max_keysize = DES3_EDE_KEY_SIZE, - .ivsize = DES3_EDE_BLOCK_SIZE, .base = { .cra_name = "ecb(des3_ede)", .cra_driver_name = "safexcel-ecb-des3_ede", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), .cra_alignmask = 0, - .cra_init = safexcel_skcipher_cra_init, + .cra_init = safexcel_skcipher_des3_ecb_cra_init, .cra_exit = safexcel_skcipher_cra_exit, .cra_module = THIS_MODULE, }, @@ -1161,16 +1538,14 @@ static int safexcel_aead_encrypt(struct aead_request *req) { struct safexcel_cipher_req *creq = aead_request_ctx(req); - return safexcel_queue_req(&req->base, creq, SAFEXCEL_ENCRYPT, - CONTEXT_CONTROL_CRYPTO_MODE_CBC, SAFEXCEL_AES); + return safexcel_queue_req(&req->base, creq, SAFEXCEL_ENCRYPT); } static int safexcel_aead_decrypt(struct aead_request *req) { struct safexcel_cipher_req *creq = aead_request_ctx(req); - return safexcel_queue_req(&req->base, creq, SAFEXCEL_DECRYPT, - CONTEXT_CONTROL_CRYPTO_MODE_CBC, SAFEXCEL_AES); + return safexcel_queue_req(&req->base, creq, SAFEXCEL_DECRYPT); } static int safexcel_aead_cra_init(struct crypto_tfm *tfm) @@ -1185,6 +1560,8 @@ static int safexcel_aead_cra_init(struct crypto_tfm *tfm) ctx->priv = tmpl->priv; + ctx->alg = SAFEXCEL_AES; /* default */ + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CBC; /* default */ ctx->aead = true; ctx->base.send = safexcel_aead_send; ctx->base.handle_result = safexcel_aead_handle_result; @@ -1203,9 +1580,9 @@ static int safexcel_aead_sha1_cra_init(struct crypto_tfm *tfm) struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_cbc_aes = { .type = SAFEXCEL_ALG_TYPE_AEAD, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_SHA1, .alg.aead = { - .setkey = safexcel_aead_aes_setkey, + .setkey = safexcel_aead_setkey, .encrypt = safexcel_aead_encrypt, .decrypt = safexcel_aead_decrypt, .ivsize = AES_BLOCK_SIZE, @@ -1213,7 +1590,7 @@ struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_cbc_aes = { .base = { .cra_name = "authenc(hmac(sha1),cbc(aes))", .cra_driver_name = "safexcel-authenc-hmac-sha1-cbc-aes", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, @@ -1238,9 +1615,9 @@ static int safexcel_aead_sha256_cra_init(struct crypto_tfm *tfm) struct safexcel_alg_template safexcel_alg_authenc_hmac_sha256_cbc_aes = { .type = SAFEXCEL_ALG_TYPE_AEAD, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_SHA2_256, .alg.aead = { - .setkey = safexcel_aead_aes_setkey, + .setkey = safexcel_aead_setkey, .encrypt = safexcel_aead_encrypt, .decrypt = safexcel_aead_decrypt, .ivsize = AES_BLOCK_SIZE, @@ -1248,7 +1625,7 @@ struct safexcel_alg_template safexcel_alg_authenc_hmac_sha256_cbc_aes = { .base = { .cra_name = "authenc(hmac(sha256),cbc(aes))", .cra_driver_name = "safexcel-authenc-hmac-sha256-cbc-aes", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, @@ -1273,9 +1650,9 @@ static int safexcel_aead_sha224_cra_init(struct crypto_tfm *tfm) struct safexcel_alg_template safexcel_alg_authenc_hmac_sha224_cbc_aes = { .type = SAFEXCEL_ALG_TYPE_AEAD, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_SHA2_256, .alg.aead = { - .setkey = safexcel_aead_aes_setkey, + .setkey = safexcel_aead_setkey, .encrypt = safexcel_aead_encrypt, .decrypt = safexcel_aead_decrypt, .ivsize = AES_BLOCK_SIZE, @@ -1283,7 +1660,7 @@ struct safexcel_alg_template safexcel_alg_authenc_hmac_sha224_cbc_aes = { .base = { .cra_name = "authenc(hmac(sha224),cbc(aes))", .cra_driver_name = "safexcel-authenc-hmac-sha224-cbc-aes", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, @@ -1308,9 +1685,9 @@ static int safexcel_aead_sha512_cra_init(struct crypto_tfm *tfm) struct safexcel_alg_template safexcel_alg_authenc_hmac_sha512_cbc_aes = { .type = SAFEXCEL_ALG_TYPE_AEAD, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_SHA2_512, .alg.aead = { - .setkey = safexcel_aead_aes_setkey, + .setkey = safexcel_aead_setkey, .encrypt = safexcel_aead_encrypt, .decrypt = safexcel_aead_decrypt, .ivsize = AES_BLOCK_SIZE, @@ -1318,7 +1695,7 @@ struct safexcel_alg_template safexcel_alg_authenc_hmac_sha512_cbc_aes = { .base = { .cra_name = "authenc(hmac(sha512),cbc(aes))", .cra_driver_name = "safexcel-authenc-hmac-sha512-cbc-aes", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, @@ -1343,9 +1720,9 @@ static int safexcel_aead_sha384_cra_init(struct crypto_tfm *tfm) struct safexcel_alg_template safexcel_alg_authenc_hmac_sha384_cbc_aes = { .type = SAFEXCEL_ALG_TYPE_AEAD, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_SHA2_512, .alg.aead = { - .setkey = safexcel_aead_aes_setkey, + .setkey = safexcel_aead_setkey, .encrypt = safexcel_aead_encrypt, .decrypt = safexcel_aead_decrypt, .ivsize = AES_BLOCK_SIZE, @@ -1353,7 +1730,7 @@ struct safexcel_alg_template safexcel_alg_authenc_hmac_sha384_cbc_aes = { .base = { .cra_name = "authenc(hmac(sha384),cbc(aes))", .cra_driver_name = "safexcel-authenc-hmac-sha384-cbc-aes", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, @@ -1365,3 +1742,564 @@ struct safexcel_alg_template safexcel_alg_authenc_hmac_sha384_cbc_aes = { }, }, }; + +static int safexcel_aead_sha1_des3_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_aead_sha1_cra_init(tfm); + ctx->alg = SAFEXCEL_3DES; /* override default */ + return 0; +} + +struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_cbc_des3_ede = { + .type = SAFEXCEL_ALG_TYPE_AEAD, + .algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA1, + .alg.aead = { + .setkey = safexcel_aead_setkey, + .encrypt = safexcel_aead_encrypt, + .decrypt = safexcel_aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + .base = { + .cra_name = "authenc(hmac(sha1),cbc(des3_ede))", + .cra_driver_name = "safexcel-authenc-hmac-sha1-cbc-des3_ede", + .cra_priority = SAFEXCEL_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), + .cra_alignmask = 0, + .cra_init = safexcel_aead_sha1_des3_cra_init, + .cra_exit = safexcel_aead_cra_exit, + .cra_module = THIS_MODULE, + }, + }, +}; + +static int safexcel_aead_sha1_ctr_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_aead_sha1_cra_init(tfm); + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD; /* override default */ + return 0; +} + +struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_ctr_aes = { + .type = SAFEXCEL_ALG_TYPE_AEAD, + .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_SHA1, + .alg.aead = { + .setkey = safexcel_aead_setkey, + .encrypt = safexcel_aead_encrypt, + .decrypt = safexcel_aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + .base = { + .cra_name = "authenc(hmac(sha1),rfc3686(ctr(aes)))", + .cra_driver_name = "safexcel-authenc-hmac-sha1-ctr-aes", + .cra_priority = SAFEXCEL_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), + .cra_alignmask = 0, + .cra_init = safexcel_aead_sha1_ctr_cra_init, + .cra_exit = safexcel_aead_cra_exit, + .cra_module = THIS_MODULE, + }, + }, +}; + +static int safexcel_aead_sha256_ctr_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_aead_sha256_cra_init(tfm); + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD; /* override default */ + return 0; +} + +struct safexcel_alg_template safexcel_alg_authenc_hmac_sha256_ctr_aes = { + .type = SAFEXCEL_ALG_TYPE_AEAD, + .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_SHA2_256, + .alg.aead = { + .setkey = safexcel_aead_setkey, + .encrypt = safexcel_aead_encrypt, + .decrypt = safexcel_aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + .base = { + .cra_name = "authenc(hmac(sha256),rfc3686(ctr(aes)))", + .cra_driver_name = "safexcel-authenc-hmac-sha256-ctr-aes", + .cra_priority = SAFEXCEL_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), + .cra_alignmask = 0, + .cra_init = safexcel_aead_sha256_ctr_cra_init, + .cra_exit = safexcel_aead_cra_exit, + .cra_module = THIS_MODULE, + }, + }, +}; + +static int safexcel_aead_sha224_ctr_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_aead_sha224_cra_init(tfm); + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD; /* override default */ + return 0; +} + +struct safexcel_alg_template safexcel_alg_authenc_hmac_sha224_ctr_aes = { + .type = SAFEXCEL_ALG_TYPE_AEAD, + .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_SHA2_256, + .alg.aead = { + .setkey = safexcel_aead_setkey, + .encrypt = safexcel_aead_encrypt, + .decrypt = safexcel_aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + .base = { + .cra_name = "authenc(hmac(sha224),rfc3686(ctr(aes)))", + .cra_driver_name = "safexcel-authenc-hmac-sha224-ctr-aes", + .cra_priority = SAFEXCEL_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), + .cra_alignmask = 0, + .cra_init = safexcel_aead_sha224_ctr_cra_init, + .cra_exit = safexcel_aead_cra_exit, + .cra_module = THIS_MODULE, + }, + }, +}; + +static int safexcel_aead_sha512_ctr_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_aead_sha512_cra_init(tfm); + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD; /* override default */ + return 0; +} + +struct safexcel_alg_template safexcel_alg_authenc_hmac_sha512_ctr_aes = { + .type = SAFEXCEL_ALG_TYPE_AEAD, + .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_SHA2_512, + .alg.aead = { + .setkey = safexcel_aead_setkey, + .encrypt = safexcel_aead_encrypt, + .decrypt = safexcel_aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + .base = { + .cra_name = "authenc(hmac(sha512),rfc3686(ctr(aes)))", + .cra_driver_name = "safexcel-authenc-hmac-sha512-ctr-aes", + .cra_priority = SAFEXCEL_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), + .cra_alignmask = 0, + .cra_init = safexcel_aead_sha512_ctr_cra_init, + .cra_exit = safexcel_aead_cra_exit, + .cra_module = THIS_MODULE, + }, + }, +}; + +static int safexcel_aead_sha384_ctr_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_aead_sha384_cra_init(tfm); + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD; /* override default */ + return 0; +} + +struct safexcel_alg_template safexcel_alg_authenc_hmac_sha384_ctr_aes = { + .type = SAFEXCEL_ALG_TYPE_AEAD, + .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_SHA2_512, + .alg.aead = { + .setkey = safexcel_aead_setkey, + .encrypt = safexcel_aead_encrypt, + .decrypt = safexcel_aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + .base = { + .cra_name = "authenc(hmac(sha384),rfc3686(ctr(aes)))", + .cra_driver_name = "safexcel-authenc-hmac-sha384-ctr-aes", + .cra_priority = SAFEXCEL_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), + .cra_alignmask = 0, + .cra_init = safexcel_aead_sha384_ctr_cra_init, + .cra_exit = safexcel_aead_cra_exit, + .cra_module = THIS_MODULE, + }, + }, +}; + +static int safexcel_skcipher_aesxts_setkey(struct crypto_skcipher *ctfm, + const u8 *key, unsigned int len) +{ + struct crypto_tfm *tfm = crypto_skcipher_tfm(ctfm); + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + struct safexcel_crypto_priv *priv = ctx->priv; + struct crypto_aes_ctx aes; + int ret, i; + unsigned int keylen; + + /* Check for illegal XTS keys */ + ret = xts_verify_key(ctfm, key, len); + if (ret) + return ret; + + /* Only half of the key data is cipher key */ + keylen = (len >> 1); + ret = aes_expandkey(&aes, key, keylen); + if (ret) { + crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return ret; + } + + if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) { + for (i = 0; i < keylen / sizeof(u32); i++) { + if (ctx->key[i] != cpu_to_le32(aes.key_enc[i])) { + ctx->base.needs_inv = true; + break; + } + } + } + + for (i = 0; i < keylen / sizeof(u32); i++) + ctx->key[i] = cpu_to_le32(aes.key_enc[i]); + + /* The other half is the tweak key */ + ret = aes_expandkey(&aes, (u8 *)(key + keylen), keylen); + if (ret) { + crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return ret; + } + + if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) { + for (i = 0; i < keylen / sizeof(u32); i++) { + if (ctx->key[i + keylen / sizeof(u32)] != + cpu_to_le32(aes.key_enc[i])) { + ctx->base.needs_inv = true; + break; + } + } + } + + for (i = 0; i < keylen / sizeof(u32); i++) + ctx->key[i + keylen / sizeof(u32)] = + cpu_to_le32(aes.key_enc[i]); + + ctx->key_len = keylen << 1; + + memzero_explicit(&aes, sizeof(aes)); + return 0; +} + +static int safexcel_skcipher_aes_xts_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_skcipher_cra_init(tfm); + ctx->alg = SAFEXCEL_AES; + ctx->xts = 1; + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_XTS; + return 0; +} + +static int safexcel_encrypt_xts(struct skcipher_request *req) +{ + if (req->cryptlen < XTS_BLOCK_SIZE) + return -EINVAL; + return safexcel_queue_req(&req->base, skcipher_request_ctx(req), + SAFEXCEL_ENCRYPT); +} + +static int safexcel_decrypt_xts(struct skcipher_request *req) +{ + if (req->cryptlen < XTS_BLOCK_SIZE) + return -EINVAL; + return safexcel_queue_req(&req->base, skcipher_request_ctx(req), + SAFEXCEL_DECRYPT); +} + +struct safexcel_alg_template safexcel_alg_xts_aes = { + .type = SAFEXCEL_ALG_TYPE_SKCIPHER, + .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_AES_XTS, + .alg.skcipher = { + .setkey = safexcel_skcipher_aesxts_setkey, + .encrypt = safexcel_encrypt_xts, + .decrypt = safexcel_decrypt_xts, + /* XTS actually uses 2 AES keys glued together */ + .min_keysize = AES_MIN_KEY_SIZE * 2, + .max_keysize = AES_MAX_KEY_SIZE * 2, + .ivsize = XTS_BLOCK_SIZE, + .base = { + .cra_name = "xts(aes)", + .cra_driver_name = "safexcel-xts-aes", + .cra_priority = SAFEXCEL_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = XTS_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), + .cra_alignmask = 0, + .cra_init = safexcel_skcipher_aes_xts_cra_init, + .cra_exit = safexcel_skcipher_cra_exit, + .cra_module = THIS_MODULE, + }, + }, +}; + +static int safexcel_aead_gcm_setkey(struct crypto_aead *ctfm, const u8 *key, + unsigned int len) +{ + struct crypto_tfm *tfm = crypto_aead_tfm(ctfm); + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + struct safexcel_crypto_priv *priv = ctx->priv; + struct crypto_aes_ctx aes; + u32 hashkey[AES_BLOCK_SIZE >> 2]; + int ret, i; + + ret = aes_expandkey(&aes, key, len); + if (ret) { + crypto_aead_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + memzero_explicit(&aes, sizeof(aes)); + return ret; + } + + if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) { + for (i = 0; i < len / sizeof(u32); i++) { + if (ctx->key[i] != cpu_to_le32(aes.key_enc[i])) { + ctx->base.needs_inv = true; + break; + } + } + } + + for (i = 0; i < len / sizeof(u32); i++) + ctx->key[i] = cpu_to_le32(aes.key_enc[i]); + + ctx->key_len = len; + + /* Compute hash key by encrypting zeroes with cipher key */ + crypto_cipher_clear_flags(ctx->hkaes, CRYPTO_TFM_REQ_MASK); + crypto_cipher_set_flags(ctx->hkaes, crypto_aead_get_flags(ctfm) & + CRYPTO_TFM_REQ_MASK); + ret = crypto_cipher_setkey(ctx->hkaes, key, len); + crypto_aead_set_flags(ctfm, crypto_cipher_get_flags(ctx->hkaes) & + CRYPTO_TFM_RES_MASK); + if (ret) + return ret; + + memset(hashkey, 0, AES_BLOCK_SIZE); + crypto_cipher_encrypt_one(ctx->hkaes, (u8 *)hashkey, (u8 *)hashkey); + + if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) { + for (i = 0; i < AES_BLOCK_SIZE / sizeof(u32); i++) { + if (ctx->ipad[i] != cpu_to_be32(hashkey[i])) { + ctx->base.needs_inv = true; + break; + } + } + } + + for (i = 0; i < AES_BLOCK_SIZE / sizeof(u32); i++) + ctx->ipad[i] = cpu_to_be32(hashkey[i]); + + memzero_explicit(hashkey, AES_BLOCK_SIZE); + memzero_explicit(&aes, sizeof(aes)); + return 0; +} + +static int safexcel_aead_gcm_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_aead_cra_init(tfm); + ctx->hash_alg = CONTEXT_CONTROL_CRYPTO_ALG_GHASH; + ctx->state_sz = GHASH_BLOCK_SIZE; + ctx->xcm = EIP197_XCM_MODE_GCM; + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_XCM; /* override default */ + + ctx->hkaes = crypto_alloc_cipher("aes", 0, 0); + if (IS_ERR(ctx->hkaes)) + return PTR_ERR(ctx->hkaes); + + return 0; +} + +static void safexcel_aead_gcm_cra_exit(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + crypto_free_cipher(ctx->hkaes); + safexcel_aead_cra_exit(tfm); +} + +static int safexcel_aead_gcm_setauthsize(struct crypto_aead *tfm, + unsigned int authsize) +{ + return crypto_gcm_check_authsize(authsize); +} + +struct safexcel_alg_template safexcel_alg_gcm = { + .type = SAFEXCEL_ALG_TYPE_AEAD, + .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_GHASH, + .alg.aead = { + .setkey = safexcel_aead_gcm_setkey, + .setauthsize = safexcel_aead_gcm_setauthsize, + .encrypt = safexcel_aead_encrypt, + .decrypt = safexcel_aead_decrypt, + .ivsize = GCM_AES_IV_SIZE, + .maxauthsize = GHASH_DIGEST_SIZE, + .base = { + .cra_name = "gcm(aes)", + .cra_driver_name = "safexcel-gcm-aes", + .cra_priority = SAFEXCEL_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), + .cra_alignmask = 0, + .cra_init = safexcel_aead_gcm_cra_init, + .cra_exit = safexcel_aead_gcm_cra_exit, + .cra_module = THIS_MODULE, + }, + }, +}; + +static int safexcel_aead_ccm_setkey(struct crypto_aead *ctfm, const u8 *key, + unsigned int len) +{ + struct crypto_tfm *tfm = crypto_aead_tfm(ctfm); + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + struct safexcel_crypto_priv *priv = ctx->priv; + struct crypto_aes_ctx aes; + int ret, i; + + ret = aes_expandkey(&aes, key, len); + if (ret) { + crypto_aead_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + memzero_explicit(&aes, sizeof(aes)); + return ret; + } + + if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) { + for (i = 0; i < len / sizeof(u32); i++) { + if (ctx->key[i] != cpu_to_le32(aes.key_enc[i])) { + ctx->base.needs_inv = true; + break; + } + } + } + + for (i = 0; i < len / sizeof(u32); i++) { + ctx->key[i] = cpu_to_le32(aes.key_enc[i]); + ctx->ipad[i + 2 * AES_BLOCK_SIZE / sizeof(u32)] = + cpu_to_be32(aes.key_enc[i]); + } + + ctx->key_len = len; + ctx->state_sz = 2 * AES_BLOCK_SIZE + len; + + if (len == AES_KEYSIZE_192) + ctx->hash_alg = CONTEXT_CONTROL_CRYPTO_ALG_XCBC192; + else if (len == AES_KEYSIZE_256) + ctx->hash_alg = CONTEXT_CONTROL_CRYPTO_ALG_XCBC256; + else + ctx->hash_alg = CONTEXT_CONTROL_CRYPTO_ALG_XCBC128; + + memzero_explicit(&aes, sizeof(aes)); + return 0; +} + +static int safexcel_aead_ccm_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_aead_cra_init(tfm); + ctx->hash_alg = CONTEXT_CONTROL_CRYPTO_ALG_XCBC128; + ctx->state_sz = 3 * AES_BLOCK_SIZE; + ctx->xcm = EIP197_XCM_MODE_CCM; + ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_XCM; /* override default */ + return 0; +} + +static int safexcel_aead_ccm_setauthsize(struct crypto_aead *tfm, + unsigned int authsize) +{ + /* Borrowed from crypto/ccm.c */ + switch (authsize) { + case 4: + case 6: + case 8: + case 10: + case 12: + case 14: + case 16: + break; + default: + return -EINVAL; + } + + return 0; +} + +static int safexcel_ccm_encrypt(struct aead_request *req) +{ + struct safexcel_cipher_req *creq = aead_request_ctx(req); + + if (req->iv[0] < 1 || req->iv[0] > 7) + return -EINVAL; + + return safexcel_queue_req(&req->base, creq, SAFEXCEL_ENCRYPT); +} + +static int safexcel_ccm_decrypt(struct aead_request *req) +{ + struct safexcel_cipher_req *creq = aead_request_ctx(req); + + if (req->iv[0] < 1 || req->iv[0] > 7) + return -EINVAL; + + return safexcel_queue_req(&req->base, creq, SAFEXCEL_DECRYPT); +} + +struct safexcel_alg_template safexcel_alg_ccm = { + .type = SAFEXCEL_ALG_TYPE_AEAD, + .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_CBC_MAC_ALL, + .alg.aead = { + .setkey = safexcel_aead_ccm_setkey, + .setauthsize = safexcel_aead_ccm_setauthsize, + .encrypt = safexcel_ccm_encrypt, + .decrypt = safexcel_ccm_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = AES_BLOCK_SIZE, + .base = { + .cra_name = "ccm(aes)", + .cra_driver_name = "safexcel-ccm-aes", + .cra_priority = SAFEXCEL_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), + .cra_alignmask = 0, + .cra_init = safexcel_aead_ccm_cra_init, + .cra_exit = safexcel_aead_cra_exit, + .cra_module = THIS_MODULE, + }, + }, +}; diff --git a/drivers/crypto/inside-secure/safexcel_hash.c b/drivers/crypto/inside-secure/safexcel_hash.c index a80a5e757b1f49820fec1487fc6c0011b02b6fde..2effb6d21e8bb200b22cf0de08414df9710e8469 100644 --- a/drivers/crypto/inside-secure/safexcel_hash.c +++ b/drivers/crypto/inside-secure/safexcel_hash.c @@ -29,33 +29,31 @@ struct safexcel_ahash_req { bool finish; bool hmac; bool needs_inv; + bool hmac_zlen; + bool len_is_le; int nents; dma_addr_t result_dma; u32 digest; - u8 state_sz; /* expected sate size, only set once */ + u8 state_sz; /* expected state size, only set once */ + u8 block_sz; /* block size, only set once */ u32 state[SHA512_DIGEST_SIZE / sizeof(u32)] __aligned(sizeof(u32)); - u64 len[2]; - u64 processed[2]; + u64 len; + u64 processed; - u8 cache[SHA512_BLOCK_SIZE << 1] __aligned(sizeof(u32)); + u8 cache[HASH_CACHE_SIZE] __aligned(sizeof(u32)); dma_addr_t cache_dma; unsigned int cache_sz; - u8 cache_next[SHA512_BLOCK_SIZE << 1] __aligned(sizeof(u32)); + u8 cache_next[HASH_CACHE_SIZE] __aligned(sizeof(u32)); }; static inline u64 safexcel_queued_len(struct safexcel_ahash_req *req) { - u64 len, processed; - - len = (0xffffffff * req->len[1]) + req->len[0]; - processed = (0xffffffff * req->processed[1]) + req->processed[0]; - - return len - processed; + return req->len - req->processed; } static void safexcel_hash_token(struct safexcel_command_desc *cdesc, @@ -79,75 +77,104 @@ static void safexcel_hash_token(struct safexcel_command_desc *cdesc, static void safexcel_context_control(struct safexcel_ahash_ctx *ctx, struct safexcel_ahash_req *req, - struct safexcel_command_desc *cdesc, - unsigned int digestsize) + struct safexcel_command_desc *cdesc) { struct safexcel_crypto_priv *priv = ctx->priv; - int i; + u64 count = 0; - cdesc->control_data.control0 |= CONTEXT_CONTROL_TYPE_HASH_OUT; cdesc->control_data.control0 |= ctx->alg; - cdesc->control_data.control0 |= req->digest; - - if (!req->finish) - cdesc->control_data.control0 |= CONTEXT_CONTROL_NO_FINISH_HASH; - - if (req->digest == CONTEXT_CONTROL_DIGEST_PRECOMPUTED) { - if (req->processed[0] || req->processed[1]) { - if (ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_MD5) - cdesc->control_data.control0 |= CONTEXT_CONTROL_SIZE(5); - else if (ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_SHA1) - cdesc->control_data.control0 |= CONTEXT_CONTROL_SIZE(6); - else if (ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_SHA224 || - ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_SHA256) - cdesc->control_data.control0 |= CONTEXT_CONTROL_SIZE(9); - else if (ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_SHA384 || - ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_SHA512) - cdesc->control_data.control0 |= CONTEXT_CONTROL_SIZE(17); - - cdesc->control_data.control1 |= CONTEXT_CONTROL_DIGEST_CNT; + + /* + * Copy the input digest if needed, and setup the context + * fields. Do this now as we need it to setup the first command + * descriptor. + */ + if (!req->processed) { + /* First - and possibly only - block of basic hash only */ + if (req->finish) { + cdesc->control_data.control0 |= + CONTEXT_CONTROL_TYPE_HASH_OUT | + CONTEXT_CONTROL_RESTART_HASH | + /* ensure its not 0! */ + CONTEXT_CONTROL_SIZE(1); } else { - cdesc->control_data.control0 |= CONTEXT_CONTROL_RESTART_HASH; + cdesc->control_data.control0 |= + CONTEXT_CONTROL_TYPE_HASH_OUT | + CONTEXT_CONTROL_RESTART_HASH | + CONTEXT_CONTROL_NO_FINISH_HASH | + /* ensure its not 0! */ + CONTEXT_CONTROL_SIZE(1); } + return; + } - /* - * Copy the input digest if needed, and setup the context - * fields. Do this now as we need it to setup the first command - * descriptor. - */ - if (req->processed[0] || req->processed[1]) { - for (i = 0; i < digestsize / sizeof(u32); i++) - ctx->base.ctxr->data[i] = cpu_to_le32(req->state[i]); - - if (req->finish) { - u64 count = req->processed[0] / EIP197_COUNTER_BLOCK_SIZE; - count += ((0xffffffff / EIP197_COUNTER_BLOCK_SIZE) * - req->processed[1]); - - /* This is a haredware limitation, as the - * counter must fit into an u32. This represents - * a farily big amount of input data, so we - * shouldn't see this. - */ - if (unlikely(count & 0xffff0000)) { - dev_warn(priv->dev, - "Input data is too big\n"); - return; - } - - ctx->base.ctxr->data[i] = cpu_to_le32(count); + /* Hash continuation or HMAC, setup (inner) digest from state */ + memcpy(ctx->base.ctxr->data, req->state, req->state_sz); + + if (req->finish) { + /* Compute digest count for hash/HMAC finish operations */ + if ((req->digest == CONTEXT_CONTROL_DIGEST_PRECOMPUTED) || + req->hmac_zlen || (req->processed != req->block_sz)) { + count = req->processed / EIP197_COUNTER_BLOCK_SIZE; + + /* This is a hardware limitation, as the + * counter must fit into an u32. This represents + * a fairly big amount of input data, so we + * shouldn't see this. + */ + if (unlikely(count & 0xffffffff00000000ULL)) { + dev_warn(priv->dev, + "Input data is too big\n"); + return; } } - } else if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC) { - cdesc->control_data.control0 |= CONTEXT_CONTROL_SIZE(2 * req->state_sz / sizeof(u32)); - memcpy(ctx->base.ctxr->data, ctx->ipad, req->state_sz); - memcpy(ctx->base.ctxr->data + req->state_sz / sizeof(u32), - ctx->opad, req->state_sz); + if ((req->digest == CONTEXT_CONTROL_DIGEST_PRECOMPUTED) || + /* Special case: zero length HMAC */ + req->hmac_zlen || + /* PE HW < 4.4 cannot do HMAC continue, fake using hash */ + (req->processed != req->block_sz)) { + /* Basic hash continue operation, need digest + cnt */ + cdesc->control_data.control0 |= + CONTEXT_CONTROL_SIZE((req->state_sz >> 2) + 1) | + CONTEXT_CONTROL_TYPE_HASH_OUT | + CONTEXT_CONTROL_DIGEST_PRECOMPUTED; + /* For zero-len HMAC, don't finalize, already padded! */ + if (req->hmac_zlen) + cdesc->control_data.control0 |= + CONTEXT_CONTROL_NO_FINISH_HASH; + cdesc->control_data.control1 |= + CONTEXT_CONTROL_DIGEST_CNT; + ctx->base.ctxr->data[req->state_sz >> 2] = + cpu_to_le32(count); + req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED; + + /* Clear zero-length HMAC flag for next operation! */ + req->hmac_zlen = false; + } else { /* HMAC */ + /* Need outer digest for HMAC finalization */ + memcpy(ctx->base.ctxr->data + (req->state_sz >> 2), + ctx->opad, req->state_sz); + + /* Single pass HMAC - no digest count */ + cdesc->control_data.control0 |= + CONTEXT_CONTROL_SIZE(req->state_sz >> 1) | + CONTEXT_CONTROL_TYPE_HASH_OUT | + CONTEXT_CONTROL_DIGEST_HMAC; + } + } else { /* Hash continuation, do not finish yet */ + cdesc->control_data.control0 |= + CONTEXT_CONTROL_SIZE(req->state_sz >> 2) | + CONTEXT_CONTROL_DIGEST_PRECOMPUTED | + CONTEXT_CONTROL_TYPE_HASH_OUT | + CONTEXT_CONTROL_NO_FINISH_HASH; } } -static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int ring, +static int safexcel_ahash_enqueue(struct ahash_request *areq); + +static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, + int ring, struct crypto_async_request *async, bool *should_complete, int *ret) { @@ -155,6 +182,7 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin struct ahash_request *areq = ahash_request_cast(async); struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq); struct safexcel_ahash_req *sreq = ahash_request_ctx(areq); + struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(ahash); u64 cache_len; *ret = 0; @@ -188,9 +216,31 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin sreq->cache_sz = 0; } - if (sreq->finish) + if (sreq->finish) { + if (sreq->hmac && + (sreq->digest != CONTEXT_CONTROL_DIGEST_HMAC)) { + /* Faking HMAC using hash - need to do outer hash */ + memcpy(sreq->cache, sreq->state, + crypto_ahash_digestsize(ahash)); + + memcpy(sreq->state, ctx->opad, sreq->state_sz); + + sreq->len = sreq->block_sz + + crypto_ahash_digestsize(ahash); + sreq->processed = sreq->block_sz; + sreq->hmac = 0; + + ctx->base.needs_inv = true; + areq->nbytes = 0; + safexcel_ahash_enqueue(areq); + + *should_complete = false; /* Not done yet */ + return 1; + } + memcpy(areq->result, sreq->state, crypto_ahash_digestsize(ahash)); + } cache_len = safexcel_queued_len(sreq); if (cache_len) @@ -205,7 +255,6 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring, int *commands, int *results) { struct ahash_request *areq = ahash_request_cast(async); - struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq); struct safexcel_ahash_req *req = ahash_request_ctx(areq); struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq)); struct safexcel_crypto_priv *priv = ctx->priv; @@ -213,33 +262,25 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring, struct safexcel_result_desc *rdesc; struct scatterlist *sg; int i, extra = 0, n_cdesc = 0, ret = 0; - u64 queued, len, cache_len, cache_max; - - cache_max = crypto_ahash_blocksize(ahash); - if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC) - cache_max <<= 1; + u64 queued, len, cache_len; queued = len = safexcel_queued_len(req); - if (queued <= cache_max) + if (queued <= HASH_CACHE_SIZE) cache_len = queued; else cache_len = queued - areq->nbytes; - if (!req->last_req) { + if (!req->finish && !req->last_req) { /* If this is not the last request and the queued data does not - * fit into full blocks, cache it for the next send() call. + * fit into full cache blocks, cache it for the next send call. */ - extra = queued & (crypto_ahash_blocksize(ahash) - 1); - - if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC && - extra < crypto_ahash_blocksize(ahash)) - extra += crypto_ahash_blocksize(ahash); + extra = queued & (HASH_CACHE_SIZE - 1); /* If this is not the last request and the queued data * is a multiple of a block, cache the last one for now. */ if (!extra) - extra = crypto_ahash_blocksize(ahash); + extra = HASH_CACHE_SIZE; sg_pcopy_to_buffer(areq->src, sg_nents(areq->src), req->cache_next, extra, @@ -247,6 +288,12 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring, queued -= extra; len -= extra; + + if (!queued) { + *commands = 0; + *results = 0; + return 0; + } } /* Add a command descriptor for the cached data, if any */ @@ -272,8 +319,14 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring, goto send_command; } + /* Skip descriptor generation for zero-length requests */ + if (!areq->nbytes) + goto send_command; + /* Now handle the current ahash request buffer(s) */ - req->nents = dma_map_sg(priv->dev, areq->src, sg_nents(areq->src), + req->nents = dma_map_sg(priv->dev, areq->src, + sg_nents_for_len(areq->src, + areq->nbytes), DMA_TO_DEVICE); if (!req->nents) { ret = -ENOMEM; @@ -288,7 +341,8 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring, sglen = queued; cdesc = safexcel_add_cdesc(priv, ring, !n_cdesc, - !(queued - sglen), sg_dma_address(sg), + !(queued - sglen), + sg_dma_address(sg), sglen, len, ctx->base.ctxr_dma); if (IS_ERR(cdesc)) { ret = PTR_ERR(cdesc); @@ -306,7 +360,7 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring, send_command: /* Setup the context options */ - safexcel_context_control(ctx, req, first_cdesc, req->state_sz); + safexcel_context_control(ctx, req, first_cdesc); /* Add the token */ safexcel_hash_token(first_cdesc, len, req->state_sz); @@ -328,9 +382,7 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring, safexcel_rdr_req_set(priv, ring, rdesc, &areq->base); - req->processed[0] += len; - if (req->processed[0] < len) - req->processed[1]++; + req->processed += len; *commands = n_cdesc; *results = 1; @@ -355,27 +407,6 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring, return ret; } -static inline bool safexcel_ahash_needs_inv_get(struct ahash_request *areq) -{ - struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq)); - struct safexcel_ahash_req *req = ahash_request_ctx(areq); - unsigned int state_w_sz = req->state_sz / sizeof(u32); - u64 processed; - int i; - - processed = req->processed[0] / EIP197_COUNTER_BLOCK_SIZE; - processed += (0xffffffff / EIP197_COUNTER_BLOCK_SIZE) * req->processed[1]; - - for (i = 0; i < state_w_sz; i++) - if (ctx->base.ctxr->data[i] != cpu_to_le32(req->state[i])) - return true; - - if (ctx->base.ctxr->data[state_w_sz] != cpu_to_le32(processed)) - return true; - - return false; -} - static int safexcel_handle_inv_result(struct safexcel_crypto_priv *priv, int ring, struct crypto_async_request *async, @@ -523,30 +554,25 @@ static int safexcel_ahash_exit_inv(struct crypto_tfm *tfm) /* safexcel_ahash_cache: cache data until at least one request can be sent to * the engine, aka. when there is at least 1 block size in the pipe. */ -static int safexcel_ahash_cache(struct ahash_request *areq, u32 cache_max) +static int safexcel_ahash_cache(struct ahash_request *areq) { struct safexcel_ahash_req *req = ahash_request_ctx(areq); - u64 queued, cache_len; + u64 cache_len; - /* queued: everything accepted by the driver which will be handled by - * the next send() calls. - * tot sz handled by update() - tot sz handled by send() - */ - queued = safexcel_queued_len(req); /* cache_len: everything accepted by the driver but not sent yet, * tot sz handled by update() - last req sz - tot sz handled by send() */ - cache_len = queued - areq->nbytes; + cache_len = safexcel_queued_len(req); /* * In case there isn't enough bytes to proceed (less than a * block size), cache the data until we have enough. */ - if (cache_len + areq->nbytes <= cache_max) { + if (cache_len + areq->nbytes <= HASH_CACHE_SIZE) { sg_pcopy_to_buffer(areq->src, sg_nents(areq->src), req->cache + cache_len, areq->nbytes, 0); - return areq->nbytes; + return 0; } /* We couldn't cache all the data */ @@ -564,14 +590,25 @@ static int safexcel_ahash_enqueue(struct ahash_request *areq) if (ctx->base.ctxr) { if (priv->flags & EIP197_TRC_CACHE && !ctx->base.needs_inv && - (req->processed[0] || req->processed[1]) && - req->digest == CONTEXT_CONTROL_DIGEST_PRECOMPUTED) - /* We're still setting needs_inv here, even though it is + req->processed && + (/* invalidate for basic hash continuation finish */ + (req->finish && + (req->digest == CONTEXT_CONTROL_DIGEST_PRECOMPUTED)) || + /* invalidate if (i)digest changed */ + memcmp(ctx->base.ctxr->data, req->state, req->state_sz) || + /* invalidate for HMAC continuation finish */ + (req->finish && (req->processed != req->block_sz)) || + /* invalidate for HMAC finish with odigest changed */ + (req->finish && + memcmp(ctx->base.ctxr->data + (req->state_sz>>2), + ctx->opad, req->state_sz)))) + /* + * We're still setting needs_inv here, even though it is * cleared right away, because the needs_inv flag can be * set in other functions and we want to keep the same * logic. */ - ctx->base.needs_inv = safexcel_ahash_needs_inv_get(areq); + ctx->base.needs_inv = true; if (ctx->base.needs_inv) { ctx->base.needs_inv = false; @@ -601,35 +638,23 @@ static int safexcel_ahash_enqueue(struct ahash_request *areq) static int safexcel_ahash_update(struct ahash_request *areq) { struct safexcel_ahash_req *req = ahash_request_ctx(areq); - struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq); - u32 cache_max; + int ret; /* If the request is 0 length, do nothing */ if (!areq->nbytes) return 0; - req->len[0] += areq->nbytes; - if (req->len[0] < areq->nbytes) - req->len[1]++; - - cache_max = crypto_ahash_blocksize(ahash); - if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC) - cache_max <<= 1; + /* Add request to the cache if it fits */ + ret = safexcel_ahash_cache(areq); - safexcel_ahash_cache(areq, cache_max); + /* Update total request length */ + req->len += areq->nbytes; - /* - * We're not doing partial updates when performing an hmac request. - * Everything will be handled by the final() call. + /* If not all data could fit into the cache, go process the excess. + * Also go process immediately for an HMAC IV precompute, which + * will never be finished at all, but needs to be processed anyway. */ - if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC) - return 0; - - if (req->hmac) - return safexcel_ahash_enqueue(areq); - - if (!req->last_req && - safexcel_queued_len(req) > cache_max) + if ((ret && !req->finish) || req->last_req) return safexcel_ahash_enqueue(areq); return 0; @@ -640,11 +665,14 @@ static int safexcel_ahash_final(struct ahash_request *areq) struct safexcel_ahash_req *req = ahash_request_ctx(areq); struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq)); - req->last_req = true; req->finish = true; - /* If we have an overall 0 length request */ - if (!req->len[0] && !req->len[1] && !areq->nbytes) { + if (unlikely(!req->len && !areq->nbytes)) { + /* + * If we have an overall 0 length *hash* request: + * The HW cannot do 0 length hash, so we provide the correct + * result directly here. + */ if (ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_MD5) memcpy(areq->result, md5_zero_message_hash, MD5_DIGEST_SIZE); @@ -665,6 +693,43 @@ static int safexcel_ahash_final(struct ahash_request *areq) SHA512_DIGEST_SIZE); return 0; + } else if (unlikely(req->hmac && + (req->len == req->block_sz) && + !areq->nbytes)) { + /* + * If we have an overall 0 length *HMAC* request: + * For HMAC, we need to finalize the inner digest + * and then perform the outer hash. + */ + + /* generate pad block in the cache */ + /* start with a hash block of all zeroes */ + memset(req->cache, 0, req->block_sz); + /* set the first byte to 0x80 to 'append a 1 bit' */ + req->cache[0] = 0x80; + /* add the length in bits in the last 2 bytes */ + if (req->len_is_le) { + /* Little endian length word (e.g. MD5) */ + req->cache[req->block_sz-8] = (req->block_sz << 3) & + 255; + req->cache[req->block_sz-7] = (req->block_sz >> 5); + } else { + /* Big endian length word (e.g. any SHA) */ + req->cache[req->block_sz-2] = (req->block_sz >> 5); + req->cache[req->block_sz-1] = (req->block_sz << 3) & + 255; + } + + req->len += req->block_sz; /* plus 1 hash block */ + + /* Set special zero-length HMAC flag */ + req->hmac_zlen = true; + + /* Finalize HMAC */ + req->digest = CONTEXT_CONTROL_DIGEST_HMAC; + } else if (req->hmac) { + /* Finalize HMAC */ + req->digest = CONTEXT_CONTROL_DIGEST_HMAC; } return safexcel_ahash_enqueue(areq); @@ -674,7 +739,6 @@ static int safexcel_ahash_finup(struct ahash_request *areq) { struct safexcel_ahash_req *req = ahash_request_ctx(areq); - req->last_req = true; req->finish = true; safexcel_ahash_update(areq); @@ -683,52 +747,36 @@ static int safexcel_ahash_finup(struct ahash_request *areq) static int safexcel_ahash_export(struct ahash_request *areq, void *out) { - struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq); struct safexcel_ahash_req *req = ahash_request_ctx(areq); struct safexcel_ahash_export_state *export = out; - u32 cache_sz; - cache_sz = crypto_ahash_blocksize(ahash); - if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC) - cache_sz <<= 1; - - export->len[0] = req->len[0]; - export->len[1] = req->len[1]; - export->processed[0] = req->processed[0]; - export->processed[1] = req->processed[1]; + export->len = req->len; + export->processed = req->processed; export->digest = req->digest; memcpy(export->state, req->state, req->state_sz); - memcpy(export->cache, req->cache, cache_sz); + memcpy(export->cache, req->cache, HASH_CACHE_SIZE); return 0; } static int safexcel_ahash_import(struct ahash_request *areq, const void *in) { - struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq); struct safexcel_ahash_req *req = ahash_request_ctx(areq); const struct safexcel_ahash_export_state *export = in; - u32 cache_sz; int ret; ret = crypto_ahash_init(areq); if (ret) return ret; - cache_sz = crypto_ahash_blocksize(ahash); - if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC) - cache_sz <<= 1; - - req->len[0] = export->len[0]; - req->len[1] = export->len[1]; - req->processed[0] = export->processed[0]; - req->processed[1] = export->processed[1]; + req->len = export->len; + req->processed = export->processed; req->digest = export->digest; - memcpy(req->cache, export->cache, cache_sz); + memcpy(req->cache, export->cache, HASH_CACHE_SIZE); memcpy(req->state, export->state, req->state_sz); return 0; @@ -757,15 +805,10 @@ static int safexcel_sha1_init(struct ahash_request *areq) memset(req, 0, sizeof(*req)); - req->state[0] = SHA1_H0; - req->state[1] = SHA1_H1; - req->state[2] = SHA1_H2; - req->state[3] = SHA1_H3; - req->state[4] = SHA1_H4; - ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA1; req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED; req->state_sz = SHA1_DIGEST_SIZE; + req->block_sz = SHA1_BLOCK_SIZE; return 0; } @@ -802,7 +845,7 @@ static void safexcel_ahash_cra_exit(struct crypto_tfm *tfm) struct safexcel_alg_template safexcel_alg_sha1 = { .type = SAFEXCEL_ALG_TYPE_AHASH, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_SHA1, .alg.ahash = { .init = safexcel_sha1_init, .update = safexcel_ahash_update, @@ -817,7 +860,7 @@ struct safexcel_alg_template safexcel_alg_sha1 = { .base = { .cra_name = "sha1", .cra_driver_name = "safexcel-sha1", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = SHA1_BLOCK_SIZE, @@ -832,10 +875,23 @@ struct safexcel_alg_template safexcel_alg_sha1 = { static int safexcel_hmac_sha1_init(struct ahash_request *areq) { + struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq)); struct safexcel_ahash_req *req = ahash_request_ctx(areq); - safexcel_sha1_init(areq); - req->digest = CONTEXT_CONTROL_DIGEST_HMAC; + memset(req, 0, sizeof(*req)); + + /* Start from ipad precompute */ + memcpy(req->state, ctx->ipad, SHA1_DIGEST_SIZE); + /* Already processed the key^ipad part now! */ + req->len = SHA1_BLOCK_SIZE; + req->processed = SHA1_BLOCK_SIZE; + + ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA1; + req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED; + req->state_sz = SHA1_DIGEST_SIZE; + req->block_sz = SHA1_BLOCK_SIZE; + req->hmac = true; + return 0; } @@ -1004,21 +1060,16 @@ static int safexcel_hmac_alg_setkey(struct crypto_ahash *tfm, const u8 *key, struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm)); struct safexcel_crypto_priv *priv = ctx->priv; struct safexcel_ahash_export_state istate, ostate; - int ret, i; + int ret; ret = safexcel_hmac_setkey(alg, key, keylen, &istate, &ostate); if (ret) return ret; - if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr) { - for (i = 0; i < state_sz / sizeof(u32); i++) { - if (ctx->ipad[i] != le32_to_cpu(istate.state[i]) || - ctx->opad[i] != le32_to_cpu(ostate.state[i])) { - ctx->base.needs_inv = true; - break; - } - } - } + if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr && + (memcmp(ctx->ipad, istate.state, state_sz) || + memcmp(ctx->opad, ostate.state, state_sz))) + ctx->base.needs_inv = true; memcpy(ctx->ipad, &istate.state, state_sz); memcpy(ctx->opad, &ostate.state, state_sz); @@ -1035,7 +1086,7 @@ static int safexcel_hmac_sha1_setkey(struct crypto_ahash *tfm, const u8 *key, struct safexcel_alg_template safexcel_alg_hmac_sha1 = { .type = SAFEXCEL_ALG_TYPE_AHASH, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_SHA1, .alg.ahash = { .init = safexcel_hmac_sha1_init, .update = safexcel_ahash_update, @@ -1051,7 +1102,7 @@ struct safexcel_alg_template safexcel_alg_hmac_sha1 = { .base = { .cra_name = "hmac(sha1)", .cra_driver_name = "safexcel-hmac-sha1", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = SHA1_BLOCK_SIZE, @@ -1071,18 +1122,10 @@ static int safexcel_sha256_init(struct ahash_request *areq) memset(req, 0, sizeof(*req)); - req->state[0] = SHA256_H0; - req->state[1] = SHA256_H1; - req->state[2] = SHA256_H2; - req->state[3] = SHA256_H3; - req->state[4] = SHA256_H4; - req->state[5] = SHA256_H5; - req->state[6] = SHA256_H6; - req->state[7] = SHA256_H7; - ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA256; req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED; req->state_sz = SHA256_DIGEST_SIZE; + req->block_sz = SHA256_BLOCK_SIZE; return 0; } @@ -1099,7 +1142,7 @@ static int safexcel_sha256_digest(struct ahash_request *areq) struct safexcel_alg_template safexcel_alg_sha256 = { .type = SAFEXCEL_ALG_TYPE_AHASH, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_SHA2_256, .alg.ahash = { .init = safexcel_sha256_init, .update = safexcel_ahash_update, @@ -1114,7 +1157,7 @@ struct safexcel_alg_template safexcel_alg_sha256 = { .base = { .cra_name = "sha256", .cra_driver_name = "safexcel-sha256", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = SHA256_BLOCK_SIZE, @@ -1134,18 +1177,10 @@ static int safexcel_sha224_init(struct ahash_request *areq) memset(req, 0, sizeof(*req)); - req->state[0] = SHA224_H0; - req->state[1] = SHA224_H1; - req->state[2] = SHA224_H2; - req->state[3] = SHA224_H3; - req->state[4] = SHA224_H4; - req->state[5] = SHA224_H5; - req->state[6] = SHA224_H6; - req->state[7] = SHA224_H7; - ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA224; req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED; req->state_sz = SHA256_DIGEST_SIZE; + req->block_sz = SHA256_BLOCK_SIZE; return 0; } @@ -1162,7 +1197,7 @@ static int safexcel_sha224_digest(struct ahash_request *areq) struct safexcel_alg_template safexcel_alg_sha224 = { .type = SAFEXCEL_ALG_TYPE_AHASH, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_SHA2_256, .alg.ahash = { .init = safexcel_sha224_init, .update = safexcel_ahash_update, @@ -1177,7 +1212,7 @@ struct safexcel_alg_template safexcel_alg_sha224 = { .base = { .cra_name = "sha224", .cra_driver_name = "safexcel-sha224", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = SHA224_BLOCK_SIZE, @@ -1199,10 +1234,23 @@ static int safexcel_hmac_sha224_setkey(struct crypto_ahash *tfm, const u8 *key, static int safexcel_hmac_sha224_init(struct ahash_request *areq) { + struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq)); struct safexcel_ahash_req *req = ahash_request_ctx(areq); - safexcel_sha224_init(areq); - req->digest = CONTEXT_CONTROL_DIGEST_HMAC; + memset(req, 0, sizeof(*req)); + + /* Start from ipad precompute */ + memcpy(req->state, ctx->ipad, SHA256_DIGEST_SIZE); + /* Already processed the key^ipad part now! */ + req->len = SHA256_BLOCK_SIZE; + req->processed = SHA256_BLOCK_SIZE; + + ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA224; + req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED; + req->state_sz = SHA256_DIGEST_SIZE; + req->block_sz = SHA256_BLOCK_SIZE; + req->hmac = true; + return 0; } @@ -1218,7 +1266,7 @@ static int safexcel_hmac_sha224_digest(struct ahash_request *areq) struct safexcel_alg_template safexcel_alg_hmac_sha224 = { .type = SAFEXCEL_ALG_TYPE_AHASH, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_SHA2_256, .alg.ahash = { .init = safexcel_hmac_sha224_init, .update = safexcel_ahash_update, @@ -1234,7 +1282,7 @@ struct safexcel_alg_template safexcel_alg_hmac_sha224 = { .base = { .cra_name = "hmac(sha224)", .cra_driver_name = "safexcel-hmac-sha224", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = SHA224_BLOCK_SIZE, @@ -1256,10 +1304,23 @@ static int safexcel_hmac_sha256_setkey(struct crypto_ahash *tfm, const u8 *key, static int safexcel_hmac_sha256_init(struct ahash_request *areq) { + struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq)); struct safexcel_ahash_req *req = ahash_request_ctx(areq); - safexcel_sha256_init(areq); - req->digest = CONTEXT_CONTROL_DIGEST_HMAC; + memset(req, 0, sizeof(*req)); + + /* Start from ipad precompute */ + memcpy(req->state, ctx->ipad, SHA256_DIGEST_SIZE); + /* Already processed the key^ipad part now! */ + req->len = SHA256_BLOCK_SIZE; + req->processed = SHA256_BLOCK_SIZE; + + ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA256; + req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED; + req->state_sz = SHA256_DIGEST_SIZE; + req->block_sz = SHA256_BLOCK_SIZE; + req->hmac = true; + return 0; } @@ -1275,7 +1336,7 @@ static int safexcel_hmac_sha256_digest(struct ahash_request *areq) struct safexcel_alg_template safexcel_alg_hmac_sha256 = { .type = SAFEXCEL_ALG_TYPE_AHASH, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_SHA2_256, .alg.ahash = { .init = safexcel_hmac_sha256_init, .update = safexcel_ahash_update, @@ -1291,7 +1352,7 @@ struct safexcel_alg_template safexcel_alg_hmac_sha256 = { .base = { .cra_name = "hmac(sha256)", .cra_driver_name = "safexcel-hmac-sha256", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = SHA256_BLOCK_SIZE, @@ -1311,26 +1372,10 @@ static int safexcel_sha512_init(struct ahash_request *areq) memset(req, 0, sizeof(*req)); - req->state[0] = lower_32_bits(SHA512_H0); - req->state[1] = upper_32_bits(SHA512_H0); - req->state[2] = lower_32_bits(SHA512_H1); - req->state[3] = upper_32_bits(SHA512_H1); - req->state[4] = lower_32_bits(SHA512_H2); - req->state[5] = upper_32_bits(SHA512_H2); - req->state[6] = lower_32_bits(SHA512_H3); - req->state[7] = upper_32_bits(SHA512_H3); - req->state[8] = lower_32_bits(SHA512_H4); - req->state[9] = upper_32_bits(SHA512_H4); - req->state[10] = lower_32_bits(SHA512_H5); - req->state[11] = upper_32_bits(SHA512_H5); - req->state[12] = lower_32_bits(SHA512_H6); - req->state[13] = upper_32_bits(SHA512_H6); - req->state[14] = lower_32_bits(SHA512_H7); - req->state[15] = upper_32_bits(SHA512_H7); - ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA512; req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED; req->state_sz = SHA512_DIGEST_SIZE; + req->block_sz = SHA512_BLOCK_SIZE; return 0; } @@ -1347,7 +1392,7 @@ static int safexcel_sha512_digest(struct ahash_request *areq) struct safexcel_alg_template safexcel_alg_sha512 = { .type = SAFEXCEL_ALG_TYPE_AHASH, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_SHA2_512, .alg.ahash = { .init = safexcel_sha512_init, .update = safexcel_ahash_update, @@ -1362,7 +1407,7 @@ struct safexcel_alg_template safexcel_alg_sha512 = { .base = { .cra_name = "sha512", .cra_driver_name = "safexcel-sha512", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = SHA512_BLOCK_SIZE, @@ -1382,26 +1427,10 @@ static int safexcel_sha384_init(struct ahash_request *areq) memset(req, 0, sizeof(*req)); - req->state[0] = lower_32_bits(SHA384_H0); - req->state[1] = upper_32_bits(SHA384_H0); - req->state[2] = lower_32_bits(SHA384_H1); - req->state[3] = upper_32_bits(SHA384_H1); - req->state[4] = lower_32_bits(SHA384_H2); - req->state[5] = upper_32_bits(SHA384_H2); - req->state[6] = lower_32_bits(SHA384_H3); - req->state[7] = upper_32_bits(SHA384_H3); - req->state[8] = lower_32_bits(SHA384_H4); - req->state[9] = upper_32_bits(SHA384_H4); - req->state[10] = lower_32_bits(SHA384_H5); - req->state[11] = upper_32_bits(SHA384_H5); - req->state[12] = lower_32_bits(SHA384_H6); - req->state[13] = upper_32_bits(SHA384_H6); - req->state[14] = lower_32_bits(SHA384_H7); - req->state[15] = upper_32_bits(SHA384_H7); - ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA384; req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED; req->state_sz = SHA512_DIGEST_SIZE; + req->block_sz = SHA512_BLOCK_SIZE; return 0; } @@ -1418,7 +1447,7 @@ static int safexcel_sha384_digest(struct ahash_request *areq) struct safexcel_alg_template safexcel_alg_sha384 = { .type = SAFEXCEL_ALG_TYPE_AHASH, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_SHA2_512, .alg.ahash = { .init = safexcel_sha384_init, .update = safexcel_ahash_update, @@ -1433,7 +1462,7 @@ struct safexcel_alg_template safexcel_alg_sha384 = { .base = { .cra_name = "sha384", .cra_driver_name = "safexcel-sha384", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = SHA384_BLOCK_SIZE, @@ -1455,10 +1484,23 @@ static int safexcel_hmac_sha512_setkey(struct crypto_ahash *tfm, const u8 *key, static int safexcel_hmac_sha512_init(struct ahash_request *areq) { + struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq)); struct safexcel_ahash_req *req = ahash_request_ctx(areq); - safexcel_sha512_init(areq); - req->digest = CONTEXT_CONTROL_DIGEST_HMAC; + memset(req, 0, sizeof(*req)); + + /* Start from ipad precompute */ + memcpy(req->state, ctx->ipad, SHA512_DIGEST_SIZE); + /* Already processed the key^ipad part now! */ + req->len = SHA512_BLOCK_SIZE; + req->processed = SHA512_BLOCK_SIZE; + + ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA512; + req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED; + req->state_sz = SHA512_DIGEST_SIZE; + req->block_sz = SHA512_BLOCK_SIZE; + req->hmac = true; + return 0; } @@ -1474,7 +1516,7 @@ static int safexcel_hmac_sha512_digest(struct ahash_request *areq) struct safexcel_alg_template safexcel_alg_hmac_sha512 = { .type = SAFEXCEL_ALG_TYPE_AHASH, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_SHA2_512, .alg.ahash = { .init = safexcel_hmac_sha512_init, .update = safexcel_ahash_update, @@ -1490,7 +1532,7 @@ struct safexcel_alg_template safexcel_alg_hmac_sha512 = { .base = { .cra_name = "hmac(sha512)", .cra_driver_name = "safexcel-hmac-sha512", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = SHA512_BLOCK_SIZE, @@ -1512,10 +1554,23 @@ static int safexcel_hmac_sha384_setkey(struct crypto_ahash *tfm, const u8 *key, static int safexcel_hmac_sha384_init(struct ahash_request *areq) { + struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq)); struct safexcel_ahash_req *req = ahash_request_ctx(areq); - safexcel_sha384_init(areq); - req->digest = CONTEXT_CONTROL_DIGEST_HMAC; + memset(req, 0, sizeof(*req)); + + /* Start from ipad precompute */ + memcpy(req->state, ctx->ipad, SHA512_DIGEST_SIZE); + /* Already processed the key^ipad part now! */ + req->len = SHA512_BLOCK_SIZE; + req->processed = SHA512_BLOCK_SIZE; + + ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA384; + req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED; + req->state_sz = SHA512_DIGEST_SIZE; + req->block_sz = SHA512_BLOCK_SIZE; + req->hmac = true; + return 0; } @@ -1531,7 +1586,7 @@ static int safexcel_hmac_sha384_digest(struct ahash_request *areq) struct safexcel_alg_template safexcel_alg_hmac_sha384 = { .type = SAFEXCEL_ALG_TYPE_AHASH, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_SHA2_512, .alg.ahash = { .init = safexcel_hmac_sha384_init, .update = safexcel_ahash_update, @@ -1547,7 +1602,7 @@ struct safexcel_alg_template safexcel_alg_hmac_sha384 = { .base = { .cra_name = "hmac(sha384)", .cra_driver_name = "safexcel-hmac-sha384", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = SHA384_BLOCK_SIZE, @@ -1567,14 +1622,10 @@ static int safexcel_md5_init(struct ahash_request *areq) memset(req, 0, sizeof(*req)); - req->state[0] = MD5_H0; - req->state[1] = MD5_H1; - req->state[2] = MD5_H2; - req->state[3] = MD5_H3; - ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_MD5; req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED; req->state_sz = MD5_DIGEST_SIZE; + req->block_sz = MD5_HMAC_BLOCK_SIZE; return 0; } @@ -1591,7 +1642,7 @@ static int safexcel_md5_digest(struct ahash_request *areq) struct safexcel_alg_template safexcel_alg_md5 = { .type = SAFEXCEL_ALG_TYPE_AHASH, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_MD5, .alg.ahash = { .init = safexcel_md5_init, .update = safexcel_ahash_update, @@ -1606,7 +1657,7 @@ struct safexcel_alg_template safexcel_alg_md5 = { .base = { .cra_name = "md5", .cra_driver_name = "safexcel-md5", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = MD5_HMAC_BLOCK_SIZE, @@ -1621,10 +1672,24 @@ struct safexcel_alg_template safexcel_alg_md5 = { static int safexcel_hmac_md5_init(struct ahash_request *areq) { + struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq)); struct safexcel_ahash_req *req = ahash_request_ctx(areq); - safexcel_md5_init(areq); - req->digest = CONTEXT_CONTROL_DIGEST_HMAC; + memset(req, 0, sizeof(*req)); + + /* Start from ipad precompute */ + memcpy(req->state, ctx->ipad, MD5_DIGEST_SIZE); + /* Already processed the key^ipad part now! */ + req->len = MD5_HMAC_BLOCK_SIZE; + req->processed = MD5_HMAC_BLOCK_SIZE; + + ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_MD5; + req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED; + req->state_sz = MD5_DIGEST_SIZE; + req->block_sz = MD5_HMAC_BLOCK_SIZE; + req->len_is_le = true; /* MD5 is little endian! ... */ + req->hmac = true; + return 0; } @@ -1647,7 +1712,7 @@ static int safexcel_hmac_md5_digest(struct ahash_request *areq) struct safexcel_alg_template safexcel_alg_hmac_md5 = { .type = SAFEXCEL_ALG_TYPE_AHASH, - .engines = EIP97IES | EIP197B | EIP197D, + .algo_mask = SAFEXCEL_ALG_MD5, .alg.ahash = { .init = safexcel_hmac_md5_init, .update = safexcel_ahash_update, @@ -1663,7 +1728,7 @@ struct safexcel_alg_template safexcel_alg_hmac_md5 = { .base = { .cra_name = "hmac(md5)", .cra_driver_name = "safexcel-hmac-md5", - .cra_priority = 300, + .cra_priority = SAFEXCEL_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = MD5_HMAC_BLOCK_SIZE, diff --git a/drivers/crypto/inside-secure/safexcel_ring.c b/drivers/crypto/inside-secure/safexcel_ring.c index 142bc3f5c45c9b46498a64829daf5b578603004e..0f269b89cfd4c5afd922a66774654397b19be34d 100644 --- a/drivers/crypto/inside-secure/safexcel_ring.c +++ b/drivers/crypto/inside-secure/safexcel_ring.c @@ -137,7 +137,13 @@ struct safexcel_command_desc *safexcel_add_cdesc(struct safexcel_crypto_priv *pr struct safexcel_token *token = (struct safexcel_token *)cdesc->control_data.token; - cdesc->control_data.packet_length = full_data_len; + /* + * Note that the length here MUST be >0 or else the EIP(1)97 + * may hang. Newer EIP197 firmware actually incorporates this + * fix already, but that doesn't help the EIP97 and we may + * also be running older firmware. + */ + cdesc->control_data.packet_length = full_data_len ?: 1; cdesc->control_data.options = EIP197_OPTION_MAGIC_VALUE | EIP197_OPTION_64BIT_CTX | EIP197_OPTION_CTX_CTRL_IN_CMD; @@ -145,7 +151,8 @@ struct safexcel_command_desc *safexcel_add_cdesc(struct safexcel_crypto_priv *pr (lower_32_bits(context) & GENMASK(31, 2)) >> 2; cdesc->control_data.context_hi = upper_32_bits(context); - if (priv->version == EIP197B || priv->version == EIP197D) + if (priv->version == EIP197B_MRVL || + priv->version == EIP197D_MRVL) cdesc->control_data.options |= EIP197_OPTION_RC_AUTO; /* TODO: large xform HMAC with SHA-384/512 uses refresh = 3 */ diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index acedafe3fa98cd1d0ee07ba885a062a5080ec0eb..9181523ba7607362056bea1edff52c35a71d5516 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/drivers/crypto/ixp4xx_crypto.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include @@ -756,10 +756,7 @@ static int setup_cipher(struct crypto_tfm *tfm, int encrypt, } cipher_cfg |= keylen_cfg; } else { - u32 tmp[DES_EXPKEY_WORDS]; - if (des_ekey(tmp, key) == 0) { - *flags |= CRYPTO_TFM_RES_WEAK_KEY; - } + crypto_des_verify_key(tfm, key); } /* write cfg word to cryptinfo */ *(u32*)cinfo = cpu_to_be32(cipher_cfg); @@ -851,14 +848,8 @@ static int ablk_setkey(struct crypto_ablkcipher *tfm, const u8 *key, static int ablk_des3_setkey(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int key_len) { - u32 flags = crypto_ablkcipher_get_flags(tfm); - int err; - - err = __des3_verify_key(&flags, key); - if (unlikely(err)) - crypto_ablkcipher_set_flags(tfm, flags); - - return ablk_setkey(tfm, key, key_len); + return verify_ablkcipher_des3_key(tfm, key) ?: + ablk_setkey(tfm, key, key_len); } static int ablk_rfc3686_setkey(struct crypto_ablkcipher *tfm, const u8 *key, @@ -1181,7 +1172,6 @@ static int des3_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) { struct ixp_ctx *ctx = crypto_aead_ctx(tfm); - u32 flags = CRYPTO_TFM_RES_BAD_KEY_LEN; struct crypto_authenc_keys keys; int err; @@ -1193,12 +1183,8 @@ static int des3_aead_setkey(struct crypto_aead *tfm, const u8 *key, if (keys.authkeylen > sizeof(ctx->authkey)) goto badkey; - if (keys.enckeylen != DES3_EDE_KEY_SIZE) - goto badkey; - - flags = crypto_aead_get_flags(tfm); - err = __des3_verify_key(&flags, keys.enckey); - if (unlikely(err)) + err = verify_aead_des3_key(tfm, keys.enckey, keys.enckeylen); + if (err) goto badkey; memcpy(ctx->authkey, keys.authkey, keys.authkeylen); @@ -1209,7 +1195,6 @@ static int des3_aead_setkey(struct crypto_aead *tfm, const u8 *key, memzero_explicit(&keys, sizeof(keys)); return aead_setup(tfm, crypto_aead_authsize(tfm)); badkey: - crypto_aead_set_flags(tfm, flags); memzero_explicit(&keys, sizeof(keys)); return err; } diff --git a/drivers/crypto/marvell/cipher.c b/drivers/crypto/marvell/cipher.c index f4321f3c077727370b7b6a2e2b09ef52b5b501cd..84ceddfee76b48e2dcac9d4b0b2c77c3d00123df 100644 --- a/drivers/crypto/marvell/cipher.c +++ b/drivers/crypto/marvell/cipher.c @@ -10,7 +10,7 @@ */ #include -#include +#include #include "cesa.h" @@ -254,7 +254,7 @@ static int mv_cesa_aes_setkey(struct crypto_skcipher *cipher, const u8 *key, int ret; int i; - ret = crypto_aes_expand_key(&ctx->aes, key, len); + ret = aes_expandkey(&ctx->aes, key, len); if (ret) { crypto_skcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); return ret; @@ -272,21 +272,12 @@ static int mv_cesa_aes_setkey(struct crypto_skcipher *cipher, const u8 *key, static int mv_cesa_des_setkey(struct crypto_skcipher *cipher, const u8 *key, unsigned int len) { - struct crypto_tfm *tfm = crypto_skcipher_tfm(cipher); - struct mv_cesa_des_ctx *ctx = crypto_tfm_ctx(tfm); - u32 tmp[DES_EXPKEY_WORDS]; - int ret; - - if (len != DES_KEY_SIZE) { - crypto_skcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } + struct mv_cesa_des_ctx *ctx = crypto_skcipher_ctx(cipher); + int err; - ret = des_ekey(tmp, key); - if (!ret && (tfm->crt_flags & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) { - tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; - return -EINVAL; - } + err = verify_skcipher_des_key(cipher, key); + if (err) + return err; memcpy(ctx->key, key, DES_KEY_SIZE); @@ -299,8 +290,8 @@ static int mv_cesa_des3_ede_setkey(struct crypto_skcipher *cipher, struct mv_cesa_des_ctx *ctx = crypto_skcipher_ctx(cipher); int err; - err = des3_verify_key(cipher, key); - if (unlikely(err)) + err = verify_skcipher_des3_key(cipher, key); + if (err) return err; memcpy(ctx->key, key, DES3_EDE_KEY_SIZE); diff --git a/drivers/crypto/marvell/hash.c b/drivers/crypto/marvell/hash.c index 0f0ac851f4eb8951e476f0b9b14c254b84921e8b..a2b35fb0fb890637795d68b12bdc0b8d0b5f7436 100644 --- a/drivers/crypto/marvell/hash.c +++ b/drivers/crypto/marvell/hash.c @@ -1148,8 +1148,7 @@ static int mv_cesa_ahmac_pad_init(struct ahash_request *req, } /* Set the memory region to 0 to avoid any leak. */ - memset(keydup, 0, keylen); - kfree(keydup); + kzfree(keydup); if (ret) return ret; diff --git a/drivers/crypto/mediatek/mtk-aes.c b/drivers/crypto/mediatek/mtk-aes.c index b7477ee32ca098969d8345e3512e657cdfba74ba..90c9644fb8a8694e90e47c32fcd662f2b8d75fd4 100644 --- a/drivers/crypto/mediatek/mtk-aes.c +++ b/drivers/crypto/mediatek/mtk-aes.c @@ -23,7 +23,7 @@ #define AES_CT_CTRL_HDR cpu_to_le32(0x00220000) -/* AES-CBC/ECB/CTR command token */ +/* AES-CBC/ECB/CTR/OFB/CFB command token */ #define AES_CMD0 cpu_to_le32(0x05000000) #define AES_CMD1 cpu_to_le32(0x2d060000) #define AES_CMD2 cpu_to_le32(0xe4a63806) @@ -50,6 +50,8 @@ /* AES transform information word 1 fields */ #define AES_TFM_ECB cpu_to_le32(0x0 << 0) #define AES_TFM_CBC cpu_to_le32(0x1 << 0) +#define AES_TFM_OFB cpu_to_le32(0x4 << 0) +#define AES_TFM_CFB128 cpu_to_le32(0x5 << 0) #define AES_TFM_CTR_INIT cpu_to_le32(0x2 << 0) /* init counter to 1 */ #define AES_TFM_CTR_LOAD cpu_to_le32(0x6 << 0) /* load/reuse counter */ #define AES_TFM_3IV cpu_to_le32(0x7 << 5) /* using IV 0-2 */ @@ -58,13 +60,15 @@ #define AES_TFM_ENC_HASH cpu_to_le32(0x1 << 17) /* AES flags */ -#define AES_FLAGS_CIPHER_MSK GENMASK(2, 0) +#define AES_FLAGS_CIPHER_MSK GENMASK(4, 0) #define AES_FLAGS_ECB BIT(0) #define AES_FLAGS_CBC BIT(1) #define AES_FLAGS_CTR BIT(2) -#define AES_FLAGS_GCM BIT(3) -#define AES_FLAGS_ENCRYPT BIT(4) -#define AES_FLAGS_BUSY BIT(5) +#define AES_FLAGS_OFB BIT(3) +#define AES_FLAGS_CFB128 BIT(4) +#define AES_FLAGS_GCM BIT(5) +#define AES_FLAGS_ENCRYPT BIT(6) +#define AES_FLAGS_BUSY BIT(7) #define AES_AUTH_TAG_ERR cpu_to_le32(BIT(26)) @@ -101,6 +105,7 @@ struct mtk_aes_reqctx { struct mtk_aes_base_ctx { struct mtk_cryp *cryp; u32 keylen; + __le32 key[12]; __le32 keymode; mtk_aes_fn start; @@ -405,7 +410,7 @@ static int mtk_aes_map(struct mtk_cryp *cryp, struct mtk_aes_rec *aes) return mtk_aes_complete(cryp, aes, -EINVAL); } -/* Initialize transform information of CBC/ECB/CTR mode */ +/* Initialize transform information of CBC/ECB/CTR/OFB/CFB mode */ static void mtk_aes_info_init(struct mtk_cryp *cryp, struct mtk_aes_rec *aes, size_t len) { @@ -434,7 +439,12 @@ static void mtk_aes_info_init(struct mtk_cryp *cryp, struct mtk_aes_rec *aes, case AES_FLAGS_CTR: info->tfm[1] = AES_TFM_CTR_LOAD; goto ctr; - + case AES_FLAGS_OFB: + info->tfm[1] = AES_TFM_OFB; + break; + case AES_FLAGS_CFB128: + info->tfm[1] = AES_TFM_CFB128; + break; default: /* Should not happen... */ return; @@ -525,6 +535,8 @@ static int mtk_aes_handle_queue(struct mtk_cryp *cryp, u8 id, backlog->complete(backlog, -EINPROGRESS); ctx = crypto_tfm_ctx(areq->tfm); + /* Write key into state buffer */ + memcpy(ctx->info.state, ctx->key, sizeof(ctx->key)); aes->areq = areq; aes->ctx = ctx; @@ -644,21 +656,26 @@ static int mtk_aes_setkey(struct crypto_ablkcipher *tfm, } ctx->keylen = SIZE_IN_WORDS(keylen); - mtk_aes_write_state_le(ctx->info.state, (const u32 *)key, keylen); + mtk_aes_write_state_le(ctx->key, (const u32 *)key, keylen); return 0; } static int mtk_aes_crypt(struct ablkcipher_request *req, u64 mode) { - struct mtk_aes_base_ctx *ctx; + struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); + struct mtk_aes_base_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); struct mtk_aes_reqctx *rctx; + struct mtk_cryp *cryp; + + cryp = mtk_aes_find_dev(ctx); + if (!cryp) + return -ENODEV; - ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req)); rctx = ablkcipher_request_ctx(req); rctx->mode = mode; - return mtk_aes_handle_queue(ctx->cryp, !(mode & AES_FLAGS_ENCRYPT), + return mtk_aes_handle_queue(cryp, !(mode & AES_FLAGS_ENCRYPT), &req->base); } @@ -692,16 +709,29 @@ static int mtk_aes_ctr_decrypt(struct ablkcipher_request *req) return mtk_aes_crypt(req, AES_FLAGS_CTR); } +static int mtk_aes_ofb_encrypt(struct ablkcipher_request *req) +{ + return mtk_aes_crypt(req, AES_FLAGS_ENCRYPT | AES_FLAGS_OFB); +} + +static int mtk_aes_ofb_decrypt(struct ablkcipher_request *req) +{ + return mtk_aes_crypt(req, AES_FLAGS_OFB); +} + +static int mtk_aes_cfb_encrypt(struct ablkcipher_request *req) +{ + return mtk_aes_crypt(req, AES_FLAGS_ENCRYPT | AES_FLAGS_CFB128); +} + +static int mtk_aes_cfb_decrypt(struct ablkcipher_request *req) +{ + return mtk_aes_crypt(req, AES_FLAGS_CFB128); +} + static int mtk_aes_cra_init(struct crypto_tfm *tfm) { struct mtk_aes_ctx *ctx = crypto_tfm_ctx(tfm); - struct mtk_cryp *cryp = NULL; - - cryp = mtk_aes_find_dev(&ctx->base); - if (!cryp) { - pr_err("can't find crypto device\n"); - return -ENODEV; - } tfm->crt_ablkcipher.reqsize = sizeof(struct mtk_aes_reqctx); ctx->base.start = mtk_aes_start; @@ -711,13 +741,6 @@ static int mtk_aes_cra_init(struct crypto_tfm *tfm) static int mtk_aes_ctr_cra_init(struct crypto_tfm *tfm) { struct mtk_aes_ctx *ctx = crypto_tfm_ctx(tfm); - struct mtk_cryp *cryp = NULL; - - cryp = mtk_aes_find_dev(&ctx->base); - if (!cryp) { - pr_err("can't find crypto device\n"); - return -ENODEV; - } tfm->crt_ablkcipher.reqsize = sizeof(struct mtk_aes_reqctx); ctx->base.start = mtk_aes_ctr_start; @@ -787,6 +810,48 @@ static struct crypto_alg aes_algs[] = { .decrypt = mtk_aes_ctr_decrypt, } }, +{ + .cra_name = "ofb(aes)", + .cra_driver_name = "ofb-aes-mtk", + .cra_priority = 400, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_init = mtk_aes_cra_init, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct mtk_aes_ctx), + .cra_alignmask = 0xf, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_u.ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = mtk_aes_setkey, + .encrypt = mtk_aes_ofb_encrypt, + .decrypt = mtk_aes_ofb_decrypt, + } +}, +{ + .cra_name = "cfb(aes)", + .cra_driver_name = "cfb-aes-mtk", + .cra_priority = 400, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_init = mtk_aes_cra_init, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct mtk_aes_ctx), + .cra_alignmask = 0xf, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_u.ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = mtk_aes_setkey, + .encrypt = mtk_aes_cfb_encrypt, + .decrypt = mtk_aes_cfb_decrypt, + } +}, }; static inline struct mtk_aes_gcm_ctx * @@ -905,14 +970,11 @@ static int mtk_aes_gcm_start(struct mtk_cryp *cryp, struct mtk_aes_rec *aes) aes->resume = mtk_aes_transfer_complete; /* Compute total process length. */ aes->total = len + gctx->authsize; - /* Compute text length. */ - gctx->textlen = req->cryptlen; /* Hardware will append authenticated tag to output buffer */ scatterwalk_map_and_copy(tag, req->dst, len, gctx->authsize, 1); } else { aes->resume = mtk_aes_gcm_tag_verify; aes->total = len; - gctx->textlen = req->cryptlen - gctx->authsize; } return mtk_aes_gcm_dma(cryp, aes, req->src, req->dst, len); @@ -923,6 +985,15 @@ static int mtk_aes_gcm_crypt(struct aead_request *req, u64 mode) struct mtk_aes_base_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); struct mtk_aes_gcm_ctx *gctx = mtk_aes_gcm_ctx_cast(ctx); struct mtk_aes_reqctx *rctx = aead_request_ctx(req); + struct mtk_cryp *cryp; + bool enc = !!(mode & AES_FLAGS_ENCRYPT); + + cryp = mtk_aes_find_dev(ctx); + if (!cryp) + return -ENODEV; + + /* Compute text length. */ + gctx->textlen = req->cryptlen - (enc ? 0 : gctx->authsize); /* Empty messages are not supported yet */ if (!gctx->textlen && !req->assoclen) @@ -930,8 +1001,7 @@ static int mtk_aes_gcm_crypt(struct aead_request *req, u64 mode) rctx->mode = AES_FLAGS_GCM | mode; - return mtk_aes_handle_queue(ctx->cryp, !!(mode & AES_FLAGS_ENCRYPT), - &req->base); + return mtk_aes_handle_queue(cryp, enc, &req->base); } /* @@ -1003,10 +1073,8 @@ static int mtk_aes_gcm_setkey(struct crypto_aead *aead, const u8 *key, if (err) goto out; - /* Write key into state buffer */ - mtk_aes_write_state_le(ctx->info.state, (const u32 *)key, keylen); - /* Write key(H) into state buffer */ - mtk_aes_write_state_be(ctx->info.state + ctx->keylen, data->hash, + mtk_aes_write_state_le(ctx->key, (const u32 *)key, keylen); + mtk_aes_write_state_be(ctx->key + ctx->keylen, data->hash, AES_BLOCK_SIZE); out: kzfree(data); @@ -1046,13 +1114,6 @@ static int mtk_aes_gcm_decrypt(struct aead_request *req) static int mtk_aes_gcm_init(struct crypto_aead *aead) { struct mtk_aes_gcm_ctx *ctx = crypto_aead_ctx(aead); - struct mtk_cryp *cryp = NULL; - - cryp = mtk_aes_find_dev(&ctx->base); - if (!cryp) { - pr_err("can't find crypto device\n"); - return -ENODEV; - } ctx->ctr = crypto_alloc_skcipher("ctr(aes)", 0, CRYPTO_ALG_ASYNC); diff --git a/drivers/crypto/mediatek/mtk-platform.c b/drivers/crypto/mediatek/mtk-platform.c index 125318a88cd4edca93dacb5e2f9db3934c355553..7e3ad085b5bdd2b9c213789c18fa8df46d7f85ae 100644 --- a/drivers/crypto/mediatek/mtk-platform.c +++ b/drivers/crypto/mediatek/mtk-platform.c @@ -481,7 +481,6 @@ static int mtk_desc_ring_alloc(struct mtk_cryp *cryp) static int mtk_crypto_probe(struct platform_device *pdev) { - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct mtk_cryp *cryp; int i, err; @@ -489,16 +488,14 @@ static int mtk_crypto_probe(struct platform_device *pdev) if (!cryp) return -ENOMEM; - cryp->base = devm_ioremap_resource(&pdev->dev, res); + cryp->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(cryp->base)) return PTR_ERR(cryp->base); for (i = 0; i < MTK_IRQ_NUM; i++) { cryp->irq[i] = platform_get_irq(pdev, i); - if (cryp->irq[i] < 0) { - dev_err(cryp->dev, "no IRQ:%d resource info\n", i); + if (cryp->irq[i] < 0) return cryp->irq[i]; - } } cryp->clk_cryp = devm_clk_get(&pdev->dev, "cryp"); diff --git a/drivers/crypto/mediatek/mtk-sha.c b/drivers/crypto/mediatek/mtk-sha.c index f03b0f06fb2fb4efb25eeea8e58c679cfbd788c2..9e9f48bb7f850b9c560ae58f55f3ca418db9e80c 100644 --- a/drivers/crypto/mediatek/mtk-sha.c +++ b/drivers/crypto/mediatek/mtk-sha.c @@ -778,7 +778,9 @@ static int mtk_sha_finup(struct ahash_request *req) ctx->flags |= SHA_FLAGS_FINUP; err1 = mtk_sha_update(req); - if (err1 == -EINPROGRESS || err1 == -EBUSY) + if (err1 == -EINPROGRESS || + (err1 == -EBUSY && (ahash_request_flags(req) & + CRYPTO_TFM_REQ_MAY_BACKLOG))) return err1; /* * final() has to be always called to cleanup resources diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index f1fa637cb029d0b234fd1c025e57633b83108092..bf8d2197bc11e98c3363b4acfc4380f233295063 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -994,16 +994,12 @@ static int mxs_dcp_probe(struct platform_device *pdev) } dcp_vmi_irq = platform_get_irq(pdev, 0); - if (dcp_vmi_irq < 0) { - dev_err(dev, "Failed to get IRQ: (%d)!\n", dcp_vmi_irq); + if (dcp_vmi_irq < 0) return dcp_vmi_irq; - } dcp_irq = platform_get_irq(pdev, 1); - if (dcp_irq < 0) { - dev_err(dev, "Failed to get IRQ: (%d)!\n", dcp_irq); + if (dcp_irq < 0) return dcp_irq; - } sdcp = devm_kzalloc(dev, sizeof(*sdcp), GFP_KERNEL); if (!sdcp) diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 760e72a5893b708d26a1ed4cfcddea60d8c6009f..dc15b06e96ab786a57d37a1f5647c98f6c8b14ca 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -760,21 +760,13 @@ static int n2_des_setkey(struct crypto_ablkcipher *cipher, const u8 *key, struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); struct n2_cipher_context *ctx = crypto_tfm_ctx(tfm); struct n2_cipher_alg *n2alg = n2_cipher_alg(tfm); - u32 tmp[DES_EXPKEY_WORDS]; int err; - ctx->enc_type = n2alg->enc_type; - - if (keylen != DES_KEY_SIZE) { - crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } + err = verify_ablkcipher_des_key(cipher, key); + if (err) + return err; - err = des_ekey(tmp, key); - if (err == 0 && (tfm->crt_flags & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) { - tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; - return -EINVAL; - } + ctx->enc_type = n2alg->enc_type; ctx->key_len = keylen; memcpy(ctx->key.des, key, keylen); @@ -787,15 +779,11 @@ static int n2_3des_setkey(struct crypto_ablkcipher *cipher, const u8 *key, struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); struct n2_cipher_context *ctx = crypto_tfm_ctx(tfm); struct n2_cipher_alg *n2alg = n2_cipher_alg(tfm); - u32 flags; int err; - flags = crypto_ablkcipher_get_flags(cipher); - err = __des3_verify_key(&flags, key); - if (unlikely(err)) { - crypto_ablkcipher_set_flags(cipher, flags); + err = verify_ablkcipher_des3_key(cipher, key); + if (err) return err; - } ctx->enc_type = n2alg->enc_type; @@ -1295,20 +1283,20 @@ struct n2_hash_tmpl { u8 hmac_type; }; -static const u32 md5_init[MD5_HASH_WORDS] = { +static const u32 n2_md5_init[MD5_HASH_WORDS] = { cpu_to_le32(MD5_H0), cpu_to_le32(MD5_H1), cpu_to_le32(MD5_H2), cpu_to_le32(MD5_H3), }; -static const u32 sha1_init[SHA1_DIGEST_SIZE / 4] = { +static const u32 n2_sha1_init[SHA1_DIGEST_SIZE / 4] = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4, }; -static const u32 sha256_init[SHA256_DIGEST_SIZE / 4] = { +static const u32 n2_sha256_init[SHA256_DIGEST_SIZE / 4] = { SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3, SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7, }; -static const u32 sha224_init[SHA256_DIGEST_SIZE / 4] = { +static const u32 n2_sha224_init[SHA256_DIGEST_SIZE / 4] = { SHA224_H0, SHA224_H1, SHA224_H2, SHA224_H3, SHA224_H4, SHA224_H5, SHA224_H6, SHA224_H7, }; @@ -1316,7 +1304,7 @@ static const u32 sha224_init[SHA256_DIGEST_SIZE / 4] = { static const struct n2_hash_tmpl hash_tmpls[] = { { .name = "md5", .hash_zero = md5_zero_message_hash, - .hash_init = md5_init, + .hash_init = n2_md5_init, .auth_type = AUTH_TYPE_MD5, .hmac_type = AUTH_TYPE_HMAC_MD5, .hw_op_hashsz = MD5_DIGEST_SIZE, @@ -1324,7 +1312,7 @@ static const struct n2_hash_tmpl hash_tmpls[] = { .block_size = MD5_HMAC_BLOCK_SIZE }, { .name = "sha1", .hash_zero = sha1_zero_message_hash, - .hash_init = sha1_init, + .hash_init = n2_sha1_init, .auth_type = AUTH_TYPE_SHA1, .hmac_type = AUTH_TYPE_HMAC_SHA1, .hw_op_hashsz = SHA1_DIGEST_SIZE, @@ -1332,7 +1320,7 @@ static const struct n2_hash_tmpl hash_tmpls[] = { .block_size = SHA1_BLOCK_SIZE }, { .name = "sha256", .hash_zero = sha256_zero_message_hash, - .hash_init = sha256_init, + .hash_init = n2_sha256_init, .auth_type = AUTH_TYPE_SHA256, .hmac_type = AUTH_TYPE_HMAC_SHA256, .hw_op_hashsz = SHA256_DIGEST_SIZE, @@ -1340,7 +1328,7 @@ static const struct n2_hash_tmpl hash_tmpls[] = { .block_size = SHA256_BLOCK_SIZE }, { .name = "sha224", .hash_zero = sha224_zero_message_hash, - .hash_init = sha224_init, + .hash_init = n2_sha224_init, .auth_type = AUTH_TYPE_SHA256, .hmac_type = AUTH_TYPE_RESERVED, .hw_op_hashsz = SHA256_DIGEST_SIZE, diff --git a/drivers/crypto/nx/nx-842-powernv.c b/drivers/crypto/nx/nx-842-powernv.c index e78ff5c65ed6ca8b4ddc5b6d319902101c06fc65..c037a2403b82c369c2c7558af5d49242ea46afbc 100644 --- a/drivers/crypto/nx/nx-842-powernv.c +++ b/drivers/crypto/nx/nx-842-powernv.c @@ -1020,6 +1020,7 @@ static __init int nx842_powernv_init(void) ret = nx842_powernv_probe_vas(dn); if (ret) { nx842_delete_coprocs(); + of_node_put(dn); return ret; } } diff --git a/drivers/crypto/nx/nx.h b/drivers/crypto/nx/nx.h index c6b5a3be02be604e6eeb554944bfdb6baf995ce1..7ecca168f8c48b6998d958ceea23d6604786a622 100644 --- a/drivers/crypto/nx/nx.h +++ b/drivers/crypto/nx/nx.h @@ -9,9 +9,6 @@ #define NX_STRING "IBM Power7+ Nest Accelerator Crypto Driver" #define NX_VERSION "1.0" -static const char nx_driver_string[] = NX_STRING; -static const char nx_driver_version[] = NX_VERSION; - /* a scatterlist in the format PHYP is expecting */ struct nx_sg { u64 addr; diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 45a4647f7030ac88d3974a092ae912c96046c55c..2f53fbb7410010b8eca1cdcbfd5b70c9db2de58d 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -1180,7 +1180,6 @@ static int omap_aes_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(dev, "can't get IRQ resource\n"); err = irq; goto err_irq; } diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c index 1ee69a97967767c022bd1011651099051536a5f2..b19d7e5d55ecd9ea0a3d97180001cca43e5e63ca 100644 --- a/drivers/crypto/omap-des.c +++ b/drivers/crypto/omap-des.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include @@ -650,20 +650,13 @@ static int omap_des_setkey(struct crypto_ablkcipher *cipher, const u8 *key, unsigned int keylen) { struct omap_des_ctx *ctx = crypto_ablkcipher_ctx(cipher); - struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); + int err; pr_debug("enter, keylen: %d\n", keylen); - /* Do we need to test against weak key? */ - if (tfm->crt_flags & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS) { - u32 tmp[DES_EXPKEY_WORDS]; - int ret = des_ekey(tmp, key); - - if (!ret) { - tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; - return -EINVAL; - } - } + err = verify_ablkcipher_des_key(cipher, key); + if (err) + return err; memcpy(ctx->key, key, keylen); ctx->keylen = keylen; @@ -672,20 +665,16 @@ static int omap_des_setkey(struct crypto_ablkcipher *cipher, const u8 *key, } static int omap_des3_setkey(struct crypto_ablkcipher *cipher, const u8 *key, - unsigned int keylen) + unsigned int keylen) { struct omap_des_ctx *ctx = crypto_ablkcipher_ctx(cipher); - u32 flags; int err; pr_debug("enter, keylen: %d\n", keylen); - flags = crypto_ablkcipher_get_flags(cipher); - err = __des3_verify_key(&flags, key); - if (unlikely(err)) { - crypto_ablkcipher_set_flags(cipher, flags); + err = verify_ablkcipher_des3_key(cipher, key); + if (err) return err; - } memcpy(ctx->key, key, keylen); ctx->keylen = keylen; @@ -1049,7 +1038,6 @@ static int omap_des_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(dev, "can't get IRQ resource: %d\n", irq); err = irq; goto err_irq; } diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index e8e2907bd9f40f28e8c7b6f4d24e88088631e70f..ac80bc6af093059565ac03960dba01f1ef92e91b 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -1989,7 +1989,6 @@ static int omap_sham_get_res_pdev(struct omap_sham_dev *dd, /* Get the IRQ */ dd->irq = platform_get_irq(pdev, 0); if (dd->irq < 0) { - dev_err(dev, "no IRQ resource info\n"); err = dd->irq; goto err; } diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index ad020133da199bc0c2a4204023891f3b8808d538..8a066125007835dd7a281dec26576e1e4823fa5b 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -145,7 +145,7 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, ctx->cword.encrypt.keygen = 1; ctx->cword.decrypt.keygen = 1; - if (crypto_aes_expand_key(&gen_aes, in_key, key_len)) { + if (aes_expandkey(&gen_aes, in_key, key_len)) { *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; return -EINVAL; } @@ -300,7 +300,7 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, return iv; } -static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +static void padlock_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct aes_ctx *ctx = aes_ctx(tfm); @@ -309,7 +309,7 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) padlock_store_cword(&ctx->cword.encrypt); } -static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +static void padlock_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct aes_ctx *ctx = aes_ctx(tfm); @@ -332,8 +332,8 @@ static struct crypto_alg aes_alg = { .cia_min_keysize = AES_MIN_KEY_SIZE, .cia_max_keysize = AES_MAX_KEY_SIZE, .cia_setkey = aes_set_key, - .cia_encrypt = aes_encrypt, - .cia_decrypt = aes_decrypt, + .cia_encrypt = padlock_aes_encrypt, + .cia_decrypt = padlock_aes_decrypt, } } }; diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c index b985cb85c9bcf257cb70b89989494e9e4fd356ac..3cbefb41b099c1d87da5dc55466e1ab2dfce6ce9 100644 --- a/drivers/crypto/picoxcell_crypto.c +++ b/drivers/crypto/picoxcell_crypto.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include @@ -736,16 +736,12 @@ static void spacc_aead_cra_exit(struct crypto_aead *tfm) static int spacc_des_setkey(struct crypto_ablkcipher *cipher, const u8 *key, unsigned int len) { - struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); - struct spacc_ablk_ctx *ctx = crypto_tfm_ctx(tfm); - u32 tmp[DES_EXPKEY_WORDS]; + struct spacc_ablk_ctx *ctx = crypto_ablkcipher_ctx(cipher); + int err; - if (unlikely(!des_ekey(tmp, key)) && - (crypto_ablkcipher_get_flags(cipher) & - CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) { - tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; - return -EINVAL; - } + err = verify_ablkcipher_des_key(cipher, key); + if (err) + return err; memcpy(ctx->key, key, len); ctx->key_len = len; @@ -761,15 +757,11 @@ static int spacc_des3_setkey(struct crypto_ablkcipher *cipher, const u8 *key, unsigned int len) { struct spacc_ablk_ctx *ctx = crypto_ablkcipher_ctx(cipher); - u32 flags; int err; - flags = crypto_ablkcipher_get_flags(cipher); - err = __des3_verify_key(&flags, key); - if (unlikely(err)) { - crypto_ablkcipher_set_flags(cipher, flags); + err = verify_ablkcipher_des3_key(cipher, key); + if (err) return err; - } memcpy(ctx->key, key, len); ctx->key_len = len; @@ -1624,7 +1616,7 @@ MODULE_DEVICE_TABLE(of, spacc_of_id_table); static int spacc_probe(struct platform_device *pdev) { int i, err, ret; - struct resource *mem, *irq; + struct resource *irq; struct device_node *np = pdev->dev.of_node; struct spacc_engine *engine = devm_kzalloc(&pdev->dev, sizeof(*engine), GFP_KERNEL); @@ -1653,8 +1645,7 @@ static int spacc_probe(struct platform_device *pdev) engine->name = dev_name(&pdev->dev); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - engine->regs = devm_ioremap_resource(&pdev->dev, mem); + engine->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(engine->regs)) return PTR_ERR(engine->regs); diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index 5c4c0a2531296a157ae146f19226d9d8f608830f..d78f8d5c89c3fe4f6906fca888ca4bc192255ef4 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -95,7 +95,7 @@ struct service_hndl { static inline int get_current_node(void) { - return topology_physical_package_id(smp_processor_id()); + return topology_physical_package_id(raw_smp_processor_id()); } int adf_service_register(struct service_hndl *service); diff --git a/drivers/crypto/qce/ablkcipher.c b/drivers/crypto/qce/ablkcipher.c index a976210ba41cfbac30190be9b48c251b83140b28..7a98bf5cc9672ab26e7a3e0048aced98a844febf 100644 --- a/drivers/crypto/qce/ablkcipher.c +++ b/drivers/crypto/qce/ablkcipher.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include "cipher.h" @@ -154,27 +154,17 @@ static int qce_ablkcipher_setkey(struct crypto_ablkcipher *ablk, const u8 *key, { struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablk); struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm); - unsigned long flags = to_cipher_tmpl(tfm)->alg_flags; int ret; if (!key || !keylen) return -EINVAL; - if (IS_AES(flags)) { - switch (keylen) { - case AES_KEYSIZE_128: - case AES_KEYSIZE_256: - break; - default: - goto fallback; - } - } else if (IS_DES(flags)) { - u32 tmp[DES_EXPKEY_WORDS]; - - ret = des_ekey(tmp, key); - if (!ret && (crypto_ablkcipher_get_flags(ablk) & - CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) - goto weakkey; + switch (keylen) { + case AES_KEYSIZE_128: + case AES_KEYSIZE_256: + break; + default: + goto fallback; } ctx->enc_keylen = keylen; @@ -185,24 +175,32 @@ static int qce_ablkcipher_setkey(struct crypto_ablkcipher *ablk, const u8 *key, if (!ret) ctx->enc_keylen = keylen; return ret; -weakkey: - crypto_ablkcipher_set_flags(ablk, CRYPTO_TFM_RES_WEAK_KEY); - return -EINVAL; +} + +static int qce_des_setkey(struct crypto_ablkcipher *ablk, const u8 *key, + unsigned int keylen) +{ + struct qce_cipher_ctx *ctx = crypto_ablkcipher_ctx(ablk); + int err; + + err = verify_ablkcipher_des_key(ablk, key); + if (err) + return err; + + ctx->enc_keylen = keylen; + memcpy(ctx->enc_key, key, keylen); + return 0; } static int qce_des3_setkey(struct crypto_ablkcipher *ablk, const u8 *key, unsigned int keylen) { struct qce_cipher_ctx *ctx = crypto_ablkcipher_ctx(ablk); - u32 flags; int err; - flags = crypto_ablkcipher_get_flags(ablk); - err = __des3_verify_key(&flags, key); - if (unlikely(err)) { - crypto_ablkcipher_set_flags(ablk, flags); + err = verify_ablkcipher_des3_key(ablk, key); + if (err) return err; - } ctx->enc_keylen = keylen; memcpy(ctx->enc_key, key, keylen); @@ -374,8 +372,9 @@ static int qce_ablkcipher_register_one(const struct qce_ablkcipher_def *def, alg->cra_ablkcipher.ivsize = def->ivsize; alg->cra_ablkcipher.min_keysize = def->min_keysize; alg->cra_ablkcipher.max_keysize = def->max_keysize; - alg->cra_ablkcipher.setkey = IS_3DES(def->flags) ? - qce_des3_setkey : qce_ablkcipher_setkey; + alg->cra_ablkcipher.setkey = IS_3DES(def->flags) ? qce_des3_setkey : + IS_DES(def->flags) ? qce_des_setkey : + qce_ablkcipher_setkey; alg->cra_ablkcipher.encrypt = qce_ablkcipher_encrypt; alg->cra_ablkcipher.decrypt = qce_ablkcipher_decrypt; diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c index ef1d74e8ddb26061a12069e1143e067d17a85934..08d4ce3bfddfd8bee1f6236b313f1f53f1fad396 100644 --- a/drivers/crypto/qce/core.c +++ b/drivers/crypto/qce/core.c @@ -167,7 +167,6 @@ static int qce_crypto_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct qce_device *qce; - struct resource *res; int ret; qce = devm_kzalloc(dev, sizeof(*qce), GFP_KERNEL); @@ -177,8 +176,7 @@ static int qce_crypto_probe(struct platform_device *pdev) qce->dev = dev; platform_set_drvdata(pdev, qce); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - qce->base = devm_ioremap_resource(&pdev->dev, res); + qce->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(qce->base)) return PTR_ERR(qce->base); diff --git a/drivers/crypto/qcom-rng.c b/drivers/crypto/qcom-rng.c index e54249ccc009202973fcbaf4635ac563ab174cbf..4730f84b646dee0dae99bb3378352c4a529840ac 100644 --- a/drivers/crypto/qcom-rng.c +++ b/drivers/crypto/qcom-rng.c @@ -153,7 +153,6 @@ static struct rng_alg qcom_rng_alg = { static int qcom_rng_probe(struct platform_device *pdev) { - struct resource *res; struct qcom_rng *rng; int ret; @@ -164,8 +163,7 @@ static int qcom_rng_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rng); mutex_init(&rng->lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - rng->base = devm_ioremap_resource(&pdev->dev, res); + rng->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(rng->base)) return PTR_ERR(rng->base); diff --git a/drivers/crypto/rockchip/rk3288_crypto.c b/drivers/crypto/rockchip/rk3288_crypto.c index 8d7e2545e65aa0a00a6ae1b5ed34d8005d275844..e5714ef24bf2abb2b382404ea9468630ee988dd7 100644 --- a/drivers/crypto/rockchip/rk3288_crypto.c +++ b/drivers/crypto/rockchip/rk3288_crypto.c @@ -311,7 +311,6 @@ MODULE_DEVICE_TABLE(of, crypto_of_id_table); static int rk_crypto_probe(struct platform_device *pdev) { - struct resource *res; struct device *dev = &pdev->dev; struct rk_crypto_info *crypto_info; int err = 0; @@ -339,8 +338,7 @@ static int rk_crypto_probe(struct platform_device *pdev) spin_lock_init(&crypto_info->lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - crypto_info->reg = devm_ioremap_resource(&pdev->dev, res); + crypto_info->reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(crypto_info->reg)) { err = PTR_ERR(crypto_info->reg); goto err_crypto; diff --git a/drivers/crypto/rockchip/rk3288_crypto.h b/drivers/crypto/rockchip/rk3288_crypto.h index 54ee5b3ed9db8d23b13c0f34dc82d146503ec491..18e2b3f2933631e8dcc7b93e3d106f78e17b18e7 100644 --- a/drivers/crypto/rockchip/rk3288_crypto.h +++ b/drivers/crypto/rockchip/rk3288_crypto.h @@ -3,7 +3,7 @@ #define __RK3288_CRYPTO_H__ #include -#include +#include #include #include #include diff --git a/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c b/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c index 96078aaa209832dc85d55612af4d36af9df5d431..d0f4b2d180592e8c7f9cff5976e70cbf29bf8f54 100644 --- a/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c +++ b/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c @@ -46,15 +46,12 @@ static int rk_aes_setkey(struct crypto_ablkcipher *cipher, static int rk_des_setkey(struct crypto_ablkcipher *cipher, const u8 *key, unsigned int keylen) { - struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); - struct rk_cipher_ctx *ctx = crypto_tfm_ctx(tfm); - u32 tmp[DES_EXPKEY_WORDS]; + struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(cipher); + int err; - if (!des_ekey(tmp, key) && - (tfm->crt_flags & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) { - tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; - return -EINVAL; - } + err = verify_ablkcipher_des_key(cipher, key); + if (err) + return err; ctx->keylen = keylen; memcpy_toio(ctx->dev->reg + RK_CRYPTO_TDES_KEY1_0, key, keylen); @@ -65,15 +62,11 @@ static int rk_tdes_setkey(struct crypto_ablkcipher *cipher, const u8 *key, unsigned int keylen) { struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(cipher); - u32 flags; int err; - flags = crypto_ablkcipher_get_flags(cipher); - err = __des3_verify_key(&flags, key); - if (unlikely(err)) { - crypto_ablkcipher_set_flags(cipher, flags); + err = verify_ablkcipher_des3_key(cipher, key); + if (err) return err; - } ctx->keylen = keylen; memcpy_toio(ctx->dev->reg + RK_CRYPTO_TDES_KEY1_0, key, keylen); diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 9ef25230c1995400de4149cf8b91989e0e933d56..010f1bb20dadae833e7388c3360eee215d53eb99 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -2056,9 +2056,12 @@ static int s5p_aes_crypt(struct ablkcipher_request *req, unsigned long mode) struct s5p_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); struct s5p_aes_dev *dev = ctx->dev; + if (!req->nbytes) + return 0; + if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE) && ((mode & FLAGS_AES_MODE_MASK) != FLAGS_AES_CTR)) { - dev_err(dev->dev, "request size is not exact amount of AES blocks\n"); + dev_dbg(dev->dev, "request size is not exact amount of AES blocks\n"); return -EINVAL; } @@ -2170,7 +2173,7 @@ static struct crypto_alg algs[] = { .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = AES_BLOCK_SIZE, + .cra_blocksize = 1, .cra_ctxsize = sizeof(struct s5p_aes_ctx), .cra_alignmask = 0x0f, .cra_type = &crypto_ablkcipher_type, diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index b0b8e3d48aef1c7fc9bed475d9eadec929152614..8ac8ec6decd533ecdc1d527703890ca32198e592 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -1403,10 +1403,8 @@ static int sahara_probe(struct platform_device *pdev) /* Get the IRQ */ irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "failed to get irq resource\n"); + if (irq < 0) return irq; - } err = devm_request_irq(&pdev->dev, irq, sahara_irq_handler, 0, dev_name(&pdev->dev), dev); diff --git a/drivers/crypto/stm32/Kconfig b/drivers/crypto/stm32/Kconfig index d6576280fc9bbb3706d6fce54cd3f9f646e6ef8e..1aba9372cd232515bd34857467d653508ecfa1a0 100644 --- a/drivers/crypto/stm32/Kconfig +++ b/drivers/crypto/stm32/Kconfig @@ -25,7 +25,7 @@ config CRYPTO_DEV_STM32_CRYP depends on ARCH_STM32 select CRYPTO_HASH select CRYPTO_ENGINE - select CRYPTO_DES + select CRYPTO_LIB_DES help This enables support for the CRYP (AES/DES/TDES) hw accelerator which can be found on STMicroelectronics STM32 SOC. diff --git a/drivers/crypto/stm32/stm32-crc32.c b/drivers/crypto/stm32/stm32-crc32.c index 440c9f1bd006619efdffbf479f9bb46f70caa235..9e11c3480353ff23d4c1c5a2e86d0568141200db 100644 --- a/drivers/crypto/stm32/stm32-crc32.c +++ b/drivers/crypto/stm32/stm32-crc32.c @@ -255,7 +255,6 @@ static int stm32_crc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct stm32_crc *crc; - struct resource *res; int ret; crc = devm_kzalloc(dev, sizeof(*crc), GFP_KERNEL); @@ -264,8 +263,7 @@ static int stm32_crc_probe(struct platform_device *pdev) crc->dev = dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - crc->regs = devm_ioremap_resource(dev, res); + crc->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(crc->regs)) { dev_err(dev, "Cannot map CRC IO\n"); return PTR_ERR(crc->regs); diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c index 98ae02826e8fb9b6f5dd5d7ce26376f168358149..ba5ea6434f9cac93d3af878fda193070006394ba 100644 --- a/drivers/crypto/stm32/stm32-cryp.c +++ b/drivers/crypto/stm32/stm32-cryp.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include @@ -767,35 +767,15 @@ static int stm32_cryp_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, static int stm32_cryp_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int keylen) { - u32 tmp[DES_EXPKEY_WORDS]; - - if (keylen != DES_KEY_SIZE) - return -EINVAL; - - if ((crypto_ablkcipher_get_flags(tfm) & - CRYPTO_TFM_REQ_FORBID_WEAK_KEYS) && - unlikely(!des_ekey(tmp, key))) { - crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_WEAK_KEY); - return -EINVAL; - } - - return stm32_cryp_setkey(tfm, key, keylen); + return verify_ablkcipher_des_key(tfm, key) ?: + stm32_cryp_setkey(tfm, key, keylen); } static int stm32_cryp_tdes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int keylen) { - u32 flags; - int err; - - flags = crypto_ablkcipher_get_flags(tfm); - err = __des3_verify_key(&flags, key); - if (unlikely(err)) { - crypto_ablkcipher_set_flags(tfm, flags); - return err; - } - - return stm32_cryp_setkey(tfm, key, keylen); + return verify_ablkcipher_des3_key(tfm, key) ?: + stm32_cryp_setkey(tfm, key, keylen); } static int stm32_cryp_aes_aead_setkey(struct crypto_aead *tfm, const u8 *key, @@ -1955,7 +1935,6 @@ static int stm32_cryp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct stm32_cryp *cryp; - struct resource *res; struct reset_control *rst; int irq, ret; @@ -1969,16 +1948,13 @@ static int stm32_cryp_probe(struct platform_device *pdev) cryp->dev = dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - cryp->regs = devm_ioremap_resource(dev, res); + cryp->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(cryp->regs)) return PTR_ERR(cryp->regs); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "Cannot get IRQ resource\n"); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(dev, irq, stm32_cryp_irq, stm32_cryp_irq_thread, IRQF_ONESHOT, diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c index 2b70d8796f25b5884920b8708760963e89503d42..cfc8e0e37beec8f1ece81ba9d891fc5a9efb0118 100644 --- a/drivers/crypto/stm32/stm32-hash.c +++ b/drivers/crypto/stm32/stm32-hash.c @@ -1450,10 +1450,8 @@ static int stm32_hash_probe(struct platform_device *pdev) return ret; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "Cannot get IRQ resource\n"); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(dev, irq, stm32_hash_irq_handler, stm32_hash_irq_thread, IRQF_ONESHOT, diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c index 6f7cbf6c2b550a156bb1fb4728a80ba2ec862969..6536fd4bee6578269d09b3b8998af24799783412 100644 --- a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c +++ b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c @@ -542,25 +542,11 @@ int sun4i_ss_des_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen) { struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); - struct sun4i_ss_ctx *ss = op->ss; - u32 flags; - u32 tmp[DES_EXPKEY_WORDS]; - int ret; - - if (unlikely(keylen != DES_KEY_SIZE)) { - dev_err(ss->dev, "Invalid keylen %u\n", keylen); - crypto_skcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - flags = crypto_skcipher_get_flags(tfm); + int err; - ret = des_ekey(tmp, key); - if (unlikely(!ret) && (flags & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) { - crypto_skcipher_set_flags(tfm, CRYPTO_TFM_RES_WEAK_KEY); - dev_dbg(ss->dev, "Weak key %u\n", keylen); - return -EINVAL; - } + err = verify_skcipher_des_key(tfm, key); + if (err) + return err; op->keylen = keylen; memcpy(op->key, key, keylen); @@ -578,8 +564,8 @@ int sun4i_ss_des3_setkey(struct crypto_skcipher *tfm, const u8 *key, struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); int err; - err = des3_verify_key(tfm, key); - if (unlikely(err)) + err = verify_skcipher_des3_key(tfm, key); + if (err) return err; op->keylen = keylen; diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-core.c b/drivers/crypto/sunxi-ss/sun4i-ss-core.c index 2e8704271f45c25ade649e4e2d32c94c38916319..9aa6fe081a2743406fdcf16d6d9dc253ffd56dee 100644 --- a/drivers/crypto/sunxi-ss/sun4i-ss-core.c +++ b/drivers/crypto/sunxi-ss/sun4i-ss-core.c @@ -225,7 +225,6 @@ static struct sun4i_ss_alg_template ss_algs[] = { static int sun4i_ss_probe(struct platform_device *pdev) { - struct resource *res; u32 v; int err, i; unsigned long cr; @@ -240,8 +239,7 @@ static int sun4i_ss_probe(struct platform_device *pdev) if (!ss) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ss->base = devm_ioremap_resource(&pdev->dev, res); + ss->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ss->base)) { dev_err(&pdev->dev, "Cannot request MMIO\n"); return PTR_ERR(ss->base); diff --git a/drivers/crypto/sunxi-ss/sun4i-ss.h b/drivers/crypto/sunxi-ss/sun4i-ss.h index 8654d48aedc0add7e755e168575bd57d30c4b4c9..35a27a7145f84cff0fc38d75bc8c0c69758589d2 100644 --- a/drivers/crypto/sunxi-ss/sun4i-ss.h +++ b/drivers/crypto/sunxi-ss/sun4i-ss.h @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index c9d686a0e8056a123b6bd3136e8436b82ada089b..cb6c10b1bf36a25bff207cafa3e711e6663ba285 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include #include @@ -925,7 +925,6 @@ static int aead_des3_setkey(struct crypto_aead *authenc, struct talitos_ctx *ctx = crypto_aead_ctx(authenc); struct device *dev = ctx->dev; struct crypto_authenc_keys keys; - u32 flags; int err; err = crypto_authenc_extractkeys(&keys, key, keylen); @@ -936,15 +935,9 @@ static int aead_des3_setkey(struct crypto_aead *authenc, if (keys.authkeylen + keys.enckeylen > TALITOS_MAX_KEY_SIZE) goto badkey; - if (keys.enckeylen != DES3_EDE_KEY_SIZE) - goto badkey; - - flags = crypto_aead_get_flags(authenc); - err = __des3_verify_key(&flags, keys.enckey); - if (unlikely(err)) { - crypto_aead_set_flags(authenc, flags); + err = verify_aead_des3_key(authenc, keys.enckey, keys.enckeylen); + if (err) goto out; - } if (ctx->keylen) dma_unmap_single(dev, ctx->dma_key, ctx->keylen, DMA_TO_DEVICE); @@ -1517,32 +1510,15 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *cipher, static int ablkcipher_des_setkey(struct crypto_ablkcipher *cipher, const u8 *key, unsigned int keylen) { - u32 tmp[DES_EXPKEY_WORDS]; - - if (unlikely(crypto_ablkcipher_get_flags(cipher) & - CRYPTO_TFM_REQ_FORBID_WEAK_KEYS) && - !des_ekey(tmp, key)) { - crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_WEAK_KEY); - return -EINVAL; - } - - return ablkcipher_setkey(cipher, key, keylen); + return verify_ablkcipher_des_key(cipher, key) ?: + ablkcipher_setkey(cipher, key, keylen); } static int ablkcipher_des3_setkey(struct crypto_ablkcipher *cipher, const u8 *key, unsigned int keylen) { - u32 flags; - int err; - - flags = crypto_ablkcipher_get_flags(cipher); - err = __des3_verify_key(&flags, key); - if (unlikely(err)) { - crypto_ablkcipher_set_flags(cipher, flags); - return err; - } - - return ablkcipher_setkey(cipher, key, keylen); + return verify_ablkcipher_des3_key(cipher, key) ?: + ablkcipher_setkey(cipher, key, keylen); } static int ablkcipher_aes_setkey(struct crypto_ablkcipher *cipher, diff --git a/drivers/crypto/ux500/Kconfig b/drivers/crypto/ux500/Kconfig index 349d34eaac13982fdd865696ce4bc552b5006e79..b1c6f739f77b7dbc09a4de6f530106ae02f4e6da 100644 --- a/drivers/crypto/ux500/Kconfig +++ b/drivers/crypto/ux500/Kconfig @@ -9,7 +9,7 @@ config CRYPTO_DEV_UX500_CRYP depends on CRYPTO_DEV_UX500 select CRYPTO_ALGAPI select CRYPTO_BLKCIPHER - select CRYPTO_DES + select CRYPTO_LIB_DES help This selects the crypto driver for the UX500_CRYP hardware. It supports AES-ECB, CBC and CTR with keys sizes of 128, 192 and 256 bit sizes. diff --git a/drivers/crypto/ux500/cryp/cryp.h b/drivers/crypto/ux500/cryp/cryp.h index bd89504e816787d062a210c077195e376dceb406..8da7f87b339b4785edece0bcfde305a0f96ffb01 100644 --- a/drivers/crypto/ux500/cryp/cryp.h +++ b/drivers/crypto/ux500/cryp/cryp.h @@ -241,12 +241,12 @@ struct cryp_device_data { struct clk *clk; struct regulator *pwr_regulator; int power_status; - struct spinlock ctx_lock; + spinlock_t ctx_lock; struct cryp_ctx *current_ctx; struct klist_node list_node; struct cryp_dma dma; bool power_state; - struct spinlock power_state_spinlock; + spinlock_t power_state_spinlock; bool restore_dev_ctx; }; diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c index b4beb54c0dbea201a3e80628e6958b35a3fec7fb..1628ae7a14677210b99f2ac33dcb6021da63638b 100644 --- a/drivers/crypto/ux500/cryp/cryp_core.c +++ b/drivers/crypto/ux500/cryp/cryp_core.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include @@ -528,9 +528,9 @@ static int cryp_set_dma_transfer(struct cryp_ctx *ctx, dev_dbg(ctx->device->dev, "[%s]: ", __func__); - if (unlikely(!IS_ALIGNED((u32)sg, 4))) { + if (unlikely(!IS_ALIGNED((unsigned long)sg, 4))) { dev_err(ctx->device->dev, "[%s]: Data in sg list isn't " - "aligned! Addr: 0x%08x", __func__, (u32)sg); + "aligned! Addr: 0x%08lx", __func__, (unsigned long)sg); return -EFAULT; } @@ -763,9 +763,9 @@ static int hw_crypt_noxts(struct cryp_ctx *ctx, ctx->outlen = ctx->datalen; - if (unlikely(!IS_ALIGNED((u32)indata, 4))) { + if (unlikely(!IS_ALIGNED((unsigned long)indata, 4))) { pr_debug(DEV_DBG_NAME " [%s]: Data isn't aligned! Addr: " - "0x%08x", __func__, (u32)indata); + "0x%08lx", __func__, (unsigned long)indata); return -EINVAL; } @@ -987,26 +987,13 @@ static int des_ablkcipher_setkey(struct crypto_ablkcipher *cipher, const u8 *key, unsigned int keylen) { struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher); - u32 *flags = &cipher->base.crt_flags; - u32 tmp[DES_EXPKEY_WORDS]; - int ret; + int err; pr_debug(DEV_DBG_NAME " [%s]", __func__); - if (keylen != DES_KEY_SIZE) { - *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; - pr_debug(DEV_DBG_NAME " [%s]: CRYPTO_TFM_RES_BAD_KEY_LEN", - __func__); - return -EINVAL; - } - ret = des_ekey(tmp, key); - if (unlikely(ret == 0) && - (*flags & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) { - *flags |= CRYPTO_TFM_RES_WEAK_KEY; - pr_debug(DEV_DBG_NAME " [%s]: CRYPTO_TFM_RES_WEAK_KEY", - __func__); - return -EINVAL; - } + err = verify_ablkcipher_des_key(cipher, key); + if (err) + return err; memcpy(ctx->key, key, keylen); ctx->keylen = keylen; @@ -1019,17 +1006,13 @@ static int des3_ablkcipher_setkey(struct crypto_ablkcipher *cipher, const u8 *key, unsigned int keylen) { struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher); - u32 flags; int err; pr_debug(DEV_DBG_NAME " [%s]", __func__); - flags = crypto_ablkcipher_get_flags(cipher); - err = __des3_verify_key(&flags, key); - if (unlikely(err)) { - crypto_ablkcipher_set_flags(cipher, flags); + err = verify_ablkcipher_des3_key(cipher, key); + if (err) return err; - } memcpy(ctx->key, key, keylen); ctx->keylen = keylen; diff --git a/drivers/crypto/ux500/hash/hash_alg.h b/drivers/crypto/ux500/hash/hash_alg.h index ab2bd00c1c36552c1b3a9500ed4034d6d0db4065..7c9bcc15125ff5ecc289d0de7a41b6b51cee066a 100644 --- a/drivers/crypto/ux500/hash/hash_alg.h +++ b/drivers/crypto/ux500/hash/hash_alg.h @@ -366,10 +366,10 @@ struct hash_device_data { phys_addr_t phybase; struct klist_node list_node; struct device *dev; - struct spinlock ctx_lock; + spinlock_t ctx_lock; struct hash_ctx *current_ctx; bool power_state; - struct spinlock power_state_lock; + spinlock_t power_state_lock; struct regulator *regulator; struct clk *clk; bool restore_dev_state; diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c index f1ebc3dfa21e005d4399a735807c81a35b6714b6..c172a695347777752c4a7fef17ce0cab36534074 100644 --- a/drivers/crypto/ux500/hash/hash_core.c +++ b/drivers/crypto/ux500/hash/hash_core.c @@ -806,7 +806,7 @@ static int hash_process_data(struct hash_device_data *device_data, * HW peripheral, otherwise we first copy data * to a local buffer */ - if ((0 == (((u32)data_buffer) % 4)) && + if (IS_ALIGNED((unsigned long)data_buffer, 4) && (0 == *index)) hash_processblock(device_data, (const u32 *)data_buffer, @@ -864,7 +864,8 @@ static int hash_dma_final(struct ahash_request *req) if (ret) return ret; - dev_dbg(device_data->dev, "%s: (ctx=0x%x)!\n", __func__, (u32) ctx); + dev_dbg(device_data->dev, "%s: (ctx=0x%lx)!\n", __func__, + (unsigned long)ctx); if (req_ctx->updated) { ret = hash_resume_state(device_data, &device_data->state); @@ -969,7 +970,8 @@ static int hash_hw_final(struct ahash_request *req) if (ret) return ret; - dev_dbg(device_data->dev, "%s: (ctx=0x%x)!\n", __func__, (u32) ctx); + dev_dbg(device_data->dev, "%s: (ctx=0x%lx)!\n", __func__, + (unsigned long)ctx); if (req_ctx->updated) { ret = hash_resume_state(device_data, &device_data->state); @@ -1272,8 +1274,8 @@ void hash_get_digest(struct hash_device_data *device_data, else loop_ctr = SHA256_DIGEST_SIZE / sizeof(u32); - dev_dbg(device_data->dev, "%s: digest array:(0x%x)\n", - __func__, (u32) digest); + dev_dbg(device_data->dev, "%s: digest array:(0x%lx)\n", + __func__, (unsigned long)digest); /* Copy result into digest array */ for (count = 0; count < loop_ctr; count++) { diff --git a/drivers/crypto/virtio/virtio_crypto_algs.c b/drivers/crypto/virtio/virtio_crypto_algs.c index 10f266d462d6088e221edd203f9d758ce81efc4b..42d19205166b085e25bee8fd7a1cde5f0a52d941 100644 --- a/drivers/crypto/virtio/virtio_crypto_algs.c +++ b/drivers/crypto/virtio/virtio_crypto_algs.c @@ -129,13 +129,11 @@ static int virtio_crypto_alg_ablkcipher_init_session( * Avoid to do DMA from the stack, switch to using * dynamically-allocated for the key */ - uint8_t *cipher_key = kmalloc(keylen, GFP_ATOMIC); + uint8_t *cipher_key = kmemdup(key, keylen, GFP_ATOMIC); if (!cipher_key) return -ENOMEM; - memcpy(cipher_key, key, keylen); - spin_lock(&vcrypto->ctrl_lock); /* Pad ctrl header */ vcrypto->ctrl.header.opcode = diff --git a/drivers/crypto/vmx/aes_xts.c b/drivers/crypto/vmx/aes_xts.c index 49f7258045fafc55c97cd26dfdf493d3512eb088..d59e736882f617661db73550c2ff623297477a69 100644 --- a/drivers/crypto/vmx/aes_xts.c +++ b/drivers/crypto/vmx/aes_xts.c @@ -84,7 +84,7 @@ static int p8_aes_xts_crypt(struct skcipher_request *req, int enc) u8 tweak[AES_BLOCK_SIZE]; int ret; - if (!crypto_simd_usable()) { + if (!crypto_simd_usable() || (req->cryptlen % XTS_BLOCK_SIZE) != 0) { struct skcipher_request *subreq = skcipher_request_ctx(req); *subreq = *req; diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index ba98a4e3ad3388256b2c61918095d052d8e5c5ed..defe1d4387105e4a4ff368b57d8a0fbcadb9fd61 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -93,15 +93,28 @@ config ARM_EXYNOS_BUS_DEVFREQ This does not yet operate with optimal voltages. config ARM_TEGRA_DEVFREQ - tristate "Tegra DEVFREQ Driver" - depends on ARCH_TEGRA_124_SOC - select DEVFREQ_GOV_SIMPLE_ONDEMAND + tristate "NVIDIA Tegra30/114/124/210 DEVFREQ Driver" + depends on ARCH_TEGRA_3x_SOC || ARCH_TEGRA_114_SOC || \ + ARCH_TEGRA_132_SOC || ARCH_TEGRA_124_SOC || \ + ARCH_TEGRA_210_SOC || \ + COMPILE_TEST select PM_OPP help This adds the DEVFREQ driver for the Tegra family of SoCs. It reads ACTMON counters of memory controllers and adjusts the operating frequencies and voltages with OPP support. +config ARM_TEGRA20_DEVFREQ + tristate "NVIDIA Tegra20 DEVFREQ Driver" + depends on (TEGRA_MC && TEGRA20_EMC) || COMPILE_TEST + depends on COMMON_CLK + select DEVFREQ_GOV_SIMPLE_ONDEMAND + select PM_OPP + help + This adds the DEVFREQ driver for the Tegra20 family of SoCs. + It reads Memory Controller counters and adjusts the operating + frequencies and voltages with OPP support. + config ARM_RK3399_DMC_DEVFREQ tristate "ARM RK3399 DMC DEVFREQ Driver" depends on ARCH_ROCKCHIP diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 32b8d4d3f12c742a56c00ed74618fe9c90172da4..338ae8440db63a82baeb9050d96f74599b9f2bd2 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -10,7 +10,8 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o # DEVFREQ Drivers obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o -obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o +obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o +obj-$(CONFIG_ARM_TEGRA20_DEVFREQ) += tegra20-devfreq.o # DEVFREQ Event Drivers obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/ diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index ab22bf8a12d6955020e64220384e0fa4643e83d8..446490c9d635347d1b36634e4f6895d23e1fff3a 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -254,7 +254,7 @@ static struct devfreq_governor *try_then_request_governor(const char *name) /* Restore previous state before return */ mutex_lock(&devfreq_list_lock); if (err) - return ERR_PTR(err); + return (err < 0) ? ERR_PTR(err) : ERR_PTR(-EINVAL); governor = find_devfreq_governor(name); } @@ -402,7 +402,7 @@ static void devfreq_monitor(struct work_struct *work) * devfreq_monitor_start() - Start load monitoring of devfreq instance * @devfreq: the devfreq instance. * - * Helper function for starting devfreq device load monitoing. By + * Helper function for starting devfreq device load monitoring. By * default delayed work based monitoring is supported. Function * to be called from governor in response to DEVFREQ_GOV_START * event when device is added to devfreq framework. @@ -420,7 +420,7 @@ EXPORT_SYMBOL(devfreq_monitor_start); * devfreq_monitor_stop() - Stop load monitoring of a devfreq instance * @devfreq: the devfreq instance. * - * Helper function to stop devfreq device load monitoing. Function + * Helper function to stop devfreq device load monitoring. Function * to be called from governor in response to DEVFREQ_GOV_STOP * event when device is removed from devfreq framework. */ @@ -434,7 +434,7 @@ EXPORT_SYMBOL(devfreq_monitor_stop); * devfreq_monitor_suspend() - Suspend load monitoring of a devfreq instance * @devfreq: the devfreq instance. * - * Helper function to suspend devfreq device load monitoing. Function + * Helper function to suspend devfreq device load monitoring. Function * to be called from governor in response to DEVFREQ_GOV_SUSPEND * event or when polling interval is set to zero. * @@ -461,7 +461,7 @@ EXPORT_SYMBOL(devfreq_monitor_suspend); * devfreq_monitor_resume() - Resume load monitoring of a devfreq instance * @devfreq: the devfreq instance. * - * Helper function to resume devfreq device load monitoing. Function + * Helper function to resume devfreq device load monitoring. Function * to be called from governor in response to DEVFREQ_GOV_RESUME * event or when polling interval is set to non-zero. */ @@ -867,7 +867,7 @@ EXPORT_SYMBOL_GPL(devfreq_get_devfreq_by_phandle); /** * devm_devfreq_remove_device() - Resource-managed devfreq_remove_device() - * @dev: the device to add devfreq feature. + * @dev: the device from which to remove devfreq feature. * @devfreq: the devfreq instance to be removed */ void devm_devfreq_remove_device(struct device *dev, struct devfreq *devfreq) diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c index 3ee3dd5653aa762ba90b57f1ed4e9145167b8789..87b42055e6bc932013b726b9579680a3ad0067dc 100644 --- a/drivers/devfreq/event/exynos-ppmu.c +++ b/drivers/devfreq/event/exynos-ppmu.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,11 @@ #include "exynos-ppmu.h" +enum exynos_ppmu_type { + EXYNOS_TYPE_PPMU, + EXYNOS_TYPE_PPMU_V2, +}; + struct exynos_ppmu_data { struct clk *clk; }; @@ -33,6 +39,7 @@ struct exynos_ppmu { struct regmap *regmap; struct exynos_ppmu_data ppmu; + enum exynos_ppmu_type ppmu_type; }; #define PPMU_EVENT(name) \ @@ -86,6 +93,12 @@ static struct __exynos_ppmu_events { PPMU_EVENT(d1-cpu), PPMU_EVENT(d1-general), PPMU_EVENT(d1-rt), + + /* For Exynos5422 SoC */ + PPMU_EVENT(dmc0_0), + PPMU_EVENT(dmc0_1), + PPMU_EVENT(dmc1_0), + PPMU_EVENT(dmc1_1), }; static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev) @@ -151,9 +164,9 @@ static int exynos_ppmu_set_event(struct devfreq_event_dev *edev) if (ret < 0) return ret; - /* Set the event of Read/Write data count */ + /* Set the event of proper data type monitoring */ ret = regmap_write(info->regmap, PPMU_BEVTxSEL(id), - PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT); + edev->desc->event_type); if (ret < 0) return ret; @@ -365,23 +378,11 @@ static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev) if (ret < 0) return ret; - /* Set the event of Read/Write data count */ - switch (id) { - case PPMU_PMNCNT0: - case PPMU_PMNCNT1: - case PPMU_PMNCNT2: - ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id), - PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT); - if (ret < 0) - return ret; - break; - case PPMU_PMNCNT3: - ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id), - PPMU_V2_EVT3_RW_DATA_CNT); - if (ret < 0) - return ret; - break; - } + /* Set the event of proper data type monitoring */ + ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id), + edev->desc->event_type); + if (ret < 0) + return ret; /* Reset cycle counter/performance counter and enable PPMU */ ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc); @@ -480,31 +481,24 @@ static const struct devfreq_event_ops exynos_ppmu_v2_ops = { static const struct of_device_id exynos_ppmu_id_match[] = { { .compatible = "samsung,exynos-ppmu", - .data = (void *)&exynos_ppmu_ops, + .data = (void *)EXYNOS_TYPE_PPMU, }, { .compatible = "samsung,exynos-ppmu-v2", - .data = (void *)&exynos_ppmu_v2_ops, + .data = (void *)EXYNOS_TYPE_PPMU_V2, }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, exynos_ppmu_id_match); -static struct devfreq_event_ops *exynos_bus_get_ops(struct device_node *np) -{ - const struct of_device_id *match; - - match = of_match_node(exynos_ppmu_id_match, np); - return (struct devfreq_event_ops *)match->data; -} - static int of_get_devfreq_events(struct device_node *np, struct exynos_ppmu *info) { struct devfreq_event_desc *desc; - struct devfreq_event_ops *event_ops; struct device *dev = info->dev; struct device_node *events_np, *node; int i, j, count; + const struct of_device_id *of_id; + int ret; events_np = of_get_child_by_name(np, "events"); if (!events_np) { @@ -512,7 +506,6 @@ static int of_get_devfreq_events(struct device_node *np, "failed to get child node of devfreq-event devices\n"); return -EINVAL; } - event_ops = exynos_bus_get_ops(np); count = of_get_child_count(events_np); desc = devm_kcalloc(dev, count, sizeof(*desc), GFP_KERNEL); @@ -520,6 +513,12 @@ static int of_get_devfreq_events(struct device_node *np, return -ENOMEM; info->num_events = count; + of_id = of_match_device(exynos_ppmu_id_match, dev); + if (of_id) + info->ppmu_type = (enum exynos_ppmu_type)of_id->data; + else + return -EINVAL; + j = 0; for_each_child_of_node(events_np, node) { for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) { @@ -537,10 +536,51 @@ static int of_get_devfreq_events(struct device_node *np, continue; } - desc[j].ops = event_ops; + switch (info->ppmu_type) { + case EXYNOS_TYPE_PPMU: + desc[j].ops = &exynos_ppmu_ops; + break; + case EXYNOS_TYPE_PPMU_V2: + desc[j].ops = &exynos_ppmu_v2_ops; + break; + } + desc[j].driver_data = info; of_property_read_string(node, "event-name", &desc[j].name); + ret = of_property_read_u32(node, "event-data-type", + &desc[j].event_type); + if (ret) { + /* Set the event of proper data type counting. + * Check if the data type has been defined in DT, + * use default if not. + */ + if (info->ppmu_type == EXYNOS_TYPE_PPMU_V2) { + struct devfreq_event_dev edev; + int id; + /* Not all registers take the same value for + * read+write data count. + */ + edev.desc = &desc[j]; + id = exynos_ppmu_find_ppmu_id(&edev); + + switch (id) { + case PPMU_PMNCNT0: + case PPMU_PMNCNT1: + case PPMU_PMNCNT2: + desc[j].event_type = PPMU_V2_RO_DATA_CNT + | PPMU_V2_WO_DATA_CNT; + break; + case PPMU_PMNCNT3: + desc[j].event_type = + PPMU_V2_EVT3_RW_DATA_CNT; + break; + } + } else { + desc[j].event_type = PPMU_RO_DATA_CNT | + PPMU_WO_DATA_CNT; + } + } j++; } diff --git a/drivers/devfreq/exynos-bus.c b/drivers/devfreq/exynos-bus.c index d9f377912c1044adb81015315f8f7dd63f07f7d1..c832673273a28daa7413fac8bb770eb8af0c4ca1 100644 --- a/drivers/devfreq/exynos-bus.c +++ b/drivers/devfreq/exynos-bus.c @@ -22,7 +22,6 @@ #include #define DEFAULT_SATURATION_RATIO 40 -#define DEFAULT_VOLTAGE_TOLERANCE 2 struct exynos_bus { struct device *dev; @@ -34,9 +33,8 @@ struct exynos_bus { unsigned long curr_freq; - struct regulator *regulator; + struct opp_table *opp_table; struct clk *clk; - unsigned int voltage_tolerance; unsigned int ratio; }; @@ -90,62 +88,29 @@ static int exynos_bus_get_event(struct exynos_bus *bus, } /* - * Must necessary function for devfreq simple-ondemand governor + * devfreq function for both simple-ondemand and passive governor */ static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags) { struct exynos_bus *bus = dev_get_drvdata(dev); struct dev_pm_opp *new_opp; - unsigned long old_freq, new_freq, new_volt, tol; int ret = 0; - /* Get new opp-bus instance according to new bus clock */ + /* Get correct frequency for bus. */ new_opp = devfreq_recommended_opp(dev, freq, flags); if (IS_ERR(new_opp)) { dev_err(dev, "failed to get recommended opp instance\n"); return PTR_ERR(new_opp); } - new_freq = dev_pm_opp_get_freq(new_opp); - new_volt = dev_pm_opp_get_voltage(new_opp); dev_pm_opp_put(new_opp); - old_freq = bus->curr_freq; - - if (old_freq == new_freq) - return 0; - tol = new_volt * bus->voltage_tolerance / 100; - /* Change voltage and frequency according to new OPP level */ mutex_lock(&bus->lock); + ret = dev_pm_opp_set_rate(dev, *freq); + if (!ret) + bus->curr_freq = *freq; - if (old_freq < new_freq) { - ret = regulator_set_voltage_tol(bus->regulator, new_volt, tol); - if (ret < 0) { - dev_err(bus->dev, "failed to set voltage\n"); - goto out; - } - } - - ret = clk_set_rate(bus->clk, new_freq); - if (ret < 0) { - dev_err(dev, "failed to change clock of bus\n"); - clk_set_rate(bus->clk, old_freq); - goto out; - } - - if (old_freq > new_freq) { - ret = regulator_set_voltage_tol(bus->regulator, new_volt, tol); - if (ret < 0) { - dev_err(bus->dev, "failed to set voltage\n"); - goto out; - } - } - bus->curr_freq = new_freq; - - dev_dbg(dev, "Set the frequency of bus (%luHz -> %luHz, %luHz)\n", - old_freq, new_freq, clk_get_rate(bus->clk)); -out: mutex_unlock(&bus->lock); return ret; @@ -191,57 +156,12 @@ static void exynos_bus_exit(struct device *dev) if (ret < 0) dev_warn(dev, "failed to disable the devfreq-event devices\n"); - if (bus->regulator) - regulator_disable(bus->regulator); - dev_pm_opp_of_remove_table(dev); clk_disable_unprepare(bus->clk); -} - -/* - * Must necessary function for devfreq passive governor - */ -static int exynos_bus_passive_target(struct device *dev, unsigned long *freq, - u32 flags) -{ - struct exynos_bus *bus = dev_get_drvdata(dev); - struct dev_pm_opp *new_opp; - unsigned long old_freq, new_freq; - int ret = 0; - - /* Get new opp-bus instance according to new bus clock */ - new_opp = devfreq_recommended_opp(dev, freq, flags); - if (IS_ERR(new_opp)) { - dev_err(dev, "failed to get recommended opp instance\n"); - return PTR_ERR(new_opp); + if (bus->opp_table) { + dev_pm_opp_put_regulators(bus->opp_table); + bus->opp_table = NULL; } - - new_freq = dev_pm_opp_get_freq(new_opp); - dev_pm_opp_put(new_opp); - - old_freq = bus->curr_freq; - - if (old_freq == new_freq) - return 0; - - /* Change the frequency according to new OPP level */ - mutex_lock(&bus->lock); - - ret = clk_set_rate(bus->clk, new_freq); - if (ret < 0) { - dev_err(dev, "failed to set the clock of bus\n"); - goto out; - } - - *freq = new_freq; - bus->curr_freq = new_freq; - - dev_dbg(dev, "Set the frequency of bus (%luHz -> %luHz, %luHz)\n", - old_freq, new_freq, clk_get_rate(bus->clk)); -out: - mutex_unlock(&bus->lock); - - return ret; } static void exynos_bus_passive_exit(struct device *dev) @@ -256,21 +176,19 @@ static int exynos_bus_parent_parse_of(struct device_node *np, struct exynos_bus *bus) { struct device *dev = bus->dev; + struct opp_table *opp_table; + const char *vdd = "vdd"; int i, ret, count, size; - /* Get the regulator to provide each bus with the power */ - bus->regulator = devm_regulator_get(dev, "vdd"); - if (IS_ERR(bus->regulator)) { - dev_err(dev, "failed to get VDD regulator\n"); - return PTR_ERR(bus->regulator); - } - - ret = regulator_enable(bus->regulator); - if (ret < 0) { - dev_err(dev, "failed to enable VDD regulator\n"); + opp_table = dev_pm_opp_set_regulators(dev, &vdd, 1); + if (IS_ERR(opp_table)) { + ret = PTR_ERR(opp_table); + dev_err(dev, "failed to set regulators %d\n", ret); return ret; } + bus->opp_table = opp_table; + /* * Get the devfreq-event devices to get the current utilization of * buses. This raw data will be used in devfreq ondemand governor. @@ -311,14 +229,11 @@ static int exynos_bus_parent_parse_of(struct device_node *np, if (of_property_read_u32(np, "exynos,saturation-ratio", &bus->ratio)) bus->ratio = DEFAULT_SATURATION_RATIO; - if (of_property_read_u32(np, "exynos,voltage-tolerance", - &bus->voltage_tolerance)) - bus->voltage_tolerance = DEFAULT_VOLTAGE_TOLERANCE; - return 0; err_regulator: - regulator_disable(bus->regulator); + dev_pm_opp_put_regulators(bus->opp_table); + bus->opp_table = NULL; return ret; } @@ -383,6 +298,7 @@ static int exynos_bus_probe(struct platform_device *pdev) struct exynos_bus *bus; int ret, max_state; unsigned long min_freq, max_freq; + bool passive = false; if (!np) { dev_err(dev, "failed to find devicetree node\n"); @@ -396,27 +312,27 @@ static int exynos_bus_probe(struct platform_device *pdev) bus->dev = &pdev->dev; platform_set_drvdata(pdev, bus); - /* Parse the device-tree to get the resource information */ - ret = exynos_bus_parse_of(np, bus); - if (ret < 0) - return ret; - profile = devm_kzalloc(dev, sizeof(*profile), GFP_KERNEL); - if (!profile) { - ret = -ENOMEM; - goto err; - } + if (!profile) + return -ENOMEM; node = of_parse_phandle(dev->of_node, "devfreq", 0); if (node) { of_node_put(node); - goto passive; + passive = true; } else { ret = exynos_bus_parent_parse_of(np, bus); + if (ret < 0) + return ret; } + /* Parse the device-tree to get the resource information */ + ret = exynos_bus_parse_of(np, bus); if (ret < 0) - goto err; + goto err_reg; + + if (passive) + goto passive; /* Initialize the struct profile and governor data for parent device */ profile->polling_ms = 50; @@ -468,7 +384,7 @@ static int exynos_bus_probe(struct platform_device *pdev) goto out; passive: /* Initialize the struct profile and governor data for passive device */ - profile->target = exynos_bus_passive_target; + profile->target = exynos_bus_target; profile->exit = exynos_bus_passive_exit; /* Get the instance of parent devfreq device */ @@ -507,6 +423,11 @@ static int exynos_bus_probe(struct platform_device *pdev) err: dev_pm_opp_of_remove_table(dev); clk_disable_unprepare(bus->clk); +err_reg: + if (!passive) { + dev_pm_opp_put_regulators(bus->opp_table); + bus->opp_table = NULL; + } return ret; } diff --git a/drivers/devfreq/governor_passive.c b/drivers/devfreq/governor_passive.c index 58308948b86377b111410675e2e82487ca8d722a..be6eeab9c814e439bd206be1630aae44a06f5dca 100644 --- a/drivers/devfreq/governor_passive.c +++ b/drivers/devfreq/governor_passive.c @@ -149,7 +149,6 @@ static int devfreq_passive_notifier_call(struct notifier_block *nb, static int devfreq_passive_event_handler(struct devfreq *devfreq, unsigned int event, void *data) { - struct device *dev = devfreq->dev.parent; struct devfreq_passive_data *p_data = (struct devfreq_passive_data *)devfreq->data; struct devfreq *parent = (struct devfreq *)p_data->parent; @@ -165,12 +164,12 @@ static int devfreq_passive_event_handler(struct devfreq *devfreq, p_data->this = devfreq; nb->notifier_call = devfreq_passive_notifier_call; - ret = devm_devfreq_register_notifier(dev, parent, nb, + ret = devfreq_register_notifier(parent, nb, DEVFREQ_TRANSITION_NOTIFIER); break; case DEVFREQ_GOV_STOP: - devm_devfreq_unregister_notifier(dev, parent, nb, - DEVFREQ_TRANSITION_NOTIFIER); + WARN_ON(devfreq_unregister_notifier(parent, nb, + DEVFREQ_TRANSITION_NOTIFIER)); break; default: break; diff --git a/drivers/devfreq/rk3399_dmc.c b/drivers/devfreq/rk3399_dmc.c index 682465fa57e1123f6e625e95263c2effc480d753..2e65d7279d79e24daf42cf6522a4f3ca90546210 100644 --- a/drivers/devfreq/rk3399_dmc.c +++ b/drivers/devfreq/rk3399_dmc.c @@ -351,7 +351,7 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev) /* * Get dram timing and pass it to arm trust firmware, - * the dram drvier in arm trust firmware will get these + * the dram driver in arm trust firmware will get these * timing and to do dram initial. */ if (!of_get_ddr_timings(&data->timing, np)) { diff --git a/drivers/devfreq/tegra20-devfreq.c b/drivers/devfreq/tegra20-devfreq.c new file mode 100644 index 0000000000000000000000000000000000000000..ff82bac9ee4ec498384938d7536e614de649bcc5 --- /dev/null +++ b/drivers/devfreq/tegra20-devfreq.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NVIDIA Tegra20 devfreq driver + * + * Copyright (C) 2019 GRATE-DRIVER project + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "governor.h" + +#define MC_STAT_CONTROL 0x90 +#define MC_STAT_EMC_CLOCK_LIMIT 0xa0 +#define MC_STAT_EMC_CLOCKS 0xa4 +#define MC_STAT_EMC_CONTROL 0xa8 +#define MC_STAT_EMC_COUNT 0xb8 + +#define EMC_GATHER_CLEAR (1 << 8) +#define EMC_GATHER_ENABLE (3 << 8) + +struct tegra_devfreq { + struct devfreq *devfreq; + struct clk *emc_clock; + void __iomem *regs; +}; + +static int tegra_devfreq_target(struct device *dev, unsigned long *freq, + u32 flags) +{ + struct tegra_devfreq *tegra = dev_get_drvdata(dev); + struct devfreq *devfreq = tegra->devfreq; + struct dev_pm_opp *opp; + unsigned long rate; + int err; + + opp = devfreq_recommended_opp(dev, freq, flags); + if (IS_ERR(opp)) + return PTR_ERR(opp); + + rate = dev_pm_opp_get_freq(opp); + dev_pm_opp_put(opp); + + err = clk_set_min_rate(tegra->emc_clock, rate); + if (err) + return err; + + err = clk_set_rate(tegra->emc_clock, 0); + if (err) + goto restore_min_rate; + + return 0; + +restore_min_rate: + clk_set_min_rate(tegra->emc_clock, devfreq->previous_freq); + + return err; +} + +static int tegra_devfreq_get_dev_status(struct device *dev, + struct devfreq_dev_status *stat) +{ + struct tegra_devfreq *tegra = dev_get_drvdata(dev); + + /* + * EMC_COUNT returns number of memory events, that number is lower + * than the number of clocks. Conversion ratio of 1/8 results in a + * bit higher bandwidth than actually needed, it is good enough for + * the time being because drivers don't support requesting minimum + * needed memory bandwidth yet. + * + * TODO: adjust the ratio value once relevant drivers will support + * memory bandwidth management. + */ + stat->busy_time = readl_relaxed(tegra->regs + MC_STAT_EMC_COUNT); + stat->total_time = readl_relaxed(tegra->regs + MC_STAT_EMC_CLOCKS) / 8; + stat->current_frequency = clk_get_rate(tegra->emc_clock); + + writel_relaxed(EMC_GATHER_CLEAR, tegra->regs + MC_STAT_CONTROL); + writel_relaxed(EMC_GATHER_ENABLE, tegra->regs + MC_STAT_CONTROL); + + return 0; +} + +static struct devfreq_dev_profile tegra_devfreq_profile = { + .polling_ms = 500, + .target = tegra_devfreq_target, + .get_dev_status = tegra_devfreq_get_dev_status, +}; + +static struct tegra_mc *tegra_get_memory_controller(void) +{ + struct platform_device *pdev; + struct device_node *np; + struct tegra_mc *mc; + + np = of_find_compatible_node(NULL, NULL, "nvidia,tegra20-mc-gart"); + if (!np) + return ERR_PTR(-ENOENT); + + pdev = of_find_device_by_node(np); + of_node_put(np); + if (!pdev) + return ERR_PTR(-ENODEV); + + mc = platform_get_drvdata(pdev); + if (!mc) + return ERR_PTR(-EPROBE_DEFER); + + return mc; +} + +static int tegra_devfreq_probe(struct platform_device *pdev) +{ + struct tegra_devfreq *tegra; + struct tegra_mc *mc; + unsigned long max_rate; + unsigned long rate; + int err; + + mc = tegra_get_memory_controller(); + if (IS_ERR(mc)) { + err = PTR_ERR(mc); + dev_err(&pdev->dev, "failed to get memory controller: %d\n", + err); + return err; + } + + tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); + if (!tegra) + return -ENOMEM; + + /* EMC is a system-critical clock that is always enabled */ + tegra->emc_clock = devm_clk_get(&pdev->dev, "emc"); + if (IS_ERR(tegra->emc_clock)) { + err = PTR_ERR(tegra->emc_clock); + dev_err(&pdev->dev, "failed to get emc clock: %d\n", err); + return err; + } + + tegra->regs = mc->regs; + + max_rate = clk_round_rate(tegra->emc_clock, ULONG_MAX); + + for (rate = 0; rate <= max_rate; rate++) { + rate = clk_round_rate(tegra->emc_clock, rate); + + err = dev_pm_opp_add(&pdev->dev, rate, 0); + if (err) { + dev_err(&pdev->dev, "failed to add opp: %d\n", err); + goto remove_opps; + } + } + + /* + * Reset statistic gathers state, select global bandwidth for the + * statistics collection mode and set clocks counter saturation + * limit to maximum. + */ + writel_relaxed(0x00000000, tegra->regs + MC_STAT_CONTROL); + writel_relaxed(0x00000000, tegra->regs + MC_STAT_EMC_CONTROL); + writel_relaxed(0xffffffff, tegra->regs + MC_STAT_EMC_CLOCK_LIMIT); + + platform_set_drvdata(pdev, tegra); + + tegra->devfreq = devfreq_add_device(&pdev->dev, &tegra_devfreq_profile, + DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL); + if (IS_ERR(tegra->devfreq)) { + err = PTR_ERR(tegra->devfreq); + goto remove_opps; + } + + return 0; + +remove_opps: + dev_pm_opp_remove_all_dynamic(&pdev->dev); + + return err; +} + +static int tegra_devfreq_remove(struct platform_device *pdev) +{ + struct tegra_devfreq *tegra = platform_get_drvdata(pdev); + + devfreq_remove_device(tegra->devfreq); + dev_pm_opp_remove_all_dynamic(&pdev->dev); + + return 0; +} + +static struct platform_driver tegra_devfreq_driver = { + .probe = tegra_devfreq_probe, + .remove = tegra_devfreq_remove, + .driver = { + .name = "tegra20-devfreq", + }, +}; +module_platform_driver(tegra_devfreq_driver); + +MODULE_ALIAS("platform:tegra20-devfreq"); +MODULE_AUTHOR("Dmitry Osipenko "); +MODULE_DESCRIPTION("NVIDIA Tegra20 devfreq driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/devfreq/tegra-devfreq.c b/drivers/devfreq/tegra30-devfreq.c similarity index 80% rename from drivers/devfreq/tegra-devfreq.c rename to drivers/devfreq/tegra30-devfreq.c index 35c38aad8b4f4eac44fb24477d526c3b75b82d9b..a6ba75f4106d80456e79b7d226875af24dff2254 100644 --- a/drivers/devfreq/tegra-devfreq.c +++ b/drivers/devfreq/tegra30-devfreq.c @@ -132,7 +132,6 @@ static struct tegra_devfreq_device_config actmon_device_configs[] = { struct tegra_devfreq_device { const struct tegra_devfreq_device_config *config; void __iomem *regs; - spinlock_t lock; /* Average event count sampled in the last interrupt */ u32 avg_count; @@ -160,6 +159,8 @@ struct tegra_devfreq { struct notifier_block rate_change_nb; struct tegra_devfreq_device devices[ARRAY_SIZE(actmon_device_configs)]; + + int irq; }; struct tegra_actmon_emc_ratio { @@ -179,23 +180,23 @@ static struct tegra_actmon_emc_ratio actmon_emc_ratios[] = { static u32 actmon_readl(struct tegra_devfreq *tegra, u32 offset) { - return readl(tegra->regs + offset); + return readl_relaxed(tegra->regs + offset); } static void actmon_writel(struct tegra_devfreq *tegra, u32 val, u32 offset) { - writel(val, tegra->regs + offset); + writel_relaxed(val, tegra->regs + offset); } static u32 device_readl(struct tegra_devfreq_device *dev, u32 offset) { - return readl(dev->regs + offset); + return readl_relaxed(dev->regs + offset); } static void device_writel(struct tegra_devfreq_device *dev, u32 val, u32 offset) { - writel(val, dev->regs + offset); + writel_relaxed(val, dev->regs + offset); } static unsigned long do_percent(unsigned long val, unsigned int pct) @@ -231,18 +232,14 @@ static void tegra_devfreq_update_wmark(struct tegra_devfreq *tegra, static void actmon_write_barrier(struct tegra_devfreq *tegra) { /* ensure the update has reached the ACTMON */ - wmb(); - actmon_readl(tegra, ACTMON_GLB_STATUS); + readl(tegra->regs + ACTMON_GLB_STATUS); } static void actmon_isr_device(struct tegra_devfreq *tegra, struct tegra_devfreq_device *dev) { - unsigned long flags; u32 intr_status, dev_ctrl; - spin_lock_irqsave(&dev->lock, flags); - dev->avg_count = device_readl(dev, ACTMON_DEV_AVG_COUNT); tegra_devfreq_update_avg_wmark(tegra, dev); @@ -291,26 +288,6 @@ static void actmon_isr_device(struct tegra_devfreq *tegra, device_writel(dev, ACTMON_INTR_STATUS_CLEAR, ACTMON_DEV_INTR_STATUS); actmon_write_barrier(tegra); - - spin_unlock_irqrestore(&dev->lock, flags); -} - -static irqreturn_t actmon_isr(int irq, void *data) -{ - struct tegra_devfreq *tegra = data; - bool handled = false; - unsigned int i; - u32 val; - - val = actmon_readl(tegra, ACTMON_GLB_STATUS); - for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { - if (val & tegra->devices[i].config->irq_mask) { - actmon_isr_device(tegra, tegra->devices + i); - handled = true; - } - } - - return handled ? IRQ_WAKE_THREAD : IRQ_NONE; } static unsigned long actmon_cpu_to_emc_rate(struct tegra_devfreq *tegra, @@ -337,15 +314,12 @@ static void actmon_update_target(struct tegra_devfreq *tegra, unsigned long cpu_freq = 0; unsigned long static_cpu_emc_freq = 0; unsigned int avg_sustain_coef; - unsigned long flags; if (dev->config->avg_dependency_threshold) { cpu_freq = cpufreq_get(0); static_cpu_emc_freq = actmon_cpu_to_emc_rate(tegra, cpu_freq); } - spin_lock_irqsave(&dev->lock, flags); - dev->target_freq = dev->avg_count / ACTMON_SAMPLING_PERIOD; avg_sustain_coef = 100 * 100 / dev->config->boost_up_threshold; dev->target_freq = do_percent(dev->target_freq, avg_sustain_coef); @@ -353,19 +327,31 @@ static void actmon_update_target(struct tegra_devfreq *tegra, if (dev->avg_count >= dev->config->avg_dependency_threshold) dev->target_freq = max(dev->target_freq, static_cpu_emc_freq); - - spin_unlock_irqrestore(&dev->lock, flags); } static irqreturn_t actmon_thread_isr(int irq, void *data) { struct tegra_devfreq *tegra = data; + bool handled = false; + unsigned int i; + u32 val; mutex_lock(&tegra->devfreq->lock); - update_devfreq(tegra->devfreq); + + val = actmon_readl(tegra, ACTMON_GLB_STATUS); + for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { + if (val & tegra->devices[i].config->irq_mask) { + actmon_isr_device(tegra, tegra->devices + i); + handled = true; + } + } + + if (handled) + update_devfreq(tegra->devfreq); + mutex_unlock(&tegra->devfreq->lock); - return IRQ_HANDLED; + return handled ? IRQ_HANDLED : IRQ_NONE; } static int tegra_actmon_rate_notify_cb(struct notifier_block *nb, @@ -375,7 +361,6 @@ static int tegra_actmon_rate_notify_cb(struct notifier_block *nb, struct tegra_devfreq *tegra; struct tegra_devfreq_device *dev; unsigned int i; - unsigned long flags; if (action != POST_RATE_CHANGE) return NOTIFY_OK; @@ -387,9 +372,7 @@ static int tegra_actmon_rate_notify_cb(struct notifier_block *nb, for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { dev = &tegra->devices[i]; - spin_lock_irqsave(&dev->lock, flags); tegra_devfreq_update_wmark(tegra, dev); - spin_unlock_irqrestore(&dev->lock, flags); } actmon_write_barrier(tegra); @@ -397,48 +380,6 @@ static int tegra_actmon_rate_notify_cb(struct notifier_block *nb, return NOTIFY_OK; } -static void tegra_actmon_enable_interrupts(struct tegra_devfreq *tegra) -{ - struct tegra_devfreq_device *dev; - u32 val; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { - dev = &tegra->devices[i]; - - val = device_readl(dev, ACTMON_DEV_CTRL); - val |= ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN; - val |= ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN; - val |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; - val |= ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN; - - device_writel(dev, val, ACTMON_DEV_CTRL); - } - - actmon_write_barrier(tegra); -} - -static void tegra_actmon_disable_interrupts(struct tegra_devfreq *tegra) -{ - struct tegra_devfreq_device *dev; - u32 val; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { - dev = &tegra->devices[i]; - - val = device_readl(dev, ACTMON_DEV_CTRL); - val &= ~ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN; - val &= ~ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN; - val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; - val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN; - - device_writel(dev, val, ACTMON_DEV_CTRL); - } - - actmon_write_barrier(tegra); -} - static void tegra_actmon_configure_device(struct tegra_devfreq *tegra, struct tegra_devfreq_device *dev) { @@ -462,34 +403,80 @@ static void tegra_actmon_configure_device(struct tegra_devfreq *tegra, << ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_NUM_SHIFT; val |= (ACTMON_ABOVE_WMARK_WINDOW - 1) << ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_NUM_SHIFT; + val |= ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN; + val |= ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN; + val |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; + val |= ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN; val |= ACTMON_DEV_CTRL_ENB; device_writel(dev, val, ACTMON_DEV_CTRL); +} + +static void tegra_actmon_start(struct tegra_devfreq *tegra) +{ + unsigned int i; + + disable_irq(tegra->irq); + + actmon_writel(tegra, ACTMON_SAMPLING_PERIOD - 1, + ACTMON_GLB_PERIOD_CTRL); + + for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) + tegra_actmon_configure_device(tegra, &tegra->devices[i]); + + actmon_write_barrier(tegra); + + enable_irq(tegra->irq); +} + +static void tegra_actmon_stop(struct tegra_devfreq *tegra) +{ + unsigned int i; + + disable_irq(tegra->irq); + + for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { + device_writel(&tegra->devices[i], 0x00000000, ACTMON_DEV_CTRL); + device_writel(&tegra->devices[i], ACTMON_INTR_STATUS_CLEAR, + ACTMON_DEV_INTR_STATUS); + } actmon_write_barrier(tegra); + + enable_irq(tegra->irq); } static int tegra_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) { struct tegra_devfreq *tegra = dev_get_drvdata(dev); + struct devfreq *devfreq = tegra->devfreq; struct dev_pm_opp *opp; - unsigned long rate = *freq * KHZ; + unsigned long rate; + int err; - opp = devfreq_recommended_opp(dev, &rate, flags); + opp = devfreq_recommended_opp(dev, freq, flags); if (IS_ERR(opp)) { - dev_err(dev, "Failed to find opp for %lu KHz\n", *freq); + dev_err(dev, "Failed to find opp for %lu Hz\n", *freq); return PTR_ERR(opp); } rate = dev_pm_opp_get_freq(opp); dev_pm_opp_put(opp); - clk_set_min_rate(tegra->emc_clock, rate); - clk_set_rate(tegra->emc_clock, 0); + err = clk_set_min_rate(tegra->emc_clock, rate); + if (err) + return err; - *freq = rate; + err = clk_set_rate(tegra->emc_clock, 0); + if (err) + goto restore_min_rate; return 0; + +restore_min_rate: + clk_set_min_rate(tegra->emc_clock, devfreq->previous_freq); + + return err; } static int tegra_devfreq_get_dev_status(struct device *dev, @@ -497,13 +484,15 @@ static int tegra_devfreq_get_dev_status(struct device *dev, { struct tegra_devfreq *tegra = dev_get_drvdata(dev); struct tegra_devfreq_device *actmon_dev; + unsigned long cur_freq; - stat->current_frequency = tegra->cur_freq; + cur_freq = READ_ONCE(tegra->cur_freq); /* To be used by the tegra governor */ stat->private_data = tegra; /* The below are to be used by the other governors */ + stat->current_frequency = cur_freq * KHZ; actmon_dev = &tegra->devices[MCALL]; @@ -514,7 +503,7 @@ static int tegra_devfreq_get_dev_status(struct device *dev, stat->busy_time *= 100 / BUS_SATURATION_RATIO; /* Number of cycles in a sampling period */ - stat->total_time = ACTMON_SAMPLING_PERIOD * tegra->cur_freq; + stat->total_time = ACTMON_SAMPLING_PERIOD * cur_freq; stat->busy_time = min(stat->busy_time, stat->total_time); @@ -553,7 +542,7 @@ static int tegra_governor_get_target(struct devfreq *devfreq, target_freq = max(target_freq, dev->target_freq); } - *freq = target_freq; + *freq = target_freq * KHZ; return 0; } @@ -566,22 +555,22 @@ static int tegra_governor_event_handler(struct devfreq *devfreq, switch (event) { case DEVFREQ_GOV_START: devfreq_monitor_start(devfreq); - tegra_actmon_enable_interrupts(tegra); + tegra_actmon_start(tegra); break; case DEVFREQ_GOV_STOP: - tegra_actmon_disable_interrupts(tegra); + tegra_actmon_stop(tegra); devfreq_monitor_stop(devfreq); break; case DEVFREQ_GOV_SUSPEND: - tegra_actmon_disable_interrupts(tegra); + tegra_actmon_stop(tegra); devfreq_monitor_suspend(devfreq); break; case DEVFREQ_GOV_RESUME: devfreq_monitor_resume(devfreq); - tegra_actmon_enable_interrupts(tegra); + tegra_actmon_start(tegra); break; } @@ -592,25 +581,22 @@ static struct devfreq_governor tegra_devfreq_governor = { .name = "tegra_actmon", .get_target_freq = tegra_governor_get_target, .event_handler = tegra_governor_event_handler, + .immutable = true, }; static int tegra_devfreq_probe(struct platform_device *pdev) { struct tegra_devfreq *tegra; struct tegra_devfreq_device *dev; - struct resource *res; unsigned int i; unsigned long rate; - int irq; int err; tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); if (!tegra) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - tegra->regs = devm_ioremap_resource(&pdev->dev, res); + tegra->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(tegra->regs)) return PTR_ERR(tegra->regs); @@ -632,13 +618,10 @@ static int tegra_devfreq_probe(struct platform_device *pdev) return PTR_ERR(tegra->emc_clock); } - clk_set_rate(tegra->emc_clock, ULONG_MAX); - - tegra->rate_change_nb.notifier_call = tegra_actmon_rate_notify_cb; - err = clk_notifier_register(tegra->emc_clock, &tegra->rate_change_nb); - if (err) { - dev_err(&pdev->dev, - "Failed to register rate change notifier\n"); + tegra->irq = platform_get_irq(pdev, 0); + if (tegra->irq < 0) { + err = tegra->irq; + dev_err(&pdev->dev, "Failed to get IRQ: %d\n", err); return err; } @@ -656,73 +639,94 @@ static int tegra_devfreq_probe(struct platform_device *pdev) tegra->max_freq = clk_round_rate(tegra->emc_clock, ULONG_MAX) / KHZ; tegra->cur_freq = clk_get_rate(tegra->emc_clock) / KHZ; - actmon_writel(tegra, ACTMON_SAMPLING_PERIOD - 1, - ACTMON_GLB_PERIOD_CTRL); - for (i = 0; i < ARRAY_SIZE(actmon_device_configs); i++) { dev = tegra->devices + i; dev->config = actmon_device_configs + i; dev->regs = tegra->regs + dev->config->offset; - spin_lock_init(&dev->lock); - - tegra_actmon_configure_device(tegra, dev); } for (rate = 0; rate <= tegra->max_freq * KHZ; rate++) { rate = clk_round_rate(tegra->emc_clock, rate); - dev_pm_opp_add(&pdev->dev, rate, 0); - } - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq); - return irq; + err = dev_pm_opp_add(&pdev->dev, rate, 0); + if (err) { + dev_err(&pdev->dev, "Failed to add OPP: %d\n", err); + goto remove_opps; + } } platform_set_drvdata(pdev, tegra); - err = devm_request_threaded_irq(&pdev->dev, irq, actmon_isr, - actmon_thread_isr, IRQF_SHARED, - "tegra-devfreq", tegra); + tegra->rate_change_nb.notifier_call = tegra_actmon_rate_notify_cb; + err = clk_notifier_register(tegra->emc_clock, &tegra->rate_change_nb); if (err) { - dev_err(&pdev->dev, "Interrupt request failed\n"); - return err; + dev_err(&pdev->dev, + "Failed to register rate change notifier\n"); + goto remove_opps; + } + + err = devfreq_add_governor(&tegra_devfreq_governor); + if (err) { + dev_err(&pdev->dev, "Failed to add governor: %d\n", err); + goto unreg_notifier; } tegra_devfreq_profile.initial_freq = clk_get_rate(tegra->emc_clock); - tegra->devfreq = devm_devfreq_add_device(&pdev->dev, - &tegra_devfreq_profile, - "tegra_actmon", - NULL); + tegra->devfreq = devfreq_add_device(&pdev->dev, + &tegra_devfreq_profile, + "tegra_actmon", + NULL); + if (IS_ERR(tegra->devfreq)) { + err = PTR_ERR(tegra->devfreq); + goto remove_governor; + } + + err = devm_request_threaded_irq(&pdev->dev, tegra->irq, NULL, + actmon_thread_isr, IRQF_ONESHOT, + "tegra-devfreq", tegra); + if (err) { + dev_err(&pdev->dev, "Interrupt request failed: %d\n", err); + goto remove_devfreq; + } return 0; + +remove_devfreq: + devfreq_remove_device(tegra->devfreq); + +remove_governor: + devfreq_remove_governor(&tegra_devfreq_governor); + +unreg_notifier: + clk_notifier_unregister(tegra->emc_clock, &tegra->rate_change_nb); + +remove_opps: + dev_pm_opp_remove_all_dynamic(&pdev->dev); + + reset_control_reset(tegra->reset); + clk_disable_unprepare(tegra->clock); + + return err; } static int tegra_devfreq_remove(struct platform_device *pdev) { struct tegra_devfreq *tegra = platform_get_drvdata(pdev); - int irq = platform_get_irq(pdev, 0); - u32 val; - unsigned int i; - for (i = 0; i < ARRAY_SIZE(actmon_device_configs); i++) { - val = device_readl(&tegra->devices[i], ACTMON_DEV_CTRL); - val &= ~ACTMON_DEV_CTRL_ENB; - device_writel(&tegra->devices[i], val, ACTMON_DEV_CTRL); - } - - actmon_write_barrier(tegra); - - devm_free_irq(&pdev->dev, irq, tegra); + devfreq_remove_device(tegra->devfreq); + devfreq_remove_governor(&tegra_devfreq_governor); clk_notifier_unregister(tegra->emc_clock, &tegra->rate_change_nb); + dev_pm_opp_remove_all_dynamic(&pdev->dev); + reset_control_reset(tegra->reset); clk_disable_unprepare(tegra->clock); return 0; } static const struct of_device_id tegra_devfreq_of_match[] = { + { .compatible = "nvidia,tegra30-actmon" }, { .compatible = "nvidia,tegra124-actmon" }, { }, }; @@ -737,36 +741,7 @@ static struct platform_driver tegra_devfreq_driver = { .of_match_table = tegra_devfreq_of_match, }, }; - -static int __init tegra_devfreq_init(void) -{ - int ret = 0; - - ret = devfreq_add_governor(&tegra_devfreq_governor); - if (ret) { - pr_err("%s: failed to add governor: %d\n", __func__, ret); - return ret; - } - - ret = platform_driver_register(&tegra_devfreq_driver); - if (ret) - devfreq_remove_governor(&tegra_devfreq_governor); - - return ret; -} -module_init(tegra_devfreq_init) - -static void __exit tegra_devfreq_exit(void) -{ - int ret = 0; - - platform_driver_unregister(&tegra_devfreq_driver); - - ret = devfreq_remove_governor(&tegra_devfreq_governor); - if (ret) - pr_err("%s: failed to remove governor: %d\n", __func__, ret); -} -module_exit(tegra_devfreq_exit) +module_platform_driver(tegra_devfreq_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Tegra devfreq driver"); diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 03fa0c58cef3b8ff93268c61afafab35a77a77c3..7c511e3db4c8e7cff0d89128f2e509eda114a536 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -294,8 +294,8 @@ config INTEL_IOATDMA If unsure, say N. config INTEL_IOP_ADMA - tristate "Intel IOP ADMA support" - depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX + tristate "Intel IOP32x ADMA support" + depends on ARCH_IOP32X || COMPILE_TEST select DMA_ENGINE select ASYNC_TX_ENABLE_CHANNEL_SWITCH help diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c index 30243f5c07105026f90f27eb7bf3bbcb4bfb831b..8a05db3343d39047baf0b9d6ab46e43a1fe4abf1 100644 --- a/drivers/dma/acpi-dma.c +++ b/drivers/dma/acpi-dma.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -82,6 +83,12 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp, if (si->base_request_line == 0 && si->num_handshake_signals == 0) return 0; + /* Set up DMA mask based on value from CSRT */ + ret = dma_coerce_mask_and_coherent(&adev->dev, + DMA_BIT_MASK(si->dma_address_width)); + if (ret) + return 0; + adma->base_request_line = si->base_request_line; adma->end_request_line = si->base_request_line + si->num_handshake_signals - 1; @@ -140,7 +147,7 @@ static void acpi_dma_parse_csrt(struct acpi_device *adev, struct acpi_dma *adma) * @dev: struct device of DMA controller * @acpi_dma_xlate: translation function which converts a dma specifier * into a dma_chan structure - * @data pointer to controller specific data to be used by + * @data: pointer to controller specific data to be used by * translation function * * Allocated memory should be freed with appropriate acpi_dma_controller_free() @@ -224,7 +231,7 @@ static void devm_acpi_dma_release(struct device *dev, void *res) * devm_acpi_dma_controller_register - resource managed acpi_dma_controller_register() * @dev: device that is registering this DMA controller * @acpi_dma_xlate: translation function - * @data pointer to controller specific data + * @data: pointer to controller specific data * * Managed acpi_dma_controller_register(). DMA controller registered by this * function are automatically freed on driver detach. See @@ -257,6 +264,7 @@ EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_register); /** * devm_acpi_dma_controller_free - resource managed acpi_dma_controller_free() + * @dev: device that is unregistering as DMA controller * * Unregister a DMA controller registered with * devm_acpi_dma_controller_register(). Normally this function will not need to diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index 8101ff2f05c1c326f67c4214a2bd93f73ce9c158..e4c593f48575c22b6a22c1d14cb05aa03fe675c8 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -37,10 +37,19 @@ #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14 #define BCM2835_DMA_CHAN_NAME_SIZE 8 +/** + * struct bcm2835_dmadev - BCM2835 DMA controller + * @ddev: DMA device + * @base: base address of register map + * @dma_parms: DMA parameters (to convey 1 GByte max segment size to clients) + * @zero_page: bus address of zero page (to detect transactions copying from + * zero page and avoid accessing memory if so) + */ struct bcm2835_dmadev { struct dma_device ddev; void __iomem *base; struct device_dma_parameters dma_parms; + dma_addr_t zero_page; }; struct bcm2835_dma_cb { @@ -687,11 +696,12 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( size_t period_len, enum dma_transfer_direction direction, unsigned long flags) { + struct bcm2835_dmadev *od = to_bcm2835_dma_dev(chan->device); struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); struct bcm2835_desc *d; dma_addr_t src, dst; u32 info = BCM2835_DMA_WAIT_RESP; - u32 extra = BCM2835_DMA_INT_EN; + u32 extra = 0; size_t max_len = bcm2835_dma_max_frame_length(c); size_t frames; @@ -707,6 +717,11 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( return NULL; } + if (flags & DMA_PREP_INTERRUPT) + extra |= BCM2835_DMA_INT_EN; + else + period_len = buf_len; + /* * warn if buf_len is not a multiple of period_len - this may leed * to unexpected latencies for interrupts and thus audiable clicks @@ -732,6 +747,10 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( dst = c->cfg.dst_addr; src = buf_addr; info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC; + + /* non-lite channels can write zeroes w/o accessing memory */ + if (buf_addr == od->zero_page && !c->is_lite_channel) + info |= BCM2835_DMA_S_IGNORE; } /* calculate number of frames */ @@ -778,7 +797,10 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan) /* stop DMA activity */ if (c->desc) { - vchan_terminate_vdesc(&c->desc->vd); + if (c->desc->vd.tx.flags & DMA_PREP_INTERRUPT) + vchan_terminate_vdesc(&c->desc->vd); + else + vchan_vdesc_fini(&c->desc->vd); c->desc = NULL; bcm2835_dma_abort(c); } @@ -831,6 +853,9 @@ static void bcm2835_dma_free(struct bcm2835_dmadev *od) list_del(&c->vc.chan.device_node); tasklet_kill(&c->vc.task); } + + dma_unmap_page_attrs(od->ddev.dev, od->zero_page, PAGE_SIZE, + DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); } static const struct of_device_id bcm2835_dma_of_match[] = { @@ -871,8 +896,10 @@ static int bcm2835_dma_probe(struct platform_device *pdev) pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) + if (rc) { + dev_err(&pdev->dev, "Unable to set DMA mask\n"); return rc; + } od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL); if (!od) @@ -907,11 +934,20 @@ static int bcm2835_dma_probe(struct platform_device *pdev) od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) | BIT(DMA_MEM_TO_MEM); od->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; + od->ddev.descriptor_reuse = true; od->ddev.dev = &pdev->dev; INIT_LIST_HEAD(&od->ddev.channels); platform_set_drvdata(pdev, od); + od->zero_page = dma_map_page_attrs(od->ddev.dev, ZERO_PAGE(0), 0, + PAGE_SIZE, DMA_TO_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); + if (dma_mapping_error(od->ddev.dev, od->zero_page)) { + dev_err(&pdev->dev, "Failed to map zero page\n"); + return -ENOMEM; + } + /* Request DMA channel mask from device tree */ if (of_property_read_u32(pdev->dev.of_node, "brcm,dma-channel-mask", diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 7fe9309a876bde8fcb6e035dd0fd27baf464f333..cafb1cc065bb76f397541f54bb597982dbc4ece4 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -92,6 +92,7 @@ #define JZ_SOC_DATA_PROGRAMMABLE_DMA BIT(1) #define JZ_SOC_DATA_PER_CHAN_PM BIT(2) #define JZ_SOC_DATA_NO_DCKES_DCKEC BIT(3) +#define JZ_SOC_DATA_BREAK_LINKS BIT(4) /** * struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller. @@ -355,6 +356,7 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_slave_sg( void *context) { struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); + struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan); struct jz4780_dma_desc *desc; unsigned int i; int err; @@ -375,7 +377,8 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_slave_sg( desc->desc[i].dcm |= JZ_DMA_DCM_TIE; - if (i != (sg_len - 1)) { + if (i != (sg_len - 1) && + !(jzdma->soc_data->flags & JZ_SOC_DATA_BREAK_LINKS)) { /* Automatically proceeed to the next descriptor. */ desc->desc[i].dcm |= JZ_DMA_DCM_LINK; @@ -664,6 +667,8 @@ static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan, static bool jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma, struct jz4780_dma_chan *jzchan) { + const unsigned int soc_flags = jzdma->soc_data->flags; + struct jz4780_dma_desc *desc = jzchan->desc; uint32_t dcs; bool ack = true; @@ -691,8 +696,11 @@ static bool jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma, jz4780_dma_begin(jzchan); } else if (dcs & JZ_DMA_DCS_TT) { - vchan_cookie_complete(&jzchan->desc->vdesc); - jzchan->desc = NULL; + if (!(soc_flags & JZ_SOC_DATA_BREAK_LINKS) || + (jzchan->curr_hwdesc + 1 == desc->count)) { + vchan_cookie_complete(&desc->vdesc); + jzchan->desc = NULL; + } jz4780_dma_begin(jzchan); } else { @@ -878,10 +886,8 @@ static int jz4780_dma_probe(struct platform_device *pdev) } ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(dev, "failed to get IRQ: %d\n", ret); + if (ret < 0) return ret; - } jzdma->irq = ret; @@ -992,6 +998,7 @@ static int jz4780_dma_remove(struct platform_device *pdev) static const struct jz4780_dma_soc_data jz4740_dma_soc_data = { .nb_channels = 6, .transfer_ord_max = 5, + .flags = JZ_SOC_DATA_BREAK_LINKS, }; static const struct jz4780_dma_soc_data jz4725b_dma_soc_data = { diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 3d22ae8dca7203ab797646ed6e972aedeb84a32b..a2cadfa2e6d7848e8d4a163a0a6e5f387b26622c 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -72,6 +72,10 @@ static bool norandom; module_param(norandom, bool, 0644); MODULE_PARM_DESC(norandom, "Disable random offset setup (default: random)"); +static bool polled; +module_param(polled, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(polled, "Use polling for completion instead of interrupts"); + static bool verbose; module_param(verbose, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(verbose, "Enable \"success\" result messages (default: off)"); @@ -110,6 +114,7 @@ struct dmatest_params { bool norandom; int alignment; unsigned int transfer_size; + bool polled; }; /** @@ -651,7 +656,10 @@ static int dmatest_func(void *data) /* * src and dst buffers are freed by ourselves below */ - flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; + if (params->polled) + flags = DMA_CTRL_ACK; + else + flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; ktime = ktime_get(); while (!kthread_should_stop() @@ -780,8 +788,10 @@ static int dmatest_func(void *data) } done->done = false; - tx->callback = dmatest_callback; - tx->callback_param = done; + if (!params->polled) { + tx->callback = dmatest_callback; + tx->callback_param = done; + } cookie = tx->tx_submit(tx); if (dma_submit_error(cookie)) { @@ -790,12 +800,22 @@ static int dmatest_func(void *data) msleep(100); goto error_unmap_continue; } - dma_async_issue_pending(chan); - wait_event_freezable_timeout(thread->done_wait, done->done, - msecs_to_jiffies(params->timeout)); + if (params->polled) { + status = dma_sync_wait(chan, cookie); + dmaengine_terminate_sync(chan); + if (status == DMA_COMPLETE) + done->done = true; + } else { + dma_async_issue_pending(chan); + + wait_event_freezable_timeout(thread->done_wait, + done->done, + msecs_to_jiffies(params->timeout)); - status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); + status = dma_async_is_tx_complete(chan, cookie, NULL, + NULL); + } if (!done->done) { result("test timed out", total_tests, src->off, dst->off, @@ -1065,6 +1085,7 @@ static void add_threaded_test(struct dmatest_info *info) params->norandom = norandom; params->alignment = alignment; params->transfer_size = transfer_size; + params->polled = polled; request_channels(info, DMA_MEMCPY); request_channels(info, DMA_MEMSET); diff --git a/drivers/dma/dw/Makefile b/drivers/dma/dw/Makefile index 63ed895c09aaf3681799213c6de49cfe45b8dcc3..b6f06699e91a9d6a8159d407dc1861ac59b50424 100644 --- a/drivers/dma/dw/Makefile +++ b/drivers/dma/dw/Makefile @@ -3,7 +3,9 @@ obj-$(CONFIG_DW_DMAC_CORE) += dw_dmac_core.o dw_dmac_core-objs := core.o dw.o idma32.o obj-$(CONFIG_DW_DMAC) += dw_dmac.o -dw_dmac-objs := platform.o +dw_dmac-y := platform.o +dw_dmac-$(CONFIG_ACPI) += acpi.o +dw_dmac-$(CONFIG_OF) += of.o obj-$(CONFIG_DW_DMAC_PCI) += dw_dmac_pci.o dw_dmac_pci-objs := pci.o diff --git a/drivers/dma/dw/acpi.c b/drivers/dma/dw/acpi.c new file mode 100644 index 0000000000000000000000000000000000000000..f6e8d55b4f6e9a007b554309b9896fc4a1e6f772 --- /dev/null +++ b/drivers/dma/dw/acpi.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2013,2019 Intel Corporation + +#include +#include + +#include "internal.h" + +static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param) +{ + struct acpi_dma_spec *dma_spec = param; + struct dw_dma_slave slave = { + .dma_dev = dma_spec->dev, + .src_id = dma_spec->slave_id, + .dst_id = dma_spec->slave_id, + .m_master = 0, + .p_master = 1, + }; + + return dw_dma_filter(chan, &slave); +} + +void dw_dma_acpi_controller_register(struct dw_dma *dw) +{ + struct device *dev = dw->dma.dev; + struct acpi_dma_filter_info *info; + int ret; + + if (!has_acpi_companion(dev)) + return; + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return; + + dma_cap_zero(info->dma_cap); + dma_cap_set(DMA_SLAVE, info->dma_cap); + info->filter_fn = dw_dma_acpi_filter; + + ret = acpi_dma_controller_register(dev, acpi_dma_simple_xlate, info); + if (ret) + dev_err(dev, "could not register acpi_dma_controller\n"); +} + +void dw_dma_acpi_controller_free(struct dw_dma *dw) +{ + struct device *dev = dw->dma.dev; + + if (!has_acpi_companion(dev)) + return; + + acpi_dma_controller_free(dev); +} diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h index 1dd7a4e6dd235b871ae9d3c105d85d5fd585af4d..2e1c52eefdeb44d4cac97f75d6418cd437d777c9 100644 --- a/drivers/dma/dw/internal.h +++ b/drivers/dma/dw/internal.h @@ -23,4 +23,55 @@ int do_dw_dma_enable(struct dw_dma_chip *chip); extern bool dw_dma_filter(struct dma_chan *chan, void *param); +#ifdef CONFIG_ACPI +void dw_dma_acpi_controller_register(struct dw_dma *dw); +void dw_dma_acpi_controller_free(struct dw_dma *dw); +#else /* !CONFIG_ACPI */ +static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {} +static inline void dw_dma_acpi_controller_free(struct dw_dma *dw) {} +#endif /* !CONFIG_ACPI */ + +struct platform_device; + +#ifdef CONFIG_OF +struct dw_dma_platform_data *dw_dma_parse_dt(struct platform_device *pdev); +void dw_dma_of_controller_register(struct dw_dma *dw); +void dw_dma_of_controller_free(struct dw_dma *dw); +#else +static inline struct dw_dma_platform_data *dw_dma_parse_dt(struct platform_device *pdev) +{ + return NULL; +} +static inline void dw_dma_of_controller_register(struct dw_dma *dw) {} +static inline void dw_dma_of_controller_free(struct dw_dma *dw) {} +#endif + +struct dw_dma_chip_pdata { + const struct dw_dma_platform_data *pdata; + int (*probe)(struct dw_dma_chip *chip); + int (*remove)(struct dw_dma_chip *chip); + struct dw_dma_chip *chip; +}; + +static __maybe_unused const struct dw_dma_chip_pdata dw_dma_chip_pdata = { + .probe = dw_dma_probe, + .remove = dw_dma_remove, +}; + +static const struct dw_dma_platform_data idma32_pdata = { + .nr_channels = 8, + .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, + .chan_priority = CHAN_PRIORITY_ASCENDING, + .block_size = 131071, + .nr_masters = 1, + .data_width = {4}, + .multi_block = {1, 1, 1, 1, 1, 1, 1, 1}, +}; + +static __maybe_unused const struct dw_dma_chip_pdata idma32_chip_pdata = { + .pdata = &idma32_pdata, + .probe = idma32_dma_probe, + .remove = idma32_dma_remove, +}; + #endif /* _DMA_DW_INTERNAL_H */ diff --git a/drivers/dma/dw/of.c b/drivers/dma/dw/of.c new file mode 100644 index 0000000000000000000000000000000000000000..9e27831dee324d0db00ab0494ba0d6351335cd73 --- /dev/null +++ b/drivers/dma/dw/of.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Platform driver for the Synopsys DesignWare DMA Controller + * + * Copyright (C) 2007-2008 Atmel Corporation + * Copyright (C) 2010-2011 ST Microelectronics + * Copyright (C) 2013 Intel Corporation + */ + +#include +#include +#include + +#include "internal.h" + +static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct dw_dma *dw = ofdma->of_dma_data; + struct dw_dma_slave slave = { + .dma_dev = dw->dma.dev, + }; + dma_cap_mask_t cap; + + if (dma_spec->args_count != 3) + return NULL; + + slave.src_id = dma_spec->args[0]; + slave.dst_id = dma_spec->args[0]; + slave.m_master = dma_spec->args[1]; + slave.p_master = dma_spec->args[2]; + + if (WARN_ON(slave.src_id >= DW_DMA_MAX_NR_REQUESTS || + slave.dst_id >= DW_DMA_MAX_NR_REQUESTS || + slave.m_master >= dw->pdata->nr_masters || + slave.p_master >= dw->pdata->nr_masters)) + return NULL; + + dma_cap_zero(cap); + dma_cap_set(DMA_SLAVE, cap); + + /* TODO: there should be a simpler way to do this */ + return dma_request_channel(cap, dw_dma_filter, &slave); +} + +struct dw_dma_platform_data *dw_dma_parse_dt(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct dw_dma_platform_data *pdata; + u32 tmp, arr[DW_DMA_MAX_NR_MASTERS], mb[DW_DMA_MAX_NR_CHANNELS]; + u32 nr_masters; + u32 nr_channels; + + if (!np) { + dev_err(&pdev->dev, "Missing DT data\n"); + return NULL; + } + + if (of_property_read_u32(np, "dma-masters", &nr_masters)) + return NULL; + if (nr_masters < 1 || nr_masters > DW_DMA_MAX_NR_MASTERS) + return NULL; + + if (of_property_read_u32(np, "dma-channels", &nr_channels)) + return NULL; + if (nr_channels > DW_DMA_MAX_NR_CHANNELS) + return NULL; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + pdata->nr_masters = nr_masters; + pdata->nr_channels = nr_channels; + + if (!of_property_read_u32(np, "chan_allocation_order", &tmp)) + pdata->chan_allocation_order = (unsigned char)tmp; + + if (!of_property_read_u32(np, "chan_priority", &tmp)) + pdata->chan_priority = tmp; + + if (!of_property_read_u32(np, "block_size", &tmp)) + pdata->block_size = tmp; + + if (!of_property_read_u32_array(np, "data-width", arr, nr_masters)) { + for (tmp = 0; tmp < nr_masters; tmp++) + pdata->data_width[tmp] = arr[tmp]; + } else if (!of_property_read_u32_array(np, "data_width", arr, nr_masters)) { + for (tmp = 0; tmp < nr_masters; tmp++) + pdata->data_width[tmp] = BIT(arr[tmp] & 0x07); + } + + if (!of_property_read_u32_array(np, "multi-block", mb, nr_channels)) { + for (tmp = 0; tmp < nr_channels; tmp++) + pdata->multi_block[tmp] = mb[tmp]; + } else { + for (tmp = 0; tmp < nr_channels; tmp++) + pdata->multi_block[tmp] = 1; + } + + if (!of_property_read_u32(np, "snps,dma-protection-control", &tmp)) { + if (tmp > CHAN_PROTCTL_MASK) + return NULL; + pdata->protctl = tmp; + } + + return pdata; +} + +void dw_dma_of_controller_register(struct dw_dma *dw) +{ + struct device *dev = dw->dma.dev; + int ret; + + if (!dev->of_node) + return; + + ret = of_dma_controller_register(dev->of_node, dw_dma_of_xlate, dw); + if (ret) + dev_err(dev, "could not register of_dma_controller\n"); +} + +void dw_dma_of_controller_free(struct dw_dma *dw) +{ + struct device *dev = dw->dma.dev; + + if (!dev->of_node) + return; + + of_dma_controller_free(dev->of_node); +} diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c index 8de87b15a9889e1976171cd0f7342e875d652fb2..cf6e8ec4c0ff47c20e7420ae3c8f4f697bb32370 100644 --- a/drivers/dma/dw/pci.c +++ b/drivers/dma/dw/pci.c @@ -12,38 +12,10 @@ #include "internal.h" -struct dw_dma_pci_data { - const struct dw_dma_platform_data *pdata; - int (*probe)(struct dw_dma_chip *chip); - int (*remove)(struct dw_dma_chip *chip); - struct dw_dma_chip *chip; -}; - -static const struct dw_dma_pci_data dw_pci_data = { - .probe = dw_dma_probe, - .remove = dw_dma_remove, -}; - -static const struct dw_dma_platform_data idma32_pdata = { - .nr_channels = 8, - .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, - .chan_priority = CHAN_PRIORITY_ASCENDING, - .block_size = 131071, - .nr_masters = 1, - .data_width = {4}, - .multi_block = {1, 1, 1, 1, 1, 1, 1, 1}, -}; - -static const struct dw_dma_pci_data idma32_pci_data = { - .pdata = &idma32_pdata, - .probe = idma32_dma_probe, - .remove = idma32_dma_remove, -}; - static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) { - const struct dw_dma_pci_data *drv_data = (void *)pid->driver_data; - struct dw_dma_pci_data *data; + const struct dw_dma_chip_pdata *drv_data = (void *)pid->driver_data; + struct dw_dma_chip_pdata *data; struct dw_dma_chip *chip; int ret; @@ -95,7 +67,7 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) static void dw_pci_remove(struct pci_dev *pdev) { - struct dw_dma_pci_data *data = pci_get_drvdata(pdev); + struct dw_dma_chip_pdata *data = pci_get_drvdata(pdev); struct dw_dma_chip *chip = data->chip; int ret; @@ -108,7 +80,7 @@ static void dw_pci_remove(struct pci_dev *pdev) static int dw_pci_suspend_late(struct device *dev) { - struct dw_dma_pci_data *data = dev_get_drvdata(dev); + struct dw_dma_chip_pdata *data = dev_get_drvdata(dev); struct dw_dma_chip *chip = data->chip; return do_dw_dma_disable(chip); @@ -116,7 +88,7 @@ static int dw_pci_suspend_late(struct device *dev) static int dw_pci_resume_early(struct device *dev) { - struct dw_dma_pci_data *data = dev_get_drvdata(dev); + struct dw_dma_chip_pdata *data = dev_get_drvdata(dev); struct dw_dma_chip *chip = data->chip; return do_dw_dma_enable(chip); @@ -130,29 +102,29 @@ static const struct dev_pm_ops dw_pci_dev_pm_ops = { static const struct pci_device_id dw_pci_id_table[] = { /* Medfield (GPDMA) */ - { PCI_VDEVICE(INTEL, 0x0827), (kernel_ulong_t)&dw_pci_data }, + { PCI_VDEVICE(INTEL, 0x0827), (kernel_ulong_t)&dw_dma_chip_pdata }, /* BayTrail */ - { PCI_VDEVICE(INTEL, 0x0f06), (kernel_ulong_t)&dw_pci_data }, - { PCI_VDEVICE(INTEL, 0x0f40), (kernel_ulong_t)&dw_pci_data }, + { PCI_VDEVICE(INTEL, 0x0f06), (kernel_ulong_t)&dw_dma_chip_pdata }, + { PCI_VDEVICE(INTEL, 0x0f40), (kernel_ulong_t)&dw_dma_chip_pdata }, /* Merrifield */ - { PCI_VDEVICE(INTEL, 0x11a2), (kernel_ulong_t)&idma32_pci_data }, + { PCI_VDEVICE(INTEL, 0x11a2), (kernel_ulong_t)&idma32_chip_pdata }, /* Braswell */ - { PCI_VDEVICE(INTEL, 0x2286), (kernel_ulong_t)&dw_pci_data }, - { PCI_VDEVICE(INTEL, 0x22c0), (kernel_ulong_t)&dw_pci_data }, + { PCI_VDEVICE(INTEL, 0x2286), (kernel_ulong_t)&dw_dma_chip_pdata }, + { PCI_VDEVICE(INTEL, 0x22c0), (kernel_ulong_t)&dw_dma_chip_pdata }, - /* Elkhart Lake iDMA 32-bit (OSE DMA) */ - { PCI_VDEVICE(INTEL, 0x4bb4), (kernel_ulong_t)&idma32_pci_data }, - { PCI_VDEVICE(INTEL, 0x4bb5), (kernel_ulong_t)&idma32_pci_data }, - { PCI_VDEVICE(INTEL, 0x4bb6), (kernel_ulong_t)&idma32_pci_data }, + /* Elkhart Lake iDMA 32-bit (PSE DMA) */ + { PCI_VDEVICE(INTEL, 0x4bb4), (kernel_ulong_t)&idma32_chip_pdata }, + { PCI_VDEVICE(INTEL, 0x4bb5), (kernel_ulong_t)&idma32_chip_pdata }, + { PCI_VDEVICE(INTEL, 0x4bb6), (kernel_ulong_t)&idma32_chip_pdata }, /* Haswell */ - { PCI_VDEVICE(INTEL, 0x9c60), (kernel_ulong_t)&dw_pci_data }, + { PCI_VDEVICE(INTEL, 0x9c60), (kernel_ulong_t)&dw_dma_chip_pdata }, /* Broadwell */ - { PCI_VDEVICE(INTEL, 0x9ce0), (kernel_ulong_t)&dw_pci_data }, + { PCI_VDEVICE(INTEL, 0x9ce0), (kernel_ulong_t)&dw_dma_chip_pdata }, { } }; diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 382dfd9e9600e2753c09e7d82c71f5e936e3c430..c90c798e5ec347f8b2ddf4dbb4a6bd650834d46b 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -17,163 +17,28 @@ #include #include #include -#include #include -#include #include "internal.h" #define DRV_NAME "dw_dmac" -static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec, - struct of_dma *ofdma) -{ - struct dw_dma *dw = ofdma->of_dma_data; - struct dw_dma_slave slave = { - .dma_dev = dw->dma.dev, - }; - dma_cap_mask_t cap; - - if (dma_spec->args_count != 3) - return NULL; - - slave.src_id = dma_spec->args[0]; - slave.dst_id = dma_spec->args[0]; - slave.m_master = dma_spec->args[1]; - slave.p_master = dma_spec->args[2]; - - if (WARN_ON(slave.src_id >= DW_DMA_MAX_NR_REQUESTS || - slave.dst_id >= DW_DMA_MAX_NR_REQUESTS || - slave.m_master >= dw->pdata->nr_masters || - slave.p_master >= dw->pdata->nr_masters)) - return NULL; - - dma_cap_zero(cap); - dma_cap_set(DMA_SLAVE, cap); - - /* TODO: there should be a simpler way to do this */ - return dma_request_channel(cap, dw_dma_filter, &slave); -} - -#ifdef CONFIG_ACPI -static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param) -{ - struct acpi_dma_spec *dma_spec = param; - struct dw_dma_slave slave = { - .dma_dev = dma_spec->dev, - .src_id = dma_spec->slave_id, - .dst_id = dma_spec->slave_id, - .m_master = 0, - .p_master = 1, - }; - - return dw_dma_filter(chan, &slave); -} - -static void dw_dma_acpi_controller_register(struct dw_dma *dw) -{ - struct device *dev = dw->dma.dev; - struct acpi_dma_filter_info *info; - int ret; - - info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); - if (!info) - return; - - dma_cap_zero(info->dma_cap); - dma_cap_set(DMA_SLAVE, info->dma_cap); - info->filter_fn = dw_dma_acpi_filter; - - ret = devm_acpi_dma_controller_register(dev, acpi_dma_simple_xlate, - info); - if (ret) - dev_err(dev, "could not register acpi_dma_controller\n"); -} -#else /* !CONFIG_ACPI */ -static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {} -#endif /* !CONFIG_ACPI */ - -#ifdef CONFIG_OF -static struct dw_dma_platform_data * -dw_dma_parse_dt(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct dw_dma_platform_data *pdata; - u32 tmp, arr[DW_DMA_MAX_NR_MASTERS], mb[DW_DMA_MAX_NR_CHANNELS]; - u32 nr_masters; - u32 nr_channels; - - if (!np) { - dev_err(&pdev->dev, "Missing DT data\n"); - return NULL; - } - - if (of_property_read_u32(np, "dma-masters", &nr_masters)) - return NULL; - if (nr_masters < 1 || nr_masters > DW_DMA_MAX_NR_MASTERS) - return NULL; - - if (of_property_read_u32(np, "dma-channels", &nr_channels)) - return NULL; - if (nr_channels > DW_DMA_MAX_NR_CHANNELS) - return NULL; - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return NULL; - - pdata->nr_masters = nr_masters; - pdata->nr_channels = nr_channels; - - if (!of_property_read_u32(np, "chan_allocation_order", &tmp)) - pdata->chan_allocation_order = (unsigned char)tmp; - - if (!of_property_read_u32(np, "chan_priority", &tmp)) - pdata->chan_priority = tmp; - - if (!of_property_read_u32(np, "block_size", &tmp)) - pdata->block_size = tmp; - - if (!of_property_read_u32_array(np, "data-width", arr, nr_masters)) { - for (tmp = 0; tmp < nr_masters; tmp++) - pdata->data_width[tmp] = arr[tmp]; - } else if (!of_property_read_u32_array(np, "data_width", arr, nr_masters)) { - for (tmp = 0; tmp < nr_masters; tmp++) - pdata->data_width[tmp] = BIT(arr[tmp] & 0x07); - } - - if (!of_property_read_u32_array(np, "multi-block", mb, nr_channels)) { - for (tmp = 0; tmp < nr_channels; tmp++) - pdata->multi_block[tmp] = mb[tmp]; - } else { - for (tmp = 0; tmp < nr_channels; tmp++) - pdata->multi_block[tmp] = 1; - } - - if (!of_property_read_u32(np, "snps,dma-protection-control", &tmp)) { - if (tmp > CHAN_PROTCTL_MASK) - return NULL; - pdata->protctl = tmp; - } - - return pdata; -} -#else -static inline struct dw_dma_platform_data * -dw_dma_parse_dt(struct platform_device *pdev) -{ - return NULL; -} -#endif - static int dw_probe(struct platform_device *pdev) { + const struct dw_dma_chip_pdata *match; + struct dw_dma_chip_pdata *data; struct dw_dma_chip *chip; struct device *dev = &pdev->dev; - struct resource *mem; - const struct dw_dma_platform_data *pdata; int err; + match = device_get_match_data(dev); + if (!match) + return -ENODEV; + + data = devm_kmemdup(&pdev->dev, match, sizeof(*match), GFP_KERNEL); + if (!data) + return -ENOMEM; + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; @@ -182,8 +47,7 @@ static int dw_probe(struct platform_device *pdev) if (chip->irq < 0) return chip->irq; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - chip->regs = devm_ioremap_resource(dev, mem); + chip->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(chip->regs)) return PTR_ERR(chip->regs); @@ -191,13 +55,16 @@ static int dw_probe(struct platform_device *pdev) if (err) return err; - pdata = dev_get_platdata(dev); - if (!pdata) - pdata = dw_dma_parse_dt(pdev); + if (!data->pdata) + data->pdata = dev_get_platdata(dev); + if (!data->pdata) + data->pdata = dw_dma_parse_dt(pdev); chip->dev = dev; chip->id = pdev->id; - chip->pdata = pdata; + chip->pdata = data->pdata; + + data->chip = chip; chip->clk = devm_clk_get(chip->dev, "hclk"); if (IS_ERR(chip->clk)) @@ -208,22 +75,15 @@ static int dw_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); - err = dw_dma_probe(chip); + err = data->probe(chip); if (err) goto err_dw_dma_probe; - platform_set_drvdata(pdev, chip); + platform_set_drvdata(pdev, data); - if (pdev->dev.of_node) { - err = of_dma_controller_register(pdev->dev.of_node, - dw_dma_of_xlate, chip->dw); - if (err) - dev_err(&pdev->dev, - "could not register of_dma_controller\n"); - } + dw_dma_of_controller_register(chip->dw); - if (ACPI_HANDLE(&pdev->dev)) - dw_dma_acpi_controller_register(chip->dw); + dw_dma_acpi_controller_register(chip->dw); return 0; @@ -235,12 +95,18 @@ static int dw_probe(struct platform_device *pdev) static int dw_remove(struct platform_device *pdev) { - struct dw_dma_chip *chip = platform_get_drvdata(pdev); + struct dw_dma_chip_pdata *data = platform_get_drvdata(pdev); + struct dw_dma_chip *chip = data->chip; + int ret; + + dw_dma_acpi_controller_free(chip->dw); - if (pdev->dev.of_node) - of_dma_controller_free(pdev->dev.of_node); + dw_dma_of_controller_free(chip->dw); + + ret = data->remove(chip); + if (ret) + dev_warn(chip->dev, "can't remove device properly: %d\n", ret); - dw_dma_remove(chip); pm_runtime_disable(&pdev->dev); clk_disable_unprepare(chip->clk); @@ -249,7 +115,8 @@ static int dw_remove(struct platform_device *pdev) static void dw_shutdown(struct platform_device *pdev) { - struct dw_dma_chip *chip = platform_get_drvdata(pdev); + struct dw_dma_chip_pdata *data = platform_get_drvdata(pdev); + struct dw_dma_chip *chip = data->chip; /* * We have to call do_dw_dma_disable() to stop any ongoing transfer. On @@ -269,7 +136,7 @@ static void dw_shutdown(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id dw_dma_of_id_table[] = { - { .compatible = "snps,dma-spear1340" }, + { .compatible = "snps,dma-spear1340", .data = &dw_dma_chip_pdata }, {} }; MODULE_DEVICE_TABLE(of, dw_dma_of_id_table); @@ -277,9 +144,15 @@ MODULE_DEVICE_TABLE(of, dw_dma_of_id_table); #ifdef CONFIG_ACPI static const struct acpi_device_id dw_dma_acpi_id_table[] = { - { "INTL9C60", 0 }, - { "80862286", 0 }, - { "808622C0", 0 }, + { "INTL9C60", (kernel_ulong_t)&dw_dma_chip_pdata }, + { "80862286", (kernel_ulong_t)&dw_dma_chip_pdata }, + { "808622C0", (kernel_ulong_t)&dw_dma_chip_pdata }, + + /* Elkhart Lake iDMA 32-bit (PSE DMA) */ + { "80864BB4", (kernel_ulong_t)&idma32_chip_pdata }, + { "80864BB5", (kernel_ulong_t)&idma32_chip_pdata }, + { "80864BB6", (kernel_ulong_t)&idma32_chip_pdata }, + { } }; MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table); @@ -289,7 +162,8 @@ MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table); static int dw_suspend_late(struct device *dev) { - struct dw_dma_chip *chip = dev_get_drvdata(dev); + struct dw_dma_chip_pdata *data = dev_get_drvdata(dev); + struct dw_dma_chip *chip = data->chip; do_dw_dma_disable(chip); clk_disable_unprepare(chip->clk); @@ -299,7 +173,8 @@ static int dw_suspend_late(struct device *dev) static int dw_resume_early(struct device *dev) { - struct dw_dma_chip *chip = dev_get_drvdata(dev); + struct dw_dma_chip_pdata *data = dev_get_drvdata(dev); + struct dw_dma_chip *chip = data->chip; int ret; ret = clk_prepare_enable(chip->clk); diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index 44d92c34dec31d4850566ca8d1809e623164e785..b1a7ca91701a80365e74e2f0d6669b8816297629 100644 --- a/drivers/dma/fsl-edma-common.c +++ b/drivers/dma/fsl-edma-common.c @@ -90,8 +90,21 @@ static void mux_configure8(struct fsl_edma_chan *fsl_chan, void __iomem *addr, iowrite8(val8, addr + off); } +static void mux_configure32(struct fsl_edma_chan *fsl_chan, void __iomem *addr, + u32 off, u32 slot, bool enable) +{ + u32 val; + + if (enable) + val = EDMAMUX_CHCFG_ENBL << 24 | slot; + else + val = EDMAMUX_CHCFG_DIS; + + iowrite32(val, addr + off * 4); +} + void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan, - unsigned int slot, bool enable) + unsigned int slot, bool enable) { u32 ch = fsl_chan->vchan.chan.chan_id; void __iomem *muxaddr; @@ -103,7 +116,10 @@ void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan, muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux]; slot = EDMAMUX_CHCFG_SOURCE(slot); - mux_configure8(fsl_chan, muxaddr, ch_off, slot, enable); + if (fsl_chan->edma->drvdata->version == v3) + mux_configure32(fsl_chan, muxaddr, ch_off, slot, enable); + else + mux_configure8(fsl_chan, muxaddr, ch_off, slot, enable); } EXPORT_SYMBOL_GPL(fsl_edma_chan_mux); diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h index 4e175560292ca26ab3370ae2e88e96a3ca0bcdbb..5eaa2902ed3919e370f6c77cb401b2ca21f5781f 100644 --- a/drivers/dma/fsl-edma-common.h +++ b/drivers/dma/fsl-edma-common.h @@ -125,6 +125,7 @@ struct fsl_edma_chan { dma_addr_t dma_dev_addr; u32 dma_dev_size; enum dma_data_direction dma_dir; + char chan_name[16]; }; struct fsl_edma_desc { @@ -139,11 +140,13 @@ struct fsl_edma_desc { enum edma_version { v1, /* 32ch, Vybrid, mpc57x, etc */ v2, /* 64ch Coldfire */ + v3, /* 32ch, i.mx7ulp */ }; struct fsl_edma_drvdata { enum edma_version version; u32 dmamuxs; + bool has_dmaclk; int (*setup_irq)(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma); }; @@ -153,6 +156,7 @@ struct fsl_edma_engine { void __iomem *membase; void __iomem *muxbase[DMAMUX_NR]; struct clk *muxclk[DMAMUX_NR]; + struct clk *dmaclk; struct mutex fsl_edma_mutex; const struct fsl_edma_drvdata *drvdata; u32 n_chans; diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c index fcbad6ae954a820774f994fbaf1c99d7130df005..b626c06ac2e0bb3d502c5e9625caa9b26e11f9c1 100644 --- a/drivers/dma/fsl-edma.c +++ b/drivers/dma/fsl-edma.c @@ -20,6 +20,13 @@ #include "fsl-edma-common.h" +static void fsl_edma_synchronize(struct dma_chan *chan) +{ + struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); + + vchan_synchronize(&fsl_chan->vchan); +} + static irqreturn_t fsl_edma_tx_handler(int irq, void *dev_id) { struct fsl_edma_engine *fsl_edma = dev_id; @@ -125,16 +132,12 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma int ret; fsl_edma->txirq = platform_get_irq_byname(pdev, "edma-tx"); - if (fsl_edma->txirq < 0) { - dev_err(&pdev->dev, "Can't get edma-tx irq.\n"); + if (fsl_edma->txirq < 0) return fsl_edma->txirq; - } fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err"); - if (fsl_edma->errirq < 0) { - dev_err(&pdev->dev, "Can't get edma-err irq.\n"); + if (fsl_edma->errirq < 0) return fsl_edma->errirq; - } if (fsl_edma->txirq == fsl_edma->errirq) { ret = devm_request_irq(&pdev->dev, fsl_edma->txirq, @@ -162,6 +165,49 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma return 0; } +static int +fsl_edma2_irq_init(struct platform_device *pdev, + struct fsl_edma_engine *fsl_edma) +{ + int i, ret, irq; + int count; + + count = platform_irq_count(pdev); + dev_dbg(&pdev->dev, "%s Found %d interrupts\r\n", __func__, count); + if (count <= 2) { + dev_err(&pdev->dev, "Interrupts in DTS not correct.\n"); + return -EINVAL; + } + /* + * 16 channel independent interrupts + 1 error interrupt on i.mx7ulp. + * 2 channel share one interrupt, for example, ch0/ch16, ch1/ch17... + * For now, just simply request irq without IRQF_SHARED flag, since 16 + * channels are enough on i.mx7ulp whose M4 domain own some peripherals. + */ + for (i = 0; i < count; i++) { + irq = platform_get_irq(pdev, i); + if (irq < 0) + return -ENXIO; + + sprintf(fsl_edma->chans[i].chan_name, "eDMA2-CH%02d", i); + + /* The last IRQ is for eDMA err */ + if (i == count - 1) + ret = devm_request_irq(&pdev->dev, irq, + fsl_edma_err_handler, + 0, "eDMA2-ERR", fsl_edma); + else + ret = devm_request_irq(&pdev->dev, irq, + fsl_edma_tx_handler, 0, + fsl_edma->chans[i].chan_name, + fsl_edma); + if (ret) + return ret; + } + + return 0; +} + static void fsl_edma_irq_exit( struct platform_device *pdev, struct fsl_edma_engine *fsl_edma) { @@ -187,8 +233,16 @@ static struct fsl_edma_drvdata vf610_data = { .setup_irq = fsl_edma_irq_init, }; +static struct fsl_edma_drvdata imx7ulp_data = { + .version = v3, + .dmamuxs = 1, + .has_dmaclk = true, + .setup_irq = fsl_edma2_irq_init, +}; + static const struct of_device_id fsl_edma_dt_ids[] = { { .compatible = "fsl,vf610-edma", .data = &vf610_data}, + { .compatible = "fsl,imx7ulp-edma", .data = &imx7ulp_data}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids); @@ -236,6 +290,20 @@ static int fsl_edma_probe(struct platform_device *pdev) fsl_edma_setup_regs(fsl_edma); regs = &fsl_edma->regs; + if (drvdata->has_dmaclk) { + fsl_edma->dmaclk = devm_clk_get(&pdev->dev, "dma"); + if (IS_ERR(fsl_edma->dmaclk)) { + dev_err(&pdev->dev, "Missing DMA block clock.\n"); + return PTR_ERR(fsl_edma->dmaclk); + } + + ret = clk_prepare_enable(fsl_edma->dmaclk); + if (ret) { + dev_err(&pdev->dev, "DMA clk block failed.\n"); + return ret; + } + } + for (i = 0; i < fsl_edma->drvdata->dmamuxs; i++) { char clkname[32]; @@ -302,6 +370,7 @@ static int fsl_edma_probe(struct platform_device *pdev) fsl_edma->dma_dev.device_pause = fsl_edma_pause; fsl_edma->dma_dev.device_resume = fsl_edma_resume; fsl_edma->dma_dev.device_terminate_all = fsl_edma_terminate_all; + fsl_edma->dma_dev.device_synchronize = fsl_edma_synchronize; fsl_edma->dma_dev.device_issue_pending = fsl_edma_issue_pending; fsl_edma->dma_dev.src_addr_widths = FSL_EDMA_BUSWIDTHS; diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c index 8e341c0c13bcf5772e7a33eedb9fc6e045c46895..06664fbd2d911638167f35ea06ea57bd0d2565f0 100644 --- a/drivers/dma/fsl-qdma.c +++ b/drivers/dma/fsl-qdma.c @@ -758,10 +758,8 @@ fsl_qdma_irq_init(struct platform_device *pdev, fsl_qdma->error_irq = platform_get_irq_byname(pdev, "qdma-error"); - if (fsl_qdma->error_irq < 0) { - dev_err(&pdev->dev, "Can't get qdma controller irq.\n"); + if (fsl_qdma->error_irq < 0) return fsl_qdma->error_irq; - } ret = devm_request_irq(&pdev->dev, fsl_qdma->error_irq, fsl_qdma_error_handler, 0, @@ -776,11 +774,8 @@ fsl_qdma_irq_init(struct platform_device *pdev, fsl_qdma->queue_irq[i] = platform_get_irq_byname(pdev, irq_name); - if (fsl_qdma->queue_irq[i] < 0) { - dev_err(&pdev->dev, - "Can't get qdma queue %d irq.\n", i); + if (fsl_qdma->queue_irq[i] < 0) return fsl_qdma->queue_irq[i]; - } ret = devm_request_irq(&pdev->dev, fsl_qdma->queue_irq[i], diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 00a089e24150ac235877702586e049a48c2e5a2d..5c0fb3134825f56ce02af12738eabcbdbfcbbacf 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -556,6 +556,7 @@ static int imxdma_xfer_desc(struct imxdma_desc *d) * We fall-through here intentionally, since a 2D transfer is * similar to MEMCPY just adding the 2D slot configuration. */ + /* Fall through */ case IMXDMA_DESC_MEMCPY: imx_dmav1_writel(imxdma, d->src, DMA_SAR(imxdmac->channel)); imx_dmav1_writel(imxdma, d->dest, DMA_DAR(imxdmac->channel)); diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index a01f4b5d793c4ed591b6666110b7ed00e5bce8e6..9ba74ab7e912e90fe78ab9f02b4120d79ab14fb4 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1886,10 +1886,6 @@ static int sdma_init(struct sdma_engine *sdma) sdma->context_phys = ccb_phys + MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control); - /* Zero-out the CCB structures array just allocated */ - memset(sdma->channel_control, 0, - MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control)); - /* disable all channels */ for (i = 0; i < sdma->drvdata->num_events; i++) writel_relaxed(0, sdma->regs + chnenbl_ofs(sdma, i)); diff --git a/drivers/dma/ioat/dca.c b/drivers/dma/ioat/dca.c index 70fd8454d0025556689fbe93912f72c7bb57d105..be61c32a876f1196a259eadc4b33544cf9138fb1 100644 --- a/drivers/dma/ioat/dca.c +++ b/drivers/dma/ioat/dca.c @@ -286,8 +286,7 @@ struct dca_provider *ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase) return NULL; dca = alloc_dca_provider(&ioat_dca_ops, - sizeof(*ioatdca) - + (sizeof(struct ioat_dca_slot) * slots)); + struct_size(ioatdca, req_slots, slots)); if (!dca) return NULL; diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index c6c0143670d9d5a543b15a3d8a50e45adb5c04b5..a3f942a6a946ab7c40196f6152891b62302a5e3a 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -16,13 +16,13 @@ #include #include #include +#include #include #include #include #include -#include - +#include "iop-adma.h" #include "dmaengine.h" #define to_iop_adma_chan(chan) container_of(chan, struct iop_adma_chan, common) @@ -116,9 +116,9 @@ static void __iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan) list_for_each_entry_safe(iter, _iter, &iop_chan->chain, chain_node) { pr_debug("\tcookie: %d slot: %d busy: %d " - "this_desc: %#x next_desc: %#x ack: %d\n", + "this_desc: %pad next_desc: %#llx ack: %d\n", iter->async_tx.cookie, iter->idx, busy, - iter->async_tx.phys, iop_desc_get_next_desc(iter), + &iter->async_tx.phys, (u64)iop_desc_get_next_desc(iter), async_tx_test_ack(&iter->async_tx)); prefetch(_iter); prefetch(&_iter->async_tx); @@ -306,9 +306,9 @@ iop_adma_alloc_slots(struct iop_adma_chan *iop_chan, int num_slots, int i; dev_dbg(iop_chan->device->common.dev, "allocated slot: %d " - "(desc %p phys: %#x) slots_per_op %d\n", + "(desc %p phys: %#llx) slots_per_op %d\n", iter->idx, iter->hw_desc, - iter->async_tx.phys, slots_per_op); + (u64)iter->async_tx.phys, slots_per_op); /* pre-ack all but the last descriptor */ if (num_slots != slots_per_op) @@ -364,13 +364,11 @@ iop_adma_tx_submit(struct dma_async_tx_descriptor *tx) struct iop_adma_chan *iop_chan = to_iop_adma_chan(tx->chan); struct iop_adma_desc_slot *grp_start, *old_chain_tail; int slot_cnt; - int slots_per_op; dma_cookie_t cookie; dma_addr_t next_dma; grp_start = sw_desc->group_head; slot_cnt = grp_start->slot_cnt; - slots_per_op = grp_start->slots_per_op; spin_lock_bh(&iop_chan->lock); cookie = dma_cookie_assign(tx); @@ -516,7 +514,7 @@ iop_adma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dma_dest, return NULL; BUG_ON(len > IOP_ADMA_MAX_BYTE_COUNT); - dev_dbg(iop_chan->device->common.dev, "%s len: %u\n", + dev_dbg(iop_chan->device->common.dev, "%s len: %zu\n", __func__, len); spin_lock_bh(&iop_chan->lock); @@ -549,7 +547,7 @@ iop_adma_prep_dma_xor(struct dma_chan *chan, dma_addr_t dma_dest, BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT); dev_dbg(iop_chan->device->common.dev, - "%s src_cnt: %d len: %u flags: %lx\n", + "%s src_cnt: %d len: %zu flags: %lx\n", __func__, src_cnt, len, flags); spin_lock_bh(&iop_chan->lock); @@ -582,7 +580,7 @@ iop_adma_prep_dma_xor_val(struct dma_chan *chan, dma_addr_t *dma_src, if (unlikely(!len)) return NULL; - dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %u\n", + dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %zu\n", __func__, src_cnt, len); spin_lock_bh(&iop_chan->lock); @@ -620,7 +618,7 @@ iop_adma_prep_dma_pq(struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src, BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT); dev_dbg(iop_chan->device->common.dev, - "%s src_cnt: %d len: %u flags: %lx\n", + "%s src_cnt: %d len: %zu flags: %lx\n", __func__, src_cnt, len, flags); if (dmaf_p_disabled_continue(flags)) @@ -683,7 +681,7 @@ iop_adma_prep_dma_pq_val(struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src, return NULL; BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT); - dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %u\n", + dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %zu\n", __func__, src_cnt, len); spin_lock_bh(&iop_chan->lock); diff --git a/arch/arm/include/asm/hardware/iop3xx-adma.h b/drivers/dma/iop-adma.h similarity index 99% rename from arch/arm/include/asm/hardware/iop3xx-adma.h rename to drivers/dma/iop-adma.h index 6d998df17efd1a54a9cb26c3a34e159328499289..c499c9578f0097d4f00c3ef215a7f3e80fe0f555 100644 --- a/arch/arm/include/asm/hardware/iop3xx-adma.h +++ b/drivers/dma/iop-adma.h @@ -6,8 +6,7 @@ #define _ADMA_H #include #include -#include -#include +#include /* Memory copy units */ #define DMA_CCR(chan) (chan->mmr_base + 0x0) @@ -34,10 +33,6 @@ #define AAU_EDCR1_IDX 17 #define AAU_EDCR2_IDX 26 -#define DMA0_ID 0 -#define DMA1_ID 1 -#define AAU_ID 2 - struct iop3xx_aau_desc_ctrl { unsigned int int_en:1; unsigned int blk1_cmd_ctrl:3; diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c index 546995c2087637c8bfdce527ee9c739332ed9adf..f40051d6aecbcd51bcdf04f560ac130624fea596 100644 --- a/drivers/dma/mediatek/mtk-uart-apdma.c +++ b/drivers/dma/mediatek/mtk-uart-apdma.c @@ -547,10 +547,8 @@ static int mtk_uart_apdma_probe(struct platform_device *pdev) vchan_init(&c->vc, &mtkd->ddev); rc = platform_get_irq(pdev, i); - if (rc < 0) { - dev_err(&pdev->dev, "failed to get IRQ[%d]\n", i); + if (rc < 0) goto err_no_dma; - } c->irq = rc; } diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c index fa5dab481203ce36534b905f47f34aec0d443f82..e3850f04f6763fd81527eca39879e14d80cd70eb 100644 --- a/drivers/dma/mv_xor_v2.c +++ b/drivers/dma/mv_xor_v2.c @@ -33,7 +33,6 @@ #define MV_XOR_V2_DMA_IMSG_CDAT_OFF 0x014 #define MV_XOR_V2_DMA_IMSG_THRD_OFF 0x018 #define MV_XOR_V2_DMA_IMSG_THRD_MASK 0x7FFF -#define MV_XOR_V2_DMA_IMSG_THRD_SHIFT 0x0 #define MV_XOR_V2_DMA_IMSG_TIMER_EN BIT(18) #define MV_XOR_V2_DMA_DESQ_AWATTR_OFF 0x01C /* Same flags as MV_XOR_V2_DMA_DESQ_ARATTR_OFF */ @@ -50,7 +49,6 @@ #define MV_XOR_V2_DMA_DESQ_ADD_OFF 0x808 #define MV_XOR_V2_DMA_IMSG_TMOT 0x810 #define MV_XOR_V2_DMA_IMSG_TIMER_THRD_MASK 0x1FFF -#define MV_XOR_V2_DMA_IMSG_TIMER_THRD_SHIFT 0 /* XOR Global registers */ #define MV_XOR_V2_GLOB_BW_CTRL 0x4 @@ -261,16 +259,15 @@ void mv_xor_v2_enable_imsg_thrd(struct mv_xor_v2_device *xor_dev) /* Configure threshold of number of descriptors, and enable timer */ reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_THRD_OFF); - reg &= (~MV_XOR_V2_DMA_IMSG_THRD_MASK << MV_XOR_V2_DMA_IMSG_THRD_SHIFT); - reg |= (MV_XOR_V2_DONE_IMSG_THRD << MV_XOR_V2_DMA_IMSG_THRD_SHIFT); + reg &= ~MV_XOR_V2_DMA_IMSG_THRD_MASK; + reg |= MV_XOR_V2_DONE_IMSG_THRD; reg |= MV_XOR_V2_DMA_IMSG_TIMER_EN; writel(reg, xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_THRD_OFF); /* Configure Timer Threshold */ reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_TMOT); - reg &= (~MV_XOR_V2_DMA_IMSG_TIMER_THRD_MASK << - MV_XOR_V2_DMA_IMSG_TIMER_THRD_SHIFT); - reg |= (MV_XOR_V2_TIMER_THRD << MV_XOR_V2_DMA_IMSG_TIMER_THRD_SHIFT); + reg &= ~MV_XOR_V2_DMA_IMSG_TIMER_THRD_MASK; + reg |= MV_XOR_V2_TIMER_THRD; writel(reg, xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_TMOT); } diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 1163af2ba4a36fef2f313dd09236eee4039236de..6cce9ef61b2944020d67c821606e3451bd2e33bb 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -1922,9 +1922,10 @@ static int dmac_alloc_resources(struct pl330_dmac *pl330) if (ret) { dev_err(pl330->ddma.dev, "%s:%d Can't to create channels for DMAC!\n", __func__, __LINE__); - dma_free_coherent(pl330->ddma.dev, + dma_free_attrs(pl330->ddma.dev, chans * pl330->mcbufsz, - pl330->mcode_cpu, pl330->mcode_bus); + pl330->mcode_cpu, pl330->mcode_bus, + DMA_ATTR_PRIVILEGED); return ret; } @@ -2003,9 +2004,9 @@ static void pl330_del(struct pl330_dmac *pl330) /* Free DMAC resources */ dmac_free_threads(pl330); - dma_free_coherent(pl330->ddma.dev, + dma_free_attrs(pl330->ddma.dev, pl330->pcfg.num_chan * pl330->mcbufsz, pl330->mcode_cpu, - pl330->mcode_bus); + pl330->mcode_bus, DMA_ATTR_PRIVILEGED); } /* forward declaration */ diff --git a/drivers/dma/qcom/hidma_ll.c b/drivers/dma/qcom/hidma_ll.c index 5bf8b145c427c890971e30d5fdf334114bdc27a9..bb4471e84e484554231229def9921a967ebc0413 100644 --- a/drivers/dma/qcom/hidma_ll.c +++ b/drivers/dma/qcom/hidma_ll.c @@ -749,7 +749,6 @@ struct hidma_lldev *hidma_ll_init(struct device *dev, u32 nr_tres, if (!lldev->tre_ring) return NULL; - memset(lldev->tre_ring, 0, (HIDMA_TRE_SIZE + 1) * nr_tres); lldev->tre_ring_size = HIDMA_TRE_SIZE * nr_tres; lldev->nr_tres = nr_tres; @@ -769,7 +768,6 @@ struct hidma_lldev *hidma_ll_init(struct device *dev, u32 nr_tres, if (!lldev->evre_ring) return NULL; - memset(lldev->evre_ring, 0, (HIDMA_EVRE_SIZE + 1) * nr_tres); lldev->evre_ring_size = HIDMA_EVRE_SIZE * nr_tres; /* the EVRE ring has to be EVRE_SIZE aligned */ diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c index 3022d66e7a33bd681b1ee79cf645bc84a5f29b50..806ca02c52d711702793c13804b1fec4ae5ea9ad 100644 --- a/drivers/dma/qcom/hidma_mgmt.c +++ b/drivers/dma/qcom/hidma_mgmt.c @@ -183,7 +183,6 @@ static int hidma_mgmt_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "irq resources not found\n"); rc = irq; goto out; } @@ -388,7 +387,6 @@ static int __init hidma_mgmt_of_populate_channels(struct device_node *np) ret = PTR_ERR(new_pdev); goto out; } - of_node_get(child); new_pdev->dev.of_node = child; of_dma_configure(&new_pdev->dev, child, true); /* @@ -396,9 +394,14 @@ static int __init hidma_mgmt_of_populate_channels(struct device_node *np) * platforms with or without MSI support. */ of_msi_configure(&new_pdev->dev, child); - of_node_put(child); } + + kfree(res); + + return ret; + out: + of_node_put(child); kfree(res); return ret; diff --git a/drivers/dma/s3c24xx-dma.c b/drivers/dma/s3c24xx-dma.c index ad30f3d2c7f693edd49a985d397b5dacb1713aa4..43da8eeb18ef0710b21c43854d2f3a951991d525 100644 --- a/drivers/dma/s3c24xx-dma.c +++ b/drivers/dma/s3c24xx-dma.c @@ -1237,11 +1237,8 @@ static int s3c24xx_dma_probe(struct platform_device *pdev) phy->host = s3cdma; phy->irq = platform_get_irq(pdev, i); - if (phy->irq < 0) { - dev_err(&pdev->dev, "failed to get irq %d, err %d\n", - i, phy->irq); + if (phy->irq < 0) continue; - } ret = devm_request_irq(&pdev->dev, phy->irq, s3c24xx_dma_irq, 0, pdev->name, phy); diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 1072c450c37ab89d7c78ea0f521927fcb13410ae..3993ab65c62cd34469f755cfdcac52da98f96fef 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -1749,10 +1749,8 @@ static int rcar_dmac_chan_probe(struct rcar_dmac *dmac, /* Request the channel interrupt. */ sprintf(pdev_irqname, "ch%u", index); rchan->irq = platform_get_irq_byname(pdev, pdev_irqname); - if (rchan->irq < 0) { - dev_err(dmac->dev, "no IRQ specified for channel %u\n", index); + if (rchan->irq < 0) return -ENODEV; - } irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:%u", dev_name(dmac->dev), index); diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c index 17063aaf51bce98b163e1a61f7430668a3d6e49d..b218a013c2600f449dac819c2ab11ab6ef74ce5e 100644 --- a/drivers/dma/sh/usb-dmac.c +++ b/drivers/dma/sh/usb-dmac.c @@ -717,10 +717,8 @@ static int usb_dmac_chan_probe(struct usb_dmac *dmac, /* Request the channel interrupt. */ sprintf(pdev_irqname, "ch%u", index); uchan->irq = platform_get_irq_byname(pdev, pdev_irqname); - if (uchan->irq < 0) { - dev_err(dmac->dev, "no IRQ specified for channel %u\n", index); + if (uchan->irq < 0) return -ENODEV; - } irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:%u", dev_name(dmac->dev), index); diff --git a/drivers/dma/st_fdma.c b/drivers/dma/st_fdma.c index a3ee0f6bb6640b3b24021e99510750e4af01b896..67087dbe2f9facd8690616304ab7eb1e076c6e8a 100644 --- a/drivers/dma/st_fdma.c +++ b/drivers/dma/st_fdma.c @@ -771,10 +771,8 @@ static int st_fdma_probe(struct platform_device *pdev) platform_set_drvdata(pdev, fdev); fdev->irq = platform_get_irq(pdev, 0); - if (fdev->irq < 0) { - dev_err(&pdev->dev, "Failed to get irq resource\n"); + if (fdev->irq < 0) return -EINVAL; - } ret = devm_request_irq(&pdev->dev, fdev->irq, st_fdma_irq_handler, 0, dev_name(&pdev->dev), fdev); diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index ef4d109e718900178f5b7f1bbacd53d5feaa142d..5989b08935211537026f289a0b1eb5bc320b4284 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -243,12 +243,6 @@ static void stm32_dma_write(struct stm32_dma_device *dmadev, u32 reg, u32 val) writel_relaxed(val, dmadev->base + reg); } -static struct stm32_dma_desc *stm32_dma_alloc_desc(u32 num_sgs) -{ - return kzalloc(sizeof(struct stm32_dma_desc) + - sizeof(struct stm32_dma_sg_req) * num_sgs, GFP_NOWAIT); -} - static int stm32_dma_get_width(struct stm32_dma_chan *chan, enum dma_slave_buswidth width) { @@ -853,7 +847,7 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( return NULL; } - desc = stm32_dma_alloc_desc(sg_len); + desc = kzalloc(struct_size(desc, sg_req, sg_len), GFP_NOWAIT); if (!desc) return NULL; @@ -954,7 +948,7 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( num_periods = buf_len / period_len; - desc = stm32_dma_alloc_desc(num_periods); + desc = kzalloc(struct_size(desc, sg_req, num_periods), GFP_NOWAIT); if (!desc) return NULL; @@ -989,7 +983,7 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( int i; num_sgs = DIV_ROUND_UP(len, STM32_DMA_ALIGNED_MAX_DATA_ITEMS); - desc = stm32_dma_alloc_desc(num_sgs); + desc = kzalloc(struct_size(desc, sg_req, num_sgs), GFP_NOWAIT); if (!desc) return NULL; @@ -1366,12 +1360,8 @@ static int stm32_dma_probe(struct platform_device *pdev) for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) { chan = &dmadev->chan[i]; ret = platform_get_irq(pdev, i); - if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "No irq resource for chan %d\n", i); + if (ret < 0) goto err_unregister; - } chan->irq = ret; ret = devm_request_irq(&pdev->dev, chan->irq, diff --git a/drivers/dma/stm32-dmamux.c b/drivers/dma/stm32-dmamux.c index b552949da14b20a3755e540bcc637dcaf661a75e..3c89bd39e09681d47cca617bdcef6cdc1d023afa 100644 --- a/drivers/dma/stm32-dmamux.c +++ b/drivers/dma/stm32-dmamux.c @@ -185,8 +185,7 @@ static int stm32_dmamux_probe(struct platform_device *pdev) if (!node) return -ENODEV; - count = device_property_read_u32_array(&pdev->dev, "dma-masters", - NULL, 0); + count = device_property_count_u32(&pdev->dev, "dma-masters"); if (count < 0) { dev_err(&pdev->dev, "Can't get DMA master(s) node\n"); return -ENODEV; diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c index 1311de74bfdde5f817937fd2a929a1e02ce00c0f..5838311cf990044f8a0b962590e851ccedc805f1 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -1555,8 +1555,7 @@ static int stm32_mdma_probe(struct platform_device *pdev) nr_requests); } - count = device_property_read_u32_array(&pdev->dev, "st,ahb-addr-masks", - NULL, 0); + count = device_property_count_u32(&pdev->dev, "st,ahb-addr-masks"); if (count < 0) count = 0; @@ -1638,10 +1637,8 @@ static int stm32_mdma_probe(struct platform_device *pdev) } dmadev->irq = platform_get_irq(pdev, 0); - if (dmadev->irq < 0) { - dev_err(&pdev->dev, "failed to get IRQ\n"); + if (dmadev->irq < 0) return dmadev->irq; - } ret = devm_request_irq(&pdev->dev, dmadev->irq, stm32_mdma_irq_handler, 0, dev_name(&pdev->dev), dmadev); diff --git a/drivers/dma/sun4i-dma.c b/drivers/dma/sun4i-dma.c index 1f80568b2613eaeb5f7998a76269292abdca5232..e397a50058c8825f2ea3ac188f8f64d160bf08dc 100644 --- a/drivers/dma/sun4i-dma.c +++ b/drivers/dma/sun4i-dma.c @@ -1132,10 +1132,8 @@ static int sun4i_dma_probe(struct platform_device *pdev) return PTR_ERR(priv->base); priv->irq = platform_get_irq(pdev, 0); - if (priv->irq < 0) { - dev_err(&pdev->dev, "Cannot claim IRQ\n"); + if (priv->irq < 0) return priv->irq; - } priv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c index ed5b68dcfe50c8bb9c6da0fbca820528d34f93dd..06cd7f867f7cafe2cb11c42c0456fb621edd09af 100644 --- a/drivers/dma/sun6i-dma.c +++ b/drivers/dma/sun6i-dma.c @@ -1251,10 +1251,8 @@ static int sun6i_dma_probe(struct platform_device *pdev) return PTR_ERR(sdc->base); sdc->irq = platform_get_irq(pdev, 0); - if (sdc->irq < 0) { - dev_err(&pdev->dev, "Cannot claim IRQ\n"); + if (sdc->irq < 0) return sdc->irq; - } sdc->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(sdc->clk)) { diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index 79e9593815f1217eb5d1887ba144c856834f51a6..3a45079d11ecff40db8ea5b1824c55894a7429e7 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -152,6 +152,7 @@ struct tegra_dma_sg_req { bool last_sg; struct list_head node; struct tegra_dma_desc *dma_desc; + unsigned int words_xferred; }; /* @@ -496,6 +497,7 @@ static void tegra_dma_configure_for_next(struct tegra_dma_channel *tdc, tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR, nsg_req->ch_regs.csr | TEGRA_APBDMA_CSR_ENB); nsg_req->configured = true; + nsg_req->words_xferred = 0; tegra_dma_resume(tdc); } @@ -511,6 +513,7 @@ static void tdc_start_head_req(struct tegra_dma_channel *tdc) typeof(*sg_req), node); tegra_dma_start(tdc, sg_req); sg_req->configured = true; + sg_req->words_xferred = 0; tdc->busy = true; } @@ -638,6 +641,8 @@ static void handle_cont_sngl_cycle_dma_done(struct tegra_dma_channel *tdc, list_add_tail(&dma_desc->cb_node, &tdc->cb_desc); dma_desc->cb_count++; + sgreq->words_xferred = 0; + /* If not last req then put at end of pending list */ if (!list_is_last(&sgreq->node, &tdc->pending_sg_req)) { list_move_tail(&sgreq->node, &tdc->pending_sg_req); @@ -797,6 +802,65 @@ static int tegra_dma_terminate_all(struct dma_chan *dc) return 0; } +static unsigned int tegra_dma_sg_bytes_xferred(struct tegra_dma_channel *tdc, + struct tegra_dma_sg_req *sg_req) +{ + unsigned long status, wcount = 0; + + if (!list_is_first(&sg_req->node, &tdc->pending_sg_req)) + return 0; + + if (tdc->tdma->chip_data->support_separate_wcount_reg) + wcount = tdc_read(tdc, TEGRA_APBDMA_CHAN_WORD_TRANSFER); + + status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS); + + if (!tdc->tdma->chip_data->support_separate_wcount_reg) + wcount = status; + + if (status & TEGRA_APBDMA_STATUS_ISE_EOC) + return sg_req->req_len; + + wcount = get_current_xferred_count(tdc, sg_req, wcount); + + if (!wcount) { + /* + * If wcount wasn't ever polled for this SG before, then + * simply assume that transfer hasn't started yet. + * + * Otherwise it's the end of the transfer. + * + * The alternative would be to poll the status register + * until EOC bit is set or wcount goes UP. That's so + * because EOC bit is getting set only after the last + * burst's completion and counter is less than the actual + * transfer size by 4 bytes. The counter value wraps around + * in a cyclic mode before EOC is set(!), so we can't easily + * distinguish start of transfer from its end. + */ + if (sg_req->words_xferred) + wcount = sg_req->req_len - 4; + + } else if (wcount < sg_req->words_xferred) { + /* + * This case will never happen for a non-cyclic transfer. + * + * For a cyclic transfer, although it is possible for the + * next transfer to have already started (resetting the word + * count), this case should still not happen because we should + * have detected that the EOC bit is set and hence the transfer + * was completed. + */ + WARN_ON_ONCE(1); + + wcount = sg_req->req_len - 4; + } else { + sg_req->words_xferred = wcount; + } + + return wcount; +} + static enum dma_status tegra_dma_tx_status(struct dma_chan *dc, dma_cookie_t cookie, struct dma_tx_state *txstate) { @@ -806,6 +870,7 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc, enum dma_status ret; unsigned long flags; unsigned int residual; + unsigned int bytes = 0; ret = dma_cookie_status(dc, cookie, txstate); if (ret == DMA_COMPLETE) @@ -825,6 +890,7 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc, list_for_each_entry(sg_req, &tdc->pending_sg_req, node) { dma_desc = sg_req->dma_desc; if (dma_desc->txd.cookie == cookie) { + bytes = tegra_dma_sg_bytes_xferred(tdc, sg_req); ret = dma_desc->dma_status; goto found; } @@ -836,7 +902,7 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc, found: if (dma_desc && txstate) { residual = dma_desc->bytes_requested - - (dma_desc->bytes_transferred % + ((dma_desc->bytes_transferred + bytes) % dma_desc->bytes_requested); dma_set_residue(txstate, residual); } @@ -1441,12 +1507,7 @@ static int tegra_dma_probe(struct platform_device *pdev) BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | BIT(DMA_SLAVE_BUSWIDTH_8_BYTES); tdma->dma_dev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); - /* - * XXX The hardware appears to support - * DMA_RESIDUE_GRANULARITY_BURST-level reporting, but it's - * only used by this driver during tegra_dma_terminate_all() - */ - tdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; + tdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; tdma->dma_dev.device_config = tegra_dma_slave_config; tdma->dma_dev.device_terminate_all = tegra_dma_terminate_all; tdma->dma_dev.device_tx_status = tegra_dma_tx_status; diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index b33cf6e8ab8ef85b67a885fafa8161ee1c989d68..5f8adf5c1f203f4c1905f728c752ed2dbbfe64b5 100644 --- a/drivers/dma/tegra210-adma.c +++ b/drivers/dma/tegra210-adma.c @@ -42,12 +42,8 @@ #define ADMA_CH_CONFIG_MAX_BUFS 8 #define ADMA_CH_FIFO_CTRL 0x2c -#define TEGRA210_ADMA_CH_FIFO_CTRL_OFLWTHRES(val) (((val) & 0xf) << 24) -#define TEGRA210_ADMA_CH_FIFO_CTRL_STRVTHRES(val) (((val) & 0xf) << 16) #define TEGRA210_ADMA_CH_FIFO_CTRL_TXSIZE(val) (((val) & 0xf) << 8) #define TEGRA210_ADMA_CH_FIFO_CTRL_RXSIZE(val) ((val) & 0xf) -#define TEGRA186_ADMA_CH_FIFO_CTRL_OFLWTHRES(val) (((val) & 0x1f) << 24) -#define TEGRA186_ADMA_CH_FIFO_CTRL_STRVTHRES(val) (((val) & 0x1f) << 16) #define TEGRA186_ADMA_CH_FIFO_CTRL_TXSIZE(val) (((val) & 0x1f) << 8) #define TEGRA186_ADMA_CH_FIFO_CTRL_RXSIZE(val) ((val) & 0x1f) @@ -64,14 +60,10 @@ #define TEGRA_ADMA_BURST_COMPLETE_TIME 20 -#define TEGRA210_FIFO_CTRL_DEFAULT (TEGRA210_ADMA_CH_FIFO_CTRL_OFLWTHRES(1) | \ - TEGRA210_ADMA_CH_FIFO_CTRL_STRVTHRES(1) | \ - TEGRA210_ADMA_CH_FIFO_CTRL_TXSIZE(3) | \ +#define TEGRA210_FIFO_CTRL_DEFAULT (TEGRA210_ADMA_CH_FIFO_CTRL_TXSIZE(3) | \ TEGRA210_ADMA_CH_FIFO_CTRL_RXSIZE(3)) -#define TEGRA186_FIFO_CTRL_DEFAULT (TEGRA186_ADMA_CH_FIFO_CTRL_OFLWTHRES(1) | \ - TEGRA186_ADMA_CH_FIFO_CTRL_STRVTHRES(1) | \ - TEGRA186_ADMA_CH_FIFO_CTRL_TXSIZE(3) | \ +#define TEGRA186_FIFO_CTRL_DEFAULT (TEGRA186_ADMA_CH_FIFO_CTRL_TXSIZE(3) | \ TEGRA186_ADMA_CH_FIFO_CTRL_RXSIZE(3)) #define ADMA_CH_REG_FIELD_VAL(val, mask, shift) (((val) & mask) << shift) diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index ceabdea40ae0fd20aca3e54fb30f2d1e7f562a28..ba7c4f07fcd6f8592cbe95e635b1091b376b9c8d 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include @@ -133,6 +133,17 @@ #define EDMA_CONT_PARAMS_FIXED_EXACT 1002 #define EDMA_CONT_PARAMS_FIXED_NOT_EXACT 1003 +/* + * 64bit array registers are split into two 32bit registers: + * reg0: channel/event 0-31 + * reg1: channel/event 32-63 + * + * bit 5 in the channel number tells the array index (0/1) + * bit 0-4 (0x1f) is the bit offset within the register + */ +#define EDMA_REG_ARRAY_INDEX(channel) ((channel) >> 5) +#define EDMA_CHANNEL_BIT(channel) (BIT((channel) & 0x1f)) + /* PaRAM slots are laid out like this */ struct edmacc_param { u32 opt; @@ -169,6 +180,7 @@ struct edma_desc { struct list_head node; enum dma_transfer_direction direction; int cyclic; + bool polled; int absync; int pset_nr; struct edma_chan *echan; @@ -412,12 +424,6 @@ static inline void edma_param_or(struct edma_cc *ecc, int offset, int param_no, edma_or(ecc, EDMA_PARM + offset + (param_no << 5), or); } -static inline void edma_set_bits(int offset, int len, unsigned long *p) -{ - for (; len > 0; len--) - set_bit(offset + (len - 1), p); -} - static void edma_assign_priority_to_queue(struct edma_cc *ecc, int queue_no, int priority) { @@ -441,15 +447,14 @@ static void edma_setup_interrupt(struct edma_chan *echan, bool enable) { struct edma_cc *ecc = echan->ecc; int channel = EDMA_CHAN_SLOT(echan->ch_num); + int idx = EDMA_REG_ARRAY_INDEX(channel); + int ch_bit = EDMA_CHANNEL_BIT(channel); if (enable) { - edma_shadow0_write_array(ecc, SH_ICR, channel >> 5, - BIT(channel & 0x1f)); - edma_shadow0_write_array(ecc, SH_IESR, channel >> 5, - BIT(channel & 0x1f)); + edma_shadow0_write_array(ecc, SH_ICR, idx, ch_bit); + edma_shadow0_write_array(ecc, SH_IESR, idx, ch_bit); } else { - edma_shadow0_write_array(ecc, SH_IECR, channel >> 5, - BIT(channel & 0x1f)); + edma_shadow0_write_array(ecc, SH_IECR, idx, ch_bit); } } @@ -587,26 +592,26 @@ static void edma_start(struct edma_chan *echan) { struct edma_cc *ecc = echan->ecc; int channel = EDMA_CHAN_SLOT(echan->ch_num); - int j = (channel >> 5); - unsigned int mask = BIT(channel & 0x1f); + int idx = EDMA_REG_ARRAY_INDEX(channel); + int ch_bit = EDMA_CHANNEL_BIT(channel); if (!echan->hw_triggered) { /* EDMA channels without event association */ - dev_dbg(ecc->dev, "ESR%d %08x\n", j, - edma_shadow0_read_array(ecc, SH_ESR, j)); - edma_shadow0_write_array(ecc, SH_ESR, j, mask); + dev_dbg(ecc->dev, "ESR%d %08x\n", idx, + edma_shadow0_read_array(ecc, SH_ESR, idx)); + edma_shadow0_write_array(ecc, SH_ESR, idx, ch_bit); } else { /* EDMA channel with event association */ - dev_dbg(ecc->dev, "ER%d %08x\n", j, - edma_shadow0_read_array(ecc, SH_ER, j)); + dev_dbg(ecc->dev, "ER%d %08x\n", idx, + edma_shadow0_read_array(ecc, SH_ER, idx)); /* Clear any pending event or error */ - edma_write_array(ecc, EDMA_ECR, j, mask); - edma_write_array(ecc, EDMA_EMCR, j, mask); + edma_write_array(ecc, EDMA_ECR, idx, ch_bit); + edma_write_array(ecc, EDMA_EMCR, idx, ch_bit); /* Clear any SER */ - edma_shadow0_write_array(ecc, SH_SECR, j, mask); - edma_shadow0_write_array(ecc, SH_EESR, j, mask); - dev_dbg(ecc->dev, "EER%d %08x\n", j, - edma_shadow0_read_array(ecc, SH_EER, j)); + edma_shadow0_write_array(ecc, SH_SECR, idx, ch_bit); + edma_shadow0_write_array(ecc, SH_EESR, idx, ch_bit); + dev_dbg(ecc->dev, "EER%d %08x\n", idx, + edma_shadow0_read_array(ecc, SH_EER, idx)); } } @@ -614,19 +619,19 @@ static void edma_stop(struct edma_chan *echan) { struct edma_cc *ecc = echan->ecc; int channel = EDMA_CHAN_SLOT(echan->ch_num); - int j = (channel >> 5); - unsigned int mask = BIT(channel & 0x1f); + int idx = EDMA_REG_ARRAY_INDEX(channel); + int ch_bit = EDMA_CHANNEL_BIT(channel); - edma_shadow0_write_array(ecc, SH_EECR, j, mask); - edma_shadow0_write_array(ecc, SH_ECR, j, mask); - edma_shadow0_write_array(ecc, SH_SECR, j, mask); - edma_write_array(ecc, EDMA_EMCR, j, mask); + edma_shadow0_write_array(ecc, SH_EECR, idx, ch_bit); + edma_shadow0_write_array(ecc, SH_ECR, idx, ch_bit); + edma_shadow0_write_array(ecc, SH_SECR, idx, ch_bit); + edma_write_array(ecc, EDMA_EMCR, idx, ch_bit); /* clear possibly pending completion interrupt */ - edma_shadow0_write_array(ecc, SH_ICR, j, mask); + edma_shadow0_write_array(ecc, SH_ICR, idx, ch_bit); - dev_dbg(ecc->dev, "EER%d %08x\n", j, - edma_shadow0_read_array(ecc, SH_EER, j)); + dev_dbg(ecc->dev, "EER%d %08x\n", idx, + edma_shadow0_read_array(ecc, SH_EER, idx)); /* REVISIT: consider guarding against inappropriate event * chaining by overwriting with dummy_paramset. @@ -640,45 +645,49 @@ static void edma_stop(struct edma_chan *echan) static void edma_pause(struct edma_chan *echan) { int channel = EDMA_CHAN_SLOT(echan->ch_num); - unsigned int mask = BIT(channel & 0x1f); - edma_shadow0_write_array(echan->ecc, SH_EECR, channel >> 5, mask); + edma_shadow0_write_array(echan->ecc, SH_EECR, + EDMA_REG_ARRAY_INDEX(channel), + EDMA_CHANNEL_BIT(channel)); } /* Re-enable EDMA hardware events on the specified channel. */ static void edma_resume(struct edma_chan *echan) { int channel = EDMA_CHAN_SLOT(echan->ch_num); - unsigned int mask = BIT(channel & 0x1f); - edma_shadow0_write_array(echan->ecc, SH_EESR, channel >> 5, mask); + edma_shadow0_write_array(echan->ecc, SH_EESR, + EDMA_REG_ARRAY_INDEX(channel), + EDMA_CHANNEL_BIT(channel)); } static void edma_trigger_channel(struct edma_chan *echan) { struct edma_cc *ecc = echan->ecc; int channel = EDMA_CHAN_SLOT(echan->ch_num); - unsigned int mask = BIT(channel & 0x1f); + int idx = EDMA_REG_ARRAY_INDEX(channel); + int ch_bit = EDMA_CHANNEL_BIT(channel); - edma_shadow0_write_array(ecc, SH_ESR, (channel >> 5), mask); + edma_shadow0_write_array(ecc, SH_ESR, idx, ch_bit); - dev_dbg(ecc->dev, "ESR%d %08x\n", (channel >> 5), - edma_shadow0_read_array(ecc, SH_ESR, (channel >> 5))); + dev_dbg(ecc->dev, "ESR%d %08x\n", idx, + edma_shadow0_read_array(ecc, SH_ESR, idx)); } static void edma_clean_channel(struct edma_chan *echan) { struct edma_cc *ecc = echan->ecc; int channel = EDMA_CHAN_SLOT(echan->ch_num); - int j = (channel >> 5); - unsigned int mask = BIT(channel & 0x1f); + int idx = EDMA_REG_ARRAY_INDEX(channel); + int ch_bit = EDMA_CHANNEL_BIT(channel); - dev_dbg(ecc->dev, "EMR%d %08x\n", j, edma_read_array(ecc, EDMA_EMR, j)); - edma_shadow0_write_array(ecc, SH_ECR, j, mask); + dev_dbg(ecc->dev, "EMR%d %08x\n", idx, + edma_read_array(ecc, EDMA_EMR, idx)); + edma_shadow0_write_array(ecc, SH_ECR, idx, ch_bit); /* Clear the corresponding EMR bits */ - edma_write_array(ecc, EDMA_EMCR, j, mask); + edma_write_array(ecc, EDMA_EMCR, idx, ch_bit); /* Clear any SER */ - edma_shadow0_write_array(ecc, SH_SECR, j, mask); + edma_shadow0_write_array(ecc, SH_SECR, idx, ch_bit); edma_write(ecc, EDMA_CCERRCLR, BIT(16) | BIT(1) | BIT(0)); } @@ -708,7 +717,8 @@ static int edma_alloc_channel(struct edma_chan *echan, int channel = EDMA_CHAN_SLOT(echan->ch_num); /* ensure access through shadow region 0 */ - edma_or_array2(ecc, EDMA_DRAE, 0, channel >> 5, BIT(channel & 0x1f)); + edma_or_array2(ecc, EDMA_DRAE, 0, EDMA_REG_ARRAY_INDEX(channel), + EDMA_CHANNEL_BIT(channel)); /* ensure no events are pending */ edma_stop(echan); @@ -1011,6 +1021,7 @@ static int edma_config_pset(struct dma_chan *chan, struct edma_pset *epset, src_cidx = cidx; dst_bidx = acnt; dst_cidx = cidx; + epset->addr = src_addr; } else { dev_err(dev, "%s: direction not implemented yet\n", __func__); return -EINVAL; @@ -1211,8 +1222,9 @@ static struct dma_async_tx_descriptor *edma_prep_dma_memcpy( edesc->pset[0].param.opt |= ITCCHEN; if (nslots == 1) { - /* Enable transfer complete interrupt */ - edesc->pset[0].param.opt |= TCINTEN; + /* Enable transfer complete interrupt if requested */ + if (tx_flags & DMA_PREP_INTERRUPT) + edesc->pset[0].param.opt |= TCINTEN; } else { /* Enable transfer complete chaining for the first slot */ edesc->pset[0].param.opt |= TCCHEN; @@ -1239,9 +1251,14 @@ static struct dma_async_tx_descriptor *edma_prep_dma_memcpy( } edesc->pset[1].param.opt |= ITCCHEN; - edesc->pset[1].param.opt |= TCINTEN; + /* Enable transfer complete interrupt if requested */ + if (tx_flags & DMA_PREP_INTERRUPT) + edesc->pset[1].param.opt |= TCINTEN; } + if (!(tx_flags & DMA_PREP_INTERRUPT)) + edesc->polled = true; + return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags); } @@ -1721,7 +1738,11 @@ static u32 edma_residue(struct edma_desc *edesc) int loop_count = EDMA_MAX_TR_WAIT_LOOPS; struct edma_chan *echan = edesc->echan; struct edma_pset *pset = edesc->pset; - dma_addr_t done, pos; + dma_addr_t done, pos, pos_old; + int channel = EDMA_CHAN_SLOT(echan->ch_num); + int idx = EDMA_REG_ARRAY_INDEX(channel); + int ch_bit = EDMA_CHANNEL_BIT(channel); + int event_reg; int i; /* @@ -1734,16 +1755,20 @@ static u32 edma_residue(struct edma_desc *edesc) * "pos" may represent a transfer request that is still being * processed by the EDMACC or EDMATC. We will busy wait until * any one of the situations occurs: - * 1. the DMA hardware is idle - * 2. a new transfer request is setup + * 1. while and event is pending for the channel + * 2. a position updated * 3. we hit the loop limit */ - while (edma_read(echan->ecc, EDMA_CCSTAT) & EDMA_CCSTAT_ACTV) { - /* check if a new transfer request is setup */ - if (edma_get_position(echan->ecc, - echan->slot[0], dst) != pos) { + if (is_slave_direction(edesc->direction)) + event_reg = SH_ER; + else + event_reg = SH_ESR; + + pos_old = pos; + while (edma_shadow0_read_array(echan->ecc, event_reg, idx) & ch_bit) { + pos = edma_get_position(echan->ecc, echan->slot[0], dst); + if (pos != pos_old) break; - } if (!--loop_count) { dev_dbg_ratelimited(echan->vchan.chan.device->dev, @@ -1768,6 +1793,12 @@ static u32 edma_residue(struct edma_desc *edesc) return edesc->residue_stat; } + /* + * If the position is 0, then EDMA loaded the closing dummy slot, the + * transfer is completed + */ + if (!pos) + return 0; /* * For SG operation we catch up with the last processed * status. @@ -1796,19 +1827,46 @@ static enum dma_status edma_tx_status(struct dma_chan *chan, struct dma_tx_state *txstate) { struct edma_chan *echan = to_edma_chan(chan); - struct virt_dma_desc *vdesc; + struct dma_tx_state txstate_tmp; enum dma_status ret; unsigned long flags; ret = dma_cookie_status(chan, cookie, txstate); - if (ret == DMA_COMPLETE || !txstate) + + if (ret == DMA_COMPLETE) return ret; + /* Provide a dummy dma_tx_state for completion checking */ + if (!txstate) + txstate = &txstate_tmp; + spin_lock_irqsave(&echan->vchan.lock, flags); - if (echan->edesc && echan->edesc->vdesc.tx.cookie == cookie) + if (echan->edesc && echan->edesc->vdesc.tx.cookie == cookie) { txstate->residue = edma_residue(echan->edesc); - else if ((vdesc = vchan_find_desc(&echan->vchan, cookie))) - txstate->residue = to_edma_desc(&vdesc->tx)->residue; + } else { + struct virt_dma_desc *vdesc = vchan_find_desc(&echan->vchan, + cookie); + + if (vdesc) + txstate->residue = to_edma_desc(&vdesc->tx)->residue; + else + txstate->residue = 0; + } + + /* + * Mark the cookie completed if the residue is 0 for non cyclic + * transfers + */ + if (ret != DMA_COMPLETE && !txstate->residue && + echan->edesc && echan->edesc->polled && + echan->edesc->vdesc.tx.cookie == cookie) { + edma_stop(echan); + vchan_cookie_complete(&echan->edesc->vdesc); + echan->edesc = NULL; + edma_execute(echan); + ret = DMA_COMPLETE; + } + spin_unlock_irqrestore(&echan->vchan.lock, flags); return ret; @@ -2185,11 +2243,13 @@ static struct dma_chan *of_edma_xlate(struct of_phandle_args *dma_spec, } #endif +static bool edma_filter_fn(struct dma_chan *chan, void *param); + static int edma_probe(struct platform_device *pdev) { struct edma_soc_info *info = pdev->dev.platform_data; s8 (*queue_priority_mapping)[2]; - int i, off, ln; + int i, off; const s16 (*rsv_slots)[2]; const s16 (*xbar_chans)[2]; int irq; @@ -2273,21 +2333,22 @@ static int edma_probe(struct platform_device *pdev) ecc->default_queue = info->default_queue; - for (i = 0; i < ecc->num_slots; i++) - edma_write_slot(ecc, i, &dummy_paramset); - if (info->rsv) { /* Set the reserved slots in inuse list */ rsv_slots = info->rsv->rsv_slots; if (rsv_slots) { - for (i = 0; rsv_slots[i][0] != -1; i++) { - off = rsv_slots[i][0]; - ln = rsv_slots[i][1]; - edma_set_bits(off, ln, ecc->slot_inuse); - } + for (i = 0; rsv_slots[i][0] != -1; i++) + bitmap_set(ecc->slot_inuse, rsv_slots[i][0], + rsv_slots[i][1]); } } + for (i = 0; i < ecc->num_slots; i++) { + /* Reset only unused - not reserved - paRAM slots */ + if (!test_bit(i, ecc->slot_inuse)) + edma_write_slot(ecc, i, &dummy_paramset); + } + /* Clear the xbar mapped channels in unused list */ xbar_chans = info->xbar_chans; if (xbar_chans) { @@ -2366,11 +2427,10 @@ static int edma_probe(struct platform_device *pdev) edma_assign_priority_to_queue(ecc, queue_priority_mapping[i][0], queue_priority_mapping[i][1]); - for (i = 0; i < ecc->num_region; i++) { - edma_write_array2(ecc, EDMA_DRAE, i, 0, 0x0); - edma_write_array2(ecc, EDMA_DRAE, i, 1, 0x0); - edma_write_array(ecc, EDMA_QRAE, i, 0x0); - } + edma_write_array2(ecc, EDMA_DRAE, 0, 0, 0x0); + edma_write_array2(ecc, EDMA_DRAE, 0, 1, 0x0); + edma_write_array(ecc, EDMA_QRAE, 0, 0x0); + ecc->info = info; /* Init the dma device and channels */ @@ -2482,8 +2542,9 @@ static int edma_pm_resume(struct device *dev) for (i = 0; i < ecc->num_channels; i++) { if (echan[i].alloced) { /* ensure access through shadow region 0 */ - edma_or_array2(ecc, EDMA_DRAE, 0, i >> 5, - BIT(i & 0x1f)); + edma_or_array2(ecc, EDMA_DRAE, 0, + EDMA_REG_ARRAY_INDEX(i), + EDMA_CHANNEL_BIT(i)); edma_setup_interrupt(&echan[i], true); @@ -2524,7 +2585,7 @@ static struct platform_driver edma_tptc_driver = { }, }; -bool edma_filter_fn(struct dma_chan *chan, void *param) +static bool edma_filter_fn(struct dma_chan *chan, void *param) { bool match = false; @@ -2539,7 +2600,6 @@ bool edma_filter_fn(struct dma_chan *chan, void *param) } return match; } -EXPORT_SYMBOL(edma_filter_fn); static int edma_init(void) { diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c index d07c0d5de7a256388e1806afa4264e91f2f51e2d..6b6ba238b81a756b8e2e8b5c41154283a94531af 100644 --- a/drivers/dma/ti/omap-dma.c +++ b/drivers/dma/ti/omap-dma.c @@ -91,6 +91,7 @@ struct omap_desc { bool using_ll; enum dma_transfer_direction dir; dma_addr_t dev_addr; + bool polled; int32_t fi; /* for OMAP_DMA_SYNC_PACKET / double indexing */ int16_t ei; /* for double indexing */ @@ -202,6 +203,7 @@ static const unsigned es_bytes[] = { [CSDP_DATA_TYPE_32] = 4, }; +static bool omap_dma_filter_fn(struct dma_chan *chan, void *param); static struct of_dma_filter_info omap_dma_info = { .filter_fn = omap_dma_filter_fn, }; @@ -812,31 +814,22 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan, dma_cookie_t cookie, struct dma_tx_state *txstate) { struct omap_chan *c = to_omap_dma_chan(chan); - struct virt_dma_desc *vd; enum dma_status ret; unsigned long flags; + struct omap_desc *d = NULL; ret = dma_cookie_status(chan, cookie, txstate); - - if (!c->paused && c->running) { - uint32_t ccr = omap_dma_chan_read(c, CCR); - /* - * The channel is no longer active, set the return value - * accordingly - */ - if (!(ccr & CCR_ENABLE)) - ret = DMA_COMPLETE; - } - - if (ret == DMA_COMPLETE || !txstate) + if (ret == DMA_COMPLETE) return ret; spin_lock_irqsave(&c->vc.lock, flags); - vd = vchan_find_desc(&c->vc, cookie); - if (vd) { - txstate->residue = omap_dma_desc_size(to_omap_dma_desc(&vd->tx)); - } else if (c->desc && c->desc->vd.tx.cookie == cookie) { - struct omap_desc *d = c->desc; + if (c->desc && c->desc->vd.tx.cookie == cookie) + d = c->desc; + + if (!txstate) + goto out; + + if (d) { dma_addr_t pos; if (d->dir == DMA_MEM_TO_DEV) @@ -848,10 +841,31 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan, txstate->residue = omap_dma_desc_size_pos(d, pos); } else { - txstate->residue = 0; + struct virt_dma_desc *vd = vchan_find_desc(&c->vc, cookie); + + if (vd) + txstate->residue = omap_dma_desc_size( + to_omap_dma_desc(&vd->tx)); + else + txstate->residue = 0; } - if (ret == DMA_IN_PROGRESS && c->paused) + +out: + if (ret == DMA_IN_PROGRESS && c->paused) { ret = DMA_PAUSED; + } else if (d && d->polled && c->running) { + uint32_t ccr = omap_dma_chan_read(c, CCR); + /* + * The channel is no longer active, set the return value + * accordingly and mark it as completed + */ + if (!(ccr & CCR_ENABLE)) { + ret = DMA_COMPLETE; + omap_dma_start_desc(c); + vchan_cookie_complete(&d->vd); + } + } + spin_unlock_irqrestore(&c->vc.lock, flags); return ret; @@ -1178,7 +1192,10 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_memcpy( d->ccr = c->ccr; d->ccr |= CCR_DST_AMODE_POSTINC | CCR_SRC_AMODE_POSTINC; - d->cicr = CICR_DROP_IE | CICR_FRAME_IE; + if (tx_flags & DMA_PREP_INTERRUPT) + d->cicr |= CICR_FRAME_IE; + else + d->polled = true; d->csdp = data_type; @@ -1639,7 +1656,7 @@ static struct platform_driver omap_dma_driver = { }, }; -bool omap_dma_filter_fn(struct dma_chan *chan, void *param) +static bool omap_dma_filter_fn(struct dma_chan *chan, void *param) { if (chan->device->dev->driver == &omap_dma_driver.driver) { struct omap_dmadev *od = to_omap_dma_dev(chan->device); @@ -1653,7 +1670,6 @@ bool omap_dma_filter_fn(struct dma_chan *chan, void *param) } return false; } -EXPORT_SYMBOL_GPL(omap_dma_filter_fn); static int omap_dma_init(void) { diff --git a/drivers/dma/uniphier-mdmac.c b/drivers/dma/uniphier-mdmac.c index ec65a7430dc45a4b4c1ad2f3d3b0da67def3a83d..fde54687856b8340aee2b84b70777abc1a304d00 100644 --- a/drivers/dma/uniphier-mdmac.c +++ b/drivers/dma/uniphier-mdmac.c @@ -354,11 +354,8 @@ static int uniphier_mdmac_chan_init(struct platform_device *pdev, int irq, ret; irq = platform_get_irq(pdev, chan_id); - if (irq < 0) { - dev_err(&pdev->dev, "failed to get IRQ number for ch%d\n", - chan_id); + if (irq < 0) return irq; - } irq_name = devm_kasprintf(dev, GFP_KERNEL, "uniphier-mio-dmac-ch%d", chan_id); diff --git a/drivers/dma/xgene-dma.c b/drivers/dma/xgene-dma.c index 957c269ce1fd0832a78e576941788b8d6cefae6d..cd60fa6d67501463443c7a1a0fb6e71f80557db1 100644 --- a/drivers/dma/xgene-dma.c +++ b/drivers/dma/xgene-dma.c @@ -1678,20 +1678,16 @@ static int xgene_dma_get_resources(struct platform_device *pdev, /* Get DMA error interrupt */ irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_err(&pdev->dev, "Failed to get Error IRQ\n"); + if (irq <= 0) return -ENXIO; - } pdma->err_irq = irq; /* Get DMA Rx ring descriptor interrupts for all DMA channels */ for (i = 1; i <= XGENE_DMA_MAX_CHANNEL; i++) { irq = platform_get_irq(pdev, i); - if (irq <= 0) { - dev_err(&pdev->dev, "Failed to get Rx IRQ\n"); + if (irq <= 0) return -ENXIO; - } pdma->chan[i - 1].rx_irq = irq; } diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 200c04ce5b0ed20361157a1c655c99bb14bee47c..2a2603bfb918547e86720dac5f0584dc57f33fdb 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -510,4 +510,11 @@ config EDAC_ASPEED First, ECC must be configured in the bootloader. Then, this driver will expose error counters via the EDAC kernel framework. +config EDAC_BLUEFIELD + tristate "Mellanox BlueField Memory ECC" + depends on ARM64 && ((MELLANOX_PLATFORM && ACPI) || COMPILE_TEST) + help + Support for error detection and correction on the + Mellanox BlueField SoCs. + endif # EDAC diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 165ca65e1a3a55a9d0181fe5c23b71ba956704be..d265ff9311f02eb914e857d2593934da8e037f68 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -85,3 +85,4 @@ obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o obj-$(CONFIG_EDAC_TI) += ti_edac.o obj-$(CONFIG_EDAC_QCOM) += qcom_edac.o obj-$(CONFIG_EDAC_ASPEED) += aspeed_edac.o +obj-$(CONFIG_EDAC_BLUEFIELD) += bluefield_edac.o diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index c2e693e34d434e53c801546d02700e5ee219644f..fbda4b876afd19937db8dcd7f0846006bd6b7743 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -222,7 +222,6 @@ static unsigned long get_total_mem(void) static const struct of_device_id altr_sdram_ctrl_of_match[] = { { .compatible = "altr,sdram-edac", .data = &c5_data}, { .compatible = "altr,sdram-edac-a10", .data = &a10_data}, - { .compatible = "altr,sdram-edac-s10", .data = &a10_data}, {}, }; MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match); @@ -1170,6 +1169,24 @@ static int __init __maybe_unused altr_init_a10_ecc_device_type(char *compat) return 0; } +/*********************** SDRAM EDAC Device Functions *********************/ + +#ifdef CONFIG_EDAC_ALTERA_SDRAM + +static const struct edac_device_prv_data s10_sdramecc_data = { + .setup = altr_check_ecc_deps, + .ce_clear_mask = ALTR_S10_ECC_SERRPENA, + .ue_clear_mask = ALTR_S10_ECC_DERRPENA, + .ecc_enable_mask = ALTR_S10_ECC_EN, + .ecc_en_ofst = ALTR_S10_ECC_CTRL_SDRAM_OFST, + .ce_set_mask = ALTR_S10_ECC_TSERRA, + .ue_set_mask = ALTR_S10_ECC_TDERRA, + .set_err_ofst = ALTR_S10_ECC_INTTEST_OFST, + .ecc_irq_handler = altr_edac_a10_ecc_irq, + .inject_fops = &altr_edac_a10_device_inject_fops, +}; +#endif /* CONFIG_EDAC_ALTERA_SDRAM */ + /*********************** OCRAM EDAC Device Functions *********************/ #ifdef CONFIG_EDAC_ALTERA_OCRAM @@ -1758,6 +1775,9 @@ static const struct of_device_id altr_edac_a10_device_of_match[] = { #endif #ifdef CONFIG_EDAC_ALTERA_SDMMC { .compatible = "altr,socfpga-sdmmc-ecc", .data = &a10_sdmmcecca_data }, +#endif +#ifdef CONFIG_EDAC_ALTERA_SDRAM + { .compatible = "altr,sdram-edac-s10", .data = &s10_sdramecc_data }, #endif {}, }; @@ -1866,6 +1886,7 @@ static void altr_edac_a10_irq_handler(struct irq_desc *desc) struct altr_arria10_edac *edac = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); int irq = irq_desc_get_irq(desc); + unsigned long bits; dberr = (irq == edac->db_irq) ? 1 : 0; sm_offset = dberr ? A10_SYSMGR_ECC_INTSTAT_DERR_OFST : @@ -1875,7 +1896,8 @@ static void altr_edac_a10_irq_handler(struct irq_desc *desc) regmap_read(edac->ecc_mgr_map, sm_offset, &irq_status); - for_each_set_bit(bit, (unsigned long *)&irq_status, 32) { + bits = irq_status; + for_each_set_bit(bit, &bits, 32) { irq = irq_linear_revmap(edac->domain, dberr * 32 + bit); if (irq) generic_handle_irq(irq); @@ -1889,6 +1911,10 @@ static int validate_parent_available(struct device_node *np) struct device_node *parent; int ret = 0; + /* SDRAM must be present for Linux (implied parent) */ + if (of_device_is_compatible(np, "altr,sdram-edac-s10")) + return 0; + /* Ensure parent device is enabled if parent node exists */ parent = of_parse_phandle(np, "altr,ecc-parent", 0); if (parent && !of_device_is_available(parent)) @@ -1898,6 +1924,22 @@ static int validate_parent_available(struct device_node *np) return ret; } +static int get_s10_sdram_edac_resource(struct device_node *np, + struct resource *res) +{ + struct device_node *parent; + int ret; + + parent = of_parse_phandle(np, "altr,sdr-syscon", 0); + if (!parent) + return -ENODEV; + + ret = of_address_to_resource(parent, 0, res); + of_node_put(parent); + + return ret; +} + static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, struct device_node *np) { @@ -1925,7 +1967,11 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, if (!devres_open_group(edac->dev, altr_edac_a10_device_add, GFP_KERNEL)) return -ENOMEM; - rc = of_address_to_resource(np, 0, &res); + if (of_device_is_compatible(np, "altr,sdram-edac-s10")) + rc = get_s10_sdram_edac_resource(np, &res); + else + rc = of_address_to_resource(np, 0, &res); + if (rc < 0) { edac_printk(KERN_ERR, EDAC_DEVICE, "%s: no resource address\n", ecc_name); @@ -2231,13 +2277,15 @@ static int altr_edac_a10_probe(struct platform_device *pdev) of_device_is_compatible(child, "altr,socfpga-dma-ecc") || of_device_is_compatible(child, "altr,socfpga-usb-ecc") || of_device_is_compatible(child, "altr,socfpga-qspi-ecc") || +#ifdef CONFIG_EDAC_ALTERA_SDRAM + of_device_is_compatible(child, "altr,sdram-edac-s10") || +#endif of_device_is_compatible(child, "altr,socfpga-sdmmc-ecc")) altr_edac_a10_device_add(edac, child); #ifdef CONFIG_EDAC_ALTERA_SDRAM - else if ((of_device_is_compatible(child, "altr,sdram-edac-a10")) || - (of_device_is_compatible(child, "altr,sdram-edac-s10"))) + else if (of_device_is_compatible(child, "altr,sdram-edac-a10")) of_platform_populate(pdev->dev.of_node, altr_sdram_ctrl_of_match, NULL, &pdev->dev); diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h index 55654cc4bcdf35373517dd2c95d2af109d47de28..3727e72c8c2e70a98df2854608e1858bafb7d1fe 100644 --- a/drivers/edac/altera_edac.h +++ b/drivers/edac/altera_edac.h @@ -289,6 +289,29 @@ struct altr_sdram_mc_data { #define ALTR_A10_ECC_INIT_WATCHDOG_10US 10000 /************* Stratix10 Defines **************/ +#define ALTR_S10_ECC_CTRL_SDRAM_OFST 0x00 +#define ALTR_S10_ECC_EN BIT(0) + +#define ALTR_S10_ECC_ERRINTEN_OFST 0x10 +#define ALTR_S10_ECC_ERRINTENS_OFST 0x14 +#define ALTR_S10_ECC_ERRINTENR_OFST 0x18 +#define ALTR_S10_ECC_SERRINTEN BIT(0) + +#define ALTR_S10_ECC_INTMODE_OFST 0x1C +#define ALTR_S10_ECC_INTMODE BIT(0) + +#define ALTR_S10_ECC_INTSTAT_OFST 0x20 +#define ALTR_S10_ECC_SERRPENA BIT(0) +#define ALTR_S10_ECC_DERRPENA BIT(8) +#define ALTR_S10_ECC_ERRPENA_MASK (ALTR_S10_ECC_SERRPENA | \ + ALTR_S10_ECC_DERRPENA) + +#define ALTR_S10_ECC_INTTEST_OFST 0x24 +#define ALTR_S10_ECC_TSERRA BIT(0) +#define ALTR_S10_ECC_TDERRA BIT(8) +#define ALTR_S10_ECC_TSERRB BIT(16) +#define ALTR_S10_ECC_TDERRB BIT(24) + #define ALTR_S10_DERR_ADDRA_OFST 0x2C /* Stratix10 ECC Manager Defines */ @@ -300,7 +323,7 @@ struct altr_sdram_mc_data { #define S10_SYSMGR_UE_ADDR_OFST 0x224 #define S10_DDR0_IRQ_MASK BIT(16) -#define S10_DBE_IRQ_MASK 0x3FE +#define S10_DBE_IRQ_MASK 0x3FFFE /* Define ECC Block Offsets for peripherals */ #define ECC_BLK_ADDRESS_OFST 0x40 diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 873437be86d9c2d571953ef7624c06a0bb868f78..c1d4536ae466e7b3d683ecb0741baf7e7f653407 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -788,51 +788,45 @@ static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan) (dclr & BIT(15)) ? "yes" : "no"); } -/* - * The Address Mask should be a contiguous set of bits in the non-interleaved - * case. So to check for CS interleaving, find the most- and least-significant - * bits of the mask, generate a contiguous bitmask, and compare the two. - */ -static bool f17_cs_interleaved(struct amd64_pvt *pvt, u8 ctrl, int cs) +#define CS_EVEN_PRIMARY BIT(0) +#define CS_ODD_PRIMARY BIT(1) +#define CS_EVEN_SECONDARY BIT(2) +#define CS_ODD_SECONDARY BIT(3) + +#define CS_EVEN (CS_EVEN_PRIMARY | CS_EVEN_SECONDARY) +#define CS_ODD (CS_ODD_PRIMARY | CS_ODD_SECONDARY) + +static int f17_get_cs_mode(int dimm, u8 ctrl, struct amd64_pvt *pvt) { - u32 mask = pvt->csels[ctrl].csmasks[cs >> 1]; - u32 msb = fls(mask) - 1, lsb = ffs(mask) - 1; - u32 test_mask = GENMASK(msb, lsb); + int cs_mode = 0; - edac_dbg(1, "mask=0x%08x test_mask=0x%08x\n", mask, test_mask); + if (csrow_enabled(2 * dimm, ctrl, pvt)) + cs_mode |= CS_EVEN_PRIMARY; - return mask ^ test_mask; + if (csrow_enabled(2 * dimm + 1, ctrl, pvt)) + cs_mode |= CS_ODD_PRIMARY; + + /* Asymmetric dual-rank DIMM support. */ + if (csrow_sec_enabled(2 * dimm + 1, ctrl, pvt)) + cs_mode |= CS_ODD_SECONDARY; + + return cs_mode; } static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl) { - int dimm, size0, size1, cs0, cs1; + int dimm, size0, size1, cs0, cs1, cs_mode; edac_printk(KERN_DEBUG, EDAC_MC, "UMC%d chip selects:\n", ctrl); - for (dimm = 0; dimm < 4; dimm++) { - size0 = 0; + for (dimm = 0; dimm < 2; dimm++) { cs0 = dimm * 2; - - if (csrow_enabled(cs0, ctrl, pvt)) - size0 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, cs0); - - size1 = 0; cs1 = dimm * 2 + 1; - if (csrow_enabled(cs1, ctrl, pvt)) { - /* - * CS interleaving is only supported if both CSes have - * the same amount of memory. Because they are - * interleaved, it will look like both CSes have the - * full amount of memory. Save the size for both as - * half the amount we found on CS0, if interleaved. - */ - if (f17_cs_interleaved(pvt, ctrl, cs1)) - size1 = size0 = (size0 >> 1); - else - size1 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, cs1); - } + cs_mode = f17_get_cs_mode(dimm, ctrl, pvt); + + size0 = pvt->ops->dbam_to_cs(pvt, ctrl, cs_mode, cs0); + size1 = pvt->ops->dbam_to_cs(pvt, ctrl, cs_mode, cs1); amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n", cs0, size0, @@ -942,89 +936,119 @@ static void prep_chip_selects(struct amd64_pvt *pvt) } else if (pvt->fam == 0x15 && pvt->model == 0x30) { pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4; pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2; + } else if (pvt->fam >= 0x17) { + int umc; + + for_each_umc(umc) { + pvt->csels[umc].b_cnt = 4; + pvt->csels[umc].m_cnt = 2; + } + } else { pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8; pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4; } } +static void read_umc_base_mask(struct amd64_pvt *pvt) +{ + u32 umc_base_reg, umc_base_reg_sec; + u32 umc_mask_reg, umc_mask_reg_sec; + u32 base_reg, base_reg_sec; + u32 mask_reg, mask_reg_sec; + u32 *base, *base_sec; + u32 *mask, *mask_sec; + int cs, umc; + + for_each_umc(umc) { + umc_base_reg = get_umc_base(umc) + UMCCH_BASE_ADDR; + umc_base_reg_sec = get_umc_base(umc) + UMCCH_BASE_ADDR_SEC; + + for_each_chip_select(cs, umc, pvt) { + base = &pvt->csels[umc].csbases[cs]; + base_sec = &pvt->csels[umc].csbases_sec[cs]; + + base_reg = umc_base_reg + (cs * 4); + base_reg_sec = umc_base_reg_sec + (cs * 4); + + if (!amd_smn_read(pvt->mc_node_id, base_reg, base)) + edac_dbg(0, " DCSB%d[%d]=0x%08x reg: 0x%x\n", + umc, cs, *base, base_reg); + + if (!amd_smn_read(pvt->mc_node_id, base_reg_sec, base_sec)) + edac_dbg(0, " DCSB_SEC%d[%d]=0x%08x reg: 0x%x\n", + umc, cs, *base_sec, base_reg_sec); + } + + umc_mask_reg = get_umc_base(umc) + UMCCH_ADDR_MASK; + umc_mask_reg_sec = get_umc_base(umc) + UMCCH_ADDR_MASK_SEC; + + for_each_chip_select_mask(cs, umc, pvt) { + mask = &pvt->csels[umc].csmasks[cs]; + mask_sec = &pvt->csels[umc].csmasks_sec[cs]; + + mask_reg = umc_mask_reg + (cs * 4); + mask_reg_sec = umc_mask_reg_sec + (cs * 4); + + if (!amd_smn_read(pvt->mc_node_id, mask_reg, mask)) + edac_dbg(0, " DCSM%d[%d]=0x%08x reg: 0x%x\n", + umc, cs, *mask, mask_reg); + + if (!amd_smn_read(pvt->mc_node_id, mask_reg_sec, mask_sec)) + edac_dbg(0, " DCSM_SEC%d[%d]=0x%08x reg: 0x%x\n", + umc, cs, *mask_sec, mask_reg_sec); + } + } +} + /* * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers */ static void read_dct_base_mask(struct amd64_pvt *pvt) { - int base_reg0, base_reg1, mask_reg0, mask_reg1, cs; + int cs; prep_chip_selects(pvt); - if (pvt->umc) { - base_reg0 = get_umc_base(0) + UMCCH_BASE_ADDR; - base_reg1 = get_umc_base(1) + UMCCH_BASE_ADDR; - mask_reg0 = get_umc_base(0) + UMCCH_ADDR_MASK; - mask_reg1 = get_umc_base(1) + UMCCH_ADDR_MASK; - } else { - base_reg0 = DCSB0; - base_reg1 = DCSB1; - mask_reg0 = DCSM0; - mask_reg1 = DCSM1; - } + if (pvt->umc) + return read_umc_base_mask(pvt); for_each_chip_select(cs, 0, pvt) { - int reg0 = base_reg0 + (cs * 4); - int reg1 = base_reg1 + (cs * 4); + int reg0 = DCSB0 + (cs * 4); + int reg1 = DCSB1 + (cs * 4); u32 *base0 = &pvt->csels[0].csbases[cs]; u32 *base1 = &pvt->csels[1].csbases[cs]; - if (pvt->umc) { - if (!amd_smn_read(pvt->mc_node_id, reg0, base0)) - edac_dbg(0, " DCSB0[%d]=0x%08x reg: 0x%x\n", - cs, *base0, reg0); + if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, base0)) + edac_dbg(0, " DCSB0[%d]=0x%08x reg: F2x%x\n", + cs, *base0, reg0); - if (!amd_smn_read(pvt->mc_node_id, reg1, base1)) - edac_dbg(0, " DCSB1[%d]=0x%08x reg: 0x%x\n", - cs, *base1, reg1); - } else { - if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, base0)) - edac_dbg(0, " DCSB0[%d]=0x%08x reg: F2x%x\n", - cs, *base0, reg0); - - if (pvt->fam == 0xf) - continue; + if (pvt->fam == 0xf) + continue; - if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, base1)) - edac_dbg(0, " DCSB1[%d]=0x%08x reg: F2x%x\n", - cs, *base1, (pvt->fam == 0x10) ? reg1 - : reg0); - } + if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, base1)) + edac_dbg(0, " DCSB1[%d]=0x%08x reg: F2x%x\n", + cs, *base1, (pvt->fam == 0x10) ? reg1 + : reg0); } for_each_chip_select_mask(cs, 0, pvt) { - int reg0 = mask_reg0 + (cs * 4); - int reg1 = mask_reg1 + (cs * 4); + int reg0 = DCSM0 + (cs * 4); + int reg1 = DCSM1 + (cs * 4); u32 *mask0 = &pvt->csels[0].csmasks[cs]; u32 *mask1 = &pvt->csels[1].csmasks[cs]; - if (pvt->umc) { - if (!amd_smn_read(pvt->mc_node_id, reg0, mask0)) - edac_dbg(0, " DCSM0[%d]=0x%08x reg: 0x%x\n", - cs, *mask0, reg0); - - if (!amd_smn_read(pvt->mc_node_id, reg1, mask1)) - edac_dbg(0, " DCSM1[%d]=0x%08x reg: 0x%x\n", - cs, *mask1, reg1); - } else { - if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, mask0)) - edac_dbg(0, " DCSM0[%d]=0x%08x reg: F2x%x\n", - cs, *mask0, reg0); + if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, mask0)) + edac_dbg(0, " DCSM0[%d]=0x%08x reg: F2x%x\n", + cs, *mask0, reg0); - if (pvt->fam == 0xf) - continue; + if (pvt->fam == 0xf) + continue; - if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, mask1)) - edac_dbg(0, " DCSM1[%d]=0x%08x reg: F2x%x\n", - cs, *mask1, (pvt->fam == 0x10) ? reg1 - : reg0); - } + if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, mask1)) + edac_dbg(0, " DCSM1[%d]=0x%08x reg: F2x%x\n", + cs, *mask1, (pvt->fam == 0x10) ? reg1 + : reg0); } } @@ -1556,18 +1580,58 @@ static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, return ddr3_cs_size(cs_mode, false); } -static int f17_base_addr_to_cs_size(struct amd64_pvt *pvt, u8 umc, +static int f17_addr_mask_to_cs_size(struct amd64_pvt *pvt, u8 umc, unsigned int cs_mode, int csrow_nr) { - u32 base_addr = pvt->csels[umc].csbases[csrow_nr]; + u32 addr_mask_orig, addr_mask_deinterleaved; + u32 msb, weight, num_zero_bits; + int dimm, size = 0; - /* Each mask is used for every two base addresses. */ - u32 addr_mask = pvt->csels[umc].csmasks[csrow_nr >> 1]; + /* No Chip Selects are enabled. */ + if (!cs_mode) + return size; - /* Register [31:1] = Address [39:9]. Size is in kBs here. */ - u32 size = ((addr_mask >> 1) - (base_addr >> 1) + 1) >> 1; + /* Requested size of an even CS but none are enabled. */ + if (!(cs_mode & CS_EVEN) && !(csrow_nr & 1)) + return size; - edac_dbg(1, "BaseAddr: 0x%x, AddrMask: 0x%x\n", base_addr, addr_mask); + /* Requested size of an odd CS but none are enabled. */ + if (!(cs_mode & CS_ODD) && (csrow_nr & 1)) + return size; + + /* + * There is one mask per DIMM, and two Chip Selects per DIMM. + * CS0 and CS1 -> DIMM0 + * CS2 and CS3 -> DIMM1 + */ + dimm = csrow_nr >> 1; + + /* Asymmetric dual-rank DIMM support. */ + if ((csrow_nr & 1) && (cs_mode & CS_ODD_SECONDARY)) + addr_mask_orig = pvt->csels[umc].csmasks_sec[dimm]; + else + addr_mask_orig = pvt->csels[umc].csmasks[dimm]; + + /* + * The number of zero bits in the mask is equal to the number of bits + * in a full mask minus the number of bits in the current mask. + * + * The MSB is the number of bits in the full mask because BIT[0] is + * always 0. + */ + msb = fls(addr_mask_orig) - 1; + weight = hweight_long(addr_mask_orig); + num_zero_bits = msb - weight; + + /* Take the number of zero bits off from the top of the mask. */ + addr_mask_deinterleaved = GENMASK_ULL(msb - num_zero_bits, 1); + + edac_dbg(1, "CS%d DIMM%d AddrMasks:\n", csrow_nr, dimm); + edac_dbg(1, " Original AddrMask: 0x%x\n", addr_mask_orig); + edac_dbg(1, " Deinterleaved AddrMask: 0x%x\n", addr_mask_deinterleaved); + + /* Register [31:1] = Address [39:9]. Size is in kBs here. */ + size = (addr_mask_deinterleaved >> 2) + 1; /* Return size in MBs. */ return size >> 10; @@ -2232,7 +2296,7 @@ static struct amd64_family_type family_types[] = { .f6_id = PCI_DEVICE_ID_AMD_17H_DF_F6, .ops = { .early_channel_count = f17_early_channel_count, - .dbam_to_cs = f17_base_addr_to_cs_size, + .dbam_to_cs = f17_addr_mask_to_cs_size, } }, [F17_M10H_CPUS] = { @@ -2241,7 +2305,7 @@ static struct amd64_family_type family_types[] = { .f6_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F6, .ops = { .early_channel_count = f17_early_channel_count, - .dbam_to_cs = f17_base_addr_to_cs_size, + .dbam_to_cs = f17_addr_mask_to_cs_size, } }, [F17_M30H_CPUS] = { @@ -2250,7 +2314,16 @@ static struct amd64_family_type family_types[] = { .f6_id = PCI_DEVICE_ID_AMD_17H_M30H_DF_F6, .ops = { .early_channel_count = f17_early_channel_count, - .dbam_to_cs = f17_base_addr_to_cs_size, + .dbam_to_cs = f17_addr_mask_to_cs_size, + } + }, + [F17_M70H_CPUS] = { + .ctl_name = "F17h_M70h", + .f0_id = PCI_DEVICE_ID_AMD_17H_M70H_DF_F0, + .f6_id = PCI_DEVICE_ID_AMD_17H_M70H_DF_F6, + .ops = { + .early_channel_count = f17_early_channel_count, + .dbam_to_cs = f17_addr_mask_to_cs_size, } }, }; @@ -2537,13 +2610,6 @@ static void decode_umc_error(int node_id, struct mce *m) err.channel = find_umc_channel(m); - if (umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, err.channel, &sys_addr)) { - err.err_code = ERR_NORM_ADDR; - goto log_error; - } - - error_address_to_page_and_offset(sys_addr, &err); - if (!(m->status & MCI_STATUS_SYNDV)) { err.err_code = ERR_SYND; goto log_error; @@ -2560,6 +2626,13 @@ static void decode_umc_error(int node_id, struct mce *m) err.csrow = m->synd & 0x7; + if (umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, err.channel, &sys_addr)) { + err.err_code = ERR_NORM_ADDR; + goto log_error; + } + + error_address_to_page_and_offset(sys_addr, &err); + log_error: __log_ecc_error(mci, &err, ecc_type); } @@ -2809,10 +2882,12 @@ static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr_orig) int csrow_nr = csrow_nr_orig; u32 cs_mode, nr_pages; - if (!pvt->umc) + if (!pvt->umc) { csrow_nr >>= 1; - - cs_mode = DBAM_DIMM(csrow_nr, dbam); + cs_mode = DBAM_DIMM(csrow_nr, dbam); + } else { + cs_mode = f17_get_cs_mode(csrow_nr >> 1, dct, pvt); + } nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode, csrow_nr); nr_pages <<= 20 - PAGE_SHIFT; @@ -2824,6 +2899,49 @@ static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr_orig) return nr_pages; } +static int init_csrows_df(struct mem_ctl_info *mci) +{ + struct amd64_pvt *pvt = mci->pvt_info; + enum edac_type edac_mode = EDAC_NONE; + enum dev_type dev_type = DEV_UNKNOWN; + struct dimm_info *dimm; + int empty = 1; + u8 umc, cs; + + if (mci->edac_ctl_cap & EDAC_FLAG_S16ECD16ED) { + edac_mode = EDAC_S16ECD16ED; + dev_type = DEV_X16; + } else if (mci->edac_ctl_cap & EDAC_FLAG_S8ECD8ED) { + edac_mode = EDAC_S8ECD8ED; + dev_type = DEV_X8; + } else if (mci->edac_ctl_cap & EDAC_FLAG_S4ECD4ED) { + edac_mode = EDAC_S4ECD4ED; + dev_type = DEV_X4; + } else if (mci->edac_ctl_cap & EDAC_FLAG_SECDED) { + edac_mode = EDAC_SECDED; + } + + for_each_umc(umc) { + for_each_chip_select(cs, umc, pvt) { + if (!csrow_enabled(cs, umc, pvt)) + continue; + + empty = 0; + dimm = mci->csrows[cs]->channels[umc]->dimm; + + edac_dbg(1, "MC node: %d, csrow: %d\n", + pvt->mc_node_id, cs); + + dimm->nr_pages = get_csrow_nr_pages(pvt, umc, cs); + dimm->mtype = pvt->dram_type; + dimm->edac_mode = edac_mode; + dimm->dtype = dev_type; + } + } + + return empty; +} + /* * Initialize the array of csrow attribute instances, based on the values * from pci config hardware registers. @@ -2838,15 +2956,16 @@ static int init_csrows(struct mem_ctl_info *mci) int nr_pages = 0; u32 val; - if (!pvt->umc) { - amd64_read_pci_cfg(pvt->F3, NBCFG, &val); + if (pvt->umc) + return init_csrows_df(mci); - pvt->nbcfg = val; + amd64_read_pci_cfg(pvt->F3, NBCFG, &val); - edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n", - pvt->mc_node_id, val, - !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE)); - } + pvt->nbcfg = val; + + edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n", + pvt->mc_node_id, val, + !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE)); /* * We iterate over DCT0 here but we look at DCT1 in parallel, if needed. @@ -2883,13 +3002,7 @@ static int init_csrows(struct mem_ctl_info *mci) edac_dbg(1, "Total csrow%d pages: %u\n", i, nr_pages); /* Determine DIMM ECC mode: */ - if (pvt->umc) { - if (mci->edac_ctl_cap & EDAC_FLAG_S4ECD4ED) - edac_mode = EDAC_S4ECD4ED; - else if (mci->edac_ctl_cap & EDAC_FLAG_SECDED) - edac_mode = EDAC_SECDED; - - } else if (pvt->nbcfg & NBCFG_ECC_ENABLE) { + if (pvt->nbcfg & NBCFG_ECC_ENABLE) { edac_mode = (pvt->nbcfg & NBCFG_CHIPKILL) ? EDAC_S4ECD4ED : EDAC_SECDED; @@ -3137,12 +3250,15 @@ static bool ecc_enabled(struct pci_dev *F3, u16 nid) static inline void f17h_determine_edac_ctl_cap(struct mem_ctl_info *mci, struct amd64_pvt *pvt) { - u8 i, ecc_en = 1, cpk_en = 1; + u8 i, ecc_en = 1, cpk_en = 1, dev_x4 = 1, dev_x16 = 1; for_each_umc(i) { if (pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) { ecc_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_ENABLED); cpk_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_CHIPKILL_CAP); + + dev_x4 &= !!(pvt->umc[i].dimm_cfg & BIT(6)); + dev_x16 &= !!(pvt->umc[i].dimm_cfg & BIT(7)); } } @@ -3150,8 +3266,15 @@ f17h_determine_edac_ctl_cap(struct mem_ctl_info *mci, struct amd64_pvt *pvt) if (ecc_en) { mci->edac_ctl_cap |= EDAC_FLAG_SECDED; - if (cpk_en) + if (!cpk_en) + return; + + if (dev_x4) mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED; + else if (dev_x16) + mci->edac_ctl_cap |= EDAC_FLAG_S16ECD16ED; + else + mci->edac_ctl_cap |= EDAC_FLAG_S8ECD8ED; } } @@ -3241,6 +3364,10 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt) fam_type = &family_types[F17_M30H_CPUS]; pvt->ops = &family_types[F17_M30H_CPUS].ops; break; + } else if (pvt->model >= 0x70 && pvt->model <= 0x7f) { + fam_type = &family_types[F17_M70H_CPUS]; + pvt->ops = &family_types[F17_M70H_CPUS].ops; + break; } /* fall through */ case 0x18: diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 8f66472f7adc221ee5e4e6787f35547c663b8930..8c3cda81e6192b3f95600bbdd6261a280d15fe50 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -96,6 +96,7 @@ /* Hardware limit on ChipSelect rows per MC and processors per system */ #define NUM_CHIPSELECTS 8 #define DRAM_RANGES 8 +#define NUM_CONTROLLERS 8 #define ON true #define OFF false @@ -119,6 +120,8 @@ #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F6 0x15ee #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F0 0x1490 #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F6 0x1496 +#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F0 0x1440 +#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F6 0x1446 /* * Function 1 - Address Map @@ -168,7 +171,8 @@ #define DCSM0 0x60 #define DCSM1 0x160 -#define csrow_enabled(i, dct, pvt) ((pvt)->csels[(dct)].csbases[(i)] & DCSB_CS_ENABLE) +#define csrow_enabled(i, dct, pvt) ((pvt)->csels[(dct)].csbases[(i)] & DCSB_CS_ENABLE) +#define csrow_sec_enabled(i, dct, pvt) ((pvt)->csels[(dct)].csbases_sec[(i)] & DCSB_CS_ENABLE) #define DRAM_CONTROL 0x78 @@ -258,7 +262,9 @@ /* UMC CH register offsets */ #define UMCCH_BASE_ADDR 0x0 +#define UMCCH_BASE_ADDR_SEC 0x10 #define UMCCH_ADDR_MASK 0x20 +#define UMCCH_ADDR_MASK_SEC 0x28 #define UMCCH_ADDR_CFG 0x30 #define UMCCH_DIMM_CFG 0x80 #define UMCCH_UMC_CFG 0x100 @@ -285,6 +291,7 @@ enum amd_families { F17_CPUS, F17_M10H_CPUS, F17_M30H_CPUS, + F17_M70H_CPUS, NUM_FAMILIES, }; @@ -311,9 +318,11 @@ struct dram_range { /* A DCT chip selects collection */ struct chip_select { u32 csbases[NUM_CHIPSELECTS]; + u32 csbases_sec[NUM_CHIPSELECTS]; u8 b_cnt; u32 csmasks[NUM_CHIPSELECTS]; + u32 csmasks_sec[NUM_CHIPSELECTS]; u8 m_cnt; }; @@ -351,8 +360,8 @@ struct amd64_pvt { u32 dbam0; /* DRAM Base Address Mapping reg for DCT0 */ u32 dbam1; /* DRAM Base Address Mapping reg for DCT1 */ - /* one for each DCT */ - struct chip_select csels[2]; + /* one for each DCT/UMC */ + struct chip_select csels[NUM_CONTROLLERS]; /* DRAM base and limit pairs F1x[78,70,68,60,58,50,48,40] */ struct dram_range ranges[DRAM_RANGES]; diff --git a/drivers/edac/bluefield_edac.c b/drivers/edac/bluefield_edac.c new file mode 100644 index 0000000000000000000000000000000000000000..e4736eb37bfb33d147a791b05bb145345d67cf17 --- /dev/null +++ b/drivers/edac/bluefield_edac.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Bluefield-specific EDAC driver. + * + * Copyright (c) 2019 Mellanox Technologies. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "edac_module.h" + +#define DRIVER_NAME "bluefield-edac" + +/* + * Mellanox BlueField EMI (External Memory Interface) register definitions. + */ + +#define MLXBF_ECC_CNT 0x340 +#define MLXBF_ECC_CNT__SERR_CNT GENMASK(15, 0) +#define MLXBF_ECC_CNT__DERR_CNT GENMASK(31, 16) + +#define MLXBF_ECC_ERR 0x348 +#define MLXBF_ECC_ERR__SECC BIT(0) +#define MLXBF_ECC_ERR__DECC BIT(16) + +#define MLXBF_ECC_LATCH_SEL 0x354 +#define MLXBF_ECC_LATCH_SEL__START BIT(24) + +#define MLXBF_ERR_ADDR_0 0x358 + +#define MLXBF_ERR_ADDR_1 0x37c + +#define MLXBF_SYNDROM 0x35c +#define MLXBF_SYNDROM__DERR BIT(0) +#define MLXBF_SYNDROM__SERR BIT(1) +#define MLXBF_SYNDROM__SYN GENMASK(25, 16) + +#define MLXBF_ADD_INFO 0x364 +#define MLXBF_ADD_INFO__ERR_PRANK GENMASK(9, 8) + +#define MLXBF_EDAC_MAX_DIMM_PER_MC 2 +#define MLXBF_EDAC_ERROR_GRAIN 8 + +/* + * Request MLNX_SIP_GET_DIMM_INFO + * + * Retrieve information about DIMM on a certain slot. + * + * Call register usage: + * a0: MLNX_SIP_GET_DIMM_INFO + * a1: (Memory controller index) << 16 | (Dimm index in memory controller) + * a2-7: not used. + * + * Return status: + * a0: MLXBF_DIMM_INFO defined below describing the DIMM. + * a1-3: not used. + */ +#define MLNX_SIP_GET_DIMM_INFO 0x82000008 + +/* Format for the SMC response about the memory information */ +#define MLXBF_DIMM_INFO__SIZE_GB GENMASK_ULL(15, 0) +#define MLXBF_DIMM_INFO__IS_RDIMM BIT(16) +#define MLXBF_DIMM_INFO__IS_LRDIMM BIT(17) +#define MLXBF_DIMM_INFO__IS_NVDIMM BIT(18) +#define MLXBF_DIMM_INFO__RANKS GENMASK_ULL(23, 21) +#define MLXBF_DIMM_INFO__PACKAGE_X GENMASK_ULL(31, 24) + +struct bluefield_edac_priv { + int dimm_ranks[MLXBF_EDAC_MAX_DIMM_PER_MC]; + void __iomem *emi_base; + int dimm_per_mc; +}; + +static u64 smc_call1(u64 smc_op, u64 smc_arg) +{ + struct arm_smccc_res res; + + arm_smccc_smc(smc_op, smc_arg, 0, 0, 0, 0, 0, 0, &res); + + return res.a0; +} + +/* + * Gather the ECC information from the External Memory Interface registers + * and report it to the edac handler. + */ +static void bluefield_gather_report_ecc(struct mem_ctl_info *mci, + int error_cnt, + int is_single_ecc) +{ + struct bluefield_edac_priv *priv = mci->pvt_info; + u32 dram_additional_info, err_prank, edea0, edea1; + u32 ecc_latch_select, dram_syndrom, serr, derr, syndrom; + enum hw_event_mc_err_type ecc_type; + u64 ecc_dimm_addr; + int ecc_dimm; + + ecc_type = is_single_ecc ? HW_EVENT_ERR_CORRECTED : + HW_EVENT_ERR_UNCORRECTED; + + /* + * Tell the External Memory Interface to populate the relevant + * registers with information about the last ECC error occurrence. + */ + ecc_latch_select = MLXBF_ECC_LATCH_SEL__START; + writel(ecc_latch_select, priv->emi_base + MLXBF_ECC_LATCH_SEL); + + /* + * Verify that the ECC reported info in the registers is of the + * same type as the one asked to report. If not, just report the + * error without the detailed information. + */ + dram_syndrom = readl(priv->emi_base + MLXBF_SYNDROM); + serr = FIELD_GET(MLXBF_SYNDROM__SERR, dram_syndrom); + derr = FIELD_GET(MLXBF_SYNDROM__DERR, dram_syndrom); + syndrom = FIELD_GET(MLXBF_SYNDROM__SYN, dram_syndrom); + + if ((is_single_ecc && !serr) || (!is_single_ecc && !derr)) { + edac_mc_handle_error(ecc_type, mci, error_cnt, 0, 0, 0, + 0, 0, -1, mci->ctl_name, ""); + return; + } + + dram_additional_info = readl(priv->emi_base + MLXBF_ADD_INFO); + err_prank = FIELD_GET(MLXBF_ADD_INFO__ERR_PRANK, dram_additional_info); + + ecc_dimm = (err_prank >= 2 && priv->dimm_ranks[0] <= 2) ? 1 : 0; + + edea0 = readl(priv->emi_base + MLXBF_ERR_ADDR_0); + edea1 = readl(priv->emi_base + MLXBF_ERR_ADDR_1); + + ecc_dimm_addr = ((u64)edea1 << 32) | edea0; + + edac_mc_handle_error(ecc_type, mci, error_cnt, + PFN_DOWN(ecc_dimm_addr), + offset_in_page(ecc_dimm_addr), + syndrom, ecc_dimm, 0, 0, mci->ctl_name, ""); +} + +static void bluefield_edac_check(struct mem_ctl_info *mci) +{ + struct bluefield_edac_priv *priv = mci->pvt_info; + u32 ecc_count, single_error_count, double_error_count, ecc_error = 0; + + /* + * The memory controller might not be initialized by the firmware + * when there isn't memory, which may lead to bad register readings. + */ + if (mci->edac_cap == EDAC_FLAG_NONE) + return; + + ecc_count = readl(priv->emi_base + MLXBF_ECC_CNT); + single_error_count = FIELD_GET(MLXBF_ECC_CNT__SERR_CNT, ecc_count); + double_error_count = FIELD_GET(MLXBF_ECC_CNT__DERR_CNT, ecc_count); + + if (single_error_count) { + ecc_error |= MLXBF_ECC_ERR__SECC; + + bluefield_gather_report_ecc(mci, single_error_count, 1); + } + + if (double_error_count) { + ecc_error |= MLXBF_ECC_ERR__DECC; + + bluefield_gather_report_ecc(mci, double_error_count, 0); + } + + /* Write to clear reported errors. */ + if (ecc_count) + writel(ecc_error, priv->emi_base + MLXBF_ECC_ERR); +} + +/* Initialize the DIMMs information for the given memory controller. */ +static void bluefield_edac_init_dimms(struct mem_ctl_info *mci) +{ + struct bluefield_edac_priv *priv = mci->pvt_info; + int mem_ctrl_idx = mci->mc_idx; + struct dimm_info *dimm; + u64 smc_info, smc_arg; + int is_empty = 1, i; + + for (i = 0; i < priv->dimm_per_mc; i++) { + dimm = mci->dimms[i]; + + smc_arg = mem_ctrl_idx << 16 | i; + smc_info = smc_call1(MLNX_SIP_GET_DIMM_INFO, smc_arg); + + if (!FIELD_GET(MLXBF_DIMM_INFO__SIZE_GB, smc_info)) { + dimm->mtype = MEM_EMPTY; + continue; + } + + is_empty = 0; + + dimm->edac_mode = EDAC_SECDED; + + if (FIELD_GET(MLXBF_DIMM_INFO__IS_NVDIMM, smc_info)) + dimm->mtype = MEM_NVDIMM; + else if (FIELD_GET(MLXBF_DIMM_INFO__IS_LRDIMM, smc_info)) + dimm->mtype = MEM_LRDDR4; + else if (FIELD_GET(MLXBF_DIMM_INFO__IS_RDIMM, smc_info)) + dimm->mtype = MEM_RDDR4; + else + dimm->mtype = MEM_DDR4; + + dimm->nr_pages = + FIELD_GET(MLXBF_DIMM_INFO__SIZE_GB, smc_info) * + (SZ_1G / PAGE_SIZE); + dimm->grain = MLXBF_EDAC_ERROR_GRAIN; + + /* Mem controller for BlueField only supports x4, x8 and x16 */ + switch (FIELD_GET(MLXBF_DIMM_INFO__PACKAGE_X, smc_info)) { + case 4: + dimm->dtype = DEV_X4; + break; + case 8: + dimm->dtype = DEV_X8; + break; + case 16: + dimm->dtype = DEV_X16; + break; + default: + dimm->dtype = DEV_UNKNOWN; + } + + priv->dimm_ranks[i] = + FIELD_GET(MLXBF_DIMM_INFO__RANKS, smc_info); + } + + if (is_empty) + mci->edac_cap = EDAC_FLAG_NONE; + else + mci->edac_cap = EDAC_FLAG_SECDED; +} + +static int bluefield_edac_mc_probe(struct platform_device *pdev) +{ + struct bluefield_edac_priv *priv; + struct device *dev = &pdev->dev; + struct edac_mc_layer layers[1]; + struct mem_ctl_info *mci; + struct resource *emi_res; + unsigned int mc_idx, dimm_count; + int rc, ret; + + /* Read the MSS (Memory SubSystem) index from ACPI table. */ + if (device_property_read_u32(dev, "mss_number", &mc_idx)) { + dev_warn(dev, "bf_edac: MSS number unknown\n"); + return -EINVAL; + } + + /* Read the DIMMs per MC from ACPI table. */ + if (device_property_read_u32(dev, "dimm_per_mc", &dimm_count)) { + dev_warn(dev, "bf_edac: DIMMs per MC unknown\n"); + return -EINVAL; + } + + if (dimm_count > MLXBF_EDAC_MAX_DIMM_PER_MC) { + dev_warn(dev, "bf_edac: DIMMs per MC not valid\n"); + return -EINVAL; + } + + emi_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!emi_res) + return -EINVAL; + + layers[0].type = EDAC_MC_LAYER_SLOT; + layers[0].size = dimm_count; + layers[0].is_virt_csrow = true; + + mci = edac_mc_alloc(mc_idx, ARRAY_SIZE(layers), layers, sizeof(*priv)); + if (!mci) + return -ENOMEM; + + priv = mci->pvt_info; + + priv->dimm_per_mc = dimm_count; + priv->emi_base = devm_ioremap_resource(dev, emi_res); + if (IS_ERR(priv->emi_base)) { + dev_err(dev, "failed to map EMI IO resource\n"); + ret = PTR_ERR(priv->emi_base); + goto err; + } + + mci->pdev = dev; + mci->mtype_cap = MEM_FLAG_DDR4 | MEM_FLAG_RDDR4 | + MEM_FLAG_LRDDR4 | MEM_FLAG_NVDIMM; + mci->edac_ctl_cap = EDAC_FLAG_SECDED; + + mci->mod_name = DRIVER_NAME; + mci->ctl_name = "BlueField_Memory_Controller"; + mci->dev_name = dev_name(dev); + mci->edac_check = bluefield_edac_check; + + /* Initialize mci with the actual populated DIMM information. */ + bluefield_edac_init_dimms(mci); + + platform_set_drvdata(pdev, mci); + + /* Register with EDAC core */ + rc = edac_mc_add_mc(mci); + if (rc) { + dev_err(dev, "failed to register with EDAC core\n"); + ret = rc; + goto err; + } + + /* Only POLL mode supported so far. */ + edac_op_state = EDAC_OPSTATE_POLL; + + return 0; + +err: + edac_mc_free(mci); + + return ret; + +} + +static int bluefield_edac_mc_remove(struct platform_device *pdev) +{ + struct mem_ctl_info *mci = platform_get_drvdata(pdev); + + edac_mc_del_mc(&pdev->dev); + edac_mc_free(mci); + + return 0; +} + +static const struct acpi_device_id bluefield_mc_acpi_ids[] = { + {"MLNXBF08", 0}, + {} +}; + +MODULE_DEVICE_TABLE(acpi, bluefield_mc_acpi_ids); + +static struct platform_driver bluefield_edac_mc_driver = { + .driver = { + .name = DRIVER_NAME, + .acpi_match_table = bluefield_mc_acpi_ids, + }, + .probe = bluefield_edac_mc_probe, + .remove = bluefield_edac_mc_remove, +}; + +module_platform_driver(bluefield_edac_mc_driver); + +MODULE_DESCRIPTION("Mellanox BlueField memory edac driver"); +MODULE_AUTHOR("Mellanox Technologies"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 64922c8fa7e3b729ea6b7919b371fcd76515491b..e6fd079783bd27f6a75da1976f8db4edeb9e6377 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -114,8 +114,8 @@ static const struct kernel_param_ops edac_report_ops = { module_param_cb(edac_report, &edac_report_ops, &edac_report, 0644); -unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf, - unsigned len) +unsigned int edac_dimm_info_location(struct dimm_info *dimm, char *buf, + unsigned int len) { struct mem_ctl_info *mci = dimm->mci; int i, n, count = 0; @@ -236,9 +236,9 @@ EXPORT_SYMBOL_GPL(edac_mem_types); * At return, the pointer 'p' will be incremented to be used on a next call * to this function. */ -void *edac_align_ptr(void **p, unsigned size, int n_elems) +void *edac_align_ptr(void **p, unsigned int size, int n_elems) { - unsigned align, r; + unsigned int align, r; void *ptr = *p; *p += size * n_elems; @@ -275,38 +275,37 @@ void *edac_align_ptr(void **p, unsigned size, int n_elems) static void _edac_mc_free(struct mem_ctl_info *mci) { - int i, chn, row; struct csrow_info *csr; - const unsigned int tot_dimms = mci->tot_dimms; - const unsigned int tot_channels = mci->num_cschannel; - const unsigned int tot_csrows = mci->nr_csrows; + int i, chn, row; if (mci->dimms) { - for (i = 0; i < tot_dimms; i++) + for (i = 0; i < mci->tot_dimms; i++) kfree(mci->dimms[i]); kfree(mci->dimms); } + if (mci->csrows) { - for (row = 0; row < tot_csrows; row++) { + for (row = 0; row < mci->nr_csrows; row++) { csr = mci->csrows[row]; - if (csr) { - if (csr->channels) { - for (chn = 0; chn < tot_channels; chn++) - kfree(csr->channels[chn]); - kfree(csr->channels); - } - kfree(csr); + if (!csr) + continue; + + if (csr->channels) { + for (chn = 0; chn < mci->num_cschannel; chn++) + kfree(csr->channels[chn]); + kfree(csr->channels); } + kfree(csr); } kfree(mci->csrows); } kfree(mci); } -struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, - unsigned n_layers, +struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num, + unsigned int n_layers, struct edac_mc_layer *layers, - unsigned sz_pvt) + unsigned int sz_pvt) { struct mem_ctl_info *mci; struct edac_mc_layer *layer; @@ -314,9 +313,9 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, struct rank_info *chan; struct dimm_info *dimm; u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS]; - unsigned pos[EDAC_MAX_LAYERS]; - unsigned size, tot_dimms = 1, count = 1; - unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0; + unsigned int pos[EDAC_MAX_LAYERS]; + unsigned int size, tot_dimms = 1, count = 1; + unsigned int tot_csrows = 1, tot_channels = 1, tot_errcount = 0; void *pvt, *p, *ptr = NULL; int i, j, row, chn, n, len, off; bool per_rank = false; @@ -1235,9 +1234,13 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, if (p > e->location) *(p - 1) = '\0'; - /* Report the error via the trace interface */ - grain_bits = fls_long(e->grain) + 1; + /* Sanity-check driver-supplied grain value. */ + if (WARN_ON_ONCE(!e->grain)) + e->grain = 1; + grain_bits = fls_long(e->grain - 1); + + /* Report the error via the trace interface */ if (IS_ENABLED(CONFIG_RAS)) trace_mc_event(type, e->msg, e->label, e->error_count, mci->mc_idx, e->top_layer, e->mid_layer, diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h index 4165e15995ad8a16975744ac5440b2db10ca4b8e..02aac5c61d0044a89546651a9b67f697869287e3 100644 --- a/drivers/edac/edac_mc.h +++ b/drivers/edac/edac_mc.h @@ -122,10 +122,10 @@ do { \ * On success, return a pointer to struct mem_ctl_info pointer; * %NULL otherwise */ -struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, - unsigned n_layers, +struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num, + unsigned int n_layers, struct edac_mc_layer *layers, - unsigned sz_pvt); + unsigned int sz_pvt); /** * edac_get_owner - Return the owner's mod_name of EDAC MC diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 4386ea4b9b5af81d069b88fb240ee721a707e4d2..32d016f1ecd1b0c5f8b4042b428952e0edb187dd 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -131,7 +131,7 @@ static const char * const edac_caps[] = { struct dev_ch_attribute { struct device_attribute attr; - int channel; + unsigned int channel; }; #define DEVICE_CHANNEL(_name, _mode, _show, _store, _var) \ @@ -200,7 +200,7 @@ static ssize_t channel_dimm_label_show(struct device *dev, char *data) { struct csrow_info *csrow = to_csrow(dev); - unsigned chan = to_channel(mattr); + unsigned int chan = to_channel(mattr); struct rank_info *rank = csrow->channels[chan]; /* if field has not been initialized, there is nothing to send */ @@ -216,7 +216,7 @@ static ssize_t channel_dimm_label_store(struct device *dev, const char *data, size_t count) { struct csrow_info *csrow = to_csrow(dev); - unsigned chan = to_channel(mattr); + unsigned int chan = to_channel(mattr); struct rank_info *rank = csrow->channels[chan]; size_t copy_count = count; @@ -240,7 +240,7 @@ static ssize_t channel_ce_count_show(struct device *dev, struct device_attribute *mattr, char *data) { struct csrow_info *csrow = to_csrow(dev); - unsigned chan = to_channel(mattr); + unsigned int chan = to_channel(mattr); struct rank_info *rank = csrow->channels[chan]; return sprintf(data, "%u\n", rank->ce_count); @@ -278,7 +278,7 @@ static void csrow_attr_release(struct device *dev) { struct csrow_info *csrow = container_of(dev, struct csrow_info, dev); - edac_dbg(1, "Releasing csrow device %s\n", dev_name(dev)); + edac_dbg(1, "device %s released\n", dev_name(dev)); kfree(csrow); } @@ -414,14 +414,16 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci, dev_set_name(&csrow->dev, "csrow%d", index); dev_set_drvdata(&csrow->dev, csrow); - edac_dbg(0, "creating (virtual) csrow node %s\n", - dev_name(&csrow->dev)); - err = device_add(&csrow->dev); - if (err) + if (err) { + edac_dbg(1, "failure: create device %s\n", dev_name(&csrow->dev)); put_device(&csrow->dev); + return err; + } - return err; + edac_dbg(0, "device %s created\n", dev_name(&csrow->dev)); + + return 0; } /* Create a CSROW object under specifed edac_mc_device */ @@ -435,12 +437,8 @@ static int edac_create_csrow_objects(struct mem_ctl_info *mci) if (!nr_pages_per_csrow(csrow)) continue; err = edac_create_csrow_object(mci, mci->csrows[i], i); - if (err < 0) { - edac_dbg(1, - "failure: create csrow objects for csrow %d\n", - i); + if (err < 0) goto error; - } } return 0; @@ -624,7 +622,7 @@ static void dimm_attr_release(struct device *dev) { struct dimm_info *dimm = container_of(dev, struct dimm_info, dev); - edac_dbg(1, "Releasing dimm device %s\n", dev_name(dev)); + edac_dbg(1, "device %s released\n", dev_name(dev)); kfree(dimm); } @@ -653,12 +651,21 @@ static int edac_create_dimm_object(struct mem_ctl_info *mci, pm_runtime_forbid(&mci->dev); err = device_add(&dimm->dev); - if (err) + if (err) { + edac_dbg(1, "failure: create device %s\n", dev_name(&dimm->dev)); put_device(&dimm->dev); + return err; + } - edac_dbg(0, "created rank/dimm device %s\n", dev_name(&dimm->dev)); + if (IS_ENABLED(CONFIG_EDAC_DEBUG)) { + char location[80]; - return err; + edac_dimm_info_location(dimm, location, sizeof(location)); + edac_dbg(0, "device %s created at location %s\n", + dev_name(&dimm->dev), location); + } + + return 0; } /* @@ -901,7 +908,7 @@ static void mci_attr_release(struct device *dev) { struct mem_ctl_info *mci = container_of(dev, struct mem_ctl_info, dev); - edac_dbg(1, "Releasing csrow device %s\n", dev_name(dev)); + edac_dbg(1, "device %s released\n", dev_name(dev)); kfree(mci); } @@ -933,14 +940,15 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci, dev_set_drvdata(&mci->dev, mci); pm_runtime_forbid(&mci->dev); - edac_dbg(0, "creating device %s\n", dev_name(&mci->dev)); err = device_add(&mci->dev); if (err < 0) { edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev)); put_device(&mci->dev); - goto out; + return err; } + edac_dbg(0, "device %s created\n", dev_name(&mci->dev)); + /* * Create the dimm/rank devices */ @@ -950,22 +958,9 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci, if (!dimm->nr_pages) continue; -#ifdef CONFIG_EDAC_DEBUG - edac_dbg(1, "creating dimm%d, located at ", i); - if (edac_debug_level >= 1) { - int lay; - for (lay = 0; lay < mci->n_layers; lay++) - printk(KERN_CONT "%s %d ", - edac_layer_name[mci->layers[lay].type], - dimm->location[lay]); - printk(KERN_CONT "\n"); - } -#endif err = edac_create_dimm_object(mci, dimm, i); - if (err) { - edac_dbg(1, "failure: create dimm %d obj\n", i); + if (err) goto fail_unregister_dimm; - } } #ifdef CONFIG_EDAC_LEGACY_SYSFS @@ -987,7 +982,6 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci, } device_unregister(&mci->dev); -out: return err; } @@ -1011,14 +1005,14 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) struct dimm_info *dimm = mci->dimms[i]; if (dimm->nr_pages == 0) continue; - edac_dbg(0, "removing device %s\n", dev_name(&dimm->dev)); + edac_dbg(1, "unregistering device %s\n", dev_name(&dimm->dev)); device_unregister(&dimm->dev); } } void edac_unregister_sysfs(struct mem_ctl_info *mci) { - edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev)); + edac_dbg(1, "unregistering device %s\n", dev_name(&mci->dev)); device_unregister(&mci->dev); } @@ -1029,7 +1023,7 @@ static void mc_attr_release(struct device *dev) * parent device, used to create the /sys/devices/mc sysfs node. * So, there are no attributes on it. */ - edac_dbg(1, "Releasing device %s\n", dev_name(dev)); + edac_dbg(1, "device %s released\n", dev_name(dev)); kfree(dev); } @@ -1044,10 +1038,8 @@ int __init edac_mc_sysfs_init(void) int err; mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL); - if (!mci_pdev) { - err = -ENOMEM; - goto out; - } + if (!mci_pdev) + return -ENOMEM; mci_pdev->bus = edac_get_sysfs_subsys(); mci_pdev->type = &mc_attr_type; @@ -1055,17 +1047,15 @@ int __init edac_mc_sysfs_init(void) dev_set_name(mci_pdev, "mc"); err = device_add(mci_pdev); - if (err < 0) - goto out_put_device; + if (err < 0) { + edac_dbg(1, "failure: create device %s\n", dev_name(mci_pdev)); + put_device(mci_pdev); + return err; + } edac_dbg(0, "device %s created\n", dev_name(mci_pdev)); return 0; - - out_put_device: - put_device(mci_pdev); - out: - return err; } void edac_mc_sysfs_exit(void) diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c index 7f19f1c672c3aaf1cf8e22de6612ee26634a5b72..d413a0bdc9ad9da8637b811e79a81023c39c1906 100644 --- a/drivers/edac/ghes_edac.c +++ b/drivers/edac/ghes_edac.c @@ -68,7 +68,7 @@ struct memdev_dmi_entry { struct ghes_edac_dimm_fill { struct mem_ctl_info *mci; - unsigned count; + unsigned int count; }; static void ghes_edac_count_dimms(const struct dmi_header *dh, void *arg) diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c index 83392f2841de0949119fc3bb3af47254ef9b69c4..c370d5457e6b69454edfe565a3243d43b2d3286e 100644 --- a/drivers/edac/i10nm_base.c +++ b/drivers/edac/i10nm_base.c @@ -123,9 +123,9 @@ static int i10nm_get_all_munits(void) } static const struct x86_cpu_id i10nm_cpuids[] = { - { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_TREMONT_X, 0, 0 }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_TREMONT_D, 0, 0 }, { X86_VENDOR_INTEL, 6, INTEL_FAM6_ICELAKE_X, 0, 0 }, - { X86_VENDOR_INTEL, 6, INTEL_FAM6_ICELAKE_XEON_D, 0, 0 }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ICELAKE_D, 0, 0 }, { } }; MODULE_DEVICE_TABLE(x86cpu, i10nm_cpuids); diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c index b506eef6b146d8570f6dcba9be5205d96ad9e9f9..251f2b692785d8729d2c48e35a663dacffdadf4e 100644 --- a/drivers/edac/i5100_edac.c +++ b/drivers/edac/i5100_edac.c @@ -417,7 +417,8 @@ static const char *i5100_err_msg(unsigned err) } /* convert csrow index into a rank (per channel -- 0..5) */ -static int i5100_csrow_to_rank(const struct mem_ctl_info *mci, int csrow) +static unsigned int i5100_csrow_to_rank(const struct mem_ctl_info *mci, + unsigned int csrow) { const struct i5100_priv *priv = mci->pvt_info; @@ -425,7 +426,8 @@ static int i5100_csrow_to_rank(const struct mem_ctl_info *mci, int csrow) } /* convert csrow index into a channel (0..1) */ -static int i5100_csrow_to_chan(const struct mem_ctl_info *mci, int csrow) +static unsigned int i5100_csrow_to_chan(const struct mem_ctl_info *mci, + unsigned int csrow) { const struct i5100_priv *priv = mci->pvt_info; @@ -653,11 +655,11 @@ static struct pci_dev *pci_get_device_func(unsigned vendor, return ret; } -static unsigned long i5100_npages(struct mem_ctl_info *mci, int csrow) +static unsigned long i5100_npages(struct mem_ctl_info *mci, unsigned int csrow) { struct i5100_priv *priv = mci->pvt_info; - const unsigned chan_rank = i5100_csrow_to_rank(mci, csrow); - const unsigned chan = i5100_csrow_to_chan(mci, csrow); + const unsigned int chan_rank = i5100_csrow_to_rank(mci, csrow); + const unsigned int chan = i5100_csrow_to_chan(mci, csrow); unsigned addr_lines; /* dimm present? */ @@ -852,8 +854,8 @@ static void i5100_init_csrows(struct mem_ctl_info *mci) for (i = 0; i < mci->tot_dimms; i++) { struct dimm_info *dimm; const unsigned long npages = i5100_npages(mci, i); - const unsigned chan = i5100_csrow_to_chan(mci, i); - const unsigned rank = i5100_csrow_to_rank(mci, i); + const unsigned int chan = i5100_csrow_to_chan(mci, i); + const unsigned int rank = i5100_csrow_to_rank(mci, i); if (!npages) continue; diff --git a/drivers/edac/pnd2_edac.c b/drivers/edac/pnd2_edac.c index ca25f8fe57ef3272ab90b0b42816bc1b0e73ebab..b1193be1ef1d8387bdda03407f17e149c4c87934 100644 --- a/drivers/edac/pnd2_edac.c +++ b/drivers/edac/pnd2_edac.c @@ -260,11 +260,14 @@ static u64 get_sideband_reg_base_addr(void) } } +#define DNV_MCHBAR_SIZE 0x8000 +#define DNV_SB_PORT_SIZE 0x10000 static int dnv_rd_reg(int port, int off, int op, void *data, size_t sz, char *name) { struct pci_dev *pdev; char *base; u64 addr; + unsigned long size; if (op == 4) { pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x1980, NULL); @@ -279,15 +282,17 @@ static int dnv_rd_reg(int port, int off, int op, void *data, size_t sz, char *na addr = get_mem_ctrl_hub_base_addr(); if (!addr) return -ENODEV; + size = DNV_MCHBAR_SIZE; } else { /* MMIO via sideband register base address */ addr = get_sideband_reg_base_addr(); if (!addr) return -ENODEV; addr += (port << 16); + size = DNV_SB_PORT_SIZE; } - base = ioremap((resource_size_t)addr, 0x10000); + base = ioremap((resource_size_t)addr, size); if (!base) return -ENODEV; @@ -1533,7 +1538,7 @@ static struct dunit_ops dnv_ops = { static const struct x86_cpu_id pnd2_cpuids[] = { { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_GOLDMONT, 0, (kernel_ulong_t)&apl_ops }, - { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_GOLDMONT_X, 0, (kernel_ulong_t)&dnv_ops }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_GOLDMONT_D, 0, (kernel_ulong_t)&dnv_ops }, { } }; MODULE_DEVICE_TABLE(x86cpu, pnd2_cpuids); diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 37746b045e18704daff9fee7aca2f86863760101..f743502ca9b72219c2d0d0b2fa0c4e26b62db4e8 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -3429,7 +3429,7 @@ static const struct x86_cpu_id sbridge_cpuids[] = { INTEL_CPU_FAM6(IVYBRIDGE_X, pci_dev_descr_ibridge_table), INTEL_CPU_FAM6(HASWELL_X, pci_dev_descr_haswell_table), INTEL_CPU_FAM6(BROADWELL_X, pci_dev_descr_broadwell_table), - INTEL_CPU_FAM6(BROADWELL_XEON_D, pci_dev_descr_broadwell_table), + INTEL_CPU_FAM6(BROADWELL_D, pci_dev_descr_broadwell_table), INTEL_CPU_FAM6(XEON_PHI_KNL, pci_dev_descr_knl_table), INTEL_CPU_FAM6(XEON_PHI_KNM, pci_dev_descr_knl_table), { } diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index ee9b5f70bfa40daa4f2dba92a6bbdfbae9469adc..ad02dc6747a439ba59c5ada29b150df6b1ab100d 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -140,10 +140,8 @@ static int adc_jack_probe(struct platform_device *pdev) return err; data->irq = platform_get_irq(pdev, 0); - if (data->irq < 0) { - dev_err(&pdev->dev, "platform_get_irq failed\n"); + if (data->irq < 0) return -ENODEV; - } err = request_any_context_irq(data->irq, adc_jack_irq_thread, pdata->irq_flags, pdata->name, data); diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 7e9f4c9ee87d8da092133e0e5a91710b7afd840e..e970134c95fabd3295df2f5f3a4cc29ca1d4384a 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -1253,7 +1253,7 @@ static int arizona_extcon_get_micd_configs(struct device *dev, int i, j; u32 *vals; - nconfs = device_property_read_u32_array(arizona->dev, prop, NULL, 0); + nconfs = device_property_count_u32(arizona->dev, prop); if (nconfs <= 0) return 0; diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c index 7254852e6ec0750c59b40de04f7b0db9b036ba62..415afaf479e7c732aaadc5bd2d398f3a5678e1ec 100644 --- a/drivers/extcon/extcon-axp288.c +++ b/drivers/extcon/extcon-axp288.c @@ -121,7 +121,6 @@ static const char * const axp288_pwr_up_down_info[] = { "Last shutdown caused by PMIC UVLO threshold", "Last shutdown caused by SOC initiated cold off", "Last shutdown caused by user pressing the power button", - NULL, }; /* @@ -130,18 +129,21 @@ static const char * const axp288_pwr_up_down_info[] = { */ static void axp288_extcon_log_rsi(struct axp288_extcon_info *info) { - const char * const *rsi; unsigned int val, i, clear_mask = 0; + unsigned long bits; int ret; ret = regmap_read(info->regmap, AXP288_PS_BOOT_REASON_REG, &val); - for (i = 0, rsi = axp288_pwr_up_down_info; *rsi; rsi++, i++) { - if (val & BIT(i)) { - dev_dbg(info->dev, "%s\n", *rsi); - clear_mask |= BIT(i); - } + if (ret < 0) { + dev_err(info->dev, "failed to read reset source indicator\n"); + return; } + bits = val & GENMASK(ARRAY_SIZE(axp288_pwr_up_down_info) - 1, 0); + for_each_set_bit(i, &bits, ARRAY_SIZE(axp288_pwr_up_down_info)) + dev_dbg(info->dev, "%s\n", axp288_pwr_up_down_info[i]); + clear_mask = bits; + /* Clear the register value for next reboot (write 1 to clear bit) */ regmap_write(info->regmap, AXP288_PS_BOOT_REASON_REG, clear_mask); } diff --git a/drivers/extcon/extcon-fsa9480.c b/drivers/extcon/extcon-fsa9480.c index 350fb34abfa0ca19fe70b47f58de52d9291c4a36..8405512f5199d4ba337146e5d721c7d871a4a5a2 100644 --- a/drivers/extcon/extcon-fsa9480.c +++ b/drivers/extcon/extcon-fsa9480.c @@ -363,6 +363,7 @@ MODULE_DEVICE_TABLE(i2c, fsa9480_id); static const struct of_device_id fsa9480_of_match[] = { { .compatible = "fcs,fsa9480", }, + { .compatible = "fcs,fsa880", }, { }, }; MODULE_DEVICE_TABLE(of, fsa9480_of_match); diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index faddeac948dbc3b954db78e1b1affc5608028440..c211222f5d0ccf6166a394a6b7ff02a16bcb5327 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c @@ -22,26 +22,22 @@ /** * struct gpio_extcon_data - A simple GPIO-controlled extcon device state container. * @edev: Extcon device. - * @irq: Interrupt line for the external connector. * @work: Work fired by the interrupt. * @debounce_jiffies: Number of jiffies to wait for the GPIO to stabilize, from the debounce * value. * @gpiod: GPIO descriptor for this external connector. * @extcon_id: The unique id of specific external connector. * @debounce: Debounce time for GPIO IRQ in ms. - * @irq_flags: IRQ Flags (e.g., IRQF_TRIGGER_LOW). * @check_on_resume: Boolean describing whether to check the state of gpio * while resuming from sleep. */ struct gpio_extcon_data { struct extcon_dev *edev; - int irq; struct delayed_work work; unsigned long debounce_jiffies; struct gpio_desc *gpiod; unsigned int extcon_id; unsigned long debounce; - unsigned long irq_flags; bool check_on_resume; }; @@ -69,6 +65,8 @@ static int gpio_extcon_probe(struct platform_device *pdev) { struct gpio_extcon_data *data; struct device *dev = &pdev->dev; + unsigned long irq_flags; + int irq; int ret; data = devm_kzalloc(dev, sizeof(struct gpio_extcon_data), GFP_KERNEL); @@ -82,15 +80,26 @@ static int gpio_extcon_probe(struct platform_device *pdev) * developed to get the extcon id from device-tree or others. * On later, it have to be solved. */ - if (!data->irq_flags || data->extcon_id > EXTCON_NONE) + if (data->extcon_id > EXTCON_NONE) return -EINVAL; data->gpiod = devm_gpiod_get(dev, "extcon", GPIOD_IN); if (IS_ERR(data->gpiod)) return PTR_ERR(data->gpiod); - data->irq = gpiod_to_irq(data->gpiod); - if (data->irq <= 0) - return data->irq; + irq = gpiod_to_irq(data->gpiod); + if (irq <= 0) + return irq; + + /* + * It is unlikely that this is an acknowledged interrupt that goes + * away after handling, what we are looking for are falling edges + * if the signal is active low, and rising edges if the signal is + * active high. + */ + if (gpiod_is_active_low(data->gpiod)) + irq_flags = IRQF_TRIGGER_FALLING; + else + irq_flags = IRQF_TRIGGER_RISING; /* Allocate the memory of extcon devie and register extcon device */ data->edev = devm_extcon_dev_allocate(dev, &data->extcon_id); @@ -109,8 +118,8 @@ static int gpio_extcon_probe(struct platform_device *pdev) * Request the interrupt of gpio to detect whether external connector * is attached or detached. */ - ret = devm_request_any_context_irq(dev, data->irq, - gpio_irq_handler, data->irq_flags, + ret = devm_request_any_context_irq(dev, irq, + gpio_irq_handler, irq_flags, pdev->name, data); if (ret < 0) return ret; diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c index a343a6ef35065dc6cce978ac51bb000be464c443..e6b50ca8300869c60e43b8bd35fc5f8cdb69eabf 100644 --- a/drivers/extcon/extcon-max77843.c +++ b/drivers/extcon/extcon-max77843.c @@ -774,12 +774,12 @@ static int max77843_init_muic_regmap(struct max77693_dev *max77843) { int ret; - max77843->i2c_muic = i2c_new_dummy(max77843->i2c->adapter, + max77843->i2c_muic = i2c_new_dummy_device(max77843->i2c->adapter, I2C_ADDR_MUIC); - if (!max77843->i2c_muic) { + if (IS_ERR(max77843->i2c_muic)) { dev_err(&max77843->i2c->dev, "Cannot allocate I2C device for MUIC\n"); - return -ENOMEM; + return PTR_ERR(max77843->i2c_muic); } i2c_set_clientdata(max77843->i2c_muic, max77843); diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c index 98e4f616b8f1457123b37d9de4cb950543867fe5..dc43847ad2b0809401dd21373c0c4df992cd171f 100644 --- a/drivers/extcon/extcon-sm5502.c +++ b/drivers/extcon/extcon-sm5502.c @@ -597,7 +597,7 @@ static int sm5022_muic_i2c_probe(struct i2c_client *i2c, ret = devm_request_threaded_irq(info->dev, virq, NULL, sm5502_muic_irq_handler, - IRQF_NO_SUSPEND, + IRQF_NO_SUSPEND | IRQF_ONESHOT, muic_irq->name, info); if (ret) { dev_err(info->dev, diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index ba8d3d0ef32c7fc0dfb11f393a76d01be0f83c7e..e40a77bfe8210fe4a81f87adfcfa2d4fc417aee7 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -216,6 +216,24 @@ config INTEL_STRATIX10_SERVICE Say Y here if you want Stratix10 service layer support. +config INTEL_STRATIX10_RSU + tristate "Intel Stratix10 Remote System Update" + depends on INTEL_STRATIX10_SERVICE + help + The Intel Remote System Update (RSU) driver exposes interfaces + access through the Intel Service Layer to user space via sysfs + device attribute nodes. The RSU interfaces report/control some of + the optional RSU features of the Stratix 10 SoC FPGA. + + The RSU provides a way for customers to update the boot + configuration of a Stratix 10 SoC device with significantly reduced + risk of corrupting the bitstream storage and bricking the system. + + Enable RSU support if you are using an Intel SoC FPGA with the RSU + feature enabled and you want Linux user space control. + + Say Y here if you want Intel RSU support. + config QCOM_SCM bool depends on ARM || ARM64 @@ -271,6 +289,20 @@ config TRUSTED_FOUNDATIONS Choose N if you don't know what this is about. +config TURRIS_MOX_RWTM + tristate "Turris Mox rWTM secure firmware driver" + depends on ARCH_MVEBU || COMPILE_TEST + depends on HAS_DMA && OF + depends on MAILBOX + select HW_RANDOM + select ARMADA_37XX_RWTM_MBOX + help + This driver communicates with the firmware on the Cortex-M3 secure + processor of the Turris Mox router. Enable if you are building for + Turris Mox, and you will be able to read the device serial number and + other manufacturing data and also utilize the Entropy Bit Generator + for hardware random number generation. + config HAVE_ARM_SMCCC bool diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 3fa0b34eb72fdfa44964711e9a26872abf5223a6..3fcb91975bdc68612ccff283cdd7f07fd29b63a4 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_EDD) += edd.o obj-$(CONFIG_EFI_PCDP) += pcdp.o obj-$(CONFIG_DMIID) += dmi-id.o obj-$(CONFIG_INTEL_STRATIX10_SERVICE) += stratix10-svc.o +obj-$(CONFIG_INTEL_STRATIX10_RSU) += stratix10-rsu.o obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o @@ -22,6 +23,7 @@ obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o +obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o obj-$(CONFIG_ARM_SCMI_PROTOCOL) += arm_scmi/ obj-y += psci/ diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index c47d28d556b6af6f2a9f37feafa22aec948fb1b6..5f298f00a82e3710c91b95ba626a951b60b62446 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -2,5 +2,5 @@ obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-bus-y = bus.o scmi-driver-y = driver.o -scmi-protocols-y = base.o clock.o perf.o power.o sensors.o +scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c index 204390297f4bd4e249a6f3987e992ff1eb2b7d56..f804e8af6521b9808a833830368776abddc81305 100644 --- a/drivers/firmware/arm_scmi/base.c +++ b/drivers/firmware/arm_scmi/base.c @@ -204,7 +204,7 @@ static int scmi_base_discover_agent_get(const struct scmi_handle *handle, if (ret) return ret; - *(__le32 *)t->tx.buf = cpu_to_le32(id); + put_unaligned_le32(id, t->tx.buf); ret = scmi_do_xfer(handle, t); if (!ret) diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c index 0a194af924385bac2019bf976d7e6e8263db9eeb..32526a793f3ace11cb5835cf336aea22aae53325 100644 --- a/drivers/firmware/arm_scmi/clock.c +++ b/drivers/firmware/arm_scmi/clock.c @@ -56,7 +56,7 @@ struct scmi_msg_resp_clock_describe_rates { struct scmi_clock_set_rate { __le32 flags; #define CLOCK_SET_ASYNC BIT(0) -#define CLOCK_SET_DELAYED BIT(1) +#define CLOCK_SET_IGNORE_RESP BIT(1) #define CLOCK_SET_ROUND_UP BIT(2) #define CLOCK_SET_ROUND_AUTO BIT(3) __le32 id; @@ -67,6 +67,7 @@ struct scmi_clock_set_rate { struct clock_info { int num_clocks; int max_async_req; + atomic_t cur_async_req; struct scmi_clock_info *clk; }; @@ -106,7 +107,7 @@ static int scmi_clock_attributes_get(const struct scmi_handle *handle, if (ret) return ret; - *(__le32 *)t->tx.buf = cpu_to_le32(clk_id); + put_unaligned_le32(clk_id, t->tx.buf); attr = t->rx.buf; ret = scmi_do_xfer(handle, t); @@ -203,39 +204,47 @@ scmi_clock_rate_get(const struct scmi_handle *handle, u32 clk_id, u64 *value) if (ret) return ret; - *(__le32 *)t->tx.buf = cpu_to_le32(clk_id); + put_unaligned_le32(clk_id, t->tx.buf); ret = scmi_do_xfer(handle, t); - if (!ret) { - __le32 *pval = t->rx.buf; - - *value = le32_to_cpu(*pval); - *value |= (u64)le32_to_cpu(*(pval + 1)) << 32; - } + if (!ret) + *value = get_unaligned_le64(t->rx.buf); scmi_xfer_put(handle, t); return ret; } static int scmi_clock_rate_set(const struct scmi_handle *handle, u32 clk_id, - u32 config, u64 rate) + u64 rate) { int ret; + u32 flags = 0; struct scmi_xfer *t; struct scmi_clock_set_rate *cfg; + struct clock_info *ci = handle->clk_priv; ret = scmi_xfer_get_init(handle, CLOCK_RATE_SET, SCMI_PROTOCOL_CLOCK, sizeof(*cfg), 0, &t); if (ret) return ret; + if (ci->max_async_req && + atomic_inc_return(&ci->cur_async_req) < ci->max_async_req) + flags |= CLOCK_SET_ASYNC; + cfg = t->tx.buf; - cfg->flags = cpu_to_le32(config); + cfg->flags = cpu_to_le32(flags); cfg->id = cpu_to_le32(clk_id); cfg->value_low = cpu_to_le32(rate & 0xffffffff); cfg->value_high = cpu_to_le32(rate >> 32); - ret = scmi_do_xfer(handle, t); + if (flags & CLOCK_SET_ASYNC) + ret = scmi_do_xfer_with_response(handle, t); + else + ret = scmi_do_xfer(handle, t); + + if (ci->max_async_req) + atomic_dec(&ci->cur_async_req); scmi_xfer_put(handle, t); return ret; diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 44fd4f9404a9740b06863f00a0357c0f22e68895..5237c2ff79fea1dfce305a20542b3d3b9f17d5b6 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -15,6 +15,8 @@ #include #include +#include + #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))) @@ -48,11 +50,11 @@ struct scmi_msg_resp_prot_version { /** * struct scmi_msg_hdr - Message(Tx/Rx) header * - * @id: The identifier of the command being sent - * @protocol_id: The identifier of the protocol used to send @id command - * @seq: The token to identify the message. when a message/command returns, - * the platform returns the whole message header unmodified including - * the token + * @id: The identifier of the message being sent + * @protocol_id: The identifier of the protocol used to send @id message + * @seq: The token to identify the message. When a message returns, the + * platform returns the whole message header unmodified including the + * token * @status: Status of the transfer once it's complete * @poll_completion: Indicate if the transfer needs to be polled for * completion or interrupt mode is used @@ -84,17 +86,21 @@ struct scmi_msg { * @rx: Receive message, the buffer should be pre-allocated to store * message. If request-ACK protocol is used, we can reuse the same * buffer for the rx path as we use for the tx path. - * @done: completion event + * @done: command message transmit completion event + * @async: pointer to delayed response message received event completion */ struct scmi_xfer { struct scmi_msg_hdr hdr; struct scmi_msg tx; struct scmi_msg rx; struct completion done; + 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); int scmi_handle_put(const struct scmi_handle *handle); diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index b5bc4c7a8fab2957bb0842b95e32d152f11837aa..3eb0382491cebbc973de870eda7fc43ec244eee2 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -30,8 +30,14 @@ #include "common.h" #define MSG_ID_MASK GENMASK(7, 0) +#define MSG_XTRACT_ID(hdr) FIELD_GET(MSG_ID_MASK, (hdr)) #define MSG_TYPE_MASK GENMASK(9, 8) +#define MSG_XTRACT_TYPE(hdr) FIELD_GET(MSG_TYPE_MASK, (hdr)) +#define MSG_TYPE_COMMAND 0 +#define MSG_TYPE_DELAYED_RESP 2 +#define MSG_TYPE_NOTIFICATION 3 #define MSG_PROTOCOL_ID_MASK GENMASK(17, 10) +#define MSG_XTRACT_PROT_ID(hdr) FIELD_GET(MSG_PROTOCOL_ID_MASK, (hdr)) #define MSG_TOKEN_ID_MASK GENMASK(27, 18) #define MSG_XTRACT_TOKEN(hdr) FIELD_GET(MSG_TOKEN_ID_MASK, (hdr)) #define MSG_TOKEN_MAX (MSG_XTRACT_TOKEN(MSG_TOKEN_ID_MASK) + 1) @@ -86,7 +92,7 @@ struct scmi_desc { }; /** - * struct scmi_chan_info - Structure representing a SCMI channel informfation + * struct scmi_chan_info - Structure representing a SCMI channel information * * @cl: Mailbox Client * @chan: Transmit/Receive mailbox channel @@ -111,8 +117,9 @@ struct scmi_chan_info { * @handle: Instance of SCMI handle to send to clients * @version: SCMI revision information containing protocol version, * implementation version and (sub-)vendor identification. - * @minfo: Message info - * @tx_idr: IDR object to map protocol id to channel info pointer + * @tx_minfo: Universal Transmit 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_imp: List of protocols implemented, currently maximum of * MAX_PROTOCOLS_IMP elements allocated by the base protocol * @node: List head @@ -123,8 +130,9 @@ struct scmi_info { const struct scmi_desc *desc; struct scmi_revision_info version; struct scmi_handle handle; - struct scmi_xfers_info minfo; + struct scmi_xfers_info tx_minfo; struct idr tx_idr; + struct idr rx_idr; u8 *protocols_imp; struct list_head node; int users; @@ -182,7 +190,7 @@ static inline int scmi_to_linux_errno(int errno) static inline void scmi_dump_header_dbg(struct device *dev, struct scmi_msg_hdr *hdr) { - dev_dbg(dev, "Command ID: %x Sequence ID: %x Protocol: %x\n", + dev_dbg(dev, "Message ID: %x Sequence ID: %x Protocol: %x\n", hdr->id, hdr->seq, hdr->protocol_id); } @@ -190,64 +198,20 @@ static void scmi_fetch_response(struct scmi_xfer *xfer, struct scmi_shared_mem __iomem *mem) { xfer->hdr.status = ioread32(mem->msg_payload); - /* Skip the length of header and statues in payload area i.e 8 bytes*/ + /* Skip the length of header and status in payload area i.e 8 bytes */ xfer->rx.len = min_t(size_t, xfer->rx.len, ioread32(&mem->length) - 8); /* Take a copy to the rx buffer.. */ memcpy_fromio(xfer->rx.buf, mem->msg_payload + 4, xfer->rx.len); } -/** - * scmi_rx_callback() - mailbox client callback for receive messages - * - * @cl: client pointer - * @m: mailbox message - * - * Processes one received message to appropriate transfer information and - * signals completion of the transfer. - * - * NOTE: This function will be invoked in IRQ context, hence should be - * as optimal as possible. - */ -static void scmi_rx_callback(struct mbox_client *cl, void *m) -{ - u16 xfer_id; - struct scmi_xfer *xfer; - struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl); - struct device *dev = cinfo->dev; - struct scmi_info *info = handle_to_scmi_info(cinfo->handle); - struct scmi_xfers_info *minfo = &info->minfo; - struct scmi_shared_mem __iomem *mem = cinfo->payload; - - xfer_id = MSG_XTRACT_TOKEN(ioread32(&mem->msg_header)); - - /* Are we even expecting this? */ - if (!test_bit(xfer_id, minfo->xfer_alloc_table)) { - dev_err(dev, "message for %d is not expected!\n", xfer_id); - return; - } - - xfer = &minfo->xfer_block[xfer_id]; - - scmi_dump_header_dbg(dev, &xfer->hdr); - /* Is the message of valid length? */ - if (xfer->rx.len > info->desc->max_msg_size) { - dev_err(dev, "unable to handle %zu xfer(max %d)\n", - xfer->rx.len, info->desc->max_msg_size); - return; - } - - scmi_fetch_response(xfer, mem); - complete(&xfer->done); -} - /** * pack_scmi_header() - packs and returns 32-bit header * * @hdr: pointer to header containing all the information on message id, * protocol id and sequence id. * - * Return: 32-bit packed command header to be sent to the platform. + * Return: 32-bit packed message header to be sent to the platform. */ static inline u32 pack_scmi_header(struct scmi_msg_hdr *hdr) { @@ -256,6 +220,18 @@ static inline u32 pack_scmi_header(struct scmi_msg_hdr *hdr) FIELD_PREP(MSG_PROTOCOL_ID_MASK, hdr->protocol_id); } +/** + * unpack_scmi_header() - unpacks and records message and protocol id + * + * @msg_hdr: 32-bit packed message header sent from the platform + * @hdr: pointer to header to fetch message and protocol id. + */ +static inline void unpack_scmi_header(u32 msg_hdr, struct scmi_msg_hdr *hdr) +{ + hdr->id = MSG_XTRACT_ID(msg_hdr); + hdr->protocol_id = MSG_XTRACT_PROT_ID(msg_hdr); +} + /** * scmi_tx_prepare() - mailbox client callback to prepare for the transfer * @@ -271,6 +247,14 @@ static void scmi_tx_prepare(struct mbox_client *cl, void *m) struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl); struct scmi_shared_mem __iomem *mem = cinfo->payload; + /* + * Ideally channel must be free by now unless OS timeout last + * request and platform continued to process the same, wait + * until it releases the shared memory, otherwise we may endup + * overwriting its response with new message payload or vice-versa + */ + spin_until_cond(ioread32(&mem->channel_status) & + SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); /* Mark channel busy + clear error */ iowrite32(0x0, &mem->channel_status); iowrite32(t->hdr.poll_completion ? 0 : SCMI_SHMEM_FLAG_INTR_ENABLED, @@ -285,8 +269,9 @@ static void scmi_tx_prepare(struct mbox_client *cl, void *m) * scmi_xfer_get() - Allocate one message * * @handle: Pointer to SCMI entity handle + * @minfo: Pointer to Tx/Rx Message management info based on channel type * - * Helper function which is used by various command functions that are + * Helper function which is used by various message functions that are * exposed to clients of this driver for allocating a message traffic event. * * This function can sleep depending on pending requests already in the system @@ -295,13 +280,13 @@ static void scmi_tx_prepare(struct mbox_client *cl, void *m) * * Return: 0 if all went fine, else corresponding error. */ -static struct scmi_xfer *scmi_xfer_get(const struct scmi_handle *handle) +static struct scmi_xfer *scmi_xfer_get(const struct scmi_handle *handle, + struct scmi_xfers_info *minfo) { u16 xfer_id; struct scmi_xfer *xfer; unsigned long flags, bit_pos; struct scmi_info *info = handle_to_scmi_info(handle); - struct scmi_xfers_info *minfo = &info->minfo; /* Keep the locked section as small as possible */ spin_lock_irqsave(&minfo->xfer_lock, flags); @@ -324,18 +309,17 @@ static struct scmi_xfer *scmi_xfer_get(const struct scmi_handle *handle) } /** - * scmi_xfer_put() - Release a message + * __scmi_xfer_put() - Release a message * - * @handle: Pointer to SCMI entity handle + * @minfo: Pointer to Tx/Rx Message management info based on channel type * @xfer: message that was reserved by scmi_xfer_get * * This holds a spinlock to maintain integrity of internal data structures. */ -void scmi_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer) +static void +__scmi_xfer_put(struct scmi_xfers_info *minfo, struct scmi_xfer *xfer) { unsigned long flags; - struct scmi_info *info = handle_to_scmi_info(handle); - struct scmi_xfers_info *minfo = &info->minfo; /* * Keep the locked section as small as possible @@ -347,6 +331,68 @@ void scmi_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer) spin_unlock_irqrestore(&minfo->xfer_lock, flags); } +/** + * scmi_rx_callback() - mailbox client callback for receive messages + * + * @cl: client pointer + * @m: mailbox message + * + * Processes one received message to appropriate transfer information and + * signals completion of the transfer. + * + * NOTE: This function will be invoked in IRQ context, hence should be + * as optimal as possible. + */ +static void scmi_rx_callback(struct mbox_client *cl, void *m) +{ + u8 msg_type; + u32 msg_hdr; + u16 xfer_id; + struct scmi_xfer *xfer; + struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl); + struct device *dev = cinfo->dev; + struct scmi_info *info = handle_to_scmi_info(cinfo->handle); + struct scmi_xfers_info *minfo = &info->tx_minfo; + struct scmi_shared_mem __iomem *mem = cinfo->payload; + + msg_hdr = ioread32(&mem->msg_header); + msg_type = MSG_XTRACT_TYPE(msg_hdr); + xfer_id = MSG_XTRACT_TOKEN(msg_hdr); + + if (msg_type == MSG_TYPE_NOTIFICATION) + return; /* Notifications not yet supported */ + + /* Are we even expecting this? */ + if (!test_bit(xfer_id, minfo->xfer_alloc_table)) { + dev_err(dev, "message for %d is not expected!\n", xfer_id); + return; + } + + xfer = &minfo->xfer_block[xfer_id]; + + scmi_dump_header_dbg(dev, &xfer->hdr); + + scmi_fetch_response(xfer, mem); + + if (msg_type == MSG_TYPE_DELAYED_RESP) + complete(xfer->async_done); + else + complete(&xfer->done); +} + +/** + * scmi_xfer_put() - Release a transmit message + * + * @handle: Pointer to SCMI entity handle + * @xfer: message that was reserved by scmi_xfer_get + */ +void scmi_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer) +{ + struct scmi_info *info = handle_to_scmi_info(handle); + + __scmi_xfer_put(&info->tx_minfo, xfer); +} + static bool scmi_xfer_poll_done(const struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) { @@ -435,8 +481,36 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) return ret; } +#define SCMI_MAX_RESPONSE_TIMEOUT (2 * MSEC_PER_SEC) + +/** + * scmi_do_xfer_with_response() - Do one transfer and wait until the delayed + * response is received + * + * @handle: Pointer to SCMI entity 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) +{ + int ret, timeout = msecs_to_jiffies(SCMI_MAX_RESPONSE_TIMEOUT); + DECLARE_COMPLETION_ONSTACK(async_response); + + xfer->async_done = &async_response; + + ret = scmi_do_xfer(handle, xfer); + if (!ret && !wait_for_completion_timeout(xfer->async_done, timeout)) + ret = -ETIMEDOUT; + + xfer->async_done = NULL; + return ret; +} + /** - * scmi_xfer_get_init() - Allocate and initialise one message + * scmi_xfer_get_init() - Allocate and initialise one message for transmit * * @handle: Pointer to SCMI entity handle * @msg_id: Message identifier @@ -457,6 +531,7 @@ int scmi_xfer_get_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id, int ret; struct scmi_xfer *xfer; struct scmi_info *info = handle_to_scmi_info(handle); + struct scmi_xfers_info *minfo = &info->tx_minfo; struct device *dev = info->dev; /* Ensure we have sane transfer sizes */ @@ -464,7 +539,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); + xfer = scmi_xfer_get(handle, minfo); if (IS_ERR(xfer)) { ret = PTR_ERR(xfer); dev_err(dev, "failed to get free message slot(%d)\n", ret); @@ -597,27 +672,13 @@ int scmi_handle_put(const struct scmi_handle *handle) return 0; } -static const struct scmi_desc scmi_generic_desc = { - .max_rx_timeout_ms = 30, /* We may increase this if required */ - .max_msg = 20, /* Limited by MBOX_TX_QUEUE_LEN */ - .max_msg_size = 128, -}; - -/* Each compatible listed below must have descriptor associated with it */ -static const struct of_device_id scmi_of_match[] = { - { .compatible = "arm,scmi", .data = &scmi_generic_desc }, - { /* Sentinel */ }, -}; - -MODULE_DEVICE_TABLE(of, scmi_of_match); - static int scmi_xfer_info_init(struct scmi_info *sinfo) { int i; struct scmi_xfer *xfer; struct device *dev = sinfo->dev; const struct scmi_desc *desc = sinfo->desc; - struct scmi_xfers_info *info = &sinfo->minfo; + struct scmi_xfers_info *info = &sinfo->tx_minfo; /* Pre-allocated messages, no more than what hdr.seq can support */ if (WARN_ON(desc->max_msg >= MSG_TOKEN_MAX)) { @@ -652,61 +713,32 @@ static int scmi_xfer_info_init(struct scmi_info *sinfo) return 0; } -static int scmi_mailbox_check(struct device_node *np) +static int scmi_mailbox_check(struct device_node *np, int idx) { - return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, NULL); + return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", + idx, NULL); } -static int scmi_mbox_free_channel(int id, void *p, void *data) +static int scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, + int prot_id, bool tx) { - struct scmi_chan_info *cinfo = p; - struct idr *idr = data; - - if (!IS_ERR_OR_NULL(cinfo->chan)) { - mbox_free_channel(cinfo->chan); - cinfo->chan = NULL; - } - - idr_remove(idr, id); - - return 0; -} - -static int scmi_remove(struct platform_device *pdev) -{ - int ret = 0; - struct scmi_info *info = platform_get_drvdata(pdev); - struct idr *idr = &info->tx_idr; - - mutex_lock(&scmi_list_mutex); - if (info->users) - ret = -EBUSY; - else - list_del(&info->node); - mutex_unlock(&scmi_list_mutex); - - if (ret) - return ret; - - /* Safe to free channels since no more users */ - ret = idr_for_each(idr, scmi_mbox_free_channel, idr); - idr_destroy(&info->tx_idr); - - return ret; -} - -static inline int -scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, int prot_id) -{ - int ret; + int ret, idx; struct resource res; resource_size_t size; struct device_node *shmem, *np = dev->of_node; struct scmi_chan_info *cinfo; struct mbox_client *cl; + struct idr *idr; + const char *desc = tx ? "Tx" : "Rx"; - if (scmi_mailbox_check(np)) { - cinfo = idr_find(&info->tx_idr, SCMI_PROTOCOL_BASE); + /* Transmit channel is first entry i.e. index 0 */ + idx = tx ? 0 : 1; + idr = tx ? &info->tx_idr : &info->rx_idr; + + if (scmi_mailbox_check(np, idx)) { + cinfo = idr_find(idr, SCMI_PROTOCOL_BASE); + if (unlikely(!cinfo)) /* Possible only if platform has no Rx */ + return -EINVAL; goto idr_alloc; } @@ -719,36 +751,36 @@ scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, int prot_id) cl = &cinfo->cl; cl->dev = dev; cl->rx_callback = scmi_rx_callback; - cl->tx_prepare = scmi_tx_prepare; + cl->tx_prepare = tx ? scmi_tx_prepare : NULL; cl->tx_block = false; - cl->knows_txdone = true; + cl->knows_txdone = tx; - shmem = of_parse_phandle(np, "shmem", 0); + shmem = of_parse_phandle(np, "shmem", idx); ret = of_address_to_resource(shmem, 0, &res); of_node_put(shmem); if (ret) { - dev_err(dev, "failed to get SCMI Tx payload mem resource\n"); + dev_err(dev, "failed to get SCMI %s payload memory\n", desc); return ret; } size = resource_size(&res); cinfo->payload = devm_ioremap(info->dev, res.start, size); if (!cinfo->payload) { - dev_err(dev, "failed to ioremap SCMI Tx payload\n"); + dev_err(dev, "failed to ioremap SCMI %s payload\n", desc); return -EADDRNOTAVAIL; } - /* Transmit channel is first entry i.e. index 0 */ - cinfo->chan = mbox_request_channel(cl, 0); + cinfo->chan = mbox_request_channel(cl, idx); if (IS_ERR(cinfo->chan)) { ret = PTR_ERR(cinfo->chan); if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to request SCMI Tx mailbox\n"); + dev_err(dev, "failed to request SCMI %s mailbox\n", + desc); return ret; } idr_alloc: - ret = idr_alloc(&info->tx_idr, cinfo, prot_id, prot_id + 1, GFP_KERNEL); + ret = idr_alloc(idr, cinfo, prot_id, prot_id + 1, GFP_KERNEL); if (ret != prot_id) { dev_err(dev, "unable to allocate SCMI idr slot err %d\n", ret); return ret; @@ -758,6 +790,17 @@ scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, int prot_id) return 0; } +static inline int +scmi_mbox_txrx_setup(struct scmi_info *info, struct device *dev, int prot_id) +{ + int ret = scmi_mbox_chan_setup(info, dev, prot_id, true); + + if (!ret) /* Rx is optional, hence no error check */ + scmi_mbox_chan_setup(info, dev, prot_id, false); + + return ret; +} + static inline void scmi_create_protocol_device(struct device_node *np, struct scmi_info *info, int prot_id) @@ -771,7 +814,7 @@ scmi_create_protocol_device(struct device_node *np, struct scmi_info *info, return; } - if (scmi_mbox_chan_setup(info, &sdev->dev, prot_id)) { + if (scmi_mbox_txrx_setup(info, &sdev->dev, prot_id)) { dev_err(&sdev->dev, "failed to setup transport\n"); scmi_device_destroy(sdev); return; @@ -791,7 +834,7 @@ static int scmi_probe(struct platform_device *pdev) struct device_node *child, *np = dev->of_node; /* Only mailbox method supported, check for the presence of one */ - if (scmi_mailbox_check(np)) { + if (scmi_mailbox_check(np, 0)) { dev_err(dev, "no mailbox found in %pOF\n", np); return -EINVAL; } @@ -814,12 +857,13 @@ static int scmi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, info); idr_init(&info->tx_idr); + idr_init(&info->rx_idr); handle = &info->handle; handle->dev = info->dev; handle->version = &info->version; - ret = scmi_mbox_chan_setup(info, dev, SCMI_PROTOCOL_BASE); + ret = scmi_mbox_txrx_setup(info, dev, SCMI_PROTOCOL_BASE); if (ret) return ret; @@ -854,6 +898,62 @@ static int scmi_probe(struct platform_device *pdev) return 0; } +static int scmi_mbox_free_channel(int id, void *p, void *data) +{ + struct scmi_chan_info *cinfo = p; + struct idr *idr = data; + + if (!IS_ERR_OR_NULL(cinfo->chan)) { + mbox_free_channel(cinfo->chan); + cinfo->chan = NULL; + } + + idr_remove(idr, id); + + return 0; +} + +static int scmi_remove(struct platform_device *pdev) +{ + int ret = 0; + struct scmi_info *info = platform_get_drvdata(pdev); + struct idr *idr = &info->tx_idr; + + mutex_lock(&scmi_list_mutex); + if (info->users) + ret = -EBUSY; + else + list_del(&info->node); + mutex_unlock(&scmi_list_mutex); + + if (ret) + return ret; + + /* Safe to free channels since no more users */ + ret = idr_for_each(idr, scmi_mbox_free_channel, idr); + idr_destroy(&info->tx_idr); + + idr = &info->rx_idr; + ret = idr_for_each(idr, scmi_mbox_free_channel, idr); + idr_destroy(&info->rx_idr); + + return ret; +} + +static const struct scmi_desc scmi_generic_desc = { + .max_rx_timeout_ms = 30, /* We may increase this if required */ + .max_msg = 20, /* Limited by MBOX_TX_QUEUE_LEN */ + .max_msg_size = 128, +}; + +/* Each compatible listed below must have descriptor associated with it */ +static const struct of_device_id scmi_of_match[] = { + { .compatible = "arm,scmi", .data = &scmi_generic_desc }, + { /* Sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, scmi_of_match); + static struct platform_driver scmi_driver = { .driver = { .name = "arm-scmi", diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index 3c8ae7cc35de3cf1b10cb452adbd8f0282b39a27..4a8012e3cb8c3725402ae5388edc978d909af2e9 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -5,7 +5,10 @@ * Copyright (C) 2018 ARM Ltd. */ +#include #include +#include +#include #include #include #include @@ -21,6 +24,7 @@ enum scmi_performance_protocol_cmd { PERF_LEVEL_GET = 0x8, PERF_NOTIFY_LIMITS = 0x9, PERF_NOTIFY_LEVEL = 0xa, + PERF_DESCRIBE_FASTCHANNEL = 0xb, }; struct scmi_opp { @@ -44,6 +48,7 @@ struct scmi_msg_resp_perf_domain_attributes { #define SUPPORTS_SET_PERF_LVL(x) ((x) & BIT(30)) #define SUPPORTS_PERF_LIMIT_NOTIFY(x) ((x) & BIT(29)) #define SUPPORTS_PERF_LEVEL_NOTIFY(x) ((x) & BIT(28)) +#define SUPPORTS_PERF_FASTCHANNELS(x) ((x) & BIT(27)) __le32 rate_limit_us; __le32 sustained_freq_khz; __le32 sustained_perf_level; @@ -87,17 +92,56 @@ struct scmi_msg_resp_perf_describe_levels { } opp[0]; }; +struct scmi_perf_get_fc_info { + __le32 domain; + __le32 message_id; +}; + +struct scmi_msg_resp_perf_desc_fc { + __le32 attr; +#define SUPPORTS_DOORBELL(x) ((x) & BIT(0)) +#define DOORBELL_REG_WIDTH(x) FIELD_GET(GENMASK(2, 1), (x)) + __le32 rate_limit; + __le32 chan_addr_low; + __le32 chan_addr_high; + __le32 chan_size; + __le32 db_addr_low; + __le32 db_addr_high; + __le32 db_set_lmask; + __le32 db_set_hmask; + __le32 db_preserve_lmask; + __le32 db_preserve_hmask; +}; + +struct scmi_fc_db_info { + int width; + u64 set; + u64 mask; + void __iomem *addr; +}; + +struct scmi_fc_info { + void __iomem *level_set_addr; + void __iomem *limit_set_addr; + void __iomem *level_get_addr; + void __iomem *limit_get_addr; + struct scmi_fc_db_info *level_set_db; + struct scmi_fc_db_info *limit_set_db; +}; + struct perf_dom_info { bool set_limits; bool set_perf; bool perf_limit_notify; bool perf_level_notify; + bool perf_fastchannels; u32 opp_count; u32 sustained_freq_khz; u32 sustained_perf_level; u32 mult_factor; char name[SCMI_MAX_STR_SIZE]; struct scmi_opp opp[MAX_OPPS]; + struct scmi_fc_info *fc_info; }; struct scmi_perf_info { @@ -151,7 +195,7 @@ scmi_perf_domain_attributes_get(const struct scmi_handle *handle, u32 domain, if (ret) return ret; - *(__le32 *)t->tx.buf = cpu_to_le32(domain); + put_unaligned_le32(domain, t->tx.buf); attr = t->rx.buf; ret = scmi_do_xfer(handle, t); @@ -162,6 +206,7 @@ scmi_perf_domain_attributes_get(const struct scmi_handle *handle, u32 domain, dom_info->set_perf = SUPPORTS_SET_PERF_LVL(flags); dom_info->perf_limit_notify = SUPPORTS_PERF_LIMIT_NOTIFY(flags); dom_info->perf_level_notify = SUPPORTS_PERF_LEVEL_NOTIFY(flags); + dom_info->perf_fastchannels = SUPPORTS_PERF_FASTCHANNELS(flags); dom_info->sustained_freq_khz = le32_to_cpu(attr->sustained_freq_khz); dom_info->sustained_perf_level = @@ -249,8 +294,42 @@ scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain, return ret; } -static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain, - u32 max_perf, u32 min_perf) +#define SCMI_PERF_FC_RING_DB(w) \ +do { \ + u##w val = 0; \ + \ + if (db->mask) \ + val = ioread##w(db->addr) & db->mask; \ + iowrite##w((u##w)db->set | val, db->addr); \ +} while (0) + +static void scmi_perf_fc_ring_db(struct scmi_fc_db_info *db) +{ + if (!db || !db->addr) + return; + + if (db->width == 1) + SCMI_PERF_FC_RING_DB(8); + else if (db->width == 2) + SCMI_PERF_FC_RING_DB(16); + else if (db->width == 4) + SCMI_PERF_FC_RING_DB(32); + else /* db->width == 8 */ +#ifdef CONFIG_64BIT + SCMI_PERF_FC_RING_DB(64); +#else + { + u64 val = 0; + + if (db->mask) + val = ioread64_hi_lo(db->addr) & db->mask; + iowrite64_hi_lo(db->set, db->addr); + } +#endif +} + +static int scmi_perf_mb_limits_set(const struct scmi_handle *handle, u32 domain, + u32 max_perf, u32 min_perf) { int ret; struct scmi_xfer *t; @@ -272,8 +351,24 @@ static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain, 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_set(const struct scmi_handle *handle, u32 domain, + u32 max_perf, u32 min_perf) +{ + struct scmi_perf_info *pi = handle->perf_priv; + struct perf_dom_info *dom = pi->dom_info + domain; + + if (dom->fc_info && dom->fc_info->limit_set_addr) { + iowrite32(max_perf, dom->fc_info->limit_set_addr); + iowrite32(min_perf, dom->fc_info->limit_set_addr + 4); + scmi_perf_fc_ring_db(dom->fc_info->limit_set_db); + return 0; + } + + return scmi_perf_mb_limits_set(handle, 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) { int ret; struct scmi_xfer *t; @@ -284,7 +379,7 @@ static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain, if (ret) return ret; - *(__le32 *)t->tx.buf = cpu_to_le32(domain); + put_unaligned_le32(domain, t->tx.buf); ret = scmi_do_xfer(handle, t); if (!ret) { @@ -298,8 +393,23 @@ static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain, return ret; } -static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain, - u32 level, bool poll) +static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain, + u32 *max_perf, u32 *min_perf) +{ + struct scmi_perf_info *pi = handle->perf_priv; + struct perf_dom_info *dom = pi->dom_info + domain; + + if (dom->fc_info && dom->fc_info->limit_get_addr) { + *max_perf = ioread32(dom->fc_info->limit_get_addr); + *min_perf = ioread32(dom->fc_info->limit_get_addr + 4); + return 0; + } + + return scmi_perf_mb_limits_get(handle, domain, max_perf, min_perf); +} + +static int scmi_perf_mb_level_set(const struct scmi_handle *handle, u32 domain, + u32 level, bool poll) { int ret; struct scmi_xfer *t; @@ -321,8 +431,23 @@ static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain, return ret; } -static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain, - u32 *level, bool poll) +static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain, + u32 level, bool poll) +{ + struct scmi_perf_info *pi = handle->perf_priv; + struct perf_dom_info *dom = pi->dom_info + domain; + + if (dom->fc_info && dom->fc_info->level_set_addr) { + iowrite32(level, dom->fc_info->level_set_addr); + scmi_perf_fc_ring_db(dom->fc_info->level_set_db); + return 0; + } + + return scmi_perf_mb_level_set(handle, domain, level, poll); +} + +static int scmi_perf_mb_level_get(const struct scmi_handle *handle, u32 domain, + u32 *level, bool poll) { int ret; struct scmi_xfer *t; @@ -333,16 +458,128 @@ static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain, return ret; t->hdr.poll_completion = poll; - *(__le32 *)t->tx.buf = cpu_to_le32(domain); + put_unaligned_le32(domain, t->tx.buf); ret = scmi_do_xfer(handle, t); if (!ret) - *level = le32_to_cpu(*(__le32 *)t->rx.buf); + *level = get_unaligned_le32(t->rx.buf); scmi_xfer_put(handle, t); return ret; } +static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain, + u32 *level, bool poll) +{ + struct scmi_perf_info *pi = handle->perf_priv; + struct perf_dom_info *dom = pi->dom_info + domain; + + if (dom->fc_info && dom->fc_info->level_get_addr) { + *level = ioread32(dom->fc_info->level_get_addr); + return 0; + } + + return scmi_perf_mb_level_get(handle, domain, level, poll); +} + +static bool scmi_perf_fc_size_is_valid(u32 msg, u32 size) +{ + if ((msg == PERF_LEVEL_GET || msg == PERF_LEVEL_SET) && size == 4) + return true; + if ((msg == PERF_LIMITS_GET || msg == PERF_LIMITS_SET) && size == 8) + return true; + return false; +} + +static void +scmi_perf_domain_desc_fc(const struct scmi_handle *handle, u32 domain, + u32 message_id, void __iomem **p_addr, + struct scmi_fc_db_info **p_db) +{ + int ret; + u32 flags; + u64 phys_addr; + u8 size; + void __iomem *addr; + struct scmi_xfer *t; + struct scmi_fc_db_info *db; + struct scmi_perf_get_fc_info *info; + struct scmi_msg_resp_perf_desc_fc *resp; + + if (!p_addr) + return; + + ret = scmi_xfer_get_init(handle, PERF_DESCRIBE_FASTCHANNEL, + SCMI_PROTOCOL_PERF, + sizeof(*info), sizeof(*resp), &t); + if (ret) + return; + + info = t->tx.buf; + info->domain = cpu_to_le32(domain); + info->message_id = cpu_to_le32(message_id); + + ret = scmi_do_xfer(handle, t); + if (ret) + goto err_xfer; + + resp = t->rx.buf; + flags = le32_to_cpu(resp->attr); + size = le32_to_cpu(resp->chan_size); + if (!scmi_perf_fc_size_is_valid(message_id, size)) + goto err_xfer; + + 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); + if (!addr) + goto err_xfer; + *p_addr = addr; + + if (p_db && SUPPORTS_DOORBELL(flags)) { + db = devm_kzalloc(handle->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); + if (!addr) + goto err_xfer; + + db->addr = addr; + db->width = size; + db->set = le32_to_cpu(resp->db_set_lmask); + db->set |= (u64)le32_to_cpu(resp->db_set_hmask) << 32; + db->mask = le32_to_cpu(resp->db_preserve_lmask); + db->mask |= (u64)le32_to_cpu(resp->db_preserve_hmask) << 32; + *p_db = db; + } +err_xfer: + scmi_xfer_put(handle, t); +} + +static void scmi_perf_domain_init_fc(const struct scmi_handle *handle, + u32 domain, struct scmi_fc_info **p_fc) +{ + struct scmi_fc_info *fc; + + fc = devm_kzalloc(handle->dev, sizeof(*fc), GFP_KERNEL); + if (!fc) + return; + + scmi_perf_domain_desc_fc(handle, domain, PERF_LEVEL_SET, + &fc->level_set_addr, &fc->level_set_db); + scmi_perf_domain_desc_fc(handle, domain, PERF_LEVEL_GET, + &fc->level_get_addr, NULL); + scmi_perf_domain_desc_fc(handle, domain, PERF_LIMITS_SET, + &fc->limit_set_addr, &fc->limit_set_db); + scmi_perf_domain_desc_fc(handle, domain, PERF_LIMITS_GET, + &fc->limit_get_addr, NULL); + *p_fc = fc; +} + /* Device specific ops */ static int scmi_dev_domain_id(struct device *dev) { @@ -494,6 +731,9 @@ static int scmi_perf_protocol_init(struct scmi_handle *handle) scmi_perf_domain_attributes_get(handle, domain, dom); scmi_perf_describe_levels_get(handle, domain, dom); + + if (dom->perf_fastchannels) + scmi_perf_domain_init_fc(handle, domain, &dom->fc_info); } handle->perf_ops = &perf_ops; diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c index 62f3401a1f01e90d9ddceabbe462416471d67614..5abef7079c0a31a84e7290209ff01f4bf0559e99 100644 --- a/drivers/firmware/arm_scmi/power.c +++ b/drivers/firmware/arm_scmi/power.c @@ -96,7 +96,7 @@ scmi_power_domain_attributes_get(const struct scmi_handle *handle, u32 domain, if (ret) return ret; - *(__le32 *)t->tx.buf = cpu_to_le32(domain); + put_unaligned_le32(domain, t->tx.buf); attr = t->rx.buf; ret = scmi_do_xfer(handle, t); @@ -147,11 +147,11 @@ scmi_power_state_get(const struct scmi_handle *handle, u32 domain, u32 *state) if (ret) return ret; - *(__le32 *)t->tx.buf = cpu_to_le32(domain); + put_unaligned_le32(domain, t->tx.buf); ret = scmi_do_xfer(handle, t); if (!ret) - *state = le32_to_cpu(*(__le32 *)t->rx.buf); + *state = get_unaligned_le32(t->rx.buf); scmi_xfer_put(handle, t); return ret; diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c new file mode 100644 index 0000000000000000000000000000000000000000..64cc819155819983002b5b29078b8b1f1f19bb98 --- /dev/null +++ b/drivers/firmware/arm_scmi/reset.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * System Control and Management Interface (SCMI) Reset Protocol + * + * Copyright (C) 2019 ARM Ltd. + */ + +#include "common.h" + +enum scmi_reset_protocol_cmd { + RESET_DOMAIN_ATTRIBUTES = 0x3, + RESET = 0x4, + RESET_NOTIFY = 0x5, +}; + +enum scmi_reset_protocol_notify { + RESET_ISSUED = 0x0, +}; + +#define NUM_RESET_DOMAIN_MASK 0xffff +#define RESET_NOTIFY_ENABLE BIT(0) + +struct scmi_msg_resp_reset_domain_attributes { + __le32 attributes; +#define SUPPORTS_ASYNC_RESET(x) ((x) & BIT(31)) +#define SUPPORTS_NOTIFY_RESET(x) ((x) & BIT(30)) + __le32 latency; + u8 name[SCMI_MAX_STR_SIZE]; +}; + +struct scmi_msg_reset_domain_reset { + __le32 domain_id; + __le32 flags; +#define AUTONOMOUS_RESET BIT(0) +#define EXPLICIT_RESET_ASSERT BIT(1) +#define ASYNCHRONOUS_RESET BIT(2) + __le32 reset_state; +#define ARCH_RESET_TYPE BIT(31) +#define COLD_RESET_STATE BIT(0) +#define ARCH_COLD_RESET (ARCH_RESET_TYPE | COLD_RESET_STATE) +}; + +struct reset_dom_info { + bool async_reset; + bool reset_notify; + u32 latency_us; + char name[SCMI_MAX_STR_SIZE]; +}; + +struct scmi_reset_info { + int num_domains; + struct reset_dom_info *dom_info; +}; + +static int scmi_reset_attributes_get(const struct scmi_handle *handle, + 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); + if (ret) + return ret; + + ret = scmi_do_xfer(handle, t); + if (!ret) { + attr = get_unaligned_le32(t->rx.buf); + pi->num_domains = attr & NUM_RESET_DOMAIN_MASK; + } + + scmi_xfer_put(handle, t); + return ret; +} + +static int +scmi_reset_domain_attributes_get(const struct scmi_handle *handle, 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); + if (ret) + return ret; + + put_unaligned_le32(domain, t->tx.buf); + attr = t->rx.buf; + + ret = scmi_do_xfer(handle, t); + if (!ret) { + u32 attributes = le32_to_cpu(attr->attributes); + + dom_info->async_reset = SUPPORTS_ASYNC_RESET(attributes); + dom_info->reset_notify = SUPPORTS_NOTIFY_RESET(attributes); + dom_info->latency_us = le32_to_cpu(attr->latency); + if (dom_info->latency_us == U32_MAX) + dom_info->latency_us = 0; + strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE); + } + + scmi_xfer_put(handle, t); + return ret; +} + +static int scmi_reset_num_domains_get(const struct scmi_handle *handle) +{ + struct scmi_reset_info *pi = handle->reset_priv; + + return pi->num_domains; +} + +static char *scmi_reset_name_get(const struct scmi_handle *handle, u32 domain) +{ + struct scmi_reset_info *pi = handle->reset_priv; + 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) +{ + struct scmi_reset_info *pi = handle->reset_priv; + 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, + 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 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); + if (ret) + return ret; + + dom = t->tx.buf; + dom->domain_id = cpu_to_le32(domain); + dom->flags = cpu_to_le32(flags); + dom->domain_id = cpu_to_le32(state); + + if (rdom->async_reset) + ret = scmi_do_xfer_with_response(handle, t); + else + ret = scmi_do_xfer(handle, t); + + scmi_xfer_put(handle, t); + return ret; +} + +static int scmi_reset_domain_reset(const struct scmi_handle *handle, u32 domain) +{ + return scmi_domain_reset(handle, domain, AUTONOMOUS_RESET, + ARCH_COLD_RESET); +} + +static int +scmi_reset_domain_assert(const struct scmi_handle *handle, u32 domain) +{ + return scmi_domain_reset(handle, domain, EXPLICIT_RESET_ASSERT, + ARCH_COLD_RESET); +} + +static int +scmi_reset_domain_deassert(const struct scmi_handle *handle, u32 domain) +{ + return scmi_domain_reset(handle, domain, 0, ARCH_COLD_RESET); +} + +static struct scmi_reset_ops reset_ops = { + .num_domains_get = scmi_reset_num_domains_get, + .name_get = scmi_reset_name_get, + .latency_get = scmi_reset_latency_get, + .reset = scmi_reset_domain_reset, + .assert = scmi_reset_domain_assert, + .deassert = scmi_reset_domain_deassert, +}; + +static int scmi_reset_protocol_init(struct scmi_handle *handle) +{ + int domain; + u32 version; + struct scmi_reset_info *pinfo; + + scmi_version_get(handle, SCMI_PROTOCOL_RESET, &version); + + dev_dbg(handle->dev, "Reset Version %d.%d\n", + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); + + pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL); + if (!pinfo) + return -ENOMEM; + + scmi_reset_attributes_get(handle, pinfo); + + pinfo->dom_info = devm_kcalloc(handle->dev, pinfo->num_domains, + sizeof(*pinfo->dom_info), GFP_KERNEL); + if (!pinfo->dom_info) + return -ENOMEM; + + 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); + } + + handle->reset_ops = &reset_ops; + handle->reset_priv = pinfo; + + return 0; +} + +static int __init scmi_reset_init(void) +{ + return scmi_protocol_register(SCMI_PROTOCOL_RESET, + &scmi_reset_protocol_init); +} +subsys_initcall(scmi_reset_init); diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c index 0e94ab56f679834ca0fb89b772c01861a6a8768c..a400ea805fc236738047efc3dc351cfa79aed895 100644 --- a/drivers/firmware/arm_scmi/sensors.c +++ b/drivers/firmware/arm_scmi/sensors.c @@ -9,8 +9,8 @@ enum scmi_sensor_protocol_cmd { SENSOR_DESCRIPTION_GET = 0x3, - SENSOR_CONFIG_SET = 0x4, - SENSOR_TRIP_POINT_SET = 0x5, + SENSOR_TRIP_POINT_NOTIFY = 0x4, + SENSOR_TRIP_POINT_CONFIG = 0x5, SENSOR_READING_GET = 0x6, }; @@ -42,9 +42,10 @@ struct scmi_msg_resp_sensor_description { } desc[0]; }; -struct scmi_msg_set_sensor_config { +struct scmi_msg_sensor_trip_point_notify { __le32 id; __le32 event_control; +#define SENSOR_TP_NOTIFY_ALL BIT(0) }; struct scmi_msg_set_sensor_trip_point { @@ -119,7 +120,7 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, do { /* Set the number of sensors to be skipped/already read */ - *(__le32 *)t->tx.buf = cpu_to_le32(desc_index); + put_unaligned_le32(desc_index, t->tx.buf); ret = scmi_do_xfer(handle, t); if (ret) @@ -135,9 +136,10 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, } for (cnt = 0; cnt < num_returned; cnt++) { - u32 attrh; + u32 attrh, attrl; struct scmi_sensor_info *s; + attrl = le32_to_cpu(buf->desc[cnt].attributes_low); attrh = le32_to_cpu(buf->desc[cnt].attributes_high); s = &si->sensors[desc_index + cnt]; s->id = le32_to_cpu(buf->desc[cnt].id); @@ -146,6 +148,8 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, /* Sign extend to a full s8 */ if (s->scale & SENSOR_SCALE_SIGN) s->scale |= SENSOR_SCALE_EXTEND; + s->async = SUPPORTS_ASYNC_READ(attrl); + s->num_trip_points = NUM_TRIP_POINTS(attrl); strlcpy(s->name, buf->desc[cnt].name, SCMI_MAX_STR_SIZE); } @@ -160,15 +164,15 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, return ret; } -static int -scmi_sensor_configuration_set(const struct scmi_handle *handle, u32 sensor_id) +static int scmi_sensor_trip_point_notify(const struct scmi_handle *handle, + u32 sensor_id, bool enable) { int ret; - u32 evt_cntl = BIT(0); + u32 evt_cntl = enable ? SENSOR_TP_NOTIFY_ALL : 0; struct scmi_xfer *t; - struct scmi_msg_set_sensor_config *cfg; + struct scmi_msg_sensor_trip_point_notify *cfg; - ret = scmi_xfer_get_init(handle, SENSOR_CONFIG_SET, + ret = scmi_xfer_get_init(handle, SENSOR_TRIP_POINT_NOTIFY, SCMI_PROTOCOL_SENSOR, sizeof(*cfg), 0, &t); if (ret) return ret; @@ -183,15 +187,16 @@ scmi_sensor_configuration_set(const struct scmi_handle *handle, u32 sensor_id) return ret; } -static int scmi_sensor_trip_point_set(const struct scmi_handle *handle, - u32 sensor_id, u8 trip_id, u64 trip_value) +static int +scmi_sensor_trip_point_config(const struct scmi_handle *handle, 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_SET, + ret = scmi_xfer_get_init(handle, SENSOR_TRIP_POINT_CONFIG, SCMI_PROTOCOL_SENSOR, sizeof(*trip), 0, &t); if (ret) return ret; @@ -209,11 +214,13 @@ static int scmi_sensor_trip_point_set(const struct scmi_handle *handle, } static int scmi_sensor_reading_get(const struct scmi_handle *handle, - u32 sensor_id, bool async, u64 *value) + 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 scmi_sensor_info *s = si->sensors + sensor_id; ret = scmi_xfer_get_init(handle, SENSOR_READING_GET, SCMI_PROTOCOL_SENSOR, sizeof(*sensor), @@ -223,14 +230,18 @@ static int scmi_sensor_reading_get(const struct scmi_handle *handle, sensor = t->tx.buf; sensor->id = cpu_to_le32(sensor_id); - sensor->flags = cpu_to_le32(async ? SENSOR_READ_ASYNC : 0); - ret = scmi_do_xfer(handle, t); - if (!ret) { - __le32 *pval = t->rx.buf; - - *value = le32_to_cpu(*pval); - *value |= (u64)le32_to_cpu(*(pval + 1)) << 32; + if (s->async) { + sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC); + ret = scmi_do_xfer_with_response(handle, t); + if (!ret) + *value = get_unaligned_le64((void *) + ((__le32 *)t->rx.buf + 1)); + } else { + sensor->flags = cpu_to_le32(0); + ret = scmi_do_xfer(handle, t); + if (!ret) + *value = get_unaligned_le64(t->rx.buf); } scmi_xfer_put(handle, t); @@ -255,8 +266,8 @@ static int scmi_sensor_count_get(const struct scmi_handle *handle) static struct scmi_sensor_ops sensor_ops = { .count_get = scmi_sensor_count_get, .info_get = scmi_sensor_info_get, - .configuration_set = scmi_sensor_configuration_set, - .trip_point_set = scmi_sensor_trip_point_set, + .trip_point_notify = scmi_sensor_trip_point_notify, + .trip_point_config = scmi_sensor_trip_point_config, .reading_get = scmi_sensor_reading_get, }; diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index 725164b832424d07af472bf314ab84f77a84ac78..a80c331c3a6e5b11cff260a9b68c1a3a5910ea05 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -1011,10 +1011,6 @@ static int scpi_probe(struct platform_device *pdev) scpi_info->firmware_version)); scpi_info->scpi_ops = &scpi_ops; - ret = devm_device_add_groups(dev, versions_groups); - if (ret) - dev_err(dev, "unable to create sysfs version group\n"); - return devm_of_platform_populate(dev); } @@ -1030,6 +1026,7 @@ static struct platform_driver scpi_driver = { .driver = { .name = "scpi_protocol", .of_match_table = scpi_of_match, + .dev_groups = versions_groups, }, .probe = scpi_probe, .remove = scpi_remove, diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index d4ea929e8b344c1a48e0c96fc771ef374c65c4c2..178ee8106828775f90a317bbb86a3b75d8dfb9ac 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -180,6 +180,19 @@ config RESET_ATTACK_MITIGATION have been evicted, since otherwise it will trigger even on clean reboots. +config EFI_RCI2_TABLE + bool "EFI Runtime Configuration Interface Table Version 2 Support" + help + Displays the content of the Runtime Configuration Interface + Table version 2 on Dell EMC PowerEdge systems as a binary + attribute 'rci2' under /sys/firmware/efi/tables directory. + + RCI2 table contains BIOS HII in XML format and is used to populate + BIOS setup page in Dell EMC OpenManage Server Administrator tool. + The BIOS setup page contains BIOS tokens which can be configured. + + Say Y here for Dell EMC PowerEdge systems. + endmenu config UEFI_CPER diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index d2d0d20306200eedece2d5de4e708e70a9bbb16c..4ac2de4dfa72aaf6e22a351417dd5c1dac207819 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o obj-$(CONFIG_EFI_TEST) += test/ obj-$(CONFIG_EFI_DEV_PATH_PARSER) += dev-path-parser.o obj-$(CONFIG_APPLE_PROPERTIES) += apple-properties.o +obj-$(CONFIG_EFI_RCI2_TABLE) += rci2-table.o arm-obj-$(CONFIG_EFI) := arm-init.o arm-runtime.o obj-$(CONFIG_ARM) += $(arm-obj-y) diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index 8fa977c7861f961c32af4dfa3b949e9c5f1460ec..addf0749dd8b6ea6b3d6f423363fbdfddbaea17e 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -390,6 +390,21 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, printk( "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", pfx, pcie->bridge.secondary_status, pcie->bridge.control); + + /* Fatal errors call __ghes_panic() before AER handler prints this */ + if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) && + (gdata->error_severity & CPER_SEV_FATAL)) { + struct aer_capability_regs *aer; + + aer = (struct aer_capability_regs *)pcie->aer_info; + printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n", + pfx, aer->uncor_status, aer->uncor_mask); + printk("%saer_uncor_severity: 0x%08x\n", + pfx, aer->uncor_severity); + printk("%sTLP Header: %08x %08x %08x %08x\n", pfx, + aer->header_log.dw0, aer->header_log.dw1, + aer->header_log.dw2, aer->header_log.dw3); + } } static void cper_print_tstamp(const char *pfx, diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index ad3b1f4866b35951592dc4a4ecef92cf30cd4a1d..8f1ab04f6743ae9c402ac813195fd1a19d8f5b63 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -39,11 +39,9 @@ struct efi __read_mostly efi = { .acpi20 = EFI_INVALID_TABLE_ADDR, .smbios = EFI_INVALID_TABLE_ADDR, .smbios3 = EFI_INVALID_TABLE_ADDR, - .sal_systab = EFI_INVALID_TABLE_ADDR, .boot_info = EFI_INVALID_TABLE_ADDR, .hcdp = EFI_INVALID_TABLE_ADDR, .uga = EFI_INVALID_TABLE_ADDR, - .uv_systab = EFI_INVALID_TABLE_ADDR, .fw_vendor = EFI_INVALID_TABLE_ADDR, .runtime = EFI_INVALID_TABLE_ADDR, .config_table = EFI_INVALID_TABLE_ADDR, @@ -57,25 +55,6 @@ struct efi __read_mostly efi = { }; EXPORT_SYMBOL(efi); -static unsigned long *efi_tables[] = { - &efi.mps, - &efi.acpi, - &efi.acpi20, - &efi.smbios, - &efi.smbios3, - &efi.sal_systab, - &efi.boot_info, - &efi.hcdp, - &efi.uga, - &efi.uv_systab, - &efi.fw_vendor, - &efi.runtime, - &efi.config_table, - &efi.esrt, - &efi.properties_table, - &efi.mem_attr_table, -}; - struct mm_struct efi_mm = { .mm_rb = RB_ROOT, .mm_users = ATOMIC_INIT(2), @@ -476,7 +455,6 @@ static __initdata efi_config_table_type_t common_tables[] = { {ACPI_TABLE_GUID, "ACPI", &efi.acpi}, {HCDP_TABLE_GUID, "HCDP", &efi.hcdp}, {MPS_TABLE_GUID, "MPS", &efi.mps}, - {SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab}, {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios}, {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3}, {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga}, @@ -487,6 +465,9 @@ static __initdata efi_config_table_type_t common_tables[] = { {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log}, {LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log}, {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve}, +#ifdef CONFIG_EFI_RCI2_TABLE + {DELLEMC_EFI_RCI2_TABLE_GUID, NULL, &rci2_table_phys}, +#endif {NULL_GUID, NULL, NULL}, }; @@ -964,20 +945,6 @@ int efi_status_to_err(efi_status_t status) return err; } -bool efi_is_table_address(unsigned long phys_addr) -{ - unsigned int i; - - if (phys_addr == EFI_INVALID_TABLE_ADDR) - return false; - - for (i = 0; i < ARRAY_SIZE(efi_tables); i++) - if (*(efi_tables[i]) == phys_addr) - return true; - - return false; -} - static DEFINE_SPINLOCK(efi_mem_reserve_persistent_lock); static struct linux_efi_memreserve *efi_memreserve_root __ro_after_init; diff --git a/drivers/firmware/efi/rci2-table.c b/drivers/firmware/efi/rci2-table.c new file mode 100644 index 0000000000000000000000000000000000000000..3e290f96620a408e1c0eda16e53d85a866208a87 --- /dev/null +++ b/drivers/firmware/efi/rci2-table.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Export Runtime Configuration Interface Table Version 2 (RCI2) + * to sysfs + * + * Copyright (C) 2019 Dell Inc + * by Narendra K + * + * System firmware advertises the address of the RCI2 Table via + * an EFI Configuration Table entry. This code retrieves the RCI2 + * table from the address and exports it to sysfs as a binary + * attribute 'rci2' under /sys/firmware/efi/tables directory. + */ + +#include +#include +#include +#include +#include +#include + +#define RCI_SIGNATURE "_RC_" + +struct rci2_table_global_hdr { + u16 type; + u16 resvd0; + u16 hdr_len; + u8 rci2_sig[4]; + u16 resvd1; + u32 resvd2; + u32 resvd3; + u8 major_rev; + u8 minor_rev; + u16 num_of_structs; + u32 rci2_len; + u16 rci2_chksum; +} __packed; + +static u8 *rci2_base; +static u32 rci2_table_len; +unsigned long rci2_table_phys __ro_after_init = EFI_INVALID_TABLE_ADDR; + +static ssize_t raw_table_read(struct file *file, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t pos, size_t count) +{ + memcpy(buf, attr->private + pos, count); + return count; +} + +static BIN_ATTR(rci2, S_IRUSR, raw_table_read, NULL, 0); + +static u16 checksum(void) +{ + u8 len_is_odd = rci2_table_len % 2; + u32 chksum_len = rci2_table_len; + u16 *base = (u16 *)rci2_base; + u8 buf[2] = {0}; + u32 offset = 0; + u16 chksum = 0; + + if (len_is_odd) + chksum_len -= 1; + + while (offset < chksum_len) { + chksum += *base; + offset += 2; + base++; + } + + if (len_is_odd) { + buf[0] = *(u8 *)base; + chksum += *(u16 *)(buf); + } + + return chksum; +} + +int __init efi_rci2_sysfs_init(void) +{ + struct kobject *tables_kobj; + int ret = -ENOMEM; + + rci2_base = memremap(rci2_table_phys, + sizeof(struct rci2_table_global_hdr), + MEMREMAP_WB); + if (!rci2_base) { + pr_debug("RCI2 table init failed - could not map RCI2 table\n"); + goto err; + } + + if (strncmp(rci2_base + + offsetof(struct rci2_table_global_hdr, rci2_sig), + RCI_SIGNATURE, 4)) { + pr_debug("RCI2 table init failed - incorrect signature\n"); + ret = -ENODEV; + goto err_unmap; + } + + rci2_table_len = *(u32 *)(rci2_base + + offsetof(struct rci2_table_global_hdr, + rci2_len)); + + memunmap(rci2_base); + + if (!rci2_table_len) { + pr_debug("RCI2 table init failed - incorrect table length\n"); + goto err; + } + + rci2_base = memremap(rci2_table_phys, rci2_table_len, MEMREMAP_WB); + if (!rci2_base) { + pr_debug("RCI2 table - could not map RCI2 table\n"); + goto err; + } + + if (checksum() != 0) { + pr_debug("RCI2 table - incorrect checksum\n"); + ret = -ENODEV; + goto err_unmap; + } + + tables_kobj = kobject_create_and_add("tables", efi_kobj); + if (!tables_kobj) { + pr_debug("RCI2 table - tables_kobj creation failed\n"); + goto err_unmap; + } + + bin_attr_rci2.size = rci2_table_len; + bin_attr_rci2.private = rci2_base; + ret = sysfs_create_bin_file(tables_kobj, &bin_attr_rci2); + if (ret != 0) { + pr_debug("RCI2 table - rci2 sysfs bin file creation failed\n"); + kobject_del(tables_kobj); + kobject_put(tables_kobj); + goto err_unmap; + } + + return 0; + + err_unmap: + memunmap(rci2_base); + err: + pr_debug("RCI2 table - sysfs initialization failed\n"); + return ret; +} +late_initcall(efi_rci2_sysfs_init); diff --git a/drivers/firmware/google/vpd.c b/drivers/firmware/google/vpd.c index 0739f3b70347bb6ad340c216f3e5515f726ddd33..db0812263d462309193837dc022a538cee7ff98f 100644 --- a/drivers/firmware/google/vpd.c +++ b/drivers/firmware/google/vpd.c @@ -92,8 +92,8 @@ static int vpd_section_check_key_name(const u8 *key, s32 key_len) return VPD_OK; } -static int vpd_section_attrib_add(const u8 *key, s32 key_len, - const u8 *value, s32 value_len, +static int vpd_section_attrib_add(const u8 *key, u32 key_len, + const u8 *value, u32 value_len, void *arg) { int ret; diff --git a/drivers/firmware/google/vpd_decode.c b/drivers/firmware/google/vpd_decode.c index 92e3258552fcafefc93c30ccf155a7043d40b92e..dda525c0f968271ad576381d103ad2c54d945a65 100644 --- a/drivers/firmware/google/vpd_decode.c +++ b/drivers/firmware/google/vpd_decode.c @@ -9,8 +9,8 @@ #include "vpd_decode.h" -static int vpd_decode_len(const s32 max_len, const u8 *in, - s32 *length, s32 *decoded_len) +static int vpd_decode_len(const u32 max_len, const u8 *in, + u32 *length, u32 *decoded_len) { u8 more; int i = 0; @@ -30,18 +30,39 @@ static int vpd_decode_len(const s32 max_len, const u8 *in, } while (more); *decoded_len = i; + return VPD_OK; +} + +static int vpd_decode_entry(const u32 max_len, const u8 *input_buf, + u32 *_consumed, const u8 **entry, u32 *entry_len) +{ + u32 decoded_len; + u32 consumed = *_consumed; + + if (vpd_decode_len(max_len - consumed, &input_buf[consumed], + entry_len, &decoded_len) != VPD_OK) + return VPD_FAIL; + if (max_len - consumed < decoded_len) + return VPD_FAIL; + + consumed += decoded_len; + *entry = input_buf + consumed; + + /* entry_len is untrusted data and must be checked again. */ + if (max_len - consumed < *entry_len) + return VPD_FAIL; + consumed += decoded_len; + *_consumed = consumed; return VPD_OK; } -int vpd_decode_string(const s32 max_len, const u8 *input_buf, s32 *consumed, +int vpd_decode_string(const u32 max_len, const u8 *input_buf, u32 *consumed, vpd_decode_callback callback, void *callback_arg) { int type; - int res; - s32 key_len; - s32 value_len; - s32 decoded_len; + u32 key_len; + u32 value_len; const u8 *key; const u8 *value; @@ -56,26 +77,14 @@ int vpd_decode_string(const s32 max_len, const u8 *input_buf, s32 *consumed, case VPD_TYPE_STRING: (*consumed)++; - /* key */ - res = vpd_decode_len(max_len - *consumed, &input_buf[*consumed], - &key_len, &decoded_len); - if (res != VPD_OK || *consumed + decoded_len >= max_len) + if (vpd_decode_entry(max_len, input_buf, consumed, &key, + &key_len) != VPD_OK) return VPD_FAIL; - *consumed += decoded_len; - key = &input_buf[*consumed]; - *consumed += key_len; - - /* value */ - res = vpd_decode_len(max_len - *consumed, &input_buf[*consumed], - &value_len, &decoded_len); - if (res != VPD_OK || *consumed + decoded_len > max_len) + if (vpd_decode_entry(max_len, input_buf, consumed, &value, + &value_len) != VPD_OK) return VPD_FAIL; - *consumed += decoded_len; - value = &input_buf[*consumed]; - *consumed += value_len; - if (type == VPD_TYPE_STRING) return callback(key, key_len, value, value_len, callback_arg); diff --git a/drivers/firmware/google/vpd_decode.h b/drivers/firmware/google/vpd_decode.h index cf8c2ace155a11e1d12d1d5b9981b47b6b167325..8dbe41cac599b14b094a37d409a4a9c8d3660816 100644 --- a/drivers/firmware/google/vpd_decode.h +++ b/drivers/firmware/google/vpd_decode.h @@ -25,8 +25,8 @@ enum { }; /* Callback for vpd_decode_string to invoke. */ -typedef int vpd_decode_callback(const u8 *key, s32 key_len, - const u8 *value, s32 value_len, +typedef int vpd_decode_callback(const u8 *key, u32 key_len, + const u8 *value, u32 value_len, void *arg); /* @@ -44,7 +44,7 @@ typedef int vpd_decode_callback(const u8 *key, s32 key_len, * If one entry is successfully decoded, sends it to callback and returns the * result. */ -int vpd_decode_string(const s32 max_len, const u8 *input_buf, s32 *consumed, +int vpd_decode_string(const u32 max_len, const u8 *input_buf, u32 *consumed, vpd_decode_callback callback, void *callback_arg); #endif /* __VPD_DECODE_H */ diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig index 42b566f8903fad18c15c3ba76b12422be79dd5dd..0dbee32da4c6d52ea3a84704245fee151ef37d65 100644 --- a/drivers/firmware/imx/Kconfig +++ b/drivers/firmware/imx/Kconfig @@ -1,4 +1,15 @@ # SPDX-License-Identifier: GPL-2.0-only +config IMX_DSP + bool "IMX DSP Protocol driver" + depends on IMX_MBOX + help + This enables DSP IPC protocol between host AP (Linux) + and the firmware running on DSP. + DSP exists on some i.MX8 processors (e.g i.MX8QM, i.MX8QXP). + + It acts like a doorbell. Client might use shared memory to + exchange information with DSP side. + config IMX_SCU bool "IMX SCU Protocol driver" depends on IMX_MBOX diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile index 802c4ad8e8f96736d868c9588a51302b18ba5a7e..08bc9ddfbdfb5112b1a6c5983a159f0626fba00f 100644 --- a/drivers/firmware/imx/Makefile +++ b/drivers/firmware/imx/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_IMX_DSP) += imx-dsp.o obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o diff --git a/drivers/firmware/imx/imx-dsp.c b/drivers/firmware/imx/imx-dsp.c new file mode 100644 index 0000000000000000000000000000000000000000..a43d2db5cbdb4ca36f2de05371992eca7dd531b2 --- /dev/null +++ b/drivers/firmware/imx/imx-dsp.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 NXP + * Author: Daniel Baluta + * + * Implementation of the DSP IPC interface (host side) + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * imx_dsp_ring_doorbell - triggers an interrupt on the other side (DSP) + * + * @dsp: DSP IPC handle + * @chan_idx: index of the channel where to trigger the interrupt + * + * Returns non-negative value for success, negative value for error + */ +int imx_dsp_ring_doorbell(struct imx_dsp_ipc *ipc, unsigned int idx) +{ + int ret; + struct imx_dsp_chan *dsp_chan; + + if (idx >= DSP_MU_CHAN_NUM) + return -EINVAL; + + dsp_chan = &ipc->chans[idx]; + ret = mbox_send_message(dsp_chan->ch, NULL); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL(imx_dsp_ring_doorbell); + +/* + * imx_dsp_handle_rx - rx callback used by imx mailbox + * + * @c: mbox client + * @msg: message received + * + * Users of DSP IPC will need to privde handle_reply and handle_request + * callbacks. + */ +static void imx_dsp_handle_rx(struct mbox_client *c, void *msg) +{ + struct imx_dsp_chan *chan = container_of(c, struct imx_dsp_chan, cl); + + if (chan->idx == 0) { + chan->ipc->ops->handle_reply(chan->ipc); + } else { + chan->ipc->ops->handle_request(chan->ipc); + imx_dsp_ring_doorbell(chan->ipc, 1); + } +} + +static int imx_dsp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct imx_dsp_ipc *dsp_ipc; + struct imx_dsp_chan *dsp_chan; + struct mbox_client *cl; + char *chan_name; + int ret; + int i, j; + + device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent); + + dsp_ipc = devm_kzalloc(dev, sizeof(*dsp_ipc), GFP_KERNEL); + if (!dsp_ipc) + return -ENOMEM; + + for (i = 0; i < DSP_MU_CHAN_NUM; i++) { + if (i < 2) + chan_name = kasprintf(GFP_KERNEL, "txdb%d", i); + else + chan_name = kasprintf(GFP_KERNEL, "rxdb%d", i - 2); + + if (!chan_name) + return -ENOMEM; + + dsp_chan = &dsp_ipc->chans[i]; + cl = &dsp_chan->cl; + cl->dev = dev; + cl->tx_block = false; + cl->knows_txdone = true; + cl->rx_callback = imx_dsp_handle_rx; + + dsp_chan->ipc = dsp_ipc; + dsp_chan->idx = i % 2; + dsp_chan->ch = mbox_request_channel_byname(cl, chan_name); + if (IS_ERR(dsp_chan->ch)) { + ret = PTR_ERR(dsp_chan->ch); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to request mbox chan %s ret %d\n", + chan_name, ret); + goto out; + } + + dev_dbg(dev, "request mbox chan %s\n", chan_name); + /* chan_name is not used anymore by framework */ + kfree(chan_name); + } + + dsp_ipc->dev = dev; + + dev_set_drvdata(dev, dsp_ipc); + + dev_info(dev, "NXP i.MX DSP IPC initialized\n"); + + return devm_of_platform_populate(dev); +out: + kfree(chan_name); + for (j = 0; j < i; j++) { + dsp_chan = &dsp_ipc->chans[j]; + mbox_free_channel(dsp_chan->ch); + } + + return ret; +} + +static int imx_dsp_remove(struct platform_device *pdev) +{ + struct imx_dsp_chan *dsp_chan; + struct imx_dsp_ipc *dsp_ipc; + int i; + + dsp_ipc = dev_get_drvdata(&pdev->dev); + + for (i = 0; i < DSP_MU_CHAN_NUM; i++) { + dsp_chan = &dsp_ipc->chans[i]; + mbox_free_channel(dsp_chan->ch); + } + + return 0; +} + +static struct platform_driver imx_dsp_driver = { + .driver = { + .name = "imx-dsp", + }, + .probe = imx_dsp_probe, + .remove = imx_dsp_remove, +}; +builtin_platform_driver(imx_dsp_driver); + +MODULE_AUTHOR("Daniel Baluta "); +MODULE_DESCRIPTION("IMX DSP IPC protocol driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c index 480cec69e2c96e9a1f280dd85240c0e31c2b2c1b..b556612207e536a85dcdc8464b0256d3ff3f992a 100644 --- a/drivers/firmware/imx/scu-pd.c +++ b/drivers/firmware/imx/scu-pd.c @@ -92,7 +92,8 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { { "gpt", IMX_SC_R_GPT_0, 5, true, 0 }, { "kpp", IMX_SC_R_KPP, 1, false, 0 }, { "fspi", IMX_SC_R_FSPI_0, 2, true, 0 }, - { "mu", IMX_SC_R_MU_0A, 14, true, 0 }, + { "mu_a", IMX_SC_R_MU_0A, 14, true, 0 }, + { "mu_b", IMX_SC_R_MU_13B, 1, true, 13 }, /* CONN SS */ { "usb", IMX_SC_R_USB_0, 2, true, 0 }, @@ -130,6 +131,7 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { { "lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true, 0 }, { "lpuart", IMX_SC_R_UART_0, 4, true, 0 }, { "lpspi", IMX_SC_R_SPI_0, 4, true, 0 }, + { "irqstr_dsp", IMX_SC_R_IRQSTR_DSP, 1, false, 0 }, /* VPU SS */ { "vpu", IMX_SC_R_VPU, 1, false, 0 }, diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c index f82ccd39a913f2c4b8fe726b79b8b04c52ccd3b5..84f4ff351c6290309db7afdada06fb470f3ffb82 100644 --- a/drivers/firmware/psci/psci.c +++ b/drivers/firmware/psci/psci.c @@ -103,7 +103,7 @@ static inline bool psci_power_state_loses_context(u32 state) return state & mask; } -static inline bool psci_power_state_is_valid(u32 state) +bool psci_power_state_is_valid(u32 state) { const u32 valid_mask = psci_has_ext_power_state() ? PSCI_1_0_EXT_POWER_STATE_MASK : @@ -277,175 +277,24 @@ static int __init psci_features(u32 psci_func_id) } #ifdef CONFIG_CPU_IDLE -static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state); - -static int psci_dt_parse_state_node(struct device_node *np, u32 *state) -{ - int err = of_property_read_u32(np, "arm,psci-suspend-param", state); - - if (err) { - pr_warn("%pOF missing arm,psci-suspend-param property\n", np); - return err; - } - - if (!psci_power_state_is_valid(*state)) { - pr_warn("Invalid PSCI power state %#x\n", *state); - return -EINVAL; - } - - return 0; -} - -static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu) -{ - int i, ret = 0, count = 0; - u32 *psci_states; - struct device_node *state_node; - - /* Count idle states */ - while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states", - count))) { - count++; - of_node_put(state_node); - } - - if (!count) - return -ENODEV; - - psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL); - if (!psci_states) - return -ENOMEM; - - for (i = 0; i < count; i++) { - state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i); - ret = psci_dt_parse_state_node(state_node, &psci_states[i]); - of_node_put(state_node); - - if (ret) - goto free_mem; - - pr_debug("psci-power-state %#x index %d\n", psci_states[i], i); - } - - /* Idle states parsed correctly, initialize per-cpu pointer */ - per_cpu(psci_power_state, cpu) = psci_states; - return 0; - -free_mem: - kfree(psci_states); - return ret; -} - -#ifdef CONFIG_ACPI -#include - -static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu) -{ - int i, count; - u32 *psci_states; - struct acpi_lpi_state *lpi; - struct acpi_processor *pr = per_cpu(processors, cpu); - - if (unlikely(!pr || !pr->flags.has_lpi)) - return -EINVAL; - - count = pr->power.count - 1; - if (count <= 0) - return -ENODEV; - - psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL); - if (!psci_states) - return -ENOMEM; - - for (i = 0; i < count; i++) { - u32 state; - - lpi = &pr->power.lpi_states[i + 1]; - /* - * Only bits[31:0] represent a PSCI power_state while - * bits[63:32] must be 0x0 as per ARM ACPI FFH Specification - */ - state = lpi->address; - if (!psci_power_state_is_valid(state)) { - pr_warn("Invalid PSCI power state %#x\n", state); - kfree(psci_states); - return -EINVAL; - } - psci_states[i] = state; - } - /* Idle states parsed correctly, initialize per-cpu pointer */ - per_cpu(psci_power_state, cpu) = psci_states; - return 0; -} -#else -static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu) -{ - return -EINVAL; -} -#endif - -int psci_cpu_init_idle(unsigned int cpu) -{ - struct device_node *cpu_node; - int ret; - - /* - * If the PSCI cpu_suspend function hook has not been initialized - * idle states must not be enabled, so bail out - */ - if (!psci_ops.cpu_suspend) - return -EOPNOTSUPP; - - if (!acpi_disabled) - return psci_acpi_cpu_init_idle(cpu); - - cpu_node = of_get_cpu_node(cpu, NULL); - if (!cpu_node) - return -ENODEV; - - ret = psci_dt_cpu_init_idle(cpu_node, cpu); - - of_node_put(cpu_node); - - return ret; -} - -static int psci_suspend_finisher(unsigned long index) +static int psci_suspend_finisher(unsigned long state) { - u32 *state = __this_cpu_read(psci_power_state); + u32 power_state = state; - return psci_ops.cpu_suspend(state[index - 1], - __pa_symbol(cpu_resume)); + return psci_ops.cpu_suspend(power_state, __pa_symbol(cpu_resume)); } -int psci_cpu_suspend_enter(unsigned long index) +int psci_cpu_suspend_enter(u32 state) { int ret; - u32 *state = __this_cpu_read(psci_power_state); - /* - * idle state index 0 corresponds to wfi, should never be called - * from the cpu_suspend operations - */ - if (WARN_ON_ONCE(!index)) - return -EINVAL; - if (!psci_power_state_loses_context(state[index - 1])) - ret = psci_ops.cpu_suspend(state[index - 1], 0); + if (!psci_power_state_loses_context(state)) + ret = psci_ops.cpu_suspend(state, 0); else - ret = cpu_suspend(index, psci_suspend_finisher); + ret = cpu_suspend(state, psci_suspend_finisher); return ret; } - -/* ARM specific CPU idle operations */ -#ifdef CONFIG_ARM -static const struct cpuidle_ops psci_cpuidle_ops __initconst = { - .suspend = psci_cpu_suspend_enter, - .init = psci_dt_cpu_init_idle, -}; - -CPUIDLE_METHOD_OF_DECLARE(psci, "psci", &psci_cpuidle_ops); -#endif #endif static int psci_system_suspend(unsigned long unused) diff --git a/drivers/firmware/psci/psci_checker.c b/drivers/firmware/psci/psci_checker.c index f3659443f8c2cc14ee46cc878f977eb8f9434685..6a445397771ca027841e82b6ab93f48db877ef28 100644 --- a/drivers/firmware/psci/psci_checker.c +++ b/drivers/firmware/psci/psci_checker.c @@ -228,8 +228,11 @@ static int hotplug_tests(void) static void dummy_callback(struct timer_list *unused) {} -static int suspend_cpu(int index, bool broadcast) +static int suspend_cpu(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { + struct cpuidle_state *state = &drv->states[index]; + bool broadcast = state->flags & CPUIDLE_FLAG_TIMER_STOP; int ret; arch_cpu_idle_enter(); @@ -254,11 +257,7 @@ static int suspend_cpu(int index, bool broadcast) } } - /* - * Replicate the common ARM cpuidle enter function - * (arm_enter_idle_state). - */ - ret = CPU_PM_CPU_IDLE_ENTER(arm_cpuidle_suspend, index); + ret = state->enter(dev, drv, index); if (broadcast) tick_broadcast_exit(); @@ -301,9 +300,8 @@ static int suspend_test_thread(void *arg) * doesn't use PSCI). */ for (index = 1; index < drv->state_count; ++index) { - struct cpuidle_state *state = &drv->states[index]; - bool broadcast = state->flags & CPUIDLE_FLAG_TIMER_STOP; int ret; + struct cpuidle_state *state = &drv->states[index]; /* * Set the timer to wake this CPU up in some time (which @@ -318,7 +316,7 @@ static int suspend_test_thread(void *arg) /* IRQs must be disabled during suspend operations. */ local_irq_disable(); - ret = suspend_cpu(index, broadcast); + ret = suspend_cpu(dev, drv, index); /* * We have woken up. Re-enable IRQs to handle any diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 2ddc118dba1b402eb3f8118e71d2bbf3b568fb1d..4802ab170fe51a57fb83f962bbf6f8a4b7936717 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -425,21 +426,23 @@ EXPORT_SYMBOL(qcom_scm_set_remote_state); * @mem_sz: size of the region. * @srcvm: vmid for current set of owners, each set bit in * flag indicate a unique owner - * @newvm: array having new owners and corrsponding permission + * @newvm: array having new owners and corresponding permission * flags * @dest_cnt: number of owners in next set. * - * Return negative errno on failure, 0 on success, with @srcvm updated. + * Return negative errno on failure or 0 on success with @srcvm updated. */ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, unsigned int *srcvm, - struct qcom_scm_vmperm *newvm, int dest_cnt) + const struct qcom_scm_vmperm *newvm, + unsigned int dest_cnt) { struct qcom_scm_current_perm_info *destvm; struct qcom_scm_mem_map_info *mem_to_map; phys_addr_t mem_to_map_phys; phys_addr_t dest_phys; phys_addr_t ptr_phys; + dma_addr_t ptr_dma; size_t mem_to_map_sz; size_t dest_sz; size_t src_sz; @@ -447,52 +450,50 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, int next_vm; __le32 *src; void *ptr; - int ret; - int len; - int i; + int ret, i, b; + unsigned long srcvm_bits = *srcvm; - src_sz = hweight_long(*srcvm) * sizeof(*src); + src_sz = hweight_long(srcvm_bits) * sizeof(*src); mem_to_map_sz = sizeof(*mem_to_map); dest_sz = dest_cnt * sizeof(*destvm); ptr_sz = ALIGN(src_sz, SZ_64) + ALIGN(mem_to_map_sz, SZ_64) + ALIGN(dest_sz, SZ_64); - ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_phys, GFP_KERNEL); + ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_dma, GFP_KERNEL); if (!ptr) return -ENOMEM; + ptr_phys = dma_to_phys(__scm->dev, ptr_dma); /* Fill source vmid detail */ src = ptr; - len = hweight_long(*srcvm); - for (i = 0; i < len; i++) { - src[i] = cpu_to_le32(ffs(*srcvm) - 1); - *srcvm ^= 1 << (ffs(*srcvm) - 1); - } + i = 0; + for_each_set_bit(b, &srcvm_bits, BITS_PER_LONG) + src[i++] = cpu_to_le32(b); /* Fill details of mem buff to map */ mem_to_map = ptr + ALIGN(src_sz, SZ_64); mem_to_map_phys = ptr_phys + ALIGN(src_sz, SZ_64); - mem_to_map[0].mem_addr = cpu_to_le64(mem_addr); - mem_to_map[0].mem_size = cpu_to_le64(mem_sz); + mem_to_map->mem_addr = cpu_to_le64(mem_addr); + mem_to_map->mem_size = cpu_to_le64(mem_sz); next_vm = 0; /* Fill details of next vmid detail */ destvm = ptr + ALIGN(mem_to_map_sz, SZ_64) + ALIGN(src_sz, SZ_64); dest_phys = ptr_phys + ALIGN(mem_to_map_sz, SZ_64) + ALIGN(src_sz, SZ_64); - for (i = 0; i < dest_cnt; i++) { - destvm[i].vmid = cpu_to_le32(newvm[i].vmid); - destvm[i].perm = cpu_to_le32(newvm[i].perm); - destvm[i].ctx = 0; - destvm[i].ctx_size = 0; - next_vm |= BIT(newvm[i].vmid); + for (i = 0; i < dest_cnt; i++, destvm++, newvm++) { + destvm->vmid = cpu_to_le32(newvm->vmid); + destvm->perm = cpu_to_le32(newvm->perm); + destvm->ctx = 0; + destvm->ctx_size = 0; + next_vm |= BIT(newvm->vmid); } ret = __qcom_scm_assign_mem(__scm->dev, mem_to_map_phys, mem_to_map_sz, ptr_phys, src_sz, dest_phys, dest_sz); - dma_free_coherent(__scm->dev, ALIGN(ptr_sz, SZ_64), ptr, ptr_phys); + dma_free_coherent(__scm->dev, ptr_sz, ptr, ptr_dma); if (ret) { dev_err(__scm->dev, - "Assign memory protection call failed %d.\n", ret); + "Assign memory protection call failed %d\n", ret); return -EINVAL; } diff --git a/drivers/firmware/stratix10-rsu.c b/drivers/firmware/stratix10-rsu.c new file mode 100644 index 0000000000000000000000000000000000000000..bb008c01992055dacd28d61f2f0519ce50203301 --- /dev/null +++ b/drivers/firmware/stratix10-rsu.c @@ -0,0 +1,451 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018-2019, Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RSU_STATE_MASK GENMASK_ULL(31, 0) +#define RSU_VERSION_MASK GENMASK_ULL(63, 32) +#define RSU_ERROR_LOCATION_MASK GENMASK_ULL(31, 0) +#define RSU_ERROR_DETAIL_MASK GENMASK_ULL(63, 32) +#define RSU_FW_VERSION_MASK GENMASK_ULL(15, 0) + +#define RSU_TIMEOUT (msecs_to_jiffies(SVC_RSU_REQUEST_TIMEOUT_MS)) + +#define INVALID_RETRY_COUNTER 0xFFFFFFFF + +typedef void (*rsu_callback)(struct stratix10_svc_client *client, + struct stratix10_svc_cb_data *data); +/** + * struct stratix10_rsu_priv - rsu data structure + * @chan: pointer to the allocated service channel + * @client: active service client + * @completion: state for callback completion + * @lock: a mutex to protect callback completion state + * @status.current_image: address of image currently running in flash + * @status.fail_image: address of failed image in flash + * @status.version: the version number of RSU firmware + * @status.state: the state of RSU system + * @status.error_details: error code + * @status.error_location: the error offset inside the image that failed + * @retry_counter: the current image's retry counter + */ +struct stratix10_rsu_priv { + struct stratix10_svc_chan *chan; + struct stratix10_svc_client client; + struct completion completion; + struct mutex lock; + struct { + unsigned long current_image; + unsigned long fail_image; + unsigned int version; + unsigned int state; + unsigned int error_details; + unsigned int error_location; + } status; + unsigned int retry_counter; +}; + +/** + * rsu_status_callback() - Status callback from Intel Service Layer + * @client: pointer to service client + * @data: pointer to callback data structure + * + * Callback from Intel service layer for RSU status request. Status is + * only updated after a system reboot, so a get updated status call is + * made during driver probe. + */ +static void rsu_status_callback(struct stratix10_svc_client *client, + struct stratix10_svc_cb_data *data) +{ + struct stratix10_rsu_priv *priv = client->priv; + struct arm_smccc_res *res = (struct arm_smccc_res *)data->kaddr1; + + if (data->status == BIT(SVC_STATUS_RSU_OK)) { + priv->status.version = FIELD_GET(RSU_VERSION_MASK, + res->a2); + priv->status.state = FIELD_GET(RSU_STATE_MASK, res->a2); + priv->status.fail_image = res->a1; + priv->status.current_image = res->a0; + priv->status.error_location = + FIELD_GET(RSU_ERROR_LOCATION_MASK, res->a3); + priv->status.error_details = + FIELD_GET(RSU_ERROR_DETAIL_MASK, res->a3); + } else { + dev_err(client->dev, "COMMAND_RSU_STATUS returned 0x%lX\n", + res->a0); + priv->status.version = 0; + priv->status.state = 0; + priv->status.fail_image = 0; + priv->status.current_image = 0; + priv->status.error_location = 0; + priv->status.error_details = 0; + } + + complete(&priv->completion); +} + +/** + * rsu_command_callback() - Update callback from Intel Service Layer + * @client: pointer to client + * @data: pointer to callback data structure + * + * Callback from Intel service layer for RSU commands. + */ +static void rsu_command_callback(struct stratix10_svc_client *client, + struct stratix10_svc_cb_data *data) +{ + struct stratix10_rsu_priv *priv = client->priv; + + if (data->status != BIT(SVC_STATUS_RSU_OK)) + dev_err(client->dev, "RSU returned status is %i\n", + data->status); + complete(&priv->completion); +} + +/** + * rsu_retry_callback() - Callback from Intel service layer for getting + * the current image's retry counter from firmware + * @client: pointer to client + * @data: pointer to callback data structure + * + * Callback from Intel service layer for retry counter, which is used by + * user to know how many times the images is still allowed to reload + * itself before giving up and starting RSU fail-over flow. + */ +static void rsu_retry_callback(struct stratix10_svc_client *client, + struct stratix10_svc_cb_data *data) +{ + struct stratix10_rsu_priv *priv = client->priv; + unsigned int *counter = (unsigned int *)data->kaddr1; + + if (data->status == BIT(SVC_STATUS_RSU_OK)) + priv->retry_counter = *counter; + else + dev_err(client->dev, "Failed to get retry counter %i\n", + data->status); + + complete(&priv->completion); +} + +/** + * rsu_send_msg() - send a message to Intel service layer + * @priv: pointer to rsu private data + * @command: RSU status or update command + * @arg: the request argument, the bitstream address or notify status + * @callback: function pointer for the callback (status or update) + * + * Start an Intel service layer transaction to perform the SMC call that + * is necessary to get RSU boot log or set the address of bitstream to + * boot after reboot. + * + * Returns 0 on success or -ETIMEDOUT on error. + */ +static int rsu_send_msg(struct stratix10_rsu_priv *priv, + enum stratix10_svc_command_code command, + unsigned long arg, + rsu_callback callback) +{ + struct stratix10_svc_client_msg msg; + int ret; + + mutex_lock(&priv->lock); + reinit_completion(&priv->completion); + priv->client.receive_cb = callback; + + msg.command = command; + if (arg) + msg.arg[0] = arg; + + ret = stratix10_svc_send(priv->chan, &msg); + if (ret < 0) + goto status_done; + + ret = wait_for_completion_interruptible_timeout(&priv->completion, + RSU_TIMEOUT); + if (!ret) { + dev_err(priv->client.dev, + "timeout waiting for SMC call\n"); + ret = -ETIMEDOUT; + goto status_done; + } else if (ret < 0) { + dev_err(priv->client.dev, + "error %d waiting for SMC call\n", ret); + goto status_done; + } else { + ret = 0; + } + +status_done: + stratix10_svc_done(priv->chan); + mutex_unlock(&priv->lock); + return ret; +} + +/* + * This driver exposes some optional features of the Intel Stratix 10 SoC FPGA. + * The sysfs interfaces exposed here are FPGA Remote System Update (RSU) + * related. They allow user space software to query the configuration system + * status and to request optional reboot behavior specific to Intel FPGAs. + */ + +static ssize_t current_image_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); + + if (!priv) + return -ENODEV; + + return sprintf(buf, "0x%08lx\n", priv->status.current_image); +} + +static ssize_t fail_image_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); + + if (!priv) + return -ENODEV; + + return sprintf(buf, "0x%08lx\n", priv->status.fail_image); +} + +static ssize_t version_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); + + if (!priv) + return -ENODEV; + + return sprintf(buf, "0x%08x\n", priv->status.version); +} + +static ssize_t state_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); + + if (!priv) + return -ENODEV; + + return sprintf(buf, "0x%08x\n", priv->status.state); +} + +static ssize_t error_location_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); + + if (!priv) + return -ENODEV; + + return sprintf(buf, "0x%08x\n", priv->status.error_location); +} + +static ssize_t error_details_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); + + if (!priv) + return -ENODEV; + + return sprintf(buf, "0x%08x\n", priv->status.error_details); +} + +static ssize_t retry_counter_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); + + if (!priv) + return -ENODEV; + + return sprintf(buf, "0x%08x\n", priv->retry_counter); +} + +static ssize_t reboot_image_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); + unsigned long address; + int ret; + + if (priv == 0) + return -ENODEV; + + ret = kstrtoul(buf, 0, &address); + if (ret) + return ret; + + ret = rsu_send_msg(priv, COMMAND_RSU_UPDATE, + address, rsu_command_callback); + if (ret) { + dev_err(dev, "Error, RSU update returned %i\n", ret); + return ret; + } + + return count; +} + +static ssize_t notify_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); + unsigned long status; + int ret; + + if (priv == 0) + return -ENODEV; + + ret = kstrtoul(buf, 0, &status); + if (ret) + return ret; + + ret = rsu_send_msg(priv, COMMAND_RSU_NOTIFY, + status, rsu_command_callback); + if (ret) { + dev_err(dev, "Error, RSU notify returned %i\n", ret); + return ret; + } + + /* to get the updated state */ + ret = rsu_send_msg(priv, COMMAND_RSU_STATUS, + 0, rsu_status_callback); + if (ret) { + dev_err(dev, "Error, getting RSU status %i\n", ret); + return ret; + } + + /* only 19.3 or late version FW supports retry counter feature */ + if (FIELD_GET(RSU_FW_VERSION_MASK, priv->status.version)) { + ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, + 0, rsu_retry_callback); + if (ret) { + dev_err(dev, + "Error, getting RSU retry %i\n", ret); + return ret; + } + } + + return count; +} + +static DEVICE_ATTR_RO(current_image); +static DEVICE_ATTR_RO(fail_image); +static DEVICE_ATTR_RO(state); +static DEVICE_ATTR_RO(version); +static DEVICE_ATTR_RO(error_location); +static DEVICE_ATTR_RO(error_details); +static DEVICE_ATTR_RO(retry_counter); +static DEVICE_ATTR_WO(reboot_image); +static DEVICE_ATTR_WO(notify); + +static struct attribute *rsu_attrs[] = { + &dev_attr_current_image.attr, + &dev_attr_fail_image.attr, + &dev_attr_state.attr, + &dev_attr_version.attr, + &dev_attr_error_location.attr, + &dev_attr_error_details.attr, + &dev_attr_retry_counter.attr, + &dev_attr_reboot_image.attr, + &dev_attr_notify.attr, + NULL +}; + +ATTRIBUTE_GROUPS(rsu); + +static int stratix10_rsu_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct stratix10_rsu_priv *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->client.dev = dev; + priv->client.receive_cb = NULL; + priv->client.priv = priv; + priv->status.current_image = 0; + priv->status.fail_image = 0; + priv->status.error_location = 0; + priv->status.error_details = 0; + priv->status.version = 0; + priv->status.state = 0; + priv->retry_counter = INVALID_RETRY_COUNTER; + + mutex_init(&priv->lock); + priv->chan = stratix10_svc_request_channel_byname(&priv->client, + SVC_CLIENT_RSU); + if (IS_ERR(priv->chan)) { + dev_err(dev, "couldn't get service channel %s\n", + SVC_CLIENT_RSU); + return PTR_ERR(priv->chan); + } + + init_completion(&priv->completion); + platform_set_drvdata(pdev, priv); + + /* get the initial state from firmware */ + ret = rsu_send_msg(priv, COMMAND_RSU_STATUS, + 0, rsu_status_callback); + if (ret) { + dev_err(dev, "Error, getting RSU status %i\n", ret); + stratix10_svc_free_channel(priv->chan); + } + + /* only 19.3 or late version FW supports retry counter feature */ + if (FIELD_GET(RSU_FW_VERSION_MASK, priv->status.version)) { + ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, + rsu_retry_callback); + if (ret) { + dev_err(dev, + "Error, getting RSU retry %i\n", ret); + stratix10_svc_free_channel(priv->chan); + } + } + + return ret; +} + +static int stratix10_rsu_remove(struct platform_device *pdev) +{ + struct stratix10_rsu_priv *priv = platform_get_drvdata(pdev); + + stratix10_svc_free_channel(priv->chan); + return 0; +} + +static struct platform_driver stratix10_rsu_driver = { + .probe = stratix10_rsu_probe, + .remove = stratix10_rsu_remove, + .driver = { + .name = "stratix10-rsu", + .dev_groups = rsu_groups, + }, +}; + +module_platform_driver(stratix10_rsu_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Remote System Update Driver"); +MODULE_AUTHOR("Richard Gong "); diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c index 6e6514825ad022d3e311b9a8c2de66d3aa578e0e..b485321189e111bb4cde1c6ccf7a93a80dfbca7f 100644 --- a/drivers/firmware/stratix10-svc.c +++ b/drivers/firmware/stratix10-svc.c @@ -38,12 +38,23 @@ #define FPGA_CONFIG_DATA_CLAIM_TIMEOUT_MS 200 #define FPGA_CONFIG_STATUS_TIMEOUT_SEC 30 +/* stratix10 service layer clients */ +#define STRATIX10_RSU "stratix10-rsu" + typedef void (svc_invoke_fn)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, struct arm_smccc_res *); struct stratix10_svc_chan; +/** + * struct stratix10_svc - svc private data + * @stratix10_svc_rsu: pointer to stratix10 RSU device + */ +struct stratix10_svc { + struct platform_device *stratix10_svc_rsu; +}; + /** * struct stratix10_svc_sh_memory - service shared memory structure * @sync_complete: state for a completion @@ -296,7 +307,12 @@ static void svc_thread_recv_status_ok(struct stratix10_svc_data *p_data, cb_data->status = BIT(SVC_STATUS_RECONFIG_COMPLETED); break; case COMMAND_RSU_UPDATE: + case COMMAND_RSU_NOTIFY: + cb_data->status = BIT(SVC_STATUS_RSU_OK); + break; + case COMMAND_RSU_RETRY: cb_data->status = BIT(SVC_STATUS_RSU_OK); + cb_data->kaddr1 = &res.a1; break; default: pr_warn("it shouldn't happen\n"); @@ -386,6 +402,16 @@ static int svc_normal_to_secure_thread(void *data) a1 = pdata->arg[0]; a2 = 0; break; + case COMMAND_RSU_NOTIFY: + a0 = INTEL_SIP_SMC_RSU_NOTIFY; + a1 = pdata->arg[0]; + a2 = 0; + break; + case COMMAND_RSU_RETRY: + a0 = INTEL_SIP_SMC_RSU_RETRY_COUNTER; + a1 = 0; + a2 = 0; + break; default: pr_warn("it shouldn't happen\n"); break; @@ -438,7 +464,28 @@ static int svc_normal_to_secure_thread(void *data) pr_debug("%s: STATUS_REJECTED\n", __func__); break; case INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR: + case INTEL_SIP_SMC_RSU_ERROR: pr_err("%s: STATUS_ERROR\n", __func__); + switch (pdata->command) { + /* for FPGA mgr */ + case COMMAND_RECONFIG_DATA_CLAIM: + case COMMAND_RECONFIG: + case COMMAND_RECONFIG_DATA_SUBMIT: + case COMMAND_RECONFIG_STATUS: + cbdata->status = + BIT(SVC_STATUS_RECONFIG_ERROR); + break; + + /* for RSU */ + case COMMAND_RSU_STATUS: + case COMMAND_RSU_UPDATE: + case COMMAND_RSU_NOTIFY: + case COMMAND_RSU_RETRY: + cbdata->status = + BIT(SVC_STATUS_RSU_ERROR); + break; + } + cbdata->status = BIT(SVC_STATUS_RECONFIG_ERROR); cbdata->kaddr1 = NULL; cbdata->kaddr2 = NULL; @@ -530,7 +577,7 @@ static int svc_get_sh_memory(struct platform_device *pdev, if (!sh_memory->addr || !sh_memory->size) { dev_err(dev, - "fails to get shared memory info from secure world\n"); + "failed to get shared memory info from secure world\n"); return -ENOMEM; } @@ -768,7 +815,7 @@ int stratix10_svc_send(struct stratix10_svc_chan *chan, void *msg) "svc_smc_hvc_thread"); if (IS_ERR(chan->ctrl->task)) { dev_err(chan->ctrl->dev, - "fails to create svc_smc_hvc_thread\n"); + "failed to create svc_smc_hvc_thread\n"); kfree(p_data); return -EINVAL; } @@ -913,6 +960,8 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev) struct stratix10_svc_chan *chans; struct gen_pool *genpool; struct stratix10_svc_sh_memory *sh_memory; + struct stratix10_svc *svc; + svc_invoke_fn *invoke_fn; size_t fifo_size; int ret; @@ -957,7 +1006,7 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev) fifo_size = sizeof(struct stratix10_svc_data) * SVC_NUM_DATA_IN_FIFO; ret = kfifo_alloc(&controller->svc_fifo, fifo_size, GFP_KERNEL); if (ret) { - dev_err(dev, "fails to allocate FIFO\n"); + dev_err(dev, "failed to allocate FIFO\n"); return ret; } spin_lock_init(&controller->svc_fifo_lock); @@ -975,6 +1024,24 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev) list_add_tail(&controller->node, &svc_ctrl); platform_set_drvdata(pdev, controller); + /* add svc client device(s) */ + svc = devm_kzalloc(dev, sizeof(*svc), GFP_KERNEL); + if (!svc) + return -ENOMEM; + + svc->stratix10_svc_rsu = platform_device_alloc(STRATIX10_RSU, 0); + if (!svc->stratix10_svc_rsu) { + dev_err(dev, "failed to allocate %s device\n", STRATIX10_RSU); + return -ENOMEM; + } + + ret = platform_device_add(svc->stratix10_svc_rsu); + if (ret) { + platform_device_put(svc->stratix10_svc_rsu); + return ret; + } + dev_set_drvdata(dev, svc); + pr_info("Intel Service Layer Driver Initialized\n"); return ret; @@ -982,8 +1049,11 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev) static int stratix10_svc_drv_remove(struct platform_device *pdev) { + struct stratix10_svc *svc = dev_get_drvdata(&pdev->dev); struct stratix10_svc_controller *ctrl = platform_get_drvdata(pdev); + platform_device_unregister(svc->stratix10_svc_rsu); + kfifo_free(&ctrl->svc_fifo); if (ctrl->task) { kthread_stop(ctrl->task); diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index cdee0b45943d2bfb3103736b9a80b66d878c4e97..4126be9e321605530d0e80b2e1c131fe0a60c847 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -635,6 +635,7 @@ static int ti_sci_get_device_state(const struct ti_sci_handle *handle, /** * ti_sci_cmd_get_device() - command to request for device managed by TISCI + * that can be shared with other hosts. * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle * @id: Device Identifier * @@ -642,11 +643,29 @@ static int ti_sci_get_device_state(const struct ti_sci_handle *handle, * usage count by balancing get_device with put_device. No refcounting is * managed by driver for that purpose. * - * NOTE: The request is for exclusive access for the processor. - * * Return: 0 if all went fine, else return appropriate error. */ static int ti_sci_cmd_get_device(const struct ti_sci_handle *handle, u32 id) +{ + return ti_sci_set_device_state(handle, id, 0, + MSG_DEVICE_SW_STATE_ON); +} + +/** + * ti_sci_cmd_get_device_exclusive() - command to request for device managed by + * TISCI that is exclusively owned by the + * requesting host. + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle + * @id: Device Identifier + * + * Request for the device - NOTE: the client MUST maintain integrity of + * usage count by balancing get_device with put_device. No refcounting is + * managed by driver for that purpose. + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_get_device_exclusive(const struct ti_sci_handle *handle, + u32 id) { return ti_sci_set_device_state(handle, id, MSG_FLAG_DEVICE_EXCLUSIVE, @@ -665,6 +684,26 @@ static int ti_sci_cmd_get_device(const struct ti_sci_handle *handle, u32 id) * Return: 0 if all went fine, else return appropriate error. */ static int ti_sci_cmd_idle_device(const struct ti_sci_handle *handle, u32 id) +{ + return ti_sci_set_device_state(handle, id, 0, + MSG_DEVICE_SW_STATE_RETENTION); +} + +/** + * ti_sci_cmd_idle_device_exclusive() - Command to idle a device managed by + * TISCI that is exclusively owned by + * requesting host. + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle + * @id: Device Identifier + * + * Request for the device - NOTE: the client MUST maintain integrity of + * usage count by balancing get_device with put_device. No refcounting is + * managed by driver for that purpose. + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_idle_device_exclusive(const struct ti_sci_handle *handle, + u32 id) { return ti_sci_set_device_state(handle, id, MSG_FLAG_DEVICE_EXCLUSIVE, @@ -2894,7 +2933,9 @@ static void ti_sci_setup_ops(struct ti_sci_info *info) core_ops->reboot_device = ti_sci_cmd_core_reboot; dops->get_device = ti_sci_cmd_get_device; + dops->get_device_exclusive = ti_sci_cmd_get_device_exclusive; dops->idle_device = ti_sci_cmd_idle_device; + dops->idle_device_exclusive = ti_sci_cmd_idle_device_exclusive; dops->put_device = ti_sci_cmd_put_device; dops->is_valid = ti_sci_cmd_dev_is_valid; diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c new file mode 100644 index 0000000000000000000000000000000000000000..72be58960e540f4b178ccddd826abda69e172249 --- /dev/null +++ b/drivers/firmware/turris-mox-rwtm.c @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Turris Mox rWTM firmware driver + * + * Copyright (C) 2019 Marek Behun + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "turris-mox-rwtm" + +/* + * The macros and constants below come from Turris Mox's rWTM firmware code. + * This firmware is open source and it's sources can be found at + * https://gitlab.labs.nic.cz/turris/mox-boot-builder/tree/master/wtmi. + */ + +#define MBOX_STS_SUCCESS (0 << 30) +#define MBOX_STS_FAIL (1 << 30) +#define MBOX_STS_BADCMD (2 << 30) +#define MBOX_STS_ERROR(s) ((s) & (3 << 30)) +#define MBOX_STS_VALUE(s) (((s) >> 10) & 0xfffff) +#define MBOX_STS_CMD(s) ((s) & 0x3ff) + +enum mbox_cmd { + MBOX_CMD_GET_RANDOM = 1, + MBOX_CMD_BOARD_INFO = 2, + MBOX_CMD_ECDSA_PUB_KEY = 3, + MBOX_CMD_HASH = 4, + MBOX_CMD_SIGN = 5, + MBOX_CMD_VERIFY = 6, + + MBOX_CMD_OTP_READ = 7, + MBOX_CMD_OTP_WRITE = 8, +}; + +struct mox_kobject; + +struct mox_rwtm { + struct device *dev; + struct mbox_client mbox_client; + struct mbox_chan *mbox; + struct mox_kobject *kobj; + struct hwrng hwrng; + + struct armada_37xx_rwtm_rx_msg reply; + + void *buf; + dma_addr_t buf_phys; + + struct mutex busy; + struct completion cmd_done; + + /* board information */ + int has_board_info; + u64 serial_number; + int board_version, ram_size; + u8 mac_address1[6], mac_address2[6]; + + /* public key burned in eFuse */ + int has_pubkey; + u8 pubkey[135]; +}; + +struct mox_kobject { + struct kobject kobj; + struct mox_rwtm *rwtm; +}; + +static inline struct kobject *rwtm_to_kobj(struct mox_rwtm *rwtm) +{ + return &rwtm->kobj->kobj; +} + +static inline struct mox_rwtm *to_rwtm(struct kobject *kobj) +{ + return container_of(kobj, struct mox_kobject, kobj)->rwtm; +} + +static void mox_kobj_release(struct kobject *kobj) +{ + kfree(to_rwtm(kobj)->kobj); +} + +static struct kobj_type mox_kobj_ktype = { + .release = mox_kobj_release, + .sysfs_ops = &kobj_sysfs_ops, +}; + +static int mox_kobj_create(struct mox_rwtm *rwtm) +{ + rwtm->kobj = kzalloc(sizeof(*rwtm->kobj), GFP_KERNEL); + if (!rwtm->kobj) + return -ENOMEM; + + kobject_init(rwtm_to_kobj(rwtm), &mox_kobj_ktype); + if (kobject_add(rwtm_to_kobj(rwtm), firmware_kobj, "turris-mox-rwtm")) { + kobject_put(rwtm_to_kobj(rwtm)); + return -ENXIO; + } + + rwtm->kobj->rwtm = rwtm; + + return 0; +} + +#define MOX_ATTR_RO(name, format, cat) \ +static ssize_t \ +name##_show(struct kobject *kobj, struct kobj_attribute *a, \ + char *buf) \ +{ \ + struct mox_rwtm *rwtm = to_rwtm(kobj); \ + if (!rwtm->has_##cat) \ + return -ENODATA; \ + return sprintf(buf, format, rwtm->name); \ +} \ +static struct kobj_attribute mox_attr_##name = __ATTR_RO(name) + +MOX_ATTR_RO(serial_number, "%016llX\n", board_info); +MOX_ATTR_RO(board_version, "%i\n", board_info); +MOX_ATTR_RO(ram_size, "%i\n", board_info); +MOX_ATTR_RO(mac_address1, "%pM\n", board_info); +MOX_ATTR_RO(mac_address2, "%pM\n", board_info); +MOX_ATTR_RO(pubkey, "%s\n", pubkey); + +static int mox_get_status(enum mbox_cmd cmd, u32 retval) +{ + if (MBOX_STS_CMD(retval) != cmd || + MBOX_STS_ERROR(retval) != MBOX_STS_SUCCESS) + return -EIO; + else if (MBOX_STS_ERROR(retval) == MBOX_STS_FAIL) + return -(int)MBOX_STS_VALUE(retval); + else + return MBOX_STS_VALUE(retval); +} + +static const struct attribute *mox_rwtm_attrs[] = { + &mox_attr_serial_number.attr, + &mox_attr_board_version.attr, + &mox_attr_ram_size.attr, + &mox_attr_mac_address1.attr, + &mox_attr_mac_address2.attr, + &mox_attr_pubkey.attr, + NULL +}; + +static void mox_rwtm_rx_callback(struct mbox_client *cl, void *data) +{ + struct mox_rwtm *rwtm = dev_get_drvdata(cl->dev); + struct armada_37xx_rwtm_rx_msg *msg = data; + + rwtm->reply = *msg; + complete(&rwtm->cmd_done); +} + +static void reply_to_mac_addr(u8 *mac, u32 t1, u32 t2) +{ + mac[0] = t1 >> 8; + mac[1] = t1; + mac[2] = t2 >> 24; + mac[3] = t2 >> 16; + mac[4] = t2 >> 8; + mac[5] = t2; +} + +static int mox_get_board_info(struct mox_rwtm *rwtm) +{ + struct armada_37xx_rwtm_tx_msg msg; + struct armada_37xx_rwtm_rx_msg *reply = &rwtm->reply; + int ret; + + msg.command = MBOX_CMD_BOARD_INFO; + ret = mbox_send_message(rwtm->mbox, &msg); + if (ret < 0) + return ret; + + ret = wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2); + if (ret < 0) + return ret; + + ret = mox_get_status(MBOX_CMD_BOARD_INFO, reply->retval); + if (ret < 0 && ret != -ENODATA) { + return ret; + } else if (ret == -ENODATA) { + dev_warn(rwtm->dev, + "Board does not have manufacturing information burned!\n"); + } else { + rwtm->serial_number = reply->status[1]; + rwtm->serial_number <<= 32; + rwtm->serial_number |= reply->status[0]; + rwtm->board_version = reply->status[2]; + rwtm->ram_size = reply->status[3]; + reply_to_mac_addr(rwtm->mac_address1, reply->status[4], + reply->status[5]); + reply_to_mac_addr(rwtm->mac_address2, reply->status[6], + reply->status[7]); + rwtm->has_board_info = 1; + + pr_info("Turris Mox serial number %016llX\n", + rwtm->serial_number); + pr_info(" board version %i\n", rwtm->board_version); + pr_info(" burned RAM size %i MiB\n", rwtm->ram_size); + } + + msg.command = MBOX_CMD_ECDSA_PUB_KEY; + ret = mbox_send_message(rwtm->mbox, &msg); + if (ret < 0) + return ret; + + ret = wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2); + if (ret < 0) + return ret; + + ret = mox_get_status(MBOX_CMD_ECDSA_PUB_KEY, reply->retval); + if (ret < 0 && ret != -ENODATA) { + return ret; + } else if (ret == -ENODATA) { + dev_warn(rwtm->dev, "Board has no public key burned!\n"); + } else { + u32 *s = reply->status; + + rwtm->has_pubkey = 1; + sprintf(rwtm->pubkey, + "%06x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x", + ret, s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], + s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15]); + } + + return 0; +} + +static int mox_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) +{ + struct mox_rwtm *rwtm = (struct mox_rwtm *) rng->priv; + struct armada_37xx_rwtm_tx_msg msg; + int ret; + + if (max > 4096) + max = 4096; + + msg.command = MBOX_CMD_GET_RANDOM; + msg.args[0] = 1; + msg.args[1] = rwtm->buf_phys; + msg.args[2] = (max + 3) & ~3; + + if (!wait) { + if (!mutex_trylock(&rwtm->busy)) + return -EBUSY; + } else { + mutex_lock(&rwtm->busy); + } + + ret = mbox_send_message(rwtm->mbox, &msg); + if (ret < 0) + goto unlock_mutex; + + ret = wait_for_completion_interruptible(&rwtm->cmd_done); + if (ret < 0) + goto unlock_mutex; + + ret = mox_get_status(MBOX_CMD_GET_RANDOM, rwtm->reply.retval); + if (ret < 0) + goto unlock_mutex; + + memcpy(data, rwtm->buf, max); + ret = max; + +unlock_mutex: + mutex_unlock(&rwtm->busy); + return ret; +} + +static int turris_mox_rwtm_probe(struct platform_device *pdev) +{ + struct mox_rwtm *rwtm; + struct device *dev = &pdev->dev; + int ret; + + rwtm = devm_kzalloc(dev, sizeof(*rwtm), GFP_KERNEL); + if (!rwtm) + return -ENOMEM; + + rwtm->dev = dev; + rwtm->buf = dmam_alloc_coherent(dev, PAGE_SIZE, &rwtm->buf_phys, + GFP_KERNEL); + if (!rwtm->buf) + return -ENOMEM; + + ret = mox_kobj_create(rwtm); + if (ret < 0) { + dev_err(dev, "Cannot create turris-mox-rwtm kobject!\n"); + return ret; + } + + ret = sysfs_create_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs); + if (ret < 0) { + dev_err(dev, "Cannot create sysfs files!\n"); + goto put_kobj; + } + + platform_set_drvdata(pdev, rwtm); + + mutex_init(&rwtm->busy); + + rwtm->mbox_client.dev = dev; + rwtm->mbox_client.rx_callback = mox_rwtm_rx_callback; + + rwtm->mbox = mbox_request_channel(&rwtm->mbox_client, 0); + if (IS_ERR(rwtm->mbox)) { + ret = PTR_ERR(rwtm->mbox); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Cannot request mailbox channel: %i\n", + ret); + goto remove_files; + } + + init_completion(&rwtm->cmd_done); + + ret = mox_get_board_info(rwtm); + if (ret < 0) + dev_warn(dev, "Cannot read board information: %i\n", ret); + + rwtm->hwrng.name = DRIVER_NAME "_hwrng"; + rwtm->hwrng.read = mox_hwrng_read; + rwtm->hwrng.priv = (unsigned long) rwtm; + rwtm->hwrng.quality = 1024; + + ret = devm_hwrng_register(dev, &rwtm->hwrng); + if (ret < 0) { + dev_err(dev, "Cannot register HWRNG: %i\n", ret); + goto free_channel; + } + + return 0; + +free_channel: + mbox_free_channel(rwtm->mbox); +remove_files: + sysfs_remove_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs); +put_kobj: + kobject_put(rwtm_to_kobj(rwtm)); + return ret; +} + +static int turris_mox_rwtm_remove(struct platform_device *pdev) +{ + struct mox_rwtm *rwtm = platform_get_drvdata(pdev); + + sysfs_remove_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs); + kobject_put(rwtm_to_kobj(rwtm)); + mbox_free_channel(rwtm->mbox); + + return 0; +} + +static const struct of_device_id turris_mox_rwtm_match[] = { + { .compatible = "cznic,turris-mox-rwtm", }, + { }, +}; + +MODULE_DEVICE_TABLE(of, turris_mox_rwtm_match); + +static struct platform_driver turris_mox_rwtm_driver = { + .probe = turris_mox_rwtm_probe, + .remove = turris_mox_rwtm_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = turris_mox_rwtm_match, + }, +}; +module_platform_driver(turris_mox_rwtm_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Turris Mox rWTM firmware driver"); +MODULE_AUTHOR("Marek Behun "); diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index cdd4f73b48690e9c4a66e397ca7737e7a3a1a8f5..73c779e920edc2254e74f2a83312a9416d1351b6 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -46,11 +46,11 @@ config FPGA_MGR_ALTERA_PS_SPI using the passive serial interface over SPI. config FPGA_MGR_ALTERA_CVP - tristate "Altera Arria-V/Cyclone-V/Stratix-V CvP FPGA Manager" + tristate "Altera CvP FPGA Manager" depends on PCI help - FPGA manager driver support for Arria-V, Cyclone-V, Stratix-V - and Arria 10 Altera FPGAs using the CvP interface over PCIe. + FPGA manager driver support for Arria-V, Cyclone-V, Stratix-V, + Arria 10 and Stratix10 Altera FPGAs using the CvP interface over PCIe. config FPGA_MGR_ZYNQ_FPGA tristate "Xilinx Zynq FPGA" diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 312b9371742f80bbc2b03d7ada8c8ee7c4b9f7a7..4865b74b00a4bc0dbf13906b89cb19cc4a46f834 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -39,8 +39,9 @@ obj-$(CONFIG_FPGA_DFL_FME_BRIDGE) += dfl-fme-br.o obj-$(CONFIG_FPGA_DFL_FME_REGION) += dfl-fme-region.o obj-$(CONFIG_FPGA_DFL_AFU) += dfl-afu.o -dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o +dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o dfl-fme-error.o dfl-afu-objs := dfl-afu-main.o dfl-afu-region.o dfl-afu-dma-region.o +dfl-afu-objs += dfl-afu-error.o # Drivers for FPGAs which implement DFL obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o diff --git a/drivers/fpga/altera-cvp.c b/drivers/fpga/altera-cvp.c index 770915fb97f96351cb5feafd223ac7c8f833662b..4e0edb60bfba6ae8c8f8f8fa7f6656feca098bb6 100644 --- a/drivers/fpga/altera-cvp.c +++ b/drivers/fpga/altera-cvp.c @@ -22,10 +22,10 @@ #define TIMEOUT_US 2000 /* CVP STATUS timeout for USERMODE polling */ /* Vendor Specific Extended Capability Registers */ -#define VSE_PCIE_EXT_CAP_ID 0x200 +#define VSE_PCIE_EXT_CAP_ID 0x0 #define VSE_PCIE_EXT_CAP_ID_VAL 0x000b /* 16bit */ -#define VSE_CVP_STATUS 0x21c /* 32bit */ +#define VSE_CVP_STATUS 0x1c /* 32bit */ #define VSE_CVP_STATUS_CFG_RDY BIT(18) /* CVP_CONFIG_READY */ #define VSE_CVP_STATUS_CFG_ERR BIT(19) /* CVP_CONFIG_ERROR */ #define VSE_CVP_STATUS_CVP_EN BIT(20) /* ctrl block is enabling CVP */ @@ -33,41 +33,93 @@ #define VSE_CVP_STATUS_CFG_DONE BIT(23) /* CVP_CONFIG_DONE */ #define VSE_CVP_STATUS_PLD_CLK_IN_USE BIT(24) /* PLD_CLK_IN_USE */ -#define VSE_CVP_MODE_CTRL 0x220 /* 32bit */ +#define VSE_CVP_MODE_CTRL 0x20 /* 32bit */ #define VSE_CVP_MODE_CTRL_CVP_MODE BIT(0) /* CVP (1) or normal mode (0) */ #define VSE_CVP_MODE_CTRL_HIP_CLK_SEL BIT(1) /* PMA (1) or fabric clock (0) */ #define VSE_CVP_MODE_CTRL_NUMCLKS_OFF 8 /* NUMCLKS bits offset */ #define VSE_CVP_MODE_CTRL_NUMCLKS_MASK GENMASK(15, 8) -#define VSE_CVP_DATA 0x228 /* 32bit */ -#define VSE_CVP_PROG_CTRL 0x22c /* 32bit */ +#define VSE_CVP_DATA 0x28 /* 32bit */ +#define VSE_CVP_PROG_CTRL 0x2c /* 32bit */ #define VSE_CVP_PROG_CTRL_CONFIG BIT(0) #define VSE_CVP_PROG_CTRL_START_XFER BIT(1) +#define VSE_CVP_PROG_CTRL_MASK GENMASK(1, 0) -#define VSE_UNCOR_ERR_STATUS 0x234 /* 32bit */ +#define VSE_UNCOR_ERR_STATUS 0x34 /* 32bit */ #define VSE_UNCOR_ERR_CVP_CFG_ERR BIT(5) /* CVP_CONFIG_ERROR_LATCHED */ +#define V1_VSEC_OFFSET 0x200 /* Vendor Specific Offset V1 */ +/* V2 Defines */ +#define VSE_CVP_TX_CREDITS 0x49 /* 8bit */ + +#define V2_CREDIT_TIMEOUT_US 20000 +#define V2_CHECK_CREDIT_US 10 +#define V2_POLL_TIMEOUT_US 1000000 +#define V2_USER_TIMEOUT_US 500000 + +#define V1_POLL_TIMEOUT_US 10 + #define DRV_NAME "altera-cvp" #define ALTERA_CVP_MGR_NAME "Altera CvP FPGA Manager" +/* Write block sizes */ +#define ALTERA_CVP_V1_SIZE 4 +#define ALTERA_CVP_V2_SIZE 4096 + /* Optional CvP config error status check for debugging */ static bool altera_cvp_chkcfg; +struct cvp_priv; + struct altera_cvp_conf { struct fpga_manager *mgr; struct pci_dev *pci_dev; void __iomem *map; - void (*write_data)(struct altera_cvp_conf *, u32); + void (*write_data)(struct altera_cvp_conf *conf, + u32 data); char mgr_name[64]; u8 numclks; + u32 sent_packets; + u32 vsec_offset; + const struct cvp_priv *priv; +}; + +struct cvp_priv { + void (*switch_clk)(struct altera_cvp_conf *conf); + int (*clear_state)(struct altera_cvp_conf *conf); + int (*wait_credit)(struct fpga_manager *mgr, u32 blocks); + size_t block_size; + int poll_time_us; + int user_time_us; }; +static int altera_read_config_byte(struct altera_cvp_conf *conf, + int where, u8 *val) +{ + return pci_read_config_byte(conf->pci_dev, conf->vsec_offset + where, + val); +} + +static int altera_read_config_dword(struct altera_cvp_conf *conf, + int where, u32 *val) +{ + return pci_read_config_dword(conf->pci_dev, conf->vsec_offset + where, + val); +} + +static int altera_write_config_dword(struct altera_cvp_conf *conf, + int where, u32 val) +{ + return pci_write_config_dword(conf->pci_dev, conf->vsec_offset + where, + val); +} + static enum fpga_mgr_states altera_cvp_state(struct fpga_manager *mgr) { struct altera_cvp_conf *conf = mgr->priv; u32 status; - pci_read_config_dword(conf->pci_dev, VSE_CVP_STATUS, &status); + altera_read_config_dword(conf, VSE_CVP_STATUS, &status); if (status & VSE_CVP_STATUS_CFG_DONE) return FPGA_MGR_STATE_OPERATING; @@ -85,7 +137,8 @@ static void altera_cvp_write_data_iomem(struct altera_cvp_conf *conf, u32 val) static void altera_cvp_write_data_config(struct altera_cvp_conf *conf, u32 val) { - pci_write_config_dword(conf->pci_dev, VSE_CVP_DATA, val); + pci_write_config_dword(conf->pci_dev, conf->vsec_offset + VSE_CVP_DATA, + val); } /* switches between CvP clock and internal clock */ @@ -95,10 +148,10 @@ static void altera_cvp_dummy_write(struct altera_cvp_conf *conf) u32 val; /* set 1 CVP clock cycle for every CVP Data Register Write */ - pci_read_config_dword(conf->pci_dev, VSE_CVP_MODE_CTRL, &val); + altera_read_config_dword(conf, VSE_CVP_MODE_CTRL, &val); val &= ~VSE_CVP_MODE_CTRL_NUMCLKS_MASK; val |= 1 << VSE_CVP_MODE_CTRL_NUMCLKS_OFF; - pci_write_config_dword(conf->pci_dev, VSE_CVP_MODE_CTRL, val); + altera_write_config_dword(conf, VSE_CVP_MODE_CTRL, val); for (i = 0; i < CVP_DUMMY_WR; i++) conf->write_data(conf, 0); /* dummy data, could be any value */ @@ -115,7 +168,7 @@ static int altera_cvp_wait_status(struct altera_cvp_conf *conf, u32 status_mask, retries++; do { - pci_read_config_dword(conf->pci_dev, VSE_CVP_STATUS, &val); + altera_read_config_dword(conf, VSE_CVP_STATUS, &val); if ((val & status_mask) == status_val) return 0; @@ -126,32 +179,136 @@ static int altera_cvp_wait_status(struct altera_cvp_conf *conf, u32 status_mask, return -ETIMEDOUT; } +static int altera_cvp_chk_error(struct fpga_manager *mgr, size_t bytes) +{ + struct altera_cvp_conf *conf = mgr->priv; + u32 val; + int ret; + + /* STEP 10 (optional) - check CVP_CONFIG_ERROR flag */ + ret = altera_read_config_dword(conf, VSE_CVP_STATUS, &val); + if (ret || (val & VSE_CVP_STATUS_CFG_ERR)) { + dev_err(&mgr->dev, "CVP_CONFIG_ERROR after %zu bytes!\n", + bytes); + return -EPROTO; + } + return 0; +} + +/* + * CvP Version2 Functions + * Recent Intel FPGAs use a credit mechanism to throttle incoming + * bitstreams and a different method of clearing the state. + */ + +static int altera_cvp_v2_clear_state(struct altera_cvp_conf *conf) +{ + u32 val; + int ret; + + /* Clear the START_XFER and CVP_CONFIG bits */ + ret = altera_read_config_dword(conf, VSE_CVP_PROG_CTRL, &val); + if (ret) { + dev_err(&conf->pci_dev->dev, + "Error reading CVP Program Control Register\n"); + return ret; + } + + val &= ~VSE_CVP_PROG_CTRL_MASK; + ret = altera_write_config_dword(conf, VSE_CVP_PROG_CTRL, val); + if (ret) { + dev_err(&conf->pci_dev->dev, + "Error writing CVP Program Control Register\n"); + return ret; + } + + return altera_cvp_wait_status(conf, VSE_CVP_STATUS_CFG_RDY, 0, + conf->priv->poll_time_us); +} + +static int altera_cvp_v2_wait_for_credit(struct fpga_manager *mgr, + u32 blocks) +{ + u32 timeout = V2_CREDIT_TIMEOUT_US / V2_CHECK_CREDIT_US; + struct altera_cvp_conf *conf = mgr->priv; + int ret; + u8 val; + + do { + ret = altera_read_config_byte(conf, VSE_CVP_TX_CREDITS, &val); + if (ret) { + dev_err(&conf->pci_dev->dev, + "Error reading CVP Credit Register\n"); + return ret; + } + + /* Return if there is space in FIFO */ + if (val - (u8)conf->sent_packets) + return 0; + + ret = altera_cvp_chk_error(mgr, blocks * ALTERA_CVP_V2_SIZE); + if (ret) { + dev_err(&conf->pci_dev->dev, + "CE Bit error credit reg[0x%x]:sent[0x%x]\n", + val, conf->sent_packets); + return -EAGAIN; + } + + /* Limit the check credit byte traffic */ + usleep_range(V2_CHECK_CREDIT_US, V2_CHECK_CREDIT_US + 1); + } while (timeout--); + + dev_err(&conf->pci_dev->dev, "Timeout waiting for credit\n"); + return -ETIMEDOUT; +} + +static int altera_cvp_send_block(struct altera_cvp_conf *conf, + const u32 *data, size_t len) +{ + u32 mask, words = len / sizeof(u32); + int i, remainder; + + for (i = 0; i < words; i++) + conf->write_data(conf, *data++); + + /* write up to 3 trailing bytes, if any */ + remainder = len % sizeof(u32); + if (remainder) { + mask = BIT(remainder * 8) - 1; + if (mask) + conf->write_data(conf, *data & mask); + } + + return 0; +} + static int altera_cvp_teardown(struct fpga_manager *mgr, struct fpga_image_info *info) { struct altera_cvp_conf *conf = mgr->priv; - struct pci_dev *pdev = conf->pci_dev; int ret; u32 val; /* STEP 12 - reset START_XFER bit */ - pci_read_config_dword(pdev, VSE_CVP_PROG_CTRL, &val); + altera_read_config_dword(conf, VSE_CVP_PROG_CTRL, &val); val &= ~VSE_CVP_PROG_CTRL_START_XFER; - pci_write_config_dword(pdev, VSE_CVP_PROG_CTRL, val); + altera_write_config_dword(conf, VSE_CVP_PROG_CTRL, val); /* STEP 13 - reset CVP_CONFIG bit */ val &= ~VSE_CVP_PROG_CTRL_CONFIG; - pci_write_config_dword(pdev, VSE_CVP_PROG_CTRL, val); + altera_write_config_dword(conf, VSE_CVP_PROG_CTRL, val); /* * STEP 14 * - set CVP_NUMCLKS to 1 and then issue CVP_DUMMY_WR dummy * writes to the HIP */ - altera_cvp_dummy_write(conf); /* from CVP clock to internal clock */ + if (conf->priv->switch_clk) + conf->priv->switch_clk(conf); /* STEP 15 - poll CVP_CONFIG_READY bit for 0 with 10us timeout */ - ret = altera_cvp_wait_status(conf, VSE_CVP_STATUS_CFG_RDY, 0, 10); + ret = altera_cvp_wait_status(conf, VSE_CVP_STATUS_CFG_RDY, 0, + conf->priv->poll_time_us); if (ret) dev_err(&mgr->dev, "CFG_RDY == 0 timeout\n"); @@ -163,7 +320,6 @@ static int altera_cvp_write_init(struct fpga_manager *mgr, const char *buf, size_t count) { struct altera_cvp_conf *conf = mgr->priv; - struct pci_dev *pdev = conf->pci_dev; u32 iflags, val; int ret; @@ -183,7 +339,7 @@ static int altera_cvp_write_init(struct fpga_manager *mgr, conf->numclks = 1; /* for uncompressed and unencrypted images */ /* STEP 1 - read CVP status and check CVP_EN flag */ - pci_read_config_dword(pdev, VSE_CVP_STATUS, &val); + altera_read_config_dword(conf, VSE_CVP_STATUS, &val); if (!(val & VSE_CVP_STATUS_CVP_EN)) { dev_err(&mgr->dev, "CVP mode off: 0x%04x\n", val); return -ENODEV; @@ -201,30 +357,42 @@ static int altera_cvp_write_init(struct fpga_manager *mgr, * - set HIP_CLK_SEL and CVP_MODE (must be set in the order mentioned) */ /* switch from fabric to PMA clock */ - pci_read_config_dword(pdev, VSE_CVP_MODE_CTRL, &val); + altera_read_config_dword(conf, VSE_CVP_MODE_CTRL, &val); val |= VSE_CVP_MODE_CTRL_HIP_CLK_SEL; - pci_write_config_dword(pdev, VSE_CVP_MODE_CTRL, val); + altera_write_config_dword(conf, VSE_CVP_MODE_CTRL, val); /* set CVP mode */ - pci_read_config_dword(pdev, VSE_CVP_MODE_CTRL, &val); + altera_read_config_dword(conf, VSE_CVP_MODE_CTRL, &val); val |= VSE_CVP_MODE_CTRL_CVP_MODE; - pci_write_config_dword(pdev, VSE_CVP_MODE_CTRL, val); + altera_write_config_dword(conf, VSE_CVP_MODE_CTRL, val); /* * STEP 3 * - set CVP_NUMCLKS to 1 and issue CVP_DUMMY_WR dummy writes to the HIP */ - altera_cvp_dummy_write(conf); + if (conf->priv->switch_clk) + conf->priv->switch_clk(conf); + + if (conf->priv->clear_state) { + ret = conf->priv->clear_state(conf); + if (ret) { + dev_err(&mgr->dev, "Problem clearing out state\n"); + return ret; + } + } + + conf->sent_packets = 0; /* STEP 4 - set CVP_CONFIG bit */ - pci_read_config_dword(pdev, VSE_CVP_PROG_CTRL, &val); + altera_read_config_dword(conf, VSE_CVP_PROG_CTRL, &val); /* request control block to begin transfer using CVP */ val |= VSE_CVP_PROG_CTRL_CONFIG; - pci_write_config_dword(pdev, VSE_CVP_PROG_CTRL, val); + altera_write_config_dword(conf, VSE_CVP_PROG_CTRL, val); - /* STEP 5 - poll CVP_CONFIG READY for 1 with 10us timeout */ + /* STEP 5 - poll CVP_CONFIG READY for 1 with timeout */ ret = altera_cvp_wait_status(conf, VSE_CVP_STATUS_CFG_RDY, - VSE_CVP_STATUS_CFG_RDY, 10); + VSE_CVP_STATUS_CFG_RDY, + conf->priv->poll_time_us); if (ret) { dev_warn(&mgr->dev, "CFG_RDY == 1 timeout\n"); return ret; @@ -234,33 +402,28 @@ static int altera_cvp_write_init(struct fpga_manager *mgr, * STEP 6 * - set CVP_NUMCLKS to 1 and issue CVP_DUMMY_WR dummy writes to the HIP */ - altera_cvp_dummy_write(conf); + if (conf->priv->switch_clk) + conf->priv->switch_clk(conf); + + if (altera_cvp_chkcfg) { + ret = altera_cvp_chk_error(mgr, 0); + if (ret) { + dev_warn(&mgr->dev, "CFG_RDY == 1 timeout\n"); + return ret; + } + } /* STEP 7 - set START_XFER */ - pci_read_config_dword(pdev, VSE_CVP_PROG_CTRL, &val); + altera_read_config_dword(conf, VSE_CVP_PROG_CTRL, &val); val |= VSE_CVP_PROG_CTRL_START_XFER; - pci_write_config_dword(pdev, VSE_CVP_PROG_CTRL, val); + altera_write_config_dword(conf, VSE_CVP_PROG_CTRL, val); /* STEP 8 - start transfer (set CVP_NUMCLKS for bitstream) */ - pci_read_config_dword(pdev, VSE_CVP_MODE_CTRL, &val); - val &= ~VSE_CVP_MODE_CTRL_NUMCLKS_MASK; - val |= conf->numclks << VSE_CVP_MODE_CTRL_NUMCLKS_OFF; - pci_write_config_dword(pdev, VSE_CVP_MODE_CTRL, val); - - return 0; -} - -static inline int altera_cvp_chk_error(struct fpga_manager *mgr, size_t bytes) -{ - struct altera_cvp_conf *conf = mgr->priv; - u32 val; - - /* STEP 10 (optional) - check CVP_CONFIG_ERROR flag */ - pci_read_config_dword(conf->pci_dev, VSE_CVP_STATUS, &val); - if (val & VSE_CVP_STATUS_CFG_ERR) { - dev_err(&mgr->dev, "CVP_CONFIG_ERROR after %zu bytes!\n", - bytes); - return -EPROTO; + if (conf->priv->switch_clk) { + altera_read_config_dword(conf, VSE_CVP_MODE_CTRL, &val); + val &= ~VSE_CVP_MODE_CTRL_NUMCLKS_MASK; + val |= conf->numclks << VSE_CVP_MODE_CTRL_NUMCLKS_OFF; + altera_write_config_dword(conf, VSE_CVP_MODE_CTRL, val); } return 0; } @@ -269,20 +432,32 @@ static int altera_cvp_write(struct fpga_manager *mgr, const char *buf, size_t count) { struct altera_cvp_conf *conf = mgr->priv; + size_t done, remaining, len; const u32 *data; - size_t done, remaining; int status = 0; - u32 mask; /* STEP 9 - write 32-bit data from RBF file to CVP data register */ data = (u32 *)buf; remaining = count; done = 0; - while (remaining >= 4) { - conf->write_data(conf, *data++); - done += 4; - remaining -= 4; + while (remaining) { + /* Use credit throttling if available */ + if (conf->priv->wait_credit) { + status = conf->priv->wait_credit(mgr, done); + if (status) { + dev_err(&conf->pci_dev->dev, + "Wait Credit ERR: 0x%x\n", status); + return status; + } + } + + len = min(conf->priv->block_size, remaining); + altera_cvp_send_block(conf, data, len); + data += len / sizeof(u32); + done += len; + remaining -= len; + conf->sent_packets++; /* * STEP 10 (optional) and STEP 11 @@ -300,11 +475,6 @@ static int altera_cvp_write(struct fpga_manager *mgr, const char *buf, } } - /* write up to 3 trailing bytes, if any */ - mask = BIT(remaining * 8) - 1; - if (mask) - conf->write_data(conf, *data & mask); - if (altera_cvp_chkcfg) status = altera_cvp_chk_error(mgr, count); @@ -315,31 +485,30 @@ static int altera_cvp_write_complete(struct fpga_manager *mgr, struct fpga_image_info *info) { struct altera_cvp_conf *conf = mgr->priv; - struct pci_dev *pdev = conf->pci_dev; + u32 mask, val; int ret; - u32 mask; - u32 val; ret = altera_cvp_teardown(mgr, info); if (ret) return ret; /* STEP 16 - check CVP_CONFIG_ERROR_LATCHED bit */ - pci_read_config_dword(pdev, VSE_UNCOR_ERR_STATUS, &val); + altera_read_config_dword(conf, VSE_UNCOR_ERR_STATUS, &val); if (val & VSE_UNCOR_ERR_CVP_CFG_ERR) { dev_err(&mgr->dev, "detected CVP_CONFIG_ERROR_LATCHED!\n"); return -EPROTO; } /* STEP 17 - reset CVP_MODE and HIP_CLK_SEL bit */ - pci_read_config_dword(pdev, VSE_CVP_MODE_CTRL, &val); + altera_read_config_dword(conf, VSE_CVP_MODE_CTRL, &val); val &= ~VSE_CVP_MODE_CTRL_HIP_CLK_SEL; val &= ~VSE_CVP_MODE_CTRL_CVP_MODE; - pci_write_config_dword(pdev, VSE_CVP_MODE_CTRL, val); + altera_write_config_dword(conf, VSE_CVP_MODE_CTRL, val); /* STEP 18 - poll PLD_CLK_IN_USE and USER_MODE bits */ mask = VSE_CVP_STATUS_PLD_CLK_IN_USE | VSE_CVP_STATUS_USERMODE; - ret = altera_cvp_wait_status(conf, mask, mask, TIMEOUT_US); + ret = altera_cvp_wait_status(conf, mask, mask, + conf->priv->user_time_us); if (ret) dev_err(&mgr->dev, "PLD_CLK_IN_USE|USERMODE timeout\n"); @@ -353,6 +522,21 @@ static const struct fpga_manager_ops altera_cvp_ops = { .write_complete = altera_cvp_write_complete, }; +static const struct cvp_priv cvp_priv_v1 = { + .switch_clk = altera_cvp_dummy_write, + .block_size = ALTERA_CVP_V1_SIZE, + .poll_time_us = V1_POLL_TIMEOUT_US, + .user_time_us = TIMEOUT_US, +}; + +static const struct cvp_priv cvp_priv_v2 = { + .clear_state = altera_cvp_v2_clear_state, + .wait_credit = altera_cvp_v2_wait_for_credit, + .block_size = ALTERA_CVP_V2_SIZE, + .poll_time_us = V2_POLL_TIMEOUT_US, + .user_time_us = V2_USER_TIMEOUT_US, +}; + static ssize_t chkcfg_show(struct device_driver *dev, char *buf) { return snprintf(buf, 3, "%d\n", altera_cvp_chkcfg); @@ -394,22 +578,29 @@ static int altera_cvp_probe(struct pci_dev *pdev, { struct altera_cvp_conf *conf; struct fpga_manager *mgr; + int ret, offset; u16 cmd, val; u32 regval; - int ret; + + /* Discover the Vendor Specific Offset for this device */ + offset = pci_find_next_ext_capability(pdev, 0, PCI_EXT_CAP_ID_VNDR); + if (!offset) { + dev_err(&pdev->dev, "No Vendor Specific Offset.\n"); + return -ENODEV; + } /* * First check if this is the expected FPGA device. PCI config * space access works without enabling the PCI device, memory * space access is enabled further down. */ - pci_read_config_word(pdev, VSE_PCIE_EXT_CAP_ID, &val); + pci_read_config_word(pdev, offset + VSE_PCIE_EXT_CAP_ID, &val); if (val != VSE_PCIE_EXT_CAP_ID_VAL) { dev_err(&pdev->dev, "Wrong EXT_CAP_ID value 0x%x\n", val); return -ENODEV; } - pci_read_config_dword(pdev, VSE_CVP_STATUS, ®val); + pci_read_config_dword(pdev, offset + VSE_CVP_STATUS, ®val); if (!(regval & VSE_CVP_STATUS_CVP_EN)) { dev_err(&pdev->dev, "CVP is disabled for this device: CVP_STATUS Reg 0x%x\n", @@ -421,6 +612,8 @@ static int altera_cvp_probe(struct pci_dev *pdev, if (!conf) return -ENOMEM; + conf->vsec_offset = offset; + /* * Enable memory BAR access. We cannot use pci_enable_device() here * because it will make the driver unusable with FPGA devices that @@ -445,6 +638,11 @@ static int altera_cvp_probe(struct pci_dev *pdev, conf->pci_dev = pdev; conf->write_data = altera_cvp_write_data_iomem; + if (conf->vsec_offset == V1_VSEC_OFFSET) + conf->priv = &cvp_priv_v1; + else + conf->priv = &cvp_priv_v2; + conf->map = pci_iomap(pdev, CVP_BAR, 0); if (!conf->map) { dev_warn(&pdev->dev, "Mapping CVP BAR failed\n"); diff --git a/drivers/fpga/altera-pr-ip-core-plat.c b/drivers/fpga/altera-pr-ip-core-plat.c index b293d83143f122b38a6f50d47d8c68baa1467828..99b9cc0e70f08fbf462310f6eb822712cc807757 100644 --- a/drivers/fpga/altera-pr-ip-core-plat.c +++ b/drivers/fpga/altera-pr-ip-core-plat.c @@ -32,7 +32,9 @@ static int alt_pr_platform_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; - return alt_pr_unregister(dev); + alt_pr_unregister(dev); + + return 0; } static const struct of_device_id alt_pr_of_match[] = { diff --git a/drivers/fpga/altera-pr-ip-core.c b/drivers/fpga/altera-pr-ip-core.c index a7a3bf0b520284a8abefa06810fa7e4f2ae443ba..2cf25fd5e897957ac4582cfdd8f832669909d52a 100644 --- a/drivers/fpga/altera-pr-ip-core.c +++ b/drivers/fpga/altera-pr-ip-core.c @@ -201,15 +201,13 @@ int alt_pr_register(struct device *dev, void __iomem *reg_base) } EXPORT_SYMBOL_GPL(alt_pr_register); -int alt_pr_unregister(struct device *dev) +void alt_pr_unregister(struct device *dev) { struct fpga_manager *mgr = dev_get_drvdata(dev); dev_dbg(dev, "%s\n", __func__); fpga_mgr_unregister(mgr); - - return 0; } EXPORT_SYMBOL_GPL(alt_pr_unregister); diff --git a/drivers/fpga/dfl-afu-error.c b/drivers/fpga/dfl-afu-error.c new file mode 100644 index 0000000000000000000000000000000000000000..c1467ae1a6b636b60c287ceb5f397e7fc0d79f9b --- /dev/null +++ b/drivers/fpga/dfl-afu-error.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for FPGA Accelerated Function Unit (AFU) Error Reporting + * + * Copyright 2019 Intel Corporation, Inc. + * + * Authors: + * Wu Hao + * Xiao Guangrong + * Joseph Grecco + * Enno Luebbers + * Tim Whisonant + * Ananda Ravuri + * Mitchel Henry + */ + +#include + +#include "dfl-afu.h" + +#define PORT_ERROR_MASK 0x8 +#define PORT_ERROR 0x10 +#define PORT_FIRST_ERROR 0x18 +#define PORT_MALFORMED_REQ0 0x20 +#define PORT_MALFORMED_REQ1 0x28 + +#define ERROR_MASK GENMASK_ULL(63, 0) + +/* mask or unmask port errors by the error mask register. */ +static void __afu_port_err_mask(struct device *dev, bool mask) +{ + void __iomem *base; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); + + writeq(mask ? ERROR_MASK : 0, base + PORT_ERROR_MASK); +} + +static void afu_port_err_mask(struct device *dev, bool mask) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + + mutex_lock(&pdata->lock); + __afu_port_err_mask(dev, mask); + mutex_unlock(&pdata->lock); +} + +/* clear port errors. */ +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; + u64 v; + + base_err = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); + base_hdr = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + mutex_lock(&pdata->lock); + + /* + * clear Port Errors + * + * - Check for AP6 State + * - Halt Port by keeping Port in reset + * - Set PORT Error mask to all 1 to mask errors + * - Clear all errors + * - Set Port mask to all 0 to enable errors + * - All errors start capturing new errors + * - Enable Port by pulling the port out of reset + */ + + /* if device is still in AP6 power state, can not clear any error. */ + v = readq(base_hdr + PORT_HDR_STS); + if (FIELD_GET(PORT_STS_PWR_STATE, v) == PORT_STS_PWR_STATE_AP6) { + dev_err(dev, "Could not clear errors, device in AP6 state.\n"); + goto done; + } + + /* Halt Port by keeping Port in reset */ + ret = __afu_port_disable(pdev); + if (ret) + goto done; + + /* Mask all errors */ + __afu_port_err_mask(dev, true); + + /* Clear errors if err input matches with current port errors.*/ + v = readq(base_err + PORT_ERROR); + + if (v == err) { + writeq(v, base_err + PORT_ERROR); + + v = readq(base_err + PORT_FIRST_ERROR); + writeq(v, base_err + PORT_FIRST_ERROR); + } else { + ret = -EINVAL; + } + + /* Clear mask */ + __afu_port_err_mask(dev, false); + + /* Enable the Port by clear the reset */ + __afu_port_enable(pdev); + +done: + mutex_unlock(&pdata->lock); + return ret; +} + +static ssize_t errors_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + u64 error; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); + + mutex_lock(&pdata->lock); + error = readq(base + PORT_ERROR); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "0x%llx\n", (unsigned long long)error); +} + +static ssize_t errors_store(struct device *dev, struct device_attribute *attr, + const char *buff, size_t count) +{ + u64 value; + int ret; + + if (kstrtou64(buff, 0, &value)) + return -EINVAL; + + ret = afu_port_err_clear(dev, value); + + return ret ? ret : count; +} +static DEVICE_ATTR_RW(errors); + +static ssize_t first_error_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + u64 error; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); + + mutex_lock(&pdata->lock); + error = readq(base + PORT_FIRST_ERROR); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "0x%llx\n", (unsigned long long)error); +} +static DEVICE_ATTR_RO(first_error); + +static ssize_t first_malformed_req_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + u64 req0, req1; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); + + mutex_lock(&pdata->lock); + req0 = readq(base + PORT_MALFORMED_REQ0); + req1 = readq(base + PORT_MALFORMED_REQ1); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "0x%016llx%016llx\n", + (unsigned long long)req1, (unsigned long long)req0); +} +static DEVICE_ATTR_RO(first_malformed_req); + +static struct attribute *port_err_attrs[] = { + &dev_attr_errors.attr, + &dev_attr_first_error.attr, + &dev_attr_first_malformed_req.attr, + NULL, +}; + +static umode_t port_err_attrs_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = kobj_to_dev(kobj); + + /* + * sysfs entries are visible only if related private feature is + * enumerated. + */ + if (!dfl_get_feature_by_id(dev, PORT_FEATURE_ID_ERROR)) + return 0; + + return attr->mode; +} + +const struct attribute_group port_err_group = { + .name = "errors", + .attrs = port_err_attrs, + .is_visible = port_err_attrs_visible, +}; + +static int port_err_init(struct platform_device *pdev, + struct dfl_feature *feature) +{ + afu_port_err_mask(&pdev->dev, false); + + return 0; +} + +static void port_err_uinit(struct platform_device *pdev, + struct dfl_feature *feature) +{ + afu_port_err_mask(&pdev->dev, true); +} + +const struct dfl_feature_id port_err_id_table[] = { + {.id = PORT_FEATURE_ID_ERROR,}, + {0,} +}; + +const struct dfl_feature_ops port_err_ops = { + .init = port_err_init, + .uinit = port_err_uinit, +}; diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c index 02baa6a227c0c3317039d7d5ad3203188c7f7e13..e4a34dc7947f92fda2d77d04a859b801198b14e6 100644 --- a/drivers/fpga/dfl-afu-main.c +++ b/drivers/fpga/dfl-afu-main.c @@ -22,14 +22,17 @@ #include "dfl-afu.h" /** - * port_enable - enable a port + * __afu_port_enable - enable a port by clear reset * @pdev: port platform device. * * Enable Port by clear the port soft reset bit, which is set by default. * The AFU is unable to respond to any MMIO access while in reset. - * port_enable function should only be used after port_disable function. + * __afu_port_enable function should only be used after __afu_port_disable + * function. + * + * The caller needs to hold lock for protection. */ -static void port_enable(struct platform_device *pdev) +void __afu_port_enable(struct platform_device *pdev) { struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); void __iomem *base; @@ -52,13 +55,14 @@ static void port_enable(struct platform_device *pdev) #define RST_POLL_TIMEOUT 1000 /* us */ /** - * port_disable - disable a port + * __afu_port_disable - disable a port by hold reset * @pdev: port platform device. * - * Disable Port by setting the port soft reset bit, it puts the port into - * reset. + * Disable Port by setting the port soft reset bit, it puts the port into reset. + * + * The caller needs to hold lock for protection. */ -static int port_disable(struct platform_device *pdev) +int __afu_port_disable(struct platform_device *pdev) { struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); void __iomem *base; @@ -104,9 +108,9 @@ static int __port_reset(struct platform_device *pdev) { int ret; - ret = port_disable(pdev); + ret = __afu_port_disable(pdev); if (!ret) - port_enable(pdev); + __afu_port_enable(pdev); return ret; } @@ -141,27 +145,267 @@ id_show(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR_RO(id); -static const struct attribute *port_hdr_attrs[] = { +static ssize_t +ltr_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + u64 v; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + mutex_lock(&pdata->lock); + v = readq(base + PORT_HDR_CTRL); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_CTRL_LATENCY, v)); +} + +static ssize_t +ltr_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + bool ltr; + u64 v; + + if (kstrtobool(buf, <r)) + return -EINVAL; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + mutex_lock(&pdata->lock); + v = readq(base + PORT_HDR_CTRL); + v &= ~PORT_CTRL_LATENCY; + v |= FIELD_PREP(PORT_CTRL_LATENCY, ltr ? 1 : 0); + writeq(v, base + PORT_HDR_CTRL); + mutex_unlock(&pdata->lock); + + return count; +} +static DEVICE_ATTR_RW(ltr); + +static ssize_t +ap1_event_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + u64 v; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + mutex_lock(&pdata->lock); + v = readq(base + PORT_HDR_STS); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP1_EVT, v)); +} + +static ssize_t +ap1_event_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + bool clear; + + if (kstrtobool(buf, &clear) || !clear) + return -EINVAL; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + mutex_lock(&pdata->lock); + writeq(PORT_STS_AP1_EVT, base + PORT_HDR_STS); + mutex_unlock(&pdata->lock); + + return count; +} +static DEVICE_ATTR_RW(ap1_event); + +static ssize_t +ap2_event_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + u64 v; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + mutex_lock(&pdata->lock); + v = readq(base + PORT_HDR_STS); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP2_EVT, v)); +} + +static ssize_t +ap2_event_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + bool clear; + + if (kstrtobool(buf, &clear) || !clear) + return -EINVAL; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + mutex_lock(&pdata->lock); + writeq(PORT_STS_AP2_EVT, base + PORT_HDR_STS); + mutex_unlock(&pdata->lock); + + return count; +} +static DEVICE_ATTR_RW(ap2_event); + +static ssize_t +power_state_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + u64 v; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + mutex_lock(&pdata->lock); + v = readq(base + PORT_HDR_STS); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "0x%x\n", (u8)FIELD_GET(PORT_STS_PWR_STATE, v)); +} +static DEVICE_ATTR_RO(power_state); + +static ssize_t +userclk_freqcmd_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + u64 userclk_freq_cmd; + void __iomem *base; + + if (kstrtou64(buf, 0, &userclk_freq_cmd)) + return -EINVAL; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + mutex_lock(&pdata->lock); + writeq(userclk_freq_cmd, base + PORT_HDR_USRCLK_CMD0); + mutex_unlock(&pdata->lock); + + return count; +} +static DEVICE_ATTR_WO(userclk_freqcmd); + +static ssize_t +userclk_freqcntrcmd_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + u64 userclk_freqcntr_cmd; + void __iomem *base; + + if (kstrtou64(buf, 0, &userclk_freqcntr_cmd)) + return -EINVAL; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + mutex_lock(&pdata->lock); + writeq(userclk_freqcntr_cmd, base + PORT_HDR_USRCLK_CMD1); + mutex_unlock(&pdata->lock); + + return count; +} +static DEVICE_ATTR_WO(userclk_freqcntrcmd); + +static ssize_t +userclk_freqsts_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + u64 userclk_freqsts; + void __iomem *base; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + mutex_lock(&pdata->lock); + userclk_freqsts = readq(base + PORT_HDR_USRCLK_STS0); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "0x%llx\n", (unsigned long long)userclk_freqsts); +} +static DEVICE_ATTR_RO(userclk_freqsts); + +static ssize_t +userclk_freqcntrsts_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + u64 userclk_freqcntrsts; + void __iomem *base; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + mutex_lock(&pdata->lock); + userclk_freqcntrsts = readq(base + PORT_HDR_USRCLK_STS1); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "0x%llx\n", + (unsigned long long)userclk_freqcntrsts); +} +static DEVICE_ATTR_RO(userclk_freqcntrsts); + +static struct attribute *port_hdr_attrs[] = { &dev_attr_id.attr, + &dev_attr_ltr.attr, + &dev_attr_ap1_event.attr, + &dev_attr_ap2_event.attr, + &dev_attr_power_state.attr, + &dev_attr_userclk_freqcmd.attr, + &dev_attr_userclk_freqcntrcmd.attr, + &dev_attr_userclk_freqsts.attr, + &dev_attr_userclk_freqcntrsts.attr, NULL, }; -static int port_hdr_init(struct platform_device *pdev, - struct dfl_feature *feature) +static umode_t port_hdr_attrs_visible(struct kobject *kobj, + struct attribute *attr, int n) { - dev_dbg(&pdev->dev, "PORT HDR Init.\n"); + struct device *dev = kobj_to_dev(kobj); + umode_t mode = attr->mode; + void __iomem *base; - port_reset(pdev); + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + if (dfl_feature_revision(base) > 0) { + /* + * userclk sysfs interfaces are only visible in case port + * revision is 0, as hardware with revision >0 doesn't + * support this. + */ + if (attr == &dev_attr_userclk_freqcmd.attr || + attr == &dev_attr_userclk_freqcntrcmd.attr || + attr == &dev_attr_userclk_freqsts.attr || + attr == &dev_attr_userclk_freqcntrsts.attr) + mode = 0; + } - return sysfs_create_files(&pdev->dev.kobj, port_hdr_attrs); + return mode; } -static void port_hdr_uinit(struct platform_device *pdev, - struct dfl_feature *feature) +static const struct attribute_group port_hdr_group = { + .attrs = port_hdr_attrs, + .is_visible = port_hdr_attrs_visible, +}; + +static int port_hdr_init(struct platform_device *pdev, + struct dfl_feature *feature) { - dev_dbg(&pdev->dev, "PORT HDR UInit.\n"); + port_reset(pdev); - sysfs_remove_files(&pdev->dev.kobj, port_hdr_attrs); + return 0; } static long @@ -185,9 +429,13 @@ port_hdr_ioctl(struct platform_device *pdev, struct dfl_feature *feature, return ret; } +static const struct dfl_feature_id port_hdr_id_table[] = { + {.id = PORT_FEATURE_ID_HEADER,}, + {0,} +}; + static const struct dfl_feature_ops port_hdr_ops = { .init = port_hdr_init, - .uinit = port_hdr_uinit, .ioctl = port_hdr_ioctl, }; @@ -214,51 +462,90 @@ afu_id_show(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR_RO(afu_id); -static const struct attribute *port_afu_attrs[] = { +static struct attribute *port_afu_attrs[] = { &dev_attr_afu_id.attr, NULL }; +static umode_t port_afu_attrs_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = kobj_to_dev(kobj); + + /* + * sysfs entries are visible only if related private feature is + * enumerated. + */ + if (!dfl_get_feature_by_id(dev, PORT_FEATURE_ID_AFU)) + return 0; + + return attr->mode; +} + +static const struct attribute_group port_afu_group = { + .attrs = port_afu_attrs, + .is_visible = port_afu_attrs_visible, +}; + static int port_afu_init(struct platform_device *pdev, struct dfl_feature *feature) { struct resource *res = &pdev->resource[feature->resource_index]; - int ret; - dev_dbg(&pdev->dev, "PORT AFU Init.\n"); + return afu_mmio_region_add(dev_get_platdata(&pdev->dev), + DFL_PORT_REGION_INDEX_AFU, + resource_size(res), res->start, + DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ | + DFL_PORT_REGION_WRITE); +} - ret = afu_mmio_region_add(dev_get_platdata(&pdev->dev), - DFL_PORT_REGION_INDEX_AFU, resource_size(res), - res->start, DFL_PORT_REGION_READ | - DFL_PORT_REGION_WRITE | DFL_PORT_REGION_MMAP); - if (ret) - return ret; +static const struct dfl_feature_id port_afu_id_table[] = { + {.id = PORT_FEATURE_ID_AFU,}, + {0,} +}; - return sysfs_create_files(&pdev->dev.kobj, port_afu_attrs); -} +static const struct dfl_feature_ops port_afu_ops = { + .init = port_afu_init, +}; -static void port_afu_uinit(struct platform_device *pdev, - struct dfl_feature *feature) +static int port_stp_init(struct platform_device *pdev, + struct dfl_feature *feature) { - dev_dbg(&pdev->dev, "PORT AFU UInit.\n"); + struct resource *res = &pdev->resource[feature->resource_index]; - sysfs_remove_files(&pdev->dev.kobj, port_afu_attrs); + return afu_mmio_region_add(dev_get_platdata(&pdev->dev), + DFL_PORT_REGION_INDEX_STP, + resource_size(res), res->start, + DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ | + DFL_PORT_REGION_WRITE); } -static const struct dfl_feature_ops port_afu_ops = { - .init = port_afu_init, - .uinit = port_afu_uinit, +static const struct dfl_feature_id port_stp_id_table[] = { + {.id = PORT_FEATURE_ID_STP,}, + {0,} +}; + +static const struct dfl_feature_ops port_stp_ops = { + .init = port_stp_init, }; static struct dfl_feature_driver port_feature_drvs[] = { { - .id = PORT_FEATURE_ID_HEADER, + .id_table = port_hdr_id_table, .ops = &port_hdr_ops, }, { - .id = PORT_FEATURE_ID_AFU, + .id_table = port_afu_id_table, .ops = &port_afu_ops, }, + { + .id_table = port_err_id_table, + .ops = &port_err_ops, + }, + { + .id_table = port_stp_id_table, + .ops = &port_stp_ops, + }, { .ops = NULL, } @@ -545,9 +832,9 @@ static int port_enable_set(struct platform_device *pdev, bool enable) mutex_lock(&pdata->lock); if (enable) - port_enable(pdev); + __afu_port_enable(pdev); else - ret = port_disable(pdev); + ret = __afu_port_disable(pdev); mutex_unlock(&pdata->lock); return ret; @@ -599,9 +886,17 @@ static int afu_remove(struct platform_device *pdev) return 0; } +static const struct attribute_group *afu_dev_groups[] = { + &port_hdr_group, + &port_afu_group, + &port_err_group, + NULL +}; + static struct platform_driver afu_driver = { .driver = { - .name = DFL_FPGA_FEATURE_DEV_PORT, + .name = DFL_FPGA_FEATURE_DEV_PORT, + .dev_groups = afu_dev_groups, }, .probe = afu_probe, .remove = afu_remove, diff --git a/drivers/fpga/dfl-afu.h b/drivers/fpga/dfl-afu.h index 0c7630ae3cda50c5aa69a2789181ec50505f8012..576e9496008634a400fe73a0d57bfe93e8a9fbbf 100644 --- a/drivers/fpga/dfl-afu.h +++ b/drivers/fpga/dfl-afu.h @@ -79,6 +79,10 @@ struct dfl_afu { struct dfl_feature_platform_data *pdata; }; +/* hold pdata->lock when call __afu_port_enable/disable */ +void __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); int afu_mmio_region_add(struct dfl_feature_platform_data *pdata, u32 region_index, u64 region_size, u64 phys, u32 flags); @@ -97,4 +101,9 @@ int afu_dma_unmap_region(struct dfl_feature_platform_data *pdata, u64 iova); struct dfl_afu_dma_region * afu_dma_region_find(struct dfl_feature_platform_data *pdata, u64 iova, u64 size); + +extern const struct dfl_feature_ops port_err_ops; +extern const struct dfl_feature_id port_err_id_table[]; +extern const struct attribute_group port_err_group; + #endif /* __DFL_AFU_H */ diff --git a/drivers/fpga/dfl-fme-error.c b/drivers/fpga/dfl-fme-error.c new file mode 100644 index 0000000000000000000000000000000000000000..f897d414b923acf0d6f4f1cfc1531ae20a89ac05 --- /dev/null +++ b/drivers/fpga/dfl-fme-error.c @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for FPGA Management Engine Error Management + * + * Copyright 2019 Intel Corporation, Inc. + * + * Authors: + * Kang Luwei + * Xiao Guangrong + * Wu Hao + * Joseph Grecco + * Enno Luebbers + * Tim Whisonant + * Ananda Ravuri + * Mitchel, Henry + */ + +#include + +#include "dfl.h" +#include "dfl-fme.h" + +#define FME_ERROR_MASK 0x8 +#define FME_ERROR 0x10 +#define MBP_ERROR BIT_ULL(6) +#define PCIE0_ERROR_MASK 0x18 +#define PCIE0_ERROR 0x20 +#define PCIE1_ERROR_MASK 0x28 +#define PCIE1_ERROR 0x30 +#define FME_FIRST_ERROR 0x38 +#define FME_NEXT_ERROR 0x40 +#define RAS_NONFAT_ERROR_MASK 0x48 +#define RAS_NONFAT_ERROR 0x50 +#define RAS_CATFAT_ERROR_MASK 0x58 +#define RAS_CATFAT_ERROR 0x60 +#define RAS_ERROR_INJECT 0x68 +#define INJECT_ERROR_MASK GENMASK_ULL(2, 0) + +#define ERROR_MASK GENMASK_ULL(63, 0) + +static ssize_t pcie0_errors_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + u64 value; + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); + + mutex_lock(&pdata->lock); + value = readq(base + PCIE0_ERROR); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "0x%llx\n", (unsigned long long)value); +} + +static ssize_t pcie0_errors_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + int ret = 0; + u64 v, val; + + if (kstrtou64(buf, 0, &val)) + return -EINVAL; + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); + + mutex_lock(&pdata->lock); + writeq(GENMASK_ULL(63, 0), base + PCIE0_ERROR_MASK); + + v = readq(base + PCIE0_ERROR); + if (val == v) + writeq(v, base + PCIE0_ERROR); + else + ret = -EINVAL; + + writeq(0ULL, base + PCIE0_ERROR_MASK); + mutex_unlock(&pdata->lock); + return ret ? ret : count; +} +static DEVICE_ATTR_RW(pcie0_errors); + +static ssize_t pcie1_errors_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + u64 value; + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); + + mutex_lock(&pdata->lock); + value = readq(base + PCIE1_ERROR); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "0x%llx\n", (unsigned long long)value); +} + +static ssize_t pcie1_errors_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + int ret = 0; + u64 v, val; + + if (kstrtou64(buf, 0, &val)) + return -EINVAL; + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); + + mutex_lock(&pdata->lock); + writeq(GENMASK_ULL(63, 0), base + PCIE1_ERROR_MASK); + + v = readq(base + PCIE1_ERROR); + if (val == v) + writeq(v, base + PCIE1_ERROR); + else + ret = -EINVAL; + + writeq(0ULL, base + PCIE1_ERROR_MASK); + mutex_unlock(&pdata->lock); + return ret ? ret : count; +} +static DEVICE_ATTR_RW(pcie1_errors); + +static ssize_t nonfatal_errors_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + void __iomem *base; + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); + + return sprintf(buf, "0x%llx\n", + (unsigned long long)readq(base + RAS_NONFAT_ERROR)); +} +static DEVICE_ATTR_RO(nonfatal_errors); + +static ssize_t catfatal_errors_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + void __iomem *base; + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); + + return sprintf(buf, "0x%llx\n", + (unsigned long long)readq(base + RAS_CATFAT_ERROR)); +} +static DEVICE_ATTR_RO(catfatal_errors); + +static ssize_t inject_errors_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + u64 v; + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); + + mutex_lock(&pdata->lock); + v = readq(base + RAS_ERROR_INJECT); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "0x%llx\n", + (unsigned long long)FIELD_GET(INJECT_ERROR_MASK, v)); +} + +static ssize_t inject_errors_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + u8 inject_error; + u64 v; + + if (kstrtou8(buf, 0, &inject_error)) + return -EINVAL; + + if (inject_error & ~INJECT_ERROR_MASK) + return -EINVAL; + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); + + mutex_lock(&pdata->lock); + v = readq(base + RAS_ERROR_INJECT); + v &= ~INJECT_ERROR_MASK; + v |= FIELD_PREP(INJECT_ERROR_MASK, inject_error); + writeq(v, base + RAS_ERROR_INJECT); + mutex_unlock(&pdata->lock); + + return count; +} +static DEVICE_ATTR_RW(inject_errors); + +static ssize_t fme_errors_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + u64 value; + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); + + mutex_lock(&pdata->lock); + value = readq(base + FME_ERROR); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "0x%llx\n", (unsigned long long)value); +} + +static ssize_t fme_errors_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + u64 v, val; + int ret = 0; + + if (kstrtou64(buf, 0, &val)) + return -EINVAL; + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); + + mutex_lock(&pdata->lock); + writeq(GENMASK_ULL(63, 0), base + FME_ERROR_MASK); + + v = readq(base + FME_ERROR); + if (val == v) + writeq(v, base + FME_ERROR); + else + ret = -EINVAL; + + /* Workaround: disable MBP_ERROR if feature revision is 0 */ + writeq(dfl_feature_revision(base) ? 0ULL : MBP_ERROR, + base + FME_ERROR_MASK); + mutex_unlock(&pdata->lock); + return ret ? ret : count; +} +static DEVICE_ATTR_RW(fme_errors); + +static ssize_t first_error_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + u64 value; + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); + + mutex_lock(&pdata->lock); + value = readq(base + FME_FIRST_ERROR); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "0x%llx\n", (unsigned long long)value); +} +static DEVICE_ATTR_RO(first_error); + +static ssize_t next_error_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + u64 value; + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); + + mutex_lock(&pdata->lock); + value = readq(base + FME_NEXT_ERROR); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "0x%llx\n", (unsigned long long)value); +} +static DEVICE_ATTR_RO(next_error); + +static struct attribute *fme_global_err_attrs[] = { + &dev_attr_pcie0_errors.attr, + &dev_attr_pcie1_errors.attr, + &dev_attr_nonfatal_errors.attr, + &dev_attr_catfatal_errors.attr, + &dev_attr_inject_errors.attr, + &dev_attr_fme_errors.attr, + &dev_attr_first_error.attr, + &dev_attr_next_error.attr, + NULL, +}; + +static umode_t fme_global_err_attrs_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = kobj_to_dev(kobj); + + /* + * sysfs entries are visible only if related private feature is + * enumerated. + */ + if (!dfl_get_feature_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR)) + return 0; + + return attr->mode; +} + +const struct attribute_group fme_global_err_group = { + .name = "errors", + .attrs = fme_global_err_attrs, + .is_visible = fme_global_err_attrs_visible, +}; + +static void fme_err_mask(struct device *dev, bool mask) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + void __iomem *base; + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); + + mutex_lock(&pdata->lock); + + /* Workaround: keep MBP_ERROR always masked if revision is 0 */ + if (dfl_feature_revision(base)) + writeq(mask ? ERROR_MASK : 0, base + FME_ERROR_MASK); + else + writeq(mask ? ERROR_MASK : MBP_ERROR, base + FME_ERROR_MASK); + + writeq(mask ? ERROR_MASK : 0, base + PCIE0_ERROR_MASK); + writeq(mask ? ERROR_MASK : 0, base + PCIE1_ERROR_MASK); + writeq(mask ? ERROR_MASK : 0, base + RAS_NONFAT_ERROR_MASK); + writeq(mask ? ERROR_MASK : 0, base + RAS_CATFAT_ERROR_MASK); + + mutex_unlock(&pdata->lock); +} + +static int fme_global_err_init(struct platform_device *pdev, + struct dfl_feature *feature) +{ + fme_err_mask(&pdev->dev, false); + + return 0; +} + +static void fme_global_err_uinit(struct platform_device *pdev, + struct dfl_feature *feature) +{ + fme_err_mask(&pdev->dev, true); +} + +const struct dfl_feature_id fme_global_err_id_table[] = { + {.id = FME_FEATURE_ID_GLOBAL_ERR,}, + {0,} +}; + +const struct dfl_feature_ops fme_global_err_ops = { + .init = fme_global_err_init, + .uinit = fme_global_err_uinit, +}; diff --git a/drivers/fpga/dfl-fme-main.c b/drivers/fpga/dfl-fme-main.c index 086ad2420ade94f09b576a5dc3bad75ff7ade957..4d78e182878f97acc2f4f2b90a626089e3c04c17 100644 --- a/drivers/fpga/dfl-fme-main.c +++ b/drivers/fpga/dfl-fme-main.c @@ -16,6 +16,7 @@ #include #include +#include #include #include "dfl.h" @@ -72,50 +73,126 @@ static ssize_t bitstream_metadata_show(struct device *dev, } static DEVICE_ATTR_RO(bitstream_metadata); -static const struct attribute *fme_hdr_attrs[] = { +static ssize_t cache_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + void __iomem *base; + u64 v; + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); + + v = readq(base + FME_HDR_CAP); + + return sprintf(buf, "%u\n", + (unsigned int)FIELD_GET(FME_CAP_CACHE_SIZE, v)); +} +static DEVICE_ATTR_RO(cache_size); + +static ssize_t fabric_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + void __iomem *base; + u64 v; + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); + + v = readq(base + FME_HDR_CAP); + + return sprintf(buf, "%u\n", + (unsigned int)FIELD_GET(FME_CAP_FABRIC_VERID, v)); +} +static DEVICE_ATTR_RO(fabric_version); + +static ssize_t socket_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + void __iomem *base; + u64 v; + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); + + v = readq(base + FME_HDR_CAP); + + return sprintf(buf, "%u\n", + (unsigned int)FIELD_GET(FME_CAP_SOCKET_ID, v)); +} +static DEVICE_ATTR_RO(socket_id); + +static struct attribute *fme_hdr_attrs[] = { &dev_attr_ports_num.attr, &dev_attr_bitstream_id.attr, &dev_attr_bitstream_metadata.attr, + &dev_attr_cache_size.attr, + &dev_attr_fabric_version.attr, + &dev_attr_socket_id.attr, NULL, }; -static int fme_hdr_init(struct platform_device *pdev, - struct dfl_feature *feature) +static const struct attribute_group fme_hdr_group = { + .attrs = fme_hdr_attrs, +}; + +static long fme_hdr_ioctl_release_port(struct dfl_feature_platform_data *pdata, + unsigned long arg) { - void __iomem *base = feature->ioaddr; - int ret; + struct dfl_fpga_cdev *cdev = pdata->dfl_cdev; + int port_id; - dev_dbg(&pdev->dev, "FME HDR Init.\n"); - dev_dbg(&pdev->dev, "FME cap %llx.\n", - (unsigned long long)readq(base + FME_HDR_CAP)); + if (get_user(port_id, (int __user *)arg)) + return -EFAULT; - ret = sysfs_create_files(&pdev->dev.kobj, fme_hdr_attrs); - if (ret) - return ret; + return dfl_fpga_cdev_release_port(cdev, port_id); +} - return 0; +static long fme_hdr_ioctl_assign_port(struct dfl_feature_platform_data *pdata, + unsigned long arg) +{ + struct dfl_fpga_cdev *cdev = pdata->dfl_cdev; + int port_id; + + if (get_user(port_id, (int __user *)arg)) + return -EFAULT; + + return dfl_fpga_cdev_assign_port(cdev, port_id); } -static void fme_hdr_uinit(struct platform_device *pdev, - struct dfl_feature *feature) +static long fme_hdr_ioctl(struct platform_device *pdev, + struct dfl_feature *feature, + unsigned int cmd, unsigned long arg) { - dev_dbg(&pdev->dev, "FME HDR UInit.\n"); - sysfs_remove_files(&pdev->dev.kobj, fme_hdr_attrs); + struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); + + switch (cmd) { + case DFL_FPGA_FME_PORT_RELEASE: + return fme_hdr_ioctl_release_port(pdata, arg); + case DFL_FPGA_FME_PORT_ASSIGN: + return fme_hdr_ioctl_assign_port(pdata, arg); + } + + return -ENODEV; } +static const struct dfl_feature_id fme_hdr_id_table[] = { + {.id = FME_FEATURE_ID_HEADER,}, + {0,} +}; + static const struct dfl_feature_ops fme_hdr_ops = { - .init = fme_hdr_init, - .uinit = fme_hdr_uinit, + .ioctl = fme_hdr_ioctl, }; static struct dfl_feature_driver fme_feature_drvs[] = { { - .id = FME_FEATURE_ID_HEADER, + .id_table = fme_hdr_id_table, .ops = &fme_hdr_ops, }, { - .id = FME_FEATURE_ID_PR_MGMT, - .ops = &pr_mgmt_ops, + .id_table = fme_pr_mgmt_id_table, + .ops = &fme_pr_mgmt_ops, + }, + { + .id_table = fme_global_err_id_table, + .ops = &fme_global_err_ops, }, { .ops = NULL, @@ -263,9 +340,16 @@ static int fme_remove(struct platform_device *pdev) return 0; } +static const struct attribute_group *fme_dev_groups[] = { + &fme_hdr_group, + &fme_global_err_group, + NULL +}; + static struct platform_driver fme_driver = { .driver = { - .name = DFL_FPGA_FEATURE_DEV_FME, + .name = DFL_FPGA_FEATURE_DEV_FME, + .dev_groups = fme_dev_groups, }, .probe = fme_probe, .remove = fme_remove, diff --git a/drivers/fpga/dfl-fme-pr.c b/drivers/fpga/dfl-fme-pr.c index 3c71dc3faaf5b99bc632d86a73f776fbb94cd581..a233a53db708175f7637470b173e4c3fe52c5b4f 100644 --- a/drivers/fpga/dfl-fme-pr.c +++ b/drivers/fpga/dfl-fme-pr.c @@ -470,7 +470,12 @@ static long fme_pr_ioctl(struct platform_device *pdev, return ret; } -const struct dfl_feature_ops pr_mgmt_ops = { +const struct dfl_feature_id fme_pr_mgmt_id_table[] = { + {.id = FME_FEATURE_ID_PR_MGMT,}, + {0} +}; + +const struct dfl_feature_ops fme_pr_mgmt_ops = { .init = pr_mgmt_init, .uinit = pr_mgmt_uinit, .ioctl = fme_pr_ioctl, diff --git a/drivers/fpga/dfl-fme.h b/drivers/fpga/dfl-fme.h index 5394a216c5c0fc5f9a7b8a4c35c28d71ce71d6ef..6685c8ef965bd26d1e4ba3335a2e47377a84d04c 100644 --- a/drivers/fpga/dfl-fme.h +++ b/drivers/fpga/dfl-fme.h @@ -33,6 +33,10 @@ struct dfl_fme { struct dfl_feature_platform_data *pdata; }; -extern const struct dfl_feature_ops pr_mgmt_ops; +extern const struct dfl_feature_ops fme_pr_mgmt_ops; +extern const struct dfl_feature_id fme_pr_mgmt_id_table[]; +extern const struct dfl_feature_ops fme_global_err_ops; +extern const struct dfl_feature_id fme_global_err_id_table[]; +extern const struct attribute_group fme_global_err_group; #endif /* __DFL_FME_H */ diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c index 66b5720582bb36ed1006d2c0acc2624d6e9ed336..89ca292236ad8655ea582b72d264e4bf1bde8aa5 100644 --- a/drivers/fpga/dfl-pci.c +++ b/drivers/fpga/dfl-pci.c @@ -223,8 +223,43 @@ int cci_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *pcidevid) return ret; } +static int cci_pci_sriov_configure(struct pci_dev *pcidev, int num_vfs) +{ + struct cci_drvdata *drvdata = pci_get_drvdata(pcidev); + struct dfl_fpga_cdev *cdev = drvdata->cdev; + int ret = 0; + + if (!num_vfs) { + /* + * disable SRIOV and then put released ports back to default + * PF access mode. + */ + pci_disable_sriov(pcidev); + + dfl_fpga_cdev_config_ports_pf(cdev); + + } else { + /* + * before enable SRIOV, put released ports into VF access mode + * first of all. + */ + ret = dfl_fpga_cdev_config_ports_vf(cdev, num_vfs); + if (ret) + return ret; + + ret = pci_enable_sriov(pcidev, num_vfs); + if (ret) + dfl_fpga_cdev_config_ports_pf(cdev); + } + + return ret; +} + static void cci_pci_remove(struct pci_dev *pcidev) { + if (dev_is_pf(&pcidev->dev)) + cci_pci_sriov_configure(pcidev, 0); + cci_remove_feature_devs(pcidev); pci_disable_pcie_error_reporting(pcidev); } @@ -234,6 +269,7 @@ static struct pci_driver cci_pci_driver = { .id_table = cci_pcie_id_tbl, .probe = cci_pci_probe, .remove = cci_pci_remove, + .sriov_configure = cci_pci_sriov_configure, }; module_pci_driver(cci_pci_driver); diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c index 4b66aaa32b5ab2f1f91d94caf93cd335e2725906..96a2b8274a33a7c0e20bf94959d6f29c692ffd34 100644 --- a/drivers/fpga/dfl.c +++ b/drivers/fpga/dfl.c @@ -231,16 +231,20 @@ EXPORT_SYMBOL_GPL(dfl_fpga_port_ops_del); */ int dfl_fpga_check_port_id(struct platform_device *pdev, void *pport_id) { - struct dfl_fpga_port_ops *port_ops = dfl_fpga_port_ops_get(pdev); - int port_id; + struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct dfl_fpga_port_ops *port_ops; + + if (pdata->id != FEATURE_DEV_ID_UNUSED) + return pdata->id == *(int *)pport_id; + port_ops = dfl_fpga_port_ops_get(pdev); if (!port_ops || !port_ops->get_id) return 0; - port_id = port_ops->get_id(pdev); + pdata->id = port_ops->get_id(pdev); dfl_fpga_port_ops_put(port_ops); - return port_id == *(int *)pport_id; + return pdata->id == *(int *)pport_id; } EXPORT_SYMBOL_GPL(dfl_fpga_check_port_id); @@ -255,7 +259,8 @@ void dfl_fpga_dev_feature_uinit(struct platform_device *pdev) dfl_fpga_dev_for_each_feature(pdata, feature) if (feature->ops) { - feature->ops->uinit(pdev, feature); + if (feature->ops->uinit) + feature->ops->uinit(pdev, feature); feature->ops = NULL; } } @@ -266,17 +271,34 @@ static int dfl_feature_instance_init(struct platform_device *pdev, struct dfl_feature *feature, struct dfl_feature_driver *drv) { - int ret; + int ret = 0; - ret = drv->ops->init(pdev, feature); - if (ret) - return ret; + if (drv->ops->init) { + ret = drv->ops->init(pdev, feature); + if (ret) + return ret; + } feature->ops = drv->ops; return ret; } +static bool dfl_feature_drv_match(struct dfl_feature *feature, + struct dfl_feature_driver *driver) +{ + const struct dfl_feature_id *ids = driver->id_table; + + if (ids) { + while (ids->id) { + if (ids->id == feature->id) + return true; + ids++; + } + } + return false; +} + /** * dfl_fpga_dev_feature_init - init for sub features of dfl feature device * @pdev: feature device. @@ -297,8 +319,7 @@ int dfl_fpga_dev_feature_init(struct platform_device *pdev, while (drv->ops) { dfl_fpga_dev_for_each_feature(pdata, feature) { - /* match feature and drv using id */ - if (feature->id == drv->id) { + if (dfl_feature_drv_match(feature, drv)) { ret = dfl_feature_instance_init(pdev, pdata, feature, drv); if (ret) @@ -474,6 +495,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) pdata->dev = fdev; pdata->num = binfo->feature_num; pdata->dfl_cdev = binfo->cdev; + pdata->id = FEATURE_DEV_ID_UNUSED; mutex_init(&pdata->lock); lockdep_set_class_and_name(&pdata->lock, &dfl_pdata_keys[type], dfl_pdata_key_strings[type]); @@ -973,25 +995,27 @@ void dfl_fpga_feature_devs_remove(struct dfl_fpga_cdev *cdev) { struct dfl_feature_platform_data *pdata, *ptmp; - remove_feature_devs(cdev); - mutex_lock(&cdev->lock); - if (cdev->fme_dev) { - /* the fme should be unregistered. */ - WARN_ON(device_is_registered(cdev->fme_dev)); + if (cdev->fme_dev) put_device(cdev->fme_dev); - } list_for_each_entry_safe(pdata, ptmp, &cdev->port_dev_list, node) { struct platform_device *port_dev = pdata->dev; - /* the port should be unregistered. */ - WARN_ON(device_is_registered(&port_dev->dev)); + /* remove released ports */ + if (!device_is_registered(&port_dev->dev)) { + dfl_id_free(feature_dev_id_type(port_dev), + port_dev->id); + platform_device_put(port_dev); + } + list_del(&pdata->node); put_device(&port_dev->dev); } mutex_unlock(&cdev->lock); + remove_feature_devs(cdev); + fpga_region_unregister(cdev->region); devm_kfree(cdev->parent, cdev); } @@ -1042,6 +1066,170 @@ static int __init dfl_fpga_init(void) return ret; } +/** + * dfl_fpga_cdev_release_port - release a port platform device + * + * @cdev: parent container device. + * @port_id: id of the port platform device. + * + * This function allows user to release a port platform device. This is a + * mandatory step before turn a port from PF into VF for SRIOV support. + * + * Return: 0 on success, negative error code otherwise. + */ +int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id) +{ + struct platform_device *port_pdev; + int ret = -ENODEV; + + mutex_lock(&cdev->lock); + port_pdev = __dfl_fpga_cdev_find_port(cdev, &port_id, + dfl_fpga_check_port_id); + if (!port_pdev) + goto unlock_exit; + + if (!device_is_registered(&port_pdev->dev)) { + ret = -EBUSY; + goto put_dev_exit; + } + + ret = dfl_feature_dev_use_begin(dev_get_platdata(&port_pdev->dev)); + if (ret) + goto put_dev_exit; + + platform_device_del(port_pdev); + cdev->released_port_num++; +put_dev_exit: + put_device(&port_pdev->dev); +unlock_exit: + mutex_unlock(&cdev->lock); + return ret; +} +EXPORT_SYMBOL_GPL(dfl_fpga_cdev_release_port); + +/** + * dfl_fpga_cdev_assign_port - assign a port platform device back + * + * @cdev: parent container device. + * @port_id: id of the port platform device. + * + * This function allows user to assign a port platform device back. This is + * a mandatory step after disable SRIOV support. + * + * Return: 0 on success, negative error code otherwise. + */ +int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id) +{ + struct platform_device *port_pdev; + int ret = -ENODEV; + + mutex_lock(&cdev->lock); + port_pdev = __dfl_fpga_cdev_find_port(cdev, &port_id, + dfl_fpga_check_port_id); + if (!port_pdev) + goto unlock_exit; + + if (device_is_registered(&port_pdev->dev)) { + ret = -EBUSY; + goto put_dev_exit; + } + + ret = platform_device_add(port_pdev); + if (ret) + goto put_dev_exit; + + dfl_feature_dev_use_end(dev_get_platdata(&port_pdev->dev)); + cdev->released_port_num--; +put_dev_exit: + put_device(&port_pdev->dev); +unlock_exit: + mutex_unlock(&cdev->lock); + return ret; +} +EXPORT_SYMBOL_GPL(dfl_fpga_cdev_assign_port); + +static void config_port_access_mode(struct device *fme_dev, int port_id, + bool is_vf) +{ + void __iomem *base; + u64 v; + + base = dfl_get_feature_ioaddr_by_id(fme_dev, FME_FEATURE_ID_HEADER); + + v = readq(base + FME_HDR_PORT_OFST(port_id)); + + v &= ~FME_PORT_OFST_ACC_CTRL; + v |= FIELD_PREP(FME_PORT_OFST_ACC_CTRL, + is_vf ? FME_PORT_OFST_ACC_VF : FME_PORT_OFST_ACC_PF); + + writeq(v, base + FME_HDR_PORT_OFST(port_id)); +} + +#define config_port_vf_mode(dev, id) config_port_access_mode(dev, id, true) +#define config_port_pf_mode(dev, id) config_port_access_mode(dev, id, false) + +/** + * dfl_fpga_cdev_config_ports_pf - configure ports to PF access mode + * + * @cdev: parent container device. + * + * This function is needed in sriov configuration routine. It could be used to + * configure the all released ports from VF access mode to PF. + */ +void dfl_fpga_cdev_config_ports_pf(struct dfl_fpga_cdev *cdev) +{ + struct dfl_feature_platform_data *pdata; + + mutex_lock(&cdev->lock); + list_for_each_entry(pdata, &cdev->port_dev_list, node) { + if (device_is_registered(&pdata->dev->dev)) + continue; + + config_port_pf_mode(cdev->fme_dev, pdata->id); + } + mutex_unlock(&cdev->lock); +} +EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_pf); + +/** + * dfl_fpga_cdev_config_ports_vf - configure ports to VF access mode + * + * @cdev: parent container device. + * @num_vfs: VF device number. + * + * This function is needed in sriov configuration routine. It could be used to + * configure the released ports from PF access mode to VF. + * + * Return: 0 on success, negative error code otherwise. + */ +int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vfs) +{ + struct dfl_feature_platform_data *pdata; + int ret = 0; + + mutex_lock(&cdev->lock); + /* + * can't turn multiple ports into 1 VF device, only 1 port for 1 VF + * device, so if released port number doesn't match VF device number, + * then reject the request with -EINVAL error code. + */ + if (cdev->released_port_num != num_vfs) { + ret = -EINVAL; + goto done; + } + + list_for_each_entry(pdata, &cdev->port_dev_list, node) { + if (device_is_registered(&pdata->dev->dev)) + continue; + + config_port_vf_mode(cdev->fme_dev, pdata->id); + } +done: + mutex_unlock(&cdev->lock); + return ret; +} +EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_vf); + static void __exit dfl_fpga_exit(void) { dfl_chardev_uinit(); diff --git a/drivers/fpga/dfl.h b/drivers/fpga/dfl.h index a8b869e9e5b79f6d19d41d2600d4c239c7234499..9f0e656de720e08c11678383acdf92fdc02e8e70 100644 --- a/drivers/fpga/dfl.h +++ b/drivers/fpga/dfl.h @@ -30,8 +30,8 @@ /* plus one for fme device */ #define MAX_DFL_FEATURE_DEV_NUM (MAX_DFL_FPGA_PORT_NUM + 1) -/* Reserved 0x0 for Header Group Register and 0xff for AFU */ -#define FEATURE_ID_FIU_HEADER 0x0 +/* Reserved 0xfe for Header Group Register and 0xff for AFU */ +#define FEATURE_ID_FIU_HEADER 0xfe #define FEATURE_ID_AFU 0xff #define FME_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER @@ -119,6 +119,11 @@ #define PORT_HDR_NEXT_AFU NEXT_AFU #define PORT_HDR_CAP 0x30 #define PORT_HDR_CTRL 0x38 +#define PORT_HDR_STS 0x40 +#define PORT_HDR_USRCLK_CMD0 0x50 +#define PORT_HDR_USRCLK_CMD1 0x58 +#define PORT_HDR_USRCLK_STS0 0x60 +#define PORT_HDR_USRCLK_STS1 0x68 /* Port Capability Register Bitfield */ #define PORT_CAP_PORT_NUM GENMASK_ULL(1, 0) /* ID of this port */ @@ -130,6 +135,16 @@ /* Latency tolerance reporting. '1' >= 40us, '0' < 40us.*/ #define PORT_CTRL_LATENCY BIT_ULL(2) #define PORT_CTRL_SFTRST_ACK BIT_ULL(4) /* HW ack for reset */ + +/* Port Status Register Bitfield */ +#define PORT_STS_AP2_EVT BIT_ULL(13) /* AP2 event detected */ +#define PORT_STS_AP1_EVT BIT_ULL(12) /* AP1 event detected */ +#define PORT_STS_PWR_STATE GENMASK_ULL(11, 8) /* AFU power states */ +#define PORT_STS_PWR_STATE_NORM 0 +#define PORT_STS_PWR_STATE_AP1 1 /* 50% throttling */ +#define PORT_STS_PWR_STATE_AP2 2 /* 90% throttling */ +#define PORT_STS_PWR_STATE_AP6 6 /* 100% throttling */ + /** * struct dfl_fpga_port_ops - port ops * @@ -154,13 +169,22 @@ void dfl_fpga_port_ops_put(struct dfl_fpga_port_ops *ops); int dfl_fpga_check_port_id(struct platform_device *pdev, void *pport_id); /** - * struct dfl_feature_driver - sub feature's driver + * struct dfl_feature_id - dfl private feature id * - * @id: sub feature id. - * @ops: ops of this sub feature. + * @id: unique dfl private feature id. */ -struct dfl_feature_driver { +struct dfl_feature_id { u64 id; +}; + +/** + * struct dfl_feature_driver - dfl private feature driver + * + * @id_table: id_table for dfl private features supported by this driver. + * @ops: ops of this dfl private feature driver. + */ +struct dfl_feature_driver { + const struct dfl_feature_id *id_table; const struct dfl_feature_ops *ops; }; @@ -183,6 +207,8 @@ struct dfl_feature { #define DEV_STATUS_IN_USE 0 +#define FEATURE_DEV_ID_UNUSED (-1) + /** * struct dfl_feature_platform_data - platform data for feature devices * @@ -191,6 +217,7 @@ struct dfl_feature { * @cdev: cdev of feature dev. * @dev: ptr to platform device linked with this platform data. * @dfl_cdev: ptr to container device. + * @id: id used for this feature device. * @disable_count: count for port disable. * @num: number for sub features. * @dev_status: dev status (e.g. DEV_STATUS_IN_USE). @@ -203,6 +230,7 @@ struct dfl_feature_platform_data { struct cdev cdev; struct platform_device *dev; struct dfl_fpga_cdev *dfl_cdev; + int id; unsigned int disable_count; unsigned long dev_status; void *private; @@ -331,6 +359,11 @@ static inline bool dfl_feature_is_port(void __iomem *base) (FIELD_GET(DFH_ID, v) == DFH_ID_FIU_PORT); } +static inline u8 dfl_feature_revision(void __iomem *base) +{ + return (u8)FIELD_GET(DFH_REVISION, readq(base + DFH)); +} + /** * struct dfl_fpga_enum_info - DFL FPGA enumeration information * @@ -373,6 +406,7 @@ void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info); * @fme_dev: FME feature device under this container device. * @lock: mutex lock to protect the port device list. * @port_dev_list: list of all port feature devices under this container device. + * @released_port_num: released port number under this container device. */ struct dfl_fpga_cdev { struct device *parent; @@ -380,6 +414,7 @@ struct dfl_fpga_cdev { struct device *fme_dev; struct mutex lock; struct list_head port_dev_list; + int released_port_num; }; struct dfl_fpga_cdev * @@ -407,4 +442,9 @@ dfl_fpga_cdev_find_port(struct dfl_fpga_cdev *cdev, void *data, return pdev; } + +int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id); +int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id); +void dfl_fpga_cdev_config_ports_pf(struct dfl_fpga_cdev *cdev); +int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vf); #endif /* __FPGA_DFL_H */ diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c index 80bd8f1b2aa60fc06b8f132898105fab9c14c939..4bab9028940a812cebf6dfbf0ad17785042c4287 100644 --- a/drivers/fpga/fpga-bridge.c +++ b/drivers/fpga/fpga-bridge.c @@ -19,11 +19,6 @@ static struct class *fpga_bridge_class; /* Lock for adding/removing bridges to linked lists*/ static spinlock_t bridge_list_lock; -static int fpga_bridge_of_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - /** * fpga_bridge_enable - Enable transactions on the bridge * @@ -104,8 +99,7 @@ struct fpga_bridge *of_fpga_bridge_get(struct device_node *np, { struct device *dev; - dev = class_find_device(fpga_bridge_class, NULL, np, - fpga_bridge_of_node_match); + dev = class_find_device_by_of_node(fpga_bridge_class, np); if (!dev) return ERR_PTR(-ENODEV); diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index c3866816456abee4159af6eafe1d0ab107c69a22..e05104f5e40c6a492608644478bdec2ff150c461 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -482,11 +482,6 @@ struct fpga_manager *fpga_mgr_get(struct device *dev) } EXPORT_SYMBOL_GPL(fpga_mgr_get); -static int fpga_mgr_of_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - /** * of_fpga_mgr_get - Given a device node, get a reference to a fpga mgr. * @@ -498,8 +493,7 @@ struct fpga_manager *of_fpga_mgr_get(struct device_node *node) { struct device *dev; - dev = class_find_device(fpga_mgr_class, NULL, node, - fpga_mgr_of_node_match); + dev = class_find_device_by_of_node(fpga_mgr_class, node); if (!dev) return ERR_PTR(-ENODEV); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index bb13c266c32968be8bd0864ddd2cf00266d910e7..38e096e6925fa65dfbd95e84bf9081feeba43cd0 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -275,7 +275,7 @@ config GPIO_ICH config GPIO_IOP tristate "Intel IOP GPIO" - depends on ARCH_IOP32X || ARCH_IOP33X || COMPILE_TEST + depends on ARCH_IOP32X || COMPILE_TEST select GPIO_GENERIC help Say yes here to support the GPIO functionality of a number of Intel @@ -288,7 +288,7 @@ config GPIO_IXP4XX depends on ARM # For depends on ARCH_IXP4XX select GPIO_GENERIC - select IRQ_DOMAIN + select GPIOLIB_IRQCHIP select IRQ_DOMAIN_HIERARCHY help Say yes here to support the GPIO functionality of a number of Intel @@ -311,6 +311,13 @@ config GPIO_LPC18XX Select this option to enable GPIO driver for NXP LPC18XX/43XX devices. +config GPIO_LPC32XX + tristate "NXP LPC32XX GPIO support" + depends on OF_GPIO && (ARCH_LPC32XX || COMPILE_TEST) + help + Select this option to enable GPIO driver for + NXP LPC32XX devices. + config GPIO_LYNXPOINT tristate "Intel Lynxpoint GPIO support" depends on ACPI && X86 @@ -539,6 +546,7 @@ config GPIO_THUNDERX tristate "Cavium ThunderX/OCTEON-TX GPIO" depends on ARCH_THUNDER || (64BIT && COMPILE_TEST) depends on PCI_MSI + select GPIOLIB_IRQCHIP select IRQ_DOMAIN_HIERARCHY select IRQ_FASTEOI_HIERARCHY_HANDLERS help @@ -1445,6 +1453,15 @@ config GPIO_XRA1403 help GPIO driver for EXAR XRA1403 16-bit SPI-based GPIO expander. +config GPIO_MOXTET + tristate "Turris Mox Moxtet bus GPIO expander" + depends on MOXTET + help + Say yes here if you are building for the Turris Mox router. + This is the driver needed for configuring the GPIOs via the Moxtet + bus. For example the Mox module with SFP cage needs this driver + so that phylink can use corresponding GPIOs. + endmenu menu "USB GPIO expanders" @@ -1465,7 +1482,6 @@ endmenu config GPIO_MOCKUP tristate "GPIO Testing Driver" - depends on GPIOLIB select IRQ_SIM help This enables GPIO Testing driver, which provides a way to test GPIO diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index a4e91175c70805508d2bfe90c567102264bb59ca..d2fd19c15bae3fbad7b7f7ce2fbf2ca9f1429efb 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -67,14 +67,13 @@ obj-$(CONFIG_GPIO_IT87) += gpio-it87.o obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o -obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o obj-$(CONFIG_GPIO_LP87565) += gpio-lp87565.o obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o -obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o +obj-$(CONFIG_GPIO_LPC32XX) += gpio-lpc32xx.o obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o obj-$(CONFIG_GPIO_MADERA) += gpio-madera.o obj-$(CONFIG_GPIO_MAX3191X) += gpio-max3191x.o @@ -93,6 +92,7 @@ obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o obj-$(CONFIG_GPIO_MLXBF) += gpio-mlxbf.o obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o +obj-$(CONFIG_GPIO_MOXTET) += gpio-moxtet.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index c07fad975049d5fe935ad5b0b3ce49ad4275c052..5640efe5e75049a3c3b44f759126dd5bab740181 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -142,7 +142,7 @@ static const struct gpio_chip template_chip = { static int arizona_gpio_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); - struct arizona_pdata *pdata = dev_get_platdata(arizona->dev); + struct arizona_pdata *pdata = &arizona->pdata; struct arizona_gpio *arizona_gpio; int ret; @@ -177,7 +177,7 @@ static int arizona_gpio_probe(struct platform_device *pdev) return -EINVAL; } - if (pdata && pdata->gpio_base) + if (pdata->gpio_base) arizona_gpio->gpio_chip.base = pdata->gpio_base; else arizona_gpio->gpio_chip.base = -1; diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index 13d80bfbc3b6b47cec33ffcb07c4ff6a74d3c0ce..09e53c5f3b0a462170c0d83195bb8ea34097d409 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -52,6 +52,7 @@ struct aspeed_gpio_config { */ struct aspeed_gpio { struct gpio_chip chip; + struct irq_chip irqc; spinlock_t lock; void __iomem *base; int irq; @@ -661,12 +662,14 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc) struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct irq_chip *ic = irq_desc_get_chip(desc); struct aspeed_gpio *data = gpiochip_get_data(gc); - unsigned int i, p, girq; + unsigned int i, p, girq, banks; unsigned long reg; + struct aspeed_gpio *gpio = gpiochip_get_data(gc); chained_irq_enter(ic, desc); - for (i = 0; i < ARRAY_SIZE(aspeed_gpio_banks); i++) { + banks = DIV_ROUND_UP(gpio->chip.ngpio, 32); + for (i = 0; i < banks; i++) { const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; reg = ioread32(bank_reg(data, bank, reg_irq_status)); @@ -681,16 +684,11 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(ic, desc); } -static struct irq_chip aspeed_gpio_irqchip = { - .name = "aspeed-gpio", - .irq_ack = aspeed_gpio_irq_ack, - .irq_mask = aspeed_gpio_irq_mask, - .irq_unmask = aspeed_gpio_irq_unmask, - .irq_set_type = aspeed_gpio_set_type, -}; - -static void set_irq_valid_mask(struct aspeed_gpio *gpio) +static void aspeed_init_irq_valid_mask(struct gpio_chip *gc, + unsigned long *valid_mask, + unsigned int ngpios) { + struct aspeed_gpio *gpio = gpiochip_get_data(gc); const struct aspeed_bank_props *props = gpio->config->props; while (!is_bank_props_sentinel(props)) { @@ -701,42 +699,16 @@ static void set_irq_valid_mask(struct aspeed_gpio *gpio) for_each_clear_bit(offset, &input, 32) { unsigned int i = props->bank * 32 + offset; - if (i >= gpio->config->nr_gpios) + if (i >= gpio->chip.ngpio) break; - clear_bit(i, gpio->chip.irq.valid_mask); + clear_bit(i, valid_mask); } props++; } } -static int aspeed_gpio_setup_irqs(struct aspeed_gpio *gpio, - struct platform_device *pdev) -{ - int rc; - - rc = platform_get_irq(pdev, 0); - if (rc < 0) - return rc; - - gpio->irq = rc; - - set_irq_valid_mask(gpio); - - rc = gpiochip_irqchip_add(&gpio->chip, &aspeed_gpio_irqchip, - 0, handle_bad_irq, IRQ_TYPE_NONE); - if (rc) { - dev_info(&pdev->dev, "Could not add irqchip\n"); - return rc; - } - - gpiochip_set_chained_irqchip(&gpio->chip, &aspeed_gpio_irqchip, - gpio->irq, aspeed_gpio_irq_handler); - - return 0; -} - static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip, unsigned int offset, bool enable) { @@ -1040,10 +1012,10 @@ int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc, unsigned long flags; if (!gpio->cf_copro_bankmap) - gpio->cf_copro_bankmap = kzalloc(gpio->config->nr_gpios >> 3, GFP_KERNEL); + gpio->cf_copro_bankmap = kzalloc(gpio->chip.ngpio >> 3, GFP_KERNEL); if (!gpio->cf_copro_bankmap) return -ENOMEM; - if (offset < 0 || offset > gpio->config->nr_gpios) + if (offset < 0 || offset > gpio->chip.ngpio) return -EINVAL; bindex = offset >> 3; @@ -1088,7 +1060,7 @@ int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc) if (!gpio->cf_copro_bankmap) return -ENXIO; - if (offset < 0 || offset > gpio->config->nr_gpios) + if (offset < 0 || offset > gpio->chip.ngpio) return -EINVAL; bindex = offset >> 3; @@ -1141,9 +1113,25 @@ static const struct aspeed_gpio_config ast2500_config = /* 232 for simplicity, actual number is 228 (4-GPIO hole in GPIOAB) */ { .nr_gpios = 232, .props = ast2500_bank_props, }; +static const struct aspeed_bank_props ast2600_bank_props[] = { + /* input output */ + {5, 0xffffffff, 0x0000ffff}, /* U/V/W/X */ + {6, 0xffff0000, 0x0fff0000}, /* Y/Z */ + { }, +}; + +static const struct aspeed_gpio_config ast2600_config = + /* + * ast2600 has two controllers one with 208 GPIOs and one with 36 GPIOs. + * We expect ngpio being set in the device tree and this is a fallback + * option. + */ + { .nr_gpios = 208, .props = ast2600_bank_props, }; + static const struct of_device_id aspeed_gpio_of_table[] = { { .compatible = "aspeed,ast2400-gpio", .data = &ast2400_config, }, { .compatible = "aspeed,ast2500-gpio", .data = &ast2500_config, }, + { .compatible = "aspeed,ast2600-gpio", .data = &ast2600_config, }, {} }; MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table); @@ -1152,7 +1140,8 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) { const struct of_device_id *gpio_id; struct aspeed_gpio *gpio; - int rc, i, banks; + int rc, i, banks, err; + u32 ngpio; gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); if (!gpio) @@ -1178,7 +1167,10 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) gpio->config = gpio_id->data; gpio->chip.parent = &pdev->dev; - gpio->chip.ngpio = gpio->config->nr_gpios; + err = of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpio); + gpio->chip.ngpio = (u16) ngpio; + if (err) + gpio->chip.ngpio = gpio->config->nr_gpios; gpio->chip.direction_input = aspeed_gpio_dir_in; gpio->chip.direction_output = aspeed_gpio_dir_out; gpio->chip.get_direction = aspeed_gpio_get_direction; @@ -1189,10 +1181,9 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) gpio->chip.set_config = aspeed_gpio_set_config; gpio->chip.label = dev_name(&pdev->dev); gpio->chip.base = -1; - gpio->chip.irq.need_valid_mask = true; /* Allocate a cache of the output registers */ - banks = gpio->config->nr_gpios >> 5; + banks = DIV_ROUND_UP(gpio->chip.ngpio, 32); gpio->dcache = devm_kcalloc(&pdev->dev, banks, sizeof(u32), GFP_KERNEL); if (!gpio->dcache) @@ -1212,16 +1203,42 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) aspeed_gpio_change_cmd_source(gpio, bank, 3, GPIO_CMDSRC_ARM); } - rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); - if (rc < 0) - return rc; + /* Optionally set up an irqchip if there is an IRQ */ + rc = platform_get_irq(pdev, 0); + if (rc > 0) { + struct gpio_irq_chip *girq; + + gpio->irq = rc; + girq = &gpio->chip.irq; + girq->chip = &gpio->irqc; + girq->chip->name = dev_name(&pdev->dev); + girq->chip->irq_ack = aspeed_gpio_irq_ack; + girq->chip->irq_mask = aspeed_gpio_irq_mask; + girq->chip->irq_unmask = aspeed_gpio_irq_unmask; + girq->chip->irq_set_type = aspeed_gpio_set_type; + girq->parent_handler = aspeed_gpio_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, 1, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = gpio->irq; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + girq->init_valid_mask = aspeed_init_irq_valid_mask; + } gpio->offset_timer = devm_kzalloc(&pdev->dev, gpio->chip.ngpio, GFP_KERNEL); if (!gpio->offset_timer) return -ENOMEM; - return aspeed_gpio_setup_irqs(gpio, pdev); + rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); + if (rc < 0) + return rc; + + return 0; } static struct platform_driver aspeed_gpio_driver = { diff --git a/drivers/gpio/gpio-bd70528.c b/drivers/gpio/gpio-bd70528.c index fd85605d2dabbf802b6b1a0c7c2b24a5ffedea54..0c1ead12d8839036382392a8d8f35c4131646fd2 100644 --- a/drivers/gpio/gpio-bd70528.c +++ b/drivers/gpio/gpio-bd70528.c @@ -36,7 +36,7 @@ static int bd70528_set_debounce(struct bd70528_gpio *bdgpio, break; default: dev_err(bdgpio->chip.dev, - "Invalid debouce value %u\n", debounce); + "Invalid debounce value %u\n", debounce); return -EINVAL; } return regmap_update_bits(bdgpio->chip.regmap, GPIO_IN_REG(offset), @@ -153,7 +153,7 @@ static int bd70528_gpio_get_i(struct bd70528_gpio *bdgpio, unsigned int offset) static int bd70528_gpio_get(struct gpio_chip *chip, unsigned int offset) { - int ret = -EINVAL; + int ret; struct bd70528_gpio *bdgpio = gpiochip_get_data(chip); /* diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index af936dcca6596f2e60fb66f5615ff80210e1905d..05e3f99ae59cfba62ee1dd2f91aac538ea406ab2 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -636,10 +636,8 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) if (of_property_read_bool(np, "interrupt-controller")) { priv->parent_irq = platform_get_irq(pdev, 0); - if (priv->parent_irq <= 0) { - dev_err(dev, "Couldn't get IRQ"); + if (priv->parent_irq <= 0) return -ENOENT; - } } else { priv->parent_irq = -ENOENT; } diff --git a/drivers/gpio/gpio-cadence.c b/drivers/gpio/gpio-cadence.c index 712ae212b0b4eb65b35403e56eb8072e28b27c0d..a4d3239d25944dd772a7d1d75498331d7acce3d6 100644 --- a/drivers/gpio/gpio-cadence.c +++ b/drivers/gpio/gpio-cadence.c @@ -214,27 +214,33 @@ static int cdns_gpio_probe(struct platform_device *pdev) goto err_revert_dir; } - ret = devm_gpiochip_add_data(&pdev->dev, &cgpio->gc, cgpio); - if (ret < 0) { - dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); - goto err_disable_clk; - } - /* - * irq_chip support + * Optional irq_chip support */ irq = platform_get_irq(pdev, 0); if (irq >= 0) { - ret = gpiochip_irqchip_add(&cgpio->gc, &cdns_gpio_irqchip, - 0, handle_level_irq, - IRQ_TYPE_NONE); - if (ret) { - dev_err(&pdev->dev, "Could not add irqchip, %d\n", - ret); + struct gpio_irq_chip *girq; + + girq = &cgpio->gc.irq; + girq->chip = &cdns_gpio_irqchip; + girq->parent_handler = cdns_gpio_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, 1, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) { + ret = -ENOMEM; goto err_disable_clk; } - gpiochip_set_chained_irqchip(&cgpio->gc, &cdns_gpio_irqchip, - irq, cdns_gpio_irq_handler); + girq->parents[0] = irq; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_level_irq; + } + + ret = devm_gpiochip_add_data(&pdev->dev, &cgpio->gc, cgpio); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); + goto err_disable_clk; } cgpio->bypass_orig = ioread32(cgpio->regs + CDNS_GPIO_BYPASS_MODE); diff --git a/drivers/gpio/gpio-creg-snps.c b/drivers/gpio/gpio-creg-snps.c index 8cbc94d0d424ea682f6056c4804bea24690f7537..ff19a8ad5663a2bd3dd76b9a10a4dcb0aa54cd33 100644 --- a/drivers/gpio/gpio-creg-snps.c +++ b/drivers/gpio/gpio-creg-snps.c @@ -137,7 +137,6 @@ static int creg_gpio_probe(struct platform_device *pdev) const struct of_device_id *match; struct device *dev = &pdev->dev; struct creg_gpio *hcg; - struct resource *mem; u32 ngpios; int ret; @@ -145,8 +144,7 @@ static int creg_gpio_probe(struct platform_device *pdev) if (!hcg) return -ENOMEM; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcg->regs = devm_ioremap_resource(dev, mem); + hcg->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(hcg->regs)) return PTR_ERR(hcg->regs); diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 3108be5e208cf65106506124a3e4cc55eb69ea74..92e127e74813438847a97924e36197d26176d6da 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -27,6 +27,7 @@ #include #include "gpiolib.h" +#include "gpiolib-acpi.h" #define GPIO_SWPORTA_DR 0x00 #define GPIO_SWPORTA_DDR 0x04 diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c index 7b9ac4a12c20be762b17b3d30d0cf62f7d94afdd..fe7a73f52329b7b2b40d0cfcdf8df37623e992e3 100644 --- a/drivers/gpio/gpio-eic-sprd.c +++ b/drivers/gpio/gpio-eic-sprd.c @@ -584,10 +584,8 @@ static int sprd_eic_probe(struct platform_device *pdev) sprd_eic->type = pdata->type; sprd_eic->irq = platform_get_irq(pdev, 0); - if (sprd_eic->irq < 0) { - dev_err(&pdev->dev, "Failed to get EIC interrupt.\n"); + if (sprd_eic->irq < 0) return sprd_eic->irq; - } for (i = 0; i < SPRD_EIC_MAX_BANK; i++) { /* diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index a87951293aaac50f72dc9ea2cbb86e2851a79847..620f25b7efb402c1133d952cde8f5e558b95d626 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -272,11 +272,12 @@ static int em_gio_probe(struct platform_device *pdev) struct resource *io[2], *irq[2]; struct gpio_chip *gpio_chip; struct irq_chip *irq_chip; - const char *name = dev_name(&pdev->dev); + struct device *dev = &pdev->dev; + const char *name = dev_name(dev); unsigned int ngpios; int ret; - p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); + p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); if (!p) return -ENOMEM; @@ -290,27 +291,27 @@ static int em_gio_probe(struct platform_device *pdev) irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1); if (!io[0] || !io[1] || !irq[0] || !irq[1]) { - dev_err(&pdev->dev, "missing IRQ or IOMEM\n"); + dev_err(dev, "missing IRQ or IOMEM\n"); return -EINVAL; } - p->base0 = devm_ioremap_nocache(&pdev->dev, io[0]->start, + p->base0 = devm_ioremap_nocache(dev, io[0]->start, resource_size(io[0])); if (!p->base0) return -ENOMEM; - p->base1 = devm_ioremap_nocache(&pdev->dev, io[1]->start, + p->base1 = devm_ioremap_nocache(dev, io[1]->start, resource_size(io[1])); if (!p->base1) return -ENOMEM; - if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) { - dev_err(&pdev->dev, "Missing ngpios OF property\n"); + if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) { + dev_err(dev, "Missing ngpios OF property\n"); return -EINVAL; } gpio_chip = &p->gpio_chip; - gpio_chip->of_node = pdev->dev.of_node; + gpio_chip->of_node = dev->of_node; gpio_chip->direction_input = em_gio_direction_input; gpio_chip->get = em_gio_get; gpio_chip->direction_output = em_gio_direction_output; @@ -319,7 +320,7 @@ static int em_gio_probe(struct platform_device *pdev) gpio_chip->request = em_gio_request; gpio_chip->free = em_gio_free; gpio_chip->label = name; - gpio_chip->parent = &pdev->dev; + gpio_chip->parent = dev; gpio_chip->owner = THIS_MODULE; gpio_chip->base = -1; gpio_chip->ngpio = ngpios; @@ -333,33 +334,33 @@ static int em_gio_probe(struct platform_device *pdev) irq_chip->irq_release_resources = em_gio_irq_relres; irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; - p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, ngpios, 0, + p->irq_domain = irq_domain_add_simple(dev->of_node, ngpios, 0, &em_gio_irq_domain_ops, p); if (!p->irq_domain) { - dev_err(&pdev->dev, "cannot initialize irq domain\n"); + dev_err(dev, "cannot initialize irq domain\n"); return -ENXIO; } - ret = devm_add_action_or_reset(&pdev->dev, em_gio_irq_domain_remove, + ret = devm_add_action_or_reset(dev, em_gio_irq_domain_remove, p->irq_domain); if (ret) return ret; - if (devm_request_irq(&pdev->dev, irq[0]->start, + if (devm_request_irq(dev, irq[0]->start, em_gio_irq_handler, 0, name, p)) { - dev_err(&pdev->dev, "failed to request low IRQ\n"); + dev_err(dev, "failed to request low IRQ\n"); return -ENOENT; } - if (devm_request_irq(&pdev->dev, irq[1]->start, + if (devm_request_irq(dev, irq[1]->start, em_gio_irq_handler, 0, name, p)) { - dev_err(&pdev->dev, "failed to request high IRQ\n"); + dev_err(dev, "failed to request high IRQ\n"); return -ENOENT; } - ret = devm_gpiochip_add_data(&pdev->dev, gpio_chip, p); + ret = devm_gpiochip_add_data(dev, gpio_chip, p); if (ret) { - dev_err(&pdev->dev, "failed to add GPIO controller\n"); + dev_err(dev, "failed to add GPIO controller\n"); return ret; } diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index a90870a60c1518e726d98cb292a3d542dcf7fa0c..226da8df6f1000ce41afd2666d6e0118fbc64b45 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -269,56 +269,6 @@ static struct irq_chip ep93xx_gpio_irq_chip = { .irq_set_type = ep93xx_gpio_irq_type, }; -static int ep93xx_gpio_init_irq(struct platform_device *pdev, - struct ep93xx_gpio *epg) -{ - int ab_parent_irq = platform_get_irq(pdev, 0); - struct device *dev = &pdev->dev; - int gpio_irq; - int ret; - int i; - - /* The A bank */ - ret = gpiochip_irqchip_add(&epg->gc[0], &ep93xx_gpio_irq_chip, - 64, handle_level_irq, - IRQ_TYPE_NONE); - if (ret) { - dev_err(dev, "Could not add irqchip 0\n"); - return ret; - } - gpiochip_set_chained_irqchip(&epg->gc[0], &ep93xx_gpio_irq_chip, - ab_parent_irq, - ep93xx_gpio_ab_irq_handler); - - /* The B bank */ - ret = gpiochip_irqchip_add(&epg->gc[1], &ep93xx_gpio_irq_chip, - 72, handle_level_irq, - IRQ_TYPE_NONE); - if (ret) { - dev_err(dev, "Could not add irqchip 1\n"); - return ret; - } - gpiochip_set_chained_irqchip(&epg->gc[1], &ep93xx_gpio_irq_chip, - ab_parent_irq, - ep93xx_gpio_ab_irq_handler); - - /* The F bank */ - for (i = 0; i < 8; i++) { - gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i; - irq_set_chip_data(gpio_irq, &epg->gc[5]); - irq_set_chip_and_handler(gpio_irq, &ep93xx_gpio_irq_chip, - handle_level_irq); - irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST); - } - - for (i = 1; i <= 8; i++) - irq_set_chained_handler_and_data(platform_get_irq(pdev, i), - ep93xx_gpio_f_irq_handler, - &epg->gc[i]); - return 0; -} - - /************************************************************************* * gpiolib interface for EP93xx on-chip GPIOs *************************************************************************/ @@ -328,26 +278,33 @@ struct ep93xx_gpio_bank { int dir; int base; bool has_irq; + bool has_hierarchical_irq; + unsigned int irq_base; }; -#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _has_irq) \ +#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _has_irq, _has_hier, _irq_base) \ { \ .label = _label, \ .data = _data, \ .dir = _dir, \ .base = _base, \ .has_irq = _has_irq, \ + .has_hierarchical_irq = _has_hier, \ + .irq_base = _irq_base, \ } static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = { - EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true), /* Bank A has 8 IRQs */ - EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true), /* Bank B has 8 IRQs */ - EP93XX_GPIO_BANK("C", 0x08, 0x18, 40, false), - EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24, false), - EP93XX_GPIO_BANK("E", 0x20, 0x24, 32, false), - EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, true), /* Bank F has 8 IRQs */ - EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48, false), - EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false), + /* Bank A has 8 IRQs */ + EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true, false, 64), + /* Bank B has 8 IRQs */ + EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true, false, 72), + EP93XX_GPIO_BANK("C", 0x08, 0x18, 40, false, false, 0), + EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24, false, false, 0), + EP93XX_GPIO_BANK("E", 0x20, 0x24, 32, false, false, 0), + /* Bank F has 8 IRQs */ + EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, false, true, 0), + EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48, false, false, 0), + EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false, false, 0), }; static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset, @@ -369,12 +326,15 @@ static int ep93xx_gpio_f_to_irq(struct gpio_chip *gc, unsigned offset) return EP93XX_GPIO_F_IRQ_BASE + offset; } -static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev, +static int ep93xx_gpio_add_bank(struct gpio_chip *gc, + struct platform_device *pdev, struct ep93xx_gpio *epg, struct ep93xx_gpio_bank *bank) { void __iomem *data = epg->base + bank->data; void __iomem *dir = epg->base + bank->dir; + struct device *dev = &pdev->dev; + struct gpio_irq_chip *girq; int err; err = bgpio_init(gc, dev, 1, data, NULL, NULL, dir, NULL, 0); @@ -384,8 +344,59 @@ static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev, gc->label = bank->label; gc->base = bank->base; - if (bank->has_irq) + girq = &gc->irq; + if (bank->has_irq || bank->has_hierarchical_irq) { gc->set_config = ep93xx_gpio_set_config; + girq->chip = &ep93xx_gpio_irq_chip; + } + + if (bank->has_irq) { + int ab_parent_irq = platform_get_irq(pdev, 0); + + girq->parent_handler = ep93xx_gpio_ab_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(dev, 1, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_level_irq; + girq->parents[0] = ab_parent_irq; + girq->first = bank->irq_base; + } + + /* Only bank F has especially funky IRQ handling */ + if (bank->has_hierarchical_irq) { + int gpio_irq; + int i; + + /* + * FIXME: convert this to use hierarchical IRQ support! + * this requires fixing the root irqchip to be hierarchial. + */ + girq->parent_handler = ep93xx_gpio_f_irq_handler; + girq->num_parents = 8; + girq->parents = devm_kcalloc(dev, 8, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + /* Pick resources 1..8 for these IRQs */ + for (i = 1; i <= 8; i++) + girq->parents[i - 1] = platform_get_irq(pdev, i); + for (i = 0; i < 8; i++) { + gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i; + irq_set_chip_data(gpio_irq, &epg->gc[5]); + irq_set_chip_and_handler(gpio_irq, + &ep93xx_gpio_irq_chip, + handle_level_irq); + irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST); + } + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_level_irq; + gc->to_irq = ep93xx_gpio_f_to_irq; + } return devm_gpiochip_add_data(dev, gc, epg); } @@ -407,16 +418,11 @@ static int ep93xx_gpio_probe(struct platform_device *pdev) struct gpio_chip *gc = &epg->gc[i]; struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i]; - if (ep93xx_gpio_add_bank(gc, &pdev->dev, epg, bank)) + if (ep93xx_gpio_add_bank(gc, pdev, epg, bank)) dev_warn(&pdev->dev, "Unable to add gpio bank %s\n", bank->label); - /* Only bank F has especially funky IRQ handling */ - if (i == 5) - gc->to_irq = ep93xx_gpio_f_to_irq; } - ep93xx_gpio_init_irq(pdev, epg); - return 0; } diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c index 250e71f3e68825833bca14c5b04116618be997a6..fbddb166242874d3669ed83ba6cddc2dec225be8 100644 --- a/drivers/gpio/gpio-ftgpio010.c +++ b/drivers/gpio/gpio-ftgpio010.c @@ -290,16 +290,14 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) girq->num_parents = 1; girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents), GFP_KERNEL); - if (!girq->parents) - return -ENOMEM; + if (!girq->parents) { + ret = -ENOMEM; + goto dis_clk; + } girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_bad_irq; girq->parents[0] = irq; - ret = devm_gpiochip_add_data(dev, &g->gc, g); - if (ret) - goto dis_clk; - /* Disable, unmask and clear all interrupts */ writel(0x0, g->base + GPIO_INT_EN); writel(0x0, g->base + GPIO_INT_MASK); @@ -308,6 +306,10 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) /* Clear any use of debounce */ writel(0x0, g->base + GPIO_DEBOUNCE_EN); + ret = devm_gpiochip_add_data(dev, &g->gc, g); + if (ret) + goto dis_clk; + platform_set_drvdata(pdev, g); dev_info(dev, "FTGPIO010 @%p registered\n", g->base); diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 0937b605e134276882ec58f99a2cc9001f60e715..08234e64993a951879d21bfc22b8f3debe1a1e74 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -408,8 +408,6 @@ static int grgpio_probe(struct platform_device *ofdev) * Continue without irq functionality for that * gpio line */ - dev_err(priv->dev, - "Failed to get irq for offset %d\n", i); continue; } priv->uirqs[lirq->index].uirq = ret; diff --git a/drivers/gpio/gpio-hlwd.c b/drivers/gpio/gpio-hlwd.c index e5fa00f8145f3e41eba8f48f851d832b42d88ac8..4a17599f6d44d23db22eb18d6ef9c5a409c10706 100644 --- a/drivers/gpio/gpio-hlwd.c +++ b/drivers/gpio/gpio-hlwd.c @@ -244,43 +244,45 @@ static int hlwd_gpio_probe(struct platform_device *pdev) ngpios = 32; hlwd->gpioc.ngpio = ngpios; - res = devm_gpiochip_add_data(&pdev->dev, &hlwd->gpioc, hlwd); - if (res) - return res; - /* Mask and ack all interrupts */ iowrite32be(0, hlwd->regs + HW_GPIOB_INTMASK); iowrite32be(0xffffffff, hlwd->regs + HW_GPIOB_INTFLAG); /* * If this GPIO controller is not marked as an interrupt controller in - * the DT, return. + * the DT, skip interrupt support. */ - if (!of_property_read_bool(pdev->dev.of_node, "interrupt-controller")) - return 0; - - hlwd->irq = platform_get_irq(pdev, 0); - if (hlwd->irq < 0) { - dev_info(&pdev->dev, "platform_get_irq returned %d\n", - hlwd->irq); - return hlwd->irq; + if (of_property_read_bool(pdev->dev.of_node, "interrupt-controller")) { + struct gpio_irq_chip *girq; + + hlwd->irq = platform_get_irq(pdev, 0); + if (hlwd->irq < 0) { + dev_info(&pdev->dev, "platform_get_irq returned %d\n", + hlwd->irq); + return hlwd->irq; + } + + hlwd->irqc.name = dev_name(&pdev->dev); + hlwd->irqc.irq_mask = hlwd_gpio_irq_mask; + hlwd->irqc.irq_unmask = hlwd_gpio_irq_unmask; + hlwd->irqc.irq_enable = hlwd_gpio_irq_enable; + hlwd->irqc.irq_set_type = hlwd_gpio_irq_set_type; + + girq = &hlwd->gpioc.irq; + girq->chip = &hlwd->irqc; + girq->parent_handler = hlwd_gpio_irqhandler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, 1, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = hlwd->irq; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_level_irq; } - hlwd->irqc.name = dev_name(&pdev->dev); - hlwd->irqc.irq_mask = hlwd_gpio_irq_mask; - hlwd->irqc.irq_unmask = hlwd_gpio_irq_unmask; - hlwd->irqc.irq_enable = hlwd_gpio_irq_enable; - hlwd->irqc.irq_set_type = hlwd_gpio_irq_set_type; - - res = gpiochip_irqchip_add(&hlwd->gpioc, &hlwd->irqc, 0, - handle_level_irq, IRQ_TYPE_NONE); - if (res) - return res; - - gpiochip_set_chained_irqchip(&hlwd->gpioc, &hlwd->irqc, - hlwd->irq, hlwd_gpio_irqhandler); - - return 0; + return devm_gpiochip_add_data(&pdev->dev, &hlwd->gpioc, hlwd); } static const struct of_device_id hlwd_gpio_match[] = { diff --git a/drivers/gpio/gpio-htc-egpio.c b/drivers/gpio/gpio-htc-egpio.c index 9d3ac51a765c1405b4fe0ec68e2beec9b2dd1dfd..6eb56f7ab9c94e73dbb1aeb761511450620d105c 100644 --- a/drivers/gpio/gpio-htc-egpio.c +++ b/drivers/gpio/gpio-htc-egpio.c @@ -118,20 +118,6 @@ static void egpio_handler(struct irq_desc *desc) } } -int htc_egpio_get_wakeup_irq(struct device *dev) -{ - struct egpio_info *ei = dev_get_drvdata(dev); - - /* Read current pins. */ - u16 readval = egpio_readw(ei, ei->ack_register); - /* Ack/unmask interrupts. */ - ack_irqs(ei); - /* Return first set pin. */ - readval &= ei->irqs_enabled; - return ei->irq_start + ffs(readval) - 1; -} -EXPORT_SYMBOL(htc_egpio_get_wakeup_irq); - static inline int egpio_pos(struct egpio_info *ei, int bit) { return bit >> ei->reg_shift; diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c index 4e803baf980e63fb34820238ebd3a8ceb6c8d6d8..4d835f9089df8b95892270b7756604202123e21e 100644 --- a/drivers/gpio/gpio-intel-mid.c +++ b/drivers/gpio/gpio-intel-mid.c @@ -329,6 +329,7 @@ static int intel_gpio_probe(struct pci_dev *pdev, u32 gpio_base; u32 irq_base; int retval; + struct gpio_irq_chip *girq; struct intel_mid_gpio_ddata *ddata = (struct intel_mid_gpio_ddata *)id->driver_data; @@ -369,6 +370,22 @@ static int intel_gpio_probe(struct pci_dev *pdev, spin_lock_init(&priv->lock); + girq = &priv->chip.irq; + girq->chip = &intel_mid_irqchip; + girq->parent_handler = intel_mid_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = pdev->irq; + girq->first = irq_base; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_simple_irq; + + intel_mid_irq_init_hw(priv); + pci_set_drvdata(pdev, priv); retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); if (retval) { @@ -376,24 +393,6 @@ static int intel_gpio_probe(struct pci_dev *pdev, return retval; } - retval = gpiochip_irqchip_add(&priv->chip, - &intel_mid_irqchip, - irq_base, - handle_simple_irq, - IRQ_TYPE_NONE); - if (retval) { - dev_err(&pdev->dev, - "could not connect irqchip to gpiochip\n"); - return retval; - } - - intel_mid_irq_init_hw(priv); - - gpiochip_set_chained_irqchip(&priv->chip, - &intel_mid_irqchip, - pdev->irq, - intel_mid_irq_handler); - pm_runtime_put_noidle(&pdev->dev); pm_runtime_allow(&pdev->dev); diff --git a/drivers/gpio/gpio-ixp4xx.c b/drivers/gpio/gpio-ixp4xx.c index 670c2a85a35bffc1e01d944220058e79882b64dc..b3b050604e0be02ab165fc2a7ce6a15a66e14ad8 100644 --- a/drivers/gpio/gpio-ixp4xx.c +++ b/drivers/gpio/gpio-ixp4xx.c @@ -47,7 +47,6 @@ * @dev: containing device for this instance * @fwnode: the fwnode for this GPIO chip * @gc: gpiochip for this instance - * @domain: irqdomain for this chip instance * @base: remapped I/O-memory base * @irq_edge: Each bit represents an IRQ: 1: edge-triggered, * 0: level triggered @@ -56,48 +55,22 @@ struct ixp4xx_gpio { struct device *dev; struct fwnode_handle *fwnode; struct gpio_chip gc; - struct irq_domain *domain; void __iomem *base; unsigned long long irq_edge; }; -/** - * struct ixp4xx_gpio_map - IXP4 GPIO to parent IRQ map - * @gpio_offset: offset of the IXP4 GPIO line - * @parent_hwirq: hwirq on the parent IRQ controller - */ -struct ixp4xx_gpio_map { - int gpio_offset; - int parent_hwirq; -}; - -/* GPIO lines 0..12 have corresponding IRQs, GPIOs 13..15 have no IRQs */ -const struct ixp4xx_gpio_map ixp4xx_gpiomap[] = { - { .gpio_offset = 0, .parent_hwirq = 6 }, - { .gpio_offset = 1, .parent_hwirq = 7 }, - { .gpio_offset = 2, .parent_hwirq = 19 }, - { .gpio_offset = 3, .parent_hwirq = 20 }, - { .gpio_offset = 4, .parent_hwirq = 21 }, - { .gpio_offset = 5, .parent_hwirq = 22 }, - { .gpio_offset = 6, .parent_hwirq = 23 }, - { .gpio_offset = 7, .parent_hwirq = 24 }, - { .gpio_offset = 8, .parent_hwirq = 25 }, - { .gpio_offset = 9, .parent_hwirq = 26 }, - { .gpio_offset = 10, .parent_hwirq = 27 }, - { .gpio_offset = 11, .parent_hwirq = 28 }, - { .gpio_offset = 12, .parent_hwirq = 29 }, -}; - static void ixp4xx_gpio_irq_ack(struct irq_data *d) { - struct ixp4xx_gpio *g = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct ixp4xx_gpio *g = gpiochip_get_data(gc); __raw_writel(BIT(d->hwirq), g->base + IXP4XX_REG_GPIS); } static void ixp4xx_gpio_irq_unmask(struct irq_data *d) { - struct ixp4xx_gpio *g = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct ixp4xx_gpio *g = gpiochip_get_data(gc); /* ACK when unmasking if not edge-triggered */ if (!(g->irq_edge & BIT(d->hwirq))) @@ -108,7 +81,8 @@ static void ixp4xx_gpio_irq_unmask(struct irq_data *d) static int ixp4xx_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - struct ixp4xx_gpio *g = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct ixp4xx_gpio *g = gpiochip_get_data(gc); int line = d->hwirq; unsigned long flags; u32 int_style; @@ -187,122 +161,31 @@ static struct irq_chip ixp4xx_gpio_irqchip = { .irq_set_type = ixp4xx_gpio_irq_set_type, }; -static int ixp4xx_gpio_to_irq(struct gpio_chip *gc, unsigned int offset) +static int ixp4xx_gpio_child_to_parent_hwirq(struct gpio_chip *gc, + unsigned int child, + unsigned int child_type, + unsigned int *parent, + unsigned int *parent_type) { - struct ixp4xx_gpio *g = gpiochip_get_data(gc); - struct irq_fwspec fwspec; - - fwspec.fwnode = g->fwnode; - fwspec.param_count = 2; - fwspec.param[0] = offset; - fwspec.param[1] = IRQ_TYPE_NONE; - - return irq_create_fwspec_mapping(&fwspec); -} + /* All these interrupts are level high in the CPU */ + *parent_type = IRQ_TYPE_LEVEL_HIGH; -static int ixp4xx_gpio_irq_domain_translate(struct irq_domain *domain, - struct irq_fwspec *fwspec, - unsigned long *hwirq, - unsigned int *type) -{ - int ret; - - /* We support standard DT translation */ - if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) { - return irq_domain_translate_twocell(domain, fwspec, - hwirq, type); + /* GPIO lines 0..12 have dedicated IRQs */ + if (child == 0) { + *parent = 6; + return 0; } - - /* This goes away when we transition to DT */ - if (is_fwnode_irqchip(fwspec->fwnode)) { - ret = irq_domain_translate_twocell(domain, fwspec, - hwirq, type); - if (ret) - return ret; - WARN_ON(*type == IRQ_TYPE_NONE); + if (child == 1) { + *parent = 7; return 0; } - return -EINVAL; -} - -static int ixp4xx_gpio_irq_domain_alloc(struct irq_domain *d, - unsigned int irq, unsigned int nr_irqs, - void *data) -{ - struct ixp4xx_gpio *g = d->host_data; - irq_hw_number_t hwirq; - unsigned int type = IRQ_TYPE_NONE; - struct irq_fwspec *fwspec = data; - int ret; - int i; - - ret = ixp4xx_gpio_irq_domain_translate(d, fwspec, &hwirq, &type); - if (ret) - return ret; - - dev_dbg(g->dev, "allocate IRQ %d..%d, hwirq %lu..%lu\n", - irq, irq + nr_irqs - 1, - hwirq, hwirq + nr_irqs - 1); - - for (i = 0; i < nr_irqs; i++) { - struct irq_fwspec parent_fwspec; - const struct ixp4xx_gpio_map *map; - int j; - - /* Not all lines support IRQs */ - for (j = 0; j < ARRAY_SIZE(ixp4xx_gpiomap); j++) { - map = &ixp4xx_gpiomap[j]; - if (map->gpio_offset == hwirq) - break; - } - if (j == ARRAY_SIZE(ixp4xx_gpiomap)) { - dev_err(g->dev, "can't look up hwirq %lu\n", hwirq); - return -EINVAL; - } - dev_dbg(g->dev, "found parent hwirq %u\n", map->parent_hwirq); - - /* - * We set handle_bad_irq because the .set_type() should - * always be invoked and set the right type of handler. - */ - irq_domain_set_info(d, - irq + i, - hwirq + i, - &ixp4xx_gpio_irqchip, - g, - handle_bad_irq, - NULL, NULL); - irq_set_probe(irq + i); - - /* - * Create a IRQ fwspec to send up to the parent irqdomain: - * specify the hwirq we address on the parent and tie it - * all together up the chain. - */ - parent_fwspec.fwnode = d->parent->fwnode; - parent_fwspec.param_count = 2; - parent_fwspec.param[0] = map->parent_hwirq; - /* This parent only handles asserted level IRQs */ - parent_fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH; - dev_dbg(g->dev, "alloc_irqs_parent for %d parent hwirq %d\n", - irq + i, map->parent_hwirq); - ret = irq_domain_alloc_irqs_parent(d, irq + i, 1, - &parent_fwspec); - if (ret) - dev_err(g->dev, - "failed to allocate parent hwirq %d for hwirq %lu\n", - map->parent_hwirq, hwirq); + if (child >= 2 && child <= 12) { + *parent = child + 17; + return 0; } - - return 0; + return -EINVAL; } -static const struct irq_domain_ops ixp4xx_gpio_irqdomain_ops = { - .translate = ixp4xx_gpio_irq_domain_translate, - .alloc = ixp4xx_gpio_irq_domain_alloc, - .free = irq_domain_free_irqs_common, -}; - static int ixp4xx_gpio_probe(struct platform_device *pdev) { unsigned long flags; @@ -311,8 +194,8 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev) struct irq_domain *parent; struct resource *res; struct ixp4xx_gpio *g; + struct gpio_irq_chip *girq; int ret; - int i; g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL); if (!g) @@ -321,9 +204,36 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); g->base = devm_ioremap_resource(dev, res); - if (IS_ERR(g->base)) { - dev_err(dev, "ioremap error\n"); + if (IS_ERR(g->base)) return PTR_ERR(g->base); + + /* + * When we convert to device tree we will simply look up the + * parent irqdomain using irq_find_host(parent) as parent comes + * from IRQCHIP_DECLARE(), then use of_node_to_fwnode() to get + * the fwnode. For now we need this boardfile style code. + */ + if (np) { + struct device_node *irq_parent; + + irq_parent = of_irq_find_parent(np); + if (!irq_parent) { + dev_err(dev, "no IRQ parent node\n"); + return -ENODEV; + } + parent = irq_find_host(irq_parent); + if (!parent) { + dev_err(dev, "no IRQ parent domain\n"); + return -ENODEV; + } + g->fwnode = of_node_to_fwnode(np); + } else { + parent = ixp4xx_get_irq_domain(); + g->fwnode = irq_domain_alloc_fwnode(&res->start); + if (!g->fwnode) { + dev_err(dev, "no domain base\n"); + return -ENODEV; + } } /* @@ -360,7 +270,6 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev) dev_err(dev, "unable to init generic GPIO\n"); return ret; } - g->gc.to_irq = ixp4xx_gpio_to_irq; g->gc.ngpio = 16; g->gc.label = "IXP4XX_GPIO_CHIP"; /* @@ -372,86 +281,22 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev) g->gc.parent = &pdev->dev; g->gc.owner = THIS_MODULE; + girq = &g->gc.irq; + girq->chip = &ixp4xx_gpio_irqchip; + girq->fwnode = g->fwnode; + girq->parent_domain = parent; + girq->child_to_parent_hwirq = ixp4xx_gpio_child_to_parent_hwirq; + girq->handler = handle_bad_irq; + girq->default_type = IRQ_TYPE_NONE; + ret = devm_gpiochip_add_data(dev, &g->gc, g); if (ret) { dev_err(dev, "failed to add SoC gpiochip\n"); return ret; } - /* - * When we convert to device tree we will simply look up the - * parent irqdomain using irq_find_host(parent) as parent comes - * from IRQCHIP_DECLARE(), then use of_node_to_fwnode() to get - * the fwnode. For now we need this boardfile style code. - */ - if (np) { - struct device_node *irq_parent; - - irq_parent = of_irq_find_parent(np); - if (!irq_parent) { - dev_err(dev, "no IRQ parent node\n"); - return -ENODEV; - } - parent = irq_find_host(irq_parent); - if (!parent) { - dev_err(dev, "no IRQ parent domain\n"); - return -ENODEV; - } - g->fwnode = of_node_to_fwnode(np); - } else { - parent = ixp4xx_get_irq_domain(); - g->fwnode = irq_domain_alloc_fwnode(g->base); - if (!g->fwnode) { - dev_err(dev, "no domain base\n"); - return -ENODEV; - } - } - g->domain = irq_domain_create_hierarchy(parent, - IRQ_DOMAIN_FLAG_HIERARCHY, - ARRAY_SIZE(ixp4xx_gpiomap), - g->fwnode, - &ixp4xx_gpio_irqdomain_ops, - g); - if (!g->domain) { - irq_domain_free_fwnode(g->fwnode); - dev_err(dev, "no hierarchical irq domain\n"); - return ret; - } - - /* - * After adding OF support, this is no longer needed: irqs - * will be allocated for the respective fwnodes. - */ - if (!np) { - for (i = 0; i < ARRAY_SIZE(ixp4xx_gpiomap); i++) { - const struct ixp4xx_gpio_map *map = &ixp4xx_gpiomap[i]; - struct irq_fwspec fwspec; - - fwspec.fwnode = g->fwnode; - /* This is the hwirq for the GPIO line side of things */ - fwspec.param[0] = map->gpio_offset; - fwspec.param[1] = IRQ_TYPE_EDGE_RISING; - fwspec.param_count = 2; - ret = __irq_domain_alloc_irqs(g->domain, - -1, /* just pick something */ - 1, - NUMA_NO_NODE, - &fwspec, - false, - NULL); - if (ret < 0) { - irq_domain_free_fwnode(g->fwnode); - dev_err(dev, - "can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n", - map->gpio_offset, map->parent_hwirq, - ret); - return ret; - } - } - } - platform_set_drvdata(pdev, g); - dev_info(dev, "IXP4 GPIO @%p registered\n", g->base); + dev_info(dev, "IXP4 GPIO registered\n"); return 0; } diff --git a/drivers/gpio/gpio-ks8695.c b/drivers/gpio/gpio-ks8695.c deleted file mode 100644 index a0f87c124894a4eb32c6c9bc6808fca6b47f93bb..0000000000000000000000000000000000000000 --- a/drivers/gpio/gpio-ks8695.c +++ /dev/null @@ -1,284 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * arch/arm/mach-ks8695/gpio.c - * - * Copyright (C) 2006 Andrew Victor - * Updated to GPIOLIB, Copyright 2008 Simtec Electronics - * Daniel Silverstone - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -/* - * Configure a GPIO line for either GPIO function, or its internal - * function (Interrupt, Timer, etc). - */ -static void ks8695_gpio_mode(unsigned int pin, short gpio) -{ - unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN }; - unsigned long x, flags; - - if (pin > KS8695_GPIO_5) /* only GPIO 0..5 have internal functions */ - return; - - local_irq_save(flags); - - x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC); - if (gpio) /* GPIO: set bit to 0 */ - x &= ~enable[pin]; - else /* Internal function: set bit to 1 */ - x |= enable[pin]; - __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPC); - - local_irq_restore(flags); -} - - -static unsigned short gpio_irq[] = { KS8695_IRQ_EXTERN0, KS8695_IRQ_EXTERN1, KS8695_IRQ_EXTERN2, KS8695_IRQ_EXTERN3 }; - -/* - * Configure GPIO pin as external interrupt source. - */ -int ks8695_gpio_interrupt(unsigned int pin, unsigned int type) -{ - unsigned long x, flags; - - if (pin > KS8695_GPIO_3) /* only GPIO 0..3 can generate IRQ */ - return -EINVAL; - - local_irq_save(flags); - - /* set pin as input */ - x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM); - x &= ~IOPM(pin); - __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM); - - local_irq_restore(flags); - - /* Set IRQ triggering type */ - irq_set_irq_type(gpio_irq[pin], type); - - /* enable interrupt mode */ - ks8695_gpio_mode(pin, 0); - - return 0; -} -EXPORT_SYMBOL(ks8695_gpio_interrupt); - - - -/* .... Generic GPIO interface .............................................. */ - -/* - * Configure the GPIO line as an input. - */ -static int ks8695_gpio_direction_input(struct gpio_chip *gc, unsigned int pin) -{ - unsigned long x, flags; - - if (pin > KS8695_GPIO_15) - return -EINVAL; - - /* set pin to GPIO mode */ - ks8695_gpio_mode(pin, 1); - - local_irq_save(flags); - - /* set pin as input */ - x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM); - x &= ~IOPM(pin); - __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM); - - local_irq_restore(flags); - - return 0; -} - - -/* - * Configure the GPIO line as an output, with default state. - */ -static int ks8695_gpio_direction_output(struct gpio_chip *gc, - unsigned int pin, int state) -{ - unsigned long x, flags; - - if (pin > KS8695_GPIO_15) - return -EINVAL; - - /* set pin to GPIO mode */ - ks8695_gpio_mode(pin, 1); - - local_irq_save(flags); - - /* set line state */ - x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD); - if (state) - x |= IOPD(pin); - else - x &= ~IOPD(pin); - __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD); - - /* set pin as output */ - x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM); - x |= IOPM(pin); - __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM); - - local_irq_restore(flags); - - return 0; -} - - -/* - * Set the state of an output GPIO line. - */ -static void ks8695_gpio_set_value(struct gpio_chip *gc, - unsigned int pin, int state) -{ - unsigned long x, flags; - - if (pin > KS8695_GPIO_15) - return; - - local_irq_save(flags); - - /* set output line state */ - x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD); - if (state) - x |= IOPD(pin); - else - x &= ~IOPD(pin); - __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD); - - local_irq_restore(flags); -} - - -/* - * Read the state of a GPIO line. - */ -static int ks8695_gpio_get_value(struct gpio_chip *gc, unsigned int pin) -{ - unsigned long x; - - if (pin > KS8695_GPIO_15) - return -EINVAL; - - x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD); - return (x & IOPD(pin)) != 0; -} - - -/* - * Map GPIO line to IRQ number. - */ -static int ks8695_gpio_to_irq(struct gpio_chip *gc, unsigned int pin) -{ - if (pin > KS8695_GPIO_3) /* only GPIO 0..3 can generate IRQ */ - return -EINVAL; - - return gpio_irq[pin]; -} - -/* GPIOLIB interface */ - -static struct gpio_chip ks8695_gpio_chip = { - .label = "KS8695", - .direction_input = ks8695_gpio_direction_input, - .direction_output = ks8695_gpio_direction_output, - .get = ks8695_gpio_get_value, - .set = ks8695_gpio_set_value, - .to_irq = ks8695_gpio_to_irq, - .base = 0, - .ngpio = 16, - .can_sleep = false, -}; - -/* Register the GPIOs */ -void ks8695_register_gpios(void) -{ - if (gpiochip_add_data(&ks8695_gpio_chip, NULL)) - printk(KERN_ERR "Unable to register core GPIOs\n"); -} - -/* .... Debug interface ..................................................... */ - -#ifdef CONFIG_DEBUG_FS - -static int ks8695_gpio_show(struct seq_file *s, void *unused) -{ - unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN }; - unsigned int intmask[] = { IOPC_IOEINT0TM, IOPC_IOEINT1TM, IOPC_IOEINT2TM, IOPC_IOEINT3TM }; - unsigned long mode, ctrl, data; - int i; - - mode = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM); - ctrl = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC); - data = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD); - - seq_printf(s, "Pin\tI/O\tFunction\tState\n\n"); - - for (i = KS8695_GPIO_0; i <= KS8695_GPIO_15 ; i++) { - seq_printf(s, "%i:\t", i); - - seq_printf(s, "%s\t", (mode & IOPM(i)) ? "Output" : "Input"); - - if (i <= KS8695_GPIO_3) { - if (ctrl & enable[i]) { - seq_printf(s, "EXT%i ", i); - - switch ((ctrl & intmask[i]) >> (4 * i)) { - case IOPC_TM_LOW: - seq_printf(s, "(Low)"); break; - case IOPC_TM_HIGH: - seq_printf(s, "(High)"); break; - case IOPC_TM_RISING: - seq_printf(s, "(Rising)"); break; - case IOPC_TM_FALLING: - seq_printf(s, "(Falling)"); break; - case IOPC_TM_EDGE: - seq_printf(s, "(Edges)"); break; - } - } else - seq_printf(s, "GPIO\t"); - } else if (i <= KS8695_GPIO_5) { - if (ctrl & enable[i]) - seq_printf(s, "TOUT%i\t", i - KS8695_GPIO_4); - else - seq_printf(s, "GPIO\t"); - } else { - seq_printf(s, "GPIO\t"); - } - - seq_printf(s, "\t"); - - seq_printf(s, "%i\n", (data & IOPD(i)) ? 1 : 0); - } - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ks8695_gpio); - -static int __init ks8695_gpio_debugfs_init(void) -{ - /* /sys/kernel/debug/ks8695_gpio */ - debugfs_create_file("ks8695_gpio", S_IFREG | S_IRUGO, NULL, NULL, - &ks8695_gpio_fops); - return 0; -} -postcore_initcall(ks8695_gpio_debugfs_init); - -#endif diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 24885b3db3d504d203b5985a694175603eab82a1..4e626c4235c2e161f704ebe39902d2753bd9c9f5 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -16,36 +16,33 @@ #include #include -#include -#include - -#define LPC32XX_GPIO_P3_INP_STATE _GPREG(0x000) -#define LPC32XX_GPIO_P3_OUTP_SET _GPREG(0x004) -#define LPC32XX_GPIO_P3_OUTP_CLR _GPREG(0x008) -#define LPC32XX_GPIO_P3_OUTP_STATE _GPREG(0x00C) -#define LPC32XX_GPIO_P2_DIR_SET _GPREG(0x010) -#define LPC32XX_GPIO_P2_DIR_CLR _GPREG(0x014) -#define LPC32XX_GPIO_P2_DIR_STATE _GPREG(0x018) -#define LPC32XX_GPIO_P2_INP_STATE _GPREG(0x01C) -#define LPC32XX_GPIO_P2_OUTP_SET _GPREG(0x020) -#define LPC32XX_GPIO_P2_OUTP_CLR _GPREG(0x024) -#define LPC32XX_GPIO_P2_MUX_SET _GPREG(0x028) -#define LPC32XX_GPIO_P2_MUX_CLR _GPREG(0x02C) -#define LPC32XX_GPIO_P2_MUX_STATE _GPREG(0x030) -#define LPC32XX_GPIO_P0_INP_STATE _GPREG(0x040) -#define LPC32XX_GPIO_P0_OUTP_SET _GPREG(0x044) -#define LPC32XX_GPIO_P0_OUTP_CLR _GPREG(0x048) -#define LPC32XX_GPIO_P0_OUTP_STATE _GPREG(0x04C) -#define LPC32XX_GPIO_P0_DIR_SET _GPREG(0x050) -#define LPC32XX_GPIO_P0_DIR_CLR _GPREG(0x054) -#define LPC32XX_GPIO_P0_DIR_STATE _GPREG(0x058) -#define LPC32XX_GPIO_P1_INP_STATE _GPREG(0x060) -#define LPC32XX_GPIO_P1_OUTP_SET _GPREG(0x064) -#define LPC32XX_GPIO_P1_OUTP_CLR _GPREG(0x068) -#define LPC32XX_GPIO_P1_OUTP_STATE _GPREG(0x06C) -#define LPC32XX_GPIO_P1_DIR_SET _GPREG(0x070) -#define LPC32XX_GPIO_P1_DIR_CLR _GPREG(0x074) -#define LPC32XX_GPIO_P1_DIR_STATE _GPREG(0x078) +#define LPC32XX_GPIO_P3_INP_STATE (0x000) +#define LPC32XX_GPIO_P3_OUTP_SET (0x004) +#define LPC32XX_GPIO_P3_OUTP_CLR (0x008) +#define LPC32XX_GPIO_P3_OUTP_STATE (0x00C) +#define LPC32XX_GPIO_P2_DIR_SET (0x010) +#define LPC32XX_GPIO_P2_DIR_CLR (0x014) +#define LPC32XX_GPIO_P2_DIR_STATE (0x018) +#define LPC32XX_GPIO_P2_INP_STATE (0x01C) +#define LPC32XX_GPIO_P2_OUTP_SET (0x020) +#define LPC32XX_GPIO_P2_OUTP_CLR (0x024) +#define LPC32XX_GPIO_P2_MUX_SET (0x028) +#define LPC32XX_GPIO_P2_MUX_CLR (0x02C) +#define LPC32XX_GPIO_P2_MUX_STATE (0x030) +#define LPC32XX_GPIO_P0_INP_STATE (0x040) +#define LPC32XX_GPIO_P0_OUTP_SET (0x044) +#define LPC32XX_GPIO_P0_OUTP_CLR (0x048) +#define LPC32XX_GPIO_P0_OUTP_STATE (0x04C) +#define LPC32XX_GPIO_P0_DIR_SET (0x050) +#define LPC32XX_GPIO_P0_DIR_CLR (0x054) +#define LPC32XX_GPIO_P0_DIR_STATE (0x058) +#define LPC32XX_GPIO_P1_INP_STATE (0x060) +#define LPC32XX_GPIO_P1_OUTP_SET (0x064) +#define LPC32XX_GPIO_P1_OUTP_CLR (0x068) +#define LPC32XX_GPIO_P1_OUTP_STATE (0x06C) +#define LPC32XX_GPIO_P1_DIR_SET (0x070) +#define LPC32XX_GPIO_P1_DIR_CLR (0x074) +#define LPC32XX_GPIO_P1_DIR_STATE (0x078) #define GPIO012_PIN_TO_BIT(x) (1 << (x)) #define GPIO3_PIN_TO_BIT(x) (1 << ((x) + 25)) @@ -72,12 +69,12 @@ #define LPC32XX_GPO_P3_GRP (LPC32XX_GPI_P3_GRP + LPC32XX_GPI_P3_MAX) struct gpio_regs { - void __iomem *inp_state; - void __iomem *outp_state; - void __iomem *outp_set; - void __iomem *outp_clr; - void __iomem *dir_set; - void __iomem *dir_clr; + unsigned long inp_state; + unsigned long outp_state; + unsigned long outp_set; + unsigned long outp_clr; + unsigned long dir_set; + unsigned long dir_clr; }; /* @@ -165,16 +162,27 @@ static struct gpio_regs gpio_grp_regs_p3 = { struct lpc32xx_gpio_chip { struct gpio_chip chip; struct gpio_regs *gpio_grp; + void __iomem *reg_base; }; +static inline u32 gpreg_read(struct lpc32xx_gpio_chip *group, unsigned long offset) +{ + return __raw_readl(group->reg_base + offset); +} + +static inline void gpreg_write(struct lpc32xx_gpio_chip *group, u32 val, unsigned long offset) +{ + __raw_writel(val, group->reg_base + offset); +} + static void __set_gpio_dir_p012(struct lpc32xx_gpio_chip *group, unsigned pin, int input) { if (input) - __raw_writel(GPIO012_PIN_TO_BIT(pin), + gpreg_write(group, GPIO012_PIN_TO_BIT(pin), group->gpio_grp->dir_clr); else - __raw_writel(GPIO012_PIN_TO_BIT(pin), + gpreg_write(group, GPIO012_PIN_TO_BIT(pin), group->gpio_grp->dir_set); } @@ -184,19 +192,19 @@ static void __set_gpio_dir_p3(struct lpc32xx_gpio_chip *group, u32 u = GPIO3_PIN_TO_BIT(pin); if (input) - __raw_writel(u, group->gpio_grp->dir_clr); + gpreg_write(group, u, group->gpio_grp->dir_clr); else - __raw_writel(u, group->gpio_grp->dir_set); + gpreg_write(group, u, group->gpio_grp->dir_set); } static void __set_gpio_level_p012(struct lpc32xx_gpio_chip *group, unsigned pin, int high) { if (high) - __raw_writel(GPIO012_PIN_TO_BIT(pin), + gpreg_write(group, GPIO012_PIN_TO_BIT(pin), group->gpio_grp->outp_set); else - __raw_writel(GPIO012_PIN_TO_BIT(pin), + gpreg_write(group, GPIO012_PIN_TO_BIT(pin), group->gpio_grp->outp_clr); } @@ -206,31 +214,31 @@ static void __set_gpio_level_p3(struct lpc32xx_gpio_chip *group, u32 u = GPIO3_PIN_TO_BIT(pin); if (high) - __raw_writel(u, group->gpio_grp->outp_set); + gpreg_write(group, u, group->gpio_grp->outp_set); else - __raw_writel(u, group->gpio_grp->outp_clr); + gpreg_write(group, u, group->gpio_grp->outp_clr); } static void __set_gpo_level_p3(struct lpc32xx_gpio_chip *group, unsigned pin, int high) { if (high) - __raw_writel(GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_set); + gpreg_write(group, GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_set); else - __raw_writel(GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_clr); + gpreg_write(group, GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_clr); } static int __get_gpio_state_p012(struct lpc32xx_gpio_chip *group, unsigned pin) { - return GPIO012_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state), + return GPIO012_PIN_IN_SEL(gpreg_read(group, group->gpio_grp->inp_state), pin); } static int __get_gpio_state_p3(struct lpc32xx_gpio_chip *group, unsigned pin) { - int state = __raw_readl(group->gpio_grp->inp_state); + int state = gpreg_read(group, group->gpio_grp->inp_state); /* * P3 GPIO pin input mapping is not contiguous, GPIOP3-0..4 is mapped @@ -242,13 +250,13 @@ static int __get_gpio_state_p3(struct lpc32xx_gpio_chip *group, static int __get_gpi_state_p3(struct lpc32xx_gpio_chip *group, unsigned pin) { - return GPI3_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state), pin); + return GPI3_PIN_IN_SEL(gpreg_read(group, group->gpio_grp->inp_state), pin); } static int __get_gpo_state_p3(struct lpc32xx_gpio_chip *group, unsigned pin) { - return GPO3_PIN_IN_SEL(__raw_readl(group->gpio_grp->outp_state), pin); + return GPO3_PIN_IN_SEL(gpreg_read(group, group->gpio_grp->outp_state), pin); } /* @@ -497,12 +505,18 @@ static int lpc32xx_of_xlate(struct gpio_chip *gc, static int lpc32xx_gpio_probe(struct platform_device *pdev) { int i; + void __iomem *reg_base; + + reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg_base)) + return PTR_ERR(reg_base); for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++) { if (pdev->dev.of_node) { lpc32xx_gpiochip[i].chip.of_xlate = lpc32xx_of_xlate; lpc32xx_gpiochip[i].chip.of_gpio_n_cells = 3; lpc32xx_gpiochip[i].chip.of_node = pdev->dev.of_node; + lpc32xx_gpiochip[i].reg_base = reg_base; } devm_gpiochip_add_data(&pdev->dev, &lpc32xx_gpiochip[i].chip, &lpc32xx_gpiochip[i]); @@ -527,3 +541,7 @@ static struct platform_driver lpc32xx_gpio_driver = { }; module_platform_driver(lpc32xx_gpio_driver); + +MODULE_AUTHOR("Kevin Wells "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIO driver for LPC32xx SoC"); diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index 31b4a091ab60aeded67e06607020006e0d49092d..6bb9741ad036affb084a47937dfaa73a5f691b37 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -358,25 +358,30 @@ static int lp_gpio_probe(struct platform_device *pdev) gc->can_sleep = false; gc->parent = dev; - ret = devm_gpiochip_add_data(dev, gc, lg); - if (ret) { - dev_err(dev, "failed adding lp-gpio chip\n"); - return ret; - } - /* set up interrupts */ if (irq_rc && irq_rc->start) { + struct gpio_irq_chip *girq; + + girq = &gc->irq; + girq->chip = &lp_irqchip; + girq->parent_handler = lp_gpio_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = (unsigned)irq_rc->start; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_simple_irq; + lp_gpio_irq_init_hw(lg); - ret = gpiochip_irqchip_add(gc, &lp_irqchip, 0, - handle_simple_irq, IRQ_TYPE_NONE); - if (ret) { - dev_err(dev, "failed to add irqchip\n"); - return ret; - } + } - gpiochip_set_chained_irqchip(gc, &lp_irqchip, - (unsigned)irq_rc->start, - lp_gpio_irq_handler); + ret = devm_gpiochip_add_data(dev, gc, lg); + if (ret) { + dev_err(dev, "failed adding lp-gpio chip\n"); + return ret; } pm_runtime_enable(dev); diff --git a/drivers/gpio/gpio-madera.c b/drivers/gpio/gpio-madera.c index 4dbc837d12155446bd977982d6de35eedd5a56d6..7086f8b5388fd712dc7c8198a7f1fe83fc280a4b 100644 --- a/drivers/gpio/gpio-madera.c +++ b/drivers/gpio/gpio-madera.c @@ -120,7 +120,7 @@ static const struct gpio_chip madera_gpio_chip = { static int madera_gpio_probe(struct platform_device *pdev) { struct madera *madera = dev_get_drvdata(pdev->dev.parent); - struct madera_pdata *pdata = dev_get_platdata(madera->dev); + struct madera_pdata *pdata = &madera->pdata; struct madera_gpio *madera_gpio; int ret; @@ -136,6 +136,9 @@ static int madera_gpio_probe(struct platform_device *pdev) madera_gpio->gpio_chip.parent = pdev->dev.parent; switch (madera->type) { + case CS47L15: + madera_gpio->gpio_chip.ngpio = CS47L15_NUM_GPIOS; + break; case CS47L35: madera_gpio->gpio_chip.ngpio = CS47L35_NUM_GPIOS; break; @@ -147,13 +150,18 @@ static int madera_gpio_probe(struct platform_device *pdev) case CS47L91: madera_gpio->gpio_chip.ngpio = CS47L90_NUM_GPIOS; break; + case CS42L92: + case CS47L92: + case CS47L93: + madera_gpio->gpio_chip.ngpio = CS47L92_NUM_GPIOS; + break; default: dev_err(&pdev->dev, "Unknown chip variant %d\n", madera->type); return -EINVAL; } /* We want to be usable on systems that don't use devicetree or acpi */ - if (pdata && pdata->gpio_base) + if (pdata->gpio_base) madera_gpio->gpio_chip.base = pdata->gpio_base; else madera_gpio->gpio_chip.base = -1; diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c index b7d89e30131e2db1bc541bd4fa4b30c32cafe422..47d05e357e61a05b742fd75d892fa3d3e5506af0 100644 --- a/drivers/gpio/gpio-max77620.c +++ b/drivers/gpio/gpio-max77620.c @@ -270,10 +270,8 @@ static int max77620_gpio_probe(struct platform_device *pdev) int ret; gpio_irq = platform_get_irq(pdev, 0); - if (gpio_irq <= 0) { - dev_err(&pdev->dev, "GPIO irq not available %d\n", gpio_irq); + if (gpio_irq <= 0) return -ENODEV; - } mgpio = devm_kzalloc(&pdev->dev, sizeof(*mgpio), GFP_KERNEL); if (!mgpio) diff --git a/drivers/gpio/gpio-max77650.c b/drivers/gpio/gpio-max77650.c index 3f03f4e8956c0b04d34873950a5825479fd5ada2..3075f2513c6f08981c4d4de772d19029d52248af 100644 --- a/drivers/gpio/gpio-max77650.c +++ b/drivers/gpio/gpio-max77650.c @@ -188,3 +188,4 @@ module_platform_driver(max77650_gpio_driver); MODULE_DESCRIPTION("MAXIM 77650/77651 GPIO driver"); MODULE_AUTHOR("Bartosz Golaszewski "); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:max77650-gpio"); diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c index 8f466993cd241cfbda0effba3b10efed3a991768..501e89548f533bb796589a2bcaeeccc9d19bfc32 100644 --- a/drivers/gpio/gpio-mb86s7x.c +++ b/drivers/gpio/gpio-mb86s7x.c @@ -21,6 +21,7 @@ #include #include "gpiolib.h" +#include "gpiolib-acpi.h" /* * Only first 8bits of a register correspond to each pin, diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 3302125e5265110722d131c7979a8a5d4da0e081..4f27ddfe1e2f07363cec6ab7d20d65f819be61f1 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -397,6 +397,7 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id { const struct mrfld_gpio_pinrange *range; const char *pinctrl_dev_name; + struct gpio_irq_chip *girq; struct mrfld_gpio *priv; u32 gpio_base, irq_base; void __iomem *base; @@ -444,6 +445,21 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id raw_spin_lock_init(&priv->lock); + girq = &priv->chip.irq; + girq->chip = &mrfld_irqchip; + girq->parent_handler = mrfld_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = pdev->irq; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + + mrfld_irq_init_hw(priv); + pci_set_drvdata(pdev, priv); retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); if (retval) { @@ -465,18 +481,6 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id } } - retval = gpiochip_irqchip_add(&priv->chip, &mrfld_irqchip, irq_base, - handle_bad_irq, IRQ_TYPE_NONE); - if (retval) { - dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n"); - return retval; - } - - mrfld_irq_init_hw(priv); - - gpiochip_set_chained_irqchip(&priv->chip, &mrfld_irqchip, pdev->irq, - mrfld_irq_handler); - return 0; } diff --git a/drivers/gpio/gpio-moxtet.c b/drivers/gpio/gpio-moxtet.c new file mode 100644 index 0000000000000000000000000000000000000000..3fd729994a3878eb844a84a62180321f5cd441b1 --- /dev/null +++ b/drivers/gpio/gpio-moxtet.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Turris Mox Moxtet GPIO expander + * + * Copyright (C) 2018 Marek Behun + */ + +#include +#include +#include +#include + +#define MOXTET_GPIO_NGPIOS 12 +#define MOXTET_GPIO_INPUTS 4 + +struct moxtet_gpio_desc { + u16 in_mask; + u16 out_mask; +}; + +static const struct moxtet_gpio_desc descs[] = { + [TURRIS_MOX_MODULE_SFP] = { + .in_mask = GENMASK(2, 0), + .out_mask = GENMASK(5, 4), + }, +}; + +struct moxtet_gpio_chip { + struct device *dev; + struct gpio_chip gpio_chip; + const struct moxtet_gpio_desc *desc; +}; + +static int moxtet_gpio_get_value(struct gpio_chip *gc, unsigned int offset) +{ + struct moxtet_gpio_chip *chip = gpiochip_get_data(gc); + int ret; + + if (chip->desc->in_mask & BIT(offset)) { + ret = moxtet_device_read(chip->dev); + } else if (chip->desc->out_mask & BIT(offset)) { + ret = moxtet_device_written(chip->dev); + if (ret >= 0) + ret <<= MOXTET_GPIO_INPUTS; + } else { + return -EINVAL; + } + + if (ret < 0) + return ret; + + return !!(ret & BIT(offset)); +} + +static void moxtet_gpio_set_value(struct gpio_chip *gc, unsigned int offset, + int val) +{ + struct moxtet_gpio_chip *chip = gpiochip_get_data(gc); + int state; + + state = moxtet_device_written(chip->dev); + if (state < 0) + return; + + offset -= MOXTET_GPIO_INPUTS; + + if (val) + state |= BIT(offset); + else + state &= ~BIT(offset); + + moxtet_device_write(chip->dev, state); +} + +static int moxtet_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + struct moxtet_gpio_chip *chip = gpiochip_get_data(gc); + + /* All lines are hard wired to be either input or output, not both. */ + if (chip->desc->in_mask & BIT(offset)) + return 1; + else if (chip->desc->out_mask & BIT(offset)) + return 0; + else + return -EINVAL; +} + +static int moxtet_gpio_direction_input(struct gpio_chip *gc, + unsigned int offset) +{ + struct moxtet_gpio_chip *chip = gpiochip_get_data(gc); + + if (chip->desc->in_mask & BIT(offset)) + return 0; + else if (chip->desc->out_mask & BIT(offset)) + return -ENOTSUPP; + else + return -EINVAL; +} + +static int moxtet_gpio_direction_output(struct gpio_chip *gc, + unsigned int offset, int val) +{ + struct moxtet_gpio_chip *chip = gpiochip_get_data(gc); + + if (chip->desc->out_mask & BIT(offset)) + moxtet_gpio_set_value(gc, offset, val); + else if (chip->desc->in_mask & BIT(offset)) + return -ENOTSUPP; + else + return -EINVAL; + + return 0; +} + +static int moxtet_gpio_probe(struct device *dev) +{ + struct moxtet_gpio_chip *chip; + struct device_node *nc = dev->of_node; + int id; + + id = to_moxtet_device(dev)->id; + + if (id >= ARRAY_SIZE(descs)) { + dev_err(dev, "%pOF Moxtet device id 0x%x is not supported by gpio-moxtet driver\n", + nc, id); + return -ENOTSUPP; + } + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->dev = dev; + chip->gpio_chip.parent = dev; + chip->desc = &descs[id]; + + dev_set_drvdata(dev, chip); + + chip->gpio_chip.label = dev_name(dev); + chip->gpio_chip.get_direction = moxtet_gpio_get_direction; + chip->gpio_chip.direction_input = moxtet_gpio_direction_input; + chip->gpio_chip.direction_output = moxtet_gpio_direction_output; + chip->gpio_chip.get = moxtet_gpio_get_value; + chip->gpio_chip.set = moxtet_gpio_set_value; + chip->gpio_chip.base = -1; + + chip->gpio_chip.ngpio = MOXTET_GPIO_NGPIOS; + + chip->gpio_chip.can_sleep = true; + chip->gpio_chip.owner = THIS_MODULE; + + return devm_gpiochip_add_data(dev, &chip->gpio_chip, chip); +} + +static const struct of_device_id moxtet_gpio_dt_ids[] = { + { .compatible = "cznic,moxtet-gpio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, moxtet_gpio_dt_ids); + +static const enum turris_mox_module_id moxtet_gpio_module_table[] = { + TURRIS_MOX_MODULE_SFP, + 0, +}; + +static struct moxtet_driver moxtet_gpio_driver = { + .driver = { + .name = "moxtet-gpio", + .of_match_table = moxtet_gpio_dt_ids, + .probe = moxtet_gpio_probe, + }, + .id_table = moxtet_gpio_module_table, +}; +module_moxtet_driver(moxtet_gpio_driver); + +MODULE_AUTHOR("Marek Behun "); +MODULE_DESCRIPTION("Turris Mox Moxtet GPIO expander"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index c8673a5d941223c0b27e3a4062f2d7685e0ed178..16a47de29c94c43bbcbceb0063510e77a50df753 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -32,6 +32,7 @@ #define GPIO_IMR 0x10 #define GPIO_ICR 0x14 #define GPIO_ICR2 0x18 +#define GPIO_IBE 0x18 struct mpc8xxx_gpio_chip { struct gpio_chip gc; @@ -45,6 +46,27 @@ struct mpc8xxx_gpio_chip { unsigned int irqn; }; +/* The GPIO Input Buffer Enable register(GPIO_IBE) is used to + * control the input enable of each individual GPIO port. + * When an individual GPIO port’s direction is set to + * input (GPIO_GPDIR[DRn=0]), the associated input enable must be + * set (GPIOxGPIE[IEn]=1) to propagate the port value to the GPIO + * Data Register. + */ +static int ls1028a_gpio_dir_in_init(struct gpio_chip *gc) +{ + unsigned long flags; + struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc); + + spin_lock_irqsave(&gc->bgpio_lock, flags); + + gc->write_reg(mpc8xxx_gc->regs + GPIO_IBE, 0xffffffff); + + spin_unlock_irqrestore(&gc->bgpio_lock, flags); + + return 0; +} + /* * This hardware has a big endian bit assignment such that GPIO line 0 is * connected to bit 31, line 1 to bit 30 ... line 31 to bit 0. @@ -261,6 +283,7 @@ static const struct irq_domain_ops mpc8xxx_gpio_irq_ops = { }; struct mpc8xxx_gpio_devtype { + int (*gpio_dir_in_init)(struct gpio_chip *chip); int (*gpio_dir_out)(struct gpio_chip *, unsigned int, int); int (*gpio_get)(struct gpio_chip *, unsigned int); int (*irq_set_type)(struct irq_data *, unsigned int); @@ -271,6 +294,10 @@ static const struct mpc8xxx_gpio_devtype mpc512x_gpio_devtype = { .irq_set_type = mpc512x_irq_set_type, }; +static const struct mpc8xxx_gpio_devtype ls1028a_gpio_devtype = { + .gpio_dir_in_init = ls1028a_gpio_dir_in_init, +}; + static const struct mpc8xxx_gpio_devtype mpc5125_gpio_devtype = { .gpio_dir_out = mpc5125_gpio_dir_out, .irq_set_type = mpc512x_irq_set_type, @@ -291,6 +318,8 @@ static const struct of_device_id mpc8xxx_gpio_ids[] = { { .compatible = "fsl,mpc5121-gpio", .data = &mpc512x_gpio_devtype, }, { .compatible = "fsl,mpc5125-gpio", .data = &mpc5125_gpio_devtype, }, { .compatible = "fsl,pq3-gpio", }, + { .compatible = "fsl,ls1028a-gpio", .data = &ls1028a_gpio_devtype, }, + { .compatible = "fsl,ls1088a-gpio", .data = &ls1028a_gpio_devtype, }, { .compatible = "fsl,qoriq-gpio", }, {} }; @@ -376,6 +405,9 @@ static int mpc8xxx_probe(struct platform_device *pdev) /* ack and mask all irqs */ gc->write_reg(mpc8xxx_gc->regs + GPIO_IER, 0xffffffff); gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR, 0); + /* enable input buffer */ + if (devtype->gpio_dir_in_init) + devtype->gpio_dir_in_init(gc); irq_set_chained_handler_and_data(mpc8xxx_gc->irqn, mpc8xxx_gpio_irq_cascade, mpc8xxx_gc); diff --git a/drivers/gpio/gpio-mt7621.c b/drivers/gpio/gpio-mt7621.c index 79654fb2e50f2d55c73bce8e029345aa7a77f79c..d1d785f983a79164af6d8d05d4cc968a78355068 100644 --- a/drivers/gpio/gpio-mt7621.c +++ b/drivers/gpio/gpio-mt7621.c @@ -241,13 +241,6 @@ mediatek_gpio_bank_probe(struct device *dev, if (!rg->chip.label) return -ENOMEM; - ret = devm_gpiochip_add_data(dev, &rg->chip, mtk); - if (ret < 0) { - dev_err(dev, "Could not register gpio %d, ret=%d\n", - rg->chip.ngpio, ret); - return ret; - } - rg->irq_chip.name = dev_name(dev); rg->irq_chip.parent_device = dev; rg->irq_chip.irq_unmask = mediatek_gpio_irq_unmask; @@ -256,8 +249,10 @@ mediatek_gpio_bank_probe(struct device *dev, rg->irq_chip.irq_set_type = mediatek_gpio_irq_type; if (mtk->gpio_irq) { + struct gpio_irq_chip *girq; + /* - * Manually request the irq here instead of passing + * Directly request the irq here instead of passing * a flow-handler to gpiochip_set_chained_irqchip, * because the irq is shared. */ @@ -271,15 +266,21 @@ mediatek_gpio_bank_probe(struct device *dev, return ret; } - ret = gpiochip_irqchip_add(&rg->chip, &rg->irq_chip, - 0, handle_simple_irq, IRQ_TYPE_NONE); - if (ret) { - dev_err(dev, "failed to add gpiochip_irqchip\n"); - return ret; - } + girq = &rg->chip.irq; + girq->chip = &rg->irq_chip; + /* This will let us handle the parent IRQ in the driver */ + girq->parent_handler = NULL; + girq->num_parents = 0; + girq->parents = NULL; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_simple_irq; + } - gpiochip_set_chained_irqchip(&rg->chip, &rg->irq_chip, - mtk->gpio_irq, NULL); + ret = devm_gpiochip_add_data(dev, &rg->chip, mtk); + if (ret < 0) { + dev_err(dev, "Could not register gpio %d, ret=%d\n", + rg->chip.ngpio, ret); + return ret; } /* set polarity to low for all gpios */ diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index b2813580c5825a08d7f05b45885b8798f44b17fa..7907a875586626d4592ca2d71ffedfd72131f684 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -435,12 +435,9 @@ static int mxc_gpio_probe(struct platform_device *pdev) return port->irq; /* the controller clock is optional */ - port->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(port->clk)) { - if (PTR_ERR(port->clk) == -EPROBE_DEFER) - return -EPROBE_DEFER; - port->clk = NULL; - } + port->clk = devm_clk_get_optional(&pdev->dev, NULL); + if (IS_ERR(port->clk)) + return PTR_ERR(port->clk); err = clk_prepare_enable(port->clk); if (err) { diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 48fea4c68e8d08df15ada9d917fdf295e19aeb5a..de5d1383f28da9538336a16e67a127be14f8f9a2 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -28,9 +29,9 @@ #define PCA953X_INVERT 0x02 #define PCA953X_DIRECTION 0x03 -#define REG_ADDR_MASK 0x3f -#define REG_ADDR_EXT 0x40 -#define REG_ADDR_AI 0x80 +#define REG_ADDR_MASK GENMASK(5, 0) +#define REG_ADDR_EXT BIT(6) +#define REG_ADDR_AI BIT(7) #define PCA957X_IN 0x00 #define PCA957X_INVRT 0x01 @@ -55,17 +56,17 @@ #define PCAL6524_OUT_INDCONF 0x2c #define PCAL6524_DEBOUNCE 0x2d -#define PCA_GPIO_MASK 0x00FF +#define PCA_GPIO_MASK GENMASK(7, 0) -#define PCAL_GPIO_MASK 0x1f -#define PCAL_PINCTRL_MASK 0x60 +#define PCAL_GPIO_MASK GENMASK(4, 0) +#define PCAL_PINCTRL_MASK GENMASK(6, 5) -#define PCA_INT 0x0100 -#define PCA_PCAL 0x0200 +#define PCA_INT BIT(8) +#define PCA_PCAL BIT(9) #define PCA_LATCH_INT (PCA_PCAL | PCA_INT) -#define PCA953X_TYPE 0x1000 -#define PCA957X_TYPE 0x2000 -#define PCA_TYPE_MASK 0xF000 +#define PCA953X_TYPE BIT(12) +#define PCA957X_TYPE BIT(13) +#define PCA_TYPE_MASK GENMASK(15, 12) #define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK) @@ -565,7 +566,7 @@ static void pca953x_irq_mask(struct irq_data *d) struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct pca953x_chip *chip = gpiochip_get_data(gc); - chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ)); + chip->irq_mask[d->hwirq / BANK_SZ] &= ~BIT(d->hwirq % BANK_SZ); } static void pca953x_irq_unmask(struct irq_data *d) @@ -573,7 +574,7 @@ static void pca953x_irq_unmask(struct irq_data *d) struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct pca953x_chip *chip = gpiochip_get_data(gc); - chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ); + chip->irq_mask[d->hwirq / BANK_SZ] |= BIT(d->hwirq % BANK_SZ); } static int pca953x_irq_set_wake(struct irq_data *d, unsigned int on) @@ -640,7 +641,7 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct pca953x_chip *chip = gpiochip_get_data(gc); int bank_nb = d->hwirq / BANK_SZ; - u8 mask = 1 << (d->hwirq % BANK_SZ); + u8 mask = BIT(d->hwirq % BANK_SZ); if (!(type & IRQ_TYPE_EDGE_BOTH)) { dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", @@ -665,7 +666,7 @@ static void pca953x_irq_shutdown(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct pca953x_chip *chip = gpiochip_get_data(gc); - u8 mask = 1 << (d->hwirq % BANK_SZ); + u8 mask = BIT(d->hwirq % BANK_SZ); chip->irq_trig_raise[d->hwirq / BANK_SZ] &= ~mask; chip->irq_trig_fall[d->hwirq / BANK_SZ] &= ~mask; @@ -846,12 +847,12 @@ static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert) ret = regcache_sync_region(chip->regmap, chip->regs->output, chip->regs->output + NBANK(chip)); - if (ret != 0) + if (ret) goto out; ret = regcache_sync_region(chip->regmap, chip->regs->direction, chip->regs->direction + NBANK(chip)); - if (ret != 0) + if (ret) goto out; /* set platform specific polarity inversion */ @@ -946,19 +947,15 @@ static int pca953x_probe(struct i2c_client *client, if (i2c_id) { chip->driver_data = i2c_id->driver_data; } else { - const struct acpi_device_id *acpi_id; - struct device *dev = &client->dev; - - chip->driver_data = (uintptr_t)of_device_get_match_data(dev); - if (!chip->driver_data) { - acpi_id = acpi_match_device(pca953x_acpi_ids, dev); - if (!acpi_id) { - ret = -ENODEV; - goto err_exit; - } - - chip->driver_data = acpi_id->driver_data; + const void *match; + + match = device_get_match_data(&client->dev); + if (!match) { + ret = -ENODEV; + goto err_exit; } + + chip->driver_data = (uintptr_t)match; } i2c_set_clientdata(client, chip); @@ -1038,8 +1035,7 @@ static int pca953x_remove(struct i2c_client *client) ret = pdata->teardown(client, chip->gpio_chip.base, chip->gpio_chip.ngpio, pdata->context); if (ret < 0) - dev_err(&client->dev, "%s failed, %d\n", - "teardown", ret); + dev_err(&client->dev, "teardown failed, %d\n", ret); } else { ret = 0; } @@ -1061,14 +1057,14 @@ static int pca953x_regcache_sync(struct device *dev) */ ret = regcache_sync_region(chip->regmap, chip->regs->direction, chip->regs->direction + NBANK(chip)); - if (ret != 0) { + if (ret) { dev_err(dev, "Failed to sync GPIO dir registers: %d\n", ret); return ret; } ret = regcache_sync_region(chip->regmap, chip->regs->output, chip->regs->output + NBANK(chip)); - if (ret != 0) { + if (ret) { dev_err(dev, "Failed to sync GPIO out registers: %d\n", ret); return ret; } @@ -1077,7 +1073,7 @@ static int pca953x_regcache_sync(struct device *dev) if (chip->driver_data & PCA_PCAL) { ret = regcache_sync_region(chip->regmap, PCAL953X_IN_LATCH, PCAL953X_IN_LATCH + NBANK(chip)); - if (ret != 0) { + if (ret) { dev_err(dev, "Failed to sync INT latch registers: %d\n", ret); return ret; @@ -1085,7 +1081,7 @@ static int pca953x_regcache_sync(struct device *dev) ret = regcache_sync_region(chip->regmap, PCAL953X_INT_MASK, PCAL953X_INT_MASK + NBANK(chip)); - if (ret != 0) { + if (ret) { dev_err(dev, "Failed to sync INT mask registers: %d\n", ret); return ret; @@ -1117,7 +1113,7 @@ static int pca953x_resume(struct device *dev) if (!atomic_read(&chip->wakeup_path)) { ret = regulator_enable(chip->regulator); - if (ret != 0) { + if (ret) { dev_err(dev, "Failed to enable regulator: %d\n", ret); return 0; } @@ -1130,7 +1126,7 @@ static int pca953x_resume(struct device *dev) return ret; ret = regcache_sync(chip->regmap); - if (ret != 0) { + if (ret) { dev_err(dev, "Failed to restore register map: %d\n", ret); return ret; } diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 1d99293096f27ceac6f1a45e4144fbd1fc148040..3f3d9a94b7093bda5cc4ca456b2c142efd34d8f6 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -409,8 +409,7 @@ static int pch_gpio_probe(struct pci_dev *pdev, static int __maybe_unused pch_gpio_suspend(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct pch_gpio *chip = pci_get_drvdata(pdev); + struct pch_gpio *chip = dev_get_drvdata(dev); unsigned long flags; spin_lock_irqsave(&chip->spinlock, flags); @@ -422,8 +421,7 @@ static int __maybe_unused pch_gpio_suspend(struct device *dev) static int __maybe_unused pch_gpio_resume(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct pch_gpio *chip = pci_get_drvdata(pdev); + struct pch_gpio *chip = dev_get_drvdata(dev); unsigned long flags; spin_lock_irqsave(&chip->spinlock, flags); diff --git a/drivers/gpio/gpio-pmic-eic-sprd.c b/drivers/gpio/gpio-pmic-eic-sprd.c index 24228cf79afc151ea60afebf4a426f9e94325f93..05000cace9b2415cd7cd003bcddc9109b61d226d 100644 --- a/drivers/gpio/gpio-pmic-eic-sprd.c +++ b/drivers/gpio/gpio-pmic-eic-sprd.c @@ -305,10 +305,8 @@ static int sprd_pmic_eic_probe(struct platform_device *pdev) mutex_init(&pmic_eic->buslock); pmic_eic->irq = platform_get_irq(pdev, 0); - if (pmic_eic->irq < 0) { - dev_err(&pdev->dev, "Failed to get PMIC EIC interrupt.\n"); + if (pmic_eic->irq < 0) return pmic_eic->irq; - } pmic_eic->map = dev_get_regmap(pdev->dev.parent, NULL); if (!pmic_eic->map) diff --git a/drivers/gpio/gpio-sprd.c b/drivers/gpio/gpio-sprd.c index f5c8b3a351d593cc7347cc516f8196bc3c68ac1d..d7314d39ab65ba25d00ff2d1ae00f79b679ce6e8 100644 --- a/drivers/gpio/gpio-sprd.c +++ b/drivers/gpio/gpio-sprd.c @@ -226,10 +226,8 @@ static int sprd_gpio_probe(struct platform_device *pdev) return -ENOMEM; sprd_gpio->irq = platform_get_irq(pdev, 0); - if (sprd_gpio->irq < 0) { - dev_err(&pdev->dev, "Failed to get GPIO interrupt.\n"); + if (sprd_gpio->irq < 0) return sprd_gpio->irq; - } sprd_gpio->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(sprd_gpio->base)) diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index dbf9cbe36b2bd5523db5eec8193155ef68dbb8d3..994d542daf53fca19537e17dcbae4ff1b7cbe2cc 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -429,6 +429,23 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) return IRQ_HANDLED; } +static void stmpe_init_irq_valid_mask(struct gpio_chip *gc, + unsigned long *valid_mask, + unsigned int ngpios) +{ + struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); + int i; + + if (!stmpe_gpio->norequest_mask) + return; + + /* Forbid unused lines to be mapped as IRQs */ + for (i = 0; i < sizeof(u32); i++) { + if (stmpe_gpio->norequest_mask & BIT(i)) + clear_bit(i, valid_mask); + } +} + static int stmpe_gpio_probe(struct platform_device *pdev) { struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); @@ -454,14 +471,21 @@ static int stmpe_gpio_probe(struct platform_device *pdev) stmpe_gpio->chip.parent = &pdev->dev; stmpe_gpio->chip.of_node = np; stmpe_gpio->chip.base = -1; + /* + * REVISIT: this makes sure the valid mask gets allocated and + * filled in when adding the gpio_chip, but the rest of the + * gpio_irqchip is still filled in using the old method + * in gpiochip_irqchip_add_nested() so clean this up once we + * get the gpio_irqchip to initialize while adding the + * gpio_chip also for threaded irqchips. + */ + stmpe_gpio->chip.irq.init_valid_mask = stmpe_init_irq_valid_mask; if (IS_ENABLED(CONFIG_DEBUG_FS)) stmpe_gpio->chip.dbg_show = stmpe_dbg_show; of_property_read_u32(np, "st,norequest-mask", &stmpe_gpio->norequest_mask); - if (stmpe_gpio->norequest_mask) - stmpe_gpio->chip.irq.need_valid_mask = true; irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -487,14 +511,6 @@ static int stmpe_gpio_probe(struct platform_device *pdev) dev_err(&pdev->dev, "unable to get irq: %d\n", ret); goto out_disable; } - if (stmpe_gpio->norequest_mask) { - int i; - - /* Forbid unused lines to be mapped as IRQs */ - for (i = 0; i < sizeof(u32); i++) - if (stmpe_gpio->norequest_mask & BIT(i)) - clear_bit(i, stmpe_gpio->chip.irq.valid_mask); - } ret = gpiochip_irqchip_add_nested(&stmpe_gpio->chip, &stmpe_gpio_irq_chip, 0, diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index bd1f3f775ce95ecca0c1cafb515a26f93c7ffb65..5e375186f90ef77408e7040114c81f5798154b1b 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -171,10 +171,8 @@ static int tb10x_gpio_probe(struct platform_device *pdev) struct irq_chip_generic *gc; ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(dev, "No interrupt specified.\n"); + if (ret < 0) return ret; - } tb10x_gpio->gc.to_irq = tb10x_gpio_to_irq; tb10x_gpio->irq = ret; diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 0f59161a4701d12a384379618690f4a741536911..8a01d3694b2817ebf43685b43f88e6e883c54f2a 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -624,10 +624,8 @@ static int tegra_gpio_probe(struct platform_device *pdev) for (i = 0; i < tgi->bank_count; i++) { ret = platform_get_irq(pdev, i); - if (ret < 0) { - dev_err(&pdev->dev, "Missing IRQ resource: %d\n", ret); + if (ret < 0) return ret; - } bank = &tgi->bank_info[i]; bank->bank = i; diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c index 715371b5102a5c6a8663649aa2539f709e804a26..ddad5c7ea61769446ef9d73e291ec42b6b2e7c08 100644 --- a/drivers/gpio/gpio-thunderx.c +++ b/drivers/gpio/gpio-thunderx.c @@ -53,7 +53,6 @@ struct thunderx_line { struct thunderx_gpio { struct gpio_chip chip; u8 __iomem *register_base; - struct irq_domain *irqd; struct msix_entry *msix_entries; /* per line MSI-X */ struct thunderx_line *line_entries; /* per line irq info */ raw_spinlock_t lock; @@ -283,54 +282,60 @@ static void thunderx_gpio_set_multiple(struct gpio_chip *chip, } } -static void thunderx_gpio_irq_ack(struct irq_data *data) +static void thunderx_gpio_irq_ack(struct irq_data *d) { - struct thunderx_line *txline = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct thunderx_gpio *txgpio = gpiochip_get_data(gc); writeq(GPIO_INTR_INTR, - txline->txgpio->register_base + intr_reg(txline->line)); + txgpio->register_base + intr_reg(irqd_to_hwirq(d))); } -static void thunderx_gpio_irq_mask(struct irq_data *data) +static void thunderx_gpio_irq_mask(struct irq_data *d) { - struct thunderx_line *txline = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct thunderx_gpio *txgpio = gpiochip_get_data(gc); writeq(GPIO_INTR_ENA_W1C, - txline->txgpio->register_base + intr_reg(txline->line)); + txgpio->register_base + intr_reg(irqd_to_hwirq(d))); } -static void thunderx_gpio_irq_mask_ack(struct irq_data *data) +static void thunderx_gpio_irq_mask_ack(struct irq_data *d) { - struct thunderx_line *txline = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct thunderx_gpio *txgpio = gpiochip_get_data(gc); writeq(GPIO_INTR_ENA_W1C | GPIO_INTR_INTR, - txline->txgpio->register_base + intr_reg(txline->line)); + txgpio->register_base + intr_reg(irqd_to_hwirq(d))); } -static void thunderx_gpio_irq_unmask(struct irq_data *data) +static void thunderx_gpio_irq_unmask(struct irq_data *d) { - struct thunderx_line *txline = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct thunderx_gpio *txgpio = gpiochip_get_data(gc); writeq(GPIO_INTR_ENA_W1S, - txline->txgpio->register_base + intr_reg(txline->line)); + txgpio->register_base + intr_reg(irqd_to_hwirq(d))); } -static int thunderx_gpio_irq_set_type(struct irq_data *data, +static int thunderx_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type) { - struct thunderx_line *txline = irq_data_get_irq_chip_data(data); - struct thunderx_gpio *txgpio = txline->txgpio; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct thunderx_gpio *txgpio = gpiochip_get_data(gc); + struct thunderx_line *txline = + &txgpio->line_entries[irqd_to_hwirq(d)]; u64 bit_cfg; - irqd_set_trigger_type(data, flow_type); + irqd_set_trigger_type(d, flow_type); bit_cfg = txline->fil_bits | GPIO_BIT_CFG_INT_EN; if (flow_type & IRQ_TYPE_EDGE_BOTH) { - irq_set_handler_locked(data, handle_fasteoi_ack_irq); + irq_set_handler_locked(d, handle_fasteoi_ack_irq); bit_cfg |= GPIO_BIT_CFG_INT_TYPE; } else { - irq_set_handler_locked(data, handle_fasteoi_mask_irq); + irq_set_handler_locked(d, handle_fasteoi_mask_irq); } raw_spin_lock(&txgpio->lock); @@ -359,33 +364,6 @@ static void thunderx_gpio_irq_disable(struct irq_data *data) irq_chip_disable_parent(data); } -static int thunderx_gpio_irq_request_resources(struct irq_data *data) -{ - struct thunderx_line *txline = irq_data_get_irq_chip_data(data); - struct thunderx_gpio *txgpio = txline->txgpio; - int r; - - r = gpiochip_lock_as_irq(&txgpio->chip, txline->line); - if (r) - return r; - - r = irq_chip_request_resources_parent(data); - if (r) - gpiochip_unlock_as_irq(&txgpio->chip, txline->line); - - return r; -} - -static void thunderx_gpio_irq_release_resources(struct irq_data *data) -{ - struct thunderx_line *txline = irq_data_get_irq_chip_data(data); - struct thunderx_gpio *txgpio = txline->txgpio; - - irq_chip_release_resources_parent(data); - - gpiochip_unlock_as_irq(&txgpio->chip, txline->line); -} - /* * Interrupts are chained from underlying MSI-X vectors. We have * these irq_chip functions to be able to handle level triggering @@ -402,48 +380,22 @@ static struct irq_chip thunderx_gpio_irq_chip = { .irq_unmask = thunderx_gpio_irq_unmask, .irq_eoi = irq_chip_eoi_parent, .irq_set_affinity = irq_chip_set_affinity_parent, - .irq_request_resources = thunderx_gpio_irq_request_resources, - .irq_release_resources = thunderx_gpio_irq_release_resources, .irq_set_type = thunderx_gpio_irq_set_type, .flags = IRQCHIP_SET_TYPE_MASKED }; -static int thunderx_gpio_irq_translate(struct irq_domain *d, - struct irq_fwspec *fwspec, - irq_hw_number_t *hwirq, - unsigned int *type) +static int thunderx_gpio_child_to_parent_hwirq(struct gpio_chip *gc, + unsigned int child, + unsigned int child_type, + unsigned int *parent, + unsigned int *parent_type) { - struct thunderx_gpio *txgpio = d->host_data; - - if (WARN_ON(fwspec->param_count < 2)) - return -EINVAL; - if (fwspec->param[0] >= txgpio->chip.ngpio) - return -EINVAL; - *hwirq = fwspec->param[0]; - *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; - return 0; -} - -static int thunderx_gpio_irq_alloc(struct irq_domain *d, unsigned int virq, - unsigned int nr_irqs, void *arg) -{ - struct thunderx_line *txline = arg; + struct thunderx_gpio *txgpio = gpiochip_get_data(gc); - return irq_domain_set_hwirq_and_chip(d, virq, txline->line, - &thunderx_gpio_irq_chip, txline); -} - -static const struct irq_domain_ops thunderx_gpio_irqd_ops = { - .alloc = thunderx_gpio_irq_alloc, - .translate = thunderx_gpio_irq_translate -}; - -static int thunderx_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) -{ - struct thunderx_gpio *txgpio = gpiochip_get_data(chip); - - return irq_find_mapping(txgpio->irqd, offset); + *parent = txgpio->base_msi + (2 * child); + *parent_type = IRQ_TYPE_LEVEL_HIGH; + return 0; } static int thunderx_gpio_probe(struct pci_dev *pdev, @@ -453,6 +405,7 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, struct device *dev = &pdev->dev; struct thunderx_gpio *txgpio; struct gpio_chip *chip; + struct gpio_irq_chip *girq; int ngpio, i; int err = 0; @@ -497,8 +450,8 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, } txgpio->msix_entries = devm_kcalloc(dev, - ngpio, sizeof(struct msix_entry), - GFP_KERNEL); + ngpio, sizeof(struct msix_entry), + GFP_KERNEL); if (!txgpio->msix_entries) { err = -ENOMEM; goto out; @@ -539,27 +492,6 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, if (err < 0) goto out; - /* - * Push GPIO specific irqdomain on hierarchy created as a side - * effect of the pci_enable_msix() - */ - txgpio->irqd = irq_domain_create_hierarchy(irq_get_irq_data(txgpio->msix_entries[0].vector)->domain, - 0, 0, of_node_to_fwnode(dev->of_node), - &thunderx_gpio_irqd_ops, txgpio); - if (!txgpio->irqd) { - err = -ENOMEM; - goto out; - } - - /* Push on irq_data and the domain for each line. */ - for (i = 0; i < ngpio; i++) { - err = irq_domain_push_irq(txgpio->irqd, - txgpio->msix_entries[i].vector, - &txgpio->line_entries[i]); - if (err < 0) - dev_err(dev, "irq_domain_push_irq: %d\n", err); - } - chip->label = KBUILD_MODNAME; chip->parent = dev; chip->owner = THIS_MODULE; @@ -574,11 +506,28 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, chip->set = thunderx_gpio_set; chip->set_multiple = thunderx_gpio_set_multiple; chip->set_config = thunderx_gpio_set_config; - chip->to_irq = thunderx_gpio_to_irq; + girq = &chip->irq; + girq->chip = &thunderx_gpio_irq_chip; + girq->fwnode = of_node_to_fwnode(dev->of_node); + girq->parent_domain = + irq_get_irq_data(txgpio->msix_entries[0].vector)->domain; + girq->child_to_parent_hwirq = thunderx_gpio_child_to_parent_hwirq; + girq->handler = handle_bad_irq; + girq->default_type = IRQ_TYPE_NONE; + err = devm_gpiochip_add_data(dev, chip, txgpio); if (err) goto out; + /* Push on irq_data and the domain for each line. */ + for (i = 0; i < ngpio; i++) { + err = irq_domain_push_irq(chip->irq.domain, + txgpio->msix_entries[i].vector, + chip); + if (err < 0) + dev_err(dev, "irq_domain_push_irq: %d\n", err); + } + dev_info(dev, "ThunderX GPIO: %d lines with base %d.\n", ngpio, chip->base); return 0; @@ -593,10 +542,10 @@ static void thunderx_gpio_remove(struct pci_dev *pdev) struct thunderx_gpio *txgpio = pci_get_drvdata(pdev); for (i = 0; i < txgpio->chip.ngpio; i++) - irq_domain_pop_irq(txgpio->irqd, + irq_domain_pop_irq(txgpio->chip.irq.domain, txgpio->msix_entries[i].vector); - irq_domain_remove(txgpio->irqd); + irq_domain_remove(txgpio->chip.irq.domain); pci_set_drvdata(pdev, NULL); } diff --git a/drivers/gpio/gpio-tqmx86.c b/drivers/gpio/gpio-tqmx86.c index d5880db7f9d47bae4db8267bf6dd7af1fb655f30..a3109bcaa0ac289911a2fe0b7d9f5882c5afd5e7 100644 --- a/drivers/gpio/gpio-tqmx86.c +++ b/drivers/gpio/gpio-tqmx86.c @@ -214,11 +214,23 @@ static const struct dev_pm_ops tqmx86_gpio_dev_pm_ops = { tqmx86_gpio_runtime_resume, NULL) }; +static void tqmx86_init_irq_valid_mask(struct gpio_chip *chip, + unsigned long *valid_mask, + unsigned int ngpios) +{ + /* Only GPIOs 4-7 are valid for interrupts. Clear the others */ + clear_bit(0, valid_mask); + clear_bit(1, valid_mask); + clear_bit(2, valid_mask); + clear_bit(3, valid_mask); +} + static int tqmx86_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct tqmx86_gpio_data *gpio; struct gpio_chip *chip; + struct gpio_irq_chip *girq; void __iomem *io_base; struct resource *res; int ret, irq; @@ -259,17 +271,10 @@ static int tqmx86_gpio_probe(struct platform_device *pdev) chip->get = tqmx86_gpio_get; chip->set = tqmx86_gpio_set; chip->ngpio = TQMX86_NGPIO; - chip->irq.need_valid_mask = true; chip->parent = pdev->dev.parent; pm_runtime_enable(&pdev->dev); - ret = devm_gpiochip_add_data(dev, chip, gpio); - if (ret) { - dev_err(dev, "Could not register GPIO chip\n"); - goto out_pm_dis; - } - if (irq) { struct irq_chip *irq_chip = &gpio->irq_chip; u8 irq_status; @@ -287,23 +292,28 @@ static int tqmx86_gpio_probe(struct platform_device *pdev) irq_status = tqmx86_gpio_read(gpio, TQMX86_GPIIS); tqmx86_gpio_write(gpio, irq_status, TQMX86_GPIIS); - ret = gpiochip_irqchip_add(chip, irq_chip, - 0, handle_simple_irq, - IRQ_TYPE_EDGE_BOTH); - if (ret) { - dev_err(dev, "Could not add irq chip\n"); + girq = &chip->irq; + girq->chip = irq_chip; + girq->parent_handler = tqmx86_gpio_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, 1, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) { + ret = -ENOMEM; goto out_pm_dis; } - - gpiochip_set_chained_irqchip(chip, irq_chip, - irq, tqmx86_gpio_irq_handler); + girq->parents[0] = irq; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_simple_irq; + girq->init_valid_mask = tqmx86_init_irq_valid_mask; } - /* Only GPIOs 4-7 are valid for interrupts. Clear the others */ - clear_bit(0, chip->irq.valid_mask); - clear_bit(1, chip->irq.valid_mask); - clear_bit(2, chip->irq.valid_mask); - clear_bit(3, chip->irq.valid_mask); + ret = devm_gpiochip_add_data(dev, chip, gpio); + if (ret) { + dev_err(dev, "Could not register GPIO chip\n"); + goto out_pm_dis; + } dev_info(dev, "GPIO functionality initialized with %d pins\n", chip->ngpio); diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 7ba668db171ba5854825b4b6178a5428aeeda2d2..58776f2d69ff84e3c05c90d28a69c2a2248e115f 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -243,6 +243,7 @@ static int vf610_gpio_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct vf610_gpio_port *port; struct gpio_chip *gc; + struct gpio_irq_chip *girq; struct irq_chip *ic; int i; int ret; @@ -318,10 +319,6 @@ static int vf610_gpio_probe(struct platform_device *pdev) ic->irq_set_type = vf610_gpio_irq_set_type; ic->irq_set_wake = vf610_gpio_irq_set_wake; - ret = devm_gpiochip_add_data(dev, gc, port); - if (ret < 0) - return ret; - /* Mask all GPIO interrupts */ for (i = 0; i < gc->ngpio; i++) vf610_gpio_writel(0, port->base + PORT_PCR(i)); @@ -329,15 +326,20 @@ static int vf610_gpio_probe(struct platform_device *pdev) /* Clear the interrupt status register for all GPIO's */ vf610_gpio_writel(~0, port->base + PORT_ISFR); - ret = gpiochip_irqchip_add(gc, ic, 0, handle_edge_irq, IRQ_TYPE_NONE); - if (ret) { - dev_err(dev, "failed to add irqchip\n"); - return ret; - } - gpiochip_set_chained_irqchip(gc, ic, port->irq, - vf610_gpio_irq_handler); + girq = &gc->irq; + girq->chip = ic; + girq->parent_handler = vf610_gpio_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, 1, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = port->irq; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_edge_irq; - return 0; + return devm_gpiochip_add_data(dev, gc, port); } static struct platform_driver vf610_gpio_driver = { diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c index 9b604f13e3029d9411c9cba18c90bdac4c2d89f7..c301c1d56dd289c358727c98b5e4db5229caeda8 100644 --- a/drivers/gpio/gpio-viperboard.c +++ b/drivers/gpio/gpio-viperboard.c @@ -79,7 +79,7 @@ MODULE_PARM_DESC(gpioa_freq, /* ----- begin of gipo a chip -------------------------------------------- */ static int vprbrd_gpioa_get(struct gpio_chip *chip, - unsigned offset) + unsigned int offset) { int ret, answer, error = 0; struct vprbrd_gpio *gpio = gpiochip_get_data(chip); @@ -129,7 +129,7 @@ static int vprbrd_gpioa_get(struct gpio_chip *chip, } static void vprbrd_gpioa_set(struct gpio_chip *chip, - unsigned offset, int value) + unsigned int offset, int value) { int ret; struct vprbrd_gpio *gpio = gpiochip_get_data(chip); @@ -170,7 +170,7 @@ static void vprbrd_gpioa_set(struct gpio_chip *chip, } static int vprbrd_gpioa_direction_input(struct gpio_chip *chip, - unsigned offset) + unsigned int offset) { int ret; struct vprbrd_gpio *gpio = gpiochip_get_data(chip); @@ -207,7 +207,7 @@ static int vprbrd_gpioa_direction_input(struct gpio_chip *chip, } static int vprbrd_gpioa_direction_output(struct gpio_chip *chip, - unsigned offset, int value) + unsigned int offset, int value) { int ret; struct vprbrd_gpio *gpio = gpiochip_get_data(chip); @@ -251,8 +251,8 @@ static int vprbrd_gpioa_direction_output(struct gpio_chip *chip, /* ----- begin of gipo b chip -------------------------------------------- */ -static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned offset, - unsigned dir) +static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned int offset, + unsigned int dir) { struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf; int ret; @@ -273,7 +273,7 @@ static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned offset, } static int vprbrd_gpiob_get(struct gpio_chip *chip, - unsigned offset) + unsigned int offset) { int ret; u16 val; @@ -305,7 +305,7 @@ static int vprbrd_gpiob_get(struct gpio_chip *chip, } static void vprbrd_gpiob_set(struct gpio_chip *chip, - unsigned offset, int value) + unsigned int offset, int value) { int ret; struct vprbrd_gpio *gpio = gpiochip_get_data(chip); @@ -338,7 +338,7 @@ static void vprbrd_gpiob_set(struct gpio_chip *chip, } static int vprbrd_gpiob_direction_input(struct gpio_chip *chip, - unsigned offset) + unsigned int offset) { int ret; struct vprbrd_gpio *gpio = gpiochip_get_data(chip); @@ -359,7 +359,7 @@ static int vprbrd_gpiob_direction_input(struct gpio_chip *chip, } static int vprbrd_gpiob_direction_output(struct gpio_chip *chip, - unsigned offset, int value) + unsigned int offset, int value) { int ret; struct vprbrd_gpio *gpio = gpiochip_get_data(chip); diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c index 38c01912c7b2313aa917dd48dc03bc23ae137d79..25d86441666edde84bb16fd4884f34604ae56060 100644 --- a/drivers/gpio/gpio-xgene-sb.c +++ b/drivers/gpio/gpio-xgene-sb.c @@ -16,6 +16,7 @@ #include #include "gpiolib.h" +#include "gpiolib-acpi.h" /* Common property names */ #define XGENE_NIRQ_PROPERTY "apm,nr-irqs" diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c index 54d3359444f356659576d34053cfa25b6f3cad24..d7b16bb9e4e4c515051e5b725416c395873eca37 100644 --- a/drivers/gpio/gpio-xlp.c +++ b/drivers/gpio/gpio-xlp.c @@ -290,6 +290,7 @@ MODULE_DEVICE_TABLE(of, xlp_gpio_of_ids); static int xlp_gpio_probe(struct platform_device *pdev) { struct gpio_chip *gc; + struct gpio_irq_chip *girq; struct xlp_gpio_priv *priv; void __iomem *gpio_base; int irq_base, irq, err; @@ -395,27 +396,27 @@ static int xlp_gpio_probe(struct platform_device *pdev) irq_base = 0; } + girq = &gc->irq; + girq->chip = &xlp_gpio_irq_chip; + girq->parent_handler = xlp_gpio_generic_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, 1, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = irq; + girq->first = irq_base; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_level_irq; + err = gpiochip_add_data(gc, priv); if (err < 0) return err; - err = gpiochip_irqchip_add(gc, &xlp_gpio_irq_chip, irq_base, - handle_level_irq, IRQ_TYPE_NONE); - if (err) { - dev_err(&pdev->dev, "Could not connect irqchip to gpiochip!\n"); - goto out_gpio_remove; - } - - gpiochip_set_chained_irqchip(gc, &xlp_gpio_irq_chip, irq, - xlp_gpio_generic_handler); - dev_info(&pdev->dev, "registered %d GPIOs\n", gc->ngpio); return 0; - -out_gpio_remove: - gpiochip_remove(gc); - return err; } #ifdef CONFIG_ACPI diff --git a/drivers/gpio/gpio-zx.c b/drivers/gpio/gpio-zx.c index 8637adb6bc205c16c6ed3768f5ae9d6cd39e0b1a..98cbaf0e415e7dc9759f8a69e75066e523ef267c 100644 --- a/drivers/gpio/gpio-zx.c +++ b/drivers/gpio/gpio-zx.c @@ -215,6 +215,7 @@ static int zx_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct zx_gpio *chip; + struct gpio_irq_chip *girq; int irq, id, ret; chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); @@ -242,32 +243,30 @@ static int zx_gpio_probe(struct platform_device *pdev) chip->gc.parent = dev; chip->gc.owner = THIS_MODULE; - ret = gpiochip_add_data(&chip->gc, chip); - if (ret) - return ret; - /* * irq_chip support */ writew_relaxed(0xffff, chip->base + ZX_GPIO_IM); writew_relaxed(0, chip->base + ZX_GPIO_IE); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "invalid IRQ\n"); - gpiochip_remove(&chip->gc); - return -ENODEV; - } + if (irq < 0) + return irq; + girq = &chip->gc.irq; + girq->chip = &zx_irqchip; + girq->parent_handler = zx_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, 1, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = irq; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_simple_irq; - ret = gpiochip_irqchip_add(&chip->gc, &zx_irqchip, - 0, handle_simple_irq, - IRQ_TYPE_NONE); - if (ret) { - dev_err(dev, "could not add irqchip\n"); - gpiochip_remove(&chip->gc); + ret = gpiochip_add_data(&chip->gc, chip); + if (ret) return ret; - } - gpiochip_set_chained_irqchip(&chip->gc, &zx_irqchip, - irq, zx_irq_handler); platform_set_drvdata(pdev, chip); dev_info(dev, "ZX GPIO chip registered\n"); diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index f241b6c13dbeef7d17b0fdd28075874a429e4fea..cd475ff4bcadbace686d7dc85d4e3ea9985e0589 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -830,6 +830,7 @@ static int zynq_gpio_probe(struct platform_device *pdev) int ret, bank_num; struct zynq_gpio *gpio; struct gpio_chip *chip; + struct gpio_irq_chip *girq; const struct of_device_id *match; gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); @@ -849,10 +850,8 @@ static int zynq_gpio_probe(struct platform_device *pdev) return PTR_ERR(gpio->base_addr); gpio->irq = platform_get_irq(pdev, 0); - if (gpio->irq < 0) { - dev_err(&pdev->dev, "invalid IRQ\n"); + if (gpio->irq < 0) return gpio->irq; - } /* configure the gpio chip */ chip = &gpio->chip; @@ -887,34 +886,38 @@ static int zynq_gpio_probe(struct platform_device *pdev) if (ret < 0) goto err_pm_dis; - /* report a bug if gpio chip registration fails */ - ret = gpiochip_add_data(chip, gpio); - if (ret) { - dev_err(&pdev->dev, "Failed to add gpio chip\n"); - goto err_pm_put; - } - /* disable interrupts for all banks */ for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr + ZYNQ_GPIO_INTDIS_OFFSET(bank_num)); - ret = gpiochip_irqchip_add(chip, &zynq_gpio_edge_irqchip, 0, - handle_level_irq, IRQ_TYPE_NONE); - if (ret) { - dev_err(&pdev->dev, "Failed to add irq chip\n"); - goto err_rm_gpiochip; + /* Set up the GPIO irqchip */ + girq = &chip->irq; + girq->chip = &zynq_gpio_edge_irqchip; + girq->parent_handler = zynq_gpio_irqhandler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, 1, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) { + ret = -ENOMEM; + goto err_pm_put; } + girq->parents[0] = gpio->irq; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_level_irq; - gpiochip_set_chained_irqchip(chip, &zynq_gpio_edge_irqchip, gpio->irq, - zynq_gpio_irqhandler); + /* report a bug if gpio chip registration fails */ + ret = gpiochip_add_data(chip, gpio); + if (ret) { + dev_err(&pdev->dev, "Failed to add gpio chip\n"); + goto err_pm_put; + } pm_runtime_put(&pdev->dev); return 0; -err_rm_gpiochip: - gpiochip_remove(chip); err_pm_put: pm_runtime_put(&pdev->dev); err_pm_dis: diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index bda28eb82c3fadc70feed81beff1c540fe93d322..609ed16ae9333bd25f154e3f4f399d6cfeda5234 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -19,6 +19,7 @@ #include #include "gpiolib.h" +#include "gpiolib-acpi.h" static int run_edge_events_on_boot = -1; module_param(run_edge_events_on_boot, int, 0444); @@ -391,6 +392,13 @@ int acpi_dev_add_driver_gpios(struct acpi_device *adev, } EXPORT_SYMBOL_GPL(acpi_dev_add_driver_gpios); +void acpi_dev_remove_driver_gpios(struct acpi_device *adev) +{ + if (adev) + adev->driver_gpios = NULL; +} +EXPORT_SYMBOL_GPL(acpi_dev_remove_driver_gpios); + static void devm_acpi_dev_release_driver_gpios(struct device *dev, void *res) { acpi_dev_remove_driver_gpios(ACPI_COMPANION(dev)); @@ -729,6 +737,16 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, return ret ? ERR_PTR(ret) : lookup.desc; } +static bool acpi_can_fallback_to_crs(struct acpi_device *adev, + const char *con_id) +{ + /* Never allow fallback if the device has properties */ + if (acpi_dev_has_props(adev) || adev->driver_gpios) + return false; + + return con_id == NULL; +} + struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, unsigned int idx, @@ -1265,15 +1283,6 @@ int acpi_gpio_count(struct device *dev, const char *con_id) return count ? count : -ENOENT; } -bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id) -{ - /* Never allow fallback if the device has properties */ - if (acpi_dev_has_props(adev) || adev->driver_gpios) - return false; - - return con_id == NULL; -} - /* Run deferred acpi_gpiochip_request_irqs() */ static int acpi_gpio_handle_deferred_request_irqs(void) { diff --git a/drivers/gpio/gpiolib-acpi.h b/drivers/gpio/gpiolib-acpi.h new file mode 100644 index 0000000000000000000000000000000000000000..1c6d65cf062968e6cd89402ae5ef3d3dd9e04c17 --- /dev/null +++ b/drivers/gpio/gpiolib-acpi.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * ACPI helpers for GPIO API + * + * Copyright (C) 2012,2019 Intel Corporation + */ + +#ifndef GPIOLIB_ACPI_H +#define GPIOLIB_ACPI_H + +struct acpi_device; + +/** + * struct acpi_gpio_info - ACPI GPIO specific information + * @adev: reference to ACPI device which consumes GPIO resource + * @flags: GPIO initialization flags + * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo + * @pin_config: pin bias as provided by ACPI + * @polarity: interrupt polarity as provided by ACPI + * @triggering: triggering type as provided by ACPI + * @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping + */ +struct acpi_gpio_info { + struct acpi_device *adev; + enum gpiod_flags flags; + bool gpioint; + int pin_config; + int polarity; + int triggering; + unsigned int quirks; +}; + +#ifdef CONFIG_ACPI +void acpi_gpiochip_add(struct gpio_chip *chip); +void acpi_gpiochip_remove(struct gpio_chip *chip); + +void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); +void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); + +int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, + struct acpi_gpio_info *info); +int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags, + struct acpi_gpio_info *info); + +struct gpio_desc *acpi_find_gpio(struct device *dev, + const char *con_id, + unsigned int idx, + enum gpiod_flags *dflags, + unsigned long *lookupflags); +struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode, + const char *propname, int index, + struct acpi_gpio_info *info); + +int acpi_gpio_count(struct device *dev, const char *con_id); +#else +static inline void acpi_gpiochip_add(struct gpio_chip *chip) { } +static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { } + +static inline void +acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { } + +static inline void +acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } + +static inline int +acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info) +{ + return 0; +} +static inline int +acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags, + struct acpi_gpio_info *info) +{ + return 0; +} + +static inline struct gpio_desc * +acpi_find_gpio(struct device *dev, const char *con_id, + unsigned int idx, enum gpiod_flags *dflags, + unsigned long *lookupflags) +{ + return ERR_PTR(-ENOENT); +} +static inline struct gpio_desc * +acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname, + int index, struct acpi_gpio_info *info) +{ + return ERR_PTR(-ENXIO); +} +static inline int acpi_gpio_count(struct device *dev, const char *con_id) +{ + return -ENODEV; +} +#endif + +#endif /* GPIOLIB_ACPI_H */ diff --git a/drivers/gpio/gpiolib-devres.c b/drivers/gpio/gpiolib-devres.c index 0acc2cc6e868fdefec661540d97513959e00575e..98e3c20d9730e66ad46bff8317e96fb4996eda32 100644 --- a/drivers/gpio/gpiolib-devres.c +++ b/drivers/gpio/gpiolib-devres.c @@ -59,7 +59,7 @@ struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, { return devm_gpiod_get_index(dev, con_id, 0, flags); } -EXPORT_SYMBOL(devm_gpiod_get); +EXPORT_SYMBOL_GPL(devm_gpiod_get); /** * devm_gpiod_get_optional - Resource-managed gpiod_get_optional() @@ -77,7 +77,7 @@ struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev, { return devm_gpiod_get_index_optional(dev, con_id, 0, flags); } -EXPORT_SYMBOL(devm_gpiod_get_optional); +EXPORT_SYMBOL_GPL(devm_gpiod_get_optional); /** * devm_gpiod_get_index - Resource-managed gpiod_get_index() @@ -127,7 +127,7 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, return desc; } -EXPORT_SYMBOL(devm_gpiod_get_index); +EXPORT_SYMBOL_GPL(devm_gpiod_get_index); /** * devm_gpiod_get_from_of_node() - obtain a GPIO from an OF node @@ -182,7 +182,7 @@ struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev, return desc; } -EXPORT_SYMBOL(devm_gpiod_get_from_of_node); +EXPORT_SYMBOL_GPL(devm_gpiod_get_from_of_node); /** * devm_fwnode_get_index_gpiod_from_child - get a GPIO descriptor from a @@ -239,7 +239,7 @@ struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev, return desc; } -EXPORT_SYMBOL(devm_fwnode_get_index_gpiod_from_child); +EXPORT_SYMBOL_GPL(devm_fwnode_get_index_gpiod_from_child); /** * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional() @@ -268,7 +268,7 @@ struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev, return desc; } -EXPORT_SYMBOL(devm_gpiod_get_index_optional); +EXPORT_SYMBOL_GPL(devm_gpiod_get_index_optional); /** * devm_gpiod_get_array - Resource-managed gpiod_get_array() @@ -303,7 +303,7 @@ struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev, return descs; } -EXPORT_SYMBOL(devm_gpiod_get_array); +EXPORT_SYMBOL_GPL(devm_gpiod_get_array); /** * devm_gpiod_get_array_optional - Resource-managed gpiod_get_array_optional() @@ -328,7 +328,7 @@ devm_gpiod_get_array_optional(struct device *dev, const char *con_id, return descs; } -EXPORT_SYMBOL(devm_gpiod_get_array_optional); +EXPORT_SYMBOL_GPL(devm_gpiod_get_array_optional); /** * devm_gpiod_put - Resource-managed gpiod_put() @@ -344,7 +344,7 @@ void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) WARN_ON(devres_release(dev, devm_gpiod_release, devm_gpiod_match, &desc)); } -EXPORT_SYMBOL(devm_gpiod_put); +EXPORT_SYMBOL_GPL(devm_gpiod_put); /** * devm_gpiod_unhinge - Remove resource management from a gpio descriptor @@ -374,7 +374,7 @@ void devm_gpiod_unhinge(struct device *dev, struct gpio_desc *desc) /* Anything else we should warn about */ WARN_ON(ret); } -EXPORT_SYMBOL(devm_gpiod_unhinge); +EXPORT_SYMBOL_GPL(devm_gpiod_unhinge); /** * devm_gpiod_put_array - Resource-managed gpiod_put_array() @@ -390,7 +390,7 @@ void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs) WARN_ON(devres_release(dev, devm_gpiod_release_array, devm_gpiod_match_array, &descs)); } -EXPORT_SYMBOL(devm_gpiod_put_array); +EXPORT_SYMBOL_GPL(devm_gpiod_put_array); @@ -444,7 +444,7 @@ int devm_gpio_request(struct device *dev, unsigned gpio, const char *label) return 0; } -EXPORT_SYMBOL(devm_gpio_request); +EXPORT_SYMBOL_GPL(devm_gpio_request); /** * devm_gpio_request_one - request a single GPIO with initial setup @@ -474,7 +474,7 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio, return 0; } -EXPORT_SYMBOL(devm_gpio_request_one); +EXPORT_SYMBOL_GPL(devm_gpio_request_one); /** * devm_gpio_free - free a GPIO @@ -492,4 +492,4 @@ void devm_gpio_free(struct device *dev, unsigned int gpio) WARN_ON(devres_release(dev, devm_gpio_release, devm_gpio_match, &gpio)); } -EXPORT_SYMBOL(devm_gpio_free); +EXPORT_SYMBOL_GPL(devm_gpio_free); diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 9b44c49a922783d4f06e09248d8211ff50c61c48..1eea2c6c2e1d827453dd16dc4c7831f5bd7d600c 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -21,6 +21,34 @@ #include #include "gpiolib.h" +#include "gpiolib-of.h" + +/* + * This is used by external users of of_gpio_count() from + * + * FIXME: get rid of those external users by converting them to GPIO + * descriptors and let them all use gpiod_get_count() + */ +int of_gpio_get_count(struct device *dev, const char *con_id) +{ + int ret; + char propname[32]; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { + if (con_id) + snprintf(propname, sizeof(propname), "%s-%s", + con_id, gpio_suffixes[i]); + else + snprintf(propname, sizeof(propname), "%s", + gpio_suffixes[i]); + + ret = of_gpio_named_count(dev->of_node, propname); + if (ret > 0) + break; + } + return ret ? ret : -ENOENT; +} static int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, void *data) { @@ -53,6 +81,23 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip, return gpiochip_get_desc(chip, ret); } +/** + * of_gpio_need_valid_mask() - figure out if the OF GPIO driver needs + * to set the .valid_mask + * @dev: the device for the GPIO provider + * @return: true if the valid mask needs to be set + */ +bool of_gpio_need_valid_mask(const struct gpio_chip *gc) +{ + int size; + struct device_node *np = gc->of_node; + + size = of_property_count_u32_elems(np, "gpio-reserved-ranges"); + if (size > 0 && size % 2 == 0) + return true; + return false; +} + static void of_gpio_flags_quirks(struct device_node *np, const char *propname, enum of_gpio_flags *flags, @@ -178,7 +223,7 @@ static void of_gpio_flags_quirks(struct device_node *np, * value on the error condition. If @flags is not NULL the function also fills * in flags for the GPIO. */ -struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, +static struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, const char *propname, int index, enum of_gpio_flags *flags) { struct of_phandle_args gpiospec; @@ -229,7 +274,76 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name, else return desc_to_gpio(desc); } -EXPORT_SYMBOL(of_get_named_gpio_flags); +EXPORT_SYMBOL_GPL(of_get_named_gpio_flags); + +/** + * gpiod_get_from_of_node() - obtain a GPIO from an OF node + * @node: handle of the OF node + * @propname: name of the DT property representing the GPIO + * @index: index of the GPIO to obtain for the consumer + * @dflags: GPIO initialization flags + * @label: label to attach to the requested GPIO + * + * Returns: + * On successful request the GPIO pin is configured in accordance with + * provided @dflags. + * + * In case of error an ERR_PTR() is returned. + */ +struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, + const char *propname, int index, + enum gpiod_flags dflags, + const char *label) +{ + unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT; + struct gpio_desc *desc; + enum of_gpio_flags flags; + bool active_low = false; + bool single_ended = false; + bool open_drain = false; + bool transitory = false; + int ret; + + desc = of_get_named_gpiod_flags(node, propname, + index, &flags); + + if (!desc || IS_ERR(desc)) { + return desc; + } + + active_low = flags & OF_GPIO_ACTIVE_LOW; + single_ended = flags & OF_GPIO_SINGLE_ENDED; + open_drain = flags & OF_GPIO_OPEN_DRAIN; + transitory = flags & OF_GPIO_TRANSITORY; + + ret = gpiod_request(desc, label); + if (ret == -EBUSY && (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE)) + return desc; + if (ret) + return ERR_PTR(ret); + + if (active_low) + lflags |= GPIO_ACTIVE_LOW; + + if (single_ended) { + if (open_drain) + lflags |= GPIO_OPEN_DRAIN; + else + lflags |= GPIO_OPEN_SOURCE; + } + + if (transitory) + lflags |= GPIO_TRANSITORY; + + ret = gpiod_configure_flags(desc, propname, lflags, dflags); + if (ret < 0) { + gpiod_put(desc); + return ERR_PTR(ret); + } + + return desc; +} +EXPORT_SYMBOL_GPL(gpiod_get_from_of_node); /* * The SPI GPIO bindings happened before we managed to establish that GPIO @@ -324,6 +438,19 @@ static struct gpio_desc *of_find_regulator_gpio(struct device *dev, const char * return desc; } +static struct gpio_desc *of_find_arizona_gpio(struct device *dev, + const char *con_id, + enum of_gpio_flags *of_flags) +{ + if (!IS_ENABLED(CONFIG_MFD_ARIZONA)) + return ERR_PTR(-ENOENT); + + if (!con_id || strcmp(con_id, "wlf,reset")) + return ERR_PTR(-ENOENT); + + return of_get_named_gpiod_flags(dev->of_node, con_id, 0, of_flags); +} + struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, unsigned int idx, unsigned long *flags) { @@ -365,6 +492,9 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, desc = of_find_regulator_gpio(dev, con_id, &of_flags); } + if (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT) + desc = of_find_arizona_gpio(dev, con_id, &of_flags); + if (IS_ERR(desc)) return desc; @@ -514,8 +644,9 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip) * GPIO chips. This function performs only one sanity check: whether GPIO * is less than ngpios (that is specified in the gpio_chip). */ -int of_gpio_simple_xlate(struct gpio_chip *gc, - const struct of_phandle_args *gpiospec, u32 *flags) +static int of_gpio_simple_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, + u32 *flags) { /* * We're discouraging gpio_cells < 2, since that way you'll have to @@ -539,7 +670,6 @@ int of_gpio_simple_xlate(struct gpio_chip *gc, return gpiospec->args[0]; } -EXPORT_SYMBOL(of_gpio_simple_xlate); /** * of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank) @@ -596,7 +726,7 @@ int of_mm_gpiochip_add_data(struct device_node *np, pr_err("%pOF: GPIO chip registration failed with status %d\n", np, ret); return ret; } -EXPORT_SYMBOL(of_mm_gpiochip_add_data); +EXPORT_SYMBOL_GPL(of_mm_gpiochip_add_data); /** * of_mm_gpiochip_remove - Remove memory mapped GPIO chip (bank) @@ -613,7 +743,7 @@ void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc) iounmap(mm_gc->regs); kfree(gc->label); } -EXPORT_SYMBOL(of_mm_gpiochip_remove); +EXPORT_SYMBOL_GPL(of_mm_gpiochip_remove); static void of_gpiochip_init_valid_mask(struct gpio_chip *chip) { @@ -725,7 +855,7 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { return 0; } int of_gpiochip_add(struct gpio_chip *chip) { - int status; + int ret; if (!chip->of_node) return 0; @@ -740,9 +870,9 @@ int of_gpiochip_add(struct gpio_chip *chip) of_gpiochip_init_valid_mask(chip); - status = of_gpiochip_add_pin_range(chip); - if (status) - return status; + ret = of_gpiochip_add_pin_range(chip); + if (ret) + return ret; /* If the chip defines names itself, these take precedence */ if (!chip->names) @@ -751,13 +881,13 @@ int of_gpiochip_add(struct gpio_chip *chip) of_node_get(chip->of_node); - status = of_gpiochip_scan_gpios(chip); - if (status) { + ret = of_gpiochip_scan_gpios(chip); + if (ret) { of_node_put(chip->of_node); gpiochip_remove_pin_ranges(chip); } - return status; + return ret; } void of_gpiochip_remove(struct gpio_chip *chip) diff --git a/drivers/gpio/gpiolib-of.h b/drivers/gpio/gpiolib-of.h new file mode 100644 index 0000000000000000000000000000000000000000..9768831b1fe2f25ba88e04fa120cd4dc9e48543a --- /dev/null +++ b/drivers/gpio/gpiolib-of.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef GPIOLIB_OF_H +#define GPIOLIB_OF_H + +struct gpio_chip; +enum of_gpio_flags; + +#ifdef CONFIG_OF_GPIO +struct gpio_desc *of_find_gpio(struct device *dev, + const char *con_id, + unsigned int idx, + unsigned long *lookupflags); +int of_gpiochip_add(struct gpio_chip *gc); +void of_gpiochip_remove(struct gpio_chip *gc); +int of_gpio_get_count(struct device *dev, const char *con_id); +bool of_gpio_need_valid_mask(const struct gpio_chip *gc); +#else +static inline struct gpio_desc *of_find_gpio(struct device *dev, + const char *con_id, + unsigned int idx, + unsigned long *lookupflags) +{ + return ERR_PTR(-ENOENT); +} +static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; } +static inline void of_gpiochip_remove(struct gpio_chip *gc) { } +static inline int of_gpio_get_count(struct device *dev, const char *con_id) +{ + return 0; +} +static inline bool of_gpio_need_valid_mask(const struct gpio_chip *gc) +{ + return false; +} +#endif /* CONFIG_OF_GPIO */ + +#endif /* GPIOLIB_OF_H */ diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d9074191edef4da533d27673660e6f357df32fe7..822988818efcb201926344e77de9724076a4b232 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -30,6 +29,8 @@ #include #include "gpiolib.h" +#include "gpiolib-of.h" +#include "gpiolib-acpi.h" #define CREATE_TRACE_POINTS #include @@ -213,7 +214,7 @@ int gpiod_get_direction(struct gpio_desc *desc) { struct gpio_chip *chip; unsigned offset; - int status; + int ret; chip = gpiod_to_chip(desc); offset = gpio_chip_hwgpio(desc); @@ -221,17 +222,17 @@ int gpiod_get_direction(struct gpio_desc *desc) if (!chip->get_direction) return -ENOTSUPP; - status = chip->get_direction(chip, offset); - if (status > 0) { + ret = chip->get_direction(chip, offset); + if (ret > 0) { /* GPIOF_DIR_IN, or other positive */ - status = 1; + ret = 1; clear_bit(FLAG_IS_OUT, &desc->flags); } - if (status == 0) { + if (ret == 0) { /* GPIOF_DIR_OUT */ set_bit(FLAG_IS_OUT, &desc->flags); } - return status; + return ret; } EXPORT_SYMBOL_GPL(gpiod_get_direction); @@ -350,7 +351,7 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip) { unsigned long *p; - p = kmalloc_array(BITS_TO_LONGS(chip->ngpio), sizeof(*p), GFP_KERNEL); + p = bitmap_alloc(chip->ngpio, GFP_KERNEL); if (!p) return NULL; @@ -360,38 +361,31 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip) return p; } -static int gpiochip_alloc_valid_mask(struct gpio_chip *gpiochip) +static int gpiochip_alloc_valid_mask(struct gpio_chip *gc) { -#ifdef CONFIG_OF_GPIO - int size; - struct device_node *np = gpiochip->of_node; - - size = of_property_count_u32_elems(np, "gpio-reserved-ranges"); - if (size > 0 && size % 2 == 0) - gpiochip->need_valid_mask = true; -#endif - - if (!gpiochip->need_valid_mask) + if (!(of_gpio_need_valid_mask(gc) || gc->init_valid_mask)) return 0; - gpiochip->valid_mask = gpiochip_allocate_mask(gpiochip); - if (!gpiochip->valid_mask) + gc->valid_mask = gpiochip_allocate_mask(gc); + if (!gc->valid_mask) return -ENOMEM; return 0; } -static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip) +static int gpiochip_init_valid_mask(struct gpio_chip *gc) { - if (gpiochip->init_valid_mask) - return gpiochip->init_valid_mask(gpiochip); + if (gc->init_valid_mask) + return gc->init_valid_mask(gc, + gc->valid_mask, + gc->ngpio); return 0; } static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip) { - kfree(gpiochip->valid_mask); + bitmap_free(gpiochip->valid_mask); gpiochip->valid_mask = NULL; } @@ -865,7 +859,7 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p) } ret = kfifo_put(&le->events, ge); - if (ret != 0) + if (ret) wake_up_poll(&le->wait, EPOLLIN); return IRQ_HANDLED; @@ -1182,21 +1176,21 @@ static void gpiodevice_release(struct device *dev) static int gpiochip_setup_dev(struct gpio_device *gdev) { - int status; + int ret; cdev_init(&gdev->chrdev, &gpio_fileops); gdev->chrdev.owner = THIS_MODULE; gdev->dev.devt = MKDEV(MAJOR(gpio_devt), gdev->id); - status = cdev_device_add(&gdev->chrdev, &gdev->dev); - if (status) - return status; + ret = cdev_device_add(&gdev->chrdev, &gdev->dev); + if (ret) + return ret; chip_dbg(gdev->chip, "added GPIO chardev (%d:%d)\n", MAJOR(gpio_devt), gdev->id); - status = gpiochip_sysfs_register(gdev); - if (status) + ret = gpiochip_sysfs_register(gdev); + if (ret) goto err_remove_device; /* From this point, the .release() function cleans up gpio_device */ @@ -1209,7 +1203,7 @@ static int gpiochip_setup_dev(struct gpio_device *gdev) err_remove_device: cdev_device_del(&gdev->chrdev, &gdev->dev); - return status; + return ret; } static void gpiochip_machine_hog(struct gpio_chip *chip, struct gpiod_hog *hog) @@ -1250,13 +1244,13 @@ static void machine_gpiochip_add(struct gpio_chip *chip) static void gpiochip_setup_devs(void) { struct gpio_device *gdev; - int err; + int ret; list_for_each_entry(gdev, &gpio_devices, list) { - err = gpiochip_setup_dev(gdev); - if (err) + ret = gpiochip_setup_dev(gdev); + if (ret) pr_err("%s: Failed to initialize gpio device (%d)\n", - dev_name(&gdev->dev), err); + dev_name(&gdev->dev), ret); } } @@ -1265,7 +1259,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, struct lock_class_key *request_key) { unsigned long flags; - int status = 0; + int ret = 0; unsigned i; int base = chip->base; struct gpio_device *gdev; @@ -1295,7 +1289,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, gdev->id = ida_simple_get(&gpio_ida, 0, 0, GFP_KERNEL); if (gdev->id < 0) { - status = gdev->id; + ret = gdev->id; goto err_free_gdev; } dev_set_name(&gdev->dev, "gpiochip%d", gdev->id); @@ -1311,13 +1305,13 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, gdev->descs = kcalloc(chip->ngpio, sizeof(gdev->descs[0]), GFP_KERNEL); if (!gdev->descs) { - status = -ENOMEM; + ret = -ENOMEM; goto err_free_ida; } if (chip->ngpio == 0) { chip_err(chip, "tried to insert a GPIO chip with zero lines\n"); - status = -EINVAL; + ret = -EINVAL; goto err_free_descs; } @@ -1327,7 +1321,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, gdev->label = kstrdup_const(chip->label ?: "unknown", GFP_KERNEL); if (!gdev->label) { - status = -ENOMEM; + ret = -ENOMEM; goto err_free_descs; } @@ -1346,7 +1340,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, if (base < 0) { base = gpiochip_find_base(chip->ngpio); if (base < 0) { - status = base; + ret = base; spin_unlock_irqrestore(&gpio_lock, flags); goto err_free_label; } @@ -1360,8 +1354,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, } gdev->base = base; - status = gpiodev_add_to_list(gdev); - if (status) { + ret = gpiodev_add_to_list(gdev); + if (ret) { spin_unlock_irqrestore(&gpio_lock, flags); goto err_free_label; } @@ -1375,20 +1369,20 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, INIT_LIST_HEAD(&gdev->pin_ranges); #endif - status = gpiochip_set_desc_names(chip); - if (status) + ret = gpiochip_set_desc_names(chip); + if (ret) goto err_remove_from_list; - status = gpiochip_alloc_valid_mask(chip); - if (status) + ret = gpiochip_alloc_valid_mask(chip); + if (ret) goto err_remove_from_list; - status = of_gpiochip_add(chip); - if (status) + ret = of_gpiochip_add(chip); + if (ret) goto err_free_gpiochip_mask; - status = gpiochip_init_valid_mask(chip); - if (status) + ret = gpiochip_init_valid_mask(chip); + if (ret) goto err_remove_of_chip; for (i = 0; i < chip->ngpio; i++) { @@ -1411,12 +1405,12 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, machine_gpiochip_add(chip); - status = gpiochip_irqchip_init_valid_mask(chip); - if (status) + ret = gpiochip_irqchip_init_valid_mask(chip); + if (ret) goto err_remove_acpi_chip; - status = gpiochip_add_irqchip(chip, lock_key, request_key); - if (status) + ret = gpiochip_add_irqchip(chip, lock_key, request_key); + if (ret) goto err_remove_irqchip_mask; /* @@ -1428,8 +1422,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, * Otherwise, defer until later. */ if (gpiolib_initialized) { - status = gpiochip_setup_dev(gdev); - if (status) + ret = gpiochip_setup_dev(gdev); + if (ret) goto err_remove_irqchip; } return 0; @@ -1459,9 +1453,9 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, /* failures here can mean systems won't boot... */ pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__, gdev->base, gdev->base + gdev->ngpio - 1, - chip->label ? : "generic", status); + chip->label ? : "generic", ret); kfree(gdev); - return status; + return ret; } EXPORT_SYMBOL_GPL(gpiochip_add_data_with_key); @@ -1627,21 +1621,25 @@ static struct gpio_chip *find_chip_by_name(const char *name) * The following is irqchip helper code for gpiochips. */ -static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip) +static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gc) { - if (!gpiochip->irq.need_valid_mask) + struct gpio_irq_chip *girq = &gc->irq; + + if (!girq->init_valid_mask) return 0; - gpiochip->irq.valid_mask = gpiochip_allocate_mask(gpiochip); - if (!gpiochip->irq.valid_mask) + girq->valid_mask = gpiochip_allocate_mask(gc); + if (!girq->valid_mask) return -ENOMEM; + girq->init_valid_mask(gc, girq->valid_mask, gc->ngpio); + return 0; } static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip) { - kfree(gpiochip->irq.valid_mask); + bitmap_free(gpiochip->irq.valid_mask); gpiochip->irq.valid_mask = NULL; } @@ -1741,6 +1739,273 @@ void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip, } EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip); +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY + +/** + * gpiochip_set_hierarchical_irqchip() - connects a hierarchical irqchip + * to a gpiochip + * @gc: the gpiochip to set the irqchip hierarchical handler to + * @irqchip: the irqchip to handle this level of the hierarchy, the interrupt + * will then percolate up to the parent + */ +static void gpiochip_set_hierarchical_irqchip(struct gpio_chip *gc, + struct irq_chip *irqchip) +{ + /* DT will deal with mapping each IRQ as we go along */ + if (is_of_node(gc->irq.fwnode)) + return; + + /* + * This is for legacy and boardfile "irqchip" fwnodes: allocate + * irqs upfront instead of dynamically since we don't have the + * dynamic type of allocation that hardware description languages + * provide. Once all GPIO drivers using board files are gone from + * the kernel we can delete this code, but for a transitional period + * it is necessary to keep this around. + */ + if (is_fwnode_irqchip(gc->irq.fwnode)) { + int i; + int ret; + + for (i = 0; i < gc->ngpio; i++) { + struct irq_fwspec fwspec; + unsigned int parent_hwirq; + unsigned int parent_type; + struct gpio_irq_chip *girq = &gc->irq; + + /* + * We call the child to parent translation function + * only to check if the child IRQ is valid or not. + * Just pick the rising edge type here as that is what + * we likely need to support. + */ + ret = girq->child_to_parent_hwirq(gc, i, + IRQ_TYPE_EDGE_RISING, + &parent_hwirq, + &parent_type); + if (ret) { + chip_err(gc, "skip set-up on hwirq %d\n", + i); + continue; + } + + fwspec.fwnode = gc->irq.fwnode; + /* This is the hwirq for the GPIO line side of things */ + fwspec.param[0] = girq->child_offset_to_irq(gc, i); + /* Just pick something */ + fwspec.param[1] = IRQ_TYPE_EDGE_RISING; + fwspec.param_count = 2; + ret = __irq_domain_alloc_irqs(gc->irq.domain, + /* just pick something */ + -1, + 1, + NUMA_NO_NODE, + &fwspec, + false, + NULL); + if (ret < 0) { + chip_err(gc, + "can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n", + i, parent_hwirq, + ret); + } + } + } + + chip_err(gc, "%s unknown fwnode type proceed anyway\n", __func__); + + return; +} + +static int gpiochip_hierarchy_irq_domain_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) +{ + /* We support standard DT translation */ + if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) { + return irq_domain_translate_twocell(d, fwspec, hwirq, type); + } + + /* This is for board files and others not using DT */ + if (is_fwnode_irqchip(fwspec->fwnode)) { + int ret; + + ret = irq_domain_translate_twocell(d, fwspec, hwirq, type); + if (ret) + return ret; + WARN_ON(*type == IRQ_TYPE_NONE); + return 0; + } + return -EINVAL; +} + +static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d, + unsigned int irq, + unsigned int nr_irqs, + void *data) +{ + struct gpio_chip *gc = d->host_data; + irq_hw_number_t hwirq; + unsigned int type = IRQ_TYPE_NONE; + struct irq_fwspec *fwspec = data; + struct irq_fwspec parent_fwspec; + unsigned int parent_hwirq; + unsigned int parent_type; + struct gpio_irq_chip *girq = &gc->irq; + int ret; + + /* + * The nr_irqs parameter is always one except for PCI multi-MSI + * so this should not happen. + */ + WARN_ON(nr_irqs != 1); + + ret = gc->irq.child_irq_domain_ops.translate(d, fwspec, &hwirq, &type); + if (ret) + return ret; + + chip_info(gc, "allocate IRQ %d, hwirq %lu\n", irq, hwirq); + + ret = girq->child_to_parent_hwirq(gc, hwirq, type, + &parent_hwirq, &parent_type); + if (ret) { + chip_err(gc, "can't look up hwirq %lu\n", hwirq); + return ret; + } + chip_info(gc, "found parent hwirq %u\n", parent_hwirq); + + /* + * We set handle_bad_irq because the .set_type() should + * always be invoked and set the right type of handler. + */ + irq_domain_set_info(d, + irq, + hwirq, + gc->irq.chip, + gc, + girq->handler, + NULL, NULL); + irq_set_probe(irq); + + /* + * Create a IRQ fwspec to send up to the parent irqdomain: + * specify the hwirq we address on the parent and tie it + * all together up the chain. + */ + parent_fwspec.fwnode = d->parent->fwnode; + /* This parent only handles asserted level IRQs */ + girq->populate_parent_fwspec(gc, &parent_fwspec, parent_hwirq, + parent_type); + chip_info(gc, "alloc_irqs_parent for %d parent hwirq %d\n", + irq, parent_hwirq); + ret = irq_domain_alloc_irqs_parent(d, irq, 1, &parent_fwspec); + if (ret) + chip_err(gc, + "failed to allocate parent hwirq %d for hwirq %lu\n", + parent_hwirq, hwirq); + + return ret; +} + +static unsigned int gpiochip_child_offset_to_irq_noop(struct gpio_chip *chip, + unsigned int offset) +{ + return offset; +} + +static void gpiochip_hierarchy_setup_domain_ops(struct irq_domain_ops *ops) +{ + ops->activate = gpiochip_irq_domain_activate; + ops->deactivate = gpiochip_irq_domain_deactivate; + ops->alloc = gpiochip_hierarchy_irq_domain_alloc; + ops->free = irq_domain_free_irqs_common; + + /* + * We only allow overriding the translate() function for + * hierarchical chips, and this should only be done if the user + * really need something other than 1:1 translation. + */ + if (!ops->translate) + ops->translate = gpiochip_hierarchy_irq_domain_translate; +} + +static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc) +{ + if (!gc->irq.child_to_parent_hwirq || + !gc->irq.fwnode) { + chip_err(gc, "missing irqdomain vital data\n"); + return -EINVAL; + } + + if (!gc->irq.child_offset_to_irq) + gc->irq.child_offset_to_irq = gpiochip_child_offset_to_irq_noop; + + if (!gc->irq.populate_parent_fwspec) + gc->irq.populate_parent_fwspec = + gpiochip_populate_parent_fwspec_twocell; + + gpiochip_hierarchy_setup_domain_ops(&gc->irq.child_irq_domain_ops); + + gc->irq.domain = irq_domain_create_hierarchy( + gc->irq.parent_domain, + 0, + gc->ngpio, + gc->irq.fwnode, + &gc->irq.child_irq_domain_ops, + gc); + + if (!gc->irq.domain) + return -ENOMEM; + + gpiochip_set_hierarchical_irqchip(gc, gc->irq.chip); + + return 0; +} + +static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc) +{ + return !!gc->irq.parent_domain; +} + +void gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip, + struct irq_fwspec *fwspec, + unsigned int parent_hwirq, + unsigned int parent_type) +{ + fwspec->param_count = 2; + fwspec->param[0] = parent_hwirq; + fwspec->param[1] = parent_type; +} +EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_twocell); + +void gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip, + struct irq_fwspec *fwspec, + unsigned int parent_hwirq, + unsigned int parent_type) +{ + fwspec->param_count = 4; + fwspec->param[0] = 0; + fwspec->param[1] = parent_hwirq; + fwspec->param[2] = 0; + fwspec->param[3] = parent_type; +} +EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_fourcell); + +#else + +static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc) +{ + return -EINVAL; +} + +static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc) +{ + return false; +} + +#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */ + /** * gpiochip_irq_map() - maps an IRQ into a GPIO irqchip * @d: the irqdomain used by this irqchip @@ -1755,7 +2020,7 @@ int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { struct gpio_chip *chip = d->host_data; - int err = 0; + int ret = 0; if (!gpiochip_irqchip_irq_valid(chip, hwirq)) return -ENXIO; @@ -1773,12 +2038,12 @@ int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, irq_set_noprobe(irq); if (chip->irq.num_parents == 1) - err = irq_set_parent(irq, chip->irq.parents[0]); + ret = irq_set_parent(irq, chip->irq.parents[0]); else if (chip->irq.map) - err = irq_set_parent(irq, chip->irq.map[hwirq]); + ret = irq_set_parent(irq, chip->irq.map[hwirq]); - if (err < 0) - return err; + if (ret < 0) + return ret; /* * No set-up of the hardware will happen if IRQ_TYPE_NONE @@ -1809,6 +2074,11 @@ static const struct irq_domain_ops gpiochip_domain_ops = { .xlate = irq_domain_xlate_twocell, }; +/* + * TODO: move these activate/deactivate in under the hierarchicial + * irqchip implementation as static once SPMI and SSBI (all external + * users) are phased over. + */ /** * gpiochip_irq_domain_activate() - Lock a GPIO to be used as an IRQ * @domain: The IRQ domain used by this IRQ chip @@ -1848,10 +2118,25 @@ EXPORT_SYMBOL_GPL(gpiochip_irq_domain_deactivate); static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) { + struct irq_domain *domain = chip->irq.domain; + if (!gpiochip_irqchip_irq_valid(chip, offset)) return -ENXIO; - return irq_create_mapping(chip->irq.domain, offset); +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY + if (irq_domain_is_hierarchy(domain)) { + struct irq_fwspec spec; + + spec.fwnode = domain->fwnode; + spec.param_count = 2; + spec.param[0] = chip->irq.child_offset_to_irq(chip, offset); + spec.param[1] = IRQ_TYPE_NONE; + + return irq_create_fwspec_mapping(&spec); + } +#endif + + return irq_create_mapping(domain, offset); } static int gpiochip_irq_reqres(struct irq_data *d) @@ -1928,7 +2213,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip, struct lock_class_key *request_key) { struct irq_chip *irqchip = gpiochip->irq.chip; - const struct irq_domain_ops *ops; + const struct irq_domain_ops *ops = NULL; struct device_node *np; unsigned int type; unsigned int i; @@ -1964,16 +2249,25 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip, gpiochip->irq.lock_key = lock_key; gpiochip->irq.request_key = request_key; - if (gpiochip->irq.domain_ops) - ops = gpiochip->irq.domain_ops; - else - ops = &gpiochip_domain_ops; - - gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio, - gpiochip->irq.first, - ops, gpiochip); - if (!gpiochip->irq.domain) - return -EINVAL; + /* If a parent irqdomain is provided, let's build a hierarchy */ + if (gpiochip_hierarchy_is_hierarchical(gpiochip)) { + int ret = gpiochip_hierarchy_add_domain(gpiochip); + if (ret) + return ret; + } else { + /* Some drivers provide custom irqdomain ops */ + if (gpiochip->irq.domain_ops) + ops = gpiochip->irq.domain_ops; + + if (!ops) + ops = &gpiochip_domain_ops; + gpiochip->irq.domain = irq_domain_add_simple(np, + gpiochip->ngpio, + gpiochip->irq.first, + ops, gpiochip); + if (!gpiochip->irq.domain) + return -EINVAL; + } if (gpiochip->irq.parent_handler) { void *data = gpiochip->irq.parent_handler_data ?: gpiochip; @@ -2336,7 +2630,7 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); static int gpiod_request_commit(struct gpio_desc *desc, const char *label) { struct gpio_chip *chip = desc->gdev->chip; - int status; + int ret; unsigned long flags; unsigned offset; @@ -2354,10 +2648,10 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) { desc_set_label(desc, label ? : "?"); - status = 0; + ret = 0; } else { kfree_const(label); - status = -EBUSY; + ret = -EBUSY; goto done; } @@ -2366,12 +2660,12 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) spin_unlock_irqrestore(&gpio_lock, flags); offset = gpio_chip_hwgpio(desc); if (gpiochip_line_is_valid(chip, offset)) - status = chip->request(chip, offset); + ret = chip->request(chip, offset); else - status = -EINVAL; + ret = -EINVAL; spin_lock_irqsave(&gpio_lock, flags); - if (status < 0) { + if (ret < 0) { desc_set_label(desc, NULL); kfree_const(label); clear_bit(FLAG_REQUESTED, &desc->flags); @@ -2386,7 +2680,7 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) } done: spin_unlock_irqrestore(&gpio_lock, flags); - return status; + return ret; } /* @@ -2429,24 +2723,24 @@ static int validate_desc(const struct gpio_desc *desc, const char *func) int gpiod_request(struct gpio_desc *desc, const char *label) { - int status = -EPROBE_DEFER; + int ret = -EPROBE_DEFER; struct gpio_device *gdev; VALIDATE_DESC(desc); gdev = desc->gdev; if (try_module_get(gdev->owner)) { - status = gpiod_request_commit(desc, label); - if (status < 0) + ret = gpiod_request_commit(desc, label); + if (ret < 0) module_put(gdev->owner); else get_device(&gdev->dev); } - if (status) - gpiod_dbg(desc, "%s: status %d\n", __func__, status); + if (ret) + gpiod_dbg(desc, "%s: status %d\n", __func__, ret); - return status; + return ret; } static bool gpiod_free_commit(struct gpio_desc *desc) @@ -2548,22 +2842,22 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum, enum gpiod_flags dflags) { struct gpio_desc *desc = gpiochip_get_desc(chip, hwnum); - int err; + int ret; if (IS_ERR(desc)) { chip_err(chip, "failed to get GPIO descriptor\n"); return desc; } - err = gpiod_request_commit(desc, label); - if (err < 0) - return ERR_PTR(err); + ret = gpiod_request_commit(desc, label); + if (ret < 0) + return ERR_PTR(ret); - err = gpiod_configure_flags(desc, label, lflags, dflags); - if (err) { + ret = gpiod_configure_flags(desc, label, lflags, dflags); + if (ret) { chip_err(chip, "setup of own GPIO %s failed\n", label); gpiod_free_commit(desc); - return ERR_PTR(err); + return ERR_PTR(ret); } return desc; @@ -2626,7 +2920,7 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned offset, int gpiod_direction_input(struct gpio_desc *desc) { struct gpio_chip *chip; - int status = 0; + int ret = 0; VALIDATE_DESC(desc); chip = desc->gdev->chip; @@ -2650,7 +2944,7 @@ int gpiod_direction_input(struct gpio_desc *desc) * assume we are in input mode after this. */ if (chip->direction_input) { - status = chip->direction_input(chip, gpio_chip_hwgpio(desc)); + ret = chip->direction_input(chip, gpio_chip_hwgpio(desc)); } else if (chip->get_direction && (chip->get_direction(chip, gpio_chip_hwgpio(desc)) != 1)) { gpiod_warn(desc, @@ -2658,7 +2952,7 @@ int gpiod_direction_input(struct gpio_desc *desc) __func__); return -EIO; } - if (status == 0) + if (ret == 0) clear_bit(FLAG_IS_OUT, &desc->flags); if (test_bit(FLAG_PULL_UP, &desc->flags)) @@ -2668,9 +2962,9 @@ int gpiod_direction_input(struct gpio_desc *desc) gpio_set_config(chip, gpio_chip_hwgpio(desc), PIN_CONFIG_BIAS_PULL_DOWN); - trace_gpio_direction(desc_to_gpio(desc), 1, status); + trace_gpio_direction(desc_to_gpio(desc), 1, ret); - return status; + return ret; } EXPORT_SYMBOL_GPL(gpiod_direction_input); @@ -2942,7 +3236,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, struct gpio_array *array_info, unsigned long *value_bitmap) { - int err, i = 0; + int ret, i = 0; /* * Validate array_info against desc_array and its size. @@ -2955,11 +3249,11 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, if (!can_sleep) WARN_ON(array_info->chip->can_sleep); - err = gpio_chip_get_multiple(array_info->chip, + ret = gpio_chip_get_multiple(array_info->chip, array_info->get_mask, value_bitmap); - if (err) - return err; + if (ret) + return ret; if (!raw && !bitmap_empty(array_info->invert_mask, array_size)) bitmap_xor(value_bitmap, value_bitmap, @@ -3147,24 +3441,24 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_value); */ static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value) { - int err = 0; + int ret = 0; struct gpio_chip *chip = desc->gdev->chip; int offset = gpio_chip_hwgpio(desc); if (value) { - err = chip->direction_input(chip, offset); - if (!err) + ret = chip->direction_input(chip, offset); + if (!ret) clear_bit(FLAG_IS_OUT, &desc->flags); } else { - err = chip->direction_output(chip, offset, 0); - if (!err) + ret = chip->direction_output(chip, offset, 0); + if (!ret) set_bit(FLAG_IS_OUT, &desc->flags); } - trace_gpio_direction(desc_to_gpio(desc), value, err); - if (err < 0) + trace_gpio_direction(desc_to_gpio(desc), value, ret); + if (ret < 0) gpiod_err(desc, "%s: Error in set_value for open drain err %d\n", - __func__, err); + __func__, ret); } /* @@ -3174,24 +3468,24 @@ static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value) */ static void gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value) { - int err = 0; + int ret = 0; struct gpio_chip *chip = desc->gdev->chip; int offset = gpio_chip_hwgpio(desc); if (value) { - err = chip->direction_output(chip, offset, 1); - if (!err) + ret = chip->direction_output(chip, offset, 1); + if (!ret) set_bit(FLAG_IS_OUT, &desc->flags); } else { - err = chip->direction_input(chip, offset); - if (!err) + ret = chip->direction_input(chip, offset); + if (!ret) clear_bit(FLAG_IS_OUT, &desc->flags); } - trace_gpio_direction(desc_to_gpio(desc), !value, err); - if (err < 0) + trace_gpio_direction(desc_to_gpio(desc), !value, ret); + if (ret < 0) gpiod_err(desc, "%s: Error in set_value for open source err %d\n", - __func__, err); + __func__, ret); } static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value) @@ -4008,27 +4302,6 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, return desc; } -static int dt_gpio_count(struct device *dev, const char *con_id) -{ - int ret; - char propname[32]; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { - if (con_id) - snprintf(propname, sizeof(propname), "%s-%s", - con_id, gpio_suffixes[i]); - else - snprintf(propname, sizeof(propname), "%s", - gpio_suffixes[i]); - - ret = of_gpio_named_count(dev->of_node, propname); - if (ret > 0) - break; - } - return ret ? ret : -ENOENT; -} - static int platform_gpio_count(struct device *dev, const char *con_id) { struct gpiod_lookup_table *table; @@ -4061,7 +4334,7 @@ int gpiod_count(struct device *dev, const char *con_id) int count = -ENOENT; if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) - count = dt_gpio_count(dev, con_id); + count = of_gpio_get_count(dev, con_id); else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev)) count = acpi_gpio_count(dev, con_id); @@ -4123,7 +4396,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_optional); int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, unsigned long lflags, enum gpiod_flags dflags) { - int status; + int ret; if (lflags & GPIO_ACTIVE_LOW) set_bit(FLAG_ACTIVE_LOW, &desc->flags); @@ -4156,9 +4429,9 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, else if (lflags & GPIO_PULL_DOWN) set_bit(FLAG_PULL_DOWN, &desc->flags); - status = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY)); - if (status < 0) - return status; + ret = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY)); + if (ret < 0) + return ret; /* No particular flag request, return here... */ if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) { @@ -4168,12 +4441,12 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, /* Process flags */ if (dflags & GPIOD_FLAGS_BIT_DIR_OUT) - status = gpiod_direction_output(desc, + ret = gpiod_direction_output(desc, !!(dflags & GPIOD_FLAGS_BIT_DIR_VAL)); else - status = gpiod_direction_input(desc); + ret = gpiod_direction_input(desc); - return status; + return ret; } /** @@ -4197,7 +4470,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, { unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT; struct gpio_desc *desc = NULL; - int status; + int ret; /* Maybe we have a device name, maybe not */ const char *devname = dev ? dev_name(dev) : "?"; @@ -4232,9 +4505,9 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, * If a connection label was passed use that, else attempt to use * the device name as label */ - status = gpiod_request(desc, con_id ? con_id : devname); - if (status < 0) { - if (status == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) { + ret = gpiod_request(desc, con_id ? con_id : devname); + if (ret < 0) { + if (ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) { /* * This happens when there are several consumers for * the same GPIO line: we just return here without @@ -4247,89 +4520,20 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, con_id ? con_id : devname); return desc; } else { - return ERR_PTR(status); + return ERR_PTR(ret); } } - status = gpiod_configure_flags(desc, con_id, lookupflags, flags); - if (status < 0) { - dev_dbg(dev, "setup of GPIO %s failed\n", con_id); - gpiod_put(desc); - return ERR_PTR(status); - } - - return desc; -} -EXPORT_SYMBOL_GPL(gpiod_get_index); - -/** - * gpiod_get_from_of_node() - obtain a GPIO from an OF node - * @node: handle of the OF node - * @propname: name of the DT property representing the GPIO - * @index: index of the GPIO to obtain for the consumer - * @dflags: GPIO initialization flags - * @label: label to attach to the requested GPIO - * - * Returns: - * On successful request the GPIO pin is configured in accordance with - * provided @dflags. - * - * In case of error an ERR_PTR() is returned. - */ -struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, - const char *propname, int index, - enum gpiod_flags dflags, - const char *label) -{ - unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT; - struct gpio_desc *desc; - enum of_gpio_flags flags; - bool active_low = false; - bool single_ended = false; - bool open_drain = false; - bool transitory = false; - int ret; - - desc = of_get_named_gpiod_flags(node, propname, - index, &flags); - - if (!desc || IS_ERR(desc)) { - return desc; - } - - active_low = flags & OF_GPIO_ACTIVE_LOW; - single_ended = flags & OF_GPIO_SINGLE_ENDED; - open_drain = flags & OF_GPIO_OPEN_DRAIN; - transitory = flags & OF_GPIO_TRANSITORY; - - ret = gpiod_request(desc, label); - if (ret == -EBUSY && (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE)) - return desc; - if (ret) - return ERR_PTR(ret); - - if (active_low) - lflags |= GPIO_ACTIVE_LOW; - - if (single_ended) { - if (open_drain) - lflags |= GPIO_OPEN_DRAIN; - else - lflags |= GPIO_OPEN_SOURCE; - } - - if (transitory) - lflags |= GPIO_TRANSITORY; - - ret = gpiod_configure_flags(desc, propname, lflags, dflags); + ret = gpiod_configure_flags(desc, con_id, lookupflags, flags); if (ret < 0) { + dev_dbg(dev, "setup of GPIO %s failed\n", con_id); gpiod_put(desc); return ERR_PTR(ret); } return desc; } -EXPORT_SYMBOL(gpiod_get_from_of_node); +EXPORT_SYMBOL_GPL(gpiod_get_index); /** * fwnode_get_named_gpiod - obtain a GPIO from firmware node @@ -4439,7 +4643,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, struct gpio_chip *chip; struct gpio_desc *local_desc; int hwnum; - int status; + int ret; chip = gpiod_to_chip(desc); hwnum = gpio_chip_hwgpio(desc); @@ -4447,10 +4651,10 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, local_desc = gpiochip_request_own_desc(chip, hwnum, name, lflags, dflags); if (IS_ERR(local_desc)) { - status = PTR_ERR(local_desc); + ret = PTR_ERR(local_desc); pr_err("requesting hog GPIO %s (chip %s, offset %d) failed, %d\n", - name, chip->label, hwnum, status); - return status; + name, chip->label, hwnum, ret); + return ret; } /* Mark GPIO as hogged so it can be identified and removed later */ diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 7c52c2442173e71dd2c712a418193118399beb9b..b8b10a409c7b9c6584e6e176d9246aec5c394258 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -16,9 +16,6 @@ #include #include -enum of_gpio_flags; -struct acpi_device; - /** * struct gpio_device - internal state container for GPIO devices * @id: numerical ID number for the GPIO chip @@ -69,126 +66,9 @@ struct gpio_device { #endif }; -/** - * struct acpi_gpio_info - ACPI GPIO specific information - * @adev: reference to ACPI device which consumes GPIO resource - * @flags: GPIO initialization flags - * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo - * @pin_config: pin bias as provided by ACPI - * @polarity: interrupt polarity as provided by ACPI - * @triggering: triggering type as provided by ACPI - * @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping - */ -struct acpi_gpio_info { - struct acpi_device *adev; - enum gpiod_flags flags; - bool gpioint; - int pin_config; - int polarity; - int triggering; - unsigned int quirks; -}; - /* gpio suffixes used for ACPI and device tree lookup */ static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" }; -#ifdef CONFIG_OF_GPIO -struct gpio_desc *of_find_gpio(struct device *dev, - const char *con_id, - unsigned int idx, - unsigned long *lookupflags); -struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, - const char *list_name, int index, enum of_gpio_flags *flags); -int of_gpiochip_add(struct gpio_chip *gc); -void of_gpiochip_remove(struct gpio_chip *gc); -#else -static inline struct gpio_desc *of_find_gpio(struct device *dev, - const char *con_id, - unsigned int idx, - unsigned long *lookupflags) -{ - return ERR_PTR(-ENOENT); -} -static inline struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, - const char *list_name, int index, enum of_gpio_flags *flags) -{ - return ERR_PTR(-ENOENT); -} -static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; } -static inline void of_gpiochip_remove(struct gpio_chip *gc) { } -#endif /* CONFIG_OF_GPIO */ - -#ifdef CONFIG_ACPI -void acpi_gpiochip_add(struct gpio_chip *chip); -void acpi_gpiochip_remove(struct gpio_chip *chip); - -void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); -void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); - -int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, - struct acpi_gpio_info *info); -int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags, - struct acpi_gpio_info *info); - -struct gpio_desc *acpi_find_gpio(struct device *dev, - const char *con_id, - unsigned int idx, - enum gpiod_flags *dflags, - unsigned long *lookupflags); -struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode, - const char *propname, int index, - struct acpi_gpio_info *info); - -int acpi_gpio_count(struct device *dev, const char *con_id); - -bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id); -#else -static inline void acpi_gpiochip_add(struct gpio_chip *chip) { } -static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { } - -static inline void -acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { } - -static inline void -acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } - -static inline int -acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info) -{ - return 0; -} -static inline int -acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags, - struct acpi_gpio_info *info) -{ - return 0; -} - -static inline struct gpio_desc * -acpi_find_gpio(struct device *dev, const char *con_id, - unsigned int idx, enum gpiod_flags *dflags, - unsigned long *lookupflags) -{ - return ERR_PTR(-ENOENT); -} -static inline struct gpio_desc * -acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname, - int index, struct acpi_gpio_info *info) -{ - return ERR_PTR(-ENXIO); -} -static inline int acpi_gpio_count(struct device *dev, const char *con_id) -{ - return -ENODEV; -} - -static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev, - const char *con_id) -{ - return false; -} -#endif - struct gpio_array { struct gpio_desc **desc; unsigned int size; diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c new file mode 100644 index 0000000000000000000000000000000000000000..7e99860ca447ed5f5a345d5cb070955d5cbb3c60 --- /dev/null +++ b/drivers/gpio/sgpio-aspeed.c @@ -0,0 +1,533 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2019 American Megatrends International LLC. + * + * Author: Karthikeyan Mani + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_NR_SGPIO 80 + +#define ASPEED_SGPIO_CTRL 0x54 + +#define ASPEED_SGPIO_PINS_MASK GENMASK(9, 6) +#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16) +#define ASPEED_SGPIO_ENABLE BIT(0) + +struct aspeed_sgpio { + struct gpio_chip chip; + struct clk *pclk; + spinlock_t lock; + void __iomem *base; + uint32_t dir_in[3]; + int irq; +}; + +struct aspeed_sgpio_bank { + uint16_t val_regs; + uint16_t rdata_reg; + uint16_t irq_regs; + const char names[4][3]; +}; + +/* + * Note: The "value" register returns the input value when the GPIO is + * configured as an input. + * + * The "rdata" register returns the output value when the GPIO is + * configured as an output. + */ +static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = { + { + .val_regs = 0x0000, + .rdata_reg = 0x0070, + .irq_regs = 0x0004, + .names = { "A", "B", "C", "D" }, + }, + { + .val_regs = 0x001C, + .rdata_reg = 0x0074, + .irq_regs = 0x0020, + .names = { "E", "F", "G", "H" }, + }, + { + .val_regs = 0x0038, + .rdata_reg = 0x0078, + .irq_regs = 0x003C, + .names = { "I", "J" }, + }, +}; + +enum aspeed_sgpio_reg { + reg_val, + reg_rdata, + reg_irq_enable, + reg_irq_type0, + reg_irq_type1, + reg_irq_type2, + reg_irq_status, +}; + +#define GPIO_VAL_VALUE 0x00 +#define GPIO_IRQ_ENABLE 0x00 +#define GPIO_IRQ_TYPE0 0x04 +#define GPIO_IRQ_TYPE1 0x08 +#define GPIO_IRQ_TYPE2 0x0C +#define GPIO_IRQ_STATUS 0x10 + +static void __iomem *bank_reg(struct aspeed_sgpio *gpio, + const struct aspeed_sgpio_bank *bank, + const enum aspeed_sgpio_reg reg) +{ + switch (reg) { + case reg_val: + return gpio->base + bank->val_regs + GPIO_VAL_VALUE; + case reg_rdata: + return gpio->base + bank->rdata_reg; + case reg_irq_enable: + return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE; + case reg_irq_type0: + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0; + case reg_irq_type1: + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1; + case reg_irq_type2: + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2; + case reg_irq_status: + return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS; + default: + /* acturally if code runs to here, it's an error case */ + BUG_ON(1); + } +} + +#define GPIO_BANK(x) ((x) >> 5) +#define GPIO_OFFSET(x) ((x) & 0x1f) +#define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) + +static const struct aspeed_sgpio_bank *to_bank(unsigned int offset) +{ + unsigned int bank = GPIO_BANK(offset); + + WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks)); + return &aspeed_sgpio_banks[bank]; +} + +static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct aspeed_sgpio *gpio = gpiochip_get_data(gc); + const struct aspeed_sgpio_bank *bank = to_bank(offset); + unsigned long flags; + enum aspeed_sgpio_reg reg; + bool is_input; + int rc = 0; + + spin_lock_irqsave(&gpio->lock, flags); + + is_input = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset); + reg = is_input ? reg_val : reg_rdata; + rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset)); + + spin_unlock_irqrestore(&gpio->lock, flags); + + return rc; +} + +static void sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val) +{ + struct aspeed_sgpio *gpio = gpiochip_get_data(gc); + const struct aspeed_sgpio_bank *bank = to_bank(offset); + void __iomem *addr; + u32 reg = 0; + + addr = bank_reg(gpio, bank, reg_val); + reg = ioread32(addr); + + if (val) + reg |= GPIO_BIT(offset); + else + reg &= ~GPIO_BIT(offset); + + iowrite32(reg, addr); +} + +static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val) +{ + struct aspeed_sgpio *gpio = gpiochip_get_data(gc); + unsigned long flags; + + spin_lock_irqsave(&gpio->lock, flags); + + sgpio_set_value(gc, offset, val); + + spin_unlock_irqrestore(&gpio->lock, flags); +} + +static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset) +{ + struct aspeed_sgpio *gpio = gpiochip_get_data(gc); + unsigned long flags; + + spin_lock_irqsave(&gpio->lock, flags); + gpio->dir_in[GPIO_BANK(offset)] |= GPIO_BIT(offset); + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val) +{ + struct aspeed_sgpio *gpio = gpiochip_get_data(gc); + unsigned long flags; + + spin_lock_irqsave(&gpio->lock, flags); + + gpio->dir_in[GPIO_BANK(offset)] &= ~GPIO_BIT(offset); + sgpio_set_value(gc, offset, val); + + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + int dir_status; + struct aspeed_sgpio *gpio = gpiochip_get_data(gc); + unsigned long flags; + + spin_lock_irqsave(&gpio->lock, flags); + dir_status = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset); + spin_unlock_irqrestore(&gpio->lock, flags); + + return dir_status; + +} + +static void irqd_to_aspeed_sgpio_data(struct irq_data *d, + struct aspeed_sgpio **gpio, + const struct aspeed_sgpio_bank **bank, + u32 *bit, int *offset) +{ + struct aspeed_sgpio *internal; + + *offset = irqd_to_hwirq(d); + internal = irq_data_get_irq_chip_data(d); + WARN_ON(!internal); + + *gpio = internal; + *bank = to_bank(*offset); + *bit = GPIO_BIT(*offset); +} + +static void aspeed_sgpio_irq_ack(struct irq_data *d) +{ + const struct aspeed_sgpio_bank *bank; + struct aspeed_sgpio *gpio; + unsigned long flags; + void __iomem *status_addr; + int offset; + u32 bit; + + irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); + + status_addr = bank_reg(gpio, bank, reg_irq_status); + + spin_lock_irqsave(&gpio->lock, flags); + + iowrite32(bit, status_addr); + + spin_unlock_irqrestore(&gpio->lock, flags); +} + +static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set) +{ + const struct aspeed_sgpio_bank *bank; + struct aspeed_sgpio *gpio; + unsigned long flags; + u32 reg, bit; + void __iomem *addr; + int offset; + + irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); + addr = bank_reg(gpio, bank, reg_irq_enable); + + spin_lock_irqsave(&gpio->lock, flags); + + reg = ioread32(addr); + if (set) + reg |= bit; + else + reg &= ~bit; + + iowrite32(reg, addr); + + spin_unlock_irqrestore(&gpio->lock, flags); +} + +static void aspeed_sgpio_irq_mask(struct irq_data *d) +{ + aspeed_sgpio_irq_set_mask(d, false); +} + +static void aspeed_sgpio_irq_unmask(struct irq_data *d) +{ + aspeed_sgpio_irq_set_mask(d, true); +} + +static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type) +{ + u32 type0 = 0; + u32 type1 = 0; + u32 type2 = 0; + u32 bit, reg; + const struct aspeed_sgpio_bank *bank; + irq_flow_handler_t handler; + struct aspeed_sgpio *gpio; + unsigned long flags; + void __iomem *addr; + int offset; + + irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_BOTH: + type2 |= bit; + /* fall through */ + case IRQ_TYPE_EDGE_RISING: + type0 |= bit; + /* fall through */ + case IRQ_TYPE_EDGE_FALLING: + handler = handle_edge_irq; + break; + case IRQ_TYPE_LEVEL_HIGH: + type0 |= bit; + /* fall through */ + case IRQ_TYPE_LEVEL_LOW: + type1 |= bit; + handler = handle_level_irq; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&gpio->lock, flags); + + addr = bank_reg(gpio, bank, reg_irq_type0); + reg = ioread32(addr); + reg = (reg & ~bit) | type0; + iowrite32(reg, addr); + + addr = bank_reg(gpio, bank, reg_irq_type1); + reg = ioread32(addr); + reg = (reg & ~bit) | type1; + iowrite32(reg, addr); + + addr = bank_reg(gpio, bank, reg_irq_type2); + reg = ioread32(addr); + reg = (reg & ~bit) | type2; + iowrite32(reg, addr); + + spin_unlock_irqrestore(&gpio->lock, flags); + + irq_set_handler_locked(d, handler); + + return 0; +} + +static void aspeed_sgpio_irq_handler(struct irq_desc *desc) +{ + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct irq_chip *ic = irq_desc_get_chip(desc); + struct aspeed_sgpio *data = gpiochip_get_data(gc); + unsigned int i, p, girq; + unsigned long reg; + + chained_irq_enter(ic, desc); + + for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { + const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i]; + + reg = ioread32(bank_reg(data, bank, reg_irq_status)); + + for_each_set_bit(p, ®, 32) { + girq = irq_find_mapping(gc->irq.domain, i * 32 + p); + generic_handle_irq(girq); + } + + } + + chained_irq_exit(ic, desc); +} + +static struct irq_chip aspeed_sgpio_irqchip = { + .name = "aspeed-sgpio", + .irq_ack = aspeed_sgpio_irq_ack, + .irq_mask = aspeed_sgpio_irq_mask, + .irq_unmask = aspeed_sgpio_irq_unmask, + .irq_set_type = aspeed_sgpio_set_type, +}; + +static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, + struct platform_device *pdev) +{ + int rc, i; + const struct aspeed_sgpio_bank *bank; + struct gpio_irq_chip *irq; + + rc = platform_get_irq(pdev, 0); + if (rc < 0) + return rc; + + gpio->irq = rc; + + /* Disable IRQ and clear Interrupt status registers for all SPGIO Pins. */ + for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { + bank = &aspeed_sgpio_banks[i]; + /* disable irq enable bits */ + iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable)); + /* clear status bits */ + iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status)); + } + + irq = &gpio->chip.irq; + irq->chip = &aspeed_sgpio_irqchip; + irq->handler = handle_bad_irq; + irq->default_type = IRQ_TYPE_NONE; + irq->parent_handler = aspeed_sgpio_irq_handler; + irq->parent_handler_data = gpio; + irq->parents = &gpio->irq; + irq->num_parents = 1; + + /* set IRQ settings and Enable Interrupt */ + for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { + bank = &aspeed_sgpio_banks[i]; + /* set falling or level-low irq */ + iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0)); + /* trigger type is edge */ + iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1)); + /* dual edge trigger mode. */ + iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type2)); + /* enable irq */ + iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_enable)); + } + + return 0; +} + +static const struct of_device_id aspeed_sgpio_of_table[] = { + { .compatible = "aspeed,ast2400-sgpio" }, + { .compatible = "aspeed,ast2500-sgpio" }, + {} +}; + +MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table); + +static int __init aspeed_sgpio_probe(struct platform_device *pdev) +{ + struct aspeed_sgpio *gpio; + u32 nr_gpios, sgpio_freq, sgpio_clk_div; + int rc; + unsigned long apb_freq; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + + gpio->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(gpio->base)) + return PTR_ERR(gpio->base); + + rc = of_property_read_u32(pdev->dev.of_node, "ngpios", &nr_gpios); + if (rc < 0) { + dev_err(&pdev->dev, "Could not read ngpios property\n"); + return -EINVAL; + } else if (nr_gpios > MAX_NR_SGPIO) { + dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n", + MAX_NR_SGPIO, nr_gpios); + return -EINVAL; + } + + rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq); + if (rc < 0) { + dev_err(&pdev->dev, "Could not read bus-frequency property\n"); + return -EINVAL; + } + + gpio->pclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(gpio->pclk)) { + dev_err(&pdev->dev, "devm_clk_get failed\n"); + return PTR_ERR(gpio->pclk); + } + + apb_freq = clk_get_rate(gpio->pclk); + + /* + * From the datasheet, + * SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1) + * period = 2 * (GPIO254[31:16] + 1) / PCLK + * frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK) + * frequency = PCLK / (2 * (GPIO254[31:16] + 1)) + * frequency * 2 * (GPIO254[31:16] + 1) = PCLK + * GPIO254[31:16] = PCLK / (frequency * 2) - 1 + */ + if (sgpio_freq == 0) + return -EINVAL; + + sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1; + + if (sgpio_clk_div > (1 << 16) - 1) + return -EINVAL; + + iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | + FIELD_PREP(ASPEED_SGPIO_PINS_MASK, (nr_gpios / 8)) | + ASPEED_SGPIO_ENABLE, + gpio->base + ASPEED_SGPIO_CTRL); + + spin_lock_init(&gpio->lock); + + gpio->chip.parent = &pdev->dev; + gpio->chip.ngpio = nr_gpios; + gpio->chip.direction_input = aspeed_sgpio_dir_in; + gpio->chip.direction_output = aspeed_sgpio_dir_out; + gpio->chip.get_direction = aspeed_sgpio_get_direction; + gpio->chip.request = NULL; + gpio->chip.free = NULL; + gpio->chip.get = aspeed_sgpio_get; + gpio->chip.set = aspeed_sgpio_set; + gpio->chip.set_config = NULL; + gpio->chip.label = dev_name(&pdev->dev); + gpio->chip.base = -1; + + /* set all SGPIO pins as input (1). */ + memset(gpio->dir_in, 0xff, sizeof(gpio->dir_in)); + + aspeed_sgpio_setup_irqs(gpio, pdev); + + rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); + if (rc < 0) + return rc; + + return 0; +} + +static struct platform_driver aspeed_sgpio_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = aspeed_sgpio_of_table, + }, +}; + +module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe); +MODULE_DESCRIPTION("Aspeed Serial GPIO Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index ad19df0686c93c0cdd66d18543764a4925357ab5..bd2498bbd74ac2b42ac4ffd98f7c29e09f1a04e0 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -93,11 +93,6 @@ static struct bus_type mipi_dsi_bus_type = { .pm = &mipi_dsi_device_pm_ops, }; -static int of_device_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - /** * of_find_mipi_dsi_device_by_node() - find the MIPI DSI device matching a * device tree node @@ -110,7 +105,7 @@ struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np) { struct device *dev; - dev = bus_find_device(&mipi_dsi_bus_type, NULL, np, of_device_match); + dev = bus_find_device_by_of_node(&mipi_dsi_bus_type, np); return dev ? to_mipi_dsi_device(dev) : NULL; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 58baf49d992625ef75628392195f3769f32ded02..badab94be2d6eaac5bd2b32d5d668df6caf8b9bb 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -242,9 +242,7 @@ static struct component_match *exynos_drm_match_add(struct device *dev) if (!info->driver || !(info->flags & DRM_COMPONENT_DRIVER)) continue; - while ((d = bus_find_device(&platform_bus_type, p, - &info->driver->driver, - (void *)platform_bus_type.match))) { + while ((d = platform_find_device_by_driver(p, &info->driver->driver))) { put_device(p); if (!(info->flags & DRM_FIMC_DEVICE) || @@ -412,9 +410,8 @@ static void exynos_drm_unregister_devices(void) if (!info->driver || !(info->flags & DRM_VIRTUAL_DEVICE)) continue; - while ((dev = bus_find_device(&platform_bus_type, NULL, - &info->driver->driver, - (void *)platform_bus_type.match))) { + while ((dev = platform_find_device_by_driver(NULL, + &info->driver->driver))) { put_device(dev); platform_device_unregister(to_platform_device(dev)); } diff --git a/drivers/gpu/drm/mcde/mcde_drv.c b/drivers/gpu/drm/mcde/mcde_drv.c index baf63fb6850a418c5c4b245fc09bf93fff0ef894..c07abf9e201c13f9d0cbde32cac402997e03e722 100644 --- a/drivers/gpu/drm/mcde/mcde_drv.c +++ b/drivers/gpu/drm/mcde/mcde_drv.c @@ -477,8 +477,7 @@ static int mcde_probe(struct platform_device *pdev) struct device_driver *drv = &mcde_component_drivers[i]->driver; struct device *p = NULL, *d; - while ((d = bus_find_device(&platform_bus_type, p, drv, - (void *)platform_bus_type.match))) { + while ((d = platform_find_device_by_driver(p, drv))) { put_device(p); component_match_add(dev, &match, mcde_compare_dev, d); p = d; diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c index 92ac995dd9c66be77484f5f634d463098607f91a..6e8145c36e933fc97dbf01214c8c93d9a4f10576 100644 --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c @@ -222,7 +222,7 @@ void panfrost_mmu_unmap(struct panfrost_gem_object *bo) size_t unmapped_page; size_t pgsize = get_pgsize(iova, len - unmapped_len); - unmapped_page = ops->unmap(ops, iova, pgsize); + unmapped_page = ops->unmap(ops, iova, pgsize, NULL); if (!unmapped_page) break; @@ -247,20 +247,28 @@ static void mmu_tlb_inv_context_s1(void *cookie) mmu_hw_do_operation(pfdev, 0, 0, ~0UL, AS_COMMAND_FLUSH_MEM); } -static void mmu_tlb_inv_range_nosync(unsigned long iova, size_t size, - size_t granule, bool leaf, void *cookie) -{} - static void mmu_tlb_sync_context(void *cookie) { //struct panfrost_device *pfdev = cookie; // TODO: Wait 1000 GPU cycles for HW_ISSUE_6367/T60X } -static const struct iommu_gather_ops mmu_tlb_ops = { +static void mmu_tlb_flush_walk(unsigned long iova, size_t size, size_t granule, + void *cookie) +{ + mmu_tlb_sync_context(cookie); +} + +static void mmu_tlb_flush_leaf(unsigned long iova, size_t size, size_t granule, + void *cookie) +{ + mmu_tlb_sync_context(cookie); +} + +static const struct iommu_flush_ops mmu_tlb_ops = { .tlb_flush_all = mmu_tlb_inv_context_s1, - .tlb_add_flush = mmu_tlb_inv_range_nosync, - .tlb_sync = mmu_tlb_sync_context, + .tlb_flush_walk = mmu_tlb_flush_walk, + .tlb_flush_leaf = mmu_tlb_flush_leaf, }; static const char *access_type_name(struct panfrost_device *pfdev, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 53d2c5bd61dcd1545d87153d1f1e9f92429ddf1d..38dc263769615c70e2b56f21fc885e6ca8a75c8b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -330,8 +330,7 @@ static struct component_match *rockchip_drm_match_add(struct device *dev) struct device *p = NULL, *d; do { - d = bus_find_device(&platform_bus_type, p, &drv->driver, - (void *)platform_bus_type.match); + d = platform_find_device_by_driver(p, &drv->driver); put_device(p); p = d; diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index bf11930e40e19ea3cd0eb2e65017d8530a64ae0b..1551c8253bec0e62b5f0ca7c16128f8ac93c58fc 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -237,8 +237,7 @@ static void vc4_match_add_drivers(struct device *dev, struct device_driver *drv = &drivers[i]->driver; struct device *p = NULL, *d; - while ((d = bus_find_device(&platform_bus_type, p, drv, - (void *)platform_bus_type.match))) { + while ((d = platform_find_device_by_driver(p, drv))) { put_device(p); component_match_add(dev, match, compare_dev, d); p = d; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index 0af048d1a8156acfdb24af337f3b3479c4bb1004..0c647be81ab01b697db78e84e2e481d1152c16b6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -46,8 +46,6 @@ #define RETRIES 3 #define VMW_HYPERVISOR_MAGIC 0x564D5868 -#define VMW_HYPERVISOR_PORT 0x5658 -#define VMW_HYPERVISOR_HB_PORT 0x5659 #define VMW_PORT_CMD_MSG 30 #define VMW_PORT_CMD_HB_MSG 0 @@ -93,7 +91,7 @@ static int vmw_open_channel(struct rpc_channel *channel, unsigned int protocol) VMW_PORT(VMW_PORT_CMD_OPEN_CHANNEL, (protocol | GUESTMSG_FLAG_COOKIE), si, di, - VMW_HYPERVISOR_PORT, + 0, VMW_HYPERVISOR_MAGIC, eax, ebx, ecx, edx, si, di); @@ -126,7 +124,7 @@ static int vmw_close_channel(struct rpc_channel *channel) VMW_PORT(VMW_PORT_CMD_CLOSE_CHANNEL, 0, si, di, - (VMW_HYPERVISOR_PORT | (channel->channel_id << 16)), + channel->channel_id << 16, VMW_HYPERVISOR_MAGIC, eax, ebx, ecx, edx, si, di); @@ -160,7 +158,8 @@ static unsigned long vmw_port_hb_out(struct rpc_channel *channel, VMW_PORT_HB_OUT( (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG, msg_len, si, di, - VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16), + VMWARE_HYPERVISOR_HB | (channel->channel_id << 16) | + VMWARE_HYPERVISOR_OUT, VMW_HYPERVISOR_MAGIC, bp, eax, ebx, ecx, edx, si, di); @@ -181,7 +180,7 @@ static unsigned long vmw_port_hb_out(struct rpc_channel *channel, VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_SENDPAYLOAD << 16), word, si, di, - VMW_HYPERVISOR_PORT | (channel->channel_id << 16), + channel->channel_id << 16, VMW_HYPERVISOR_MAGIC, eax, ebx, ecx, edx, si, di); } @@ -213,7 +212,7 @@ static unsigned long vmw_port_hb_in(struct rpc_channel *channel, char *reply, VMW_PORT_HB_IN( (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG, reply_len, si, di, - VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16), + VMWARE_HYPERVISOR_HB | (channel->channel_id << 16), VMW_HYPERVISOR_MAGIC, bp, eax, ebx, ecx, edx, si, di); @@ -230,7 +229,7 @@ static unsigned long vmw_port_hb_in(struct rpc_channel *channel, char *reply, VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_RECVPAYLOAD << 16), MESSAGE_STATUS_SUCCESS, si, di, - VMW_HYPERVISOR_PORT | (channel->channel_id << 16), + channel->channel_id << 16, VMW_HYPERVISOR_MAGIC, eax, ebx, ecx, edx, si, di); @@ -269,7 +268,7 @@ static int vmw_send_msg(struct rpc_channel *channel, const char *msg) VMW_PORT(VMW_PORT_CMD_SENDSIZE, msg_len, si, di, - VMW_HYPERVISOR_PORT | (channel->channel_id << 16), + channel->channel_id << 16, VMW_HYPERVISOR_MAGIC, eax, ebx, ecx, edx, si, di); @@ -327,7 +326,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg, VMW_PORT(VMW_PORT_CMD_RECVSIZE, 0, si, di, - (VMW_HYPERVISOR_PORT | (channel->channel_id << 16)), + channel->channel_id << 16, VMW_HYPERVISOR_MAGIC, eax, ebx, ecx, edx, si, di); @@ -371,7 +370,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg, VMW_PORT(VMW_PORT_CMD_RECVSTATUS, MESSAGE_STATUS_SUCCESS, si, di, - (VMW_HYPERVISOR_PORT | (channel->channel_id << 16)), + channel->channel_id << 16, VMW_HYPERVISOR_MAGIC, eax, ebx, ecx, edx, si, di); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h index 4907e50fb20a23a6d6ca6b88bf0b52354564c7b1..f685c7071decdd9c7affb75cc7bf93184c0721ea 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h @@ -32,6 +32,7 @@ #ifndef _VMWGFX_MSG_H #define _VMWGFX_MSG_H +#include /** * Hypervisor-specific bi-directional communication channel. Should never @@ -44,7 +45,7 @@ * @in_ebx: [IN] Message Len, through EBX * @in_si: [IN] Input argument through SI, set to 0 if not used * @in_di: [IN] Input argument through DI, set ot 0 if not used - * @port_num: [IN] port number + [channel id] + * @flags: [IN] hypercall flags + [channel id] * @magic: [IN] hypervisor magic value * @eax: [OUT] value of EAX register * @ebx: [OUT] e.g. status from an HB message status command @@ -54,10 +55,10 @@ * @di: [OUT] */ #define VMW_PORT(cmd, in_ebx, in_si, in_di, \ - port_num, magic, \ + flags, magic, \ eax, ebx, ecx, edx, si, di) \ ({ \ - asm volatile ("inl %%dx, %%eax;" : \ + asm volatile (VMWARE_HYPERCALL : \ "=a"(eax), \ "=b"(ebx), \ "=c"(ecx), \ @@ -67,7 +68,7 @@ "a"(magic), \ "b"(in_ebx), \ "c"(cmd), \ - "d"(port_num), \ + "d"(flags), \ "S"(in_si), \ "D"(in_di) : \ "memory"); \ @@ -85,7 +86,7 @@ * @in_ecx: [IN] Message Len, through ECX * @in_si: [IN] Input argument through SI, set to 0 if not used * @in_di: [IN] Input argument through DI, set to 0 if not used - * @port_num: [IN] port number + [channel id] + * @flags: [IN] hypercall flags + [channel id] * @magic: [IN] hypervisor magic value * @bp: [IN] * @eax: [OUT] value of EAX register @@ -98,12 +99,12 @@ #ifdef __x86_64__ #define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di, \ - port_num, magic, bp, \ + flags, magic, bp, \ eax, ebx, ecx, edx, si, di) \ ({ \ asm volatile ("push %%rbp;" \ "mov %12, %%rbp;" \ - "rep outsb;" \ + VMWARE_HYPERCALL_HB_OUT \ "pop %%rbp;" : \ "=a"(eax), \ "=b"(ebx), \ @@ -114,7 +115,7 @@ "a"(magic), \ "b"(cmd), \ "c"(in_ecx), \ - "d"(port_num), \ + "d"(flags), \ "S"(in_si), \ "D"(in_di), \ "r"(bp) : \ @@ -123,12 +124,12 @@ #define VMW_PORT_HB_IN(cmd, in_ecx, in_si, in_di, \ - port_num, magic, bp, \ + flags, magic, bp, \ eax, ebx, ecx, edx, si, di) \ ({ \ asm volatile ("push %%rbp;" \ "mov %12, %%rbp;" \ - "rep insb;" \ + VMWARE_HYPERCALL_HB_IN \ "pop %%rbp" : \ "=a"(eax), \ "=b"(ebx), \ @@ -139,7 +140,7 @@ "a"(magic), \ "b"(cmd), \ "c"(in_ecx), \ - "d"(port_num), \ + "d"(flags), \ "S"(in_si), \ "D"(in_di), \ "r"(bp) : \ @@ -157,13 +158,13 @@ * just pushed it. */ #define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di, \ - port_num, magic, bp, \ + flags, magic, bp, \ eax, ebx, ecx, edx, si, di) \ ({ \ asm volatile ("push %12;" \ "push %%ebp;" \ "mov 0x04(%%esp), %%ebp;" \ - "rep outsb;" \ + VMWARE_HYPERCALL_HB_OUT \ "pop %%ebp;" \ "add $0x04, %%esp;" : \ "=a"(eax), \ @@ -175,7 +176,7 @@ "a"(magic), \ "b"(cmd), \ "c"(in_ecx), \ - "d"(port_num), \ + "d"(flags), \ "S"(in_si), \ "D"(in_di), \ "m"(bp) : \ @@ -184,13 +185,13 @@ #define VMW_PORT_HB_IN(cmd, in_ecx, in_si, in_di, \ - port_num, magic, bp, \ + flags, magic, bp, \ eax, ebx, ecx, edx, si, di) \ ({ \ asm volatile ("push %12;" \ "push %%ebp;" \ "mov 0x04(%%esp), %%ebp;" \ - "rep insb;" \ + VMWARE_HYPERCALL_HB_IN \ "pop %%ebp;" \ "add $0x04, %%esp;" : \ "=a"(eax), \ @@ -202,7 +203,7 @@ "a"(magic), \ "b"(cmd), \ "c"(in_ecx), \ - "d"(port_num), \ + "d"(flags), \ "S"(in_si), \ "D"(in_di), \ "m"(bp) : \ diff --git a/drivers/greybus/Kconfig b/drivers/greybus/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..b84fcaf8b105cf030be181dae737245ab03fd0ef --- /dev/null +++ b/drivers/greybus/Kconfig @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0 +menuconfig GREYBUS + tristate "Greybus support" + depends on SYSFS + ---help--- + This option enables the Greybus driver core. Greybus is an + hardware protocol that was designed to provide Unipro with a + sane application layer. It was originally designed for the + ARA project, a module phone system, but has shown up in other + phones, and can be tunneled over other busses in order to + control hardware devices. + + Say Y here to enable support for these types of drivers. + + To compile this code as a module, chose M here: the module + will be called greybus.ko + +if GREYBUS + +config GREYBUS_ES2 + tristate "Greybus ES3 USB host controller" + depends on USB + ---help--- + Select this option if you have a Toshiba ES3 USB device that + acts as a Greybus "host controller". This device is a bridge + from a USB device to a Unipro network. + + To compile this code as a module, chose M here: the module + will be called gb-es2.ko + +endif # GREYBUS + diff --git a/drivers/greybus/Makefile b/drivers/greybus/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9bccdd229aa2ee6d77cb16763c9bca2a2092a2d2 --- /dev/null +++ b/drivers/greybus/Makefile @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0 +# Greybus core +greybus-y := core.o \ + debugfs.o \ + hd.o \ + manifest.o \ + module.o \ + interface.o \ + bundle.o \ + connection.o \ + control.o \ + svc.o \ + svc_watchdog.o \ + operation.o + +obj-$(CONFIG_GREYBUS) += greybus.o + +# needed for trace events +ccflags-y += -I$(src) + +# Greybus Host controller drivers +gb-es2-y := es2.o + +obj-$(CONFIG_GREYBUS_ES2) += gb-es2.o + + diff --git a/drivers/greybus/arpc.h b/drivers/greybus/arpc.h new file mode 100644 index 0000000000000000000000000000000000000000..c8b83c5cfa79f9f1626f81b5389ff17d9a3b389b --- /dev/null +++ b/drivers/greybus/arpc.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Copyright(c) 2016 Google Inc. All rights reserved. + * Copyright(c) 2016 Linaro Ltd. All rights reserved. + */ + +#ifndef __ARPC_H +#define __ARPC_H + +/* APBridgeA RPC (ARPC) */ + +enum arpc_result { + ARPC_SUCCESS = 0x00, + ARPC_NO_MEMORY = 0x01, + ARPC_INVALID = 0x02, + ARPC_TIMEOUT = 0x03, + ARPC_UNKNOWN_ERROR = 0xff, +}; + +struct arpc_request_message { + __le16 id; /* RPC unique id */ + __le16 size; /* Size in bytes of header + payload */ + __u8 type; /* RPC type */ + __u8 data[0]; /* ARPC data */ +} __packed; + +struct arpc_response_message { + __le16 id; /* RPC unique id */ + __u8 result; /* Result of RPC */ +} __packed; + +/* ARPC requests */ +#define ARPC_TYPE_CPORT_CONNECTED 0x01 +#define ARPC_TYPE_CPORT_QUIESCE 0x02 +#define ARPC_TYPE_CPORT_CLEAR 0x03 +#define ARPC_TYPE_CPORT_FLUSH 0x04 +#define ARPC_TYPE_CPORT_SHUTDOWN 0x05 + +struct arpc_cport_connected_req { + __le16 cport_id; +} __packed; + +struct arpc_cport_quiesce_req { + __le16 cport_id; + __le16 peer_space; + __le16 timeout; +} __packed; + +struct arpc_cport_clear_req { + __le16 cport_id; +} __packed; + +struct arpc_cport_flush_req { + __le16 cport_id; +} __packed; + +struct arpc_cport_shutdown_req { + __le16 cport_id; + __le16 timeout; + __u8 phase; +} __packed; + +#endif /* __ARPC_H */ diff --git a/drivers/staging/greybus/bundle.c b/drivers/greybus/bundle.c similarity index 99% rename from drivers/staging/greybus/bundle.c rename to drivers/greybus/bundle.c index 3f702db9e0986bb1ca390ccf187b021a8b3d6bd2..84660729538b95cb8624080490025a68cba4fa54 100644 --- a/drivers/staging/greybus/bundle.c +++ b/drivers/greybus/bundle.c @@ -6,7 +6,7 @@ * Copyright 2014-2015 Linaro Ltd. */ -#include "greybus.h" +#include #include "greybus_trace.h" static ssize_t bundle_class_show(struct device *dev, diff --git a/drivers/staging/greybus/connection.c b/drivers/greybus/connection.c similarity index 99% rename from drivers/staging/greybus/connection.c rename to drivers/greybus/connection.c index eda964208cce183acc14aed87be83f99bfa58fc3..fc8f57f97ce62d719515f63f81e4c55f4cbd089a 100644 --- a/drivers/staging/greybus/connection.c +++ b/drivers/greybus/connection.c @@ -7,8 +7,8 @@ */ #include +#include -#include "greybus.h" #include "greybus_trace.h" #define GB_CONNECTION_CPORT_QUIESCE_TIMEOUT 1000 diff --git a/drivers/staging/greybus/control.c b/drivers/greybus/control.c similarity index 99% rename from drivers/staging/greybus/control.c rename to drivers/greybus/control.c index a9e8b6036cac9eb6c3636cf14f4a96f486e2528b..359a2584197397dc5351fa0f01b1c3ac5a79444f 100644 --- a/drivers/staging/greybus/control.c +++ b/drivers/greybus/control.c @@ -9,7 +9,7 @@ #include #include #include -#include "greybus.h" +#include /* Highest control-protocol version supported */ #define GB_CONTROL_VERSION_MAJOR 0 diff --git a/drivers/staging/greybus/core.c b/drivers/greybus/core.c similarity index 99% rename from drivers/staging/greybus/core.c rename to drivers/greybus/core.c index d6b0d49130c0e93f73a0a7ad9d2ad468aa32bd02..e546c6431877fce0ce71967ebe3b222de6d6f972 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/greybus/core.c @@ -9,7 +9,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define CREATE_TRACE_POINTS -#include "greybus.h" +#include #include "greybus_trace.h" #define GB_BUNDLE_AUTOSUSPEND_MS 3000 diff --git a/drivers/staging/greybus/debugfs.c b/drivers/greybus/debugfs.c similarity index 94% rename from drivers/staging/greybus/debugfs.c rename to drivers/greybus/debugfs.c index 56e20c30feb5d2342176bba96c38af510cd6bc4a..e102d7badb9d90f0581067f334d64c986d72e54f 100644 --- a/drivers/staging/greybus/debugfs.c +++ b/drivers/greybus/debugfs.c @@ -7,8 +7,7 @@ */ #include - -#include "greybus.h" +#include static struct dentry *gb_debug_root; diff --git a/drivers/staging/greybus/es2.c b/drivers/greybus/es2.c similarity index 99% rename from drivers/staging/greybus/es2.c rename to drivers/greybus/es2.c index be6af18cec31584547fc0a19a49e3d2d5ceab83a..366716f11b1a5087a6263fe5f0d9d08873839848 100644 --- a/drivers/staging/greybus/es2.c +++ b/drivers/greybus/es2.c @@ -11,12 +11,11 @@ #include #include #include +#include #include #include "arpc.h" -#include "greybus.h" #include "greybus_trace.h" -#include "connection.h" /* Default timeout for USB vendor requests. */ diff --git a/drivers/staging/greybus/greybus_trace.h b/drivers/greybus/greybus_trace.h similarity index 99% rename from drivers/staging/greybus/greybus_trace.h rename to drivers/greybus/greybus_trace.h index 7b5e2c6b1f6b9701a9afa812233fed645317f536..1bc9f1275c653c5dd00df5f955bb9681329a0434 100644 --- a/drivers/staging/greybus/greybus_trace.h +++ b/drivers/greybus/greybus_trace.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Greybus driver and device API * diff --git a/drivers/staging/greybus/hd.c b/drivers/greybus/hd.c similarity index 96% rename from drivers/staging/greybus/hd.c rename to drivers/greybus/hd.c index 969f86697673793297ed4bb838ae587d3caca2c4..72b21bf2d7d36a85cbfd05d261d760fa37f16205 100644 --- a/drivers/staging/greybus/hd.c +++ b/drivers/greybus/hd.c @@ -8,8 +8,8 @@ #include #include +#include -#include "greybus.h" #include "greybus_trace.h" EXPORT_TRACEPOINT_SYMBOL_GPL(gb_hd_create); @@ -31,7 +31,7 @@ int gb_hd_output(struct gb_host_device *hd, void *req, u16 size, u8 cmd, EXPORT_SYMBOL_GPL(gb_hd_output); static ssize_t bus_id_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { struct gb_host_device *hd = to_gb_host_device(dev); @@ -70,7 +70,7 @@ EXPORT_SYMBOL_GPL(gb_hd_cport_release_reserved); /* Locking: Caller guarantees serialisation */ int gb_hd_cport_allocate(struct gb_host_device *hd, int cport_id, - unsigned long flags) + unsigned long flags) { struct ida *id_map = &hd->cport_id_map; int ida_start, ida_end; @@ -122,9 +122,9 @@ struct device_type greybus_hd_type = { }; struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver, - struct device *parent, - size_t buffer_size_max, - size_t num_cports) + struct device *parent, + size_t buffer_size_max, + size_t num_cports) { struct gb_host_device *hd; int ret; diff --git a/drivers/staging/greybus/interface.c b/drivers/greybus/interface.c similarity index 99% rename from drivers/staging/greybus/interface.c rename to drivers/greybus/interface.c index d7b5b89a2f406c87a0def2cc676f7c302b1e4c76..67dbe6fda9a133b43baf7feda84df58f4cc5364d 100644 --- a/drivers/staging/greybus/interface.c +++ b/drivers/greybus/interface.c @@ -7,8 +7,8 @@ */ #include +#include -#include "greybus.h" #include "greybus_trace.h" #define GB_INTERFACE_MODE_SWITCH_TIMEOUT 2000 diff --git a/drivers/staging/greybus/manifest.c b/drivers/greybus/manifest.c similarity index 95% rename from drivers/staging/greybus/manifest.c rename to drivers/greybus/manifest.c index 08db49264f2b3f506b37daeabf78fe1073ee666e..dd7040697bde9fcdbb17527b2759a16d4e94d651 100644 --- a/drivers/staging/greybus/manifest.c +++ b/drivers/greybus/manifest.c @@ -6,7 +6,7 @@ * Copyright 2014-2015 Linaro Ltd. */ -#include "greybus.h" +#include static const char *get_descriptor_type_string(u8 type) { @@ -104,15 +104,15 @@ static int identify_descriptor(struct gb_interface *intf, size_t expected_size; if (size < sizeof(*desc_header)) { - dev_err(&intf->dev, "manifest too small (%zu < %zu)\n", - size, sizeof(*desc_header)); + dev_err(&intf->dev, "manifest too small (%zu < %zu)\n", size, + sizeof(*desc_header)); return -EINVAL; /* Must at least have header */ } desc_size = le16_to_cpu(desc_header->size); if (desc_size > size) { dev_err(&intf->dev, "descriptor too big (%zu > %zu)\n", - desc_size, size); + desc_size, size); return -EINVAL; } @@ -139,22 +139,22 @@ static int identify_descriptor(struct gb_interface *intf, case GREYBUS_TYPE_INVALID: default: dev_err(&intf->dev, "invalid descriptor type (%u)\n", - desc_header->type); + desc_header->type); return -EINVAL; } if (desc_size < expected_size) { dev_err(&intf->dev, "%s descriptor too small (%zu < %zu)\n", - get_descriptor_type_string(desc_header->type), - desc_size, expected_size); + get_descriptor_type_string(desc_header->type), + desc_size, expected_size); return -EINVAL; } /* Descriptor bigger than what we expect */ if (desc_size > expected_size) { dev_warn(&intf->dev, "%s descriptor size mismatch (want %zu got %zu)\n", - get_descriptor_type_string(desc_header->type), - expected_size, desc_size); + get_descriptor_type_string(desc_header->type), + expected_size, desc_size); } descriptor = kzalloc(sizeof(*descriptor), GFP_KERNEL); @@ -208,7 +208,7 @@ static char *gb_string_get(struct gb_interface *intf, u8 string_id) /* Allocate an extra byte so we can guarantee it's NUL-terminated */ string = kmemdup(&desc_string->string, desc_string->length + 1, - GFP_KERNEL); + GFP_KERNEL); if (!string) return ERR_PTR(-ENOMEM); string[desc_string->length] = '\0'; @@ -264,8 +264,7 @@ static u32 gb_manifest_parse_cports(struct gb_bundle *bundle) desc_cport = tmp->data; if (cport_id == le16_to_cpu(desc_cport->id)) { dev_err(&bundle->dev, - "duplicate CPort %u found\n", - cport_id); + "duplicate CPort %u found\n", cport_id); goto exit; } } @@ -277,7 +276,7 @@ static u32 gb_manifest_parse_cports(struct gb_bundle *bundle) return 0; bundle->cport_desc = kcalloc(count, sizeof(*bundle->cport_desc), - GFP_KERNEL); + GFP_KERNEL); if (!bundle->cport_desc) goto exit; @@ -287,7 +286,7 @@ static u32 gb_manifest_parse_cports(struct gb_bundle *bundle) list_for_each_entry_safe(desc, next, &list, links) { desc_cport = desc->data; memcpy(&bundle->cport_desc[i++], desc_cport, - sizeof(*desc_cport)); + sizeof(*desc_cport)); /* Release the cport descriptor */ release_manifest_descriptor(desc); @@ -333,9 +332,9 @@ static u32 gb_manifest_parse_bundles(struct gb_interface *intf) /* Ignore any legacy control bundles */ if (bundle_id == GB_CONTROL_BUNDLE_ID) { dev_dbg(&intf->dev, "%s - ignoring control bundle\n", - __func__); + __func__); release_cport_descriptors(&intf->manifest_descs, - bundle_id); + bundle_id); continue; } @@ -468,7 +467,7 @@ bool gb_manifest_parse(struct gb_interface *intf, void *data, size_t size) /* we have to have at _least_ the manifest header */ if (size < sizeof(*header)) { dev_err(&intf->dev, "short manifest (%zu < %zu)\n", - size, sizeof(*header)); + size, sizeof(*header)); return false; } @@ -478,15 +477,15 @@ bool gb_manifest_parse(struct gb_interface *intf, void *data, size_t size) manifest_size = le16_to_cpu(header->size); if (manifest_size != size) { dev_err(&intf->dev, "manifest size mismatch (%zu != %u)\n", - size, manifest_size); + size, manifest_size); return false; } /* Validate major/minor number */ if (header->version_major > GREYBUS_VERSION_MAJOR) { dev_err(&intf->dev, "manifest version too new (%u.%u > %u.%u)\n", - header->version_major, header->version_minor, - GREYBUS_VERSION_MAJOR, GREYBUS_VERSION_MINOR); + header->version_major, header->version_minor, + GREYBUS_VERSION_MAJOR, GREYBUS_VERSION_MINOR); return false; } @@ -513,7 +512,7 @@ bool gb_manifest_parse(struct gb_interface *intf, void *data, size_t size) } if (found != 1) { dev_err(&intf->dev, "manifest must have 1 interface descriptor (%u found)\n", - found); + found); result = false; goto out; } diff --git a/drivers/staging/greybus/module.c b/drivers/greybus/module.c similarity index 99% rename from drivers/staging/greybus/module.c rename to drivers/greybus/module.c index b251a53d0e8ee6617a78e86367302b4c1ff07443..36f77f9e1d7439eaf9c16e871a3fd28a6a218bf5 100644 --- a/drivers/staging/greybus/module.c +++ b/drivers/greybus/module.c @@ -6,7 +6,7 @@ * Copyright 2016 Linaro Ltd. */ -#include "greybus.h" +#include #include "greybus_trace.h" static ssize_t eject_store(struct device *dev, diff --git a/drivers/staging/greybus/operation.c b/drivers/greybus/operation.c similarity index 99% rename from drivers/staging/greybus/operation.c rename to drivers/greybus/operation.c index fe268f7b63ed76e01b3b62bb7601ed0a352c74f4..8459e9bc07498988ab46b5fdf411bcd679299ca4 100644 --- a/drivers/staging/greybus/operation.c +++ b/drivers/greybus/operation.c @@ -12,8 +12,8 @@ #include #include #include +#include -#include "greybus.h" #include "greybus_trace.h" static struct kmem_cache *gb_operation_cache; diff --git a/drivers/staging/greybus/svc.c b/drivers/greybus/svc.c similarity index 99% rename from drivers/staging/greybus/svc.c rename to drivers/greybus/svc.c index 05bc45287b87658b8c5c23c588204fd083aea997..ce7740ef449babaf0f7bfd1afd2021cb6c7a7aec 100644 --- a/drivers/staging/greybus/svc.c +++ b/drivers/greybus/svc.c @@ -8,8 +8,7 @@ #include #include - -#include "greybus.h" +#include #define SVC_INTF_EJECT_TIMEOUT 9000 #define SVC_INTF_ACTIVATE_TIMEOUT 6000 diff --git a/drivers/staging/greybus/svc_watchdog.c b/drivers/greybus/svc_watchdog.c similarity index 99% rename from drivers/staging/greybus/svc_watchdog.c rename to drivers/greybus/svc_watchdog.c index 7868ad8211c5df7694c46377097b0fc8ff6276d1..b6b1682c19c455a87810e4c6477275430a8c25fa 100644 --- a/drivers/staging/greybus/svc_watchdog.c +++ b/drivers/greybus/svc_watchdog.c @@ -8,7 +8,7 @@ #include #include #include -#include "greybus.h" +#include #define SVC_WATCHDOG_PERIOD (2 * HZ) diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index 8b3a922bdad3415e8831e83901fa2fd81426f40e..2cf83856f2e41c7e6c1456224988eaaa6a370e0f 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -303,7 +303,7 @@ static void ms_ff_worker(struct work_struct *work) r->magnitude[MAGNITUDE_WEAK] = ms->weak; /* right actuator */ ret = hid_hw_output_report(hdev, (__u8 *)r, sizeof(*r)); - if (ret) + if (ret < 0) hid_warn(hdev, "failed to send FF report\n"); } diff --git a/drivers/hsi/clients/ssi_protocol.c b/drivers/hsi/clients/ssi_protocol.c index 9aeed98b87a1d19624eb6b8d31e1acd88769f9b1..0253e76f1df27bb5cbe7ff68b8f62117436a641d 100644 --- a/drivers/hsi/clients/ssi_protocol.c +++ b/drivers/hsi/clients/ssi_protocol.c @@ -181,7 +181,8 @@ static void ssip_skb_to_msg(struct sk_buff *skb, struct hsi_msg *msg) sg = sg_next(sg); BUG_ON(!sg); frag = &skb_shinfo(skb)->frags[i]; - sg_set_page(sg, frag->page.p, frag->size, frag->page_offset); + sg_set_page(sg, skb_frag_page(frag), skb_frag_size(frag), + skb_frag_off(frag)); } } diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index 9a59957922d41e82e763260a41e98c158e77cbea..79e5356a737a2ad6b9fb19a498613eba20aa9761 100644 --- a/drivers/hv/Kconfig +++ b/drivers/hv/Kconfig @@ -14,9 +14,6 @@ config HYPERV config HYPERV_TIMER def_bool HYPERV -config HYPERV_TSCPAGE - def_bool HYPERV && X86_64 - config HYPERV_UTILS tristate "Microsoft Hyper-V Utilities driver" depends on HYPERV && CONNECTOR && NLS diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index fb16a622e8ab8dd9623e734baf5ef6b6f23d18ff..50eaa1fd6e4599b43bf07dfa3408eff0b9f4562b 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -190,11 +190,11 @@ int hv_ringbuffer_read(struct vmbus_channel *channel, u64 *requestid, bool raw); /* - * Maximum channels is determined by the size of the interrupt page - * which is PAGE_SIZE. 1/2 of PAGE_SIZE is for send endpoint interrupt - * and the other is receive endpoint interrupt + * The Maximum number of channels (16348) is determined by the size of the + * interrupt page, which is HV_HYP_PAGE_SIZE. 1/2 of HV_HYP_PAGE_SIZE is to + * send endpoint interrupts, and the other is to receive endpoint interrupts. */ -#define MAX_NUM_CHANNELS ((PAGE_SIZE >> 1) << 3) /* 16348 channels */ +#define MAX_NUM_CHANNELS ((HV_HYP_PAGE_SIZE >> 1) << 3) /* The value here must be in multiple of 32 */ /* TODO: Need to make this configurable */ diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 650dd71f9724ae605761066b75ff191dc8bd7229..2ca5668bdb626a866b9b581caa0e76af23378f28 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -246,6 +246,16 @@ config SENSORS_ADT7475 This driver can also be built as a module. If so, the module will be called adt7475. +config SENSORS_AS370 + tristate "Synaptics AS370 SoC hardware monitoring driver" + help + If you say yes here you get support for the PVT sensors of + the Synaptics AS370 SoC + + This driver can also be built as a module. If so, the module + will be called as370-hwmon. + + config SENSORS_ASC7621 tristate "Andigilog aSC7621" depends on I2C @@ -1382,8 +1392,8 @@ config SENSORS_SHTC1 tristate "Sensiron humidity and temperature sensors. SHTC1 and compat." depends on I2C help - If you say yes here you get support for the Sensiron SHTC1 and SHTW1 - humidity and temperature sensors. + If you say yes here you get support for the Sensiron SHTC1, SHTW1, + and SHTC3 humidity and temperature sensors. This driver can also be built as a module. If so, the module will be called shtc1. @@ -1570,16 +1580,6 @@ config SENSORS_ADC128D818 This driver can also be built as a module. If so, the module will be called adc128d818. -config SENSORS_ADS1015 - tristate "Texas Instruments ADS1015" - depends on I2C - help - If you say yes here you get support for Texas Instruments - ADS1015/ADS1115 12/16-bit 4-input ADC device. - - This driver can also be built as a module. If so, the module - will be called ads1015. - config SENSORS_ADS7828 tristate "Texas Instruments ADS7828 and compatibles" depends on I2C @@ -1834,17 +1834,12 @@ config SENSORS_W83795 will be called w83795. config SENSORS_W83795_FANCTRL - bool "Include automatic fan control support (DANGEROUS)" + bool "Include automatic fan control support" depends on SENSORS_W83795 help If you say yes here, support for automatic fan speed control will be included in the driver. - This part of the code wasn't carefully reviewed and tested yet, - so enabling this option is strongly discouraged on production - servers. Only developers and testers should enable it for the - time being. - Please also note that this option will create sysfs attribute files which may change in the future, so you shouldn't rely on them being stable. diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 8db472ea04f00880b8aee3a303847d95fb733261..c86ce4d3d36b9e67f2173cceed38466c36051657 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -35,7 +35,6 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o -obj-$(CONFIG_SENSORS_ADS1015) += ads1015.o obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o obj-$(CONFIG_SENSORS_ADS7871) += ads7871.o obj-$(CONFIG_SENSORS_ADT7X10) += adt7x10.o @@ -48,6 +47,7 @@ obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o obj-$(CONFIG_SENSORS_ARM_SCMI) += scmi-hwmon.o obj-$(CONFIG_SENSORS_ARM_SCPI) += scpi-hwmon.o +obj-$(CONFIG_SENSORS_AS370) += as370-hwmon.o obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o obj-$(CONFIG_SENSORS_ASPEED) += aspeed-pwm-tacho.o obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 6ba1a08253f0a3cc12a7657e4c31a0853c13b963..4cf25458f0b9515e419a6f0b88047bf35809a2e5 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -681,8 +681,8 @@ static int setup_attrs(struct acpi_power_meter_resource *resource) if (resource->caps.flags & POWER_METER_CAN_CAP) { if (!can_cap_in_hardware()) { - dev_err(&resource->acpi_dev->dev, - "Ignoring unsafe software power cap!\n"); + dev_warn(&resource->acpi_dev->dev, + "Ignoring unsafe software power cap!\n"); goto skip_unsafe_cap; } diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c deleted file mode 100644 index 3727a3762eb8874ffd0c3e111d5f18858b949ece..0000000000000000000000000000000000000000 --- a/drivers/hwmon/ads1015.c +++ /dev/null @@ -1,324 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * ads1015.c - lm_sensors driver for ads1015 12-bit 4-input ADC - * (C) Copyright 2010 - * Dirk Eibach, Guntermann & Drunck GmbH - * - * Based on the ads7828 driver by Steve Hardy. - * - * Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads1015.pdf - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* ADS1015 registers */ -enum { - ADS1015_CONVERSION = 0, - ADS1015_CONFIG = 1, -}; - -/* PGA fullscale voltages in mV */ -static const unsigned int fullscale_table[8] = { - 6144, 4096, 2048, 1024, 512, 256, 256, 256 }; - -/* Data rates in samples per second */ -static const unsigned int data_rate_table_1015[8] = { - 128, 250, 490, 920, 1600, 2400, 3300, 3300 -}; - -static const unsigned int data_rate_table_1115[8] = { - 8, 16, 32, 64, 128, 250, 475, 860 -}; - -#define ADS1015_DEFAULT_CHANNELS 0xff -#define ADS1015_DEFAULT_PGA 2 -#define ADS1015_DEFAULT_DATA_RATE 4 - -enum ads1015_chips { - ads1015, - ads1115, -}; - -struct ads1015_data { - struct device *hwmon_dev; - struct mutex update_lock; /* mutex protect updates */ - struct ads1015_channel_data channel_data[ADS1015_CHANNELS]; - enum ads1015_chips id; -}; - -static int ads1015_read_adc(struct i2c_client *client, unsigned int channel) -{ - u16 config; - struct ads1015_data *data = i2c_get_clientdata(client); - unsigned int pga = data->channel_data[channel].pga; - unsigned int data_rate = data->channel_data[channel].data_rate; - unsigned int conversion_time_ms; - const unsigned int * const rate_table = data->id == ads1115 ? - data_rate_table_1115 : data_rate_table_1015; - int res; - - mutex_lock(&data->update_lock); - - /* get channel parameters */ - res = i2c_smbus_read_word_swapped(client, ADS1015_CONFIG); - if (res < 0) - goto err_unlock; - config = res; - conversion_time_ms = DIV_ROUND_UP(1000, rate_table[data_rate]); - - /* setup and start single conversion */ - config &= 0x001f; - config |= (1 << 15) | (1 << 8); - config |= (channel & 0x0007) << 12; - config |= (pga & 0x0007) << 9; - config |= (data_rate & 0x0007) << 5; - - res = i2c_smbus_write_word_swapped(client, ADS1015_CONFIG, config); - if (res < 0) - goto err_unlock; - - /* wait until conversion finished */ - msleep(conversion_time_ms); - res = i2c_smbus_read_word_swapped(client, ADS1015_CONFIG); - if (res < 0) - goto err_unlock; - config = res; - if (!(config & (1 << 15))) { - /* conversion not finished in time */ - res = -EIO; - goto err_unlock; - } - - res = i2c_smbus_read_word_swapped(client, ADS1015_CONVERSION); - -err_unlock: - mutex_unlock(&data->update_lock); - return res; -} - -static int ads1015_reg_to_mv(struct i2c_client *client, unsigned int channel, - s16 reg) -{ - struct ads1015_data *data = i2c_get_clientdata(client); - unsigned int pga = data->channel_data[channel].pga; - int fullscale = fullscale_table[pga]; - const int mask = data->id == ads1115 ? 0x7fff : 0x7ff0; - - return DIV_ROUND_CLOSEST(reg * fullscale, mask); -} - -/* sysfs callback function */ -static ssize_t in_show(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct i2c_client *client = to_i2c_client(dev); - int res; - int index = attr->index; - - res = ads1015_read_adc(client, index); - if (res < 0) - return res; - - return sprintf(buf, "%d\n", ads1015_reg_to_mv(client, index, res)); -} - -static const struct sensor_device_attribute ads1015_in[] = { - SENSOR_ATTR_RO(in0_input, in, 0), - SENSOR_ATTR_RO(in1_input, in, 1), - SENSOR_ATTR_RO(in2_input, in, 2), - SENSOR_ATTR_RO(in3_input, in, 3), - SENSOR_ATTR_RO(in4_input, in, 4), - SENSOR_ATTR_RO(in5_input, in, 5), - SENSOR_ATTR_RO(in6_input, in, 6), - SENSOR_ATTR_RO(in7_input, in, 7), -}; - -/* - * Driver interface - */ - -static int ads1015_remove(struct i2c_client *client) -{ - struct ads1015_data *data = i2c_get_clientdata(client); - int k; - - hwmon_device_unregister(data->hwmon_dev); - for (k = 0; k < ADS1015_CHANNELS; ++k) - device_remove_file(&client->dev, &ads1015_in[k].dev_attr); - return 0; -} - -#ifdef CONFIG_OF -static int ads1015_get_channels_config_of(struct i2c_client *client) -{ - struct ads1015_data *data = i2c_get_clientdata(client); - struct device_node *node; - - if (!client->dev.of_node - || !of_get_next_child(client->dev.of_node, NULL)) - return -EINVAL; - - for_each_child_of_node(client->dev.of_node, node) { - u32 pval; - unsigned int channel; - unsigned int pga = ADS1015_DEFAULT_PGA; - unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE; - - if (of_property_read_u32(node, "reg", &pval)) { - dev_err(&client->dev, "invalid reg on %pOF\n", node); - continue; - } - - channel = pval; - if (channel >= ADS1015_CHANNELS) { - dev_err(&client->dev, - "invalid channel index %d on %pOF\n", - channel, node); - continue; - } - - if (!of_property_read_u32(node, "ti,gain", &pval)) { - pga = pval; - if (pga > 6) { - dev_err(&client->dev, "invalid gain on %pOF\n", - node); - return -EINVAL; - } - } - - if (!of_property_read_u32(node, "ti,datarate", &pval)) { - data_rate = pval; - if (data_rate > 7) { - dev_err(&client->dev, - "invalid data_rate on %pOF\n", node); - return -EINVAL; - } - } - - data->channel_data[channel].enabled = true; - data->channel_data[channel].pga = pga; - data->channel_data[channel].data_rate = data_rate; - } - - return 0; -} -#endif - -static void ads1015_get_channels_config(struct i2c_client *client) -{ - unsigned int k; - struct ads1015_data *data = i2c_get_clientdata(client); - struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev); - - /* prefer platform data */ - if (pdata) { - memcpy(data->channel_data, pdata->channel_data, - sizeof(data->channel_data)); - return; - } - -#ifdef CONFIG_OF - if (!ads1015_get_channels_config_of(client)) - return; -#endif - - /* fallback on default configuration */ - for (k = 0; k < ADS1015_CHANNELS; ++k) { - data->channel_data[k].enabled = true; - data->channel_data[k].pga = ADS1015_DEFAULT_PGA; - data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE; - } -} - -static int ads1015_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct ads1015_data *data; - int err; - unsigned int k; - - data = devm_kzalloc(&client->dev, sizeof(struct ads1015_data), - GFP_KERNEL); - if (!data) - return -ENOMEM; - - if (client->dev.of_node) - data->id = (enum ads1015_chips) - of_device_get_match_data(&client->dev); - else - data->id = id->driver_data; - i2c_set_clientdata(client, data); - mutex_init(&data->update_lock); - - /* build sysfs attribute group */ - ads1015_get_channels_config(client); - for (k = 0; k < ADS1015_CHANNELS; ++k) { - if (!data->channel_data[k].enabled) - continue; - err = device_create_file(&client->dev, &ads1015_in[k].dev_attr); - if (err) - goto exit_remove; - } - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - - return 0; - -exit_remove: - for (k = 0; k < ADS1015_CHANNELS; ++k) - device_remove_file(&client->dev, &ads1015_in[k].dev_attr); - return err; -} - -static const struct i2c_device_id ads1015_id[] = { - { "ads1015", ads1015}, - { "ads1115", ads1115}, - { } -}; -MODULE_DEVICE_TABLE(i2c, ads1015_id); - -static const struct of_device_id __maybe_unused ads1015_of_match[] = { - { - .compatible = "ti,ads1015", - .data = (void *)ads1015 - }, - { - .compatible = "ti,ads1115", - .data = (void *)ads1115 - }, - { }, -}; -MODULE_DEVICE_TABLE(of, ads1015_of_match); - -static struct i2c_driver ads1015_driver = { - .driver = { - .name = "ads1015", - .of_match_table = of_match_ptr(ads1015_of_match), - }, - .probe = ads1015_probe, - .remove = ads1015_remove, - .id_table = ads1015_id, -}; - -module_i2c_driver(ads1015_driver); - -MODULE_AUTHOR("Dirk Eibach "); -MODULE_DESCRIPTION("ADS1015 driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index c3c6031a728520d9e0035de8ff2e5e02d693d41f..6c64d50c9aae8ec175d9477fa98af6c851849d2f 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -187,7 +187,7 @@ static const struct of_device_id __maybe_unused adt7475_of_match[] = { MODULE_DEVICE_TABLE(of, adt7475_of_match); struct adt7475_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex lock; unsigned long measure_updated; @@ -212,6 +212,7 @@ struct adt7475_data { u8 vid; u8 vrm; + const struct attribute_group *groups[9]; }; static struct i2c_driver adt7475_driver; @@ -346,8 +347,8 @@ static ssize_t voltage_store(struct device *dev, { struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); - struct i2c_client *client = to_i2c_client(dev); - struct adt7475_data *data = i2c_get_clientdata(client); + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned char reg; long val; @@ -440,8 +441,8 @@ static ssize_t temp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); - struct i2c_client *client = to_i2c_client(dev); - struct adt7475_data *data = i2c_get_clientdata(client); + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned char reg = 0; u8 out; int temp; @@ -542,8 +543,7 @@ static ssize_t temp_st_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); - struct i2c_client *client = to_i2c_client(dev); - struct adt7475_data *data = i2c_get_clientdata(client); + struct adt7475_data *data = dev_get_drvdata(dev); long val; switch (sattr->index) { @@ -570,8 +570,8 @@ static ssize_t temp_st_store(struct device *dev, size_t count) { struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); - struct i2c_client *client = to_i2c_client(dev); - struct adt7475_data *data = i2c_get_clientdata(client); + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned char reg; int shift, idx; ulong val; @@ -647,8 +647,8 @@ static ssize_t point2_show(struct device *dev, struct device_attribute *attr, static ssize_t point2_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct adt7475_data *data = i2c_get_clientdata(client); + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); int temp; long val; @@ -710,8 +710,8 @@ static ssize_t tach_store(struct device *dev, struct device_attribute *attr, { struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); - struct i2c_client *client = to_i2c_client(dev); - struct adt7475_data *data = i2c_get_clientdata(client); + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; if (kstrtoul(buf, 10, &val)) @@ -769,8 +769,8 @@ static ssize_t pwm_store(struct device *dev, struct device_attribute *attr, { struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); - struct i2c_client *client = to_i2c_client(dev); - struct adt7475_data *data = i2c_get_clientdata(client); + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned char reg = 0; long val; @@ -818,8 +818,8 @@ static ssize_t stall_disable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); - struct i2c_client *client = to_i2c_client(dev); - struct adt7475_data *data = i2c_get_clientdata(client); + struct adt7475_data *data = dev_get_drvdata(dev); + u8 mask = BIT(5 + sattr->index); return sprintf(buf, "%d\n", !!(data->enh_acoustics[0] & mask)); @@ -830,8 +830,8 @@ static ssize_t stall_disable_store(struct device *dev, const char *buf, size_t count) { struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); - struct i2c_client *client = to_i2c_client(dev); - struct adt7475_data *data = i2c_get_clientdata(client); + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long val; u8 mask = BIT(5 + sattr->index); @@ -914,8 +914,8 @@ static ssize_t pwmchan_store(struct device *dev, size_t count) { struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); - struct i2c_client *client = to_i2c_client(dev); - struct adt7475_data *data = i2c_get_clientdata(client); + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int r; long val; @@ -938,8 +938,8 @@ static ssize_t pwmctrl_store(struct device *dev, size_t count) { struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); - struct i2c_client *client = to_i2c_client(dev); - struct adt7475_data *data = i2c_get_clientdata(client); + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int r; long val; @@ -982,8 +982,8 @@ static ssize_t pwmfreq_store(struct device *dev, size_t count) { struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); - struct i2c_client *client = to_i2c_client(dev); - struct adt7475_data *data = i2c_get_clientdata(client); + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int out; long val; @@ -1022,8 +1022,8 @@ static ssize_t pwm_use_point2_pwm_at_crit_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct adt7475_data *data = i2c_get_clientdata(client); + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long val; if (kstrtol(buf, 10, &val)) @@ -1342,26 +1342,6 @@ static int adt7475_detect(struct i2c_client *client, return 0; } -static void adt7475_remove_files(struct i2c_client *client, - struct adt7475_data *data) -{ - sysfs_remove_group(&client->dev.kobj, &adt7475_attr_group); - if (data->has_fan4) - sysfs_remove_group(&client->dev.kobj, &fan4_attr_group); - if (data->has_pwm2) - sysfs_remove_group(&client->dev.kobj, &pwm2_attr_group); - if (data->has_voltage & (1 << 0)) - sysfs_remove_group(&client->dev.kobj, &in0_attr_group); - if (data->has_voltage & (1 << 3)) - sysfs_remove_group(&client->dev.kobj, &in3_attr_group); - if (data->has_voltage & (1 << 4)) - sysfs_remove_group(&client->dev.kobj, &in4_attr_group); - if (data->has_voltage & (1 << 5)) - sysfs_remove_group(&client->dev.kobj, &in5_attr_group); - if (data->has_vid) - sysfs_remove_group(&client->dev.kobj, &vid_attr_group); -} - static int adt7475_update_limits(struct i2c_client *client) { struct adt7475_data *data = i2c_get_clientdata(client); @@ -1489,7 +1469,8 @@ static int adt7475_probe(struct i2c_client *client, }; struct adt7475_data *data; - int i, ret = 0, revision; + struct device *hwmon_dev; + int i, ret = 0, revision, group_num = 0; u8 config2, config3; data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); @@ -1497,6 +1478,7 @@ static int adt7475_probe(struct i2c_client *client, return -ENOMEM; mutex_init(&data->lock); + data->client = client; i2c_set_clientdata(client, data); if (client->dev.of_node) @@ -1590,52 +1572,40 @@ static int adt7475_probe(struct i2c_client *client, break; } - ret = sysfs_create_group(&client->dev.kobj, &adt7475_attr_group); - if (ret) - return ret; + data->groups[group_num++] = &adt7475_attr_group; /* Features that can be disabled individually */ if (data->has_fan4) { - ret = sysfs_create_group(&client->dev.kobj, &fan4_attr_group); - if (ret) - goto eremove; + data->groups[group_num++] = &fan4_attr_group; } if (data->has_pwm2) { - ret = sysfs_create_group(&client->dev.kobj, &pwm2_attr_group); - if (ret) - goto eremove; + data->groups[group_num++] = &pwm2_attr_group; } if (data->has_voltage & (1 << 0)) { - ret = sysfs_create_group(&client->dev.kobj, &in0_attr_group); - if (ret) - goto eremove; + data->groups[group_num++] = &in0_attr_group; } if (data->has_voltage & (1 << 3)) { - ret = sysfs_create_group(&client->dev.kobj, &in3_attr_group); - if (ret) - goto eremove; + data->groups[group_num++] = &in3_attr_group; } if (data->has_voltage & (1 << 4)) { - ret = sysfs_create_group(&client->dev.kobj, &in4_attr_group); - if (ret) - goto eremove; + data->groups[group_num++] = &in4_attr_group; } if (data->has_voltage & (1 << 5)) { - ret = sysfs_create_group(&client->dev.kobj, &in5_attr_group); - if (ret) - goto eremove; + data->groups[group_num++] = &in5_attr_group; } if (data->has_vid) { data->vrm = vid_which_vrm(); - ret = sysfs_create_group(&client->dev.kobj, &vid_attr_group); - if (ret) - goto eremove; + data->groups[group_num] = &vid_attr_group; } - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - ret = PTR_ERR(data->hwmon_dev); - goto eremove; + /* register device with all the acquired attributes */ + hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev, + client->name, data, + data->groups); + + if (IS_ERR(hwmon_dev)) { + ret = PTR_ERR(hwmon_dev); + return ret; } dev_info(&client->dev, "%s device, revision %d\n", @@ -1657,21 +1627,7 @@ static int adt7475_probe(struct i2c_client *client, /* Limits and settings, should never change update more than once */ ret = adt7475_update_limits(client); if (ret) - goto eremove; - - return 0; - -eremove: - adt7475_remove_files(client, data); - return ret; -} - -static int adt7475_remove(struct i2c_client *client) -{ - struct adt7475_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - adt7475_remove_files(client, data); + return ret; return 0; } @@ -1683,7 +1639,6 @@ static struct i2c_driver adt7475_driver = { .of_match_table = of_match_ptr(adt7475_of_match), }, .probe = adt7475_probe, - .remove = adt7475_remove, .id_table = adt7475_id, .detect = adt7475_detect, .address_list = normal_i2c, @@ -1757,8 +1712,8 @@ static void adt7475_read_pwm(struct i2c_client *client, int index) static int adt7475_update_measure(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct adt7475_data *data = i2c_get_clientdata(client); + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; u16 ext; int i; int ret; @@ -1854,8 +1809,7 @@ static int adt7475_update_measure(struct device *dev) static struct adt7475_data *adt7475_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct adt7475_data *data = i2c_get_clientdata(client); + struct adt7475_data *data = dev_get_drvdata(dev); int ret; mutex_lock(&data->lock); diff --git a/drivers/hwmon/as370-hwmon.c b/drivers/hwmon/as370-hwmon.c new file mode 100644 index 0000000000000000000000000000000000000000..464244ba8d584a7db2def5afd2b5f05365d80719 --- /dev/null +++ b/drivers/hwmon/as370-hwmon.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Synaptics AS370 SoC Hardware Monitoring Driver + * + * Copyright (C) 2018 Synaptics Incorporated + * Author: Jisheng Zhang + */ + +#include +#include +#include +#include +#include +#include + +#define CTRL 0x0 +#define PD BIT(0) +#define EN BIT(1) +#define T_SEL BIT(2) +#define V_SEL BIT(3) +#define NMOS_SEL BIT(8) +#define PMOS_SEL BIT(9) +#define STS 0x4 +#define BN_MASK GENMASK(11, 0) +#define EOC BIT(12) + +struct as370_hwmon { + void __iomem *base; +}; + +static void init_pvt(struct as370_hwmon *hwmon) +{ + u32 val; + void __iomem *addr = hwmon->base + CTRL; + + val = PD; + writel_relaxed(val, addr); + val |= T_SEL; + writel_relaxed(val, addr); + val |= EN; + writel_relaxed(val, addr); + val &= ~PD; + writel_relaxed(val, addr); +} + +static int as370_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *temp) +{ + int val; + struct as370_hwmon *hwmon = dev_get_drvdata(dev); + + switch (attr) { + case hwmon_temp_input: + val = readl_relaxed(hwmon->base + STS) & BN_MASK; + *temp = DIV_ROUND_CLOSEST(val * 251802, 4096) - 85525; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static umode_t +as370_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + if (type != hwmon_temp) + return 0; + + switch (attr) { + case hwmon_temp_input: + return 0444; + default: + return 0; + } +} + +static const u32 as370_hwmon_temp_config[] = { + HWMON_T_INPUT, + 0 +}; + +static const struct hwmon_channel_info as370_hwmon_temp = { + .type = hwmon_temp, + .config = as370_hwmon_temp_config, +}; + +static const struct hwmon_channel_info *as370_hwmon_info[] = { + &as370_hwmon_temp, + NULL +}; + +static const struct hwmon_ops as370_hwmon_ops = { + .is_visible = as370_hwmon_is_visible, + .read = as370_hwmon_read, +}; + +static const struct hwmon_chip_info as370_chip_info = { + .ops = &as370_hwmon_ops, + .info = as370_hwmon_info, +}; + +static int as370_hwmon_probe(struct platform_device *pdev) +{ + struct device *hwmon_dev; + struct as370_hwmon *hwmon; + struct device *dev = &pdev->dev; + + hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL); + if (!hwmon) + return -ENOMEM; + + hwmon->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(hwmon->base)) + return PTR_ERR(hwmon->base); + + init_pvt(hwmon); + + hwmon_dev = devm_hwmon_device_register_with_info(dev, + "as370", + hwmon, + &as370_chip_info, + NULL); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct of_device_id as370_hwmon_match[] = { + { .compatible = "syna,as370-hwmon" }, + {}, +}; +MODULE_DEVICE_TABLE(of, as370_hwmon_match); + +static struct platform_driver as370_hwmon_driver = { + .probe = as370_hwmon_probe, + .driver = { + .name = "as370-hwmon", + .of_match_table = as370_hwmon_match, + }, +}; +module_platform_driver(as370_hwmon_driver); + +MODULE_AUTHOR("Jisheng Zhang"); +MODULE_DESCRIPTION("Synaptics AS370 SoC hardware monitor"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index c9fa84b256783df45824abe066bdbe1cb5896422..4c609e23a4efb93d683bcefbd6e78b4ab53ea0ea 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -706,21 +706,21 @@ static int asb100_detect_subclients(struct i2c_client *client) goto ERROR_SC_2; } - data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]); - if (!data->lm75[0]) { + data->lm75[0] = i2c_new_dummy_device(adapter, sc_addr[0]); + if (IS_ERR(data->lm75[0])) { dev_err(&client->dev, "subclient %d registration at address 0x%x failed.\n", 1, sc_addr[0]); - err = -ENOMEM; + err = PTR_ERR(data->lm75[0]); goto ERROR_SC_2; } - data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]); - if (!data->lm75[1]) { + data->lm75[1] = i2c_new_dummy_device(adapter, sc_addr[1]); + if (IS_ERR(data->lm75[1])) { dev_err(&client->dev, "subclient %d registration at address 0x%x failed.\n", 2, sc_addr[1]); - err = -ENOMEM; + err = PTR_ERR(data->lm75[1]); goto ERROR_SC_3; } diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index e232fa948833bcc693955376529494f0590ac5df..79b8df25837127d6a6eec37410a36aba75460b3d 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -5,7 +5,7 @@ * * The ATXP1 can reside on I2C addresses 0x37 or 0x4e. The chip is * not auto-detected by the driver and must be instantiated explicitly. - * See Documentation/i2c/instantiating-devices for more information. + * See Documentation/i2c/instantiating-devices.rst for more information. */ #include diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index fe6618e49dc436cafda1e5ad12f6a8cbd89ef7c6..d855c78fb8bea77d87df0fe2a16289a039bc63ed 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -736,7 +736,7 @@ static int __init coretemp_init(void) err = platform_driver_register(&coretemp_driver); if (err) - return err; + goto outzone; err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/coretemp:online", coretemp_cpu_online, coretemp_cpu_offline); @@ -747,6 +747,7 @@ static int __init coretemp_init(void) outdrv: platform_driver_unregister(&coretemp_driver); +outzone: kfree(zone_devices); return err; } diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c index f1c2d5faedf0d76d2074b305065cf2261e6ceb72..b85a125dd86f46a26ac817bd42a718c4ad97310c 100644 --- a/drivers/hwmon/iio_hwmon.c +++ b/drivers/hwmon/iio_hwmon.c @@ -44,12 +44,20 @@ static ssize_t iio_hwmon_read_val(struct device *dev, int ret; struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); struct iio_hwmon_state *state = dev_get_drvdata(dev); + struct iio_channel *chan = &state->channels[sattr->index]; + enum iio_chan_type type; + + ret = iio_read_channel_processed(chan, &result); + if (ret < 0) + return ret; - ret = iio_read_channel_processed(&state->channels[sattr->index], - &result); + ret = iio_get_channel_type(chan, &type); if (ret < 0) return ret; + if (type == IIO_POWER) + result *= 1000; /* mili-Watts to micro-Watts conversion */ + return sprintf(buf, "%d\n", result); } @@ -59,7 +67,7 @@ static int iio_hwmon_probe(struct platform_device *pdev) struct iio_hwmon_state *st; struct sensor_device_attribute *a; int ret, i; - int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1; + int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1, power_i = 1; enum iio_chan_type type; struct iio_channel *channels; struct device *hwmon_dev; @@ -114,6 +122,10 @@ static int iio_hwmon_probe(struct platform_device *pdev) n = curr_i++; prefix = "curr"; break; + case IIO_POWER: + n = power_i++; + prefix = "power"; + break; case IIO_HUMIDITYRELATIVE: n = humidity_i++; prefix = "humidity"; diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index c77e89239dcd9a32c143203030362264d86f83b7..5c1dddde193c3e1ce50c539ba91e00b885a73190 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -349,6 +349,7 @@ static const struct pci_device_id k10temp_id_table[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) }, { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) }, {} }; diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index 4994c90c892986d9546765607eb7726b41adfee9..f73bd4eceb28f0e46c628b1902b3b2d6d90c0195 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c @@ -10,10 +10,8 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -24,108 +22,18 @@ #define SEL_CORE 0x04 struct k8temp_data { - struct device *hwmon_dev; struct mutex update_lock; - const char *name; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ /* registers values */ u8 sensorsp; /* sensor presence bits - SEL_CORE, SEL_PLACE */ - u32 temp[2][2]; /* core, place */ u8 swap_core_select; /* meaning of SEL_CORE is inverted */ u32 temp_offset; }; -static struct k8temp_data *k8temp_update_device(struct device *dev) -{ - struct k8temp_data *data = dev_get_drvdata(dev); - struct pci_dev *pdev = to_pci_dev(dev); - u8 tmp; - - mutex_lock(&data->update_lock); - - if (!data->valid - || time_after(jiffies, data->last_updated + HZ)) { - pci_read_config_byte(pdev, REG_TEMP, &tmp); - tmp &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */ - pci_write_config_byte(pdev, REG_TEMP, tmp); - pci_read_config_dword(pdev, REG_TEMP, &data->temp[0][0]); - - if (data->sensorsp & SEL_PLACE) { - tmp |= SEL_PLACE; /* Select sensor 1, core0 */ - pci_write_config_byte(pdev, REG_TEMP, tmp); - pci_read_config_dword(pdev, REG_TEMP, - &data->temp[0][1]); - } - - if (data->sensorsp & SEL_CORE) { - tmp &= ~SEL_PLACE; /* Select sensor 0, core1 */ - tmp |= SEL_CORE; - pci_write_config_byte(pdev, REG_TEMP, tmp); - pci_read_config_dword(pdev, REG_TEMP, - &data->temp[1][0]); - - if (data->sensorsp & SEL_PLACE) { - tmp |= SEL_PLACE; /* Select sensor 1, core1 */ - pci_write_config_byte(pdev, REG_TEMP, tmp); - pci_read_config_dword(pdev, REG_TEMP, - &data->temp[1][1]); - } - } - - data->last_updated = jiffies; - data->valid = 1; - } - - mutex_unlock(&data->update_lock); - return data; -} - -/* - * Sysfs stuff - */ - -static ssize_t name_show(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - struct k8temp_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%s\n", data->name); -} - - -static ssize_t temp_show(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute_2 *attr = - to_sensor_dev_attr_2(devattr); - int core = attr->nr; - int place = attr->index; - int temp; - struct k8temp_data *data = k8temp_update_device(dev); - - if (data->swap_core_select && (data->sensorsp & SEL_CORE)) - core = core ? 0 : 1; - - temp = TEMP_FROM_REG(data->temp[core][place]) + data->temp_offset; - - return sprintf(buf, "%d\n", temp); -} - -/* core, place */ - -static SENSOR_DEVICE_ATTR_2_RO(temp1_input, temp, 0, 0); -static SENSOR_DEVICE_ATTR_2_RO(temp2_input, temp, 0, 1); -static SENSOR_DEVICE_ATTR_2_RO(temp3_input, temp, 1, 0); -static SENSOR_DEVICE_ATTR_2_RO(temp4_input, temp, 1, 1); -static DEVICE_ATTR_RO(name); - static const struct pci_device_id k8temp_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) }, { 0 }, }; - MODULE_DEVICE_TABLE(pci, k8temp_ids); static int is_rev_g_desktop(u8 model) @@ -159,14 +67,76 @@ static int is_rev_g_desktop(u8 model) return 1; } +static umode_t +k8temp_is_visible(const void *drvdata, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct k8temp_data *data = drvdata; + + if ((channel & 1) && !(data->sensorsp & SEL_PLACE)) + return 0; + + if ((channel & 2) && !(data->sensorsp & SEL_CORE)) + return 0; + + return 0444; +} + +static int +k8temp_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct k8temp_data *data = dev_get_drvdata(dev); + struct pci_dev *pdev = to_pci_dev(dev->parent); + int core, place; + u32 temp; + u8 tmp; + + core = (channel >> 1) & 1; + place = channel & 1; + + core ^= data->swap_core_select; + + mutex_lock(&data->update_lock); + pci_read_config_byte(pdev, REG_TEMP, &tmp); + tmp &= ~(SEL_PLACE | SEL_CORE); + if (core) + tmp |= SEL_CORE; + if (place) + tmp |= SEL_PLACE; + pci_write_config_byte(pdev, REG_TEMP, tmp); + pci_read_config_dword(pdev, REG_TEMP, &temp); + mutex_unlock(&data->update_lock); + + *val = TEMP_FROM_REG(temp) + data->temp_offset; + + return 0; +} + +static const struct hwmon_ops k8temp_ops = { + .is_visible = k8temp_is_visible, + .read = k8temp_read, +}; + +static const struct hwmon_channel_info *k8temp_info[] = { + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT, HWMON_T_INPUT, HWMON_T_INPUT, HWMON_T_INPUT), + NULL +}; + +static const struct hwmon_chip_info k8temp_chip_info = { + .ops = &k8temp_ops, + .info = k8temp_info, +}; + static int k8temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - int err; u8 scfg; u32 temp; u8 model, stepping; struct k8temp_data *data; + struct device *hwmon_dev; data = devm_kzalloc(&pdev->dev, sizeof(struct k8temp_data), GFP_KERNEL); if (!data) @@ -231,86 +201,21 @@ static int k8temp_probe(struct pci_dev *pdev, data->sensorsp &= ~SEL_CORE; } - data->name = "k8temp"; mutex_init(&data->update_lock); - pci_set_drvdata(pdev, data); - - /* Register sysfs hooks */ - err = device_create_file(&pdev->dev, - &sensor_dev_attr_temp1_input.dev_attr); - if (err) - goto exit_remove; - - /* sensor can be changed and reports something */ - if (data->sensorsp & SEL_PLACE) { - err = device_create_file(&pdev->dev, - &sensor_dev_attr_temp2_input.dev_attr); - if (err) - goto exit_remove; - } - - /* core can be changed and reports something */ - if (data->sensorsp & SEL_CORE) { - err = device_create_file(&pdev->dev, - &sensor_dev_attr_temp3_input.dev_attr); - if (err) - goto exit_remove; - if (data->sensorsp & SEL_PLACE) { - err = device_create_file(&pdev->dev, - &sensor_dev_attr_temp4_input. - dev_attr); - if (err) - goto exit_remove; - } - } - - err = device_create_file(&pdev->dev, &dev_attr_name); - if (err) - goto exit_remove; - data->hwmon_dev = hwmon_device_register(&pdev->dev); + hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, + "k8temp", + data, + &k8temp_chip_info, + NULL); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - - return 0; - -exit_remove: - device_remove_file(&pdev->dev, - &sensor_dev_attr_temp1_input.dev_attr); - device_remove_file(&pdev->dev, - &sensor_dev_attr_temp2_input.dev_attr); - device_remove_file(&pdev->dev, - &sensor_dev_attr_temp3_input.dev_attr); - device_remove_file(&pdev->dev, - &sensor_dev_attr_temp4_input.dev_attr); - device_remove_file(&pdev->dev, &dev_attr_name); - return err; -} - -static void k8temp_remove(struct pci_dev *pdev) -{ - struct k8temp_data *data = pci_get_drvdata(pdev); - - hwmon_device_unregister(data->hwmon_dev); - device_remove_file(&pdev->dev, - &sensor_dev_attr_temp1_input.dev_attr); - device_remove_file(&pdev->dev, - &sensor_dev_attr_temp2_input.dev_attr); - device_remove_file(&pdev->dev, - &sensor_dev_attr_temp3_input.dev_attr); - device_remove_file(&pdev->dev, - &sensor_dev_attr_temp4_input.dev_attr); - device_remove_file(&pdev->dev, &dev_attr_name); + return PTR_ERR_OR_ZERO(hwmon_dev); } static struct pci_driver k8temp_driver = { .name = "k8temp", .id_table = k8temp_ids, .probe = k8temp_probe, - .remove = k8temp_remove, }; module_pci_driver(k8temp_driver); diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index ce5ec403ec739c819ee8f896e5958d63380246ee..5e6392294c0351e529754bef61426dbdcd35876d 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -16,9 +16,9 @@ #include #include #include +#include #include "lm75.h" - /* * This driver handles the LM75 and compatible digital temperature sensors. */ @@ -36,6 +36,7 @@ enum lm75_type { /* keep sorted in alphabetical order */ max6626, max31725, mcp980x, + pct2075, stds75, stlm75, tcn75, @@ -50,6 +51,41 @@ enum lm75_type { /* keep sorted in alphabetical order */ tmp75c, }; +/** + * struct lm75_params - lm75 configuration parameters. + * @set_mask: Bits to set in configuration register when configuring + * the chip. + * @clr_mask: Bits to clear in configuration register when configuring + * the chip. + * @default_resolution: Default number of bits to represent the temperature + * value. + * @resolution_limits: Limit register resolution. Optional. Should be set if + * the resolution of limit registers does not match the + * resolution of the temperature register. + * @resolutions: List of resolutions associated with sample times. + * Optional. Should be set if num_sample_times is larger + * than 1, and if the resolution changes with sample times. + * If set, number of entries must match num_sample_times. + * @default_sample_time:Sample time to be set by default. + * @num_sample_times: Number of possible sample times to be set. Optional. + * Should be set if the number of sample times is larger + * than one. + * @sample_times: All the possible sample times to be set. Mandatory if + * num_sample_times is larger than 1. If set, number of + * entries must match num_sample_times. + */ + +struct lm75_params { + u8 set_mask; + u8 clr_mask; + u8 default_resolution; + u8 resolution_limits; + const u8 *resolutions; + unsigned int default_sample_time; + u8 num_sample_times; + const unsigned int *sample_times; +}; + /* Addresses scanned */ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; @@ -59,24 +95,231 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, #define LM75_REG_CONF 0x01 #define LM75_REG_HYST 0x02 #define LM75_REG_MAX 0x03 +#define PCT2075_REG_IDLE 0x04 /* Each client has this additional data */ struct lm75_data { - struct i2c_client *client; - struct regmap *regmap; - u8 orig_conf; - u8 resolution; /* In bits, between 9 and 16 */ - u8 resolution_limits; - unsigned int sample_time; /* In ms */ + struct i2c_client *client; + struct regmap *regmap; + u8 orig_conf; + u8 current_conf; + u8 resolution; /* In bits, 9 to 16 */ + unsigned int sample_time; /* In ms */ + enum lm75_type kind; + const struct lm75_params *params; }; /*-----------------------------------------------------------------------*/ +static const u8 lm75_sample_set_masks[] = { 0 << 5, 1 << 5, 2 << 5, 3 << 5 }; + +#define LM75_SAMPLE_CLEAR_MASK (3 << 5) + +/* The structure below stores the configuration values of the supported devices. + * In case of being supported multiple configurations, the default one must + * always be the first element of the array + */ +static const struct lm75_params device_params[] = { + [adt75] = { + .clr_mask = 1 << 5, /* not one-shot mode */ + .default_resolution = 12, + .default_sample_time = MSEC_PER_SEC / 10, + }, + [ds1775] = { + .clr_mask = 3 << 5, + .set_mask = 2 << 5, /* 11-bit mode */ + .default_resolution = 11, + .default_sample_time = 500, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 125, 250, 500, 1000 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [ds75] = { + .clr_mask = 3 << 5, + .set_mask = 2 << 5, /* 11-bit mode */ + .default_resolution = 11, + .default_sample_time = 600, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 150, 300, 600, 1200 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [stds75] = { + .clr_mask = 3 << 5, + .set_mask = 2 << 5, /* 11-bit mode */ + .default_resolution = 11, + .default_sample_time = 600, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 150, 300, 600, 1200 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [stlm75] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 6, + }, + [ds7505] = { + .set_mask = 3 << 5, /* 12-bit mode*/ + .default_resolution = 12, + .default_sample_time = 200, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 25, 50, 100, 200 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [g751] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 10, + }, + [lm75] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 10, + }, + [lm75a] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 10, + }, + [lm75b] = { + .default_resolution = 11, + .default_sample_time = MSEC_PER_SEC / 10, + }, + [max6625] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 7, + }, + [max6626] = { + .default_resolution = 12, + .default_sample_time = MSEC_PER_SEC / 7, + .resolution_limits = 9, + }, + [max31725] = { + .default_resolution = 16, + .default_sample_time = MSEC_PER_SEC / 20, + }, + [tcn75] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 18, + }, + [pct2075] = { + .default_resolution = 11, + .default_sample_time = MSEC_PER_SEC / 10, + .num_sample_times = 31, + .sample_times = (unsigned int []){ 100, 200, 300, 400, 500, 600, + 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, + 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, + 2800, 2900, 3000, 3100 }, + }, + [mcp980x] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode */ + .default_resolution = 12, + .resolution_limits = 9, + .default_sample_time = 240, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 30, 60, 120, 240 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp100] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode */ + .default_resolution = 12, + .default_sample_time = 320, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 40, 80, 160, 320 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp101] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode */ + .default_resolution = 12, + .default_sample_time = 320, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 40, 80, 160, 320 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp105] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode*/ + .default_resolution = 12, + .default_sample_time = 220, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 28, 55, 110, 220 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp112] = { + .set_mask = 3 << 5, /* 8 samples / second */ + .clr_mask = 1 << 7, /* no one-shot mode*/ + .default_resolution = 12, + .default_sample_time = 125, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 125, 250, 1000, 4000 }, + }, + [tmp175] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode*/ + .default_resolution = 12, + .default_sample_time = 220, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 28, 55, 110, 220 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp275] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode*/ + .default_resolution = 12, + .default_sample_time = 220, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 28, 55, 110, 220 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp75] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode*/ + .default_resolution = 12, + .default_sample_time = 220, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 28, 55, 110, 220 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp75b] = { /* not one-shot mode, Conversion rate 37Hz */ + .clr_mask = 1 << 7 | 3 << 5, + .default_resolution = 12, + .default_sample_time = MSEC_PER_SEC / 37, + .sample_times = (unsigned int []){ MSEC_PER_SEC / 37, + MSEC_PER_SEC / 18, + MSEC_PER_SEC / 9, MSEC_PER_SEC / 4 }, + .num_sample_times = 4, + }, + [tmp75c] = { + .clr_mask = 1 << 5, /*not one-shot mode*/ + .default_resolution = 12, + .default_sample_time = MSEC_PER_SEC / 12, + } +}; + static inline long lm75_reg_to_mc(s16 temp, u8 resolution) { return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8); } +static int lm75_write_config(struct lm75_data *data, u8 set_mask, + u8 clr_mask) +{ + u8 value; + + clr_mask |= LM75_SHUTDOWN; + value = data->current_conf & ~clr_mask; + value |= set_mask; + + if (data->current_conf != value) { + s32 err; + + err = i2c_smbus_write_byte_data(data->client, LM75_REG_CONF, + value); + if (err) + return err; + data->current_conf = value; + } + return 0; +} + static int lm75_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { @@ -120,16 +363,12 @@ static int lm75_read(struct device *dev, enum hwmon_sensor_types type, return 0; } -static int lm75_write(struct device *dev, enum hwmon_sensor_types type, - u32 attr, int channel, long temp) +static int lm75_write_temp(struct device *dev, u32 attr, long temp) { struct lm75_data *data = dev_get_drvdata(dev); u8 resolution; int reg; - if (type != hwmon_temp) - return -EINVAL; - switch (attr) { case hwmon_temp_max: reg = LM75_REG_MAX; @@ -145,8 +384,8 @@ static int lm75_write(struct device *dev, enum hwmon_sensor_types type, * Resolution of limit registers is assumed to be the same as the * temperature input register resolution unless given explicitly. */ - if (data->resolution_limits) - resolution = data->resolution_limits; + if (data->params->resolution_limits) + resolution = data->params->resolution_limits; else resolution = data->resolution; @@ -154,16 +393,88 @@ static int lm75_write(struct device *dev, enum hwmon_sensor_types type, temp = DIV_ROUND_CLOSEST(temp << (resolution - 8), 1000) << (16 - resolution); - return regmap_write(data->regmap, reg, temp); + return regmap_write(data->regmap, reg, (u16)temp); +} + +static int lm75_update_interval(struct device *dev, long val) +{ + struct lm75_data *data = dev_get_drvdata(dev); + unsigned int reg; + u8 index; + s32 err; + + index = find_closest(val, data->params->sample_times, + (int)data->params->num_sample_times); + + switch (data->kind) { + default: + err = lm75_write_config(data, lm75_sample_set_masks[index], + LM75_SAMPLE_CLEAR_MASK); + if (err) + return err; + + data->sample_time = data->params->sample_times[index]; + if (data->params->resolutions) + data->resolution = data->params->resolutions[index]; + break; + case tmp112: + err = regmap_read(data->regmap, LM75_REG_CONF, ®); + if (err < 0) + return err; + reg &= ~0x00c0; + reg |= (3 - index) << 6; + err = regmap_write(data->regmap, LM75_REG_CONF, reg); + if (err < 0) + return err; + data->sample_time = data->params->sample_times[index]; + break; + case pct2075: + err = i2c_smbus_write_byte_data(data->client, PCT2075_REG_IDLE, + index + 1); + if (err) + return err; + data->sample_time = data->params->sample_times[index]; + break; + } + return 0; +} + +static int lm75_write_chip(struct device *dev, u32 attr, long val) +{ + switch (attr) { + case hwmon_chip_update_interval: + return lm75_update_interval(dev, val); + default: + return -EINVAL; + } + return 0; +} + +static int lm75_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + switch (type) { + case hwmon_chip: + return lm75_write_chip(dev, attr, val); + case hwmon_temp: + return lm75_write_temp(dev, attr, val); + default: + return -EINVAL; + } + return 0; } static umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) { + const struct lm75_data *config_data = data; + switch (type) { case hwmon_chip: switch (attr) { case hwmon_chip_update_interval: + if (config_data->params->num_sample_times > 1) + return 0644; return 0444; } break; @@ -208,13 +519,13 @@ static bool lm75_is_writeable_reg(struct device *dev, unsigned int reg) static bool lm75_is_volatile_reg(struct device *dev, unsigned int reg) { - return reg == LM75_REG_TEMP; + return reg == LM75_REG_TEMP || reg == LM75_REG_CONF; } static const struct regmap_config lm75_regmap_config = { .reg_bits = 8, .val_bits = 16, - .max_register = LM75_REG_MAX, + .max_register = PCT2075_REG_IDLE, .writeable_reg = lm75_is_writeable_reg, .volatile_reg = lm75_is_volatile_reg, .val_format_endian = REGMAP_ENDIAN_BIG, @@ -238,8 +549,6 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) struct device *hwmon_dev; struct lm75_data *data; int status, err; - u8 set_mask, clr_mask; - int new; enum lm75_type kind; if (client->dev.of_node) @@ -256,6 +565,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) return -ENOMEM; data->client = client; + data->kind = kind; data->regmap = devm_regmap_init_i2c(client, &lm75_regmap_config); if (IS_ERR(data->regmap)) @@ -264,113 +574,30 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) /* Set to LM75 resolution (9 bits, 1/2 degree C) and range. * Then tweak to be more precise when appropriate. */ - set_mask = 0; - clr_mask = LM75_SHUTDOWN; /* continuous conversions */ - - switch (kind) { - case adt75: - clr_mask |= 1 << 5; /* not one-shot mode */ - data->resolution = 12; - data->sample_time = MSEC_PER_SEC / 8; - break; - case ds1775: - case ds75: - case stds75: - clr_mask |= 3 << 5; - set_mask |= 2 << 5; /* 11-bit mode */ - data->resolution = 11; - data->sample_time = MSEC_PER_SEC; - break; - case stlm75: - data->resolution = 9; - data->sample_time = MSEC_PER_SEC / 5; - break; - case ds7505: - set_mask |= 3 << 5; /* 12-bit mode */ - data->resolution = 12; - data->sample_time = MSEC_PER_SEC / 4; - break; - case g751: - case lm75: - case lm75a: - data->resolution = 9; - data->sample_time = MSEC_PER_SEC / 2; - break; - case lm75b: - data->resolution = 11; - data->sample_time = MSEC_PER_SEC / 4; - break; - case max6625: - data->resolution = 9; - data->sample_time = MSEC_PER_SEC / 4; - break; - case max6626: - data->resolution = 12; - data->resolution_limits = 9; - data->sample_time = MSEC_PER_SEC / 4; - break; - case max31725: - data->resolution = 16; - data->sample_time = MSEC_PER_SEC / 8; - break; - case tcn75: - data->resolution = 9; - data->sample_time = MSEC_PER_SEC / 8; - break; - case mcp980x: - data->resolution_limits = 9; - /* fall through */ - case tmp100: - case tmp101: - set_mask |= 3 << 5; /* 12-bit mode */ - data->resolution = 12; - data->sample_time = MSEC_PER_SEC; - clr_mask |= 1 << 7; /* not one-shot mode */ - break; - case tmp112: - set_mask |= 3 << 5; /* 12-bit mode */ - clr_mask |= 1 << 7; /* not one-shot mode */ - data->resolution = 12; - data->sample_time = MSEC_PER_SEC / 4; - break; - case tmp105: - case tmp175: - case tmp275: - case tmp75: - set_mask |= 3 << 5; /* 12-bit mode */ - clr_mask |= 1 << 7; /* not one-shot mode */ - data->resolution = 12; - data->sample_time = MSEC_PER_SEC / 2; - break; - case tmp75b: /* not one-shot mode, Conversion rate 37Hz */ - clr_mask |= 1 << 7 | 0x3 << 5; - data->resolution = 12; - data->sample_time = MSEC_PER_SEC / 37; - break; - case tmp75c: - clr_mask |= 1 << 5; /* not one-shot mode */ - data->resolution = 12; - data->sample_time = MSEC_PER_SEC / 4; - break; - } - /* configure as specified */ + data->params = &device_params[data->kind]; + + /* Save default sample time and resolution*/ + data->sample_time = data->params->default_sample_time; + data->resolution = data->params->default_resolution; + + /* Cache original configuration */ status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); if (status < 0) { dev_dbg(dev, "Can't read config? %d\n", status); return status; } data->orig_conf = status; - new = status & ~clr_mask; - new |= set_mask; - if (status != new) - i2c_smbus_write_byte_data(client, LM75_REG_CONF, new); + data->current_conf = status; - err = devm_add_action_or_reset(dev, lm75_remove, data); + err = lm75_write_config(data, data->params->set_mask, + data->params->clr_mask); if (err) return err; - dev_dbg(dev, "Config %02x\n", new); + err = devm_add_action_or_reset(dev, lm75_remove, data); + if (err) + return err; hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, &lm75_chip_info, @@ -397,6 +624,7 @@ static const struct i2c_device_id lm75_ids[] = { { "max31725", max31725, }, { "max31726", max31725, }, { "mcp980x", mcp980x, }, + { "pct2075", pct2075, }, { "stds75", stds75, }, { "stlm75", stlm75, }, { "tcn75", tcn75, }, @@ -466,6 +694,10 @@ static const struct of_device_id __maybe_unused lm75_of_match[] = { .compatible = "maxim,mcp980x", .data = (void *)mcp980x }, + { + .compatible = "nxp,pct2075", + .data = (void *)pct2075 + }, { .compatible = "st,stds75", .data = (void *)stds75 diff --git a/drivers/hwmon/ltc2990.c b/drivers/hwmon/ltc2990.c index f9431ad43ad3b02a0b83e3e4990d56aa2f0fcdba..53ff5051774ccc5e1a3254105da6499b1b69fed4 100644 --- a/drivers/hwmon/ltc2990.c +++ b/drivers/hwmon/ltc2990.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #define LTC2990_STATUS 0x00 #define LTC2990_CONTROL 0x01 @@ -206,7 +206,6 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c, int ret; struct device *hwmon_dev; struct ltc2990_data *data; - struct device_node *of_node = i2c->dev.of_node; if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) @@ -218,9 +217,10 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c, data->i2c = i2c; - if (of_node) { - ret = of_property_read_u32_array(of_node, "lltc,meas-mode", - data->mode, 2); + if (dev_fwnode(&i2c->dev)) { + ret = device_property_read_u32_array(&i2c->dev, + "lltc,meas-mode", + data->mode, 2); if (ret < 0) return ret; diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index d42bc0883a32b4ba115f113d84e6503ecd43e081..7efa6bfef06097e5d20878566a84bc9666b3f2d6 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -20,6 +20,7 @@ * * Chip #vin #fan #pwm #temp chip IDs man ID * nct6106d 9 3 3 6+3 0xc450 0xc1 0x5ca3 + * nct6116d 9 5 5 3+3 0xd280 0xc1 0x5ca3 * nct6775f 9 4 3 6+3 0xb470 0xc1 0x5ca3 * nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3 * nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3 @@ -58,12 +59,13 @@ #define USE_ALTERNATE -enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793, - nct6795, nct6796, nct6797, nct6798 }; +enum kinds { nct6106, nct6116, nct6775, nct6776, nct6779, nct6791, nct6792, + nct6793, nct6795, nct6796, nct6797, nct6798 }; /* used to set data->name = nct6775_device_names[data->sio_kind] */ static const char * const nct6775_device_names[] = { "nct6106", + "nct6116", "nct6775", "nct6776", "nct6779", @@ -78,6 +80,7 @@ static const char * const nct6775_device_names[] = { static const char * const nct6775_sio_names[] __initconst = { "NCT6106D", + "NCT6116D", "NCT6775F", "NCT6776D/F", "NCT6779D", @@ -115,6 +118,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ #define SIO_NCT6106_ID 0xc450 +#define SIO_NCT6116_ID 0xd280 #define SIO_NCT6775_ID 0xb470 #define SIO_NCT6776_ID 0xc330 #define SIO_NCT6779_ID 0xc560 @@ -825,10 +829,8 @@ static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4 }; static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 }; static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 }; -static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 }; static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c }; static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 }; -static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 }; static const u16 NCT6106_REG_TEMP_SOURCE[] = { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 }; @@ -896,6 +898,70 @@ static const u16 NCT6106_REG_TEMP_CRIT[32] = { [12] = 0x205, }; +/* NCT6112D/NCT6114D/NCT6116D specific data */ + +static const u16 NCT6116_REG_FAN[] = { 0x20, 0x22, 0x24, 0x26, 0x28 }; +static const u16 NCT6116_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4, 0xe6, 0xe8 }; +static const u16 NCT6116_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0xf6, 0xf5 }; +static const u16 NCT6116_FAN_PULSE_SHIFT[] = { 0, 2, 4, 6, 6 }; + +static const u16 NCT6116_REG_PWM[] = { 0x119, 0x129, 0x139, 0x199, 0x1a9 }; +static const u16 NCT6116_REG_FAN_MODE[] = { 0x113, 0x123, 0x133, 0x193, 0x1a3 }; +static const u16 NCT6116_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130, 0x190, 0x1a0 }; +static const u16 NCT6116_REG_TEMP_SOURCE[] = { + 0xb0, 0xb1, 0xb2 }; + +static const u16 NCT6116_REG_CRITICAL_TEMP[] = { + 0x11a, 0x12a, 0x13a, 0x19a, 0x1aa }; +static const u16 NCT6116_REG_CRITICAL_TEMP_TOLERANCE[] = { + 0x11b, 0x12b, 0x13b, 0x19b, 0x1ab }; + +static const u16 NCT6116_REG_CRITICAL_PWM_ENABLE[] = { + 0x11c, 0x12c, 0x13c, 0x19c, 0x1ac }; +static const u16 NCT6116_REG_CRITICAL_PWM[] = { + 0x11d, 0x12d, 0x13d, 0x19d, 0x1ad }; + +static const u16 NCT6116_REG_FAN_STEP_UP_TIME[] = { + 0x114, 0x124, 0x134, 0x194, 0x1a4 }; +static const u16 NCT6116_REG_FAN_STEP_DOWN_TIME[] = { + 0x115, 0x125, 0x135, 0x195, 0x1a5 }; +static const u16 NCT6116_REG_FAN_STOP_OUTPUT[] = { + 0x116, 0x126, 0x136, 0x196, 0x1a6 }; +static const u16 NCT6116_REG_FAN_START_OUTPUT[] = { + 0x117, 0x127, 0x137, 0x197, 0x1a7 }; +static const u16 NCT6116_REG_FAN_STOP_TIME[] = { + 0x118, 0x128, 0x138, 0x198, 0x1a8 }; +static const u16 NCT6116_REG_TOLERANCE_H[] = { + 0x112, 0x122, 0x132, 0x192, 0x1a2 }; + +static const u16 NCT6116_REG_TARGET[] = { + 0x111, 0x121, 0x131, 0x191, 0x1a1 }; + +static const u16 NCT6116_REG_AUTO_TEMP[] = { + 0x160, 0x170, 0x180, 0x1d0, 0x1e0 }; +static const u16 NCT6116_REG_AUTO_PWM[] = { + 0x164, 0x174, 0x184, 0x1d4, 0x1e4 }; + +static const s8 NCT6116_ALARM_BITS[] = { + 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */ + 9, -1, -1, -1, -1, -1, -1, /* in8..in9 */ + -1, /* unused */ + 32, 33, 34, 35, 36, /* fan1..fan5 */ + -1, -1, -1, /* unused */ + 16, 17, 18, -1, -1, -1, /* temp1..temp6 */ + 48, -1 /* intrusion0, intrusion1 */ +}; + +static const s8 NCT6116_BEEP_BITS[] = { + 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */ + 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */ + 32, /* global beep enable */ + 24, 25, 26, 27, 28, /* fan1..fan5 */ + -1, -1, -1, /* unused */ + 16, 17, 18, -1, -1, -1, /* temp1..temp6 */ + 34, -1 /* intrusion0, intrusion1 */ +}; + static enum pwm_enable reg_to_pwm_enable(int pwm, int mode) { if (mode == 0 && pwm == 255) @@ -1294,6 +1360,11 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg) return reg == 0x20 || reg == 0x22 || reg == 0x24 || reg == 0xe0 || reg == 0xe2 || reg == 0xe4 || reg == 0x111 || reg == 0x121 || reg == 0x131; + case nct6116: + return reg == 0x20 || reg == 0x22 || reg == 0x24 || + reg == 0x26 || reg == 0x28 || reg == 0xe0 || reg == 0xe2 || + reg == 0xe4 || reg == 0xe6 || reg == 0xe8 || reg == 0x111 || + reg == 0x121 || reg == 0x131 || reg == 0x191 || reg == 0x1a1; case nct6775: return (((reg & 0xff00) == 0x100 || (reg & 0xff00) == 0x200) && @@ -1673,6 +1744,7 @@ static void nct6775_update_pwm_limits(struct device *dev) data->auto_pwm[i][data->auto_pwm_num] = 0xff; break; case nct6106: + case nct6116: case nct6779: case nct6791: case nct6792: @@ -3109,6 +3181,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr, case nct6776: break; /* always enabled, nothing to do */ case nct6106: + case nct6116: case nct6779: case nct6791: case nct6792: @@ -3535,6 +3608,23 @@ nct6775_check_fan_inputs(struct nct6775_data *data) fan3pin = !(cr24 & 0x80); pwm3pin = cr24 & 0x08; + } else if (data->kind == nct6116) { + int cr1a = superio_inb(sioreg, 0x1a); + int cr1b = superio_inb(sioreg, 0x1b); + int cr24 = superio_inb(sioreg, 0x24); + int cr2a = superio_inb(sioreg, 0x2a); + int cr2b = superio_inb(sioreg, 0x2b); + int cr2f = superio_inb(sioreg, 0x2f); + + fan3pin = !(cr2b & 0x10); + fan4pin = (cr2b & 0x80) || // pin 1(2) + (!(cr2f & 0x10) && (cr1a & 0x04)); // pin 65(66) + fan5pin = (cr2b & 0x80) || // pin 126(127) + (!(cr1b & 0x03) && (cr2a & 0x02)); // pin 94(96) + + pwm3pin = fan3pin && (cr24 & 0x08); + pwm4pin = fan4pin; + pwm5pin = fan5pin; } else { /* * NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D, @@ -3765,7 +3855,7 @@ static int nct6775_probe(struct platform_device *pdev) data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME; data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME; data->REG_TOLERANCE_H = NCT6106_REG_TOLERANCE_H; - data->REG_PWM[0] = NCT6106_REG_PWM; + data->REG_PWM[0] = NCT6116_REG_PWM; data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT; data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT; data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP; @@ -3784,7 +3874,7 @@ static int nct6775_probe(struct platform_device *pdev) data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM; data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET; data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE; - data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL; + data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL; data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL; data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP; data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL; @@ -3806,6 +3896,79 @@ static int nct6775_probe(struct platform_device *pdev) reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L; reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H; + break; + case nct6116: + data->in_num = 9; + data->pwm_num = 3; + data->auto_pwm_num = 4; + data->temp_fixed_num = 3; + data->num_temp_alarms = 3; + data->num_temp_beeps = 3; + + data->fan_from_reg = fan_from_reg13; + data->fan_from_reg_min = fan_from_reg13; + + data->temp_label = nct6776_temp_label; + data->temp_mask = NCT6776_TEMP_MASK; + data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK; + + data->REG_VBAT = NCT6106_REG_VBAT; + data->REG_DIODE = NCT6106_REG_DIODE; + data->DIODE_MASK = NCT6106_DIODE_MASK; + data->REG_VIN = NCT6106_REG_IN; + data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN; + data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX; + data->REG_TARGET = NCT6116_REG_TARGET; + data->REG_FAN = NCT6116_REG_FAN; + data->REG_FAN_MODE = NCT6116_REG_FAN_MODE; + data->REG_FAN_MIN = NCT6116_REG_FAN_MIN; + data->REG_FAN_PULSES = NCT6116_REG_FAN_PULSES; + data->FAN_PULSE_SHIFT = NCT6116_FAN_PULSE_SHIFT; + data->REG_FAN_TIME[0] = NCT6116_REG_FAN_STOP_TIME; + data->REG_FAN_TIME[1] = NCT6116_REG_FAN_STEP_UP_TIME; + data->REG_FAN_TIME[2] = NCT6116_REG_FAN_STEP_DOWN_TIME; + data->REG_TOLERANCE_H = NCT6116_REG_TOLERANCE_H; + data->REG_PWM[0] = NCT6116_REG_PWM; + data->REG_PWM[1] = NCT6116_REG_FAN_START_OUTPUT; + data->REG_PWM[2] = NCT6116_REG_FAN_STOP_OUTPUT; + data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP; + data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE; + data->REG_PWM_READ = NCT6106_REG_PWM_READ; + data->REG_PWM_MODE = NCT6106_REG_PWM_MODE; + data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK; + data->REG_AUTO_TEMP = NCT6116_REG_AUTO_TEMP; + data->REG_AUTO_PWM = NCT6116_REG_AUTO_PWM; + data->REG_CRITICAL_TEMP = NCT6116_REG_CRITICAL_TEMP; + data->REG_CRITICAL_TEMP_TOLERANCE + = NCT6116_REG_CRITICAL_TEMP_TOLERANCE; + data->REG_CRITICAL_PWM_ENABLE = NCT6116_REG_CRITICAL_PWM_ENABLE; + data->CRITICAL_PWM_ENABLE_MASK + = NCT6106_CRITICAL_PWM_ENABLE_MASK; + data->REG_CRITICAL_PWM = NCT6116_REG_CRITICAL_PWM; + data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET; + data->REG_TEMP_SOURCE = NCT6116_REG_TEMP_SOURCE; + data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL; + data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL; + data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP; + data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL; + data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE; + data->REG_ALARM = NCT6106_REG_ALARM; + data->ALARM_BITS = NCT6116_ALARM_BITS; + data->REG_BEEP = NCT6106_REG_BEEP; + data->BEEP_BITS = NCT6116_BEEP_BITS; + + reg_temp = NCT6106_REG_TEMP; + reg_temp_mon = NCT6106_REG_TEMP_MON; + num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP); + num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON); + reg_temp_over = NCT6106_REG_TEMP_OVER; + reg_temp_hyst = NCT6106_REG_TEMP_HYST; + reg_temp_config = NCT6106_REG_TEMP_CONFIG; + reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE; + reg_temp_crit = NCT6106_REG_TEMP_CRIT; + reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L; + reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H; + break; case nct6775: data->in_num = 9; @@ -4352,6 +4515,7 @@ static int nct6775_probe(struct platform_device *pdev) data->have_vid = (cr2a & 0x60) == 0x40; break; case nct6106: + case nct6116: case nct6779: case nct6791: case nct6792: @@ -4381,6 +4545,7 @@ static int nct6775_probe(struct platform_device *pdev) NCT6775_REG_CR_FAN_DEBOUNCE); switch (data->kind) { case nct6106: + case nct6116: tmp |= 0xe0; break; case nct6775: @@ -4576,6 +4741,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) case SIO_NCT6106_ID: sio_data->kind = nct6106; break; + case SIO_NCT6116_ID: + sio_data->kind = nct6116; + break; case SIO_NCT6775_ID: sio_data->kind = nct6775; break; diff --git a/drivers/hwmon/nct7904.c b/drivers/hwmon/nct7904.c index 710c30562fc1fe62ff14bee4122c539c3cd7ad71..95b447cfa24cb82a118fa62f3bc4c99caec33153 100644 --- a/drivers/hwmon/nct7904.c +++ b/drivers/hwmon/nct7904.c @@ -46,10 +46,34 @@ #define DTS_T_CTRL1_REG 0x27 #define VT_ADC_MD_REG 0x2E +#define VSEN1_HV_LL_REG 0x02 /* Bank 1; 2 regs (HV/LV) per sensor */ +#define VSEN1_LV_LL_REG 0x03 /* Bank 1; 2 regs (HV/LV) per sensor */ +#define VSEN1_HV_HL_REG 0x00 /* Bank 1; 2 regs (HV/LV) per sensor */ +#define VSEN1_LV_HL_REG 0x01 /* Bank 1; 2 regs (HV/LV) per sensor */ +#define SMI_STS1_REG 0xC1 /* Bank 0; SMI Status Register */ +#define SMI_STS3_REG 0xC3 /* Bank 0; SMI Status Register */ +#define SMI_STS5_REG 0xC5 /* Bank 0; SMI Status Register */ +#define SMI_STS7_REG 0xC7 /* Bank 0; SMI Status Register */ +#define SMI_STS8_REG 0xC8 /* Bank 0; SMI Status Register */ + #define VSEN1_HV_REG 0x40 /* Bank 0; 2 regs (HV/LV) per sensor */ #define TEMP_CH1_HV_REG 0x42 /* Bank 0; same as VSEN2_HV */ #define LTD_HV_REG 0x62 /* Bank 0; 2 regs in VSEN range */ +#define LTD_HV_HL_REG 0x44 /* Bank 1; 1 reg for LTD */ +#define LTD_LV_HL_REG 0x45 /* Bank 1; 1 reg for LTD */ +#define LTD_HV_LL_REG 0x46 /* Bank 1; 1 reg for LTD */ +#define LTD_LV_LL_REG 0x47 /* Bank 1; 1 reg for LTD */ +#define TEMP_CH1_CH_REG 0x05 /* Bank 1; 1 reg for LTD */ +#define TEMP_CH1_W_REG 0x06 /* Bank 1; 1 reg for LTD */ +#define TEMP_CH1_WH_REG 0x07 /* Bank 1; 1 reg for LTD */ +#define TEMP_CH1_C_REG 0x04 /* Bank 1; 1 reg per sensor */ +#define DTS_T_CPU1_C_REG 0x90 /* Bank 1; 1 reg per sensor */ +#define DTS_T_CPU1_CH_REG 0x91 /* Bank 1; 1 reg per sensor */ +#define DTS_T_CPU1_W_REG 0x92 /* Bank 1; 1 reg per sensor */ +#define DTS_T_CPU1_WH_REG 0x93 /* Bank 1; 1 reg per sensor */ #define FANIN1_HV_REG 0x80 /* Bank 0; 2 regs (HV/LV) per sensor */ +#define FANIN1_HV_HL_REG 0x60 /* Bank 1; 2 regs (HV/LV) per sensor */ +#define FANIN1_LV_HL_REG 0x61 /* Bank 1; 2 regs (HV/LV) per sensor */ #define T_CPU1_HV_REG 0xA0 /* Bank 0; 2 regs (HV/LV) per sensor */ #define PRTS_REG 0x03 /* Bank 2 */ @@ -58,6 +82,8 @@ #define FANCTL1_FMR_REG 0x00 /* Bank 3; 1 reg per channel */ #define FANCTL1_OUT_REG 0x10 /* Bank 3; 1 reg per channel */ +#define ENABLE_TSI BIT(1) + static const unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END }; @@ -72,6 +98,7 @@ struct nct7904_data { u8 fan_mode[FANCTL_MAX]; u8 enable_dts; u8 has_dts; + u8 temp_mode; /* 0: TR mode, 1: TD mode */ }; /* Access functions */ @@ -170,6 +197,25 @@ static int nct7904_read_fan(struct device *dev, u32 attr, int channel, rpm = 1350000 / cnt; *val = rpm; return 0; + case hwmon_fan_min: + ret = nct7904_read_reg16(data, BANK_1, + FANIN1_HV_HL_REG + channel * 2); + if (ret < 0) + return ret; + cnt = ((ret & 0xff00) >> 3) | (ret & 0x1f); + if (cnt == 0x1fff) + rpm = 0; + else + rpm = 1350000 / cnt; + *val = rpm; + return 0; + case hwmon_fan_alarm: + ret = nct7904_read_reg(data, BANK_0, + SMI_STS5_REG + (channel >> 3)); + if (ret < 0) + return ret; + *val = (ret >> (channel & 0x07)) & 1; + return 0; default: return -EOPNOTSUPP; } @@ -179,8 +225,20 @@ static umode_t nct7904_fan_is_visible(const void *_data, u32 attr, int channel) { const struct nct7904_data *data = _data; - if (attr == hwmon_fan_input && data->fanin_mask & (1 << channel)) - return 0444; + switch (attr) { + case hwmon_fan_input: + case hwmon_fan_alarm: + if (data->fanin_mask & (1 << channel)) + return 0444; + break; + case hwmon_fan_min: + if (data->fanin_mask & (1 << channel)) + return 0644; + break; + default: + break; + } + return 0; } @@ -211,6 +269,37 @@ static int nct7904_read_in(struct device *dev, u32 attr, int channel, volt *= 6; /* 0.006V scale */ *val = volt; return 0; + case hwmon_in_min: + ret = nct7904_read_reg16(data, BANK_1, + VSEN1_HV_LL_REG + index * 4); + if (ret < 0) + return ret; + volt = ((ret & 0xff00) >> 5) | (ret & 0x7); + if (index < 14) + volt *= 2; /* 0.002V scale */ + else + volt *= 6; /* 0.006V scale */ + *val = volt; + return 0; + case hwmon_in_max: + ret = nct7904_read_reg16(data, BANK_1, + VSEN1_HV_HL_REG + index * 4); + if (ret < 0) + return ret; + volt = ((ret & 0xff00) >> 5) | (ret & 0x7); + if (index < 14) + volt *= 2; /* 0.002V scale */ + else + volt *= 6; /* 0.006V scale */ + *val = volt; + return 0; + case hwmon_in_alarm: + ret = nct7904_read_reg(data, BANK_0, + SMI_STS1_REG + (index >> 3)); + if (ret < 0) + return ret; + *val = (ret >> (index & 0x07)) & 1; + return 0; default: return -EOPNOTSUPP; } @@ -221,9 +310,20 @@ static umode_t nct7904_in_is_visible(const void *_data, u32 attr, int channel) const struct nct7904_data *data = _data; int index = nct7904_chan_to_index[channel]; - if (channel > 0 && attr == hwmon_in_input && - (data->vsen_mask & BIT(index))) - return 0444; + switch (attr) { + case hwmon_in_input: + case hwmon_in_alarm: + if (channel > 0 && (data->vsen_mask & BIT(index))) + return 0444; + break; + case hwmon_in_min: + case hwmon_in_max: + if (channel > 0 && (data->vsen_mask & BIT(index))) + return 0644; + break; + default: + break; + } return 0; } @@ -233,6 +333,7 @@ static int nct7904_read_temp(struct device *dev, u32 attr, int channel, { struct nct7904_data *data = dev_get_drvdata(dev); int ret, temp; + unsigned int reg1, reg2, reg3; switch (attr) { case hwmon_temp_input: @@ -250,16 +351,106 @@ static int nct7904_read_temp(struct device *dev, u32 attr, int channel, temp = ((ret & 0xff00) >> 5) | (ret & 0x7); *val = sign_extend32(temp, 10) * 125; return 0; + case hwmon_temp_alarm: + if (channel == 4) { + ret = nct7904_read_reg(data, BANK_0, + SMI_STS3_REG); + if (ret < 0) + return ret; + *val = (ret >> 1) & 1; + } else if (channel < 4) { + ret = nct7904_read_reg(data, BANK_0, + SMI_STS1_REG); + if (ret < 0) + return ret; + *val = (ret >> (((channel * 2) + 1) & 0x07)) & 1; + } else { + if ((channel - 5) < 4) { + ret = nct7904_read_reg(data, BANK_0, + SMI_STS7_REG + + ((channel - 5) >> 3)); + if (ret < 0) + return ret; + *val = (ret >> ((channel - 5) & 0x07)) & 1; + } else { + ret = nct7904_read_reg(data, BANK_0, + SMI_STS8_REG + + ((channel - 5) >> 3)); + if (ret < 0) + return ret; + *val = (ret >> (((channel - 5) & 0x07) - 4)) + & 1; + } + } + return 0; + case hwmon_temp_type: + if (channel < 5) { + if ((data->tcpu_mask >> channel) & 0x01) { + if ((data->temp_mode >> channel) & 0x01) + *val = 3; /* TD */ + else + *val = 4; /* TR */ + } else { + *val = 0; + } + } else { + if ((data->has_dts >> (channel - 5)) & 0x01) { + if (data->enable_dts & ENABLE_TSI) + *val = 5; /* TSI */ + else + *val = 6; /* PECI */ + } else { + *val = 0; + } + } + return 0; + case hwmon_temp_max: + reg1 = LTD_HV_LL_REG; + reg2 = TEMP_CH1_W_REG; + reg3 = DTS_T_CPU1_W_REG; + break; + case hwmon_temp_max_hyst: + reg1 = LTD_LV_LL_REG; + reg2 = TEMP_CH1_WH_REG; + reg3 = DTS_T_CPU1_WH_REG; + break; + case hwmon_temp_crit: + reg1 = LTD_HV_HL_REG; + reg2 = TEMP_CH1_C_REG; + reg3 = DTS_T_CPU1_C_REG; + break; + case hwmon_temp_crit_hyst: + reg1 = LTD_LV_HL_REG; + reg2 = TEMP_CH1_CH_REG; + reg3 = DTS_T_CPU1_CH_REG; + break; default: return -EOPNOTSUPP; } + + if (channel == 4) + ret = nct7904_read_reg(data, BANK_1, reg1); + else if (channel < 5) + ret = nct7904_read_reg(data, BANK_1, + reg2 + channel * 8); + else + ret = nct7904_read_reg(data, BANK_1, + reg3 + (channel - 5) * 4); + + if (ret < 0) + return ret; + *val = ret * 1000; + return 0; } static umode_t nct7904_temp_is_visible(const void *_data, u32 attr, int channel) { const struct nct7904_data *data = _data; - if (attr == hwmon_temp_input) { + switch (attr) { + case hwmon_temp_input: + case hwmon_temp_alarm: + case hwmon_temp_type: if (channel < 5) { if (data->tcpu_mask & BIT(channel)) return 0444; @@ -267,6 +458,21 @@ static umode_t nct7904_temp_is_visible(const void *_data, u32 attr, int channel) if (data->has_dts & BIT(channel - 5)) return 0444; } + break; + case hwmon_temp_max: + case hwmon_temp_max_hyst: + case hwmon_temp_crit: + case hwmon_temp_crit_hyst: + if (channel < 5) { + if (data->tcpu_mask & BIT(channel)) + return 0644; + } else { + if (data->has_dts & BIT(channel - 5)) + return 0644; + } + break; + default: + break; } return 0; @@ -297,6 +503,137 @@ static int nct7904_read_pwm(struct device *dev, u32 attr, int channel, } } +static int nct7904_write_temp(struct device *dev, u32 attr, int channel, + long val) +{ + struct nct7904_data *data = dev_get_drvdata(dev); + int ret; + unsigned int reg1, reg2, reg3; + + val = clamp_val(val / 1000, -128, 127); + + switch (attr) { + case hwmon_temp_max: + reg1 = LTD_HV_LL_REG; + reg2 = TEMP_CH1_W_REG; + reg3 = DTS_T_CPU1_W_REG; + break; + case hwmon_temp_max_hyst: + reg1 = LTD_LV_LL_REG; + reg2 = TEMP_CH1_WH_REG; + reg3 = DTS_T_CPU1_WH_REG; + break; + case hwmon_temp_crit: + reg1 = LTD_HV_HL_REG; + reg2 = TEMP_CH1_C_REG; + reg3 = DTS_T_CPU1_C_REG; + break; + case hwmon_temp_crit_hyst: + reg1 = LTD_LV_HL_REG; + reg2 = TEMP_CH1_CH_REG; + reg3 = DTS_T_CPU1_CH_REG; + break; + default: + return -EOPNOTSUPP; + } + if (channel == 4) + ret = nct7904_write_reg(data, BANK_1, reg1, val); + else if (channel < 5) + ret = nct7904_write_reg(data, BANK_1, + reg2 + channel * 8, val); + else + ret = nct7904_write_reg(data, BANK_1, + reg3 + (channel - 5) * 4, val); + + return ret; +} + +static int nct7904_write_fan(struct device *dev, u32 attr, int channel, + long val) +{ + struct nct7904_data *data = dev_get_drvdata(dev); + int ret; + u8 tmp; + + switch (attr) { + case hwmon_fan_min: + if (val <= 0) + return -EINVAL; + + val = clamp_val(DIV_ROUND_CLOSEST(1350000, val), 1, 0x1fff); + tmp = (val >> 5) & 0xff; + ret = nct7904_write_reg(data, BANK_1, + FANIN1_HV_HL_REG + channel * 2, tmp); + if (ret < 0) + return ret; + tmp = val & 0x1f; + ret = nct7904_write_reg(data, BANK_1, + FANIN1_LV_HL_REG + channel * 2, tmp); + return ret; + default: + return -EOPNOTSUPP; + } +} + +static int nct7904_write_in(struct device *dev, u32 attr, int channel, + long val) +{ + struct nct7904_data *data = dev_get_drvdata(dev); + int ret, index, tmp; + + index = nct7904_chan_to_index[channel]; + + if (index < 14) + val = val / 2; /* 0.002V scale */ + else + val = val / 6; /* 0.006V scale */ + + val = clamp_val(val, 0, 0x7ff); + + switch (attr) { + case hwmon_in_min: + tmp = nct7904_read_reg(data, BANK_1, + VSEN1_LV_LL_REG + index * 4); + if (tmp < 0) + return tmp; + tmp &= ~0x7; + tmp |= val & 0x7; + ret = nct7904_write_reg(data, BANK_1, + VSEN1_LV_LL_REG + index * 4, tmp); + if (ret < 0) + return ret; + tmp = nct7904_read_reg(data, BANK_1, + VSEN1_HV_LL_REG + index * 4); + if (tmp < 0) + return tmp; + tmp = (val >> 3) & 0xff; + ret = nct7904_write_reg(data, BANK_1, + VSEN1_HV_LL_REG + index * 4, tmp); + return ret; + case hwmon_in_max: + tmp = nct7904_read_reg(data, BANK_1, + VSEN1_LV_HL_REG + index * 4); + if (tmp < 0) + return tmp; + tmp &= ~0x7; + tmp |= val & 0x7; + ret = nct7904_write_reg(data, BANK_1, + VSEN1_LV_HL_REG + index * 4, tmp); + if (ret < 0) + return ret; + tmp = nct7904_read_reg(data, BANK_1, + VSEN1_HV_HL_REG + index * 4); + if (tmp < 0) + return tmp; + tmp = (val >> 3) & 0xff; + ret = nct7904_write_reg(data, BANK_1, + VSEN1_HV_HL_REG + index * 4, tmp); + return ret; + default: + return -EOPNOTSUPP; + } +} + static int nct7904_write_pwm(struct device *dev, u32 attr, int channel, long val) { @@ -354,8 +691,14 @@ static int nct7904_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long val) { switch (type) { + case hwmon_in: + return nct7904_write_in(dev, attr, channel, val); + case hwmon_fan: + return nct7904_write_fan(dev, attr, channel, val); case hwmon_pwm: return nct7904_write_pwm(dev, attr, channel, val); + case hwmon_temp: + return nct7904_write_temp(dev, attr, channel, val); default: return -EOPNOTSUPP; } @@ -404,51 +747,91 @@ static int nct7904_detect(struct i2c_client *client, static const struct hwmon_channel_info *nct7904_info[] = { HWMON_CHANNEL_INFO(in, - HWMON_I_INPUT, /* dummy, skipped in is_visible */ - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT), + /* dummy, skipped in is_visible */ + 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_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_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_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_INPUT, - HWMON_F_INPUT, - HWMON_F_INPUT, - HWMON_F_INPUT, - HWMON_F_INPUT, - HWMON_F_INPUT, - HWMON_F_INPUT), + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM), HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE, HWMON_PWM_INPUT | HWMON_PWM_ENABLE, HWMON_PWM_INPUT | HWMON_PWM_ENABLE, HWMON_PWM_INPUT | HWMON_PWM_ENABLE), HWMON_CHANNEL_INFO(temp, - HWMON_T_INPUT, - HWMON_T_INPUT, - HWMON_T_INPUT, - HWMON_T_INPUT, - HWMON_T_INPUT, - HWMON_T_INPUT, - HWMON_T_INPUT, - HWMON_T_INPUT, - HWMON_T_INPUT), + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | + HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | + HWMON_T_CRIT_HYST, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | + HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | + HWMON_T_CRIT_HYST, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | + HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | + HWMON_T_CRIT_HYST, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | + HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | + HWMON_T_CRIT_HYST, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | + HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | + HWMON_T_CRIT_HYST, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | + HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | + HWMON_T_CRIT_HYST, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | + HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | + HWMON_T_CRIT_HYST, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | + HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | + HWMON_T_CRIT_HYST, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | + HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | + HWMON_T_CRIT_HYST), NULL }; @@ -530,11 +913,14 @@ static int nct7904_probe(struct i2c_client *client, if (ret < 0) return ret; + data->temp_mode = 0; for (i = 0; i < 4; i++) { val = (ret & (0x03 << i)) >> (i * 2); bit = (1 << i); if (val == 0) data->tcpu_mask &= ~bit; + else if (val == 0x1 || val == 0x2) + data->temp_mode |= bit; } /* PECI */ @@ -557,7 +943,7 @@ static int nct7904_probe(struct i2c_client *client, if (ret < 0) return ret; data->has_dts = ret & 0xF; - if (data->enable_dts & 0x2) { + if (data->enable_dts & ENABLE_TSI) { ret = nct7904_read_reg(data, BANK_0, DTS_T_CTRL1_REG); if (ret < 0) return ret; diff --git a/drivers/hwmon/npcm750-pwm-fan.c b/drivers/hwmon/npcm750-pwm-fan.c index 09aaefa6fdb8c192e561d720dab6cc7d65a40138..11a28609da3c769343fd83c976a6ffdc13050bc5 100644 --- a/drivers/hwmon/npcm750-pwm-fan.c +++ b/drivers/hwmon/npcm750-pwm-fan.c @@ -967,10 +967,8 @@ static int npcm7xx_pwm_fan_probe(struct platform_device *pdev) spin_lock_init(&data->fan_lock[i]); data->fan_irq[i] = platform_get_irq(pdev, i); - if (data->fan_irq[i] < 0) { - dev_err(dev, "get IRQ fan%d failed\n", i); + if (data->fan_irq[i] < 0) return data->fan_irq[i]; - } sprintf(name, "NPCM7XX-FAN-MD%d", i); ret = devm_request_irq(dev, data->fan_irq[i], npcm7xx_fan_isr, diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index b6588483fae125a28562df82e90b2fb1446f29ea..d62d69bb7e490412b72ec7e6eb4e2ad612add115 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -46,6 +46,15 @@ config SENSORS_IBM_CFFPS This driver can also be built as a module. If so, the module will be called ibm-cffps. +config SENSORS_INSPUR_IPSPS + tristate "INSPUR Power System Power Supply" + help + If you say yes here you get hardware monitoring support for the INSPUR + Power System power supply. + + This driver can also be built as a module. If so, the module will + be called inspur-ipsps. + config SENSORS_IR35221 tristate "Infineon IR35221" help diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index c950ea9a5d003e0645be173a871303875cc6a47b..03bacfcfd6607dbb2365b6d1e912489f3838f92b 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_PMBUS) += pmbus_core.o obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o obj-$(CONFIG_SENSORS_ADM1275) += adm1275.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_IR38064) += ir38064.o obj-$(CONFIG_SENSORS_IRPS5401) += irps5401.o diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c index ee2ee9e3ffd739ab06116b6d6ef9db1867980665..d44745e498e76b0d847caaff878118e711a571d0 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "pmbus.h" @@ -20,8 +21,9 @@ #define CFFPS_PN_CMD 0x9B #define CFFPS_SN_CMD 0x9E #define CFFPS_CCIN_CMD 0xBD -#define CFFPS_FW_CMD_START 0xFA -#define CFFPS_FW_NUM_BYTES 4 +#define CFFPS_FW_CMD 0xFA +#define CFFPS1_FW_NUM_BYTES 4 +#define CFFPS2_FW_NUM_WORDS 3 #define CFFPS_SYS_CONFIG_CMD 0xDA #define CFFPS_INPUT_HISTORY_CMD 0xD6 @@ -52,6 +54,8 @@ enum { CFFPS_DEBUGFS_NUM_ENTRIES }; +enum versions { cffps1, cffps2 }; + struct ibm_cffps_input_history { struct mutex update_lock; unsigned long last_update; @@ -61,6 +65,7 @@ struct ibm_cffps_input_history { }; struct ibm_cffps { + enum versions version; struct i2c_client *client; struct ibm_cffps_input_history input_history; @@ -132,6 +137,8 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf, struct ibm_cffps *psu = to_psu(idxp, idx); char data[I2C_SMBUS_BLOCK_MAX] = { 0 }; + pmbus_set_page(psu->client, 0); + switch (idx) { case CFFPS_DEBUGFS_INPUT_HISTORY: return ibm_cffps_read_input_history(psu, buf, count, ppos); @@ -152,16 +159,36 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf, rc = snprintf(data, 5, "%04X", rc); goto done; case CFFPS_DEBUGFS_FW: - for (i = 0; i < CFFPS_FW_NUM_BYTES; ++i) { - rc = i2c_smbus_read_byte_data(psu->client, - CFFPS_FW_CMD_START + i); - if (rc < 0) - return rc; + switch (psu->version) { + case cffps1: + for (i = 0; i < CFFPS1_FW_NUM_BYTES; ++i) { + rc = i2c_smbus_read_byte_data(psu->client, + CFFPS_FW_CMD + + i); + if (rc < 0) + return rc; + + snprintf(&data[i * 2], 3, "%02X", rc); + } - snprintf(&data[i * 2], 3, "%02X", rc); - } + rc = i * 2; + break; + case cffps2: + for (i = 0; i < CFFPS2_FW_NUM_WORDS; ++i) { + rc = i2c_smbus_read_word_data(psu->client, + CFFPS_FW_CMD + + i); + if (rc < 0) + return rc; + + snprintf(&data[i * 4], 5, "%04X", rc); + } - rc = i * 2; + rc = i * 4; + break; + default: + return -EOPNOTSUPP; + } goto done; default: return -EINVAL; @@ -279,6 +306,8 @@ static void ibm_cffps_led_brightness_set(struct led_classdev *led_cdev, psu->led_state = CFFPS_LED_ON; } + pmbus_set_page(psu->client, 0); + rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD, psu->led_state); if (rc < 0) @@ -299,6 +328,8 @@ static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev, if (led_cdev->brightness == LED_OFF) return 0; + pmbus_set_page(psu->client, 0); + rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD, CFFPS_LED_BLINK); if (rc < 0) @@ -328,15 +359,32 @@ static void ibm_cffps_create_led_class(struct ibm_cffps *psu) dev_warn(dev, "failed to register led class: %d\n", rc); } -static struct pmbus_driver_info ibm_cffps_info = { - .pages = 1, - .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | - PMBUS_HAVE_PIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP | - PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_VOUT | - PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT | - PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_STATUS_FAN12, - .read_byte_data = ibm_cffps_read_byte_data, - .read_word_data = ibm_cffps_read_word_data, +static struct pmbus_driver_info ibm_cffps_info[] = { + [cffps1] = { + .pages = 1, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | + PMBUS_HAVE_PIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP | + PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 | + PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_STATUS_FAN12, + .read_byte_data = ibm_cffps_read_byte_data, + .read_word_data = ibm_cffps_read_word_data, + }, + [cffps2] = { + .pages = 2, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | + PMBUS_HAVE_PIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP | + PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 | + PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_STATUS_FAN12, + .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 | + PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT, + .read_byte_data = ibm_cffps_read_byte_data, + .read_word_data = ibm_cffps_read_word_data, + }, }; static struct pmbus_platform_data ibm_cffps_pdata = { @@ -347,12 +395,21 @@ static int ibm_cffps_probe(struct i2c_client *client, const struct i2c_device_id *id) { int i, rc; + enum versions vs; struct dentry *debugfs; struct dentry *ibm_cffps_dir; struct ibm_cffps *psu; + const void *md = of_device_get_match_data(&client->dev); + + if (md) + vs = (enum versions)md; + else if (id) + vs = (enum versions)id->driver_data; + else + vs = cffps1; client->dev.platform_data = &ibm_cffps_pdata; - rc = pmbus_do_probe(client, id, &ibm_cffps_info); + rc = pmbus_do_probe(client, id, &ibm_cffps_info[vs]); if (rc) return rc; @@ -364,6 +421,7 @@ static int ibm_cffps_probe(struct i2c_client *client, if (!psu) return 0; + psu->version = vs; psu->client = client; mutex_init(&psu->input_history.update_lock); psu->input_history.last_update = jiffies - HZ; @@ -405,13 +463,21 @@ static int ibm_cffps_probe(struct i2c_client *client, } static const struct i2c_device_id ibm_cffps_id[] = { - { "ibm_cffps1", 1 }, + { "ibm_cffps1", cffps1 }, + { "ibm_cffps2", cffps2 }, {} }; MODULE_DEVICE_TABLE(i2c, ibm_cffps_id); static const struct of_device_id ibm_cffps_of_match[] = { - { .compatible = "ibm,cffps1" }, + { + .compatible = "ibm,cffps1", + .data = (void *)cffps1 + }, + { + .compatible = "ibm,cffps2", + .data = (void *)cffps2 + }, {} }; MODULE_DEVICE_TABLE(of, ibm_cffps_of_match); diff --git a/drivers/hwmon/pmbus/inspur-ipsps.c b/drivers/hwmon/pmbus/inspur-ipsps.c new file mode 100644 index 0000000000000000000000000000000000000000..42e01549184aa8e892dd52026dcc21638f3b6fa5 --- /dev/null +++ b/drivers/hwmon/pmbus/inspur-ipsps.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2019 Inspur Corp. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pmbus.h" + +#define IPSPS_REG_VENDOR_ID 0x99 +#define IPSPS_REG_MODEL 0x9A +#define IPSPS_REG_FW_VERSION 0x9B +#define IPSPS_REG_PN 0x9C +#define IPSPS_REG_SN 0x9E +#define IPSPS_REG_HW_VERSION 0xB0 +#define IPSPS_REG_MODE 0xFC + +#define MODE_ACTIVE 0x55 +#define MODE_STANDBY 0x0E +#define MODE_REDUNDANCY 0x00 + +#define MODE_ACTIVE_STRING "active" +#define MODE_STANDBY_STRING "standby" +#define MODE_REDUNDANCY_STRING "redundancy" + +enum ipsps_index { + vendor, + model, + fw_version, + part_number, + serial_number, + hw_version, + mode, + num_regs, +}; + +static const u8 ipsps_regs[num_regs] = { + [vendor] = IPSPS_REG_VENDOR_ID, + [model] = IPSPS_REG_MODEL, + [fw_version] = IPSPS_REG_FW_VERSION, + [part_number] = IPSPS_REG_PN, + [serial_number] = IPSPS_REG_SN, + [hw_version] = IPSPS_REG_HW_VERSION, + [mode] = IPSPS_REG_MODE, +}; + +static ssize_t ipsps_string_show(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + u8 reg; + int rc; + char *p; + char data[I2C_SMBUS_BLOCK_MAX + 1]; + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + reg = ipsps_regs[attr->index]; + rc = i2c_smbus_read_block_data(client, reg, data); + if (rc < 0) + return rc; + + /* filled with printable characters, ending with # */ + p = memscan(data, '#', rc); + *p = '\0'; + + return snprintf(buf, PAGE_SIZE, "%s\n", data); +} + +static ssize_t ipsps_fw_version_show(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + u8 reg; + int rc; + u8 data[I2C_SMBUS_BLOCK_MAX] = { 0 }; + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + reg = ipsps_regs[attr->index]; + rc = i2c_smbus_read_block_data(client, reg, data); + if (rc < 0) + return rc; + + 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 */); +} + +static ssize_t ipsps_mode_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + u8 reg; + int rc; + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + reg = ipsps_regs[attr->index]; + rc = i2c_smbus_read_byte_data(client, reg); + if (rc < 0) + return rc; + + switch (rc) { + case MODE_ACTIVE: + return snprintf(buf, PAGE_SIZE, "[%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); + case MODE_REDUNDANCY: + return snprintf(buf, PAGE_SIZE, "%s %s [%s]\n", + MODE_ACTIVE_STRING, + MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING); + default: + return snprintf(buf, PAGE_SIZE, "unspecified\n"); + } +} + +static ssize_t ipsps_mode_store(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + u8 reg; + int rc; + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + reg = ipsps_regs[attr->index]; + if (sysfs_streq(MODE_STANDBY_STRING, buf)) { + rc = i2c_smbus_write_byte_data(client, reg, + MODE_STANDBY); + if (rc < 0) + return rc; + return count; + } else if (sysfs_streq(MODE_ACTIVE_STRING, buf)) { + rc = i2c_smbus_write_byte_data(client, reg, + MODE_ACTIVE); + if (rc < 0) + return rc; + return count; + } + + return -EINVAL; +} + +static SENSOR_DEVICE_ATTR_RO(vendor, ipsps_string, vendor); +static SENSOR_DEVICE_ATTR_RO(model, ipsps_string, model); +static SENSOR_DEVICE_ATTR_RO(part_number, ipsps_string, part_number); +static SENSOR_DEVICE_ATTR_RO(serial_number, ipsps_string, serial_number); +static SENSOR_DEVICE_ATTR_RO(hw_version, ipsps_string, hw_version); +static SENSOR_DEVICE_ATTR_RO(fw_version, ipsps_fw_version, fw_version); +static SENSOR_DEVICE_ATTR_RW(mode, ipsps_mode, mode); + +static struct attribute *ipsps_attrs[] = { + &sensor_dev_attr_vendor.dev_attr.attr, + &sensor_dev_attr_model.dev_attr.attr, + &sensor_dev_attr_part_number.dev_attr.attr, + &sensor_dev_attr_serial_number.dev_attr.attr, + &sensor_dev_attr_hw_version.dev_attr.attr, + &sensor_dev_attr_fw_version.dev_attr.attr, + &sensor_dev_attr_mode.dev_attr.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(ipsps); + +static struct pmbus_driver_info ipsps_info = { + .pages = 1, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | + PMBUS_HAVE_IIN | PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | + PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | + PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT | + PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_STATUS_FAN12, + .groups = ipsps_groups, +}; + +static struct pmbus_platform_data ipsps_pdata = { + .flags = PMBUS_SKIP_STATUS_CHECK, +}; + +static int ipsps_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + client->dev.platform_data = &ipsps_pdata; + return pmbus_do_probe(client, id, &ipsps_info); +} + +static const struct i2c_device_id ipsps_id[] = { + { "ipsps1", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ipsps_id); + +#ifdef CONFIG_OF +static const struct of_device_id ipsps_of_match[] = { + { .compatible = "inspur,ipsps1" }, + {} +}; +MODULE_DEVICE_TABLE(of, ipsps_of_match); +#endif + +static struct i2c_driver ipsps_driver = { + .driver = { + .name = "inspur-ipsps", + .of_match_table = of_match_ptr(ipsps_of_match), + }, + .probe = ipsps_probe, + .remove = pmbus_do_remove, + .id_table = ipsps_id, +}; + +module_i2c_driver(ipsps_driver); + +MODULE_AUTHOR("John Wang"); +MODULE_DESCRIPTION("PMBus driver for Inspur Power System power supplies"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c index 69d9029ea410d03581515b954a74a5264f2a6f20..254b0f98c7552024dad65835e3805342b9147ba4 100644 --- a/drivers/hwmon/pmbus/max31785.c +++ b/drivers/hwmon/pmbus/max31785.c @@ -244,8 +244,6 @@ static int max31785_write_word_data(struct i2c_client *client, int page, #define MAX31785_VOUT_FUNCS \ (PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT) -#define MAX37185_NUM_FAN_PAGES 6 - static const struct pmbus_driver_info max31785_info = { .pages = MAX31785_NR_PAGES, diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index c846759bc1c0866d3954f5fd9b895e315275a800..a9229c6b0e84dcc7435d18bd9e19bef9a60227ae 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include "pmbus.h" diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 54c0ff00d67fe731e9cdacd6ae8dcafaf0dbc566..42ffd2e5182d57edc3bf3c0e54513f0dc4422bf7 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -304,7 +304,7 @@ static int pwm_fan_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); - ctx->irq = platform_get_irq(pdev, 0); + ctx->irq = platform_get_irq_optional(pdev, 0); if (ctx->irq == -EPROBE_DEFER) return ctx->irq; diff --git a/drivers/hwmon/raspberrypi-hwmon.c b/drivers/hwmon/raspberrypi-hwmon.c index efe4bb1ff221c871d99c1c6697690cf870cdeea7..d3a64a35f7a9af2d11fe31de0d37b5abb7c2301a 100644 --- a/drivers/hwmon/raspberrypi-hwmon.c +++ b/drivers/hwmon/raspberrypi-hwmon.c @@ -146,7 +146,7 @@ static struct platform_driver rpi_hwmon_driver = { }; module_platform_driver(rpi_hwmon_driver); -MODULE_AUTHOR("Stefan Wahren "); +MODULE_AUTHOR("Stefan Wahren "); MODULE_DESCRIPTION("Raspberry Pi voltage sensor driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:raspberrypi-hwmon"); diff --git a/drivers/hwmon/scmi-hwmon.c b/drivers/hwmon/scmi-hwmon.c index 0c93fc5ca762ecfe7690fe482f9ff4f9a9a77b4d..8a7732c0bef3e4fdbd1a2fa4b56d5998f38eae2b 100644 --- a/drivers/hwmon/scmi-hwmon.c +++ b/drivers/hwmon/scmi-hwmon.c @@ -72,7 +72,7 @@ static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, const struct scmi_handle *h = scmi_sensors->handle; sensor = *(scmi_sensors->info[type] + channel); - ret = h->sensor_ops->reading_get(h, sensor->id, false, &value); + ret = h->sensor_ops->reading_get(h, sensor->id, &value); if (ret) return ret; diff --git a/drivers/hwmon/shtc1.c b/drivers/hwmon/shtc1.c index 83fe08185ac7d9a9a1a92338277b742fa0547919..a0078ccede03f9302db615deab5e0d65df75fdcc 100644 --- a/drivers/hwmon/shtc1.c +++ b/drivers/hwmon/shtc1.c @@ -24,19 +24,33 @@ static const unsigned char shtc1_cmd_measure_blocking_lpm[] = { 0x64, 0x58 }; static const unsigned char shtc1_cmd_measure_nonblocking_lpm[] = { 0x60, 0x9c }; /* command for reading the ID register */ -static const unsigned char shtc1_cmd_read_id_reg[] = { 0xef, 0xc8 }; +static const unsigned char shtc1_cmd_read_id_reg[] = { 0xef, 0xc8 }; -/* constants for reading the ID register */ -#define SHTC1_ID 0x07 -#define SHTC1_ID_REG_MASK 0x1f +/* + * constants for reading the ID register + * SHTC1: 0x0007 with mask 0x003f + * SHTW1: 0x0007 with mask 0x003f + * SHTC3: 0x0807 with mask 0x083f + */ +#define SHTC3_ID 0x0807 +#define SHTC3_ID_MASK 0x083f +#define SHTC1_ID 0x0007 +#define SHTC1_ID_MASK 0x003f /* delays for non-blocking i2c commands, both in us */ #define SHTC1_NONBLOCKING_WAIT_TIME_HPM 14400 #define SHTC1_NONBLOCKING_WAIT_TIME_LPM 1000 +#define SHTC3_NONBLOCKING_WAIT_TIME_HPM 12100 +#define SHTC3_NONBLOCKING_WAIT_TIME_LPM 800 #define SHTC1_CMD_LENGTH 2 #define SHTC1_RESPONSE_LENGTH 6 +enum shtcx_chips { + shtc1, + shtc3, +}; + struct shtc1_data { struct i2c_client *client; struct mutex update_lock; @@ -47,6 +61,7 @@ struct shtc1_data { unsigned int nonblocking_wait_time; /* in us */ struct shtc1_platform_data setup; + enum shtcx_chips chip; int temperature; /* 1000 * temperature in dgr C */ int humidity; /* 1000 * relative humidity in %RH */ @@ -157,13 +172,16 @@ static void shtc1_select_command(struct shtc1_data *data) data->command = data->setup.blocking_io ? shtc1_cmd_measure_blocking_hpm : shtc1_cmd_measure_nonblocking_hpm; - data->nonblocking_wait_time = SHTC1_NONBLOCKING_WAIT_TIME_HPM; - + data->nonblocking_wait_time = (data->chip == shtc1) ? + SHTC1_NONBLOCKING_WAIT_TIME_HPM : + SHTC3_NONBLOCKING_WAIT_TIME_HPM; } else { data->command = data->setup.blocking_io ? shtc1_cmd_measure_blocking_lpm : shtc1_cmd_measure_nonblocking_lpm; - data->nonblocking_wait_time = SHTC1_NONBLOCKING_WAIT_TIME_LPM; + data->nonblocking_wait_time = (data->chip == shtc1) ? + SHTC1_NONBLOCKING_WAIT_TIME_LPM : + SHTC3_NONBLOCKING_WAIT_TIME_LPM; } } @@ -171,9 +189,11 @@ static int shtc1_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret; - char id_reg[2]; + u16 id_reg; + char id_reg_buf[2]; struct shtc1_data *data; struct device *hwmon_dev; + enum shtcx_chips chip = id->driver_data; struct i2c_adapter *adap = client->adapter; struct device *dev = &client->dev; @@ -187,13 +207,20 @@ static int shtc1_probe(struct i2c_client *client, dev_err(dev, "could not send read_id_reg command: %d\n", ret); return ret < 0 ? ret : -ENODEV; } - ret = i2c_master_recv(client, id_reg, sizeof(id_reg)); - if (ret != sizeof(id_reg)) { + ret = i2c_master_recv(client, id_reg_buf, sizeof(id_reg_buf)); + if (ret != sizeof(id_reg_buf)) { dev_err(dev, "could not read ID register: %d\n", ret); return -ENODEV; } - if ((id_reg[1] & SHTC1_ID_REG_MASK) != SHTC1_ID) { - dev_err(dev, "ID register doesn't match\n"); + + id_reg = be16_to_cpup((__be16 *)id_reg_buf); + if (chip == shtc3) { + if ((id_reg & SHTC3_ID_MASK) != SHTC3_ID) { + dev_err(dev, "SHTC3 ID register does not match\n"); + return -ENODEV; + } + } else if ((id_reg & SHTC1_ID_MASK) != SHTC1_ID) { + dev_err(dev, "SHTC1 ID register does not match\n"); return -ENODEV; } @@ -204,6 +231,7 @@ static int shtc1_probe(struct i2c_client *client, data->setup.blocking_io = false; data->setup.high_precision = true; data->client = client; + data->chip = chip; if (client->dev.platform_data) data->setup = *(struct shtc1_platform_data *)dev->platform_data; @@ -222,8 +250,9 @@ static int shtc1_probe(struct i2c_client *client, /* device ID table */ static const struct i2c_device_id shtc1_id[] = { - { "shtc1", 0 }, - { "shtw1", 0 }, + { "shtc1", shtc1 }, + { "shtw1", shtc1 }, + { "shtc3", shtc3 }, { } }; MODULE_DEVICE_TABLE(i2c, shtc1_id); diff --git a/drivers/hwmon/smm665.c b/drivers/hwmon/smm665.c index d8c91c2cb8cf5eab77498c81cd465033597bc2dd..af01f763f7d1e364c39a4e3a090019830bc63aca 100644 --- a/drivers/hwmon/smm665.c +++ b/drivers/hwmon/smm665.c @@ -197,7 +197,7 @@ static int smm665_read_adc(struct smm665_data *data, int adc) if (rv != -ENXIO) { /* * We expect ENXIO to reflect NACK - * (per Documentation/i2c/fault-codes). + * (per Documentation/i2c/fault-codes.rst). * Everything else is an error. */ dev_dbg(&client->dev, @@ -586,10 +586,10 @@ static int smm665_probe(struct i2c_client *client, data->client = client; data->type = id->driver_data; - data->cmdreg = i2c_new_dummy(adapter, (client->addr & ~SMM665_REGMASK) + data->cmdreg = i2c_new_dummy_device(adapter, (client->addr & ~SMM665_REGMASK) | SMM665_CMDREG_BASE); - if (!data->cmdreg) - return -ENOMEM; + if (IS_ERR(data->cmdreg)) + return PTR_ERR(data->cmdreg); switch (data->type) { case smm465: diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index d2c04b6a3f2b7cfd7974b8cf19ae1f21ad80ed69..015f1ea319669eff7932daf49456a6638b9a7add 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -894,12 +894,12 @@ w83781d_detect_subclients(struct i2c_client *new_client) } for (i = 0; i < num_sc; i++) { - data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]); - if (!data->lm75[i]) { + data->lm75[i] = i2c_new_dummy_device(adapter, sc_addr[i]); + if (IS_ERR(data->lm75[i])) { dev_err(&new_client->dev, "Subclient %d registration at address 0x%x failed.\n", i, sc_addr[i]); - err = -ENOMEM; + err = PTR_ERR(data->lm75[i]); if (i == 1) goto ERROR_SC_3; goto ERROR_SC_2; diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index 050ad42016914803181eb5e6f306185039f4eac8..aad8d4da5802be02cf981778ea68642075706f4a 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -1260,7 +1260,7 @@ static int w83791d_detect_subclients(struct i2c_client *client) struct i2c_adapter *adapter = client->adapter; struct w83791d_data *data = i2c_get_clientdata(client); int address = client->addr; - int i, id, err; + int i, id; u8 val; id = i2c_adapter_id(adapter); @@ -1272,8 +1272,7 @@ static int w83791d_detect_subclients(struct i2c_client *client) "invalid subclient " "address %d; must be 0x48-0x4f\n", force_subclients[i]); - err = -ENODEV; - goto error_sc_0; + return -ENODEV; } } w83791d_write(client, W83791D_REG_I2C_SUBADDR, @@ -1283,29 +1282,22 @@ static int w83791d_detect_subclients(struct i2c_client *client) val = w83791d_read(client, W83791D_REG_I2C_SUBADDR); if (!(val & 0x08)) - data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7)); + data->lm75[0] = devm_i2c_new_dummy_device(&client->dev, adapter, + 0x48 + (val & 0x7)); if (!(val & 0x80)) { - if ((data->lm75[0] != NULL) && + if (!IS_ERR(data->lm75[0]) && ((val & 0x7) == ((val >> 4) & 0x7))) { dev_err(&client->dev, "duplicate addresses 0x%x, " "use force_subclient\n", data->lm75[0]->addr); - err = -ENODEV; - goto error_sc_1; + return -ENODEV; } - data->lm75[1] = i2c_new_dummy(adapter, - 0x48 + ((val >> 4) & 0x7)); + data->lm75[1] = devm_i2c_new_dummy_device(&client->dev, adapter, + 0x48 + ((val >> 4) & 0x7)); } return 0; - -/* Undo inits in case of errors */ - -error_sc_1: - i2c_unregister_device(data->lm75[0]); -error_sc_0: - return err; } @@ -1394,7 +1386,7 @@ static int w83791d_probe(struct i2c_client *client, /* Register sysfs hooks */ err = sysfs_create_group(&client->dev.kobj, &w83791d_group); if (err) - goto error3; + return err; /* Check if pins of fan/pwm 4-5 are in use as GPIO */ has_fanpwm45 = w83791d_read(client, W83791D_REG_GPIO) & 0x10; @@ -1419,9 +1411,6 @@ static int w83791d_probe(struct i2c_client *client, sysfs_remove_group(&client->dev.kobj, &w83791d_group_fanpwm45); error4: sysfs_remove_group(&client->dev.kobj, &w83791d_group); -error3: - i2c_unregister_device(data->lm75[0]); - i2c_unregister_device(data->lm75[1]); return err; } @@ -1432,9 +1421,6 @@ static int w83791d_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &w83791d_group); - i2c_unregister_device(data->lm75[0]); - i2c_unregister_device(data->lm75[1]); - return 0; } diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index da8a6d62aa2347c9c7fd8dac5aae66193082b3f5..7fc8a1160c8f95269a8c29e07db0ff3e92c962d9 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -924,7 +924,7 @@ store_sf2_level(struct device *dev, struct device_attribute *attr, static int w83792d_detect_subclients(struct i2c_client *new_client) { - int i, id, err; + int i, id; int address = new_client->addr; u8 val; struct i2c_adapter *adapter = new_client->adapter; @@ -938,8 +938,7 @@ w83792d_detect_subclients(struct i2c_client *new_client) dev_err(&new_client->dev, "invalid subclient address %d; must be 0x48-0x4f\n", force_subclients[i]); - err = -ENODEV; - goto ERROR_SC_0; + return -ENODEV; } } w83792d_write_value(new_client, W83792D_REG_I2C_SUBADDR, @@ -949,28 +948,21 @@ w83792d_detect_subclients(struct i2c_client *new_client) val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR); if (!(val & 0x08)) - data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7)); + data->lm75[0] = devm_i2c_new_dummy_device(&new_client->dev, adapter, + 0x48 + (val & 0x7)); if (!(val & 0x80)) { - if ((data->lm75[0] != NULL) && + if (!IS_ERR(data->lm75[0]) && ((val & 0x7) == ((val >> 4) & 0x7))) { dev_err(&new_client->dev, "duplicate addresses 0x%x, use force_subclient\n", data->lm75[0]->addr); - err = -ENODEV; - goto ERROR_SC_1; + return -ENODEV; } - data->lm75[1] = i2c_new_dummy(adapter, - 0x48 + ((val >> 4) & 0x7)); + data->lm75[1] = devm_i2c_new_dummy_device(&new_client->dev, adapter, + 0x48 + ((val >> 4) & 0x7)); } return 0; - -/* Undo inits in case of errors */ - -ERROR_SC_1: - i2c_unregister_device(data->lm75[0]); -ERROR_SC_0: - return err; } static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0); @@ -1396,7 +1388,7 @@ w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id) /* Register sysfs hooks */ err = sysfs_create_group(&dev->kobj, &w83792d_group); if (err) - goto exit_i2c_unregister; + return err; /* * Read GPIO enable register to check if pins for fan 4,5 are used as @@ -1441,9 +1433,6 @@ w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id) sysfs_remove_group(&dev->kobj, &w83792d_group); for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++) sysfs_remove_group(&dev->kobj, &w83792d_group_fan[i]); -exit_i2c_unregister: - i2c_unregister_device(data->lm75[0]); - i2c_unregister_device(data->lm75[1]); return err; } @@ -1459,9 +1448,6 @@ w83792d_remove(struct i2c_client *client) sysfs_remove_group(&client->dev.kobj, &w83792d_group_fan[i]); - i2c_unregister_device(data->lm75[0]); - i2c_unregister_device(data->lm75[1]); - return 0; } diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 46f5dfec8d0a29ef6ff40b151d19f4e3024320fd..9df48b70c70c7381fbcba60119182a39edb2a2cd 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -1551,9 +1551,6 @@ static int w83793_remove(struct i2c_client *client) for (i = 0; i < ARRAY_SIZE(w83793_temp); i++) device_remove_file(dev, &w83793_temp[i].dev_attr); - i2c_unregister_device(data->lm75[0]); - i2c_unregister_device(data->lm75[1]); - /* Decrease data reference counter */ mutex_lock(&watchdog_data_mutex); kref_put(&data->kref, w83793_release_resources); @@ -1565,7 +1562,7 @@ static int w83793_remove(struct i2c_client *client) static int w83793_detect_subclients(struct i2c_client *client) { - int i, id, err; + int i, id; int address = client->addr; u8 tmp; struct i2c_adapter *adapter = client->adapter; @@ -1580,8 +1577,7 @@ w83793_detect_subclients(struct i2c_client *client) "invalid subclient " "address %d; must be 0x48-0x4f\n", force_subclients[i]); - err = -EINVAL; - goto ERROR_SC_0; + return -EINVAL; } } w83793_write_value(client, W83793_REG_I2C_SUBADDR, @@ -1591,28 +1587,21 @@ w83793_detect_subclients(struct i2c_client *client) tmp = w83793_read_value(client, W83793_REG_I2C_SUBADDR); if (!(tmp & 0x08)) - data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (tmp & 0x7)); + data->lm75[0] = devm_i2c_new_dummy_device(&client->dev, adapter, + 0x48 + (tmp & 0x7)); if (!(tmp & 0x80)) { - if ((data->lm75[0] != NULL) + if (!IS_ERR(data->lm75[0]) && ((tmp & 0x7) == ((tmp >> 4) & 0x7))) { dev_err(&client->dev, "duplicate addresses 0x%x, " "use force_subclients\n", data->lm75[0]->addr); - err = -ENODEV; - goto ERROR_SC_1; + return -ENODEV; } - data->lm75[1] = i2c_new_dummy(adapter, - 0x48 + ((tmp >> 4) & 0x7)); + data->lm75[1] = devm_i2c_new_dummy_device(&client->dev, adapter, + 0x48 + ((tmp >> 4) & 0x7)); } return 0; - - /* Undo inits in case of errors */ - -ERROR_SC_1: - i2c_unregister_device(data->lm75[0]); -ERROR_SC_0: - return err; } /* Return 0 if detection is successful, -ENODEV otherwise */ @@ -1945,9 +1934,6 @@ static int w83793_probe(struct i2c_client *client, for (i = 0; i < ARRAY_SIZE(w83793_temp); i++) device_remove_file(dev, &w83793_temp[i].dev_attr); - - i2c_unregister_device(data->lm75[0]); - i2c_unregister_device(data->lm75[1]); free_mem: kfree(data); exit: diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index 14638db4991de8e922c8cdb26979a1989ae47ec9..7a9f5fb0833081f50953d1132803e9f1c55ca732 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -106,7 +106,7 @@ config CORESIGHT_CPU_DEBUG can quickly get to know program counter (PC), secure state, exception level, etc. Before use debugging functionality, platform needs to ensure the clock domain and power domain are enabled - properly, please refer Documentation/trace/coresight-cpu-debug.txt + properly, please refer Documentation/trace/coresight-cpu-debug.rst for detailed description and the example for usage. endif diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 2463aa7ab4f6747a7a04670aba38a202ecb3e77b..96544b348c273fe3ede7ac5e40547afd8b4322bc 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -646,24 +646,23 @@ static int debug_remove(struct amba_device *adev) return 0; } +static const struct amba_cs_uci_id uci_id_debug[] = { + { + /* CPU Debug UCI data */ + .devarch = 0x47706a15, + .devarch_mask = 0xfff0ffff, + .devtype = 0x00000015, + } +}; + static const struct amba_id debug_ids[] = { - { /* Debug for Cortex-A53 */ - .id = 0x000bbd03, - .mask = 0x000fffff, - }, - { /* Debug for Cortex-A57 */ - .id = 0x000bbd07, - .mask = 0x000fffff, - }, - { /* Debug for Cortex-A72 */ - .id = 0x000bbd08, - .mask = 0x000fffff, - }, - { /* Debug for Cortex-A73 */ - .id = 0x000bbd09, - .mask = 0x000fffff, - }, - { 0, 0 }, + CS_AMBA_ID(0x000bbd03), /* Cortex-A53 */ + CS_AMBA_ID(0x000bbd07), /* Cortex-A57 */ + CS_AMBA_ID(0x000bbd08), /* Cortex-A72 */ + CS_AMBA_ID(0x000bbd09), /* Cortex-A73 */ + CS_AMBA_UCI_ID(0x000f0205, uci_id_debug), /* Qualcomm Kryo */ + CS_AMBA_UCI_ID(0x000f0211, uci_id_debug), /* Qualcomm Kryo */ + {}, }; static struct amba_driver debug_driver = { diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c index a0365e23678e27fb968c47b76a5c2ba424ca07a4..219c10eb752cca3770b0e10dc5083406298dc767 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c @@ -296,11 +296,8 @@ static ssize_t mode_store(struct device *dev, spin_lock(&drvdata->spinlock); config->mode = val & ETMv4_MODE_ALL; - - if (config->mode & ETM_MODE_EXCLUDE) - etm4_set_mode_exclude(drvdata, true); - else - etm4_set_mode_exclude(drvdata, false); + etm4_set_mode_exclude(drvdata, + config->mode & ETM_MODE_EXCLUDE ? true : false); if (drvdata->instrp0 == true) { /* start by clearing instruction P0 field */ @@ -999,10 +996,8 @@ static ssize_t addr_range_store(struct device *dev, * Program include or exclude control bits for vinst or vdata * whenever we change addr comparators to ETM_ADDR_TYPE_RANGE */ - if (config->mode & ETM_MODE_EXCLUDE) - etm4_set_mode_exclude(drvdata, true); - else - etm4_set_mode_exclude(drvdata, false); + etm4_set_mode_exclude(drvdata, + config->mode & ETM_MODE_EXCLUDE ? true : false); spin_unlock(&drvdata->spinlock); return size; diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index 7bcac8896fc1d7f266176bdaddbdfbab318ed73e..a128b5063f46c9571b7076bd478c3f344f65a052 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -34,7 +34,8 @@ #include "coresight-etm-perf.h" static int boot_enable; -module_param_named(boot_enable, boot_enable, int, S_IRUGO); +module_param(boot_enable, int, 0444); +MODULE_PARM_DESC(boot_enable, "Enable tracing on boot"); /* The number of ETMv4 currently registered */ static int etm4_count; @@ -47,7 +48,7 @@ static enum cpuhp_state hp_online; static void etm4_os_unlock(struct etmv4_drvdata *drvdata) { - /* Writing any value to ETMOSLAR unlocks the trace registers */ + /* Writing 0 to TRCOSLAR unlocks the trace registers */ writel_relaxed(0x0, drvdata->base + TRCOSLAR); drvdata->os_unlock = true; isb(); @@ -188,6 +189,13 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata) dev_err(etm_dev, "timeout while waiting for Idle Trace Status\n"); + /* + * As recommended by section 4.3.7 ("Synchronization when using the + * memory-mapped interface") of ARM IHI 0064D + */ + dsb(sy); + isb(); + done: CS_LOCK(drvdata->base); @@ -453,8 +461,12 @@ static void etm4_disable_hw(void *info) /* EN, bit[0] Trace unit enable bit */ control &= ~0x1; - /* make sure everything completes before disabling */ - mb(); + /* + * Make sure everything completes before disabling, as recommended + * by section 7.3.77 ("TRCVICTLR, ViewInst Main Control Register, + * SSTATUS") of ARM IHI 0064D + */ + dsb(sy); isb(); writel_relaxed(control, drvdata->base + TRCPRGCTLR); @@ -1047,10 +1059,8 @@ static int etm4_starting_cpu(unsigned int cpu) return 0; spin_lock(&etmdrvdata[cpu]->spinlock); - if (!etmdrvdata[cpu]->os_unlock) { + if (!etmdrvdata[cpu]->os_unlock) etm4_os_unlock(etmdrvdata[cpu]); - etmdrvdata[cpu]->os_unlock = true; - } if (local_read(&etmdrvdata[cpu]->mode)) etm4_enable_hw(etmdrvdata[cpu]); @@ -1192,11 +1202,15 @@ static struct amba_cs_uci_id uci_id_etm4[] = { }; static const struct amba_id etm4_ids[] = { - CS_AMBA_ID(0x000bb95d), /* Cortex-A53 */ - CS_AMBA_ID(0x000bb95e), /* Cortex-A57 */ - CS_AMBA_ID(0x000bb95a), /* Cortex-A72 */ - CS_AMBA_ID(0x000bb959), /* Cortex-A73 */ - CS_AMBA_UCI_ID(0x000bb9da, uci_id_etm4), /* Cortex-A35 */ + CS_AMBA_ID(0x000bb95d), /* Cortex-A53 */ + CS_AMBA_ID(0x000bb95e), /* Cortex-A57 */ + CS_AMBA_ID(0x000bb95a), /* Cortex-A72 */ + CS_AMBA_ID(0x000bb959), /* Cortex-A73 */ + CS_AMBA_UCI_ID(0x000bb9da, uci_id_etm4),/* Cortex-A35 */ + CS_AMBA_UCI_ID(0x000f0205, uci_id_etm4),/* Qualcomm Kryo */ + CS_AMBA_UCI_ID(0x000f0211, uci_id_etm4),/* Qualcomm Kryo */ + CS_AMBA_ID(0x000bb802), /* Qualcomm Kryo 385 Cortex-A55 */ + CS_AMBA_ID(0x000bb803), /* Qualcomm Kryo 385 Cortex-A75 */ {}, }; diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index fa97cb9ab4f9dc6ba8e980fbcace0294e3a309f8..05f7896c3a0159992e0aafdb0d37a6939a7d566d 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -5,6 +5,7 @@ * Description: CoreSight Funnel driver */ +#include #include #include #include @@ -192,7 +193,7 @@ static int funnel_probe(struct device *dev, struct resource *res) if (is_of_node(dev_fwnode(dev)) && of_device_is_compatible(dev->of_node, "arm,coresight-funnel")) - pr_warn_once("Uses OBSOLETE CoreSight funnel binding\n"); + dev_warn_once(dev, "Uses OBSOLETE CoreSight funnel binding\n"); desc.name = coresight_alloc_device_name(&funnel_devs, dev); if (!desc.name) @@ -302,11 +303,19 @@ static const struct of_device_id static_funnel_match[] = { {} }; +#ifdef CONFIG_ACPI +static const struct acpi_device_id static_funnel_ids[] = { + {"ARMHC9FE", 0}, + {}, +}; +#endif + static struct platform_driver static_funnel_driver = { .probe = static_funnel_probe, .driver = { .name = "coresight-static-funnel", .of_match_table = static_funnel_match, + .acpi_match_table = ACPI_PTR(static_funnel_ids), .pm = &funnel_dev_pm_ops, .suppress_bind_attrs = true, }, diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c index dad7d96c5943619a4c34a91e45188dd74d1fbec2..3c5bee429105efc8d4d9e7d389c2996b21828313 100644 --- a/drivers/hwtracing/coresight/coresight-platform.c +++ b/drivers/hwtracing/coresight/coresight-platform.c @@ -37,11 +37,6 @@ static int coresight_alloc_conns(struct device *dev, return 0; } -int coresight_device_fwnode_match(struct device *dev, const void *fwnode) -{ - return dev_fwnode(dev) == fwnode; -} - static struct device * coresight_find_device_by_fwnode(struct fwnode_handle *fwnode) { @@ -51,8 +46,7 @@ coresight_find_device_by_fwnode(struct fwnode_handle *fwnode) * If we have a non-configurable replicator, it will be found on the * platform bus. */ - dev = bus_find_device(&platform_bus_type, NULL, - fwnode, coresight_device_fwnode_match); + dev = bus_find_device_by_fwnode(&platform_bus_type, fwnode); if (dev) return dev; @@ -60,8 +54,7 @@ coresight_find_device_by_fwnode(struct fwnode_handle *fwnode) * We have a configurable component - circle through the AMBA bus * looking for the device that matches the endpoint node. */ - return bus_find_device(&amba_bustype, NULL, - fwnode, coresight_device_fwnode_match); + return bus_find_device_by_fwnode(&amba_bustype, fwnode); } #ifdef CONFIG_OF diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 7d401790dd7e102a31675d8b1b8baee411661708..82e563cdc879483aba8113a388f1ec6250aabab0 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -185,11 +185,11 @@ static inline int etm_writel_cp14(u32 off, u32 val) { return 0; } } /* coresight AMBA ID, full UCI structure: id table entry. */ -#define CS_AMBA_UCI_ID(pid, uci_ptr) \ - { \ - .id = pid, \ - .mask = 0x000fffff, \ - .data = uci_ptr \ +#define CS_AMBA_UCI_ID(pid, uci_ptr) \ + { \ + .id = pid, \ + .mask = 0x000fffff, \ + .data = (void *)uci_ptr \ } /* extract the data value from a UCI structure given amba_id pointer. */ @@ -202,6 +202,4 @@ static inline void *coresight_get_uci_data(const struct amba_id *id) void coresight_release_platform_data(struct coresight_platform_data *pdata); -int coresight_device_fwnode_match(struct device *dev, const void *fwnode); - #endif diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index b7d6d59d56db2a59e9b25ec4b9bdf8643edfcf0f..b29ba640eb25b94cd3e63f0b199ddf71574c94ce 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -184,7 +184,8 @@ static int replicator_probe(struct device *dev, struct resource *res) if (is_of_node(dev_fwnode(dev)) && of_device_is_compatible(dev->of_node, "arm,coresight-replicator")) - pr_warn_once("Uses OBSOLETE CoreSight replicator binding\n"); + dev_warn_once(dev, + "Uses OBSOLETE CoreSight replicator binding\n"); desc.name = coresight_alloc_device_name(&replicator_devs, dev); if (!desc.name) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index 23b7ff00af5ca4bf32eadc7cf3ea640c4a1e5f9c..807416b75ecc2bfdf36322856f3987d20c52bcb8 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -479,30 +479,11 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev, * traces. */ if (!buf->snapshot && to_read > handle->size) { - u32 mask = 0; - - /* - * The value written to RRP must be byte-address aligned to - * the width of the trace memory databus _and_ to a frame - * boundary (16 byte), whichever is the biggest. For example, - * for 32-bit, 64-bit and 128-bit wide trace memory, the four - * LSBs must be 0s. For 256-bit wide trace memory, the five - * LSBs must be 0s. - */ - switch (drvdata->memwidth) { - case TMC_MEM_INTF_WIDTH_32BITS: - case TMC_MEM_INTF_WIDTH_64BITS: - case TMC_MEM_INTF_WIDTH_128BITS: - mask = GENMASK(31, 4); - break; - case TMC_MEM_INTF_WIDTH_256BITS: - mask = GENMASK(31, 5); - break; - } + u32 mask = tmc_get_memwidth_mask(drvdata); /* * Make sure the new size is aligned in accordance with the - * requirement explained above. + * requirement explained in function tmc_get_memwidth_mask(). */ to_read = handle->size & mask; /* Move the RAM read pointer up */ diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 17006705287a525c697d9970ffed9f7e99aaef6f..625882bc8b08fe778ebbeaf170ca404cef2bac1e 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -871,6 +871,7 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata, return ERR_PTR(rc); } + refcount_set(&etr_buf->refcount, 1); dev_dbg(dev, "allocated buffer of size %ldKB in mode %d\n", (unsigned long)size >> 10, etr_buf->mode); return etr_buf; @@ -927,15 +928,24 @@ static void tmc_sync_etr_buf(struct tmc_drvdata *drvdata) rrp = tmc_read_rrp(drvdata); rwp = tmc_read_rwp(drvdata); status = readl_relaxed(drvdata->base + TMC_STS); + + /* + * If there were memory errors in the session, truncate the + * buffer. + */ + if (WARN_ON_ONCE(status & TMC_STS_MEMERR)) { + dev_dbg(&drvdata->csdev->dev, + "tmc memory error detected, truncating buffer\n"); + etr_buf->len = 0; + etr_buf->full = 0; + return; + } + etr_buf->full = status & TMC_STS_FULL; WARN_ON(!etr_buf->ops || !etr_buf->ops->sync); etr_buf->ops->sync(etr_buf, rrp, rwp); - - /* Insert barrier packets at the beginning, if there was an overflow */ - if (etr_buf->full) - tmc_etr_buf_insert_barrier_packet(etr_buf, etr_buf->offset); } static void __tmc_etr_enable_hw(struct tmc_drvdata *drvdata) @@ -1072,6 +1082,13 @@ static void tmc_etr_sync_sysfs_buf(struct tmc_drvdata *drvdata) drvdata->sysfs_buf = NULL; } else { tmc_sync_etr_buf(drvdata); + /* + * Insert barrier packets at the beginning, if there was + * an overflow. + */ + if (etr_buf->full) + tmc_etr_buf_insert_barrier_packet(etr_buf, + etr_buf->offset); } } @@ -1263,8 +1280,6 @@ get_perf_etr_buf_cpu_wide(struct tmc_drvdata *drvdata, if (IS_ERR(etr_buf)) return etr_buf; - refcount_set(&etr_buf->refcount, 1); - /* Now that we have a buffer, add it to the IDR. */ mutex_lock(&drvdata->idr_mutex); ret = idr_alloc(&drvdata->idr, etr_buf, pid, pid + 1, GFP_KERNEL); @@ -1291,19 +1306,11 @@ get_perf_etr_buf_per_thread(struct tmc_drvdata *drvdata, struct perf_event *event, int nr_pages, void **pages, bool snapshot) { - struct etr_buf *etr_buf; - /* * In per-thread mode the etr_buf isn't shared, so just go ahead * with memory allocation. */ - etr_buf = alloc_etr_buf(drvdata, event, nr_pages, pages, snapshot); - if (IS_ERR(etr_buf)) - goto out; - - refcount_set(&etr_buf->refcount, 1); -out: - return etr_buf; + return alloc_etr_buf(drvdata, event, nr_pages, pages, snapshot); } static struct etr_buf * @@ -1410,10 +1417,12 @@ static void tmc_free_etr_buffer(void *config) * tmc_etr_sync_perf_buffer: Copy the actual trace data from the hardware * buffer to the perf ring buffer. */ -static void tmc_etr_sync_perf_buffer(struct etr_perf_buffer *etr_perf) +static void tmc_etr_sync_perf_buffer(struct etr_perf_buffer *etr_perf, + unsigned long src_offset, + unsigned long to_copy) { - long bytes, to_copy; - long pg_idx, pg_offset, src_offset; + long bytes; + long pg_idx, pg_offset; unsigned long head = etr_perf->head; char **dst_pages, *src_buf; struct etr_buf *etr_buf = etr_perf->etr_buf; @@ -1422,8 +1431,6 @@ static void tmc_etr_sync_perf_buffer(struct etr_perf_buffer *etr_perf) pg_idx = head >> PAGE_SHIFT; pg_offset = head & (PAGE_SIZE - 1); dst_pages = (char **)etr_perf->pages; - src_offset = etr_buf->offset; - to_copy = etr_buf->len; while (to_copy > 0) { /* @@ -1434,6 +1441,8 @@ static void tmc_etr_sync_perf_buffer(struct etr_perf_buffer *etr_perf) * 3) what is available in the destination page. * in one iteration. */ + if (src_offset >= etr_buf->size) + src_offset -= etr_buf->size; bytes = tmc_etr_buf_get_data(etr_buf, src_offset, to_copy, &src_buf); if (WARN_ON_ONCE(bytes <= 0)) @@ -1454,8 +1463,6 @@ static void tmc_etr_sync_perf_buffer(struct etr_perf_buffer *etr_perf) /* Move source pointers */ src_offset += bytes; - if (src_offset >= etr_buf->size) - src_offset -= etr_buf->size; } } @@ -1471,7 +1478,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev, void *config) { bool lost = false; - unsigned long flags, size = 0; + unsigned long flags, offset, size = 0; struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); struct etr_perf_buffer *etr_perf = config; struct etr_buf *etr_buf = etr_perf->etr_buf; @@ -1484,7 +1491,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev, goto out; } - if (WARN_ON(drvdata->perf_data != etr_perf)) { + if (WARN_ON(drvdata->perf_buf != etr_buf)) { lost = true; spin_unlock_irqrestore(&drvdata->spinlock, flags); goto out; @@ -1496,12 +1503,38 @@ tmc_update_etr_buffer(struct coresight_device *csdev, tmc_sync_etr_buf(drvdata); CS_LOCK(drvdata->base); - /* Reset perf specific data */ - drvdata->perf_data = NULL; spin_unlock_irqrestore(&drvdata->spinlock, flags); + lost = etr_buf->full; + offset = etr_buf->offset; size = etr_buf->len; - tmc_etr_sync_perf_buffer(etr_perf); + + /* + * The ETR buffer may be bigger than the space available in the + * perf ring buffer (handle->size). If so advance the offset so that we + * get the latest trace data. In snapshot mode none of that matters + * since we are expected to clobber stale data in favour of the latest + * traces. + */ + if (!etr_perf->snapshot && size > handle->size) { + u32 mask = tmc_get_memwidth_mask(drvdata); + + /* + * Make sure the new size is aligned in accordance with the + * requirement explained in function tmc_get_memwidth_mask(). + */ + size = handle->size & mask; + offset = etr_buf->offset + etr_buf->len - size; + + if (offset >= etr_buf->size) + offset -= etr_buf->size; + lost = true; + } + + /* Insert barrier packets at the beginning, if there was an overflow */ + if (lost) + tmc_etr_buf_insert_barrier_packet(etr_buf, etr_buf->offset); + tmc_etr_sync_perf_buffer(etr_perf, offset, size); /* * In snapshot mode we simply increment the head by the number of byte @@ -1511,8 +1544,6 @@ tmc_update_etr_buffer(struct coresight_device *csdev, */ if (etr_perf->snapshot) handle->head += size; - - lost |= etr_buf->full; out: /* * Don't set the TRUNCATED flag in snapshot mode because 1) the @@ -1556,7 +1587,6 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) } etr_perf->head = PERF_IDX2OFF(handle->head, etr_perf); - drvdata->perf_data = etr_perf; /* * No HW configuration is needed if the sink is already in @@ -1572,6 +1602,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) /* Associate with monitored process. */ drvdata->pid = pid; drvdata->mode = CS_MODE_PERF; + drvdata->perf_buf = etr_perf->etr_buf; atomic_inc(csdev->refcnt); } @@ -1617,6 +1648,8 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev) /* Dissociate from monitored process. */ drvdata->pid = -1; drvdata->mode = CS_MODE_DISABLED; + /* Reset perf specific data */ + drvdata->perf_buf = NULL; spin_unlock_irqrestore(&drvdata->spinlock, flags); diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index be37aff573b44a225de50a1dd36475cafc1ecfc5..1cf82fa582898dd988247d8589230812e7c54ac7 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -70,6 +70,34 @@ void tmc_disable_hw(struct tmc_drvdata *drvdata) writel_relaxed(0x0, drvdata->base + TMC_CTL); } +u32 tmc_get_memwidth_mask(struct tmc_drvdata *drvdata) +{ + u32 mask = 0; + + /* + * When moving RRP or an offset address forward, the new values must + * be byte-address aligned to the width of the trace memory databus + * _and_ to a frame boundary (16 byte), whichever is the biggest. For + * example, for 32-bit, 64-bit and 128-bit wide trace memory, the four + * LSBs must be 0s. For 256-bit wide trace memory, the five LSBs must + * be 0s. + */ + switch (drvdata->memwidth) { + case TMC_MEM_INTF_WIDTH_32BITS: + /* fallthrough */ + case TMC_MEM_INTF_WIDTH_64BITS: + /* fallthrough */ + case TMC_MEM_INTF_WIDTH_128BITS: + mask = GENMASK(31, 4); + break; + case TMC_MEM_INTF_WIDTH_256BITS: + mask = GENMASK(31, 5); + break; + } + + return mask; +} + static int tmc_read_prepare(struct tmc_drvdata *drvdata) { int ret = 0; @@ -236,6 +264,7 @@ coresight_tmc_reg(ffcr, TMC_FFCR); coresight_tmc_reg(mode, TMC_MODE); coresight_tmc_reg(pscr, TMC_PSCR); coresight_tmc_reg(axictl, TMC_AXICTL); +coresight_tmc_reg(authstatus, TMC_AUTHSTATUS); coresight_tmc_reg(devid, CORESIGHT_DEVID); coresight_tmc_reg64(rrp, TMC_RRP, TMC_RRPHI); coresight_tmc_reg64(rwp, TMC_RWP, TMC_RWPHI); @@ -255,6 +284,7 @@ static struct attribute *coresight_tmc_mgmt_attrs[] = { &dev_attr_devid.attr, &dev_attr_dba.attr, &dev_attr_axictl.attr, + &dev_attr_authstatus.attr, NULL, }; @@ -342,6 +372,13 @@ static inline bool tmc_etr_can_use_sg(struct device *dev) return fwnode_property_present(dev->fwnode, "arm,scatter-gather"); } +static inline bool tmc_etr_has_non_secure_access(struct tmc_drvdata *drvdata) +{ + u32 auth = readl_relaxed(drvdata->base + TMC_AUTHSTATUS); + + return (auth & TMC_AUTH_NSID_MASK) == 0x3; +} + /* Detect and initialise the capabilities of a TMC ETR */ static int tmc_etr_setup_caps(struct device *parent, u32 devid, void *dev_caps) { @@ -349,6 +386,9 @@ static int tmc_etr_setup_caps(struct device *parent, u32 devid, void *dev_caps) u32 dma_mask = 0; struct tmc_drvdata *drvdata = dev_get_drvdata(parent); + if (!tmc_etr_has_non_secure_access(drvdata)) + return -EACCES; + /* Set the unadvertised capabilities */ tmc_etr_init_caps(drvdata, (u32)(unsigned long)dev_caps); diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 1ed50411cc3c34540fd1f7ebd3759241d55741a4..71de978575f36320222bea3e50ff20588648c0dc 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -39,6 +39,7 @@ #define TMC_ITATBCTR2 0xef0 #define TMC_ITATBCTR1 0xef4 #define TMC_ITATBCTR0 0xef8 +#define TMC_AUTHSTATUS 0xfb8 /* register description */ /* TMC_CTL - 0x020 */ @@ -47,6 +48,7 @@ #define TMC_STS_TMCREADY_BIT 2 #define TMC_STS_FULL BIT(0) #define TMC_STS_TRIGGERED BIT(1) +#define TMC_STS_MEMERR BIT(5) /* * TMC_AXICTL - 0x110 * @@ -89,6 +91,8 @@ #define TMC_DEVID_AXIAW_SHIFT 17 #define TMC_DEVID_AXIAW_MASK 0x7f +#define TMC_AUTH_NSID_MASK GENMASK(1, 0) + enum tmc_config_type { TMC_CONFIG_TYPE_ETB, TMC_CONFIG_TYPE_ETR, @@ -178,8 +182,8 @@ struct etr_buf { * device configuration register (DEVID) * @idr: Holds etr_bufs allocated for this ETR. * @idr_mutex: Access serialisation for idr. - * @perf_data: PERF buffer for ETR. - * @sysfs_data: SYSFS buffer for ETR. + * @sysfs_buf: SYSFS buffer for ETR. + * @perf_buf: PERF buffer for ETR. */ struct tmc_drvdata { void __iomem *base; @@ -202,7 +206,7 @@ struct tmc_drvdata { struct idr idr; struct mutex idr_mutex; struct etr_buf *sysfs_buf; - void *perf_data; + struct etr_buf *perf_buf; }; struct etr_buf_operations { @@ -251,6 +255,7 @@ void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata); void tmc_flush_and_stop(struct tmc_drvdata *drvdata); void tmc_enable_hw(struct tmc_drvdata *drvdata); void tmc_disable_hw(struct tmc_drvdata *drvdata); +u32 tmc_get_memwidth_mask(struct tmc_drvdata *drvdata); /* ETB/ETF functions */ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata); diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 55db77f6410b04c2af25e822a9eed3b3f3f53b59..6453c67a4d010f77509fff9256ad34c3b889ec53 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -1046,9 +1046,7 @@ static void coresight_fixup_device_conns(struct coresight_device *csdev) struct coresight_connection *conn = &csdev->pdata->conns[i]; struct device *dev = NULL; - dev = bus_find_device(&coresight_bustype, NULL, - (void *)conn->child_fwnode, - coresight_device_fwnode_match); + dev = bus_find_device_by_fwnode(&coresight_bustype, conn->child_fwnode); if (dev) { conn->child_dev = to_coresight_device(dev); /* and put reference from 'bus_find_device()' */ diff --git a/drivers/hwtracing/intel_th/Makefile b/drivers/hwtracing/intel_th/Makefile index d9252fa8d9ca19142bb72e808636de10006457fd..b63eb8f309ad116068b9f6ac1cf10d277a2cfed2 100644 --- a/drivers/hwtracing/intel_th/Makefile +++ b/drivers/hwtracing/intel_th/Makefile @@ -20,3 +20,6 @@ intel_th_msu-y := msu.o obj-$(CONFIG_INTEL_TH_PTI) += intel_th_pti.o intel_th_pti-y := pti.o + +obj-$(CONFIG_INTEL_TH_MSU) += intel_th_msu_sink.o +intel_th_msu_sink-y := msu-sink.o diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c index 55922896d862686fbe64e9ea214f1d15413f1797..d5c1821b31c65054e4d2059282b25c2c463a3074 100644 --- a/drivers/hwtracing/intel_th/core.c +++ b/drivers/hwtracing/intel_th/core.c @@ -789,12 +789,6 @@ static int intel_th_populate(struct intel_th *th) return 0; } -static int match_devt(struct device *dev, const void *data) -{ - dev_t devt = (dev_t)(unsigned long)(void *)data; - return dev->devt == devt; -} - static int intel_th_output_open(struct inode *inode, struct file *file) { const struct file_operations *fops; @@ -802,9 +796,7 @@ static int intel_th_output_open(struct inode *inode, struct file *file) struct device *dev; int err; - dev = bus_find_device(&intel_th_bus, NULL, - (void *)(unsigned long)inode->i_rdev, - match_devt); + dev = bus_find_device_by_devt(&intel_th_bus, inode->i_rdev); if (!dev || !dev->driver) return -ENODEV; diff --git a/drivers/hwtracing/intel_th/msu-sink.c b/drivers/hwtracing/intel_th/msu-sink.c new file mode 100644 index 0000000000000000000000000000000000000000..2c7f5116be126609714bb5f290289447b8b40d76 --- /dev/null +++ b/drivers/hwtracing/intel_th/msu-sink.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * An example software sink buffer for Intel TH MSU. + * + * Copyright (C) 2019 Intel Corporation. + */ + +#include +#include +#include +#include +#include + +#define MAX_SGTS 16 + +struct msu_sink_private { + struct device *dev; + struct sg_table **sgts; + unsigned int nr_sgts; +}; + +static void *msu_sink_assign(struct device *dev, int *mode) +{ + struct msu_sink_private *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return NULL; + + priv->sgts = kcalloc(MAX_SGTS, sizeof(void *), GFP_KERNEL); + if (!priv->sgts) { + kfree(priv); + return NULL; + } + + priv->dev = dev; + *mode = MSC_MODE_MULTI; + + return priv; +} + +static void msu_sink_unassign(void *data) +{ + struct msu_sink_private *priv = data; + + kfree(priv->sgts); + kfree(priv); +} + +/* See also: msc.c: __msc_buffer_win_alloc() */ +static int msu_sink_alloc_window(void *data, struct sg_table **sgt, size_t size) +{ + struct msu_sink_private *priv = data; + unsigned int nents; + struct scatterlist *sg_ptr; + void *block; + int ret, i; + + if (priv->nr_sgts == MAX_SGTS) + return -ENOMEM; + + nents = DIV_ROUND_UP(size, PAGE_SIZE); + + ret = sg_alloc_table(*sgt, nents, GFP_KERNEL); + if (ret) + return -ENOMEM; + + priv->sgts[priv->nr_sgts++] = *sgt; + + for_each_sg((*sgt)->sgl, sg_ptr, nents, i) { + block = dma_alloc_coherent(priv->dev->parent->parent, + PAGE_SIZE, &sg_dma_address(sg_ptr), + GFP_KERNEL); + sg_set_buf(sg_ptr, block, PAGE_SIZE); + } + + return nents; +} + +/* See also: msc.c: __msc_buffer_win_free() */ +static void msu_sink_free_window(void *data, struct sg_table *sgt) +{ + struct msu_sink_private *priv = data; + struct scatterlist *sg_ptr; + int i; + + for_each_sg(sgt->sgl, sg_ptr, sgt->nents, i) { + dma_free_coherent(priv->dev->parent->parent, PAGE_SIZE, + sg_virt(sg_ptr), sg_dma_address(sg_ptr)); + } + + sg_free_table(sgt); + priv->nr_sgts--; +} + +static int msu_sink_ready(void *data, struct sg_table *sgt, size_t bytes) +{ + struct msu_sink_private *priv = data; + + intel_th_msc_window_unlock(priv->dev, sgt); + + return 0; +} + +static const struct msu_buffer sink_mbuf = { + .name = "sink", + .assign = msu_sink_assign, + .unassign = msu_sink_unassign, + .alloc_window = msu_sink_alloc_window, + .free_window = msu_sink_free_window, + .ready = msu_sink_ready, +}; + +module_intel_th_msu_buffer(sink_mbuf); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c index 8ab28e5fb366f62d18168b0d0b8fc305df85cf9c..fc9f15f36ad4e1a460f9a7f6aeb49a2e861d36a3 100644 --- a/drivers/hwtracing/intel_th/msu.c +++ b/drivers/hwtracing/intel_th/msu.c @@ -17,21 +17,48 @@ #include #include #include +#include #include #ifdef CONFIG_X86 #include #endif +#include #include "intel_th.h" #include "msu.h" #define msc_dev(x) (&(x)->thdev->dev) +/* + * Lockout state transitions: + * READY -> INUSE -+-> LOCKED -+-> READY -> etc. + * \-----------/ + * WIN_READY: window can be used by HW + * WIN_INUSE: window is in use + * WIN_LOCKED: window is filled up and is being processed by the buffer + * handling code + * + * All state transitions happen automatically, except for the LOCKED->READY, + * which needs to be signalled by the buffer code by calling + * intel_th_msc_window_unlock(). + * + * When the interrupt handler has to switch to the next window, it checks + * whether it's READY, and if it is, it performs the switch and tracing + * continues. If it's LOCKED, it stops the trace. + */ +enum lockout_state { + WIN_READY = 0, + WIN_INUSE, + WIN_LOCKED +}; + /** * struct msc_window - multiblock mode window descriptor * @entry: window list linkage (msc::win_list) * @pgoff: page offset into the buffer that this window starts at + * @lockout: lockout state, see comment below + * @lo_lock: lockout state serialization * @nr_blocks: number of blocks (pages) in this window * @nr_segs: number of segments in this window (<= @nr_blocks) * @_sgt: array of block descriptors @@ -40,6 +67,8 @@ struct msc_window { struct list_head entry; unsigned long pgoff; + enum lockout_state lockout; + spinlock_t lo_lock; unsigned int nr_blocks; unsigned int nr_segs; struct msc *msc; @@ -66,8 +95,8 @@ struct msc_iter { struct msc_window *start_win; struct msc_window *win; unsigned long offset; - int start_block; - int block; + struct scatterlist *start_block; + struct scatterlist *block; unsigned int block_off; unsigned int wrap_count; unsigned int eof; @@ -77,6 +106,8 @@ struct msc_iter { * struct msc - MSC device representation * @reg_base: register window base address * @thdev: intel_th_device pointer + * @mbuf: MSU buffer, if assigned + * @mbuf_priv MSU buffer's private data, if @mbuf * @win_list: list of windows in multiblock mode * @single_sgt: single mode buffer * @cur_win: current window @@ -100,6 +131,10 @@ struct msc { void __iomem *msu_base; struct intel_th_device *thdev; + const struct msu_buffer *mbuf; + void *mbuf_priv; + + struct work_struct work; struct list_head win_list; struct sg_table single_sgt; struct msc_window *cur_win; @@ -108,6 +143,8 @@ struct msc { unsigned int single_wrap : 1; void *base; dma_addr_t base_addr; + u32 orig_addr; + u32 orig_sz; /* <0: no buffer, 0: no users, >0: active users */ atomic_t user_count; @@ -126,6 +163,101 @@ struct msc { unsigned int index; }; +static LIST_HEAD(msu_buffer_list); +static struct mutex msu_buffer_mutex; + +/** + * struct msu_buffer_entry - internal MSU buffer bookkeeping + * @entry: link to msu_buffer_list + * @mbuf: MSU buffer object + * @owner: module that provides this MSU buffer + */ +struct msu_buffer_entry { + struct list_head entry; + const struct msu_buffer *mbuf; + struct module *owner; +}; + +static struct msu_buffer_entry *__msu_buffer_entry_find(const char *name) +{ + struct msu_buffer_entry *mbe; + + lockdep_assert_held(&msu_buffer_mutex); + + list_for_each_entry(mbe, &msu_buffer_list, entry) { + if (!strcmp(mbe->mbuf->name, name)) + return mbe; + } + + return NULL; +} + +static const struct msu_buffer * +msu_buffer_get(const char *name) +{ + struct msu_buffer_entry *mbe; + + mutex_lock(&msu_buffer_mutex); + mbe = __msu_buffer_entry_find(name); + if (mbe && !try_module_get(mbe->owner)) + mbe = NULL; + mutex_unlock(&msu_buffer_mutex); + + return mbe ? mbe->mbuf : NULL; +} + +static void msu_buffer_put(const struct msu_buffer *mbuf) +{ + struct msu_buffer_entry *mbe; + + mutex_lock(&msu_buffer_mutex); + mbe = __msu_buffer_entry_find(mbuf->name); + if (mbe) + module_put(mbe->owner); + mutex_unlock(&msu_buffer_mutex); +} + +int intel_th_msu_buffer_register(const struct msu_buffer *mbuf, + struct module *owner) +{ + struct msu_buffer_entry *mbe; + int ret = 0; + + mbe = kzalloc(sizeof(*mbe), GFP_KERNEL); + if (!mbe) + return -ENOMEM; + + mutex_lock(&msu_buffer_mutex); + if (__msu_buffer_entry_find(mbuf->name)) { + ret = -EEXIST; + kfree(mbe); + goto unlock; + } + + mbe->mbuf = mbuf; + mbe->owner = owner; + list_add_tail(&mbe->entry, &msu_buffer_list); +unlock: + mutex_unlock(&msu_buffer_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(intel_th_msu_buffer_register); + +void intel_th_msu_buffer_unregister(const struct msu_buffer *mbuf) +{ + struct msu_buffer_entry *mbe; + + mutex_lock(&msu_buffer_mutex); + mbe = __msu_buffer_entry_find(mbuf->name); + if (mbe) { + list_del(&mbe->entry); + kfree(mbe); + } + mutex_unlock(&msu_buffer_mutex); +} +EXPORT_SYMBOL_GPL(intel_th_msu_buffer_unregister); + static inline bool msc_block_is_empty(struct msc_block_desc *bdesc) { /* header hasn't been written */ @@ -139,28 +271,25 @@ static inline bool msc_block_is_empty(struct msc_block_desc *bdesc) return false; } -static inline struct msc_block_desc * -msc_win_block(struct msc_window *win, unsigned int block) +static inline struct scatterlist *msc_win_base_sg(struct msc_window *win) { - return sg_virt(&win->sgt->sgl[block]); + return win->sgt->sgl; } -static inline size_t -msc_win_actual_bsz(struct msc_window *win, unsigned int block) +static inline struct msc_block_desc *msc_win_base(struct msc_window *win) { - return win->sgt->sgl[block].length; + return sg_virt(msc_win_base_sg(win)); } -static inline dma_addr_t -msc_win_baddr(struct msc_window *win, unsigned int block) +static inline dma_addr_t msc_win_base_dma(struct msc_window *win) { - return sg_dma_address(&win->sgt->sgl[block]); + return sg_dma_address(msc_win_base_sg(win)); } static inline unsigned long -msc_win_bpfn(struct msc_window *win, unsigned int block) +msc_win_base_pfn(struct msc_window *win) { - return msc_win_baddr(win, block) >> PAGE_SHIFT; + return PFN_DOWN(msc_win_base_dma(win)); } /** @@ -188,6 +317,26 @@ static struct msc_window *msc_next_window(struct msc_window *win) return list_next_entry(win, entry); } +static size_t msc_win_total_sz(struct msc_window *win) +{ + struct scatterlist *sg; + unsigned int blk; + size_t size = 0; + + for_each_sg(win->sgt->sgl, sg, win->nr_segs, blk) { + struct msc_block_desc *bdesc = sg_virt(sg); + + if (msc_block_wrapped(bdesc)) + return win->nr_blocks << PAGE_SHIFT; + + size += msc_total_sz(bdesc); + if (msc_block_last_written(bdesc)) + break; + } + + return size; +} + /** * msc_find_window() - find a window matching a given sg_table * @msc: MSC device @@ -216,7 +365,7 @@ msc_find_window(struct msc *msc, struct sg_table *sgt, bool nonempty) found++; /* skip the empty ones */ - if (nonempty && msc_block_is_empty(msc_win_block(win, 0))) + if (nonempty && msc_block_is_empty(msc_win_base(win))) continue; if (found) @@ -250,44 +399,38 @@ static struct msc_window *msc_oldest_window(struct msc *msc) } /** - * msc_win_oldest_block() - locate the oldest block in a given window + * msc_win_oldest_sg() - locate the oldest block in a given window * @win: window to look at * * Return: index of the block with the oldest data */ -static unsigned int msc_win_oldest_block(struct msc_window *win) +static struct scatterlist *msc_win_oldest_sg(struct msc_window *win) { unsigned int blk; - struct msc_block_desc *bdesc = msc_win_block(win, 0); + struct scatterlist *sg; + struct msc_block_desc *bdesc = msc_win_base(win); /* without wrapping, first block is the oldest */ if (!msc_block_wrapped(bdesc)) - return 0; + return msc_win_base_sg(win); /* * with wrapping, last written block contains both the newest and the * oldest data for this window. */ - for (blk = 0; blk < win->nr_segs; blk++) { - bdesc = msc_win_block(win, blk); + for_each_sg(win->sgt->sgl, sg, win->nr_segs, blk) { + struct msc_block_desc *bdesc = sg_virt(sg); if (msc_block_last_written(bdesc)) - return blk; + return sg; } - return 0; + return msc_win_base_sg(win); } static struct msc_block_desc *msc_iter_bdesc(struct msc_iter *iter) { - return msc_win_block(iter->win, iter->block); -} - -static void msc_iter_init(struct msc_iter *iter) -{ - memset(iter, 0, sizeof(*iter)); - iter->start_block = -1; - iter->block = -1; + return sg_virt(iter->block); } static struct msc_iter *msc_iter_install(struct msc *msc) @@ -312,7 +455,6 @@ static struct msc_iter *msc_iter_install(struct msc *msc) goto unlock; } - msc_iter_init(iter); iter->msc = msc; list_add_tail(&iter->entry, &msc->iter_list); @@ -333,10 +475,10 @@ static void msc_iter_remove(struct msc_iter *iter, struct msc *msc) static void msc_iter_block_start(struct msc_iter *iter) { - if (iter->start_block != -1) + if (iter->start_block) return; - iter->start_block = msc_win_oldest_block(iter->win); + iter->start_block = msc_win_oldest_sg(iter->win); iter->block = iter->start_block; iter->wrap_count = 0; @@ -360,7 +502,7 @@ static int msc_iter_win_start(struct msc_iter *iter, struct msc *msc) return -EINVAL; iter->win = iter->start_win; - iter->start_block = -1; + iter->start_block = NULL; msc_iter_block_start(iter); @@ -370,7 +512,7 @@ static int msc_iter_win_start(struct msc_iter *iter, struct msc *msc) static int msc_iter_win_advance(struct msc_iter *iter) { iter->win = msc_next_window(iter->win); - iter->start_block = -1; + iter->start_block = NULL; if (iter->win == iter->start_win) { iter->eof++; @@ -400,8 +542,10 @@ static int msc_iter_block_advance(struct msc_iter *iter) return msc_iter_win_advance(iter); /* block advance */ - if (++iter->block == iter->win->nr_segs) - iter->block = 0; + if (sg_is_last(iter->block)) + iter->block = msc_win_base_sg(iter->win); + else + iter->block = sg_next(iter->block); /* no wrapping, sanity check in case there is no last written block */ if (!iter->wrap_count && iter->block == iter->start_block) @@ -506,14 +650,15 @@ msc_buffer_iterate(struct msc_iter *iter, size_t size, void *data, static void msc_buffer_clear_hw_header(struct msc *msc) { struct msc_window *win; + struct scatterlist *sg; list_for_each_entry(win, &msc->win_list, entry) { unsigned int blk; size_t hw_sz = sizeof(struct msc_block_desc) - offsetof(struct msc_block_desc, hw_tag); - for (blk = 0; blk < win->nr_segs; blk++) { - struct msc_block_desc *bdesc = msc_win_block(win, blk); + for_each_sg(win->sgt->sgl, sg, win->nr_segs, blk) { + struct msc_block_desc *bdesc = sg_virt(sg); memset(&bdesc->hw_tag, 0, hw_sz); } @@ -527,6 +672,9 @@ static int intel_th_msu_init(struct msc *msc) if (!msc->do_irq) return 0; + if (!msc->mbuf) + return 0; + mintctl = ioread32(msc->msu_base + REG_MSU_MINTCTL); mintctl |= msc->index ? M1BLIE : M0BLIE; iowrite32(mintctl, msc->msu_base + REG_MSU_MINTCTL); @@ -554,6 +702,49 @@ static void intel_th_msu_deinit(struct msc *msc) iowrite32(mintctl, msc->msu_base + REG_MSU_MINTCTL); } +static int msc_win_set_lockout(struct msc_window *win, + enum lockout_state expect, + enum lockout_state new) +{ + enum lockout_state old; + unsigned long flags; + int ret = 0; + + if (!win->msc->mbuf) + return 0; + + spin_lock_irqsave(&win->lo_lock, flags); + old = win->lockout; + + if (old != expect) { + ret = -EINVAL; + dev_warn_ratelimited(msc_dev(win->msc), + "expected lockout state %d, got %d\n", + expect, old); + goto unlock; + } + + win->lockout = new; + + if (old == expect && new == WIN_LOCKED) + atomic_inc(&win->msc->user_count); + else if (old == expect && old == WIN_LOCKED) + atomic_dec(&win->msc->user_count); + +unlock: + spin_unlock_irqrestore(&win->lo_lock, flags); + + if (ret) { + if (expect == WIN_READY && old == WIN_LOCKED) + return -EBUSY; + + /* from intel_th_msc_window_unlock(), don't warn if not locked */ + if (expect == WIN_LOCKED && old == new) + return 0; + } + + return ret; +} /** * msc_configure() - set up MSC hardware * @msc: the MSC device to configure @@ -571,8 +762,15 @@ static int msc_configure(struct msc *msc) if (msc->mode > MSC_MODE_MULTI) return -ENOTSUPP; - if (msc->mode == MSC_MODE_MULTI) + if (msc->mode == MSC_MODE_MULTI) { + if (msc_win_set_lockout(msc->cur_win, WIN_READY, WIN_INUSE)) + return -EBUSY; + msc_buffer_clear_hw_header(msc); + } + + msc->orig_addr = ioread32(msc->reg_base + REG_MSU_MSC0BAR); + msc->orig_sz = ioread32(msc->reg_base + REG_MSU_MSC0SIZE); reg = msc->base_addr >> PAGE_SHIFT; iowrite32(reg, msc->reg_base + REG_MSU_MSC0BAR); @@ -594,10 +792,14 @@ static int msc_configure(struct msc *msc) iowrite32(reg, msc->reg_base + REG_MSU_MSC0CTL); + intel_th_msu_init(msc); + msc->thdev->output.multiblock = msc->mode == MSC_MODE_MULTI; intel_th_trace_enable(msc->thdev); msc->enabled = 1; + if (msc->mbuf && msc->mbuf->activate) + msc->mbuf->activate(msc->mbuf_priv); return 0; } @@ -611,10 +813,17 @@ static int msc_configure(struct msc *msc) */ static void msc_disable(struct msc *msc) { + struct msc_window *win = msc->cur_win; u32 reg; lockdep_assert_held(&msc->buf_mutex); + if (msc->mode == MSC_MODE_MULTI) + msc_win_set_lockout(win, WIN_INUSE, WIN_LOCKED); + + if (msc->mbuf && msc->mbuf->deactivate) + msc->mbuf->deactivate(msc->mbuf_priv); + intel_th_msu_deinit(msc); intel_th_trace_disable(msc->thdev); if (msc->mode == MSC_MODE_SINGLE) { @@ -630,16 +839,25 @@ static void msc_disable(struct msc *msc) reg = ioread32(msc->reg_base + REG_MSU_MSC0CTL); reg &= ~MSC_EN; iowrite32(reg, msc->reg_base + REG_MSU_MSC0CTL); + + if (msc->mbuf && msc->mbuf->ready) + msc->mbuf->ready(msc->mbuf_priv, win->sgt, + msc_win_total_sz(win)); + msc->enabled = 0; - iowrite32(0, msc->reg_base + REG_MSU_MSC0BAR); - iowrite32(0, msc->reg_base + REG_MSU_MSC0SIZE); + iowrite32(msc->orig_addr, msc->reg_base + REG_MSU_MSC0BAR); + iowrite32(msc->orig_sz, msc->reg_base + REG_MSU_MSC0SIZE); dev_dbg(msc_dev(msc), "MSCnNWSA: %08x\n", ioread32(msc->reg_base + REG_MSU_MSC0NWSA)); reg = ioread32(msc->reg_base + REG_MSU_MSC0STS); dev_dbg(msc_dev(msc), "MSCnSTS: %08x\n", reg); + + reg = ioread32(msc->reg_base + REG_MSU_MSUSTS); + reg &= msc->index ? MSUSTS_MSC1BLAST : MSUSTS_MSC0BLAST; + iowrite32(reg, msc->reg_base + REG_MSU_MSUSTS); } static int intel_th_msc_activate(struct intel_th_device *thdev) @@ -791,10 +1009,9 @@ static int __msc_buffer_win_alloc(struct msc_window *win, return nr_segs; err_nomem: - for (i--; i >= 0; i--) + for_each_sg(win->sgt->sgl, sg_ptr, i, ret) dma_free_coherent(msc_dev(win->msc)->parent->parent, PAGE_SIZE, - msc_win_block(win, i), - msc_win_baddr(win, i)); + sg_virt(sg_ptr), sg_dma_address(sg_ptr)); sg_free_table(win->sgt); @@ -804,20 +1021,26 @@ static int __msc_buffer_win_alloc(struct msc_window *win, #ifdef CONFIG_X86 static void msc_buffer_set_uc(struct msc_window *win, unsigned int nr_segs) { + struct scatterlist *sg_ptr; int i; - for (i = 0; i < nr_segs; i++) + for_each_sg(win->sgt->sgl, sg_ptr, nr_segs, i) { /* Set the page as uncached */ - set_memory_uc((unsigned long)msc_win_block(win, i), 1); + set_memory_uc((unsigned long)sg_virt(sg_ptr), + PFN_DOWN(sg_ptr->length)); + } } static void msc_buffer_set_wb(struct msc_window *win) { + struct scatterlist *sg_ptr; int i; - for (i = 0; i < win->nr_segs; i++) + for_each_sg(win->sgt->sgl, sg_ptr, win->nr_segs, i) { /* Reset the page to write-back */ - set_memory_wb((unsigned long)msc_win_block(win, i), 1); + set_memory_wb((unsigned long)sg_virt(sg_ptr), + PFN_DOWN(sg_ptr->length)); + } } #else /* !X86 */ static inline void @@ -843,19 +1066,14 @@ static int msc_buffer_win_alloc(struct msc *msc, unsigned int nr_blocks) if (!nr_blocks) return 0; - /* - * This limitation hold as long as we need random access to the - * block. When that changes, this can go away. - */ - if (nr_blocks > SG_MAX_SINGLE_ALLOC) - return -EINVAL; - win = kzalloc(sizeof(*win), GFP_KERNEL); if (!win) return -ENOMEM; win->msc = msc; win->sgt = &win->_sgt; + win->lockout = WIN_READY; + spin_lock_init(&win->lo_lock); if (!list_empty(&msc->win_list)) { struct msc_window *prev = list_last_entry(&msc->win_list, @@ -865,8 +1083,13 @@ static int msc_buffer_win_alloc(struct msc *msc, unsigned int nr_blocks) win->pgoff = prev->pgoff + prev->nr_blocks; } - ret = __msc_buffer_win_alloc(win, nr_blocks); - if (ret < 0) + if (msc->mbuf && msc->mbuf->alloc_window) + ret = msc->mbuf->alloc_window(msc->mbuf_priv, &win->sgt, + nr_blocks << PAGE_SHIFT); + else + ret = __msc_buffer_win_alloc(win, nr_blocks); + + if (ret <= 0) goto err_nomem; msc_buffer_set_uc(win, ret); @@ -875,8 +1098,8 @@ static int msc_buffer_win_alloc(struct msc *msc, unsigned int nr_blocks) win->nr_blocks = nr_blocks; if (list_empty(&msc->win_list)) { - msc->base = msc_win_block(win, 0); - msc->base_addr = msc_win_baddr(win, 0); + msc->base = msc_win_base(win); + msc->base_addr = msc_win_base_dma(win); msc->cur_win = win; } @@ -893,14 +1116,15 @@ static int msc_buffer_win_alloc(struct msc *msc, unsigned int nr_blocks) static void __msc_buffer_win_free(struct msc *msc, struct msc_window *win) { + struct scatterlist *sg; int i; - for (i = 0; i < win->nr_segs; i++) { - struct page *page = sg_page(&win->sgt->sgl[i]); + for_each_sg(win->sgt->sgl, sg, win->nr_segs, i) { + struct page *page = sg_page(sg); page->mapping = NULL; dma_free_coherent(msc_dev(win->msc)->parent->parent, PAGE_SIZE, - msc_win_block(win, i), msc_win_baddr(win, i)); + sg_virt(sg), sg_dma_address(sg)); } sg_free_table(win->sgt); } @@ -925,7 +1149,10 @@ static void msc_buffer_win_free(struct msc *msc, struct msc_window *win) msc_buffer_set_wb(win); - __msc_buffer_win_free(msc, win); + if (msc->mbuf && msc->mbuf->free_window) + msc->mbuf->free_window(msc->mbuf_priv, win->sgt); + else + __msc_buffer_win_free(msc, win); kfree(win); } @@ -943,6 +1170,7 @@ static void msc_buffer_relink(struct msc *msc) /* call with msc::mutex locked */ list_for_each_entry(win, &msc->win_list, entry) { + struct scatterlist *sg; unsigned int blk; u32 sw_tag = 0; @@ -958,12 +1186,12 @@ static void msc_buffer_relink(struct msc *msc) next_win = list_next_entry(win, entry); } - for (blk = 0; blk < win->nr_segs; blk++) { - struct msc_block_desc *bdesc = msc_win_block(win, blk); + for_each_sg(win->sgt->sgl, sg, win->nr_segs, blk) { + struct msc_block_desc *bdesc = sg_virt(sg); memset(bdesc, 0, sizeof(*bdesc)); - bdesc->next_win = msc_win_bpfn(next_win, 0); + bdesc->next_win = msc_win_base_pfn(next_win); /* * Similarly to last window, last block should point @@ -971,13 +1199,15 @@ static void msc_buffer_relink(struct msc *msc) */ if (blk == win->nr_segs - 1) { sw_tag |= MSC_SW_TAG_LASTBLK; - bdesc->next_blk = msc_win_bpfn(win, 0); + bdesc->next_blk = msc_win_base_pfn(win); } else { - bdesc->next_blk = msc_win_bpfn(win, blk + 1); + dma_addr_t addr = sg_dma_address(sg_next(sg)); + + bdesc->next_blk = PFN_DOWN(addr); } bdesc->sw_tag = sw_tag; - bdesc->block_sz = msc_win_actual_bsz(win, blk) / 64; + bdesc->block_sz = sg->length / 64; } } @@ -1136,6 +1366,7 @@ static int msc_buffer_free_unless_used(struct msc *msc) static struct page *msc_buffer_get_page(struct msc *msc, unsigned long pgoff) { struct msc_window *win; + struct scatterlist *sg; unsigned int blk; if (msc->mode == MSC_MODE_SINGLE) @@ -1150,9 +1381,9 @@ static struct page *msc_buffer_get_page(struct msc *msc, unsigned long pgoff) found: pgoff -= win->pgoff; - for (blk = 0; blk < win->nr_segs; blk++) { - struct page *page = sg_page(&win->sgt->sgl[blk]); - size_t pgsz = PFN_DOWN(msc_win_actual_bsz(win, blk)); + for_each_sg(win->sgt->sgl, sg, win->nr_segs, blk) { + struct page *page = sg_page(sg); + size_t pgsz = PFN_DOWN(sg->length); if (pgoff < pgsz) return page + pgoff; @@ -1456,24 +1687,83 @@ static void msc_win_switch(struct msc *msc) else msc->cur_win = list_next_entry(msc->cur_win, entry); - msc->base = msc_win_block(msc->cur_win, 0); - msc->base_addr = msc_win_baddr(msc->cur_win, 0); + msc->base = msc_win_base(msc->cur_win); + msc->base_addr = msc_win_base_dma(msc->cur_win); intel_th_trace_switch(msc->thdev); } +/** + * intel_th_msc_window_unlock - put the window back in rotation + * @dev: MSC device to which this relates + * @sgt: buffer's sg_table for the window, does nothing if NULL + */ +void intel_th_msc_window_unlock(struct device *dev, struct sg_table *sgt) +{ + struct msc *msc = dev_get_drvdata(dev); + struct msc_window *win; + + if (!sgt) + return; + + win = msc_find_window(msc, sgt, false); + if (!win) + return; + + msc_win_set_lockout(win, WIN_LOCKED, WIN_READY); +} +EXPORT_SYMBOL_GPL(intel_th_msc_window_unlock); + +static void msc_work(struct work_struct *work) +{ + struct msc *msc = container_of(work, struct msc, work); + + intel_th_msc_deactivate(msc->thdev); +} + static irqreturn_t intel_th_msc_interrupt(struct intel_th_device *thdev) { struct msc *msc = dev_get_drvdata(&thdev->dev); u32 msusts = ioread32(msc->msu_base + REG_MSU_MSUSTS); u32 mask = msc->index ? MSUSTS_MSC1BLAST : MSUSTS_MSC0BLAST; + struct msc_window *win, *next_win; + + if (!msc->do_irq || !msc->mbuf) + return IRQ_NONE; + + msusts &= mask; + + if (!msusts) + return msc->enabled ? IRQ_HANDLED : IRQ_NONE; + + iowrite32(msusts, msc->msu_base + REG_MSU_MSUSTS); - if (!(msusts & mask)) { - if (msc->enabled) - return IRQ_HANDLED; + if (!msc->enabled) return IRQ_NONE; + + /* grab the window before we do the switch */ + win = msc->cur_win; + if (!win) + return IRQ_HANDLED; + next_win = msc_next_window(win); + if (!next_win) + return IRQ_HANDLED; + + /* next window: if READY, proceed, if LOCKED, stop the trace */ + if (msc_win_set_lockout(next_win, WIN_READY, WIN_INUSE)) { + schedule_work(&msc->work); + return IRQ_HANDLED; } + /* current window: INUSE -> LOCKED */ + msc_win_set_lockout(win, WIN_INUSE, WIN_LOCKED); + + msc_win_switch(msc); + + if (msc->mbuf && msc->mbuf->ready) + msc->mbuf->ready(msc->mbuf_priv, win->sgt, + msc_win_total_sz(win)); + return IRQ_HANDLED; } @@ -1511,21 +1801,43 @@ wrap_store(struct device *dev, struct device_attribute *attr, const char *buf, static DEVICE_ATTR_RW(wrap); +static void msc_buffer_unassign(struct msc *msc) +{ + lockdep_assert_held(&msc->buf_mutex); + + if (!msc->mbuf) + return; + + msc->mbuf->unassign(msc->mbuf_priv); + msu_buffer_put(msc->mbuf); + msc->mbuf_priv = NULL; + msc->mbuf = NULL; +} + static ssize_t mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct msc *msc = dev_get_drvdata(dev); + const char *mode = msc_mode[msc->mode]; + ssize_t ret; + + mutex_lock(&msc->buf_mutex); + if (msc->mbuf) + mode = msc->mbuf->name; + ret = scnprintf(buf, PAGE_SIZE, "%s\n", mode); + mutex_unlock(&msc->buf_mutex); - return scnprintf(buf, PAGE_SIZE, "%s\n", msc_mode[msc->mode]); + return ret; } static ssize_t mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { + const struct msu_buffer *mbuf = NULL; struct msc *msc = dev_get_drvdata(dev); size_t len = size; - char *cp; + char *cp, *mode; int i, ret; if (!capable(CAP_SYS_RAWIO)) @@ -1535,17 +1847,59 @@ mode_store(struct device *dev, struct device_attribute *attr, const char *buf, if (cp) len = cp - buf; - for (i = 0; i < ARRAY_SIZE(msc_mode); i++) - if (!strncmp(msc_mode[i], buf, len)) - goto found; + mode = kstrndup(buf, len, GFP_KERNEL); + i = match_string(msc_mode, ARRAY_SIZE(msc_mode), mode); + if (i >= 0) + goto found; + + /* Buffer sinks only work with a usable IRQ */ + if (!msc->do_irq) { + kfree(mode); + return -EINVAL; + } + + mbuf = msu_buffer_get(mode); + kfree(mode); + if (mbuf) + goto found; return -EINVAL; found: mutex_lock(&msc->buf_mutex); + ret = 0; + + /* Same buffer: do nothing */ + if (mbuf && mbuf == msc->mbuf) { + /* put the extra reference we just got */ + msu_buffer_put(mbuf); + goto unlock; + } + ret = msc_buffer_unlocked_free_unless_used(msc); - if (!ret) - msc->mode = i; + if (ret) + goto unlock; + + if (mbuf) { + void *mbuf_priv = mbuf->assign(dev, &i); + + if (!mbuf_priv) { + ret = -ENOMEM; + goto unlock; + } + + msc_buffer_unassign(msc); + msc->mbuf_priv = mbuf_priv; + msc->mbuf = mbuf; + } else { + msc_buffer_unassign(msc); + } + + msc->mode = i; + +unlock: + if (ret && mbuf) + msu_buffer_put(mbuf); mutex_unlock(&msc->buf_mutex); return ret ? ret : size; @@ -1667,7 +2021,12 @@ win_switch_store(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&msc->buf_mutex); - if (msc->mode != MSC_MODE_MULTI) + /* + * Window switch can only happen in the "multi" mode. + * If a external buffer is engaged, they have the full + * control over window switching. + */ + if (msc->mode != MSC_MODE_MULTI || msc->mbuf) ret = -ENOTSUPP; else msc_win_switch(msc); @@ -1720,10 +2079,7 @@ static int intel_th_msc_probe(struct intel_th_device *thdev) msc->reg_base = base + msc->index * 0x100; msc->msu_base = base; - err = intel_th_msu_init(msc); - if (err) - return err; - + INIT_WORK(&msc->work, msc_work); err = intel_th_msc_init(msc); if (err) return err; @@ -1739,7 +2095,6 @@ static void intel_th_msc_remove(struct intel_th_device *thdev) int ret; intel_th_msc_deactivate(thdev); - intel_th_msu_deinit(msc); /* * Buffers should not be used at this point except if the diff --git a/drivers/hwtracing/intel_th/msu.h b/drivers/hwtracing/intel_th/msu.h index 13d9b141daaaaf3da7e4b8195e2ec6c41929fb42..e771f509bd023c03bac6ccd7faeada8ec093808a 100644 --- a/drivers/hwtracing/intel_th/msu.h +++ b/drivers/hwtracing/intel_th/msu.h @@ -44,14 +44,6 @@ enum { #define M0BLIE BIT(16) #define M1BLIE BIT(24) -/* MSC operating modes (MSC_MODE) */ -enum { - MSC_MODE_SINGLE = 0, - MSC_MODE_MULTI, - MSC_MODE_EXI, - MSC_MODE_DEBUG, -}; - /* MSCnSTS bits */ #define MSCSTS_WRAPSTAT BIT(1) /* Wrap occurred */ #define MSCSTS_PLE BIT(2) /* Pipeline Empty */ @@ -93,6 +85,16 @@ static inline unsigned long msc_data_sz(struct msc_block_desc *bdesc) return bdesc->valid_dw * 4 - MSC_BDESC; } +static inline unsigned long msc_total_sz(struct msc_block_desc *bdesc) +{ + return bdesc->valid_dw * 4; +} + +static inline unsigned long msc_block_sz(struct msc_block_desc *bdesc) +{ + return bdesc->block_sz * 64 - MSC_BDESC; +} + static inline bool msc_block_wrapped(struct msc_block_desc *bdesc) { if (bdesc->hw_tag & (MSC_HW_TAG_BLOCKWRAP | MSC_HW_TAG_WINWRAP)) @@ -104,7 +106,7 @@ static inline bool msc_block_wrapped(struct msc_block_desc *bdesc) static inline bool msc_block_last_written(struct msc_block_desc *bdesc) { if ((bdesc->hw_tag & MSC_HW_TAG_ENDBIT) || - (msc_data_sz(bdesc) != DATA_IN_PAGE)) + (msc_data_sz(bdesc) != msc_block_sz(bdesc))) return true; return false; diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index 181e7ff1ec4fc374e31968e3a89c0fc9592a6d73..603b83ac50852a81b99f5f28fc9a26df8c2a5cb8 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c @@ -89,13 +89,6 @@ static struct class stm_class = { .dev_groups = stm_groups, }; -static int stm_dev_match(struct device *dev, const void *data) -{ - const char *name = data; - - return sysfs_streq(name, dev_name(dev)); -} - /** * stm_find_device() - find stm device by name * @buf: character buffer containing the name @@ -116,7 +109,7 @@ struct stm_device *stm_find_device(const char *buf) if (!stm_core_up) return NULL; - dev = class_find_device(&stm_class, NULL, buf, stm_dev_match); + dev = class_find_device_by_name(&stm_class, buf); if (!dev) return NULL; diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index abedd55a12647bdf7051237fb1b0641dc7b38d4a..1474e57ecafc470258e1b3f4c516b05d12950213 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -54,7 +54,7 @@ config I2C_CHARDEV Say Y here to use i2c-* device files, usually found in the /dev directory on your system. They make it possible to have user-space programs use the I2C bus. Information on how to do this is - contained in the file . + contained in the file . This support is also available as a module. If so, the module will be called i2c-dev. @@ -107,7 +107,7 @@ config I2C_STUB especially for certain kinds of sensor chips. If you do build this module, be sure to read the notes and warnings - in . + in . If you don't know what to do here, definitely say N. diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 09367fc014c3f867b9f40c5c3457b07b411bb7b7..a362245cc55845029096baad47646d30b8d7d12b 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -684,7 +684,7 @@ config I2C_IMX_LPI2C config I2C_IOP3XX tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface" - depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX + depends on ARCH_IOP32X || ARCH_IXP4XX help Say Y here if you want to use the IIC bus controller on the Intel IOPx3xx I/O Processors or IXP4xx Network Processors. @@ -1206,7 +1206,7 @@ config I2C_PARPORT and makes it easier to add support for new devices. An adapter type parameter is now mandatory. Please read the file - Documentation/i2c/busses/i2c-parport for details. + Documentation/i2c/busses/i2c-parport.rst for details. Another driver exists, named i2c-parport-light, which doesn't depend on the parport driver. This is meant for embedded systems. Don't say diff --git a/drivers/i2c/busses/i2c-amd-mp2-pci.c b/drivers/i2c/busses/i2c-amd-mp2-pci.c index c7fe3b44a860174a936665fbf0e1dfc628f4466a..5e4800d72e00bc5a4c7a5b98294d22f99a093168 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-pci.c +++ b/drivers/i2c/busses/i2c-amd-mp2-pci.c @@ -457,18 +457,12 @@ static struct pci_driver amd_mp2_pci_driver = { }; module_pci_driver(amd_mp2_pci_driver); -static int amd_mp2_device_match(struct device *dev, const void *data) -{ - return 1; -} - struct amd_mp2_dev *amd_mp2_find_device(void) { struct device *dev; struct pci_dev *pci_dev; - dev = driver_find_device(&amd_mp2_pci_driver.driver, NULL, NULL, - amd_mp2_device_match); + dev = driver_find_next_device(&amd_mp2_pci_driver.driver, NULL); if (!dev) return NULL; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 2e08b4722dc41bd2821a9bce4c2871d89de94755..36e9559f880c3384afd27ca003b06c2e4a56005f 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -77,7 +77,7 @@ * SMBus Host Notify yes * Interrupt processing yes * - * See the file Documentation/i2c/busses/i2c-i801 for details. + * See the file Documentation/i2c/busses/i2c-i801.rst for details. */ #include diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c index c82e78f57386e0d6b219d8a5eddff88396aea5a6..37347c93e8e04dd9c91453c91d39e7a2b6a1e7fe 100644 --- a/drivers/i2c/busses/i2c-taos-evm.c +++ b/drivers/i2c/busses/i2c-taos-evm.c @@ -125,7 +125,7 @@ static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr, /* * Voluntarily dropping error code of kstrtou8 since all * error code that it could return are invalid according - * to Documentation/i2c/fault-codes. + * to Documentation/i2c/fault-codes.rst. */ if (kstrtou8(p + 1, 16, &data->byte)) return -EPROTO; diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index 4dbbc9a35f6561fb918dbd663b5bd2e4cd64eee2..9cb2aa1e20ef31a2707a5e82678cf15264b2a572 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -354,17 +354,13 @@ static int i2c_acpi_find_match_adapter(struct device *dev, const void *data) return ACPI_HANDLE(dev) == (acpi_handle)data; } -static int i2c_acpi_find_match_device(struct device *dev, const void *data) -{ - return ACPI_COMPANION(dev) == data; -} - struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle) { struct device *dev; dev = bus_find_device(&i2c_bus_type, NULL, handle, i2c_acpi_find_match_adapter); + return dev ? i2c_verify_adapter(dev) : NULL; } EXPORT_SYMBOL_GPL(i2c_acpi_find_adapter_by_handle); @@ -373,8 +369,7 @@ static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev) { struct device *dev; - dev = bus_find_device(&i2c_bus_type, NULL, adev, - i2c_acpi_find_match_device); + dev = bus_find_device_by_acpi_dev(&i2c_bus_type, adev); return dev ? i2c_verify_client(dev) : NULL; } diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 9c440fa6a3dd109349a86365a678e46ffe8b89f7..72b300174cb8b2b7636900f2b3148f0390d8c106 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -2206,7 +2206,7 @@ static int i2c_detect_address(struct i2c_client *temp_client, dev_warn(&adapter->dev, "This adapter will soon drop class based instantiation of devices. " "Please make sure client 0x%02x gets instantiated by other means. " - "Check 'Documentation/i2c/instantiating-devices' for details.\n", + "Check 'Documentation/i2c/instantiating-devices.rst' for details.\n", info.addr); dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n", @@ -2236,7 +2236,7 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) if (adapter->class == I2C_CLASS_DEPRECATED) { dev_dbg(&adapter->dev, "This adapter dropped support for I2C classes and won't auto-detect %s devices anymore. " - "If you need it, check 'Documentation/i2c/instantiating-devices' for alternatives.\n", + "If you need it, check 'Documentation/i2c/instantiating-devices.rst' for alternatives.\n", driver->driver.name); return 0; } diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index d1c48dec7118e798d15db3ed653e5c2c83e828e5..6f632d543fcc1f569184fce28f737c4d8436206a 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -113,11 +113,6 @@ void of_i2c_register_devices(struct i2c_adapter *adap) of_node_put(bus); } -static int of_dev_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - static int of_dev_or_parent_node_match(struct device *dev, const void *data) { if (dev->of_node == data) @@ -135,7 +130,7 @@ struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) struct device *dev; struct i2c_client *client; - dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match); + dev = bus_find_device_by_of_node(&i2c_bus_type, node); if (!dev) return NULL; diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c index 69cc040c3a1c9fd9e7aec39486cc4edb0b0c98da..9e2e1406f85ece3c85768ed1ec5f1493120389ff 100644 --- a/drivers/i3c/device.c +++ b/drivers/i3c/device.c @@ -200,6 +200,59 @@ struct i3c_device *dev_to_i3cdev(struct device *dev) } EXPORT_SYMBOL_GPL(dev_to_i3cdev); +/** + * i3c_device_match_id() - Returns the i3c_device_id entry matching @i3cdev + * @i3cdev: I3C device + * @id_table: I3C device match table + * + * Return: a pointer to an i3c_device_id object or NULL if there's no match. + */ +const struct i3c_device_id * +i3c_device_match_id(struct i3c_device *i3cdev, + const struct i3c_device_id *id_table) +{ + struct i3c_device_info devinfo; + const struct i3c_device_id *id; + + i3c_device_get_info(i3cdev, &devinfo); + + /* + * The lower 32bits of the provisional ID is just filled with a random + * value, try to match using DCR info. + */ + if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) { + u16 manuf = I3C_PID_MANUF_ID(devinfo.pid); + u16 part = I3C_PID_PART_ID(devinfo.pid); + u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); + + /* First try to match by manufacturer/part ID. */ + for (id = id_table; id->match_flags != 0; id++) { + if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) != + I3C_MATCH_MANUF_AND_PART) + continue; + + if (manuf != id->manuf_id || part != id->part_id) + continue; + + if ((id->match_flags & I3C_MATCH_EXTRA_INFO) && + ext_info != id->extra_info) + continue; + + return id; + } + } + + /* Fallback to DCR match. */ + for (id = id_table; id->match_flags != 0; id++) { + if ((id->match_flags & I3C_MATCH_DCR) && + id->dcr == devinfo.dcr) + return id; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(i3c_device_match_id); + /** * i3c_driver_register_with_owner() - register an I3C device driver * diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index d6f8b038a89678fcd40bce106e020c902aa4cbd3..5c051dba32a51fa8a00b3e7304cbc7bc9cad2aee 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -123,7 +123,7 @@ static struct i3c_dev_desc *dev_to_i3cdesc(struct device *dev) if (dev->type == &i3c_device_type) return dev_to_i3cdev(dev)->desc; - master = container_of(dev, struct i3c_master_controller, dev); + master = dev_to_i3cmaster(dev); return master->this; } @@ -276,51 +276,6 @@ static const struct device_type i3c_device_type = { .uevent = i3c_device_uevent, }; -static const struct i3c_device_id * -i3c_device_match_id(struct i3c_device *i3cdev, - const struct i3c_device_id *id_table) -{ - struct i3c_device_info devinfo; - const struct i3c_device_id *id; - - i3c_device_get_info(i3cdev, &devinfo); - - /* - * The lower 32bits of the provisional ID is just filled with a random - * value, try to match using DCR info. - */ - if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) { - u16 manuf = I3C_PID_MANUF_ID(devinfo.pid); - u16 part = I3C_PID_PART_ID(devinfo.pid); - u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); - - /* First try to match by manufacturer/part ID. */ - for (id = id_table; id->match_flags != 0; id++) { - if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) != - I3C_MATCH_MANUF_AND_PART) - continue; - - if (manuf != id->manuf_id || part != id->part_id) - continue; - - if ((id->match_flags & I3C_MATCH_EXTRA_INFO) && - ext_info != id->extra_info) - continue; - - return id; - } - } - - /* Fallback to DCR match. */ - for (id = id_table; id->match_flags != 0; id++) { - if ((id->match_flags & I3C_MATCH_DCR) && - id->dcr == devinfo.dcr) - return id; - } - - return NULL; -} - static int i3c_device_match(struct device *dev, struct device_driver *drv) { struct i3c_device *i3cdev; @@ -645,6 +600,8 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master, dev->common.master = master; dev->boardinfo = boardinfo; + dev->addr = boardinfo->base.addr; + dev->lvr = boardinfo->lvr; return dev; } @@ -963,8 +920,8 @@ int i3c_master_defslvs_locked(struct i3c_master_controller *master) desc = defslvs->slaves; i3c_bus_for_each_i2cdev(bus, i2cdev) { - desc->lvr = i2cdev->boardinfo->lvr; - desc->static_addr = i2cdev->boardinfo->base.addr << 1; + desc->lvr = i2cdev->lvr; + desc->static_addr = i2cdev->addr << 1; desc++; } @@ -1084,8 +1041,10 @@ static int i3c_master_getmwl_locked(struct i3c_master_controller *master, if (ret) goto out; - if (dest.payload.len != sizeof(*mwl)) - return -EIO; + if (dest.payload.len != sizeof(*mwl)) { + ret = -EIO; + goto out; + } info->max_write_len = be16_to_cpu(mwl->len); @@ -1631,8 +1590,8 @@ static void i3c_master_detach_free_devs(struct i3c_master_controller *master) common.node) { i3c_master_detach_i2c_dev(i2cdev); i3c_bus_set_addr_slot_status(&master->bus, - i2cdev->boardinfo->base.addr, - I3C_ADDR_SLOT_FREE); + i2cdev->addr, + I3C_ADDR_SLOT_FREE); i3c_master_free_i2c_dev(i2cdev); } } @@ -2093,8 +2052,10 @@ static int of_populate_i3c_bus(struct i3c_master_controller *master) for_each_available_child_of_node(i3cbus_np, node) { ret = of_i3c_master_add_dev(master, node); - if (ret) + if (ret) { + of_node_put(node); return ret; + } } /* diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 09912d75c6d5398e63ebd5148a6cc5441721d595..b0ff0e12d84ca0faa8a5a5f2ebfcc7b53cdbb1e2 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -1033,12 +1033,12 @@ static int dw_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev) return -ENOMEM; data->index = pos; - master->addrs[pos] = dev->boardinfo->base.addr; + master->addrs[pos] = dev->addr; master->free_pos &= ~BIT(pos); i2c_dev_set_master_data(dev, data); writel(DEV_ADDR_TABLE_LEGACY_I2C_DEV | - DEV_ADDR_TABLE_STATIC_ADDR(dev->boardinfo->base.addr), + DEV_ADDR_TABLE_STATIC_ADDR(dev->addr), master->regs + DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c index 237f24adddc632bc3470df59572cb6a68a9198f9..10db0bf0655a9f71938f146f802857eac4c9c329 100644 --- a/drivers/i3c/master/i3c-master-cdns.c +++ b/drivers/i3c/master/i3c-master-cdns.c @@ -903,7 +903,8 @@ static void cdns_i3c_master_upd_i3c_addr(struct i3c_dev_desc *dev) static int cdns_i3c_master_get_rr_slot(struct cdns_i3c_master *master, u8 dyn_addr) { - u32 activedevs, rr; + unsigned long activedevs; + u32 rr; int i; if (!dyn_addr) { @@ -913,13 +914,10 @@ static int cdns_i3c_master_get_rr_slot(struct cdns_i3c_master *master, return ffs(master->free_rr_slots) - 1; } - activedevs = readl(master->regs + DEVS_CTRL) & - DEVS_CTRL_DEVS_ACTIVE_MASK; - - for (i = 1; i <= master->maxdevs; i++) { - if (!(BIT(i) & activedevs)) - continue; + activedevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK; + activedevs &= ~BIT(0); + for_each_set_bit(i, &activedevs, master->maxdevs + 1) { rr = readl(master->regs + DEV_ID_RR0(i)); if (!(rr & DEV_ID_RR0_IS_I3C) || DEV_ID_RR0_GET_DEV_ADDR(rr) != dyn_addr) @@ -1005,9 +1003,9 @@ static int cdns_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev) master->free_rr_slots &= ~BIT(slot); i2c_dev_set_master_data(dev, data); - writel(prepare_rr0_dev_address(dev->boardinfo->base.addr), + writel(prepare_rr0_dev_address(dev->addr), master->regs + DEV_ID_RR0(data->id)); - writel(dev->boardinfo->lvr, master->regs + DEV_ID_RR2(data->id)); + writel(dev->lvr, master->regs + DEV_ID_RR2(data->id)); writel(readl(master->regs + DEVS_CTRL) | DEVS_CTRL_DEV_ACTIVE(data->id), master->regs + DEVS_CTRL); @@ -1126,18 +1124,16 @@ static void cdns_i3c_master_upd_i3c_scl_lim(struct cdns_i3c_master *master) static int cdns_i3c_master_do_daa(struct i3c_master_controller *m) { struct cdns_i3c_master *master = to_cdns_i3c_master(m); - u32 olddevs, newdevs; + unsigned long olddevs, newdevs; int ret, slot; u8 addrs[MAX_DEVS] = { }; u8 last_addr = 0; olddevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK; + olddevs |= BIT(0); /* Prepare RR slots before launching DAA. */ - for (slot = 1; slot <= master->maxdevs; slot++) { - if (olddevs & BIT(slot)) - continue; - + for_each_clear_bit(slot, &olddevs, master->maxdevs + 1) { ret = i3c_master_get_free_addr(m, last_addr + 1); if (ret < 0) return -ENOSPC; @@ -1161,10 +1157,8 @@ static int cdns_i3c_master_do_daa(struct i3c_master_controller *m) * Clear all retaining registers filled during DAA. We already * have the addressed assigned to them in the addrs array. */ - for (slot = 1; slot <= master->maxdevs; slot++) { - if (newdevs & BIT(slot)) - i3c_master_add_i3c_dev_locked(m, addrs[slot]); - } + for_each_set_bit(slot, &newdevs, master->maxdevs + 1) + i3c_master_add_i3c_dev_locked(m, addrs[slot]); /* * Clear slots that ended up not being used. Can be caused by I3C diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 9eada392df15951607225a98c6987e1dbbbddc66..1c227ea8ecd3cb5dcf4606ffb7b8a290426927e5 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -567,15 +567,6 @@ config BLK_DEV_SVWKS This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5 chipsets. -config BLK_DEV_SGIIOC4 - tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support" - depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4 - select BLK_DEV_IDEDMA_PCI - help - This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4 - chipset, which has one channel and can support two devices. - Please say Y here if you have an Altix System from SGI. - config BLK_DEV_SIIMAGE tristate "Silicon Image chipset support" select BLK_DEV_IDEDMA_PCI diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index 9f617a77970f4e3bb853aeff2968cc6871291aa5..cac02db4098d48ef6fe64347cfac1817191157f1 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -59,7 +59,6 @@ obj-$(CONFIG_BLK_DEV_PDC202XX_NEW) += pdc202xx_new.o obj-$(CONFIG_BLK_DEV_PIIX) += piix.o obj-$(CONFIG_BLK_DEV_RZ1000) += rz1000.o obj-$(CONFIG_BLK_DEV_SVWKS) += serverworks.o -obj-$(CONFIG_BLK_DEV_SGIIOC4) += sgiioc4.o obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimage.o obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o diff --git a/drivers/ide/sgiioc4.c b/drivers/ide/sgiioc4.c deleted file mode 100644 index 2d35e9f7516fb7037c597be81602ac73610c2867..0000000000000000000000000000000000000000 --- a/drivers/ide/sgiioc4.c +++ /dev/null @@ -1,630 +0,0 @@ -/* - * Copyright (c) 2003-2006 Silicon Graphics, Inc. All Rights Reserved. - * Copyright (C) 2008-2009 MontaVista Software, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "SGIIOC4" - -/* IOC4 Specific Definitions */ -#define IOC4_CMD_OFFSET 0x100 -#define IOC4_CTRL_OFFSET 0x120 -#define IOC4_DMA_OFFSET 0x140 -#define IOC4_INTR_OFFSET 0x0 - -#define IOC4_TIMING 0x00 -#define IOC4_DMA_PTR_L 0x01 -#define IOC4_DMA_PTR_H 0x02 -#define IOC4_DMA_ADDR_L 0x03 -#define IOC4_DMA_ADDR_H 0x04 -#define IOC4_BC_DEV 0x05 -#define IOC4_BC_MEM 0x06 -#define IOC4_DMA_CTRL 0x07 -#define IOC4_DMA_END_ADDR 0x08 - -/* Bits in the IOC4 Control/Status Register */ -#define IOC4_S_DMA_START 0x01 -#define IOC4_S_DMA_STOP 0x02 -#define IOC4_S_DMA_DIR 0x04 -#define IOC4_S_DMA_ACTIVE 0x08 -#define IOC4_S_DMA_ERROR 0x10 -#define IOC4_ATA_MEMERR 0x02 - -/* Read/Write Directions */ -#define IOC4_DMA_WRITE 0x04 -#define IOC4_DMA_READ 0x00 - -/* Interrupt Register Offsets */ -#define IOC4_INTR_REG 0x03 -#define IOC4_INTR_SET 0x05 -#define IOC4_INTR_CLEAR 0x07 - -#define IOC4_IDE_CACHELINE_SIZE 128 -#define IOC4_CMD_CTL_BLK_SIZE 0x20 -#define IOC4_SUPPORTED_FIRMWARE_REV 46 - -struct ioc4_dma_regs { - u32 timing_reg0; - u32 timing_reg1; - u32 low_mem_ptr; - u32 high_mem_ptr; - u32 low_mem_addr; - u32 high_mem_addr; - u32 dev_byte_count; - u32 mem_byte_count; - u32 status; -}; - -/* Each Physical Region Descriptor Entry size is 16 bytes (2 * 64 bits) */ -/* IOC4 has only 1 IDE channel */ -#define IOC4_PRD_BYTES 16 -#define IOC4_PRD_ENTRIES (PAGE_SIZE / (4 * IOC4_PRD_BYTES)) - - -static void sgiioc4_init_hwif_ports(struct ide_hw *hw, - unsigned long data_port, - unsigned long ctrl_port, - unsigned long irq_port) -{ - unsigned long reg = data_port; - int i; - - /* Registers are word (32 bit) aligned */ - for (i = 0; i <= 7; i++) - hw->io_ports_array[i] = reg + i * 4; - - hw->io_ports.ctl_addr = ctrl_port; - hw->io_ports.irq_addr = irq_port; -} - -static int sgiioc4_checkirq(ide_hwif_t *hwif) -{ - unsigned long intr_addr = hwif->io_ports.irq_addr + IOC4_INTR_REG * 4; - - if (readl((void __iomem *)intr_addr) & 0x03) - return 1; - - return 0; -} - -static u8 sgiioc4_read_status(ide_hwif_t *); - -static int sgiioc4_clearirq(ide_drive_t *drive) -{ - u32 intr_reg; - ide_hwif_t *hwif = drive->hwif; - struct ide_io_ports *io_ports = &hwif->io_ports; - unsigned long other_ir = io_ports->irq_addr + (IOC4_INTR_REG << 2); - - /* Code to check for PCI error conditions */ - intr_reg = readl((void __iomem *)other_ir); - if (intr_reg & 0x03) { /* Valid IOC4-IDE interrupt */ - /* - * Using sgiioc4_read_status to read the Status register has a - * side effect of clearing the interrupt. The first read should - * clear it if it is set. The second read should return - * a "clear" status if it got cleared. If not, then spin - * for a bit trying to clear it. - */ - u8 stat = sgiioc4_read_status(hwif); - int count = 0; - - stat = sgiioc4_read_status(hwif); - while ((stat & ATA_BUSY) && (count++ < 100)) { - udelay(1); - stat = sgiioc4_read_status(hwif); - } - - if (intr_reg & 0x02) { - struct pci_dev *dev = to_pci_dev(hwif->dev); - /* Error when transferring DMA data on PCI bus */ - u32 pci_err_addr_low, pci_err_addr_high, - pci_stat_cmd_reg; - - pci_err_addr_low = - readl((void __iomem *)io_ports->irq_addr); - pci_err_addr_high = - readl((void __iomem *)(io_ports->irq_addr + 4)); - pci_read_config_dword(dev, PCI_COMMAND, - &pci_stat_cmd_reg); - printk(KERN_ERR "%s(%s): PCI Bus Error when doing DMA: " - "status-cmd reg is 0x%x\n", - __func__, drive->name, pci_stat_cmd_reg); - printk(KERN_ERR "%s(%s): PCI Error Address is 0x%x%x\n", - __func__, drive->name, - pci_err_addr_high, pci_err_addr_low); - /* Clear the PCI Error indicator */ - pci_write_config_dword(dev, PCI_COMMAND, 0x00000146); - } - - /* Clear the Interrupt, Error bits on the IOC4 */ - writel(0x03, (void __iomem *)other_ir); - - intr_reg = readl((void __iomem *)other_ir); - } - - return intr_reg & 3; -} - -static void sgiioc4_dma_start(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - unsigned long ioc4_dma_addr = hwif->dma_base + IOC4_DMA_CTRL * 4; - unsigned int reg = readl((void __iomem *)ioc4_dma_addr); - unsigned int temp_reg = reg | IOC4_S_DMA_START; - - writel(temp_reg, (void __iomem *)ioc4_dma_addr); -} - -static u32 sgiioc4_ide_dma_stop(ide_hwif_t *hwif, u64 dma_base) -{ - unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4; - u32 ioc4_dma; - int count; - - count = 0; - ioc4_dma = readl((void __iomem *)ioc4_dma_addr); - while ((ioc4_dma & IOC4_S_DMA_STOP) && (count++ < 200)) { - udelay(1); - ioc4_dma = readl((void __iomem *)ioc4_dma_addr); - } - return ioc4_dma; -} - -/* Stops the IOC4 DMA Engine */ -static int sgiioc4_dma_end(ide_drive_t *drive) -{ - u32 ioc4_dma, bc_dev, bc_mem, num, valid = 0, cnt = 0; - ide_hwif_t *hwif = drive->hwif; - unsigned long dma_base = hwif->dma_base; - int dma_stat = 0; - unsigned long *ending_dma = ide_get_hwifdata(hwif); - - writel(IOC4_S_DMA_STOP, (void __iomem *)(dma_base + IOC4_DMA_CTRL * 4)); - - ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); - - if (ioc4_dma & IOC4_S_DMA_STOP) { - printk(KERN_ERR - "%s(%s): IOC4 DMA STOP bit is still 1 :" - "ioc4_dma_reg 0x%x\n", - __func__, drive->name, ioc4_dma); - dma_stat = 1; - } - - /* - * The IOC4 will DMA 1's to the ending DMA area to indicate that - * previous data DMA is complete. This is necessary because of relaxed - * ordering between register reads and DMA writes on the Altix. - */ - while ((cnt++ < 200) && (!valid)) { - for (num = 0; num < 16; num++) { - if (ending_dma[num]) { - valid = 1; - break; - } - } - udelay(1); - } - if (!valid) { - printk(KERN_ERR "%s(%s) : DMA incomplete\n", __func__, - drive->name); - dma_stat = 1; - } - - bc_dev = readl((void __iomem *)(dma_base + IOC4_BC_DEV * 4)); - bc_mem = readl((void __iomem *)(dma_base + IOC4_BC_MEM * 4)); - - if ((bc_dev & 0x01FF) || (bc_mem & 0x1FF)) { - if (bc_dev > bc_mem + 8) { - printk(KERN_ERR - "%s(%s): WARNING!! byte_count_dev %d " - "!= byte_count_mem %d\n", - __func__, drive->name, bc_dev, bc_mem); - } - } - - return dma_stat; -} - -static void sgiioc4_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ -} - -/* Returns 1 if DMA IRQ issued, 0 otherwise */ -static int sgiioc4_dma_test_irq(ide_drive_t *drive) -{ - return sgiioc4_checkirq(drive->hwif); -} - -static void sgiioc4_dma_host_set(ide_drive_t *drive, int on) -{ - if (!on) - sgiioc4_clearirq(drive); -} - -static void sgiioc4_resetproc(ide_drive_t *drive) -{ - struct ide_cmd *cmd = &drive->hwif->cmd; - - sgiioc4_dma_end(drive); - ide_dma_unmap_sg(drive, cmd); - sgiioc4_clearirq(drive); -} - -static void sgiioc4_dma_lost_irq(ide_drive_t *drive) -{ - sgiioc4_resetproc(drive); - - ide_dma_lost_irq(drive); -} - -static u8 sgiioc4_read_status(ide_hwif_t *hwif) -{ - unsigned long port = hwif->io_ports.status_addr; - u8 reg = (u8) readb((void __iomem *) port); - - if (!(reg & ATA_BUSY)) { /* Not busy... check for interrupt */ - unsigned long other_ir = port - 0x110; - unsigned int intr_reg = (u32) readl((void __iomem *) other_ir); - - /* Clear the Interrupt, Error bits on the IOC4 */ - if (intr_reg & 0x03) { - writel(0x03, (void __iomem *) other_ir); - intr_reg = (u32) readl((void __iomem *) other_ir); - } - } - - return reg; -} - -/* Creates a DMA map for the scatter-gather list entries */ -static int ide_dma_sgiioc4(ide_hwif_t *hwif, const struct ide_port_info *d) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET; - int num_ports = sizeof(struct ioc4_dma_regs); - void *pad; - - printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name); - - if (request_mem_region(dma_base, num_ports, hwif->name) == NULL) { - printk(KERN_ERR "%s(%s) -- ERROR: addresses 0x%08lx to 0x%08lx " - "already in use\n", __func__, hwif->name, - dma_base, dma_base + num_ports - 1); - return -1; - } - - hwif->dma_base = (unsigned long)hwif->io_ports.irq_addr + - IOC4_DMA_OFFSET; - - hwif->sg_max_nents = IOC4_PRD_ENTRIES; - - hwif->prd_max_nents = IOC4_PRD_ENTRIES; - hwif->prd_ent_size = IOC4_PRD_BYTES; - - if (ide_allocate_dma_engine(hwif)) - goto dma_pci_alloc_failure; - - pad = dma_alloc_coherent(&dev->dev, IOC4_IDE_CACHELINE_SIZE, - (dma_addr_t *)&hwif->extra_base, GFP_KERNEL); - if (pad) { - ide_set_hwifdata(hwif, pad); - return 0; - } - - ide_release_dma_engine(hwif); - - printk(KERN_ERR "%s(%s) -- ERROR: Unable to allocate DMA maps\n", - __func__, hwif->name); - printk(KERN_INFO "%s: changing from DMA to PIO mode", hwif->name); - -dma_pci_alloc_failure: - release_mem_region(dma_base, num_ports); - - return -1; -} - -/* Initializes the IOC4 DMA Engine */ -static void sgiioc4_configure_for_dma(int dma_direction, ide_drive_t *drive) -{ - u32 ioc4_dma; - ide_hwif_t *hwif = drive->hwif; - unsigned long dma_base = hwif->dma_base; - unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4; - u32 dma_addr, ending_dma_addr; - - ioc4_dma = readl((void __iomem *)ioc4_dma_addr); - - if (ioc4_dma & IOC4_S_DMA_ACTIVE) { - printk(KERN_WARNING "%s(%s): Warning!! DMA from previous " - "transfer was still active\n", __func__, drive->name); - writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr); - ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); - - if (ioc4_dma & IOC4_S_DMA_STOP) - printk(KERN_ERR "%s(%s): IOC4 DMA STOP bit is " - "still 1\n", __func__, drive->name); - } - - ioc4_dma = readl((void __iomem *)ioc4_dma_addr); - if (ioc4_dma & IOC4_S_DMA_ERROR) { - printk(KERN_WARNING "%s(%s): Warning!! DMA Error during " - "previous transfer, status 0x%x\n", - __func__, drive->name, ioc4_dma); - writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr); - ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); - - if (ioc4_dma & IOC4_S_DMA_STOP) - printk(KERN_ERR "%s(%s): IOC4 DMA STOP bit is " - "still 1\n", __func__, drive->name); - } - - /* Address of the Scatter Gather List */ - dma_addr = cpu_to_le32(hwif->dmatable_dma); - writel(dma_addr, (void __iomem *)(dma_base + IOC4_DMA_PTR_L * 4)); - - /* Address of the Ending DMA */ - memset(ide_get_hwifdata(hwif), 0, IOC4_IDE_CACHELINE_SIZE); - ending_dma_addr = cpu_to_le32(hwif->extra_base); - writel(ending_dma_addr, (void __iomem *)(dma_base + - IOC4_DMA_END_ADDR * 4)); - - writel(dma_direction, (void __iomem *)ioc4_dma_addr); -} - -/* IOC4 Scatter Gather list Format */ -/* 128 Bit entries to support 64 bit addresses in the future */ -/* The Scatter Gather list Entry should be in the BIG-ENDIAN Format */ -/* --------------------------------------------------------------------- */ -/* | Upper 32 bits - Zero | Lower 32 bits- address | */ -/* --------------------------------------------------------------------- */ -/* | Upper 32 bits - Zero |EOL| 15 unused | 16 Bit Length| */ -/* --------------------------------------------------------------------- */ -/* Creates the scatter gather list, DMA Table */ - -static int sgiioc4_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) -{ - ide_hwif_t *hwif = drive->hwif; - unsigned int *table = hwif->dmatable_cpu; - unsigned int count = 0, i = cmd->sg_nents; - struct scatterlist *sg = hwif->sg_table; - - while (i && sg_dma_len(sg)) { - dma_addr_t cur_addr; - int cur_len; - cur_addr = sg_dma_address(sg); - cur_len = sg_dma_len(sg); - - while (cur_len) { - if (count++ >= IOC4_PRD_ENTRIES) { - printk(KERN_WARNING - "%s: DMA table too small\n", - drive->name); - return 0; - } else { - u32 bcount = - 0x10000 - (cur_addr & 0xffff); - - if (bcount > cur_len) - bcount = cur_len; - - /* - * Put the address, length in - * the IOC4 dma-table format - */ - *table = 0x0; - table++; - *table = cpu_to_be32(cur_addr); - table++; - *table = 0x0; - table++; - - *table = cpu_to_be32(bcount); - table++; - - cur_addr += bcount; - cur_len -= bcount; - } - } - - sg = sg_next(sg); - i--; - } - - if (count) { - table--; - *table |= cpu_to_be32(0x80000000); - return count; - } - - return 0; /* revert to PIO for this request */ -} - -static int sgiioc4_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) -{ - int ddir; - u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE); - - if (sgiioc4_build_dmatable(drive, cmd) == 0) - /* try PIO instead of DMA */ - return 1; - - if (write) - /* Writes TO the IOC4 FROM Main Memory */ - ddir = IOC4_DMA_READ; - else - /* Writes FROM the IOC4 TO Main Memory */ - ddir = IOC4_DMA_WRITE; - - sgiioc4_configure_for_dma(ddir, drive); - - return 0; -} - -static const struct ide_tp_ops sgiioc4_tp_ops = { - .exec_command = ide_exec_command, - .read_status = sgiioc4_read_status, - .read_altstatus = ide_read_altstatus, - .write_devctl = ide_write_devctl, - - .dev_select = ide_dev_select, - .tf_load = ide_tf_load, - .tf_read = ide_tf_read, - - .input_data = ide_input_data, - .output_data = ide_output_data, -}; - -static const struct ide_port_ops sgiioc4_port_ops = { - .set_dma_mode = sgiioc4_set_dma_mode, - /* reset DMA engine, clear IRQs */ - .resetproc = sgiioc4_resetproc, -}; - -static const struct ide_dma_ops sgiioc4_dma_ops = { - .dma_host_set = sgiioc4_dma_host_set, - .dma_setup = sgiioc4_dma_setup, - .dma_start = sgiioc4_dma_start, - .dma_end = sgiioc4_dma_end, - .dma_test_irq = sgiioc4_dma_test_irq, - .dma_lost_irq = sgiioc4_dma_lost_irq, -}; - -static const struct ide_port_info sgiioc4_port_info = { - .name = DRV_NAME, - .chipset = ide_pci, - .init_dma = ide_dma_sgiioc4, - .tp_ops = &sgiioc4_tp_ops, - .port_ops = &sgiioc4_port_ops, - .dma_ops = &sgiioc4_dma_ops, - .host_flags = IDE_HFLAG_MMIO, - .irq_flags = IRQF_SHARED, - .mwdma_mask = ATA_MWDMA2_ONLY, -}; - -static int sgiioc4_ide_setup_pci_device(struct pci_dev *dev) -{ - unsigned long cmd_base, irqport; - unsigned long bar0, cmd_phys_base, ctl; - void __iomem *virt_base; - struct ide_hw hw, *hws[] = { &hw }; - int rc; - - /* Get the CmdBlk and CtrlBlk base registers */ - bar0 = pci_resource_start(dev, 0); - virt_base = pci_ioremap_bar(dev, 0); - if (virt_base == NULL) { - printk(KERN_ERR "%s: Unable to remap BAR 0 address: 0x%lx\n", - DRV_NAME, bar0); - return -ENOMEM; - } - cmd_base = (unsigned long)virt_base + IOC4_CMD_OFFSET; - ctl = (unsigned long)virt_base + IOC4_CTRL_OFFSET; - irqport = (unsigned long)virt_base + IOC4_INTR_OFFSET; - - cmd_phys_base = bar0 + IOC4_CMD_OFFSET; - if (request_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE, - DRV_NAME) == NULL) { - printk(KERN_ERR "%s %s -- ERROR: addresses 0x%08lx to 0x%08lx " - "already in use\n", DRV_NAME, pci_name(dev), - cmd_phys_base, cmd_phys_base + IOC4_CMD_CTL_BLK_SIZE); - rc = -EBUSY; - goto req_mem_rgn_err; - } - - /* Initialize the IO registers */ - memset(&hw, 0, sizeof(hw)); - sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport); - hw.irq = dev->irq; - hw.dev = &dev->dev; - - /* Initialize chipset IRQ registers */ - writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4)); - - rc = ide_host_add(&sgiioc4_port_info, hws, 1, NULL); - if (!rc) - return 0; - - release_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE); -req_mem_rgn_err: - iounmap(virt_base); - return rc; -} - -static unsigned int pci_init_sgiioc4(struct pci_dev *dev) -{ - int ret; - - printk(KERN_INFO "%s: IDE controller at PCI slot %s, revision %d\n", - DRV_NAME, pci_name(dev), dev->revision); - - if (dev->revision < IOC4_SUPPORTED_FIRMWARE_REV) { - printk(KERN_ERR "Skipping %s IDE controller in slot %s: " - "firmware is obsolete - please upgrade to " - "revision46 or higher\n", - DRV_NAME, pci_name(dev)); - ret = -EAGAIN; - goto out; - } - ret = sgiioc4_ide_setup_pci_device(dev); -out: - return ret; -} - -static int ioc4_ide_attach_one(struct ioc4_driver_data *idd) -{ - /* - * PCI-RT does not bring out IDE connection. - * Do not attach to this particular IOC4. - */ - if (idd->idd_variant == IOC4_VARIANT_PCI_RT) - return 0; - - return pci_init_sgiioc4(idd->idd_pdev); -} - -static struct ioc4_submodule ioc4_ide_submodule = { - .is_name = "IOC4_ide", - .is_owner = THIS_MODULE, - .is_probe = ioc4_ide_attach_one, -}; - -static int __init ioc4_ide_init(void) -{ - return ioc4_register_submodule(&ioc4_ide_submodule); -} - -late_initcall(ioc4_ide_init); /* Call only after IDE init is done */ - -MODULE_AUTHOR("Aniket Malatpure/Jeremy Higdon"); -MODULE_DESCRIPTION("IDE PCI driver module for SGI IOC4 Base-IO Card"); -MODULE_LICENSE("GPL"); diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index fa5ff77b8fe49af3ab33feea79a78b163253a48b..347b08b56042f707203fd625e6e757b7b186ae6a 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -1072,26 +1072,26 @@ static const struct x86_cpu_id intel_idle_ids[] __initconst = { INTEL_CPU_FAM6(ATOM_AIRMONT, idle_cpu_cht), INTEL_CPU_FAM6(IVYBRIDGE, idle_cpu_ivb), INTEL_CPU_FAM6(IVYBRIDGE_X, idle_cpu_ivt), - INTEL_CPU_FAM6(HASWELL_CORE, idle_cpu_hsw), + INTEL_CPU_FAM6(HASWELL, idle_cpu_hsw), INTEL_CPU_FAM6(HASWELL_X, idle_cpu_hsw), - INTEL_CPU_FAM6(HASWELL_ULT, idle_cpu_hsw), - INTEL_CPU_FAM6(HASWELL_GT3E, idle_cpu_hsw), - INTEL_CPU_FAM6(ATOM_SILVERMONT_X, idle_cpu_avn), - INTEL_CPU_FAM6(BROADWELL_CORE, idle_cpu_bdw), - INTEL_CPU_FAM6(BROADWELL_GT3E, idle_cpu_bdw), + INTEL_CPU_FAM6(HASWELL_L, idle_cpu_hsw), + INTEL_CPU_FAM6(HASWELL_G, idle_cpu_hsw), + INTEL_CPU_FAM6(ATOM_SILVERMONT_D, idle_cpu_avn), + INTEL_CPU_FAM6(BROADWELL, idle_cpu_bdw), + INTEL_CPU_FAM6(BROADWELL_G, idle_cpu_bdw), INTEL_CPU_FAM6(BROADWELL_X, idle_cpu_bdw), - INTEL_CPU_FAM6(BROADWELL_XEON_D, idle_cpu_bdw), - INTEL_CPU_FAM6(SKYLAKE_MOBILE, idle_cpu_skl), - INTEL_CPU_FAM6(SKYLAKE_DESKTOP, idle_cpu_skl), - INTEL_CPU_FAM6(KABYLAKE_MOBILE, idle_cpu_skl), - INTEL_CPU_FAM6(KABYLAKE_DESKTOP, idle_cpu_skl), + INTEL_CPU_FAM6(BROADWELL_D, idle_cpu_bdw), + INTEL_CPU_FAM6(SKYLAKE_L, idle_cpu_skl), + INTEL_CPU_FAM6(SKYLAKE, idle_cpu_skl), + INTEL_CPU_FAM6(KABYLAKE_L, idle_cpu_skl), + INTEL_CPU_FAM6(KABYLAKE, idle_cpu_skl), INTEL_CPU_FAM6(SKYLAKE_X, idle_cpu_skx), INTEL_CPU_FAM6(XEON_PHI_KNL, idle_cpu_knl), INTEL_CPU_FAM6(XEON_PHI_KNM, idle_cpu_knl), INTEL_CPU_FAM6(ATOM_GOLDMONT, idle_cpu_bxt), INTEL_CPU_FAM6(ATOM_GOLDMONT_PLUS, idle_cpu_bxt), - INTEL_CPU_FAM6(ATOM_GOLDMONT_X, idle_cpu_dnv), - INTEL_CPU_FAM6(ATOM_TREMONT_X, idle_cpu_dnv), + INTEL_CPU_FAM6(ATOM_GOLDMONT_D, idle_cpu_dnv), + INTEL_CPU_FAM6(ATOM_TREMONT_D, idle_cpu_dnv), {} }; @@ -1311,7 +1311,7 @@ static void intel_idle_state_table_update(void) case INTEL_FAM6_ATOM_GOLDMONT_PLUS: bxt_idle_state_table_update(); break; - case INTEL_FAM6_SKYLAKE_DESKTOP: + case INTEL_FAM6_SKYLAKE: sklh_idle_state_table_update(); break; } diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 9b9656ce37e60d2f46daa2d4c7821838ecc6e98c..d4ef35aeb5792690e0369ff55f52592aa49300a1 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -202,9 +202,7 @@ config HID_SENSOR_ACCEL_3D config IIO_CROS_EC_ACCEL_LEGACY tristate "ChromeOS EC Legacy Accelerometer Sensor" - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select CROS_EC_LPC_REGISTER_DEVICE + depends on IIO_CROS_EC_SENSORS_CORE help Say yes here to get support for accelerometers on Chromebook using legacy EC firmware. diff --git a/drivers/iio/accel/cros_ec_accel_legacy.c b/drivers/iio/accel/cros_ec_accel_legacy.c index ad19d9c716f41e4611af354511b1354711e2701c..39002cb5605d2233ccbae01e9e3fd2187b928cae 100644 --- a/drivers/iio/accel/cros_ec_accel_legacy.c +++ b/drivers/iio/accel/cros_ec_accel_legacy.c @@ -5,13 +5,14 @@ * Copyright 2017 Google, Inc * * This driver uses the memory mapper cros-ec interface to communicate - * with the Chrome OS EC about accelerometer data. + * with the Chrome OS EC about accelerometer data or older commands. * Accelerometer access is presented through iio sysfs. */ #include #include #include +#include #include #include #include @@ -25,160 +26,41 @@ #define DRV_NAME "cros-ec-accel-legacy" +#define CROS_EC_SENSOR_LEGACY_NUM 2 /* * Sensor scale hard coded at 10 bits per g, computed as: * g / (2^10 - 1) = 0.009586168; with g = 9.80665 m.s^-2 */ #define ACCEL_LEGACY_NSCALE 9586168 -/* Indices for EC sensor values. */ -enum { - X, - Y, - Z, - MAX_AXIS, -}; - -/* State data for cros_ec_accel_legacy iio driver. */ -struct cros_ec_accel_legacy_state { - struct cros_ec_device *ec; - - /* - * Array holding data from a single capture. 2 bytes per channel - * for the 3 channels plus the timestamp which is always last and - * 8-bytes aligned. - */ - s16 capture_data[8]; - s8 sign[MAX_AXIS]; - u8 sensor_num; -}; - -static int ec_cmd_read_u8(struct cros_ec_device *ec, unsigned int offset, - u8 *dest) -{ - return ec->cmd_readmem(ec, offset, 1, dest); -} - -static int ec_cmd_read_u16(struct cros_ec_device *ec, unsigned int offset, - u16 *dest) -{ - __le16 tmp; - int ret = ec->cmd_readmem(ec, offset, 2, &tmp); - - *dest = le16_to_cpu(tmp); - - return ret; -} - -/** - * read_ec_until_not_busy() - Read from EC status byte until it reads not busy. - * @st: Pointer to state information for device. - * - * This function reads EC status until its busy bit gets cleared. It does not - * wait indefinitely and returns -EIO if the EC status is still busy after a - * few hundreds milliseconds. - * - * Return: 8-bit status if ok, -EIO on error - */ -static int read_ec_until_not_busy(struct cros_ec_accel_legacy_state *st) -{ - struct cros_ec_device *ec = st->ec; - u8 status; - int attempts = 0; - - ec_cmd_read_u8(ec, EC_MEMMAP_ACC_STATUS, &status); - while (status & EC_MEMMAP_ACC_STATUS_BUSY_BIT) { - /* Give up after enough attempts, return error. */ - if (attempts++ >= 50) - return -EIO; - - /* Small delay every so often. */ - if (attempts % 5 == 0) - msleep(25); - - ec_cmd_read_u8(ec, EC_MEMMAP_ACC_STATUS, &status); - } - - return status; -} - -/** - * read_ec_accel_data_unsafe() - Read acceleration data from EC shared memory. - * @st: Pointer to state information for device. - * @scan_mask: Bitmap of the sensor indices to scan. - * @data: Location to store data. - * - * This is the unsafe function for reading the EC data. It does not guarantee - * that the EC will not modify the data as it is being read in. - */ -static void read_ec_accel_data_unsafe(struct cros_ec_accel_legacy_state *st, - unsigned long scan_mask, s16 *data) -{ - int i = 0; - int num_enabled = bitmap_weight(&scan_mask, MAX_AXIS); - - /* Read all sensors enabled in scan_mask. Each value is 2 bytes. */ - while (num_enabled--) { - i = find_next_bit(&scan_mask, MAX_AXIS, i); - ec_cmd_read_u16(st->ec, - EC_MEMMAP_ACC_DATA + - sizeof(s16) * - (1 + i + st->sensor_num * MAX_AXIS), - data); - *data *= st->sign[i]; - i++; - data++; - } -} - -/** - * read_ec_accel_data() - Read acceleration data from EC shared memory. - * @st: Pointer to state information for device. - * @scan_mask: Bitmap of the sensor indices to scan. - * @data: Location to store data. - * - * This is the safe function for reading the EC data. It guarantees that - * the data sampled was not modified by the EC while being read. - * - * Return: 0 if ok, -ve on error - */ -static int read_ec_accel_data(struct cros_ec_accel_legacy_state *st, - unsigned long scan_mask, s16 *data) +static int cros_ec_accel_legacy_read_cmd(struct iio_dev *indio_dev, + unsigned long scan_mask, s16 *data) { - u8 samp_id = 0xff; - u8 status = 0; + struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); int ret; - int attempts = 0; + unsigned int i; + u8 sensor_num; /* - * Continually read all data from EC until the status byte after - * all reads reflects that the EC is not busy and the sample id - * matches the sample id from before all reads. This guarantees - * that data read in was not modified by the EC while reading. + * Read all sensor data through a command. + * Save sensor_num, it is assumed to stay. */ - while ((status & (EC_MEMMAP_ACC_STATUS_BUSY_BIT | - EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK)) != samp_id) { - /* If we have tried to read too many times, return error. */ - if (attempts++ >= 5) - return -EIO; - - /* Read status byte until EC is not busy. */ - ret = read_ec_until_not_busy(st); - if (ret < 0) - return ret; - status = ret; - - /* - * Store the current sample id so that we can compare to the - * sample id after reading the data. - */ - samp_id = status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK; - - /* Read all EC data, format it, and store it into data. */ - read_ec_accel_data_unsafe(st, scan_mask, data); + sensor_num = st->param.info.sensor_num; + st->param.cmd = MOTIONSENSE_CMD_DUMP; + st->param.dump.max_sensor_count = CROS_EC_SENSOR_LEGACY_NUM; + ret = cros_ec_motion_send_host_cmd(st, + sizeof(st->resp->dump) + CROS_EC_SENSOR_LEGACY_NUM * + sizeof(struct ec_response_motion_sensor_data)); + st->param.info.sensor_num = sensor_num; + if (ret != 0) { + dev_warn(&indio_dev->dev, "Unable to read sensor data\n"); + return ret; + } - /* Read status byte. */ - ec_cmd_read_u8(st->ec, EC_MEMMAP_ACC_STATUS, &status); + for_each_set_bit(i, &scan_mask, indio_dev->masklength) { + *data = st->resp->dump.sensor[sensor_num].data[i] * + st->sign[i]; + data++; } return 0; @@ -188,28 +70,40 @@ static int cros_ec_accel_legacy_read(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { - struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev); + struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); s16 data = 0; - int ret = IIO_VAL_INT; + int ret; + int idx = chan->scan_index; + + mutex_lock(&st->cmd_lock); switch (mask) { case IIO_CHAN_INFO_RAW: - ret = read_ec_accel_data(st, (1 << chan->scan_index), &data); - if (ret) - return ret; + ret = st->read_ec_sensors_data(indio_dev, 1 << idx, &data); + if (ret < 0) + break; + ret = IIO_VAL_INT; *val = data; - return IIO_VAL_INT; + break; case IIO_CHAN_INFO_SCALE: + WARN_ON(st->type != MOTIONSENSE_TYPE_ACCEL); *val = 0; *val2 = ACCEL_LEGACY_NSCALE; - return IIO_VAL_INT_PLUS_NANO; + ret = IIO_VAL_INT_PLUS_NANO; + break; case IIO_CHAN_INFO_CALIBBIAS: /* Calibration not supported. */ *val = 0; - return IIO_VAL_INT; + ret = IIO_VAL_INT; + break; default: - return -EINVAL; + ret = cros_ec_sensors_core_read(st, chan, val, val2, + mask); + break; } + mutex_unlock(&st->cmd_lock); + + return ret; } static int cros_ec_accel_legacy_write(struct iio_dev *indio_dev, @@ -231,86 +125,14 @@ static const struct iio_info cros_ec_accel_legacy_info = { .write_raw = &cros_ec_accel_legacy_write, }; -/** - * cros_ec_accel_legacy_capture() - The trigger handler function - * @irq: The interrupt number. - * @p: Private data - always a pointer to the poll func. - * - * On a trigger event occurring, if the pollfunc is attached then this - * handler is called as a threaded interrupt (and hence may sleep). It - * is responsible for grabbing data from the device and pushing it into - * the associated buffer. - * - * Return: IRQ_HANDLED +/* + * Present the channel using HTML5 standard: + * need to invert X and Y and invert some lid axis. */ -static irqreturn_t cros_ec_accel_legacy_capture(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev); - - /* Clear capture data. */ - memset(st->capture_data, 0, sizeof(st->capture_data)); - - /* - * Read data based on which channels are enabled in scan mask. Note - * that on a capture we are always reading the calibrated data. - */ - read_ec_accel_data(st, *indio_dev->active_scan_mask, st->capture_data); - - iio_push_to_buffers_with_timestamp(indio_dev, (void *)st->capture_data, - iio_get_time_ns(indio_dev)); - - /* - * Tell the core we are done with this trigger and ready for the - * next one. - */ - iio_trigger_notify_done(indio_dev->trig); - - return IRQ_HANDLED; -} - -static char *cros_ec_accel_legacy_loc_strings[] = { - [MOTIONSENSE_LOC_BASE] = "base", - [MOTIONSENSE_LOC_LID] = "lid", - [MOTIONSENSE_LOC_MAX] = "unknown", -}; - -static ssize_t cros_ec_accel_legacy_loc(struct iio_dev *indio_dev, - uintptr_t private, - const struct iio_chan_spec *chan, - char *buf) -{ - struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev); - - return sprintf(buf, "%s\n", - cros_ec_accel_legacy_loc_strings[st->sensor_num + - MOTIONSENSE_LOC_BASE]); -} - -static ssize_t cros_ec_accel_legacy_id(struct iio_dev *indio_dev, - uintptr_t private, - const struct iio_chan_spec *chan, - char *buf) -{ - struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev); - - return sprintf(buf, "%d\n", st->sensor_num); -} - -static const struct iio_chan_spec_ext_info cros_ec_accel_legacy_ext_info[] = { - { - .name = "id", - .shared = IIO_SHARED_BY_ALL, - .read = cros_ec_accel_legacy_id, - }, - { - .name = "location", - .shared = IIO_SHARED_BY_ALL, - .read = cros_ec_accel_legacy_loc, - }, - { } -}; +#define CROS_EC_ACCEL_ROTATE_AXIS(_axis) \ + ((_axis) == CROS_EC_SENSOR_Z ? CROS_EC_SENSOR_Z : \ + ((_axis) == CROS_EC_SENSOR_X ? CROS_EC_SENSOR_Y : \ + CROS_EC_SENSOR_X)) #define CROS_EC_ACCEL_LEGACY_CHAN(_axis) \ { \ @@ -321,28 +143,28 @@ static const struct iio_chan_spec_ext_info cros_ec_accel_legacy_ext_info[] = { BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_CALIBBIAS), \ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE), \ - .ext_info = cros_ec_accel_legacy_ext_info, \ + .ext_info = cros_ec_sensors_ext_info, \ .scan_type = { \ .sign = 's', \ - .realbits = 16, \ - .storagebits = 16, \ + .realbits = CROS_EC_SENSOR_BITS, \ + .storagebits = CROS_EC_SENSOR_BITS, \ }, \ + .scan_index = CROS_EC_ACCEL_ROTATE_AXIS(_axis), \ } \ -static struct iio_chan_spec ec_accel_channels[] = { - CROS_EC_ACCEL_LEGACY_CHAN(X), - CROS_EC_ACCEL_LEGACY_CHAN(Y), - CROS_EC_ACCEL_LEGACY_CHAN(Z), - IIO_CHAN_SOFT_TIMESTAMP(MAX_AXIS) +static const struct iio_chan_spec cros_ec_accel_legacy_channels[] = { + CROS_EC_ACCEL_LEGACY_CHAN(CROS_EC_SENSOR_X), + CROS_EC_ACCEL_LEGACY_CHAN(CROS_EC_SENSOR_Y), + CROS_EC_ACCEL_LEGACY_CHAN(CROS_EC_SENSOR_Z), + IIO_CHAN_SOFT_TIMESTAMP(CROS_EC_SENSOR_MAX_AXIS) }; static int cros_ec_accel_legacy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct cros_ec_dev *ec = dev_get_drvdata(dev->parent); - struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev); struct iio_dev *indio_dev; - struct cros_ec_accel_legacy_state *state; + struct cros_ec_sensors_core_state *state; int ret; if (!ec || !ec->ec_dev) { @@ -350,46 +172,32 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev) return -EINVAL; } - if (!ec->ec_dev->cmd_readmem) { - dev_warn(&pdev->dev, "EC does not support direct reads.\n"); - return -EINVAL; - } - indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*state)); if (!indio_dev) return -ENOMEM; - platform_set_drvdata(pdev, indio_dev); - state = iio_priv(indio_dev); - state->ec = ec->ec_dev; - state->sensor_num = sensor_platform->sensor_num; - - indio_dev->dev.parent = dev; - indio_dev->name = pdev->name; - indio_dev->channels = ec_accel_channels; - /* - * Present the channel using HTML5 standard: - * need to invert X and Y and invert some lid axis. - */ - ec_accel_channels[X].scan_index = Y; - ec_accel_channels[Y].scan_index = X; - ec_accel_channels[Z].scan_index = Z; + ret = cros_ec_sensors_core_init(pdev, indio_dev, true); + if (ret) + return ret; - state->sign[Y] = 1; + indio_dev->info = &cros_ec_accel_legacy_info; + state = iio_priv(indio_dev); - if (state->sensor_num == MOTIONSENSE_LOC_LID) - state->sign[X] = state->sign[Z] = -1; + if (state->ec->cmd_readmem != NULL) + state->read_ec_sensors_data = cros_ec_sensors_read_lpc; else - state->sign[X] = state->sign[Z] = 1; - - indio_dev->num_channels = ARRAY_SIZE(ec_accel_channels); - indio_dev->dev.parent = &pdev->dev; - indio_dev->info = &cros_ec_accel_legacy_info; - indio_dev->modes = INDIO_DIRECT_MODE; + state->read_ec_sensors_data = cros_ec_accel_legacy_read_cmd; + + indio_dev->channels = cros_ec_accel_legacy_channels; + indio_dev->num_channels = ARRAY_SIZE(cros_ec_accel_legacy_channels); + /* The lid sensor needs to be presented inverted. */ + if (state->loc == MOTIONSENSE_LOC_LID) { + state->sign[CROS_EC_SENSOR_X] = -1; + state->sign[CROS_EC_SENSOR_Z] = -1; + } ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, - cros_ec_accel_legacy_capture, - NULL); + cros_ec_sensors_capture, NULL); if (ret) return ret; diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 6645771aa349accd7e4ed4bc363a60e17b5a9ae3..fee535d6e45b0c17f853b5300dfbb666a7028581 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1486,8 +1486,8 @@ static const struct acpi_device_id kx_acpi_match[] = { {"KIOX0008", KXCJ91008}, {"KIOX0009", KXTJ21009}, {"KIOX000A", KXCJ91008}, - {"KIOX010A", KXCJ91008}, /* KXCJ91008 inside the display of a 2-in-1 */ - {"KIOX020A", KXCJ91008}, + {"KIOX010A", KXCJ91008}, /* KXCJ91008 in the display of a yoga 2-in-1 */ + {"KIOX020A", KXCJ91008}, /* KXCJ91008 in the base of a yoga 2-in-1 */ {"KXTJ1009", KXTJ21009}, {"KXJ2109", KXTJ21009}, {"SMO8500", KXCJ91008}, diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index 637e6e676061f31820066f24ca4e4bda6d2f5b2f..3d5bea651923eb54de3345686ca45b1cc5d73400 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -424,7 +424,7 @@ static int mxc4005_probe(struct i2c_client *client, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &mxc4005_info; - ret = iio_triggered_buffer_setup(indio_dev, + ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, iio_pollfunc_store_time, mxc4005_trigger_handler, NULL); @@ -452,7 +452,7 @@ static int mxc4005_probe(struct i2c_client *client, if (ret) { dev_err(&client->dev, "failed to init threaded irq\n"); - goto err_buffer_cleanup; + return ret; } data->dready_trig->dev.parent = &client->dev; @@ -460,43 +460,16 @@ static int mxc4005_probe(struct i2c_client *client, iio_trigger_set_drvdata(data->dready_trig, indio_dev); indio_dev->trig = data->dready_trig; iio_trigger_get(indio_dev->trig); - ret = iio_trigger_register(data->dready_trig); + ret = devm_iio_trigger_register(&client->dev, + data->dready_trig); if (ret) { dev_err(&client->dev, "failed to register trigger\n"); - goto err_trigger_unregister; + return ret; } } - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(&client->dev, - "unable to register iio device %d\n", ret); - goto err_buffer_cleanup; - } - - return 0; - -err_trigger_unregister: - iio_trigger_unregister(data->dready_trig); -err_buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); - - return ret; -} - -static int mxc4005_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct mxc4005_data *data = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - iio_triggered_buffer_cleanup(indio_dev); - if (data->dready_trig) - iio_trigger_unregister(data->dready_trig); - - return 0; + return devm_iio_device_register(&client->dev, indio_dev); } static const struct acpi_device_id mxc4005_acpi_match[] = { @@ -517,7 +490,6 @@ static struct i2c_driver mxc4005_driver = { .acpi_match_table = ACPI_PTR(mxc4005_acpi_match), }, .probe = mxc4005_probe, - .remove = mxc4005_remove, .id_table = mxc4005_id, }; diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c index a923f90f6e803e9df51a653895df9615db1ffd63..66d768d971e1e6212219b219673399f9fe4eded0 100644 --- a/drivers/iio/accel/sca3000.c +++ b/drivers/iio/accel/sca3000.c @@ -111,7 +111,7 @@ /* Currently unsupported */ #define SCA3000_MD_CTRL_AND_Y BIT(3) #define SCA3000_MD_CTRL_AND_X BIT(4) -#define SAC3000_MD_CTRL_AND_Z BIT(5) +#define SCA3000_MD_CTRL_AND_Z BIT(5) /* * Some control registers of complex access methods requiring this register to diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index 979ab9679b996439ec8280fe06a7e85ebc5ebc83..af09943f38c9b39d38846c003989fe5111c62ccb 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -68,6 +68,7 @@ static const struct st_sensors_platform_data default_accel_pdata = { .drdy_int_pin = 1, }; +const struct st_sensor_settings *st_accel_get_settings(const char *name); int st_accel_common_probe(struct iio_dev *indio_dev); void st_accel_common_remove(struct iio_dev *indio_dev); diff --git a/drivers/iio/accel/st_accel_buffer.c b/drivers/iio/accel/st_accel_buffer.c index 0205c0167cdd6b9f33836001be51cfebd3024b0b..9f2b40474b8ec7fb9e36e382cd0beedd55a2299d 100644 --- a/drivers/iio/accel/st_accel_buffer.c +++ b/drivers/iio/accel/st_accel_buffer.c @@ -29,65 +29,51 @@ int st_accel_trig_set_state(struct iio_trigger *trig, bool state) return st_sensors_set_dataready_irq(indio_dev, state); } -static int st_accel_buffer_preenable(struct iio_dev *indio_dev) -{ - return st_sensors_set_enable(indio_dev, true); -} - static int st_accel_buffer_postenable(struct iio_dev *indio_dev) { int err; - struct st_sensor_data *adata = iio_priv(indio_dev); - - adata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (adata->buffer_data == NULL) { - err = -ENOMEM; - goto allocate_memory_error; - } err = iio_triggered_buffer_postenable(indio_dev); if (err < 0) - goto st_accel_buffer_postenable_error; + return err; err = st_sensors_set_axis_enable(indio_dev, - (u8)indio_dev->active_scan_mask[0]); + (u8)indio_dev->active_scan_mask[0]); if (err < 0) - goto st_sensors_set_axis_enable_error; + goto st_accel_buffer_predisable; - return err; + err = st_sensors_set_enable(indio_dev, true); + if (err < 0) + goto st_accel_buffer_enable_all_axis; -st_sensors_set_axis_enable_error: + return 0; + +st_accel_buffer_enable_all_axis: + st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS); +st_accel_buffer_predisable: iio_triggered_buffer_predisable(indio_dev); -st_accel_buffer_postenable_error: - kfree(adata->buffer_data); -allocate_memory_error: return err; } static int st_accel_buffer_predisable(struct iio_dev *indio_dev) { int err, err2; - struct st_sensor_data *adata = iio_priv(indio_dev); - - err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS); - if (err < 0) - goto st_accel_buffer_predisable_error; err = st_sensors_set_enable(indio_dev, false); if (err < 0) - goto st_accel_buffer_predisable_error; + goto st_accel_buffer_predisable; + + err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS); -st_accel_buffer_predisable_error: +st_accel_buffer_predisable: err2 = iio_triggered_buffer_predisable(indio_dev); if (!err) err = err2; - kfree(adata->buffer_data); return err; } static const struct iio_buffer_setup_ops st_accel_buffer_setup_ops = { - .preenable = &st_accel_buffer_preenable, .postenable = &st_accel_buffer_postenable, .predisable = &st_accel_buffer_predisable, }; diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index e02b799319790a682fe6d58fc0fcd38d0f365bbe..2e37f8a6d8cfc71087e5ccdf6ca4876bd8add706 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -1147,32 +1146,45 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev, #endif } +/* + * st_accel_get_settings() - get sensor settings from device name + * @name: device name buffer reference. + * + * Return: valid reference on success, NULL otherwise. + */ +const struct st_sensor_settings *st_accel_get_settings(const char *name) +{ + int index = st_sensors_get_settings_index(name, + st_accel_sensors_settings, + ARRAY_SIZE(st_accel_sensors_settings)); + if (index < 0) + return NULL; + + return &st_accel_sensors_settings[index]; +} +EXPORT_SYMBOL(st_accel_get_settings); + int st_accel_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *adata = iio_priv(indio_dev); struct st_sensors_platform_data *pdata = (struct st_sensors_platform_data *)adata->dev->platform_data; - int irq = adata->get_irq_data_ready(indio_dev); struct iio_chan_spec *channels; size_t channels_size; int err; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &accel_info; - mutex_init(&adata->tb.buf_lock); err = st_sensors_power_enable(indio_dev); if (err) return err; - err = st_sensors_check_device_support(indio_dev, - ARRAY_SIZE(st_accel_sensors_settings), - st_accel_sensors_settings); + err = st_sensors_verify_id(indio_dev); if (err < 0) goto st_accel_power_off; adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS; - adata->multiread_bit = adata->sensor_settings->multi_read_bit; indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; channels_size = indio_dev->num_channels * sizeof(struct iio_chan_spec); @@ -1204,7 +1216,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev) if (err < 0) goto st_accel_power_off; - if (irq > 0) { + if (adata->irq > 0) { err = st_sensors_allocate_trigger(indio_dev, ST_ACCEL_TRIGGER_OPS); if (err < 0) @@ -1221,7 +1233,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev) return 0; st_accel_device_register_error: - if (irq > 0) + if (adata->irq > 0) st_sensors_deallocate_trigger(indio_dev); st_accel_probe_trigger_error: st_accel_deallocate_ring(indio_dev); @@ -1239,7 +1251,7 @@ void st_accel_common_remove(struct iio_dev *indio_dev) st_sensors_power_disable(indio_dev); iio_device_unregister(indio_dev); - if (adata->get_irq_data_ready(indio_dev) > 0) + if (adata->irq > 0) st_sensors_deallocate_trigger(indio_dev); st_accel_deallocate_ring(indio_dev); diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index c3c8f2e73c2a39af7eff2f7b27c9b069ddaf3b00..50fa0fc32baa133f17a77ff7e1ca5a947fcd69ee 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -150,22 +150,33 @@ MODULE_DEVICE_TABLE(i2c, st_accel_id_table); static int st_accel_i2c_probe(struct i2c_client *client) { - struct iio_dev *indio_dev; + const struct st_sensor_settings *settings; struct st_sensor_data *adata; + struct iio_dev *indio_dev; const char *match; int ret; + match = device_get_match_data(&client->dev); + if (match) + strlcpy(client->name, match, sizeof(client->name)); + + settings = st_accel_get_settings(client->name); + if (!settings) { + dev_err(&client->dev, "device name %s not recognized.\n", + client->name); + return -ENODEV; + } + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adata)); if (!indio_dev) return -ENOMEM; adata = iio_priv(indio_dev); + adata->sensor_settings = (struct st_sensor_settings *)settings; - match = device_get_match_data(&client->dev); - if (match) - strlcpy(client->name, match, sizeof(client->name)); - - st_sensors_i2c_configure(indio_dev, client, adata); + ret = st_sensors_i2c_configure(indio_dev, client); + if (ret < 0) + return ret; ret = st_accel_common_probe(indio_dev); if (ret < 0) diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index 474742e35d9226271a397cf47cd632d6a9f4671b..8af7027d5598fe2dacb4ce7bd9ba737a8e9df256 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -102,19 +102,31 @@ MODULE_DEVICE_TABLE(of, st_accel_of_match); static int st_accel_spi_probe(struct spi_device *spi) { - struct iio_dev *indio_dev; + const struct st_sensor_settings *settings; struct st_sensor_data *adata; + struct iio_dev *indio_dev; int err; + st_sensors_of_name_probe(&spi->dev, st_accel_of_match, + spi->modalias, sizeof(spi->modalias)); + + settings = st_accel_get_settings(spi->modalias); + if (!settings) { + dev_err(&spi->dev, "device name %s not recognized.\n", + spi->modalias); + return -ENODEV; + } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adata)); if (!indio_dev) return -ENOMEM; adata = iio_priv(indio_dev); + adata->sensor_settings = (struct st_sensor_settings *)settings; - st_sensors_of_name_probe(&spi->dev, st_accel_of_match, - spi->modalias, sizeof(spi->modalias)); - st_sensors_spi_configure(indio_dev, spi, adata); + err = st_sensors_spi_configure(indio_dev, spi); + if (err < 0) + return err; err = st_accel_common_probe(indio_dev); if (err < 0) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 7e3286265a3845346d11b82d7d8c2b3fe72042fe..f0af3a42f53cf6d605b3c1ad413468bcdd9138dd 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -958,7 +958,7 @@ config TI_ADC161S626 config TI_ADS1015 tristate "Texas Instruments ADS1015 ADC" - depends on I2C && !SENSORS_ADS1015 + depends on I2C select REGMAP_I2C select IIO_BUFFER select IIO_TRIGGERED_BUFFER diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index aba0fd123a51bb714aa767235915639e1b777ee7..f5ba94c03a8d9d59cbd9eba8b841810bd0cf50e2 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -35,6 +35,11 @@ static const unsigned int ad7606_scale_avail[2] = { 152588, 305176 }; + +static const unsigned int ad7616_sw_scale_avail[3] = { + 76293, 152588, 305176 +}; + static const unsigned int ad7606_oversampling_avail[7] = { 1, 2, 4, 8, 16, 32, 64, }; @@ -55,6 +60,29 @@ static int ad7606_reset(struct ad7606_state *st) return -ENODEV; } +static int ad7606_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int writeval, + unsigned int *readval) +{ + struct ad7606_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + if (readval) { + ret = st->bops->reg_read(st, reg); + if (ret < 0) + goto err_unlock; + *readval = ret; + ret = 0; + } else { + ret = st->bops->reg_write(st, reg, writeval); + } +err_unlock: + mutex_unlock(&st->lock); + return ret; +} + static int ad7606_read_samples(struct ad7606_state *st) { unsigned int num = st->chip_info->num_channels; @@ -308,29 +336,6 @@ static const struct attribute_group ad7606_attribute_group_range = { .attrs = ad7606_attributes_range, }; -#define AD760X_CHANNEL(num, mask) { \ - .type = IIO_VOLTAGE, \ - .indexed = 1, \ - .channel = num, \ - .address = num, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ - .info_mask_shared_by_all = mask, \ - .scan_index = num, \ - .scan_type = { \ - .sign = 's', \ - .realbits = 16, \ - .storagebits = 16, \ - .endianness = IIO_CPU, \ - }, \ -} - -#define AD7605_CHANNEL(num) \ - AD760X_CHANNEL(num, 0) - -#define AD7606_CHANNEL(num) \ - AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)) - static const struct iio_chan_spec ad7605_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(4), AD7605_CHANNEL(0), @@ -405,12 +410,19 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { .oversampling_avail = ad7606_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), }, + [ID_AD7606B] = { + .channels = ad7606_channels, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + }, [ID_AD7616] = { .channels = ad7616_channels, .num_channels = 17, .oversampling_avail = ad7616_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail), .os_req_reset = true, + .init_delay_ms = 15, }, }; @@ -519,6 +531,14 @@ static const struct iio_info ad7606_info_os_and_range = { .validate_trigger = &ad7606_validate_trigger, }; +static const struct iio_info ad7606_info_os_range_and_debug = { + .read_raw = &ad7606_read_raw, + .write_raw = &ad7606_write_raw, + .debugfs_reg_access = &ad7606_reg_access, + .attrs = &ad7606_attribute_group_os_and_range, + .validate_trigger = &ad7606_validate_trigger, +}; + static const struct iio_info ad7606_info_os = { .read_raw = &ad7606_read_raw, .write_raw = &ad7606_write_raw, @@ -617,35 +637,29 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, if (ret) dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); + /* AD7616 requires al least 15ms to reconfigure after a reset */ + if (st->chip_info->init_delay_ms) { + if (msleep_interruptible(st->chip_info->init_delay_ms)) + return -ERESTARTSYS; + } + st->write_scale = ad7606_write_scale_hw; st->write_os = ad7606_write_os_hw; - if (st->chip_info->sw_mode_config) + if (st->bops->sw_mode_config) st->sw_mode_en = device_property_present(st->dev, "adi,sw-mode"); if (st->sw_mode_en) { + /* Scale of 0.076293 is only available in sw mode */ + st->scale_avail = ad7616_sw_scale_avail; + st->num_scales = ARRAY_SIZE(ad7616_sw_scale_avail); + /* After reset, in software mode, ±10 V is set by default */ memset32(st->range, 2, ARRAY_SIZE(st->range)); - indio_dev->info = &ad7606_info_os_and_range; - - /* - * In software mode, the range gpio has no longer its function. - * Instead, the scale can be configured individually for each - * channel from the range registers. - */ - if (st->chip_info->write_scale_sw) - st->write_scale = st->chip_info->write_scale_sw; - - /* - * In software mode, the oversampling is no longer configured - * with GPIO pins. Instead, the oversampling can be configured - * in configuratiion register. - */ - if (st->chip_info->write_os_sw) - st->write_os = st->chip_info->write_os_sw; - - ret = st->chip_info->sw_mode_config(indio_dev); + indio_dev->info = &ad7606_info_os_range_and_debug; + + ret = st->bops->sw_mode_config(indio_dev); if (ret < 0) return ret; } diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h index d8a509c2c428c2ebc07b1329ac043b8897bb01e4..9350ef1f63b59e21f55add24233dea0647b12fe2 100644 --- a/drivers/iio/adc/ad7606.h +++ b/drivers/iio/adc/ad7606.h @@ -8,6 +8,36 @@ #ifndef IIO_ADC_AD7606_H_ #define IIO_ADC_AD7606_H_ +#define AD760X_CHANNEL(num, mask_sep, mask_type, mask_all) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = num, \ + .address = num, \ + .info_mask_separate = mask_sep, \ + .info_mask_shared_by_type = mask_type, \ + .info_mask_shared_by_all = mask_all, \ + .scan_index = num, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ +} + +#define AD7605_CHANNEL(num) \ + AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW), \ + BIT(IIO_CHAN_INFO_SCALE), 0) + +#define AD7606_CHANNEL(num) \ + AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW), \ + BIT(IIO_CHAN_INFO_SCALE), \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)) + +#define AD7616_CHANNEL(num) \ + AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),\ + 0, BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)) + /** * struct ad7606_chip_info - chip specific information * @channels: channel specification @@ -16,12 +46,8 @@ * oversampling ratios. * @oversampling_num number of elements stored in oversampling_avail array * @os_req_reset some devices require a reset to update oversampling - * @write_scale_sw pointer to the function which writes the scale via spi - in software mode - * @write_os_sw pointer to the function which writes the os via spi - in software mode - * @sw_mode_config: pointer to a function which configured the device - * for software mode + * @init_delay_ms required delay in miliseconds for initialization + * after a restart */ struct ad7606_chip_info { const struct iio_chan_spec *channels; @@ -29,9 +55,7 @@ struct ad7606_chip_info { const unsigned int *oversampling_avail; unsigned int oversampling_num; bool os_req_reset; - int (*write_scale_sw)(struct iio_dev *indio_dev, int ch, int val); - int (*write_os_sw)(struct iio_dev *indio_dev, int val); - int (*sw_mode_config)(struct iio_dev *indio_dev); + unsigned long init_delay_ms; }; /** @@ -63,6 +87,7 @@ struct ad7606_chip_info { * @complete completion to indicate end of conversion * @trig The IIO trigger associated with the device. * @data buffer for reading data from the device + * @d16 be16 buffer for reading data from the device */ struct ad7606_state { struct device *dev; @@ -96,15 +121,32 @@ struct ad7606_state { * 16 * 16-bit samples + 64-bit timestamp */ unsigned short data[20] ____cacheline_aligned; + __be16 d16[2]; }; /** * struct ad7606_bus_ops - driver bus operations * @read_block function pointer for reading blocks of data + * @sw_mode_config: pointer to a function which configured the device + * for software mode + * @reg_read function pointer for reading spi register + * @reg_write function pointer for writing spi register + * @write_mask function pointer for write spi register with mask + * @rd_wr_cmd pointer to the function which calculates the spi address */ struct ad7606_bus_ops { /* more methods added in future? */ int (*read_block)(struct device *dev, int num, void *data); + int (*sw_mode_config)(struct iio_dev *indio_dev); + int (*reg_read)(struct ad7606_state *st, unsigned int addr); + int (*reg_write)(struct ad7606_state *st, + unsigned int addr, + unsigned int val); + int (*write_mask)(struct ad7606_state *st, + unsigned int addr, + unsigned long mask, + unsigned int val); + u16 (*rd_wr_cmd)(int addr, char isWriteOp); }; int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, @@ -116,6 +158,7 @@ enum ad7606_supported_device_ids { ID_AD7606_8, ID_AD7606_6, ID_AD7606_4, + ID_AD7606B, ID_AD7616, }; diff --git a/drivers/iio/adc/ad7606_par.c b/drivers/iio/adc/ad7606_par.c index 1b08028facde8c25552a99a65489ae0671784abb..f732b3ac78785444de9ed38b09ad4bd6a5b87b91 100644 --- a/drivers/iio/adc/ad7606_par.c +++ b/drivers/iio/adc/ad7606_par.c @@ -53,10 +53,8 @@ static int ad7606_par_probe(struct platform_device *pdev) int irq; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq: %d\n", irq); + if (irq < 0) return irq; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); addr = devm_ioremap_resource(&pdev->dev, res); diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c index b7faef69a58f2f96009d5d857460cc06a225066b..29945ad07dca89bcb364c60e4ce1d2687cbeabb1 100644 --- a/drivers/iio/adc/ad7606_spi.c +++ b/drivers/iio/adc/ad7606_spi.c @@ -15,6 +15,91 @@ #define MAX_SPI_FREQ_HZ 23500000 /* VDRIVE above 4.75 V */ +#define AD7616_CONFIGURATION_REGISTER 0x02 +#define AD7616_OS_MASK GENMASK(4, 2) +#define AD7616_BURST_MODE BIT(6) +#define AD7616_SEQEN_MODE BIT(5) +#define AD7616_RANGE_CH_A_ADDR_OFF 0x04 +#define AD7616_RANGE_CH_B_ADDR_OFF 0x06 +/* + * Range of channels from a group are stored in 2 registers. + * 0, 1, 2, 3 in a register followed by 4, 5, 6, 7 in second register. + * For channels from second group(8-15) the order is the same, only with + * an offset of 2 for register address. + */ +#define AD7616_RANGE_CH_ADDR(ch) ((ch) >> 2) +/* The range of the channel is stored in 2 bits */ +#define AD7616_RANGE_CH_MSK(ch) (0b11 << (((ch) & 0b11) * 2)) +#define AD7616_RANGE_CH_MODE(ch, mode) ((mode) << ((((ch) & 0b11)) * 2)) + +#define AD7606_CONFIGURATION_REGISTER 0x02 +#define AD7606_SINGLE_DOUT 0x00 + +/* + * Range for AD7606B channels are stored in registers starting with address 0x3. + * Each register stores range for 2 channels(4 bits per channel). + */ +#define AD7606_RANGE_CH_MSK(ch) (GENMASK(3, 0) << (4 * ((ch) & 0x1))) +#define AD7606_RANGE_CH_MODE(ch, mode) \ + ((GENMASK(3, 0) & mode) << (4 * ((ch) & 0x1))) +#define AD7606_RANGE_CH_ADDR(ch) (0x03 + ((ch) >> 1)) +#define AD7606_OS_MODE 0x08 + +static const struct iio_chan_spec ad7616_sw_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(16), + AD7616_CHANNEL(0), + AD7616_CHANNEL(1), + AD7616_CHANNEL(2), + AD7616_CHANNEL(3), + AD7616_CHANNEL(4), + AD7616_CHANNEL(5), + AD7616_CHANNEL(6), + AD7616_CHANNEL(7), + AD7616_CHANNEL(8), + AD7616_CHANNEL(9), + AD7616_CHANNEL(10), + AD7616_CHANNEL(11), + AD7616_CHANNEL(12), + AD7616_CHANNEL(13), + AD7616_CHANNEL(14), + AD7616_CHANNEL(15), +}; + +static const struct iio_chan_spec ad7606b_sw_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(8), + AD7616_CHANNEL(0), + AD7616_CHANNEL(1), + AD7616_CHANNEL(2), + AD7616_CHANNEL(3), + AD7616_CHANNEL(4), + AD7616_CHANNEL(5), + AD7616_CHANNEL(6), + AD7616_CHANNEL(7), +}; + +static const unsigned int ad7606B_oversampling_avail[9] = { + 1, 2, 4, 8, 16, 32, 64, 128, 256 +}; + +static u16 ad7616_spi_rd_wr_cmd(int addr, char isWriteOp) +{ + /* + * The address of register consist of one w/r bit + * 6 bits of address followed by one reserved bit. + */ + return ((addr & 0x7F) << 1) | ((isWriteOp & 0x1) << 7); +} + +static u16 ad7606B_spi_rd_wr_cmd(int addr, char is_write_op) +{ + /* + * The address of register consists of one bit which + * specifies a read command placed in bit 6, followed by + * 6 bits of address. + */ + return (addr & 0x3F) | (((~is_write_op) & 0x1) << 6); +} + static int ad7606_spi_read_block(struct device *dev, int count, void *buf) { @@ -35,17 +120,210 @@ static int ad7606_spi_read_block(struct device *dev, return 0; } +static int ad7606_spi_reg_read(struct ad7606_state *st, unsigned int addr) +{ + struct spi_device *spi = to_spi_device(st->dev); + struct spi_transfer t[] = { + { + .tx_buf = &st->d16[0], + .len = 2, + .cs_change = 0, + }, { + .rx_buf = &st->d16[1], + .len = 2, + }, + }; + int ret; + + st->d16[0] = cpu_to_be16(st->bops->rd_wr_cmd(addr, 0) << 8); + + ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t)); + if (ret < 0) + return ret; + + return be16_to_cpu(st->d16[1]); +} + +static int ad7606_spi_reg_write(struct ad7606_state *st, + unsigned int addr, + unsigned int val) +{ + struct spi_device *spi = to_spi_device(st->dev); + + st->d16[0] = cpu_to_be16((st->bops->rd_wr_cmd(addr, 1) << 8) | + (val & 0x1FF)); + + return spi_write(spi, &st->d16[0], sizeof(st->d16[0])); +} + +static int ad7606_spi_write_mask(struct ad7606_state *st, + unsigned int addr, + unsigned long mask, + unsigned int val) +{ + int readval; + + readval = st->bops->reg_read(st, addr); + if (readval < 0) + return readval; + + readval &= ~mask; + readval |= val; + + return st->bops->reg_write(st, addr, readval); +} + +static int ad7616_write_scale_sw(struct iio_dev *indio_dev, int ch, int val) +{ + struct ad7606_state *st = iio_priv(indio_dev); + unsigned int ch_addr, mode, ch_index; + + + /* + * Ad7616 has 16 channels divided in group A and group B. + * The range of channels from A are stored in registers with address 4 + * while channels from B are stored in register with address 6. + * The last bit from channels determines if it is from group A or B + * because the order of channels in iio is 0A, 0B, 1A, 1B... + */ + ch_index = ch >> 1; + + ch_addr = AD7616_RANGE_CH_ADDR(ch_index); + + if ((ch & 0x1) == 0) /* channel A */ + ch_addr += AD7616_RANGE_CH_A_ADDR_OFF; + else /* channel B */ + ch_addr += AD7616_RANGE_CH_B_ADDR_OFF; + + /* 0b01 for 2.5v, 0b10 for 5v and 0b11 for 10v */ + mode = AD7616_RANGE_CH_MODE(ch_index, ((val + 1) & 0b11)); + return st->bops->write_mask(st, ch_addr, AD7616_RANGE_CH_MSK(ch_index), + mode); +} + +static int ad7616_write_os_sw(struct iio_dev *indio_dev, int val) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + return st->bops->write_mask(st, AD7616_CONFIGURATION_REGISTER, + AD7616_OS_MASK, val << 2); +} + +static int ad7606_write_scale_sw(struct iio_dev *indio_dev, int ch, int val) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + return ad7606_spi_write_mask(st, + AD7606_RANGE_CH_ADDR(ch), + AD7606_RANGE_CH_MSK(ch), + AD7606_RANGE_CH_MODE(ch, val)); +} + +static int ad7606_write_os_sw(struct iio_dev *indio_dev, int val) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + return ad7606_spi_reg_write(st, AD7606_OS_MODE, val); +} + +static int ad7616_sw_mode_config(struct iio_dev *indio_dev) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + /* + * Scale can be configured individually for each channel + * in software mode. + */ + indio_dev->channels = ad7616_sw_channels; + + st->write_scale = ad7616_write_scale_sw; + st->write_os = &ad7616_write_os_sw; + + /* Activate Burst mode and SEQEN MODE */ + return st->bops->write_mask(st, + AD7616_CONFIGURATION_REGISTER, + AD7616_BURST_MODE | AD7616_SEQEN_MODE, + AD7616_BURST_MODE | AD7616_SEQEN_MODE); +} + +static int ad7606B_sw_mode_config(struct iio_dev *indio_dev) +{ + struct ad7606_state *st = iio_priv(indio_dev); + unsigned long os[3] = {1}; + + /* + * Software mode is enabled when all three oversampling + * pins are set to high. If oversampling gpios are defined + * in the device tree, then they need to be set to high, + * otherwise, they must be hardwired to VDD + */ + if (st->gpio_os) { + gpiod_set_array_value(ARRAY_SIZE(os), + st->gpio_os->desc, st->gpio_os->info, os); + } + /* OS of 128 and 256 are available only in software mode */ + st->oversampling_avail = ad7606B_oversampling_avail; + st->num_os_ratios = ARRAY_SIZE(ad7606B_oversampling_avail); + + st->write_scale = ad7606_write_scale_sw; + st->write_os = &ad7606_write_os_sw; + + /* Configure device spi to output on a single channel */ + st->bops->reg_write(st, + AD7606_CONFIGURATION_REGISTER, + AD7606_SINGLE_DOUT); + + /* + * Scale can be configured individually for each channel + * in software mode. + */ + indio_dev->channels = ad7606b_sw_channels; + + return 0; +} + static const struct ad7606_bus_ops ad7606_spi_bops = { .read_block = ad7606_spi_read_block, }; +static const struct ad7606_bus_ops ad7616_spi_bops = { + .read_block = ad7606_spi_read_block, + .reg_read = ad7606_spi_reg_read, + .reg_write = ad7606_spi_reg_write, + .write_mask = ad7606_spi_write_mask, + .rd_wr_cmd = ad7616_spi_rd_wr_cmd, + .sw_mode_config = ad7616_sw_mode_config, +}; + +static const struct ad7606_bus_ops ad7606B_spi_bops = { + .read_block = ad7606_spi_read_block, + .reg_read = ad7606_spi_reg_read, + .reg_write = ad7606_spi_reg_write, + .write_mask = ad7606_spi_write_mask, + .rd_wr_cmd = ad7606B_spi_rd_wr_cmd, + .sw_mode_config = ad7606B_sw_mode_config, +}; + static int ad7606_spi_probe(struct spi_device *spi) { const struct spi_device_id *id = spi_get_device_id(spi); + const struct ad7606_bus_ops *bops; + + switch (id->driver_data) { + case ID_AD7616: + bops = &ad7616_spi_bops; + break; + case ID_AD7606B: + bops = &ad7606B_spi_bops; + break; + default: + bops = &ad7606_spi_bops; + break; + } return ad7606_probe(&spi->dev, spi->irq, NULL, id->name, id->driver_data, - &ad7606_spi_bops); + bops); } static const struct spi_device_id ad7606_id_table[] = { @@ -53,6 +331,7 @@ static const struct spi_device_id ad7606_id_table[] = { { "ad7606-4", ID_AD7606_4 }, { "ad7606-6", ID_AD7606_6 }, { "ad7606-8", ID_AD7606_8 }, + { "ad7606b", ID_AD7606B }, { "ad7616", ID_AD7616 }, {} }; @@ -63,6 +342,7 @@ static const struct of_device_id ad7606_of_match[] = { { .compatible = "adi,ad7606-4" }, { .compatible = "adi,ad7606-6" }, { .compatible = "adi,ad7606-8" }, + { .compatible = "adi,ad7606b" }, { .compatible = "adi,ad7616" }, { }, }; diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 32f1c4a33b2085495bcc1f01909aa76a8fc4a329..abe99856c823ab6250bbfdedea447dcb337389d3 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -1179,10 +1179,8 @@ static int at91_adc_probe(struct platform_device *pdev) idev->info = &at91_adc_info; st->irq = platform_get_irq(pdev, 0); - if (st->irq < 0) { - dev_err(&pdev->dev, "No IRQ ID is designated\n"); + if (st->irq < 0) return -ENODEV; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c index 31d51bcc5f2cd8fb13e432bfe321965a369d1faf..adc9cf7a075d200702cc34665e271a0e174d241a 100644 --- a/drivers/iio/adc/axp288_adc.c +++ b/drivers/iio/adc/axp288_adc.c @@ -225,10 +225,8 @@ static int axp288_adc_probe(struct platform_device *pdev) info = iio_priv(indio_dev); info->irq = platform_get_irq(pdev, 0); - if (info->irq < 0) { - dev_err(&pdev->dev, "no irq resource?\n"); + if (info->irq < 0) return info->irq; - } platform_set_drvdata(pdev, indio_dev); info->regmap = axp20x->regmap; /* diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c index c46c0aa15376c934578bd0ef40df015f2639a289..646ebdc0a8b4cbf552edefaaec017db75f61f416 100644 --- a/drivers/iio/adc/bcm_iproc_adc.c +++ b/drivers/iio/adc/bcm_iproc_adc.c @@ -540,11 +540,8 @@ static int iproc_adc_probe(struct platform_device *pdev) } adc_priv->irqno = platform_get_irq(pdev, 0); - if (adc_priv->irqno <= 0) { - dev_err(&pdev->dev, "platform_get_irq failed\n"); - ret = -ENODEV; - return ret; - } + if (adc_priv->irqno <= 0) + return -ENODEV; ret = regmap_update_bits(adc_priv->regmap, IPROC_REGCTL2, IPROC_ADC_AUXIN_SCAN_ENA, 0); diff --git a/drivers/iio/adc/da9150-gpadc.c b/drivers/iio/adc/da9150-gpadc.c index 3544339961010dfb2b6efc2ed492a905c2fb4a57..ae8bcc32f63d94be10396f75a075e6535cc9dd73 100644 --- a/drivers/iio/adc/da9150-gpadc.c +++ b/drivers/iio/adc/da9150-gpadc.c @@ -337,10 +337,8 @@ static int da9150_gpadc_probe(struct platform_device *pdev) init_completion(&gpadc->complete); irq = platform_get_irq_byname(pdev, "GPADC"); - if (irq < 0) { - dev_err(dev, "Failed to get IRQ: %d\n", irq); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(dev, irq, NULL, da9150_gpadc_irq, IRQF_ONESHOT, "GPADC", gpadc); diff --git a/drivers/iio/adc/envelope-detector.c b/drivers/iio/adc/envelope-detector.c index 2f2b563c116223ae824f9f58b6c86ef5eff628c9..28f3d6758eb5f51a03dc246d20077afe2ee3a1e4 100644 --- a/drivers/iio/adc/envelope-detector.c +++ b/drivers/iio/adc/envelope-detector.c @@ -357,11 +357,8 @@ static int envelope_detector_probe(struct platform_device *pdev) } env->comp_irq = platform_get_irq_byname(pdev, "comp"); - if (env->comp_irq < 0) { - if (env->comp_irq != -EPROBE_DEFER) - dev_err(dev, "failed to get compare interrupt\n"); + if (env->comp_irq < 0) return env->comp_irq; - } ret = devm_request_irq(dev, env->comp_irq, envelope_detector_comp_isr, 0, "envelope-detector", env); diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index d4c3ece216792ac922f67c702110071c0c4f0595..42a3ced11fbdc5e8562331d557afab2bb73330c0 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -805,10 +805,8 @@ static int exynos_adc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq resource?\n"); + if (irq < 0) return irq; - } info->irq = irq; irq = platform_get_irq(pdev, 1); diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index df19ecae52f74a89977132b7d83030b47f42760d..fa71489195c64b8a0480bb3f6d4cff202c69b67a 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -340,7 +340,6 @@ static int mx25_gcq_probe(struct platform_device *pdev) priv->irq = platform_get_irq(pdev, 0); if (priv->irq <= 0) { - dev_err(dev, "Failed to get IRQ\n"); ret = priv->irq; if (!ret) ret = -ENXIO; diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index 35951c47004eb762cb3f48405ee3c5c200e5983f..8da45bf36d36054b4234f2358b0f91d7591176ee 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -456,6 +456,11 @@ static irqreturn_t hi8435_trigger_handler(int irq, void *private) return IRQ_HANDLED; } +static void hi8435_triggered_event_cleanup(void *data) +{ + iio_triggered_event_cleanup(data); +} + static int hi8435_probe(struct spi_device *spi) { struct iio_dev *idev; @@ -477,7 +482,7 @@ static int hi8435_probe(struct spi_device *spi) hi8435_writeb(priv, HI8435_CTRL_REG, 0); } else { udelay(5); - gpiod_set_value(reset_gpio, 1); + gpiod_set_value_cansleep(reset_gpio, 1); } spi_set_drvdata(spi, idev); @@ -513,27 +518,13 @@ static int hi8435_probe(struct spi_device *spi) if (ret) return ret; - ret = iio_device_register(idev); - if (ret < 0) { - dev_err(&spi->dev, "unable to register device\n"); - goto unregister_triggered_event; - } - - return 0; - -unregister_triggered_event: - iio_triggered_event_cleanup(idev); - return ret; -} - -static int hi8435_remove(struct spi_device *spi) -{ - struct iio_dev *idev = spi_get_drvdata(spi); - - iio_device_unregister(idev); - iio_triggered_event_cleanup(idev); + ret = devm_add_action_or_reset(&spi->dev, + hi8435_triggered_event_cleanup, + idev); + if (ret) + return ret; - return 0; + return devm_iio_device_register(&spi->dev, idev); } static const struct of_device_id hi8435_dt_ids[] = { @@ -554,7 +545,6 @@ static struct spi_driver hi8435_driver = { .of_match_table = of_match_ptr(hi8435_dt_ids), }, .probe = hi8435_probe, - .remove = hi8435_remove, .id_table = hi8435_id, }; module_spi_driver(hi8435_driver); diff --git a/drivers/iio/adc/imx7d_adc.c b/drivers/iio/adc/imx7d_adc.c index 26a7bbe4d534df3fb237bbf8597850dd4643966e..2a2fbf788e9567a78a67032744c9de2bcd7aa30c 100644 --- a/drivers/iio/adc/imx7d_adc.c +++ b/drivers/iio/adc/imx7d_adc.c @@ -492,10 +492,8 @@ static int imx7d_adc_probe(struct platform_device *pdev) return PTR_ERR(info->regs); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "No irq resource?\n"); + if (irq < 0) return irq; - } info->clk = devm_clk_get(dev, "adc"); if (IS_ERR(info->clk)) { diff --git a/drivers/iio/adc/lpc32xx_adc.c b/drivers/iio/adc/lpc32xx_adc.c index a6ee1c3a9064b3ca67faf38249b935c745adb2f6..b896f7ff4572eb539a94f44b11ac57be25d66d8a 100644 --- a/drivers/iio/adc/lpc32xx_adc.c +++ b/drivers/iio/adc/lpc32xx_adc.c @@ -172,10 +172,8 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_err(&pdev->dev, "failed getting interrupt resource\n"); + if (irq <= 0) return -ENXIO; - } retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0, LPC32XXAD_NAME, st); diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c index da84adfdb819224def1ef9db2b24b94f265b3841..214883458582583c1c68949b6cca19ef39a29a82 100644 --- a/drivers/iio/adc/max1027.c +++ b/drivers/iio/adc/max1027.c @@ -427,8 +427,9 @@ static int max1027_probe(struct spi_device *spi) return -ENOMEM; } - ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, - &max1027_trigger_handler, NULL); + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + &iio_pollfunc_store_time, + &max1027_trigger_handler, NULL); if (ret < 0) { dev_err(&indio_dev->dev, "Failed to setup buffer\n"); return ret; @@ -439,7 +440,7 @@ static int max1027_probe(struct spi_device *spi) if (st->trig == NULL) { ret = -ENOMEM; dev_err(&indio_dev->dev, "Failed to allocate iio trigger\n"); - goto fail_trigger_alloc; + return ret; } st->trig->ops = &max1027_trigger_ops; @@ -454,7 +455,7 @@ static int max1027_probe(struct spi_device *spi) spi->dev.driver->name, st->trig); if (ret < 0) { dev_err(&indio_dev->dev, "Failed to allocate IRQ.\n"); - goto fail_dev_register; + return ret; } /* Disable averaging */ @@ -462,34 +463,10 @@ static int max1027_probe(struct spi_device *spi) ret = spi_write(st->spi, &st->reg, 1); if (ret < 0) { dev_err(&indio_dev->dev, "Failed to configure averaging register\n"); - goto fail_dev_register; - } - - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(&indio_dev->dev, "Failed to register iio device\n"); - goto fail_dev_register; + return ret; } - return 0; - -fail_dev_register: -fail_trigger_alloc: - iio_triggered_buffer_cleanup(indio_dev); - - return ret; -} - -static int max1027_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - - pr_debug("%s: remove(spi = 0x%p)\n", __func__, spi); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - - return 0; + return devm_iio_device_register(&spi->dev, indio_dev); } static struct spi_driver max1027_driver = { @@ -498,7 +475,6 @@ static struct spi_driver max1027_driver = { .of_match_table = of_match_ptr(max1027_adc_dt_ids), }, .probe = max1027_probe, - .remove = max1027_remove, .id_table = max1027_id, }; module_spi_driver(max1027_driver); diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c index 193b3b81de4d31775fde5bc7b0ea801c330073dd..910f3585fa54b022a756660f693d70baf100b4af 100644 --- a/drivers/iio/adc/npcm_adc.c +++ b/drivers/iio/adc/npcm_adc.c @@ -225,7 +225,6 @@ static int npcm_adc_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq <= 0) { - dev_err(dev, "failed getting interrupt resource\n"); ret = -EINVAL; goto err_disable_clk; } diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c index dd8299831e09a4bcd4f869b70cf0fa5b60d667e6..582ba047c4a67404a71903cfff94af4e90f01b7b 100644 --- a/drivers/iio/adc/rockchip_saradc.c +++ b/drivers/iio/adc/rockchip_saradc.c @@ -244,10 +244,8 @@ static int rockchip_saradc_probe(struct platform_device *pdev) init_completion(&info->completion); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq resource?\n"); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr, 0, dev_name(&pdev->dev), info); diff --git a/drivers/iio/adc/sc27xx_adc.c b/drivers/iio/adc/sc27xx_adc.c index f7f7a18904b45bb7f368843a4dcae60f0ade30a9..a6c046575ec3aec1cf855350e3b197df38e459b6 100644 --- a/drivers/iio/adc/sc27xx_adc.c +++ b/drivers/iio/adc/sc27xx_adc.c @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -46,14 +45,18 @@ /* Bits definitions for SC27XX_ADC_INT_CLR registers */ #define SC27XX_ADC_IRQ_CLR BIT(0) +/* Bits definitions for SC27XX_ADC_INT_RAW registers */ +#define SC27XX_ADC_IRQ_RAW BIT(0) + /* Mask definition for SC27XX_ADC_DATA register */ #define SC27XX_ADC_DATA_MASK GENMASK(11, 0) /* Timeout (ms) for the trylock of hardware spinlocks */ #define SC27XX_ADC_HWLOCK_TIMEOUT 5000 -/* Timeout (ms) for ADC data conversion according to ADC datasheet */ -#define SC27XX_ADC_RDY_TIMEOUT 100 +/* Timeout (us) for ADC data conversion according to ADC datasheet */ +#define SC27XX_ADC_RDY_TIMEOUT 1000000 +#define SC27XX_ADC_POLL_RAW_STATUS 500 /* Maximum ADC channel number */ #define SC27XX_ADC_CHANNEL_MAX 32 @@ -72,10 +75,8 @@ struct sc27xx_adc_data { * subsystems which will access the unique ADC controller. */ struct hwspinlock *hwlock; - struct completion completion; int channel_scale[SC27XX_ADC_CHANNEL_MAX]; u32 base; - int value; int irq; }; @@ -188,9 +189,7 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel, int scale, int *val) { int ret; - u32 tmp; - - reinit_completion(&data->completion); + u32 tmp, value, status; ret = hwspin_lock_timeout_raw(data->hwlock, SC27XX_ADC_HWLOCK_TIMEOUT); if (ret) { @@ -203,6 +202,11 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel, if (ret) goto unlock_adc; + ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR, + SC27XX_ADC_IRQ_CLR, SC27XX_ADC_IRQ_CLR); + if (ret) + goto disable_adc; + /* Configure the channel id and scale */ tmp = (scale << SC27XX_ADC_SCALE_SHIFT) & SC27XX_ADC_SCALE_MASK; tmp |= channel & SC27XX_ADC_CHN_ID_MASK; @@ -226,15 +230,22 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel, if (ret) goto disable_adc; - ret = wait_for_completion_timeout(&data->completion, - msecs_to_jiffies(SC27XX_ADC_RDY_TIMEOUT)); - if (!ret) { - dev_err(data->dev, "read ADC data timeout\n"); - ret = -ETIMEDOUT; - } else { - ret = 0; + ret = regmap_read_poll_timeout(data->regmap, + data->base + SC27XX_ADC_INT_RAW, + status, (status & SC27XX_ADC_IRQ_RAW), + SC27XX_ADC_POLL_RAW_STATUS, + SC27XX_ADC_RDY_TIMEOUT); + if (ret) { + dev_err(data->dev, "read adc timeout, status = 0x%x\n", status); + goto disable_adc; } + ret = regmap_read(data->regmap, data->base + SC27XX_ADC_DATA, &value); + if (ret) + goto disable_adc; + + value &= SC27XX_ADC_DATA_MASK; + disable_adc: regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL, SC27XX_ADC_EN, 0); @@ -242,32 +253,11 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel, hwspin_unlock_raw(data->hwlock); if (!ret) - *val = data->value; + *val = value; return ret; } -static irqreturn_t sc27xx_adc_isr(int irq, void *dev_id) -{ - struct sc27xx_adc_data *data = dev_id; - int ret; - - ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR, - SC27XX_ADC_IRQ_CLR, SC27XX_ADC_IRQ_CLR); - if (ret) - return IRQ_RETVAL(ret); - - ret = regmap_read(data->regmap, data->base + SC27XX_ADC_DATA, - &data->value); - if (ret) - return IRQ_RETVAL(ret); - - data->value &= SC27XX_ADC_DATA_MASK; - complete(&data->completion); - - return IRQ_HANDLED; -} - static void sc27xx_adc_volt_ratio(struct sc27xx_adc_data *data, int channel, int scale, u32 *div_numerator, u32 *div_denominator) @@ -454,11 +444,6 @@ static int sc27xx_adc_enable(struct sc27xx_adc_data *data) if (ret) goto disable_adc; - ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_EN, - SC27XX_ADC_IRQ_EN, SC27XX_ADC_IRQ_EN); - if (ret) - goto disable_clk; - /* ADC channel scales' calibration from nvmem device */ ret = sc27xx_adc_scale_calibration(data, true); if (ret) @@ -484,9 +469,6 @@ static void sc27xx_adc_disable(void *_data) { struct sc27xx_adc_data *data = _data; - regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_EN, - SC27XX_ADC_IRQ_EN, 0); - /* Disable ADC work clock and controller clock */ regmap_update_bits(data->regmap, SC27XX_ARM_CLK_EN, SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0); @@ -504,88 +486,76 @@ static void sc27xx_adc_free_hwlock(void *_data) static int sc27xx_adc_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct sc27xx_adc_data *sc27xx_data; struct iio_dev *indio_dev; int ret; - indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*sc27xx_data)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*sc27xx_data)); if (!indio_dev) return -ENOMEM; sc27xx_data = iio_priv(indio_dev); - sc27xx_data->regmap = dev_get_regmap(pdev->dev.parent, NULL); + sc27xx_data->regmap = dev_get_regmap(dev->parent, NULL); if (!sc27xx_data->regmap) { - dev_err(&pdev->dev, "failed to get ADC regmap\n"); + dev_err(dev, "failed to get ADC regmap\n"); return -ENODEV; } ret = of_property_read_u32(np, "reg", &sc27xx_data->base); if (ret) { - dev_err(&pdev->dev, "failed to get ADC base address\n"); + dev_err(dev, "failed to get ADC base address\n"); return ret; } sc27xx_data->irq = platform_get_irq(pdev, 0); - if (sc27xx_data->irq < 0) { - dev_err(&pdev->dev, "failed to get ADC irq number\n"); + if (sc27xx_data->irq < 0) return sc27xx_data->irq; - } ret = of_hwspin_lock_get_id(np, 0); if (ret < 0) { - dev_err(&pdev->dev, "failed to get hwspinlock id\n"); + dev_err(dev, "failed to get hwspinlock id\n"); return ret; } sc27xx_data->hwlock = hwspin_lock_request_specific(ret); if (!sc27xx_data->hwlock) { - dev_err(&pdev->dev, "failed to request hwspinlock\n"); + dev_err(dev, "failed to request hwspinlock\n"); return -ENXIO; } - ret = devm_add_action(&pdev->dev, sc27xx_adc_free_hwlock, + ret = devm_add_action_or_reset(dev, sc27xx_adc_free_hwlock, sc27xx_data->hwlock); if (ret) { - sc27xx_adc_free_hwlock(sc27xx_data->hwlock); - dev_err(&pdev->dev, "failed to add hwspinlock action\n"); + dev_err(dev, "failed to add hwspinlock action\n"); return ret; } - init_completion(&sc27xx_data->completion); - sc27xx_data->dev = &pdev->dev; + sc27xx_data->dev = dev; ret = sc27xx_adc_enable(sc27xx_data); if (ret) { - dev_err(&pdev->dev, "failed to enable ADC module\n"); - return ret; - } - - ret = devm_add_action(&pdev->dev, sc27xx_adc_disable, sc27xx_data); - if (ret) { - sc27xx_adc_disable(sc27xx_data); - dev_err(&pdev->dev, "failed to add ADC disable action\n"); + dev_err(dev, "failed to enable ADC module\n"); return ret; } - ret = devm_request_threaded_irq(&pdev->dev, sc27xx_data->irq, NULL, - sc27xx_adc_isr, IRQF_ONESHOT, - pdev->name, sc27xx_data); + ret = devm_add_action_or_reset(dev, sc27xx_adc_disable, sc27xx_data); if (ret) { - dev_err(&pdev->dev, "failed to request ADC irq\n"); + dev_err(dev, "failed to add ADC disable action\n"); return ret; } - indio_dev->dev.parent = &pdev->dev; - indio_dev->name = dev_name(&pdev->dev); + indio_dev->dev.parent = dev; + indio_dev->name = dev_name(dev); indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &sc27xx_info; indio_dev->channels = sc27xx_channels; indio_dev->num_channels = ARRAY_SIZE(sc27xx_channels); - ret = devm_iio_device_register(&pdev->dev, indio_dev); + ret = devm_iio_device_register(dev, indio_dev); if (ret) - dev_err(&pdev->dev, "could not register iio (ADC)"); + dev_err(dev, "could not register iio (ADC)"); return ret; } diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c index a33d0a4cc08835aee785bfb75a40defd5b2642ea..592b97c464daca2ea9a1a97a6119f0ec8ce7fed0 100644 --- a/drivers/iio/adc/spear_adc.c +++ b/drivers/iio/adc/spear_adc.c @@ -301,7 +301,6 @@ static int spear_adc_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq <= 0) { - dev_err(dev, "failed getting interrupt resource\n"); ret = -EINVAL; goto errout2; } diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index 1f7ce5186dfcec7541c4b5462f0db7aa3a8ed8d4..9b85fefc0a963f382a0365f6aefec33770a187e1 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -14,9 +14,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -51,6 +53,17 @@ #define STM32_ADC_CORE_SLEEP_DELAY_MS 2000 +/* SYSCFG registers */ +#define STM32MP1_SYSCFG_PMCSETR 0x04 +#define STM32MP1_SYSCFG_PMCCLRR 0x44 + +/* SYSCFG bit fields */ +#define STM32MP1_SYSCFG_ANASWVDD_MASK BIT(9) + +/* SYSCFG capability flags */ +#define HAS_VBOOSTER BIT(0) +#define HAS_ANASWVDD BIT(1) + /** * stm32_adc_common_regs - stm32 common registers, compatible dependent data * @csr: common status register offset @@ -74,11 +87,13 @@ struct stm32_adc_priv; * @regs: common registers for all instances * @clk_sel: clock selection routine * @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet) + * @has_syscfg: SYSCFG capability flags */ struct stm32_adc_priv_cfg { const struct stm32_adc_common_regs *regs; int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *); u32 max_clk_rate_hz; + unsigned int has_syscfg; }; /** @@ -87,22 +102,32 @@ struct stm32_adc_priv_cfg { * @domain: irq domain reference * @aclk: clock reference for the analog circuitry * @bclk: bus clock common for all ADCs, depends on part used + * @booster: booster supply reference + * @vdd: vdd supply reference * @vdda: vdda analog supply reference * @vref: regulator reference + * @vdd_uv: vdd supply voltage (microvolts) + * @vdda_uv: vdda supply voltage (microvolts) * @cfg: compatible configuration data * @common: common data for all ADC instances * @ccr_bak: backup CCR in low power mode + * @syscfg: reference to syscon, system control registers */ struct stm32_adc_priv { int irq[STM32_ADC_MAX_ADCS]; struct irq_domain *domain; struct clk *aclk; struct clk *bclk; + struct regulator *booster; + struct regulator *vdd; struct regulator *vdda; struct regulator *vref; + int vdd_uv; + int vdda_uv; const struct stm32_adc_priv_cfg *cfg; struct stm32_adc_common common; u32 ccr_bak; + struct regmap *syscfg; }; static struct stm32_adc_priv *to_stm32_adc_priv(struct stm32_adc_common *com) @@ -349,7 +374,6 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, */ if (i && priv->irq[i] == -ENXIO) continue; - dev_err(&pdev->dev, "failed to get irq\n"); return priv->irq[i]; } @@ -390,6 +414,82 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, } } +static int stm32_adc_core_switches_supply_en(struct stm32_adc_priv *priv, + struct device *dev) +{ + int ret; + + /* + * On STM32H7 and STM32MP1, the ADC inputs are multiplexed with analog + * switches (via PCSEL) which have reduced performances when their + * supply is below 2.7V (vdda by default): + * - Voltage booster can be used, to get full ADC performances + * (increases power consumption). + * - Vdd can be used to supply them, if above 2.7V (STM32MP1 only). + * + * Recommended settings for ANASWVDD and EN_BOOSTER: + * - vdda < 2.7V but vdd > 2.7V: ANASWVDD = 1, EN_BOOSTER = 0 (stm32mp1) + * - vdda < 2.7V and vdd < 2.7V: ANASWVDD = 0, EN_BOOSTER = 1 + * - vdda >= 2.7V: ANASWVDD = 0, EN_BOOSTER = 0 (default) + */ + if (priv->vdda_uv < 2700000) { + if (priv->syscfg && priv->vdd_uv > 2700000) { + ret = regulator_enable(priv->vdd); + if (ret < 0) { + dev_err(dev, "vdd enable failed %d\n", ret); + return ret; + } + + ret = regmap_write(priv->syscfg, + STM32MP1_SYSCFG_PMCSETR, + STM32MP1_SYSCFG_ANASWVDD_MASK); + if (ret < 0) { + regulator_disable(priv->vdd); + dev_err(dev, "vdd select failed, %d\n", ret); + return ret; + } + dev_dbg(dev, "analog switches supplied by vdd\n"); + + return 0; + } + + if (priv->booster) { + /* + * This is optional, as this is a trade-off between + * analog performance and power consumption. + */ + ret = regulator_enable(priv->booster); + if (ret < 0) { + dev_err(dev, "booster enable failed %d\n", ret); + return ret; + } + dev_dbg(dev, "analog switches supplied by booster\n"); + + return 0; + } + } + + /* Fallback using vdda (default), nothing to do */ + dev_dbg(dev, "analog switches supplied by vdda (%d uV)\n", + priv->vdda_uv); + + return 0; +} + +static void stm32_adc_core_switches_supply_dis(struct stm32_adc_priv *priv) +{ + if (priv->vdda_uv < 2700000) { + if (priv->syscfg && priv->vdd_uv > 2700000) { + regmap_write(priv->syscfg, STM32MP1_SYSCFG_PMCCLRR, + STM32MP1_SYSCFG_ANASWVDD_MASK); + regulator_disable(priv->vdd); + return; + } + if (priv->booster) + regulator_disable(priv->booster); + } +} + static int stm32_adc_core_hw_start(struct device *dev) { struct stm32_adc_common *common = dev_get_drvdata(dev); @@ -402,10 +502,21 @@ static int stm32_adc_core_hw_start(struct device *dev) return ret; } + ret = regulator_get_voltage(priv->vdda); + if (ret < 0) { + dev_err(dev, "vdda get voltage failed, %d\n", ret); + goto err_vdda_disable; + } + priv->vdda_uv = ret; + + ret = stm32_adc_core_switches_supply_en(priv, dev); + if (ret < 0) + goto err_vdda_disable; + ret = regulator_enable(priv->vref); if (ret < 0) { dev_err(dev, "vref enable failed\n"); - goto err_vdda_disable; + goto err_switches_dis; } if (priv->bclk) { @@ -433,6 +544,8 @@ static int stm32_adc_core_hw_start(struct device *dev) clk_disable_unprepare(priv->bclk); err_regulator_disable: regulator_disable(priv->vref); +err_switches_dis: + stm32_adc_core_switches_supply_dis(priv); err_vdda_disable: regulator_disable(priv->vdda); @@ -451,9 +564,80 @@ static void stm32_adc_core_hw_stop(struct device *dev) if (priv->bclk) clk_disable_unprepare(priv->bclk); regulator_disable(priv->vref); + stm32_adc_core_switches_supply_dis(priv); regulator_disable(priv->vdda); } +static int stm32_adc_core_switches_probe(struct device *dev, + struct stm32_adc_priv *priv) +{ + struct device_node *np = dev->of_node; + int ret; + + /* Analog switches supply can be controlled by syscfg (optional) */ + priv->syscfg = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); + if (IS_ERR(priv->syscfg)) { + ret = PTR_ERR(priv->syscfg); + if (ret != -ENODEV) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "Can't probe syscfg: %d\n", ret); + return ret; + } + priv->syscfg = NULL; + } + + /* Booster can be used to supply analog switches (optional) */ + if (priv->cfg->has_syscfg & HAS_VBOOSTER && + of_property_read_bool(np, "booster-supply")) { + priv->booster = devm_regulator_get_optional(dev, "booster"); + if (IS_ERR(priv->booster)) { + ret = PTR_ERR(priv->booster); + if (ret != -ENODEV) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "can't get booster %d\n", + ret); + return ret; + } + priv->booster = NULL; + } + } + + /* Vdd can be used to supply analog switches (optional) */ + if (priv->cfg->has_syscfg & HAS_ANASWVDD && + of_property_read_bool(np, "vdd-supply")) { + priv->vdd = devm_regulator_get_optional(dev, "vdd"); + if (IS_ERR(priv->vdd)) { + ret = PTR_ERR(priv->vdd); + if (ret != -ENODEV) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "can't get vdd %d\n", ret); + return ret; + } + priv->vdd = NULL; + } + } + + if (priv->vdd) { + ret = regulator_enable(priv->vdd); + if (ret < 0) { + dev_err(dev, "vdd enable failed %d\n", ret); + return ret; + } + + ret = regulator_get_voltage(priv->vdd); + if (ret < 0) { + dev_err(dev, "vdd get voltage failed %d\n", ret); + regulator_disable(priv->vdd); + return ret; + } + priv->vdd_uv = ret; + + regulator_disable(priv->vdd); + } + + return 0; +} + static int stm32_adc_probe(struct platform_device *pdev) { struct stm32_adc_priv *priv; @@ -514,6 +698,10 @@ static int stm32_adc_probe(struct platform_device *pdev) priv->bclk = NULL; } + ret = stm32_adc_core_switches_probe(dev, priv); + if (ret) + return ret; + pm_runtime_get_noresume(dev); pm_runtime_set_active(dev); pm_runtime_set_autosuspend_delay(dev, STM32_ADC_CORE_SLEEP_DELAY_MS); @@ -611,12 +799,14 @@ static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = { .regs = &stm32h7_adc_common_regs, .clk_sel = stm32h7_adc_clk_sel, .max_clk_rate_hz = 36000000, + .has_syscfg = HAS_VBOOSTER, }; static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = { .regs = &stm32h7_adc_common_regs, .clk_sel = stm32h7_adc_clk_sel, .max_clk_rate_hz = 40000000, + .has_syscfg = HAS_VBOOSTER | HAS_ANASWVDD, }; static const struct of_device_id stm32_adc_of_match[] = { diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 205e1699f954fced46bea0e886003a23a0cd0bca..6a7dd08b1e0b1fde1fbf361135228b969b7597fe 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -1919,10 +1919,8 @@ static int stm32_adc_probe(struct platform_device *pdev) } adc->irq = platform_get_irq(pdev, 0); - if (adc->irq < 0) { - dev_err(&pdev->dev, "failed to get irq\n"); + if (adc->irq < 0) return adc->irq; - } ret = devm_request_irq(&pdev->dev, adc->irq, stm32_adc_isr, 0, pdev->name, adc); diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index ee1e0569d0e166b5ba90156a3120a7d699d921e6..e493242c266ef77d4ab854672716a2ffc45a170a 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -1601,11 +1601,8 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) * So IRQ associated to filter instance 0 is dedicated to the Filter 0. */ irq = platform_get_irq(pdev, 0); - if (irq < 0) { - if (irq != -EPROBE_DEFER) - dev_err(dev, "Failed to get IRQ: %d\n", irq); + if (irq < 0) return irq; - } ret = devm_request_irq(dev, irq, stm32_dfsdm_irq, 0, pdev->name, adc); diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c index f13c6248a662f9bca7110bb6abc5cf84e9191ad4..176e1cb4abb1f3251f7d295a08e27c7260ee8f30 100644 --- a/drivers/iio/adc/sun4i-gpadc-iio.c +++ b/drivers/iio/adc/sun4i-gpadc-iio.c @@ -460,10 +460,8 @@ static int sun4i_irq_init(struct platform_device *pdev, const char *name, atomic_set(atomic, 1); ret = platform_get_irq_byname(pdev, name); - if (ret < 0) { - dev_err(&pdev->dev, "no %s interrupt registered\n", name); + if (ret < 0) return ret; - } ret = regmap_irq_get_virq(mfd_dev->regmap_irqc, ret); if (ret < 0) { diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index 2fa6ec83bb13475fa3e076b96a4f844ce4763a09..f24148bd15de42cc9f3fafbf1e9876a9af0195a5 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -905,10 +905,8 @@ static int twl6030_gpadc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "failed to get irq\n"); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(dev, irq, NULL, twl6030_gpadc_irq_handler, diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 41d3621c4787e0e8579a22a19d44b681b2128ee9..98b30475bbc6acf67ad8ac9429cdd35798a6c17e 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -821,10 +821,8 @@ static int vf610_adc_probe(struct platform_device *pdev) return PTR_ERR(info->regs); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq resource?\n"); + if (irq < 0) return irq; - } ret = devm_request_irq(info->dev, irq, vf610_adc_isr, 0, 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 17af4e0fd5f8c45bd2cabd0633385625f4187a7e..6a4919cd83c39ef182096a46e8c9e969cf40ee73 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c @@ -63,10 +63,35 @@ static int cros_ec_sensors_read(struct iio_dev *indio_dev, /* Save values */ for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++) - st->core.calib[i] = + st->core.calib[i].offset = st->core.resp->sensor_offset.offset[i]; ret = IIO_VAL_INT; - *val = st->core.calib[idx]; + *val = st->core.calib[idx].offset; + break; + case IIO_CHAN_INFO_CALIBSCALE: + st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_SCALE; + st->core.param.sensor_offset.flags = 0; + + ret = cros_ec_motion_send_host_cmd(&st->core, 0); + if (ret == -EPROTO) { + /* Reading calibscale is not supported on older EC. */ + *val = 1; + *val2 = 0; + ret = IIO_VAL_INT_PLUS_MICRO; + break; + } else if (ret) { + break; + } + + /* Save values */ + for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++) + st->core.calib[i].scale = + st->core.resp->sensor_scale.scale[i]; + + *val = st->core.calib[idx].scale >> 15; + *val2 = ((st->core.calib[idx].scale & 0x7FFF) * 1000000LL) / + MOTION_SENSE_DEFAULT_SCALE; + ret = IIO_VAL_INT_PLUS_MICRO; break; case IIO_CHAN_INFO_SCALE: st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE; @@ -134,7 +159,7 @@ static int cros_ec_sensors_write(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_CALIBBIAS: - st->core.calib[idx] = val; + st->core.calib[idx].offset = val; /* Send to EC for each axis, even if not complete */ st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET; @@ -142,10 +167,25 @@ static int cros_ec_sensors_write(struct iio_dev *indio_dev, MOTION_SENSE_SET_OFFSET; for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++) st->core.param.sensor_offset.offset[i] = - st->core.calib[i]; + st->core.calib[i].offset; st->core.param.sensor_offset.temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; + ret = cros_ec_motion_send_host_cmd(&st->core, 0); + break; + case IIO_CHAN_INFO_CALIBSCALE: + st->core.calib[idx].scale = val; + /* Send to EC for each axis, even if not complete */ + + st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_SCALE; + st->core.param.sensor_offset.flags = + MOTION_SENSE_SET_OFFSET; + for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++) + st->core.param.sensor_scale.scale[i] = + st->core.calib[i].scale; + st->core.param.sensor_scale.temp = + EC_MOTION_SENSE_INVALID_CALIB_TEMP; + ret = cros_ec_motion_send_host_cmd(&st->core, 0); break; case IIO_CHAN_INFO_SCALE: @@ -175,6 +215,7 @@ static int cros_ec_sensors_write(struct iio_dev *indio_dev, static const struct iio_info ec_sensors_info = { .read_raw = &cros_ec_sensors_read, .write_raw = &cros_ec_sensors_write, + .read_avail = &cros_ec_sensors_core_read_avail, }; static int cros_ec_sensors_probe(struct platform_device *pdev) @@ -206,11 +247,14 @@ static int cros_ec_sensors_probe(struct platform_device *pdev) /* Common part */ channel->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_CALIBBIAS); + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_CALIBSCALE); channel->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_FREQUENCY) | BIT(IIO_CHAN_INFO_SAMP_FREQ); + channel->info_mask_shared_by_all_available = + BIT(IIO_CHAN_INFO_SAMP_FREQ); channel->scan_type.realbits = CROS_EC_SENSOR_BITS; channel->scan_type.storagebits = CROS_EC_SENSOR_BITS; channel->scan_index = i; 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 130362ca421bb2b188abcaf8d80c79c882944224..d44ae126f45782189ba1c46fa5801dca8781702c 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 @@ -25,6 +25,62 @@ static char *cros_ec_loc[] = { [MOTIONSENSE_LOC_MAX] = "unknown", }; +static int cros_ec_get_host_cmd_version_mask(struct cros_ec_device *ec_dev, + u16 cmd_offset, u16 cmd, u32 *mask) +{ + int ret; + struct { + struct cros_ec_command msg; + union { + struct ec_params_get_cmd_versions params; + struct ec_response_get_cmd_versions resp; + }; + } __packed buf = { + .msg = { + .command = EC_CMD_GET_CMD_VERSIONS + cmd_offset, + .insize = sizeof(struct ec_response_get_cmd_versions), + .outsize = sizeof(struct ec_params_get_cmd_versions) + }, + .params = {.cmd = cmd} + }; + + ret = cros_ec_cmd_xfer_status(ec_dev, &buf.msg); + if (ret >= 0) + *mask = buf.resp.version_mask; + return ret; +} + +static void get_default_min_max_freq(enum motionsensor_type type, + u32 *min_freq, + u32 *max_freq) +{ + switch (type) { + case MOTIONSENSE_TYPE_ACCEL: + case MOTIONSENSE_TYPE_GYRO: + *min_freq = 12500; + *max_freq = 100000; + break; + case MOTIONSENSE_TYPE_MAG: + *min_freq = 5000; + *max_freq = 25000; + break; + case MOTIONSENSE_TYPE_PROX: + case MOTIONSENSE_TYPE_LIGHT: + *min_freq = 100; + *max_freq = 50000; + break; + case MOTIONSENSE_TYPE_BARO: + *min_freq = 250; + *max_freq = 20000; + break; + case MOTIONSENSE_TYPE_ACTIVITY: + default: + *min_freq = 0; + *max_freq = 0; + break; + } +} + int cros_ec_sensors_core_init(struct platform_device *pdev, struct iio_dev *indio_dev, bool physical_device) @@ -33,6 +89,8 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, struct cros_ec_sensors_core_state *state = iio_priv(indio_dev); struct cros_ec_dev *ec = dev_get_drvdata(pdev->dev.parent); struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev); + u32 ver_mask; + int ret, i; platform_set_drvdata(pdev, indio_dev); @@ -47,8 +105,15 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, mutex_init(&state->cmd_lock); + ret = cros_ec_get_host_cmd_version_mask(state->ec, + ec->cmd_offset, + EC_CMD_MOTION_SENSE_CMD, + &ver_mask); + if (ret < 0) + return ret; + /* Set up the host command structure. */ - state->msg->version = 2; + state->msg->version = fls(ver_mask) - 1; state->msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset; state->msg->outsize = sizeof(struct ec_params_motion_sense); @@ -60,12 +125,32 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, state->param.cmd = MOTIONSENSE_CMD_INFO; state->param.info.sensor_num = sensor_platform->sensor_num; - if (cros_ec_motion_send_host_cmd(state, 0)) { + ret = cros_ec_motion_send_host_cmd(state, 0); + if (ret) { dev_warn(dev, "Can not access sensor info\n"); - return -EIO; + return ret; } state->type = state->resp->info.type; state->loc = state->resp->info.location; + + /* Set sign vector, only used for backward compatibility. */ + memset(state->sign, 1, CROS_EC_SENSOR_MAX_AXIS); + + for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++) + state->calib[i].scale = MOTION_SENSE_DEFAULT_SCALE; + + /* 0 is a correct value used to stop the device */ + state->frequencies[0] = 0; + if (state->msg->version < 3) { + get_default_min_max_freq(state->resp->info.type, + &state->frequencies[1], + &state->frequencies[2]); + } else { + state->frequencies[1] = + state->resp->info_3.min_frequency; + state->frequencies[2] = + state->resp->info_3.max_frequency; + } } return 0; @@ -86,7 +171,7 @@ int cros_ec_motion_send_host_cmd(struct cros_ec_sensors_core_state *state, ret = cros_ec_cmd_xfer_status(state->ec, state->msg); if (ret < 0) - return -EIO; + return ret; if (ret && state->resp != (struct ec_response_motion_sense *)state->msg->data) @@ -118,7 +203,7 @@ static ssize_t cros_ec_sensors_calibrate(struct iio_dev *indio_dev, } else { /* Save values */ for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++) - st->calib[i] = st->resp->perform_calib.offset[i]; + st->calib[i].offset = st->resp->perform_calib.offset[i]; } mutex_unlock(&st->cmd_lock); @@ -268,6 +353,7 @@ static int cros_ec_sensors_read_data_unsafe(struct iio_dev *indio_dev, if (ret < 0) return ret; + *data *= st->sign[i]; data++; } @@ -396,7 +482,7 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { - int ret = IIO_VAL_INT; + int ret; switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: @@ -404,22 +490,27 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st, st->param.ec_rate.data = EC_MOTION_SENSE_NO_VALUE; - if (cros_ec_motion_send_host_cmd(st, 0)) - ret = -EIO; - else - *val = st->resp->ec_rate.ret; + ret = cros_ec_motion_send_host_cmd(st, 0); + if (ret) + break; + + *val = st->resp->ec_rate.ret; + ret = IIO_VAL_INT; break; case IIO_CHAN_INFO_FREQUENCY: st->param.cmd = MOTIONSENSE_CMD_SENSOR_ODR; st->param.sensor_odr.data = EC_MOTION_SENSE_NO_VALUE; - if (cros_ec_motion_send_host_cmd(st, 0)) - ret = -EIO; - else - *val = st->resp->sensor_odr.ret; + ret = cros_ec_motion_send_host_cmd(st, 0); + if (ret) + break; + + *val = st->resp->sensor_odr.ret; + ret = IIO_VAL_INT; break; default: + ret = -EINVAL; break; } @@ -427,11 +518,32 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st, } EXPORT_SYMBOL_GPL(cros_ec_sensors_core_read); +int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, + int *type, + int *length, + long mask) +{ + struct cros_ec_sensors_core_state *state = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *length = ARRAY_SIZE(state->frequencies); + *vals = (const int *)&state->frequencies; + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(cros_ec_sensors_core_read_avail); + int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, struct iio_chan_spec const *chan, int val, int val2, long mask) { - int ret = 0; + int ret; switch (mask) { case IIO_CHAN_INFO_FREQUENCY: @@ -441,17 +553,16 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, /* Always roundup, so caller gets at least what it asks for. */ st->param.sensor_odr.roundup = 1; - if (cros_ec_motion_send_host_cmd(st, 0)) - ret = -EIO; + ret = cros_ec_motion_send_host_cmd(st, 0); break; case IIO_CHAN_INFO_SAMP_FREQ: st->param.cmd = MOTIONSENSE_CMD_EC_RATE; st->param.ec_rate.data = val; - if (cros_ec_motion_send_host_cmd(st, 0)) - ret = -EIO; - else - st->curr_sampl_freq = val; + ret = cros_ec_motion_send_host_cmd(st, 0); + if (ret) + break; + st->curr_sampl_freq = val; break; default: ret = -EINVAL; diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index a8a3fe428d8d64b6fed7e00fe3ac21591951d1a0..442ff787f7afab97e73ba94abad9464fc0b74c96 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -8,11 +8,16 @@ #include #include #include +#include #include +#include + #include #include #include +#define HZ_PER_MHZ 1000000L + static struct { u32 usage_id; int unit; /* 0 for default others from HID sensor spec */ @@ -68,16 +73,6 @@ static struct { {HID_USAGE_SENSOR_HUMIDITY, 0, 1000, 0}, }; -static int pow_10(unsigned power) -{ - int i; - int ret = 1; - for (i = 0; i < power; ++i) - ret = ret * 10; - - return ret; -} - static void simple_div(int dividend, int divisor, int *whole, int *micro_frac) { @@ -96,14 +91,16 @@ static void simple_div(int dividend, int divisor, int *whole, rem *= 10; exp++; } - *micro_frac = (rem / divisor) * pow_10(6-exp); + *micro_frac = (rem / divisor) * int_pow(10, 6 - exp); } } static void split_micro_fraction(unsigned int no, int exp, int *val1, int *val2) { - *val1 = no/pow_10(exp); - *val2 = no%pow_10(exp) * pow_10(6-exp); + int divisor = int_pow(10, exp); + + *val1 = no / divisor; + *val2 = no % divisor * int_pow(10, 6 - exp); } /* @@ -125,7 +122,7 @@ static void convert_from_vtf_format(u32 value, int size, int exp, } exp = hid_sensor_convert_exponent(exp); if (exp >= 0) { - *val1 = sign * value * pow_10(exp); + *val1 = sign * value * int_pow(10, exp); *val2 = 0; } else { split_micro_fraction(value, -exp, val1, val2); @@ -138,6 +135,7 @@ static void convert_from_vtf_format(u32 value, int size, int exp, static u32 convert_to_vtf_format(int size, int exp, int val1, int val2) { + int divisor; u32 value; int sign = 1; @@ -145,10 +143,13 @@ static u32 convert_to_vtf_format(int size, int exp, int val1, int val2) sign = -1; exp = hid_sensor_convert_exponent(exp); if (exp < 0) { - value = abs(val1) * pow_10(-exp); - value += abs(val2) / pow_10(6+exp); - } else - value = abs(val1) / pow_10(exp); + divisor = int_pow(10, 6 + exp); + value = abs(val1) * int_pow(10, -exp); + value += abs(val2) / divisor; + } else { + divisor = int_pow(10, exp); + value = abs(val1) / divisor; + } if (sign < 0) value = ((1LL << (size * 8)) - value); @@ -211,12 +212,12 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, if (val1 < 0 || val2 < 0) return -EINVAL; - value = val1 * pow_10(6) + val2; + value = val1 * HZ_PER_MHZ + val2; if (value) { if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND) - value = pow_10(9)/value; + value = NSEC_PER_SEC / value; else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND) - value = pow_10(6)/value; + value = USEC_PER_SEC / value; else value = 0; } @@ -305,40 +306,44 @@ EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value); static void adjust_exponent_nano(int *val0, int *val1, int scale0, int scale1, int exp) { + int divisor; int i; int x; int res; int rem; if (exp > 0) { - *val0 = scale0 * pow_10(exp); + *val0 = scale0 * int_pow(10, exp); res = 0; if (exp > 9) { *val1 = 0; return; } for (i = 0; i < exp; ++i) { - x = scale1 / pow_10(8 - i); - res += (pow_10(exp - 1 - i) * x); - scale1 = scale1 % pow_10(8 - i); + divisor = int_pow(10, 8 - i); + x = scale1 / divisor; + res += int_pow(10, exp - 1 - i) * x; + scale1 = scale1 % divisor; } *val0 += res; - *val1 = scale1 * pow_10(exp); + *val1 = scale1 * int_pow(10, exp); } else if (exp < 0) { exp = abs(exp); if (exp > 9) { *val0 = *val1 = 0; return; } - *val0 = scale0 / pow_10(exp); - rem = scale0 % pow_10(exp); + divisor = int_pow(10, exp); + *val0 = scale0 / divisor; + rem = scale0 % divisor; res = 0; for (i = 0; i < (9 - exp); ++i) { - x = scale1 / pow_10(8 - i); - res += (pow_10(8 - exp - i) * x); - scale1 = scale1 % pow_10(8 - i); + divisor = int_pow(10, 8 - i); + x = scale1 / divisor; + res += int_pow(10, 8 - exp - i) * x; + scale1 = scale1 % divisor; } - *val1 = rem * pow_10(9 - exp) + res; + *val1 = rem * int_pow(10, 9 - exp) + res; } else { *val0 = scale0; *val1 = scale1; diff --git a/drivers/iio/common/st_sensors/Kconfig b/drivers/iio/common/st_sensors/Kconfig index 91b98e152d758600b7518e91eef6f4d76acd6310..9364ec7a811fd0769afc00327c38b90b69ed8f48 100644 --- a/drivers/iio/common/st_sensors/Kconfig +++ b/drivers/iio/common/st_sensors/Kconfig @@ -5,9 +5,11 @@ config IIO_ST_SENSORS_I2C tristate + select REGMAP_I2C config IIO_ST_SENSORS_SPI tristate + select REGMAP_SPI config IIO_ST_SENSORS_CORE tristate diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index 4a68669dc555d10d088f97750d2b32c421661a03..eee30130ae23871219c1558c933e70f22227ad34 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -17,15 +17,16 @@ #include #include #include +#include #include static int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) { - int i; struct st_sensor_data *sdata = iio_priv(indio_dev); unsigned int num_data_channels = sdata->num_data_channels; + int i; for_each_set_bit(i, indio_dev->active_scan_mask, num_data_channels) { const struct iio_chan_spec *channel = &indio_dev->channels[i]; @@ -36,11 +37,8 @@ static int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) channel->scan_type.storagebits >> 3; buf = PTR_ALIGN(buf, storage_bytes); - if (sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, - channel->address, - bytes_to_read, buf, - sdata->multiread_bit) < - bytes_to_read) + if (regmap_bulk_read(sdata->regmap, channel->address, + buf, bytes_to_read) < 0) return -EIO; /* Advance the buffer pointer */ diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 8b22dc24148219fd4d7e0afdeb27afa8eeeb4db4..4a3064fb6cd9c350bc7ce25d113b14d72433ea9f 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -28,19 +29,10 @@ static inline u32 st_sensors_get_unaligned_le24(const u8 *p) int st_sensors_write_data_with_mask(struct iio_dev *indio_dev, u8 reg_addr, u8 mask, u8 data) { - int err; - u8 new_data; struct st_sensor_data *sdata = iio_priv(indio_dev); - err = sdata->tf->read_byte(&sdata->tb, sdata->dev, reg_addr, &new_data); - if (err < 0) - goto st_sensors_write_data_with_mask_error; - - new_data = ((new_data & (~mask)) | ((data << __ffs(mask)) & mask)); - err = sdata->tf->write_byte(&sdata->tb, sdata->dev, reg_addr, new_data); - -st_sensors_write_data_with_mask_error: - return err; + return regmap_update_bits(sdata->regmap, + reg_addr, mask, data << __ffs(mask)); } int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev, @@ -48,19 +40,15 @@ int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev, unsigned *readval) { struct st_sensor_data *sdata = iio_priv(indio_dev); - u8 readdata; int err; if (!readval) - return sdata->tf->write_byte(&sdata->tb, sdata->dev, - (u8)reg, (u8)writeval); + return regmap_write(sdata->regmap, reg, writeval); - err = sdata->tf->read_byte(&sdata->tb, sdata->dev, (u8)reg, &readdata); + err = regmap_read(sdata->regmap, reg, readval); if (err < 0) return err; - *readval = (unsigned)readdata; - return 0; } EXPORT_SYMBOL(st_sensors_debugfs_reg_access); @@ -545,7 +533,7 @@ int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale) EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain); static int st_sensors_read_axis_data(struct iio_dev *indio_dev, - struct iio_chan_spec const *ch, int *data) + struct iio_chan_spec const *ch, int *data) { int err; u8 *outdata; @@ -554,13 +542,12 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev, byte_for_channel = DIV_ROUND_UP(ch->scan_type.realbits + ch->scan_type.shift, 8); - outdata = kmalloc(byte_for_channel, GFP_KERNEL); + outdata = kmalloc(byte_for_channel, GFP_DMA | GFP_KERNEL); if (!outdata) return -ENOMEM; - err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, - ch->address, byte_for_channel, - outdata, sdata->multiread_bit); + err = regmap_bulk_read(sdata->regmap, ch->address, + outdata, byte_for_channel); if (err < 0) goto st_sensors_free_memory; @@ -608,69 +595,55 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev, } EXPORT_SYMBOL(st_sensors_read_info_raw); -static int st_sensors_init_interface_mode(struct iio_dev *indio_dev, - const struct st_sensor_settings *sensor_settings) +/* + * st_sensors_get_settings_index() - get index of the sensor settings for a + * specific device from list of settings + * @name: device name buffer reference. + * @list: sensor settings list. + * @list_length: length of sensor settings list. + * + * Return: non negative number on success (valid index), + * negative error code otherwise. + */ +int st_sensors_get_settings_index(const char *name, + const struct st_sensor_settings *list, + const int list_length) { - struct st_sensor_data *sdata = iio_priv(indio_dev); - struct device_node *np = sdata->dev->of_node; - struct st_sensors_platform_data *pdata; + int i, n; - pdata = (struct st_sensors_platform_data *)sdata->dev->platform_data; - if (((np && of_property_read_bool(np, "spi-3wire")) || - (pdata && pdata->spi_3wire)) && sensor_settings->sim.addr) { - int err; - - err = sdata->tf->write_byte(&sdata->tb, sdata->dev, - sensor_settings->sim.addr, - sensor_settings->sim.value); - if (err < 0) { - dev_err(&indio_dev->dev, - "failed to init interface mode\n"); - return err; + for (i = 0; i < list_length; i++) { + for (n = 0; n < ST_SENSORS_MAX_4WAI; n++) { + if (strcmp(name, list[i].sensors_supported[n]) == 0) + return i; } } - return 0; + return -ENODEV; } +EXPORT_SYMBOL(st_sensors_get_settings_index); -int st_sensors_check_device_support(struct iio_dev *indio_dev, - int num_sensors_list, - const struct st_sensor_settings *sensor_settings) +/* + * st_sensors_verify_id() - verify sensor ID (WhoAmI) is matching with the + * expected value + * @indio_dev: IIO device reference. + * + * Return: 0 on success (valid sensor ID), else a negative error code. + */ +int st_sensors_verify_id(struct iio_dev *indio_dev) { - int i, n, err = 0; - u8 wai; struct st_sensor_data *sdata = iio_priv(indio_dev); + int wai, err; - for (i = 0; i < num_sensors_list; i++) { - for (n = 0; n < ST_SENSORS_MAX_4WAI; n++) { - if (strcmp(indio_dev->name, - sensor_settings[i].sensors_supported[n]) == 0) { - break; - } - } - if (n < ST_SENSORS_MAX_4WAI) - break; - } - if (i == num_sensors_list) { - dev_err(&indio_dev->dev, "device name %s not recognized.\n", - indio_dev->name); - return -ENODEV; - } - - err = st_sensors_init_interface_mode(indio_dev, &sensor_settings[i]); - if (err < 0) - return err; - - if (sensor_settings[i].wai_addr) { - err = sdata->tf->read_byte(&sdata->tb, sdata->dev, - sensor_settings[i].wai_addr, &wai); + if (sdata->sensor_settings->wai_addr) { + err = regmap_read(sdata->regmap, + sdata->sensor_settings->wai_addr, &wai); if (err < 0) { dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n"); return err; } - if (sensor_settings[i].wai != wai) { + if (sdata->sensor_settings->wai != wai) { dev_err(&indio_dev->dev, "%s: WhoAmI mismatch (0x%x).\n", indio_dev->name, wai); @@ -678,12 +651,9 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev, } } - sdata->sensor_settings = - (struct st_sensor_settings *)&sensor_settings[i]; - - return i; + return 0; } -EXPORT_SYMBOL(st_sensors_check_device_support); +EXPORT_SYMBOL(st_sensors_verify_id); ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c index b1c9812407e7633cb2be2f2f7644db07c26838a7..aa89d54a7c595f87b15a1b5948651983c929cddc 100644 --- a/drivers/iio/common/st_sensors/st_sensors_i2c.c +++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c @@ -13,68 +13,58 @@ #include #include #include +#include #include #define ST_SENSORS_I2C_MULTIREAD 0x80 -static unsigned int st_sensors_i2c_get_irq(struct iio_dev *indio_dev) -{ - struct st_sensor_data *sdata = iio_priv(indio_dev); - - return to_i2c_client(sdata->dev)->irq; -} - -static int st_sensors_i2c_read_byte(struct st_sensor_transfer_buffer *tb, - struct device *dev, u8 reg_addr, u8 *res_byte) -{ - int err; - - err = i2c_smbus_read_byte_data(to_i2c_client(dev), reg_addr); - if (err < 0) - goto st_accel_i2c_read_byte_error; - - *res_byte = err & 0xff; - -st_accel_i2c_read_byte_error: - return err < 0 ? err : 0; -} - -static int st_sensors_i2c_read_multiple_byte( - struct st_sensor_transfer_buffer *tb, struct device *dev, - u8 reg_addr, int len, u8 *data, bool multiread_bit) -{ - if (multiread_bit) - reg_addr |= ST_SENSORS_I2C_MULTIREAD; - - return i2c_smbus_read_i2c_block_data_or_emulated(to_i2c_client(dev), - reg_addr, len, data); -} - -static int st_sensors_i2c_write_byte(struct st_sensor_transfer_buffer *tb, - struct device *dev, u8 reg_addr, u8 data) -{ - return i2c_smbus_write_byte_data(to_i2c_client(dev), reg_addr, data); -} +static const struct regmap_config st_sensors_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; -static const struct st_sensor_transfer_function st_sensors_tf_i2c = { - .read_byte = st_sensors_i2c_read_byte, - .write_byte = st_sensors_i2c_write_byte, - .read_multiple_byte = st_sensors_i2c_read_multiple_byte, +static const struct regmap_config st_sensors_i2c_regmap_multiread_bit_config = { + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = ST_SENSORS_I2C_MULTIREAD, }; -void st_sensors_i2c_configure(struct iio_dev *indio_dev, - struct i2c_client *client, struct st_sensor_data *sdata) +/* + * st_sensors_i2c_configure() - configure I2C interface + * @indio_dev: IIO device reference. + * @client: i2c client reference. + * + * Return: 0 on success, else a negative error code. + */ +int st_sensors_i2c_configure(struct iio_dev *indio_dev, + struct i2c_client *client) { + struct st_sensor_data *sdata = iio_priv(indio_dev); + const struct regmap_config *config; + + if (sdata->sensor_settings->multi_read_bit) + config = &st_sensors_i2c_regmap_multiread_bit_config; + else + config = &st_sensors_i2c_regmap_config; + + sdata->regmap = devm_regmap_init_i2c(client, config); + if (IS_ERR(sdata->regmap)) { + dev_err(&client->dev, "Failed to register i2c regmap (%d)\n", + (int)PTR_ERR(sdata->regmap)); + return PTR_ERR(sdata->regmap); + } + i2c_set_clientdata(client, indio_dev); indio_dev->dev.parent = &client->dev; indio_dev->name = client->name; sdata->dev = &client->dev; - sdata->tf = &st_sensors_tf_i2c; - sdata->get_irq_data_ready = st_sensors_i2c_get_irq; + sdata->irq = client->irq; + + return 0; } EXPORT_SYMBOL(st_sensors_i2c_configure); diff --git a/drivers/iio/common/st_sensors/st_sensors_spi.c b/drivers/iio/common/st_sensors/st_sensors_spi.c index 2213843f02cb77722bc47eb058ba72c7e3f03a90..2262f81b07c20254924cdac34b2314867ceddd23 100644 --- a/drivers/iio/common/st_sensors/st_sensors_spi.c +++ b/drivers/iio/common/st_sensors/st_sensors_spi.c @@ -11,108 +11,108 @@ #include #include #include +#include #include - +#include "st_sensors_core.h" #define ST_SENSORS_SPI_MULTIREAD 0xc0 -#define ST_SENSORS_SPI_READ 0x80 -static unsigned int st_sensors_spi_get_irq(struct iio_dev *indio_dev) -{ - struct st_sensor_data *sdata = iio_priv(indio_dev); +static const struct regmap_config st_sensors_spi_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; - return to_spi_device(sdata->dev)->irq; -} +static const struct regmap_config st_sensors_spi_regmap_multiread_bit_config = { + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = ST_SENSORS_SPI_MULTIREAD, +}; -static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb, - struct device *dev, u8 reg_addr, int len, u8 *data, bool multiread_bit) +/* + * st_sensors_is_spi_3_wire() - check if SPI 3-wire mode has been selected + * @spi: spi device reference. + * + * Return: true if SPI 3-wire mode is selected, false otherwise. + */ +static bool st_sensors_is_spi_3_wire(struct spi_device *spi) { - int err; - - struct spi_transfer xfers[] = { - { - .tx_buf = tb->tx_buf, - .bits_per_word = 8, - .len = 1, - }, - { - .rx_buf = tb->rx_buf, - .bits_per_word = 8, - .len = len, - } - }; - - mutex_lock(&tb->buf_lock); - if ((multiread_bit) && (len > 1)) - tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_MULTIREAD; - else - tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_READ; + struct device_node *np = spi->dev.of_node; + struct st_sensors_platform_data *pdata; - err = spi_sync_transfer(to_spi_device(dev), xfers, ARRAY_SIZE(xfers)); - if (err) - goto acc_spi_read_error; + pdata = (struct st_sensors_platform_data *)spi->dev.platform_data; + if ((np && of_property_read_bool(np, "spi-3wire")) || + (pdata && pdata->spi_3wire)) { + return true; + } - memcpy(data, tb->rx_buf, len); - mutex_unlock(&tb->buf_lock); - return len; - -acc_spi_read_error: - mutex_unlock(&tb->buf_lock); - return err; + return false; } -static int st_sensors_spi_read_byte(struct st_sensor_transfer_buffer *tb, - struct device *dev, u8 reg_addr, u8 *res_byte) +/* + * st_sensors_configure_spi_3_wire() - configure SPI 3-wire if needed + * @spi: spi device reference. + * @settings: sensor specific settings reference. + * + * Return: 0 on success, else a negative error code. + */ +static int st_sensors_configure_spi_3_wire(struct spi_device *spi, + struct st_sensor_settings *settings) { - return st_sensors_spi_read(tb, dev, reg_addr, 1, res_byte, false); -} + if (settings->sim.addr) { + u8 buffer[] = { + settings->sim.addr, + settings->sim.value + }; -static int st_sensors_spi_read_multiple_byte( - struct st_sensor_transfer_buffer *tb, struct device *dev, - u8 reg_addr, int len, u8 *data, bool multiread_bit) -{ - return st_sensors_spi_read(tb, dev, reg_addr, len, data, multiread_bit); + return spi_write(spi, buffer, 2); + } + + return 0; } -static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb, - struct device *dev, u8 reg_addr, u8 data) +/* + * st_sensors_spi_configure() - configure SPI interface + * @indio_dev: IIO device reference. + * @spi: spi device reference. + * + * Return: 0 on success, else a negative error code. + */ +int st_sensors_spi_configure(struct iio_dev *indio_dev, + struct spi_device *spi) { + struct st_sensor_data *sdata = iio_priv(indio_dev); + const struct regmap_config *config; int err; - struct spi_transfer xfers = { - .tx_buf = tb->tx_buf, - .bits_per_word = 8, - .len = 2, - }; + if (st_sensors_is_spi_3_wire(spi)) { + err = st_sensors_configure_spi_3_wire(spi, + sdata->sensor_settings); + if (err < 0) + return err; + } - mutex_lock(&tb->buf_lock); - tb->tx_buf[0] = reg_addr; - tb->tx_buf[1] = data; - - err = spi_sync_transfer(to_spi_device(dev), &xfers, 1); - mutex_unlock(&tb->buf_lock); + if (sdata->sensor_settings->multi_read_bit) + config = &st_sensors_spi_regmap_multiread_bit_config; + else + config = &st_sensors_spi_regmap_config; - return err; -} + sdata->regmap = devm_regmap_init_spi(spi, config); + if (IS_ERR(sdata->regmap)) { + dev_err(&spi->dev, "Failed to register spi regmap (%d)\n", + (int)PTR_ERR(sdata->regmap)); + return PTR_ERR(sdata->regmap); + } -static const struct st_sensor_transfer_function st_sensors_tf_spi = { - .read_byte = st_sensors_spi_read_byte, - .write_byte = st_sensors_spi_write_byte, - .read_multiple_byte = st_sensors_spi_read_multiple_byte, -}; - -void st_sensors_spi_configure(struct iio_dev *indio_dev, - struct spi_device *spi, struct st_sensor_data *sdata) -{ spi_set_drvdata(spi, indio_dev); indio_dev->dev.parent = &spi->dev; indio_dev->name = spi->modalias; sdata->dev = &spi->dev; - sdata->tf = &st_sensors_tf_spi; - sdata->get_irq_data_ready = st_sensors_spi_get_irq; + sdata->irq = spi->irq; + + return 0; } EXPORT_SYMBOL(st_sensors_spi_configure); diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index 630c8cb35e8be128fabda3ec5f60e6515999e4b6..4a2efa00f7f2d50e937ba1d0c818468f0c962e18 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "st_sensors_core.h" @@ -26,8 +27,7 @@ static int st_sensors_new_samples_available(struct iio_dev *indio_dev, struct st_sensor_data *sdata) { - u8 status; - int ret; + int ret, status; /* How would I know if I can't check it? */ if (!sdata->sensor_settings->drdy_irq.stat_drdy.addr) @@ -37,9 +37,9 @@ static int st_sensors_new_samples_available(struct iio_dev *indio_dev, if (!indio_dev->active_scan_mask) return 0; - ret = sdata->tf->read_byte(&sdata->tb, sdata->dev, - sdata->sensor_settings->drdy_irq.stat_drdy.addr, - &status); + ret = regmap_read(sdata->regmap, + sdata->sensor_settings->drdy_irq.stat_drdy.addr, + &status); if (ret < 0) { dev_err(sdata->dev, "error checking samples available\n"); @@ -121,9 +121,9 @@ static irqreturn_t st_sensors_irq_thread(int irq, void *p) int st_sensors_allocate_trigger(struct iio_dev *indio_dev, const struct iio_trigger_ops *trigger_ops) { - int err, irq; struct st_sensor_data *sdata = iio_priv(indio_dev); unsigned long irq_trig; + int err; sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name); if (sdata->trig == NULL) { @@ -135,8 +135,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, sdata->trig->ops = trigger_ops; sdata->trig->dev.parent = sdata->dev; - irq = sdata->get_irq_data_ready(indio_dev); - irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq)); + irq_trig = irqd_get_trigger_type(irq_get_irq_data(sdata->irq)); /* * If the IRQ is triggered on falling edge, we need to mark the * interrupt as active low, if the hardware supports this. @@ -206,12 +205,12 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, sdata->sensor_settings->drdy_irq.stat_drdy.addr) irq_trig |= IRQF_SHARED; - err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev), - st_sensors_irq_handler, - st_sensors_irq_thread, - irq_trig, - sdata->trig->name, - sdata->trig); + err = request_threaded_irq(sdata->irq, + st_sensors_irq_handler, + st_sensors_irq_thread, + irq_trig, + sdata->trig->name, + sdata->trig); if (err) { dev_err(&indio_dev->dev, "failed to request trigger IRQ.\n"); goto iio_trigger_free; @@ -227,7 +226,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, return 0; iio_trigger_register_error: - free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig); + free_irq(sdata->irq, sdata->trig); iio_trigger_free: iio_trigger_free(sdata->trig); return err; @@ -239,7 +238,7 @@ void st_sensors_deallocate_trigger(struct iio_dev *indio_dev) struct st_sensor_data *sdata = iio_priv(indio_dev); iio_trigger_unregister(sdata->trig); - free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig); + free_irq(sdata->irq, sdata->trig); iio_trigger_free(sdata->trig); } EXPORT_SYMBOL(st_sensors_deallocate_trigger); diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 4335214800d24f37559a8ba60c9d3e2af780f5bb..2ebe08326048954fab107ea442aca4bb54940464 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -220,7 +220,7 @@ static int ad5380_read_raw(struct iio_dev *indio_dev, if (ret) return ret; *val >>= chan->scan_type.shift; - val -= (1 << chan->scan_type.realbits) / 2; + *val -= (1 << chan->scan_type.realbits) / 2; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 2 * st->vref; diff --git a/drivers/iio/dummy/iio_simple_dummy.c b/drivers/iio/dummy/iio_simple_dummy.c index 8f99c005458a7d6c6bd79c621dd0bc38c9e1ca9c..6cb02299a2152274b44a655026ad1633e8aca9b8 100644 --- a/drivers/iio/dummy/iio_simple_dummy.c +++ b/drivers/iio/dummy/iio_simple_dummy.c @@ -693,9 +693,9 @@ static int iio_dummy_remove(struct iio_sw_device *swd) * Varies depending on bus type of the device. As there is no device * here, call probe directly. For information on device registration * i2c: - * Documentation/i2c/writing-clients + * Documentation/i2c/writing-clients.rst * spi: - * Documentation/spi/spi-summary + * Documentation/spi/spi-summary.rst */ static const struct iio_sw_device_ops iio_dummy_device_ops = { .probe = iio_dummy_probe, diff --git a/drivers/iio/gyro/st_gyro.h b/drivers/iio/gyro/st_gyro.h index 460d190be4a4e9393ab3ae83e818d43455abc3be..592f6b34e987eecc827e53de64ed7dc79e550b6c 100644 --- a/drivers/iio/gyro/st_gyro.h +++ b/drivers/iio/gyro/st_gyro.h @@ -32,6 +32,7 @@ static const struct st_sensors_platform_data gyro_pdata = { .drdy_int_pin = 2, }; +const struct st_sensor_settings *st_gyro_get_settings(const char *name); int st_gyro_common_probe(struct iio_dev *indio_dev); void st_gyro_common_remove(struct iio_dev *indio_dev); diff --git a/drivers/iio/gyro/st_gyro_buffer.c b/drivers/iio/gyro/st_gyro_buffer.c index 6e362f735e92ab4ebd13fee9c6ea6cbefffa048e..7465ad62391c09cab6d977f7194b7fae89232323 100644 --- a/drivers/iio/gyro/st_gyro_buffer.c +++ b/drivers/iio/gyro/st_gyro_buffer.c @@ -29,61 +29,51 @@ int st_gyro_trig_set_state(struct iio_trigger *trig, bool state) return st_sensors_set_dataready_irq(indio_dev, state); } -static int st_gyro_buffer_preenable(struct iio_dev *indio_dev) -{ - return st_sensors_set_enable(indio_dev, true); -} - static int st_gyro_buffer_postenable(struct iio_dev *indio_dev) { int err; - struct st_sensor_data *gdata = iio_priv(indio_dev); - gdata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (gdata->buffer_data == NULL) { - err = -ENOMEM; - goto allocate_memory_error; - } + err = iio_triggered_buffer_postenable(indio_dev); + if (err < 0) + return err; err = st_sensors_set_axis_enable(indio_dev, - (u8)indio_dev->active_scan_mask[0]); + (u8)indio_dev->active_scan_mask[0]); if (err < 0) - goto st_gyro_buffer_postenable_error; + goto st_gyro_buffer_predisable; - err = iio_triggered_buffer_postenable(indio_dev); + err = st_sensors_set_enable(indio_dev, true); if (err < 0) - goto st_gyro_buffer_postenable_error; + goto st_gyro_buffer_enable_all_axis; - return err; + return 0; -st_gyro_buffer_postenable_error: - kfree(gdata->buffer_data); -allocate_memory_error: +st_gyro_buffer_enable_all_axis: + st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS); +st_gyro_buffer_predisable: + iio_triggered_buffer_predisable(indio_dev); return err; } static int st_gyro_buffer_predisable(struct iio_dev *indio_dev) { - int err; - struct st_sensor_data *gdata = iio_priv(indio_dev); + int err, err2; - err = iio_triggered_buffer_predisable(indio_dev); + err = st_sensors_set_enable(indio_dev, false); if (err < 0) - goto st_gyro_buffer_predisable_error; + goto st_gyro_buffer_predisable; err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS); - if (err < 0) - goto st_gyro_buffer_predisable_error; - err = st_sensors_set_enable(indio_dev, false); +st_gyro_buffer_predisable: + err2 = iio_triggered_buffer_predisable(indio_dev); + if (!err) + err = err2; -st_gyro_buffer_predisable_error: - kfree(gdata->buffer_data); return err; } static const struct iio_buffer_setup_ops st_gyro_buffer_setup_ops = { - .preenable = &st_gyro_buffer_preenable, .postenable = &st_gyro_buffer_postenable, .predisable = &st_gyro_buffer_predisable, }; diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index e995dc77e30eefbb4f6759b91079a5c76bc49a35..c0acbb5d2ffb5c6b8a2235e5ca0ef4cca0105acd 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -368,28 +367,41 @@ static const struct iio_trigger_ops st_gyro_trigger_ops = { #define ST_GYRO_TRIGGER_OPS NULL #endif +/* + * st_gyro_get_settings() - get sensor settings from device name + * @name: device name buffer reference. + * + * Return: valid reference on success, NULL otherwise. + */ +const struct st_sensor_settings *st_gyro_get_settings(const char *name) +{ + int index = st_sensors_get_settings_index(name, + st_gyro_sensors_settings, + ARRAY_SIZE(st_gyro_sensors_settings)); + if (index < 0) + return NULL; + + return &st_gyro_sensors_settings[index]; +} +EXPORT_SYMBOL(st_gyro_get_settings); + int st_gyro_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *gdata = iio_priv(indio_dev); - int irq = gdata->get_irq_data_ready(indio_dev); int err; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &gyro_info; - mutex_init(&gdata->tb.buf_lock); err = st_sensors_power_enable(indio_dev); if (err) return err; - err = st_sensors_check_device_support(indio_dev, - ARRAY_SIZE(st_gyro_sensors_settings), - st_gyro_sensors_settings); + err = st_sensors_verify_id(indio_dev); if (err < 0) goto st_gyro_power_off; gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS; - gdata->multiread_bit = gdata->sensor_settings->multi_read_bit; indio_dev->channels = gdata->sensor_settings->ch; indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; @@ -406,7 +418,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) if (err < 0) goto st_gyro_power_off; - if (irq > 0) { + if (gdata->irq > 0) { err = st_sensors_allocate_trigger(indio_dev, ST_GYRO_TRIGGER_OPS); if (err < 0) @@ -423,7 +435,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) return 0; st_gyro_device_register_error: - if (irq > 0) + if (gdata->irq > 0) st_sensors_deallocate_trigger(indio_dev); st_gyro_probe_trigger_error: st_gyro_deallocate_ring(indio_dev); @@ -441,7 +453,7 @@ void st_gyro_common_remove(struct iio_dev *indio_dev) st_sensors_power_disable(indio_dev); iio_device_unregister(indio_dev); - if (gdata->get_irq_data_ready(indio_dev) > 0) + if (gdata->irq > 0) st_sensors_deallocate_trigger(indio_dev); st_gyro_deallocate_ring(indio_dev); diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index f2a8683db7d96006942ebb3cff97629284e82d54..05a1a0874bd5e291c4c4c4beca4e7dedc601ce35 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -63,21 +63,33 @@ MODULE_DEVICE_TABLE(of, st_gyro_of_match); #endif static int st_gyro_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { - struct iio_dev *indio_dev; + const struct st_sensor_settings *settings; struct st_sensor_data *gdata; + struct iio_dev *indio_dev; int err; + st_sensors_of_name_probe(&client->dev, st_gyro_of_match, + client->name, sizeof(client->name)); + + settings = st_gyro_get_settings(client->name); + if (!settings) { + dev_err(&client->dev, "device name %s not recognized.\n", + client->name); + return -ENODEV; + } + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*gdata)); if (!indio_dev) return -ENOMEM; gdata = iio_priv(indio_dev); - st_sensors_of_name_probe(&client->dev, st_gyro_of_match, - client->name, sizeof(client->name)); + gdata->sensor_settings = (struct st_sensor_settings *)settings; - st_sensors_i2c_configure(indio_dev, client, gdata); + err = st_sensors_i2c_configure(indio_dev, client); + if (err < 0) + return err; err = st_gyro_common_probe(indio_dev); if (err < 0) diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c index 93c48248bea6f406bdddb38683308dec124e53bf..b5c6242512312fa9707618b7d2cce2100d527c79 100644 --- a/drivers/iio/gyro/st_gyro_spi.c +++ b/drivers/iio/gyro/st_gyro_spi.c @@ -69,19 +69,31 @@ MODULE_DEVICE_TABLE(of, st_gyro_of_match); static int st_gyro_spi_probe(struct spi_device *spi) { - struct iio_dev *indio_dev; + const struct st_sensor_settings *settings; struct st_sensor_data *gdata; + struct iio_dev *indio_dev; int err; + st_sensors_of_name_probe(&spi->dev, st_gyro_of_match, + spi->modalias, sizeof(spi->modalias)); + + settings = st_gyro_get_settings(spi->modalias); + if (!settings) { + dev_err(&spi->dev, "device name %s not recognized.\n", + spi->modalias); + return -ENODEV; + } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*gdata)); if (!indio_dev) return -ENOMEM; gdata = iio_priv(indio_dev); + gdata->sensor_settings = (struct st_sensor_settings *)settings; - st_sensors_of_name_probe(&spi->dev, st_gyro_of_match, - spi->modalias, sizeof(spi->modalias)); - st_sensors_spi_configure(indio_dev, spi, gdata); + err = st_sensors_spi_configure(indio_dev, spi); + if (err < 0) + return err; err = st_gyro_common_probe(indio_dev); if (err < 0) diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c index f18da78592297706a6a6d86ed289572cb9e77734..3bac98e731d9cd0b388384e0f73964bf9225e65e 100644 --- a/drivers/iio/humidity/am2315.c +++ b/drivers/iio/humidity/am2315.c @@ -240,32 +240,15 @@ static int am2315_probe(struct i2c_client *client, indio_dev->channels = am2315_channels; indio_dev->num_channels = ARRAY_SIZE(am2315_channels); - ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time, + ret = devm_iio_triggered_buffer_setup(&client->dev, + indio_dev, iio_pollfunc_store_time, am2315_trigger_handler, NULL); if (ret < 0) { dev_err(&client->dev, "iio triggered buffer setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret < 0) - goto err_buffer_cleanup; - - return 0; - -err_buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); - return ret; -} - -static int am2315_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - - return 0; + return devm_iio_device_register(&client->dev, indio_dev); } static const struct i2c_device_id am2315_i2c_id[] = { @@ -287,7 +270,6 @@ static struct i2c_driver am2315_driver = { .acpi_match_table = ACPI_PTR(am2315_acpi_id), }, .probe = am2315_probe, - .remove = am2315_remove, .id_table = am2315_i2c_id, }; diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c index 066e05f920810c74afdac0b535046af455c67388..bfe1cdb16846ebb5f32130e105014f2bca3a5cf6 100644 --- a/drivers/iio/humidity/hdc100x.c +++ b/drivers/iio/humidity/hdc100x.c @@ -385,28 +385,16 @@ static int hdc100x_probe(struct i2c_client *client, hdc100x_set_it_time(data, 1, hdc100x_int_time[1][0]); hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, 0); - ret = iio_triggered_buffer_setup(indio_dev, NULL, + ret = devm_iio_triggered_buffer_setup(&client->dev, + indio_dev, NULL, hdc100x_trigger_handler, &hdc_buffer_setup_ops); if (ret < 0) { dev_err(&client->dev, "iio triggered buffer setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret < 0) - iio_triggered_buffer_cleanup(indio_dev); - return ret; -} - -static int hdc100x_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - - return 0; + return devm_iio_device_register(&client->dev, indio_dev); } static const struct i2c_device_id hdc100x_id[] = { @@ -436,7 +424,6 @@ static struct i2c_driver hdc100x_driver = { .of_match_table = of_match_ptr(hdc100x_dt_ids), }, .probe = hdc100x_probe, - .remove = hdc100x_remove, .id_table = hdc100x_id, }; module_i2c_driver(hdc100x_driver); diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 4957e6df447ea0d39853fd61e9897baca01999d0..f3c7282321a8b53cf87dd71ae37aeda5d53b01c8 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -17,6 +17,18 @@ config ADIS16400 adis16365, adis16400 and adis16405 triaxial inertial sensors (adis16400 series also have magnetometers). +config ADIS16460 + tristate "Analog Devices ADIS16460 and similar IMU driver" + depends on SPI + select IIO_ADIS_LIB + select IIO_ADIS_LIB_BUFFER if IIO_BUFFER + help + Say yes here to build support for Analog Devices ADIS16460 inertial + sensor. + + To compile this driver as a module, choose M here: the module will be + called adis16460. + config ADIS16480 tristate "Analog Devices ADIS16480 and similar IMU driver" depends on SPI diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 9e452fce1aaf54bf5c995b84d84c01b97d943426..4a69588655043746ca1c6371d8dc579b655649e9 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -5,6 +5,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_ADIS16400) += adis16400.o +obj-$(CONFIG_ADIS16460) += adis16460.o obj-$(CONFIG_ADIS16480) += adis16480.o adis_lib-y += adis.o diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index 30281e91dbf9ebf7b86154f5113d0132836858e8..1631c255deab1a662c60dcaeff64407c46630961 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -39,18 +39,24 @@ int adis_write_reg(struct adis *adis, unsigned int reg, .len = 2, .cs_change = 1, .delay_usecs = adis->data->write_delay, + .cs_change_delay = adis->data->cs_change_delay, + .cs_change_delay_unit = SPI_DELAY_UNIT_USECS, }, { .tx_buf = adis->tx + 2, .bits_per_word = 8, .len = 2, .cs_change = 1, .delay_usecs = adis->data->write_delay, + .cs_change_delay = adis->data->cs_change_delay, + .cs_change_delay_unit = SPI_DELAY_UNIT_USECS, }, { .tx_buf = adis->tx + 4, .bits_per_word = 8, .len = 2, .cs_change = 1, .delay_usecs = adis->data->write_delay, + .cs_change_delay = adis->data->cs_change_delay, + .cs_change_delay_unit = SPI_DELAY_UNIT_USECS, }, { .tx_buf = adis->tx + 6, .bits_per_word = 8, @@ -133,12 +139,16 @@ int adis_read_reg(struct adis *adis, unsigned int reg, .len = 2, .cs_change = 1, .delay_usecs = adis->data->write_delay, + .cs_change_delay = adis->data->cs_change_delay, + .cs_change_delay_unit = SPI_DELAY_UNIT_USECS, }, { .tx_buf = adis->tx + 2, .bits_per_word = 8, .len = 2, .cs_change = 1, .delay_usecs = adis->data->read_delay, + .cs_change_delay = adis->data->cs_change_delay, + .cs_change_delay_unit = SPI_DELAY_UNIT_USECS, }, { .tx_buf = adis->tx + 4, .rx_buf = adis->rx, @@ -146,6 +156,8 @@ int adis_read_reg(struct adis *adis, unsigned int reg, .len = 2, .cs_change = 1, .delay_usecs = adis->data->read_delay, + .cs_change_delay = adis->data->cs_change_delay, + .cs_change_delay_unit = SPI_DELAY_UNIT_USECS, }, { .rx_buf = adis->rx + 2, .bits_per_word = 8, diff --git a/drivers/iio/imu/adis16460.c b/drivers/iio/imu/adis16460.c new file mode 100644 index 0000000000000000000000000000000000000000..6aed9e84abbfab965d00ce836be25da0253d3143 --- /dev/null +++ b/drivers/iio/imu/adis16460.c @@ -0,0 +1,489 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * ADIS16460 IMU driver + * + * Copyright 2019 Analog Devices Inc. + */ + +#include +#include +#include + +#include +#include + +#include + +#define ADIS16460_REG_FLASH_CNT 0x00 +#define ADIS16460_REG_DIAG_STAT 0x02 +#define ADIS16460_REG_X_GYRO_LOW 0x04 +#define ADIS16460_REG_X_GYRO_OUT 0x06 +#define ADIS16460_REG_Y_GYRO_LOW 0x08 +#define ADIS16460_REG_Y_GYRO_OUT 0x0A +#define ADIS16460_REG_Z_GYRO_LOW 0x0C +#define ADIS16460_REG_Z_GYRO_OUT 0x0E +#define ADIS16460_REG_X_ACCL_LOW 0x10 +#define ADIS16460_REG_X_ACCL_OUT 0x12 +#define ADIS16460_REG_Y_ACCL_LOW 0x14 +#define ADIS16460_REG_Y_ACCL_OUT 0x16 +#define ADIS16460_REG_Z_ACCL_LOW 0x18 +#define ADIS16460_REG_Z_ACCL_OUT 0x1A +#define ADIS16460_REG_SMPL_CNTR 0x1C +#define ADIS16460_REG_TEMP_OUT 0x1E +#define ADIS16460_REG_X_DELT_ANG 0x24 +#define ADIS16460_REG_Y_DELT_ANG 0x26 +#define ADIS16460_REG_Z_DELT_ANG 0x28 +#define ADIS16460_REG_X_DELT_VEL 0x2A +#define ADIS16460_REG_Y_DELT_VEL 0x2C +#define ADIS16460_REG_Z_DELT_VEL 0x2E +#define ADIS16460_REG_MSC_CTRL 0x32 +#define ADIS16460_REG_SYNC_SCAL 0x34 +#define ADIS16460_REG_DEC_RATE 0x36 +#define ADIS16460_REG_FLTR_CTRL 0x38 +#define ADIS16460_REG_GLOB_CMD 0x3E +#define ADIS16460_REG_X_GYRO_OFF 0x40 +#define ADIS16460_REG_Y_GYRO_OFF 0x42 +#define ADIS16460_REG_Z_GYRO_OFF 0x44 +#define ADIS16460_REG_X_ACCL_OFF 0x46 +#define ADIS16460_REG_Y_ACCL_OFF 0x48 +#define ADIS16460_REG_Z_ACCL_OFF 0x4A +#define ADIS16460_REG_LOT_ID1 0x52 +#define ADIS16460_REG_LOT_ID2 0x54 +#define ADIS16460_REG_PROD_ID 0x56 +#define ADIS16460_REG_SERIAL_NUM 0x58 +#define ADIS16460_REG_CAL_SGNTR 0x60 +#define ADIS16460_REG_CAL_CRC 0x62 +#define ADIS16460_REG_CODE_SGNTR 0x64 +#define ADIS16460_REG_CODE_CRC 0x66 + +struct adis16460_chip_info { + unsigned int num_channels; + const struct iio_chan_spec *channels; + unsigned int gyro_max_val; + unsigned int gyro_max_scale; + unsigned int accel_max_val; + unsigned int accel_max_scale; +}; + +struct adis16460 { + const struct adis16460_chip_info *chip_info; + struct adis adis; +}; + +#ifdef CONFIG_DEBUG_FS + +static int adis16460_show_serial_number(void *arg, u64 *val) +{ + struct adis16460 *adis16460 = arg; + u16 serial; + int ret; + + ret = adis_read_reg_16(&adis16460->adis, ADIS16460_REG_SERIAL_NUM, + &serial); + if (ret < 0) + return ret; + + *val = serial; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(adis16460_serial_number_fops, + adis16460_show_serial_number, NULL, "0x%.4llx\n"); + +static int adis16460_show_product_id(void *arg, u64 *val) +{ + struct adis16460 *adis16460 = arg; + u16 prod_id; + int ret; + + ret = adis_read_reg_16(&adis16460->adis, ADIS16460_REG_PROD_ID, + &prod_id); + if (ret < 0) + return ret; + + *val = prod_id; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(adis16460_product_id_fops, + adis16460_show_product_id, NULL, "%llu\n"); + +static int adis16460_show_flash_count(void *arg, u64 *val) +{ + struct adis16460 *adis16460 = arg; + u32 flash_count; + int ret; + + ret = adis_read_reg_32(&adis16460->adis, ADIS16460_REG_FLASH_CNT, + &flash_count); + if (ret < 0) + return ret; + + *val = flash_count; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(adis16460_flash_count_fops, + adis16460_show_flash_count, NULL, "%lld\n"); + +static int adis16460_debugfs_init(struct iio_dev *indio_dev) +{ + struct adis16460 *adis16460 = iio_priv(indio_dev); + + debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry, + adis16460, &adis16460_serial_number_fops); + debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry, + adis16460, &adis16460_product_id_fops); + debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry, + adis16460, &adis16460_flash_count_fops); + + return 0; +} + +#else + +static int adis16460_debugfs_init(struct iio_dev *indio_dev) +{ + return 0; +} + +#endif + +static int adis16460_set_freq(struct iio_dev *indio_dev, int val, int val2) +{ + struct adis16460 *st = iio_priv(indio_dev); + int t; + + t = val * 1000 + val2 / 1000; + if (t <= 0) + return -EINVAL; + + t = 2048000 / t; + if (t > 2048) + t = 2048; + + if (t != 0) + t--; + + return adis_write_reg_16(&st->adis, ADIS16460_REG_DEC_RATE, t); +} + +static int adis16460_get_freq(struct iio_dev *indio_dev, int *val, int *val2) +{ + struct adis16460 *st = iio_priv(indio_dev); + uint16_t t; + int ret; + unsigned int freq; + + ret = adis_read_reg_16(&st->adis, ADIS16460_REG_DEC_RATE, &t); + if (ret < 0) + return ret; + + freq = 2048000 / (t + 1); + *val = freq / 1000; + *val2 = (freq % 1000) * 1000; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int adis16460_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *val, int *val2, long info) +{ + struct adis16460 *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_RAW: + return adis_single_conversion(indio_dev, chan, 0, val); + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ANGL_VEL: + *val = st->chip_info->gyro_max_scale; + *val2 = st->chip_info->gyro_max_val; + return IIO_VAL_FRACTIONAL; + case IIO_ACCEL: + *val = st->chip_info->accel_max_scale; + *val2 = st->chip_info->accel_max_val; + return IIO_VAL_FRACTIONAL; + case IIO_TEMP: + *val = 50; /* 50 milli degrees Celsius/LSB */ + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + *val = 500; /* 25 degrees Celsius = 0x0000 */ + return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + return adis16460_get_freq(indio_dev, val, val2); + default: + return -EINVAL; + } +} + +static int adis16460_write_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int val, int val2, long info) +{ + switch (info) { + case IIO_CHAN_INFO_SAMP_FREQ: + return adis16460_set_freq(indio_dev, val, val2); + default: + return -EINVAL; + } +} + +enum { + ADIS16460_SCAN_GYRO_X, + ADIS16460_SCAN_GYRO_Y, + ADIS16460_SCAN_GYRO_Z, + ADIS16460_SCAN_ACCEL_X, + ADIS16460_SCAN_ACCEL_Y, + ADIS16460_SCAN_ACCEL_Z, + ADIS16460_SCAN_TEMP, +}; + +#define ADIS16460_MOD_CHANNEL(_type, _mod, _address, _si, _bits) \ + { \ + .type = (_type), \ + .modified = 1, \ + .channel2 = (_mod), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .address = (_address), \ + .scan_index = (_si), \ + .scan_type = { \ + .sign = 's', \ + .realbits = (_bits), \ + .storagebits = (_bits), \ + .endianness = IIO_BE, \ + }, \ + } + +#define ADIS16460_GYRO_CHANNEL(_mod) \ + ADIS16460_MOD_CHANNEL(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \ + ADIS16460_REG_ ## _mod ## _GYRO_LOW, ADIS16460_SCAN_GYRO_ ## _mod, \ + 32) + +#define ADIS16460_ACCEL_CHANNEL(_mod) \ + ADIS16460_MOD_CHANNEL(IIO_ACCEL, IIO_MOD_ ## _mod, \ + ADIS16460_REG_ ## _mod ## _ACCL_LOW, ADIS16460_SCAN_ACCEL_ ## _mod, \ + 32) + +#define ADIS16460_TEMP_CHANNEL() { \ + .type = IIO_TEMP, \ + .indexed = 1, \ + .channel = 0, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .address = ADIS16460_REG_TEMP_OUT, \ + .scan_index = ADIS16460_SCAN_TEMP, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ + } + +static const struct iio_chan_spec adis16460_channels[] = { + ADIS16460_GYRO_CHANNEL(X), + ADIS16460_GYRO_CHANNEL(Y), + ADIS16460_GYRO_CHANNEL(Z), + ADIS16460_ACCEL_CHANNEL(X), + ADIS16460_ACCEL_CHANNEL(Y), + ADIS16460_ACCEL_CHANNEL(Z), + ADIS16460_TEMP_CHANNEL(), + IIO_CHAN_SOFT_TIMESTAMP(7) +}; + +static const struct adis16460_chip_info adis16460_chip_info = { + .channels = adis16460_channels, + .num_channels = ARRAY_SIZE(adis16460_channels), + /* + * storing the value in rad/degree and the scale in degree + * gives us the result in rad and better precession than + * storing the scale directly in rad. + */ + .gyro_max_val = IIO_RAD_TO_DEGREE(200 << 16), + .gyro_max_scale = 1, + .accel_max_val = IIO_M_S_2_TO_G(20000 << 16), + .accel_max_scale = 5, +}; + +static const struct iio_info adis16460_info = { + .read_raw = &adis16460_read_raw, + .write_raw = &adis16460_write_raw, + .update_scan_mode = adis_update_scan_mode, + .debugfs_reg_access = adis_debugfs_reg_access, +}; + +static int adis16460_enable_irq(struct adis *adis, bool enable) +{ + /* + * There is no way to gate the data-ready signal internally inside the + * ADIS16460 :( + */ + if (enable) + enable_irq(adis->spi->irq); + else + disable_irq(adis->spi->irq); + + return 0; +} + +static int adis16460_initial_setup(struct iio_dev *indio_dev) +{ + struct adis16460 *st = iio_priv(indio_dev); + uint16_t prod_id; + unsigned int device_id; + int ret; + + adis_reset(&st->adis); + msleep(222); + + ret = adis_write_reg_16(&st->adis, ADIS16460_REG_GLOB_CMD, BIT(1)); + if (ret) + return ret; + msleep(75); + + ret = adis_check_status(&st->adis); + if (ret) + return ret; + + ret = adis_read_reg_16(&st->adis, ADIS16460_REG_PROD_ID, &prod_id); + if (ret) + return ret; + + ret = sscanf(indio_dev->name, "adis%u\n", &device_id); + if (ret != 1) + return -EINVAL; + + if (prod_id != device_id) + dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.", + device_id, prod_id); + + return 0; +} + +#define ADIS16460_DIAG_STAT_IN_CLK_OOS 7 +#define ADIS16460_DIAG_STAT_FLASH_MEM 6 +#define ADIS16460_DIAG_STAT_SELF_TEST 5 +#define ADIS16460_DIAG_STAT_OVERRANGE 4 +#define ADIS16460_DIAG_STAT_SPI_COMM 3 +#define ADIS16460_DIAG_STAT_FLASH_UPT 2 + +static const char * const adis16460_status_error_msgs[] = { + [ADIS16460_DIAG_STAT_IN_CLK_OOS] = "Input clock out of sync", + [ADIS16460_DIAG_STAT_FLASH_MEM] = "Flash memory failure", + [ADIS16460_DIAG_STAT_SELF_TEST] = "Self test diagnostic failure", + [ADIS16460_DIAG_STAT_OVERRANGE] = "Sensor overrange", + [ADIS16460_DIAG_STAT_SPI_COMM] = "SPI communication failure", + [ADIS16460_DIAG_STAT_FLASH_UPT] = "Flash update failure", +}; + +static const struct adis_data adis16460_data = { + .diag_stat_reg = ADIS16460_REG_DIAG_STAT, + .glob_cmd_reg = ADIS16460_REG_GLOB_CMD, + .has_paging = false, + .read_delay = 5, + .write_delay = 5, + .cs_change_delay = 16, + .status_error_msgs = adis16460_status_error_msgs, + .status_error_mask = BIT(ADIS16460_DIAG_STAT_IN_CLK_OOS) | + BIT(ADIS16460_DIAG_STAT_FLASH_MEM) | + BIT(ADIS16460_DIAG_STAT_SELF_TEST) | + BIT(ADIS16460_DIAG_STAT_OVERRANGE) | + BIT(ADIS16460_DIAG_STAT_SPI_COMM) | + BIT(ADIS16460_DIAG_STAT_FLASH_UPT), + .enable_irq = adis16460_enable_irq, +}; + +static int adis16460_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct adis16460 *st; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (indio_dev == NULL) + return -ENOMEM; + + spi_set_drvdata(spi, indio_dev); + + st = iio_priv(indio_dev); + + st->chip_info = &adis16460_chip_info; + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->channels = st->chip_info->channels; + indio_dev->num_channels = st->chip_info->num_channels; + indio_dev->info = &adis16460_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = adis_init(&st->adis, indio_dev, spi, &adis16460_data); + if (ret) + return ret; + + ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL); + if (ret) + return ret; + + adis16460_enable_irq(&st->adis, 0); + + ret = adis16460_initial_setup(indio_dev); + if (ret) + goto error_cleanup_buffer; + + ret = iio_device_register(indio_dev); + if (ret) + goto error_cleanup_buffer; + + adis16460_debugfs_init(indio_dev); + + return 0; + +error_cleanup_buffer: + adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); + return ret; +} + +static int adis16460_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct adis16460 *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); + + return 0; +} + +static const struct spi_device_id adis16460_ids[] = { + { "adis16460", 0 }, + {} +}; +MODULE_DEVICE_TABLE(spi, adis16460_ids); + +static const struct of_device_id adis16460_of_match[] = { + { .compatible = "adi,adis16460" }, + {} +}; +MODULE_DEVICE_TABLE(of, adis16460_of_match); + +static struct spi_driver adis16460_driver = { + .driver = { + .name = "adis16460", + .of_match_table = adis16460_of_match, + }, + .id_table = adis16460_ids, + .probe = adis16460_probe, + .remove = adis16460_remove, +}; +module_spi_driver(adis16460_driver); + +MODULE_AUTHOR("Dragos Bogdan "); +MODULE_DESCRIPTION("Analog Devices ADIS16460 IMU driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig index 395f3bd7de0a91e795be70fac172e8e1e73d9b13..e4c4c12236a709b4028ba3777c3b3367391b60c2 100644 --- a/drivers/iio/imu/inv_mpu6050/Kconfig +++ b/drivers/iio/imu/inv_mpu6050/Kconfig @@ -14,8 +14,9 @@ config INV_MPU6050_I2C select INV_MPU6050_IIO select REGMAP_I2C help - This driver supports the Invensense MPU6050/6500/9150 and - ICM20608/20602 motion tracking devices over I2C. + This driver supports the Invensense MPU6000/6050/6500/6515, + MPU9150/9250/9255 and ICM20608/20602 motion tracking devices + over I2C. This driver can be built as a module. The module will be called inv-mpu6050-i2c. @@ -25,7 +26,8 @@ config INV_MPU6050_SPI select INV_MPU6050_IIO select REGMAP_SPI help - This driver supports the Invensense MPU6050/6500/9150 and - ICM20608/20602 motion tracking devices over SPI. + This driver supports the Invensense MPU6000/6050/6500/6515, + MPU9150/9250/9255 and ICM20608/20602 motion tracking devices + over SPI. This driver can be built as a module. The module will be called inv-mpu6050-spi. diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 8a704cd5bddb7d7399bf8dc6d7d39652974267d7..b17f060b52fc7ba39f2dc2eb3f7ea7b545beee14 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -1137,10 +1137,9 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, if (result) return result; - result = devm_add_action(dev, inv_mpu_core_disable_regulator_action, + result = devm_add_action_or_reset(dev, inv_mpu_core_disable_regulator_action, st); if (result) { - inv_mpu_core_disable_regulator_action(st); dev_err(dev, "Failed to setup regulator cleanup action %d\n", result); return result; diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 002a423eae52cb30ebe30ca65a6e5d49c0f2e65f..77aa0e77212d11101a50c8f0bac316e4a5584d33 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -2,15 +2,17 @@ config IIO_ST_LSM6DSX tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors" - depends on (I2C || SPI) + depends on (I2C || SPI || I3C) select IIO_BUFFER select IIO_KFIFO_BUF select IIO_ST_LSM6DSX_I2C if (I2C) select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) + select IIO_ST_LSM6DSX_I3C if (I3C) help Say yes here to build support for STMicroelectronics LSM6DSx imu sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, - ism330dlc, lsm6dso, lsm6dsox, asm330lhh, lsm6dsr + ism330dlc, lsm6dso, lsm6dsox, asm330lhh, lsm6dsr, lsm6ds3tr-c, + ism330dhcx and the accelerometer/gyroscope of lsm9ds1. To compile this driver as a module, choose M here: the module will be called st_lsm6dsx. @@ -24,3 +26,8 @@ config IIO_ST_LSM6DSX_SPI tristate depends on IIO_ST_LSM6DSX select REGMAP_SPI + +config IIO_ST_LSM6DSX_I3C + tristate + depends on IIO_ST_LSM6DSX + select REGMAP_I3C diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile b/drivers/iio/imu/st_lsm6dsx/Makefile index 28cc67399d94f25346fbf15e76f9d20bc668e694..57cbcd67d64ff925a2d287ed3908655785c8e08b 100644 --- a/drivers/iio/imu/st_lsm6dsx/Makefile +++ b/drivers/iio/imu/st_lsm6dsx/Makefile @@ -5,3 +5,4 @@ st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \ obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o +obj-$(CONFIG_IIO_ST_LSM6DSX_I3C) += st_lsm6dsx_i3c.o diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index c14bf533b66b39b06c422d0cd4431733c89ba7c9..80e42c7dbcbe63039f4d23ed363799c75a1d9698 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -22,6 +22,9 @@ #define ST_ASM330LHH_DEV_NAME "asm330lhh" #define ST_LSM6DSOX_DEV_NAME "lsm6dsox" #define ST_LSM6DSR_DEV_NAME "lsm6dsr" +#define ST_LSM6DS3TRC_DEV_NAME "lsm6ds3tr-c" +#define ST_ISM330DHCX_DEV_NAME "ism330dhcx" +#define ST_LSM9DS1_DEV_NAME "lsm9ds1-imu" enum st_lsm6dsx_hw_id { ST_LSM6DS3_ID, @@ -33,6 +36,9 @@ enum st_lsm6dsx_hw_id { ST_ASM330LHH_ID, ST_LSM6DSOX_ID, ST_LSM6DSR_ID, + ST_LSM6DS3TRC_ID, + ST_ISM330DHCX_ID, + ST_LSM9DS1_ID, ST_LSM6DSX_MAX_ID, }; @@ -54,8 +60,8 @@ enum st_lsm6dsx_hw_id { .address = addr, \ .modified = 1, \ .channel2 = mod, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .scan_index = scan_idx, \ .scan_type = { \ @@ -71,6 +77,7 @@ struct st_lsm6dsx_reg { u8 mask; }; +struct st_lsm6dsx_sensor; struct st_lsm6dsx_hw; struct st_lsm6dsx_odr { @@ -97,12 +104,14 @@ struct st_lsm6dsx_fs_table_entry { /** * struct st_lsm6dsx_fifo_ops - ST IMU FIFO settings + * @update_fifo: Update FIFO configuration callback. * @read_fifo: Read FIFO callback. * @fifo_th: FIFO threshold register info (addr + mask). * @fifo_diff: FIFO diff status register info (addr + mask). * @th_wl: FIFO threshold word length. */ struct st_lsm6dsx_fifo_ops { + int (*update_fifo)(struct st_lsm6dsx_sensor *sensor, bool enable); int (*read_fifo)(struct st_lsm6dsx_hw *hw); struct { u8 addr; @@ -196,8 +205,14 @@ struct st_lsm6dsx_ext_dev_settings { /** * struct st_lsm6dsx_settings - ST IMU sensor settings * @wai: Sensor WhoAmI default value. + * @int1_addr: Control Register address for INT1 + * @int2_addr: Control Register address for INT2 + * @reset_addr: register address for reset/reboot * @max_fifo_size: Sensor max fifo length in FIFO words. * @id: List of hw id/device name supported by the driver configuration. + * @channels: IIO channels supported by the device. + * @odr_table: Hw sensors odr table (Hz + val). + * @fs_table: Hw sensors gain table (gain + val). * @decimator: List of decimator register info (addr + mask). * @batch: List of FIFO batching register info (addr + mask). * @fifo_ops: Sensor hw FIFO parameters. @@ -206,11 +221,20 @@ struct st_lsm6dsx_ext_dev_settings { */ struct st_lsm6dsx_settings { u8 wai; + u8 int1_addr; + u8 int2_addr; + u8 reset_addr; u16 max_fifo_size; struct { enum st_lsm6dsx_hw_id hw_id; const char *name; } id[ST_LSM6DSX_MAX_ID]; + struct { + const struct iio_chan_spec *chan; + int len; + } channels[2]; + struct st_lsm6dsx_odr_table_entry odr_table[2]; + struct st_lsm6dsx_fs_table_entry fs_table[2]; struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID]; struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID]; struct st_lsm6dsx_fifo_ops fifo_ops; @@ -314,6 +338,7 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw); int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val); int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark); +int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable); int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw); int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw, enum st_lsm6dsx_fifo_mode fifo_mode); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index e4d8a79d557de799a077ea8c9c4c107a5b0f23ee..b0f3da1976e4f46949c2f23e097707989a9aea93 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -2,10 +2,10 @@ /* * STMicroelectronics st_lsm6dsx FIFO buffer library driver * - * LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC: The FIFO buffer can be - * configured to store data from gyroscope and accelerometer. Samples are - * queued without any tag according to a specific pattern based on - * 'FIFO data sets' (6 bytes each): + * LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C: + * The FIFO buffer can be configured to store data from gyroscope and + * accelerometer. Samples are queued without any tag according to a + * specific pattern based on 'FIFO data sets' (6 bytes each): * - 1st data set is reserved for gyroscope data * - 2nd data set is reserved for accelerometer data * The FIFO pattern changes depending on the ODRs and decimation factors @@ -14,9 +14,10 @@ * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the * value of the decimation factor and ODR set for each FIFO data set. * - * LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR: The FIFO buffer can be configured to - * store data from gyroscope and accelerometer. Each sample is queued with - * a tag (1B) indicating data source (gyroscope, accelerometer, hw timer). + * LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX: The FIFO buffer can be + * configured to store data from gyroscope and accelerometer. Each sample + * is queued with a tag (1B) indicating data source (gyroscope, accelerometer, + * hw timer). * * FIFO supported modes: * - BYPASS: FIFO disabled @@ -601,9 +602,8 @@ int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw) return err; } -static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable) +int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable) { - struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); struct st_lsm6dsx_hw *hw = sensor->hw; int err; @@ -670,17 +670,29 @@ static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private) count = hw->settings->fifo_ops.read_fifo(hw); mutex_unlock(&hw->fifo_lock); - return !count ? IRQ_NONE : IRQ_HANDLED; + return count ? IRQ_HANDLED : IRQ_NONE; } static int st_lsm6dsx_buffer_preenable(struct iio_dev *iio_dev) { - return st_lsm6dsx_update_fifo(iio_dev, true); + struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); + struct st_lsm6dsx_hw *hw = sensor->hw; + + if (!hw->settings->fifo_ops.update_fifo) + return -ENOTSUPP; + + return hw->settings->fifo_ops.update_fifo(sensor, true); } static int st_lsm6dsx_buffer_postdisable(struct iio_dev *iio_dev) { - return st_lsm6dsx_update_fifo(iio_dev, false); + struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); + struct st_lsm6dsx_hw *hw = sensor->hw; + + if (!hw->settings->fifo_ops.update_fifo) + return -ENOTSUPP; + + return hw->settings->fifo_ops.update_fifo(sensor, false); } static const struct iio_buffer_setup_ops st_lsm6dsx_buffer_ops = { diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index a6702a74570e206784c250758ccec14563436af3..2d34955601368870cb8ee931600a67146c5bb3e7 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -10,6 +10,8 @@ * +-125/+-245/+-500/+-1000/+-2000 dps * LSM6DSx series has an integrated First-In-First-Out (FIFO) buffer * allowing dynamic batching of sensor data. + * LSM9DSx series is similar but includes an additional magnetometer, handled + * by a different driver. * * Supported sensors: * - LSM6DS3: @@ -18,18 +20,25 @@ * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 8KB * - * - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC: + * - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C: * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 4KB * - * - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR + * - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX: * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 3KB * + * - LSM9DS1: + * - Accelerometer supported ODR [Hz]: 10, 50, 119, 238, 476, 952 + * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 + * - Gyroscope supported ODR [Hz]: 15, 60, 119, 238, 476, 952 + * - Gyroscope supported full-scale [dps]: +-245/+-500/+-2000 + * - FIFO size: 32 + * * Copyright 2016 STMicroelectronics Inc. * * Lorenzo Bianconi @@ -49,79 +58,110 @@ #include "st_lsm6dsx.h" -#define ST_LSM6DSX_REG_INT1_ADDR 0x0d -#define ST_LSM6DSX_REG_INT2_ADDR 0x0e #define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK BIT(3) #define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f -#define ST_LSM6DSX_REG_RESET_ADDR 0x12 #define ST_LSM6DSX_REG_RESET_MASK BIT(0) #define ST_LSM6DSX_REG_BOOT_MASK BIT(7) #define ST_LSM6DSX_REG_BDU_ADDR 0x12 #define ST_LSM6DSX_REG_BDU_MASK BIT(6) -#define ST_LSM6DSX_REG_INT2_ON_INT1_ADDR 0x13 -#define ST_LSM6DSX_REG_INT2_ON_INT1_MASK BIT(5) - -#define ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR 0x28 -#define ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR 0x2a -#define ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR 0x2c - -#define ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR 0x22 -#define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR 0x24 -#define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR 0x26 - -static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = { - [ST_LSM6DSX_ID_ACC] = { - .reg = { - .addr = 0x10, - .mask = GENMASK(7, 4), - }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, - }, - [ST_LSM6DSX_ID_GYRO] = { - .reg = { - .addr = 0x11, - .mask = GENMASK(7, 4), - }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, - } + +static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = { + ST_LSM6DSX_CHANNEL(IIO_ACCEL, 0x28, IIO_MOD_X, 0), + ST_LSM6DSX_CHANNEL(IIO_ACCEL, 0x2a, IIO_MOD_Y, 1), + ST_LSM6DSX_CHANNEL(IIO_ACCEL, 0x2c, IIO_MOD_Z, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), }; -static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = { - [ST_LSM6DSX_ID_ACC] = { - .reg = { - .addr = 0x10, - .mask = GENMASK(3, 2), - }, - .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, - .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, - .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, - .fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 }, - }, - [ST_LSM6DSX_ID_GYRO] = { - .reg = { - .addr = 0x11, - .mask = GENMASK(3, 2), - }, - .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, - .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, - .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 }, - .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, - } +static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = { + ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x22, IIO_MOD_X, 0), + ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x24, IIO_MOD_Y, 1), + ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x26, IIO_MOD_Z, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct iio_chan_spec st_lsm6ds0_gyro_channels[] = { + ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x18, IIO_MOD_X, 0), + ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x1a, IIO_MOD_Y, 1), + ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x1c, IIO_MOD_Z, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), }; static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { + { + .wai = 0x68, + .int1_addr = 0x0c, + .int2_addr = 0x0d, + .reset_addr = 0x22, + .max_fifo_size = 32, + .id = { + { + .hw_id = ST_LSM9DS1_ID, + .name = ST_LSM9DS1_DEV_NAME, + }, + }, + .channels = { + [ST_LSM6DSX_ID_ACC] = { + .chan = st_lsm6dsx_acc_channels, + .len = ARRAY_SIZE(st_lsm6dsx_acc_channels), + }, + [ST_LSM6DSX_ID_GYRO] = { + .chan = st_lsm6ds0_gyro_channels, + .len = ARRAY_SIZE(st_lsm6ds0_gyro_channels), + }, + }, + .odr_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x20, + .mask = GENMASK(7, 5), + }, + .odr_avl[0] = { 10, 0x01 }, + .odr_avl[1] = { 50, 0x02 }, + .odr_avl[2] = { 119, 0x03 }, + .odr_avl[3] = { 238, 0x04 }, + .odr_avl[4] = { 476, 0x05 }, + .odr_avl[5] = { 952, 0x06 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(7, 5), + }, + .odr_avl[0] = { 15, 0x01 }, + .odr_avl[1] = { 60, 0x02 }, + .odr_avl[2] = { 119, 0x03 }, + .odr_avl[3] = { 238, 0x04 }, + .odr_avl[4] = { 476, 0x05 }, + .odr_avl[5] = { 952, 0x06 }, + }, + }, + .fs_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x20, + .mask = GENMASK(4, 3), + }, + .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, + .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, + .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, + .fs_avl[3] = { IIO_G_TO_M_S_2(732), 0x1 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(4, 3), + }, + .fs_avl[0] = { IIO_DEGREE_TO_RAD(245), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(500), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(2000), 0x3 }, + }, + }, + }, { .wai = 0x69, + .int1_addr = 0x0d, + .int2_addr = 0x0e, + .reset_addr = 0x12, .max_fifo_size = 1365, .id = { { @@ -129,6 +169,64 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .name = ST_LSM6DS3_DEV_NAME, }, }, + .channels = { + [ST_LSM6DSX_ID_ACC] = { + .chan = st_lsm6dsx_acc_channels, + .len = ARRAY_SIZE(st_lsm6dsx_acc_channels), + }, + [ST_LSM6DSX_ID_GYRO] = { + .chan = st_lsm6dsx_gyro_channels, + .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), + }, + }, + .odr_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + }, + .fs_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, + .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, + .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, + .fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 }, + .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, + }, + }, .decimator = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x08, @@ -140,6 +238,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, }, .fifo_ops = { + .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_fifo, .fifo_th = { .addr = 0x06, @@ -172,6 +271,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x69, + .int1_addr = 0x0d, + .int2_addr = 0x0e, + .reset_addr = 0x12, .max_fifo_size = 682, .id = { { @@ -179,6 +281,64 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .name = ST_LSM6DS3H_DEV_NAME, }, }, + .channels = { + [ST_LSM6DSX_ID_ACC] = { + .chan = st_lsm6dsx_acc_channels, + .len = ARRAY_SIZE(st_lsm6dsx_acc_channels), + }, + [ST_LSM6DSX_ID_GYRO] = { + .chan = st_lsm6dsx_gyro_channels, + .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), + }, + }, + .odr_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + }, + .fs_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, + .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, + .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, + .fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 }, + .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, + }, + }, .decimator = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x08, @@ -190,6 +350,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, }, .fifo_ops = { + .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_fifo, .fifo_th = { .addr = 0x06, @@ -222,6 +383,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x6a, + .int1_addr = 0x0d, + .int2_addr = 0x0e, + .reset_addr = 0x12, .max_fifo_size = 682, .id = { { @@ -233,6 +397,67 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .hw_id = ST_ISM330DLC_ID, .name = ST_ISM330DLC_DEV_NAME, + }, { + .hw_id = ST_LSM6DS3TRC_ID, + .name = ST_LSM6DS3TRC_DEV_NAME, + }, + }, + .channels = { + [ST_LSM6DSX_ID_ACC] = { + .chan = st_lsm6dsx_acc_channels, + .len = ARRAY_SIZE(st_lsm6dsx_acc_channels), + }, + [ST_LSM6DSX_ID_GYRO] = { + .chan = st_lsm6dsx_gyro_channels, + .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), + }, + }, + .odr_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + }, + .fs_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, + .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, + .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, + .fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 }, + .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, }, }, .decimator = { @@ -246,6 +471,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, }, .fifo_ops = { + .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_fifo, .fifo_th = { .addr = 0x06, @@ -278,6 +504,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x6c, + .int1_addr = 0x0d, + .int2_addr = 0x0e, + .reset_addr = 0x12, .max_fifo_size = 512, .id = { { @@ -288,6 +517,64 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .name = ST_LSM6DSOX_DEV_NAME, }, }, + .channels = { + [ST_LSM6DSX_ID_ACC] = { + .chan = st_lsm6dsx_acc_channels, + .len = ARRAY_SIZE(st_lsm6dsx_acc_channels), + }, + [ST_LSM6DSX_ID_GYRO] = { + .chan = st_lsm6dsx_gyro_channels, + .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), + }, + }, + .odr_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + }, + .fs_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, + .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, + .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, + .fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 }, + .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, + }, + }, .batch = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x09, @@ -299,6 +586,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, }, .fifo_ops = { + .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_tagged_fifo, .fifo_th = { .addr = 0x07, @@ -306,7 +594,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, .fifo_diff = { .addr = 0x3a, - .mask = GENMASK(8, 0), + .mask = GENMASK(9, 0), }, .th_wl = 1, }, @@ -349,6 +637,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x6b, + .int1_addr = 0x0d, + .int2_addr = 0x0e, + .reset_addr = 0x12, .max_fifo_size = 512, .id = { { @@ -356,6 +647,64 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .name = ST_ASM330LHH_DEV_NAME, }, }, + .channels = { + [ST_LSM6DSX_ID_ACC] = { + .chan = st_lsm6dsx_acc_channels, + .len = ARRAY_SIZE(st_lsm6dsx_acc_channels), + }, + [ST_LSM6DSX_ID_GYRO] = { + .chan = st_lsm6dsx_gyro_channels, + .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), + }, + }, + .odr_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + }, + .fs_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, + .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, + .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, + .fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 }, + .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, + }, + }, .batch = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x09, @@ -367,6 +716,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, }, .fifo_ops = { + .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_tagged_fifo, .fifo_th = { .addr = 0x07, @@ -374,7 +724,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, .fifo_diff = { .addr = 0x3a, - .mask = GENMASK(8, 0), + .mask = GENMASK(9, 0), }, .th_wl = 1, }, @@ -391,11 +741,75 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x6b, + .int1_addr = 0x0d, + .int2_addr = 0x0e, + .reset_addr = 0x12, .max_fifo_size = 512, .id = { { .hw_id = ST_LSM6DSR_ID, .name = ST_LSM6DSR_DEV_NAME, + }, { + .hw_id = ST_ISM330DHCX_ID, + .name = ST_ISM330DHCX_DEV_NAME, + }, + }, + .channels = { + [ST_LSM6DSX_ID_ACC] = { + .chan = st_lsm6dsx_acc_channels, + .len = ARRAY_SIZE(st_lsm6dsx_acc_channels), + }, + [ST_LSM6DSX_ID_GYRO] = { + .chan = st_lsm6dsx_gyro_channels, + .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), + }, + }, + .odr_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + }, + .fs_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, + .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, + .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, + .fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 }, + .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, }, }, .batch = { @@ -409,6 +823,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, }, .fifo_ops = { + .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_tagged_fifo, .fifo_th = { .addr = 0x07, @@ -416,7 +831,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, .fifo_diff = { .addr = 0x3a, - .mask = GENMASK(8, 0), + .mask = GENMASK(9, 0), }, .th_wl = 1, }, @@ -459,26 +874,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, }; -static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = { - ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR, - IIO_MOD_X, 0), - ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR, - IIO_MOD_Y, 1), - ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR, - IIO_MOD_Z, 2), - IIO_CHAN_SOFT_TIMESTAMP(3), -}; - -static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = { - ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR, - IIO_MOD_X, 0), - ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR, - IIO_MOD_Y, 1), - ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR, - IIO_MOD_Z, 2), - IIO_CHAN_SOFT_TIMESTAMP(3), -}; - int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable) { const struct st_lsm6dsx_shub_settings *hub_settings; @@ -533,23 +928,22 @@ static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id, static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor, u32 gain) { - struct st_lsm6dsx_hw *hw = sensor->hw; - const struct st_lsm6dsx_reg *reg; + const struct st_lsm6dsx_fs_table_entry *fs_table; unsigned int data; int i, err; - u8 val; + fs_table = &sensor->hw->settings->fs_table[sensor->id]; for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) - if (st_lsm6dsx_fs_table[sensor->id].fs_avl[i].gain == gain) + if (fs_table->fs_avl[i].gain == gain) break; if (i == ST_LSM6DSX_FS_LIST_SIZE) return -EINVAL; - val = st_lsm6dsx_fs_table[sensor->id].fs_avl[i].val; - reg = &st_lsm6dsx_fs_table[sensor->id].reg; - data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask); - err = st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data); + data = ST_LSM6DSX_SHIFT_VAL(fs_table->fs_avl[i].val, + fs_table->reg.mask); + err = st_lsm6dsx_update_bits_locked(sensor->hw, fs_table->reg.addr, + fs_table->reg.mask, data); if (err < 0) return err; @@ -560,20 +954,22 @@ static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor, int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val) { + const struct st_lsm6dsx_odr_table_entry *odr_table; int i; + odr_table = &sensor->hw->settings->odr_table[sensor->id]; for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) /* * ext devices can run at different odr respect to * accel sensor */ - if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz >= odr) + if (odr_table->odr_avl[i].hz >= odr) break; if (i == ST_LSM6DSX_ODR_LIST_SIZE) return -EINVAL; - *val = st_lsm6dsx_odr_table[sensor->id].odr_avl[i].val; + *val = odr_table->odr_avl[i].val; return 0; } @@ -638,7 +1034,7 @@ static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr) return err; } - reg = &st_lsm6dsx_odr_table[ref_sensor->id].reg; + reg = &hw->settings->odr_table[ref_sensor->id].reg; data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask); return st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data); } @@ -783,11 +1179,12 @@ st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev, { struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); enum st_lsm6dsx_sensor_id id = sensor->id; + struct st_lsm6dsx_hw *hw = sensor->hw; int i, len = 0; for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", - st_lsm6dsx_odr_table[id].odr_avl[i].hz); + hw->settings->odr_table[id].odr_avl[i].hz); buf[len - 1] = '\n'; return len; @@ -798,12 +1195,19 @@ static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev, char *buf) { struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); + const struct st_lsm6dsx_fs_table_entry *fs_table; enum st_lsm6dsx_sensor_id id = sensor->id; + struct st_lsm6dsx_hw *hw = sensor->hw; int i, len = 0; - for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) + fs_table = &hw->settings->fs_table[id]; + for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) { + if (!fs_table->fs_avl[i].gain) + break; + len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ", - st_lsm6dsx_fs_table[id].fs_avl[i].gain); + fs_table->fs_avl[i].gain); + } buf[len - 1] = '\n'; return len; @@ -873,10 +1277,10 @@ static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg) switch (drdy_pin) { case 1: - *drdy_reg = ST_LSM6DSX_REG_INT1_ADDR; + *drdy_reg = hw->settings->int1_addr; break; case 2: - *drdy_reg = ST_LSM6DSX_REG_INT2_ADDR; + *drdy_reg = hw->settings->int2_addr; break; default: dev_err(hw->dev, "unsupported data ready pin\n"); @@ -976,7 +1380,7 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) int err; /* device sw reset */ - err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR, + err = regmap_update_bits(hw->regmap, hw->settings->reset_addr, ST_LSM6DSX_REG_RESET_MASK, FIELD_PREP(ST_LSM6DSX_REG_RESET_MASK, 1)); if (err < 0) @@ -985,7 +1389,7 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) msleep(50); /* reload trimming parameter */ - err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR, + err = regmap_update_bits(hw->regmap, hw->settings->reset_addr, ST_LSM6DSX_REG_BOOT_MASK, FIELD_PREP(ST_LSM6DSX_REG_BOOT_MASK, 1)); if (err < 0) @@ -1033,28 +1437,24 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw, iio_dev->modes = INDIO_DIRECT_MODE; iio_dev->dev.parent = hw->dev; iio_dev->available_scan_masks = st_lsm6dsx_available_scan_masks; + iio_dev->channels = hw->settings->channels[id].chan; + iio_dev->num_channels = hw->settings->channels[id].len; sensor = iio_priv(iio_dev); sensor->id = id; sensor->hw = hw; - sensor->odr = st_lsm6dsx_odr_table[id].odr_avl[0].hz; - sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain; + sensor->odr = hw->settings->odr_table[id].odr_avl[0].hz; + sensor->gain = hw->settings->fs_table[id].fs_avl[0].gain; sensor->watermark = 1; switch (id) { case ST_LSM6DSX_ID_ACC: - iio_dev->channels = st_lsm6dsx_acc_channels; - iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels); iio_dev->info = &st_lsm6dsx_acc_info; - scnprintf(sensor->name, sizeof(sensor->name), "%s_accel", name); break; case ST_LSM6DSX_ID_GYRO: - iio_dev->channels = st_lsm6dsx_gyro_channels; - iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels); iio_dev->info = &st_lsm6dsx_gyro_info; - scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro", name); break; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index b3211e0ac07bf2ecc272d3d944070386d6c36796..f5251105954584f72ee7f181acf24a744e5cca3b 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -75,6 +75,18 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { .compatible = "st,lsm6dsr", .data = (void *)ST_LSM6DSR_ID, }, + { + .compatible = "st,lsm6ds3tr-c", + .data = (void *)ST_LSM6DS3TRC_ID, + }, + { + .compatible = "st,ism330dhcx", + .data = (void *)ST_ISM330DHCX_ID, + }, + { + .compatible = "st,lsm9ds1-imu", + .data = (void *)ST_LSM9DS1_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); @@ -89,6 +101,9 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { { ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID }, { ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID }, { ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID }, + { ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID }, + { ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID }, + { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID }, {}, }; MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c new file mode 100644 index 0000000000000000000000000000000000000000..57e633121bdc0dbb039884dbdb53d6be5ad84b0e --- /dev/null +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. + * + * Author: Vitor Soares + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "st_lsm6dsx.h" + +static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = { + I3C_DEVICE(0x0104, 0x006C, (void *)ST_LSM6DSO_ID), + I3C_DEVICE(0x0104, 0x006B, (void *)ST_LSM6DSR_ID), + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(i3c, st_lsm6dsx_i3c_ids); + +static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev) +{ + struct regmap_config st_lsm6dsx_i3c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + }; + const struct i3c_device_id *id = i3c_device_match_id(i3cdev, + st_lsm6dsx_i3c_ids); + struct regmap *regmap; + + 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)); + return PTR_ERR(regmap); + } + + return st_lsm6dsx_probe(&i3cdev->dev, 0, (uintptr_t)id->data, regmap); +} + +static struct i3c_driver st_lsm6dsx_driver = { + .driver = { + .name = "st_lsm6dsx_i3c", + .pm = &st_lsm6dsx_pm_ops, + }, + .probe = st_lsm6dsx_i3c_probe, + .id_table = st_lsm6dsx_i3c_ids, +}; +module_i3c_driver(st_lsm6dsx_driver); + +MODULE_AUTHOR("Vitor Soares "); +MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i3c driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index c9d3c4711018f1c7cc4790783d18da3933565517..344b28dddebb7771dae9c937723aff0b7b4fa05b 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -75,6 +75,18 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { .compatible = "st,lsm6dsr", .data = (void *)ST_LSM6DSR_ID, }, + { + .compatible = "st,lsm6ds3tr-c", + .data = (void *)ST_LSM6DS3TRC_ID, + }, + { + .compatible = "st,ism330dhcx", + .data = (void *)ST_ISM330DHCX_ID, + }, + { + .compatible = "st,lsm9ds1-imu", + .data = (void *)ST_LSM9DS1_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); @@ -89,6 +101,9 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { { ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID }, { ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID }, { ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID }, + { ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID }, + { ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID }, + { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID }, {}, }; MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index e3fd00b595d0b4ce261ec327e8f035d3d6a28c51..08d7e1ef21861b56ff3415b86da7ab762f42dd1e 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -303,6 +303,7 @@ config MAX44000 config MAX44009 tristate "MAX44009 Ambient Light Sensor" depends on I2C + select REGMAP_I2C help Say Y here if you want to build support for Maxim Integrated's MAX44009 ambient light sensor device. @@ -310,6 +311,16 @@ config MAX44009 To compile this driver as a module, choose M here: the module will be called max44009. +config NOA1305 + tristate "ON Semiconductor NOA1305 ambient light sensor" + depends on I2C + help + Say Y here if you want to build support for the ON Semiconductor + NOA1305 ambient light sensor. + + To compile this driver as a module, choose M here: + The module will be called noa1305. + config OPT3001 tristate "Texas Instruments OPT3001 Light Sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index e40794fbb43522cb9f14dea9e2f6d7873867056e..00d1f9b98f39de597c1e0a61fdbf07ac6b3ef9b7 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_LTR501) += ltr501.o obj-$(CONFIG_LV0104CS) += lv0104cs.o obj-$(CONFIG_MAX44000) += max44000.o obj-$(CONFIG_MAX44009) += max44009.o +obj-$(CONFIG_NOA1305) += noa1305.o obj-$(CONFIG_OPT3001) += opt3001.o obj-$(CONFIG_PA12203001) += pa12203001.o obj-$(CONFIG_RPR0521) += rpr0521.o diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index b09b8b60bd83b6afe443086c373e841c23cae948..c5dfb9a6b5a1129091421441a0c9a8a22ef9c528 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -1135,5 +1135,5 @@ static struct i2c_driver apds9960_driver = { module_i2c_driver(apds9960_driver); MODULE_AUTHOR("Matt Ranostay "); -MODULE_DESCRIPTION("ADPS9960 Gesture/RGB/ALS/Proximity sensor"); +MODULE_DESCRIPTION("APDS9960 Gesture/RGB/ALS/Proximity sensor"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c index 50f3438c2b498eb8b5aa545cbd4f1476bc3b6f57..0443861ba1ec924be6def0bd39075a1e59d14a3d 100644 --- a/drivers/iio/light/cm3323.c +++ b/drivers/iio/light/cm3323.c @@ -101,15 +101,16 @@ static int cm3323_init(struct iio_dev *indio_dev) return 0; } -static void cm3323_disable(struct iio_dev *indio_dev) +static void cm3323_disable(void *data) { int ret; - struct cm3323_data *data = iio_priv(indio_dev); + struct iio_dev *indio_dev = data; + struct cm3323_data *cm_data = iio_priv(indio_dev); - ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, + ret = i2c_smbus_write_word_data(cm_data->client, CM3323_CMD_CONF, CM3323_CONF_SD_BIT); if (ret < 0) - dev_err(&data->client->dev, "Error writing reg_conf\n"); + dev_err(&cm_data->client->dev, "Error writing reg_conf\n"); } static int cm3323_set_it_bits(struct cm3323_data *data, int val, int val2) @@ -243,26 +244,11 @@ static int cm3323_probe(struct i2c_client *client, return ret; } - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(&client->dev, "failed to register iio dev\n"); - goto err_init; - } - - return 0; -err_init: - cm3323_disable(indio_dev); - return ret; -} - -static int cm3323_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); - cm3323_disable(indio_dev); + ret = devm_add_action_or_reset(&client->dev, cm3323_disable, indio_dev); + if (ret < 0) + return ret; - return 0; + return devm_iio_device_register(&client->dev, indio_dev); } static const struct i2c_device_id cm3323_id[] = { @@ -276,7 +262,6 @@ static struct i2c_driver cm3323_driver = { .name = CM3323_DRV_NAME, }, .probe = cm3323_probe, - .remove = cm3323_remove, .id_table = cm3323_id, }; diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index 7702c2bcbcfa7b96f245a2a38fbc8cc65629c636..1019d625adb1e355a837e6313af81ac14ab4b769 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -646,18 +646,18 @@ static int cm36651_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); cm36651->client = client; - cm36651->ps_client = i2c_new_dummy(client->adapter, + cm36651->ps_client = i2c_new_dummy_device(client->adapter, CM36651_I2C_ADDR_PS); - if (!cm36651->ps_client) { + if (IS_ERR(cm36651->ps_client)) { dev_err(&client->dev, "%s: new i2c device failed\n", __func__); - ret = -ENODEV; + ret = PTR_ERR(cm36651->ps_client); goto error_disable_reg; } - cm36651->ara_client = i2c_new_dummy(client->adapter, CM36651_ARA); - if (!cm36651->ara_client) { + cm36651->ara_client = i2c_new_dummy_device(client->adapter, CM36651_ARA); + if (IS_ERR(cm36651->ara_client)) { dev_err(&client->dev, "%s: new i2c device failed\n", __func__); - ret = -ENODEV; + ret = PTR_ERR(cm36651->ara_client); goto error_i2c_unregister_ps; } diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c index 308ee6ff2e22ce70fc9aba349f2b83fb6a3a637f..44313a009928ee4ab9cfeb462db91ada4f46ff63 100644 --- a/drivers/iio/light/cros_ec_light_prox.c +++ b/drivers/iio/light/cros_ec_light_prox.c @@ -42,7 +42,7 @@ static int cros_ec_light_prox_read(struct iio_dev *indio_dev, struct cros_ec_light_prox_state *st = iio_priv(indio_dev); u16 data = 0; s64 val64; - int ret = IIO_VAL_INT; + int ret; int idx = chan->scan_index; mutex_lock(&st->core.cmd_lock); @@ -50,23 +50,22 @@ static int cros_ec_light_prox_read(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: if (chan->type == IIO_PROXIMITY) { - if (cros_ec_sensors_read_cmd(indio_dev, 1 << idx, - (s16 *)&data) < 0) { - ret = -EIO; + ret = cros_ec_sensors_read_cmd(indio_dev, 1 << idx, + (s16 *)&data); + if (ret) break; - } *val = data; + ret = IIO_VAL_INT; } else { ret = -EINVAL; } break; case IIO_CHAN_INFO_PROCESSED: if (chan->type == IIO_LIGHT) { - if (cros_ec_sensors_read_cmd(indio_dev, 1 << idx, - (s16 *)&data) < 0) { - ret = -EIO; + ret = cros_ec_sensors_read_cmd(indio_dev, 1 << idx, + (s16 *)&data); + if (ret) break; - } /* * The data coming from the light sensor is * pre-processed and represents the ambient light @@ -82,15 +81,16 @@ static int cros_ec_light_prox_read(struct iio_dev *indio_dev, st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET; st->core.param.sensor_offset.flags = 0; - if (cros_ec_motion_send_host_cmd(&st->core, 0)) { - ret = -EIO; + ret = cros_ec_motion_send_host_cmd(&st->core, 0); + if (ret) break; - } /* Save values */ - st->core.calib[0] = st->core.resp->sensor_offset.offset[0]; + st->core.calib[0].offset = + st->core.resp->sensor_offset.offset[0]; - *val = st->core.calib[idx]; + *val = st->core.calib[idx].offset; + ret = IIO_VAL_INT; break; case IIO_CHAN_INFO_CALIBSCALE: /* @@ -101,10 +101,9 @@ static int cros_ec_light_prox_read(struct iio_dev *indio_dev, st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE; st->core.param.sensor_range.data = EC_MOTION_SENSE_NO_VALUE; - if (cros_ec_motion_send_host_cmd(&st->core, 0)) { - ret = -EIO; + ret = cros_ec_motion_send_host_cmd(&st->core, 0); + if (ret) break; - } val64 = st->core.resp->sensor_range.ret; *val = val64 >> 16; @@ -127,28 +126,27 @@ static int cros_ec_light_prox_write(struct iio_dev *indio_dev, int val, int val2, long mask) { struct cros_ec_light_prox_state *st = iio_priv(indio_dev); - int ret = 0; + int ret; int idx = chan->scan_index; mutex_lock(&st->core.cmd_lock); switch (mask) { case IIO_CHAN_INFO_CALIBBIAS: - st->core.calib[idx] = val; + st->core.calib[idx].offset = val; /* Send to EC for each axis, even if not complete */ st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET; st->core.param.sensor_offset.flags = MOTION_SENSE_SET_OFFSET; - st->core.param.sensor_offset.offset[0] = st->core.calib[0]; + st->core.param.sensor_offset.offset[0] = + st->core.calib[0].offset; st->core.param.sensor_offset.temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - if (cros_ec_motion_send_host_cmd(&st->core, 0)) - ret = -EIO; + ret = cros_ec_motion_send_host_cmd(&st->core, 0); break; case IIO_CHAN_INFO_CALIBSCALE: st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE; st->core.param.sensor_range.data = (val << 16) | (val2 / 100); - if (cros_ec_motion_send_host_cmd(&st->core, 0)) - ret = -EIO; + ret = cros_ec_motion_send_host_cmd(&st->core, 0); break; default: ret = cros_ec_sensors_core_write(&st->core, chan, val, val2, @@ -164,6 +162,7 @@ static int cros_ec_light_prox_write(struct iio_dev *indio_dev, static const struct iio_info cros_ec_light_prox_info = { .read_raw = &cros_ec_light_prox_read, .write_raw = &cros_ec_light_prox_write, + .read_avail = &cros_ec_sensors_core_read_avail, }; static int cros_ec_light_prox_probe(struct platform_device *pdev) @@ -198,6 +197,8 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev) channel->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_FREQUENCY); + channel->info_mask_shared_by_all_available = + BIT(IIO_CHAN_INFO_SAMP_FREQ); channel->scan_type.realbits = CROS_EC_SENSOR_BITS; channel->scan_type.storagebits = CROS_EC_SENSOR_BITS; channel->scan_type.shift = 0; @@ -205,8 +206,6 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev) channel->ext_info = cros_ec_sensors_ext_info; channel->scan_type.sign = 'u'; - state->core.calib[0] = 0; - /* Sensor specific */ switch (state->core.type) { case MOTIONSENSE_TYPE_LIGHT: diff --git a/drivers/iio/light/noa1305.c b/drivers/iio/light/noa1305.c new file mode 100644 index 0000000000000000000000000000000000000000..5ebfbc52f541caeb5aa8accb63ab3119ad99d087 --- /dev/null +++ b/drivers/iio/light/noa1305.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Support for ON Semiconductor NOA1305 ambient light sensor + * + * Copyright (C) 2016 Emcraft Systems + * Copyright (C) 2019 Collabora Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NOA1305_REG_POWER_CONTROL 0x0 +#define NOA1305_POWER_CONTROL_DOWN 0x00 +#define NOA1305_POWER_CONTROL_ON 0x08 +#define NOA1305_REG_RESET 0x1 +#define NOA1305_RESET_RESET 0x10 +#define NOA1305_REG_INTEGRATION_TIME 0x2 +#define NOA1305_INTEGR_TIME_800MS 0x00 +#define NOA1305_INTEGR_TIME_400MS 0x01 +#define NOA1305_INTEGR_TIME_200MS 0x02 +#define NOA1305_INTEGR_TIME_100MS 0x03 +#define NOA1305_INTEGR_TIME_50MS 0x04 +#define NOA1305_INTEGR_TIME_25MS 0x05 +#define NOA1305_INTEGR_TIME_12_5MS 0x06 +#define NOA1305_INTEGR_TIME_6_25MS 0x07 +#define NOA1305_REG_INT_SELECT 0x3 +#define NOA1305_INT_SEL_ACTIVE_HIGH 0x01 +#define NOA1305_INT_SEL_ACTIVE_LOW 0x02 +#define NOA1305_INT_SEL_INACTIVE 0x03 +#define NOA1305_REG_INT_THRESH_LSB 0x4 +#define NOA1305_REG_INT_THRESH_MSB 0x5 +#define NOA1305_REG_ALS_DATA_LSB 0x6 +#define NOA1305_REG_ALS_DATA_MSB 0x7 +#define NOA1305_REG_DEVICE_ID_LSB 0x8 +#define NOA1305_REG_DEVICE_ID_MSB 0x9 + +#define NOA1305_DEVICE_ID 0x0519 +#define NOA1305_DRIVER_NAME "noa1305" + +struct noa1305_priv { + struct i2c_client *client; + struct regmap *regmap; + struct regulator *vin_reg; +}; + +static int noa1305_measure(struct noa1305_priv *priv) +{ + __le16 data; + int ret; + + ret = regmap_bulk_read(priv->regmap, NOA1305_REG_ALS_DATA_LSB, &data, + 2); + if (ret < 0) + return ret; + + return le16_to_cpu(data); +} + +static int noa1305_scale(struct noa1305_priv *priv, int *val, int *val2) +{ + int data; + int ret; + + ret = regmap_read(priv->regmap, NOA1305_REG_INTEGRATION_TIME, &data); + if (ret < 0) + return ret; + + /* + * Lux = count / ( * ) + * + * Integration Constant = 7.7 + * Integration Time in Seconds + */ + switch (data) { + case NOA1305_INTEGR_TIME_800MS: + *val = 100; + *val2 = 77 * 8; + break; + case NOA1305_INTEGR_TIME_400MS: + *val = 100; + *val2 = 77 * 4; + break; + case NOA1305_INTEGR_TIME_200MS: + *val = 100; + *val2 = 77 * 2; + break; + case NOA1305_INTEGR_TIME_100MS: + *val = 100; + *val2 = 77; + break; + case NOA1305_INTEGR_TIME_50MS: + *val = 1000; + *val2 = 77 * 5; + break; + case NOA1305_INTEGR_TIME_25MS: + *val = 10000; + *val2 = 77 * 25; + break; + case NOA1305_INTEGR_TIME_12_5MS: + *val = 100000; + *val2 = 77 * 125; + break; + case NOA1305_INTEGR_TIME_6_25MS: + *val = 1000000; + *val2 = 77 * 625; + break; + default: + return -EINVAL; + } + + return IIO_VAL_FRACTIONAL; +} + +static const struct iio_chan_spec noa1305_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + } +}; + +static int noa1305_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + int ret = -EINVAL; + struct noa1305_priv *priv = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_LIGHT: + ret = noa1305_measure(priv); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + default: + break; + } + break; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_LIGHT: + return noa1305_scale(priv, val, val2); + default: + break; + } + break; + default: + break; + } + + return ret; +} + +static const struct iio_info noa1305_info = { + .read_raw = noa1305_read_raw, +}; + +static bool noa1305_writable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NOA1305_REG_POWER_CONTROL: + case NOA1305_REG_RESET: + case NOA1305_REG_INTEGRATION_TIME: + case NOA1305_REG_INT_SELECT: + case NOA1305_REG_INT_THRESH_LSB: + case NOA1305_REG_INT_THRESH_MSB: + return true; + default: + return false; + } +} + +static const struct regmap_config noa1305_regmap_config = { + .name = NOA1305_DRIVER_NAME, + .reg_bits = 8, + .val_bits = 8, + .max_register = NOA1305_REG_DEVICE_ID_MSB, + .writeable_reg = noa1305_writable_reg, +}; + +static void noa1305_reg_remove(void *data) +{ + struct noa1305_priv *priv = data; + + regulator_disable(priv->vin_reg); +} + +static int noa1305_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct noa1305_priv *priv; + struct iio_dev *indio_dev; + struct regmap *regmap; + __le16 data; + unsigned int dev_id; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*priv)); + if (!indio_dev) + return -ENOMEM; + + regmap = devm_regmap_init_i2c(client, &noa1305_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Regmap initialization failed.\n"); + return PTR_ERR(regmap); + } + + priv = iio_priv(indio_dev); + + priv->vin_reg = devm_regulator_get(&client->dev, "vin"); + if (IS_ERR(priv->vin_reg)) { + dev_err(&client->dev, "get regulator vin failed\n"); + return PTR_ERR(priv->vin_reg); + } + + ret = regulator_enable(priv->vin_reg); + if (ret) { + dev_err(&client->dev, "enable regulator vin failed\n"); + return ret; + } + + ret = devm_add_action_or_reset(&client->dev, noa1305_reg_remove, priv); + if (ret) { + dev_err(&client->dev, "addition of devm action failed\n"); + return ret; + } + + i2c_set_clientdata(client, indio_dev); + priv->client = client; + priv->regmap = regmap; + + ret = regmap_bulk_read(regmap, NOA1305_REG_DEVICE_ID_LSB, &data, 2); + if (ret < 0) { + dev_err(&client->dev, "ID reading failed: %d\n", ret); + return ret; + } + + dev_id = le16_to_cpu(data); + if (dev_id != NOA1305_DEVICE_ID) { + dev_err(&client->dev, "Unknown device ID: 0x%x\n", dev_id); + return -ENODEV; + } + + ret = regmap_write(regmap, NOA1305_REG_POWER_CONTROL, + NOA1305_POWER_CONTROL_ON); + if (ret < 0) { + dev_err(&client->dev, "Enabling power control failed\n"); + return ret; + } + + ret = regmap_write(regmap, NOA1305_REG_RESET, NOA1305_RESET_RESET); + if (ret < 0) { + dev_err(&client->dev, "Device reset failed\n"); + return ret; + } + + ret = regmap_write(regmap, NOA1305_REG_INTEGRATION_TIME, + NOA1305_INTEGR_TIME_800MS); + if (ret < 0) { + dev_err(&client->dev, "Setting integration time failed\n"); + return ret; + } + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &noa1305_info; + indio_dev->channels = noa1305_channels; + indio_dev->num_channels = ARRAY_SIZE(noa1305_channels); + indio_dev->name = NOA1305_DRIVER_NAME; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = devm_iio_device_register(&client->dev, indio_dev); + if (ret) + dev_err(&client->dev, "registering device failed\n"); + + return ret; +} + +static const struct of_device_id noa1305_of_match[] = { + { .compatible = "onnn,noa1305" }, + { } +}; +MODULE_DEVICE_TABLE(of, noa1305_of_match); + +static const struct i2c_device_id noa1305_ids[] = { + { "noa1305", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, noa1305_ids); + +static struct i2c_driver noa1305_driver = { + .driver = { + .name = NOA1305_DRIVER_NAME, + .of_match_table = noa1305_of_match, + }, + .probe = noa1305_probe, + .id_table = noa1305_ids, +}; + +module_i2c_driver(noa1305_driver); + +MODULE_AUTHOR("Sergei Miroshnichenko "); +MODULE_AUTHOR("Martyn Welch dev, trig); if (ret) return ret; @@ -1271,16 +1271,6 @@ static int si1145_probe_trigger(struct iio_dev *indio_dev) return 0; } -static void si1145_remove_trigger(struct iio_dev *indio_dev) -{ - struct si1145_data *data = iio_priv(indio_dev); - - if (data->trig) { - iio_trigger_unregister(data->trig); - data->trig = NULL; - } -} - static int si1145_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1332,7 +1322,8 @@ static int si1145_probe(struct i2c_client *client, if (ret < 0) return ret; - ret = iio_triggered_buffer_setup(indio_dev, NULL, + ret = devm_iio_triggered_buffer_setup(&client->dev, + indio_dev, NULL, si1145_trigger_handler, &si1145_buffer_setup_ops); if (ret < 0) return ret; @@ -1340,23 +1331,12 @@ static int si1145_probe(struct i2c_client *client, if (client->irq) { ret = si1145_probe_trigger(indio_dev); if (ret < 0) - goto error_free_buffer; + return ret; } else { dev_info(&client->dev, "no irq, using polling\n"); } - ret = iio_device_register(indio_dev); - if (ret < 0) - goto error_free_trigger; - - return 0; - -error_free_trigger: - si1145_remove_trigger(indio_dev); -error_free_buffer: - iio_triggered_buffer_cleanup(indio_dev); - - return ret; + return devm_iio_device_register(&client->dev, indio_dev); } static const struct i2c_device_id si1145_ids[] = { @@ -1371,23 +1351,11 @@ static const struct i2c_device_id si1145_ids[] = { }; MODULE_DEVICE_TABLE(i2c, si1145_ids); -static int si1145_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); - si1145_remove_trigger(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - - return 0; -} - static struct i2c_driver si1145_driver = { .driver = { .name = "si1145", }, .probe = si1145_probe, - .remove = si1145_remove, .id_table = si1145_ids, }; diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index b955183edfe81f2b9470f8c26a9042eb8f3242b4..185c24a75ae6fa2fadfc8c9736a3c550e865b42a 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -679,9 +679,18 @@ static const struct acpi_device_id stk3310_acpi_id[] = { MODULE_DEVICE_TABLE(acpi, stk3310_acpi_id); +static const struct of_device_id stk3310_of_match[] = { + { .compatible = "sensortek,stk3310", }, + { .compatible = "sensortek,stk3311", }, + { .compatible = "sensortek,stk3335", }, + {} +}; +MODULE_DEVICE_TABLE(of, stk3310_of_match); + static struct i2c_driver stk3310_driver = { .driver = { .name = "stk3310", + .of_match_table = stk3310_of_match, .pm = STK3310_PM_OPS, .acpi_match_table = ACPI_PTR(stk3310_acpi_id), }, diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c index 83cece921843c64594f67d60e41d79cea9b4ac89..be37fcbd4654ea6a4fea5248686069d16b64425c 100644 --- a/drivers/iio/light/tsl2772.c +++ b/drivers/iio/light/tsl2772.c @@ -134,6 +134,12 @@ enum { TSL2772_CHIP_SUSPENDED = 2 }; +enum { + TSL2772_SUPPLY_VDD = 0, + TSL2772_SUPPLY_VDDIO = 1, + TSL2772_NUM_SUPPLIES = 2 +}; + /* Per-device data */ struct tsl2772_als_info { u16 als_ch0; @@ -161,8 +167,7 @@ struct tsl2772_chip { struct mutex prox_mutex; struct mutex als_mutex; struct i2c_client *client; - struct regulator *vdd_supply; - struct regulator *vddio_supply; + struct regulator_bulk_data supplies[TSL2772_NUM_SUPPLIES]; u16 prox_data; struct tsl2772_als_info als_cur_info; struct tsl2772_settings settings; @@ -697,46 +702,7 @@ static void tsl2772_disable_regulators_action(void *_data) { struct tsl2772_chip *chip = _data; - regulator_disable(chip->vdd_supply); - regulator_disable(chip->vddio_supply); -} - -static int tsl2772_enable_regulator(struct tsl2772_chip *chip, - struct regulator *regulator) -{ - int ret; - - ret = regulator_enable(regulator); - if (ret < 0) { - dev_err(&chip->client->dev, "Failed to enable regulator: %d\n", - ret); - return ret; - } - - return 0; -} - -static struct regulator *tsl2772_get_regulator(struct tsl2772_chip *chip, - char *name) -{ - struct regulator *regulator; - int ret; - - regulator = devm_regulator_get(&chip->client->dev, name); - if (IS_ERR(regulator)) { - if (PTR_ERR(regulator) != -EPROBE_DEFER) - dev_err(&chip->client->dev, - "Failed to get %s regulator %d\n", - name, (int)PTR_ERR(regulator)); - - return regulator; - } - - ret = tsl2772_enable_regulator(chip, regulator); - if (ret < 0) - return ERR_PTR(ret); - - return regulator; + regulator_bulk_disable(ARRAY_SIZE(chip->supplies), chip->supplies); } static int tsl2772_chip_on(struct iio_dev *indio_dev) @@ -860,6 +826,13 @@ static int tsl2772_chip_off(struct iio_dev *indio_dev) return tsl2772_write_control_reg(chip, 0x00); } +static void tsl2772_chip_off_action(void *data) +{ + struct iio_dev *indio_dev = data; + + tsl2772_chip_off(indio_dev); +} + /** * tsl2772_invoke_change - power cycle the device to implement the user * parameters @@ -1797,20 +1770,32 @@ static int tsl2772_probe(struct i2c_client *clientp, chip->client = clientp; i2c_set_clientdata(clientp, indio_dev); - chip->vddio_supply = tsl2772_get_regulator(chip, "vddio"); - if (IS_ERR(chip->vddio_supply)) - return PTR_ERR(chip->vddio_supply); + chip->supplies[TSL2772_SUPPLY_VDD].supply = "vdd"; + chip->supplies[TSL2772_SUPPLY_VDDIO].supply = "vddio"; + + ret = devm_regulator_bulk_get(&clientp->dev, + ARRAY_SIZE(chip->supplies), + chip->supplies); + if (ret < 0) { + if (ret != -EPROBE_DEFER) + dev_err(&clientp->dev, + "Failed to get regulators: %d\n", + ret); + + return ret; + } - chip->vdd_supply = tsl2772_get_regulator(chip, "vdd"); - if (IS_ERR(chip->vdd_supply)) { - regulator_disable(chip->vddio_supply); - return PTR_ERR(chip->vdd_supply); + ret = regulator_bulk_enable(ARRAY_SIZE(chip->supplies), chip->supplies); + if (ret < 0) { + dev_err(&clientp->dev, "Failed to enable regulators: %d\n", + ret); + return ret; } - ret = devm_add_action(&clientp->dev, tsl2772_disable_regulators_action, - chip); + ret = devm_add_action_or_reset(&clientp->dev, + tsl2772_disable_regulators_action, + chip); if (ret < 0) { - tsl2772_disable_regulators_action(chip); dev_err(&clientp->dev, "Failed to setup regulator cleanup action %d\n", ret); return ret; @@ -1877,15 +1862,13 @@ static int tsl2772_probe(struct i2c_client *clientp, if (ret < 0) return ret; - ret = iio_device_register(indio_dev); - if (ret) { - tsl2772_chip_off(indio_dev); - dev_err(&clientp->dev, - "%s: iio registration failed\n", __func__); + ret = devm_add_action_or_reset(&clientp->dev, + tsl2772_chip_off_action, + indio_dev); + if (ret < 0) return ret; - } - return 0; + return devm_iio_device_register(&clientp->dev, indio_dev); } static int tsl2772_suspend(struct device *dev) @@ -1895,8 +1878,7 @@ static int tsl2772_suspend(struct device *dev) int ret; ret = tsl2772_chip_off(indio_dev); - regulator_disable(chip->vdd_supply); - regulator_disable(chip->vddio_supply); + regulator_bulk_disable(ARRAY_SIZE(chip->supplies), chip->supplies); return ret; } @@ -1907,32 +1889,15 @@ static int tsl2772_resume(struct device *dev) struct tsl2772_chip *chip = iio_priv(indio_dev); int ret; - ret = tsl2772_enable_regulator(chip, chip->vddio_supply); + ret = regulator_bulk_enable(ARRAY_SIZE(chip->supplies), chip->supplies); if (ret < 0) return ret; - ret = tsl2772_enable_regulator(chip, chip->vdd_supply); - if (ret < 0) { - regulator_disable(chip->vddio_supply); - return ret; - } - usleep_range(TSL2772_BOOT_MIN_SLEEP_TIME, TSL2772_BOOT_MAX_SLEEP_TIME); return tsl2772_chip_on(indio_dev); } -static int tsl2772_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - tsl2772_chip_off(indio_dev); - - iio_device_unregister(indio_dev); - - return 0; -} - static const struct i2c_device_id tsl2772_idtable[] = { { "tsl2571", tsl2571 }, { "tsl2671", tsl2671 }, @@ -1979,7 +1944,6 @@ static struct i2c_driver tsl2772_driver = { }, .id_table = tsl2772_idtable, .probe = tsl2772_probe, - .remove = tsl2772_remove, }; module_i2c_driver(tsl2772_driver); diff --git a/drivers/iio/light/veml6070.c b/drivers/iio/light/veml6070.c index a3138e1b58034d883efbc7a0dab566b7e62b8b4c..0be553ad598945cacf1a3acb51aa94312ef47946 100644 --- a/drivers/iio/light/veml6070.c +++ b/drivers/iio/light/veml6070.c @@ -158,10 +158,10 @@ static int veml6070_probe(struct i2c_client *client, indio_dev->name = VEML6070_DRV_NAME; indio_dev->modes = INDIO_DIRECT_MODE; - data->client2 = i2c_new_dummy(client->adapter, VEML6070_ADDR_DATA_LSB); - if (!data->client2) { + data->client2 = i2c_new_dummy_device(client->adapter, VEML6070_ADDR_DATA_LSB); + if (IS_ERR(data->client2)) { dev_err(&client->dev, "i2c device for second chip address failed\n"); - return -ENODEV; + return PTR_ERR(data->client2); } data->config = VEML6070_IT_10 | VEML6070_COMMAND_RSRVD | diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index 7de10281ad9ed97248c4fe65c0d7e9a752790c9c..425cdd07b4e573b8ca62a30a26853fcd44dc7098 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -53,7 +53,7 @@ #define MMC35240_CTRL1_BW_SHIFT 0 #define MMC35240_WAIT_CHARGE_PUMP 50000 /* us */ -#define MMC53240_WAIT_SET_RESET 1000 /* us */ +#define MMC35240_WAIT_SET_RESET 1000 /* us */ /* * Memsic OTP process code piece is put here for reference: @@ -225,7 +225,7 @@ static int mmc35240_init(struct mmc35240_data *data) ret = mmc35240_hw_set(data, true); if (ret < 0) return ret; - usleep_range(MMC53240_WAIT_SET_RESET, MMC53240_WAIT_SET_RESET + 1); + usleep_range(MMC35240_WAIT_SET_RESET, MMC35240_WAIT_SET_RESET + 1); ret = mmc35240_hw_set(data, false); if (ret < 0) diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h index d69ef9b2a73103e3d67cb2171b4f354360b5df59..204b285725c8aaf6e60db6c92e14a4a4adf6e04f 100644 --- a/drivers/iio/magnetometer/st_magn.h +++ b/drivers/iio/magnetometer/st_magn.h @@ -22,6 +22,7 @@ #define LIS2MDL_MAGN_DEV_NAME "lis2mdl" #define LSM9DS1_MAGN_DEV_NAME "lsm9ds1_magn" +const struct st_sensor_settings *st_magn_get_settings(const char *name); int st_magn_common_probe(struct iio_dev *indio_dev); void st_magn_common_remove(struct iio_dev *indio_dev); diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c index 11d7806655bccd506428cf9270c1553141bf970d..bb425c167a9698f1aa931ef160bd8a3178f8142d 100644 --- a/drivers/iio/magnetometer/st_magn_buffer.c +++ b/drivers/iio/magnetometer/st_magn_buffer.c @@ -32,39 +32,32 @@ int st_magn_trig_set_state(struct iio_trigger *trig, bool state) static int st_magn_buffer_postenable(struct iio_dev *indio_dev) { int err; - struct st_sensor_data *mdata = iio_priv(indio_dev); - - mdata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (mdata->buffer_data == NULL) { - err = -ENOMEM; - goto allocate_memory_error; - } err = iio_triggered_buffer_postenable(indio_dev); if (err < 0) - goto st_magn_buffer_postenable_error; + return err; + + err = st_sensors_set_enable(indio_dev, true); + if (err < 0) + goto st_magn_buffer_predisable; - return st_sensors_set_enable(indio_dev, true); + return 0; -st_magn_buffer_postenable_error: - kfree(mdata->buffer_data); -allocate_memory_error: +st_magn_buffer_predisable: + iio_triggered_buffer_predisable(indio_dev); return err; } static int st_magn_buffer_predisable(struct iio_dev *indio_dev) { - int err; - struct st_sensor_data *mdata = iio_priv(indio_dev); + int err, err2; err = st_sensors_set_enable(indio_dev, false); - if (err < 0) - goto st_magn_buffer_predisable_error; - err = iio_triggered_buffer_predisable(indio_dev); + err2 = iio_triggered_buffer_predisable(indio_dev); + if (!err) + err = err2; -st_magn_buffer_predisable_error: - kfree(mdata->buffer_data); return err; } diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 2f7a1dbcdeb34d44b36b70f985a35a4375e9798e..a3a268ee2896084888ab03df7eb866db254003d9 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -470,28 +469,41 @@ static const struct iio_trigger_ops st_magn_trigger_ops = { #define ST_MAGN_TRIGGER_OPS NULL #endif +/* + * st_magn_get_settings() - get sensor settings from device name + * @name: device name buffer reference. + * + * Return: valid reference on success, NULL otherwise. + */ +const struct st_sensor_settings *st_magn_get_settings(const char *name) +{ + int index = st_sensors_get_settings_index(name, + st_magn_sensors_settings, + ARRAY_SIZE(st_magn_sensors_settings)); + if (index < 0) + return NULL; + + return &st_magn_sensors_settings[index]; +} +EXPORT_SYMBOL(st_magn_get_settings); + int st_magn_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *mdata = iio_priv(indio_dev); - int irq = mdata->get_irq_data_ready(indio_dev); int err; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &magn_info; - mutex_init(&mdata->tb.buf_lock); err = st_sensors_power_enable(indio_dev); if (err) return err; - err = st_sensors_check_device_support(indio_dev, - ARRAY_SIZE(st_magn_sensors_settings), - st_magn_sensors_settings); + err = st_sensors_verify_id(indio_dev); if (err < 0) goto st_magn_power_off; mdata->num_data_channels = ST_MAGN_NUMBER_DATA_CHANNELS; - mdata->multiread_bit = mdata->sensor_settings->multi_read_bit; indio_dev->channels = mdata->sensor_settings->ch; indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; @@ -507,7 +519,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev) if (err < 0) goto st_magn_power_off; - if (irq > 0) { + if (mdata->irq > 0) { err = st_sensors_allocate_trigger(indio_dev, ST_MAGN_TRIGGER_OPS); if (err < 0) @@ -524,7 +536,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev) return 0; st_magn_device_register_error: - if (irq > 0) + if (mdata->irq > 0) st_sensors_deallocate_trigger(indio_dev); st_magn_probe_trigger_error: st_magn_deallocate_ring(indio_dev); @@ -542,7 +554,7 @@ void st_magn_common_remove(struct iio_dev *indio_dev) st_sensors_power_disable(indio_dev); iio_device_unregister(indio_dev); - if (mdata->get_irq_data_ready(indio_dev) > 0) + if (mdata->irq > 0) st_sensors_deallocate_trigger(indio_dev); st_magn_deallocate_ring(indio_dev); diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 4d014fd1aeb07f0cebdc6686ab65cb742e0dc00a..fdba480a12becb913c1aae10177bb3bb3edc327d 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -55,21 +55,33 @@ MODULE_DEVICE_TABLE(of, st_magn_of_match); #endif static int st_magn_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { - struct iio_dev *indio_dev; + const struct st_sensor_settings *settings; struct st_sensor_data *mdata; + struct iio_dev *indio_dev; int err; + st_sensors_of_name_probe(&client->dev, st_magn_of_match, + client->name, sizeof(client->name)); + + settings = st_magn_get_settings(client->name); + if (!settings) { + dev_err(&client->dev, "device name %s not recognized.\n", + client->name); + return -ENODEV; + } + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*mdata)); if (!indio_dev) return -ENOMEM; mdata = iio_priv(indio_dev); - st_sensors_of_name_probe(&client->dev, st_magn_of_match, - client->name, sizeof(client->name)); + mdata->sensor_settings = (struct st_sensor_settings *)settings; - st_sensors_i2c_configure(indio_dev, client, mdata); + err = st_sensors_i2c_configure(indio_dev, client); + if (err < 0) + return err; err = st_magn_common_probe(indio_dev); if (err < 0) diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 0d47070611b187ab5ed6e20322c41491502976d0..fbf909bde8417009ded29187d24290121d791d71 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -51,19 +51,31 @@ MODULE_DEVICE_TABLE(of, st_magn_of_match); static int st_magn_spi_probe(struct spi_device *spi) { - struct iio_dev *indio_dev; + const struct st_sensor_settings *settings; struct st_sensor_data *mdata; + struct iio_dev *indio_dev; int err; + st_sensors_of_name_probe(&spi->dev, st_magn_of_match, + spi->modalias, sizeof(spi->modalias)); + + settings = st_magn_get_settings(spi->modalias); + if (!settings) { + dev_err(&spi->dev, "device name %s not recognized.\n", + spi->modalias); + return -ENODEV; + } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*mdata)); if (!indio_dev) return -ENOMEM; mdata = iio_priv(indio_dev); + mdata->sensor_settings = (struct st_sensor_settings *)settings; - st_sensors_of_name_probe(&spi->dev, st_magn_of_match, - spi->modalias, sizeof(spi->modalias)); - st_sensors_spi_configure(indio_dev, spi, mdata); + err = st_sensors_spi_configure(indio_dev, spi); + if (err < 0) + return err; err = st_magn_common_probe(indio_dev); if (err < 0) diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig index ebc7c72a5e36b636268793142658c838765f92f2..4cac0173db8bb8697cc89ee5b7de3c52dfb51d3f 100644 --- a/drivers/iio/potentiometer/Kconfig +++ b/drivers/iio/potentiometer/Kconfig @@ -26,6 +26,17 @@ config DS1803 To compile this driver as a module, choose M here: the module will be called ds1803. +config MAX5432 + tristate "Maxim MAX5432-MAX5435 Digital Potentiometer driver" + depends on I2C + help + Say yes here to build support for the Maxim + MAX5432, MAX5433, MAX5434 and MAX5435 digital + potentiometer chips. + + To compile this driver as a module, choose M here: the + module will be called max5432. + config MAX5481 tristate "Maxim MAX5481-MAX5484 Digital Potentiometer driver" depends on SPI diff --git a/drivers/iio/potentiometer/Makefile b/drivers/iio/potentiometer/Makefile index 8ff55138cf12b8b5450253162881d156aecb2bb0..091adf3cdd0bdb508c0d3b525abff42907972cb6 100644 --- a/drivers/iio/potentiometer/Makefile +++ b/drivers/iio/potentiometer/Makefile @@ -6,6 +6,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AD5272) += ad5272.o obj-$(CONFIG_DS1803) += ds1803.o +obj-$(CONFIG_MAX5432) += max5432.o obj-$(CONFIG_MAX5481) += max5481.o obj-$(CONFIG_MAX5487) += max5487.o obj-$(CONFIG_MCP4018) += mcp4018.o diff --git a/drivers/iio/potentiometer/max5432.c b/drivers/iio/potentiometer/max5432.c new file mode 100644 index 0000000000000000000000000000000000000000..641b1821fdf67afa0a5ce392fac40d77f3a39fee --- /dev/null +++ b/drivers/iio/potentiometer/max5432.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Maxim Integrated MAX5432-MAX5435 digital potentiometer driver + * Copyright (C) 2019 Martin Kaiser + * + * Datasheet: + * https://datasheets.maximintegrated.com/en/ds/MAX5432-MAX5435.pdf + */ + +#include +#include +#include +#include +#include +#include + +/* All chip variants have 32 wiper positions. */ +#define MAX5432_MAX_POS 31 + +#define MAX5432_OHM_50K (50 * 1000) +#define MAX5432_OHM_100K (100 * 1000) + +/* Update the volatile (currently active) setting. */ +#define MAX5432_CMD_VREG 0x11 + +struct max5432_data { + struct i2c_client *client; + unsigned long ohm; +}; + +static const struct iio_chan_spec max5432_channels[] = { + { + .type = IIO_RESISTANCE, + .indexed = 1, + .output = 1, + .channel = 0, + .address = MAX5432_CMD_VREG, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + } +}; + +static int max5432_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct max5432_data *data = iio_priv(indio_dev); + + if (mask != IIO_CHAN_INFO_SCALE) + return -EINVAL; + + if (unlikely(data->ohm > INT_MAX)) + return -ERANGE; + + *val = data->ohm; + *val2 = MAX5432_MAX_POS; + + return IIO_VAL_FRACTIONAL; +} + +static int max5432_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct max5432_data *data = iio_priv(indio_dev); + u8 data_byte; + + if (mask != IIO_CHAN_INFO_RAW) + return -EINVAL; + + if (val < 0 || val > MAX5432_MAX_POS) + return -EINVAL; + + if (val2 != 0) + return -EINVAL; + + /* Wiper position is in bits D7-D3. (D2-D0 are don't care bits.) */ + data_byte = val << 3; + return i2c_smbus_write_byte_data(data->client, chan->address, + data_byte); +} + +static const struct iio_info max5432_info = { + .read_raw = max5432_read_raw, + .write_raw = max5432_write_raw, +}; + +static int max5432_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct iio_dev *indio_dev; + struct max5432_data *data; + + indio_dev = devm_iio_device_alloc(dev, sizeof(struct max5432_data)); + if (!indio_dev) + return -ENOMEM; + + i2c_set_clientdata(client, indio_dev); + + data = iio_priv(indio_dev); + data->client = client; + data->ohm = (unsigned long)of_device_get_match_data(dev); + + indio_dev->dev.parent = dev; + indio_dev->info = &max5432_info; + indio_dev->channels = max5432_channels; + indio_dev->num_channels = ARRAY_SIZE(max5432_channels); + indio_dev->name = client->name; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id max5432_dt_ids[] = { + { .compatible = "maxim,max5432", .data = (void *)MAX5432_OHM_50K }, + { .compatible = "maxim,max5433", .data = (void *)MAX5432_OHM_100K }, + { .compatible = "maxim,max5434", .data = (void *)MAX5432_OHM_50K }, + { .compatible = "maxim,max5435", .data = (void *)MAX5432_OHM_100K }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, max5432_dt_ids); + +static struct i2c_driver max5432_driver = { + .driver = { + .name = "max5432", + .of_match_table = of_match_ptr(max5432_dt_ids), + }, + .probe = max5432_probe, +}; + +module_i2c_driver(max5432_driver); + +MODULE_AUTHOR("Martin Kaiser "); +MODULE_DESCRIPTION("max5432-max5435 digital potentiometers"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c index 034ce98d6e97834dced5bcf65248fdf440e8dc21..70148624db648f7dd32933636de6f6498fcd43e8 100644 --- a/drivers/iio/pressure/cros_ec_baro.c +++ b/drivers/iio/pressure/cros_ec_baro.c @@ -39,26 +39,29 @@ static int cros_ec_baro_read(struct iio_dev *indio_dev, { struct cros_ec_baro_state *st = iio_priv(indio_dev); u16 data = 0; - int ret = IIO_VAL_INT; + int ret; int idx = chan->scan_index; mutex_lock(&st->core.cmd_lock); switch (mask) { case IIO_CHAN_INFO_RAW: - if (cros_ec_sensors_read_cmd(indio_dev, 1 << idx, - (s16 *)&data) < 0) - ret = -EIO; + ret = cros_ec_sensors_read_cmd(indio_dev, 1 << idx, + (s16 *)&data); + if (ret) + break; + *val = data; + ret = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE; st->core.param.sensor_range.data = EC_MOTION_SENSE_NO_VALUE; - if (cros_ec_motion_send_host_cmd(&st->core, 0)) { - ret = -EIO; + ret = cros_ec_motion_send_host_cmd(&st->core, 0); + if (ret) break; - } + *val = st->core.resp->sensor_range.ret; /* scale * in_pressure_raw --> kPa */ @@ -152,8 +155,6 @@ static int cros_ec_baro_probe(struct platform_device *pdev) channel->ext_info = cros_ec_sensors_ext_info; channel->scan_type.sign = 'u'; - state->core.calib[0] = 0; - /* Sensor specific */ switch (state->core.type) { case MOTIONSENSE_TYPE_BARO: diff --git a/drivers/iio/pressure/hp03.c b/drivers/iio/pressure/hp03.c index f00102577fd54076d60dcb2146a1b5c191d64be8..026ba15ef68f3adb91a60a063fbe4d1efac190c8 100644 --- a/drivers/iio/pressure/hp03.c +++ b/drivers/iio/pressure/hp03.c @@ -243,10 +243,10 @@ static int hp03_probe(struct i2c_client *client, * which has it's dedicated I2C address and contains * the calibration constants for the sensor. */ - priv->eeprom_client = i2c_new_dummy(client->adapter, HP03_EEPROM_ADDR); - if (!priv->eeprom_client) { + priv->eeprom_client = i2c_new_dummy_device(client->adapter, HP03_EEPROM_ADDR); + if (IS_ERR(priv->eeprom_client)) { dev_err(dev, "New EEPROM I2C device failed\n"); - return -ENODEV; + return PTR_ERR(priv->eeprom_client); } priv->eeprom_regmap = regmap_init_i2c(priv->eeprom_client, diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h index 6a720cfb568629b273c3a6add38e4bcd6b7a3dab..c2e47a6c31187b99219c579056371d8add4acc94 100644 --- a/drivers/iio/pressure/st_pressure.h +++ b/drivers/iio/pressure/st_pressure.h @@ -41,6 +41,7 @@ static const struct st_sensors_platform_data default_press_pdata = { .drdy_int_pin = 1, }; +const struct st_sensor_settings *st_press_get_settings(const char *name); int st_press_common_probe(struct iio_dev *indio_dev); void st_press_common_remove(struct iio_dev *indio_dev); diff --git a/drivers/iio/pressure/st_pressure_buffer.c b/drivers/iio/pressure/st_pressure_buffer.c index 4566e08a64a15e6ca3da08e5949464d3449a370e..418dbf9e6e1e350b20fa9be1ac4a3170ec56da3f 100644 --- a/drivers/iio/pressure/st_pressure_buffer.c +++ b/drivers/iio/pressure/st_pressure_buffer.c @@ -29,52 +29,39 @@ int st_press_trig_set_state(struct iio_trigger *trig, bool state) return st_sensors_set_dataready_irq(indio_dev, state); } -static int st_press_buffer_preenable(struct iio_dev *indio_dev) -{ - return st_sensors_set_enable(indio_dev, true); -} - static int st_press_buffer_postenable(struct iio_dev *indio_dev) { int err; - struct st_sensor_data *press_data = iio_priv(indio_dev); - - press_data->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (press_data->buffer_data == NULL) { - err = -ENOMEM; - goto allocate_memory_error; - } err = iio_triggered_buffer_postenable(indio_dev); if (err < 0) - goto st_press_buffer_postenable_error; + return err; - return err; + err = st_sensors_set_enable(indio_dev, true); + if (err < 0) + goto st_press_buffer_predisable; -st_press_buffer_postenable_error: - kfree(press_data->buffer_data); -allocate_memory_error: + return 0; + +st_press_buffer_predisable: + iio_triggered_buffer_predisable(indio_dev); return err; } static int st_press_buffer_predisable(struct iio_dev *indio_dev) { - int err; - struct st_sensor_data *press_data = iio_priv(indio_dev); - - err = iio_triggered_buffer_predisable(indio_dev); - if (err < 0) - goto st_press_buffer_predisable_error; + int err, err2; err = st_sensors_set_enable(indio_dev, false); -st_press_buffer_predisable_error: - kfree(press_data->buffer_data); + err2 = iio_triggered_buffer_predisable(indio_dev); + if (!err) + err = err2; + return err; } static const struct iio_buffer_setup_ops st_press_buffer_setup_ops = { - .preenable = &st_press_buffer_preenable, .postenable = &st_press_buffer_postenable, .predisable = &st_press_buffer_predisable, }; diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index b960e76f7dfd68e278df6646f443c1f2ef00ca31..ca6863b32a5fbe2b340fab4b8032aa1b456c8041 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -664,25 +663,39 @@ static const struct iio_trigger_ops st_press_trigger_ops = { #define ST_PRESS_TRIGGER_OPS NULL #endif +/* + * st_press_get_settings() - get sensor settings from device name + * @name: device name buffer reference. + * + * Return: valid reference on success, NULL otherwise. + */ +const struct st_sensor_settings *st_press_get_settings(const char *name) +{ + int index = st_sensors_get_settings_index(name, + st_press_sensors_settings, + ARRAY_SIZE(st_press_sensors_settings)); + if (index < 0) + return NULL; + + return &st_press_sensors_settings[index]; +} +EXPORT_SYMBOL(st_press_get_settings); + int st_press_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *press_data = iio_priv(indio_dev); struct st_sensors_platform_data *pdata = (struct st_sensors_platform_data *)press_data->dev->platform_data; - int irq = press_data->get_irq_data_ready(indio_dev); int err; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &press_info; - mutex_init(&press_data->tb.buf_lock); err = st_sensors_power_enable(indio_dev); if (err) return err; - err = st_sensors_check_device_support(indio_dev, - ARRAY_SIZE(st_press_sensors_settings), - st_press_sensors_settings); + err = st_sensors_verify_id(indio_dev); if (err < 0) goto st_press_power_off; @@ -693,7 +706,6 @@ int st_press_common_probe(struct iio_dev *indio_dev) * element. */ press_data->num_data_channels = press_data->sensor_settings->num_ch - 1; - press_data->multiread_bit = press_data->sensor_settings->multi_read_bit; indio_dev->channels = press_data->sensor_settings->ch; indio_dev->num_channels = press_data->sensor_settings->num_ch; @@ -716,7 +728,7 @@ int st_press_common_probe(struct iio_dev *indio_dev) if (err < 0) goto st_press_power_off; - if (irq > 0) { + if (press_data->irq > 0) { err = st_sensors_allocate_trigger(indio_dev, ST_PRESS_TRIGGER_OPS); if (err < 0) @@ -733,7 +745,7 @@ int st_press_common_probe(struct iio_dev *indio_dev) return err; st_press_device_register_error: - if (irq > 0) + if (press_data->irq > 0) st_sensors_deallocate_trigger(indio_dev); st_press_probe_trigger_error: st_press_deallocate_ring(indio_dev); @@ -751,7 +763,7 @@ void st_press_common_remove(struct iio_dev *indio_dev) st_sensors_power_disable(indio_dev); iio_device_unregister(indio_dev); - if (press_data->get_irq_data_ready(indio_dev) > 0) + if (press_data->irq > 0) st_sensors_deallocate_trigger(indio_dev); st_press_deallocate_ring(indio_dev); diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index b7d9ba706abc52ce0c6d05abd1ae5b3eb6034764..71d2ed6b494884f8e034002f7685de464860254a 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -78,18 +78,13 @@ static const struct i2c_device_id st_press_id_table[] = { MODULE_DEVICE_TABLE(i2c, st_press_id_table); static int st_press_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { - struct iio_dev *indio_dev; + const struct st_sensor_settings *settings; struct st_sensor_data *press_data; + struct iio_dev *indio_dev; int ret; - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*press_data)); - if (!indio_dev) - return -ENOMEM; - - press_data = iio_priv(indio_dev); - if (client->dev.of_node) { st_sensors_of_name_probe(&client->dev, st_press_of_match, client->name, sizeof(client->name)); @@ -99,11 +94,27 @@ static int st_press_i2c_probe(struct i2c_client *client, return -ENODEV; strlcpy(client->name, st_press_id_table[ret].name, - sizeof(client->name)); + sizeof(client->name)); } else if (!id) return -ENODEV; - st_sensors_i2c_configure(indio_dev, client, press_data); + settings = st_press_get_settings(client->name); + if (!settings) { + dev_err(&client->dev, "device name %s not recognized.\n", + client->name); + return -ENODEV; + } + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*press_data)); + if (!indio_dev) + return -ENOMEM; + + press_data = iio_priv(indio_dev); + press_data->sensor_settings = (struct st_sensor_settings *)settings; + + ret = st_sensors_i2c_configure(indio_dev, client); + if (ret < 0) + return ret; ret = st_press_common_probe(indio_dev); if (ret < 0) diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c index ef61401c41d396318ed02c4ca849402149265574..7c8b70221e705f38aa6dbf6a3fcd50decc75a6f6 100644 --- a/drivers/iio/pressure/st_pressure_spi.c +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -61,19 +61,31 @@ MODULE_DEVICE_TABLE(of, st_press_of_match); static int st_press_spi_probe(struct spi_device *spi) { - struct iio_dev *indio_dev; + const struct st_sensor_settings *settings; struct st_sensor_data *press_data; + struct iio_dev *indio_dev; int err; + st_sensors_of_name_probe(&spi->dev, st_press_of_match, + spi->modalias, sizeof(spi->modalias)); + + settings = st_press_get_settings(spi->modalias); + if (!settings) { + dev_err(&spi->dev, "device name %s not recognized.\n", + spi->modalias); + return -ENODEV; + } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*press_data)); - if (indio_dev == NULL) + if (!indio_dev) return -ENOMEM; press_data = iio_priv(indio_dev); + press_data->sensor_settings = (struct st_sensor_settings *)settings; - st_sensors_of_name_probe(&spi->dev, st_press_of_match, - spi->modalias, sizeof(spi->modalias)); - st_sensors_spi_configure(indio_dev, spi, press_data); + err = st_sensors_spi_configure(indio_dev, spi); + if (err < 0) + return err; err = st_press_common_probe(indio_dev); if (err < 0) diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig index 6b5cce6f1a7be2ab7c6fafc039272a585fc25378..d53601447da433b4549c939245e5f143ad454718 100644 --- a/drivers/iio/proximity/Kconfig +++ b/drivers/iio/proximity/Kconfig @@ -62,7 +62,7 @@ config RFD77402 tristate "RFD77402 ToF sensor" depends on I2C help - Say Y to build a driver for the RFD77420 Time-of-Flight (distance) + Say Y to build a driver for the RFD77402 Time-of-Flight (distance) sensor module with I2C interface. To compile this driver as a module, choose M here: the diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c index c613a64c017f1e10f67867a4851e423f22a5e64a..2ab68282d0b6c8c70d3725f5ba989589ceaf6dd7 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -230,31 +230,13 @@ static int maxim_thermocouple_probe(struct spi_device *spi) data->spi = spi; data->chip = chip; - ret = iio_triggered_buffer_setup(indio_dev, NULL, + ret = devm_iio_triggered_buffer_setup(&spi->dev, + indio_dev, NULL, maxim_thermocouple_trigger_handler, NULL); if (ret) return ret; - ret = iio_device_register(indio_dev); - if (ret) - goto error_unreg_buffer; - - return 0; - -error_unreg_buffer: - iio_triggered_buffer_cleanup(indio_dev); - - return ret; -} - -static int maxim_thermocouple_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - - return 0; + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id maxim_thermocouple_id[] = { @@ -277,7 +259,6 @@ static struct spi_driver maxim_thermocouple_driver = { .of_match_table = maxim_thermocouple_of_match, }, .probe = maxim_thermocouple_probe, - .remove = maxim_thermocouple_remove, .id_table = maxim_thermocouple_id, }; module_spi_driver(maxim_thermocouple_driver); diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index ccf1ce653b2516f0d0c9160eceaedf12bc57b2b0..a5dfe65cd9b9d06862fd5064d80cb4f5054b85bc 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -608,86 +608,6 @@ static const struct iio_enum stm32_enable_mode_enum = { .get = stm32_get_enable_mode }; -static const char *const stm32_quadrature_modes[] = { - "channel_A", - "channel_B", - "quadrature", -}; - -static int stm32_set_quadrature_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - unsigned int mode) -{ - struct stm32_timer_trigger *priv = iio_priv(indio_dev); - - regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, mode + 1); - - return 0; -} - -static int stm32_get_quadrature_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct stm32_timer_trigger *priv = iio_priv(indio_dev); - u32 smcr; - int mode; - - regmap_read(priv->regmap, TIM_SMCR, &smcr); - mode = (smcr & TIM_SMCR_SMS) - 1; - if ((mode < 0) || (mode > ARRAY_SIZE(stm32_quadrature_modes))) - return -EINVAL; - - return mode; -} - -static const struct iio_enum stm32_quadrature_mode_enum = { - .items = stm32_quadrature_modes, - .num_items = ARRAY_SIZE(stm32_quadrature_modes), - .set = stm32_set_quadrature_mode, - .get = stm32_get_quadrature_mode -}; - -static const char *const stm32_count_direction_states[] = { - "up", - "down" -}; - -static int stm32_set_count_direction(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - unsigned int dir) -{ - struct stm32_timer_trigger *priv = iio_priv(indio_dev); - u32 val; - int mode; - - /* In encoder mode, direction is RO (given by TI1/TI2 signals) */ - regmap_read(priv->regmap, TIM_SMCR, &val); - mode = (val & TIM_SMCR_SMS) - 1; - if ((mode >= 0) || (mode < ARRAY_SIZE(stm32_quadrature_modes))) - return -EBUSY; - - return regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_DIR, - dir ? TIM_CR1_DIR : 0); -} - -static int stm32_get_count_direction(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct stm32_timer_trigger *priv = iio_priv(indio_dev); - u32 cr1; - - regmap_read(priv->regmap, TIM_CR1, &cr1); - - return ((cr1 & TIM_CR1_DIR) ? 1 : 0); -} - -static const struct iio_enum stm32_count_direction_enum = { - .items = stm32_count_direction_states, - .num_items = ARRAY_SIZE(stm32_count_direction_states), - .set = stm32_set_count_direction, - .get = stm32_get_count_direction -}; - static ssize_t stm32_count_get_preset(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, @@ -728,10 +648,6 @@ static const struct iio_chan_spec_ext_info stm32_trigger_count_info[] = { .read = stm32_count_get_preset, .write = stm32_count_set_preset }, - IIO_ENUM("count_direction", IIO_SEPARATE, &stm32_count_direction_enum), - IIO_ENUM_AVAILABLE("count_direction", &stm32_count_direction_enum), - IIO_ENUM("quadrature_mode", IIO_SEPARATE, &stm32_quadrature_mode_enum), - IIO_ENUM_AVAILABLE("quadrature_mode", &stm32_quadrature_mode_enum), IIO_ENUM("enable_mode", IIO_SEPARATE, &stm32_enable_mode_enum), IIO_ENUM_AVAILABLE("enable_mode", &stm32_enable_mode_enum), IIO_ENUM("trigger_mode", IIO_SEPARATE, &stm32_trigger_mode_enum), diff --git a/drivers/infiniband/hw/hfi1/vnic_sdma.c b/drivers/infiniband/hw/hfi1/vnic_sdma.c index af1b1ffcb38e8da865eac0ed902049e0d3ecf0bc..7d90b900131ba23fe4337ebe0c5e2ca2d3aa7192 100644 --- a/drivers/infiniband/hw/hfi1/vnic_sdma.c +++ b/drivers/infiniband/hw/hfi1/vnic_sdma.c @@ -102,13 +102,13 @@ static noinline int build_vnic_ulp_payload(struct sdma_engine *sde, goto bail_txadd; for (i = 0; i < skb_shinfo(tx->skb)->nr_frags; i++) { - struct skb_frag_struct *frag = &skb_shinfo(tx->skb)->frags[i]; + skb_frag_t *frag = &skb_shinfo(tx->skb)->frags[i]; /* combine physically continuous fragments later? */ ret = sdma_txadd_page(sde->dd, &tx->txreq, skb_frag_page(frag), - frag->page_offset, + skb_frag_off(frag), skb_frag_size(frag)); if (unlikely(ret)) goto bail_txadd; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index c07e387a07a38b88a02d175e6ddd889e13ef00bf..141205e763144901912a8146b0b35db13a378e91 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -4501,19 +4501,13 @@ static const struct acpi_device_id hns_roce_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, hns_roce_acpi_match); -static int hns_roce_node_match(struct device *dev, const void *fwnode) -{ - return dev->fwnode == fwnode; -} - static struct platform_device *hns_roce_find_pdev(struct fwnode_handle *fwnode) { struct device *dev; /* get the 'device' corresponding to the matching 'fwnode' */ - dev = bus_find_device(&platform_bus_type, NULL, - fwnode, hns_roce_node_match); + dev = bus_find_device_by_fwnode(&platform_bus_type, fwnode); /* get the platform device */ return dev ? to_platform_device(dev) : NULL; } diff --git a/drivers/infiniband/hw/mlx5/cmd.c b/drivers/infiniband/hw/mlx5/cmd.c index 6c8645033102ec02699445536efcdff3914a3b48..4937947400cd005913f28ea633cb6a56ad5a9ccd 100644 --- a/drivers/infiniband/hw/mlx5/cmd.c +++ b/drivers/infiniband/hw/mlx5/cmd.c @@ -186,136 +186,6 @@ int mlx5_cmd_dealloc_memic(struct mlx5_dm *dm, phys_addr_t addr, u64 length) return err; } -int mlx5_cmd_alloc_sw_icm(struct mlx5_dm *dm, int type, u64 length, - u16 uid, phys_addr_t *addr, u32 *obj_id) -{ - struct mlx5_core_dev *dev = dm->dev; - u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {}; - u32 in[MLX5_ST_SZ_DW(create_sw_icm_in)] = {}; - unsigned long *block_map; - u64 icm_start_addr; - u32 log_icm_size; - u32 num_blocks; - u32 max_blocks; - u64 block_idx; - void *sw_icm; - int ret; - - MLX5_SET(general_obj_in_cmd_hdr, in, opcode, - MLX5_CMD_OP_CREATE_GENERAL_OBJECT); - MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_SW_ICM); - MLX5_SET(general_obj_in_cmd_hdr, in, uid, uid); - - switch (type) { - case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM: - icm_start_addr = MLX5_CAP64_DEV_MEM(dev, - steering_sw_icm_start_address); - log_icm_size = MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size); - block_map = dm->steering_sw_icm_alloc_blocks; - break; - case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM: - icm_start_addr = MLX5_CAP64_DEV_MEM(dev, - header_modify_sw_icm_start_address); - log_icm_size = MLX5_CAP_DEV_MEM(dev, - log_header_modify_sw_icm_size); - block_map = dm->header_modify_sw_icm_alloc_blocks; - break; - default: - return -EINVAL; - } - - num_blocks = (length + MLX5_SW_ICM_BLOCK_SIZE(dev) - 1) >> - MLX5_LOG_SW_ICM_BLOCK_SIZE(dev); - max_blocks = BIT(log_icm_size - MLX5_LOG_SW_ICM_BLOCK_SIZE(dev)); - spin_lock(&dm->lock); - block_idx = bitmap_find_next_zero_area(block_map, - max_blocks, - 0, - num_blocks, 0); - - if (block_idx < max_blocks) - bitmap_set(block_map, - block_idx, num_blocks); - - spin_unlock(&dm->lock); - - if (block_idx >= max_blocks) - return -ENOMEM; - - sw_icm = MLX5_ADDR_OF(create_sw_icm_in, in, sw_icm); - icm_start_addr += block_idx << MLX5_LOG_SW_ICM_BLOCK_SIZE(dev); - MLX5_SET64(sw_icm, sw_icm, sw_icm_start_addr, - icm_start_addr); - MLX5_SET(sw_icm, sw_icm, log_sw_icm_size, ilog2(length)); - - ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); - if (ret) { - spin_lock(&dm->lock); - bitmap_clear(block_map, - block_idx, num_blocks); - spin_unlock(&dm->lock); - - return ret; - } - - *addr = icm_start_addr; - *obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); - - return 0; -} - -int mlx5_cmd_dealloc_sw_icm(struct mlx5_dm *dm, int type, u64 length, - u16 uid, phys_addr_t addr, u32 obj_id) -{ - struct mlx5_core_dev *dev = dm->dev; - u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {}; - u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {}; - unsigned long *block_map; - u32 num_blocks; - u64 start_idx; - int err; - - num_blocks = (length + MLX5_SW_ICM_BLOCK_SIZE(dev) - 1) >> - MLX5_LOG_SW_ICM_BLOCK_SIZE(dev); - - switch (type) { - case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM: - start_idx = - (addr - MLX5_CAP64_DEV_MEM( - dev, steering_sw_icm_start_address)) >> - MLX5_LOG_SW_ICM_BLOCK_SIZE(dev); - block_map = dm->steering_sw_icm_alloc_blocks; - break; - case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM: - start_idx = - (addr - - MLX5_CAP64_DEV_MEM( - dev, header_modify_sw_icm_start_address)) >> - MLX5_LOG_SW_ICM_BLOCK_SIZE(dev); - block_map = dm->header_modify_sw_icm_alloc_blocks; - break; - default: - return -EINVAL; - } - - MLX5_SET(general_obj_in_cmd_hdr, in, opcode, - MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); - MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_SW_ICM); - MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id); - MLX5_SET(general_obj_in_cmd_hdr, in, uid, uid); - - err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); - if (err) - return err; - - spin_lock(&dm->lock); - bitmap_clear(block_map, - start_idx, num_blocks); - spin_unlock(&dm->lock); - - return 0; -} - int mlx5_cmd_query_ext_ppcnt_counters(struct mlx5_core_dev *dev, void *out) { u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {}; diff --git a/drivers/infiniband/hw/mlx5/cmd.h b/drivers/infiniband/hw/mlx5/cmd.h index 0572dcba6eaed0affd8727b2ef52e6b81b3722a5..169cab4915e3f91093bbd7d7414e30f120dc2d28 100644 --- a/drivers/infiniband/hw/mlx5/cmd.h +++ b/drivers/infiniband/hw/mlx5/cmd.h @@ -65,8 +65,4 @@ int mlx5_cmd_alloc_q_counter(struct mlx5_core_dev *dev, u16 *counter_id, u16 uid); int mlx5_cmd_mad_ifc(struct mlx5_core_dev *dev, const void *inb, void *outb, u16 opmod, u8 port); -int mlx5_cmd_alloc_sw_icm(struct mlx5_dm *dm, int type, u64 length, - u16 uid, phys_addr_t *addr, u32 *obj_id); -int mlx5_cmd_dealloc_sw_icm(struct mlx5_dm *dm, int type, u64 length, - u16 uid, phys_addr_t addr, u32 obj_id); #endif /* MLX5_IB_CMD_H */ diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5/devx.c index af5bbb35c0589364794ca131a1e741392cfe5931..25b6482c536897f91ea4c4db7c8b97c1ae8c3305 100644 --- a/drivers/infiniband/hw/mlx5/devx.c +++ b/drivers/infiniband/hw/mlx5/devx.c @@ -922,6 +922,7 @@ static bool devx_is_general_cmd(void *in, struct mlx5_ib_dev *dev) case MLX5_CMD_OP_QUERY_CONG_STATUS: case MLX5_CMD_OP_QUERY_CONG_PARAMS: case MLX5_CMD_OP_QUERY_CONG_STATISTICS: + case MLX5_CMD_OP_QUERY_LAG: return true; default: return false; diff --git a/drivers/infiniband/hw/mlx5/flow.c b/drivers/infiniband/hw/mlx5/flow.c index b8841355fcd51182e93adab1829108e5804b73a6..1c8f04abee0c9d5fa22ef8fd69c8dcd2ee53b8e8 100644 --- a/drivers/infiniband/hw/mlx5/flow.c +++ b/drivers/infiniband/hw/mlx5/flow.c @@ -322,11 +322,11 @@ void mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction) switch (maction->flow_action_raw.sub_type) { case MLX5_IB_FLOW_ACTION_MODIFY_HEADER: mlx5_modify_header_dealloc(maction->flow_action_raw.dev->mdev, - maction->flow_action_raw.action_id); + maction->flow_action_raw.modify_hdr); break; case MLX5_IB_FLOW_ACTION_PACKET_REFORMAT: mlx5_packet_reformat_dealloc(maction->flow_action_raw.dev->mdev, - maction->flow_action_raw.action_id); + maction->flow_action_raw.pkt_reformat); break; case MLX5_IB_FLOW_ACTION_DECAP: break; @@ -352,10 +352,11 @@ mlx5_ib_create_modify_header(struct mlx5_ib_dev *dev, if (!maction) return ERR_PTR(-ENOMEM); - ret = mlx5_modify_header_alloc(dev->mdev, namespace, num_actions, in, - &maction->flow_action_raw.action_id); + maction->flow_action_raw.modify_hdr = + mlx5_modify_header_alloc(dev->mdev, namespace, num_actions, in); - if (ret) { + if (IS_ERR(maction->flow_action_raw.modify_hdr)) { + ret = PTR_ERR(maction->flow_action_raw.modify_hdr); kfree(maction); return ERR_PTR(ret); } @@ -479,11 +480,13 @@ static int mlx5_ib_flow_action_create_packet_reformat_ctx( if (ret) return ret; - ret = mlx5_packet_reformat_alloc(dev->mdev, prm_prt, len, - in, namespace, - &maction->flow_action_raw.action_id); - if (ret) + maction->flow_action_raw.pkt_reformat = + mlx5_packet_reformat_alloc(dev->mdev, prm_prt, len, + in, namespace); + if (IS_ERR(maction->flow_action_raw.pkt_reformat)) { + ret = PTR_ERR(maction->flow_action_raw.pkt_reformat); return ret; + } maction->flow_action_raw.sub_type = MLX5_IB_FLOW_ACTION_PACKET_REFORMAT; diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 0569bcab02d4811d6d84ab986fa17c14b2e7a6da..4e9f1507ffd9409dd42701ec4962cd0cb417ee62 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2280,6 +2280,7 @@ static inline int check_dm_type_support(struct mlx5_ib_dev *dev, return -EOPNOTSUPP; break; case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM: + case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM: if (!capable(CAP_SYS_RAWIO) || !capable(CAP_NET_RAW)) return -EPERM; @@ -2344,20 +2345,20 @@ static int handle_alloc_dm_sw_icm(struct ib_ucontext *ctx, struct uverbs_attr_bundle *attrs, int type) { - struct mlx5_dm *dm_db = &to_mdev(ctx->device)->dm; + struct mlx5_core_dev *dev = to_mdev(ctx->device)->mdev; u64 act_size; int err; /* Allocation size must a multiple of the basic block size * and a power of 2. */ - act_size = round_up(attr->length, MLX5_SW_ICM_BLOCK_SIZE(dm_db->dev)); + act_size = round_up(attr->length, MLX5_SW_ICM_BLOCK_SIZE(dev)); act_size = roundup_pow_of_two(act_size); dm->size = act_size; - err = mlx5_cmd_alloc_sw_icm(dm_db, type, act_size, - to_mucontext(ctx)->devx_uid, &dm->dev_addr, - &dm->icm_dm.obj_id); + err = mlx5_dm_sw_icm_alloc(dev, type, act_size, + to_mucontext(ctx)->devx_uid, &dm->dev_addr, + &dm->icm_dm.obj_id); if (err) return err; @@ -2365,9 +2366,9 @@ static int handle_alloc_dm_sw_icm(struct ib_ucontext *ctx, MLX5_IB_ATTR_ALLOC_DM_RESP_START_OFFSET, &dm->dev_addr, sizeof(dm->dev_addr)); if (err) - mlx5_cmd_dealloc_sw_icm(dm_db, type, dm->size, - to_mucontext(ctx)->devx_uid, - dm->dev_addr, dm->icm_dm.obj_id); + mlx5_dm_sw_icm_dealloc(dev, type, dm->size, + to_mucontext(ctx)->devx_uid, dm->dev_addr, + dm->icm_dm.obj_id); return err; } @@ -2407,8 +2408,14 @@ struct ib_dm *mlx5_ib_alloc_dm(struct ib_device *ibdev, attrs); break; case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM: + err = handle_alloc_dm_sw_icm(context, dm, + attr, attrs, + MLX5_SW_ICM_TYPE_STEERING); + break; case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM: - err = handle_alloc_dm_sw_icm(context, dm, attr, attrs, type); + err = handle_alloc_dm_sw_icm(context, dm, + attr, attrs, + MLX5_SW_ICM_TYPE_HEADER_MODIFY); break; default: err = -EOPNOTSUPP; @@ -2428,6 +2435,7 @@ int mlx5_ib_dealloc_dm(struct ib_dm *ibdm, struct uverbs_attr_bundle *attrs) { struct mlx5_ib_ucontext *ctx = rdma_udata_to_drv_context( &attrs->driver_udata, struct mlx5_ib_ucontext, ibucontext); + struct mlx5_core_dev *dev = to_mdev(ibdm->device)->mdev; struct mlx5_dm *dm_db = &to_mdev(ibdm->device)->dm; struct mlx5_ib_dm *dm = to_mdm(ibdm); u32 page_idx; @@ -2439,19 +2447,23 @@ int mlx5_ib_dealloc_dm(struct ib_dm *ibdm, struct uverbs_attr_bundle *attrs) if (ret) return ret; - page_idx = (dm->dev_addr - - pci_resource_start(dm_db->dev->pdev, 0) - - MLX5_CAP64_DEV_MEM(dm_db->dev, - memic_bar_start_addr)) >> - PAGE_SHIFT; + page_idx = (dm->dev_addr - pci_resource_start(dev->pdev, 0) - + MLX5_CAP64_DEV_MEM(dev, memic_bar_start_addr)) >> + PAGE_SHIFT; bitmap_clear(ctx->dm_pages, page_idx, DIV_ROUND_UP(dm->size, PAGE_SIZE)); break; case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM: + ret = mlx5_dm_sw_icm_dealloc(dev, MLX5_SW_ICM_TYPE_STEERING, + dm->size, ctx->devx_uid, dm->dev_addr, + dm->icm_dm.obj_id); + if (ret) + return ret; + break; case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM: - ret = mlx5_cmd_dealloc_sw_icm(dm_db, dm->type, dm->size, - ctx->devx_uid, dm->dev_addr, - dm->icm_dm.obj_id); + ret = mlx5_dm_sw_icm_dealloc(dev, MLX5_SW_ICM_TYPE_HEADER_MODIFY, + dm->size, ctx->devx_uid, dm->dev_addr, + dm->icm_dm.obj_id); if (ret) return ret; break; @@ -2646,7 +2658,8 @@ int parse_flow_flow_action(struct mlx5_ib_flow_action *maction, if (action->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) return -EINVAL; action->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; - action->modify_id = maction->flow_action_raw.action_id; + action->modify_hdr = + maction->flow_action_raw.modify_hdr; return 0; } if (maction->flow_action_raw.sub_type == @@ -2663,8 +2676,8 @@ int parse_flow_flow_action(struct mlx5_ib_flow_action *maction, return -EINVAL; action->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT; - action->reformat_id = - maction->flow_action_raw.action_id; + action->pkt_reformat = + maction->flow_action_raw.pkt_reformat; return 0; } /* fall through */ @@ -6096,8 +6109,6 @@ static struct ib_counters *mlx5_ib_create_counters(struct ib_device *device, static void mlx5_ib_stage_init_cleanup(struct mlx5_ib_dev *dev) { - struct mlx5_core_dev *mdev = dev->mdev; - mlx5_ib_cleanup_multiport_master(dev); if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) { srcu_barrier(&dev->mr_srcu); @@ -6105,29 +6116,11 @@ static void mlx5_ib_stage_init_cleanup(struct mlx5_ib_dev *dev) } WARN_ON(!bitmap_empty(dev->dm.memic_alloc_pages, MLX5_MAX_MEMIC_PAGES)); - - WARN_ON(dev->dm.steering_sw_icm_alloc_blocks && - !bitmap_empty( - dev->dm.steering_sw_icm_alloc_blocks, - BIT(MLX5_CAP_DEV_MEM(mdev, log_steering_sw_icm_size) - - MLX5_LOG_SW_ICM_BLOCK_SIZE(mdev)))); - - kfree(dev->dm.steering_sw_icm_alloc_blocks); - - WARN_ON(dev->dm.header_modify_sw_icm_alloc_blocks && - !bitmap_empty(dev->dm.header_modify_sw_icm_alloc_blocks, - BIT(MLX5_CAP_DEV_MEM( - mdev, log_header_modify_sw_icm_size) - - MLX5_LOG_SW_ICM_BLOCK_SIZE(mdev)))); - - kfree(dev->dm.header_modify_sw_icm_alloc_blocks); } static int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev) { struct mlx5_core_dev *mdev = dev->mdev; - u64 header_modify_icm_blocks = 0; - u64 steering_icm_blocks = 0; int err; int i; @@ -6174,51 +6167,17 @@ static int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev) INIT_LIST_HEAD(&dev->qp_list); spin_lock_init(&dev->reset_flow_resource_lock); - if (MLX5_CAP_GEN_64(mdev, general_obj_types) & - MLX5_GENERAL_OBJ_TYPES_CAP_SW_ICM) { - if (MLX5_CAP64_DEV_MEM(mdev, steering_sw_icm_start_address)) { - steering_icm_blocks = - BIT(MLX5_CAP_DEV_MEM(mdev, - log_steering_sw_icm_size) - - MLX5_LOG_SW_ICM_BLOCK_SIZE(mdev)); - - dev->dm.steering_sw_icm_alloc_blocks = - kcalloc(BITS_TO_LONGS(steering_icm_blocks), - sizeof(unsigned long), GFP_KERNEL); - if (!dev->dm.steering_sw_icm_alloc_blocks) - goto err_mp; - } - - if (MLX5_CAP64_DEV_MEM(mdev, - header_modify_sw_icm_start_address)) { - header_modify_icm_blocks = BIT( - MLX5_CAP_DEV_MEM( - mdev, log_header_modify_sw_icm_size) - - MLX5_LOG_SW_ICM_BLOCK_SIZE(mdev)); - - dev->dm.header_modify_sw_icm_alloc_blocks = - kcalloc(BITS_TO_LONGS(header_modify_icm_blocks), - sizeof(unsigned long), GFP_KERNEL); - if (!dev->dm.header_modify_sw_icm_alloc_blocks) - goto err_dm; - } - } - spin_lock_init(&dev->dm.lock); dev->dm.dev = mdev; if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) { err = init_srcu_struct(&dev->mr_srcu); if (err) - goto err_dm; + goto err_mp; } return 0; -err_dm: - kfree(dev->dm.steering_sw_icm_alloc_blocks); - kfree(dev->dm.header_modify_sw_icm_alloc_blocks); - err_mp: mlx5_ib_cleanup_multiport_master(dev); diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 9ae587b74b121ddc637ad22b697a141e25cf3878..125a507c10edc33b42e777be2b30353efe7ac4aa 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -868,7 +868,10 @@ struct mlx5_ib_flow_action { struct { struct mlx5_ib_dev *dev; u32 sub_type; - u32 action_id; + union { + struct mlx5_modify_hdr *modify_hdr; + struct mlx5_pkt_reformat *pkt_reformat; + }; } flow_action_raw; }; }; @@ -881,8 +884,6 @@ struct mlx5_dm { */ spinlock_t lock; DECLARE_BITMAP(memic_alloc_pages, MLX5_MAX_MEMIC_PAGES); - unsigned long *steering_sw_icm_alloc_blocks; - unsigned long *header_modify_sw_icm_alloc_blocks; }; struct mlx5_read_counters_attr { diff --git a/drivers/infiniband/hw/mlx5/srq_cmd.c b/drivers/infiniband/hw/mlx5/srq_cmd.c index b0d0687c7a686571a0cd8aa043282f80dadc76c5..8fc3630a9d4c3742995f31b2d06584b8024a29cf 100644 --- a/drivers/infiniband/hw/mlx5/srq_cmd.c +++ b/drivers/infiniband/hw/mlx5/srq_cmd.c @@ -86,7 +86,7 @@ struct mlx5_core_srq *mlx5_cmd_get_srq(struct mlx5_ib_dev *dev, u32 srqn) xa_lock(&table->array); srq = xa_load(&table->array, srqn); if (srq) - atomic_inc(&srq->common.refcount); + refcount_inc(&srq->common.refcount); xa_unlock(&table->array); return srq; @@ -592,7 +592,7 @@ int mlx5_cmd_create_srq(struct mlx5_ib_dev *dev, struct mlx5_core_srq *srq, if (err) return err; - atomic_set(&srq->common.refcount, 1); + refcount_set(&srq->common.refcount, 1); init_completion(&srq->common.free); err = xa_err(xa_store_irq(&table->array, srq->srqn, srq, GFP_KERNEL)); @@ -675,7 +675,7 @@ static int srq_event_notifier(struct notifier_block *nb, xa_lock(&table->array); srq = xa_load(&table->array, srqn); if (srq) - atomic_inc(&srq->common.refcount); + refcount_inc(&srq->common.refcount); xa_unlock(&table->array); if (!srq) diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c index 41a569558a1579908e8fdf0f5164d8c703ddd7b3..e336d778e076eddb3d56c37b6fd33be0de87b050 100644 --- a/drivers/infiniband/hw/qib/qib_fs.c +++ b/drivers/infiniband/hw/qib/qib_fs.c @@ -493,7 +493,7 @@ static int remove_device_files(struct super_block *sb, remove_file(dir, "flash"); inode_unlock(d_inode(dir)); ret = simple_rmdir(d_inode(root), dir); - d_delete(dir); + d_drop(dir); dput(dir); bail: diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 78fa777c87b1997c0f7ab8629801338923070aea..c332b47618160327966b493a7493e7006833d345 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -293,7 +293,8 @@ int ipoib_dma_map_tx(struct ib_device *ca, struct ipoib_tx_buf *tx_req) const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; mapping[i + off] = ib_dma_map_page(ca, skb_frag_page(frag), - frag->page_offset, skb_frag_size(frag), + skb_frag_off(frag), + skb_frag_size(frag), DMA_TO_DEVICE); if (unlikely(ib_dma_mapping_error(ca, mapping[i + off]))) goto partial_error; diff --git a/drivers/input/mouse/vmmouse.c b/drivers/input/mouse/vmmouse.c index 871e5b5ab129d9d5b4614c6992cfdc8d2e7a33ae..148245c69be75fbd4e97f7cf239eaf3bca61cde6 100644 --- a/drivers/input/mouse/vmmouse.c +++ b/drivers/input/mouse/vmmouse.c @@ -16,12 +16,12 @@ #include #include #include +#include #include "psmouse.h" #include "vmmouse.h" #define VMMOUSE_PROTO_MAGIC 0x564D5868U -#define VMMOUSE_PROTO_PORT 0x5658 /* * Main commands supported by the vmmouse hypervisor port. @@ -84,7 +84,7 @@ struct vmmouse_data { #define VMMOUSE_CMD(cmd, in1, out1, out2, out3, out4) \ ({ \ unsigned long __dummy1, __dummy2; \ - __asm__ __volatile__ ("inl %%dx" : \ + __asm__ __volatile__ (VMWARE_HYPERCALL : \ "=a"(out1), \ "=b"(out2), \ "=c"(out3), \ @@ -94,7 +94,7 @@ struct vmmouse_data { "a"(VMMOUSE_PROTO_MAGIC), \ "b"(in1), \ "c"(VMMOUSE_PROTO_CMD_##cmd), \ - "d"(VMMOUSE_PROTO_PORT) : \ + "d"(0) : \ "memory"); \ }) diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index 00cb1ba2d364398551421878d74a06c92a168bc3..3fd3e862269bdc8010568ea9b24a04ab2b14c4f3 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -186,7 +186,7 @@ static const struct v4l2_pix_format sur40_pix_format[] = { .width = SENSOR_RES_X / 2, .height = SENSOR_RES_Y / 2, .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_SRGB, + .colorspace = V4L2_COLORSPACE_RAW, .bytesperline = SENSOR_RES_X / 2, .sizeimage = (SENSOR_RES_X/2) * (SENSOR_RES_Y/2), }, @@ -195,7 +195,7 @@ static const struct v4l2_pix_format sur40_pix_format[] = { .width = SENSOR_RES_X / 2, .height = SENSOR_RES_Y / 2, .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_SRGB, + .colorspace = V4L2_COLORSPACE_RAW, .bytesperline = SENSOR_RES_X / 2, .sizeimage = (SENSOR_RES_X/2) * (SENSOR_RES_Y/2), } diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig index d5e70ebc241081e55ea28ad0f0b33a562c26fd06..6ab4012a059a57ba06fcee4624f00f2a76c47f38 100644 --- a/drivers/interconnect/qcom/Kconfig +++ b/drivers/interconnect/qcom/Kconfig @@ -5,6 +5,15 @@ config INTERCONNECT_QCOM help Support for Qualcomm's Network-on-Chip interconnect hardware. +config INTERCONNECT_QCOM_QCS404 + tristate "Qualcomm QCS404 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 qcs404-based + platforms. + config INTERCONNECT_QCOM_SDM845 tristate "Qualcomm SDM845 interconnect driver" depends on INTERCONNECT_QCOM @@ -12,3 +21,6 @@ config INTERCONNECT_QCOM_SDM845 help This is a driver for the Qualcomm Network-on-Chip on sdm845-based platforms. + +config INTERCONNECT_QCOM_SMD_RPM + tristate diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile index 1c1cea690f92274d01d77d0c922f269489739d19..67dafb783dec7586dc6dfdef24b7bd91101af9e3 100644 --- a/drivers/interconnect/qcom/Makefile +++ b/drivers/interconnect/qcom/Makefile @@ -1,5 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 +qnoc-qcs404-objs := qcs404.o qnoc-sdm845-objs := sdm845.o +icc-smd-rpm-objs := smd-rpm.o +obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += qnoc-sdm845.o +obj-$(CONFIG_INTERCONNECT_QCOM_SMD_RPM) += icc-smd-rpm.o diff --git a/drivers/interconnect/qcom/qcs404.c b/drivers/interconnect/qcom/qcs404.c new file mode 100644 index 0000000000000000000000000000000000000000..910081d6ddc00e59a9c8bd4c4e180cdba9d791d0 --- /dev/null +++ b/drivers/interconnect/qcom/qcs404.c @@ -0,0 +1,539 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Linaro Ltd + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "smd-rpm.h" + +#define RPM_BUS_MASTER_REQ 0x73616d62 +#define RPM_BUS_SLAVE_REQ 0x766c7362 + +enum { + QCS404_MASTER_AMPSS_M0 = 1, + QCS404_MASTER_GRAPHICS_3D, + QCS404_MASTER_MDP_PORT0, + QCS404_SNOC_BIMC_1_MAS, + QCS404_MASTER_TCU_0, + QCS404_MASTER_SPDM, + QCS404_MASTER_BLSP_1, + QCS404_MASTER_BLSP_2, + QCS404_MASTER_XM_USB_HS1, + QCS404_MASTER_CRYPTO_CORE0, + QCS404_MASTER_SDCC_1, + QCS404_MASTER_SDCC_2, + QCS404_SNOC_PNOC_MAS, + QCS404_MASTER_QPIC, + QCS404_MASTER_QDSS_BAM, + QCS404_BIMC_SNOC_MAS, + QCS404_PNOC_SNOC_MAS, + QCS404_MASTER_QDSS_ETR, + QCS404_MASTER_EMAC, + QCS404_MASTER_PCIE, + QCS404_MASTER_USB3, + QCS404_PNOC_INT_0, + QCS404_PNOC_INT_2, + QCS404_PNOC_INT_3, + QCS404_PNOC_SLV_0, + QCS404_PNOC_SLV_1, + QCS404_PNOC_SLV_2, + QCS404_PNOC_SLV_3, + QCS404_PNOC_SLV_4, + QCS404_PNOC_SLV_6, + QCS404_PNOC_SLV_7, + QCS404_PNOC_SLV_8, + QCS404_PNOC_SLV_9, + QCS404_PNOC_SLV_10, + QCS404_PNOC_SLV_11, + QCS404_SNOC_QDSS_INT, + QCS404_SNOC_INT_0, + QCS404_SNOC_INT_1, + QCS404_SNOC_INT_2, + QCS404_SLAVE_EBI_CH0, + QCS404_BIMC_SNOC_SLV, + QCS404_SLAVE_SPDM_WRAPPER, + QCS404_SLAVE_PDM, + QCS404_SLAVE_PRNG, + QCS404_SLAVE_TCSR, + QCS404_SLAVE_SNOC_CFG, + QCS404_SLAVE_MESSAGE_RAM, + QCS404_SLAVE_DISPLAY_CFG, + QCS404_SLAVE_GRAPHICS_3D_CFG, + QCS404_SLAVE_BLSP_1, + QCS404_SLAVE_TLMM_NORTH, + QCS404_SLAVE_PCIE_1, + QCS404_SLAVE_EMAC_CFG, + QCS404_SLAVE_BLSP_2, + QCS404_SLAVE_TLMM_EAST, + QCS404_SLAVE_TCU, + QCS404_SLAVE_PMIC_ARB, + QCS404_SLAVE_SDCC_1, + QCS404_SLAVE_SDCC_2, + QCS404_SLAVE_TLMM_SOUTH, + QCS404_SLAVE_USB_HS, + QCS404_SLAVE_USB3, + QCS404_SLAVE_CRYPTO_0_CFG, + QCS404_PNOC_SNOC_SLV, + QCS404_SLAVE_APPSS, + QCS404_SLAVE_WCSS, + QCS404_SNOC_BIMC_1_SLV, + QCS404_SLAVE_OCIMEM, + QCS404_SNOC_PNOC_SLV, + QCS404_SLAVE_QDSS_STM, + QCS404_SLAVE_CATS_128, + QCS404_SLAVE_OCMEM_64, + QCS404_SLAVE_LPASS, +}; + +#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" }, +}; + +/** + * 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 + */ +struct qcom_icc_provider { + struct icc_provider provider; + struct clk_bulk_data *bus_clks; + int num_clks; +}; + +#define QCS404_MAX_LINKS 12 + +/** + * 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 + * @rate: current bus clock rate in Hz + */ +struct qcom_icc_node { + unsigned char *name; + u16 id; + u16 links[QCS404_MAX_LINKS]; + u16 num_links; + u16 buswidth; + int mas_rpm_id; + int slv_rpm_id; + u64 rate; +}; + +struct qcom_icc_desc { + struct qcom_icc_node **nodes; + size_t num_nodes; +}; + +#define DEFINE_QNODE(_name, _id, _buswidth, _mas_rpm_id, _slv_rpm_id, \ + ...) \ + static struct qcom_icc_node _name = { \ + .name = #_name, \ + .id = _id, \ + .buswidth = _buswidth, \ + .mas_rpm_id = _mas_rpm_id, \ + .slv_rpm_id = _slv_rpm_id, \ + .num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })), \ + .links = { __VA_ARGS__ }, \ + } + +DEFINE_QNODE(mas_apps_proc, QCS404_MASTER_AMPSS_M0, 8, 0, -1, QCS404_SLAVE_EBI_CH0, QCS404_BIMC_SNOC_SLV); +DEFINE_QNODE(mas_oxili, QCS404_MASTER_GRAPHICS_3D, 8, 6, -1, QCS404_SLAVE_EBI_CH0, QCS404_BIMC_SNOC_SLV); +DEFINE_QNODE(mas_mdp, QCS404_MASTER_MDP_PORT0, 8, 8, -1, QCS404_SLAVE_EBI_CH0, QCS404_BIMC_SNOC_SLV); +DEFINE_QNODE(mas_snoc_bimc_1, QCS404_SNOC_BIMC_1_MAS, 8, 76, -1, QCS404_SLAVE_EBI_CH0); +DEFINE_QNODE(mas_tcu_0, QCS404_MASTER_TCU_0, 8, -1, -1, QCS404_SLAVE_EBI_CH0, QCS404_BIMC_SNOC_SLV); +DEFINE_QNODE(mas_spdm, QCS404_MASTER_SPDM, 4, -1, -1, QCS404_PNOC_INT_3); +DEFINE_QNODE(mas_blsp_1, QCS404_MASTER_BLSP_1, 4, 41, -1, QCS404_PNOC_INT_3); +DEFINE_QNODE(mas_blsp_2, QCS404_MASTER_BLSP_2, 4, 39, -1, QCS404_PNOC_INT_3); +DEFINE_QNODE(mas_xi_usb_hs1, QCS404_MASTER_XM_USB_HS1, 8, 138, -1, QCS404_PNOC_INT_0); +DEFINE_QNODE(mas_crypto, QCS404_MASTER_CRYPTO_CORE0, 8, 23, -1, QCS404_PNOC_SNOC_SLV, QCS404_PNOC_INT_2); +DEFINE_QNODE(mas_sdcc_1, QCS404_MASTER_SDCC_1, 8, 33, -1, QCS404_PNOC_INT_0); +DEFINE_QNODE(mas_sdcc_2, QCS404_MASTER_SDCC_2, 8, 35, -1, QCS404_PNOC_INT_0); +DEFINE_QNODE(mas_snoc_pcnoc, QCS404_SNOC_PNOC_MAS, 8, 77, -1, QCS404_PNOC_INT_2); +DEFINE_QNODE(mas_qpic, QCS404_MASTER_QPIC, 4, -1, -1, QCS404_PNOC_INT_0); +DEFINE_QNODE(mas_qdss_bam, QCS404_MASTER_QDSS_BAM, 4, -1, -1, QCS404_SNOC_QDSS_INT); +DEFINE_QNODE(mas_bimc_snoc, QCS404_BIMC_SNOC_MAS, 8, 21, -1, QCS404_SLAVE_OCMEM_64, QCS404_SLAVE_CATS_128, QCS404_SNOC_INT_0, QCS404_SNOC_INT_1); +DEFINE_QNODE(mas_pcnoc_snoc, QCS404_PNOC_SNOC_MAS, 8, 29, -1, QCS404_SNOC_BIMC_1_SLV, QCS404_SNOC_INT_2, QCS404_SNOC_INT_0); +DEFINE_QNODE(mas_qdss_etr, QCS404_MASTER_QDSS_ETR, 8, -1, -1, QCS404_SNOC_QDSS_INT); +DEFINE_QNODE(mas_emac, QCS404_MASTER_EMAC, 8, -1, -1, QCS404_SNOC_BIMC_1_SLV, QCS404_SNOC_INT_1); +DEFINE_QNODE(mas_pcie, QCS404_MASTER_PCIE, 8, -1, -1, QCS404_SNOC_BIMC_1_SLV, QCS404_SNOC_INT_1); +DEFINE_QNODE(mas_usb3, QCS404_MASTER_USB3, 8, -1, -1, QCS404_SNOC_BIMC_1_SLV, QCS404_SNOC_INT_1); +DEFINE_QNODE(pcnoc_int_0, QCS404_PNOC_INT_0, 8, 85, 114, QCS404_PNOC_SNOC_SLV, QCS404_PNOC_INT_2); +DEFINE_QNODE(pcnoc_int_2, QCS404_PNOC_INT_2, 8, 124, 184, QCS404_PNOC_SLV_10, QCS404_SLAVE_TCU, QCS404_PNOC_SLV_11, QCS404_PNOC_SLV_2, QCS404_PNOC_SLV_3, QCS404_PNOC_SLV_0, QCS404_PNOC_SLV_1, QCS404_PNOC_SLV_6, QCS404_PNOC_SLV_7, QCS404_PNOC_SLV_4, QCS404_PNOC_SLV_8, QCS404_PNOC_SLV_9); +DEFINE_QNODE(pcnoc_int_3, QCS404_PNOC_INT_3, 8, 125, 185, QCS404_PNOC_SNOC_SLV); +DEFINE_QNODE(pcnoc_s_0, QCS404_PNOC_SLV_0, 4, 89, 118, QCS404_SLAVE_PRNG, QCS404_SLAVE_SPDM_WRAPPER, QCS404_SLAVE_PDM); +DEFINE_QNODE(pcnoc_s_1, QCS404_PNOC_SLV_1, 4, 90, 119, QCS404_SLAVE_TCSR); +DEFINE_QNODE(pcnoc_s_2, QCS404_PNOC_SLV_2, 4, -1, -1, QCS404_SLAVE_GRAPHICS_3D_CFG); +DEFINE_QNODE(pcnoc_s_3, QCS404_PNOC_SLV_3, 4, 92, 121, QCS404_SLAVE_MESSAGE_RAM); +DEFINE_QNODE(pcnoc_s_4, QCS404_PNOC_SLV_4, 4, 93, 122, QCS404_SLAVE_SNOC_CFG); +DEFINE_QNODE(pcnoc_s_6, QCS404_PNOC_SLV_6, 4, 94, 123, QCS404_SLAVE_BLSP_1, QCS404_SLAVE_TLMM_NORTH, QCS404_SLAVE_EMAC_CFG); +DEFINE_QNODE(pcnoc_s_7, QCS404_PNOC_SLV_7, 4, 95, 124, QCS404_SLAVE_TLMM_SOUTH, QCS404_SLAVE_DISPLAY_CFG, QCS404_SLAVE_SDCC_1, QCS404_SLAVE_PCIE_1, QCS404_SLAVE_SDCC_2); +DEFINE_QNODE(pcnoc_s_8, QCS404_PNOC_SLV_8, 4, 96, 125, QCS404_SLAVE_CRYPTO_0_CFG); +DEFINE_QNODE(pcnoc_s_9, QCS404_PNOC_SLV_9, 4, 97, 126, QCS404_SLAVE_BLSP_2, QCS404_SLAVE_TLMM_EAST, QCS404_SLAVE_PMIC_ARB); +DEFINE_QNODE(pcnoc_s_10, QCS404_PNOC_SLV_10, 4, 157, -1, QCS404_SLAVE_USB_HS); +DEFINE_QNODE(pcnoc_s_11, QCS404_PNOC_SLV_11, 4, 158, 246, QCS404_SLAVE_USB3); +DEFINE_QNODE(qdss_int, QCS404_SNOC_QDSS_INT, 8, -1, -1, QCS404_SNOC_BIMC_1_SLV, QCS404_SNOC_INT_1); +DEFINE_QNODE(snoc_int_0, QCS404_SNOC_INT_0, 8, 99, 130, QCS404_SLAVE_LPASS, QCS404_SLAVE_APPSS, QCS404_SLAVE_WCSS); +DEFINE_QNODE(snoc_int_1, QCS404_SNOC_INT_1, 8, 100, 131, QCS404_SNOC_PNOC_SLV, QCS404_SNOC_INT_2); +DEFINE_QNODE(snoc_int_2, QCS404_SNOC_INT_2, 8, 134, 197, QCS404_SLAVE_QDSS_STM, QCS404_SLAVE_OCIMEM); +DEFINE_QNODE(slv_ebi, QCS404_SLAVE_EBI_CH0, 8, -1, 0, 0); +DEFINE_QNODE(slv_bimc_snoc, QCS404_BIMC_SNOC_SLV, 8, -1, 2, QCS404_BIMC_SNOC_MAS); +DEFINE_QNODE(slv_spdm, QCS404_SLAVE_SPDM_WRAPPER, 4, -1, -1, 0); +DEFINE_QNODE(slv_pdm, QCS404_SLAVE_PDM, 4, -1, 41, 0); +DEFINE_QNODE(slv_prng, QCS404_SLAVE_PRNG, 4, -1, 44, 0); +DEFINE_QNODE(slv_tcsr, QCS404_SLAVE_TCSR, 4, -1, 50, 0); +DEFINE_QNODE(slv_snoc_cfg, QCS404_SLAVE_SNOC_CFG, 4, -1, 70, 0); +DEFINE_QNODE(slv_message_ram, QCS404_SLAVE_MESSAGE_RAM, 4, -1, 55, 0); +DEFINE_QNODE(slv_disp_ss_cfg, QCS404_SLAVE_DISPLAY_CFG, 4, -1, -1, 0); +DEFINE_QNODE(slv_gpu_cfg, QCS404_SLAVE_GRAPHICS_3D_CFG, 4, -1, -1, 0); +DEFINE_QNODE(slv_blsp_1, QCS404_SLAVE_BLSP_1, 4, -1, 39, 0); +DEFINE_QNODE(slv_tlmm_north, QCS404_SLAVE_TLMM_NORTH, 4, -1, 214, 0); +DEFINE_QNODE(slv_pcie, QCS404_SLAVE_PCIE_1, 4, -1, -1, 0); +DEFINE_QNODE(slv_ethernet, QCS404_SLAVE_EMAC_CFG, 4, -1, -1, 0); +DEFINE_QNODE(slv_blsp_2, QCS404_SLAVE_BLSP_2, 4, -1, 37, 0); +DEFINE_QNODE(slv_tlmm_east, QCS404_SLAVE_TLMM_EAST, 4, -1, 213, 0); +DEFINE_QNODE(slv_tcu, QCS404_SLAVE_TCU, 8, -1, -1, 0); +DEFINE_QNODE(slv_pmic_arb, QCS404_SLAVE_PMIC_ARB, 4, -1, 59, 0); +DEFINE_QNODE(slv_sdcc_1, QCS404_SLAVE_SDCC_1, 4, -1, 31, 0); +DEFINE_QNODE(slv_sdcc_2, QCS404_SLAVE_SDCC_2, 4, -1, 33, 0); +DEFINE_QNODE(slv_tlmm_south, QCS404_SLAVE_TLMM_SOUTH, 4, -1, -1, 0); +DEFINE_QNODE(slv_usb_hs, QCS404_SLAVE_USB_HS, 4, -1, 40, 0); +DEFINE_QNODE(slv_usb3, QCS404_SLAVE_USB3, 4, -1, 22, 0); +DEFINE_QNODE(slv_crypto_0_cfg, QCS404_SLAVE_CRYPTO_0_CFG, 4, -1, 52, 0); +DEFINE_QNODE(slv_pcnoc_snoc, QCS404_PNOC_SNOC_SLV, 8, -1, 45, QCS404_PNOC_SNOC_MAS); +DEFINE_QNODE(slv_kpss_ahb, QCS404_SLAVE_APPSS, 4, -1, -1, 0); +DEFINE_QNODE(slv_wcss, QCS404_SLAVE_WCSS, 4, -1, 23, 0); +DEFINE_QNODE(slv_snoc_bimc_1, QCS404_SNOC_BIMC_1_SLV, 8, -1, 104, QCS404_SNOC_BIMC_1_MAS); +DEFINE_QNODE(slv_imem, QCS404_SLAVE_OCIMEM, 8, -1, 26, 0); +DEFINE_QNODE(slv_snoc_pcnoc, QCS404_SNOC_PNOC_SLV, 8, -1, 28, QCS404_SNOC_PNOC_MAS); +DEFINE_QNODE(slv_qdss_stm, QCS404_SLAVE_QDSS_STM, 4, -1, 30, 0); +DEFINE_QNODE(slv_cats_0, QCS404_SLAVE_CATS_128, 16, -1, -1, 0); +DEFINE_QNODE(slv_cats_1, QCS404_SLAVE_OCMEM_64, 8, -1, -1, 0); +DEFINE_QNODE(slv_lpass, QCS404_SLAVE_LPASS, 4, -1, -1, 0); + +static struct qcom_icc_node *qcs404_bimc_nodes[] = { + [MASTER_AMPSS_M0] = &mas_apps_proc, + [MASTER_OXILI] = &mas_oxili, + [MASTER_MDP_PORT0] = &mas_mdp, + [MASTER_SNOC_BIMC_1] = &mas_snoc_bimc_1, + [MASTER_TCU_0] = &mas_tcu_0, + [SLAVE_EBI_CH0] = &slv_ebi, + [SLAVE_BIMC_SNOC] = &slv_bimc_snoc, +}; + +static struct qcom_icc_desc qcs404_bimc = { + .nodes = qcs404_bimc_nodes, + .num_nodes = ARRAY_SIZE(qcs404_bimc_nodes), +}; + +static struct qcom_icc_node *qcs404_pcnoc_nodes[] = { + [MASTER_SPDM] = &mas_spdm, + [MASTER_BLSP_1] = &mas_blsp_1, + [MASTER_BLSP_2] = &mas_blsp_2, + [MASTER_XI_USB_HS1] = &mas_xi_usb_hs1, + [MASTER_CRYPT0] = &mas_crypto, + [MASTER_SDCC_1] = &mas_sdcc_1, + [MASTER_SDCC_2] = &mas_sdcc_2, + [MASTER_SNOC_PCNOC] = &mas_snoc_pcnoc, + [MASTER_QPIC] = &mas_qpic, + [PCNOC_INT_0] = &pcnoc_int_0, + [PCNOC_INT_2] = &pcnoc_int_2, + [PCNOC_INT_3] = &pcnoc_int_3, + [PCNOC_S_0] = &pcnoc_s_0, + [PCNOC_S_1] = &pcnoc_s_1, + [PCNOC_S_2] = &pcnoc_s_2, + [PCNOC_S_3] = &pcnoc_s_3, + [PCNOC_S_4] = &pcnoc_s_4, + [PCNOC_S_6] = &pcnoc_s_6, + [PCNOC_S_7] = &pcnoc_s_7, + [PCNOC_S_8] = &pcnoc_s_8, + [PCNOC_S_9] = &pcnoc_s_9, + [PCNOC_S_10] = &pcnoc_s_10, + [PCNOC_S_11] = &pcnoc_s_11, + [SLAVE_SPDM] = &slv_spdm, + [SLAVE_PDM] = &slv_pdm, + [SLAVE_PRNG] = &slv_prng, + [SLAVE_TCSR] = &slv_tcsr, + [SLAVE_SNOC_CFG] = &slv_snoc_cfg, + [SLAVE_MESSAGE_RAM] = &slv_message_ram, + [SLAVE_DISP_SS_CFG] = &slv_disp_ss_cfg, + [SLAVE_GPU_CFG] = &slv_gpu_cfg, + [SLAVE_BLSP_1] = &slv_blsp_1, + [SLAVE_BLSP_2] = &slv_blsp_2, + [SLAVE_TLMM_NORTH] = &slv_tlmm_north, + [SLAVE_PCIE] = &slv_pcie, + [SLAVE_ETHERNET] = &slv_ethernet, + [SLAVE_TLMM_EAST] = &slv_tlmm_east, + [SLAVE_TCU] = &slv_tcu, + [SLAVE_PMIC_ARB] = &slv_pmic_arb, + [SLAVE_SDCC_1] = &slv_sdcc_1, + [SLAVE_SDCC_2] = &slv_sdcc_2, + [SLAVE_TLMM_SOUTH] = &slv_tlmm_south, + [SLAVE_USB_HS] = &slv_usb_hs, + [SLAVE_USB3] = &slv_usb3, + [SLAVE_CRYPTO_0_CFG] = &slv_crypto_0_cfg, + [SLAVE_PCNOC_SNOC] = &slv_pcnoc_snoc, +}; + +static struct qcom_icc_desc qcs404_pcnoc = { + .nodes = qcs404_pcnoc_nodes, + .num_nodes = ARRAY_SIZE(qcs404_pcnoc_nodes), +}; + +static struct qcom_icc_node *qcs404_snoc_nodes[] = { + [MASTER_QDSS_BAM] = &mas_qdss_bam, + [MASTER_BIMC_SNOC] = &mas_bimc_snoc, + [MASTER_PCNOC_SNOC] = &mas_pcnoc_snoc, + [MASTER_QDSS_ETR] = &mas_qdss_etr, + [MASTER_EMAC] = &mas_emac, + [MASTER_PCIE] = &mas_pcie, + [MASTER_USB3] = &mas_usb3, + [QDSS_INT] = &qdss_int, + [SNOC_INT_0] = &snoc_int_0, + [SNOC_INT_1] = &snoc_int_1, + [SNOC_INT_2] = &snoc_int_2, + [SLAVE_KPSS_AHB] = &slv_kpss_ahb, + [SLAVE_WCSS] = &slv_wcss, + [SLAVE_SNOC_BIMC_1] = &slv_snoc_bimc_1, + [SLAVE_IMEM] = &slv_imem, + [SLAVE_SNOC_PCNOC] = &slv_snoc_pcnoc, + [SLAVE_QDSS_STM] = &slv_qdss_stm, + [SLAVE_CATS_0] = &slv_cats_0, + [SLAVE_CATS_1] = &slv_cats_1, + [SLAVE_LPASS] = &slv_lpass, +}; + +static struct qcom_icc_desc qcs404_snoc = { + .nodes = qcs404_snoc_nodes, + .num_nodes = ARRAY_SIZE(qcs404_snoc_nodes), +}; + +static int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, + u32 peak_bw, u32 *agg_avg, u32 *agg_peak) +{ + *agg_avg += avg_bw; + *agg_peak = max(*agg_peak, peak_bw); + + return 0; +} + +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) + qcom_icc_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); + + /* send bandwidth request message to the RPM processor */ + if (qn->mas_rpm_id != -1) { + ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, + RPM_BUS_MASTER_REQ, + qn->mas_rpm_id, + sum_bw); + if (ret) { + pr_err("qcom_icc_rpm_smd_send mas %d error %d\n", + qn->mas_rpm_id, ret); + return ret; + } + } + + if (qn->slv_rpm_id != -1) { + ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, + RPM_BUS_SLAVE_REQ, + qn->slv_rpm_id, + sum_bw); + if (ret) { + pr_err("qcom_icc_rpm_smd_send slv error %d\n", + 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; + 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_kcalloc(dev, num_nodes, sizeof(*node), GFP_KERNEL); + if (!data) + return -ENOMEM; + + qp->bus_clks = devm_kmemdup(dev, bus_clocks, sizeof(bus_clocks), + GFP_KERNEL); + if (!qp->bus_clks) + return -ENOMEM; + + qp->num_clks = ARRAY_SIZE(bus_clocks); + 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 = qcom_icc_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); + + dev_dbg(dev, "registered node %s\n", node->name); + + /* populate links */ + 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: + list_for_each_entry(node, &provider->nodes, node_list) { + icc_node_del(node); + icc_node_destroy(node->id); + } + 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); + struct icc_provider *provider = &qp->provider; + struct icc_node *n; + + list_for_each_entry(n, &provider->nodes, node_list) { + icc_node_del(n); + icc_node_destroy(n->id); + } + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); + + return icc_provider_del(provider); +} + +static const struct of_device_id qcs404_noc_of_match[] = { + { .compatible = "qcom,qcs404-bimc", .data = &qcs404_bimc }, + { .compatible = "qcom,qcs404-pcnoc", .data = &qcs404_pcnoc }, + { .compatible = "qcom,qcs404-snoc", .data = &qcs404_snoc }, + { }, +}; +MODULE_DEVICE_TABLE(of, qcs404_noc_of_match); + +static struct platform_driver qcs404_noc_driver = { + .probe = qnoc_probe, + .remove = qnoc_remove, + .driver = { + .name = "qnoc-qcs404", + .of_match_table = qcs404_noc_of_match, + }, +}; +module_platform_driver(qcs404_noc_driver); +MODULE_DESCRIPTION("Qualcomm QCS404 NoC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/interconnect/qcom/sdm845.c b/drivers/interconnect/qcom/sdm845.c index 93df67345b39d077a73b2cb7794e24fbf29df392..57955596bb5967ec8a7477cd38caa0b4d744acba 100644 --- a/drivers/interconnect/qcom/sdm845.c +++ b/drivers/interconnect/qcom/sdm845.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * */ @@ -20,23 +20,6 @@ #include #include -#define BCM_TCS_CMD_COMMIT_SHFT 30 -#define BCM_TCS_CMD_COMMIT_MASK 0x40000000 -#define BCM_TCS_CMD_VALID_SHFT 29 -#define BCM_TCS_CMD_VALID_MASK 0x20000000 -#define BCM_TCS_CMD_VOTE_X_SHFT 14 -#define BCM_TCS_CMD_VOTE_MASK 0x3fff -#define BCM_TCS_CMD_VOTE_Y_SHFT 0 -#define BCM_TCS_CMD_VOTE_Y_MASK 0xfffc000 - -#define BCM_TCS_CMD(commit, valid, vote_x, vote_y) \ - (((commit) << BCM_TCS_CMD_COMMIT_SHFT) | \ - ((valid) << BCM_TCS_CMD_VALID_SHFT) | \ - ((cpu_to_le32(vote_x) & \ - BCM_TCS_CMD_VOTE_MASK) << BCM_TCS_CMD_VOTE_X_SHFT) | \ - ((cpu_to_le32(vote_y) & \ - BCM_TCS_CMD_VOTE_MASK) << BCM_TCS_CMD_VOTE_Y_SHFT)) - #define to_qcom_provider(_provider) \ container_of(_provider, struct qcom_icc_provider, provider) diff --git a/drivers/interconnect/qcom/smd-rpm.c b/drivers/interconnect/qcom/smd-rpm.c new file mode 100644 index 0000000000000000000000000000000000000000..dc8ff8d133a9cf610d432c8b688d19852f07aac4 --- /dev/null +++ b/drivers/interconnect/qcom/smd-rpm.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RPM over SMD communication wrapper for interconnects + * + * Copyright (C) 2019 Linaro Ltd + * Author: Georgi Djakov + */ + +#include +#include +#include +#include +#include +#include + +#include "smd-rpm.h" + +#define RPM_KEY_BW 0x00007762 + +static struct qcom_smd_rpm *icc_smd_rpm; + +struct icc_rpm_smd_req { + __le32 key; + __le32 nbytes; + __le32 value; +}; + +bool qcom_icc_rpm_smd_available(void) +{ + return !!icc_smd_rpm; +} +EXPORT_SYMBOL_GPL(qcom_icc_rpm_smd_available); + +int qcom_icc_rpm_smd_send(int ctx, int rsc_type, int id, u32 val) +{ + struct icc_rpm_smd_req req = { + .key = cpu_to_le32(RPM_KEY_BW), + .nbytes = cpu_to_le32(sizeof(u32)), + .value = cpu_to_le32(val), + }; + + return qcom_rpm_smd_write(icc_smd_rpm, ctx, rsc_type, id, &req, + sizeof(req)); +} +EXPORT_SYMBOL_GPL(qcom_icc_rpm_smd_send); + +static int qcom_icc_rpm_smd_remove(struct platform_device *pdev) +{ + icc_smd_rpm = NULL; + + return 0; +} + +static int qcom_icc_rpm_smd_probe(struct platform_device *pdev) +{ + icc_smd_rpm = dev_get_drvdata(pdev->dev.parent); + + if (!icc_smd_rpm) { + dev_err(&pdev->dev, "unable to retrieve handle to RPM\n"); + return -ENODEV; + } + + return 0; +} + +static struct platform_driver qcom_interconnect_rpm_smd_driver = { + .driver = { + .name = "icc_smd_rpm", + }, + .probe = qcom_icc_rpm_smd_probe, + .remove = qcom_icc_rpm_smd_remove, +}; +module_platform_driver(qcom_interconnect_rpm_smd_driver); +MODULE_AUTHOR("Georgi Djakov "); +MODULE_DESCRIPTION("Qualcomm SMD RPM interconnect proxy driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:icc_smd_rpm"); diff --git a/drivers/interconnect/qcom/smd-rpm.h b/drivers/interconnect/qcom/smd-rpm.h new file mode 100644 index 0000000000000000000000000000000000000000..ca9d0327b8ac17f242262ea9cc76ca403f981119 --- /dev/null +++ b/drivers/interconnect/qcom/smd-rpm.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019, Linaro Ltd. + * Author: Georgi Djakov + */ + +#ifndef __DRIVERS_INTERCONNECT_QCOM_SMD_RPM_H +#define __DRIVERS_INTERCONNECT_QCOM_SMD_RPM_H + +#include + +bool qcom_icc_rpm_smd_available(void); +int qcom_icc_rpm_smd_send(int ctx, int rsc_type, int id, u32 val); + +#endif diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index e15cdcd8cb3c8c64597707aa54398444f6a1ac4c..e3842eabcfdd66560dc5c1e33af4011d10944562 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -177,11 +177,12 @@ config DMAR_TABLE config INTEL_IOMMU bool "Support for Intel IOMMU using DMA Remapping Devices" - depends on PCI_MSI && ACPI && (X86 || IA64_GENERIC) + depends on PCI_MSI && ACPI && (X86 || IA64) select IOMMU_API select IOMMU_IOVA select NEED_DMA_MAP_STATE select DMAR_TABLE + select SWIOTLB help DMA remapping (DMAR) devices support enables independent address translations for Direct Memory Access (DMA) from devices. diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index f13f36ae1af652836254ba07315f99303fba6f88..4f405f926e739cdd4d00937f9b57b4d42ee06b30 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -10,13 +10,14 @@ obj-$(CONFIG_IOMMU_IO_PGTABLE_LPAE) += io-pgtable-arm.o obj-$(CONFIG_IOMMU_IOVA) += iova.o obj-$(CONFIG_OF_IOMMU) += of_iommu.o obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o -obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o +obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o amd_iommu_quirks.o obj-$(CONFIG_AMD_IOMMU_DEBUGFS) += amd_iommu_debugfs.o obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o -obj-$(CONFIG_ARM_SMMU) += arm-smmu.o +obj-$(CONFIG_ARM_SMMU) += arm-smmu.o arm-smmu-impl.o obj-$(CONFIG_ARM_SMMU_V3) += arm-smmu-v3.o obj-$(CONFIG_DMAR_TABLE) += dmar.o obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o intel-pasid.o +obj-$(CONFIG_INTEL_IOMMU) += intel-trace.o obj-$(CONFIG_INTEL_IOMMU_DEBUGFS) += intel-iommu-debugfs.o obj-$(CONFIG_INTEL_IOMMU_SVM) += intel-svm.o obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 61de81965c44ed95b52ef857b4f31a4cb8519a28..1ed3b98324bac09ce8399b2ee0ad445e08802d20 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -436,7 +436,7 @@ static int iommu_init_device(struct device *dev) * invalid address), we ignore the capability for the device so * it'll be forced to go into translation mode. */ - if ((iommu_pass_through || !amd_iommu_force_isolation) && + if ((iommu_default_passthrough() || !amd_iommu_force_isolation) && dev_is_pci(dev) && pci_iommuv2_capable(to_pci_dev(dev))) { struct amd_iommu *iommu; @@ -2256,7 +2256,7 @@ static int amd_iommu_add_device(struct device *dev) BUG_ON(!dev_data); - if (iommu_pass_through || dev_data->iommu_v2) + if (dev_data->iommu_v2) iommu_request_dm_for_dev(dev); /* Domains are initialized for this device - have a look what we ended up with */ @@ -2577,7 +2577,9 @@ static int map_sg(struct device *dev, struct scatterlist *sglist, bus_addr = address + s->dma_address + (j << PAGE_SHIFT); phys_addr = (sg_phys(s) & PAGE_MASK) + (j << PAGE_SHIFT); - ret = iommu_map_page(domain, bus_addr, phys_addr, PAGE_SIZE, prot, GFP_ATOMIC); + ret = iommu_map_page(domain, bus_addr, phys_addr, + PAGE_SIZE, prot, + GFP_ATOMIC | __GFP_NOWARN); if (ret) goto out_unmap; @@ -2835,7 +2837,7 @@ int __init amd_iommu_init_api(void) int __init amd_iommu_init_dma_ops(void) { - swiotlb = (iommu_pass_through || sme_me_mask) ? 1 : 0; + swiotlb = (iommu_default_passthrough() || sme_me_mask) ? 1 : 0; iommu_detected = 1; if (amd_iommu_unmap_flush) @@ -3085,7 +3087,8 @@ static int amd_iommu_map(struct iommu_domain *dom, unsigned long iova, } static size_t amd_iommu_unmap(struct iommu_domain *dom, unsigned long iova, - size_t page_size) + size_t page_size, + struct iommu_iotlb_gather *gather) { struct protection_domain *domain = to_pdomain(dom); size_t unmap_size; @@ -3226,9 +3229,10 @@ static void amd_iommu_flush_iotlb_all(struct iommu_domain *domain) domain_flush_complete(dom); } -static void amd_iommu_iotlb_range_add(struct iommu_domain *domain, - unsigned long iova, size_t size) +static void amd_iommu_iotlb_sync(struct iommu_domain *domain, + struct iommu_iotlb_gather *gather) { + amd_iommu_flush_iotlb_all(domain); } const struct iommu_ops amd_iommu_ops = { @@ -3249,8 +3253,7 @@ const struct iommu_ops amd_iommu_ops = { .is_attach_deferred = amd_iommu_is_attach_deferred, .pgsize_bitmap = AMD_IOMMU_PGSIZES, .flush_iotlb_all = amd_iommu_flush_iotlb_all, - .iotlb_range_add = amd_iommu_iotlb_range_add, - .iotlb_sync = amd_iommu_flush_iotlb_all, + .iotlb_sync = amd_iommu_iotlb_sync, }; /***************************************************************************** @@ -4343,13 +4346,62 @@ static const struct irq_domain_ops amd_ir_domain_ops = { .deactivate = irq_remapping_deactivate, }; +int amd_iommu_activate_guest_mode(void *data) +{ + struct amd_ir_data *ir_data = (struct amd_ir_data *)data; + struct irte_ga *entry = (struct irte_ga *) ir_data->entry; + + if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) || + !entry || entry->lo.fields_vapic.guest_mode) + return 0; + + entry->lo.val = 0; + entry->hi.val = 0; + + entry->lo.fields_vapic.guest_mode = 1; + entry->lo.fields_vapic.ga_log_intr = 1; + entry->hi.fields.ga_root_ptr = ir_data->ga_root_ptr; + entry->hi.fields.vector = ir_data->ga_vector; + entry->lo.fields_vapic.ga_tag = ir_data->ga_tag; + + return modify_irte_ga(ir_data->irq_2_irte.devid, + ir_data->irq_2_irte.index, entry, NULL); +} +EXPORT_SYMBOL(amd_iommu_activate_guest_mode); + +int amd_iommu_deactivate_guest_mode(void *data) +{ + struct amd_ir_data *ir_data = (struct amd_ir_data *)data; + struct irte_ga *entry = (struct irte_ga *) ir_data->entry; + struct irq_cfg *cfg = ir_data->cfg; + + if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) || + !entry || !entry->lo.fields_vapic.guest_mode) + return 0; + + entry->lo.val = 0; + entry->hi.val = 0; + + entry->lo.fields_remap.dm = apic->irq_dest_mode; + entry->lo.fields_remap.int_type = apic->irq_delivery_mode; + entry->hi.fields.vector = cfg->vector; + entry->lo.fields_remap.destination = + APICID_TO_IRTE_DEST_LO(cfg->dest_apicid); + entry->hi.fields.destination = + APICID_TO_IRTE_DEST_HI(cfg->dest_apicid); + + return modify_irte_ga(ir_data->irq_2_irte.devid, + ir_data->irq_2_irte.index, entry, NULL); +} +EXPORT_SYMBOL(amd_iommu_deactivate_guest_mode); + static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info) { + int ret; struct amd_iommu *iommu; struct amd_iommu_pi_data *pi_data = vcpu_info; struct vcpu_data *vcpu_pi_info = pi_data->vcpu_data; struct amd_ir_data *ir_data = data->chip_data; - struct irte_ga *irte = (struct irte_ga *) ir_data->entry; struct irq_2_irte *irte_info = &ir_data->irq_2_irte; struct iommu_dev_data *dev_data = search_dev_data(irte_info->devid); @@ -4360,6 +4412,7 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info) if (!dev_data || !dev_data->use_vapic) return 0; + ir_data->cfg = irqd_cfg(data); pi_data->ir_data = ir_data; /* Note: @@ -4378,37 +4431,24 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info) pi_data->prev_ga_tag = ir_data->cached_ga_tag; if (pi_data->is_guest_mode) { - /* Setting */ - irte->hi.fields.ga_root_ptr = (pi_data->base >> 12); - irte->hi.fields.vector = vcpu_pi_info->vector; - irte->lo.fields_vapic.ga_log_intr = 1; - irte->lo.fields_vapic.guest_mode = 1; - irte->lo.fields_vapic.ga_tag = pi_data->ga_tag; - - ir_data->cached_ga_tag = pi_data->ga_tag; + ir_data->ga_root_ptr = (pi_data->base >> 12); + ir_data->ga_vector = vcpu_pi_info->vector; + ir_data->ga_tag = pi_data->ga_tag; + ret = amd_iommu_activate_guest_mode(ir_data); + if (!ret) + ir_data->cached_ga_tag = pi_data->ga_tag; } else { - /* Un-Setting */ - struct irq_cfg *cfg = irqd_cfg(data); - - irte->hi.val = 0; - irte->lo.val = 0; - irte->hi.fields.vector = cfg->vector; - irte->lo.fields_remap.guest_mode = 0; - irte->lo.fields_remap.destination = - APICID_TO_IRTE_DEST_LO(cfg->dest_apicid); - irte->hi.fields.destination = - APICID_TO_IRTE_DEST_HI(cfg->dest_apicid); - irte->lo.fields_remap.int_type = apic->irq_delivery_mode; - irte->lo.fields_remap.dm = apic->irq_dest_mode; + ret = amd_iommu_deactivate_guest_mode(ir_data); /* * This communicates the ga_tag back to the caller * so that it can do all the necessary clean up. */ - ir_data->cached_ga_tag = 0; + if (!ret) + ir_data->cached_ga_tag = 0; } - return modify_irte_ga(irte_info->devid, irte_info->index, irte, ir_data); + return ret; } diff --git a/drivers/iommu/amd_iommu.h b/drivers/iommu/amd_iommu.h new file mode 100644 index 0000000000000000000000000000000000000000..12d540d9b59b0a8e1941934d695b1bc7312a7b0f --- /dev/null +++ b/drivers/iommu/amd_iommu.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef AMD_IOMMU_H +#define AMD_IOMMU_H + +int __init add_special_device(u8 type, u8 id, u16 *devid, bool cmd_line); + +#ifdef CONFIG_DMI +void amd_iommu_apply_ivrs_quirks(void); +#else +static void amd_iommu_apply_ivrs_quirks(void) { } +#endif + +#endif diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 4413aa67000e576a43a7c8d0e8fd79ee2cc0574a..568c52317757ca2924598b69c7329dcfad940356 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -32,6 +32,7 @@ #include #include +#include "amd_iommu.h" #include "amd_iommu_proto.h" #include "amd_iommu_types.h" #include "irq_remapping.h" @@ -1002,7 +1003,7 @@ static void __init set_dev_entry_from_acpi(struct amd_iommu *iommu, set_iommu_for_device(iommu, devid); } -static int __init add_special_device(u8 type, u8 id, u16 *devid, bool cmd_line) +int __init add_special_device(u8 type, u8 id, u16 *devid, bool cmd_line) { struct devid_map *entry; struct list_head *list; @@ -1153,6 +1154,8 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu, if (ret) return ret; + amd_iommu_apply_ivrs_quirks(); + /* * First save the recommended feature enable bits from ACPI */ diff --git a/drivers/iommu/amd_iommu_quirks.c b/drivers/iommu/amd_iommu_quirks.c new file mode 100644 index 0000000000000000000000000000000000000000..c235f79b7a200c90f8b8d4325a61ce4373de8d86 --- /dev/null +++ b/drivers/iommu/amd_iommu_quirks.c @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * Quirks for AMD IOMMU + * + * Copyright (C) 2019 Kai-Heng Feng + */ + +#ifdef CONFIG_DMI +#include + +#include "amd_iommu.h" + +#define IVHD_SPECIAL_IOAPIC 1 + +struct ivrs_quirk_entry { + u8 id; + u16 devid; +}; + +enum { + DELL_INSPIRON_7375 = 0, + DELL_LATITUDE_5495, + LENOVO_IDEAPAD_330S_15ARR, +}; + +static const struct ivrs_quirk_entry ivrs_ioapic_quirks[][3] __initconst = { + /* ivrs_ioapic[4]=00:14.0 ivrs_ioapic[5]=00:00.2 */ + [DELL_INSPIRON_7375] = { + { .id = 4, .devid = 0xa0 }, + { .id = 5, .devid = 0x2 }, + {} + }, + /* ivrs_ioapic[4]=00:14.0 */ + [DELL_LATITUDE_5495] = { + { .id = 4, .devid = 0xa0 }, + {} + }, + /* ivrs_ioapic[32]=00:14.0 */ + [LENOVO_IDEAPAD_330S_15ARR] = { + { .id = 32, .devid = 0xa0 }, + {} + }, + {} +}; + +static int __init ivrs_ioapic_quirk_cb(const struct dmi_system_id *d) +{ + const struct ivrs_quirk_entry *i; + + for (i = d->driver_data; i->id != 0 && i->devid != 0; i++) + add_special_device(IVHD_SPECIAL_IOAPIC, i->id, (u16 *)&i->devid, 0); + + return 0; +} + +static const struct dmi_system_id ivrs_quirks[] __initconst = { + { + .callback = ivrs_ioapic_quirk_cb, + .ident = "Dell Inspiron 7375", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7375"), + }, + .driver_data = (void *)&ivrs_ioapic_quirks[DELL_INSPIRON_7375], + }, + { + .callback = ivrs_ioapic_quirk_cb, + .ident = "Dell Latitude 5495", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Latitude 5495"), + }, + .driver_data = (void *)&ivrs_ioapic_quirks[DELL_LATITUDE_5495], + }, + { + .callback = ivrs_ioapic_quirk_cb, + .ident = "Lenovo ideapad 330S-15ARR", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "81FB"), + }, + .driver_data = (void *)&ivrs_ioapic_quirks[LENOVO_IDEAPAD_330S_15ARR], + }, + {} +}; + +void __init amd_iommu_apply_ivrs_quirks(void) +{ + dmi_check_system(ivrs_quirks); +} +#endif diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index 64edd5a9694cc06400f70692a654f5c006956ddd..9ac229e92b07475f30010338e427cb146821edc1 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -873,6 +873,15 @@ struct amd_ir_data { struct msi_msg msi_entry; void *entry; /* Pointer to union irte or struct irte_ga */ void *ref; /* Pointer to the actual irte */ + + /** + * Store information for activate/de-activate + * Guest virtual APIC mode during runtime. + */ + struct irq_cfg *cfg; + int ga_vector; + int ga_root_ptr; + int ga_tag; }; struct amd_irte_ops { diff --git a/drivers/iommu/arm-smmu-impl.c b/drivers/iommu/arm-smmu-impl.c new file mode 100644 index 0000000000000000000000000000000000000000..5c87a38620c495e0b4abcdd2f8025294b6d9dbad --- /dev/null +++ b/drivers/iommu/arm-smmu-impl.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Miscellaneous Arm SMMU implementation and integration quirks +// Copyright (C) 2019 Arm Limited + +#define pr_fmt(fmt) "arm-smmu: " fmt + +#include +#include + +#include "arm-smmu.h" + + +static int arm_smmu_gr0_ns(int offset) +{ + switch(offset) { + case ARM_SMMU_GR0_sCR0: + case ARM_SMMU_GR0_sACR: + case ARM_SMMU_GR0_sGFSR: + case ARM_SMMU_GR0_sGFSYNR0: + case ARM_SMMU_GR0_sGFSYNR1: + case ARM_SMMU_GR0_sGFSYNR2: + return offset + 0x400; + default: + return offset; + } +} + +static u32 arm_smmu_read_ns(struct arm_smmu_device *smmu, int page, + int offset) +{ + if (page == ARM_SMMU_GR0) + offset = arm_smmu_gr0_ns(offset); + return readl_relaxed(arm_smmu_page(smmu, page) + offset); +} + +static void arm_smmu_write_ns(struct arm_smmu_device *smmu, int page, + int offset, u32 val) +{ + if (page == ARM_SMMU_GR0) + offset = arm_smmu_gr0_ns(offset); + writel_relaxed(val, arm_smmu_page(smmu, page) + offset); +} + +/* Since we don't care for sGFAR, we can do without 64-bit accessors */ +static const struct arm_smmu_impl calxeda_impl = { + .read_reg = arm_smmu_read_ns, + .write_reg = arm_smmu_write_ns, +}; + + +struct cavium_smmu { + struct arm_smmu_device smmu; + u32 id_base; +}; + +static int cavium_cfg_probe(struct arm_smmu_device *smmu) +{ + static atomic_t context_count = ATOMIC_INIT(0); + struct cavium_smmu *cs = container_of(smmu, struct cavium_smmu, smmu); + /* + * Cavium CN88xx erratum #27704. + * Ensure ASID and VMID allocation is unique across all SMMUs in + * the system. + */ + cs->id_base = atomic_fetch_add(smmu->num_context_banks, &context_count); + dev_notice(smmu->dev, "\tenabling workaround for Cavium erratum 27704\n"); + + return 0; +} + +static int cavium_init_context(struct arm_smmu_domain *smmu_domain) +{ + struct cavium_smmu *cs = container_of(smmu_domain->smmu, + struct cavium_smmu, smmu); + + if (smmu_domain->stage == ARM_SMMU_DOMAIN_S2) + smmu_domain->cfg.vmid += cs->id_base; + else + smmu_domain->cfg.asid += cs->id_base; + + return 0; +} + +static const struct arm_smmu_impl cavium_impl = { + .cfg_probe = cavium_cfg_probe, + .init_context = cavium_init_context, +}; + +static struct arm_smmu_device *cavium_smmu_impl_init(struct arm_smmu_device *smmu) +{ + struct cavium_smmu *cs; + + cs = devm_kzalloc(smmu->dev, sizeof(*cs), GFP_KERNEL); + if (!cs) + return ERR_PTR(-ENOMEM); + + cs->smmu = *smmu; + cs->smmu.impl = &cavium_impl; + + devm_kfree(smmu->dev, smmu); + + return &cs->smmu; +} + + +#define ARM_MMU500_ACTLR_CPRE (1 << 1) + +#define ARM_MMU500_ACR_CACHE_LOCK (1 << 26) +#define ARM_MMU500_ACR_S2CRB_TLBEN (1 << 10) +#define ARM_MMU500_ACR_SMTNMB_TLBEN (1 << 8) + +static int arm_mmu500_reset(struct arm_smmu_device *smmu) +{ + u32 reg, major; + int i; + /* + * On MMU-500 r2p0 onwards we need to clear ACR.CACHE_LOCK before + * writes to the context bank ACTLRs will stick. And we just hope that + * Secure has also cleared SACR.CACHE_LOCK for this to take effect... + */ + reg = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_ID7); + major = FIELD_GET(ID7_MAJOR, reg); + reg = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sACR); + if (major >= 2) + reg &= ~ARM_MMU500_ACR_CACHE_LOCK; + /* + * Allow unmatched Stream IDs to allocate bypass + * TLB entries for reduced latency. + */ + reg |= ARM_MMU500_ACR_SMTNMB_TLBEN | ARM_MMU500_ACR_S2CRB_TLBEN; + arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sACR, reg); + + /* + * Disable MMU-500's not-particularly-beneficial next-page + * prefetcher for the sake of errata #841119 and #826419. + */ + for (i = 0; i < smmu->num_context_banks; ++i) { + reg = arm_smmu_cb_read(smmu, i, ARM_SMMU_CB_ACTLR); + reg &= ~ARM_MMU500_ACTLR_CPRE; + arm_smmu_cb_write(smmu, i, ARM_SMMU_CB_ACTLR, reg); + } + + return 0; +} + +static const struct arm_smmu_impl arm_mmu500_impl = { + .reset = arm_mmu500_reset, +}; + + +struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu) +{ + /* + * We will inevitably have to combine model-specific implementation + * quirks with platform-specific integration quirks, but everything + * we currently support happens to work out as straightforward + * mutually-exclusive assignments. + */ + switch (smmu->model) { + case ARM_MMU500: + smmu->impl = &arm_mmu500_impl; + break; + case CAVIUM_SMMUV2: + return cavium_smmu_impl_init(smmu); + default: + break; + } + + if (of_property_read_bool(smmu->dev->of_node, + "calxeda,smmu-secure-config-access")) + smmu->impl = &calxeda_impl; + + return smmu; +} diff --git a/drivers/iommu/arm-smmu-regs.h b/drivers/iommu/arm-smmu-regs.h deleted file mode 100644 index 1c278f7ae888f1633435783623d935c96d02f618..0000000000000000000000000000000000000000 --- a/drivers/iommu/arm-smmu-regs.h +++ /dev/null @@ -1,210 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * IOMMU API for ARM architected SMMU implementations. - * - * Copyright (C) 2013 ARM Limited - * - * Author: Will Deacon - */ - -#ifndef _ARM_SMMU_REGS_H -#define _ARM_SMMU_REGS_H - -/* Configuration registers */ -#define ARM_SMMU_GR0_sCR0 0x0 -#define sCR0_CLIENTPD (1 << 0) -#define sCR0_GFRE (1 << 1) -#define sCR0_GFIE (1 << 2) -#define sCR0_EXIDENABLE (1 << 3) -#define sCR0_GCFGFRE (1 << 4) -#define sCR0_GCFGFIE (1 << 5) -#define sCR0_USFCFG (1 << 10) -#define sCR0_VMIDPNE (1 << 11) -#define sCR0_PTM (1 << 12) -#define sCR0_FB (1 << 13) -#define sCR0_VMID16EN (1 << 31) -#define sCR0_BSU_SHIFT 14 -#define sCR0_BSU_MASK 0x3 - -/* Auxiliary Configuration register */ -#define ARM_SMMU_GR0_sACR 0x10 - -/* Identification registers */ -#define ARM_SMMU_GR0_ID0 0x20 -#define ARM_SMMU_GR0_ID1 0x24 -#define ARM_SMMU_GR0_ID2 0x28 -#define ARM_SMMU_GR0_ID3 0x2c -#define ARM_SMMU_GR0_ID4 0x30 -#define ARM_SMMU_GR0_ID5 0x34 -#define ARM_SMMU_GR0_ID6 0x38 -#define ARM_SMMU_GR0_ID7 0x3c -#define ARM_SMMU_GR0_sGFSR 0x48 -#define ARM_SMMU_GR0_sGFSYNR0 0x50 -#define ARM_SMMU_GR0_sGFSYNR1 0x54 -#define ARM_SMMU_GR0_sGFSYNR2 0x58 - -#define ID0_S1TS (1 << 30) -#define ID0_S2TS (1 << 29) -#define ID0_NTS (1 << 28) -#define ID0_SMS (1 << 27) -#define ID0_ATOSNS (1 << 26) -#define ID0_PTFS_NO_AARCH32 (1 << 25) -#define ID0_PTFS_NO_AARCH32S (1 << 24) -#define ID0_CTTW (1 << 14) -#define ID0_NUMIRPT_SHIFT 16 -#define ID0_NUMIRPT_MASK 0xff -#define ID0_NUMSIDB_SHIFT 9 -#define ID0_NUMSIDB_MASK 0xf -#define ID0_EXIDS (1 << 8) -#define ID0_NUMSMRG_SHIFT 0 -#define ID0_NUMSMRG_MASK 0xff - -#define ID1_PAGESIZE (1 << 31) -#define ID1_NUMPAGENDXB_SHIFT 28 -#define ID1_NUMPAGENDXB_MASK 7 -#define ID1_NUMS2CB_SHIFT 16 -#define ID1_NUMS2CB_MASK 0xff -#define ID1_NUMCB_SHIFT 0 -#define ID1_NUMCB_MASK 0xff - -#define ID2_OAS_SHIFT 4 -#define ID2_OAS_MASK 0xf -#define ID2_IAS_SHIFT 0 -#define ID2_IAS_MASK 0xf -#define ID2_UBS_SHIFT 8 -#define ID2_UBS_MASK 0xf -#define ID2_PTFS_4K (1 << 12) -#define ID2_PTFS_16K (1 << 13) -#define ID2_PTFS_64K (1 << 14) -#define ID2_VMID16 (1 << 15) - -#define ID7_MAJOR_SHIFT 4 -#define ID7_MAJOR_MASK 0xf - -/* Global TLB invalidation */ -#define ARM_SMMU_GR0_TLBIVMID 0x64 -#define ARM_SMMU_GR0_TLBIALLNSNH 0x68 -#define ARM_SMMU_GR0_TLBIALLH 0x6c -#define ARM_SMMU_GR0_sTLBGSYNC 0x70 -#define ARM_SMMU_GR0_sTLBGSTATUS 0x74 -#define sTLBGSTATUS_GSACTIVE (1 << 0) - -/* Stream mapping registers */ -#define ARM_SMMU_GR0_SMR(n) (0x800 + ((n) << 2)) -#define SMR_VALID (1 << 31) -#define SMR_MASK_SHIFT 16 -#define SMR_ID_SHIFT 0 - -#define ARM_SMMU_GR0_S2CR(n) (0xc00 + ((n) << 2)) -#define S2CR_CBNDX_SHIFT 0 -#define S2CR_CBNDX_MASK 0xff -#define S2CR_EXIDVALID (1 << 10) -#define S2CR_TYPE_SHIFT 16 -#define S2CR_TYPE_MASK 0x3 -enum arm_smmu_s2cr_type { - S2CR_TYPE_TRANS, - S2CR_TYPE_BYPASS, - S2CR_TYPE_FAULT, -}; - -#define S2CR_PRIVCFG_SHIFT 24 -#define S2CR_PRIVCFG_MASK 0x3 -enum arm_smmu_s2cr_privcfg { - S2CR_PRIVCFG_DEFAULT, - S2CR_PRIVCFG_DIPAN, - S2CR_PRIVCFG_UNPRIV, - S2CR_PRIVCFG_PRIV, -}; - -/* Context bank attribute registers */ -#define ARM_SMMU_GR1_CBAR(n) (0x0 + ((n) << 2)) -#define CBAR_VMID_SHIFT 0 -#define CBAR_VMID_MASK 0xff -#define CBAR_S1_BPSHCFG_SHIFT 8 -#define CBAR_S1_BPSHCFG_MASK 3 -#define CBAR_S1_BPSHCFG_NSH 3 -#define CBAR_S1_MEMATTR_SHIFT 12 -#define CBAR_S1_MEMATTR_MASK 0xf -#define CBAR_S1_MEMATTR_WB 0xf -#define CBAR_TYPE_SHIFT 16 -#define CBAR_TYPE_MASK 0x3 -#define CBAR_TYPE_S2_TRANS (0 << CBAR_TYPE_SHIFT) -#define CBAR_TYPE_S1_TRANS_S2_BYPASS (1 << CBAR_TYPE_SHIFT) -#define CBAR_TYPE_S1_TRANS_S2_FAULT (2 << CBAR_TYPE_SHIFT) -#define CBAR_TYPE_S1_TRANS_S2_TRANS (3 << CBAR_TYPE_SHIFT) -#define CBAR_IRPTNDX_SHIFT 24 -#define CBAR_IRPTNDX_MASK 0xff - -#define ARM_SMMU_GR1_CBFRSYNRA(n) (0x400 + ((n) << 2)) - -#define ARM_SMMU_GR1_CBA2R(n) (0x800 + ((n) << 2)) -#define CBA2R_RW64_32BIT (0 << 0) -#define CBA2R_RW64_64BIT (1 << 0) -#define CBA2R_VMID_SHIFT 16 -#define CBA2R_VMID_MASK 0xffff - -#define ARM_SMMU_CB_SCTLR 0x0 -#define ARM_SMMU_CB_ACTLR 0x4 -#define ARM_SMMU_CB_RESUME 0x8 -#define ARM_SMMU_CB_TTBCR2 0x10 -#define ARM_SMMU_CB_TTBR0 0x20 -#define ARM_SMMU_CB_TTBR1 0x28 -#define ARM_SMMU_CB_TTBCR 0x30 -#define ARM_SMMU_CB_CONTEXTIDR 0x34 -#define ARM_SMMU_CB_S1_MAIR0 0x38 -#define ARM_SMMU_CB_S1_MAIR1 0x3c -#define ARM_SMMU_CB_PAR 0x50 -#define ARM_SMMU_CB_FSR 0x58 -#define ARM_SMMU_CB_FAR 0x60 -#define ARM_SMMU_CB_FSYNR0 0x68 -#define ARM_SMMU_CB_S1_TLBIVA 0x600 -#define ARM_SMMU_CB_S1_TLBIASID 0x610 -#define ARM_SMMU_CB_S1_TLBIVAL 0x620 -#define ARM_SMMU_CB_S2_TLBIIPAS2 0x630 -#define ARM_SMMU_CB_S2_TLBIIPAS2L 0x638 -#define ARM_SMMU_CB_TLBSYNC 0x7f0 -#define ARM_SMMU_CB_TLBSTATUS 0x7f4 -#define ARM_SMMU_CB_ATS1PR 0x800 -#define ARM_SMMU_CB_ATSR 0x8f0 - -#define SCTLR_S1_ASIDPNE (1 << 12) -#define SCTLR_CFCFG (1 << 7) -#define SCTLR_CFIE (1 << 6) -#define SCTLR_CFRE (1 << 5) -#define SCTLR_E (1 << 4) -#define SCTLR_AFE (1 << 2) -#define SCTLR_TRE (1 << 1) -#define SCTLR_M (1 << 0) - -#define CB_PAR_F (1 << 0) - -#define ATSR_ACTIVE (1 << 0) - -#define RESUME_RETRY (0 << 0) -#define RESUME_TERMINATE (1 << 0) - -#define TTBCR2_SEP_SHIFT 15 -#define TTBCR2_SEP_UPSTREAM (0x7 << TTBCR2_SEP_SHIFT) -#define TTBCR2_AS (1 << 4) - -#define TTBRn_ASID_SHIFT 48 - -#define FSR_MULTI (1 << 31) -#define FSR_SS (1 << 30) -#define FSR_UUT (1 << 8) -#define FSR_ASF (1 << 7) -#define FSR_TLBLKF (1 << 6) -#define FSR_TLBMCF (1 << 5) -#define FSR_EF (1 << 4) -#define FSR_PF (1 << 3) -#define FSR_AFF (1 << 2) -#define FSR_TF (1 << 1) - -#define FSR_IGN (FSR_AFF | FSR_ASF | \ - FSR_TLBMCF | FSR_TLBLKF) -#define FSR_FAULT (FSR_MULTI | FSR_SS | FSR_UUT | \ - FSR_EF | FSR_PF | FSR_TF | FSR_IGN) - -#define FSYNR0_WNR (1 << 4) - -#endif /* _ARM_SMMU_REGS_H */ diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index c5c93e48b4dbdf7409ca3b8008a24a4ab3214a49..8da93e730d6fd9f7eb6f1d9a2e8072232c7e3754 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -181,12 +181,13 @@ #define ARM_SMMU_MEMATTR_DEVICE_nGnRE 0x1 #define ARM_SMMU_MEMATTR_OIWB 0xf -#define Q_IDX(q, p) ((p) & ((1 << (q)->max_n_shift) - 1)) -#define Q_WRP(q, p) ((p) & (1 << (q)->max_n_shift)) -#define Q_OVERFLOW_FLAG (1 << 31) -#define Q_OVF(q, p) ((p) & Q_OVERFLOW_FLAG) +#define Q_IDX(llq, p) ((p) & ((1 << (llq)->max_n_shift) - 1)) +#define Q_WRP(llq, p) ((p) & (1 << (llq)->max_n_shift)) +#define Q_OVERFLOW_FLAG (1U << 31) +#define Q_OVF(p) ((p) & Q_OVERFLOW_FLAG) #define Q_ENT(q, p) ((q)->base + \ - Q_IDX(q, p) * (q)->ent_dwords) + Q_IDX(&((q)->llq), p) * \ + (q)->ent_dwords) #define Q_BASE_RWA (1UL << 62) #define Q_BASE_ADDR_MASK GENMASK_ULL(51, 5) @@ -306,6 +307,15 @@ #define CMDQ_ERR_CERROR_ABT_IDX 2 #define CMDQ_ERR_CERROR_ATC_INV_IDX 3 +#define CMDQ_PROD_OWNED_FLAG Q_OVERFLOW_FLAG + +/* + * This is used to size the command queue and therefore must be at least + * BITS_PER_LONG so that the valid_map works correctly (it relies on the + * total number of queue entries being a multiple of BITS_PER_LONG). + */ +#define CMDQ_BATCH_ENTRIES BITS_PER_LONG + #define CMDQ_0_OP GENMASK_ULL(7, 0) #define CMDQ_0_SSV (1UL << 11) @@ -368,9 +378,8 @@ #define PRIQ_1_ADDR_MASK GENMASK_ULL(63, 12) /* High-level queue structures */ -#define ARM_SMMU_POLL_TIMEOUT_US 100 -#define ARM_SMMU_CMDQ_SYNC_TIMEOUT_US 1000000 /* 1s! */ -#define ARM_SMMU_CMDQ_SYNC_SPIN_COUNT 10 +#define ARM_SMMU_POLL_TIMEOUT_US 1000000 /* 1s! */ +#define ARM_SMMU_POLL_SPIN_COUNT 10 #define MSI_IOVA_BASE 0x8000000 #define MSI_IOVA_LENGTH 0x100000 @@ -472,13 +481,29 @@ struct arm_smmu_cmdq_ent { #define CMDQ_OP_CMD_SYNC 0x46 struct { - u32 msidata; u64 msiaddr; } sync; }; }; +struct arm_smmu_ll_queue { + union { + u64 val; + struct { + u32 prod; + u32 cons; + }; + struct { + atomic_t prod; + atomic_t cons; + } atomic; + u8 __pad[SMP_CACHE_BYTES]; + } ____cacheline_aligned_in_smp; + u32 max_n_shift; +}; + struct arm_smmu_queue { + struct arm_smmu_ll_queue llq; int irq; /* Wired interrupt */ __le64 *base; @@ -486,17 +511,23 @@ struct arm_smmu_queue { u64 q_base; size_t ent_dwords; - u32 max_n_shift; - u32 prod; - u32 cons; u32 __iomem *prod_reg; u32 __iomem *cons_reg; }; +struct arm_smmu_queue_poll { + ktime_t timeout; + unsigned int delay; + unsigned int spin_cnt; + bool wfe; +}; + struct arm_smmu_cmdq { struct arm_smmu_queue q; - spinlock_t lock; + atomic_long_t *valid_map; + atomic_t owner_prod; + atomic_t lock; }; struct arm_smmu_evtq { @@ -576,8 +607,6 @@ struct arm_smmu_device { int gerr_irq; int combined_irq; - u32 sync_nr; - u8 prev_cmd_opcode; unsigned long ias; /* IPA */ unsigned long oas; /* PA */ @@ -596,12 +625,6 @@ struct arm_smmu_device { struct arm_smmu_strtab_cfg strtab_cfg; - /* Hi16xx adds an extra 32 bits of goodness to its MSI payload */ - union { - u32 sync_count; - u64 padding; - }; - /* IOMMU core code handle */ struct iommu_device iommu; }; @@ -614,7 +637,7 @@ struct arm_smmu_master { struct list_head domain_head; u32 *sids; unsigned int num_sids; - bool ats_enabled :1; + bool ats_enabled; }; /* SMMU private data for an IOMMU domain */ @@ -631,6 +654,7 @@ struct arm_smmu_domain { struct io_pgtable_ops *pgtbl_ops; bool non_strict; + atomic_t nr_ats_masters; enum arm_smmu_domain_stage stage; union { @@ -685,85 +709,97 @@ static void parse_driver_options(struct arm_smmu_device *smmu) } /* Low-level queue manipulation functions */ -static bool queue_full(struct arm_smmu_queue *q) +static bool queue_has_space(struct arm_smmu_ll_queue *q, u32 n) +{ + u32 space, prod, cons; + + prod = Q_IDX(q, q->prod); + cons = Q_IDX(q, q->cons); + + if (Q_WRP(q, q->prod) == Q_WRP(q, q->cons)) + space = (1 << q->max_n_shift) - (prod - cons); + else + space = cons - prod; + + return space >= n; +} + +static bool queue_full(struct arm_smmu_ll_queue *q) { return Q_IDX(q, q->prod) == Q_IDX(q, q->cons) && Q_WRP(q, q->prod) != Q_WRP(q, q->cons); } -static bool queue_empty(struct arm_smmu_queue *q) +static bool queue_empty(struct arm_smmu_ll_queue *q) { return Q_IDX(q, q->prod) == Q_IDX(q, q->cons) && Q_WRP(q, q->prod) == Q_WRP(q, q->cons); } -static void queue_sync_cons(struct arm_smmu_queue *q) +static bool queue_consumed(struct arm_smmu_ll_queue *q, u32 prod) { - q->cons = readl_relaxed(q->cons_reg); + return ((Q_WRP(q, q->cons) == Q_WRP(q, prod)) && + (Q_IDX(q, q->cons) > Q_IDX(q, prod))) || + ((Q_WRP(q, q->cons) != Q_WRP(q, prod)) && + (Q_IDX(q, q->cons) <= Q_IDX(q, prod))); } -static void queue_inc_cons(struct arm_smmu_queue *q) +static void queue_sync_cons_out(struct arm_smmu_queue *q) { - u32 cons = (Q_WRP(q, q->cons) | Q_IDX(q, q->cons)) + 1; - - q->cons = Q_OVF(q, q->cons) | Q_WRP(q, cons) | Q_IDX(q, cons); - /* * Ensure that all CPU accesses (reads and writes) to the queue * are complete before we update the cons pointer. */ mb(); - writel_relaxed(q->cons, q->cons_reg); + writel_relaxed(q->llq.cons, q->cons_reg); +} + +static void queue_inc_cons(struct arm_smmu_ll_queue *q) +{ + u32 cons = (Q_WRP(q, q->cons) | Q_IDX(q, q->cons)) + 1; + q->cons = Q_OVF(q->cons) | Q_WRP(q, cons) | Q_IDX(q, cons); } -static int queue_sync_prod(struct arm_smmu_queue *q) +static int queue_sync_prod_in(struct arm_smmu_queue *q) { int ret = 0; u32 prod = readl_relaxed(q->prod_reg); - if (Q_OVF(q, prod) != Q_OVF(q, q->prod)) + if (Q_OVF(prod) != Q_OVF(q->llq.prod)) ret = -EOVERFLOW; - q->prod = prod; + q->llq.prod = prod; return ret; } -static void queue_inc_prod(struct arm_smmu_queue *q) +static u32 queue_inc_prod_n(struct arm_smmu_ll_queue *q, int n) { - u32 prod = (Q_WRP(q, q->prod) | Q_IDX(q, q->prod)) + 1; - - q->prod = Q_OVF(q, q->prod) | Q_WRP(q, prod) | Q_IDX(q, prod); - writel(q->prod, q->prod_reg); + u32 prod = (Q_WRP(q, q->prod) | Q_IDX(q, q->prod)) + n; + return Q_OVF(q->prod) | Q_WRP(q, prod) | Q_IDX(q, prod); } -/* - * Wait for the SMMU to consume items. If sync is true, wait until the queue - * is empty. Otherwise, wait until there is at least one free slot. - */ -static int queue_poll_cons(struct arm_smmu_queue *q, bool sync, bool wfe) +static void queue_poll_init(struct arm_smmu_device *smmu, + struct arm_smmu_queue_poll *qp) { - ktime_t timeout; - unsigned int delay = 1, spin_cnt = 0; - - /* Wait longer if it's a CMD_SYNC */ - timeout = ktime_add_us(ktime_get(), sync ? - ARM_SMMU_CMDQ_SYNC_TIMEOUT_US : - ARM_SMMU_POLL_TIMEOUT_US); + qp->delay = 1; + qp->spin_cnt = 0; + qp->wfe = !!(smmu->features & ARM_SMMU_FEAT_SEV); + qp->timeout = ktime_add_us(ktime_get(), ARM_SMMU_POLL_TIMEOUT_US); +} - while (queue_sync_cons(q), (sync ? !queue_empty(q) : queue_full(q))) { - if (ktime_compare(ktime_get(), timeout) > 0) - return -ETIMEDOUT; +static int queue_poll(struct arm_smmu_queue_poll *qp) +{ + if (ktime_compare(ktime_get(), qp->timeout) > 0) + return -ETIMEDOUT; - if (wfe) { - wfe(); - } else if (++spin_cnt < ARM_SMMU_CMDQ_SYNC_SPIN_COUNT) { - cpu_relax(); - continue; - } else { - udelay(delay); - delay *= 2; - spin_cnt = 0; - } + if (qp->wfe) { + wfe(); + } else if (++qp->spin_cnt < ARM_SMMU_POLL_SPIN_COUNT) { + cpu_relax(); + } else { + udelay(qp->delay); + qp->delay *= 2; + qp->spin_cnt = 0; } return 0; @@ -777,16 +813,6 @@ static void queue_write(__le64 *dst, u64 *src, size_t n_dwords) *dst++ = cpu_to_le64(*src++); } -static int queue_insert_raw(struct arm_smmu_queue *q, u64 *ent) -{ - if (queue_full(q)) - return -ENOSPC; - - queue_write(Q_ENT(q, q->prod), ent, q->ent_dwords); - queue_inc_prod(q); - return 0; -} - static void queue_read(__le64 *dst, u64 *src, size_t n_dwords) { int i; @@ -797,11 +823,12 @@ static void queue_read(__le64 *dst, u64 *src, size_t n_dwords) static int queue_remove_raw(struct arm_smmu_queue *q, u64 *ent) { - if (queue_empty(q)) + if (queue_empty(&q->llq)) return -EAGAIN; - queue_read(ent, Q_ENT(q, q->cons), q->ent_dwords); - queue_inc_cons(q); + queue_read(ent, Q_ENT(q, q->llq.cons), q->ent_dwords); + queue_inc_cons(&q->llq); + queue_sync_cons_out(q); return 0; } @@ -868,20 +895,14 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent) cmd[1] |= FIELD_PREP(CMDQ_PRI_1_RESP, ent->pri.resp); break; case CMDQ_OP_CMD_SYNC: - if (ent->sync.msiaddr) + if (ent->sync.msiaddr) { cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_IRQ); - else + cmd[1] |= ent->sync.msiaddr & CMDQ_SYNC_1_MSIADDR_MASK; + } else { cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_SEV); + } cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSH, ARM_SMMU_SH_ISH); cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSIATTR, ARM_SMMU_MEMATTR_OIWB); - /* - * Commands are written little-endian, but we want the SMMU to - * receive MSIData, and thus write it back to memory, in CPU - * byte order, so big-endian needs an extra byteswap here. - */ - cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSIDATA, - cpu_to_le32(ent->sync.msidata)); - cmd[1] |= ent->sync.msiaddr & CMDQ_SYNC_1_MSIADDR_MASK; break; default: return -ENOENT; @@ -890,6 +911,27 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent) return 0; } +static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu, + u32 prod) +{ + struct arm_smmu_queue *q = &smmu->cmdq.q; + struct arm_smmu_cmdq_ent ent = { + .opcode = CMDQ_OP_CMD_SYNC, + }; + + /* + * Beware that Hi16xx adds an extra 32 bits of goodness to its MSI + * payload, so the write will zero the entire command on that platform. + */ + if (smmu->features & ARM_SMMU_FEAT_MSI && + smmu->features & ARM_SMMU_FEAT_COHERENCY) { + ent.sync.msiaddr = q->base_dma + Q_IDX(&q->llq, prod) * + q->ent_dwords * 8; + } + + arm_smmu_cmdq_build_cmd(cmd, &ent); +} + static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu) { static const char *cerror_str[] = { @@ -948,109 +990,456 @@ static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu) queue_write(Q_ENT(q, cons), cmd, q->ent_dwords); } -static void arm_smmu_cmdq_insert_cmd(struct arm_smmu_device *smmu, u64 *cmd) +/* + * Command queue locking. + * This is a form of bastardised rwlock with the following major changes: + * + * - The only LOCK routines are exclusive_trylock() and shared_lock(). + * Neither have barrier semantics, and instead provide only a control + * dependency. + * + * - The UNLOCK routines are supplemented with shared_tryunlock(), which + * fails if the caller appears to be the last lock holder (yes, this is + * racy). All successful UNLOCK routines have RELEASE semantics. + */ +static void arm_smmu_cmdq_shared_lock(struct arm_smmu_cmdq *cmdq) { - struct arm_smmu_queue *q = &smmu->cmdq.q; - bool wfe = !!(smmu->features & ARM_SMMU_FEAT_SEV); + int val; + + /* + * We can try to avoid the cmpxchg() loop by simply incrementing the + * lock counter. When held in exclusive state, the lock counter is set + * to INT_MIN so these increments won't hurt as the value will remain + * negative. + */ + if (atomic_fetch_inc_relaxed(&cmdq->lock) >= 0) + return; + + do { + val = atomic_cond_read_relaxed(&cmdq->lock, VAL >= 0); + } while (atomic_cmpxchg_relaxed(&cmdq->lock, val, val + 1) != val); +} + +static void arm_smmu_cmdq_shared_unlock(struct arm_smmu_cmdq *cmdq) +{ + (void)atomic_dec_return_release(&cmdq->lock); +} + +static bool arm_smmu_cmdq_shared_tryunlock(struct arm_smmu_cmdq *cmdq) +{ + if (atomic_read(&cmdq->lock) == 1) + return false; - smmu->prev_cmd_opcode = FIELD_GET(CMDQ_0_OP, cmd[0]); + arm_smmu_cmdq_shared_unlock(cmdq); + return true; +} + +#define arm_smmu_cmdq_exclusive_trylock_irqsave(cmdq, flags) \ +({ \ + bool __ret; \ + local_irq_save(flags); \ + __ret = !atomic_cmpxchg_relaxed(&cmdq->lock, 0, INT_MIN); \ + if (!__ret) \ + local_irq_restore(flags); \ + __ret; \ +}) + +#define arm_smmu_cmdq_exclusive_unlock_irqrestore(cmdq, flags) \ +({ \ + atomic_set_release(&cmdq->lock, 0); \ + local_irq_restore(flags); \ +}) + + +/* + * Command queue insertion. + * This is made fiddly by our attempts to achieve some sort of scalability + * since there is one queue shared amongst all of the CPUs in the system. If + * you like mixed-size concurrency, dependency ordering and relaxed atomics, + * then you'll *love* this monstrosity. + * + * The basic idea is to split the queue up into ranges of commands that are + * owned by a given CPU; the owner may not have written all of the commands + * itself, but is responsible for advancing the hardware prod pointer when + * the time comes. The algorithm is roughly: + * + * 1. Allocate some space in the queue. At this point we also discover + * whether the head of the queue is currently owned by another CPU, + * or whether we are the owner. + * + * 2. Write our commands into our allocated slots in the queue. + * + * 3. Mark our slots as valid in arm_smmu_cmdq.valid_map. + * + * 4. If we are an owner: + * a. Wait for the previous owner to finish. + * b. Mark the queue head as unowned, which tells us the range + * that we are responsible for publishing. + * c. Wait for all commands in our owned range to become valid. + * d. Advance the hardware prod pointer. + * e. Tell the next owner we've finished. + * + * 5. If we are inserting a CMD_SYNC (we may or may not have been an + * owner), then we need to stick around until it has completed: + * a. If we have MSIs, the SMMU can write back into the CMD_SYNC + * to clear the first 4 bytes. + * b. Otherwise, we spin waiting for the hardware cons pointer to + * advance past our command. + * + * The devil is in the details, particularly the use of locking for handling + * SYNC completion and freeing up space in the queue before we think that it is + * full. + */ +static void __arm_smmu_cmdq_poll_set_valid_map(struct arm_smmu_cmdq *cmdq, + u32 sprod, u32 eprod, bool set) +{ + u32 swidx, sbidx, ewidx, ebidx; + struct arm_smmu_ll_queue llq = { + .max_n_shift = cmdq->q.llq.max_n_shift, + .prod = sprod, + }; + + ewidx = BIT_WORD(Q_IDX(&llq, eprod)); + ebidx = Q_IDX(&llq, eprod) % BITS_PER_LONG; + + while (llq.prod != eprod) { + unsigned long mask; + atomic_long_t *ptr; + u32 limit = BITS_PER_LONG; + + swidx = BIT_WORD(Q_IDX(&llq, llq.prod)); + sbidx = Q_IDX(&llq, llq.prod) % BITS_PER_LONG; + + ptr = &cmdq->valid_map[swidx]; + + if ((swidx == ewidx) && (sbidx < ebidx)) + limit = ebidx; - while (queue_insert_raw(q, cmd) == -ENOSPC) { - if (queue_poll_cons(q, false, wfe)) - dev_err_ratelimited(smmu->dev, "CMDQ timeout\n"); + mask = GENMASK(limit - 1, sbidx); + + /* + * The valid bit is the inverse of the wrap bit. This means + * that a zero-initialised queue is invalid and, after marking + * all entries as valid, they become invalid again when we + * wrap. + */ + if (set) { + atomic_long_xor(mask, ptr); + } else { /* Poll */ + unsigned long valid; + + valid = (ULONG_MAX + !!Q_WRP(&llq, llq.prod)) & mask; + atomic_long_cond_read_relaxed(ptr, (VAL & mask) == valid); + } + + llq.prod = queue_inc_prod_n(&llq, limit - sbidx); } } -static void arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu, - struct arm_smmu_cmdq_ent *ent) +/* Mark all entries in the range [sprod, eprod) as valid */ +static void arm_smmu_cmdq_set_valid_map(struct arm_smmu_cmdq *cmdq, + u32 sprod, u32 eprod) +{ + __arm_smmu_cmdq_poll_set_valid_map(cmdq, sprod, eprod, true); +} + +/* Wait for all entries in the range [sprod, eprod) to become valid */ +static void arm_smmu_cmdq_poll_valid_map(struct arm_smmu_cmdq *cmdq, + u32 sprod, u32 eprod) +{ + __arm_smmu_cmdq_poll_set_valid_map(cmdq, sprod, eprod, false); +} + +/* Wait for the command queue to become non-full */ +static int arm_smmu_cmdq_poll_until_not_full(struct arm_smmu_device *smmu, + struct arm_smmu_ll_queue *llq) { - u64 cmd[CMDQ_ENT_DWORDS]; unsigned long flags; + struct arm_smmu_queue_poll qp; + struct arm_smmu_cmdq *cmdq = &smmu->cmdq; + int ret = 0; - if (arm_smmu_cmdq_build_cmd(cmd, ent)) { - dev_warn(smmu->dev, "ignoring unknown CMDQ opcode 0x%x\n", - ent->opcode); - return; + /* + * Try to update our copy of cons by grabbing exclusive cmdq access. If + * that fails, spin until somebody else updates it for us. + */ + if (arm_smmu_cmdq_exclusive_trylock_irqsave(cmdq, flags)) { + WRITE_ONCE(cmdq->q.llq.cons, readl_relaxed(cmdq->q.cons_reg)); + arm_smmu_cmdq_exclusive_unlock_irqrestore(cmdq, flags); + llq->val = READ_ONCE(cmdq->q.llq.val); + return 0; } - spin_lock_irqsave(&smmu->cmdq.lock, flags); - arm_smmu_cmdq_insert_cmd(smmu, cmd); - spin_unlock_irqrestore(&smmu->cmdq.lock, flags); + queue_poll_init(smmu, &qp); + do { + llq->val = READ_ONCE(smmu->cmdq.q.llq.val); + if (!queue_full(llq)) + break; + + ret = queue_poll(&qp); + } while (!ret); + + return ret; } /* - * The difference between val and sync_idx is bounded by the maximum size of - * a queue at 2^20 entries, so 32 bits is plenty for wrap-safe arithmetic. + * Wait until the SMMU signals a CMD_SYNC completion MSI. + * Must be called with the cmdq lock held in some capacity. */ -static int __arm_smmu_sync_poll_msi(struct arm_smmu_device *smmu, u32 sync_idx) +static int __arm_smmu_cmdq_poll_until_msi(struct arm_smmu_device *smmu, + struct arm_smmu_ll_queue *llq) { - ktime_t timeout; - u32 val; + int ret = 0; + struct arm_smmu_queue_poll qp; + struct arm_smmu_cmdq *cmdq = &smmu->cmdq; + u32 *cmd = (u32 *)(Q_ENT(&cmdq->q, llq->prod)); - timeout = ktime_add_us(ktime_get(), ARM_SMMU_CMDQ_SYNC_TIMEOUT_US); - val = smp_cond_load_acquire(&smmu->sync_count, - (int)(VAL - sync_idx) >= 0 || - !ktime_before(ktime_get(), timeout)); + queue_poll_init(smmu, &qp); - return (int)(val - sync_idx) < 0 ? -ETIMEDOUT : 0; + /* + * The MSI won't generate an event, since it's being written back + * into the command queue. + */ + qp.wfe = false; + smp_cond_load_relaxed(cmd, !VAL || (ret = queue_poll(&qp))); + llq->cons = ret ? llq->prod : queue_inc_prod_n(llq, 1); + return ret; } -static int __arm_smmu_cmdq_issue_sync_msi(struct arm_smmu_device *smmu) +/* + * Wait until the SMMU cons index passes llq->prod. + * Must be called with the cmdq lock held in some capacity. + */ +static int __arm_smmu_cmdq_poll_until_consumed(struct arm_smmu_device *smmu, + struct arm_smmu_ll_queue *llq) { - u64 cmd[CMDQ_ENT_DWORDS]; - unsigned long flags; - struct arm_smmu_cmdq_ent ent = { - .opcode = CMDQ_OP_CMD_SYNC, - .sync = { - .msiaddr = virt_to_phys(&smmu->sync_count), - }, - }; + struct arm_smmu_queue_poll qp; + struct arm_smmu_cmdq *cmdq = &smmu->cmdq; + u32 prod = llq->prod; + int ret = 0; - spin_lock_irqsave(&smmu->cmdq.lock, flags); + queue_poll_init(smmu, &qp); + llq->val = READ_ONCE(smmu->cmdq.q.llq.val); + do { + if (queue_consumed(llq, prod)) + break; - /* Piggy-back on the previous command if it's a SYNC */ - if (smmu->prev_cmd_opcode == CMDQ_OP_CMD_SYNC) { - ent.sync.msidata = smmu->sync_nr; - } else { - ent.sync.msidata = ++smmu->sync_nr; - arm_smmu_cmdq_build_cmd(cmd, &ent); - arm_smmu_cmdq_insert_cmd(smmu, cmd); - } + ret = queue_poll(&qp); + + /* + * This needs to be a readl() so that our subsequent call + * to arm_smmu_cmdq_shared_tryunlock() can fail accurately. + * + * Specifically, we need to ensure that we observe all + * shared_lock()s by other CMD_SYNCs that share our owner, + * so that a failing call to tryunlock() means that we're + * the last one out and therefore we can safely advance + * cmdq->q.llq.cons. Roughly speaking: + * + * CPU 0 CPU1 CPU2 (us) + * + * if (sync) + * shared_lock(); + * + * dma_wmb(); + * set_valid_map(); + * + * if (owner) { + * poll_valid_map(); + * + * writel(prod_reg); + * + * readl(cons_reg); + * tryunlock(); + * + * Requires us to see CPU 0's shared_lock() acquisition. + */ + llq->cons = readl(cmdq->q.cons_reg); + } while (!ret); - spin_unlock_irqrestore(&smmu->cmdq.lock, flags); + return ret; +} - return __arm_smmu_sync_poll_msi(smmu, ent.sync.msidata); +static int arm_smmu_cmdq_poll_until_sync(struct arm_smmu_device *smmu, + struct arm_smmu_ll_queue *llq) +{ + if (smmu->features & ARM_SMMU_FEAT_MSI && + smmu->features & ARM_SMMU_FEAT_COHERENCY) + return __arm_smmu_cmdq_poll_until_msi(smmu, llq); + + return __arm_smmu_cmdq_poll_until_consumed(smmu, llq); } -static int __arm_smmu_cmdq_issue_sync(struct arm_smmu_device *smmu) +static void arm_smmu_cmdq_write_entries(struct arm_smmu_cmdq *cmdq, u64 *cmds, + u32 prod, int n) { - u64 cmd[CMDQ_ENT_DWORDS]; + int i; + struct arm_smmu_ll_queue llq = { + .max_n_shift = cmdq->q.llq.max_n_shift, + .prod = prod, + }; + + for (i = 0; i < n; ++i) { + u64 *cmd = &cmds[i * CMDQ_ENT_DWORDS]; + + prod = queue_inc_prod_n(&llq, i); + queue_write(Q_ENT(&cmdq->q, prod), cmd, CMDQ_ENT_DWORDS); + } +} + +/* + * This is the actual insertion function, and provides the following + * ordering guarantees to callers: + * + * - There is a dma_wmb() before publishing any commands to the queue. + * This can be relied upon to order prior writes to data structures + * in memory (such as a CD or an STE) before the command. + * + * - On completion of a CMD_SYNC, there is a control dependency. + * This can be relied upon to order subsequent writes to memory (e.g. + * freeing an IOVA) after completion of the CMD_SYNC. + * + * - Command insertion is totally ordered, so if two CPUs each race to + * insert their own list of commands then all of the commands from one + * CPU will appear before any of the commands from the other CPU. + */ +static int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu, + u64 *cmds, int n, bool sync) +{ + u64 cmd_sync[CMDQ_ENT_DWORDS]; + u32 prod; unsigned long flags; - bool wfe = !!(smmu->features & ARM_SMMU_FEAT_SEV); - struct arm_smmu_cmdq_ent ent = { .opcode = CMDQ_OP_CMD_SYNC }; - int ret; + bool owner; + struct arm_smmu_cmdq *cmdq = &smmu->cmdq; + struct arm_smmu_ll_queue llq = { + .max_n_shift = cmdq->q.llq.max_n_shift, + }, head = llq; + int ret = 0; - arm_smmu_cmdq_build_cmd(cmd, &ent); + /* 1. Allocate some space in the queue */ + local_irq_save(flags); + llq.val = READ_ONCE(cmdq->q.llq.val); + do { + u64 old; + + while (!queue_has_space(&llq, n + sync)) { + local_irq_restore(flags); + if (arm_smmu_cmdq_poll_until_not_full(smmu, &llq)) + dev_err_ratelimited(smmu->dev, "CMDQ timeout\n"); + local_irq_save(flags); + } + + head.cons = llq.cons; + head.prod = queue_inc_prod_n(&llq, n + sync) | + CMDQ_PROD_OWNED_FLAG; + + old = cmpxchg_relaxed(&cmdq->q.llq.val, llq.val, head.val); + if (old == llq.val) + break; + + llq.val = old; + } while (1); + owner = !(llq.prod & CMDQ_PROD_OWNED_FLAG); + head.prod &= ~CMDQ_PROD_OWNED_FLAG; + llq.prod &= ~CMDQ_PROD_OWNED_FLAG; + + /* + * 2. Write our commands into the queue + * Dependency ordering from the cmpxchg() loop above. + */ + arm_smmu_cmdq_write_entries(cmdq, cmds, llq.prod, n); + if (sync) { + prod = queue_inc_prod_n(&llq, n); + arm_smmu_cmdq_build_sync_cmd(cmd_sync, smmu, prod); + queue_write(Q_ENT(&cmdq->q, prod), cmd_sync, CMDQ_ENT_DWORDS); + + /* + * In order to determine completion of our CMD_SYNC, we must + * ensure that the queue can't wrap twice without us noticing. + * We achieve that by taking the cmdq lock as shared before + * marking our slot as valid. + */ + arm_smmu_cmdq_shared_lock(cmdq); + } - spin_lock_irqsave(&smmu->cmdq.lock, flags); - arm_smmu_cmdq_insert_cmd(smmu, cmd); - ret = queue_poll_cons(&smmu->cmdq.q, true, wfe); - spin_unlock_irqrestore(&smmu->cmdq.lock, flags); + /* 3. Mark our slots as valid, ensuring commands are visible first */ + dma_wmb(); + arm_smmu_cmdq_set_valid_map(cmdq, llq.prod, head.prod); + + /* 4. If we are the owner, take control of the SMMU hardware */ + if (owner) { + /* a. Wait for previous owner to finish */ + atomic_cond_read_relaxed(&cmdq->owner_prod, VAL == llq.prod); + + /* b. Stop gathering work by clearing the owned flag */ + prod = atomic_fetch_andnot_relaxed(CMDQ_PROD_OWNED_FLAG, + &cmdq->q.llq.atomic.prod); + prod &= ~CMDQ_PROD_OWNED_FLAG; + + /* + * c. Wait for any gathered work to be written to the queue. + * Note that we read our own entries so that we have the control + * dependency required by (d). + */ + arm_smmu_cmdq_poll_valid_map(cmdq, llq.prod, prod); + + /* + * d. Advance the hardware prod pointer + * Control dependency ordering from the entries becoming valid. + */ + writel_relaxed(prod, cmdq->q.prod_reg); + + /* + * e. Tell the next owner we're done + * Make sure we've updated the hardware first, so that we don't + * race to update prod and potentially move it backwards. + */ + atomic_set_release(&cmdq->owner_prod, prod); + } + + /* 5. If we are inserting a CMD_SYNC, we must wait for it to complete */ + if (sync) { + llq.prod = queue_inc_prod_n(&llq, n); + ret = arm_smmu_cmdq_poll_until_sync(smmu, &llq); + if (ret) { + dev_err_ratelimited(smmu->dev, + "CMD_SYNC timeout at 0x%08x [hwprod 0x%08x, hwcons 0x%08x]\n", + llq.prod, + readl_relaxed(cmdq->q.prod_reg), + readl_relaxed(cmdq->q.cons_reg)); + } + + /* + * Try to unlock the cmq lock. This will fail if we're the last + * reader, in which case we can safely update cmdq->q.llq.cons + */ + if (!arm_smmu_cmdq_shared_tryunlock(cmdq)) { + WRITE_ONCE(cmdq->q.llq.cons, llq.cons); + arm_smmu_cmdq_shared_unlock(cmdq); + } + } + local_irq_restore(flags); return ret; } -static int arm_smmu_cmdq_issue_sync(struct arm_smmu_device *smmu) +static int arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu, + struct arm_smmu_cmdq_ent *ent) { - int ret; - bool msi = (smmu->features & ARM_SMMU_FEAT_MSI) && - (smmu->features & ARM_SMMU_FEAT_COHERENCY); + u64 cmd[CMDQ_ENT_DWORDS]; - ret = msi ? __arm_smmu_cmdq_issue_sync_msi(smmu) - : __arm_smmu_cmdq_issue_sync(smmu); - if (ret) - dev_err_ratelimited(smmu->dev, "CMD_SYNC timeout\n"); - return ret; + if (arm_smmu_cmdq_build_cmd(cmd, ent)) { + dev_warn(smmu->dev, "ignoring unknown CMDQ opcode 0x%x\n", + ent->opcode); + return -EINVAL; + } + + return arm_smmu_cmdq_issue_cmdlist(smmu, cmd, 1, false); +} + +static int arm_smmu_cmdq_issue_sync(struct arm_smmu_device *smmu) +{ + return arm_smmu_cmdq_issue_cmdlist(smmu, NULL, 0, true); } /* Context descriptor manipulation functions */ @@ -1305,6 +1694,7 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev) int i; struct arm_smmu_device *smmu = dev; struct arm_smmu_queue *q = &smmu->evtq.q; + struct arm_smmu_ll_queue *llq = &q->llq; u64 evt[EVTQ_ENT_DWORDS]; do { @@ -1322,12 +1712,13 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev) * Not much we can do on overflow, so scream and pretend we're * trying harder. */ - if (queue_sync_prod(q) == -EOVERFLOW) + if (queue_sync_prod_in(q) == -EOVERFLOW) dev_err(smmu->dev, "EVTQ overflow detected -- events lost\n"); - } while (!queue_empty(q)); + } while (!queue_empty(llq)); /* Sync our overflow flag, as we believe we're up to speed */ - q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons); + llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) | + Q_IDX(llq, llq->cons); return IRQ_HANDLED; } @@ -1373,19 +1764,21 @@ static irqreturn_t arm_smmu_priq_thread(int irq, void *dev) { struct arm_smmu_device *smmu = dev; struct arm_smmu_queue *q = &smmu->priq.q; + struct arm_smmu_ll_queue *llq = &q->llq; u64 evt[PRIQ_ENT_DWORDS]; do { while (!queue_remove_raw(q, evt)) arm_smmu_handle_ppr(smmu, evt); - if (queue_sync_prod(q) == -EOVERFLOW) + if (queue_sync_prod_in(q) == -EOVERFLOW) dev_err(smmu->dev, "PRIQ overflow detected -- requests lost\n"); - } while (!queue_empty(q)); + } while (!queue_empty(llq)); /* Sync our overflow flag, as we believe we're up to speed */ - q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons); - writel(q->cons, q->cons_reg); + llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) | + Q_IDX(llq, llq->cons); + queue_sync_cons_out(q); return IRQ_HANDLED; } @@ -1534,6 +1927,23 @@ static int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain, if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_ATS)) return 0; + /* + * Ensure that we've completed prior invalidation of the main TLBs + * before we read 'nr_ats_masters' in case of a concurrent call to + * arm_smmu_enable_ats(): + * + * // unmap() // arm_smmu_enable_ats() + * TLBI+SYNC atomic_inc(&nr_ats_masters); + * smp_mb(); [...] + * atomic_read(&nr_ats_masters); pci_enable_ats() // writel() + * + * Ensures that we always see the incremented 'nr_ats_masters' count if + * ATS was enabled at the PCI device before completion of the TLBI. + */ + smp_mb(); + if (!atomic_read(&smmu_domain->nr_ats_masters)) + return 0; + arm_smmu_atc_inv_to_cmd(ssid, iova, size, &cmd); spin_lock_irqsave(&smmu_domain->devices_lock, flags); @@ -1545,13 +1955,6 @@ static int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain, } /* IO_PGTABLE API */ -static void arm_smmu_tlb_sync(void *cookie) -{ - struct arm_smmu_domain *smmu_domain = cookie; - - arm_smmu_cmdq_issue_sync(smmu_domain->smmu); -} - static void arm_smmu_tlb_inv_context(void *cookie) { struct arm_smmu_domain *smmu_domain = cookie; @@ -1570,25 +1973,32 @@ static void arm_smmu_tlb_inv_context(void *cookie) /* * NOTE: when io-pgtable is in non-strict mode, we may get here with * PTEs previously cleared by unmaps on the current CPU not yet visible - * to the SMMU. We are relying on the DSB implicit in queue_inc_prod() - * to guarantee those are observed before the TLBI. Do be careful, 007. + * to the SMMU. We are relying on the dma_wmb() implicit during cmd + * insertion to guarantee those are observed before the TLBI. Do be + * careful, 007. */ arm_smmu_cmdq_issue_cmd(smmu, &cmd); arm_smmu_cmdq_issue_sync(smmu); + arm_smmu_atc_inv_domain(smmu_domain, 0, 0, 0); } -static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, - size_t granule, bool leaf, void *cookie) +static void arm_smmu_tlb_inv_range(unsigned long iova, size_t size, + size_t granule, bool leaf, + struct arm_smmu_domain *smmu_domain) { - struct arm_smmu_domain *smmu_domain = cookie; + u64 cmds[CMDQ_BATCH_ENTRIES * CMDQ_ENT_DWORDS]; struct arm_smmu_device *smmu = smmu_domain->smmu; + unsigned long start = iova, end = iova + size; + int i = 0; struct arm_smmu_cmdq_ent cmd = { .tlbi = { .leaf = leaf, - .addr = iova, }, }; + if (!size) + return; + if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) { cmd.opcode = CMDQ_OP_TLBI_NH_VA; cmd.tlbi.asid = smmu_domain->s1_cfg.cd.asid; @@ -1597,16 +2007,54 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, cmd.tlbi.vmid = smmu_domain->s2_cfg.vmid; } - do { - arm_smmu_cmdq_issue_cmd(smmu, &cmd); - cmd.tlbi.addr += granule; - } while (size -= granule); + while (iova < end) { + if (i == CMDQ_BATCH_ENTRIES) { + arm_smmu_cmdq_issue_cmdlist(smmu, cmds, i, false); + i = 0; + } + + cmd.tlbi.addr = iova; + arm_smmu_cmdq_build_cmd(&cmds[i * CMDQ_ENT_DWORDS], &cmd); + iova += granule; + i++; + } + + arm_smmu_cmdq_issue_cmdlist(smmu, cmds, i, true); + + /* + * Unfortunately, this can't be leaf-only since we may have + * zapped an entire table. + */ + arm_smmu_atc_inv_domain(smmu_domain, 0, start, size); } -static const struct iommu_gather_ops arm_smmu_gather_ops = { +static void arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather *gather, + unsigned long iova, size_t granule, + void *cookie) +{ + struct arm_smmu_domain *smmu_domain = cookie; + struct iommu_domain *domain = &smmu_domain->domain; + + iommu_iotlb_gather_add_page(domain, gather, iova, granule); +} + +static void arm_smmu_tlb_inv_walk(unsigned long iova, size_t size, + size_t granule, void *cookie) +{ + arm_smmu_tlb_inv_range(iova, size, granule, false, cookie); +} + +static void arm_smmu_tlb_inv_leaf(unsigned long iova, size_t size, + size_t granule, void *cookie) +{ + arm_smmu_tlb_inv_range(iova, size, granule, true, cookie); +} + +static const struct iommu_flush_ops arm_smmu_flush_ops = { .tlb_flush_all = arm_smmu_tlb_inv_context, - .tlb_add_flush = arm_smmu_tlb_inv_range_nosync, - .tlb_sync = arm_smmu_tlb_sync, + .tlb_flush_walk = arm_smmu_tlb_inv_walk, + .tlb_flush_leaf = arm_smmu_tlb_inv_leaf, + .tlb_add_page = arm_smmu_tlb_inv_page_nosync, }; /* IOMMU API */ @@ -1796,7 +2244,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain) .ias = ias, .oas = oas, .coherent_walk = smmu->features & ARM_SMMU_FEAT_COHERENCY, - .tlb = &arm_smmu_gather_ops, + .tlb = &arm_smmu_flush_ops, .iommu_dev = smmu->dev, }; @@ -1863,44 +2311,65 @@ static void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master) } } -static int arm_smmu_enable_ats(struct arm_smmu_master *master) +#ifdef CONFIG_PCI_ATS +static bool arm_smmu_ats_supported(struct arm_smmu_master *master) { - int ret; - size_t stu; struct pci_dev *pdev; struct arm_smmu_device *smmu = master->smmu; struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(master->dev); if (!(smmu->features & ARM_SMMU_FEAT_ATS) || !dev_is_pci(master->dev) || !(fwspec->flags & IOMMU_FWSPEC_PCI_RC_ATS) || pci_ats_disabled()) - return -ENXIO; + return false; pdev = to_pci_dev(master->dev); - if (pdev->untrusted) - return -EPERM; + return !pdev->untrusted && pdev->ats_cap; +} +#else +static bool arm_smmu_ats_supported(struct arm_smmu_master *master) +{ + return false; +} +#endif + +static void arm_smmu_enable_ats(struct arm_smmu_master *master) +{ + size_t stu; + struct pci_dev *pdev; + struct arm_smmu_device *smmu = master->smmu; + struct arm_smmu_domain *smmu_domain = master->domain; + + /* Don't enable ATS at the endpoint if it's not enabled in the STE */ + if (!master->ats_enabled) + return; /* Smallest Translation Unit: log2 of the smallest supported granule */ stu = __ffs(smmu->pgsize_bitmap); + pdev = to_pci_dev(master->dev); - ret = pci_enable_ats(pdev, stu); - if (ret) - return ret; - - master->ats_enabled = true; - return 0; + atomic_inc(&smmu_domain->nr_ats_masters); + arm_smmu_atc_inv_domain(smmu_domain, 0, 0, 0); + if (pci_enable_ats(pdev, stu)) + dev_err(master->dev, "Failed to enable ATS (STU %zu)\n", stu); } static void arm_smmu_disable_ats(struct arm_smmu_master *master) { struct arm_smmu_cmdq_ent cmd; + struct arm_smmu_domain *smmu_domain = master->domain; - if (!master->ats_enabled || !dev_is_pci(master->dev)) + if (!master->ats_enabled) return; + pci_disable_ats(to_pci_dev(master->dev)); + /* + * Ensure ATS is disabled at the endpoint before we issue the + * ATC invalidation via the SMMU. + */ + wmb(); arm_smmu_atc_inv_to_cmd(0, 0, 0, &cmd); arm_smmu_atc_inv_master(master, &cmd); - pci_disable_ats(to_pci_dev(master->dev)); - master->ats_enabled = false; + atomic_dec(&smmu_domain->nr_ats_masters); } static void arm_smmu_detach_dev(struct arm_smmu_master *master) @@ -1911,14 +2380,15 @@ static void arm_smmu_detach_dev(struct arm_smmu_master *master) if (!smmu_domain) return; + arm_smmu_disable_ats(master); + spin_lock_irqsave(&smmu_domain->devices_lock, flags); list_del(&master->domain_head); spin_unlock_irqrestore(&smmu_domain->devices_lock, flags); master->domain = NULL; + master->ats_enabled = false; arm_smmu_install_ste_for_dev(master); - - arm_smmu_disable_ats(master); } static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) @@ -1958,17 +2428,20 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) master->domain = smmu_domain; - spin_lock_irqsave(&smmu_domain->devices_lock, flags); - list_add(&master->domain_head, &smmu_domain->devices); - spin_unlock_irqrestore(&smmu_domain->devices_lock, flags); - if (smmu_domain->stage != ARM_SMMU_DOMAIN_BYPASS) - arm_smmu_enable_ats(master); + master->ats_enabled = arm_smmu_ats_supported(master); if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) arm_smmu_write_ctx_desc(smmu, &smmu_domain->s1_cfg); arm_smmu_install_ste_for_dev(master); + + spin_lock_irqsave(&smmu_domain->devices_lock, flags); + list_add(&master->domain_head, &smmu_domain->devices); + spin_unlock_irqrestore(&smmu_domain->devices_lock, flags); + + arm_smmu_enable_ats(master); + out_unlock: mutex_unlock(&smmu_domain->init_mutex); return ret; @@ -1985,21 +2458,16 @@ static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova, return ops->map(ops, iova, paddr, size, prot); } -static size_t -arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) +static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, + size_t size, struct iommu_iotlb_gather *gather) { - int ret; struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops; if (!ops) return 0; - ret = ops->unmap(ops, iova, size); - if (ret && arm_smmu_atc_inv_domain(smmu_domain, 0, iova, size)) - return 0; - - return ret; + return ops->unmap(ops, iova, size, gather); } static void arm_smmu_flush_iotlb_all(struct iommu_domain *domain) @@ -2010,12 +2478,13 @@ static void arm_smmu_flush_iotlb_all(struct iommu_domain *domain) arm_smmu_tlb_inv_context(smmu_domain); } -static void arm_smmu_iotlb_sync(struct iommu_domain *domain) +static void arm_smmu_iotlb_sync(struct iommu_domain *domain, + struct iommu_iotlb_gather *gather) { - struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu; + struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); - if (smmu) - arm_smmu_cmdq_issue_sync(smmu); + arm_smmu_tlb_inv_range(gather->start, gather->end - gather->start, + gather->pgsize, true, smmu_domain); } static phys_addr_t @@ -2034,16 +2503,11 @@ arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) static struct platform_driver arm_smmu_driver; -static int arm_smmu_match_node(struct device *dev, const void *data) -{ - return dev->fwnode == data; -} - static struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode) { - struct device *dev = driver_find_device(&arm_smmu_driver.driver, NULL, - fwnode, arm_smmu_match_node); + struct device *dev = driver_find_device_by_fwnode(&arm_smmu_driver.driver, + fwnode); put_device(dev); return dev ? dev_get_drvdata(dev) : NULL; } @@ -2286,13 +2750,13 @@ static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu, size_t qsz; do { - qsz = ((1 << q->max_n_shift) * dwords) << 3; + qsz = ((1 << q->llq.max_n_shift) * dwords) << 3; q->base = dmam_alloc_coherent(smmu->dev, qsz, &q->base_dma, GFP_KERNEL); if (q->base || qsz < PAGE_SIZE) break; - q->max_n_shift--; + q->llq.max_n_shift--; } while (1); if (!q->base) { @@ -2304,7 +2768,7 @@ static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu, if (!WARN_ON(q->base_dma & (qsz - 1))) { dev_info(smmu->dev, "allocated %u entries for %s\n", - 1 << q->max_n_shift, name); + 1 << q->llq.max_n_shift, name); } q->prod_reg = arm_smmu_page1_fixup(prod_off, smmu); @@ -2313,24 +2777,55 @@ static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu, q->q_base = Q_BASE_RWA; q->q_base |= q->base_dma & Q_BASE_ADDR_MASK; - q->q_base |= FIELD_PREP(Q_BASE_LOG2SIZE, q->max_n_shift); + q->q_base |= FIELD_PREP(Q_BASE_LOG2SIZE, q->llq.max_n_shift); - q->prod = q->cons = 0; + q->llq.prod = q->llq.cons = 0; return 0; } +static void arm_smmu_cmdq_free_bitmap(void *data) +{ + unsigned long *bitmap = data; + bitmap_free(bitmap); +} + +static int arm_smmu_cmdq_init(struct arm_smmu_device *smmu) +{ + int ret = 0; + struct arm_smmu_cmdq *cmdq = &smmu->cmdq; + unsigned int nents = 1 << cmdq->q.llq.max_n_shift; + atomic_long_t *bitmap; + + atomic_set(&cmdq->owner_prod, 0); + atomic_set(&cmdq->lock, 0); + + bitmap = (atomic_long_t *)bitmap_zalloc(nents, GFP_KERNEL); + if (!bitmap) { + dev_err(smmu->dev, "failed to allocate cmdq bitmap\n"); + ret = -ENOMEM; + } else { + cmdq->valid_map = bitmap; + devm_add_action(smmu->dev, arm_smmu_cmdq_free_bitmap, bitmap); + } + + return ret; +} + static int arm_smmu_init_queues(struct arm_smmu_device *smmu) { int ret; /* cmdq */ - spin_lock_init(&smmu->cmdq.lock); ret = arm_smmu_init_one_queue(smmu, &smmu->cmdq.q, ARM_SMMU_CMDQ_PROD, ARM_SMMU_CMDQ_CONS, CMDQ_ENT_DWORDS, "cmdq"); if (ret) return ret; + ret = arm_smmu_cmdq_init(smmu); + if (ret) + return ret; + /* evtq */ ret = arm_smmu_init_one_queue(smmu, &smmu->evtq.q, ARM_SMMU_EVTQ_PROD, ARM_SMMU_EVTQ_CONS, EVTQ_ENT_DWORDS, @@ -2708,8 +3203,8 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass) /* Command queue */ writeq_relaxed(smmu->cmdq.q.q_base, smmu->base + ARM_SMMU_CMDQ_BASE); - writel_relaxed(smmu->cmdq.q.prod, smmu->base + ARM_SMMU_CMDQ_PROD); - writel_relaxed(smmu->cmdq.q.cons, smmu->base + ARM_SMMU_CMDQ_CONS); + writel_relaxed(smmu->cmdq.q.llq.prod, smmu->base + ARM_SMMU_CMDQ_PROD); + writel_relaxed(smmu->cmdq.q.llq.cons, smmu->base + ARM_SMMU_CMDQ_CONS); enables = CR0_CMDQEN; ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0, @@ -2736,9 +3231,9 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass) /* Event queue */ writeq_relaxed(smmu->evtq.q.q_base, smmu->base + ARM_SMMU_EVTQ_BASE); - writel_relaxed(smmu->evtq.q.prod, + writel_relaxed(smmu->evtq.q.llq.prod, arm_smmu_page1_fixup(ARM_SMMU_EVTQ_PROD, smmu)); - writel_relaxed(smmu->evtq.q.cons, + writel_relaxed(smmu->evtq.q.llq.cons, arm_smmu_page1_fixup(ARM_SMMU_EVTQ_CONS, smmu)); enables |= CR0_EVTQEN; @@ -2753,9 +3248,9 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass) if (smmu->features & ARM_SMMU_FEAT_PRI) { writeq_relaxed(smmu->priq.q.q_base, smmu->base + ARM_SMMU_PRIQ_BASE); - writel_relaxed(smmu->priq.q.prod, + writel_relaxed(smmu->priq.q.llq.prod, arm_smmu_page1_fixup(ARM_SMMU_PRIQ_PROD, smmu)); - writel_relaxed(smmu->priq.q.cons, + writel_relaxed(smmu->priq.q.llq.cons, arm_smmu_page1_fixup(ARM_SMMU_PRIQ_CONS, smmu)); enables |= CR0_PRIQEN; @@ -2909,18 +3404,24 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu) } /* Queue sizes, capped to ensure natural alignment */ - smmu->cmdq.q.max_n_shift = min_t(u32, CMDQ_MAX_SZ_SHIFT, - FIELD_GET(IDR1_CMDQS, reg)); - if (!smmu->cmdq.q.max_n_shift) { - /* Odd alignment restrictions on the base, so ignore for now */ - dev_err(smmu->dev, "unit-length command queue not supported\n"); + smmu->cmdq.q.llq.max_n_shift = min_t(u32, CMDQ_MAX_SZ_SHIFT, + FIELD_GET(IDR1_CMDQS, reg)); + if (smmu->cmdq.q.llq.max_n_shift <= ilog2(CMDQ_BATCH_ENTRIES)) { + /* + * We don't support splitting up batches, so one batch of + * commands plus an extra sync needs to fit inside the command + * queue. There's also no way we can handle the weird alignment + * restrictions on the base pointer for a unit-length queue. + */ + dev_err(smmu->dev, "command queue size <= %d entries not supported\n", + CMDQ_BATCH_ENTRIES); return -ENXIO; } - smmu->evtq.q.max_n_shift = min_t(u32, EVTQ_MAX_SZ_SHIFT, - FIELD_GET(IDR1_EVTQS, reg)); - smmu->priq.q.max_n_shift = min_t(u32, PRIQ_MAX_SZ_SHIFT, - FIELD_GET(IDR1_PRIQS, reg)); + smmu->evtq.q.llq.max_n_shift = min_t(u32, EVTQ_MAX_SZ_SHIFT, + FIELD_GET(IDR1_EVTQS, reg)); + smmu->priq.q.llq.max_n_shift = min_t(u32, PRIQ_MAX_SZ_SHIFT, + FIELD_GET(IDR1_PRIQS, reg)); /* SID/SSID sizes */ smmu->ssid_bits = FIELD_GET(IDR1_SSIDSIZE, reg); diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 64977c131ee62aeeaea4865989ba8b378c924aeb..c3ef0cc8f7648b73339bed9bc4452ff131a7d01a 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -19,16 +19,13 @@ #include #include -#include +#include #include #include #include #include #include #include -#include -#include -#include #include #include #include @@ -40,12 +37,11 @@ #include #include #include -#include #include #include -#include "arm-smmu-regs.h" +#include "arm-smmu.h" /* * Apparently, some Qualcomm arm64 platforms which appear to expose their SMMU @@ -56,46 +52,9 @@ */ #define QCOM_DUMMY_VAL -1 -#define ARM_MMU500_ACTLR_CPRE (1 << 1) - -#define ARM_MMU500_ACR_CACHE_LOCK (1 << 26) -#define ARM_MMU500_ACR_S2CRB_TLBEN (1 << 10) -#define ARM_MMU500_ACR_SMTNMB_TLBEN (1 << 8) - #define TLB_LOOP_TIMEOUT 1000000 /* 1s! */ #define TLB_SPIN_COUNT 10 -/* Maximum number of context banks per SMMU */ -#define ARM_SMMU_MAX_CBS 128 - -/* SMMU global address space */ -#define ARM_SMMU_GR0(smmu) ((smmu)->base) -#define ARM_SMMU_GR1(smmu) ((smmu)->base + (1 << (smmu)->pgshift)) - -/* - * SMMU global address space with conditional offset to access secure - * aliases of non-secure registers (e.g. nsCR0: 0x400, nsGFSR: 0x448, - * nsGFSYNR0: 0x450) - */ -#define ARM_SMMU_GR0_NS(smmu) \ - ((smmu)->base + \ - ((smmu->options & ARM_SMMU_OPT_SECURE_CFG_ACCESS) \ - ? 0x400 : 0)) - -/* - * Some 64-bit registers only make sense to write atomically, but in such - * cases all the data relevant to AArch32 formats lies within the lower word, - * therefore this actually makes more sense than it might first appear. - */ -#ifdef CONFIG_64BIT -#define smmu_write_atomic_lq writeq_relaxed -#else -#define smmu_write_atomic_lq writel_relaxed -#endif - -/* Translation context bank */ -#define ARM_SMMU_CB(smmu, n) ((smmu)->cb_base + ((n) << (smmu)->pgshift)) - #define MSI_IOVA_BASE 0x8000000 #define MSI_IOVA_LENGTH 0x100000 @@ -113,19 +72,6 @@ module_param(disable_bypass, bool, S_IRUGO); MODULE_PARM_DESC(disable_bypass, "Disable bypass streams such that incoming transactions from devices that are not attached to an iommu domain will report an abort back to the device and will not be allowed to pass through the SMMU."); -enum arm_smmu_arch_version { - ARM_SMMU_V1, - ARM_SMMU_V1_64K, - ARM_SMMU_V2, -}; - -enum arm_smmu_implementation { - GENERIC_SMMU, - ARM_MMU500, - CAVIUM_SMMUV2, - QCOM_SMMUV2, -}; - struct arm_smmu_s2cr { struct iommu_group *group; int count; @@ -163,117 +109,8 @@ struct arm_smmu_master_cfg { #define for_each_cfg_sme(fw, i, idx) \ for (i = 0; idx = fwspec_smendx(fw, i), i < fw->num_ids; ++i) -struct arm_smmu_device { - struct device *dev; - - void __iomem *base; - void __iomem *cb_base; - unsigned long pgshift; - -#define ARM_SMMU_FEAT_COHERENT_WALK (1 << 0) -#define ARM_SMMU_FEAT_STREAM_MATCH (1 << 1) -#define ARM_SMMU_FEAT_TRANS_S1 (1 << 2) -#define ARM_SMMU_FEAT_TRANS_S2 (1 << 3) -#define ARM_SMMU_FEAT_TRANS_NESTED (1 << 4) -#define ARM_SMMU_FEAT_TRANS_OPS (1 << 5) -#define ARM_SMMU_FEAT_VMID16 (1 << 6) -#define ARM_SMMU_FEAT_FMT_AARCH64_4K (1 << 7) -#define ARM_SMMU_FEAT_FMT_AARCH64_16K (1 << 8) -#define ARM_SMMU_FEAT_FMT_AARCH64_64K (1 << 9) -#define ARM_SMMU_FEAT_FMT_AARCH32_L (1 << 10) -#define ARM_SMMU_FEAT_FMT_AARCH32_S (1 << 11) -#define ARM_SMMU_FEAT_EXIDS (1 << 12) - u32 features; - -#define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 << 0) - u32 options; - enum arm_smmu_arch_version version; - enum arm_smmu_implementation model; - - u32 num_context_banks; - u32 num_s2_context_banks; - DECLARE_BITMAP(context_map, ARM_SMMU_MAX_CBS); - struct arm_smmu_cb *cbs; - atomic_t irptndx; - - u32 num_mapping_groups; - u16 streamid_mask; - u16 smr_mask_mask; - struct arm_smmu_smr *smrs; - struct arm_smmu_s2cr *s2crs; - struct mutex stream_map_mutex; - - unsigned long va_size; - unsigned long ipa_size; - unsigned long pa_size; - unsigned long pgsize_bitmap; - - u32 num_global_irqs; - u32 num_context_irqs; - unsigned int *irqs; - struct clk_bulk_data *clks; - int num_clks; - - u32 cavium_id_base; /* Specific to Cavium */ - - spinlock_t global_sync_lock; - - /* IOMMU core code handle */ - struct iommu_device iommu; -}; - -enum arm_smmu_context_fmt { - ARM_SMMU_CTX_FMT_NONE, - ARM_SMMU_CTX_FMT_AARCH64, - ARM_SMMU_CTX_FMT_AARCH32_L, - ARM_SMMU_CTX_FMT_AARCH32_S, -}; - -struct arm_smmu_cfg { - u8 cbndx; - u8 irptndx; - union { - u16 asid; - u16 vmid; - }; - u32 cbar; - enum arm_smmu_context_fmt fmt; -}; -#define INVALID_IRPTNDX 0xff - -enum arm_smmu_domain_stage { - ARM_SMMU_DOMAIN_S1 = 0, - ARM_SMMU_DOMAIN_S2, - ARM_SMMU_DOMAIN_NESTED, - ARM_SMMU_DOMAIN_BYPASS, -}; - -struct arm_smmu_domain { - struct arm_smmu_device *smmu; - struct io_pgtable_ops *pgtbl_ops; - const struct iommu_gather_ops *tlb_ops; - struct arm_smmu_cfg cfg; - enum arm_smmu_domain_stage stage; - bool non_strict; - struct mutex init_mutex; /* Protects smmu pointer */ - spinlock_t cb_lock; /* Serialises ATS1* ops and TLB syncs */ - struct iommu_domain domain; -}; - -struct arm_smmu_option_prop { - u32 opt; - const char *prop; -}; - -static atomic_t cavium_smmu_context_count = ATOMIC_INIT(0); - static bool using_legacy_binding, using_generic_binding; -static struct arm_smmu_option_prop arm_smmu_options[] = { - { ARM_SMMU_OPT_SECURE_CFG_ACCESS, "calxeda,smmu-secure-config-access" }, - { 0, NULL}, -}; - static inline int arm_smmu_rpm_get(struct arm_smmu_device *smmu) { if (pm_runtime_enabled(smmu->dev)) @@ -293,20 +130,6 @@ static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom) return container_of(dom, struct arm_smmu_domain, domain); } -static void parse_driver_options(struct arm_smmu_device *smmu) -{ - int i = 0; - - do { - if (of_property_read_bool(smmu->dev->of_node, - arm_smmu_options[i].prop)) { - smmu->options |= arm_smmu_options[i].opt; - dev_notice(smmu->dev, "option %s\n", - arm_smmu_options[i].prop); - } - } while (arm_smmu_options[++i].opt); -} - static struct device_node *dev_get_dev_node(struct device *dev) { if (dev_is_pci(dev)) { @@ -415,15 +238,17 @@ static void __arm_smmu_free_bitmap(unsigned long *map, int idx) } /* Wait for any pending TLB invalidations to complete */ -static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, - void __iomem *sync, void __iomem *status) +static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, int page, + int sync, int status) { unsigned int spin_cnt, delay; + u32 reg; - writel_relaxed(QCOM_DUMMY_VAL, sync); + arm_smmu_writel(smmu, page, sync, QCOM_DUMMY_VAL); for (delay = 1; delay < TLB_LOOP_TIMEOUT; delay *= 2) { for (spin_cnt = TLB_SPIN_COUNT; spin_cnt > 0; spin_cnt--) { - if (!(readl_relaxed(status) & sTLBGSTATUS_GSACTIVE)) + reg = arm_smmu_readl(smmu, page, status); + if (!(reg & sTLBGSTATUS_GSACTIVE)) return; cpu_relax(); } @@ -435,12 +260,11 @@ static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, static void arm_smmu_tlb_sync_global(struct arm_smmu_device *smmu) { - void __iomem *base = ARM_SMMU_GR0(smmu); unsigned long flags; spin_lock_irqsave(&smmu->global_sync_lock, flags); - __arm_smmu_tlb_sync(smmu, base + ARM_SMMU_GR0_sTLBGSYNC, - base + ARM_SMMU_GR0_sTLBGSTATUS); + __arm_smmu_tlb_sync(smmu, ARM_SMMU_GR0, ARM_SMMU_GR0_sTLBGSYNC, + ARM_SMMU_GR0_sTLBGSTATUS); spin_unlock_irqrestore(&smmu->global_sync_lock, flags); } @@ -448,12 +272,11 @@ static void arm_smmu_tlb_sync_context(void *cookie) { struct arm_smmu_domain *smmu_domain = cookie; struct arm_smmu_device *smmu = smmu_domain->smmu; - void __iomem *base = ARM_SMMU_CB(smmu, smmu_domain->cfg.cbndx); unsigned long flags; spin_lock_irqsave(&smmu_domain->cb_lock, flags); - __arm_smmu_tlb_sync(smmu, base + ARM_SMMU_CB_TLBSYNC, - base + ARM_SMMU_CB_TLBSTATUS); + __arm_smmu_tlb_sync(smmu, ARM_SMMU_CB(smmu, smmu_domain->cfg.cbndx), + ARM_SMMU_CB_TLBSYNC, ARM_SMMU_CB_TLBSTATUS); spin_unlock_irqrestore(&smmu_domain->cb_lock, flags); } @@ -467,14 +290,13 @@ static void arm_smmu_tlb_sync_vmid(void *cookie) static void arm_smmu_tlb_inv_context_s1(void *cookie) { struct arm_smmu_domain *smmu_domain = cookie; - struct arm_smmu_cfg *cfg = &smmu_domain->cfg; - void __iomem *base = ARM_SMMU_CB(smmu_domain->smmu, cfg->cbndx); - /* - * NOTE: this is not a relaxed write; it needs to guarantee that PTEs - * cleared by the current CPU are visible to the SMMU before the TLBI. + * The TLBI write may be relaxed, so ensure that PTEs cleared by the + * current CPU are visible beforehand. */ - writel(cfg->asid, base + ARM_SMMU_CB_S1_TLBIASID); + wmb(); + arm_smmu_cb_write(smmu_domain->smmu, smmu_domain->cfg.cbndx, + ARM_SMMU_CB_S1_TLBIASID, smmu_domain->cfg.asid); arm_smmu_tlb_sync_context(cookie); } @@ -482,87 +304,143 @@ static void arm_smmu_tlb_inv_context_s2(void *cookie) { struct arm_smmu_domain *smmu_domain = cookie; struct arm_smmu_device *smmu = smmu_domain->smmu; - void __iomem *base = ARM_SMMU_GR0(smmu); - /* NOTE: see above */ - writel(smmu_domain->cfg.vmid, base + ARM_SMMU_GR0_TLBIVMID); + /* See above */ + wmb(); + arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_TLBIVMID, smmu_domain->cfg.vmid); arm_smmu_tlb_sync_global(smmu); } -static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, - size_t granule, bool leaf, void *cookie) +static void arm_smmu_tlb_inv_range_s1(unsigned long iova, size_t size, + size_t granule, bool leaf, void *cookie) { struct arm_smmu_domain *smmu_domain = cookie; + struct arm_smmu_device *smmu = smmu_domain->smmu; struct arm_smmu_cfg *cfg = &smmu_domain->cfg; - bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS; - void __iomem *reg = ARM_SMMU_CB(smmu_domain->smmu, cfg->cbndx); + int reg, idx = cfg->cbndx; - if (smmu_domain->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) + if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) wmb(); - if (stage1) { - reg += leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA; - - if (cfg->fmt != ARM_SMMU_CTX_FMT_AARCH64) { - iova &= ~12UL; - iova |= cfg->asid; - do { - writel_relaxed(iova, reg); - iova += granule; - } while (size -= granule); - } else { - iova >>= 12; - iova |= (u64)cfg->asid << 48; - do { - writeq_relaxed(iova, reg); - iova += granule >> 12; - } while (size -= granule); - } + reg = leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA; + + if (cfg->fmt != ARM_SMMU_CTX_FMT_AARCH64) { + iova = (iova >> 12) << 12; + iova |= cfg->asid; + do { + arm_smmu_cb_write(smmu, idx, reg, iova); + iova += granule; + } while (size -= granule); } else { - reg += leaf ? ARM_SMMU_CB_S2_TLBIIPAS2L : - ARM_SMMU_CB_S2_TLBIIPAS2; iova >>= 12; + iova |= (u64)cfg->asid << 48; do { - smmu_write_atomic_lq(iova, reg); + arm_smmu_cb_writeq(smmu, idx, reg, iova); iova += granule >> 12; } while (size -= granule); } } +static void arm_smmu_tlb_inv_range_s2(unsigned long iova, size_t size, + size_t granule, bool leaf, void *cookie) +{ + struct arm_smmu_domain *smmu_domain = cookie; + struct arm_smmu_device *smmu = smmu_domain->smmu; + int reg, idx = smmu_domain->cfg.cbndx; + + if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) + wmb(); + + reg = leaf ? ARM_SMMU_CB_S2_TLBIIPAS2L : ARM_SMMU_CB_S2_TLBIIPAS2; + iova >>= 12; + do { + if (smmu_domain->cfg.fmt == ARM_SMMU_CTX_FMT_AARCH64) + arm_smmu_cb_writeq(smmu, idx, reg, iova); + else + arm_smmu_cb_write(smmu, idx, reg, iova); + iova += granule >> 12; + } while (size -= granule); +} + /* * On MMU-401 at least, the cost of firing off multiple TLBIVMIDs appears * almost negligible, but the benefit of getting the first one in as far ahead * of the sync as possible is significant, hence we don't just make this a - * no-op and set .tlb_sync to arm_smmu_inv_context_s2() as you might think. + * no-op and set .tlb_sync to arm_smmu_tlb_inv_context_s2() as you might think. */ static void arm_smmu_tlb_inv_vmid_nosync(unsigned long iova, size_t size, size_t granule, bool leaf, void *cookie) { struct arm_smmu_domain *smmu_domain = cookie; - void __iomem *base = ARM_SMMU_GR0(smmu_domain->smmu); + struct arm_smmu_device *smmu = smmu_domain->smmu; - if (smmu_domain->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) + if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) wmb(); - writel_relaxed(smmu_domain->cfg.vmid, base + ARM_SMMU_GR0_TLBIVMID); + arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_TLBIVMID, smmu_domain->cfg.vmid); +} + +static void arm_smmu_tlb_inv_walk(unsigned long iova, size_t size, + size_t granule, void *cookie) +{ + struct arm_smmu_domain *smmu_domain = cookie; + const struct arm_smmu_flush_ops *ops = smmu_domain->flush_ops; + + ops->tlb_inv_range(iova, size, granule, false, cookie); + ops->tlb_sync(cookie); +} + +static void arm_smmu_tlb_inv_leaf(unsigned long iova, size_t size, + size_t granule, void *cookie) +{ + struct arm_smmu_domain *smmu_domain = cookie; + const struct arm_smmu_flush_ops *ops = smmu_domain->flush_ops; + + ops->tlb_inv_range(iova, size, granule, true, cookie); + ops->tlb_sync(cookie); } -static const struct iommu_gather_ops arm_smmu_s1_tlb_ops = { - .tlb_flush_all = arm_smmu_tlb_inv_context_s1, - .tlb_add_flush = arm_smmu_tlb_inv_range_nosync, - .tlb_sync = arm_smmu_tlb_sync_context, +static void arm_smmu_tlb_add_page(struct iommu_iotlb_gather *gather, + unsigned long iova, size_t granule, + void *cookie) +{ + struct arm_smmu_domain *smmu_domain = cookie; + const struct arm_smmu_flush_ops *ops = smmu_domain->flush_ops; + + ops->tlb_inv_range(iova, granule, granule, true, cookie); +} + +static const struct arm_smmu_flush_ops arm_smmu_s1_tlb_ops = { + .tlb = { + .tlb_flush_all = arm_smmu_tlb_inv_context_s1, + .tlb_flush_walk = arm_smmu_tlb_inv_walk, + .tlb_flush_leaf = arm_smmu_tlb_inv_leaf, + .tlb_add_page = arm_smmu_tlb_add_page, + }, + .tlb_inv_range = arm_smmu_tlb_inv_range_s1, + .tlb_sync = arm_smmu_tlb_sync_context, }; -static const struct iommu_gather_ops arm_smmu_s2_tlb_ops_v2 = { - .tlb_flush_all = arm_smmu_tlb_inv_context_s2, - .tlb_add_flush = arm_smmu_tlb_inv_range_nosync, - .tlb_sync = arm_smmu_tlb_sync_context, +static const struct arm_smmu_flush_ops arm_smmu_s2_tlb_ops_v2 = { + .tlb = { + .tlb_flush_all = arm_smmu_tlb_inv_context_s2, + .tlb_flush_walk = arm_smmu_tlb_inv_walk, + .tlb_flush_leaf = arm_smmu_tlb_inv_leaf, + .tlb_add_page = arm_smmu_tlb_add_page, + }, + .tlb_inv_range = arm_smmu_tlb_inv_range_s2, + .tlb_sync = arm_smmu_tlb_sync_context, }; -static const struct iommu_gather_ops arm_smmu_s2_tlb_ops_v1 = { - .tlb_flush_all = arm_smmu_tlb_inv_context_s2, - .tlb_add_flush = arm_smmu_tlb_inv_vmid_nosync, - .tlb_sync = arm_smmu_tlb_sync_vmid, +static const struct arm_smmu_flush_ops arm_smmu_s2_tlb_ops_v1 = { + .tlb = { + .tlb_flush_all = arm_smmu_tlb_inv_context_s2, + .tlb_flush_walk = arm_smmu_tlb_inv_walk, + .tlb_flush_leaf = arm_smmu_tlb_inv_leaf, + .tlb_add_page = arm_smmu_tlb_add_page, + }, + .tlb_inv_range = arm_smmu_tlb_inv_vmid_nosync, + .tlb_sync = arm_smmu_tlb_sync_vmid, }; static irqreturn_t arm_smmu_context_fault(int irq, void *dev) @@ -571,26 +449,22 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev) unsigned long iova; struct iommu_domain *domain = dev; struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); - struct arm_smmu_cfg *cfg = &smmu_domain->cfg; struct arm_smmu_device *smmu = smmu_domain->smmu; - void __iomem *gr1_base = ARM_SMMU_GR1(smmu); - void __iomem *cb_base; - - cb_base = ARM_SMMU_CB(smmu, cfg->cbndx); - fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR); + int idx = smmu_domain->cfg.cbndx; + fsr = arm_smmu_cb_read(smmu, idx, ARM_SMMU_CB_FSR); if (!(fsr & FSR_FAULT)) return IRQ_NONE; - fsynr = readl_relaxed(cb_base + ARM_SMMU_CB_FSYNR0); - iova = readq_relaxed(cb_base + ARM_SMMU_CB_FAR); - cbfrsynra = readl_relaxed(gr1_base + ARM_SMMU_GR1_CBFRSYNRA(cfg->cbndx)); + fsynr = arm_smmu_cb_read(smmu, idx, ARM_SMMU_CB_FSYNR0); + iova = arm_smmu_cb_readq(smmu, idx, ARM_SMMU_CB_FAR); + cbfrsynra = arm_smmu_gr1_read(smmu, ARM_SMMU_GR1_CBFRSYNRA(idx)); dev_err_ratelimited(smmu->dev, "Unhandled context fault: fsr=0x%x, iova=0x%08lx, fsynr=0x%x, cbfrsynra=0x%x, cb=%d\n", - fsr, iova, fsynr, cbfrsynra, cfg->cbndx); + fsr, iova, fsynr, cbfrsynra, idx); - writel(fsr, cb_base + ARM_SMMU_CB_FSR); + arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_FSR, fsr); return IRQ_HANDLED; } @@ -598,12 +472,11 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev) { u32 gfsr, gfsynr0, gfsynr1, gfsynr2; struct arm_smmu_device *smmu = dev; - void __iomem *gr0_base = ARM_SMMU_GR0_NS(smmu); - gfsr = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSR); - gfsynr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR0); - gfsynr1 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR1); - gfsynr2 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR2); + gfsr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSR); + gfsynr0 = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSYNR0); + gfsynr1 = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSYNR1); + gfsynr2 = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSYNR2); if (!gfsr) return IRQ_NONE; @@ -614,7 +487,7 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev) "\tGFSR 0x%08x, GFSYNR0 0x%08x, GFSYNR1 0x%08x, GFSYNR2 0x%08x\n", gfsr, gfsynr0, gfsynr1, gfsynr2); - writel(gfsr, gr0_base + ARM_SMMU_GR0_sGFSR); + arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sGFSR, gfsr); return IRQ_HANDLED; } @@ -627,16 +500,16 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, cb->cfg = cfg; - /* TTBCR */ + /* TCR */ if (stage1) { if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) { cb->tcr[0] = pgtbl_cfg->arm_v7s_cfg.tcr; } else { cb->tcr[0] = pgtbl_cfg->arm_lpae_s1_cfg.tcr; cb->tcr[1] = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32; - cb->tcr[1] |= TTBCR2_SEP_UPSTREAM; + cb->tcr[1] |= FIELD_PREP(TCR2_SEP, TCR2_SEP_UPSTREAM); if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64) - cb->tcr[1] |= TTBCR2_AS; + cb->tcr[1] |= TCR2_AS; } } else { cb->tcr[0] = pgtbl_cfg->arm_lpae_s2_cfg.vtcr; @@ -649,9 +522,9 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, cb->ttbr[1] = pgtbl_cfg->arm_v7s_cfg.ttbr[1]; } else { cb->ttbr[0] = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0]; - cb->ttbr[0] |= (u64)cfg->asid << TTBRn_ASID_SHIFT; + cb->ttbr[0] |= FIELD_PREP(TTBRn_ASID, cfg->asid); cb->ttbr[1] = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1]; - cb->ttbr[1] |= (u64)cfg->asid << TTBRn_ASID_SHIFT; + cb->ttbr[1] |= FIELD_PREP(TTBRn_ASID, cfg->asid); } } else { cb->ttbr[0] = pgtbl_cfg->arm_lpae_s2_cfg.vttbr; @@ -675,74 +548,71 @@ static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx) bool stage1; struct arm_smmu_cb *cb = &smmu->cbs[idx]; struct arm_smmu_cfg *cfg = cb->cfg; - void __iomem *cb_base, *gr1_base; - - cb_base = ARM_SMMU_CB(smmu, idx); /* Unassigned context banks only need disabling */ if (!cfg) { - writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR); + arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, 0); return; } - gr1_base = ARM_SMMU_GR1(smmu); stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS; /* CBA2R */ if (smmu->version > ARM_SMMU_V1) { if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64) - reg = CBA2R_RW64_64BIT; + reg = CBA2R_VA64; else - reg = CBA2R_RW64_32BIT; + reg = 0; /* 16-bit VMIDs live in CBA2R */ if (smmu->features & ARM_SMMU_FEAT_VMID16) - reg |= cfg->vmid << CBA2R_VMID_SHIFT; + reg |= FIELD_PREP(CBA2R_VMID16, cfg->vmid); - writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBA2R(idx)); + arm_smmu_gr1_write(smmu, ARM_SMMU_GR1_CBA2R(idx), reg); } /* CBAR */ - reg = cfg->cbar; + reg = FIELD_PREP(CBAR_TYPE, cfg->cbar); if (smmu->version < ARM_SMMU_V2) - reg |= cfg->irptndx << CBAR_IRPTNDX_SHIFT; + reg |= FIELD_PREP(CBAR_IRPTNDX, cfg->irptndx); /* * Use the weakest shareability/memory types, so they are * overridden by the ttbcr/pte. */ if (stage1) { - reg |= (CBAR_S1_BPSHCFG_NSH << CBAR_S1_BPSHCFG_SHIFT) | - (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT); + reg |= FIELD_PREP(CBAR_S1_BPSHCFG, CBAR_S1_BPSHCFG_NSH) | + FIELD_PREP(CBAR_S1_MEMATTR, CBAR_S1_MEMATTR_WB); } else if (!(smmu->features & ARM_SMMU_FEAT_VMID16)) { /* 8-bit VMIDs live in CBAR */ - reg |= cfg->vmid << CBAR_VMID_SHIFT; + reg |= FIELD_PREP(CBAR_VMID, cfg->vmid); } - writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(idx)); + arm_smmu_gr1_write(smmu, ARM_SMMU_GR1_CBAR(idx), reg); /* - * TTBCR + * TCR * We must write this before the TTBRs, since it determines the * access behaviour of some fields (in particular, ASID[15:8]). */ if (stage1 && smmu->version > ARM_SMMU_V1) - writel_relaxed(cb->tcr[1], cb_base + ARM_SMMU_CB_TTBCR2); - writel_relaxed(cb->tcr[0], cb_base + ARM_SMMU_CB_TTBCR); + arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_TCR2, cb->tcr[1]); + arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_TCR, cb->tcr[0]); /* TTBRs */ if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) { - writel_relaxed(cfg->asid, cb_base + ARM_SMMU_CB_CONTEXTIDR); - writel_relaxed(cb->ttbr[0], cb_base + ARM_SMMU_CB_TTBR0); - writel_relaxed(cb->ttbr[1], cb_base + ARM_SMMU_CB_TTBR1); + arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_CONTEXTIDR, cfg->asid); + arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_TTBR0, cb->ttbr[0]); + arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_TTBR1, cb->ttbr[1]); } else { - writeq_relaxed(cb->ttbr[0], cb_base + ARM_SMMU_CB_TTBR0); + arm_smmu_cb_writeq(smmu, idx, ARM_SMMU_CB_TTBR0, cb->ttbr[0]); if (stage1) - writeq_relaxed(cb->ttbr[1], cb_base + ARM_SMMU_CB_TTBR1); + arm_smmu_cb_writeq(smmu, idx, ARM_SMMU_CB_TTBR1, + cb->ttbr[1]); } /* MAIRs (stage-1 only) */ if (stage1) { - writel_relaxed(cb->mair[0], cb_base + ARM_SMMU_CB_S1_MAIR0); - writel_relaxed(cb->mair[1], cb_base + ARM_SMMU_CB_S1_MAIR1); + arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_S1_MAIR0, cb->mair[0]); + arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_S1_MAIR1, cb->mair[1]); } /* SCTLR */ @@ -752,7 +622,7 @@ static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx) if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) reg |= SCTLR_E; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_SCTLR); + arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, reg); } static int arm_smmu_init_domain_context(struct iommu_domain *domain, @@ -842,7 +712,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, ias = min(ias, 32UL); oas = min(oas, 32UL); } - smmu_domain->tlb_ops = &arm_smmu_s1_tlb_ops; + smmu_domain->flush_ops = &arm_smmu_s1_tlb_ops; break; case ARM_SMMU_DOMAIN_NESTED: /* @@ -862,9 +732,9 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, oas = min(oas, 40UL); } if (smmu->version == ARM_SMMU_V2) - smmu_domain->tlb_ops = &arm_smmu_s2_tlb_ops_v2; + smmu_domain->flush_ops = &arm_smmu_s2_tlb_ops_v2; else - smmu_domain->tlb_ops = &arm_smmu_s2_tlb_ops_v1; + smmu_domain->flush_ops = &arm_smmu_s2_tlb_ops_v1; break; default: ret = -EINVAL; @@ -884,23 +754,29 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, } if (smmu_domain->stage == ARM_SMMU_DOMAIN_S2) - cfg->vmid = cfg->cbndx + 1 + smmu->cavium_id_base; + cfg->vmid = cfg->cbndx + 1; else - cfg->asid = cfg->cbndx + smmu->cavium_id_base; + cfg->asid = cfg->cbndx; + + smmu_domain->smmu = smmu; + if (smmu->impl && smmu->impl->init_context) { + ret = smmu->impl->init_context(smmu_domain); + if (ret) + goto out_unlock; + } pgtbl_cfg = (struct io_pgtable_cfg) { .pgsize_bitmap = smmu->pgsize_bitmap, .ias = ias, .oas = oas, .coherent_walk = smmu->features & ARM_SMMU_FEAT_COHERENT_WALK, - .tlb = smmu_domain->tlb_ops, + .tlb = &smmu_domain->flush_ops->tlb, .iommu_dev = smmu->dev, }; if (smmu_domain->non_strict) pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_NON_STRICT; - smmu_domain->smmu = smmu; pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain); if (!pgtbl_ops) { ret = -ENOMEM; @@ -1019,24 +895,24 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) static void arm_smmu_write_smr(struct arm_smmu_device *smmu, int idx) { struct arm_smmu_smr *smr = smmu->smrs + idx; - u32 reg = smr->id << SMR_ID_SHIFT | smr->mask << SMR_MASK_SHIFT; + u32 reg = FIELD_PREP(SMR_ID, smr->id) | FIELD_PREP(SMR_MASK, smr->mask); if (!(smmu->features & ARM_SMMU_FEAT_EXIDS) && smr->valid) reg |= SMR_VALID; - writel_relaxed(reg, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_SMR(idx)); + arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_SMR(idx), reg); } static void arm_smmu_write_s2cr(struct arm_smmu_device *smmu, int idx) { struct arm_smmu_s2cr *s2cr = smmu->s2crs + idx; - u32 reg = (s2cr->type & S2CR_TYPE_MASK) << S2CR_TYPE_SHIFT | - (s2cr->cbndx & S2CR_CBNDX_MASK) << S2CR_CBNDX_SHIFT | - (s2cr->privcfg & S2CR_PRIVCFG_MASK) << S2CR_PRIVCFG_SHIFT; + u32 reg = FIELD_PREP(S2CR_TYPE, s2cr->type) | + FIELD_PREP(S2CR_CBNDX, s2cr->cbndx) | + FIELD_PREP(S2CR_PRIVCFG, s2cr->privcfg); if (smmu->features & ARM_SMMU_FEAT_EXIDS && smmu->smrs && smmu->smrs[idx].valid) reg |= S2CR_EXIDVALID; - writel_relaxed(reg, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_S2CR(idx)); + arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_S2CR(idx), reg); } static void arm_smmu_write_sme(struct arm_smmu_device *smmu, int idx) @@ -1052,7 +928,6 @@ static void arm_smmu_write_sme(struct arm_smmu_device *smmu, int idx) */ static void arm_smmu_test_smr_masks(struct arm_smmu_device *smmu) { - void __iomem *gr0_base = ARM_SMMU_GR0(smmu); u32 smr; if (!smmu->smrs) @@ -1063,15 +938,15 @@ static void arm_smmu_test_smr_masks(struct arm_smmu_device *smmu) * bits are set, so check each one separately. We can reject * masters later if they try to claim IDs outside these masks. */ - smr = smmu->streamid_mask << SMR_ID_SHIFT; - writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0)); - smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0)); - smmu->streamid_mask = smr >> SMR_ID_SHIFT; + smr = FIELD_PREP(SMR_ID, smmu->streamid_mask); + arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_SMR(0), smr); + smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(0)); + smmu->streamid_mask = FIELD_GET(SMR_ID, smr); - smr = smmu->streamid_mask << SMR_MASK_SHIFT; - writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0)); - smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0)); - smmu->smr_mask_mask = smr >> SMR_MASK_SHIFT; + smr = FIELD_PREP(SMR_MASK, smmu->streamid_mask); + arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_SMR(0), smr); + smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(0)); + smmu->smr_mask_mask = FIELD_GET(SMR_MASK, smr); } static int arm_smmu_find_sme(struct arm_smmu_device *smmu, u16 id, u16 mask) @@ -1140,8 +1015,8 @@ static int arm_smmu_master_alloc_smes(struct device *dev) mutex_lock(&smmu->stream_map_mutex); /* Figure out a viable stream map entry allocation */ for_each_cfg_sme(fwspec, i, idx) { - u16 sid = fwspec->ids[i]; - u16 mask = fwspec->ids[i] >> SMR_MASK_SHIFT; + u16 sid = FIELD_GET(SMR_ID, fwspec->ids[i]); + u16 mask = FIELD_GET(SMR_MASK, fwspec->ids[i]); if (idx != INVALID_SMENDX) { ret = -EEXIST; @@ -1301,7 +1176,7 @@ static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova, } static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, - size_t size) + size_t size, struct iommu_iotlb_gather *gather) { struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops; struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu; @@ -1311,7 +1186,7 @@ static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, return 0; arm_smmu_rpm_get(smmu); - ret = ops->unmap(ops, iova, size); + ret = ops->unmap(ops, iova, size, gather); arm_smmu_rpm_put(smmu); return ret; @@ -1322,21 +1197,22 @@ static void arm_smmu_flush_iotlb_all(struct iommu_domain *domain) struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); struct arm_smmu_device *smmu = smmu_domain->smmu; - if (smmu_domain->tlb_ops) { + if (smmu_domain->flush_ops) { arm_smmu_rpm_get(smmu); - smmu_domain->tlb_ops->tlb_flush_all(smmu_domain); + smmu_domain->flush_ops->tlb.tlb_flush_all(smmu_domain); arm_smmu_rpm_put(smmu); } } -static void arm_smmu_iotlb_sync(struct iommu_domain *domain) +static void arm_smmu_iotlb_sync(struct iommu_domain *domain, + struct iommu_iotlb_gather *gather) { struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); struct arm_smmu_device *smmu = smmu_domain->smmu; - if (smmu_domain->tlb_ops) { + if (smmu_domain->flush_ops) { arm_smmu_rpm_get(smmu); - smmu_domain->tlb_ops->tlb_sync(smmu_domain); + smmu_domain->flush_ops->tlb_sync(smmu_domain); arm_smmu_rpm_put(smmu); } } @@ -1349,28 +1225,25 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain, struct arm_smmu_cfg *cfg = &smmu_domain->cfg; struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops; struct device *dev = smmu->dev; - void __iomem *cb_base; + void __iomem *reg; u32 tmp; u64 phys; unsigned long va, flags; - int ret; + int ret, idx = cfg->cbndx; ret = arm_smmu_rpm_get(smmu); if (ret < 0) return 0; - cb_base = ARM_SMMU_CB(smmu, cfg->cbndx); - spin_lock_irqsave(&smmu_domain->cb_lock, flags); - /* ATS1 registers can only be written atomically */ va = iova & ~0xfffUL; - if (smmu->version == ARM_SMMU_V2) - smmu_write_atomic_lq(va, cb_base + ARM_SMMU_CB_ATS1PR); - else /* Register is only 32-bit in v1 */ - writel_relaxed(va, cb_base + ARM_SMMU_CB_ATS1PR); + if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64) + arm_smmu_cb_writeq(smmu, idx, ARM_SMMU_CB_ATS1PR, va); + else + arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_ATS1PR, va); - if (readl_poll_timeout_atomic(cb_base + ARM_SMMU_CB_ATSR, tmp, - !(tmp & ATSR_ACTIVE), 5, 50)) { + reg = arm_smmu_page(smmu, ARM_SMMU_CB(smmu, idx)) + ARM_SMMU_CB_ATSR; + if (readl_poll_timeout_atomic(reg, tmp, !(tmp & ATSR_ACTIVE), 5, 50)) { spin_unlock_irqrestore(&smmu_domain->cb_lock, flags); dev_err(dev, "iova to phys timed out on %pad. Falling back to software table walk.\n", @@ -1378,7 +1251,7 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain, return ops->iova_to_phys(ops, iova); } - phys = readq_relaxed(cb_base + ARM_SMMU_CB_PAR); + phys = arm_smmu_cb_readq(smmu, idx, ARM_SMMU_CB_PAR); spin_unlock_irqrestore(&smmu_domain->cb_lock, flags); if (phys & CB_PAR_F) { dev_err(dev, "translation fault!\n"); @@ -1426,16 +1299,11 @@ static bool arm_smmu_capable(enum iommu_cap cap) } } -static int arm_smmu_match_node(struct device *dev, const void *data) -{ - return dev->fwnode == data; -} - static struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode) { - struct device *dev = driver_find_device(&arm_smmu_driver.driver, NULL, - fwnode, arm_smmu_match_node); + struct device *dev = driver_find_device_by_fwnode(&arm_smmu_driver.driver, + fwnode); put_device(dev); return dev ? dev_get_drvdata(dev) : NULL; } @@ -1466,8 +1334,8 @@ static int arm_smmu_add_device(struct device *dev) ret = -EINVAL; for (i = 0; i < fwspec->num_ids; i++) { - u16 sid = fwspec->ids[i]; - u16 mask = fwspec->ids[i] >> SMR_MASK_SHIFT; + u16 sid = FIELD_GET(SMR_ID, fwspec->ids[i]); + u16 mask = FIELD_GET(SMR_MASK, fwspec->ids[i]); if (sid & ~smmu->streamid_mask) { dev_err(dev, "stream ID 0x%x out of range for SMMU (0x%x)\n", @@ -1648,12 +1516,12 @@ static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args) u32 mask, fwid = 0; if (args->args_count > 0) - fwid |= (u16)args->args[0]; + fwid |= FIELD_PREP(SMR_ID, args->args[0]); if (args->args_count > 1) - fwid |= (u16)args->args[1] << SMR_MASK_SHIFT; + fwid |= FIELD_PREP(SMR_MASK, args->args[1]); else if (!of_property_read_u32(args->np, "stream-match-mask", &mask)) - fwid |= (u16)mask << SMR_MASK_SHIFT; + fwid |= FIELD_PREP(SMR_MASK, mask); return iommu_fwspec_add_ids(dev, &fwid, 1); } @@ -1706,13 +1574,12 @@ static struct iommu_ops arm_smmu_ops = { static void arm_smmu_device_reset(struct arm_smmu_device *smmu) { - void __iomem *gr0_base = ARM_SMMU_GR0(smmu); int i; - u32 reg, major; + u32 reg; /* clear global FSR */ - reg = readl_relaxed(ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sGFSR); - writel(reg, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sGFSR); + reg = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSR); + arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sGFSR, reg); /* * Reset stream mapping groups: Initial values mark all SMRn as @@ -1721,47 +1588,17 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu) for (i = 0; i < smmu->num_mapping_groups; ++i) arm_smmu_write_sme(smmu, i); - if (smmu->model == ARM_MMU500) { - /* - * Before clearing ARM_MMU500_ACTLR_CPRE, need to - * clear CACHE_LOCK bit of ACR first. And, CACHE_LOCK - * bit is only present in MMU-500r2 onwards. - */ - reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID7); - major = (reg >> ID7_MAJOR_SHIFT) & ID7_MAJOR_MASK; - reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_sACR); - if (major >= 2) - reg &= ~ARM_MMU500_ACR_CACHE_LOCK; - /* - * Allow unmatched Stream IDs to allocate bypass - * TLB entries for reduced latency. - */ - reg |= ARM_MMU500_ACR_SMTNMB_TLBEN | ARM_MMU500_ACR_S2CRB_TLBEN; - writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_sACR); - } - /* Make sure all context banks are disabled and clear CB_FSR */ for (i = 0; i < smmu->num_context_banks; ++i) { - void __iomem *cb_base = ARM_SMMU_CB(smmu, i); - arm_smmu_write_context_bank(smmu, i); - writel_relaxed(FSR_FAULT, cb_base + ARM_SMMU_CB_FSR); - /* - * Disable MMU-500's not-particularly-beneficial next-page - * prefetcher for the sake of errata #841119 and #826419. - */ - if (smmu->model == ARM_MMU500) { - reg = readl_relaxed(cb_base + ARM_SMMU_CB_ACTLR); - reg &= ~ARM_MMU500_ACTLR_CPRE; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_ACTLR); - } + arm_smmu_cb_write(smmu, i, ARM_SMMU_CB_FSR, FSR_FAULT); } /* Invalidate the TLB, just in case */ - writel_relaxed(QCOM_DUMMY_VAL, gr0_base + ARM_SMMU_GR0_TLBIALLH); - writel_relaxed(QCOM_DUMMY_VAL, gr0_base + ARM_SMMU_GR0_TLBIALLNSNH); + arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_TLBIALLH, QCOM_DUMMY_VAL); + arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_TLBIALLNSNH, QCOM_DUMMY_VAL); - reg = readl_relaxed(ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0); + reg = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sCR0); /* Enable fault reporting */ reg |= (sCR0_GFRE | sCR0_GFIE | sCR0_GCFGFRE | sCR0_GCFGFIE); @@ -1780,7 +1617,7 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu) reg &= ~sCR0_FB; /* Don't upgrade barriers */ - reg &= ~(sCR0_BSU_MASK << sCR0_BSU_SHIFT); + reg &= ~(sCR0_BSU); if (smmu->features & ARM_SMMU_FEAT_VMID16) reg |= sCR0_VMID16EN; @@ -1788,9 +1625,12 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu) if (smmu->features & ARM_SMMU_FEAT_EXIDS) reg |= sCR0_EXIDENABLE; + if (smmu->impl && smmu->impl->reset) + smmu->impl->reset(smmu); + /* Push the button */ arm_smmu_tlb_sync_global(smmu); - writel(reg, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0); + arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sCR0, reg); } static int arm_smmu_id_size_to_bits(int size) @@ -1814,8 +1654,7 @@ static int arm_smmu_id_size_to_bits(int size) static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) { - unsigned long size; - void __iomem *gr0_base = ARM_SMMU_GR0(smmu); + unsigned int size; u32 id; bool cttw_reg, cttw_fw = smmu->features & ARM_SMMU_FEAT_COHERENT_WALK; int i; @@ -1825,7 +1664,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) smmu->version == ARM_SMMU_V2 ? 2 : 1); /* ID0 */ - id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID0); + id = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_ID0); /* Restrict available stages based on module parameter */ if (force_stage == 1) @@ -1879,12 +1718,12 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) smmu->features |= ARM_SMMU_FEAT_EXIDS; size = 1 << 16; } else { - size = 1 << ((id >> ID0_NUMSIDB_SHIFT) & ID0_NUMSIDB_MASK); + size = 1 << FIELD_GET(ID0_NUMSIDB, id); } smmu->streamid_mask = size - 1; if (id & ID0_SMS) { smmu->features |= ARM_SMMU_FEAT_STREAM_MATCH; - size = (id >> ID0_NUMSMRG_SHIFT) & ID0_NUMSMRG_MASK; + size = FIELD_GET(ID0_NUMSMRG, id); if (size == 0) { dev_err(smmu->dev, "stream-matching supported, but no SMRs present!\n"); @@ -1898,7 +1737,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) return -ENOMEM; dev_notice(smmu->dev, - "\tstream matching with %lu register groups", size); + "\tstream matching with %u register groups", size); } /* s2cr->type == 0 means translation, so initialise explicitly */ smmu->s2crs = devm_kmalloc_array(smmu->dev, size, sizeof(*smmu->s2crs), @@ -1919,49 +1758,38 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) } /* ID1 */ - id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID1); + id = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_ID1); smmu->pgshift = (id & ID1_PAGESIZE) ? 16 : 12; /* Check for size mismatch of SMMU address space from mapped region */ - size = 1 << (((id >> ID1_NUMPAGENDXB_SHIFT) & ID1_NUMPAGENDXB_MASK) + 1); - size <<= smmu->pgshift; - if (smmu->cb_base != gr0_base + size) + size = 1 << (FIELD_GET(ID1_NUMPAGENDXB, id) + 1); + if (smmu->numpage != 2 * size << smmu->pgshift) dev_warn(smmu->dev, - "SMMU address space size (0x%lx) differs from mapped region size (0x%tx)!\n", - size * 2, (smmu->cb_base - gr0_base) * 2); + "SMMU address space size (0x%x) differs from mapped region size (0x%x)!\n", + 2 * size << smmu->pgshift, smmu->numpage); + /* Now properly encode NUMPAGE to subsequently derive SMMU_CB_BASE */ + smmu->numpage = size; - smmu->num_s2_context_banks = (id >> ID1_NUMS2CB_SHIFT) & ID1_NUMS2CB_MASK; - smmu->num_context_banks = (id >> ID1_NUMCB_SHIFT) & ID1_NUMCB_MASK; + smmu->num_s2_context_banks = FIELD_GET(ID1_NUMS2CB, id); + smmu->num_context_banks = FIELD_GET(ID1_NUMCB, id); if (smmu->num_s2_context_banks > smmu->num_context_banks) { dev_err(smmu->dev, "impossible number of S2 context banks!\n"); return -ENODEV; } dev_notice(smmu->dev, "\t%u context banks (%u stage-2 only)\n", smmu->num_context_banks, smmu->num_s2_context_banks); - /* - * Cavium CN88xx erratum #27704. - * Ensure ASID and VMID allocation is unique across all SMMUs in - * the system. - */ - if (smmu->model == CAVIUM_SMMUV2) { - smmu->cavium_id_base = - atomic_add_return(smmu->num_context_banks, - &cavium_smmu_context_count); - smmu->cavium_id_base -= smmu->num_context_banks; - dev_notice(smmu->dev, "\tenabling workaround for Cavium erratum 27704\n"); - } smmu->cbs = devm_kcalloc(smmu->dev, smmu->num_context_banks, sizeof(*smmu->cbs), GFP_KERNEL); if (!smmu->cbs) return -ENOMEM; /* ID2 */ - id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID2); - size = arm_smmu_id_size_to_bits((id >> ID2_IAS_SHIFT) & ID2_IAS_MASK); + id = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_ID2); + size = arm_smmu_id_size_to_bits(FIELD_GET(ID2_IAS, id)); smmu->ipa_size = size; /* The output mask is also applied for bypass */ - size = arm_smmu_id_size_to_bits((id >> ID2_OAS_SHIFT) & ID2_OAS_MASK); + size = arm_smmu_id_size_to_bits(FIELD_GET(ID2_OAS, id)); smmu->pa_size = size; if (id & ID2_VMID16) @@ -1981,7 +1809,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) if (smmu->version == ARM_SMMU_V1_64K) smmu->features |= ARM_SMMU_FEAT_FMT_AARCH64_64K; } else { - size = (id >> ID2_UBS_SHIFT) & ID2_UBS_MASK; + size = FIELD_GET(ID2_UBS, id); smmu->va_size = arm_smmu_id_size_to_bits(size); if (id & ID2_PTFS_4K) smmu->features |= ARM_SMMU_FEAT_FMT_AARCH64_4K; @@ -2018,6 +1846,9 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) dev_notice(smmu->dev, "\tStage-2: %lu-bit IPA -> %lu-bit PA\n", smmu->ipa_size, smmu->pa_size); + if (smmu->impl && smmu->impl->cfg_probe) + return smmu->impl->cfg_probe(smmu); + return 0; } @@ -2130,8 +1961,6 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev, smmu->version = data->version; smmu->model = data->model; - parse_driver_options(smmu); - legacy_binding = of_find_property(dev->of_node, "mmu-masters", NULL); if (legacy_binding && !using_generic_binding) { if (!using_legacy_binding) @@ -2194,12 +2023,20 @@ static int arm_smmu_device_probe(struct platform_device *pdev) if (err) return err; + smmu = arm_smmu_impl_init(smmu); + if (IS_ERR(smmu)) + return PTR_ERR(smmu); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ioaddr = res->start; smmu->base = devm_ioremap_resource(dev, res); if (IS_ERR(smmu->base)) return PTR_ERR(smmu->base); - smmu->cb_base = smmu->base + resource_size(res) / 2; + /* + * The resource size should effectively match the value of SMMU_TOP; + * stash that temporarily until we know PAGESIZE to validate it with. + */ + smmu->numpage = resource_size(res); num_irqs = 0; while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, num_irqs))) { @@ -2339,7 +2176,7 @@ static void arm_smmu_device_shutdown(struct platform_device *pdev) arm_smmu_rpm_get(smmu); /* Turn the thing off */ - writel(sCR0_CLIENTPD, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0); + arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sCR0, sCR0_CLIENTPD); arm_smmu_rpm_put(smmu); if (pm_runtime_enabled(smmu->dev)) diff --git a/drivers/iommu/arm-smmu.h b/drivers/iommu/arm-smmu.h new file mode 100644 index 0000000000000000000000000000000000000000..b19b6cae9b5e8437c51958989d127ee0c50b16a1 --- /dev/null +++ b/drivers/iommu/arm-smmu.h @@ -0,0 +1,402 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * IOMMU API for ARM architected SMMU implementations. + * + * Copyright (C) 2013 ARM Limited + * + * Author: Will Deacon + */ + +#ifndef _ARM_SMMU_H +#define _ARM_SMMU_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Configuration registers */ +#define ARM_SMMU_GR0_sCR0 0x0 +#define sCR0_VMID16EN BIT(31) +#define sCR0_BSU GENMASK(15, 14) +#define sCR0_FB BIT(13) +#define sCR0_PTM BIT(12) +#define sCR0_VMIDPNE BIT(11) +#define sCR0_USFCFG BIT(10) +#define sCR0_GCFGFIE BIT(5) +#define sCR0_GCFGFRE BIT(4) +#define sCR0_EXIDENABLE BIT(3) +#define sCR0_GFIE BIT(2) +#define sCR0_GFRE BIT(1) +#define sCR0_CLIENTPD BIT(0) + +/* Auxiliary Configuration register */ +#define ARM_SMMU_GR0_sACR 0x10 + +/* Identification registers */ +#define ARM_SMMU_GR0_ID0 0x20 +#define ID0_S1TS BIT(30) +#define ID0_S2TS BIT(29) +#define ID0_NTS BIT(28) +#define ID0_SMS BIT(27) +#define ID0_ATOSNS BIT(26) +#define ID0_PTFS_NO_AARCH32 BIT(25) +#define ID0_PTFS_NO_AARCH32S BIT(24) +#define ID0_NUMIRPT GENMASK(23, 16) +#define ID0_CTTW BIT(14) +#define ID0_NUMSIDB GENMASK(12, 9) +#define ID0_EXIDS BIT(8) +#define ID0_NUMSMRG GENMASK(7, 0) + +#define ARM_SMMU_GR0_ID1 0x24 +#define ID1_PAGESIZE BIT(31) +#define ID1_NUMPAGENDXB GENMASK(30, 28) +#define ID1_NUMS2CB GENMASK(23, 16) +#define ID1_NUMCB GENMASK(7, 0) + +#define ARM_SMMU_GR0_ID2 0x28 +#define ID2_VMID16 BIT(15) +#define ID2_PTFS_64K BIT(14) +#define ID2_PTFS_16K BIT(13) +#define ID2_PTFS_4K BIT(12) +#define ID2_UBS GENMASK(11, 8) +#define ID2_OAS GENMASK(7, 4) +#define ID2_IAS GENMASK(3, 0) + +#define ARM_SMMU_GR0_ID3 0x2c +#define ARM_SMMU_GR0_ID4 0x30 +#define ARM_SMMU_GR0_ID5 0x34 +#define ARM_SMMU_GR0_ID6 0x38 + +#define ARM_SMMU_GR0_ID7 0x3c +#define ID7_MAJOR GENMASK(7, 4) +#define ID7_MINOR GENMASK(3, 0) + +#define ARM_SMMU_GR0_sGFSR 0x48 +#define ARM_SMMU_GR0_sGFSYNR0 0x50 +#define ARM_SMMU_GR0_sGFSYNR1 0x54 +#define ARM_SMMU_GR0_sGFSYNR2 0x58 + +/* Global TLB invalidation */ +#define ARM_SMMU_GR0_TLBIVMID 0x64 +#define ARM_SMMU_GR0_TLBIALLNSNH 0x68 +#define ARM_SMMU_GR0_TLBIALLH 0x6c +#define ARM_SMMU_GR0_sTLBGSYNC 0x70 + +#define ARM_SMMU_GR0_sTLBGSTATUS 0x74 +#define sTLBGSTATUS_GSACTIVE BIT(0) + +/* Stream mapping registers */ +#define ARM_SMMU_GR0_SMR(n) (0x800 + ((n) << 2)) +#define SMR_VALID BIT(31) +#define SMR_MASK GENMASK(31, 16) +#define SMR_ID GENMASK(15, 0) + +#define ARM_SMMU_GR0_S2CR(n) (0xc00 + ((n) << 2)) +#define S2CR_PRIVCFG GENMASK(25, 24) +enum arm_smmu_s2cr_privcfg { + S2CR_PRIVCFG_DEFAULT, + S2CR_PRIVCFG_DIPAN, + S2CR_PRIVCFG_UNPRIV, + S2CR_PRIVCFG_PRIV, +}; +#define S2CR_TYPE GENMASK(17, 16) +enum arm_smmu_s2cr_type { + S2CR_TYPE_TRANS, + S2CR_TYPE_BYPASS, + S2CR_TYPE_FAULT, +}; +#define S2CR_EXIDVALID BIT(10) +#define S2CR_CBNDX GENMASK(7, 0) + +/* Context bank attribute registers */ +#define ARM_SMMU_GR1_CBAR(n) (0x0 + ((n) << 2)) +#define CBAR_IRPTNDX GENMASK(31, 24) +#define CBAR_TYPE GENMASK(17, 16) +enum arm_smmu_cbar_type { + CBAR_TYPE_S2_TRANS, + CBAR_TYPE_S1_TRANS_S2_BYPASS, + CBAR_TYPE_S1_TRANS_S2_FAULT, + CBAR_TYPE_S1_TRANS_S2_TRANS, +}; +#define CBAR_S1_MEMATTR GENMASK(15, 12) +#define CBAR_S1_MEMATTR_WB 0xf +#define CBAR_S1_BPSHCFG GENMASK(9, 8) +#define CBAR_S1_BPSHCFG_NSH 3 +#define CBAR_VMID GENMASK(7, 0) + +#define ARM_SMMU_GR1_CBFRSYNRA(n) (0x400 + ((n) << 2)) + +#define ARM_SMMU_GR1_CBA2R(n) (0x800 + ((n) << 2)) +#define CBA2R_VMID16 GENMASK(31, 16) +#define CBA2R_VA64 BIT(0) + +#define ARM_SMMU_CB_SCTLR 0x0 +#define SCTLR_S1_ASIDPNE BIT(12) +#define SCTLR_CFCFG BIT(7) +#define SCTLR_CFIE BIT(6) +#define SCTLR_CFRE BIT(5) +#define SCTLR_E BIT(4) +#define SCTLR_AFE BIT(2) +#define SCTLR_TRE BIT(1) +#define SCTLR_M BIT(0) + +#define ARM_SMMU_CB_ACTLR 0x4 + +#define ARM_SMMU_CB_RESUME 0x8 +#define RESUME_TERMINATE BIT(0) + +#define ARM_SMMU_CB_TCR2 0x10 +#define TCR2_SEP GENMASK(17, 15) +#define TCR2_SEP_UPSTREAM 0x7 +#define TCR2_AS BIT(4) + +#define ARM_SMMU_CB_TTBR0 0x20 +#define ARM_SMMU_CB_TTBR1 0x28 +#define TTBRn_ASID GENMASK_ULL(63, 48) + +#define ARM_SMMU_CB_TCR 0x30 +#define ARM_SMMU_CB_CONTEXTIDR 0x34 +#define ARM_SMMU_CB_S1_MAIR0 0x38 +#define ARM_SMMU_CB_S1_MAIR1 0x3c + +#define ARM_SMMU_CB_PAR 0x50 +#define CB_PAR_F BIT(0) + +#define ARM_SMMU_CB_FSR 0x58 +#define FSR_MULTI BIT(31) +#define FSR_SS BIT(30) +#define FSR_UUT BIT(8) +#define FSR_ASF BIT(7) +#define FSR_TLBLKF BIT(6) +#define FSR_TLBMCF BIT(5) +#define FSR_EF BIT(4) +#define FSR_PF BIT(3) +#define FSR_AFF BIT(2) +#define FSR_TF BIT(1) + +#define FSR_IGN (FSR_AFF | FSR_ASF | \ + FSR_TLBMCF | FSR_TLBLKF) +#define FSR_FAULT (FSR_MULTI | FSR_SS | FSR_UUT | \ + FSR_EF | FSR_PF | FSR_TF | FSR_IGN) + +#define ARM_SMMU_CB_FAR 0x60 + +#define ARM_SMMU_CB_FSYNR0 0x68 +#define FSYNR0_WNR BIT(4) + +#define ARM_SMMU_CB_S1_TLBIVA 0x600 +#define ARM_SMMU_CB_S1_TLBIASID 0x610 +#define ARM_SMMU_CB_S1_TLBIVAL 0x620 +#define ARM_SMMU_CB_S2_TLBIIPAS2 0x630 +#define ARM_SMMU_CB_S2_TLBIIPAS2L 0x638 +#define ARM_SMMU_CB_TLBSYNC 0x7f0 +#define ARM_SMMU_CB_TLBSTATUS 0x7f4 +#define ARM_SMMU_CB_ATS1PR 0x800 + +#define ARM_SMMU_CB_ATSR 0x8f0 +#define ATSR_ACTIVE BIT(0) + + +/* Maximum number of context banks per SMMU */ +#define ARM_SMMU_MAX_CBS 128 + + +/* Shared driver definitions */ +enum arm_smmu_arch_version { + ARM_SMMU_V1, + ARM_SMMU_V1_64K, + ARM_SMMU_V2, +}; + +enum arm_smmu_implementation { + GENERIC_SMMU, + ARM_MMU500, + CAVIUM_SMMUV2, + QCOM_SMMUV2, +}; + +struct arm_smmu_device { + struct device *dev; + + void __iomem *base; + unsigned int numpage; + unsigned int pgshift; + +#define ARM_SMMU_FEAT_COHERENT_WALK (1 << 0) +#define ARM_SMMU_FEAT_STREAM_MATCH (1 << 1) +#define ARM_SMMU_FEAT_TRANS_S1 (1 << 2) +#define ARM_SMMU_FEAT_TRANS_S2 (1 << 3) +#define ARM_SMMU_FEAT_TRANS_NESTED (1 << 4) +#define ARM_SMMU_FEAT_TRANS_OPS (1 << 5) +#define ARM_SMMU_FEAT_VMID16 (1 << 6) +#define ARM_SMMU_FEAT_FMT_AARCH64_4K (1 << 7) +#define ARM_SMMU_FEAT_FMT_AARCH64_16K (1 << 8) +#define ARM_SMMU_FEAT_FMT_AARCH64_64K (1 << 9) +#define ARM_SMMU_FEAT_FMT_AARCH32_L (1 << 10) +#define ARM_SMMU_FEAT_FMT_AARCH32_S (1 << 11) +#define ARM_SMMU_FEAT_EXIDS (1 << 12) + u32 features; + + enum arm_smmu_arch_version version; + enum arm_smmu_implementation model; + const struct arm_smmu_impl *impl; + + u32 num_context_banks; + u32 num_s2_context_banks; + DECLARE_BITMAP(context_map, ARM_SMMU_MAX_CBS); + struct arm_smmu_cb *cbs; + atomic_t irptndx; + + u32 num_mapping_groups; + u16 streamid_mask; + u16 smr_mask_mask; + struct arm_smmu_smr *smrs; + struct arm_smmu_s2cr *s2crs; + struct mutex stream_map_mutex; + + unsigned long va_size; + unsigned long ipa_size; + unsigned long pa_size; + unsigned long pgsize_bitmap; + + u32 num_global_irqs; + u32 num_context_irqs; + unsigned int *irqs; + struct clk_bulk_data *clks; + int num_clks; + + spinlock_t global_sync_lock; + + /* IOMMU core code handle */ + struct iommu_device iommu; +}; + +enum arm_smmu_context_fmt { + ARM_SMMU_CTX_FMT_NONE, + ARM_SMMU_CTX_FMT_AARCH64, + ARM_SMMU_CTX_FMT_AARCH32_L, + ARM_SMMU_CTX_FMT_AARCH32_S, +}; + +struct arm_smmu_cfg { + u8 cbndx; + u8 irptndx; + union { + u16 asid; + u16 vmid; + }; + enum arm_smmu_cbar_type cbar; + enum arm_smmu_context_fmt fmt; +}; +#define INVALID_IRPTNDX 0xff + +enum arm_smmu_domain_stage { + ARM_SMMU_DOMAIN_S1 = 0, + ARM_SMMU_DOMAIN_S2, + ARM_SMMU_DOMAIN_NESTED, + ARM_SMMU_DOMAIN_BYPASS, +}; + +struct arm_smmu_flush_ops { + struct iommu_flush_ops tlb; + void (*tlb_inv_range)(unsigned long iova, size_t size, size_t granule, + bool leaf, void *cookie); + void (*tlb_sync)(void *cookie); +}; + +struct arm_smmu_domain { + struct arm_smmu_device *smmu; + struct io_pgtable_ops *pgtbl_ops; + const struct arm_smmu_flush_ops *flush_ops; + struct arm_smmu_cfg cfg; + enum arm_smmu_domain_stage stage; + bool non_strict; + struct mutex init_mutex; /* Protects smmu pointer */ + spinlock_t cb_lock; /* Serialises ATS1* ops and TLB syncs */ + struct iommu_domain domain; +}; + + +/* Implementation details, yay! */ +struct arm_smmu_impl { + u32 (*read_reg)(struct arm_smmu_device *smmu, int page, int offset); + void (*write_reg)(struct arm_smmu_device *smmu, int page, int offset, + u32 val); + u64 (*read_reg64)(struct arm_smmu_device *smmu, int page, int offset); + void (*write_reg64)(struct arm_smmu_device *smmu, int page, int offset, + u64 val); + int (*cfg_probe)(struct arm_smmu_device *smmu); + int (*reset)(struct arm_smmu_device *smmu); + int (*init_context)(struct arm_smmu_domain *smmu_domain); +}; + +static inline void __iomem *arm_smmu_page(struct arm_smmu_device *smmu, int n) +{ + return smmu->base + (n << smmu->pgshift); +} + +static inline u32 arm_smmu_readl(struct arm_smmu_device *smmu, int page, int offset) +{ + if (smmu->impl && unlikely(smmu->impl->read_reg)) + return smmu->impl->read_reg(smmu, page, offset); + return readl_relaxed(arm_smmu_page(smmu, page) + offset); +} + +static inline void arm_smmu_writel(struct arm_smmu_device *smmu, int page, + int offset, u32 val) +{ + if (smmu->impl && unlikely(smmu->impl->write_reg)) + smmu->impl->write_reg(smmu, page, offset, val); + else + writel_relaxed(val, arm_smmu_page(smmu, page) + offset); +} + +static inline u64 arm_smmu_readq(struct arm_smmu_device *smmu, int page, int offset) +{ + if (smmu->impl && unlikely(smmu->impl->read_reg64)) + return smmu->impl->read_reg64(smmu, page, offset); + return readq_relaxed(arm_smmu_page(smmu, page) + offset); +} + +static inline void arm_smmu_writeq(struct arm_smmu_device *smmu, int page, + int offset, u64 val) +{ + if (smmu->impl && unlikely(smmu->impl->write_reg64)) + smmu->impl->write_reg64(smmu, page, offset, val); + else + writeq_relaxed(val, arm_smmu_page(smmu, page) + offset); +} + +#define ARM_SMMU_GR0 0 +#define ARM_SMMU_GR1 1 +#define ARM_SMMU_CB(s, n) ((s)->numpage + (n)) + +#define arm_smmu_gr0_read(s, o) \ + arm_smmu_readl((s), ARM_SMMU_GR0, (o)) +#define arm_smmu_gr0_write(s, o, v) \ + arm_smmu_writel((s), ARM_SMMU_GR0, (o), (v)) + +#define arm_smmu_gr1_read(s, o) \ + arm_smmu_readl((s), ARM_SMMU_GR1, (o)) +#define arm_smmu_gr1_write(s, o, v) \ + arm_smmu_writel((s), ARM_SMMU_GR1, (o), (v)) + +#define arm_smmu_cb_read(s, n, o) \ + arm_smmu_readl((s), ARM_SMMU_CB((s), (n)), (o)) +#define arm_smmu_cb_write(s, n, o, v) \ + arm_smmu_writel((s), ARM_SMMU_CB((s), (n)), (o), (v)) +#define arm_smmu_cb_readq(s, n, o) \ + arm_smmu_readq((s), ARM_SMMU_CB((s), (n)), (o)) +#define arm_smmu_cb_writeq(s, n, o, v) \ + arm_smmu_writeq((s), ARM_SMMU_CB((s), (n)), (o), (v)) + +struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu); + +#endif /* _ARM_SMMU_H */ diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index f68a62c3c32b55e1414ee5eff0cc34a452f38489..8f412af842471aef7a56603156123a2d70fd8142 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -303,13 +303,15 @@ static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, u64 size, struct device *dev) { struct iommu_dma_cookie *cookie = domain->iova_cookie; - struct iova_domain *iovad = &cookie->iovad; unsigned long order, base_pfn; + struct iova_domain *iovad; int attr; if (!cookie || cookie->type != IOMMU_DMA_IOVA_COOKIE) return -EINVAL; + iovad = &cookie->iovad; + /* Use the smallest supported page size for IOVA granularity */ order = __ffs(domain->pgsize_bitmap); base_pfn = max_t(unsigned long, 1, base >> order); @@ -444,13 +446,18 @@ static void __iommu_dma_unmap(struct device *dev, dma_addr_t dma_addr, struct iommu_dma_cookie *cookie = domain->iova_cookie; struct iova_domain *iovad = &cookie->iovad; size_t iova_off = iova_offset(iovad, dma_addr); + struct iommu_iotlb_gather iotlb_gather; + size_t unmapped; dma_addr -= iova_off; size = iova_align(iovad, size + iova_off); + iommu_iotlb_gather_init(&iotlb_gather); + + unmapped = iommu_unmap_fast(domain, dma_addr, size, &iotlb_gather); + WARN_ON(unmapped != size); - WARN_ON(iommu_unmap_fast(domain, dma_addr, size) != size); if (!cookie->fq_domain) - iommu_tlb_sync(domain); + iommu_tlb_sync(domain, &iotlb_gather); iommu_dma_free_iova(cookie, dma_addr, size); } diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 5d0754ed5fa0c34203b8ffd7d22403a29bccd013..eecd6a4216672e430224fb961b53e98cf37ee423 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -1519,6 +1519,64 @@ static const char *dma_remap_fault_reasons[] = "PCE for translation request specifies blocking", }; +static const char * const dma_remap_sm_fault_reasons[] = { + "SM: Invalid Root Table Address", + "SM: TTM 0 for request with PASID", + "SM: TTM 0 for page group request", + "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x33-0x37 */ + "SM: Error attempting to access Root Entry", + "SM: Present bit in Root Entry is clear", + "SM: Non-zero reserved field set in Root Entry", + "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x3B-0x3F */ + "SM: Error attempting to access Context Entry", + "SM: Present bit in Context Entry is clear", + "SM: Non-zero reserved field set in the Context Entry", + "SM: Invalid Context Entry", + "SM: DTE field in Context Entry is clear", + "SM: PASID Enable field in Context Entry is clear", + "SM: PASID is larger than the max in Context Entry", + "SM: PRE field in Context-Entry is clear", + "SM: RID_PASID field error in Context-Entry", + "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x49-0x4F */ + "SM: Error attempting to access the PASID Directory Entry", + "SM: Present bit in Directory Entry is clear", + "SM: Non-zero reserved field set in PASID Directory Entry", + "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x53-0x57 */ + "SM: Error attempting to access PASID Table Entry", + "SM: Present bit in PASID Table Entry is clear", + "SM: Non-zero reserved field set in PASID Table Entry", + "SM: Invalid Scalable-Mode PASID Table Entry", + "SM: ERE field is clear in PASID Table Entry", + "SM: SRE field is clear in PASID Table Entry", + "Unknown", "Unknown",/* 0x5E-0x5F */ + "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x60-0x67 */ + "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x68-0x6F */ + "SM: Error attempting to access first-level paging entry", + "SM: Present bit in first-level paging entry is clear", + "SM: Non-zero reserved field set in first-level paging entry", + "SM: Error attempting to access FL-PML4 entry", + "SM: First-level entry address beyond MGAW in Nested translation", + "SM: Read permission error in FL-PML4 entry in Nested translation", + "SM: Read permission error in first-level paging entry in Nested translation", + "SM: Write permission error in first-level paging entry in Nested translation", + "SM: Error attempting to access second-level paging entry", + "SM: Read/Write permission error in second-level paging entry", + "SM: Non-zero reserved field set in second-level paging entry", + "SM: Invalid second-level page table pointer", + "SM: A/D bit update needed in second-level entry when set up in no snoop", + "Unknown", "Unknown", "Unknown", /* 0x7D-0x7F */ + "SM: Address in first-level translation is not canonical", + "SM: U/S set 0 for first-level translation with user privilege", + "SM: No execute permission for request with PASID and ER=1", + "SM: Address beyond the DMA hardware max", + "SM: Second-level entry address beyond the max", + "SM: No write permission for Write/AtomicOp request", + "SM: No read permission for Read/AtomicOp request", + "SM: Invalid address-interrupt address", + "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x88-0x8F */ + "SM: A/D bit update needed in first-level entry when set up in no snoop", +}; + static const char *irq_remap_fault_reasons[] = { "Detected reserved fields in the decoded interrupt-remapped request", @@ -1536,6 +1594,10 @@ static const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type) ARRAY_SIZE(irq_remap_fault_reasons))) { *fault_type = INTR_REMAP; return irq_remap_fault_reasons[fault_reason - 0x20]; + } else if (fault_reason >= 0x30 && (fault_reason - 0x30 < + ARRAY_SIZE(dma_remap_sm_fault_reasons))) { + *fault_type = DMA_REMAP; + return dma_remap_sm_fault_reasons[fault_reason - 0x30]; } else if (fault_reason < ARRAY_SIZE(dma_remap_fault_reasons)) { *fault_type = DMA_REMAP; return dma_remap_fault_reasons[fault_reason]; @@ -1611,7 +1673,8 @@ void dmar_msi_read(int irq, struct msi_msg *msg) } static int dmar_fault_do_one(struct intel_iommu *iommu, int type, - u8 fault_reason, u16 source_id, unsigned long long addr) + u8 fault_reason, int pasid, u16 source_id, + unsigned long long addr) { const char *reason; int fault_type; @@ -1624,10 +1687,11 @@ static int dmar_fault_do_one(struct intel_iommu *iommu, int type, PCI_FUNC(source_id & 0xFF), addr >> 48, fault_reason, reason); else - pr_err("[%s] Request device [%02x:%02x.%d] fault addr %llx [fault reason %02d] %s\n", + pr_err("[%s] Request device [%02x:%02x.%d] PASID %x fault addr %llx [fault reason %02d] %s\n", type ? "DMA Read" : "DMA Write", source_id >> 8, PCI_SLOT(source_id & 0xFF), - PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason); + PCI_FUNC(source_id & 0xFF), pasid, addr, + fault_reason, reason); return 0; } @@ -1659,8 +1723,9 @@ irqreturn_t dmar_fault(int irq, void *dev_id) u8 fault_reason; u16 source_id; u64 guest_addr; - int type; + int type, pasid; u32 data; + bool pasid_present; /* highest 32 bits */ data = readl(iommu->reg + reg + @@ -1672,10 +1737,12 @@ irqreturn_t dmar_fault(int irq, void *dev_id) fault_reason = dma_frcd_fault_reason(data); type = dma_frcd_type(data); + pasid = dma_frcd_pasid_value(data); data = readl(iommu->reg + reg + fault_index * PRIMARY_FAULT_REG_LEN + 8); source_id = dma_frcd_source_id(data); + pasid_present = dma_frcd_pasid_present(data); guest_addr = dmar_readq(iommu->reg + reg + fault_index * PRIMARY_FAULT_REG_LEN); guest_addr = dma_frcd_page_addr(guest_addr); @@ -1688,7 +1755,9 @@ irqreturn_t dmar_fault(int irq, void *dev_id) raw_spin_unlock_irqrestore(&iommu->register_lock, flag); if (!ratelimited) + /* Using pasid -1 if pasid is not present */ dmar_fault_do_one(iommu, type, fault_reason, + pasid_present ? pasid : -1, source_id, guest_addr); fault_index++; diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index b0c1e5f9daae5acc353ef91c5d0ab44f773fa318..9c94e16fb1277f793bb8d24062b09afb8ab49d74 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -566,7 +566,7 @@ static void sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data, static const struct iommu_ops exynos_iommu_ops; -static int __init exynos_sysmmu_probe(struct platform_device *pdev) +static int exynos_sysmmu_probe(struct platform_device *pdev) { int irq, ret; struct device *dev = &pdev->dev; @@ -583,10 +583,8 @@ static int __init exynos_sysmmu_probe(struct platform_device *pdev) return PTR_ERR(data->sfrbase); irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_err(dev, "Unable to find IRQ resource\n"); + if (irq <= 0) return irq; - } ret = devm_request_irq(dev, irq, exynos_sysmmu_irq, 0, dev_name(dev), data); @@ -1130,7 +1128,8 @@ static void exynos_iommu_tlb_invalidate_entry(struct exynos_iommu_domain *domain } static size_t exynos_iommu_unmap(struct iommu_domain *iommu_domain, - unsigned long l_iova, size_t size) + unsigned long l_iova, size_t size, + struct iommu_iotlb_gather *gather) { struct exynos_iommu_domain *domain = to_exynos_domain(iommu_domain); sysmmu_iova_t iova = (sysmmu_iova_t)l_iova; diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index c4e0e4a9ee9ec5c2f5632176591badb3161031fa..87de0b975672b0a8864277ff799b5e02e56547ea 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -41,9 +41,11 @@ #include #include #include +#include #include #include #include +#include #include "irq_remapping.h" #include "intel-pasid.h" @@ -346,6 +348,8 @@ static int domain_detach_iommu(struct dmar_domain *domain, static bool device_is_rmrr_locked(struct device *dev); static int intel_iommu_attach_device(struct iommu_domain *domain, struct device *dev); +static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain, + dma_addr_t iova); #ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON int dmar_disabled = 0; @@ -362,6 +366,7 @@ static int dmar_forcedac; static int intel_iommu_strict; static int intel_iommu_superpage = 1; static int iommu_identity_mapping; +static int intel_no_bounce; #define IDENTMAP_ALL 1 #define IDENTMAP_GFX 2 @@ -375,6 +380,9 @@ EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped); static DEFINE_SPINLOCK(device_domain_lock); static LIST_HEAD(device_domain_list); +#define device_needs_bounce(d) (!intel_no_bounce && dev_is_pci(d) && \ + to_pci_dev(d)->untrusted) + /* * Iterate over elements in device_domain_list and call the specified * callback @fn against each element. @@ -457,6 +465,9 @@ static int __init intel_iommu_setup(char *str) printk(KERN_INFO "Intel-IOMMU: not forcing on after tboot. This could expose security risk for tboot\n"); intel_iommu_tboot_noforce = 1; + } else if (!strncmp(str, "nobounce", 8)) { + pr_info("Intel-IOMMU: No bounce buffer. This could expose security risks of DMA attacks\n"); + intel_no_bounce = 1; } str += strcspn(str, ","); @@ -3296,7 +3307,7 @@ static int __init init_dmars(void) iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH); } - if (iommu_pass_through) + if (iommu_default_passthrough()) iommu_identity_mapping |= IDENTMAP_ALL; #ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA @@ -3534,6 +3545,9 @@ static dma_addr_t __intel_map_single(struct device *dev, phys_addr_t paddr, start_paddr = (phys_addr_t)iova_pfn << PAGE_SHIFT; start_paddr += paddr & ~PAGE_MASK; + + trace_map_single(dev, start_paddr, paddr, size << VTD_PAGE_SHIFT); + return start_paddr; error: @@ -3589,10 +3603,7 @@ static void intel_unmap(struct device *dev, dma_addr_t dev_addr, size_t size) if (dev_is_pci(dev)) pdev = to_pci_dev(dev); - dev_dbg(dev, "Device unmapping: pfn %lx-%lx\n", start_pfn, last_pfn); - freelist = domain_unmap(domain, start_pfn, last_pfn); - if (intel_iommu_strict || (pdev && pdev->untrusted) || !has_iova_flush_queue(&domain->iovad)) { iommu_flush_iotlb_psi(iommu, domain, start_pfn, @@ -3608,6 +3619,8 @@ static void intel_unmap(struct device *dev, dma_addr_t dev_addr, size_t size) * cpu used up by the iotlb flush operation... */ } + + trace_unmap_single(dev, dev_addr, size); } static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr, @@ -3698,6 +3711,8 @@ static void intel_unmap_sg(struct device *dev, struct scatterlist *sglist, } intel_unmap(dev, startaddr, nrpages << VTD_PAGE_SHIFT); + + trace_unmap_sg(dev, startaddr, nrpages << VTD_PAGE_SHIFT); } static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nelems, @@ -3754,6 +3769,9 @@ static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nele return 0; } + trace_map_sg(dev, iova_pfn << PAGE_SHIFT, + sg_phys(sglist), size << VTD_PAGE_SHIFT); + return nelems; } @@ -3769,6 +3787,252 @@ static const struct dma_map_ops intel_dma_ops = { .dma_supported = dma_direct_supported, }; +static void +bounce_sync_single(struct device *dev, dma_addr_t addr, size_t size, + enum dma_data_direction dir, enum dma_sync_target target) +{ + struct dmar_domain *domain; + phys_addr_t tlb_addr; + + domain = find_domain(dev); + if (WARN_ON(!domain)) + return; + + tlb_addr = intel_iommu_iova_to_phys(&domain->domain, addr); + if (is_swiotlb_buffer(tlb_addr)) + swiotlb_tbl_sync_single(dev, tlb_addr, size, dir, target); +} + +static dma_addr_t +bounce_map_single(struct device *dev, phys_addr_t paddr, size_t size, + enum dma_data_direction dir, unsigned long attrs, + u64 dma_mask) +{ + size_t aligned_size = ALIGN(size, VTD_PAGE_SIZE); + struct dmar_domain *domain; + struct intel_iommu *iommu; + unsigned long iova_pfn; + unsigned long nrpages; + phys_addr_t tlb_addr; + int prot = 0; + int ret; + + domain = find_domain(dev); + if (WARN_ON(dir == DMA_NONE || !domain)) + return DMA_MAPPING_ERROR; + + iommu = domain_get_iommu(domain); + if (WARN_ON(!iommu)) + return DMA_MAPPING_ERROR; + + nrpages = aligned_nrpages(0, size); + iova_pfn = intel_alloc_iova(dev, domain, + dma_to_mm_pfn(nrpages), dma_mask); + if (!iova_pfn) + return DMA_MAPPING_ERROR; + + /* + * Check if DMAR supports zero-length reads on write only + * mappings.. + */ + if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || + !cap_zlr(iommu->cap)) + prot |= DMA_PTE_READ; + if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) + prot |= DMA_PTE_WRITE; + + /* + * If both the physical buffer start address and size are + * page aligned, we don't need to use a bounce page. + */ + if (!IS_ALIGNED(paddr | size, VTD_PAGE_SIZE)) { + tlb_addr = swiotlb_tbl_map_single(dev, + __phys_to_dma(dev, io_tlb_start), + paddr, size, aligned_size, dir, attrs); + if (tlb_addr == DMA_MAPPING_ERROR) { + goto swiotlb_error; + } else { + /* Cleanup the padding area. */ + void *padding_start = phys_to_virt(tlb_addr); + size_t padding_size = aligned_size; + + if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) && + (dir == DMA_TO_DEVICE || + dir == DMA_BIDIRECTIONAL)) { + padding_start += size; + padding_size -= size; + } + + memset(padding_start, 0, padding_size); + } + } else { + tlb_addr = paddr; + } + + ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova_pfn), + tlb_addr >> VTD_PAGE_SHIFT, nrpages, prot); + if (ret) + goto mapping_error; + + trace_bounce_map_single(dev, iova_pfn << PAGE_SHIFT, paddr, size); + + return (phys_addr_t)iova_pfn << PAGE_SHIFT; + +mapping_error: + if (is_swiotlb_buffer(tlb_addr)) + swiotlb_tbl_unmap_single(dev, tlb_addr, size, + aligned_size, dir, attrs); +swiotlb_error: + free_iova_fast(&domain->iovad, iova_pfn, dma_to_mm_pfn(nrpages)); + dev_err(dev, "Device bounce map: %zx@%llx dir %d --- failed\n", + size, (unsigned long long)paddr, dir); + + return DMA_MAPPING_ERROR; +} + +static void +bounce_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size, + enum dma_data_direction dir, unsigned long attrs) +{ + size_t aligned_size = ALIGN(size, VTD_PAGE_SIZE); + struct dmar_domain *domain; + phys_addr_t tlb_addr; + + domain = find_domain(dev); + if (WARN_ON(!domain)) + return; + + tlb_addr = intel_iommu_iova_to_phys(&domain->domain, dev_addr); + if (WARN_ON(!tlb_addr)) + return; + + intel_unmap(dev, dev_addr, size); + if (is_swiotlb_buffer(tlb_addr)) + swiotlb_tbl_unmap_single(dev, tlb_addr, size, + aligned_size, dir, attrs); + + trace_bounce_unmap_single(dev, dev_addr, size); +} + +static dma_addr_t +bounce_map_page(struct device *dev, struct page *page, unsigned long offset, + size_t size, enum dma_data_direction dir, unsigned long attrs) +{ + return bounce_map_single(dev, page_to_phys(page) + offset, + size, dir, attrs, *dev->dma_mask); +} + +static dma_addr_t +bounce_map_resource(struct device *dev, phys_addr_t phys_addr, size_t size, + enum dma_data_direction dir, unsigned long attrs) +{ + return bounce_map_single(dev, phys_addr, size, + dir, attrs, *dev->dma_mask); +} + +static void +bounce_unmap_page(struct device *dev, dma_addr_t dev_addr, size_t size, + enum dma_data_direction dir, unsigned long attrs) +{ + bounce_unmap_single(dev, dev_addr, size, dir, attrs); +} + +static void +bounce_unmap_resource(struct device *dev, dma_addr_t dev_addr, size_t size, + enum dma_data_direction dir, unsigned long attrs) +{ + bounce_unmap_single(dev, dev_addr, size, dir, attrs); +} + +static void +bounce_unmap_sg(struct device *dev, struct scatterlist *sglist, int nelems, + enum dma_data_direction dir, unsigned long attrs) +{ + struct scatterlist *sg; + int i; + + for_each_sg(sglist, sg, nelems, i) + bounce_unmap_page(dev, sg->dma_address, + sg_dma_len(sg), dir, attrs); +} + +static int +bounce_map_sg(struct device *dev, struct scatterlist *sglist, int nelems, + enum dma_data_direction dir, unsigned long attrs) +{ + int i; + struct scatterlist *sg; + + for_each_sg(sglist, sg, nelems, i) { + sg->dma_address = bounce_map_page(dev, sg_page(sg), + sg->offset, sg->length, + dir, attrs); + if (sg->dma_address == DMA_MAPPING_ERROR) + goto out_unmap; + sg_dma_len(sg) = sg->length; + } + + return nelems; + +out_unmap: + bounce_unmap_sg(dev, sglist, i, dir, attrs | DMA_ATTR_SKIP_CPU_SYNC); + return 0; +} + +static void +bounce_sync_single_for_cpu(struct device *dev, dma_addr_t addr, + size_t size, enum dma_data_direction dir) +{ + bounce_sync_single(dev, addr, size, dir, SYNC_FOR_CPU); +} + +static void +bounce_sync_single_for_device(struct device *dev, dma_addr_t addr, + size_t size, enum dma_data_direction dir) +{ + bounce_sync_single(dev, addr, size, dir, SYNC_FOR_DEVICE); +} + +static void +bounce_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist, + int nelems, enum dma_data_direction dir) +{ + struct scatterlist *sg; + int i; + + for_each_sg(sglist, sg, nelems, i) + bounce_sync_single(dev, sg_dma_address(sg), + sg_dma_len(sg), dir, SYNC_FOR_CPU); +} + +static void +bounce_sync_sg_for_device(struct device *dev, struct scatterlist *sglist, + int nelems, enum dma_data_direction dir) +{ + struct scatterlist *sg; + int i; + + for_each_sg(sglist, sg, nelems, i) + bounce_sync_single(dev, sg_dma_address(sg), + sg_dma_len(sg), dir, SYNC_FOR_DEVICE); +} + +static const struct dma_map_ops bounce_dma_ops = { + .alloc = intel_alloc_coherent, + .free = intel_free_coherent, + .map_sg = bounce_map_sg, + .unmap_sg = bounce_unmap_sg, + .map_page = bounce_map_page, + .unmap_page = bounce_unmap_page, + .sync_single_for_cpu = bounce_sync_single_for_cpu, + .sync_single_for_device = bounce_sync_single_for_device, + .sync_sg_for_cpu = bounce_sync_sg_for_cpu, + .sync_sg_for_device = bounce_sync_sg_for_device, + .map_resource = bounce_map_resource, + .unmap_resource = bounce_unmap_resource, + .dma_supported = dma_direct_supported, +}; + static inline int iommu_domain_cache_init(void) { int ret = 0; @@ -4569,22 +4833,20 @@ const struct attribute_group *intel_iommu_groups[] = { NULL, }; -static int __init platform_optin_force_iommu(void) +static inline bool has_untrusted_dev(void) { struct pci_dev *pdev = NULL; - bool has_untrusted_dev = false; - if (!dmar_platform_optin() || no_platform_optin) - return 0; + for_each_pci_dev(pdev) + if (pdev->untrusted) + return true; - for_each_pci_dev(pdev) { - if (pdev->untrusted) { - has_untrusted_dev = true; - break; - } - } + return false; +} - if (!has_untrusted_dev) +static int __init platform_optin_force_iommu(void) +{ + if (!dmar_platform_optin() || no_platform_optin || !has_untrusted_dev()) return 0; if (no_iommu || dmar_disabled) @@ -4598,9 +4860,6 @@ static int __init platform_optin_force_iommu(void) iommu_identity_mapping |= IDENTMAP_ALL; dmar_disabled = 0; -#if defined(CONFIG_X86) && defined(CONFIG_SWIOTLB) - swiotlb = 0; -#endif no_iommu = 0; return 1; @@ -4740,7 +4999,14 @@ int __init intel_iommu_init(void) up_write(&dmar_global_lock); #if defined(CONFIG_X86) && defined(CONFIG_SWIOTLB) - swiotlb = 0; + /* + * If the system has no untrusted device or the user has decided + * to disable the bounce page mechanisms, we don't need swiotlb. + * Mark this and the pre-allocated bounce pages will be released + * later. + */ + if (!has_untrusted_dev() || intel_no_bounce) + swiotlb = 0; #endif dma_ops = &intel_dma_ops; @@ -5204,7 +5470,8 @@ static int intel_iommu_map(struct iommu_domain *domain, } static size_t intel_iommu_unmap(struct iommu_domain *domain, - unsigned long iova, size_t size) + unsigned long iova, size_t size, + struct iommu_iotlb_gather *gather) { struct dmar_domain *dmar_domain = to_dmar_domain(domain); struct page *freelist = NULL; @@ -5360,6 +5627,11 @@ static int intel_iommu_add_device(struct device *dev) } } + if (device_needs_bounce(dev)) { + dev_info(dev, "Use Intel IOMMU bounce page dma_ops\n"); + set_dma_ops(dev, &bounce_dma_ops); + } + return 0; } @@ -5377,6 +5649,9 @@ static void intel_iommu_remove_device(struct device *dev) iommu_group_remove_device(dev); iommu_device_unlink(&iommu->iommu, dev); + + if (device_needs_bounce(dev)) + set_dma_ops(dev, NULL); } static void intel_iommu_get_resv_regions(struct device *device, @@ -5690,20 +5965,46 @@ const struct iommu_ops intel_iommu_ops = { .pgsize_bitmap = INTEL_IOMMU_PGSIZES, }; -static void quirk_iommu_g4x_gfx(struct pci_dev *dev) +static void quirk_iommu_igfx(struct pci_dev *dev) { - /* G4x/GM45 integrated gfx dmar support is totally busted. */ pci_info(dev, "Disabling IOMMU for graphics on this chipset\n"); dmar_map_gfx = 0; } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_g4x_gfx); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_g4x_gfx); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_g4x_gfx); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_g4x_gfx); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_g4x_gfx); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_g4x_gfx); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_g4x_gfx); +/* G4x/GM45 integrated gfx dmar support is totally busted. */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_igfx); + +/* Broadwell igfx malfunctions with dmar */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1606, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x160B, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x160E, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1602, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x160A, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x160D, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1616, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x161B, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x161E, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1612, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x161A, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x161D, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1626, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x162B, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x162E, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1622, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x162A, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x162D, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1636, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163B, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163E, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); static void quirk_iommu_rwbf(struct pci_dev *dev) { diff --git a/drivers/iommu/intel-trace.c b/drivers/iommu/intel-trace.c new file mode 100644 index 0000000000000000000000000000000000000000..bfb6a6e37a88b426b638f7ec82d0dacd4d4bdf9e --- /dev/null +++ b/drivers/iommu/intel-trace.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel IOMMU trace support + * + * Copyright (C) 2019 Intel Corporation + * + * Author: Lu Baolu + */ + +#include +#include + +#define CREATE_TRACE_POINTS +#include diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index 4786ca061e31fd6e0ad6cb3328f66e89306e064a..81e43c1df7ecb5fdd769e2dc1bc4c265f37fec1f 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -376,13 +376,13 @@ static int set_msi_sid_cb(struct pci_dev *pdev, u16 alias, void *opaque) { struct set_msi_sid_data *data = opaque; + if (data->count == 0 || PCI_BUS_NUM(alias) == PCI_BUS_NUM(data->alias)) + data->busmatch_count++; + data->pdev = pdev; data->alias = alias; data->count++; - if (PCI_BUS_NUM(alias) == pdev->bus->number) - data->busmatch_count++; - return 0; } diff --git a/drivers/iommu/io-pgtable-arm-v7s.c b/drivers/iommu/io-pgtable-arm-v7s.c index 0fc8dfab2abf57d51418ba17f5d470eb6292b49a..4cb394937700ce4e0f5ff7133042f6e9f5f6a38c 100644 --- a/drivers/iommu/io-pgtable-arm-v7s.c +++ b/drivers/iommu/io-pgtable-arm-v7s.c @@ -112,7 +112,9 @@ #define ARM_V7S_TEX_MASK 0x7 #define ARM_V7S_ATTR_TEX(val) (((val) & ARM_V7S_TEX_MASK) << ARM_V7S_TEX_SHIFT) -#define ARM_V7S_ATTR_MTK_4GB BIT(9) /* MTK extend it for 4GB mode */ +/* MediaTek extend the two bits for PA 32bit/33bit */ +#define ARM_V7S_ATTR_MTK_PA_BIT32 BIT(9) +#define ARM_V7S_ATTR_MTK_PA_BIT33 BIT(4) /* *well, except for TEX on level 2 large pages, of course :( */ #define ARM_V7S_CONT_PAGE_TEX_SHIFT 6 @@ -169,18 +171,62 @@ struct arm_v7s_io_pgtable { spinlock_t split_lock; }; +static bool arm_v7s_pte_is_cont(arm_v7s_iopte pte, int lvl); + static dma_addr_t __arm_v7s_dma_addr(void *pages) { return (dma_addr_t)virt_to_phys(pages); } -static arm_v7s_iopte *iopte_deref(arm_v7s_iopte pte, int lvl) +static bool arm_v7s_is_mtk_enabled(struct io_pgtable_cfg *cfg) +{ + return IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT) && + (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_EXT); +} + +static arm_v7s_iopte paddr_to_iopte(phys_addr_t paddr, int lvl, + struct io_pgtable_cfg *cfg) +{ + arm_v7s_iopte pte = paddr & ARM_V7S_LVL_MASK(lvl); + + if (!arm_v7s_is_mtk_enabled(cfg)) + return pte; + + if (paddr & BIT_ULL(32)) + pte |= ARM_V7S_ATTR_MTK_PA_BIT32; + if (paddr & BIT_ULL(33)) + pte |= ARM_V7S_ATTR_MTK_PA_BIT33; + return pte; +} + +static phys_addr_t iopte_to_paddr(arm_v7s_iopte pte, int lvl, + struct io_pgtable_cfg *cfg) { + arm_v7s_iopte mask; + phys_addr_t paddr; + if (ARM_V7S_PTE_IS_TABLE(pte, lvl)) - pte &= ARM_V7S_TABLE_MASK; + mask = ARM_V7S_TABLE_MASK; + else if (arm_v7s_pte_is_cont(pte, lvl)) + mask = ARM_V7S_LVL_MASK(lvl) * ARM_V7S_CONT_PAGES; else - pte &= ARM_V7S_LVL_MASK(lvl); - return phys_to_virt(pte); + mask = ARM_V7S_LVL_MASK(lvl); + + paddr = pte & mask; + if (!arm_v7s_is_mtk_enabled(cfg)) + return paddr; + + if (pte & ARM_V7S_ATTR_MTK_PA_BIT32) + paddr |= BIT_ULL(32); + if (pte & ARM_V7S_ATTR_MTK_PA_BIT33) + paddr |= BIT_ULL(33); + return paddr; +} + +static arm_v7s_iopte *iopte_deref(arm_v7s_iopte pte, int lvl, + struct arm_v7s_io_pgtable *data) +{ + return phys_to_virt(iopte_to_paddr(pte, lvl, &data->iop.cfg)); } static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp, @@ -295,9 +341,6 @@ static arm_v7s_iopte arm_v7s_prot_to_pte(int prot, int lvl, if (lvl == 1 && (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS)) pte |= ARM_V7S_ATTR_NS_SECTION; - if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_4GB) - pte |= ARM_V7S_ATTR_MTK_4GB; - return pte; } @@ -362,7 +405,8 @@ static bool arm_v7s_pte_is_cont(arm_v7s_iopte pte, int lvl) return false; } -static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *, unsigned long, +static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *, + struct iommu_iotlb_gather *, unsigned long, size_t, int, arm_v7s_iopte *); static int arm_v7s_init_pte(struct arm_v7s_io_pgtable *data, @@ -383,7 +427,7 @@ static int arm_v7s_init_pte(struct arm_v7s_io_pgtable *data, size_t sz = ARM_V7S_BLOCK_SIZE(lvl); tblp = ptep - ARM_V7S_LVL_IDX(iova, lvl); - if (WARN_ON(__arm_v7s_unmap(data, iova + i * sz, + if (WARN_ON(__arm_v7s_unmap(data, NULL, iova + i * sz, sz, lvl, tblp) != sz)) return -EINVAL; } else if (ptep[i]) { @@ -396,7 +440,7 @@ static int arm_v7s_init_pte(struct arm_v7s_io_pgtable *data, if (num_entries > 1) pte = arm_v7s_pte_to_cont(pte, lvl); - pte |= paddr & ARM_V7S_LVL_MASK(lvl); + pte |= paddr_to_iopte(paddr, lvl, cfg); __arm_v7s_set_pte(ptep, pte, num_entries, cfg); return 0; @@ -462,7 +506,7 @@ static int __arm_v7s_map(struct arm_v7s_io_pgtable *data, unsigned long iova, } if (ARM_V7S_PTE_IS_TABLE(pte, lvl)) { - cptep = iopte_deref(pte, lvl); + cptep = iopte_deref(pte, lvl, data); } else if (pte) { /* We require an unmap first */ WARN_ON(!selftest_running); @@ -484,7 +528,8 @@ static int arm_v7s_map(struct io_pgtable_ops *ops, unsigned long iova, if (!(prot & (IOMMU_READ | IOMMU_WRITE))) return 0; - if (WARN_ON(upper_32_bits(iova) || upper_32_bits(paddr))) + if (WARN_ON(iova >= (1ULL << data->iop.cfg.ias) || + paddr >= (1ULL << data->iop.cfg.oas))) return -ERANGE; ret = __arm_v7s_map(data, iova, paddr, size, prot, 1, data->pgd); @@ -493,9 +538,8 @@ static int arm_v7s_map(struct io_pgtable_ops *ops, unsigned long iova, * a chance for anything to kick off a table walk for the new iova. */ if (iop->cfg.quirks & IO_PGTABLE_QUIRK_TLBI_ON_MAP) { - io_pgtable_tlb_add_flush(iop, iova, size, - ARM_V7S_BLOCK_SIZE(2), false); - io_pgtable_tlb_sync(iop); + io_pgtable_tlb_flush_walk(iop, iova, size, + ARM_V7S_BLOCK_SIZE(2)); } else { wmb(); } @@ -512,7 +556,8 @@ static void arm_v7s_free_pgtable(struct io_pgtable *iop) arm_v7s_iopte pte = data->pgd[i]; if (ARM_V7S_PTE_IS_TABLE(pte, 1)) - __arm_v7s_free_table(iopte_deref(pte, 1), 2, data); + __arm_v7s_free_table(iopte_deref(pte, 1, data), + 2, data); } __arm_v7s_free_table(data->pgd, 1, data); kmem_cache_destroy(data->l2_tables); @@ -541,12 +586,12 @@ static arm_v7s_iopte arm_v7s_split_cont(struct arm_v7s_io_pgtable *data, __arm_v7s_pte_sync(ptep, ARM_V7S_CONT_PAGES, &iop->cfg); size *= ARM_V7S_CONT_PAGES; - io_pgtable_tlb_add_flush(iop, iova, size, size, true); - io_pgtable_tlb_sync(iop); + io_pgtable_tlb_flush_leaf(iop, iova, size, size); return pte; } static size_t arm_v7s_split_blk_unmap(struct arm_v7s_io_pgtable *data, + struct iommu_iotlb_gather *gather, unsigned long iova, size_t size, arm_v7s_iopte blk_pte, arm_v7s_iopte *ptep) @@ -582,16 +627,16 @@ static size_t arm_v7s_split_blk_unmap(struct arm_v7s_io_pgtable *data, if (!ARM_V7S_PTE_IS_TABLE(pte, 1)) return 0; - tablep = iopte_deref(pte, 1); - return __arm_v7s_unmap(data, iova, size, 2, tablep); + tablep = iopte_deref(pte, 1, data); + return __arm_v7s_unmap(data, gather, iova, size, 2, tablep); } - io_pgtable_tlb_add_flush(&data->iop, iova, size, size, true); - io_pgtable_tlb_sync(&data->iop); + io_pgtable_tlb_add_page(&data->iop, gather, iova, size); return size; } static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *data, + struct iommu_iotlb_gather *gather, unsigned long iova, size_t size, int lvl, arm_v7s_iopte *ptep) { @@ -638,10 +683,9 @@ static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *data, for (i = 0; i < num_entries; i++) { if (ARM_V7S_PTE_IS_TABLE(pte[i], lvl)) { /* Also flush any partial walks */ - io_pgtable_tlb_add_flush(iop, iova, blk_size, - ARM_V7S_BLOCK_SIZE(lvl + 1), false); - io_pgtable_tlb_sync(iop); - ptep = iopte_deref(pte[i], lvl); + io_pgtable_tlb_flush_walk(iop, iova, blk_size, + ARM_V7S_BLOCK_SIZE(lvl + 1)); + ptep = iopte_deref(pte[i], lvl, data); __arm_v7s_free_table(ptep, lvl + 1, data); } else if (iop->cfg.quirks & IO_PGTABLE_QUIRK_NON_STRICT) { /* @@ -651,8 +695,7 @@ static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *data, */ smp_wmb(); } else { - io_pgtable_tlb_add_flush(iop, iova, blk_size, - blk_size, true); + io_pgtable_tlb_add_page(iop, gather, iova, blk_size); } iova += blk_size; } @@ -662,23 +705,24 @@ static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *data, * Insert a table at the next level to map the old region, * minus the part we want to unmap */ - return arm_v7s_split_blk_unmap(data, iova, size, pte[0], ptep); + return arm_v7s_split_blk_unmap(data, gather, iova, size, pte[0], + ptep); } /* Keep on walkin' */ - ptep = iopte_deref(pte[0], lvl); - return __arm_v7s_unmap(data, iova, size, lvl + 1, ptep); + ptep = iopte_deref(pte[0], lvl, data); + return __arm_v7s_unmap(data, gather, iova, size, lvl + 1, ptep); } static size_t arm_v7s_unmap(struct io_pgtable_ops *ops, unsigned long iova, - size_t size) + size_t size, struct iommu_iotlb_gather *gather) { struct arm_v7s_io_pgtable *data = io_pgtable_ops_to_data(ops); if (WARN_ON(upper_32_bits(iova))) return 0; - return __arm_v7s_unmap(data, iova, size, 1, data->pgd); + return __arm_v7s_unmap(data, gather, iova, size, 1, data->pgd); } static phys_addr_t arm_v7s_iova_to_phys(struct io_pgtable_ops *ops, @@ -692,7 +736,7 @@ static phys_addr_t arm_v7s_iova_to_phys(struct io_pgtable_ops *ops, do { ptep += ARM_V7S_LVL_IDX(iova, ++lvl); pte = READ_ONCE(*ptep); - ptep = iopte_deref(pte, lvl); + ptep = iopte_deref(pte, lvl, data); } while (ARM_V7S_PTE_IS_TABLE(pte, lvl)); if (!ARM_V7S_PTE_IS_VALID(pte)) @@ -701,7 +745,7 @@ static phys_addr_t arm_v7s_iova_to_phys(struct io_pgtable_ops *ops, mask = ARM_V7S_LVL_MASK(lvl); if (arm_v7s_pte_is_cont(pte, lvl)) mask *= ARM_V7S_CONT_PAGES; - return (pte & mask) | (iova & ~mask); + return iopte_to_paddr(pte, lvl, &data->iop.cfg) | (iova & ~mask); } static struct io_pgtable *arm_v7s_alloc_pgtable(struct io_pgtable_cfg *cfg, @@ -709,18 +753,21 @@ static struct io_pgtable *arm_v7s_alloc_pgtable(struct io_pgtable_cfg *cfg, { struct arm_v7s_io_pgtable *data; - if (cfg->ias > ARM_V7S_ADDR_BITS || cfg->oas > ARM_V7S_ADDR_BITS) + if (cfg->ias > ARM_V7S_ADDR_BITS) + return NULL; + + if (cfg->oas > (arm_v7s_is_mtk_enabled(cfg) ? 34 : ARM_V7S_ADDR_BITS)) return NULL; if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS | IO_PGTABLE_QUIRK_NO_PERMS | IO_PGTABLE_QUIRK_TLBI_ON_MAP | - IO_PGTABLE_QUIRK_ARM_MTK_4GB | + IO_PGTABLE_QUIRK_ARM_MTK_EXT | IO_PGTABLE_QUIRK_NON_STRICT)) return NULL; /* If ARM_MTK_4GB is enabled, the NO_PERMS is also expected. */ - if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_4GB && + if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_EXT && !(cfg->quirks & IO_PGTABLE_QUIRK_NO_PERMS)) return NULL; @@ -806,22 +853,24 @@ static void dummy_tlb_flush_all(void *cookie) WARN_ON(cookie != cfg_cookie); } -static void dummy_tlb_add_flush(unsigned long iova, size_t size, - size_t granule, bool leaf, void *cookie) +static void dummy_tlb_flush(unsigned long iova, size_t size, size_t granule, + void *cookie) { WARN_ON(cookie != cfg_cookie); WARN_ON(!(size & cfg_cookie->pgsize_bitmap)); } -static void dummy_tlb_sync(void *cookie) +static void dummy_tlb_add_page(struct iommu_iotlb_gather *gather, + unsigned long iova, size_t granule, void *cookie) { - WARN_ON(cookie != cfg_cookie); + dummy_tlb_flush(iova, granule, granule, cookie); } -static const struct iommu_gather_ops dummy_tlb_ops = { +static const struct iommu_flush_ops dummy_tlb_ops = { .tlb_flush_all = dummy_tlb_flush_all, - .tlb_add_flush = dummy_tlb_add_flush, - .tlb_sync = dummy_tlb_sync, + .tlb_flush_walk = dummy_tlb_flush, + .tlb_flush_leaf = dummy_tlb_flush, + .tlb_add_page = dummy_tlb_add_page, }; #define __FAIL(ops) ({ \ @@ -896,7 +945,7 @@ static int __init arm_v7s_do_selftests(void) size = 1UL << __ffs(cfg.pgsize_bitmap); while (i < loopnr) { iova_start = i * SZ_16M; - if (ops->unmap(ops, iova_start + size, size) != size) + if (ops->unmap(ops, iova_start + size, size, NULL) != size) return __FAIL(ops); /* Remap of partial unmap */ @@ -914,7 +963,7 @@ static int __init arm_v7s_do_selftests(void) for_each_set_bit(i, &cfg.pgsize_bitmap, BITS_PER_LONG) { size = 1UL << i; - if (ops->unmap(ops, iova, size) != size) + if (ops->unmap(ops, iova, size, NULL) != size) return __FAIL(ops); if (ops->iova_to_phys(ops, iova + 42)) diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 161a7d56264d0c26b7297930c0d843df674dd7bc..4c91359057c53d906ee5496396e28595c2153905 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -290,6 +289,7 @@ static void __arm_lpae_set_pte(arm_lpae_iopte *ptep, arm_lpae_iopte pte, } static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, + struct iommu_iotlb_gather *gather, unsigned long iova, size_t size, int lvl, arm_lpae_iopte *ptep); @@ -335,8 +335,10 @@ static int arm_lpae_init_pte(struct arm_lpae_io_pgtable *data, size_t sz = ARM_LPAE_BLOCK_SIZE(lvl, data); tblp = ptep - ARM_LPAE_LVL_IDX(iova, lvl, data); - if (WARN_ON(__arm_lpae_unmap(data, iova, sz, lvl, tblp) != sz)) + if (__arm_lpae_unmap(data, NULL, iova, sz, lvl, tblp) != sz) { + WARN_ON(1); return -EINVAL; + } } __arm_lpae_init_pte(data, paddr, prot, lvl, ptep); @@ -537,6 +539,7 @@ static void arm_lpae_free_pgtable(struct io_pgtable *iop) } static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data, + struct iommu_iotlb_gather *gather, unsigned long iova, size_t size, arm_lpae_iopte blk_pte, int lvl, arm_lpae_iopte *ptep) @@ -582,15 +585,15 @@ static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data, tablep = iopte_deref(pte, data); } else if (unmap_idx >= 0) { - io_pgtable_tlb_add_flush(&data->iop, iova, size, size, true); - io_pgtable_tlb_sync(&data->iop); + io_pgtable_tlb_add_page(&data->iop, gather, iova, size); return size; } - return __arm_lpae_unmap(data, iova, size, lvl, tablep); + return __arm_lpae_unmap(data, gather, iova, size, lvl, tablep); } static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, + struct iommu_iotlb_gather *gather, unsigned long iova, size_t size, int lvl, arm_lpae_iopte *ptep) { @@ -612,9 +615,8 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, if (!iopte_leaf(pte, lvl, iop->fmt)) { /* Also flush any partial walks */ - io_pgtable_tlb_add_flush(iop, iova, size, - ARM_LPAE_GRANULE(data), false); - io_pgtable_tlb_sync(iop); + io_pgtable_tlb_flush_walk(iop, iova, size, + ARM_LPAE_GRANULE(data)); ptep = iopte_deref(pte, data); __arm_lpae_free_pgtable(data, lvl + 1, ptep); } else if (iop->cfg.quirks & IO_PGTABLE_QUIRK_NON_STRICT) { @@ -625,7 +627,7 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, */ smp_wmb(); } else { - io_pgtable_tlb_add_flush(iop, iova, size, size, true); + io_pgtable_tlb_add_page(iop, gather, iova, size); } return size; @@ -634,17 +636,17 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, * Insert a table at the next level to map the old region, * minus the part we want to unmap */ - return arm_lpae_split_blk_unmap(data, iova, size, pte, + return arm_lpae_split_blk_unmap(data, gather, iova, size, pte, lvl + 1, ptep); } /* Keep on walkin' */ ptep = iopte_deref(pte, data); - return __arm_lpae_unmap(data, iova, size, lvl + 1, ptep); + return __arm_lpae_unmap(data, gather, iova, size, lvl + 1, ptep); } static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova, - size_t size) + size_t size, struct iommu_iotlb_gather *gather) { struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); arm_lpae_iopte *ptep = data->pgd; @@ -653,7 +655,7 @@ static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova, if (WARN_ON(iova >= (1ULL << data->iop.cfg.ias))) return 0; - return __arm_lpae_unmap(data, iova, size, lvl, ptep); + return __arm_lpae_unmap(data, gather, iova, size, lvl, ptep); } static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops, @@ -1070,22 +1072,24 @@ static void dummy_tlb_flush_all(void *cookie) WARN_ON(cookie != cfg_cookie); } -static void dummy_tlb_add_flush(unsigned long iova, size_t size, - size_t granule, bool leaf, void *cookie) +static void dummy_tlb_flush(unsigned long iova, size_t size, size_t granule, + void *cookie) { WARN_ON(cookie != cfg_cookie); WARN_ON(!(size & cfg_cookie->pgsize_bitmap)); } -static void dummy_tlb_sync(void *cookie) +static void dummy_tlb_add_page(struct iommu_iotlb_gather *gather, + unsigned long iova, size_t granule, void *cookie) { - WARN_ON(cookie != cfg_cookie); + dummy_tlb_flush(iova, granule, granule, cookie); } -static const struct iommu_gather_ops dummy_tlb_ops __initconst = { +static const struct iommu_flush_ops dummy_tlb_ops __initconst = { .tlb_flush_all = dummy_tlb_flush_all, - .tlb_add_flush = dummy_tlb_add_flush, - .tlb_sync = dummy_tlb_sync, + .tlb_flush_walk = dummy_tlb_flush, + .tlb_flush_leaf = dummy_tlb_flush, + .tlb_add_page = dummy_tlb_add_page, }; static void __init arm_lpae_dump_ops(struct io_pgtable_ops *ops) @@ -1168,7 +1172,7 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg) /* Partial unmap */ size = 1UL << __ffs(cfg->pgsize_bitmap); - if (ops->unmap(ops, SZ_1G + size, size) != size) + if (ops->unmap(ops, SZ_1G + size, size, NULL) != size) return __FAIL(ops, i); /* Remap of partial unmap */ @@ -1183,7 +1187,7 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg) for_each_set_bit(j, &cfg->pgsize_bitmap, BITS_PER_LONG) { size = 1UL << j; - if (ops->unmap(ops, iova, size) != size) + if (ops->unmap(ops, iova, size, NULL) != size) return __FAIL(ops, i); if (ops->iova_to_phys(ops, iova + 42)) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 0c674d80c37fd5768fa62296f6be72f97c5dd245..d658c7c6a2ab0a6d3d6fcffdb89edf03f9b9bda2 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -26,12 +26,10 @@ static struct kset *iommu_group_kset; static DEFINE_IDA(iommu_group_ida); -#ifdef CONFIG_IOMMU_DEFAULT_PASSTHROUGH -static unsigned int iommu_def_domain_type = IOMMU_DOMAIN_IDENTITY; -#else -static unsigned int iommu_def_domain_type = IOMMU_DOMAIN_DMA; -#endif + +static unsigned int iommu_def_domain_type __read_mostly; static bool iommu_dma_strict __read_mostly = true; +static u32 iommu_cmd_line __read_mostly; struct iommu_group { struct kobject kobj; @@ -68,6 +66,18 @@ static const char * const iommu_group_resv_type_string[] = { [IOMMU_RESV_SW_MSI] = "msi", }; +#define IOMMU_CMD_LINE_DMA_API BIT(0) + +static void iommu_set_cmd_line_dma_api(void) +{ + iommu_cmd_line |= IOMMU_CMD_LINE_DMA_API; +} + +static bool iommu_cmd_line_dma_api(void) +{ + return !!(iommu_cmd_line & IOMMU_CMD_LINE_DMA_API); +} + #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \ struct iommu_group_attribute iommu_group_attr_##_name = \ __ATTR(_name, _mode, _show, _store) @@ -80,12 +90,55 @@ struct iommu_group_attribute iommu_group_attr_##_name = \ static LIST_HEAD(iommu_device_list); static DEFINE_SPINLOCK(iommu_device_lock); +/* + * Use a function instead of an array here because the domain-type is a + * bit-field, so an array would waste memory. + */ +static const char *iommu_domain_type_str(unsigned int t) +{ + switch (t) { + case IOMMU_DOMAIN_BLOCKED: + return "Blocked"; + case IOMMU_DOMAIN_IDENTITY: + return "Passthrough"; + case IOMMU_DOMAIN_UNMANAGED: + return "Unmanaged"; + case IOMMU_DOMAIN_DMA: + return "Translated"; + default: + return "Unknown"; + } +} + +static int __init iommu_subsys_init(void) +{ + bool cmd_line = iommu_cmd_line_dma_api(); + + if (!cmd_line) { + if (IS_ENABLED(CONFIG_IOMMU_DEFAULT_PASSTHROUGH)) + iommu_set_default_passthrough(false); + else + iommu_set_default_translated(false); + + if (iommu_default_passthrough() && mem_encrypt_active()) { + pr_info("Memory encryption detected - Disabling default IOMMU Passthrough\n"); + iommu_set_default_translated(false); + } + } + + pr_info("Default domain type: %s %s\n", + iommu_domain_type_str(iommu_def_domain_type), + cmd_line ? "(set via kernel command line)" : ""); + + return 0; +} +subsys_initcall(iommu_subsys_init); + int iommu_device_register(struct iommu_device *iommu) { spin_lock(&iommu_device_lock); list_add_tail(&iommu->list, &iommu_device_list); spin_unlock(&iommu_device_lock); - return 0; } @@ -165,7 +218,11 @@ static int __init iommu_set_def_domain_type(char *str) if (ret) return ret; - iommu_def_domain_type = pt ? IOMMU_DOMAIN_IDENTITY : IOMMU_DOMAIN_DMA; + if (pt) + iommu_set_default_passthrough(true); + else + iommu_set_default_translated(true); + return 0; } early_param("iommu.passthrough", iommu_set_def_domain_type); @@ -229,60 +286,58 @@ static ssize_t iommu_group_show_name(struct iommu_group *group, char *buf) * @new: new region to insert * @regions: list of regions * - * The new element is sorted by address with respect to the other - * regions of the same type. In case it overlaps with another - * region of the same type, regions are merged. In case it - * overlaps with another region of different type, regions are - * not merged. + * Elements are sorted by start address and overlapping segments + * of the same type are merged. */ -static int iommu_insert_resv_region(struct iommu_resv_region *new, - struct list_head *regions) +int iommu_insert_resv_region(struct iommu_resv_region *new, + struct list_head *regions) { - struct iommu_resv_region *region; - phys_addr_t start = new->start; - phys_addr_t end = new->start + new->length - 1; - struct list_head *pos = regions->next; - - while (pos != regions) { - struct iommu_resv_region *entry = - list_entry(pos, struct iommu_resv_region, list); - phys_addr_t a = entry->start; - phys_addr_t b = entry->start + entry->length - 1; - int type = entry->type; - - if (end < a) { - goto insert; - } else if (start > b) { - pos = pos->next; - } else if ((start >= a) && (end <= b)) { - if (new->type == type) - return 0; - else - pos = pos->next; + struct iommu_resv_region *iter, *tmp, *nr, *top; + LIST_HEAD(stack); + + nr = iommu_alloc_resv_region(new->start, new->length, + new->prot, new->type); + if (!nr) + return -ENOMEM; + + /* First add the new element based on start address sorting */ + list_for_each_entry(iter, regions, list) { + if (nr->start < iter->start || + (nr->start == iter->start && nr->type <= iter->type)) + break; + } + list_add_tail(&nr->list, &iter->list); + + /* Merge overlapping segments of type nr->type in @regions, if any */ + list_for_each_entry_safe(iter, tmp, regions, list) { + phys_addr_t top_end, iter_end = iter->start + iter->length - 1; + + /* no merge needed on elements of different types than @nr */ + if (iter->type != nr->type) { + list_move_tail(&iter->list, &stack); + continue; + } + + /* look for the last stack element of same type as @iter */ + list_for_each_entry_reverse(top, &stack, list) + if (top->type == iter->type) + goto check_overlap; + + list_move_tail(&iter->list, &stack); + continue; + +check_overlap: + top_end = top->start + top->length - 1; + + if (iter->start > top_end + 1) { + list_move_tail(&iter->list, &stack); } else { - if (new->type == type) { - phys_addr_t new_start = min(a, start); - phys_addr_t new_end = max(b, end); - int ret; - - list_del(&entry->list); - entry->start = new_start; - entry->length = new_end - new_start + 1; - ret = iommu_insert_resv_region(entry, regions); - kfree(entry); - return ret; - } else { - pos = pos->next; - } + top->length = max(top_end, iter_end) - top->start + 1; + list_del(&iter->list); + kfree(iter); } } -insert: - region = iommu_alloc_resv_region(new->start, new->length, - new->prot, new->type); - if (!region) - return -ENOMEM; - - list_add_tail(®ion->list, pos); + list_splice(&stack, regions); return 0; } @@ -1862,7 +1917,7 @@ EXPORT_SYMBOL_GPL(iommu_map); static size_t __iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size, - bool sync) + struct iommu_iotlb_gather *iotlb_gather) { const struct iommu_ops *ops = domain->ops; size_t unmapped_page, unmapped = 0; @@ -1899,13 +1954,10 @@ static size_t __iommu_unmap(struct iommu_domain *domain, while (unmapped < size) { size_t pgsize = iommu_pgsize(domain, iova, size - unmapped); - unmapped_page = ops->unmap(domain, iova, pgsize); + unmapped_page = ops->unmap(domain, iova, pgsize, iotlb_gather); if (!unmapped_page) break; - if (sync && ops->iotlb_range_add) - ops->iotlb_range_add(domain, iova, pgsize); - pr_debug("unmapped: iova 0x%lx size 0x%zx\n", iova, unmapped_page); @@ -1913,9 +1965,6 @@ static size_t __iommu_unmap(struct iommu_domain *domain, unmapped += unmapped_page; } - if (sync && ops->iotlb_sync) - ops->iotlb_sync(domain); - trace_unmap(orig_iova, size, unmapped); return unmapped; } @@ -1923,14 +1972,22 @@ static size_t __iommu_unmap(struct iommu_domain *domain, size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) { - return __iommu_unmap(domain, iova, size, true); + struct iommu_iotlb_gather iotlb_gather; + size_t ret; + + iommu_iotlb_gather_init(&iotlb_gather); + ret = __iommu_unmap(domain, iova, size, &iotlb_gather); + iommu_tlb_sync(domain, &iotlb_gather); + + return ret; } EXPORT_SYMBOL_GPL(iommu_unmap); size_t iommu_unmap_fast(struct iommu_domain *domain, - unsigned long iova, size_t size) + unsigned long iova, size_t size, + struct iommu_iotlb_gather *iotlb_gather) { - return __iommu_unmap(domain, iova, size, false); + return __iommu_unmap(domain, iova, size, iotlb_gather); } EXPORT_SYMBOL_GPL(iommu_unmap_fast); @@ -2143,7 +2200,6 @@ request_default_domain_for_dev(struct device *dev, unsigned long type) mutex_lock(&group->mutex); - /* Check if the default domain is already direct mapped */ ret = 0; if (group->default_domain && group->default_domain->type == type) goto out; @@ -2153,7 +2209,6 @@ request_default_domain_for_dev(struct device *dev, unsigned long type) if (iommu_group_device_count(group) != 1) goto out; - /* Allocate a direct mapped domain */ ret = -ENOMEM; domain = __iommu_domain_alloc(dev->bus, type); if (!domain) @@ -2168,7 +2223,7 @@ request_default_domain_for_dev(struct device *dev, unsigned long type) iommu_group_create_direct_mappings(group, dev); - /* Make the direct mapped domain the default for this group */ + /* Make the domain the default for this group */ if (group->default_domain) iommu_domain_free(group->default_domain); group->default_domain = domain; @@ -2196,6 +2251,28 @@ int iommu_request_dma_domain_for_dev(struct device *dev) return request_default_domain_for_dev(dev, IOMMU_DOMAIN_DMA); } +void iommu_set_default_passthrough(bool cmd_line) +{ + if (cmd_line) + iommu_set_cmd_line_dma_api(); + + iommu_def_domain_type = IOMMU_DOMAIN_IDENTITY; +} + +void iommu_set_default_translated(bool cmd_line) +{ + if (cmd_line) + iommu_set_cmd_line_dma_api(); + + iommu_def_domain_type = IOMMU_DOMAIN_DMA; +} + +bool iommu_default_passthrough(void) +{ + return iommu_def_domain_type == IOMMU_DOMAIN_IDENTITY; +} +EXPORT_SYMBOL_GPL(iommu_default_passthrough); + const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode) { const struct iommu_ops *ops = NULL; diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index 3e1a8a6755723a927a7942a7429ab7e6c19a0027..41c605b0058f9615c2dbdd83f1de2404a9b1d255 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -577,7 +577,9 @@ void queue_iova(struct iova_domain *iovad, spin_unlock_irqrestore(&fq->lock, flags); - if (atomic_cmpxchg(&iovad->fq_timer_on, 0, 1) == 0) + /* Avoid false sharing as much as possible. */ + if (!atomic_read(&iovad->fq_timer_on) && + !atomic_cmpxchg(&iovad->fq_timer_on, 0, 1)) mod_timer(&iovad->fq_timer, jiffies + msecs_to_jiffies(IOVA_FQ_TIMEOUT)); } diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index ad0098c0c87c7544f18b70c0bd9dc43913ca0478..9da8309f71708f213f91dbe99374681e0da3f652 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -49,6 +49,7 @@ struct ipmmu_features { bool setup_imbuscr; bool twobit_imttbcr_sl0; bool reserved_context; + bool cache_snoop; }; struct ipmmu_vmsa_device { @@ -115,45 +116,44 @@ static struct ipmmu_vmsa_device *to_ipmmu(struct device *dev) #define IMTTBCR 0x0008 #define IMTTBCR_EAE (1 << 31) #define IMTTBCR_PMB (1 << 30) -#define IMTTBCR_SH1_NON_SHAREABLE (0 << 28) -#define IMTTBCR_SH1_OUTER_SHAREABLE (2 << 28) -#define IMTTBCR_SH1_INNER_SHAREABLE (3 << 28) -#define IMTTBCR_SH1_MASK (3 << 28) -#define IMTTBCR_ORGN1_NC (0 << 26) -#define IMTTBCR_ORGN1_WB_WA (1 << 26) -#define IMTTBCR_ORGN1_WT (2 << 26) -#define IMTTBCR_ORGN1_WB (3 << 26) -#define IMTTBCR_ORGN1_MASK (3 << 26) -#define IMTTBCR_IRGN1_NC (0 << 24) -#define IMTTBCR_IRGN1_WB_WA (1 << 24) -#define IMTTBCR_IRGN1_WT (2 << 24) -#define IMTTBCR_IRGN1_WB (3 << 24) -#define IMTTBCR_IRGN1_MASK (3 << 24) +#define IMTTBCR_SH1_NON_SHAREABLE (0 << 28) /* R-Car Gen2 only */ +#define IMTTBCR_SH1_OUTER_SHAREABLE (2 << 28) /* R-Car Gen2 only */ +#define IMTTBCR_SH1_INNER_SHAREABLE (3 << 28) /* R-Car Gen2 only */ +#define IMTTBCR_SH1_MASK (3 << 28) /* R-Car Gen2 only */ +#define IMTTBCR_ORGN1_NC (0 << 26) /* R-Car Gen2 only */ +#define IMTTBCR_ORGN1_WB_WA (1 << 26) /* R-Car Gen2 only */ +#define IMTTBCR_ORGN1_WT (2 << 26) /* R-Car Gen2 only */ +#define IMTTBCR_ORGN1_WB (3 << 26) /* R-Car Gen2 only */ +#define IMTTBCR_ORGN1_MASK (3 << 26) /* R-Car Gen2 only */ +#define IMTTBCR_IRGN1_NC (0 << 24) /* R-Car Gen2 only */ +#define IMTTBCR_IRGN1_WB_WA (1 << 24) /* R-Car Gen2 only */ +#define IMTTBCR_IRGN1_WT (2 << 24) /* R-Car Gen2 only */ +#define IMTTBCR_IRGN1_WB (3 << 24) /* R-Car Gen2 only */ +#define IMTTBCR_IRGN1_MASK (3 << 24) /* R-Car Gen2 only */ #define IMTTBCR_TSZ1_MASK (7 << 16) #define IMTTBCR_TSZ1_SHIFT 16 -#define IMTTBCR_SH0_NON_SHAREABLE (0 << 12) -#define IMTTBCR_SH0_OUTER_SHAREABLE (2 << 12) -#define IMTTBCR_SH0_INNER_SHAREABLE (3 << 12) -#define IMTTBCR_SH0_MASK (3 << 12) -#define IMTTBCR_ORGN0_NC (0 << 10) -#define IMTTBCR_ORGN0_WB_WA (1 << 10) -#define IMTTBCR_ORGN0_WT (2 << 10) -#define IMTTBCR_ORGN0_WB (3 << 10) -#define IMTTBCR_ORGN0_MASK (3 << 10) -#define IMTTBCR_IRGN0_NC (0 << 8) -#define IMTTBCR_IRGN0_WB_WA (1 << 8) -#define IMTTBCR_IRGN0_WT (2 << 8) -#define IMTTBCR_IRGN0_WB (3 << 8) -#define IMTTBCR_IRGN0_MASK (3 << 8) +#define IMTTBCR_SH0_NON_SHAREABLE (0 << 12) /* R-Car Gen2 only */ +#define IMTTBCR_SH0_OUTER_SHAREABLE (2 << 12) /* R-Car Gen2 only */ +#define IMTTBCR_SH0_INNER_SHAREABLE (3 << 12) /* R-Car Gen2 only */ +#define IMTTBCR_SH0_MASK (3 << 12) /* R-Car Gen2 only */ +#define IMTTBCR_ORGN0_NC (0 << 10) /* R-Car Gen2 only */ +#define IMTTBCR_ORGN0_WB_WA (1 << 10) /* R-Car Gen2 only */ +#define IMTTBCR_ORGN0_WT (2 << 10) /* R-Car Gen2 only */ +#define IMTTBCR_ORGN0_WB (3 << 10) /* R-Car Gen2 only */ +#define IMTTBCR_ORGN0_MASK (3 << 10) /* R-Car Gen2 only */ +#define IMTTBCR_IRGN0_NC (0 << 8) /* R-Car Gen2 only */ +#define IMTTBCR_IRGN0_WB_WA (1 << 8) /* R-Car Gen2 only */ +#define IMTTBCR_IRGN0_WT (2 << 8) /* R-Car Gen2 only */ +#define IMTTBCR_IRGN0_WB (3 << 8) /* R-Car Gen2 only */ +#define IMTTBCR_IRGN0_MASK (3 << 8) /* R-Car Gen2 only */ +#define IMTTBCR_SL0_TWOBIT_LVL_3 (0 << 6) /* R-Car Gen3 only */ +#define IMTTBCR_SL0_TWOBIT_LVL_2 (1 << 6) /* R-Car Gen3 only */ +#define IMTTBCR_SL0_TWOBIT_LVL_1 (2 << 6) /* R-Car Gen3 only */ #define IMTTBCR_SL0_LVL_2 (0 << 4) #define IMTTBCR_SL0_LVL_1 (1 << 4) #define IMTTBCR_TSZ0_MASK (7 << 0) #define IMTTBCR_TSZ0_SHIFT O -#define IMTTBCR_SL0_TWOBIT_LVL_3 (0 << 6) -#define IMTTBCR_SL0_TWOBIT_LVL_2 (1 << 6) -#define IMTTBCR_SL0_TWOBIT_LVL_1 (2 << 6) - #define IMBUSCR 0x000c #define IMBUSCR_DVM (1 << 2) #define IMBUSCR_BUSSEL_SYS (0 << 0) @@ -361,16 +361,16 @@ static void ipmmu_tlb_flush_all(void *cookie) ipmmu_tlb_invalidate(domain); } -static void ipmmu_tlb_add_flush(unsigned long iova, size_t size, - size_t granule, bool leaf, void *cookie) +static void ipmmu_tlb_flush(unsigned long iova, size_t size, + size_t granule, void *cookie) { - /* The hardware doesn't support selective TLB flush. */ + ipmmu_tlb_flush_all(cookie); } -static const struct iommu_gather_ops ipmmu_gather_ops = { +static const struct iommu_flush_ops ipmmu_flush_ops = { .tlb_flush_all = ipmmu_tlb_flush_all, - .tlb_add_flush = ipmmu_tlb_add_flush, - .tlb_sync = ipmmu_tlb_flush_all, + .tlb_flush_walk = ipmmu_tlb_flush, + .tlb_flush_leaf = ipmmu_tlb_flush, }; /* ----------------------------------------------------------------------------- @@ -422,17 +422,19 @@ static void ipmmu_domain_setup_context(struct ipmmu_vmsa_domain *domain) /* * TTBCR - * We use long descriptors with inner-shareable WBWA tables and allocate - * the whole 32-bit VA space to TTBR0. + * We use long descriptors and allocate the whole 32-bit VA space to + * TTBR0. */ if (domain->mmu->features->twobit_imttbcr_sl0) tmp = IMTTBCR_SL0_TWOBIT_LVL_1; else tmp = IMTTBCR_SL0_LVL_1; - ipmmu_ctx_write_root(domain, IMTTBCR, IMTTBCR_EAE | - IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA | - IMTTBCR_IRGN0_WB_WA | tmp); + if (domain->mmu->features->cache_snoop) + tmp |= IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA | + IMTTBCR_IRGN0_WB_WA; + + ipmmu_ctx_write_root(domain, IMTTBCR, IMTTBCR_EAE | tmp); /* MAIR0 */ ipmmu_ctx_write_root(domain, IMMAIR0, @@ -480,7 +482,7 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) domain->cfg.pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K; domain->cfg.ias = 32; domain->cfg.oas = 40; - domain->cfg.tlb = &ipmmu_gather_ops; + domain->cfg.tlb = &ipmmu_flush_ops; domain->io_domain.geometry.aperture_end = DMA_BIT_MASK(32); domain->io_domain.geometry.force_aperture = true; /* @@ -733,14 +735,14 @@ static int ipmmu_map(struct iommu_domain *io_domain, unsigned long iova, } static size_t ipmmu_unmap(struct iommu_domain *io_domain, unsigned long iova, - size_t size) + size_t size, struct iommu_iotlb_gather *gather) { struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); - return domain->iop->unmap(domain->iop, iova, size); + return domain->iop->unmap(domain->iop, iova, size, gather); } -static void ipmmu_iotlb_sync(struct iommu_domain *io_domain) +static void ipmmu_flush_iotlb_all(struct iommu_domain *io_domain) { struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); @@ -748,6 +750,12 @@ static void ipmmu_iotlb_sync(struct iommu_domain *io_domain) ipmmu_tlb_flush_all(domain); } +static void ipmmu_iotlb_sync(struct iommu_domain *io_domain, + struct iommu_iotlb_gather *gather) +{ + ipmmu_flush_iotlb_all(io_domain); +} + static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain, dma_addr_t iova) { @@ -957,7 +965,7 @@ static const struct iommu_ops ipmmu_ops = { .detach_dev = ipmmu_detach_device, .map = ipmmu_map, .unmap = ipmmu_unmap, - .flush_iotlb_all = ipmmu_iotlb_sync, + .flush_iotlb_all = ipmmu_flush_iotlb_all, .iotlb_sync = ipmmu_iotlb_sync, .iova_to_phys = ipmmu_iova_to_phys, .add_device = ipmmu_add_device, @@ -988,6 +996,7 @@ static const struct ipmmu_features ipmmu_features_default = { .setup_imbuscr = true, .twobit_imttbcr_sl0 = false, .reserved_context = false, + .cache_snoop = true, }; static const struct ipmmu_features ipmmu_features_rcar_gen3 = { @@ -998,6 +1007,7 @@ static const struct ipmmu_features ipmmu_features_rcar_gen3 = { .setup_imbuscr = false, .twobit_imttbcr_sl0 = true, .reserved_context = true, + .cache_snoop = false, }; static const struct of_device_id ipmmu_of_ids[] = { diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c index b25e2eb9e038d9460a94b487d66c718693f3c8cc..be99d408cf35dc7b8d26612b979d4c584de64c4a 100644 --- a/drivers/iommu/msm_iommu.c +++ b/drivers/iommu/msm_iommu.c @@ -168,20 +168,29 @@ static void __flush_iotlb_range(unsigned long iova, size_t size, return; } -static void __flush_iotlb_sync(void *cookie) +static void __flush_iotlb_walk(unsigned long iova, size_t size, + size_t granule, void *cookie) { - /* - * Nothing is needed here, the barrier to guarantee - * completion of the tlb sync operation is implicitly - * taken care when the iommu client does a writel before - * kick starting the other master. - */ + __flush_iotlb_range(iova, size, granule, false, cookie); +} + +static void __flush_iotlb_leaf(unsigned long iova, size_t size, + size_t granule, void *cookie) +{ + __flush_iotlb_range(iova, size, granule, true, cookie); } -static const struct iommu_gather_ops msm_iommu_gather_ops = { +static void __flush_iotlb_page(struct iommu_iotlb_gather *gather, + unsigned long iova, size_t granule, void *cookie) +{ + __flush_iotlb_range(iova, granule, granule, true, cookie); +} + +static const struct iommu_flush_ops msm_iommu_flush_ops = { .tlb_flush_all = __flush_iotlb, - .tlb_add_flush = __flush_iotlb_range, - .tlb_sync = __flush_iotlb_sync, + .tlb_flush_walk = __flush_iotlb_walk, + .tlb_flush_leaf = __flush_iotlb_leaf, + .tlb_add_page = __flush_iotlb_page, }; static int msm_iommu_alloc_ctx(unsigned long *map, int start, int end) @@ -345,7 +354,7 @@ static int msm_iommu_domain_config(struct msm_priv *priv) .pgsize_bitmap = msm_iommu_ops.pgsize_bitmap, .ias = 32, .oas = 32, - .tlb = &msm_iommu_gather_ops, + .tlb = &msm_iommu_flush_ops, .iommu_dev = priv->dev, }; @@ -509,13 +518,13 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long iova, } static size_t msm_iommu_unmap(struct iommu_domain *domain, unsigned long iova, - size_t len) + size_t len, struct iommu_iotlb_gather *gather) { struct msm_priv *priv = to_msm_priv(domain); unsigned long flags; spin_lock_irqsave(&priv->pgtlock, flags); - len = priv->iop->unmap(priv->iop, iova, len); + len = priv->iop->unmap(priv->iop, iova, len, gather); spin_unlock_irqrestore(&priv->pgtlock, flags); return len; @@ -691,6 +700,13 @@ static struct iommu_ops msm_iommu_ops = { .detach_dev = msm_iommu_detach_dev, .map = msm_iommu_map, .unmap = msm_iommu_unmap, + /* + * Nothing is needed here, the barrier to guarantee + * completion of the tlb sync operation is implicitly + * taken care when the iommu client does a writel before + * kick starting the other master. + */ + .iotlb_sync = NULL, .iova_to_phys = msm_iommu_iova_to_phys, .add_device = msm_iommu_add_device, .remove_device = msm_iommu_remove_device, @@ -750,7 +766,6 @@ static int msm_iommu_probe(struct platform_device *pdev) iommu->irq = platform_get_irq(pdev, 0); if (iommu->irq < 0) { - dev_err(iommu->dev, "could not get iommu irq\n"); ret = -ENODEV; goto fail; } diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index 82e4be4dfdaf84d17cc662fb7db2708cbeaf197c..67a483c1a9357c7629d569ae1456ca8181b92c89 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -28,6 +28,7 @@ #include "mtk_iommu.h" #define REG_MMU_PT_BASE_ADDR 0x000 +#define MMU_PT_ADDR_MASK GENMASK(31, 7) #define REG_MMU_INVALIDATE 0x020 #define F_ALL_INVLD 0x2 @@ -44,12 +45,9 @@ #define REG_MMU_DCM_DIS 0x050 #define REG_MMU_CTRL_REG 0x110 +#define F_MMU_TF_PROT_TO_PROGRAM_ADDR (2 << 4) #define F_MMU_PREFETCH_RT_REPLACE_MOD BIT(4) -#define F_MMU_TF_PROTECT_SEL_SHIFT(data) \ - ((data)->m4u_plat == M4U_MT2712 ? 4 : 5) -/* It's named by F_MMU_TF_PROT_SEL in mt2712. */ -#define F_MMU_TF_PROTECT_SEL(prot, data) \ - (((prot) & 0x3) << F_MMU_TF_PROTECT_SEL_SHIFT(data)) +#define F_MMU_TF_PROT_TO_PROGRAM_ADDR_MT8173 (2 << 5) #define REG_MMU_IVRP_PADDR 0x114 @@ -66,26 +64,32 @@ #define F_INT_CLR_BIT BIT(12) #define REG_MMU_INT_MAIN_CONTROL 0x124 -#define F_INT_TRANSLATION_FAULT BIT(0) -#define F_INT_MAIN_MULTI_HIT_FAULT BIT(1) -#define F_INT_INVALID_PA_FAULT BIT(2) -#define F_INT_ENTRY_REPLACEMENT_FAULT BIT(3) -#define F_INT_TLB_MISS_FAULT BIT(4) -#define F_INT_MISS_TRANSACTION_FIFO_FAULT BIT(5) -#define F_INT_PRETETCH_TRANSATION_FIFO_FAULT BIT(6) + /* mmu0 | mmu1 */ +#define F_INT_TRANSLATION_FAULT (BIT(0) | BIT(7)) +#define F_INT_MAIN_MULTI_HIT_FAULT (BIT(1) | BIT(8)) +#define F_INT_INVALID_PA_FAULT (BIT(2) | BIT(9)) +#define F_INT_ENTRY_REPLACEMENT_FAULT (BIT(3) | BIT(10)) +#define F_INT_TLB_MISS_FAULT (BIT(4) | BIT(11)) +#define F_INT_MISS_TRANSACTION_FIFO_FAULT (BIT(5) | BIT(12)) +#define F_INT_PRETETCH_TRANSATION_FIFO_FAULT (BIT(6) | BIT(13)) #define REG_MMU_CPE_DONE 0x12C #define REG_MMU_FAULT_ST1 0x134 +#define F_REG_MMU0_FAULT_MASK GENMASK(6, 0) +#define F_REG_MMU1_FAULT_MASK GENMASK(13, 7) -#define REG_MMU_FAULT_VA 0x13c +#define REG_MMU0_FAULT_VA 0x13c #define F_MMU_FAULT_VA_WRITE_BIT BIT(1) #define F_MMU_FAULT_VA_LAYER_BIT BIT(0) -#define REG_MMU_INVLD_PA 0x140 -#define REG_MMU_INT_ID 0x150 -#define F_MMU0_INT_ID_LARB_ID(a) (((a) >> 7) & 0x7) -#define F_MMU0_INT_ID_PORT_ID(a) (((a) >> 2) & 0x1f) +#define REG_MMU0_INVLD_PA 0x140 +#define REG_MMU1_FAULT_VA 0x144 +#define REG_MMU1_INVLD_PA 0x148 +#define REG_MMU0_INT_ID 0x150 +#define REG_MMU1_INT_ID 0x154 +#define F_MMU_INT_ID_LARB_ID(a) (((a) >> 7) & 0x7) +#define F_MMU_INT_ID_PORT_ID(a) (((a) >> 2) & 0x1f) #define MTK_PROTECT_PA_ALIGN 128 @@ -107,6 +111,30 @@ struct mtk_iommu_domain { static const struct iommu_ops mtk_iommu_ops; +/* + * In M4U 4GB mode, the physical address is remapped as below: + * + * CPU Physical address: + * ==================== + * + * 0 1G 2G 3G 4G 5G + * |---A---|---B---|---C---|---D---|---E---| + * +--I/O--+------------Memory-------------+ + * + * IOMMU output physical address: + * ============================= + * + * 4G 5G 6G 7G 8G + * |---E---|---B---|---C---|---D---| + * +------------Memory-------------+ + * + * The Region 'A'(I/O) can NOT be mapped by M4U; For Region 'B'/'C'/'D', the + * bit32 of the CPU physical address always is needed to set, and for Region + * 'E', the CPU physical address keep as is. + * Additionally, The iommu consumers always use the CPU phyiscal address. + */ +#define MTK_IOMMU_4GB_MODE_REMAP_BASE 0x140000000UL + static LIST_HEAD(m4ulist); /* List all the M4U HWs */ #define for_each_m4u(data) list_for_each_entry(data, &m4ulist, list) @@ -188,10 +216,32 @@ static void mtk_iommu_tlb_sync(void *cookie) } } -static const struct iommu_gather_ops mtk_iommu_gather_ops = { +static void mtk_iommu_tlb_flush_walk(unsigned long iova, size_t size, + size_t granule, void *cookie) +{ + mtk_iommu_tlb_add_flush_nosync(iova, size, granule, false, cookie); + mtk_iommu_tlb_sync(cookie); +} + +static void mtk_iommu_tlb_flush_leaf(unsigned long iova, size_t size, + size_t granule, void *cookie) +{ + mtk_iommu_tlb_add_flush_nosync(iova, size, granule, true, cookie); + mtk_iommu_tlb_sync(cookie); +} + +static void mtk_iommu_tlb_flush_page_nosync(struct iommu_iotlb_gather *gather, + unsigned long iova, size_t granule, + void *cookie) +{ + mtk_iommu_tlb_add_flush_nosync(iova, granule, granule, true, cookie); +} + +static const struct iommu_flush_ops mtk_iommu_flush_ops = { .tlb_flush_all = mtk_iommu_tlb_flush_all, - .tlb_add_flush = mtk_iommu_tlb_add_flush_nosync, - .tlb_sync = mtk_iommu_tlb_sync, + .tlb_flush_walk = mtk_iommu_tlb_flush_walk, + .tlb_flush_leaf = mtk_iommu_tlb_flush_leaf, + .tlb_add_page = mtk_iommu_tlb_flush_page_nosync, }; static irqreturn_t mtk_iommu_isr(int irq, void *dev_id) @@ -204,13 +254,21 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id) /* Read error info from registers */ int_state = readl_relaxed(data->base + REG_MMU_FAULT_ST1); - fault_iova = readl_relaxed(data->base + REG_MMU_FAULT_VA); + if (int_state & F_REG_MMU0_FAULT_MASK) { + regval = readl_relaxed(data->base + REG_MMU0_INT_ID); + fault_iova = readl_relaxed(data->base + REG_MMU0_FAULT_VA); + fault_pa = readl_relaxed(data->base + REG_MMU0_INVLD_PA); + } else { + regval = readl_relaxed(data->base + REG_MMU1_INT_ID); + fault_iova = readl_relaxed(data->base + REG_MMU1_FAULT_VA); + fault_pa = readl_relaxed(data->base + REG_MMU1_INVLD_PA); + } layer = fault_iova & F_MMU_FAULT_VA_LAYER_BIT; write = fault_iova & F_MMU_FAULT_VA_WRITE_BIT; - fault_pa = readl_relaxed(data->base + REG_MMU_INVLD_PA); - regval = readl_relaxed(data->base + REG_MMU_INT_ID); - fault_larb = F_MMU0_INT_ID_LARB_ID(regval); - fault_port = F_MMU0_INT_ID_PORT_ID(regval); + fault_larb = F_MMU_INT_ID_LARB_ID(regval); + fault_port = F_MMU_INT_ID_PORT_ID(regval); + + fault_larb = data->plat_data->larbid_remap[fault_larb]; if (report_iommu_fault(&dom->domain, data->dev, fault_iova, write ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ)) { @@ -242,7 +300,7 @@ static void mtk_iommu_config(struct mtk_iommu_data *data, for (i = 0; i < fwspec->num_ids; ++i) { larbid = MTK_M4U_TO_LARB(fwspec->ids[i]); portid = MTK_M4U_TO_PORT(fwspec->ids[i]); - larb_mmu = &data->smi_imu.larb_imu[larbid]; + larb_mmu = &data->larb_imu[larbid]; dev_dbg(dev, "%s iommu port: %d\n", enable ? "enable" : "disable", portid); @@ -263,17 +321,15 @@ static int mtk_iommu_domain_finalise(struct mtk_iommu_domain *dom) dom->cfg = (struct io_pgtable_cfg) { .quirks = IO_PGTABLE_QUIRK_ARM_NS | IO_PGTABLE_QUIRK_NO_PERMS | - IO_PGTABLE_QUIRK_TLBI_ON_MAP, + IO_PGTABLE_QUIRK_TLBI_ON_MAP | + IO_PGTABLE_QUIRK_ARM_MTK_EXT, .pgsize_bitmap = mtk_iommu_ops.pgsize_bitmap, .ias = 32, - .oas = 32, - .tlb = &mtk_iommu_gather_ops, + .oas = 34, + .tlb = &mtk_iommu_flush_ops, .iommu_dev = data->dev, }; - if (data->enable_4GB) - dom->cfg.quirks |= IO_PGTABLE_QUIRK_ARM_MTK_4GB; - dom->iop = alloc_io_pgtable_ops(ARM_V7S, &dom->cfg, data); if (!dom->iop) { dev_err(data->dev, "Failed to alloc io pgtable\n"); @@ -336,7 +392,7 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain, /* Update the pgtable base address register of the M4U HW */ if (!data->m4u_dom) { data->m4u_dom = dom; - writel(dom->cfg.arm_v7s_cfg.ttbr[0], + writel(dom->cfg.arm_v7s_cfg.ttbr[0] & MMU_PT_ADDR_MASK, data->base + REG_MMU_PT_BASE_ADDR); } @@ -359,32 +415,43 @@ static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, size_t size, int prot) { struct mtk_iommu_domain *dom = to_mtk_domain(domain); + struct mtk_iommu_data *data = mtk_iommu_get_m4u_data(); unsigned long flags; int ret; + /* The "4GB mode" M4U physically can not use the lower remap of Dram. */ + if (data->enable_4GB) + paddr |= BIT_ULL(32); + spin_lock_irqsave(&dom->pgtlock, flags); - ret = dom->iop->map(dom->iop, iova, paddr & DMA_BIT_MASK(32), - size, prot); + ret = dom->iop->map(dom->iop, iova, paddr, size, prot); spin_unlock_irqrestore(&dom->pgtlock, flags); return ret; } static size_t mtk_iommu_unmap(struct iommu_domain *domain, - unsigned long iova, size_t size) + unsigned long iova, size_t size, + struct iommu_iotlb_gather *gather) { struct mtk_iommu_domain *dom = to_mtk_domain(domain); unsigned long flags; size_t unmapsz; spin_lock_irqsave(&dom->pgtlock, flags); - unmapsz = dom->iop->unmap(dom->iop, iova, size); + unmapsz = dom->iop->unmap(dom->iop, iova, size, gather); spin_unlock_irqrestore(&dom->pgtlock, flags); return unmapsz; } -static void mtk_iommu_iotlb_sync(struct iommu_domain *domain) +static void mtk_iommu_flush_iotlb_all(struct iommu_domain *domain) +{ + mtk_iommu_tlb_sync(mtk_iommu_get_m4u_data()); +} + +static void mtk_iommu_iotlb_sync(struct iommu_domain *domain, + struct iommu_iotlb_gather *gather) { mtk_iommu_tlb_sync(mtk_iommu_get_m4u_data()); } @@ -401,8 +468,8 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain, pa = dom->iop->iova_to_phys(dom->iop, iova); spin_unlock_irqrestore(&dom->pgtlock, flags); - if (data->enable_4GB) - pa |= BIT_ULL(32); + if (data->enable_4GB && pa >= MTK_IOMMU_4GB_MODE_REMAP_BASE) + pa &= ~BIT_ULL(32); return pa; } @@ -490,7 +557,7 @@ static const struct iommu_ops mtk_iommu_ops = { .detach_dev = mtk_iommu_detach_device, .map = mtk_iommu_map, .unmap = mtk_iommu_unmap, - .flush_iotlb_all = mtk_iommu_iotlb_sync, + .flush_iotlb_all = mtk_iommu_flush_iotlb_all, .iotlb_sync = mtk_iommu_iotlb_sync, .iova_to_phys = mtk_iommu_iova_to_phys, .add_device = mtk_iommu_add_device, @@ -511,9 +578,11 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data *data) return ret; } - regval = F_MMU_TF_PROTECT_SEL(2, data); - if (data->m4u_plat == M4U_MT8173) - regval |= F_MMU_PREFETCH_RT_REPLACE_MOD; + if (data->plat_data->m4u_plat == M4U_MT8173) + regval = F_MMU_PREFETCH_RT_REPLACE_MOD | + F_MMU_TF_PROT_TO_PROGRAM_ADDR_MT8173; + else + regval = F_MMU_TF_PROT_TO_PROGRAM_ADDR; writel_relaxed(regval, data->base + REG_MMU_CTRL_REG); regval = F_L2_MULIT_HIT_EN | @@ -533,14 +602,14 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data *data) F_INT_PRETETCH_TRANSATION_FIFO_FAULT; writel_relaxed(regval, data->base + REG_MMU_INT_MAIN_CONTROL); - if (data->m4u_plat == M4U_MT8173) + if (data->plat_data->m4u_plat == M4U_MT8173) regval = (data->protect_base >> 1) | (data->enable_4GB << 31); else regval = lower_32_bits(data->protect_base) | upper_32_bits(data->protect_base); writel_relaxed(regval, data->base + REG_MMU_IVRP_PADDR); - if (data->enable_4GB && data->m4u_plat != M4U_MT8173) { + if (data->enable_4GB && data->plat_data->has_vld_pa_rng) { /* * If 4GB mode is enabled, the validate PA range is from * 0x1_0000_0000 to 0x1_ffff_ffff. here record bit[32:30]. @@ -550,8 +619,7 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data *data) } writel_relaxed(0, data->base + REG_MMU_DCM_DIS); - /* It's MISC control register whose default value is ok except mt8173.*/ - if (data->m4u_plat == M4U_MT8173) + if (data->plat_data->reset_axi) writel_relaxed(0, data->base + REG_MMU_STANDARD_AXI_MODE); if (devm_request_irq(data->dev, data->irq, mtk_iommu_isr, 0, @@ -584,7 +652,7 @@ static int mtk_iommu_probe(struct platform_device *pdev) if (!data) return -ENOMEM; data->dev = dev; - data->m4u_plat = (enum mtk_iommu_plat)of_device_get_match_data(dev); + data->plat_data = of_device_get_match_data(dev); /* Protect memory. HW will access here while translation fault.*/ protect = devm_kzalloc(dev, MTK_PROTECT_PA_ALIGN * 2, GFP_KERNEL); @@ -594,6 +662,8 @@ static int mtk_iommu_probe(struct platform_device *pdev) /* Whether the current dram is over 4GB */ data->enable_4GB = !!(max_pfn > (BIT_ULL(32) >> PAGE_SHIFT)); + if (!data->plat_data->has_4gb_mode) + data->enable_4GB = false; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); data->base = devm_ioremap_resource(dev, res); @@ -605,15 +675,16 @@ static int mtk_iommu_probe(struct platform_device *pdev) if (data->irq < 0) return data->irq; - data->bclk = devm_clk_get(dev, "bclk"); - if (IS_ERR(data->bclk)) - return PTR_ERR(data->bclk); + if (data->plat_data->has_bclk) { + data->bclk = devm_clk_get(dev, "bclk"); + if (IS_ERR(data->bclk)) + return PTR_ERR(data->bclk); + } larb_nr = of_count_phandle_with_args(dev->of_node, "mediatek,larbs", NULL); if (larb_nr < 0) return larb_nr; - data->smi_imu.larb_nr = larb_nr; for (i = 0; i < larb_nr; i++) { struct device_node *larbnode; @@ -638,7 +709,7 @@ static int mtk_iommu_probe(struct platform_device *pdev) of_node_put(larbnode); return -EPROBE_DEFER; } - data->smi_imu.larb_imu[id].dev = &plarbdev->dev; + data->larb_imu[id].dev = &plarbdev->dev; component_match_add_release(dev, &match, release_of, compare_of, larbnode); @@ -699,6 +770,7 @@ static int __maybe_unused mtk_iommu_suspend(struct device *dev) reg->int_control0 = readl_relaxed(base + REG_MMU_INT_CONTROL0); reg->int_main_control = readl_relaxed(base + REG_MMU_INT_MAIN_CONTROL); reg->ivrp_paddr = readl_relaxed(base + REG_MMU_IVRP_PADDR); + reg->vld_pa_rng = readl_relaxed(base + REG_MMU_VLD_PA_RNG); clk_disable_unprepare(data->bclk); return 0; } @@ -707,6 +779,7 @@ static int __maybe_unused mtk_iommu_resume(struct device *dev) { struct mtk_iommu_data *data = dev_get_drvdata(dev); struct mtk_iommu_suspend_reg *reg = &data->reg; + struct mtk_iommu_domain *m4u_dom = data->m4u_dom; void __iomem *base = data->base; int ret; @@ -722,8 +795,9 @@ static int __maybe_unused mtk_iommu_resume(struct device *dev) writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL0); writel_relaxed(reg->int_main_control, base + REG_MMU_INT_MAIN_CONTROL); writel_relaxed(reg->ivrp_paddr, base + REG_MMU_IVRP_PADDR); - if (data->m4u_dom) - writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0], + writel_relaxed(reg->vld_pa_rng, base + REG_MMU_VLD_PA_RNG); + if (m4u_dom) + writel(m4u_dom->cfg.arm_v7s_cfg.ttbr[0] & MMU_PT_ADDR_MASK, base + REG_MMU_PT_BASE_ADDR); return 0; } @@ -732,9 +806,32 @@ static const struct dev_pm_ops mtk_iommu_pm_ops = { SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_iommu_suspend, mtk_iommu_resume) }; +static const struct mtk_iommu_plat_data mt2712_data = { + .m4u_plat = M4U_MT2712, + .has_4gb_mode = true, + .has_bclk = true, + .has_vld_pa_rng = true, + .larbid_remap = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, +}; + +static const struct mtk_iommu_plat_data mt8173_data = { + .m4u_plat = M4U_MT8173, + .has_4gb_mode = true, + .has_bclk = true, + .reset_axi = true, + .larbid_remap = {0, 1, 2, 3, 4, 5}, /* Linear mapping. */ +}; + +static const struct mtk_iommu_plat_data mt8183_data = { + .m4u_plat = M4U_MT8183, + .reset_axi = true, + .larbid_remap = {0, 4, 5, 6, 7, 2, 3, 1}, +}; + static const struct of_device_id mtk_iommu_of_ids[] = { - { .compatible = "mediatek,mt2712-m4u", .data = (void *)M4U_MT2712}, - { .compatible = "mediatek,mt8173-m4u", .data = (void *)M4U_MT8173}, + { .compatible = "mediatek,mt2712-m4u", .data = &mt2712_data}, + { .compatible = "mediatek,mt8173-m4u", .data = &mt8173_data}, + { .compatible = "mediatek,mt8183-m4u", .data = &mt8183_data}, {} }; diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h index 59337323db58e2039b948ae5faca3440533215e1..fc0f16eabacdfa2340677a6db385ffa8fd94c5db 100644 --- a/drivers/iommu/mtk_iommu.h +++ b/drivers/iommu/mtk_iommu.h @@ -24,12 +24,25 @@ struct mtk_iommu_suspend_reg { u32 int_control0; u32 int_main_control; u32 ivrp_paddr; + u32 vld_pa_rng; }; enum mtk_iommu_plat { M4U_MT2701, M4U_MT2712, M4U_MT8173, + M4U_MT8183, +}; + +struct mtk_iommu_plat_data { + enum mtk_iommu_plat m4u_plat; + bool has_4gb_mode; + + /* HW will use the EMI clock if there isn't the "bclk". */ + bool has_bclk; + bool has_vld_pa_rng; + bool reset_axi; + unsigned char larbid_remap[MTK_LARB_NR_MAX]; }; struct mtk_iommu_domain; @@ -43,14 +56,14 @@ struct mtk_iommu_data { struct mtk_iommu_suspend_reg reg; struct mtk_iommu_domain *m4u_dom; struct iommu_group *m4u_group; - struct mtk_smi_iommu smi_imu; /* SMI larb iommu info */ bool enable_4GB; bool tlb_flush_active; struct iommu_device iommu; - enum mtk_iommu_plat m4u_plat; + const struct mtk_iommu_plat_data *plat_data; struct list_head list; + struct mtk_smi_larb_iommu larb_imu[MTK_LARB_NR_MAX]; }; static inline int compare_of(struct device *dev, void *data) @@ -67,14 +80,14 @@ static inline int mtk_iommu_bind(struct device *dev) { struct mtk_iommu_data *data = dev_get_drvdata(dev); - return component_bind_all(dev, &data->smi_imu); + return component_bind_all(dev, &data->larb_imu); } static inline void mtk_iommu_unbind(struct device *dev) { struct mtk_iommu_data *data = dev_get_drvdata(dev); - component_unbind_all(dev, &data->smi_imu); + component_unbind_all(dev, &data->larb_imu); } #endif diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index abeeac488372c8e5735f8838deb0ed7f5eef0eca..210b1c7c0bdae4202766dca020dda1159d6917da 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -206,7 +206,7 @@ static void mtk_iommu_config(struct mtk_iommu_data *data, for (i = 0; i < fwspec->num_ids; ++i) { larbid = mt2701_m4u_to_larb(fwspec->ids[i]); portid = mt2701_m4u_to_port(fwspec->ids[i]); - larb_mmu = &data->smi_imu.larb_imu[larbid]; + larb_mmu = &data->larb_imu[larbid]; dev_dbg(dev, "%s iommu port: %d\n", enable ? "enable" : "disable", portid); @@ -324,7 +324,8 @@ static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova, } static size_t mtk_iommu_unmap(struct iommu_domain *domain, - unsigned long iova, size_t size) + unsigned long iova, size_t size, + struct iommu_iotlb_gather *gather) { struct mtk_iommu_domain *dom = to_mtk_domain(domain); unsigned long flags; @@ -610,14 +611,12 @@ static int mtk_iommu_probe(struct platform_device *pdev) } } - data->smi_imu.larb_imu[larb_nr].dev = &plarbdev->dev; + data->larb_imu[larb_nr].dev = &plarbdev->dev; component_match_add_release(dev, &match, release_of, compare_of, larb_spec.np); larb_nr++; } - data->smi_imu.larb_nr = larb_nr; - platform_set_drvdata(pdev, data); ret = mtk_iommu_hw_init(data); diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index dfb961d8c21b7fd95feaa102a3235950950c0e5f..09c6e1c680db980aeb67dae51986b2a84e88d99a 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -35,6 +35,15 @@ static const struct iommu_ops omap_iommu_ops; +struct orphan_dev { + struct device *dev; + struct list_head node; +}; + +static LIST_HEAD(orphan_dev_list); + +static DEFINE_SPINLOCK(orphan_lock); + #define to_iommu(dev) ((struct omap_iommu *)dev_get_drvdata(dev)) /* bitmap of the page sizes currently supported */ @@ -53,6 +62,8 @@ static const struct iommu_ops omap_iommu_ops; static struct platform_driver omap_iommu_driver; static struct kmem_cache *iopte_cachep; +static int _omap_iommu_add_device(struct device *dev); + /** * to_omap_domain - Get struct omap_iommu_domain from generic iommu_domain * @dom: generic iommu domain handle @@ -65,6 +76,9 @@ static struct omap_iommu_domain *to_omap_domain(struct iommu_domain *dom) /** * omap_iommu_save_ctx - Save registers for pm off-mode support * @dev: client device + * + * This should be treated as an deprecated API. It is preserved only + * to maintain existing functionality for OMAP3 ISP driver. **/ void omap_iommu_save_ctx(struct device *dev) { @@ -92,6 +106,9 @@ EXPORT_SYMBOL_GPL(omap_iommu_save_ctx); /** * omap_iommu_restore_ctx - Restore registers for pm off-mode support * @dev: client device + * + * This should be treated as an deprecated API. It is preserved only + * to maintain existing functionality for OMAP3 ISP driver. **/ void omap_iommu_restore_ctx(struct device *dev) { @@ -186,36 +203,18 @@ static void omap2_iommu_disable(struct omap_iommu *obj) static int iommu_enable(struct omap_iommu *obj) { - int err; - struct platform_device *pdev = to_platform_device(obj->dev); - struct iommu_platform_data *pdata = dev_get_platdata(&pdev->dev); - - if (pdata && pdata->deassert_reset) { - err = pdata->deassert_reset(pdev, pdata->reset_name); - if (err) { - dev_err(obj->dev, "deassert_reset failed: %d\n", err); - return err; - } - } - - pm_runtime_get_sync(obj->dev); + int ret; - err = omap2_iommu_enable(obj); + ret = pm_runtime_get_sync(obj->dev); + if (ret < 0) + pm_runtime_put_noidle(obj->dev); - return err; + return ret < 0 ? ret : 0; } static void iommu_disable(struct omap_iommu *obj) { - struct platform_device *pdev = to_platform_device(obj->dev); - struct iommu_platform_data *pdata = dev_get_platdata(&pdev->dev); - - omap2_iommu_disable(obj); - pm_runtime_put_sync(obj->dev); - - if (pdata && pdata->assert_reset) - pdata->assert_reset(pdev, pdata->reset_name); } /* @@ -901,15 +900,219 @@ static void omap_iommu_detach(struct omap_iommu *obj) dma_unmap_single(obj->dev, obj->pd_dma, IOPGD_TABLE_SIZE, DMA_TO_DEVICE); - iommu_disable(obj); obj->pd_dma = 0; obj->iopgd = NULL; + iommu_disable(obj); spin_unlock(&obj->iommu_lock); dev_dbg(obj->dev, "%s: %s\n", __func__, obj->name); } +static void omap_iommu_save_tlb_entries(struct omap_iommu *obj) +{ + struct iotlb_lock lock; + struct cr_regs cr; + struct cr_regs *tmp; + int i; + + /* check if there are any locked tlbs to save */ + iotlb_lock_get(obj, &lock); + obj->num_cr_ctx = lock.base; + if (!obj->num_cr_ctx) + return; + + tmp = obj->cr_ctx; + for_each_iotlb_cr(obj, obj->num_cr_ctx, i, cr) + * tmp++ = cr; +} + +static void omap_iommu_restore_tlb_entries(struct omap_iommu *obj) +{ + struct iotlb_lock l; + struct cr_regs *tmp; + int i; + + /* no locked tlbs to restore */ + if (!obj->num_cr_ctx) + return; + + l.base = 0; + tmp = obj->cr_ctx; + for (i = 0; i < obj->num_cr_ctx; i++, tmp++) { + l.vict = i; + iotlb_lock_set(obj, &l); + iotlb_load_cr(obj, tmp); + } + l.base = obj->num_cr_ctx; + l.vict = i; + iotlb_lock_set(obj, &l); +} + +/** + * omap_iommu_domain_deactivate - deactivate attached iommu devices + * @domain: iommu domain attached to the target iommu device + * + * This API allows the client devices of IOMMU devices to suspend + * the IOMMUs they control at runtime, after they are idled and + * suspended all activity. System Suspend will leverage the PM + * driver late callbacks. + **/ +int omap_iommu_domain_deactivate(struct iommu_domain *domain) +{ + struct omap_iommu_domain *omap_domain = to_omap_domain(domain); + struct omap_iommu_device *iommu; + struct omap_iommu *oiommu; + int i; + + if (!omap_domain->dev) + return 0; + + iommu = omap_domain->iommus; + iommu += (omap_domain->num_iommus - 1); + for (i = 0; i < omap_domain->num_iommus; i++, iommu--) { + oiommu = iommu->iommu_dev; + pm_runtime_put_sync(oiommu->dev); + } + + return 0; +} +EXPORT_SYMBOL_GPL(omap_iommu_domain_deactivate); + +/** + * omap_iommu_domain_activate - activate attached iommu devices + * @domain: iommu domain attached to the target iommu device + * + * This API allows the client devices of IOMMU devices to resume the + * IOMMUs they control at runtime, before they can resume operations. + * System Resume will leverage the PM driver late callbacks. + **/ +int omap_iommu_domain_activate(struct iommu_domain *domain) +{ + struct omap_iommu_domain *omap_domain = to_omap_domain(domain); + struct omap_iommu_device *iommu; + struct omap_iommu *oiommu; + int i; + + if (!omap_domain->dev) + return 0; + + iommu = omap_domain->iommus; + for (i = 0; i < omap_domain->num_iommus; i++, iommu++) { + oiommu = iommu->iommu_dev; + pm_runtime_get_sync(oiommu->dev); + } + + return 0; +} +EXPORT_SYMBOL_GPL(omap_iommu_domain_activate); + +/** + * omap_iommu_runtime_suspend - disable an iommu device + * @dev: iommu device + * + * This function performs all that is necessary to disable an + * IOMMU device, either during final detachment from a client + * device, or during system/runtime suspend of the device. This + * includes programming all the appropriate IOMMU registers, and + * managing the associated omap_hwmod's state and the device's + * reset line. This function also saves the context of any + * locked TLBs if suspending. + **/ +static __maybe_unused int omap_iommu_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct iommu_platform_data *pdata = dev_get_platdata(dev); + struct omap_iommu *obj = to_iommu(dev); + int ret; + + /* save the TLBs only during suspend, and not for power down */ + if (obj->domain && obj->iopgd) + omap_iommu_save_tlb_entries(obj); + + omap2_iommu_disable(obj); + + if (pdata && pdata->device_idle) + pdata->device_idle(pdev); + + if (pdata && pdata->assert_reset) + pdata->assert_reset(pdev, pdata->reset_name); + + if (pdata && pdata->set_pwrdm_constraint) { + ret = pdata->set_pwrdm_constraint(pdev, false, &obj->pwrst); + if (ret) { + dev_warn(obj->dev, "pwrdm_constraint failed to be reset, status = %d\n", + ret); + } + } + + return 0; +} + +/** + * omap_iommu_runtime_resume - enable an iommu device + * @dev: iommu device + * + * This function performs all that is necessary to enable an + * IOMMU device, either during initial attachment to a client + * device, or during system/runtime resume of the device. This + * includes programming all the appropriate IOMMU registers, and + * managing the associated omap_hwmod's state and the device's + * reset line. The function also restores any locked TLBs if + * resuming after a suspend. + **/ +static __maybe_unused int omap_iommu_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct iommu_platform_data *pdata = dev_get_platdata(dev); + struct omap_iommu *obj = to_iommu(dev); + int ret = 0; + + if (pdata && pdata->set_pwrdm_constraint) { + ret = pdata->set_pwrdm_constraint(pdev, true, &obj->pwrst); + if (ret) { + dev_warn(obj->dev, "pwrdm_constraint failed to be set, status = %d\n", + ret); + } + } + + if (pdata && pdata->deassert_reset) { + ret = pdata->deassert_reset(pdev, pdata->reset_name); + if (ret) { + dev_err(dev, "deassert_reset failed: %d\n", ret); + return ret; + } + } + + if (pdata && pdata->device_enable) + pdata->device_enable(pdev); + + /* restore the TLBs only during resume, and not for power up */ + if (obj->domain) + omap_iommu_restore_tlb_entries(obj); + + ret = omap2_iommu_enable(obj); + + return ret; +} + +/** + * omap_iommu_suspend_prepare - prepare() dev_pm_ops implementation + * @dev: iommu device + * + * This function performs the necessary checks to determine if the IOMMU + * device needs suspending or not. The function checks if the runtime_pm + * status of the device is suspended, and returns 1 in that case. This + * results in the PM core to skip invoking any of the Sleep PM callbacks + * (suspend, suspend_late, resume, resume_early etc). + */ +static int omap_iommu_prepare(struct device *dev) +{ + if (pm_runtime_status_suspended(dev)) + return 1; + return 0; +} + static bool omap_iommu_can_register(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -974,6 +1177,7 @@ static int omap_iommu_probe(struct platform_device *pdev) struct omap_iommu *obj; struct resource *res; struct device_node *of = pdev->dev.of_node; + struct orphan_dev *orphan_dev, *tmp; if (!of) { pr_err("%s: only DT-based devices are supported\n", __func__); @@ -984,6 +1188,15 @@ static int omap_iommu_probe(struct platform_device *pdev) if (!obj) return -ENOMEM; + /* + * self-manage the ordering dependencies between omap_device_enable/idle + * and omap_device_assert/deassert_hardreset API + */ + if (pdev->dev.pm_domain) { + dev_dbg(&pdev->dev, "device pm_domain is being reset\n"); + pdev->dev.pm_domain = NULL; + } + obj->name = dev_name(&pdev->dev); obj->nr_tlb_entries = 32; err = of_property_read_u32(of, "ti,#tlb-entries", &obj->nr_tlb_entries); @@ -996,6 +1209,11 @@ static int omap_iommu_probe(struct platform_device *pdev) obj->dev = &pdev->dev; obj->ctx = (void *)obj + sizeof(*obj); + obj->cr_ctx = devm_kzalloc(&pdev->dev, + sizeof(*obj->cr_ctx) * obj->nr_tlb_entries, + GFP_KERNEL); + if (!obj->cr_ctx) + return -ENOMEM; spin_lock_init(&obj->iommu_lock); spin_lock_init(&obj->page_table_lock); @@ -1036,13 +1254,20 @@ static int omap_iommu_probe(struct platform_device *pdev) goto out_sysfs; } - pm_runtime_irq_safe(obj->dev); pm_runtime_enable(obj->dev); omap_iommu_debugfs_add(obj); dev_info(&pdev->dev, "%s registered\n", obj->name); + list_for_each_entry_safe(orphan_dev, tmp, &orphan_dev_list, node) { + err = _omap_iommu_add_device(orphan_dev->dev); + if (!err) { + list_del(&orphan_dev->node); + kfree(orphan_dev); + } + } + return 0; out_sysfs: @@ -1072,6 +1297,14 @@ static int omap_iommu_remove(struct platform_device *pdev) return 0; } +static const struct dev_pm_ops omap_iommu_pm_ops = { + .prepare = omap_iommu_prepare, + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(omap_iommu_runtime_suspend, + omap_iommu_runtime_resume, NULL) +}; + static const struct of_device_id omap_iommu_of_match[] = { { .compatible = "ti,omap2-iommu" }, { .compatible = "ti,omap4-iommu" }, @@ -1085,6 +1318,7 @@ static struct platform_driver omap_iommu_driver = { .remove = omap_iommu_remove, .driver = { .name = "omap-iommu", + .pm = &omap_iommu_pm_ops, .of_match_table = of_match_ptr(omap_iommu_of_match), }, }; @@ -1149,7 +1383,7 @@ static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, } static size_t omap_iommu_unmap(struct iommu_domain *domain, unsigned long da, - size_t size) + size_t size, struct iommu_iotlb_gather *gather) { struct omap_iommu_domain *omap_domain = to_omap_domain(domain); struct device *dev = omap_domain->dev; @@ -1423,7 +1657,7 @@ static phys_addr_t omap_iommu_iova_to_phys(struct iommu_domain *domain, return ret; } -static int omap_iommu_add_device(struct device *dev) +static int _omap_iommu_add_device(struct device *dev) { struct omap_iommu_arch_data *arch_data, *tmp; struct omap_iommu *oiommu; @@ -1432,6 +1666,8 @@ static int omap_iommu_add_device(struct device *dev) struct platform_device *pdev; int num_iommus, i; int ret; + struct orphan_dev *orphan_dev; + unsigned long flags; /* * Allocate the archdata iommu structure for DT-based devices. @@ -1463,10 +1699,26 @@ static int omap_iommu_add_device(struct device *dev) } pdev = of_find_device_by_node(np); - if (WARN_ON(!pdev)) { + if (!pdev) { of_node_put(np); kfree(arch_data); - return -EINVAL; + spin_lock_irqsave(&orphan_lock, flags); + list_for_each_entry(orphan_dev, &orphan_dev_list, + node) { + if (orphan_dev->dev == dev) + break; + } + spin_unlock_irqrestore(&orphan_lock, flags); + + if (orphan_dev && orphan_dev->dev == dev) + return -EPROBE_DEFER; + + orphan_dev = kzalloc(sizeof(*orphan_dev), GFP_KERNEL); + orphan_dev->dev = dev; + spin_lock_irqsave(&orphan_lock, flags); + list_add(&orphan_dev->node, &orphan_dev_list); + spin_unlock_irqrestore(&orphan_lock, flags); + return -EPROBE_DEFER; } oiommu = platform_get_drvdata(pdev); @@ -1477,6 +1729,7 @@ static int omap_iommu_add_device(struct device *dev) } tmp->iommu_dev = oiommu; + tmp->dev = &pdev->dev; of_node_put(np); } @@ -1511,6 +1764,17 @@ static int omap_iommu_add_device(struct device *dev) return 0; } +static int omap_iommu_add_device(struct device *dev) +{ + int ret; + + ret = _omap_iommu_add_device(dev); + if (ret == -EPROBE_DEFER) + return 0; + + return ret; +} + static void omap_iommu_remove_device(struct device *dev) { struct omap_iommu_arch_data *arch_data = dev->archdata.iommu; @@ -1554,7 +1818,7 @@ static const struct iommu_ops omap_iommu_ops = { static int __init omap_iommu_init(void) { struct kmem_cache *p; - const unsigned long flags = SLAB_HWCACHE_ALIGN; + const slab_flags_t flags = SLAB_HWCACHE_ALIGN; size_t align = 1 << 10; /* L2 pagetable alignement */ struct device_node *np; int ret; diff --git a/drivers/iommu/omap-iommu.h b/drivers/iommu/omap-iommu.h index 09968a02d291876461759be869d440e57a8696a9..18ee713ede784d16c884b9cca19ed8ce240706d4 100644 --- a/drivers/iommu/omap-iommu.h +++ b/drivers/iommu/omap-iommu.h @@ -73,16 +73,22 @@ struct omap_iommu { void *ctx; /* iommu context: registres saved area */ + struct cr_regs *cr_ctx; + u32 num_cr_ctx; + int has_bus_err_back; u32 id; struct iommu_device iommu; struct iommu_group *group; + + u8 pwrst; }; /** * struct omap_iommu_arch_data - omap iommu private data - * @iommu_dev: handle of the iommu device + * @iommu_dev: handle of the OMAP iommu device + * @dev: handle of the iommu device * * This is an omap iommu private data object, which binds an iommu user * to its iommu device. This object should be placed at the iommu user's @@ -91,6 +97,7 @@ struct omap_iommu { */ struct omap_iommu_arch_data { struct omap_iommu *iommu_dev; + struct device *dev; }; struct cr_regs { diff --git a/drivers/iommu/qcom_iommu.c b/drivers/iommu/qcom_iommu.c index 34d0b9783b3ed6f57c3fcbe9ec46d16db1e92116..c31e7bc4ccbec2f7083ba30541e2a2b70df7431a 100644 --- a/drivers/iommu/qcom_iommu.c +++ b/drivers/iommu/qcom_iommu.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -32,7 +33,7 @@ #include #include -#include "arm-smmu-regs.h" +#include "arm-smmu.h" #define SMMU_INTR_SEL_NS 0x2000 @@ -155,7 +156,7 @@ static void qcom_iommu_tlb_inv_range_nosync(unsigned long iova, size_t size, struct qcom_iommu_ctx *ctx = to_ctx(fwspec, fwspec->ids[i]); size_t s = size; - iova &= ~12UL; + iova = (iova >> 12) << 12; iova |= ctx->asid; do { iommu_writel(ctx, reg, iova); @@ -164,10 +165,32 @@ static void qcom_iommu_tlb_inv_range_nosync(unsigned long iova, size_t size, } } -static const struct iommu_gather_ops qcom_gather_ops = { +static void qcom_iommu_tlb_flush_walk(unsigned long iova, size_t size, + size_t granule, void *cookie) +{ + qcom_iommu_tlb_inv_range_nosync(iova, size, granule, false, cookie); + qcom_iommu_tlb_sync(cookie); +} + +static void qcom_iommu_tlb_flush_leaf(unsigned long iova, size_t size, + size_t granule, void *cookie) +{ + qcom_iommu_tlb_inv_range_nosync(iova, size, granule, true, cookie); + qcom_iommu_tlb_sync(cookie); +} + +static void qcom_iommu_tlb_add_page(struct iommu_iotlb_gather *gather, + unsigned long iova, size_t granule, + void *cookie) +{ + qcom_iommu_tlb_inv_range_nosync(iova, granule, granule, true, cookie); +} + +static const struct iommu_flush_ops qcom_flush_ops = { .tlb_flush_all = qcom_iommu_tlb_inv_context, - .tlb_add_flush = qcom_iommu_tlb_inv_range_nosync, - .tlb_sync = qcom_iommu_tlb_sync, + .tlb_flush_walk = qcom_iommu_tlb_flush_walk, + .tlb_flush_leaf = qcom_iommu_tlb_flush_leaf, + .tlb_add_page = qcom_iommu_tlb_add_page, }; static irqreturn_t qcom_iommu_fault(int irq, void *dev) @@ -215,7 +238,7 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain, .pgsize_bitmap = qcom_iommu_ops.pgsize_bitmap, .ias = 32, .oas = 40, - .tlb = &qcom_gather_ops, + .tlb = &qcom_flush_ops, .iommu_dev = qcom_iommu->dev, }; @@ -247,16 +270,16 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain, /* TTBRs */ iommu_writeq(ctx, ARM_SMMU_CB_TTBR0, pgtbl_cfg.arm_lpae_s1_cfg.ttbr[0] | - ((u64)ctx->asid << TTBRn_ASID_SHIFT)); + FIELD_PREP(TTBRn_ASID, ctx->asid)); iommu_writeq(ctx, ARM_SMMU_CB_TTBR1, pgtbl_cfg.arm_lpae_s1_cfg.ttbr[1] | - ((u64)ctx->asid << TTBRn_ASID_SHIFT)); + FIELD_PREP(TTBRn_ASID, ctx->asid)); - /* TTBCR */ - iommu_writel(ctx, ARM_SMMU_CB_TTBCR2, + /* TCR */ + iommu_writel(ctx, ARM_SMMU_CB_TCR2, (pgtbl_cfg.arm_lpae_s1_cfg.tcr >> 32) | - TTBCR2_SEP_UPSTREAM); - iommu_writel(ctx, ARM_SMMU_CB_TTBCR, + FIELD_PREP(TCR2_SEP, TCR2_SEP_UPSTREAM)); + iommu_writel(ctx, ARM_SMMU_CB_TCR, pgtbl_cfg.arm_lpae_s1_cfg.tcr); /* MAIRs (stage-1 only) */ @@ -417,7 +440,7 @@ static int qcom_iommu_map(struct iommu_domain *domain, unsigned long iova, } static size_t qcom_iommu_unmap(struct iommu_domain *domain, unsigned long iova, - size_t size) + size_t size, struct iommu_iotlb_gather *gather) { size_t ret; unsigned long flags; @@ -434,14 +457,14 @@ static size_t qcom_iommu_unmap(struct iommu_domain *domain, unsigned long iova, */ pm_runtime_get_sync(qcom_domain->iommu->dev); spin_lock_irqsave(&qcom_domain->pgtbl_lock, flags); - ret = ops->unmap(ops, iova, size); + ret = ops->unmap(ops, iova, size, gather); spin_unlock_irqrestore(&qcom_domain->pgtbl_lock, flags); pm_runtime_put_sync(qcom_domain->iommu->dev); return ret; } -static void qcom_iommu_iotlb_sync(struct iommu_domain *domain) +static void qcom_iommu_flush_iotlb_all(struct iommu_domain *domain) { struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain); struct io_pgtable *pgtable = container_of(qcom_domain->pgtbl_ops, @@ -454,6 +477,12 @@ static void qcom_iommu_iotlb_sync(struct iommu_domain *domain) pm_runtime_put_sync(qcom_domain->iommu->dev); } +static void qcom_iommu_iotlb_sync(struct iommu_domain *domain, + struct iommu_iotlb_gather *gather) +{ + qcom_iommu_flush_iotlb_all(domain); +} + static phys_addr_t qcom_iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) { @@ -581,7 +610,7 @@ static const struct iommu_ops qcom_iommu_ops = { .detach_dev = qcom_iommu_detach_dev, .map = qcom_iommu_map, .unmap = qcom_iommu_unmap, - .flush_iotlb_all = qcom_iommu_iotlb_sync, + .flush_iotlb_all = qcom_iommu_flush_iotlb_all, .iotlb_sync = qcom_iommu_iotlb_sync, .iova_to_phys = qcom_iommu_iova_to_phys, .add_device = qcom_iommu_add_device, @@ -696,10 +725,8 @@ static int qcom_iommu_ctx_probe(struct platform_device *pdev) return PTR_ERR(ctx->base); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "failed to get irq\n"); + if (irq < 0) return -ENODEV; - } /* clear IRQs before registering fault handler, just in case the * boot-loader left us a surprise: @@ -775,7 +802,7 @@ static int qcom_iommu_device_probe(struct platform_device *pdev) struct qcom_iommu_dev *qcom_iommu; struct device *dev = &pdev->dev; struct resource *res; - int ret, sz, max_asid = 0; + int ret, max_asid = 0; /* find the max asid (which is 1:1 to ctx bank idx), so we know how * many child ctx devices we have: @@ -783,9 +810,8 @@ static int qcom_iommu_device_probe(struct platform_device *pdev) for_each_child_of_node(dev->of_node, child) max_asid = max(max_asid, get_asid(child)); - sz = sizeof(*qcom_iommu) + (max_asid * sizeof(qcom_iommu->ctxs[0])); - - qcom_iommu = devm_kzalloc(dev, sz, GFP_KERNEL); + qcom_iommu = devm_kzalloc(dev, struct_size(qcom_iommu, ctxs, max_asid), + GFP_KERNEL); if (!qcom_iommu) return -ENOMEM; qcom_iommu->num_ctxs = max_asid; diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index dc26d74d79c2c7c337b717aae3145810d13ff552..26290f310f90bd8c6d05da9b255ec02d144cd56f 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -794,7 +794,7 @@ static int rk_iommu_map(struct iommu_domain *domain, unsigned long _iova, } static size_t rk_iommu_unmap(struct iommu_domain *domain, unsigned long _iova, - size_t size) + size_t size, struct iommu_iotlb_gather *gather) { struct rk_iommu_domain *rk_domain = to_rk_domain(domain); unsigned long flags; diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c index 22d4db302c1c8c2cc6b19a11a5ee8baf8c132acc..3b0b18e23187c19d7c787389fb33d73ca957a429 100644 --- a/drivers/iommu/s390-iommu.c +++ b/drivers/iommu/s390-iommu.c @@ -314,7 +314,8 @@ static phys_addr_t s390_iommu_iova_to_phys(struct iommu_domain *domain, } static size_t s390_iommu_unmap(struct iommu_domain *domain, - unsigned long iova, size_t size) + unsigned long iova, size_t size, + struct iommu_iotlb_gather *gather) { struct s390_domain *s390_domain = to_s390_domain(domain); int flags = ZPCI_PTE_INVALID; diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index 6d40bc1b38bf0ccc2f90a441d04729d492c4d3a5..3924f7c055440edd3ee64be0b02710102bd7efcd 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -207,7 +207,7 @@ static inline int __gart_iommu_unmap(struct gart_device *gart, } static size_t gart_iommu_unmap(struct iommu_domain *domain, unsigned long iova, - size_t bytes) + size_t bytes, struct iommu_iotlb_gather *gather) { struct gart_device *gart = gart_handle; int err; @@ -273,11 +273,17 @@ static int gart_iommu_of_xlate(struct device *dev, return 0; } -static void gart_iommu_sync(struct iommu_domain *domain) +static void gart_iommu_sync_map(struct iommu_domain *domain) { FLUSH_GART_REGS(gart_handle); } +static void gart_iommu_sync(struct iommu_domain *domain, + struct iommu_iotlb_gather *gather) +{ + gart_iommu_sync_map(domain); +} + static const struct iommu_ops gart_iommu_ops = { .capable = gart_iommu_capable, .domain_alloc = gart_iommu_domain_alloc, @@ -292,7 +298,7 @@ static const struct iommu_ops gart_iommu_ops = { .iova_to_phys = gart_iommu_iova_to_phys, .pgsize_bitmap = GART_IOMMU_PGSIZES, .of_xlate = gart_iommu_of_xlate, - .iotlb_sync_map = gart_iommu_sync, + .iotlb_sync_map = gart_iommu_sync_map, .iotlb_sync = gart_iommu_sync, }; diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index c4a652b227f8d6a794fa54a85ac9edf867f3f05f..7293fc3f796d69f61f8cbe8a4ef3176d3b9ff5b0 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -680,7 +680,7 @@ static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova, } static size_t tegra_smmu_unmap(struct iommu_domain *domain, unsigned long iova, - size_t size) + size_t size, struct iommu_iotlb_gather *gather) { struct tegra_smmu_as *as = to_smmu_as(domain); dma_addr_t pte_dma; diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c index 80a740df0737a638e6170f35c0b8b2a52cce37a0..3ea9d7682999528d1348a6d2693f6136556eea57 100644 --- a/drivers/iommu/virtio-iommu.c +++ b/drivers/iommu/virtio-iommu.c @@ -751,7 +751,7 @@ static int viommu_map(struct iommu_domain *domain, unsigned long iova, } static size_t viommu_unmap(struct iommu_domain *domain, unsigned long iova, - size_t size) + size_t size, struct iommu_iotlb_gather *gather) { int ret = 0; size_t unmapped; @@ -797,7 +797,8 @@ static phys_addr_t viommu_iova_to_phys(struct iommu_domain *domain, return paddr; } -static void viommu_iotlb_sync(struct iommu_domain *domain) +static void viommu_iotlb_sync(struct iommu_domain *domain, + struct iommu_iotlb_gather *gather) { struct viommu_domain *vdomain = to_viommu_domain(domain); diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index b0a8215a13fc086958932f96557d1c1113022c40..82520006195de1aa5f6914cf7c34f0fdd0b8ba7b 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c @@ -41,6 +41,8 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks, void *data) { for (; quirks->desc; quirks++) { + if (quirks->compatible) + continue; if (quirks->iidr != (quirks->mask & iidr)) continue; if (quirks->init(data)) @@ -63,7 +65,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type, * for "irq", depending on "type". */ raw_spin_lock_irqsave(&irq_controller_lock, flags); - val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff); + val = oldval = readl_relaxed(base + confoff); if (type & IRQ_TYPE_LEVEL_MASK) val &= ~confmask; else if (type & IRQ_TYPE_EDGE_BOTH) @@ -83,14 +85,10 @@ int gic_configure_irq(unsigned int irq, unsigned int type, * does not allow us to set the configuration or we are in a * non-secure mode, and hence it may not be catastrophic. */ - writel_relaxed(val, base + GIC_DIST_CONFIG + confoff); - if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val) { - if (WARN_ON(irq >= 32)) - ret = -EINVAL; - else - pr_warn("GIC: PPI%d is secure or misconfigured\n", - irq - 16); - } + writel_relaxed(val, base + confoff); + if (readl_relaxed(base + confoff) != val) + ret = -EINVAL; + raw_spin_unlock_irqrestore(&irq_controller_lock, flags); if (sync_access) @@ -132,26 +130,31 @@ void gic_dist_config(void __iomem *base, int gic_irqs, sync_access(); } -void gic_cpu_config(void __iomem *base, void (*sync_access)(void)) +void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void)) { int i; /* * Deal with the banked PPI and SGI interrupts - disable all - * PPI interrupts, ensure all SGI interrupts are enabled. - * Make sure everything is deactivated. + * private interrupts. Make sure everything is deactivated. */ - writel_relaxed(GICD_INT_EN_CLR_X32, base + GIC_DIST_ACTIVE_CLEAR); - writel_relaxed(GICD_INT_EN_CLR_PPI, base + GIC_DIST_ENABLE_CLEAR); - writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET); + for (i = 0; i < nr; i += 32) { + writel_relaxed(GICD_INT_EN_CLR_X32, + base + GIC_DIST_ACTIVE_CLEAR + i / 8); + writel_relaxed(GICD_INT_EN_CLR_X32, + base + GIC_DIST_ENABLE_CLEAR + i / 8); + } /* * Set priority on PPI and SGI interrupts */ - for (i = 0; i < 32; i += 4) + for (i = 0; i < nr; i += 4) writel_relaxed(GICD_INT_DEF_PRI_X4, base + GIC_DIST_PRI + i * 4 / 4); + /* Ensure all SGI interrupts are now enabled */ + writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET); + if (sync_access) sync_access(); } diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h index 5a46b6b57750c618537b94d4ea09a2ec5792d5ca..ccba8b0fe0f582696f98c36f18d9c02b99d85e0e 100644 --- a/drivers/irqchip/irq-gic-common.h +++ b/drivers/irqchip/irq-gic-common.h @@ -22,7 +22,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type, void __iomem *base, void (*sync_access)(void)); void gic_dist_config(void __iomem *base, int gic_irqs, void (*sync_access)(void)); -void gic_cpu_config(void __iomem *base, void (*sync_access)(void)); +void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void)); void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks, void *data); void gic_enable_of_quirks(const struct device_node *np, diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index 7338f90b2f9e91bcfaf9ce9bbd33963c1ce70dd2..e88e75c22b6a084d9bad7d891b1129d3f899001e 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -525,7 +525,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header, spi_start, nr_spis); } - fwnode = irq_domain_alloc_fwnode((void *)m->base_address); + fwnode = irq_domain_alloc_fwnode(&res.start); if (!fwnode) { pr_err("Unable to allocate GICv2m domain token\n"); return -EINVAL; diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 1b5c3672aea277925b57d0e5e9162d7f31dde386..62e54f1a248ba002942bc0bae0c6b97d52f9f857 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -2464,6 +2464,7 @@ static int its_alloc_device_irq(struct its_device *dev, int nvecs, irq_hw_number { int idx; + /* Find a free LPI region in lpi_map and allocate them. */ idx = bitmap_find_free_region(dev->event_map.lpi_map, dev->event_map.nr_lpis, get_count_order(nvecs)); @@ -2471,7 +2472,6 @@ static int its_alloc_device_irq(struct its_device *dev, int nvecs, irq_hw_number return -ENOSPC; *hwirq = dev->event_map.lpi_base + idx; - set_bit(idx, dev->event_map.lpi_map); return 0; } @@ -2641,14 +2641,13 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq, struct its_node *its = its_dev->its; int i; + bitmap_release_region(its_dev->event_map.lpi_map, + its_get_event_id(irq_domain_get_irq_data(domain, virq)), + get_count_order(nr_irqs)); + for (i = 0; i < nr_irqs; i++) { struct irq_data *data = irq_domain_get_irq_data(domain, virq + i); - u32 event = its_get_event_id(data); - - /* Mark interrupt index as unused */ - clear_bit(event, its_dev->event_map.lpi_map); - /* Nuke the entry in the domain */ irq_domain_reset_irq_data(data); } @@ -3921,7 +3920,7 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header, res.end = its_entry->base_address + ACPI_GICV3_ITS_MEM_SIZE - 1; res.flags = IORESOURCE_MEM; - dom_handle = irq_domain_alloc_fwnode((void *)its_entry->base_address); + dom_handle = irq_domain_alloc_fwnode(&res.start); if (!dom_handle) { pr_err("ITS@%pa: Unable to allocate GICv3 ITS domain token\n", &res.start); diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 96d927f0f91ad4fa7029130cb9462aa84be7cdf7..422664ac5f533b4c69f15933059945eb0c59994e 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -51,13 +51,17 @@ struct gic_chip_data { u32 nr_redist_regions; u64 flags; bool has_rss; - unsigned int irq_nr; - struct partition_desc *ppi_descs[16]; + unsigned int ppi_nr; + struct partition_desc **ppi_descs; }; static struct gic_chip_data gic_data __read_mostly; static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key); +#define GIC_ID_NR (1U << GICD_TYPER_ID_BITS(gic_data.rdists.gicd_typer)) +#define GIC_LINE_NR max(GICD_TYPER_SPIS(gic_data.rdists.gicd_typer), 1020U) +#define GIC_ESPI_NR GICD_TYPER_ESPIS(gic_data.rdists.gicd_typer) + /* * The behaviours of RPR and PMR registers differ depending on the value of * SCR_EL3.FIQ, and the behaviour of non-secure priority registers of the @@ -84,7 +88,7 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key); static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis); /* ppi_nmi_refs[n] == number of cpus having ppi[n + 16] set as NMI */ -static refcount_t ppi_nmi_refs[16]; +static refcount_t *ppi_nmi_refs; static struct gic_kvm_info gic_v3_kvm_info; static DEFINE_PER_CPU(bool, has_rss); @@ -97,6 +101,38 @@ static DEFINE_PER_CPU(bool, has_rss); /* Our default, arbitrary priority value. Linux only uses one anyway. */ #define DEFAULT_PMR_VALUE 0xf0 +enum gic_intid_range { + PPI_RANGE, + SPI_RANGE, + EPPI_RANGE, + ESPI_RANGE, + LPI_RANGE, + __INVALID_RANGE__ +}; + +static enum gic_intid_range __get_intid_range(irq_hw_number_t hwirq) +{ + switch (hwirq) { + case 16 ... 31: + return PPI_RANGE; + case 32 ... 1019: + return SPI_RANGE; + case EPPI_BASE_INTID ... (EPPI_BASE_INTID + 63): + return EPPI_RANGE; + case ESPI_BASE_INTID ... (ESPI_BASE_INTID + 1023): + return ESPI_RANGE; + case 8192 ... GENMASK(23, 0): + return LPI_RANGE; + default: + return __INVALID_RANGE__; + } +} + +static enum gic_intid_range get_intid_range(struct irq_data *d) +{ + return __get_intid_range(d->hwirq); +} + static inline unsigned int gic_irq(struct irq_data *d) { return d->hwirq; @@ -104,18 +140,26 @@ static inline unsigned int gic_irq(struct irq_data *d) static inline int gic_irq_in_rdist(struct irq_data *d) { - return gic_irq(d) < 32; + enum gic_intid_range range = get_intid_range(d); + return range == PPI_RANGE || range == EPPI_RANGE; } static inline void __iomem *gic_dist_base(struct irq_data *d) { - if (gic_irq_in_rdist(d)) /* SGI+PPI -> SGI_base for this CPU */ + switch (get_intid_range(d)) { + case PPI_RANGE: + case EPPI_RANGE: + /* SGI+PPI -> SGI_base for this CPU */ return gic_data_rdist_sgi_base(); - if (d->hwirq <= 1023) /* SPI -> dist_base */ + case SPI_RANGE: + case ESPI_RANGE: + /* SPI -> dist_base */ return gic_data.dist_base; - return NULL; + default: + return NULL; + } } static void gic_do_wait_for_rwp(void __iomem *base) @@ -196,24 +240,79 @@ static void gic_enable_redist(bool enable) /* * Routines to disable, enable, EOI and route interrupts */ +static u32 convert_offset_index(struct irq_data *d, u32 offset, u32 *index) +{ + switch (get_intid_range(d)) { + case PPI_RANGE: + case SPI_RANGE: + *index = d->hwirq; + return offset; + case EPPI_RANGE: + /* + * Contrary to the ESPI range, the EPPI range is contiguous + * to the PPI range in the registers, so let's adjust the + * displacement accordingly. Consistency is overrated. + */ + *index = d->hwirq - EPPI_BASE_INTID + 32; + return offset; + case ESPI_RANGE: + *index = d->hwirq - ESPI_BASE_INTID; + switch (offset) { + case GICD_ISENABLER: + return GICD_ISENABLERnE; + case GICD_ICENABLER: + return GICD_ICENABLERnE; + case GICD_ISPENDR: + return GICD_ISPENDRnE; + case GICD_ICPENDR: + return GICD_ICPENDRnE; + case GICD_ISACTIVER: + return GICD_ISACTIVERnE; + case GICD_ICACTIVER: + return GICD_ICACTIVERnE; + case GICD_IPRIORITYR: + return GICD_IPRIORITYRnE; + case GICD_ICFGR: + return GICD_ICFGRnE; + case GICD_IROUTER: + return GICD_IROUTERnE; + default: + break; + } + break; + default: + break; + } + + WARN_ON(1); + *index = d->hwirq; + return offset; +} + static int gic_peek_irq(struct irq_data *d, u32 offset) { - u32 mask = 1 << (gic_irq(d) % 32); void __iomem *base; + u32 index, mask; + + offset = convert_offset_index(d, offset, &index); + mask = 1 << (index % 32); if (gic_irq_in_rdist(d)) base = gic_data_rdist_sgi_base(); else base = gic_data.dist_base; - return !!(readl_relaxed(base + offset + (gic_irq(d) / 32) * 4) & mask); + return !!(readl_relaxed(base + offset + (index / 32) * 4) & mask); } static void gic_poke_irq(struct irq_data *d, u32 offset) { - u32 mask = 1 << (gic_irq(d) % 32); void (*rwp_wait)(void); void __iomem *base; + u32 index, mask; + + offset = convert_offset_index(d, offset, &index); + mask = 1 << (index % 32); if (gic_irq_in_rdist(d)) { base = gic_data_rdist_sgi_base(); @@ -223,7 +322,7 @@ static void gic_poke_irq(struct irq_data *d, u32 offset) rwp_wait = gic_dist_wait_for_rwp; } - writel_relaxed(mask, base + offset + (gic_irq(d) / 32) * 4); + writel_relaxed(mask, base + offset + (index / 32) * 4); rwp_wait(); } @@ -263,7 +362,7 @@ static int gic_irq_set_irqchip_state(struct irq_data *d, { u32 reg; - if (d->hwirq >= gic_data.irq_nr) /* PPI/SPI only */ + if (d->hwirq >= 8192) /* PPI/SPI only */ return -EINVAL; switch (which) { @@ -290,7 +389,7 @@ static int gic_irq_set_irqchip_state(struct irq_data *d, static int gic_irq_get_irqchip_state(struct irq_data *d, enum irqchip_irq_state which, bool *val) { - if (d->hwirq >= gic_data.irq_nr) /* PPI/SPI only */ + if (d->hwirq >= 8192) /* PPI/SPI only */ return -EINVAL; switch (which) { @@ -316,8 +415,23 @@ static int gic_irq_get_irqchip_state(struct irq_data *d, static void gic_irq_set_prio(struct irq_data *d, u8 prio) { void __iomem *base = gic_dist_base(d); + u32 offset, index; + + offset = convert_offset_index(d, GICD_IPRIORITYR, &index); - writeb_relaxed(prio, base + GICD_IPRIORITYR + gic_irq(d)); + writeb_relaxed(prio, base + offset + index); +} + +static u32 gic_get_ppi_index(struct irq_data *d) +{ + switch (get_intid_range(d)) { + case PPI_RANGE: + return d->hwirq - 16; + case EPPI_RANGE: + return d->hwirq - EPPI_BASE_INTID + 16; + default: + unreachable(); + } } static int gic_irq_nmi_setup(struct irq_data *d) @@ -340,10 +454,12 @@ static int gic_irq_nmi_setup(struct irq_data *d) return -EINVAL; /* desc lock should already be held */ - if (gic_irq(d) < 32) { + if (gic_irq_in_rdist(d)) { + u32 idx = gic_get_ppi_index(d); + /* Setting up PPI as NMI, only switch handler for first NMI */ - if (!refcount_inc_not_zero(&ppi_nmi_refs[gic_irq(d) - 16])) { - refcount_set(&ppi_nmi_refs[gic_irq(d) - 16], 1); + if (!refcount_inc_not_zero(&ppi_nmi_refs[idx])) { + refcount_set(&ppi_nmi_refs[idx], 1); desc->handle_irq = handle_percpu_devid_fasteoi_nmi; } } else { @@ -375,9 +491,11 @@ static void gic_irq_nmi_teardown(struct irq_data *d) return; /* desc lock should already be held */ - if (gic_irq(d) < 32) { + if (gic_irq_in_rdist(d)) { + u32 idx = gic_get_ppi_index(d); + /* Tearing down NMI, only switch handler for last NMI */ - if (refcount_dec_and_test(&ppi_nmi_refs[gic_irq(d) - 16])) + if (refcount_dec_and_test(&ppi_nmi_refs[idx])) desc->handle_irq = handle_percpu_devid_irq; } else { desc->handle_irq = handle_fasteoi_irq; @@ -404,17 +522,22 @@ static void gic_eoimode1_eoi_irq(struct irq_data *d) static int gic_set_type(struct irq_data *d, unsigned int type) { + enum gic_intid_range range; unsigned int irq = gic_irq(d); void (*rwp_wait)(void); void __iomem *base; + u32 offset, index; + int ret; /* Interrupt configuration for SGIs can't be changed */ if (irq < 16) return -EINVAL; + range = get_intid_range(d); + /* SPIs have restrictions on the supported types */ - if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH && - type != IRQ_TYPE_EDGE_RISING) + if ((range == SPI_RANGE || range == ESPI_RANGE) && + type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING) return -EINVAL; if (gic_irq_in_rdist(d)) { @@ -425,7 +548,16 @@ static int gic_set_type(struct irq_data *d, unsigned int type) rwp_wait = gic_dist_wait_for_rwp; } - return gic_configure_irq(irq, type, base, rwp_wait); + offset = convert_offset_index(d, GICD_ICFGR, &index); + + ret = gic_configure_irq(index, type, base + offset, rwp_wait); + if (ret && (range == PPI_RANGE || range == EPPI_RANGE)) { + /* Misconfigured PPIs are usually not fatal */ + pr_warn("GIC: PPI INTID%d is secure or misconfigured\n", irq); + ret = 0; + } + + return ret; } static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) @@ -500,7 +632,12 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs gic_arch_enable_irqs(); } - if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) { + /* Check for special IDs first */ + if ((irqnr >= 1020 && irqnr <= 1023)) + return; + + /* Treat anything but SGIs in a uniform way */ + if (likely(irqnr > 15)) { int err; if (static_branch_likely(&supports_deactivate_key)) @@ -588,10 +725,26 @@ static void __init gic_dist_init(void) * do the right thing if the kernel is running in secure mode, * but that's not the intended use case anyway. */ - for (i = 32; i < gic_data.irq_nr; i += 32) + for (i = 32; i < GIC_LINE_NR; i += 32) writel_relaxed(~0, base + GICD_IGROUPR + i / 8); - gic_dist_config(base, gic_data.irq_nr, gic_dist_wait_for_rwp); + /* Extended SPI range, not handled by the GICv2/GICv3 common code */ + for (i = 0; i < GIC_ESPI_NR; i += 32) { + writel_relaxed(~0U, base + GICD_ICENABLERnE + i / 8); + writel_relaxed(~0U, base + GICD_ICACTIVERnE + i / 8); + } + + for (i = 0; i < GIC_ESPI_NR; i += 32) + writel_relaxed(~0U, base + GICD_IGROUPRnE + i / 8); + + for (i = 0; i < GIC_ESPI_NR; i += 16) + writel_relaxed(0, base + GICD_ICFGRnE + i / 4); + + for (i = 0; i < GIC_ESPI_NR; i += 4) + writel_relaxed(GICD_INT_DEF_PRI_X4, base + GICD_IPRIORITYRnE + i); + + /* Now do the common stuff, and wait for the distributor to drain */ + gic_dist_config(base, GIC_LINE_NR, gic_dist_wait_for_rwp); /* Enable distributor with ARE, Group1 */ writel_relaxed(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1, @@ -602,8 +755,11 @@ static void __init gic_dist_init(void) * enabled. */ affinity = gic_mpidr_to_affinity(cpu_logical_map(smp_processor_id())); - for (i = 32; i < gic_data.irq_nr; i++) + for (i = 32; i < GIC_LINE_NR; i++) gic_write_irouter(affinity, base + GICD_IROUTER + i * 8); + + for (i = 0; i < GIC_ESPI_NR; i++) + gic_write_irouter(affinity, base + GICD_IROUTERnE + i * 8); } static int gic_iterate_rdists(int (*fn)(struct redist_region *, void __iomem *)) @@ -689,19 +845,24 @@ static int gic_populate_rdist(void) return -ENODEV; } -static int __gic_update_vlpi_properties(struct redist_region *region, - void __iomem *ptr) +static int __gic_update_rdist_properties(struct redist_region *region, + void __iomem *ptr) { u64 typer = gic_read_typer(ptr + GICR_TYPER); gic_data.rdists.has_vlpis &= !!(typer & GICR_TYPER_VLPIS); gic_data.rdists.has_direct_lpi &= !!(typer & GICR_TYPER_DirectLPIS); + gic_data.ppi_nr = min(GICR_TYPER_NR_PPIS(typer), gic_data.ppi_nr); return 1; } -static void gic_update_vlpi_properties(void) +static void gic_update_rdist_properties(void) { - gic_iterate_rdists(__gic_update_vlpi_properties); + gic_data.ppi_nr = UINT_MAX; + gic_iterate_rdists(__gic_update_rdist_properties); + if (WARN_ON(gic_data.ppi_nr == UINT_MAX)) + gic_data.ppi_nr = 0; + pr_info("%d PPIs implemented\n", gic_data.ppi_nr); pr_info("%sVLPI support, %sdirect LPI support\n", !gic_data.rdists.has_vlpis ? "no " : "", !gic_data.rdists.has_direct_lpi ? "no " : ""); @@ -845,6 +1006,7 @@ static int gic_dist_supports_lpis(void) static void gic_cpu_init(void) { void __iomem *rbase; + int i; /* Register ourselves with the rest of the world */ if (gic_populate_rdist()) @@ -852,12 +1014,18 @@ static void gic_cpu_init(void) gic_enable_redist(true); + WARN((gic_data.ppi_nr > 16 || GIC_ESPI_NR != 0) && + !(gic_read_ctlr() & ICC_CTLR_EL1_ExtRange), + "Distributor has extended ranges, but CPU%d doesn't\n", + smp_processor_id()); + rbase = gic_data_rdist_sgi_base(); /* Configure SGIs/PPIs as non-secure Group-1 */ - writel_relaxed(~0, rbase + GICR_IGROUPR0); + for (i = 0; i < gic_data.ppi_nr + 16; i += 32) + writel_relaxed(~0, rbase + GICR_IGROUPR0 + i / 8); - gic_cpu_config(rbase, gic_redist_wait_for_rwp); + gic_cpu_config(rbase, gic_data.ppi_nr + 16, gic_redist_wait_for_rwp); /* initialise system registers */ gic_cpu_sys_reg_init(); @@ -961,6 +1129,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) { unsigned int cpu; + u32 offset, index; void __iomem *reg; int enabled; u64 val; @@ -981,7 +1150,8 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, if (enabled) gic_mask_irq(d); - reg = gic_dist_base(d) + GICD_IROUTER + (gic_irq(d) * 8); + offset = convert_offset_index(d, GICD_IROUTER, &index); + reg = gic_dist_base(d) + offset + (index * 8); val = gic_mpidr_to_affinity(cpu_logical_map(cpu)); gic_write_irouter(val, reg); @@ -1065,8 +1235,6 @@ static struct irq_chip gic_eoimode1_chip = { IRQCHIP_MASK_ON_SUSPEND, }; -#define GIC_ID_NR (1U << GICD_TYPER_ID_BITS(gic_data.rdists.gicd_typer)) - static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { @@ -1075,36 +1243,32 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, if (static_branch_likely(&supports_deactivate_key)) chip = &gic_eoimode1_chip; - /* SGIs are private to the core kernel */ - if (hw < 16) - return -EPERM; - /* Nothing here */ - if (hw >= gic_data.irq_nr && hw < 8192) - return -EPERM; - /* Off limits */ - if (hw >= GIC_ID_NR) - return -EPERM; - - /* PPIs */ - if (hw < 32) { + switch (__get_intid_range(hw)) { + case PPI_RANGE: + case EPPI_RANGE: irq_set_percpu_devid(irq); irq_domain_set_info(d, irq, hw, chip, d->host_data, handle_percpu_devid_irq, NULL, NULL); irq_set_status_flags(irq, IRQ_NOAUTOEN); - } - /* SPIs */ - if (hw >= 32 && hw < gic_data.irq_nr) { + break; + + case SPI_RANGE: + case ESPI_RANGE: irq_domain_set_info(d, irq, hw, chip, d->host_data, handle_fasteoi_irq, NULL, NULL); irq_set_probe(irq); irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq))); - } - /* LPIs */ - if (hw >= 8192 && hw < GIC_ID_NR) { + break; + + case LPI_RANGE: if (!gic_dist_supports_lpis()) return -EPERM; irq_domain_set_info(d, irq, hw, chip, d->host_data, handle_fasteoi_irq, NULL, NULL); + break; + + default: + return -EPERM; } return 0; @@ -1126,12 +1290,24 @@ static int gic_irq_domain_translate(struct irq_domain *d, *hwirq = fwspec->param[1] + 32; break; case 1: /* PPI */ - case GIC_IRQ_TYPE_PARTITION: *hwirq = fwspec->param[1] + 16; break; + case 2: /* ESPI */ + *hwirq = fwspec->param[1] + ESPI_BASE_INTID; + break; + case 3: /* EPPI */ + *hwirq = fwspec->param[1] + EPPI_BASE_INTID; + break; case GIC_IRQ_TYPE_LPI: /* LPI */ *hwirq = fwspec->param[1]; break; + case GIC_IRQ_TYPE_PARTITION: + *hwirq = fwspec->param[1]; + if (fwspec->param[1] >= 16) + *hwirq += EPPI_BASE_INTID - 16; + else + *hwirq += 16; + break; default: return -EINVAL; } @@ -1211,7 +1387,8 @@ static int gic_irq_domain_select(struct irq_domain *d, * then we need to match the partition domain. */ if (fwspec->param_count >= 4 && - fwspec->param[0] == 1 && fwspec->param[3] != 0) + fwspec->param[0] == 1 && fwspec->param[3] != 0 && + gic_data.ppi_descs) return d == partition_get_domain(gic_data.ppi_descs[fwspec->param[1]]); return d == gic_data.domain; @@ -1232,6 +1409,9 @@ static int partition_domain_translate(struct irq_domain *d, struct device_node *np; int ret; + if (!gic_data.ppi_descs) + return -ENOMEM; + np = of_find_node_by_phandle(fwspec->param[3]); if (WARN_ON(!np)) return -EINVAL; @@ -1261,11 +1441,65 @@ static bool gic_enable_quirk_msm8996(void *data) return true; } +static bool gic_enable_quirk_hip06_07(void *data) +{ + struct gic_chip_data *d = data; + + /* + * HIP06 GICD_IIDR clashes with GIC-600 product number (despite + * not being an actual ARM implementation). The saving grace is + * that GIC-600 doesn't have ESPI, so nothing to do in that case. + * HIP07 doesn't even have a proper IIDR, and still pretends to + * have ESPI. In both cases, put them right. + */ + if (d->rdists.gicd_typer & GICD_TYPER_ESPI) { + /* Zero both ESPI and the RES0 field next to it... */ + d->rdists.gicd_typer &= ~GENMASK(9, 8); + return true; + } + + return false; +} + +static const struct gic_quirk gic_quirks[] = { + { + .desc = "GICv3: Qualcomm MSM8996 broken firmware", + .compatible = "qcom,msm8996-gic-v3", + .init = gic_enable_quirk_msm8996, + }, + { + .desc = "GICv3: HIP06 erratum 161010803", + .iidr = 0x0204043b, + .mask = 0xffffffff, + .init = gic_enable_quirk_hip06_07, + }, + { + .desc = "GICv3: HIP07 erratum 161010803", + .iidr = 0x00000000, + .mask = 0xffffffff, + .init = gic_enable_quirk_hip06_07, + }, + { + } +}; + static void gic_enable_nmi_support(void) { int i; - for (i = 0; i < 16; i++) + if (!gic_prio_masking_enabled()) + return; + + if (gic_has_group0() && !gic_dist_security_disabled()) { + pr_warn("SCR_EL3.FIQ is cleared, cannot enable use of pseudo-NMIs\n"); + return; + } + + ppi_nmi_refs = kcalloc(gic_data.ppi_nr, sizeof(*ppi_nmi_refs), GFP_KERNEL); + if (!ppi_nmi_refs) + return; + + for (i = 0; i < gic_data.ppi_nr; i++) refcount_set(&ppi_nmi_refs[i], 0); static_branch_enable(&supports_pseudo_nmis); @@ -1283,7 +1517,6 @@ static int __init gic_init_bases(void __iomem *dist_base, struct fwnode_handle *handle) { u32 typer; - int gic_irqs; int err; if (!is_hyp_mode_available()) @@ -1300,15 +1533,15 @@ static int __init gic_init_bases(void __iomem *dist_base, /* * Find out how many interrupts are supported. - * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI) */ typer = readl_relaxed(gic_data.dist_base + GICD_TYPER); gic_data.rdists.gicd_typer = typer; - gic_irqs = GICD_TYPER_IRQS(typer); - if (gic_irqs > 1020) - gic_irqs = 1020; - gic_data.irq_nr = gic_irqs; + gic_enable_quirks(readl_relaxed(gic_data.dist_base + GICD_IIDR), + gic_quirks, &gic_data); + + pr_info("%d SPIs implemented\n", GIC_LINE_NR - 32); + pr_info("%d Extended SPIs implemented\n", GIC_ESPI_NR); gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops, &gic_data); irq_domain_update_bus_token(gic_data.domain, DOMAIN_BUS_WIRED); @@ -1333,7 +1566,7 @@ static int __init gic_init_bases(void __iomem *dist_base, set_handle_irq(gic_handle_irq); - gic_update_vlpi_properties(); + gic_update_rdist_properties(); gic_smp_init(); gic_dist_init(); @@ -1348,12 +1581,7 @@ static int __init gic_init_bases(void __iomem *dist_base, gicv2m_init(handle, gic_data.domain); } - if (gic_prio_masking_enabled()) { - if (!gic_has_group0() || gic_dist_security_disabled()) - gic_enable_nmi_support(); - else - pr_warn("SCR_EL3.FIQ is cleared, cannot enable use of pseudo-NMIs\n"); - } + gic_enable_nmi_support(); return 0; @@ -1386,6 +1614,10 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node) if (!parts_node) return; + gic_data.ppi_descs = kcalloc(gic_data.ppi_nr, sizeof(*gic_data.ppi_descs), GFP_KERNEL); + if (!gic_data.ppi_descs) + return; + nr_parts = of_get_child_count(parts_node); if (!nr_parts) @@ -1437,7 +1669,7 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node) part_idx++; } - for (i = 0; i < 16; i++) { + for (i = 0; i < gic_data.ppi_nr; i++) { unsigned int irq; struct partition_desc *desc; struct irq_fwspec ppi_fwspec = { @@ -1490,16 +1722,6 @@ static void __init gic_of_setup_kvm_info(struct device_node *node) gic_set_kvm_info(&gic_v3_kvm_info); } -static const struct gic_quirk gic_quirks[] = { - { - .desc = "GICv3: Qualcomm MSM8996 broken firmware", - .compatible = "qcom,msm8996-gic-v3", - .init = gic_enable_quirk_msm8996, - }, - { - } -}; - static int __init gic_of_init(struct device_node *node, struct device_node *parent) { void __iomem *dist_base; @@ -1845,7 +2067,7 @@ gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end) if (err) goto out_redist_unmap; - domain_handle = irq_domain_alloc_fwnode(acpi_data.dist_base); + domain_handle = irq_domain_alloc_fwnode(&dist->base_address); if (!domain_handle) { err = -ENOMEM; goto out_redist_unmap; diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index e45f45e68720daaaec5322262ff1329ea4d74128..30ab623343d3b82af9a8037d9ba3ae5bd39e9e37 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -291,6 +291,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) { void __iomem *base = gic_dist_base(d); unsigned int gicirq = gic_irq(d); + int ret; /* Interrupt configuration for SGIs can't be changed */ if (gicirq < 16) @@ -301,7 +302,14 @@ static int gic_set_type(struct irq_data *d, unsigned int type) type != IRQ_TYPE_EDGE_RISING) return -EINVAL; - return gic_configure_irq(gicirq, type, base, NULL); + ret = gic_configure_irq(gicirq, type, base + GIC_DIST_CONFIG, NULL); + if (ret && gicirq < 32) { + /* Misconfigured PPIs are usually not fatal */ + pr_warn("GIC: PPI%d is secure or misconfigured\n", gicirq - 16); + ret = 0; + } + + return ret; } static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) @@ -535,7 +543,7 @@ static int gic_cpu_init(struct gic_chip_data *gic) gic_cpu_map[i] &= ~cpu_mask; } - gic_cpu_config(dist_base, NULL); + gic_cpu_config(dist_base, 32, NULL); writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK); gic_cpu_if_up(gic); @@ -1627,7 +1635,7 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, /* * Initialize GIC instance zero (no multi-GIC support). */ - domain_handle = irq_domain_alloc_fwnode(gic->raw_dist_base); + domain_handle = irq_domain_alloc_fwnode(&dist->base_address); if (!domain_handle) { pr_err("Unable to allocate domain handle\n"); gic_teardown(gic); diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c index cf705827599ca268b1045f56afd692790fa393e5..130caa1c9d939fc5364aebcd1994b4bc98a241b9 100644 --- a/drivers/irqchip/irq-hip04.c +++ b/drivers/irqchip/irq-hip04.c @@ -130,7 +130,12 @@ static int hip04_irq_set_type(struct irq_data *d, unsigned int type) raw_spin_lock(&irq_controller_lock); - ret = gic_configure_irq(irq, type, base, NULL); + ret = gic_configure_irq(irq, type, base + GIC_DIST_CONFIG, NULL); + if (ret && irq < 32) { + /* Misconfigured PPIs are usually not fatal */ + pr_warn("GIC: PPI%d is secure or misconfigured\n", irq - 16); + ret = 0; + } raw_spin_unlock(&irq_controller_lock); @@ -268,7 +273,7 @@ static void hip04_irq_cpu_init(struct hip04_irq_data *intc) if (i != cpu) hip04_cpu_map[i] &= ~cpu_mask; - gic_cpu_config(dist_base, NULL); + gic_cpu_config(dist_base, 32, NULL); writel_relaxed(0xf0, base + GIC_CPU_PRIMASK); writel_relaxed(1, base + GIC_CPU_CTRL); diff --git a/drivers/irqchip/irq-imgpdc.c b/drivers/irqchip/irq-imgpdc.c index d00489a4b54f35f60e0abc0b41a489101d612e15..698d07f48fed8ba92ef96a1f94c40623041f2e89 100644 --- a/drivers/irqchip/irq-imgpdc.c +++ b/drivers/irqchip/irq-imgpdc.c @@ -362,10 +362,8 @@ static int pdc_intc_probe(struct platform_device *pdev) } for (i = 0; i < priv->nr_perips; ++i) { irq = platform_get_irq(pdev, 1 + i); - if (irq < 0) { - dev_err(&pdev->dev, "cannot find perip IRQ #%u\n", i); + if (irq < 0) return irq; - } priv->perip_irqs[i] = irq; } /* check if too many were provided */ @@ -376,10 +374,8 @@ static int pdc_intc_probe(struct platform_device *pdev) /* Get syswake IRQ number */ irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "cannot find syswake IRQ\n"); + if (irq < 0) return irq; - } priv->syswake_irq = irq; /* Set up an IRQ domain */ diff --git a/drivers/irqchip/irq-ixp4xx.c b/drivers/irqchip/irq-ixp4xx.c index 6751c35b7e1d7c001acc7cb88234dc34d1eab3df..37e0749215c70d428087f8b4fedaa320d423aeee 100644 --- a/drivers/irqchip/irq-ixp4xx.c +++ b/drivers/irqchip/irq-ixp4xx.c @@ -319,7 +319,7 @@ void __init ixp4xx_irq_init(resource_size_t irqbase, pr_crit("IXP4XX: could not ioremap interrupt controller\n"); return; } - fwnode = irq_domain_alloc_fwnode(base); + fwnode = irq_domain_alloc_fwnode(&irqbase); if (!fwnode) { pr_crit("IXP4XX: no domain handle\n"); return; diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c index efbcf8435185244cfbfac87f3f36661d88a13ceb..8118ebe80b09ee957ff59c590c1a1b5d9ecf8b57 100644 --- a/drivers/irqchip/irq-keystone.c +++ b/drivers/irqchip/irq-keystone.c @@ -164,10 +164,8 @@ static int keystone_irq_probe(struct platform_device *pdev) } kirq->irq = platform_get_irq(pdev, 0); - if (kirq->irq < 0) { - dev_err(dev, "no irq resource %d\n", kirq->irq); + if (kirq->irq < 0) return kirq->irq; - } kirq->dev = dev; kirq->mask = ~0x0; diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c index dcdc23b9dce6d12fc96d559b26a7ee5459fad812..829084b568fa8bb2c0c8e48be53a5e99cf7f4900 100644 --- a/drivers/irqchip/irq-meson-gpio.c +++ b/drivers/irqchip/irq-meson-gpio.c @@ -24,14 +24,25 @@ #define REG_PIN_47_SEL 0x08 #define REG_FILTER_SEL 0x0c -#define REG_EDGE_POL_MASK(x) (BIT(x) | BIT(16 + (x))) +/* + * Note: The S905X3 datasheet reports that BOTH_EDGE is controlled by + * bits 24 to 31. Tests on the actual HW show that these bits are + * stuck at 0. Bits 8 to 15 are responsive and have the expected + * effect. + */ #define REG_EDGE_POL_EDGE(x) BIT(x) #define REG_EDGE_POL_LOW(x) BIT(16 + (x)) +#define REG_BOTH_EDGE(x) BIT(8 + (x)) +#define REG_EDGE_POL_MASK(x) ( \ + REG_EDGE_POL_EDGE(x) | \ + REG_EDGE_POL_LOW(x) | \ + REG_BOTH_EDGE(x)) #define REG_PIN_SEL_SHIFT(x) (((x) % 4) * 8) #define REG_FILTER_SEL_SHIFT(x) ((x) * 4) struct meson_gpio_irq_params { unsigned int nr_hwirq; + bool support_edge_both; }; static const struct meson_gpio_irq_params meson8_params = { @@ -54,6 +65,11 @@ static const struct meson_gpio_irq_params axg_params = { .nr_hwirq = 100, }; +static const struct meson_gpio_irq_params sm1_params = { + .nr_hwirq = 100, + .support_edge_both = true, +}; + static const struct of_device_id meson_irq_gpio_matches[] = { { .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params }, { .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params }, @@ -61,11 +77,12 @@ static const struct of_device_id meson_irq_gpio_matches[] = { { .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params }, { .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params }, { .compatible = "amlogic,meson-g12a-gpio-intc", .data = &axg_params }, + { .compatible = "amlogic,meson-sm1-gpio-intc", .data = &sm1_params }, { } }; struct meson_gpio_irq_controller { - unsigned int nr_hwirq; + const struct meson_gpio_irq_params *params; void __iomem *base; u32 channel_irqs[NUM_CHANNEL]; DECLARE_BITMAP(channel_map, NUM_CHANNEL); @@ -168,14 +185,22 @@ static int meson_gpio_irq_type_setup(struct meson_gpio_irq_controller *ctl, */ type &= IRQ_TYPE_SENSE_MASK; - if (type == IRQ_TYPE_EDGE_BOTH) - return -EINVAL; + /* + * New controller support EDGE_BOTH trigger. This setting takes + * precedence over the other edge/polarity settings + */ + if (type == IRQ_TYPE_EDGE_BOTH) { + if (!ctl->params->support_edge_both) + return -EINVAL; - if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) - val |= REG_EDGE_POL_EDGE(idx); + val |= REG_BOTH_EDGE(idx); + } else { + if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) + val |= REG_EDGE_POL_EDGE(idx); - if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) - val |= REG_EDGE_POL_LOW(idx); + if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) + val |= REG_EDGE_POL_LOW(idx); + } spin_lock(&ctl->lock); @@ -199,7 +224,7 @@ static unsigned int meson_gpio_irq_type_output(unsigned int type) */ if (sense & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) type |= IRQ_TYPE_LEVEL_HIGH; - else if (sense & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) + else type |= IRQ_TYPE_EDGE_RISING; return type; @@ -328,15 +353,13 @@ static int __init meson_gpio_irq_parse_dt(struct device_node *node, struct meson_gpio_irq_controller *ctl) { const struct of_device_id *match; - const struct meson_gpio_irq_params *params; int ret; match = of_match_node(meson_irq_gpio_matches, node); if (!match) return -ENODEV; - params = match->data; - ctl->nr_hwirq = params->nr_hwirq; + ctl->params = match->data; ret = of_property_read_variable_u32_array(node, "amlogic,channel-interrupts", @@ -385,7 +408,8 @@ static int __init meson_gpio_irq_of_init(struct device_node *node, if (ret) goto free_channel_irqs; - domain = irq_domain_create_hierarchy(parent_domain, 0, ctl->nr_hwirq, + domain = irq_domain_create_hierarchy(parent_domain, 0, + ctl->params->nr_hwirq, of_node_to_fwnode(node), &meson_gpio_irq_domain_ops, ctl); @@ -396,7 +420,7 @@ static int __init meson_gpio_irq_of_init(struct device_node *node, } pr_info("%d to %d gpio interrupt mux initialized\n", - ctl->nr_hwirq, NUM_CHANNEL); + ctl->params->nr_hwirq, NUM_CHANNEL); return 0; diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c index 14618dc0bd396c9d6a2c36baa10fae39463109fd..4a74ac7b7c42e59aedf40b64efefb8a21d5fd32f 100644 --- a/drivers/irqchip/irq-mmp.c +++ b/drivers/irqchip/irq-mmp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ struct icu_chip_data { unsigned int conf_enable; unsigned int conf_disable; unsigned int conf_mask; + unsigned int conf2_mask; unsigned int clr_mfp_irq_base; unsigned int clr_mfp_hwirq; struct irq_domain *domain; @@ -52,9 +54,11 @@ struct mmp_intc_conf { unsigned int conf_enable; unsigned int conf_disable; unsigned int conf_mask; + unsigned int conf2_mask; }; static void __iomem *mmp_icu_base; +static void __iomem *mmp_icu2_base; static struct icu_chip_data icu_data[MAX_ICU_NR]; static int max_icu_nr; @@ -97,6 +101,16 @@ static void icu_mask_irq(struct irq_data *d) r &= ~data->conf_mask; r |= data->conf_disable; writel_relaxed(r, mmp_icu_base + (hwirq << 2)); + + if (data->conf2_mask) { + /* + * ICU1 (above) only controls PJ4 MP1; if using SMP, + * we need to also mask the MP2 and MM cores via ICU2. + */ + r = readl_relaxed(mmp_icu2_base + (hwirq << 2)); + r &= ~data->conf2_mask; + writel_relaxed(r, mmp_icu2_base + (hwirq << 2)); + } } else { r = readl_relaxed(data->reg_mask) | (1 << hwirq); writel_relaxed(r, data->reg_mask); @@ -132,11 +146,14 @@ struct irq_chip icu_irq_chip = { static void icu_mux_irq_demux(struct irq_desc *desc) { unsigned int irq = irq_desc_get_irq(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); struct irq_domain *domain; struct icu_chip_data *data; int i; unsigned long mask, status, n; + chained_irq_enter(chip, desc); + for (i = 1; i < max_icu_nr; i++) { if (irq == icu_data[i].cascade_irq) { domain = icu_data[i].domain; @@ -146,7 +163,7 @@ static void icu_mux_irq_demux(struct irq_desc *desc) } if (i >= max_icu_nr) { pr_err("Spurious irq %d in MMP INTC\n", irq); - return; + goto out; } mask = readl_relaxed(data->reg_mask); @@ -158,6 +175,9 @@ static void icu_mux_irq_demux(struct irq_desc *desc) generic_handle_irq(icu_data[i].virq_base + n); } } + +out: + chained_irq_exit(chip, desc); } static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq, @@ -194,6 +214,14 @@ static const struct mmp_intc_conf mmp2_conf = { MMP2_ICU_INT_ROUTE_PJ4_FIQ, }; +static struct mmp_intc_conf mmp3_conf = { + .conf_enable = 0x20, + .conf_disable = 0x0, + .conf_mask = MMP2_ICU_INT_ROUTE_PJ4_IRQ | + MMP2_ICU_INT_ROUTE_PJ4_FIQ, + .conf2_mask = 0xf0, +}; + static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs) { int hwirq; @@ -395,7 +423,6 @@ static int __init mmp_of_init(struct device_node *node, icu_data[0].conf_enable = mmp_conf.conf_enable; icu_data[0].conf_disable = mmp_conf.conf_disable; icu_data[0].conf_mask = mmp_conf.conf_mask; - irq_set_default_host(icu_data[0].domain); set_handle_irq(mmp_handle_irq); max_icu_nr = 1; return 0; @@ -414,19 +441,50 @@ static int __init mmp2_of_init(struct device_node *node, icu_data[0].conf_enable = mmp2_conf.conf_enable; icu_data[0].conf_disable = mmp2_conf.conf_disable; icu_data[0].conf_mask = mmp2_conf.conf_mask; - irq_set_default_host(icu_data[0].domain); set_handle_irq(mmp2_handle_irq); max_icu_nr = 1; return 0; } IRQCHIP_DECLARE(mmp2_intc, "mrvl,mmp2-intc", mmp2_of_init); +static int __init mmp3_of_init(struct device_node *node, + struct device_node *parent) +{ + int ret; + + mmp_icu2_base = of_iomap(node, 1); + if (!mmp_icu2_base) { + pr_err("Failed to get interrupt controller register #2\n"); + return -ENODEV; + } + + ret = mmp_init_bases(node); + if (ret < 0) { + iounmap(mmp_icu2_base); + return ret; + } + + icu_data[0].conf_enable = mmp3_conf.conf_enable; + icu_data[0].conf_disable = mmp3_conf.conf_disable; + icu_data[0].conf_mask = mmp3_conf.conf_mask; + icu_data[0].conf2_mask = mmp3_conf.conf2_mask; + + if (!parent) { + /* This is the main interrupt controller. */ + set_handle_irq(mmp2_handle_irq); + } + + max_icu_nr = 1; + return 0; +} +IRQCHIP_DECLARE(mmp3_intc, "marvell,mmp3-intc", mmp3_of_init); + static int __init mmp2_mux_of_init(struct device_node *node, struct device_node *parent) { - struct resource res; int i, ret, irq, j = 0; u32 nr_irqs, mfp_irq; + u32 reg[4]; if (!parent) return -ENODEV; @@ -438,18 +496,22 @@ static int __init mmp2_mux_of_init(struct device_node *node, pr_err("Not found mrvl,intc-nr-irqs property\n"); return -EINVAL; } - ret = of_address_to_resource(node, 0, &res); - if (ret < 0) { - pr_err("Not found reg property\n"); - return -EINVAL; - } - icu_data[i].reg_status = mmp_icu_base + res.start; - ret = of_address_to_resource(node, 1, &res); + + /* + * For historical reasons, the "regs" property of the + * mrvl,mmp2-mux-intc is not a regular "regs" property containing + * addresses on the parent bus, but offsets from the intc's base. + * That is why we can't use of_address_to_resource() here. + */ + ret = of_property_read_variable_u32_array(node, "reg", reg, + ARRAY_SIZE(reg), + ARRAY_SIZE(reg)); if (ret < 0) { pr_err("Not found reg property\n"); return -EINVAL; } - icu_data[i].reg_mask = mmp_icu_base + res.start; + icu_data[i].reg_status = mmp_icu_base + reg[0]; + icu_data[i].reg_mask = mmp_icu_base + reg[2]; icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0); if (!icu_data[i].cascade_irq) return -EINVAL; diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index cf755964f2f8b49dde24dda29e0664317f2149b4..c72c036aea768001a19d5d702f490f005f6636cd 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -244,6 +244,7 @@ static int __init plic_init(struct device_node *node, struct plic_handler *handler; irq_hw_number_t hwirq; int cpu, hartid; + u32 threshold = 0; if (of_irq_parse_one(node, i, &parent)) { pr_err("failed to parse parent for context %d.\n", i); @@ -266,10 +267,16 @@ static int __init plic_init(struct device_node *node, continue; } + /* + * When running in M-mode we need to ignore the S-mode handler. + * Here we assume it always comes later, but that might be a + * little fragile. + */ handler = per_cpu_ptr(&plic_handlers, cpu); if (handler->present) { pr_warn("handler already present for context %d.\n", i); - continue; + threshold = 0xffffffff; + goto done; } handler->present = true; @@ -279,8 +286,9 @@ static int __init plic_init(struct device_node *node, handler->enable_base = plic_regs + ENABLE_BASE + i * ENABLE_PER_HART; +done: /* priority must be > threshold to trigger an interrupt */ - writel(0, handler->hart_base + CONTEXT_THRESHOLD); + writel(threshold, handler->hart_base + CONTEXT_THRESHOLD); for (hwirq = 1; hwirq <= nr_irqs; hwirq++) plic_toggle(handler, hwirq, 0); nr_handlers++; diff --git a/drivers/irqchip/irq-uniphier-aidet.c b/drivers/irqchip/irq-uniphier-aidet.c index ed7b4f47ff3f7088304bb264d92f5a672667666f..89121b39be2692de3bc952bd609c07ddd7fd6508 100644 --- a/drivers/irqchip/irq-uniphier-aidet.c +++ b/drivers/irqchip/irq-uniphier-aidet.c @@ -166,7 +166,6 @@ static int uniphier_aidet_probe(struct platform_device *pdev) struct device_node *parent_np; struct irq_domain *parent_domain; struct uniphier_aidet_priv *priv; - struct resource *res; parent_np = of_irq_find_parent(dev->of_node); if (!parent_np) @@ -181,8 +180,7 @@ static int uniphier_aidet_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->reg_base = devm_ioremap_resource(dev, res); + priv->reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->reg_base)) return PTR_ERR(priv->reg_base); diff --git a/drivers/irqchip/qcom-irq-combiner.c b/drivers/irqchip/qcom-irq-combiner.c index d88e993aa66de64363cd379346aa801ba1dd853f..abfe59284ff26edde7d33545b334274c01547687 100644 --- a/drivers/irqchip/qcom-irq-combiner.c +++ b/drivers/irqchip/qcom-irq-combiner.c @@ -248,10 +248,8 @@ static int __init combiner_probe(struct platform_device *pdev) return err; combiner->parent_irq = platform_get_irq(pdev, 0); - if (combiner->parent_irq <= 0) { - dev_err(&pdev->dev, "Error getting IRQ resource\n"); + if (combiner->parent_irq <= 0) return -EPROBE_DEFER; - } combiner->domain = irq_domain_create_linear(pdev->dev.fwnode, combiner->nirqs, &domain_ops, combiner); diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c index 81f2b183acc857cb6d12d970a103ea184d153abd..1137dd152b5cb7f6a2cd2ac43a84c3e9394f268b 100644 --- a/drivers/isdn/hardware/mISDN/avmfritz.c +++ b/drivers/isdn/hardware/mISDN/avmfritz.c @@ -509,8 +509,7 @@ HDLC_irq_xpr(struct bchannel *bch) if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) { hdlc_fill_fifo(bch); } else { - if (bch->tx_skb) - dev_kfree_skb(bch->tx_skb); + dev_kfree_skb(bch->tx_skb); if (get_next_bframe(bch)) { hdlc_fill_fifo(bch); test_and_clear_bit(FLG_TX_EMPTY, &bch->Flags); diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 4a069582fc6b6b1dcfa064739e872529b05448e9..2330a7d24267951de7880bd7d75f48abd3bac940 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -1119,8 +1119,7 @@ tx_birq(struct bchannel *bch) if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) hfcpci_fill_fifo(bch); else { - if (bch->tx_skb) - dev_kfree_skb(bch->tx_skb); + dev_kfree_skb(bch->tx_skb); if (get_next_bframe(bch)) hfcpci_fill_fifo(bch); } @@ -1132,8 +1131,7 @@ tx_dirq(struct dchannel *dch) if (dch->tx_skb && dch->tx_idx < dch->tx_skb->len) hfcpci_fill_dfifo(dch->hw); else { - if (dch->tx_skb) - dev_kfree_skb(dch->tx_skb); + dev_kfree_skb(dch->tx_skb); if (get_next_dframe(dch)) hfcpci_fill_dfifo(dch->hw); } diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c index f915399d75cac83849c8fc9b555ee18125888f59..bca880213e9192b34c10d12890ae9c4a65cf2f22 100644 --- a/drivers/isdn/hardware/mISDN/mISDNipac.c +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c @@ -190,8 +190,7 @@ isac_rme_irq(struct isac_hw *isac) #endif } WriteISAC(isac, ISAC_CMDR, 0x80); - if (isac->dch.rx_skb) - dev_kfree_skb(isac->dch.rx_skb); + dev_kfree_skb(isac->dch.rx_skb); isac->dch.rx_skb = NULL; } else { count = ReadISAC(isac, ISAC_RBCL) & 0x1f; @@ -210,8 +209,7 @@ isac_xpr_irq(struct isac_hw *isac) if (isac->dch.tx_skb && isac->dch.tx_idx < isac->dch.tx_skb->len) { isac_fill_fifo(isac); } else { - if (isac->dch.tx_skb) - dev_kfree_skb(isac->dch.tx_skb); + dev_kfree_skb(isac->dch.tx_skb); if (get_next_dframe(&isac->dch)) isac_fill_fifo(isac); } @@ -464,8 +462,7 @@ isacsx_rme_irq(struct isac_hw *isac) isac->dch.err_crc++; #endif WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC); - if (isac->dch.rx_skb) - dev_kfree_skb(isac->dch.rx_skb); + dev_kfree_skb(isac->dch.rx_skb); isac->dch.rx_skb = NULL; } else { count = ReadISAC(isac, ISACX_RBCLD) & 0x1f; @@ -1012,8 +1009,7 @@ hscx_xpr(struct hscx_hw *hx) if (hx->bch.tx_skb && hx->bch.tx_idx < hx->bch.tx_skb->len) { hscx_fill_fifo(hx); } else { - if (hx->bch.tx_skb) - dev_kfree_skb(hx->bch.tx_skb); + dev_kfree_skb(hx->bch.tx_skb); if (get_next_bframe(&hx->bch)) { hscx_fill_fifo(hx); test_and_clear_bit(FLG_TX_EMPTY, &hx->bch.Flags); diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c index fd5c52f378023ae09785d31f2b1ebd027e818d41..4a3e748a1c26ed0a47573dc82c19a4c845aeac46 100644 --- a/drivers/isdn/hardware/mISDN/mISDNisar.c +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c @@ -690,8 +690,7 @@ send_next(struct isar_ch *ch) } } } - if (ch->bch.tx_skb) - dev_kfree_skb(ch->bch.tx_skb); + dev_kfree_skb(ch->bch.tx_skb); if (get_next_bframe(&ch->bch)) { isar_fill_fifo(ch); test_and_clear_bit(FLG_TX_EMPTY, &ch->bch.Flags); diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index 4e30affd1a7caed0a99f29debfb4a8235237ec2f..61caa7e50b9abac6360a26a87704f5b0e48c7895 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -605,8 +605,7 @@ bc_next_frame(struct tiger_ch *bc) if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len) { fill_dma(bc); } else { - if (bc->bch.tx_skb) - dev_kfree_skb(bc->bch.tx_skb); + dev_kfree_skb(bc->bch.tx_skb); if (get_next_bframe(&bc->bch)) { fill_dma(bc); test_and_clear_bit(FLG_TX_EMPTY, &bc->bch.Flags); diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index 2402608dc98db4687d7a86a5c1d9f17812824b49..bad55fdacd36f0c5fb6de200d161e2021daf27e0 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -356,8 +356,7 @@ handle_rxD(struct w6692_hw *card) { card->dch.err_rx++; #endif } - if (card->dch.rx_skb) - dev_kfree_skb(card->dch.rx_skb); + dev_kfree_skb(card->dch.rx_skb); card->dch.rx_skb = NULL; WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST); } else { @@ -376,8 +375,7 @@ handle_txD(struct w6692_hw *card) { if (card->dch.tx_skb && card->dch.tx_idx < card->dch.tx_skb->len) { W6692_fill_Dfifo(card); } else { - if (card->dch.tx_skb) - dev_kfree_skb(card->dch.tx_skb); + dev_kfree_skb(card->dch.tx_skb); if (get_next_dframe(&card->dch)) W6692_fill_Dfifo(card); } @@ -636,8 +634,7 @@ send_next(struct w6692_ch *wch) if (wch->bch.tx_skb && wch->bch.tx_idx < wch->bch.tx_skb->len) { W6692_fill_Bfifo(wch); } else { - if (wch->bch.tx_skb) - dev_kfree_skb(wch->bch.tx_skb); + dev_kfree_skb(wch->bch.tx_skb); if (get_next_bframe(&wch->bch)) { W6692_fill_Bfifo(wch); test_and_clear_bit(FLG_TX_EMPTY, &wch->bch.Flags); diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index 447f241467bd854d52f0cd0d4d0dca3b76110c35..b57dcb834594de13eb1b90492a38b69a479f1b50 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -1254,8 +1254,7 @@ release_card(struct l1oip *hc) mISDN_freebchannel(hc->chan[ch].bch); kfree(hc->chan[ch].bch); #ifdef REORDER_DEBUG - if (hc->chan[ch].disorder_skb) - dev_kfree_skb(hc->chan[ch].disorder_skb); + dev_kfree_skb(hc->chan[ch].disorder_skb); #endif } } diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index 68a4815167293300825eb2003f3c7d9d2596f379..5bf7fcb282c475366d74aa11e5ff05aeaa0581c0 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c @@ -900,8 +900,7 @@ l2_disconnect(struct FsmInst *fi, int event, void *arg) send_uframe(l2, NULL, DISC | 0x10, CMD); mISDN_FsmDelTimer(&l2->t203, 1); restart_t200(l2, 2); - if (skb) - dev_kfree_skb(skb); + dev_kfree_skb(skb); } static void @@ -1722,8 +1721,7 @@ l2_set_own_busy(struct FsmInst *fi, int event, void *arg) enquiry_cr(l2, RNR, RSP, 0); test_and_clear_bit(FLG_ACK_PEND, &l2->flag); } - if (skb) - dev_kfree_skb(skb); + dev_kfree_skb(skb); } static void @@ -1736,8 +1734,7 @@ l2_clear_own_busy(struct FsmInst *fi, int event, void *arg) enquiry_cr(l2, RR, RSP, 0); test_and_clear_bit(FLG_ACK_PEND, &l2->flag); } - if (skb) - dev_kfree_skb(skb); + dev_kfree_skb(skb); } static void diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index fa2237e7bcf8ddc723b3f7dfc8299948caddcbc2..27aa32914425d5d3b39e5047237c71e2bc5ce486 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c @@ -75,8 +75,7 @@ send_socklist(struct mISDN_sock_list *sl, struct sk_buff *skb) cskb = NULL; } read_unlock(&sl->lock); - if (cskb) - dev_kfree_skb(cskb); + dev_kfree_skb(cskb); } static void @@ -134,8 +133,7 @@ send_layer2(struct mISDNstack *st, struct sk_buff *skb) } out: mutex_unlock(&st->lmutex); - if (skb) - dev_kfree_skb(skb); + dev_kfree_skb(skb); } static inline int diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index a4fa594e1caf7e5f08c3fba2991ab41aea071bfd..59d28cb19738ee5d3f1b51617be7675205766b24 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -1328,10 +1328,8 @@ mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb) } out: read_unlock_irqrestore(&mgr->lock, flags); - if (cskb) - dev_kfree_skb(cskb); - if (skb) - dev_kfree_skb(skb); + dev_kfree_skb(cskb); + dev_kfree_skb(skb); return 0; } diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index b0fdeef10bd914e68cd51b8aa56c0427a222a692..1988de1d64c05dcc843072b0b1cf1eba3f207f26 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -74,9 +74,12 @@ config LEDS_APU depends on LEDS_CLASS depends on X86 && DMI help - This driver makes the PC Engines APU/APU2/APU3 front panel LEDs + This driver makes the PC Engines APU1 front panel LEDs accessible from userspace programs through the LED subsystem. + If you're looking for APU2/3, use the pcengines-apu2 driver. + (symbol CONFIG_PCENGINES_APU2) + To compile this driver as a module, choose M here: the module will be called leds-apu. @@ -587,6 +590,7 @@ config LEDS_NETXBIG tristate "LED support for Big Network series LEDs" depends on LEDS_CLASS depends on MACH_KIRKWOOD + depends on OF_GPIO default y help This option enables support for LEDs found on the LaCie 2Big diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c index 94980c654d8934621043e132f591d747fad95d5c..60c3de5c6b9f9bb4d7e83f2da3f2629a33cd281f 100644 --- a/drivers/leds/led-class-flash.c +++ b/drivers/leds/led-class-flash.c @@ -282,8 +282,9 @@ static void led_flash_init_sysfs_groups(struct led_classdev_flash *fled_cdev) led_cdev->groups = flash_groups; } -int led_classdev_flash_register(struct device *parent, - struct led_classdev_flash *fled_cdev) +int led_classdev_flash_register_ext(struct device *parent, + struct led_classdev_flash *fled_cdev, + struct led_init_data *init_data) { struct led_classdev *led_cdev; const struct led_flash_ops *ops; @@ -309,13 +310,13 @@ int led_classdev_flash_register(struct device *parent, } /* Register led class device */ - ret = led_classdev_register(parent, led_cdev); + ret = led_classdev_register_ext(parent, led_cdev, init_data); if (ret < 0) return ret; return 0; } -EXPORT_SYMBOL_GPL(led_classdev_flash_register); +EXPORT_SYMBOL_GPL(led_classdev_flash_register_ext); void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev) { diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 4793e77808e2c72dffb621600d7ab3e399fc8c7f..647b1263c5794e1cc485447627a5b59afd566a95 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -213,13 +214,6 @@ static int led_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(leds_class_dev_pm_ops, led_suspend, led_resume); -static int match_name(struct device *dev, const void *data) -{ - if (!dev_name(dev)) - return 0; - return !strcmp(dev_name(dev), (char *)data); -} - static int led_classdev_next_name(const char *init_name, char *name, size_t len) { @@ -230,7 +224,7 @@ static int led_classdev_next_name(const char *init_name, char *name, strlcpy(name, init_name, len); while ((ret < len) && - (dev = class_find_device(leds_class, NULL, name, match_name))) { + (dev = class_find_device_by_name(leds_class, name))) { put_device(dev); ret = snprintf(name, len, "%s_%u", init_name, ++i); } @@ -242,31 +236,48 @@ static int led_classdev_next_name(const char *init_name, char *name, } /** - * of_led_classdev_register - register a new object of led_classdev class. + * led_classdev_register_ext - register a new object of led_classdev class + * with init data. * * @parent: parent of LED device * @led_cdev: the led_classdev structure for this device. - * @np: DT node describing this LED + * @init_data: LED class device initialization data */ -int of_led_classdev_register(struct device *parent, struct device_node *np, - struct led_classdev *led_cdev) +int led_classdev_register_ext(struct device *parent, + struct led_classdev *led_cdev, + struct led_init_data *init_data) { - char name[LED_MAX_NAME_SIZE]; + char composed_name[LED_MAX_NAME_SIZE]; + char final_name[LED_MAX_NAME_SIZE]; + const char *proposed_name = composed_name; int ret; - ret = led_classdev_next_name(led_cdev->name, name, sizeof(name)); + if (init_data) { + if (init_data->devname_mandatory && !init_data->devicename) { + dev_err(parent, "Mandatory device name is missing"); + return -EINVAL; + } + ret = led_compose_name(parent, init_data, composed_name); + if (ret < 0) + return ret; + } else { + proposed_name = led_cdev->name; + } + + ret = led_classdev_next_name(proposed_name, final_name, sizeof(final_name)); if (ret < 0) return ret; mutex_init(&led_cdev->led_access); mutex_lock(&led_cdev->led_access); led_cdev->dev = device_create_with_groups(leds_class, parent, 0, - led_cdev, led_cdev->groups, "%s", name); + led_cdev, led_cdev->groups, "%s", final_name); if (IS_ERR(led_cdev->dev)) { mutex_unlock(&led_cdev->led_access); return PTR_ERR(led_cdev->dev); } - led_cdev->dev->of_node = np; + if (init_data && init_data->fwnode) + led_cdev->dev->fwnode = init_data->fwnode; if (ret) dev_warn(parent, "Led %s renamed to %s due to name collision", @@ -276,6 +287,7 @@ int of_led_classdev_register(struct device *parent, struct device_node *np, ret = led_add_brightness_hw_changed(led_cdev); if (ret) { device_unregister(led_cdev->dev); + led_cdev->dev = NULL; mutex_unlock(&led_cdev->led_access); return ret; } @@ -311,7 +323,7 @@ int of_led_classdev_register(struct device *parent, struct device_node *np, return 0; } -EXPORT_SYMBOL_GPL(of_led_classdev_register); +EXPORT_SYMBOL_GPL(led_classdev_register_ext); /** * led_classdev_unregister - unregisters a object of led_properties class. @@ -321,6 +333,9 @@ EXPORT_SYMBOL_GPL(of_led_classdev_register); */ void led_classdev_unregister(struct led_classdev *led_cdev) { + if (IS_ERR_OR_NULL(led_cdev->dev)) + return; + #ifdef CONFIG_LEDS_TRIGGERS down_write(&led_cdev->trigger_lock); if (led_cdev->trigger) @@ -356,14 +371,15 @@ static void devm_led_classdev_release(struct device *dev, void *res) } /** - * devm_of_led_classdev_register - resource managed led_classdev_register() + * devm_led_classdev_register_ext - resource managed led_classdev_register_ext() * * @parent: parent of LED device * @led_cdev: the led_classdev structure for this device. + * @init_data: LED class device initialization data */ -int devm_of_led_classdev_register(struct device *parent, - struct device_node *np, - struct led_classdev *led_cdev) +int devm_led_classdev_register_ext(struct device *parent, + struct led_classdev *led_cdev, + struct led_init_data *init_data) { struct led_classdev **dr; int rc; @@ -372,7 +388,7 @@ int devm_of_led_classdev_register(struct device *parent, if (!dr) return -ENOMEM; - rc = of_led_classdev_register(parent, np, led_cdev); + rc = led_classdev_register_ext(parent, led_cdev, init_data); if (rc) { devres_free(dr); return rc; @@ -383,7 +399,7 @@ int devm_of_led_classdev_register(struct device *parent, return 0; } -EXPORT_SYMBOL_GPL(devm_of_led_classdev_register); +EXPORT_SYMBOL_GPL(devm_led_classdev_register_ext); static int devm_led_classdev_match(struct device *dev, void *res, void *data) { diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index 7107cd7e87cfde458fb0f24d0183c6de1566fa82..f1f718dbe0f873ebf72ac0ff10a0e1db8ab01496 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c @@ -13,8 +13,10 @@ #include #include #include +#include #include #include +#include #include "leds.h" DECLARE_RWSEM(leds_list_lock); @@ -23,6 +25,18 @@ EXPORT_SYMBOL_GPL(leds_list_lock); LIST_HEAD(leds_list); EXPORT_SYMBOL_GPL(leds_list); +const char * const led_colors[LED_COLOR_ID_MAX] = { + [LED_COLOR_ID_WHITE] = "white", + [LED_COLOR_ID_RED] = "red", + [LED_COLOR_ID_GREEN] = "green", + [LED_COLOR_ID_BLUE] = "blue", + [LED_COLOR_ID_AMBER] = "amber", + [LED_COLOR_ID_VIOLET] = "violet", + [LED_COLOR_ID_YELLOW] = "yellow", + [LED_COLOR_ID_IR] = "ir", +}; +EXPORT_SYMBOL_GPL(led_colors); + static int __led_set_brightness(struct led_classdev *led_cdev, enum led_brightness value) { @@ -310,14 +324,11 @@ EXPORT_SYMBOL_GPL(led_update_brightness); u32 *led_get_default_pattern(struct led_classdev *led_cdev, unsigned int *size) { - struct device_node *np = dev_of_node(led_cdev->dev); + struct fwnode_handle *fwnode = led_cdev->dev->fwnode; u32 *pattern; int count; - if (!np) - return NULL; - - count = of_property_count_u32_elems(np, "led-pattern"); + count = fwnode_property_count_u32(fwnode, "led-pattern"); if (count < 0) return NULL; @@ -325,7 +336,7 @@ u32 *led_get_default_pattern(struct led_classdev *led_cdev, unsigned int *size) if (!pattern) return NULL; - if (of_property_read_u32_array(np, "led-pattern", pattern, count)) { + if (fwnode_property_read_u32_array(fwnode, "led-pattern", pattern, count)) { kfree(pattern); return NULL; } @@ -353,3 +364,116 @@ void led_sysfs_enable(struct led_classdev *led_cdev) led_cdev->flags &= ~LED_SYSFS_DISABLE; } EXPORT_SYMBOL_GPL(led_sysfs_enable); + +static void led_parse_fwnode_props(struct device *dev, + struct fwnode_handle *fwnode, + struct led_properties *props) +{ + int ret; + + if (!fwnode) + return; + + if (fwnode_property_present(fwnode, "label")) { + ret = fwnode_property_read_string(fwnode, "label", &props->label); + if (ret) + dev_err(dev, "Error parsing 'label' property (%d)\n", ret); + return; + } + + if (fwnode_property_present(fwnode, "color")) { + ret = fwnode_property_read_u32(fwnode, "color", &props->color); + if (ret) + dev_err(dev, "Error parsing 'color' property (%d)\n", ret); + else if (props->color >= LED_COLOR_ID_MAX) + dev_err(dev, "LED color identifier out of range\n"); + else + props->color_present = true; + } + + + if (!fwnode_property_present(fwnode, "function")) + return; + + ret = fwnode_property_read_string(fwnode, "function", &props->function); + if (ret) { + dev_err(dev, + "Error parsing 'function' property (%d)\n", + ret); + } + + if (!fwnode_property_present(fwnode, "function-enumerator")) + return; + + ret = fwnode_property_read_u32(fwnode, "function-enumerator", + &props->func_enum); + if (ret) { + dev_err(dev, + "Error parsing 'function-enumerator' property (%d)\n", + ret); + } else { + props->func_enum_present = true; + } +} + +int led_compose_name(struct device *dev, struct led_init_data *init_data, + char *led_classdev_name) +{ + struct led_properties props = {}; + struct fwnode_handle *fwnode = init_data->fwnode; + const char *devicename = init_data->devicename; + + if (!led_classdev_name) + return -EINVAL; + + led_parse_fwnode_props(dev, fwnode, &props); + + if (props.label) { + /* + * If init_data.devicename is NULL, then it indicates that + * DT label should be used as-is for LED class device name. + * Otherwise the label is prepended with devicename to compose + * the final LED class device name. + */ + if (!devicename) { + strscpy(led_classdev_name, props.label, + LED_MAX_NAME_SIZE); + } else { + snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s", + devicename, props.label); + } + } else if (props.function || props.color_present) { + char tmp_buf[LED_MAX_NAME_SIZE]; + + if (props.func_enum_present) { + snprintf(tmp_buf, LED_MAX_NAME_SIZE, "%s:%s-%d", + props.color_present ? led_colors[props.color] : "", + props.function ?: "", props.func_enum); + } else { + snprintf(tmp_buf, LED_MAX_NAME_SIZE, "%s:%s", + props.color_present ? led_colors[props.color] : "", + props.function ?: ""); + } + if (init_data->devname_mandatory) { + snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s", + devicename, tmp_buf); + } else { + strscpy(led_classdev_name, tmp_buf, LED_MAX_NAME_SIZE); + + } + } else if (init_data->default_label) { + if (!devicename) { + dev_err(dev, "Legacy LED naming requires devicename segment"); + return -EINVAL; + } + snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s", + devicename, init_data->default_label); + } else if (is_of_node(fwnode)) { + strscpy(led_classdev_name, to_of_node(fwnode)->name, + LED_MAX_NAME_SIZE); + } else + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL_GPL(led_compose_name); diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 8d11a5e23227105795d55c15c8379cc04e8145da..23963e5cb5d6a1d10c27f3256288314302ba2bdf 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -167,12 +167,13 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) trig->deactivate(led_cdev); err_activate: - led_cdev->trigger = NULL; - led_cdev->trigger_data = NULL; write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags); list_del(&led_cdev->trig_list); write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags); + led_cdev->trigger = NULL; + led_cdev->trigger_data = NULL; led_set_brightness(led_cdev, LED_OFF); + kfree(event); return ret; } diff --git a/drivers/leds/leds-aat1290.c b/drivers/leds/leds-aat1290.c index bf26f5bed1f096cf3d12a0f6630137ff7fc81233..5a0fe7b7b8bc7ed03bd519b60970e9386ea728f6 100644 --- a/drivers/leds/leds-aat1290.c +++ b/drivers/leds/leds-aat1290.c @@ -42,6 +42,8 @@ #define AAT1290_FLASH_TM_NUM_LEVELS 16 #define AAT1290_MM_CURRENT_SCALE_SIZE 15 +#define AAT1290_NAME "aat1290" + struct aat1290_led_config_data { /* maximum LED current in movie mode */ @@ -75,7 +77,6 @@ struct aat1290_led { int *mm_current_scale; /* device mode */ bool movie_mode; - /* brightness cache */ unsigned int torch_brightness; }; @@ -215,7 +216,6 @@ static int aat1290_led_parse_dt(struct aat1290_led *led, struct aat1290_led_config_data *cfg, struct device_node **sub_node) { - struct led_classdev *led_cdev = &led->fled_cdev.led_cdev; struct device *dev = &led->pdev->dev; struct device_node *child_node; #if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) @@ -254,9 +254,6 @@ static int aat1290_led_parse_dt(struct aat1290_led *led, return -EINVAL; } - led_cdev->name = of_get_property(child_node, "label", NULL) ? : - child_node->name; - ret = of_property_read_u32(child_node, "led-max-microamp", &cfg->max_mm_current); /* @@ -428,7 +425,7 @@ static void aat1290_init_v4l2_flash_config(struct aat1290_led *led, struct led_classdev *led_cdev = &led->fled_cdev.led_cdev; struct led_flash_setting *s; - strlcpy(v4l2_sd_cfg->dev_name, led_cdev->name, + strlcpy(v4l2_sd_cfg->dev_name, led_cdev->dev->kobj.name, sizeof(v4l2_sd_cfg->dev_name)); s = &v4l2_sd_cfg->intensity; @@ -466,6 +463,7 @@ static int aat1290_led_probe(struct platform_device *pdev) struct aat1290_led *led; struct led_classdev *led_cdev; struct led_classdev_flash *fled_cdev; + struct led_init_data init_data = {}; struct aat1290_led_config_data led_cfg = {}; struct v4l2_flash_config v4l2_sd_cfg = {}; int ret; @@ -494,8 +492,12 @@ static int aat1290_led_probe(struct platform_device *pdev) aat1290_init_flash_timeout(led, &led_cfg); + init_data.fwnode = of_fwnode_handle(sub_node); + init_data.devicename = AAT1290_NAME; + /* Register LED Flash class device */ - ret = led_classdev_flash_register(&pdev->dev, fled_cdev); + ret = led_classdev_flash_register_ext(&pdev->dev, fled_cdev, + &init_data); if (ret < 0) goto err_flash_register; diff --git a/drivers/leds/leds-an30259a.c b/drivers/leds/leds-an30259a.c index 1c1f0c8c56f4b85c953a1e8a80a89bd630518001..250dc9d6f63502d7145b0797f77780aadf04c87b 100644 --- a/drivers/leds/leds-an30259a.c +++ b/drivers/leds/leds-an30259a.c @@ -13,7 +13,6 @@ #include #include #include -#include #define AN30259A_MAX_LEDS 3 @@ -54,6 +53,8 @@ #define AN30259A_BLINK_MAX_TIME 7500 /* ms */ #define AN30259A_SLOPE_RESOLUTION 500 /* ms */ +#define AN30259A_NAME "an30259a" + #define STATE_OFF 0 #define STATE_KEEP 1 #define STATE_ON 2 @@ -62,11 +63,11 @@ struct an30259a; struct an30259a_led { struct an30259a *chip; + struct fwnode_handle *fwnode; struct led_classdev cdev; u32 num; u32 default_state; bool sloping; - char label[LED_MAX_NAME_SIZE]; }; struct an30259a { @@ -226,14 +227,7 @@ static int an30259a_dt_init(struct i2c_client *client, led->num = source; led->chip = chip; - - if (of_property_read_string(child, "label", &str)) - snprintf(led->label, sizeof(led->label), "an30259a::"); - else - snprintf(led->label, sizeof(led->label), "an30259a:%s", - str); - - led->cdev.name = led->label; + led->fwnode = of_fwnode_handle(child); if (!of_property_read_string(child, "default-state", &str)) { if (!strcmp(str, "on")) @@ -312,13 +306,20 @@ static int an30259a_probe(struct i2c_client *client) chip->regmap = devm_regmap_init_i2c(client, &an30259a_regmap_config); for (i = 0; i < chip->num_leds; i++) { + struct led_init_data init_data = {}; + an30259a_init_default_state(&chip->leds[i]); chip->leds[i].cdev.brightness_set_blocking = an30259a_brightness_set; chip->leds[i].cdev.blink_set = an30259a_blink_set; - err = devm_led_classdev_register(&client->dev, - &chip->leds[i].cdev); + init_data.fwnode = chip->leds[i].fwnode; + init_data.devicename = AN30259A_NAME; + init_data.default_label = ":"; + + err = devm_led_classdev_register_ext(&client->dev, + &chip->leds[i].cdev, + &init_data); if (err < 0) goto exit; } @@ -353,7 +354,7 @@ MODULE_DEVICE_TABLE(i2c, an30259a_id); static struct i2c_driver an30259a_driver = { .driver = { - .name = "leds-an32059a", + .name = "leds-an30259a", .of_match_table = of_match_ptr(an30259a_match_table), }, .probe_new = an30259a_probe, @@ -364,5 +365,5 @@ static struct i2c_driver an30259a_driver = { module_i2c_driver(an30259a_driver); MODULE_AUTHOR("Simon Shields "); -MODULE_DESCRIPTION("AN32059A LED driver"); +MODULE_DESCRIPTION("AN30259A LED driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/leds-apu.c b/drivers/leds/leds-apu.c index 8d42e46e2de34878c57ee08938903a6b541956d4..7fd557aceff6970a17be7534ae71747e756c6ccf 100644 --- a/drivers/leds/leds-apu.c +++ b/drivers/leds/leds-apu.c @@ -31,6 +31,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -47,12 +49,6 @@ #define APU1_NUM_GPIO 3 #define APU1_IOSIZE sizeof(u8) -#define APU2_FCH_ACPI_MMIO_BASE 0xFED80000 -#define APU2_FCH_GPIO_BASE (APU2_FCH_ACPI_MMIO_BASE + 0x1500) -#define APU2_GPIO_BIT_WRITE 22 -#define APU2_APU2_NUM_GPIO 4 -#define APU2_IOSIZE sizeof(u32) - /* LED access parameters */ struct apu_param { void __iomem *addr; /* for ioread/iowrite */ @@ -72,19 +68,9 @@ struct apu_led_profile { unsigned long offset; /* for devm_ioremap */ }; -/* Supported platform types */ -enum apu_led_platform_types { - APU1_LED_PLATFORM, - APU2_LED_PLATFORM, -}; - struct apu_led_pdata { struct platform_device *pdev; struct apu_led_priv *pled; - const struct apu_led_profile *profile; - enum apu_led_platform_types platform; - int num_led_instances; - int iosize; /* for devm_ioremap() */ spinlock_t lock; }; @@ -96,19 +82,6 @@ static const struct apu_led_profile apu1_led_profile[] = { { "apu:green:3", LED_OFF, APU1_FCH_GPIO_BASE + 2 * APU1_IOSIZE }, }; -static const struct apu_led_profile apu2_led_profile[] = { - { "apu2:green:1", LED_ON, APU2_FCH_GPIO_BASE + 68 * APU2_IOSIZE }, - { "apu2:green:2", LED_OFF, APU2_FCH_GPIO_BASE + 69 * APU2_IOSIZE }, - { "apu2:green:3", LED_OFF, APU2_FCH_GPIO_BASE + 70 * APU2_IOSIZE }, -}; - -/* Same as apu2_led_profile, but with "3" in the LED names. */ -static const struct apu_led_profile apu3_led_profile[] = { - { "apu3:green:1", LED_ON, APU2_FCH_GPIO_BASE + 68 * APU2_IOSIZE }, - { "apu3:green:2", LED_OFF, APU2_FCH_GPIO_BASE + 69 * APU2_IOSIZE }, - { "apu3:green:3", LED_OFF, APU2_FCH_GPIO_BASE + 70 * APU2_IOSIZE }, -}; - static const struct dmi_system_id apu_led_dmi_table[] __initconst = { { .ident = "apu", @@ -117,54 +90,6 @@ static const struct dmi_system_id apu_led_dmi_table[] __initconst = { DMI_MATCH(DMI_PRODUCT_NAME, "APU") } }, - /* PC Engines APU2 with "Legacy" bios < 4.0.8 */ - { - .ident = "apu2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"), - DMI_MATCH(DMI_BOARD_NAME, "APU2") - } - }, - /* PC Engines APU2 with "Legacy" bios >= 4.0.8 */ - { - .ident = "apu2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"), - DMI_MATCH(DMI_BOARD_NAME, "apu2") - } - }, - /* PC Engines APU2 with "Mainline" bios */ - { - .ident = "apu2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"), - DMI_MATCH(DMI_BOARD_NAME, "PC Engines apu2") - } - }, - /* PC Engines APU3 with "Legacy" bios < 4.0.8 */ - { - .ident = "apu3", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"), - DMI_MATCH(DMI_BOARD_NAME, "APU3") - } - }, - /* PC Engines APU3 with "Legacy" bios >= 4.0.8 */ - { - .ident = "apu3", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"), - DMI_MATCH(DMI_BOARD_NAME, "apu3") - } - }, - /* PC Engines APU2 with "Mainline" bios */ - { - .ident = "apu3", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"), - DMI_MATCH(DMI_BOARD_NAME, "PC Engines apu3") - } - }, {} }; MODULE_DEVICE_TABLE(dmi, apu_led_dmi_table); @@ -178,52 +103,30 @@ static void apu1_led_brightness_set(struct led_classdev *led, enum led_brightnes spin_unlock(&apu_led->lock); } -static void apu2_led_brightness_set(struct led_classdev *led, enum led_brightness value) -{ - struct apu_led_priv *pled = cdev_to_priv(led); - u32 value_new; - - spin_lock(&apu_led->lock); - - value_new = ioread32(pled->param.addr); - - if (value) - value_new &= ~BIT(APU2_GPIO_BIT_WRITE); - else - value_new |= BIT(APU2_GPIO_BIT_WRITE); - - iowrite32(value_new, pled->param.addr); - - spin_unlock(&apu_led->lock); -} - static int apu_led_config(struct device *dev, struct apu_led_pdata *apuld) { int i; int err; apu_led->pled = devm_kcalloc(dev, - apu_led->num_led_instances, sizeof(struct apu_led_priv), + ARRAY_SIZE(apu1_led_profile), sizeof(struct apu_led_priv), GFP_KERNEL); if (!apu_led->pled) return -ENOMEM; - for (i = 0; i < apu_led->num_led_instances; i++) { + for (i = 0; i < ARRAY_SIZE(apu1_led_profile); i++) { struct apu_led_priv *pled = &apu_led->pled[i]; struct led_classdev *led_cdev = &pled->cdev; - led_cdev->name = apu_led->profile[i].name; - led_cdev->brightness = apu_led->profile[i].brightness; + led_cdev->name = apu1_led_profile[i].name; + led_cdev->brightness = apu1_led_profile[i].brightness; led_cdev->max_brightness = 1; led_cdev->flags = LED_CORE_SUSPENDRESUME; - if (apu_led->platform == APU1_LED_PLATFORM) - led_cdev->brightness_set = apu1_led_brightness_set; - else if (apu_led->platform == APU2_LED_PLATFORM) - led_cdev->brightness_set = apu2_led_brightness_set; + led_cdev->brightness_set = apu1_led_brightness_set; pled->param.addr = devm_ioremap(dev, - apu_led->profile[i].offset, apu_led->iosize); + apu1_led_profile[i].offset, APU1_IOSIZE); if (!pled->param.addr) { err = -ENOMEM; goto error; @@ -233,7 +136,7 @@ static int apu_led_config(struct device *dev, struct apu_led_pdata *apuld) if (err) goto error; - led_cdev->brightness_set(led_cdev, apu_led->profile[i].brightness); + apu1_led_brightness_set(led_cdev, apu1_led_profile[i].brightness); } return 0; @@ -254,28 +157,6 @@ static int __init apu_led_probe(struct platform_device *pdev) apu_led->pdev = pdev; - if (dmi_match(DMI_PRODUCT_NAME, "APU")) { - apu_led->profile = apu1_led_profile; - apu_led->platform = APU1_LED_PLATFORM; - apu_led->num_led_instances = ARRAY_SIZE(apu1_led_profile); - apu_led->iosize = APU1_IOSIZE; - } else if (dmi_match(DMI_BOARD_NAME, "APU2") || - dmi_match(DMI_BOARD_NAME, "apu2") || - dmi_match(DMI_BOARD_NAME, "PC Engines apu2")) { - apu_led->profile = apu2_led_profile; - apu_led->platform = APU2_LED_PLATFORM; - apu_led->num_led_instances = ARRAY_SIZE(apu2_led_profile); - apu_led->iosize = APU2_IOSIZE; - } else if (dmi_match(DMI_BOARD_NAME, "APU3") || - dmi_match(DMI_BOARD_NAME, "apu3") || - dmi_match(DMI_BOARD_NAME, "PC Engines apu3")) { - apu_led->profile = apu3_led_profile; - /* Otherwise identical to APU2. */ - apu_led->platform = APU2_LED_PLATFORM; - apu_led->num_led_instances = ARRAY_SIZE(apu3_led_profile); - apu_led->iosize = APU2_IOSIZE; - } - spin_lock_init(&apu_led->lock); return apu_led_config(&pdev->dev, apu_led); } @@ -291,19 +172,9 @@ static int __init apu_led_init(void) struct platform_device *pdev; int err; - if (!dmi_match(DMI_SYS_VENDOR, "PC Engines")) { - pr_err("No PC Engines board detected\n"); - return -ENODEV; - } - if (!(dmi_match(DMI_PRODUCT_NAME, "APU") || - dmi_match(DMI_PRODUCT_NAME, "APU2") || - dmi_match(DMI_PRODUCT_NAME, "apu2") || - dmi_match(DMI_PRODUCT_NAME, "PC Engines apu2") || - dmi_match(DMI_PRODUCT_NAME, "APU3") || - dmi_match(DMI_PRODUCT_NAME, "apu3") || - dmi_match(DMI_PRODUCT_NAME, "PC Engines apu3"))) { - pr_err("Unknown PC Engines board: %s\n", - dmi_get_system_info(DMI_PRODUCT_NAME)); + if (!(dmi_match(DMI_SYS_VENDOR, "PC Engines") && + dmi_match(DMI_PRODUCT_NAME, "APU"))) { + pr_err("No PC Engines APUv1 board detected. For APUv2,3 support, enable CONFIG_PCENGINES_APU2\n"); return -ENODEV; } @@ -326,7 +197,7 @@ static void __exit apu_led_exit(void) { int i; - for (i = 0; i < apu_led->num_led_instances; i++) + for (i = 0; i < ARRAY_SIZE(apu1_led_profile); i++) led_classdev_unregister(&apu_led->pled[i].cdev); platform_device_unregister(apu_led->pdev); @@ -337,6 +208,6 @@ module_init(apu_led_init); module_exit(apu_led_exit); MODULE_AUTHOR("Alan Mizrahi"); -MODULE_DESCRIPTION("PC Engines APU family LED driver"); +MODULE_DESCRIPTION("PC Engines APU1 front LED driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:leds_apu"); diff --git a/drivers/leds/leds-as3645a.c b/drivers/leds/leds-as3645a.c index 14ab6b0e4de9c4e21de601ade468cb8441eb549d..b7e0ae1af8fa5d57a68ffdbd8423b69222dc53e5 100644 --- a/drivers/leds/leds-as3645a.c +++ b/drivers/leds/leds-as3645a.c @@ -124,11 +124,6 @@ struct as3645a_config { u32 peak; }; -struct as3645a_names { - char flash[32]; - char indicator[32]; -}; - struct as3645a { struct i2c_client *client; @@ -484,12 +479,10 @@ static int as3645a_detect(struct as3645a *flash) } static int as3645a_parse_node(struct as3645a *flash, - struct as3645a_names *names, struct fwnode_handle *fwnode) { struct as3645a_config *cfg = &flash->cfg; struct fwnode_handle *child; - const char *name; int rval; fwnode_for_each_child_node(fwnode, child) { @@ -517,17 +510,6 @@ static int as3645a_parse_node(struct as3645a *flash, return -ENODEV; } - rval = fwnode_property_read_string(flash->flash_node, "label", &name); - if (!rval) { - strlcpy(names->flash, name, sizeof(names->flash)); - } else if (is_of_node(fwnode)) { - snprintf(names->flash, sizeof(names->flash), - "%pOFn:flash", to_of_node(fwnode)); - } else { - dev_err(&flash->client->dev, "flash node has no label!\n"); - return -EINVAL; - } - rval = fwnode_property_read_u32(flash->flash_node, "flash-timeout-us", &cfg->flash_timeout_us); if (rval < 0) { @@ -565,17 +547,6 @@ static int as3645a_parse_node(struct as3645a *flash, goto out_err; } - rval = fwnode_property_read_string(flash->indicator_node, "label", - &name); - if (!rval) { - strlcpy(names->indicator, name, sizeof(names->indicator)); - } else if (is_of_node(fwnode)) { - snprintf(names->indicator, sizeof(names->indicator), - "%pOFn:indicator", to_of_node(fwnode)); - } else { - dev_err(&flash->client->dev, "indicator node has no label!\n"); - return -EINVAL; - } rval = fwnode_property_read_u32(flash->indicator_node, "led-max-microamp", @@ -595,21 +566,25 @@ static int as3645a_parse_node(struct as3645a *flash, return rval; } -static int as3645a_led_class_setup(struct as3645a *flash, - struct as3645a_names *names) +static int as3645a_led_class_setup(struct as3645a *flash) { struct led_classdev *fled_cdev = &flash->fled.led_cdev; struct led_classdev *iled_cdev = &flash->iled_cdev; + struct led_init_data init_data = {}; struct led_flash_setting *cfg; int rval; - iled_cdev->name = names->indicator; iled_cdev->brightness_set_blocking = as3645a_set_indicator_brightness; iled_cdev->max_brightness = flash->cfg.indicator_max_ua / AS_INDICATOR_INTENSITY_STEP; iled_cdev->flags = LED_CORE_SUSPENDRESUME; - rval = led_classdev_register(&flash->client->dev, iled_cdev); + init_data.fwnode = flash->indicator_node; + init_data.devicename = AS_NAME; + init_data.default_label = "indicator"; + + rval = led_classdev_register_ext(&flash->client->dev, iled_cdev, + &init_data); if (rval < 0) return rval; @@ -627,7 +602,6 @@ static int as3645a_led_class_setup(struct as3645a *flash, flash->fled.ops = &as3645a_led_flash_ops; - fled_cdev->name = names->flash; fled_cdev->brightness_set_blocking = as3645a_set_assist_brightness; /* Value 0 is off in LED class. */ fled_cdev->max_brightness = @@ -635,15 +609,23 @@ static int as3645a_led_class_setup(struct as3645a *flash, flash->cfg.assist_max_ua) + 1; fled_cdev->flags = LED_DEV_CAP_FLASH | LED_CORE_SUSPENDRESUME; - rval = led_classdev_flash_register(&flash->client->dev, &flash->fled); - if (rval) { - led_classdev_unregister(iled_cdev); - dev_err(&flash->client->dev, - "led_classdev_flash_register() failed, error %d\n", - rval); - } + init_data.fwnode = flash->flash_node; + init_data.devicename = AS_NAME; + init_data.default_label = "flash"; + + rval = led_classdev_flash_register_ext(&flash->client->dev, + &flash->fled, &init_data); + if (rval) + goto out_err; return rval; + +out_err: + led_classdev_unregister(iled_cdev); + dev_err(&flash->client->dev, + "led_classdev_flash_register() failed, error %d\n", + rval); + return rval; } static int as3645a_v4l2_setup(struct as3645a *flash) @@ -667,8 +649,9 @@ static int as3645a_v4l2_setup(struct as3645a *flash) }, }; - strlcpy(cfg.dev_name, led->name, sizeof(cfg.dev_name)); - strlcpy(cfgind.dev_name, flash->iled_cdev.name, sizeof(cfg.dev_name)); + strlcpy(cfg.dev_name, led->dev->kobj.name, sizeof(cfg.dev_name)); + strlcpy(cfgind.dev_name, flash->iled_cdev.dev->kobj.name, + sizeof(cfgind.dev_name)); flash->vf = v4l2_flash_init( &flash->client->dev, flash->flash_node, &flash->fled, NULL, @@ -689,7 +672,6 @@ static int as3645a_v4l2_setup(struct as3645a *flash) static int as3645a_probe(struct i2c_client *client) { - struct as3645a_names names; struct as3645a *flash; int rval; @@ -702,7 +684,7 @@ static int as3645a_probe(struct i2c_client *client) flash->client = client; - rval = as3645a_parse_node(flash, &names, dev_fwnode(&client->dev)); + rval = as3645a_parse_node(flash, dev_fwnode(&client->dev)); if (rval < 0) return rval; @@ -717,7 +699,7 @@ static int as3645a_probe(struct i2c_client *client) if (rval) goto out_mutex_destroy; - rval = as3645a_led_class_setup(flash, &names); + rval = as3645a_led_class_setup(flash); if (rval) goto out_mutex_destroy; diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c index 0e4262462cb9d34ca1a6a767b1ad813cd537bcb2..2da448ae718e9b075543e108dcb683a250b61a86 100644 --- a/drivers/leds/leds-cr0014114.c +++ b/drivers/leds/leds-cr0014114.c @@ -8,7 +8,6 @@ #include #include #include -#include /* * CR0014114 SPI protocol descrtiption: @@ -40,8 +39,9 @@ #define CR_FW_DELAY_MSEC 10 #define CR_RECOUNT_DELAY (HZ * 3600) +#define CR_DEV_NAME "cr0014114" + struct cr0014114_led { - char name[LED_MAX_NAME_SIZE]; struct cr0014114 *priv; struct led_classdev ldev; u8 brightness; @@ -167,8 +167,7 @@ static int cr0014114_set_sync(struct led_classdev *ldev, struct cr0014114_led, ldev); - dev_dbg(led->priv->dev, "Set brightness of %s to %d\n", - led->name, brightness); + dev_dbg(led->priv->dev, "Set brightness to %d\n", brightness); mutex_lock(&led->priv->lock); led->brightness = (u8)brightness; @@ -183,42 +182,32 @@ static int cr0014114_probe_dt(struct cr0014114 *priv) size_t i = 0; struct cr0014114_led *led; struct fwnode_handle *child; - struct device_node *np; + struct led_init_data init_data = {}; int ret; - const char *str; device_for_each_child_node(priv->dev, child) { - np = to_of_node(child); led = &priv->leds[i]; - ret = fwnode_property_read_string(child, "label", &str); - if (ret) - snprintf(led->name, sizeof(led->name), - "cr0014114::"); - else - snprintf(led->name, sizeof(led->name), - "cr0014114:%s", str); - fwnode_property_read_string(child, "linux,default-trigger", &led->ldev.default_trigger); led->priv = priv; - led->ldev.name = led->name; led->ldev.max_brightness = CR_MAX_BRIGHTNESS; led->ldev.brightness_set_blocking = cr0014114_set_sync; - ret = devm_of_led_classdev_register(priv->dev, np, - &led->ldev); + init_data.fwnode = child; + init_data.devicename = CR_DEV_NAME; + init_data.default_label = ":"; + + ret = devm_led_classdev_register_ext(priv->dev, &led->ldev, + &init_data); if (ret) { dev_err(priv->dev, - "failed to register LED device %s, err %d", - led->name, ret); + "failed to register LED device, err %d", ret); fwnode_handle_put(child); return ret; } - led->ldev.dev->of_node = np; - i++; } diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index bdc98ddca1dc07d631c95d2ae1dd7186299cf8d8..a5c73f3d5f797dc63b2ee03c738a213a9f8529fb 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -73,11 +73,11 @@ static int gpio_blink_set(struct led_classdev *led_cdev, static int create_gpio_led(const struct gpio_led *template, struct gpio_led_data *led_dat, struct device *parent, - struct device_node *np, gpio_blink_set_t blink_set) + struct fwnode_handle *fwnode, gpio_blink_set_t blink_set) { + struct led_init_data init_data = {}; int ret, state; - led_dat->cdev.name = template->name; led_dat->cdev.default_trigger = template->default_trigger; led_dat->can_sleep = gpiod_cansleep(led_dat->gpiod); if (!led_dat->can_sleep) @@ -108,7 +108,16 @@ static int create_gpio_led(const struct gpio_led *template, if (ret < 0) return ret; - return devm_of_led_classdev_register(parent, np, &led_dat->cdev); + if (template->name) { + led_dat->cdev.name = template->name; + ret = devm_led_classdev_register(parent, &led_dat->cdev); + } else { + init_data.fwnode = fwnode; + ret = devm_led_classdev_register_ext(parent, &led_dat->cdev, + &init_data); + } + + return ret; } struct gpio_leds_priv { @@ -141,15 +150,6 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) struct gpio_led_data *led_dat = &priv->leds[priv->num_leds]; struct gpio_led led = {}; const char *state = NULL; - struct device_node *np = to_of_node(child); - - ret = fwnode_property_read_string(child, "label", &led.name); - if (ret && IS_ENABLED(CONFIG_OF) && np) - led.name = np->name; - if (!led.name) { - fwnode_handle_put(child); - return ERR_PTR(-EINVAL); - } led.gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL, child, GPIOD_ASIS, @@ -181,7 +181,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) if (fwnode_property_present(child, "panic-indicator")) led.panic_indicator = 1; - ret = create_gpio_led(&led, led_dat, dev, np, NULL); + ret = create_gpio_led(&led, led_dat, dev, child, NULL); if (ret < 0) { fwnode_handle_put(child); return ERR_PTR(ret); diff --git a/drivers/leds/leds-is31fl319x.c b/drivers/leds/leds-is31fl319x.c index 2d077b8edd0ebeaaec00f866f5cb656088826a8a..ca6634b8683cb65c2bec3922f104e5d3bb0f0bfe 100644 --- a/drivers/leds/leds-is31fl319x.c +++ b/drivers/leds/leds-is31fl319x.c @@ -333,12 +333,11 @@ static int is31fl319x_probe(struct i2c_client *client, { struct is31fl319x_chip *is31; struct device *dev = &client->dev; - struct i2c_adapter *adapter = to_i2c_adapter(dev->parent); int err; int i = 0; u32 aggregated_led_microamp = IS31FL319X_CURRENT_MAX; - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -EIO; is31 = devm_kzalloc(&client->dev, sizeof(*is31), GFP_KERNEL); diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c index 6fbab70dfb04d25c8ed2ea317cceb3dc92f34a42..6f29b8943913bbfc20ff1d3180c576563dfac8b2 100644 --- a/drivers/leds/leds-is31fl32xx.c +++ b/drivers/leds/leds-is31fl32xx.c @@ -324,12 +324,6 @@ static int is31fl32xx_init_regs(struct is31fl32xx_priv *priv) return 0; } -static inline size_t sizeof_is31fl32xx_priv(int num_leds) -{ - return sizeof(struct is31fl32xx_priv) + - (sizeof(struct is31fl32xx_led_data) * num_leds); -} - static int is31fl32xx_parse_child_dt(const struct device *dev, const struct device_node *child, struct is31fl32xx_led_data *led_data) @@ -450,7 +444,7 @@ static int is31fl32xx_probe(struct i2c_client *client, if (!count) return -EINVAL; - priv = devm_kzalloc(dev, sizeof_is31fl32xx_priv(count), + priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/drivers/leds/leds-ktd2692.c b/drivers/leds/leds-ktd2692.c index f63918206bfbd4180f574f8e130cad50bf9d7671..670efee9b1317affa4eb80d2c4f8866223e96cdf 100644 --- a/drivers/leds/leds-ktd2692.c +++ b/drivers/leds/leds-ktd2692.c @@ -19,7 +19,7 @@ /* Value related the movie mode */ #define KTD2692_MOVIE_MODE_CURRENT_LEVELS 16 #define KTD2692_MM_TO_FL_RATIO(x) ((x) / 3) -#define KTD2962_MM_MIN_CURR_THRESHOLD_SCALE 8 +#define KTD2692_MM_MIN_CURR_THRESHOLD_SCALE 8 /* Value related the flash mode */ #define KTD2692_FLASH_MODE_TIMEOUT_LEVELS 8 @@ -250,7 +250,7 @@ static void ktd2692_setup(struct ktd2692_context *led) ktd2692_expresswire_reset(led); gpiod_direction_output(led->aux_gpio, KTD2692_LOW); - ktd2692_expresswire_write(led, (KTD2962_MM_MIN_CURR_THRESHOLD_SCALE - 1) + ktd2692_expresswire_write(led, (KTD2692_MM_MIN_CURR_THRESHOLD_SCALE - 1) | KTD2692_REG_MM_MIN_CURR_THRESHOLD_BASE); ktd2692_expresswire_write(led, KTD2692_FLASH_MODE_CURR_PERCENT(45) | KTD2692_REG_FLASH_CURRENT_BASE); diff --git a/drivers/leds/leds-lm3532.c b/drivers/leds/leds-lm3532.c index 180895b83b888c635f0810fbbb7595217982d0bf..0507c6575c0896853b47ba735c2fef332141b600 100644 --- a/drivers/leds/leds-lm3532.c +++ b/drivers/leds/leds-lm3532.c @@ -23,11 +23,11 @@ #define LM3532_REG_PWM_B_CFG 0x14 #define LM3532_REG_PWM_C_CFG 0x15 #define LM3532_REG_ZONE_CFG_A 0x16 -#define LM3532_REG_CTRL_A_BRT 0x17 +#define LM3532_REG_CTRL_A_FS_CURR 0x17 #define LM3532_REG_ZONE_CFG_B 0x18 -#define LM3532_REG_CTRL_B_BRT 0x19 +#define LM3532_REG_CTRL_B_FS_CURR 0x19 #define LM3532_REG_ZONE_CFG_C 0x1a -#define LM3532_REG_CTRL_C_BRT 0x1b +#define LM3532_REG_CTRL_C_FS_CURR 0x1b #define LM3532_REG_ENABLE 0x1d #define LM3532_ALS_CONFIG 0x23 #define LM3532_REG_ZN_0_HI 0x60 @@ -38,9 +38,12 @@ #define LM3532_REG_ZN_2_LO 0x65 #define LM3532_REG_ZN_3_HI 0x66 #define LM3532_REG_ZN_3_LO 0x67 +#define LM3532_REG_ZONE_TRGT_A 0x70 +#define LM3532_REG_ZONE_TRGT_B 0x75 +#define LM3532_REG_ZONE_TRGT_C 0x7a #define LM3532_REG_MAX 0x7e -/* Contorl Enable */ +/* Control Enable */ #define LM3532_CTRL_A_ENABLE BIT(0) #define LM3532_CTRL_B_ENABLE BIT(1) #define LM3532_CTRL_C_ENABLE BIT(2) @@ -86,6 +89,10 @@ #define LM3532_NUM_AVG_VALS 8 #define LM3532_NUM_IMP_VALS 32 +#define LM3532_FS_CURR_MIN 5000 +#define LM3532_FS_CURR_MAX 29800 +#define LM3532_FS_CURR_STEP 800 + /* * struct lm3532_als_data * @config - value of ALS configuration register @@ -116,8 +123,11 @@ struct lm3532_als_data { * @priv - Pointer the device data structure * @control_bank - Control bank the LED is associated to * @mode - Mode of the LED string + * @ctrl_brt_pointer - Zone target register that controls the sink * @num_leds - Number of LED strings are supported in this array + * @full_scale_current - The full-scale current setting for the current sink. * @led_strings - The LED strings supported in this array + * @enabled - Enabled status * @label - LED label */ struct lm3532_led { @@ -126,7 +136,10 @@ struct lm3532_led { int control_bank; int mode; + int ctrl_brt_pointer; int num_leds; + int full_scale_current; + int enabled:1; u32 led_strings[LM3532_MAX_CONTROL_BANKS]; char label[LED_MAX_NAME_SIZE]; }; @@ -168,11 +181,11 @@ static const struct reg_default lm3532_reg_defs[] = { {LM3532_REG_PWM_B_CFG, 0x82}, {LM3532_REG_PWM_C_CFG, 0x82}, {LM3532_REG_ZONE_CFG_A, 0xf1}, - {LM3532_REG_CTRL_A_BRT, 0xf3}, + {LM3532_REG_CTRL_A_FS_CURR, 0xf3}, {LM3532_REG_ZONE_CFG_B, 0xf1}, - {LM3532_REG_CTRL_B_BRT, 0xf3}, + {LM3532_REG_CTRL_B_FS_CURR, 0xf3}, {LM3532_REG_ZONE_CFG_C, 0xf1}, - {LM3532_REG_CTRL_C_BRT, 0xf3}, + {LM3532_REG_CTRL_C_FS_CURR, 0xf3}, {LM3532_REG_ENABLE, 0xf8}, {LM3532_ALS_CONFIG, 0x44}, {LM3532_REG_ZN_0_HI, 0x35}, @@ -195,7 +208,7 @@ static const struct regmap_config lm3532_regmap_config = { .cache_type = REGCACHE_FLAT, }; -const static int als_imp_table[LM3532_NUM_IMP_VALS] = {37000, 18500, 12330, +static const int als_imp_table[LM3532_NUM_IMP_VALS] = {37000, 18500, 12330, 92500, 7400, 6170, 5290, 4630, 4110, 3700, 3360, 3080, 2850, 2640, 2440, @@ -252,7 +265,7 @@ static int lm3532_get_index(const int table[], int size, int value) return -EINVAL; } -const static int als_avrg_table[LM3532_NUM_AVG_VALS] = {17920, 35840, 71680, +static const int als_avrg_table[LM3532_NUM_AVG_VALS] = {17920, 35840, 71680, 1433360, 286720, 573440, 1146880, 2293760}; static int lm3532_get_als_avg_index(int avg_time) @@ -267,7 +280,7 @@ static int lm3532_get_als_avg_index(int avg_time) avg_time); } -const static int ramp_table[LM3532_NUM_RAMP_VALS] = { 8, 1024, 2048, 4096, 8192, +static const int ramp_table[LM3532_NUM_RAMP_VALS] = { 8, 1024, 2048, 4096, 8192, 16384, 32768, 65536}; static int lm3532_get_ramp_index(int ramp_time) { @@ -281,11 +294,15 @@ static int lm3532_get_ramp_index(int ramp_time) ramp_time); } +/* Caller must take care of locking */ static int lm3532_led_enable(struct lm3532_led *led_data) { int ctrl_en_val = BIT(led_data->control_bank); int ret; + if (led_data->enabled) + return 0; + ret = regmap_update_bits(led_data->priv->regmap, LM3532_REG_ENABLE, ctrl_en_val, ctrl_en_val); if (ret) { @@ -293,22 +310,38 @@ static int lm3532_led_enable(struct lm3532_led *led_data) return ret; } - return regulator_enable(led_data->priv->regulator); + ret = regulator_enable(led_data->priv->regulator); + if (ret < 0) + return ret; + + led_data->enabled = 1; + + return 0; } +/* Caller must take care of locking */ static int lm3532_led_disable(struct lm3532_led *led_data) { int ctrl_en_val = BIT(led_data->control_bank); int ret; + if (!led_data->enabled) + return 0; + ret = regmap_update_bits(led_data->priv->regmap, LM3532_REG_ENABLE, - ctrl_en_val, ~ctrl_en_val); + ctrl_en_val, 0); if (ret) { dev_err(led_data->priv->dev, "Failed to set ctrl:%d\n", ret); return ret; } - return regulator_disable(led_data->priv->regulator); + ret = regulator_disable(led_data->priv->regulator); + if (ret < 0) + return ret; + + led_data->enabled = 0; + + return 0; } static int lm3532_brightness_set(struct led_classdev *led_cdev, @@ -321,7 +354,7 @@ static int lm3532_brightness_set(struct led_classdev *led_cdev, mutex_lock(&led->priv->lock); - if (led->mode == LM3532_BL_MODE_ALS) { + if (led->mode == LM3532_ALS_CTRL) { if (brt_val > LED_OFF) ret = lm3532_led_enable(led); else @@ -339,8 +372,8 @@ static int lm3532_brightness_set(struct led_classdev *led_cdev, if (ret) goto unlock; - brightness_reg = LM3532_REG_CTRL_A_BRT + led->control_bank * 2; - brt_val = brt_val / LM3532_BRT_VAL_ADJUST; + brightness_reg = LM3532_REG_ZONE_TRGT_A + led->control_bank * 5 + + (led->ctrl_brt_pointer >> 2); ret = regmap_write(led->priv->regmap, brightness_reg, brt_val); @@ -356,8 +389,43 @@ static int lm3532_init_registers(struct lm3532_led *led) unsigned int output_cfg_val = 0; unsigned int output_cfg_shift = 0; unsigned int output_cfg_mask = 0; + unsigned int brightness_config_reg; + unsigned int brightness_config_val; + int fs_current_reg; + int fs_current_val; int ret, i; + if (drvdata->enable_gpio) + gpiod_direction_output(drvdata->enable_gpio, 1); + + brightness_config_reg = LM3532_REG_ZONE_CFG_A + led->control_bank * 2; + /* + * This could be hard coded to the default value but the control + * brightness register may have changed during boot. + */ + ret = regmap_read(drvdata->regmap, brightness_config_reg, + &led->ctrl_brt_pointer); + if (ret) + return ret; + + led->ctrl_brt_pointer &= LM3532_ZONE_MASK; + brightness_config_val = led->ctrl_brt_pointer | led->mode; + ret = regmap_write(drvdata->regmap, brightness_config_reg, + brightness_config_val); + if (ret) + return ret; + + if (led->full_scale_current) { + fs_current_reg = LM3532_REG_CTRL_A_FS_CURR + led->control_bank * 2; + fs_current_val = (led->full_scale_current - LM3532_FS_CURR_MIN) / + LM3532_FS_CURR_STEP; + + ret = regmap_write(drvdata->regmap, fs_current_reg, + fs_current_val); + if (ret) + return ret; + } + for (i = 0; i < led->num_leds; i++) { output_cfg_shift = led->led_strings[i] * 2; output_cfg_val |= (led->control_bank << output_cfg_shift); @@ -382,7 +450,6 @@ static int lm3532_als_configure(struct lm3532_data *priv, struct lm3532_als_data *als = priv->als_data; u32 als_vmin, als_vmax, als_vstep; int zone_reg = LM3532_REG_ZN_0_HI; - int brightnes_config_reg; int ret; int i; @@ -411,14 +478,7 @@ static int lm3532_als_configure(struct lm3532_data *priv, als->config = (als->als_avrg_time | (LM3532_ENABLE_ALS) | (als->als_input_mode << LM3532_ALS_SEL_SHIFT)); - ret = regmap_write(priv->regmap, LM3532_ALS_CONFIG, als->config); - if (ret) - return ret; - - brightnes_config_reg = LM3532_REG_ZONE_CFG_A + led->control_bank * 2; - - return regmap_update_bits(priv->regmap, brightnes_config_reg, - LM3532_I2C_CTRL, LM3532_ALS_CTRL); + return regmap_write(priv->regmap, LM3532_ALS_CONFIG, als->config); } static int lm3532_parse_als(struct lm3532_data *priv) @@ -541,18 +601,27 @@ static int lm3532_parse_node(struct lm3532_data *priv) goto child_out; } + if (fwnode_property_present(child, "led-max-microamp") && + fwnode_property_read_u32(child, "led-max-microamp", + &led->full_scale_current)) + dev_err(&priv->client->dev, + "Failed getting led-max-microamp\n"); + else + led->full_scale_current = min(led->full_scale_current, + LM3532_FS_CURR_MAX); + if (led->mode == LM3532_BL_MODE_ALS) { + led->mode = LM3532_ALS_CTRL; ret = lm3532_parse_als(priv); if (ret) dev_err(&priv->client->dev, "Failed to parse als\n"); else lm3532_als_configure(priv, led); + } else { + led->mode = LM3532_I2C_CTRL; } - led->num_leds = fwnode_property_read_u32_array(child, - "led-sources", - NULL, 0); - + led->num_leds = fwnode_property_count_u32(child, "led-sources"); if (led->num_leds > LM3532_MAX_LED_STRINGS) { dev_err(&priv->client->dev, "To many LED string defined\n"); continue; @@ -590,7 +659,13 @@ static int lm3532_parse_node(struct lm3532_data *priv) goto child_out; } - lm3532_init_registers(led); + ret = lm3532_init_registers(led); + if (ret) { + dev_err(&priv->client->dev, "register init err: %d\n", + ret); + fwnode_handle_put(child); + goto child_out; + } i++; } @@ -637,9 +712,6 @@ static int lm3532_probe(struct i2c_client *client, return ret; } - if (drvdata->enable_gpio) - gpiod_direction_output(drvdata->enable_gpio, 1); - return ret; } diff --git a/drivers/leds/leds-lm3601x.c b/drivers/leds/leds-lm3601x.c index 081aa71e43a32c51cc21f02d094006ea757a1e18..b02972f1a34155039bcb432f82adfd7c81c371ca 100644 --- a/drivers/leds/leds-lm3601x.c +++ b/drivers/leds/leds-lm3601x.c @@ -10,7 +10,6 @@ #include #include #include -#include #define LM3601X_LED_IR 0x0 #define LM3601X_LED_TORCH 0x1 @@ -90,8 +89,6 @@ struct lm3601x_led { struct regmap *regmap; struct mutex lock; - char led_name[LED_MAX_NAME_SIZE]; - unsigned int flash_timeout; unsigned int last_flag; @@ -322,10 +319,12 @@ static const struct led_flash_ops flash_ops = { .fault_get = lm3601x_flash_fault_get, }; -static int lm3601x_register_leds(struct lm3601x_led *led) +static int lm3601x_register_leds(struct lm3601x_led *led, + struct fwnode_handle *fwnode) { struct led_classdev *led_cdev; struct led_flash_setting *setting; + struct led_init_data init_data = {}; led->fled_cdev.ops = &flash_ops; @@ -342,20 +341,25 @@ static int lm3601x_register_leds(struct lm3601x_led *led) setting->val = led->flash_current_max; led_cdev = &led->fled_cdev.led_cdev; - led_cdev->name = led->led_name; led_cdev->brightness_set_blocking = lm3601x_brightness_set; led_cdev->max_brightness = DIV_ROUND_UP(led->torch_current_max, LM3601X_TORCH_REG_DIV); led_cdev->flags |= LED_DEV_CAP_FLASH; - return led_classdev_flash_register(&led->client->dev, &led->fled_cdev); + init_data.fwnode = fwnode; + init_data.devicename = led->client->name; + init_data.default_label = (led->led_mode == LM3601X_LED_TORCH) ? + "torch" : "infrared"; + + return led_classdev_flash_register_ext(&led->client->dev, + &led->fled_cdev, &init_data); } -static int lm3601x_parse_node(struct lm3601x_led *led) +static int lm3601x_parse_node(struct lm3601x_led *led, + struct fwnode_handle **fwnode) { struct fwnode_handle *child = NULL; int ret = -ENODEV; - const char *name; child = device_get_next_child_node(&led->client->dev, child); if (!child) { @@ -376,17 +380,6 @@ static int lm3601x_parse_node(struct lm3601x_led *led) goto out_err; } - ret = fwnode_property_read_string(child, "label", &name); - if (ret) { - if (led->led_mode == LM3601X_LED_TORCH) - name = "torch"; - else - name = "infrared"; - } - - snprintf(led->led_name, sizeof(led->led_name), - "%s:%s", led->client->name, name); - ret = fwnode_property_read_u32(child, "led-max-microamp", &led->torch_current_max); if (ret) { @@ -411,6 +404,8 @@ static int lm3601x_parse_node(struct lm3601x_led *led) goto out_err; } + *fwnode = child; + out_err: fwnode_handle_put(child); return ret; @@ -419,6 +414,7 @@ static int lm3601x_parse_node(struct lm3601x_led *led) static int lm3601x_probe(struct i2c_client *client) { struct lm3601x_led *led; + struct fwnode_handle *fwnode; int ret; led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL); @@ -428,7 +424,7 @@ static int lm3601x_probe(struct i2c_client *client) led->client = client; i2c_set_clientdata(client, led); - ret = lm3601x_parse_node(led); + ret = lm3601x_parse_node(led, &fwnode); if (ret) return -ENODEV; @@ -442,7 +438,7 @@ static int lm3601x_probe(struct i2c_client *client) mutex_init(&led->lock); - return lm3601x_register_leds(led); + return lm3601x_register_leds(led, fwnode); } static int lm3601x_remove(struct i2c_client *client) diff --git a/drivers/leds/leds-lm36274.c b/drivers/leds/leds-lm36274.c index ed9dc857ec8f324abef9ed2009109304262e6644..836b60c9a2b80865461e586556e230761fcc2014 100644 --- a/drivers/leds/leds-lm36274.c +++ b/drivers/leds/leds-lm36274.c @@ -90,9 +90,7 @@ static int lm36274_parse_dt(struct lm36274 *lm36274_data) snprintf(label, sizeof(label), "%s:%s", lm36274_data->pdev->name, name); - lm36274_data->num_leds = fwnode_property_read_u32_array(child, - "led-sources", - NULL, 0); + lm36274_data->num_leds = fwnode_property_count_u32(child, "led-sources"); if (lm36274_data->num_leds <= 0) return -ENODEV; diff --git a/drivers/leds/leds-lm3692x.c b/drivers/leds/leds-lm3692x.c index 4f413a7c5f05669c3f57275e37f0e5e200002c27..3d381f2f73d04014e93e9c7738df85e57168cfe0 100644 --- a/drivers/leds/leds-lm3692x.c +++ b/drivers/leds/leds-lm3692x.c @@ -13,7 +13,6 @@ #include #include #include -#include #define LM36922_MODEL 0 #define LM36923_MODEL 1 @@ -103,7 +102,6 @@ * @regmap - Devices register map * @enable_gpio - VDDIO/EN gpio to enable communication interface * @regulator - LED supply regulator pointer - * @label - LED label * @led_enable - LED sync to be enabled * @model_id - Current device model ID enumerated */ @@ -114,7 +112,6 @@ struct lm3692x_led { struct regmap *regmap; struct gpio_desc *enable_gpio; struct regulator *regulator; - char label[LED_MAX_NAME_SIZE]; int led_enable; int model_id; }; @@ -325,7 +322,7 @@ static int lm3692x_init(struct lm3692x_led *led) static int lm3692x_probe_dt(struct lm3692x_led *led) { struct fwnode_handle *child = NULL; - const char *name; + struct led_init_data init_data = {}; int ret; led->enable_gpio = devm_gpiod_get_optional(&led->client->dev, @@ -350,30 +347,23 @@ static int lm3692x_probe_dt(struct lm3692x_led *led) fwnode_property_read_string(child, "linux,default-trigger", &led->led_dev.default_trigger); - ret = fwnode_property_read_string(child, "label", &name); - if (ret) - snprintf(led->label, sizeof(led->label), - "%s::", led->client->name); - else - snprintf(led->label, sizeof(led->label), - "%s:%s", led->client->name, name); - ret = fwnode_property_read_u32(child, "reg", &led->led_enable); if (ret) { dev_err(&led->client->dev, "reg DT property missing\n"); return ret; } - led->led_dev.name = led->label; + init_data.fwnode = child; + init_data.devicename = led->client->name; + init_data.default_label = ":"; - ret = devm_led_classdev_register(&led->client->dev, &led->led_dev); + ret = devm_led_classdev_register_ext(&led->client->dev, &led->led_dev, + &init_data); if (ret) { dev_err(&led->client->dev, "led register err: %d\n", ret); return ret; } - led->led_dev.dev->of_node = to_of_node(child); - return 0; } diff --git a/drivers/leds/leds-lm3697.c b/drivers/leds/leds-lm3697.c index 54e0e35df8246e54781b0f97cfb5ab23ff49957c..b71711aff8a3cb3fa8e9983ff34e1a19fdcc86ab 100644 --- a/drivers/leds/leds-lm3697.c +++ b/drivers/leds/leds-lm3697.c @@ -244,10 +244,7 @@ static int lm3697_probe_dt(struct lm3697 *priv) led->lmu_data.lsb_brightness_reg = LM3697_CTRL_A_BRT_LSB + led->control_bank * 2; - led->num_leds = fwnode_property_read_u32_array(child, - "led-sources", - NULL, 0); - + led->num_leds = fwnode_property_count_u32(child, "led-sources"); if (led->num_leds > LM3697_MAX_LED_STRINGS) { dev_err(&priv->client->dev, "To many LED strings defined\n"); continue; diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c index 37632fc637414a4a43b0279543b9bf91051f7b5d..edb57c42e8b1d0b7cd6449e4da9a603a3872312b 100644 --- a/drivers/leds/leds-lp5562.c +++ b/drivers/leds/leds-lp5562.c @@ -260,7 +260,11 @@ static void lp5562_firmware_loaded(struct lp55xx_chip *chip) { const struct firmware *fw = chip->fw; - if (fw->size > LP5562_PROGRAM_LENGTH) { + /* + * the firmware is encoded in ascii hex character, with 2 chars + * per byte + */ + if (fw->size > (LP5562_PROGRAM_LENGTH * 2)) { dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n", fw->size); return; diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c index ed680d0c15b0be70bc41dc285e8b45df3a439033..ac2f5d6272dc0e7389bed88b76a1d2e943590576 100644 --- a/drivers/leds/leds-lp8860.c +++ b/drivers/leds/leds-lp8860.c @@ -18,7 +18,6 @@ #include #include #include -#include #define LP8860_DISP_CL1_BRT_MSB 0x00 #define LP8860_DISP_CL1_BRT_LSB 0x01 @@ -83,6 +82,8 @@ #define LP8860_CLEAR_FAULTS 0x01 +#define LP8860_NAME "lp8860" + /** * struct lp8860_led - * @lock - Lock for reading/writing the device @@ -92,7 +93,6 @@ * @eeprom_regmap - EEPROM register map * @enable_gpio - VDDIO/EN gpio to enable communication interface * @regulator - LED supply regulator pointer - * @label - LED label */ struct lp8860_led { struct mutex lock; @@ -102,7 +102,6 @@ struct lp8860_led { struct regmap *eeprom_regmap; struct gpio_desc *enable_gpio; struct regulator *regulator; - char label[LED_MAX_NAME_SIZE]; }; struct lp8860_eeprom_reg { @@ -383,25 +382,19 @@ static int lp8860_probe(struct i2c_client *client, struct lp8860_led *led; struct device_node *np = client->dev.of_node; struct device_node *child_node; - const char *name; + struct led_init_data init_data = {}; led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM; - for_each_available_child_of_node(np, child_node) { - led->led_dev.default_trigger = of_get_property(child_node, - "linux,default-trigger", - NULL); - - ret = of_property_read_string(child_node, "label", &name); - if (!ret) - snprintf(led->label, sizeof(led->label), "%s:%s", - id->name, name); - else - snprintf(led->label, sizeof(led->label), - "%s::display_cluster", id->name); - } + child_node = of_get_next_available_child(np, NULL); + if (!child_node) + return -EINVAL; + + led->led_dev.default_trigger = of_get_property(child_node, + "linux,default-trigger", + NULL); led->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_LOW); @@ -416,7 +409,6 @@ static int lp8860_probe(struct i2c_client *client, led->regulator = NULL; led->client = client; - led->led_dev.name = led->label; led->led_dev.brightness_set_blocking = lp8860_brightness_set; mutex_init(&led->lock); @@ -443,7 +435,12 @@ static int lp8860_probe(struct i2c_client *client, if (ret) return ret; - ret = devm_led_classdev_register(&client->dev, &led->led_dev); + init_data.fwnode = of_fwnode_handle(child_node); + init_data.devicename = LP8860_NAME; + init_data.default_label = ":display_cluster"; + + ret = devm_led_classdev_register_ext(&client->dev, &led->led_dev, + &init_data); if (ret) { dev_err(&client->dev, "led register err: %d\n", ret); return ret; diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c index 83e8e58d81cb8b20df2273889771d75ed8b24d12..c94995f0daa2af5cffb16323f060867673b60f8f 100644 --- a/drivers/leds/leds-lt3593.c +++ b/drivers/leds/leds-lt3593.c @@ -10,10 +10,10 @@ #include #include #include -#include + +#define LED_LT3593_NAME "lt3593" struct lt3593_led_data { - char name[LED_MAX_NAME_SIZE]; struct led_classdev cdev; struct gpio_desc *gpiod; }; @@ -66,6 +66,7 @@ static int lt3593_led_probe(struct platform_device *pdev) struct lt3593_led_data *led_data; struct fwnode_handle *child; int ret, state = LEDS_GPIO_DEFSTATE_OFF; + struct led_init_data init_data = {}; const char *tmp; if (!dev->of_node) @@ -86,14 +87,6 @@ static int lt3593_led_probe(struct platform_device *pdev) child = device_get_next_child_node(dev, NULL); - ret = fwnode_property_read_string(child, "label", &tmp); - if (ret < 0) - snprintf(led_data->name, sizeof(led_data->name), - "lt3593::"); - else - snprintf(led_data->name, sizeof(led_data->name), - "lt3593:%s", tmp); - fwnode_property_read_string(child, "linux,default-trigger", &led_data->cdev.default_trigger); @@ -102,11 +95,14 @@ static int lt3593_led_probe(struct platform_device *pdev) state = LEDS_GPIO_DEFSTATE_ON; } - led_data->cdev.name = led_data->name; led_data->cdev.brightness_set_blocking = lt3593_led_set; led_data->cdev.brightness = state ? LED_FULL : LED_OFF; - ret = devm_led_classdev_register(dev, &led_data->cdev); + init_data.fwnode = child; + init_data.devicename = LED_LT3593_NAME; + init_data.default_label = ":"; + + ret = devm_led_classdev_register_ext(dev, &led_data->cdev, &init_data); if (ret < 0) { fwnode_handle_put(child); return ret; diff --git a/drivers/leds/leds-max77650.c b/drivers/leds/leds-max77650.c index 8a8e5c65b157ab3425df4c67ad2c9d010ee0a407..4c2d0b3c6dadcc1492d2d25d5dc3a9f8d4480bde 100644 --- a/drivers/leds/leds-max77650.c +++ b/drivers/leds/leds-max77650.c @@ -62,7 +62,7 @@ static int max77650_led_brightness_set(struct led_classdev *cdev, static int max77650_led_probe(struct platform_device *pdev) { - struct device_node *of_node, *child; + struct fwnode_handle *child; struct max77650_led *leds, *led; struct device *dev; struct regmap *map; @@ -71,10 +71,6 @@ static int max77650_led_probe(struct platform_device *pdev) u32 reg; dev = &pdev->dev; - of_node = dev->of_node; - - if (!of_node) - return -ENODEV; leds = devm_kcalloc(dev, sizeof(*leds), MAX77650_LED_NUM_LEDS, GFP_KERNEL); @@ -85,14 +81,16 @@ static int max77650_led_probe(struct platform_device *pdev) if (!map) return -ENODEV; - num_leds = of_get_child_count(of_node); + num_leds = device_get_child_node_count(dev); if (!num_leds || num_leds > MAX77650_LED_NUM_LEDS) return -ENODEV; - for_each_child_of_node(of_node, child) { - rv = of_property_read_u32(child, "reg", ®); - if (rv || reg >= MAX77650_LED_NUM_LEDS) - return -EINVAL; + device_for_each_child_node(dev, child) { + rv = fwnode_property_read_u32(child, "reg", ®); + if (rv || reg >= MAX77650_LED_NUM_LEDS) { + rv = -EINVAL; + goto err_node_put; + } led = &leds[reg]; led->map = map; @@ -101,35 +99,40 @@ static int max77650_led_probe(struct platform_device *pdev) led->cdev.brightness_set_blocking = max77650_led_brightness_set; led->cdev.max_brightness = MAX77650_LED_MAX_BRIGHTNESS; - label = of_get_property(child, "label", NULL); - if (!label) { + rv = fwnode_property_read_string(child, "label", &label); + if (rv) { led->cdev.name = "max77650::"; } else { led->cdev.name = devm_kasprintf(dev, GFP_KERNEL, "max77650:%s", label); - if (!led->cdev.name) - return -ENOMEM; + if (!led->cdev.name) { + rv = -ENOMEM; + goto err_node_put; + } } - of_property_read_string(child, "linux,default-trigger", - &led->cdev.default_trigger); + fwnode_property_read_string(child, "linux,default-trigger", + &led->cdev.default_trigger); - rv = devm_of_led_classdev_register(dev, child, &led->cdev); + rv = devm_led_classdev_register(dev, &led->cdev); if (rv) - return rv; + goto err_node_put; rv = regmap_write(map, led->regA, MAX77650_LED_A_DEFAULT); if (rv) - return rv; + goto err_node_put; rv = regmap_write(map, led->regB, MAX77650_LED_B_DEFAULT); if (rv) - return rv; + goto err_node_put; } return regmap_write(map, MAX77650_REG_CNFG_LED_TOP, MAX77650_LED_TOP_DEFAULT); +err_node_put: + fwnode_handle_put(child); + return rv; } static struct platform_driver max77650_led_driver = { @@ -143,3 +146,4 @@ module_platform_driver(max77650_led_driver); MODULE_DESCRIPTION("MAXIM 77650/77651 LED driver"); MODULE_AUTHOR("Bartosz Golaszewski "); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:max77650-led"); diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c index 10497a466775412eec4e3ff77e9fefebd700dd84..14ef4ccdda3a81205bf8f60a885992d39fd9ab38 100644 --- a/drivers/leds/leds-netxbig.c +++ b/drivers/leds/leds-netxbig.c @@ -15,7 +15,48 @@ #include #include #include -#include + +struct netxbig_gpio_ext { + unsigned int *addr; + int num_addr; + unsigned int *data; + int num_data; + unsigned int enable; +}; + +enum netxbig_led_mode { + NETXBIG_LED_OFF, + NETXBIG_LED_ON, + NETXBIG_LED_SATA, + NETXBIG_LED_TIMER1, + NETXBIG_LED_TIMER2, + NETXBIG_LED_MODE_NUM, +}; + +#define NETXBIG_LED_INVALID_MODE NETXBIG_LED_MODE_NUM + +struct netxbig_led_timer { + unsigned long delay_on; + unsigned long delay_off; + enum netxbig_led_mode mode; +}; + +struct netxbig_led { + const char *name; + const char *default_trigger; + int mode_addr; + int *mode_val; + int bright_addr; + int bright_max; +}; + +struct netxbig_led_platform_data { + struct netxbig_gpio_ext *gpio_ext; + struct netxbig_led_timer *timer; + int num_timer; + struct netxbig_led *leds; + int num_leds; +}; /* * GPIO extension bus. @@ -306,7 +347,6 @@ static int create_netxbig_led(struct platform_device *pdev, return devm_led_classdev_register(&pdev->dev, &led_dat->cdev); } -#ifdef CONFIG_OF_GPIO static int gpio_ext_get_of_pdata(struct device *dev, struct device_node *np, struct netxbig_gpio_ext *gpio_ext) { @@ -388,12 +428,14 @@ static int netxbig_leds_get_of_pdata(struct device *dev, } gpio_ext = devm_kzalloc(dev, sizeof(*gpio_ext), GFP_KERNEL); - if (!gpio_ext) + if (!gpio_ext) { + of_node_put(gpio_ext_np); return -ENOMEM; + } ret = gpio_ext_get_of_pdata(dev, gpio_ext_np, gpio_ext); + of_node_put(gpio_ext_np); if (ret) return ret; - of_node_put(gpio_ext_np); pdata->gpio_ext = gpio_ext; /* Timers (optional) */ @@ -522,30 +564,20 @@ static const struct of_device_id of_netxbig_leds_match[] = { {}, }; MODULE_DEVICE_TABLE(of, of_netxbig_leds_match); -#else -static inline int -netxbig_leds_get_of_pdata(struct device *dev, - struct netxbig_led_platform_data *pdata) -{ - return -ENODEV; -} -#endif /* CONFIG_OF_GPIO */ static int netxbig_led_probe(struct platform_device *pdev) { - struct netxbig_led_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct netxbig_led_platform_data *pdata; struct netxbig_led_data *leds_data; int i; int ret; - if (!pdata) { - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - ret = netxbig_leds_get_of_pdata(&pdev->dev, pdata); - if (ret) - return ret; - } + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + ret = netxbig_leds_get_of_pdata(&pdev->dev, pdata); + if (ret) + return ret; leds_data = devm_kcalloc(&pdev->dev, pdata->num_leds, sizeof(*leds_data), @@ -571,7 +603,7 @@ static struct platform_driver netxbig_led_driver = { .probe = netxbig_led_probe, .driver = { .name = "leds-netxbig", - .of_match_table = of_match_ptr(of_netxbig_leds_match), + .of_match_table = of_netxbig_leds_match, }, }; diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index f92e2c07c1c6f7647dc524d643818b6e5c135a25..7c500dfdcfa3cac6e15b78660c0bc3c85691a66e 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -245,7 +245,7 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) struct device_node *np = dev->of_node; struct device_node *child; struct ns2_led *led, *leds; - int num_leds = 0; + int ret, num_leds = 0; num_leds = of_get_child_count(np); if (!num_leds) @@ -259,16 +259,16 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) led = leds; for_each_child_of_node(np, child) { const char *string; - int ret, i, num_modes; + int i, num_modes; struct ns2_led_modval *modval; ret = of_get_named_gpio(child, "cmd-gpio", 0); if (ret < 0) - return ret; + goto err_node_put; led->cmd = ret; ret = of_get_named_gpio(child, "slow-gpio", 0); if (ret < 0) - return ret; + goto err_node_put; led->slow = ret; ret = of_property_read_string(child, "label", &string); led->name = (ret == 0) ? string : child->name; @@ -281,7 +281,8 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) if (ret < 0 || ret % 3) { dev_err(dev, "Missing or malformed modes-map property\n"); - return -EINVAL; + ret = -EINVAL; + goto err_node_put; } num_modes = ret / 3; @@ -289,8 +290,10 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) num_modes, sizeof(struct ns2_led_modval), GFP_KERNEL); - if (!modval) - return -ENOMEM; + if (!modval) { + ret = -ENOMEM; + goto err_node_put; + } for (i = 0; i < num_modes; i++) { of_property_read_u32_index(child, @@ -314,6 +317,10 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) pdata->num_leds = num_leds; return 0; + +err_node_put: + of_node_put(child); + return ret; } static const struct of_device_id of_ns2_leds_match[] = { diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index 290871072d65b39a75bdf0f23b054ed28afa9fed..c7c7199e8ebdf740c48581a72d3f1c6d94c509ab 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index 48d068f80f114037a6461707a44a3804971e8094..8b6965a563e9b6e862f7e81c766fd3a012dd12f2 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -65,12 +65,6 @@ static int led_pwm_set(struct led_classdev *led_cdev, return 0; } -static inline size_t sizeof_pwm_leds_priv(int num_leds) -{ - return sizeof(struct led_pwm_priv) + - (sizeof(struct led_pwm_data) * num_leds); -} - static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, struct led_pwm *led, struct fwnode_handle *fwnode) { @@ -111,8 +105,7 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, if (!led_data->period && (led->pwm_period_ns > 0)) led_data->period = led->pwm_period_ns; - ret = devm_of_led_classdev_register(dev, to_of_node(fwnode), - &led_data->cdev); + ret = devm_led_classdev_register(dev, &led_data->cdev); if (ret == 0) { priv->num_leds++; led_pwm_set(&led_data->cdev, led_data->cdev.brightness); @@ -175,7 +168,7 @@ static int led_pwm_probe(struct platform_device *pdev) if (!count) return -EINVAL; - priv = devm_kzalloc(&pdev->dev, sizeof_pwm_leds_priv(count), + priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds, count), GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/drivers/leds/leds-sc27xx-bltc.c b/drivers/leds/leds-sc27xx-bltc.c index fecf27fb1cdce126267792284fa3dfbc00bf6b7f..0ede87420bfc7f2470b60d255ed80c029d98da5a 100644 --- a/drivers/leds/leds-sc27xx-bltc.c +++ b/drivers/leds/leds-sc27xx-bltc.c @@ -6,7 +6,6 @@ #include #include #include -#include /* PMIC global control register definition */ #define SC27XX_MODULE_EN0 0xc08 @@ -46,7 +45,7 @@ #define SC27XX_DELTA_T_MAX (SC27XX_LEDS_STEP * 255) struct sc27xx_led { - char name[LED_MAX_NAME_SIZE]; + struct fwnode_handle *fwnode; struct led_classdev ldev; struct sc27xx_led_priv *priv; u8 line; @@ -249,19 +248,24 @@ static int sc27xx_led_register(struct device *dev, struct sc27xx_led_priv *priv) for (i = 0; i < SC27XX_LEDS_MAX; i++) { struct sc27xx_led *led = &priv->leds[i]; + struct led_init_data init_data = {}; if (!led->active) continue; led->line = i; led->priv = priv; - led->ldev.name = led->name; led->ldev.brightness_set_blocking = sc27xx_led_set; led->ldev.pattern_set = sc27xx_led_pattern_set; led->ldev.pattern_clear = sc27xx_led_pattern_clear; led->ldev.default_trigger = "pattern"; - err = devm_led_classdev_register(dev, &led->ldev); + init_data.fwnode = led->fwnode; + init_data.devicename = "sc27xx"; + init_data.default_label = ":"; + + err = devm_led_classdev_register_ext(dev, &led->ldev, + &init_data); if (err) return err; } @@ -274,7 +278,6 @@ static int sc27xx_led_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node, *child; struct sc27xx_led_priv *priv; - const char *str; u32 base, count, reg; int err; @@ -316,15 +319,8 @@ static int sc27xx_led_probe(struct platform_device *pdev) return -EINVAL; } + priv->leds[reg].fwnode = of_fwnode_handle(child); priv->leds[reg].active = true; - - err = of_property_read_string(child, "label", &str); - if (err) - snprintf(priv->leds[reg].name, LED_MAX_NAME_SIZE, - "sc27xx::"); - else - snprintf(priv->leds[reg].name, LED_MAX_NAME_SIZE, - "sc27xx:%s", str); } err = sc27xx_led_register(dev, priv); diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c index e35dff0050f0a2eb1d97156b46ccc762172cacd5..b58f3cafe16f4bf8324c21b6abf49025ea56d8f5 100644 --- a/drivers/leds/leds-syscon.c +++ b/drivers/leds/leds-syscon.c @@ -115,7 +115,7 @@ static int syscon_led_probe(struct platform_device *pdev) } sled->cdev.brightness_set = syscon_led_set; - ret = led_classdev_register(dev, &sled->cdev); + ret = devm_led_classdev_register(dev, &sled->cdev); if (ret < 0) return ret; diff --git a/drivers/leds/leds-ti-lmu-common.c b/drivers/leds/leds-ti-lmu-common.c index adc7293004f1100b9bbfa0bc207948fe3c16c489..d7f10ad721badc62bd79c72c060deddf87d4a77b 100644 --- a/drivers/leds/leds-ti-lmu-common.c +++ b/drivers/leds/leds-ti-lmu-common.c @@ -11,10 +11,10 @@ #include -const static int ramp_table[16] = {2048, 262000, 524000, 1049000, 2090000, - 4194000, 8389000, 16780000, 33550000, 41940000, - 50330000, 58720000, 67110000, 83880000, - 100660000, 117440000}; +static const unsigned int ramp_table[16] = {2048, 262000, 524000, 1049000, + 2090000, 4194000, 8389000, 16780000, 33550000, + 41940000, 50330000, 58720000, 67110000, + 83880000, 100660000, 117440000}; static int ti_lmu_common_update_brightness(struct ti_lmu_bank *lmu_bank, int brightness) @@ -54,7 +54,7 @@ int ti_lmu_common_set_brightness(struct ti_lmu_bank *lmu_bank, int brightness) } EXPORT_SYMBOL(ti_lmu_common_set_brightness); -static int ti_lmu_common_convert_ramp_to_index(unsigned int usec) +static unsigned int ti_lmu_common_convert_ramp_to_index(unsigned int usec) { int size = ARRAY_SIZE(ramp_table); int i; @@ -78,7 +78,7 @@ static int ti_lmu_common_convert_ramp_to_index(unsigned int usec) } } - return -EINVAL; + return 0; } int ti_lmu_common_set_ramp(struct ti_lmu_bank *lmu_bank) @@ -94,9 +94,6 @@ int ti_lmu_common_set_ramp(struct ti_lmu_bank *lmu_bank) ramp_down = ti_lmu_common_convert_ramp_to_index(lmu_bank->ramp_down_usec); } - if (ramp_up < 0 || ramp_down < 0) - return -EINVAL; - ramp = (ramp_up << 4) | ramp_down; return regmap_write(regmap, lmu_bank->runtime_ramp_reg, ramp); diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h index 47b22946906983c1d4030c680004310e2325143f..0b577cece8f7e169f7eabb3427b5bc69e74267ad 100644 --- a/drivers/leds/leds.h +++ b/drivers/leds/leds.h @@ -27,5 +27,6 @@ void led_set_brightness_nosleep(struct led_classdev *led_cdev, extern struct rw_semaphore leds_list_lock; extern struct list_head leds_list; extern struct list_head trigger_list; +extern const char * const led_colors[LED_COLOR_ID_MAX]; #endif /* __LEDS_H_INCLUDED */ diff --git a/drivers/leds/trigger/ledtrig-gpio.c b/drivers/leds/trigger/ledtrig-gpio.c index 33cc99a1a16a135aa0796bcadbc9713064aa1980..dc64679b1a9243c9219f8070de9ce6f5cc396d25 100644 --- a/drivers/leds/trigger/ledtrig-gpio.c +++ b/drivers/leds/trigger/ledtrig-gpio.c @@ -131,10 +131,10 @@ static ssize_t gpio_trig_gpio_store(struct device *dev, if (gpio_data->gpio == gpio) return n; - if (!gpio) { - if (gpio_data->gpio != 0) + if (!gpio_is_valid(gpio)) { + if (gpio_is_valid(gpio_data->gpio)) free_irq(gpio_to_irq(gpio_data->gpio), led); - gpio_data->gpio = 0; + gpio_data->gpio = gpio; return n; } @@ -144,7 +144,7 @@ static ssize_t gpio_trig_gpio_store(struct device *dev, if (ret) { dev_err(dev, "request_irq failed with error %d\n", ret); } else { - if (gpio_data->gpio != 0) + if (gpio_is_valid(gpio_data->gpio)) free_irq(gpio_to_irq(gpio_data->gpio), led); gpio_data->gpio = gpio; /* After changing the GPIO, we need to update the LED. */ @@ -172,6 +172,8 @@ static int gpio_trig_activate(struct led_classdev *led) return -ENOMEM; gpio_data->led = led; + gpio_data->gpio = -ENOENT; + led_set_trigger_data(led, gpio_data); return 0; @@ -181,7 +183,7 @@ static void gpio_trig_deactivate(struct led_classdev *led) { struct gpio_trig_data *gpio_data = led_get_trigger_data(led); - if (gpio_data->gpio != 0) + if (gpio_is_valid(gpio_data->gpio)) free_irq(gpio_to_irq(gpio_data->gpio), led); kfree(gpio_data); } diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index a600934fdd9ca351b4ca7aa72caf7bf1971a75d9..7543e395a2c646bf5fa3ececeac902964f9a8433 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -4,6 +4,8 @@ * Initial release: Matias Bjorling */ +#define pr_fmt(fmt) "nvm: " fmt + #include #include #include @@ -74,7 +76,7 @@ static int nvm_reserve_luns(struct nvm_dev *dev, int lun_begin, int lun_end) for (i = lun_begin; i <= lun_end; i++) { if (test_and_set_bit(i, dev->lun_map)) { - pr_err("nvm: lun %d already allocated\n", i); + pr_err("lun %d already allocated\n", i); goto err; } } @@ -264,7 +266,7 @@ static int nvm_config_check_luns(struct nvm_geo *geo, int lun_begin, int lun_end) { if (lun_begin > lun_end || lun_end >= geo->all_luns) { - pr_err("nvm: lun out of bound (%u:%u > %u)\n", + pr_err("lun out of bound (%u:%u > %u)\n", lun_begin, lun_end, geo->all_luns - 1); return -EINVAL; } @@ -297,7 +299,7 @@ static int __nvm_config_extended(struct nvm_dev *dev, if (e->op == 0xFFFF) { e->op = NVM_TARGET_DEFAULT_OP; } else if (e->op < NVM_TARGET_MIN_OP || e->op > NVM_TARGET_MAX_OP) { - pr_err("nvm: invalid over provisioning value\n"); + pr_err("invalid over provisioning value\n"); return -EINVAL; } @@ -334,23 +336,23 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create) e = create->conf.e; break; default: - pr_err("nvm: config type not valid\n"); + pr_err("config type not valid\n"); return -EINVAL; } tt = nvm_find_target_type(create->tgttype); if (!tt) { - pr_err("nvm: target type %s not found\n", create->tgttype); + pr_err("target type %s not found\n", create->tgttype); return -EINVAL; } if ((tt->flags & NVM_TGT_F_HOST_L2P) != (dev->geo.dom & NVM_RSP_L2P)) { - pr_err("nvm: device is incompatible with target L2P type.\n"); + pr_err("device is incompatible with target L2P type.\n"); return -EINVAL; } if (nvm_target_exists(create->tgtname)) { - pr_err("nvm: target name already exists (%s)\n", + pr_err("target name already exists (%s)\n", create->tgtname); return -EINVAL; } @@ -367,7 +369,7 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create) tgt_dev = nvm_create_tgt_dev(dev, e.lun_begin, e.lun_end, e.op); if (!tgt_dev) { - pr_err("nvm: could not create target device\n"); + pr_err("could not create target device\n"); ret = -ENOMEM; goto err_t; } @@ -493,8 +495,11 @@ static int nvm_remove_tgt(struct nvm_ioctl_remove *remove) } up_read(&nvm_lock); - if (!t) + if (!t) { + pr_err("failed to remove target %s\n", + remove->tgtname); return 1; + } __nvm_remove_target(t, true); kref_put(&dev->ref, nvm_free); @@ -686,7 +691,7 @@ static int nvm_set_rqd_ppalist(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd, rqd->nr_ppas = nr_ppas; rqd->ppa_list = nvm_dev_dma_alloc(dev, GFP_KERNEL, &rqd->dma_ppa_list); if (!rqd->ppa_list) { - pr_err("nvm: failed to allocate dma memory\n"); + pr_err("failed to allocate dma memory\n"); return -ENOMEM; } @@ -731,7 +736,7 @@ static int nvm_set_flags(struct nvm_geo *geo, struct nvm_rq *rqd) return flags; } -int nvm_submit_io(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd) +int nvm_submit_io(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd, void *buf) { struct nvm_dev *dev = tgt_dev->parent; int ret; @@ -745,19 +750,45 @@ int nvm_submit_io(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd) rqd->flags = nvm_set_flags(&tgt_dev->geo, rqd); /* In case of error, fail with right address format */ - ret = dev->ops->submit_io(dev, rqd); + ret = dev->ops->submit_io(dev, rqd, buf); if (ret) nvm_rq_dev_to_tgt(tgt_dev, rqd); return ret; } EXPORT_SYMBOL(nvm_submit_io); -int nvm_submit_io_sync(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd) +static void nvm_sync_end_io(struct nvm_rq *rqd) +{ + struct completion *waiting = rqd->private; + + complete(waiting); +} + +static int nvm_submit_io_wait(struct nvm_dev *dev, struct nvm_rq *rqd, + void *buf) +{ + DECLARE_COMPLETION_ONSTACK(wait); + int ret = 0; + + rqd->end_io = nvm_sync_end_io; + rqd->private = &wait; + + ret = dev->ops->submit_io(dev, rqd, buf); + if (ret) + return ret; + + wait_for_completion_io(&wait); + + return 0; +} + +int nvm_submit_io_sync(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd, + void *buf) { struct nvm_dev *dev = tgt_dev->parent; int ret; - if (!dev->ops->submit_io_sync) + if (!dev->ops->submit_io) return -ENODEV; nvm_rq_tgt_to_dev(tgt_dev, rqd); @@ -765,9 +796,7 @@ int nvm_submit_io_sync(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd) rqd->dev = tgt_dev; rqd->flags = nvm_set_flags(&tgt_dev->geo, rqd); - /* In case of error, fail with right address format */ - ret = dev->ops->submit_io_sync(dev, rqd); - nvm_rq_dev_to_tgt(tgt_dev, rqd); + ret = nvm_submit_io_wait(dev, rqd, buf); return ret; } @@ -788,12 +817,13 @@ EXPORT_SYMBOL(nvm_end_io); static int nvm_submit_io_sync_raw(struct nvm_dev *dev, struct nvm_rq *rqd) { - if (!dev->ops->submit_io_sync) + if (!dev->ops->submit_io) return -ENODEV; + rqd->dev = NULL; rqd->flags = nvm_set_flags(&dev->geo, rqd); - return dev->ops->submit_io_sync(dev, rqd); + return nvm_submit_io_wait(dev, rqd, NULL); } static int nvm_bb_chunk_sense(struct nvm_dev *dev, struct ppa_addr ppa) @@ -1048,7 +1078,7 @@ int nvm_set_chunk_meta(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas, return 0; if (nr_ppas > NVM_MAX_VLBA) { - pr_err("nvm: unable to update all blocks atomically\n"); + pr_err("unable to update all blocks atomically\n"); return -EINVAL; } @@ -1111,27 +1141,26 @@ static int nvm_init(struct nvm_dev *dev) int ret = -EINVAL; if (dev->ops->identity(dev)) { - pr_err("nvm: device could not be identified\n"); + pr_err("device could not be identified\n"); goto err; } - pr_debug("nvm: ver:%u.%u nvm_vendor:%x\n", - geo->major_ver_id, geo->minor_ver_id, - geo->vmnt); + pr_debug("ver:%u.%u nvm_vendor:%x\n", geo->major_ver_id, + geo->minor_ver_id, geo->vmnt); ret = nvm_core_init(dev); if (ret) { - pr_err("nvm: could not initialize core structures.\n"); + pr_err("could not initialize core structures.\n"); goto err; } - pr_info("nvm: registered %s [%u/%u/%u/%u/%u]\n", + pr_info("registered %s [%u/%u/%u/%u/%u]\n", dev->name, dev->geo.ws_min, dev->geo.ws_opt, dev->geo.num_chk, dev->geo.all_luns, dev->geo.num_ch); return 0; err: - pr_err("nvm: failed to initialize nvm\n"); + pr_err("failed to initialize nvm\n"); return ret; } @@ -1169,7 +1198,7 @@ int nvm_register(struct nvm_dev *dev) dev->dma_pool = dev->ops->create_dma_pool(dev, "ppalist", exp_pool_size); if (!dev->dma_pool) { - pr_err("nvm: could not create dma pool\n"); + pr_err("could not create dma pool\n"); kref_put(&dev->ref, nvm_free); return -ENOMEM; } @@ -1214,7 +1243,7 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create) up_write(&nvm_lock); if (!dev) { - pr_err("nvm: device not found\n"); + pr_err("device not found\n"); return -EINVAL; } @@ -1288,7 +1317,7 @@ static long nvm_ioctl_get_devices(struct file *file, void __user *arg) i++; if (i > 31) { - pr_err("nvm: max 31 devices can be reported.\n"); + pr_err("max 31 devices can be reported.\n"); break; } } @@ -1315,7 +1344,7 @@ static long nvm_ioctl_dev_create(struct file *file, void __user *arg) if (create.conf.type == NVM_CONFIG_TYPE_EXTENDED && create.conf.e.rsv != 0) { - pr_err("nvm: reserved config field in use\n"); + pr_err("reserved config field in use\n"); return -EINVAL; } @@ -1331,7 +1360,7 @@ static long nvm_ioctl_dev_create(struct file *file, void __user *arg) flags &= ~NVM_TARGET_FACTORY; if (flags) { - pr_err("nvm: flag not supported\n"); + pr_err("flag not supported\n"); return -EINVAL; } } @@ -1349,7 +1378,7 @@ static long nvm_ioctl_dev_remove(struct file *file, void __user *arg) remove.tgtname[DISK_NAME_LEN - 1] = '\0'; if (remove.flags != 0) { - pr_err("nvm: no flags supported\n"); + pr_err("no flags supported\n"); return -EINVAL; } @@ -1365,7 +1394,7 @@ static long nvm_ioctl_dev_init(struct file *file, void __user *arg) return -EFAULT; if (init.flags != 0) { - pr_err("nvm: no flags supported\n"); + pr_err("no flags supported\n"); return -EINVAL; } diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c index f546e6f28b8afbad37f89315272efb040722bfcd..b413bafe93fddd97a9ee85ba29b1007490ad8b49 100644 --- a/drivers/lightnvm/pblk-core.c +++ b/drivers/lightnvm/pblk-core.c @@ -507,7 +507,7 @@ void pblk_set_sec_per_write(struct pblk *pblk, int sec_per_write) pblk->sec_per_write = sec_per_write; } -int pblk_submit_io(struct pblk *pblk, struct nvm_rq *rqd) +int pblk_submit_io(struct pblk *pblk, struct nvm_rq *rqd, void *buf) { struct nvm_tgt_dev *dev = pblk->dev; @@ -518,7 +518,7 @@ int pblk_submit_io(struct pblk *pblk, struct nvm_rq *rqd) return NVM_IO_ERR; #endif - return nvm_submit_io(dev, rqd); + return nvm_submit_io(dev, rqd, buf); } void pblk_check_chunk_state_update(struct pblk *pblk, struct nvm_rq *rqd) @@ -541,7 +541,7 @@ void pblk_check_chunk_state_update(struct pblk *pblk, struct nvm_rq *rqd) } } -int pblk_submit_io_sync(struct pblk *pblk, struct nvm_rq *rqd) +int pblk_submit_io_sync(struct pblk *pblk, struct nvm_rq *rqd, void *buf) { struct nvm_tgt_dev *dev = pblk->dev; int ret; @@ -553,7 +553,7 @@ int pblk_submit_io_sync(struct pblk *pblk, struct nvm_rq *rqd) return NVM_IO_ERR; #endif - ret = nvm_submit_io_sync(dev, rqd); + ret = nvm_submit_io_sync(dev, rqd, buf); if (trace_pblk_chunk_state_enabled() && !ret && rqd->opcode == NVM_OP_PWRITE) @@ -562,65 +562,19 @@ int pblk_submit_io_sync(struct pblk *pblk, struct nvm_rq *rqd) return ret; } -int pblk_submit_io_sync_sem(struct pblk *pblk, struct nvm_rq *rqd) +static int pblk_submit_io_sync_sem(struct pblk *pblk, struct nvm_rq *rqd, + void *buf) { struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); int ret; pblk_down_chunk(pblk, ppa_list[0]); - ret = pblk_submit_io_sync(pblk, rqd); + ret = pblk_submit_io_sync(pblk, rqd, buf); pblk_up_chunk(pblk, ppa_list[0]); return ret; } -static void pblk_bio_map_addr_endio(struct bio *bio) -{ - bio_put(bio); -} - -struct bio *pblk_bio_map_addr(struct pblk *pblk, void *data, - unsigned int nr_secs, unsigned int len, - int alloc_type, gfp_t gfp_mask) -{ - struct nvm_tgt_dev *dev = pblk->dev; - void *kaddr = data; - struct page *page; - struct bio *bio; - int i, ret; - - if (alloc_type == PBLK_KMALLOC_META) - return bio_map_kern(dev->q, kaddr, len, gfp_mask); - - bio = bio_kmalloc(gfp_mask, nr_secs); - if (!bio) - return ERR_PTR(-ENOMEM); - - for (i = 0; i < nr_secs; i++) { - page = vmalloc_to_page(kaddr); - if (!page) { - pblk_err(pblk, "could not map vmalloc bio\n"); - bio_put(bio); - bio = ERR_PTR(-ENOMEM); - goto out; - } - - ret = bio_add_pc_page(dev->q, bio, page, PAGE_SIZE, 0); - if (ret != PAGE_SIZE) { - pblk_err(pblk, "could not add page to bio\n"); - bio_put(bio); - bio = ERR_PTR(-ENOMEM); - goto out; - } - - kaddr += PAGE_SIZE; - } - - bio->bi_end_io = pblk_bio_map_addr_endio; -out: - return bio; -} - int pblk_calc_secs(struct pblk *pblk, unsigned long secs_avail, unsigned long secs_to_flush, bool skip_meta) { @@ -722,9 +676,7 @@ u64 pblk_line_smeta_start(struct pblk *pblk, struct pblk_line *line) int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line) { - struct nvm_tgt_dev *dev = pblk->dev; struct pblk_line_meta *lm = &pblk->lm; - struct bio *bio; struct ppa_addr *ppa_list; struct nvm_rq rqd; u64 paddr = pblk_line_smeta_start(pblk, line); @@ -736,16 +688,6 @@ int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line) if (ret) return ret; - bio = bio_map_kern(dev->q, line->smeta, lm->smeta_len, GFP_KERNEL); - if (IS_ERR(bio)) { - ret = PTR_ERR(bio); - goto clear_rqd; - } - - bio->bi_iter.bi_sector = 0; /* internal bio */ - bio_set_op_attrs(bio, REQ_OP_READ, 0); - - rqd.bio = bio; rqd.opcode = NVM_OP_PREAD; rqd.nr_ppas = lm->smeta_sec; rqd.is_seq = 1; @@ -754,10 +696,9 @@ int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line) for (i = 0; i < lm->smeta_sec; i++, paddr++) ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line->id); - ret = pblk_submit_io_sync(pblk, &rqd); + ret = pblk_submit_io_sync(pblk, &rqd, line->smeta); if (ret) { pblk_err(pblk, "smeta I/O submission failed: %d\n", ret); - bio_put(bio); goto clear_rqd; } @@ -776,9 +717,7 @@ int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line) static int pblk_line_smeta_write(struct pblk *pblk, struct pblk_line *line, u64 paddr) { - struct nvm_tgt_dev *dev = pblk->dev; struct pblk_line_meta *lm = &pblk->lm; - struct bio *bio; struct ppa_addr *ppa_list; struct nvm_rq rqd; __le64 *lba_list = emeta_to_lbas(pblk, line->emeta->buf); @@ -791,16 +730,6 @@ static int pblk_line_smeta_write(struct pblk *pblk, struct pblk_line *line, if (ret) return ret; - bio = bio_map_kern(dev->q, line->smeta, lm->smeta_len, GFP_KERNEL); - if (IS_ERR(bio)) { - ret = PTR_ERR(bio); - goto clear_rqd; - } - - bio->bi_iter.bi_sector = 0; /* internal bio */ - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - - rqd.bio = bio; rqd.opcode = NVM_OP_PWRITE; rqd.nr_ppas = lm->smeta_sec; rqd.is_seq = 1; @@ -814,10 +743,9 @@ static int pblk_line_smeta_write(struct pblk *pblk, struct pblk_line *line, meta->lba = lba_list[paddr] = addr_empty; } - ret = pblk_submit_io_sync_sem(pblk, &rqd); + ret = pblk_submit_io_sync_sem(pblk, &rqd, line->smeta); if (ret) { pblk_err(pblk, "smeta I/O submission failed: %d\n", ret); - bio_put(bio); goto clear_rqd; } @@ -838,10 +766,8 @@ int pblk_line_emeta_read(struct pblk *pblk, struct pblk_line *line, { struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; - struct pblk_line_mgmt *l_mg = &pblk->l_mg; struct pblk_line_meta *lm = &pblk->lm; void *ppa_list_buf, *meta_list; - struct bio *bio; struct ppa_addr *ppa_list; struct nvm_rq rqd; u64 paddr = line->emeta_ssec; @@ -867,17 +793,6 @@ int pblk_line_emeta_read(struct pblk *pblk, struct pblk_line *line, rq_ppas = pblk_calc_secs(pblk, left_ppas, 0, false); rq_len = rq_ppas * geo->csecs; - bio = pblk_bio_map_addr(pblk, emeta_buf, rq_ppas, rq_len, - l_mg->emeta_alloc_type, GFP_KERNEL); - if (IS_ERR(bio)) { - ret = PTR_ERR(bio); - goto free_rqd_dma; - } - - bio->bi_iter.bi_sector = 0; /* internal bio */ - bio_set_op_attrs(bio, REQ_OP_READ, 0); - - rqd.bio = bio; rqd.meta_list = meta_list; rqd.ppa_list = ppa_list_buf; rqd.dma_meta_list = dma_meta_list; @@ -896,7 +811,6 @@ int pblk_line_emeta_read(struct pblk *pblk, struct pblk_line *line, while (test_bit(pos, line->blk_bitmap)) { paddr += min; if (pblk_boundary_paddr_checks(pblk, paddr)) { - bio_put(bio); ret = -EINTR; goto free_rqd_dma; } @@ -906,7 +820,6 @@ int pblk_line_emeta_read(struct pblk *pblk, struct pblk_line *line, } if (pblk_boundary_paddr_checks(pblk, paddr + min)) { - bio_put(bio); ret = -EINTR; goto free_rqd_dma; } @@ -915,10 +828,9 @@ int pblk_line_emeta_read(struct pblk *pblk, struct pblk_line *line, ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line_id); } - ret = pblk_submit_io_sync(pblk, &rqd); + ret = pblk_submit_io_sync(pblk, &rqd, emeta_buf); if (ret) { pblk_err(pblk, "emeta I/O submission failed: %d\n", ret); - bio_put(bio); goto free_rqd_dma; } @@ -963,7 +875,7 @@ static int pblk_blk_erase_sync(struct pblk *pblk, struct ppa_addr ppa) /* The write thread schedules erases so that it minimizes disturbances * with writes. Thus, there is no need to take the LUN semaphore. */ - ret = pblk_submit_io_sync(pblk, &rqd); + ret = pblk_submit_io_sync(pblk, &rqd, NULL); rqd.private = pblk; __pblk_end_io_erase(pblk, &rqd); @@ -1792,7 +1704,7 @@ int pblk_blk_erase_async(struct pblk *pblk, struct ppa_addr ppa) /* The write thread schedules erases so that it minimizes disturbances * with writes. Thus, there is no need to take the LUN semaphore. */ - err = pblk_submit_io(pblk, rqd); + err = pblk_submit_io(pblk, rqd, NULL); if (err) { struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; @@ -1923,13 +1835,11 @@ void pblk_line_close_meta(struct pblk *pblk, struct pblk_line *line) static void pblk_save_lba_list(struct pblk *pblk, struct pblk_line *line) { struct pblk_line_meta *lm = &pblk->lm; - struct pblk_line_mgmt *l_mg = &pblk->l_mg; unsigned int lba_list_size = lm->emeta_len[2]; struct pblk_w_err_gc *w_err_gc = line->w_err_gc; struct pblk_emeta *emeta = line->emeta; - w_err_gc->lba_list = pblk_malloc(lba_list_size, - l_mg->emeta_alloc_type, GFP_KERNEL); + w_err_gc->lba_list = kvmalloc(lba_list_size, GFP_KERNEL); memcpy(w_err_gc->lba_list, emeta_to_lbas(pblk, emeta->buf), lba_list_size); } diff --git a/drivers/lightnvm/pblk-gc.c b/drivers/lightnvm/pblk-gc.c index 63ee205b41c477f9ebc70374f6cf208915e6c4f1..2581eebcfc41d5d4363a62ba457fae15152d3090 100644 --- a/drivers/lightnvm/pblk-gc.c +++ b/drivers/lightnvm/pblk-gc.c @@ -132,14 +132,12 @@ static __le64 *get_lba_list_from_emeta(struct pblk *pblk, struct pblk_line *line) { struct line_emeta *emeta_buf; - struct pblk_line_mgmt *l_mg = &pblk->l_mg; struct pblk_line_meta *lm = &pblk->lm; unsigned int lba_list_size = lm->emeta_len[2]; __le64 *lba_list; int ret; - emeta_buf = pblk_malloc(lm->emeta_len[0], - l_mg->emeta_alloc_type, GFP_KERNEL); + emeta_buf = kvmalloc(lm->emeta_len[0], GFP_KERNEL); if (!emeta_buf) return NULL; @@ -147,7 +145,7 @@ static __le64 *get_lba_list_from_emeta(struct pblk *pblk, if (ret) { pblk_err(pblk, "line %d read emeta failed (%d)\n", line->id, ret); - pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); + kvfree(emeta_buf); return NULL; } @@ -161,16 +159,16 @@ static __le64 *get_lba_list_from_emeta(struct pblk *pblk, if (ret) { pblk_err(pblk, "inconsistent emeta (line %d)\n", line->id); - pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); + kvfree(emeta_buf); return NULL; } - lba_list = pblk_malloc(lba_list_size, - l_mg->emeta_alloc_type, GFP_KERNEL); + lba_list = kvmalloc(lba_list_size, GFP_KERNEL); + if (lba_list) memcpy(lba_list, emeta_to_lbas(pblk, emeta_buf), lba_list_size); - pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); + kvfree(emeta_buf); return lba_list; } @@ -181,7 +179,6 @@ static void pblk_gc_line_prepare_ws(struct work_struct *work) ws); struct pblk *pblk = line_ws->pblk; struct pblk_line *line = line_ws->line; - struct pblk_line_mgmt *l_mg = &pblk->l_mg; struct pblk_line_meta *lm = &pblk->lm; struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; @@ -272,7 +269,7 @@ static void pblk_gc_line_prepare_ws(struct work_struct *work) goto next_rq; out: - pblk_mfree(lba_list, l_mg->emeta_alloc_type); + kvfree(lba_list); kfree(line_ws); kfree(invalid_bitmap); @@ -286,7 +283,7 @@ static void pblk_gc_line_prepare_ws(struct work_struct *work) fail_free_gc_rq: kfree(gc_rq); fail_free_lba_list: - pblk_mfree(lba_list, l_mg->emeta_alloc_type); + kvfree(lba_list); fail_free_invalid_bitmap: kfree(invalid_bitmap); fail_free_ws: diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c index b351c7f002de0509b7bca75a0f64a616eec7ee32..9a967a2e83dd72711db1ab538c650f126cafb97d 100644 --- a/drivers/lightnvm/pblk-init.c +++ b/drivers/lightnvm/pblk-init.c @@ -543,7 +543,7 @@ static void pblk_line_mg_free(struct pblk *pblk) for (i = 0; i < PBLK_DATA_LINES; i++) { kfree(l_mg->sline_meta[i]); - pblk_mfree(l_mg->eline_meta[i]->buf, l_mg->emeta_alloc_type); + kvfree(l_mg->eline_meta[i]->buf); kfree(l_mg->eline_meta[i]); } @@ -560,7 +560,7 @@ static void pblk_line_meta_free(struct pblk_line_mgmt *l_mg, kfree(line->erase_bitmap); kfree(line->chks); - pblk_mfree(w_err_gc->lba_list, l_mg->emeta_alloc_type); + kvfree(w_err_gc->lba_list); kfree(w_err_gc); } @@ -890,29 +890,14 @@ static int pblk_line_mg_init(struct pblk *pblk) if (!emeta) goto fail_free_emeta; - if (lm->emeta_len[0] > KMALLOC_MAX_CACHE_SIZE) { - l_mg->emeta_alloc_type = PBLK_VMALLOC_META; - - emeta->buf = vmalloc(lm->emeta_len[0]); - if (!emeta->buf) { - kfree(emeta); - goto fail_free_emeta; - } - - emeta->nr_entries = lm->emeta_sec[0]; - l_mg->eline_meta[i] = emeta; - } else { - l_mg->emeta_alloc_type = PBLK_KMALLOC_META; - - emeta->buf = kmalloc(lm->emeta_len[0], GFP_KERNEL); - if (!emeta->buf) { - kfree(emeta); - goto fail_free_emeta; - } - - emeta->nr_entries = lm->emeta_sec[0]; - l_mg->eline_meta[i] = emeta; + emeta->buf = kvmalloc(lm->emeta_len[0], GFP_KERNEL); + if (!emeta->buf) { + kfree(emeta); + goto fail_free_emeta; } + + emeta->nr_entries = lm->emeta_sec[0]; + l_mg->eline_meta[i] = emeta; } for (i = 0; i < l_mg->nr_lines; i++) @@ -926,10 +911,7 @@ static int pblk_line_mg_init(struct pblk *pblk) fail_free_emeta: while (--i >= 0) { - if (l_mg->emeta_alloc_type == PBLK_VMALLOC_META) - vfree(l_mg->eline_meta[i]->buf); - else - kfree(l_mg->eline_meta[i]->buf); + kvfree(l_mg->eline_meta[i]->buf); kfree(l_mg->eline_meta[i]); } diff --git a/drivers/lightnvm/pblk-read.c b/drivers/lightnvm/pblk-read.c index d98ea392fe3357c4bf12e0e22a38d6b2a1971b8c..8efd14e683dc447a4a64964187f3131387cd387c 100644 --- a/drivers/lightnvm/pblk-read.c +++ b/drivers/lightnvm/pblk-read.c @@ -342,7 +342,7 @@ void pblk_submit_read(struct pblk *pblk, struct bio *bio) bio_put(int_bio); int_bio = bio_clone_fast(bio, GFP_KERNEL, &pblk_bio_set); goto split_retry; - } else if (pblk_submit_io(pblk, rqd)) { + } else if (pblk_submit_io(pblk, rqd, NULL)) { /* Submitting IO to drive failed, let's report an error */ rqd->error = -ENODEV; pblk_end_io_read(rqd); @@ -417,11 +417,7 @@ static int read_rq_gc(struct pblk *pblk, struct nvm_rq *rqd, int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq) { - struct nvm_tgt_dev *dev = pblk->dev; - struct nvm_geo *geo = &dev->geo; - struct bio *bio; struct nvm_rq rqd; - int data_len; int ret = NVM_IO_OK; memset(&rqd, 0, sizeof(struct nvm_rq)); @@ -446,26 +442,12 @@ int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq) if (!(gc_rq->secs_to_gc)) goto out; - data_len = (gc_rq->secs_to_gc) * geo->csecs; - bio = pblk_bio_map_addr(pblk, gc_rq->data, gc_rq->secs_to_gc, data_len, - PBLK_VMALLOC_META, GFP_KERNEL); - if (IS_ERR(bio)) { - pblk_err(pblk, "could not allocate GC bio (%lu)\n", - PTR_ERR(bio)); - ret = PTR_ERR(bio); - goto err_free_dma; - } - - bio->bi_iter.bi_sector = 0; /* internal bio */ - bio_set_op_attrs(bio, REQ_OP_READ, 0); - rqd.opcode = NVM_OP_PREAD; rqd.nr_ppas = gc_rq->secs_to_gc; - rqd.bio = bio; - if (pblk_submit_io_sync(pblk, &rqd)) { + if (pblk_submit_io_sync(pblk, &rqd, gc_rq->data)) { ret = -EIO; - goto err_free_bio; + goto err_free_dma; } pblk_read_check_rand(pblk, &rqd, gc_rq->lba_list, gc_rq->nr_secs); @@ -489,8 +471,6 @@ int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq) pblk_free_rqd_meta(pblk, &rqd); return ret; -err_free_bio: - bio_put(bio); err_free_dma: pblk_free_rqd_meta(pblk, &rqd); return ret; diff --git a/drivers/lightnvm/pblk-recovery.c b/drivers/lightnvm/pblk-recovery.c index e6dda04de144ff347f0de304759a69f9f95189c6..299ef47a17b22ae56747b824961c029691e6fc8a 100644 --- a/drivers/lightnvm/pblk-recovery.c +++ b/drivers/lightnvm/pblk-recovery.c @@ -178,12 +178,11 @@ static int pblk_recov_pad_line(struct pblk *pblk, struct pblk_line *line, void *meta_list; struct pblk_pad_rq *pad_rq; struct nvm_rq *rqd; - struct bio *bio; struct ppa_addr *ppa_list; void *data; __le64 *lba_list = emeta_to_lbas(pblk, line->emeta->buf); u64 w_ptr = line->cur_sec; - int left_line_ppas, rq_ppas, rq_len; + int left_line_ppas, rq_ppas; int i, j; int ret = 0; @@ -212,28 +211,15 @@ static int pblk_recov_pad_line(struct pblk *pblk, struct pblk_line *line, goto fail_complete; } - rq_len = rq_ppas * geo->csecs; - - bio = pblk_bio_map_addr(pblk, data, rq_ppas, rq_len, - PBLK_VMALLOC_META, GFP_KERNEL); - if (IS_ERR(bio)) { - ret = PTR_ERR(bio); - goto fail_complete; - } - - bio->bi_iter.bi_sector = 0; /* internal bio */ - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - rqd = pblk_alloc_rqd(pblk, PBLK_WRITE_INT); ret = pblk_alloc_rqd_meta(pblk, rqd); if (ret) { pblk_free_rqd(pblk, rqd, PBLK_WRITE_INT); - bio_put(bio); goto fail_complete; } - rqd->bio = bio; + rqd->bio = NULL; rqd->opcode = NVM_OP_PWRITE; rqd->is_seq = 1; rqd->nr_ppas = rq_ppas; @@ -275,13 +261,12 @@ static int pblk_recov_pad_line(struct pblk *pblk, struct pblk_line *line, kref_get(&pad_rq->ref); pblk_down_chunk(pblk, ppa_list[0]); - ret = pblk_submit_io(pblk, rqd); + ret = pblk_submit_io(pblk, rqd, data); if (ret) { pblk_err(pblk, "I/O submission failed: %d\n", ret); pblk_up_chunk(pblk, ppa_list[0]); kref_put(&pad_rq->ref, pblk_recov_complete); pblk_free_rqd(pblk, rqd, PBLK_WRITE_INT); - bio_put(bio); goto fail_complete; } @@ -375,13 +360,12 @@ static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line, struct ppa_addr *ppa_list; void *meta_list; struct nvm_rq *rqd; - struct bio *bio; void *data; dma_addr_t dma_ppa_list, dma_meta_list; __le64 *lba_list; u64 paddr = pblk_line_smeta_start(pblk, line) + lm->smeta_sec; bool padded = false; - int rq_ppas, rq_len; + int rq_ppas; int i, j; int ret; u64 left_ppas = pblk_sec_in_open_line(pblk, line) - lm->smeta_sec; @@ -404,18 +388,9 @@ static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line, rq_ppas = pblk_calc_secs(pblk, left_ppas, 0, false); if (!rq_ppas) rq_ppas = pblk->min_write_pgs; - rq_len = rq_ppas * geo->csecs; retry_rq: - bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL); - if (IS_ERR(bio)) - return PTR_ERR(bio); - - bio->bi_iter.bi_sector = 0; /* internal bio */ - bio_set_op_attrs(bio, REQ_OP_READ, 0); - bio_get(bio); - - rqd->bio = bio; + rqd->bio = NULL; rqd->opcode = NVM_OP_PREAD; rqd->meta_list = meta_list; rqd->nr_ppas = rq_ppas; @@ -445,10 +420,9 @@ static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line, addr_to_gen_ppa(pblk, paddr + j, line->id); } - ret = pblk_submit_io_sync(pblk, rqd); + ret = pblk_submit_io_sync(pblk, rqd, data); if (ret) { pblk_err(pblk, "I/O submission failed: %d\n", ret); - bio_put(bio); return ret; } @@ -460,24 +434,20 @@ static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line, if (padded) { pblk_log_read_err(pblk, rqd); - bio_put(bio); return -EINTR; } pad_distance = pblk_pad_distance(pblk, line); ret = pblk_recov_pad_line(pblk, line, pad_distance); if (ret) { - bio_put(bio); return ret; } padded = true; - bio_put(bio); goto retry_rq; } pblk_get_packed_meta(pblk, rqd); - bio_put(bio); for (i = 0; i < rqd->nr_ppas; i++) { struct pblk_sec_meta *meta = pblk_get_meta(pblk, meta_list, i); diff --git a/drivers/lightnvm/pblk-write.c b/drivers/lightnvm/pblk-write.c index 4e63f9b5954ce499de767b3b4012f084b9528959..b9a2aeba95abd39e37709921a5376be4118aefef 100644 --- a/drivers/lightnvm/pblk-write.c +++ b/drivers/lightnvm/pblk-write.c @@ -373,7 +373,6 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line) struct pblk_emeta *emeta = meta_line->emeta; struct ppa_addr *ppa_list; struct pblk_g_ctx *m_ctx; - struct bio *bio; struct nvm_rq *rqd; void *data; u64 paddr; @@ -391,20 +390,9 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line) rq_len = rq_ppas * geo->csecs; data = ((void *)emeta->buf) + emeta->mem; - bio = pblk_bio_map_addr(pblk, data, rq_ppas, rq_len, - l_mg->emeta_alloc_type, GFP_KERNEL); - if (IS_ERR(bio)) { - pblk_err(pblk, "failed to map emeta io"); - ret = PTR_ERR(bio); - goto fail_free_rqd; - } - bio->bi_iter.bi_sector = 0; /* internal bio */ - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - rqd->bio = bio; - ret = pblk_alloc_w_rq(pblk, rqd, rq_ppas, pblk_end_io_write_meta); if (ret) - goto fail_free_bio; + goto fail_free_rqd; ppa_list = nvm_rq_to_ppa_list(rqd); for (i = 0; i < rqd->nr_ppas; ) { @@ -423,7 +411,7 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line) pblk_down_chunk(pblk, ppa_list[0]); - ret = pblk_submit_io(pblk, rqd); + ret = pblk_submit_io(pblk, rqd, data); if (ret) { pblk_err(pblk, "emeta I/O submission failed: %d\n", ret); goto fail_rollback; @@ -437,8 +425,6 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line) pblk_dealloc_page(pblk, meta_line, rq_ppas); list_add(&meta_line->list, &meta_line->list); spin_unlock(&l_mg->close_lock); -fail_free_bio: - bio_put(bio); fail_free_rqd: pblk_free_rqd(pblk, rqd, PBLK_WRITE_INT); return ret; @@ -523,7 +509,7 @@ static int pblk_submit_io_set(struct pblk *pblk, struct nvm_rq *rqd) meta_line = pblk_should_submit_meta_io(pblk, rqd); /* Submit data write for current data line */ - err = pblk_submit_io(pblk, rqd); + err = pblk_submit_io(pblk, rqd, NULL); if (err) { pblk_err(pblk, "data I/O submission failed: %d\n", err); return NVM_IO_ERR; diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h index a67855387f53d315d122b9218bbe1223801c51aa..86ffa875bfe16c0b2d2bf95bf4939535b173d1c2 100644 --- a/drivers/lightnvm/pblk.h +++ b/drivers/lightnvm/pblk.h @@ -481,11 +481,6 @@ struct pblk_line { #define PBLK_DATA_LINES 4 -enum { - PBLK_KMALLOC_META = 1, - PBLK_VMALLOC_META = 2, -}; - enum { PBLK_EMETA_TYPE_HEADER = 1, /* struct line_emeta first sector */ PBLK_EMETA_TYPE_LLBA = 2, /* lba list - type: __le64 */ @@ -521,9 +516,6 @@ struct pblk_line_mgmt { __le32 *vsc_list; /* Valid sector counts for all lines */ - /* Metadata allocation type: VMALLOC | KMALLOC */ - int emeta_alloc_type; - /* Pre-allocated metadata for data lines */ struct pblk_smeta *sline_meta[PBLK_DATA_LINES]; struct pblk_emeta *eline_meta[PBLK_DATA_LINES]; @@ -783,14 +775,10 @@ struct nvm_chk_meta *pblk_chunk_get_off(struct pblk *pblk, struct ppa_addr ppa); void pblk_log_write_err(struct pblk *pblk, struct nvm_rq *rqd); void pblk_log_read_err(struct pblk *pblk, struct nvm_rq *rqd); -int pblk_submit_io(struct pblk *pblk, struct nvm_rq *rqd); -int pblk_submit_io_sync(struct pblk *pblk, struct nvm_rq *rqd); -int pblk_submit_io_sync_sem(struct pblk *pblk, struct nvm_rq *rqd); +int pblk_submit_io(struct pblk *pblk, struct nvm_rq *rqd, void *buf); +int pblk_submit_io_sync(struct pblk *pblk, struct nvm_rq *rqd, void *buf); int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line); void pblk_check_chunk_state_update(struct pblk *pblk, struct nvm_rq *rqd); -struct bio *pblk_bio_map_addr(struct pblk *pblk, void *data, - unsigned int nr_secs, unsigned int len, - int alloc_type, gfp_t gfp_mask); struct pblk_line *pblk_line_get(struct pblk *pblk); struct pblk_line *pblk_line_get_first_data(struct pblk *pblk); struct pblk_line *pblk_line_replace_data(struct pblk *pblk); @@ -938,21 +926,6 @@ void pblk_rl_werr_line_out(struct pblk_rl *rl); int pblk_sysfs_init(struct gendisk *tdisk); void pblk_sysfs_exit(struct gendisk *tdisk); -static inline void *pblk_malloc(size_t size, int type, gfp_t flags) -{ - if (type == PBLK_KMALLOC_META) - return kmalloc(size, flags); - return vmalloc(size); -} - -static inline void pblk_mfree(void *ptr, int type) -{ - if (type == PBLK_KMALLOC_META) - kfree(ptr); - else - vfree(ptr); -} - static inline struct nvm_rq *nvm_rq_from_c_ctx(void *c_ctx) { return c_ctx - sizeof(struct nvm_rq); diff --git a/drivers/macintosh/windfarm_cpufreq_clamp.c b/drivers/macintosh/windfarm_cpufreq_clamp.c index 52fd5fca89a086b8e3ee5c62930821c867c46bc8..705c6200814b633abf9794b044f3a7b97aa7d269 100644 --- a/drivers/macintosh/windfarm_cpufreq_clamp.c +++ b/drivers/macintosh/windfarm_cpufreq_clamp.c @@ -3,9 +3,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -16,36 +18,24 @@ static int clamped; static struct wf_control *clamp_control; - -static int clamp_notifier_call(struct notifier_block *self, - unsigned long event, void *data) -{ - struct cpufreq_policy *p = data; - unsigned long max_freq; - - if (event != CPUFREQ_ADJUST) - return 0; - - max_freq = clamped ? (p->cpuinfo.min_freq) : (p->cpuinfo.max_freq); - cpufreq_verify_within_limits(p, 0, max_freq); - - return 0; -} - -static struct notifier_block clamp_notifier = { - .notifier_call = clamp_notifier_call, -}; +static struct dev_pm_qos_request qos_req; +static unsigned int min_freq, max_freq; static int clamp_set(struct wf_control *ct, s32 value) { - if (value) + unsigned int freq; + + if (value) { + freq = min_freq; printk(KERN_INFO "windfarm: Clamping CPU frequency to " "minimum !\n"); - else + } else { + freq = max_freq; printk(KERN_INFO "windfarm: CPU frequency unclamped !\n"); + } clamped = value; - cpufreq_update_policy(0); - return 0; + + return dev_pm_qos_update_request(&qos_req, freq); } static int clamp_get(struct wf_control *ct, s32 *value) @@ -74,27 +64,60 @@ static const struct wf_control_ops clamp_ops = { static int __init wf_cpufreq_clamp_init(void) { + struct cpufreq_policy *policy; struct wf_control *clamp; + struct device *dev; + int ret; + + policy = cpufreq_cpu_get(0); + if (!policy) { + pr_warn("%s: cpufreq policy not found cpu0\n", __func__); + return -EPROBE_DEFER; + } + + min_freq = policy->cpuinfo.min_freq; + max_freq = policy->cpuinfo.max_freq; + cpufreq_cpu_put(policy); + + dev = get_cpu_device(0); + if (unlikely(!dev)) { + pr_warn("%s: No cpu device for cpu0\n", __func__); + return -ENODEV; + } clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL); if (clamp == NULL) return -ENOMEM; - cpufreq_register_notifier(&clamp_notifier, CPUFREQ_POLICY_NOTIFIER); + + ret = dev_pm_qos_add_request(dev, &qos_req, DEV_PM_QOS_MAX_FREQUENCY, + max_freq); + if (ret < 0) { + pr_err("%s: Failed to add freq constraint (%d)\n", __func__, + ret); + goto free; + } + clamp->ops = &clamp_ops; clamp->name = "cpufreq-clamp"; - if (wf_register_control(clamp)) + ret = wf_register_control(clamp); + if (ret) goto fail; clamp_control = clamp; return 0; fail: + dev_pm_qos_remove_request(&qos_req); + + free: kfree(clamp); - return -ENODEV; + return ret; } static void __exit wf_cpufreq_clamp_exit(void) { - if (clamp_control) + if (clamp_control) { wf_unregister_control(clamp_control); + dev_pm_qos_remove_request(&qos_req); + } } diff --git a/drivers/md/bcache/closure.c b/drivers/md/bcache/closure.c index 73f5319295bc9c1c8a3caf47ac7b7ab4ee5cfcdd..c12cd809ab1938c3aedf64e86c30dfeb0655b354 100644 --- a/drivers/md/bcache/closure.c +++ b/drivers/md/bcache/closure.c @@ -105,8 +105,14 @@ struct closure_syncer { static void closure_sync_fn(struct closure *cl) { - cl->s->done = 1; - wake_up_process(cl->s->task); + struct closure_syncer *s = cl->s; + struct task_struct *p; + + rcu_read_lock(); + p = READ_ONCE(s->task); + s->done = 1; + wake_up_process(p); + rcu_read_unlock(); } void __sched __closure_sync(struct closure *cl) diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c index 8b123be05254d39bcc4ca33caa6af01bf5056cfb..336f439103831b624468ea18a6b1ecf645312fdb 100644 --- a/drivers/md/bcache/debug.c +++ b/drivers/md/bcache/debug.c @@ -178,10 +178,9 @@ static ssize_t bch_dump_read(struct file *file, char __user *buf, while (size) { struct keybuf_key *w; unsigned int bytes = min(i->bytes, size); - int err = copy_to_user(buf, i->buf, bytes); - if (err) - return err; + if (copy_to_user(buf, i->buf, bytes)) + return -EFAULT; ret += bytes; buf += bytes; diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c index e2059af9079181e9193795757b2ed5b448741f48..627dcea0f5b6a76a5003efd1f057164d946dc4a5 100644 --- a/drivers/md/bcache/sysfs.c +++ b/drivers/md/bcache/sysfs.c @@ -964,6 +964,7 @@ KTYPE(bch_cache_set_internal); static int __bch_cache_cmp(const void *l, const void *r) { + cond_resched(); return *((uint16_t *)r) - *((uint16_t *)l); } diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c index c9e44ac1f9a6d201de99439ad2dfb91b4373e75e..3f8577e2c13be0440d7af403cb8498d8a4b78afa 100644 --- a/drivers/md/dm-rq.c +++ b/drivers/md/dm-rq.c @@ -408,6 +408,7 @@ static int map_request(struct dm_rq_target_io *tio) ret = dm_dispatch_clone_request(clone, rq); if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE) { blk_rq_unprep_clone(clone); + blk_mq_cleanup_rq(clone); tio->ti->type->release_clone_rq(clone, &tio->info); tio->clone = NULL; return DM_MAPIO_REQUEUE; @@ -562,7 +563,7 @@ int dm_mq_init_request_queue(struct mapped_device *md, struct dm_table *t) if (err) goto out_kfree_tag_set; - q = blk_mq_init_allocated_queue(md->tag_set, md->queue); + q = blk_mq_init_allocated_queue(md->tag_set, md->queue, true); if (IS_ERR(q)) { err = PTR_ERR(q); goto out_tag_set; diff --git a/drivers/md/md-linear.c b/drivers/md/md-linear.c index 7354466ddc903561238b272818e53b116b5b3c2f..c766c559d36d54b7d84c4e0f676396d63e3c2926 100644 --- a/drivers/md/md-linear.c +++ b/drivers/md/md-linear.c @@ -258,6 +258,11 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio) bio_sector < start_sector)) goto out_of_bounds; + if (unlikely(is_mddev_broken(tmp_dev->rdev, "linear"))) { + bio_io_error(bio); + return true; + } + if (unlikely(bio_end_sector(bio) > end_sector)) { /* This bio crosses a device boundary, so we have to split it */ struct bio *split = bio_split(bio, end_sector - bio_sector, diff --git a/drivers/md/md.c b/drivers/md/md.c index 24638ccedce42b8d9fb346fc7a01ff8622f4c26d..1be7abeb24fdc4a4bdf736a9e223db546fd4fceb 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -376,6 +376,11 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio) struct mddev *mddev = q->queuedata; unsigned int sectors; + if (unlikely(test_bit(MD_BROKEN, &mddev->flags)) && (rw == WRITE)) { + bio_io_error(bio); + return BLK_QC_T_NONE; + } + blk_queue_split(q, &bio); if (mddev == NULL || mddev->pers == NULL) { @@ -1232,6 +1237,8 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev) mddev->new_layout = mddev->layout; mddev->new_chunk_sectors = mddev->chunk_sectors; } + if (mddev->level == 0) + mddev->layout = -1; if (sb->state & (1<recovery_cp = MaxSector; @@ -1647,6 +1654,10 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_ rdev->ppl.sector = rdev->sb_start + rdev->ppl.offset; } + if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RAID0_LAYOUT) && + sb->level != 0) + return -EINVAL; + if (!refdev) { ret = 1; } else { @@ -1757,6 +1768,10 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev) mddev->new_chunk_sectors = mddev->chunk_sectors; } + if (mddev->level == 0 && + !(le32_to_cpu(sb->feature_map) & MD_FEATURE_RAID0_LAYOUT)) + mddev->layout = -1; + if (le32_to_cpu(sb->feature_map) & MD_FEATURE_JOURNAL) set_bit(MD_HAS_JOURNAL, &mddev->flags); @@ -1826,8 +1841,15 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev) if (!(le32_to_cpu(sb->feature_map) & MD_FEATURE_RECOVERY_BITMAP)) rdev->saved_raid_disk = -1; - } else - set_bit(In_sync, &rdev->flags); + } else { + /* + * If the array is FROZEN, then the device can't + * be in_sync with rest of array. + */ + if (!test_bit(MD_RECOVERY_FROZEN, + &mddev->recovery)) + set_bit(In_sync, &rdev->flags); + } rdev->raid_disk = role; break; } @@ -3664,11 +3686,7 @@ int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale) return -EINVAL; if (decimals < 0) decimals = 0; - while (decimals < scale) { - result *= 10; - decimals ++; - } - *res = result; + *res = result * int_pow(10, scale - decimals); return 0; } @@ -4155,12 +4173,17 @@ __ATTR_PREALLOC(resync_start, S_IRUGO|S_IWUSR, * active-idle * like active, but no writes have been seen for a while (100msec). * + * broken + * RAID0/LINEAR-only: same as clean, but array is missing a member. + * It's useful because RAID0/LINEAR mounted-arrays aren't stopped + * when a member is gone, so this state will at least alert the + * user that something is wrong. */ enum array_state { clear, inactive, suspended, readonly, read_auto, clean, active, - write_pending, active_idle, bad_word}; + write_pending, active_idle, broken, bad_word}; static char *array_states[] = { "clear", "inactive", "suspended", "readonly", "read-auto", "clean", "active", - "write-pending", "active-idle", NULL }; + "write-pending", "active-idle", "broken", NULL }; static int match_word(const char *word, char **list) { @@ -4176,7 +4199,7 @@ array_state_show(struct mddev *mddev, char *page) { enum array_state st = inactive; - if (mddev->pers) + if (mddev->pers && !test_bit(MD_NOT_READY, &mddev->flags)) { switch(mddev->ro) { case 1: st = readonly; @@ -4196,7 +4219,10 @@ array_state_show(struct mddev *mddev, char *page) st = active; spin_unlock(&mddev->lock); } - else { + + if (test_bit(MD_BROKEN, &mddev->flags) && st == clean) + st = broken; + } else { if (list_empty(&mddev->disks) && mddev->raid_disks == 0 && mddev->dev_sectors == 0) @@ -4310,6 +4336,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) break; case write_pending: case active_idle: + case broken: /* these cannot be set */ break; } @@ -5182,6 +5209,34 @@ static struct md_sysfs_entry md_consistency_policy = __ATTR(consistency_policy, S_IRUGO | S_IWUSR, consistency_policy_show, consistency_policy_store); +static ssize_t fail_last_dev_show(struct mddev *mddev, char *page) +{ + return sprintf(page, "%d\n", mddev->fail_last_dev); +} + +/* + * Setting fail_last_dev to true to allow last device to be forcibly removed + * from RAID1/RAID10. + */ +static ssize_t +fail_last_dev_store(struct mddev *mddev, const char *buf, size_t len) +{ + int ret; + bool value; + + ret = kstrtobool(buf, &value); + if (ret) + return ret; + + if (value != mddev->fail_last_dev) + mddev->fail_last_dev = value; + + return len; +} +static struct md_sysfs_entry md_fail_last_dev = +__ATTR(fail_last_dev, S_IRUGO | S_IWUSR, fail_last_dev_show, + fail_last_dev_store); + static struct attribute *md_default_attrs[] = { &md_level.attr, &md_layout.attr, @@ -5198,6 +5253,7 @@ static struct attribute *md_default_attrs[] = { &md_array_size.attr, &max_corr_read_errors.attr, &md_consistency_policy.attr, + &md_fail_last_dev.attr, NULL, }; @@ -5744,9 +5800,6 @@ int md_run(struct mddev *mddev) md_update_sb(mddev, 0); md_new_event(mddev); - sysfs_notify_dirent_safe(mddev->sysfs_state); - sysfs_notify_dirent_safe(mddev->sysfs_action); - sysfs_notify(&mddev->kobj, NULL, "degraded"); return 0; bitmap_abort: @@ -5767,6 +5820,7 @@ static int do_md_run(struct mddev *mddev) { int err; + set_bit(MD_NOT_READY, &mddev->flags); err = md_run(mddev); if (err) goto out; @@ -5787,9 +5841,14 @@ static int do_md_run(struct mddev *mddev) set_capacity(mddev->gendisk, mddev->array_sectors); revalidate_disk(mddev->gendisk); + clear_bit(MD_NOT_READY, &mddev->flags); mddev->changed = 1; kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE); + sysfs_notify_dirent_safe(mddev->sysfs_state); + sysfs_notify_dirent_safe(mddev->sysfs_action); + sysfs_notify(&mddev->kobj, NULL, "degraded"); out: + clear_bit(MD_NOT_READY, &mddev->flags); return err; } @@ -6849,6 +6908,9 @@ static int set_array_info(struct mddev *mddev, mdu_array_info_t *info) mddev->external = 0; mddev->layout = info->layout; + if (mddev->level == 0) + /* Cannot trust RAID0 layout info here */ + mddev->layout = -1; mddev->chunk_sectors = info->chunk_size >> 9; if (mddev->persistent) { @@ -8900,6 +8962,7 @@ void md_check_recovery(struct mddev *mddev) if (mddev_trylock(mddev)) { int spares = 0; + bool try_set_sync = mddev->safemode != 0; if (!mddev->external && mddev->safemode == 1) mddev->safemode = 0; @@ -8945,7 +9008,7 @@ void md_check_recovery(struct mddev *mddev) } } - if (!mddev->external && !mddev->in_sync) { + if (try_set_sync && !mddev->external && !mddev->in_sync) { spin_lock(&mddev->lock); set_in_sync(mddev); spin_unlock(&mddev->lock); @@ -9043,7 +9106,8 @@ void md_reap_sync_thread(struct mddev *mddev) /* resync has finished, collect result */ md_unregister_thread(&mddev->sync_thread); if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) && - !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) { + !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) && + mddev->degraded != mddev->raid_disks) { /* success...*/ /* activate any spares */ if (mddev->pers->spare_active(mddev)) { diff --git a/drivers/md/md.h b/drivers/md/md.h index 10f98200e2f8a38a43d1dc158b84bf633f4d7e66..c5e3ff398b595823286f4403049d094d6fb25e80 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -248,6 +248,12 @@ enum mddev_flags { MD_UPDATING_SB, /* md_check_recovery is updating the metadata * without explicitly holding reconfig_mutex. */ + MD_NOT_READY, /* do_md_run() is active, so 'array_state' + * must not report that array is ready yet + */ + MD_BROKEN, /* This is used in RAID-0/LINEAR only, to stop + * I/O in case an array member is gone/failed. + */ }; enum mddev_sb_flags { @@ -487,6 +493,7 @@ struct mddev { unsigned int good_device_nr; /* good device num within cluster raid */ bool has_superblocks:1; + bool fail_last_dev:1; }; enum recovery_flags { @@ -735,6 +742,19 @@ extern void mddev_create_wb_pool(struct mddev *mddev, struct md_rdev *rdev, struct md_rdev *md_find_rdev_nr_rcu(struct mddev *mddev, int nr); struct md_rdev *md_find_rdev_rcu(struct mddev *mddev, dev_t dev); +static inline bool is_mddev_broken(struct md_rdev *rdev, const char *md_type) +{ + int flags = rdev->bdev->bd_disk->flags; + + if (!(flags & GENHD_FL_UP)) { + if (!test_and_set_bit(MD_BROKEN, &rdev->mddev->flags)) + pr_warn("md: %s: %s array has a missing/failed member\n", + mdname(rdev->mddev), md_type); + return true; + } + return false; +} + static inline void rdev_dec_pending(struct md_rdev *rdev, struct mddev *mddev) { int faulty = test_bit(Faulty, &rdev->flags); diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index bf5cf184a260b38a0cfa442e471de8326283aa21..f61693e596845aebafbbedb8f940e0eaec9b0bee 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -19,6 +19,9 @@ #include "raid0.h" #include "raid5.h" +static int default_layout = 0; +module_param(default_layout, int, 0644); + #define UNSUPPORTED_MDDEV_FLAGS \ ((1L << MD_HAS_JOURNAL) | \ (1L << MD_JOURNAL_CLEAN) | \ @@ -139,6 +142,22 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) } pr_debug("md/raid0:%s: FINAL %d zones\n", mdname(mddev), conf->nr_strip_zones); + + if (conf->nr_strip_zones == 1) { + conf->layout = RAID0_ORIG_LAYOUT; + } else if (mddev->layout == RAID0_ORIG_LAYOUT || + mddev->layout == RAID0_ALT_MULTIZONE_LAYOUT) { + conf->layout = mddev->layout; + } else if (default_layout == RAID0_ORIG_LAYOUT || + default_layout == RAID0_ALT_MULTIZONE_LAYOUT) { + conf->layout = default_layout; + } else { + pr_err("md/raid0:%s: cannot assemble multi-zone RAID0 with default_layout setting\n", + mdname(mddev)); + pr_err("md/raid0: please set raid.default_layout to 1 or 2\n"); + err = -ENOTSUPP; + goto abort; + } /* * now since we have the hard sector sizes, we can make sure * chunk size is a multiple of that sector size @@ -547,10 +566,12 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) static bool raid0_make_request(struct mddev *mddev, struct bio *bio) { + struct r0conf *conf = mddev->private; struct strip_zone *zone; struct md_rdev *tmp_dev; sector_t bio_sector; sector_t sector; + sector_t orig_sector; unsigned chunk_sects; unsigned sectors; @@ -584,8 +605,26 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio) bio = split; } + orig_sector = sector; zone = find_zone(mddev->private, §or); - tmp_dev = map_sector(mddev, zone, sector, §or); + switch (conf->layout) { + case RAID0_ORIG_LAYOUT: + tmp_dev = map_sector(mddev, zone, orig_sector, §or); + break; + case RAID0_ALT_MULTIZONE_LAYOUT: + tmp_dev = map_sector(mddev, zone, sector, §or); + break; + default: + WARN("md/raid0:%s: Invalid layout\n", mdname(mddev)); + bio_io_error(bio); + return true; + } + + if (unlikely(is_mddev_broken(tmp_dev, "raid0"))) { + bio_io_error(bio); + return true; + } + bio_set_dev(bio, tmp_dev->bdev); bio->bi_iter.bi_sector = sector + zone->dev_start + tmp_dev->data_offset; diff --git a/drivers/md/raid0.h b/drivers/md/raid0.h index 540e65d92642d8427fbe3af4d5960834cc967a74..3816e5477db1e743afeaf707c1971f1dbdce1901 100644 --- a/drivers/md/raid0.h +++ b/drivers/md/raid0.h @@ -8,11 +8,25 @@ struct strip_zone { int nb_dev; /* # of devices attached to the zone */ }; +/* Linux 3.14 (20d0189b101) made an unintended change to + * the RAID0 layout for multi-zone arrays (where devices aren't all + * the same size. + * RAID0_ORIG_LAYOUT restores the original layout + * RAID0_ALT_MULTIZONE_LAYOUT uses the altered layout + * The layouts are identical when there is only one zone (all + * devices the same size). + */ + +enum r0layout { + RAID0_ORIG_LAYOUT = 1, + RAID0_ALT_MULTIZONE_LAYOUT = 2, +}; struct r0conf { struct strip_zone *strip_zone; struct md_rdev **devlist; /* lists of rdevs, pointed to * by strip_zone->dev */ int nr_strip_zones; + enum r0layout layout; }; #endif diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 34e26834ad28bd15ab18a216ed324bf0aab090dc..0466ee2453b435c4ce861d422c571a010d4dc8cb 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -447,19 +447,21 @@ static void raid1_end_write_request(struct bio *bio) /* We never try FailFast to WriteMostly devices */ !test_bit(WriteMostly, &rdev->flags)) { md_error(r1_bio->mddev, rdev); - if (!test_bit(Faulty, &rdev->flags)) - /* This is the only remaining device, - * We need to retry the write without - * FailFast - */ - set_bit(R1BIO_WriteError, &r1_bio->state); - else { - /* Finished with this branch */ - r1_bio->bios[mirror] = NULL; - to_put = bio; - } - } else + } + + /* + * When the device is faulty, it is not necessary to + * handle write error. + * For failfast, this is the only remaining device, + * We need to retry the write without FailFast. + */ + if (!test_bit(Faulty, &rdev->flags)) set_bit(R1BIO_WriteError, &r1_bio->state); + else { + /* Finished with this branch */ + r1_bio->bios[mirror] = NULL; + to_put = bio; + } } else { /* * Set R1BIO_Uptodate in our master bio, so that we @@ -872,8 +874,11 @@ static void flush_pending_writes(struct r1conf *conf) * backgroup IO calls must call raise_barrier. Once that returns * there is no normal IO happeing. It must arrange to call * lower_barrier when the particular background IO completes. + * + * If resync/recovery is interrupted, returns -EINTR; + * Otherwise, returns 0. */ -static sector_t raise_barrier(struct r1conf *conf, sector_t sector_nr) +static int raise_barrier(struct r1conf *conf, sector_t sector_nr) { int idx = sector_to_idx(sector_nr); @@ -1612,12 +1617,12 @@ static void raid1_error(struct mddev *mddev, struct md_rdev *rdev) /* * If it is not operational, then we have already marked it as dead - * else if it is the last working disks, ignore the error, let the - * next level up know. + * else if it is the last working disks with "fail_last_dev == false", + * ignore the error, let the next level up know. * else mark the drive as failed */ spin_lock_irqsave(&conf->device_lock, flags); - if (test_bit(In_sync, &rdev->flags) + if (test_bit(In_sync, &rdev->flags) && !mddev->fail_last_dev && (conf->raid_disks - mddev->degraded) == 1) { /* * Don't fail the drive, act as though we were just a @@ -1901,6 +1906,22 @@ static void abort_sync_write(struct mddev *mddev, struct r1bio *r1_bio) } while (sectors_to_go > 0); } +static void put_sync_write_buf(struct r1bio *r1_bio, int uptodate) +{ + if (atomic_dec_and_test(&r1_bio->remaining)) { + struct mddev *mddev = r1_bio->mddev; + int s = r1_bio->sectors; + + if (test_bit(R1BIO_MadeGood, &r1_bio->state) || + test_bit(R1BIO_WriteError, &r1_bio->state)) + reschedule_retry(r1_bio); + else { + put_buf(r1_bio); + md_done_sync(mddev, s, uptodate); + } + } +} + static void end_sync_write(struct bio *bio) { int uptodate = !bio->bi_status; @@ -1927,16 +1948,7 @@ static void end_sync_write(struct bio *bio) ) set_bit(R1BIO_MadeGood, &r1_bio->state); - if (atomic_dec_and_test(&r1_bio->remaining)) { - int s = r1_bio->sectors; - if (test_bit(R1BIO_MadeGood, &r1_bio->state) || - test_bit(R1BIO_WriteError, &r1_bio->state)) - reschedule_retry(r1_bio); - else { - put_buf(r1_bio); - md_done_sync(mddev, s, uptodate); - } - } + put_sync_write_buf(r1_bio, uptodate); } static int r1_sync_page_io(struct md_rdev *rdev, sector_t sector, @@ -2219,17 +2231,7 @@ static void sync_request_write(struct mddev *mddev, struct r1bio *r1_bio) generic_make_request(wbio); } - if (atomic_dec_and_test(&r1_bio->remaining)) { - /* if we're here, all write(s) have completed, so clean up */ - int s = r1_bio->sectors; - if (test_bit(R1BIO_MadeGood, &r1_bio->state) || - test_bit(R1BIO_WriteError, &r1_bio->state)) - reschedule_retry(r1_bio); - else { - put_buf(r1_bio); - md_done_sync(mddev, s, 1); - } - } + put_sync_write_buf(r1_bio, 1); } /* @@ -3127,6 +3129,13 @@ static int raid1_run(struct mddev *mddev) !test_bit(In_sync, &conf->mirrors[i].rdev->flags) || test_bit(Faulty, &conf->mirrors[i].rdev->flags)) mddev->degraded++; + /* + * RAID1 needs at least one disk in active + */ + if (conf->raid_disks - mddev->degraded < 1) { + ret = -EINVAL; + goto abort; + } if (conf->raid_disks - mddev->degraded == 1) mddev->recovery_cp = MaxSector; @@ -3160,8 +3169,12 @@ static int raid1_run(struct mddev *mddev) ret = md_integrity_register(mddev); if (ret) { md_unregister_thread(&mddev->thread); - raid1_free(mddev, conf); + goto abort; } + return 0; + +abort: + raid1_free(mddev, conf); return ret; } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 8a1354a08a1a30cca7c8b68752621c923f107f5b..299c7b1c97185c7a9dcf7549f2757326b26cfea3 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -465,19 +465,21 @@ static void raid10_end_write_request(struct bio *bio) if (test_bit(FailFast, &rdev->flags) && (bio->bi_opf & MD_FAILFAST)) { md_error(rdev->mddev, rdev); - if (!test_bit(Faulty, &rdev->flags)) - /* This is the only remaining device, - * We need to retry the write without - * FailFast - */ - set_bit(R10BIO_WriteError, &r10_bio->state); - else { - r10_bio->devs[slot].bio = NULL; - to_put = bio; - dec_rdev = 1; - } - } else + } + + /* + * When the device is faulty, it is not necessary to + * handle write error. + * For failfast, this is the only remaining device, + * We need to retry the write without FailFast. + */ + if (!test_bit(Faulty, &rdev->flags)) set_bit(R10BIO_WriteError, &r10_bio->state); + else { + r10_bio->devs[slot].bio = NULL; + to_put = bio; + dec_rdev = 1; + } } } else { /* @@ -1638,12 +1640,12 @@ static void raid10_error(struct mddev *mddev, struct md_rdev *rdev) /* * If it is not operational, then we have already marked it as dead - * else if it is the last working disks, ignore the error, let the - * next level up know. + * else if it is the last working disks with "fail_last_dev == false", + * ignore the error, let the next level up know. * else mark the drive as failed */ spin_lock_irqsave(&conf->device_lock, flags); - if (test_bit(In_sync, &rdev->flags) + if (test_bit(In_sync, &rdev->flags) && !mddev->fail_last_dev && !enough(conf, rdev->raid_disk)) { /* * Don't fail the drive, just return an IO error. diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 3de4e13bde984553ac5571a690e93f43ffad5bdf..223e97ab27e6b6f1de5aaeee40a78991e3621b2b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2526,7 +2526,8 @@ static void raid5_end_read_request(struct bio * bi) int set_bad = 0; clear_bit(R5_UPTODATE, &sh->dev[i].flags); - atomic_inc(&rdev->read_errors); + if (!(bi->bi_status == BLK_STS_PROTECTION)) + atomic_inc(&rdev->read_errors); if (test_bit(R5_ReadRepl, &sh->dev[i].flags)) pr_warn_ratelimited( "md/raid:%s: read error on replacement device (sector %llu on %s).\n", @@ -2549,16 +2550,24 @@ static void raid5_end_read_request(struct bio * bi) (unsigned long long)s, bdn); } else if (atomic_read(&rdev->read_errors) - > conf->max_nr_stripes) - pr_warn("md/raid:%s: Too many read errors, failing device %s.\n", - mdname(conf->mddev), bdn); - else + > conf->max_nr_stripes) { + if (!test_bit(Faulty, &rdev->flags)) { + pr_warn("md/raid:%s: %d read_errors > %d stripes\n", + mdname(conf->mddev), + atomic_read(&rdev->read_errors), + conf->max_nr_stripes); + pr_warn("md/raid:%s: Too many read errors, failing device %s.\n", + mdname(conf->mddev), bdn); + } + } else retry = 1; if (set_bad && test_bit(In_sync, &rdev->flags) && !test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) retry = 1; if (retry) - if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) { + if (sh->qd_idx >= 0 && sh->pd_idx == i) + set_bit(R5_ReadError, &sh->dev[i].flags); + else if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) { set_bit(R5_ReadError, &sh->dev[i].flags); clear_bit(R5_ReadNoMerge, &sh->dev[i].flags); } else @@ -4612,7 +4621,6 @@ static void break_stripe_batch_list(struct stripe_head *head_sh, (1 << STRIPE_FULL_WRITE) | (1 << STRIPE_BIOFILL_RUN) | (1 << STRIPE_COMPUTE_RUN) | - (1 << STRIPE_OPS_REQ_PENDING) | (1 << STRIPE_DISCARD) | (1 << STRIPE_BATCH_READY) | (1 << STRIPE_BATCH_ERR) | @@ -5491,7 +5499,7 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi) return; logical_sector = bi->bi_iter.bi_sector & ~((sector_t)STRIPE_SECTORS-1); - last_sector = bi->bi_iter.bi_sector + (bi->bi_iter.bi_size>>9); + last_sector = bio_end_sector(bi); bi->bi_next = NULL; @@ -5718,7 +5726,8 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi) do_flush = false; } - set_bit(STRIPE_HANDLE, &sh->state); + if (!sh->batch_head) + set_bit(STRIPE_HANDLE, &sh->state); clear_bit(STRIPE_DELAYED, &sh->state); if ((!sh->batch_head || sh == sh->batch_head) && (bi->bi_opf & REQ_SYNC) && diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index cf991f13403eb224ec7f467f4f57874e21ba4c89..f90e0704bed994604f52fa31e0f27c10e1009de2 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -357,7 +357,6 @@ enum { STRIPE_FULL_WRITE, /* all blocks are set to be overwritten */ STRIPE_BIOFILL_RUN, STRIPE_COMPUTE_RUN, - STRIPE_OPS_REQ_PENDING, STRIPE_ON_UNPLUG_LIST, STRIPE_DISCARD, STRIPE_ON_RELEASE_LIST, @@ -493,9 +492,7 @@ struct disk_info { */ static inline struct bio *r5_next_bio(struct bio *bio, sector_t sector) { - int sectors = bio_sectors(bio); - - if (bio->bi_iter.bi_sector + sectors < sector + STRIPE_SECTORS) + if (bio_end_sector(bio) < sector + STRIPE_SECTORS) return bio->bi_next; else return NULL; diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 21cd9c02960b8b96496b739159dac0c9a16a4e44..b36a4133286709edc7595bf773bbd30c959fe498 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -190,7 +190,7 @@ config MEDIA_SUBDRV_AUTOSELECT depends on HAS_IOMEM select I2C select I2C_MUX - default y + default y if !EMBEDDED help By default, a media driver auto-selects all possible ancillary devices such as tuners, sensors, video encoders/decoders and @@ -207,6 +207,11 @@ config MEDIA_SUBDRV_AUTOSELECT If unsure say Y. +config MEDIA_HIDE_ANCILLARY_SUBDRV + bool + depends on MEDIA_SUBDRV_AUTOSELECT && !COMPILE_TEST && !EXPERT + default y + config MEDIA_ATTACH bool depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 451c61bde4d42f1b97c62f05f5dd88bc9f6ad3f1..5ef7daeb8cbd70827e09f8a36fe149f2531a4caa 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -1614,6 +1614,9 @@ EXPORT_SYMBOL_GPL(cec_s_phys_addr_from_edid); void cec_s_conn_info(struct cec_adapter *adap, const struct cec_connector_info *conn_info) { + if (IS_ERR_OR_NULL(adap)) + return; + if (!(adap->capabilities & CEC_CAP_CONNECTOR_INFO)) return; diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c index 52a867bde15fd53567e1eb18a8844d8ccdc188fa..4d82a5522072e16bac6410f65194115b01047d77 100644 --- a/drivers/media/cec/cec-notifier.c +++ b/drivers/media/cec/cec-notifier.c @@ -218,6 +218,8 @@ void cec_notifier_unregister(struct cec_notifier *n) mutex_lock(&n->lock); n->callback = NULL; + n->cec_adap->notifier = NULL; + n->cec_adap = NULL; mutex_unlock(&n->lock); cec_notifier_put(n); } diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index 4c399a42e874c2157975e89c3f95884d9597b9e2..d16122039b0c87b39388597d74baaad616289f8a 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -20,62 +20,52 @@ MODULE_PARM_DESC(max_memory, "maximum memory usage for capture buffers (default: /* format descriptions for capture and preview */ static struct saa7146_format formats[] = { { - .name = "RGB-8 (3-3-2)", .pixelformat = V4L2_PIX_FMT_RGB332, .trans = RGB08_COMPOSED, .depth = 8, .flags = 0, }, { - .name = "RGB-16 (5/B-6/G-5/R)", .pixelformat = V4L2_PIX_FMT_RGB565, .trans = RGB16_COMPOSED, .depth = 16, .flags = 0, }, { - .name = "RGB-24 (B-G-R)", .pixelformat = V4L2_PIX_FMT_BGR24, .trans = RGB24_COMPOSED, .depth = 24, .flags = 0, }, { - .name = "RGB-32 (B-G-R)", .pixelformat = V4L2_PIX_FMT_BGR32, .trans = RGB32_COMPOSED, .depth = 32, .flags = 0, }, { - .name = "RGB-32 (R-G-B)", .pixelformat = V4L2_PIX_FMT_RGB32, .trans = RGB32_COMPOSED, .depth = 32, .flags = 0, .swap = 0x2, }, { - .name = "Greyscale-8", .pixelformat = V4L2_PIX_FMT_GREY, .trans = Y8, .depth = 8, .flags = 0, }, { - .name = "YUV 4:2:2 planar (Y-Cb-Cr)", .pixelformat = V4L2_PIX_FMT_YUV422P, .trans = YUV422_DECOMPOSED, .depth = 16, .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR, }, { - .name = "YVU 4:2:0 planar (Y-Cb-Cr)", .pixelformat = V4L2_PIX_FMT_YVU420, .trans = YUV420_DECOMPOSED, .depth = 12, .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR, }, { - .name = "YUV 4:2:0 planar (Y-Cb-Cr)", .pixelformat = V4L2_PIX_FMT_YUV420, .trans = YUV420_DECOMPOSED, .depth = 12, .flags = FORMAT_IS_PLANAR, }, { - .name = "YUV 4:2:2 (U-Y-V-Y)", .pixelformat = V4L2_PIX_FMT_UYVY, .trans = YUV422_COMPOSED, .depth = 16, @@ -147,10 +137,10 @@ int saa7146_start_preview(struct saa7146_fh *fh) } vv->ov.win = fmt.fmt.win; - DEB_D("%dx%d+%d+%d %s field=%s\n", + DEB_D("%dx%d+%d+%d 0x%08x field=%s\n", vv->ov.win.w.width, vv->ov.win.w.height, vv->ov.win.w.left, vv->ov.win.w.top, - vv->ov_fmt->name, v4l2_field_names[vv->ov.win.field]); + vv->ov_fmt->pixelformat, v4l2_field_names[vv->ov.win.field]); if (0 != (ret = saa7146_enable_overlay(fh))) { DEB_D("enabling overlay failed: %d\n", ret); @@ -515,8 +505,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtd { if (f->index >= ARRAY_SIZE(formats)) return -EINVAL; - strscpy((char *)f->description, formats[f->index].name, - sizeof(f->description)); f->pixelformat = formats[f->index].pixelformat; return 0; } diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 07e0629af8ed2968d97c56ac63d7c43ca80c8235..50f1e0b28b250d8f20a1c689da5c7263b32117d8 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -217,9 +217,21 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_RGB444: case V4L2_PIX_FMT_XRGB444: case V4L2_PIX_FMT_ARGB444: + case V4L2_PIX_FMT_RGBX444: + case V4L2_PIX_FMT_RGBA444: + case V4L2_PIX_FMT_XBGR444: + case V4L2_PIX_FMT_ABGR444: + case V4L2_PIX_FMT_BGRX444: + case V4L2_PIX_FMT_BGRA444: case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: + case V4L2_PIX_FMT_RGBX555: + case V4L2_PIX_FMT_RGBA555: + case V4L2_PIX_FMT_XBGR555: + case V4L2_PIX_FMT_ABGR555: + case V4L2_PIX_FMT_BGRX555: + case V4L2_PIX_FMT_BGRA555: case V4L2_PIX_FMT_RGB555X: case V4L2_PIX_FMT_XRGB555X: case V4L2_PIX_FMT_ARGB555X: @@ -232,6 +244,10 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_XBGR32: case V4L2_PIX_FMT_ARGB32: case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_RGBX32: + case V4L2_PIX_FMT_BGRX32: + case V4L2_PIX_FMT_RGBA32: + case V4L2_PIX_FMT_BGRA32: tpg->color_enc = TGP_COLOR_ENC_RGB; break; case V4L2_PIX_FMT_GREY: @@ -343,9 +359,21 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_RGB444: case V4L2_PIX_FMT_XRGB444: case V4L2_PIX_FMT_ARGB444: + case V4L2_PIX_FMT_RGBX444: + case V4L2_PIX_FMT_RGBA444: + case V4L2_PIX_FMT_XBGR444: + case V4L2_PIX_FMT_ABGR444: + case V4L2_PIX_FMT_BGRX444: + case V4L2_PIX_FMT_BGRA444: case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: + case V4L2_PIX_FMT_RGBX555: + case V4L2_PIX_FMT_RGBA555: + case V4L2_PIX_FMT_XBGR555: + case V4L2_PIX_FMT_ABGR555: + case V4L2_PIX_FMT_BGRX555: + case V4L2_PIX_FMT_BGRA555: case V4L2_PIX_FMT_RGB555X: case V4L2_PIX_FMT_XRGB555X: case V4L2_PIX_FMT_ARGB555X: @@ -375,6 +403,10 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_XBGR32: case V4L2_PIX_FMT_ARGB32: case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_RGBX32: + case V4L2_PIX_FMT_BGRX32: + case V4L2_PIX_FMT_RGBA32: + case V4L2_PIX_FMT_BGRA32: case V4L2_PIX_FMT_YUV32: case V4L2_PIX_FMT_AYUV32: case V4L2_PIX_FMT_XYUV32: @@ -1007,6 +1039,12 @@ static void precalculate_color(struct tpg_data *tpg, int k) case V4L2_PIX_FMT_RGB444: case V4L2_PIX_FMT_XRGB444: case V4L2_PIX_FMT_ARGB444: + case V4L2_PIX_FMT_RGBX444: + case V4L2_PIX_FMT_RGBA444: + case V4L2_PIX_FMT_XBGR444: + case V4L2_PIX_FMT_ABGR444: + case V4L2_PIX_FMT_BGRX444: + case V4L2_PIX_FMT_BGRA444: r >>= 8; g >>= 8; b >>= 8; @@ -1014,6 +1052,12 @@ static void precalculate_color(struct tpg_data *tpg, int k) case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: + case V4L2_PIX_FMT_RGBX555: + case V4L2_PIX_FMT_RGBA555: + case V4L2_PIX_FMT_XBGR555: + case V4L2_PIX_FMT_ABGR555: + case V4L2_PIX_FMT_BGRX555: + case V4L2_PIX_FMT_BGRA555: case V4L2_PIX_FMT_RGB555X: case V4L2_PIX_FMT_XRGB555X: case V4L2_PIX_FMT_ARGB555X: @@ -1237,6 +1281,27 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset] = (g_u_s << 4) | b_v; buf[0][offset + 1] = (alpha & 0xf0) | r_y_h; break; + case V4L2_PIX_FMT_RGBX444: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_RGBA444: + buf[0][offset] = (b_v << 4) | (alpha >> 4); + buf[0][offset + 1] = (r_y_h << 4) | g_u_s; + break; + case V4L2_PIX_FMT_XBGR444: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_ABGR444: + buf[0][offset] = (g_u_s << 4) | r_y_h; + buf[0][offset + 1] = (alpha & 0xf0) | b_v; + break; + case V4L2_PIX_FMT_BGRX444: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_BGRA444: + buf[0][offset] = (r_y_h << 4) | (alpha >> 4); + buf[0][offset + 1] = (b_v << 4) | g_u_s; + break; case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: alpha = 0; @@ -1247,6 +1312,30 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset + 1] = (alpha & 0x80) | (r_y_h << 2) | (g_u_s >> 3); break; + case V4L2_PIX_FMT_RGBX555: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_RGBA555: + buf[0][offset] = (g_u_s << 6) | (b_v << 1) | + ((alpha & 0x80) >> 7); + buf[0][offset + 1] = (r_y_h << 3) | (g_u_s >> 2); + break; + case V4L2_PIX_FMT_XBGR555: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_ABGR555: + buf[0][offset] = (g_u_s << 5) | r_y_h; + buf[0][offset + 1] = (alpha & 0x80) | (b_v << 2) + | (g_u_s >> 3); + break; + case V4L2_PIX_FMT_BGRX555: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_BGRA555: + buf[0][offset] = (g_u_s << 6) | (r_y_h << 1) | + ((alpha & 0x80) >> 7); + buf[0][offset + 1] = (b_v << 3) | (g_u_s >> 2); + break; case V4L2_PIX_FMT_RGB555X: case V4L2_PIX_FMT_XRGB555X: alpha = 0; @@ -1286,6 +1375,15 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset + 2] = g_u_s; buf[0][offset + 3] = b_v; break; + case V4L2_PIX_FMT_RGBX32: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_RGBA32: + buf[0][offset] = r_y_h; + buf[0][offset + 1] = g_u_s; + buf[0][offset + 2] = b_v; + buf[0][offset + 3] = alpha; + break; case V4L2_PIX_FMT_BGR32: case V4L2_PIX_FMT_XBGR32: case V4L2_PIX_FMT_VUYX32: @@ -1298,6 +1396,15 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset + 2] = r_y_h; buf[0][offset + 3] = alpha; break; + case V4L2_PIX_FMT_BGRX32: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_BGRA32: + buf[0][offset] = alpha; + buf[0][offset + 1] = b_v; + buf[0][offset + 2] = g_u_s; + buf[0][offset + 3] = r_y_h; + break; case V4L2_PIX_FMT_SBGGR8: buf[0][offset] = odd ? g_u_s : b_v; buf[1][offset] = odd ? r_y_h : g_u_s; diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index 7d77e4d30c8ab987b6a35529968a2afb5505eabd..44cd0e530bbd3030b18dcf729406bad1a53b5a7e 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -267,8 +267,14 @@ static void vb2_dc_dmabuf_ops_detach(struct dma_buf *dbuf, /* release the scatterlist cache */ if (attach->dma_dir != DMA_NONE) - dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, - attach->dma_dir); + /* + * Cache sync can be skipped here, as the vb2_dc memory is + * allocated from device coherent memory, which means the + * memory locations do not require any explicit cache + * maintenance prior or after being used by the device. + */ + dma_unmap_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents, + attach->dma_dir, DMA_ATTR_SKIP_CPU_SYNC); sg_free_table(sgt); kfree(attach); db_attach->priv = NULL; @@ -293,14 +299,17 @@ static struct sg_table *vb2_dc_dmabuf_ops_map( /* release any previous cache */ if (attach->dma_dir != DMA_NONE) { - dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, - attach->dma_dir); + dma_unmap_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents, + attach->dma_dir, DMA_ATTR_SKIP_CPU_SYNC); attach->dma_dir = DMA_NONE; } - /* mapping to the client with new direction */ - sgt->nents = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, - dma_dir); + /* + * mapping to the client with new direction, no cache sync + * required see comment in vb2_dc_dmabuf_ops_detach() + */ + sgt->nents = dma_map_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents, + dma_dir, DMA_ATTR_SKIP_CPU_SYNC); if (!sgt->nents) { pr_err("failed to map scatterlist\n"); mutex_unlock(lock); diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 40d76eb4c2fe79b4ff8e46675284afcd7afa9e86..5a9ba3846f0a5a2630ddbe55e8dc1fa3ea75d078 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -872,17 +872,19 @@ EXPORT_SYMBOL_GPL(vb2_queue_release); __poll_t vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) { struct video_device *vfd = video_devdata(file); - __poll_t res = 0; + __poll_t res; + + res = vb2_core_poll(q, file, wait); if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { struct v4l2_fh *fh = file->private_data; poll_wait(file, &fh->wait, wait); if (v4l2_event_pending(fh)) - res = EPOLLPRI; + res |= EPOLLPRI; } - return res | vb2_core_poll(q, file, wait); + return res; } EXPORT_SYMBOL_GPL(vb2_poll); diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 209186c5cd9b920efe79534290d6be00100436f4..06ea30a689d758e5888951817546ecccd689e5fa 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -152,6 +152,9 @@ static void dvb_frontend_free(struct kref *ref) static void dvb_frontend_put(struct dvb_frontend *fe) { + /* call detach before dropping the reference count */ + if (fe->ops.detach) + fe->ops.detach(fe); /* * Check if the frontend was registered, as otherwise * kref was not initialized yet. @@ -3040,7 +3043,6 @@ void dvb_frontend_detach(struct dvb_frontend *fe) dvb_frontend_invoke_release(fe, fe->ops.release_sec); dvb_frontend_invoke_release(fe, fe->ops.tuner_ops.release); dvb_frontend_invoke_release(fe, fe->ops.analog_ops.release); - dvb_frontend_invoke_release(fe, fe->ops.detach); dvb_frontend_put(fe); } EXPORT_SYMBOL(dvb_frontend_detach); diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index a3393cd4e584f48ee2d07eb11d7edd729aaeee52..917fe034af373c755164550461ef1a72fc663afc 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -339,8 +339,10 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev, if (npads) { dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads), GFP_KERNEL); - if (!dvbdev->pads) + if (!dvbdev->pads) { + kfree(dvbdev->entity); return -ENOMEM; + } } switch (type) { @@ -476,7 +478,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, return -ENOMEM; } - dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL); + dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL); if (!dvbdevfops){ kfree (dvbdev); @@ -492,7 +494,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, dvbdev->fops = dvbdevfops; init_waitqueue_head (&dvbdev->wait_queue); - memcpy(dvbdevfops, template->fops, sizeof(struct file_operations)); dvbdevfops->owner = adap->module; list_add_tail (&dvbdev->list_head, &adap->device_list); diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index dc43749177df2a0b4bf95f66ba2886c0eb59d90f..a29e9ddf9c8213d4db08a16affc3488927616ed5 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -1,5 +1,8 @@ +comment "DVB Frontend drivers hidden by 'Autoselect ancillary drivers'" + depends on MEDIA_HIDE_ANCILLARY_SUBDRV + menu "Customise DVB Frontends" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT + visible if !MEDIA_HIDE_ANCILLARY_SUBDRV comment "Multistandard (satellite) frontends" depends on DVB_CORE diff --git a/drivers/media/dvb-frontends/cx24117.c b/drivers/media/dvb-frontends/cx24117.c index 42697a5999f7dd20022d5868b34a515f74fd1db5..9fccc906d85a4e71f27a6528edfe0536ca693827 100644 --- a/drivers/media/dvb-frontends/cx24117.c +++ b/drivers/media/dvb-frontends/cx24117.c @@ -619,8 +619,10 @@ static int cx24117_load_firmware(struct dvb_frontend *fe, /* send fw */ ret = i2c_transfer(state->priv->i2c, &msg, 1); - if (ret < 0) + if (ret < 0) { + kfree(buf); return ret; + } kfree(buf); diff --git a/drivers/media/dvb-frontends/cx24123.c b/drivers/media/dvb-frontends/cx24123.c index ac519c3eff18069fbb688f0b61e5283542411fd1..3d84ee17e54c69472bcbcae64738c27e66169099 100644 --- a/drivers/media/dvb-frontends/cx24123.c +++ b/drivers/media/dvb-frontends/cx24123.c @@ -431,7 +431,7 @@ static u32 cx24123_int_log2(u32 a, u32 b) u32 div = a / b; if (a % b >= b / 2) ++div; - if (div < (1 << 31)) { + if (div < (1UL << 31)) { for (exp = 1; div > exp; nearest++) exp += exp; } diff --git a/drivers/media/dvb-frontends/cxd2099.c b/drivers/media/dvb-frontends/cxd2099.c index 5264e873850e9d86a45a369d27f7e5c6f33d4af2..f88b5355493e51e814fa8a98432772d9bc9043a3 100644 --- a/drivers/media/dvb-frontends/cxd2099.c +++ b/drivers/media/dvb-frontends/cxd2099.c @@ -594,7 +594,7 @@ static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) return ecount; } -static struct dvb_ca_en50221 en_templ = { +static const struct dvb_ca_en50221 en_templ = { .read_attribute_mem = read_attribute_mem, .write_attribute_mem = write_attribute_mem, .read_cam_control = read_cam_control, diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index 1f006f8e8cc2f7494c347ca7f860607da7736e3e..d137199e13e69d056034f669c13afb29d637bb5b 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -632,12 +632,11 @@ static int cxd2820r_probe(struct i2c_client *client, * one dummy I2C client in in order to get own I2C client for each * register bank. */ - priv->client[1] = i2c_new_dummy(client->adapter, client->addr | (1 << 1)); - if (!priv->client[1]) { - ret = -ENODEV; + priv->client[1] = i2c_new_dummy_device(client->adapter, client->addr | (1 << 1)); + if (IS_ERR(priv->client[1])) { + ret = PTR_ERR(priv->client[1]); dev_err(&client->dev, "I2C registration failed\n"); - if (ret) - goto err_regmap_0_regmap_exit; + goto err_regmap_0_regmap_exit; } priv->regmap[1] = regmap_init_i2c(priv->client[1], ®map_config1); diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index 52f5e697c5dc9d46672bb6cb9e565178ec8335e0..0d22c700016d4812f3e0569ca963c4501b1b85f3 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -2036,7 +2036,8 @@ static int dib7000pc_detection(struct i2c_adapter *i2c_adap) if (i2c_transfer(i2c_adap, msg, 2) == 2) if (rx[0] == 0x01 && rx[1] == 0xb3) { dprintk("-D- DiB7000PC detected\n"); - return 1; + ret = 1; + goto out; } msg[0].addr = msg[1].addr = 0x40; @@ -2044,11 +2045,13 @@ static int dib7000pc_detection(struct i2c_adapter *i2c_adap) if (i2c_transfer(i2c_adap, msg, 2) == 2) if (rx[0] == 0x01 && rx[1] == 0xb3) { dprintk("-D- DiB7000PC detected\n"); - return 1; + ret = 1; + goto out; } dprintk("-D- DiB7000PC not detected\n"); +out: kfree(rx); rx_memory_error: kfree(tx); diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index a6876fa487538387025fc15eaf887a1360e102e7..2f5af4813a747e324f14f5a3bf3d463df81379b4 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -12287,7 +12287,8 @@ struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c) if (state == NULL) goto error; - demod = kmalloc(sizeof(struct drx_demod_instance), GFP_KERNEL); + demod = kmemdup(&drxj_default_demod_g, + sizeof(struct drx_demod_instance), GFP_KERNEL); if (demod == NULL) goto error; @@ -12311,8 +12312,6 @@ struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c) state->demod = demod; /* setup the demod data */ - memcpy(demod, &drxj_default_demod_g, sizeof(struct drx_demod_instance)); - demod->my_i2c_dev_addr = demod_addr; demod->my_common_attr = demod_comm_attr; demod->my_i2c_dev_addr->user_data = state; diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c index ba0c49107bd28b6792ae63330a961eef4ce36d99..d45b4ddc8f91294ce68b626286f678555e9e0b1f 100644 --- a/drivers/media/dvb-frontends/dvb-pll.c +++ b/drivers/media/dvb-frontends/dvb-pll.c @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -34,8 +35,7 @@ struct dvb_pll_priv { }; #define DVB_PLL_MAX 64 - -static unsigned int dvb_pll_devcount; +static DEFINE_IDA(pll_ida); static int debug; module_param(debug, int, 0644); @@ -787,6 +787,7 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct dvb_pll_priv *priv = NULL; int ret; const struct dvb_pll_desc *desc; + int nr; b1 = kmalloc(1, GFP_KERNEL); if (!b1) @@ -795,9 +796,14 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, b1[0] = 0; msg.buf = b1; - if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) && - (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list))) - pll_desc_id = id[dvb_pll_devcount]; + nr = ida_simple_get(&pll_ida, 0, DVB_PLL_MAX, GFP_KERNEL); + if (nr < 0) { + kfree(b1); + return NULL; + } + + if (id[nr] > DVB_PLL_UNDEFINED && id[nr] < ARRAY_SIZE(pll_list)) + pll_desc_id = id[nr]; BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list)); @@ -808,24 +814,20 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, fe->ops.i2c_gate_ctrl(fe, 1); ret = i2c_transfer (i2c, &msg, 1); - if (ret != 1) { - kfree(b1); - return NULL; - } + if (ret != 1) + goto out; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL); - if (!priv) { - kfree(b1); - return NULL; - } + if (!priv) + goto out; priv->pll_i2c_address = pll_addr; priv->i2c = i2c; priv->pll_desc = desc; - priv->nr = dvb_pll_devcount++; + priv->nr = nr; memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops)); @@ -858,6 +860,11 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, kfree(b1); return fe; +out: + kfree(b1); + ida_simple_remove(&pll_ida, nr); + + return NULL; } EXPORT_SYMBOL(dvb_pll_attach); @@ -894,9 +901,10 @@ dvb_pll_probe(struct i2c_client *client, const struct i2c_device_id *id) static int dvb_pll_remove(struct i2c_client *client) { - struct dvb_frontend *fe; + struct dvb_frontend *fe = i2c_get_clientdata(client); + struct dvb_pll_priv *priv = fe->tuner_priv; - fe = i2c_get_clientdata(client); + ida_simple_remove(&pll_ida, priv->nr); dvb_pll_release(fe); return 0; } diff --git a/drivers/media/dvb-frontends/mn88443x.c b/drivers/media/dvb-frontends/mn88443x.c index 9ec1aeef03d5ae420e4a7be756108c14b93c04ee..e4528784f8477fe897c51a18fc7f5bcb9b9196e4 100644 --- a/drivers/media/dvb-frontends/mn88443x.c +++ b/drivers/media/dvb-frontends/mn88443x.c @@ -722,9 +722,9 @@ static int mn88443x_probe(struct i2c_client *client, * Chip has two I2C addresses for each satellite/terrestrial system. * ISDB-T uses address ISDB-S + 4, so we register a dummy client. */ - chip->client_t = i2c_new_dummy(client->adapter, client->addr + 4); - if (!chip->client_t) - return -ENODEV; + chip->client_t = i2c_new_dummy_device(client->adapter, client->addr + 4); + if (IS_ERR(chip->client_t)) + return PTR_ERR(chip->client_t); chip->regmap_t = devm_regmap_init_i2c(chip->client_t, ®map_config); if (IS_ERR(chip->regmap_t)) { diff --git a/drivers/media/dvb-frontends/mn88472.c b/drivers/media/dvb-frontends/mn88472.c index 731b44b9b74ceb487edc98cd82876b92f6056cdb..73922fc8f39c22bc4c27ab4ae1b9cf4c065db626 100644 --- a/drivers/media/dvb-frontends/mn88472.c +++ b/drivers/media/dvb-frontends/mn88472.c @@ -612,12 +612,11 @@ static int mn88472_probe(struct i2c_client *client, * Also, register bank 2 do not support sequential I/O. Only single * register write or read is allowed to that bank. */ - dev->client[1] = i2c_new_dummy(client->adapter, 0x1a); - if (!dev->client[1]) { - ret = -ENODEV; + dev->client[1] = i2c_new_dummy_device(client->adapter, 0x1a); + if (IS_ERR(dev->client[1])) { + ret = PTR_ERR(dev->client[1]); dev_err(&client->dev, "I2C registration failed\n"); - if (ret) - goto err_regmap_0_regmap_exit; + goto err_regmap_0_regmap_exit; } dev->regmap[1] = regmap_init_i2c(dev->client[1], ®map_config); if (IS_ERR(dev->regmap[1])) { @@ -626,12 +625,11 @@ static int mn88472_probe(struct i2c_client *client, } i2c_set_clientdata(dev->client[1], dev); - dev->client[2] = i2c_new_dummy(client->adapter, 0x1c); - if (!dev->client[2]) { - ret = -ENODEV; + dev->client[2] = i2c_new_dummy_device(client->adapter, 0x1c); + if (IS_ERR(dev->client[2])) { + ret = PTR_ERR(dev->client[2]); dev_err(&client->dev, "2nd I2C registration failed\n"); - if (ret) - goto err_regmap_1_regmap_exit; + goto err_regmap_1_regmap_exit; } dev->regmap[2] = regmap_init_i2c(dev->client[2], ®map_config); if (IS_ERR(dev->regmap[2])) { diff --git a/drivers/media/dvb-frontends/mn88473.c b/drivers/media/dvb-frontends/mn88473.c index 08118b38533ba2cd162861d7bec03a649a135dc2..4838969ef735c4b240eb9e3cd54b659bebcbbd88 100644 --- a/drivers/media/dvb-frontends/mn88473.c +++ b/drivers/media/dvb-frontends/mn88473.c @@ -657,12 +657,11 @@ static int mn88473_probe(struct i2c_client *client, * Also, register bank 2 do not support sequential I/O. Only single * register write or read is allowed to that bank. */ - dev->client[1] = i2c_new_dummy(client->adapter, 0x1a); - if (dev->client[1] == NULL) { - ret = -ENODEV; + dev->client[1] = i2c_new_dummy_device(client->adapter, 0x1a); + if (IS_ERR(dev->client[1])) { + ret = PTR_ERR(dev->client[1]); dev_err(&client->dev, "I2C registration failed\n"); - if (ret) - goto err_regmap_0_regmap_exit; + goto err_regmap_0_regmap_exit; } dev->regmap[1] = regmap_init_i2c(dev->client[1], ®map_config); if (IS_ERR(dev->regmap[1])) { @@ -671,12 +670,11 @@ static int mn88473_probe(struct i2c_client *client, } i2c_set_clientdata(dev->client[1], dev); - dev->client[2] = i2c_new_dummy(client->adapter, 0x1c); - if (dev->client[2] == NULL) { - ret = -ENODEV; + dev->client[2] = i2c_new_dummy_device(client->adapter, 0x1c); + if (IS_ERR(dev->client[2])) { + ret = PTR_ERR(dev->client[2]); dev_err(&client->dev, "2nd I2C registration failed\n"); - if (ret) - goto err_regmap_1_regmap_exit; + goto err_regmap_1_regmap_exit; } dev->regmap[2] = regmap_init_i2c(dev->client[2], ®map_config); if (IS_ERR(dev->regmap[2])) { diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index e05c21d35dc82179c730b24bbaadb1a427515eba..60d1e59d22921643bf1abdafc90a1e459656029b 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -81,11 +81,9 @@ struct rtl2832_sdr_format { static struct rtl2832_sdr_format formats[] = { { - .name = "Complex U8", .pixelformat = V4L2_SDR_FMT_CU8, .buffersize = BULK_BUFFER_SIZE, }, { - .name = "Complex U16LE (emulated)", .pixelformat = V4L2_SDR_FMT_CU16LE, .buffersize = BULK_BUFFER_SIZE * 2, }, @@ -1116,7 +1114,6 @@ static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv, if (f->index >= dev->num_formats) return -EINVAL; - strscpy(f->description, formats[f->index].name, sizeof(f->description)); f->pixelformat = formats[f->index].pixelformat; return 0; diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 168c503e9154f97d41642562ffe3a93aea5561c0..14b93a7d335892c8b4675a1eca62ad66325b72e4 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -11,6 +11,13 @@ static const struct dvb_frontend_ops si2168_ops; +static void cmd_init(struct si2168_cmd *cmd, const u8 *buf, int wlen, int rlen) +{ + memcpy(cmd->args, buf, wlen); + cmd->wlen = wlen; + cmd->rlen = rlen; +} + /* execute firmware command */ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) { @@ -82,16 +89,23 @@ static int si2168_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire); + /* set manual value */ + if (dev->ts_mode & SI2168_TS_CLK_MANUAL) { + cmd_init(&cmd, "\x14\x00\x0d\x10\xe8\x03", 6, 4); + ret = si2168_cmd_execute(client, &cmd); + if (ret) + return ret; + } /* set TS_MODE property */ - memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); + cmd_init(&cmd, "\x14\x00\x01\x10\x10\x00", 6, 4); + if (dev->ts_mode & SI2168_TS_CLK_MANUAL) + cmd.args[4] = SI2168_TS_CLK_MANUAL; if (acquire) cmd.args[4] |= dev->ts_mode; else cmd.args[4] |= SI2168_TS_TRISTATE; if (dev->ts_clock_gapped) cmd.args[4] |= 0x40; - cmd.wlen = 6; - cmd.rlen = 4; ret = si2168_cmd_execute(client, &cmd); return ret; @@ -115,19 +129,13 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) switch (c->delivery_system) { case SYS_DVBT: - memcpy(cmd.args, "\xa0\x01", 2); - cmd.wlen = 2; - cmd.rlen = 13; + cmd_init(&cmd, "\xa0\x01", 2, 13); break; case SYS_DVBC_ANNEX_A: - memcpy(cmd.args, "\x90\x01", 2); - cmd.wlen = 2; - cmd.rlen = 9; + cmd_init(&cmd, "\x90\x01", 2, 9); break; case SYS_DVBT2: - memcpy(cmd.args, "\x50\x01", 2); - cmd.wlen = 2; - cmd.rlen = 14; + cmd_init(&cmd, "\x50\x01", 2, 14); break; default: ret = -EINVAL; @@ -164,9 +172,7 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) /* BER */ if (*status & FE_HAS_VITERBI) { - memcpy(cmd.args, "\x82\x00", 2); - cmd.wlen = 2; - cmd.rlen = 3; + cmd_init(&cmd, "\x82\x00", 2, 3); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -197,9 +203,7 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) /* UCB */ if (*status & FE_HAS_SYNC) { - memcpy(cmd.args, "\x84\x01", 2); - cmd.wlen = 2; - cmd.rlen = 3; + cmd_init(&cmd, "\x84\x01", 2, 3); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -285,22 +289,18 @@ static int si2168_set_frontend(struct dvb_frontend *fe) goto err; } - memcpy(cmd.args, "\x88\x02\x02\x02\x02", 5); - cmd.wlen = 5; - cmd.rlen = 5; + cmd_init(&cmd, "\x88\x02\x02\x02\x02", 5, 5); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; /* that has no big effect */ if (c->delivery_system == SYS_DVBT) - memcpy(cmd.args, "\x89\x21\x06\x11\xff\x98", 6); + cmd_init(&cmd, "\x89\x21\x06\x11\xff\x98", 6, 3); else if (c->delivery_system == SYS_DVBC_ANNEX_A) - memcpy(cmd.args, "\x89\x21\x06\x11\x89\xf0", 6); + cmd_init(&cmd, "\x89\x21\x06\x11\x89\xf0", 6, 3); else if (c->delivery_system == SYS_DVBT2) - memcpy(cmd.args, "\x89\x21\x06\x11\x89\x20", 6); - cmd.wlen = 6; - cmd.rlen = 3; + cmd_init(&cmd, "\x89\x21\x06\x11\x89\x20", 6, 3); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -317,103 +317,77 @@ static int si2168_set_frontend(struct dvb_frontend *fe) goto err; } - memcpy(cmd.args, "\x51\x03", 2); - cmd.wlen = 2; - cmd.rlen = 12; + cmd_init(&cmd, "\x51\x03", 2, 12); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x12\x08\x04", 3); - cmd.wlen = 3; - cmd.rlen = 3; + cmd_init(&cmd, "\x12\x08\x04", 3, 3); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x0c\x10\x12\x00", 6); - cmd.wlen = 6; - cmd.rlen = 4; + cmd_init(&cmd, "\x14\x00\x0c\x10\x12\x00", 6, 4); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x06\x10\x24\x00", 6); - cmd.wlen = 6; - cmd.rlen = 4; + cmd_init(&cmd, "\x14\x00\x06\x10\x24\x00", 6, 4); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x07\x10\x00\x24", 6); - cmd.wlen = 6; - cmd.rlen = 4; + cmd_init(&cmd, "\x14\x00\x07\x10\x00\x24", 6, 4); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x0a\x10\x00\x00", 6); + cmd_init(&cmd, "\x14\x00\x0a\x10\x00\x00", 6, 4); cmd.args[4] = delivery_system | bandwidth; if (dev->spectral_inversion) cmd.args[5] |= 1; - cmd.wlen = 6; - cmd.rlen = 4; ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; /* set DVB-C symbol rate */ if (c->delivery_system == SYS_DVBC_ANNEX_A) { - memcpy(cmd.args, "\x14\x00\x02\x11", 4); + cmd_init(&cmd, "\x14\x00\x02\x11\x00\x00", 6, 4); cmd.args[4] = ((c->symbol_rate / 1000) >> 0) & 0xff; cmd.args[5] = ((c->symbol_rate / 1000) >> 8) & 0xff; - cmd.wlen = 6; - cmd.rlen = 4; ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; } - memcpy(cmd.args, "\x14\x00\x0f\x10\x10\x00", 6); - cmd.wlen = 6; - cmd.rlen = 4; + cmd_init(&cmd, "\x14\x00\x0f\x10\x10\x00", 6, 4); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x08", 6); + cmd_init(&cmd, "\x14\x00\x09\x10\xe3\x08", 6, 4); cmd.args[5] |= dev->ts_clock_inv ? 0x00 : 0x10; - cmd.wlen = 6; - cmd.rlen = 4; ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x05", 6); + cmd_init(&cmd, "\x14\x00\x08\x10\xd7\x05", 6, 4); cmd.args[5] |= dev->ts_clock_inv ? 0x00 : 0x10; - cmd.wlen = 6; - cmd.rlen = 4; ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x01\x12\x00\x00", 6); - cmd.wlen = 6; - cmd.rlen = 4; + cmd_init(&cmd, "\x14\x00\x01\x12\x00\x00", 6, 4); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x01\x03\x0c\x00", 6); - cmd.wlen = 6; - cmd.rlen = 4; + cmd_init(&cmd, "\x14\x00\x01\x03\x0c\x00", 6, 4); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x85", 1); - cmd.wlen = 1; - cmd.rlen = 1; + cmd_init(&cmd, "\x85", 1, 1); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -443,26 +417,21 @@ static int si2168_init(struct dvb_frontend *fe) dev_dbg(&client->dev, "\n"); /* initialize */ - memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13); - cmd.wlen = 13; - cmd.rlen = 0; + cmd_init(&cmd, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", + 13, 0); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; if (dev->warm) { /* resume */ - memcpy(cmd.args, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8); - cmd.wlen = 8; - cmd.rlen = 1; + cmd_init(&cmd, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8, 1); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; udelay(100); - memcpy(cmd.args, "\x85", 1); - cmd.wlen = 1; - cmd.rlen = 1; + cmd_init(&cmd, "\x85", 1, 1); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -471,9 +440,7 @@ static int si2168_init(struct dvb_frontend *fe) } /* power up */ - memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8); - cmd.wlen = 8; - cmd.rlen = 1; + cmd_init(&cmd, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8, 1); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -511,9 +478,8 @@ static int si2168_init(struct dvb_frontend *fe) ret = -EINVAL; break; } - memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len); - cmd.wlen = len; - cmd.rlen = 1; + cmd_init(&cmd, &fw->data[(fw->size - remaining) + 1], + len, 1); ret = si2168_cmd_execute(client, &cmd); if (ret) break; @@ -521,10 +487,7 @@ static int si2168_init(struct dvb_frontend *fe) } else if (fw->size % 8 == 0) { /* firmware is in the old format */ for (remaining = fw->size; remaining > 0; remaining -= 8) { - len = 8; - memcpy(cmd.args, &fw->data[fw->size - remaining], len); - cmd.wlen = len; - cmd.rlen = 1; + cmd_init(&cmd, &fw->data[fw->size - remaining], 8, 1); ret = si2168_cmd_execute(client, &cmd); if (ret) break; @@ -541,17 +504,13 @@ static int si2168_init(struct dvb_frontend *fe) release_firmware(fw); - memcpy(cmd.args, "\x01\x01", 2); - cmd.wlen = 2; - cmd.rlen = 1; + cmd_init(&cmd, "\x01\x01", 2, 1); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; /* query firmware version */ - memcpy(cmd.args, "\x11", 1); - cmd.wlen = 1; - cmd.rlen = 10; + cmd_init(&cmd, "\x11", 1, 10); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -609,9 +568,7 @@ static int si2168_sleep(struct dvb_frontend *fe) if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) dev->warm = false; - memcpy(cmd.args, "\x13", 1); - cmd.wlen = 1; - cmd.rlen = 0; + cmd_init(&cmd, "\x13", 1, 0); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -637,9 +594,7 @@ static int si2168_select(struct i2c_mux_core *muxc, u32 chan) struct si2168_cmd cmd; /* open I2C gate */ - memcpy(cmd.args, "\xc0\x0d\x01", 3); - cmd.wlen = 3; - cmd.rlen = 0; + cmd_init(&cmd, "\xc0\x0d\x01", 3, 0); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -657,9 +612,7 @@ static int si2168_deselect(struct i2c_mux_core *muxc, u32 chan) struct si2168_cmd cmd; /* close I2C gate */ - memcpy(cmd.args, "\xc0\x0d\x00", 3); - cmd.wlen = 3; - cmd.rlen = 0; + cmd_init(&cmd, "\xc0\x0d\x00", 3, 0); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -730,25 +683,20 @@ static int si2168_probe(struct i2c_client *client, mutex_init(&dev->i2c_mutex); /* Initialize */ - memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13); - cmd.wlen = 13; - cmd.rlen = 0; + cmd_init(&cmd, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", + 13, 0); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err_kfree; /* Power up */ - memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8); - cmd.wlen = 8; - cmd.rlen = 1; + cmd_init(&cmd, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8, 1); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err_kfree; /* Query chip revision */ - memcpy(cmd.args, "\x02", 1); - cmd.wlen = 1; - cmd.rlen = 13; + cmd_init(&cmd, "\x02", 1, 13); ret = si2168_cmd_execute(client, &cmd); if (ret) goto err_kfree; diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h index 3b04f84272d9dcc28bf5803c00dbe2d8943c1e62..50dccb394efa646537ec2982ad10de1e2319e0a5 100644 --- a/drivers/media/dvb-frontends/si2168.h +++ b/drivers/media/dvb-frontends/si2168.h @@ -30,6 +30,7 @@ struct si2168_config { #define SI2168_TS_PARALLEL 0x06 #define SI2168_TS_SERIAL 0x03 #define SI2168_TS_TRISTATE 0x00 +#define SI2168_TS_CLK_MANUAL 0x20 u8 ts_mode; /* TS clock inverted */ diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c index 0c50740e7bb8bb7a087865ec0618c7988475d20b..7d93a1617e866a4ecc3e57096197a532b52c56d2 100644 --- a/drivers/media/dvb-frontends/stv0900_core.c +++ b/drivers/media/dvb-frontends/stv0900_core.c @@ -270,7 +270,7 @@ static enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *intp) static u32 stv0900_get_mclk_freq(struct stv0900_internal *intp, u32 ext_clk) { - u32 mclk = 90000000, div = 0, ad_div = 0; + u32 mclk, div, ad_div; div = stv0900_get_bits(intp, F0900_M_DIV); ad_div = ((stv0900_get_bits(intp, F0900_SELX1RATIO) == 1) ? 4 : 6); diff --git a/drivers/media/dvb-frontends/zd1301_demod.c b/drivers/media/dvb-frontends/zd1301_demod.c index 96adbba7a82b6267b9f8573cb854f6e4a1a50279..bbabe6a2d4f476e04a055d027120bfdd9c7abccb 100644 --- a/drivers/media/dvb-frontends/zd1301_demod.c +++ b/drivers/media/dvb-frontends/zd1301_demod.c @@ -421,8 +421,7 @@ static int zd1301_demod_i2c_master_xfer(struct i2c_adapter *adapter, } else { dev_dbg(&pdev->dev, "unknown msg[0].len=%u\n", msg[0].len); ret = -EOPNOTSUPP; - if (ret) - goto err; + goto err; } return num; diff --git a/drivers/media/firewire/firedtv-ci.c b/drivers/media/firewire/firedtv-ci.c index a960a0ce9debe4c7bd9928acd11781aeecf90439..9363d005e2b612da8f6e7f4cdb96020c730879cb 100644 --- a/drivers/media/firewire/firedtv-ci.c +++ b/drivers/media/firewire/firedtv-ci.c @@ -217,7 +217,7 @@ static const struct file_operations fdtv_ca_fops = { .llseek = noop_llseek, }; -static struct dvb_device fdtv_ca = { +static const struct dvb_device fdtv_ca = { .users = 1, .readers = 1, .writers = 1, diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 79ce9ec6fc1be1e612af10ec96cbbb166502033c..7eee1812bba36a668af1331faebdc33562096689 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -22,8 +22,11 @@ config VIDEO_IR_I2C # Encoder / Decoder module configuration # +comment "I2C drivers hidden by 'Autoselect ancillary drivers'" + depends on MEDIA_HIDE_ANCILLARY_SUBDRV + menu "I2C Encoders, decoders, sensors and other helper chips" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT + visible if !MEDIA_HIDE_ANCILLARY_SUBDRV comment "Audio decoders, processors and mixers" @@ -723,6 +726,19 @@ config VIDEO_OV5670 To compile this driver as a module, choose M here: the module will be called ov5670. +config VIDEO_OV5675 + tristate "OmniVision OV5675 sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT + depends on MEDIA_CONTROLLER + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the OmniVision + OV5675 camera. + + To compile this driver as a module, choose M here: the + module will be called ov5675. + config VIDEO_OV5695 tristate "OmniVision OV5695 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index fd4ea86dedd5df448ced54e00cfc061cc77a26fe..beb170b002dc95f369116e78d471cf8448622565 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_VIDEO_OV5640) += ov5640.o obj-$(CONFIG_VIDEO_OV5645) += ov5645.o obj-$(CONFIG_VIDEO_OV5647) += ov5647.o obj-$(CONFIG_VIDEO_OV5670) += ov5670.o +obj-$(CONFIG_VIDEO_OV5675) += ov5675.o obj-$(CONFIG_VIDEO_OV5695) += ov5695.o obj-$(CONFIG_VIDEO_OV6650) += ov6650.o obj-$(CONFIG_VIDEO_OV7251) += ov7251.o diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c index aa8b04cfed0f6c3c298bba33f48345710b0d8fe5..8679a44e6413bb8f7bb67e628584a8fd308e28fb 100644 --- a/drivers/media/i2c/ad9389b.c +++ b/drivers/media/i2c/ad9389b.c @@ -1148,10 +1148,10 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id * v4l2_dbg(1, debug, sd, "reg 0x41 0x%x, chip version (reg 0x00) 0x%x\n", ad9389b_rd(sd, 0x41), state->chip_revision); - state->edid_i2c_client = i2c_new_dummy(client->adapter, (0x7e>>1)); - if (state->edid_i2c_client == NULL) { + state->edid_i2c_client = i2c_new_dummy_device(client->adapter, (0x7e >> 1)); + if (IS_ERR(state->edid_i2c_client)) { v4l2_err(sd, "failed to register edid i2c client\n"); - err = -ENOMEM; + err = PTR_ERR(state->edid_i2c_client); goto err_entity; } diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 6f3dc8862622d72cf9a49258008336a76846fab3..e780969cc2f26082001ca59cdd57a628acf1cc4f 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -1329,17 +1329,17 @@ static int adv7180_probe(struct i2c_client *client, } if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { - state->csi_client = i2c_new_dummy(client->adapter, + state->csi_client = i2c_new_dummy_device(client->adapter, ADV7180_DEFAULT_CSI_I2C_ADDR); - if (!state->csi_client) - return -ENOMEM; + if (IS_ERR(state->csi_client)) + return PTR_ERR(state->csi_client); } if (state->chip_info->flags & ADV7180_FLAG_I2P) { - state->vpp_client = i2c_new_dummy(client->adapter, + state->vpp_client = i2c_new_dummy_device(client->adapter, ADV7180_DEFAULT_VPP_I2C_ADDR); - if (!state->vpp_client) { - ret = -ENOMEM; + if (IS_ERR(state->vpp_client)) { + ret = PTR_ERR(state->vpp_client); goto err_unregister_csi_client; } } diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c index 4a441ee99dd8ba51a4f8c5449705d68e8398dc7c..63e94dfcb5d33ba2551e28d789b649134585f9b7 100644 --- a/drivers/media/i2c/adv7343.c +++ b/drivers/media/i2c/adv7343.c @@ -428,8 +428,7 @@ adv7343_get_pdata(struct i2c_client *client) return pdata; } -static int adv7343_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adv7343_probe(struct i2c_client *client) { struct adv7343_state *state; int err; @@ -524,7 +523,7 @@ static struct i2c_driver adv7343_driver = { .of_match_table = of_match_ptr(adv7343_of_match), .name = "adv7343", }, - .probe = adv7343_probe, + .probe_new = adv7343_probe, .remove = adv7343_remove, .id_table = adv7343_id, }; diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index f57cd77a32fac9c741269a02267b1f9b96580e63..0a47d474e97a52950594ced5eec286eae84332b4 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -668,8 +668,7 @@ static void adv748x_dt_cleanup(struct adv748x_state *state) of_node_put(state->endpoints[i]); } -static int adv748x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adv748x_probe(struct i2c_client *client) { struct adv748x_state *state; int ret; @@ -797,13 +796,6 @@ static int adv748x_remove(struct i2c_client *client) return 0; } -static const struct i2c_device_id adv748x_id[] = { - { "adv7481", 0 }, - { "adv7482", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, adv748x_id); - static const struct of_device_id adv748x_of_table[] = { { .compatible = "adi,adv7481", }, { .compatible = "adi,adv7482", }, @@ -816,9 +808,8 @@ static struct i2c_driver adv748x_driver = { .name = "adv748x", .of_match_table = adv748x_of_table, }, - .probe = adv748x_probe, + .probe_new = adv748x_probe, .remove = adv748x_remove, - .id_table = adv748x_id, }; module_i2c_driver(adv748x_driver); diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c index 2ad6bdf1a9fce5f1b28271efc175d400b61927f4..62763ec4cd073a567b3893d0090fdfbf67dc2281 100644 --- a/drivers/media/i2c/adv7511-v4l2.c +++ b/drivers/media/i2c/adv7511-v4l2.c @@ -1872,11 +1872,11 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * goto err_entity; } - state->i2c_edid = i2c_new_dummy(client->adapter, + state->i2c_edid = i2c_new_dummy_device(client->adapter, state->i2c_edid_addr >> 1); - if (state->i2c_edid == NULL) { + if (IS_ERR(state->i2c_edid)) { v4l2_err(sd, "failed to register edid i2c client\n"); - err = -ENOMEM; + err = PTR_ERR(state->i2c_edid); goto err_entity; } @@ -1889,11 +1889,11 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * } if (state->pdata.cec_clk) { - state->i2c_cec = i2c_new_dummy(client->adapter, + state->i2c_cec = i2c_new_dummy_device(client->adapter, state->i2c_cec_addr >> 1); - if (state->i2c_cec == NULL) { + if (IS_ERR(state->i2c_cec)) { v4l2_err(sd, "failed to register cec i2c client\n"); - err = -ENOMEM; + err = PTR_ERR(state->i2c_cec); goto err_unreg_edid; } adv7511_wr(sd, 0xe2, 0x00); /* power up cec section */ @@ -1901,10 +1901,10 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * adv7511_wr(sd, 0xe2, 0x01); /* power down cec section */ } - state->i2c_pktmem = i2c_new_dummy(client->adapter, state->i2c_pktmem_addr >> 1); - if (state->i2c_pktmem == NULL) { + state->i2c_pktmem = i2c_new_dummy_device(client->adapter, state->i2c_pktmem_addr >> 1); + if (IS_ERR(state->i2c_pktmem)) { v4l2_err(sd, "failed to register pktmem i2c client\n"); - err = -ENOMEM; + err = PTR_ERR(state->i2c_pktmem); goto err_unreg_cec; } @@ -1940,8 +1940,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * err_unreg_pktmem: i2c_unregister_device(state->i2c_pktmem); err_unreg_cec: - if (state->i2c_cec) - i2c_unregister_device(state->i2c_cec); + i2c_unregister_device(state->i2c_cec); err_unreg_edid: i2c_unregister_device(state->i2c_edid); err_entity: @@ -1967,8 +1966,7 @@ static int adv7511_remove(struct i2c_client *client) adv7511_init_setup(sd); cancel_delayed_work(&state->edid_handler); i2c_unregister_device(state->i2c_edid); - if (state->i2c_cec) - i2c_unregister_device(state->i2c_cec); + i2c_unregister_device(state->i2c_cec); i2c_unregister_device(state->i2c_pktmem); destroy_workqueue(state->work_queue); v4l2_device_unregister_subdev(sd); @@ -1980,14 +1978,14 @@ static int adv7511_remove(struct i2c_client *client) /* ----------------------------------------------------------------------- */ static const struct i2c_device_id adv7511_id[] = { - { "adv7511", 0 }, + { "adv7511-v4l2", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, adv7511_id); static struct i2c_driver adv7511_driver = { .driver = { - .name = "adv7511", + .name = "adv7511-v4l2", }, .probe = adv7511_probe, .remove = adv7511_remove, diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 11ab2df02dc70c519148d1a71bec4d5050c0e47b..885619841719b390b1180b5a5fddca0ed2cea0dd 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -3351,28 +3351,17 @@ static const struct v4l2_ctrl_config adv7842_ctrl_free_run_color = { static void adv7842_unregister_clients(struct v4l2_subdev *sd) { struct adv7842_state *state = to_state(sd); - if (state->i2c_avlink) - i2c_unregister_device(state->i2c_avlink); - if (state->i2c_cec) - i2c_unregister_device(state->i2c_cec); - if (state->i2c_infoframe) - i2c_unregister_device(state->i2c_infoframe); - if (state->i2c_sdp_io) - i2c_unregister_device(state->i2c_sdp_io); - if (state->i2c_sdp) - i2c_unregister_device(state->i2c_sdp); - if (state->i2c_afe) - i2c_unregister_device(state->i2c_afe); - if (state->i2c_repeater) - i2c_unregister_device(state->i2c_repeater); - if (state->i2c_edid) - i2c_unregister_device(state->i2c_edid); - if (state->i2c_hdmi) - i2c_unregister_device(state->i2c_hdmi); - if (state->i2c_cp) - i2c_unregister_device(state->i2c_cp); - if (state->i2c_vdp) - i2c_unregister_device(state->i2c_vdp); + i2c_unregister_device(state->i2c_avlink); + i2c_unregister_device(state->i2c_cec); + i2c_unregister_device(state->i2c_infoframe); + i2c_unregister_device(state->i2c_sdp_io); + i2c_unregister_device(state->i2c_sdp); + i2c_unregister_device(state->i2c_afe); + i2c_unregister_device(state->i2c_repeater); + i2c_unregister_device(state->i2c_edid); + i2c_unregister_device(state->i2c_hdmi); + i2c_unregister_device(state->i2c_cp); + i2c_unregister_device(state->i2c_vdp); state->i2c_avlink = NULL; state->i2c_cec = NULL; @@ -3400,9 +3389,12 @@ static struct i2c_client *adv7842_dummy_client(struct v4l2_subdev *sd, const cha return NULL; } - cp = i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1); - if (!cp) - v4l2_err(sd, "register %s on i2c addr 0x%x failed\n", desc, addr); + cp = i2c_new_dummy_device(client->adapter, io_read(sd, io_reg) >> 1); + if (IS_ERR(cp)) { + v4l2_err(sd, "register %s on i2c addr 0x%x failed with %ld\n", + desc, addr, PTR_ERR(cp)); + cp = NULL; + } return cp; } diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c index e6c06cb75d33703e4462117a545539a8cc2c9267..256acf73d5eaa1ebd10a41291a922a291b056621 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_driver.c +++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c @@ -1396,8 +1396,7 @@ static int __maybe_unused et8ek8_resume(struct device *dev) return __et8ek8_set_power(sensor, true); } -static int et8ek8_probe(struct i2c_client *client, - const struct i2c_device_id *devid) +static int et8ek8_probe(struct i2c_client *client) { struct et8ek8_sensor *sensor; struct device *dev = &client->dev; @@ -1504,7 +1503,7 @@ static struct i2c_driver et8ek8_i2c_driver = { .pm = &et8ek8_pm_ops, .of_match_table = et8ek8_of_table, }, - .probe = et8ek8_probe, + .probe_new = et8ek8_probe, .remove = __exit_p(et8ek8_remove), .id_table = et8ek8_id_table, }; diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index f3ff1af209f9885a609c56fe5c6ba56baa211f0f..6011cec5e351d2f2cf16c15e3391578d3318dd40 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -1821,8 +1821,7 @@ static const struct i2c_device_id imx274_id[] = { }; MODULE_DEVICE_TABLE(i2c, imx274_id); -static int imx274_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int imx274_probe(struct i2c_client *client) { struct v4l2_subdev *sd; struct stimx274 *imx274; @@ -1984,7 +1983,7 @@ static struct i2c_driver imx274_i2c_driver = { .name = DRIVER_NAME, .of_match_table = imx274_of_id_table, }, - .probe = imx274_probe, + .probe_new = imx274_probe, .remove = imx274_remove, .id_table = imx274_id, }; diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 876d7587a1daa8a6bf84d196637e0b7aa9f56ded..e8119ad0bc71dc38de4c719a121034e357e2c3d9 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -885,9 +885,11 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) INIT_DELAYED_WORK(&ir->work, ir_work); if (probe_tx) { - ir->tx_c = i2c_new_dummy(client->adapter, 0x70); - if (!ir->tx_c) { + ir->tx_c = i2c_new_dummy_device(client->adapter, 0x70); + if (IS_ERR(ir->tx_c)) { dev_err(&client->dev, "failed to setup tx i2c address"); + err = PTR_ERR(ir->tx_c); + goto err_out_free; } else if (!zilog_init(ir)) { ir->carrier = 38000; ir->duty_cycle = 40; @@ -904,7 +906,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) return 0; err_out_free: - if (ir->tx_c) + if (!IS_ERR(ir->tx_c)) i2c_unregister_device(ir->tx_c); /* Only frees rc if it were allocated internally */ @@ -916,16 +918,12 @@ static int ir_remove(struct i2c_client *client) { struct IR_i2c *ir = i2c_get_clientdata(client); - /* kill outstanding polls */ cancel_delayed_work_sync(&ir->work); - if (ir->tx_c) - i2c_unregister_device(ir->tx_c); + i2c_unregister_device(ir->tx_c); - /* unregister device */ rc_unregister_device(ir->rc); - /* free memory */ return 0; } diff --git a/drivers/media/i2c/max2175.c b/drivers/media/i2c/max2175.c index 7b226fadcdb86ca2c7d559cbcc2c2c62d7d463cf..19a3ceea3bc20f0f5c53646565e8545ac161bcc3 100644 --- a/drivers/media/i2c/max2175.c +++ b/drivers/media/i2c/max2175.c @@ -1271,8 +1271,7 @@ static int max2175_refout_load_to_bits(struct i2c_client *client, u32 load, return 0; } -static int max2175_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max2175_probe(struct i2c_client *client) { bool master = true, am_hiz = false; u32 refout_load, refout_bits = 0; /* REFOUT disabled */ @@ -1433,7 +1432,7 @@ static struct i2c_driver max2175_driver = { .name = DRIVER_NAME, .of_match_table = max2175_of_ids, }, - .probe = max2175_probe, + .probe_new = max2175_probe, .remove = max2175_remove, .id_table = max2175_id, }; diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c index 2df743cbe09d814154f8f9a5680429d10c4e6d51..5613072908acbf481273eaff357a8eede4a78f15 100644 --- a/drivers/media/i2c/mt9m001.c +++ b/drivers/media/i2c/mt9m001.c @@ -726,8 +726,7 @@ static const struct v4l2_subdev_ops mt9m001_subdev_ops = { .pad = &mt9m001_subdev_pad_ops, }; -static int mt9m001_probe(struct i2c_client *client, - const struct i2c_device_id *did) +static int mt9m001_probe(struct i2c_client *client) { struct mt9m001 *mt9m001; struct i2c_adapter *adapter = client->adapter; @@ -872,7 +871,7 @@ static struct i2c_driver mt9m001_i2c_driver = { .pm = &mt9m001_pm_ops, .of_match_table = mt9m001_of_match, }, - .probe = mt9m001_probe, + .probe_new = mt9m001_probe, .remove = mt9m001_remove, .id_table = mt9m001_id, }; diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index 12cb012d91f71160c911d5dcc216dcfb8c3b3317..17e8253f5748ec8522164c0194f8c4981ed419d1 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -533,7 +533,7 @@ static int mt9m111_get_fmt(struct v4l2_subdev *sd, format->format = *mf; return 0; #else - return -ENOTTY; + return -EINVAL; #endif } @@ -1243,8 +1243,7 @@ static int mt9m111_probe_fw(struct i2c_client *client, struct mt9m111 *mt9m111) return ret; } -static int mt9m111_probe(struct i2c_client *client, - const struct i2c_device_id *did) +static int mt9m111_probe(struct i2c_client *client) { struct mt9m111 *mt9m111; struct i2c_adapter *adapter = client->adapter; @@ -1388,7 +1387,7 @@ static struct i2c_driver mt9m111_i2c_driver = { .name = "mt9m111", .of_match_table = of_match_ptr(mt9m111_of_match), }, - .probe = mt9m111_probe, + .probe_new = mt9m111_probe, .remove = mt9m111_remove, .id_table = mt9m111_id, }; diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index ecd167d7c4d265234292f395f4138f2c9e037a6d..4a4bd5b665a1f1a187149ef798b2f68060f39785 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -929,7 +929,7 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd, format->format = *mf; return 0; #else - return -ENOTTY; + return -EINVAL; #endif } @@ -1190,8 +1190,7 @@ static int ov2640_probe_dt(struct i2c_client *client, /* * i2c_driver functions */ -static int ov2640_probe(struct i2c_client *client, - const struct i2c_device_id *did) +static int ov2640_probe(struct i2c_client *client) { struct ov2640_priv *priv; struct i2c_adapter *adapter = client->adapter; @@ -1302,7 +1301,7 @@ static struct i2c_driver ov2640_i2c_driver = { .name = "ov2640", .of_match_table = of_match_ptr(ov2640_of_match), }, - .probe = ov2640_probe, + .probe_new = ov2640_probe, .remove = ov2640_remove, .id_table = ov2640_id, }; diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index 5ed2413eac8a1ebb817cf644f4a3008e7df1faf5..f4ded0669ff9eb71110e55fe897a3ca2cf3c66b3 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -1055,7 +1055,7 @@ static int ov2659_get_fmt(struct v4l2_subdev *sd, mutex_unlock(&ov2659->lock); return 0; #else - return -ENOTTY; + return -EINVAL; #endif } @@ -1131,8 +1131,6 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd, #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; -#else - ret = -ENOTTY; #endif } else { s64 val; @@ -1386,8 +1384,7 @@ ov2659_get_pdata(struct i2c_client *client) return pdata; } -static int ov2659_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov2659_probe(struct i2c_client *client) { const struct ov2659_platform_data *pdata = ov2659_get_pdata(client); struct v4l2_subdev *sd; @@ -1515,7 +1512,7 @@ static struct i2c_driver ov2659_i2c_driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(ov2659_of_match), }, - .probe = ov2659_probe, + .probe_new = ov2659_probe, .remove = ov2659_remove, .id_table = ov2659_id, }; diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c index b10bcfabaeeb05a2bc21283408b4f00062b7d116..59cdbc33658ce69edd7b2cece66e9905730e8b97 100644 --- a/drivers/media/i2c/ov2680.c +++ b/drivers/media/i2c/ov2680.c @@ -675,7 +675,7 @@ static int ov2680_get_fmt(struct v4l2_subdev *sd, #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API fmt = v4l2_subdev_get_try_format(&sensor->sd, cfg, format->pad); #else - ret = -ENOTTY; + ret = -EINVAL; #endif } else { fmt = &sensor->fmt; @@ -723,10 +723,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API try_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); format->format = *try_fmt; -#else - ret = -ENOTTY; #endif - goto unlock; } @@ -1023,7 +1020,7 @@ static int ov2680_check_id(struct ov2680_dev *sensor) return 0; } -static int ov2860_parse_dt(struct ov2680_dev *sensor) +static int ov2680_parse_dt(struct ov2680_dev *sensor) { struct device *dev = ov2680_to_dev(sensor); int ret; @@ -1064,7 +1061,7 @@ static int ov2680_probe(struct i2c_client *client) sensor->i2c_client = client; - ret = ov2860_parse_dt(sensor); + ret = ov2680_parse_dt(sensor); if (ret < 0) return -EINVAL; diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 759d60c6d6304b9e894c84839925efad7b3d56fc..500d9bbff10b5038cd4350432402db58e94c11d8 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -158,8 +158,8 @@ static const int ov5640_framerates[] = { /* regulator supplies */ static const char * const ov5640_supply_name[] = { "DOVDD", /* Digital I/O (1.8V) supply */ - "DVDD", /* Digital Core (1.5V) supply */ "AVDD", /* Analog (2.8V) supply */ + "DVDD", /* Digital Core (1.5V) supply */ }; #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name) @@ -2936,8 +2936,7 @@ static int ov5640_check_chip_id(struct ov5640_dev *sensor) return ret; } -static int ov5640_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov5640_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct fwnode_handle *endpoint; @@ -3022,9 +3021,14 @@ static int ov5640_probe(struct i2c_client *client, /* request optional power down pin */ sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); + if (IS_ERR(sensor->pwdn_gpio)) + return PTR_ERR(sensor->pwdn_gpio); + /* request optional reset pin */ sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(sensor->reset_gpio)) + return PTR_ERR(sensor->reset_gpio); v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops); @@ -3050,7 +3054,7 @@ static int ov5640_probe(struct i2c_client *client, if (ret) goto entity_cleanup; - ret = v4l2_async_register_subdev(&sensor->sd); + ret = v4l2_async_register_subdev_sensor_common(&sensor->sd); if (ret) goto free_ctrls; @@ -3095,7 +3099,7 @@ static struct i2c_driver ov5640_i2c_driver = { .of_match_table = ov5640_dt_ids, }, .id_table = ov5640_id, - .probe = ov5640_probe, + .probe_new = ov5640_probe, .remove = ov5640_remove, }; diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c index 124c8df04633752fc951a7b99c54004b18236b35..a6c17d15d75479afa1757acf2f6a06d913ae9d64 100644 --- a/drivers/media/i2c/ov5645.c +++ b/drivers/media/i2c/ov5645.c @@ -34,10 +34,6 @@ #include #include -#define OV5645_VOLTAGE_ANALOG 2800000 -#define OV5645_VOLTAGE_DIGITAL_CORE 1500000 -#define OV5645_VOLTAGE_DIGITAL_IO 1800000 - #define OV5645_SYSTEM_CTRL0 0x3008 #define OV5645_SYSTEM_CTRL0_START 0x02 #define OV5645_SYSTEM_CTRL0_STOP 0x42 @@ -45,6 +41,8 @@ #define OV5645_CHIP_ID_HIGH_BYTE 0x56 #define OV5645_CHIP_ID_LOW 0x300b #define OV5645_CHIP_ID_LOW_BYTE 0x45 +#define OV5645_IO_MIPI_CTRL00 0x300e +#define OV5645_PAD_OUTPUT00 0x3019 #define OV5645_AWB_MANUAL_CONTROL 0x3406 #define OV5645_AWB_MANUAL_ENABLE BIT(0) #define OV5645_AEC_PK_MANUAL 0x3503 @@ -55,6 +53,7 @@ #define OV5645_ISP_VFLIP BIT(2) #define OV5645_TIMING_TC_REG21 0x3821 #define OV5645_SENSOR_MIRROR BIT(1) +#define OV5645_MIPI_CTRL00 0x4800 #define OV5645_PRE_ISP_TEST_SETTING_1 0x503d #define OV5645_TEST_PATTERN_MASK 0x3 #define OV5645_SET_TEST_PATTERN(x) ((x) & OV5645_TEST_PATTERN_MASK) @@ -62,6 +61,15 @@ #define OV5645_SDE_SAT_U 0x5583 #define OV5645_SDE_SAT_V 0x5584 +/* regulator supplies */ +static const char * const ov5645_supply_name[] = { + "vdddo", /* Digital I/O (1.8V) supply */ + "vdda", /* Analog (2.8V) supply */ + "vddd", /* Digital Core (1.5V) supply */ +}; + +#define OV5645_NUM_SUPPLIES ARRAY_SIZE(ov5645_supply_name) + struct reg_value { u16 reg; u8 val; @@ -86,9 +94,7 @@ struct ov5645 { struct v4l2_rect crop; struct clk *xclk; - struct regulator *io_regulator; - struct regulator *core_regulator; - struct regulator *analog_regulator; + struct regulator_bulk_data supplies[OV5645_NUM_SUPPLIES]; const struct ov5645_mode_info *current_mode; @@ -121,7 +127,6 @@ static const struct reg_value ov5645_global_init_setting[] = { { 0x3503, 0x07 }, { 0x3002, 0x1c }, { 0x3006, 0xc3 }, - { 0x300e, 0x45 }, { 0x3017, 0x00 }, { 0x3018, 0x00 }, { 0x302e, 0x0b }, @@ -350,7 +355,10 @@ static const struct reg_value ov5645_global_init_setting[] = { { 0x3a1f, 0x14 }, { 0x0601, 0x02 }, { 0x3008, 0x42 }, - { 0x3008, 0x02 } + { 0x3008, 0x02 }, + { OV5645_IO_MIPI_CTRL00, 0x40 }, + { OV5645_MIPI_CTRL00, 0x24 }, + { OV5645_PAD_OUTPUT00, 0x70 } }; static const struct reg_value ov5645_setting_sxga[] = { @@ -533,55 +541,6 @@ static const struct ov5645_mode_info ov5645_mode_info_data[] = { }, }; -static int ov5645_regulators_enable(struct ov5645 *ov5645) -{ - int ret; - - ret = regulator_enable(ov5645->io_regulator); - if (ret < 0) { - dev_err(ov5645->dev, "set io voltage failed\n"); - return ret; - } - - ret = regulator_enable(ov5645->analog_regulator); - if (ret) { - dev_err(ov5645->dev, "set analog voltage failed\n"); - goto err_disable_io; - } - - ret = regulator_enable(ov5645->core_regulator); - if (ret) { - dev_err(ov5645->dev, "set core voltage failed\n"); - goto err_disable_analog; - } - - return 0; - -err_disable_analog: - regulator_disable(ov5645->analog_regulator); -err_disable_io: - regulator_disable(ov5645->io_regulator); - - return ret; -} - -static void ov5645_regulators_disable(struct ov5645 *ov5645) -{ - int ret; - - ret = regulator_disable(ov5645->core_regulator); - if (ret < 0) - dev_err(ov5645->dev, "core regulator disable failed\n"); - - ret = regulator_disable(ov5645->analog_regulator); - if (ret < 0) - dev_err(ov5645->dev, "analog regulator disable failed\n"); - - ret = regulator_disable(ov5645->io_regulator); - if (ret < 0) - dev_err(ov5645->dev, "io regulator disable failed\n"); -} - static int ov5645_write_reg(struct ov5645 *ov5645, u16 reg, u8 val) { u8 regbuf[3]; @@ -680,15 +639,14 @@ static int ov5645_set_power_on(struct ov5645 *ov5645) { int ret; - ret = ov5645_regulators_enable(ov5645); - if (ret < 0) { + ret = regulator_bulk_enable(OV5645_NUM_SUPPLIES, ov5645->supplies); + if (ret < 0) return ret; - } ret = clk_prepare_enable(ov5645->xclk); if (ret < 0) { dev_err(ov5645->dev, "clk prepare enable failed\n"); - ov5645_regulators_disable(ov5645); + regulator_bulk_disable(OV5645_NUM_SUPPLIES, ov5645->supplies); return ret; } @@ -708,7 +666,7 @@ static void ov5645_set_power_off(struct ov5645 *ov5645) gpiod_set_value_cansleep(ov5645->rst_gpio, 1); gpiod_set_value_cansleep(ov5645->enable_gpio, 0); clk_disable_unprepare(ov5645->xclk); - ov5645_regulators_disable(ov5645); + regulator_bulk_disable(OV5645_NUM_SUPPLIES, ov5645->supplies); } static int ov5645_s_power(struct v4l2_subdev *sd, int on) @@ -737,13 +695,9 @@ static int ov5645_s_power(struct v4l2_subdev *sd, int on) goto exit; } - ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, - OV5645_SYSTEM_CTRL0_STOP); - if (ret < 0) { - ov5645_set_power_off(ov5645); - goto exit; - } + usleep_range(500, 1000); } else { + ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x58); ov5645_set_power_off(ov5645); } } @@ -1049,11 +1003,20 @@ static int ov5645_s_stream(struct v4l2_subdev *subdev, int enable) dev_err(ov5645->dev, "could not sync v4l2 controls\n"); return ret; } + + ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x45); + if (ret < 0) + return ret; + ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, OV5645_SYSTEM_CTRL0_START); if (ret < 0) return ret; } else { + ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x40); + if (ret < 0) + return ret; + ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, OV5645_SYSTEM_CTRL0_STOP); if (ret < 0) @@ -1086,13 +1049,13 @@ static const struct v4l2_subdev_ops ov5645_subdev_ops = { .pad = &ov5645_subdev_pad_ops, }; -static int ov5645_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov5645_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device_node *endpoint; struct ov5645 *ov5645; u8 chip_id_high, chip_id_low; + unsigned int i; u32 xclk_freq; int ret; @@ -1150,47 +1113,13 @@ static int ov5645_probe(struct i2c_client *client, return ret; } - ov5645->io_regulator = devm_regulator_get(dev, "vdddo"); - if (IS_ERR(ov5645->io_regulator)) { - dev_err(dev, "cannot get io regulator\n"); - return PTR_ERR(ov5645->io_regulator); - } - - ret = regulator_set_voltage(ov5645->io_regulator, - OV5645_VOLTAGE_DIGITAL_IO, - OV5645_VOLTAGE_DIGITAL_IO); - if (ret < 0) { - dev_err(dev, "cannot set io voltage\n"); - return ret; - } - - ov5645->core_regulator = devm_regulator_get(dev, "vddd"); - if (IS_ERR(ov5645->core_regulator)) { - dev_err(dev, "cannot get core regulator\n"); - return PTR_ERR(ov5645->core_regulator); - } - - ret = regulator_set_voltage(ov5645->core_regulator, - OV5645_VOLTAGE_DIGITAL_CORE, - OV5645_VOLTAGE_DIGITAL_CORE); - if (ret < 0) { - dev_err(dev, "cannot set core voltage\n"); - return ret; - } - - ov5645->analog_regulator = devm_regulator_get(dev, "vdda"); - if (IS_ERR(ov5645->analog_regulator)) { - dev_err(dev, "cannot get analog regulator\n"); - return PTR_ERR(ov5645->analog_regulator); - } + for (i = 0; i < OV5645_NUM_SUPPLIES; i++) + ov5645->supplies[i].supply = ov5645_supply_name[i]; - ret = regulator_set_voltage(ov5645->analog_regulator, - OV5645_VOLTAGE_ANALOG, - OV5645_VOLTAGE_ANALOG); - if (ret < 0) { - dev_err(dev, "cannot set analog voltage\n"); + ret = devm_regulator_bulk_get(dev, OV5645_NUM_SUPPLIES, + ov5645->supplies); + if (ret < 0) return ret; - } ov5645->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); if (IS_ERR(ov5645->enable_gpio)) { @@ -1355,7 +1284,7 @@ static struct i2c_driver ov5645_i2c_driver = { .of_match_table = of_match_ptr(ov5645_of_match), .name = "ov5645", }, - .probe = ov5645_probe, + .probe_new = ov5645_probe, .remove = ov5645_remove, .id_table = ov5645_id, }; diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index 4589631798c968a41116169ccdd9e6cd9b26b800..e7d2e5b4ad4b995df4e0291d9a77fdb0287a4555 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -547,8 +547,7 @@ static int ov5647_parse_dt(struct device_node *np) return ret; } -static int ov5647_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov5647_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ov5647 *sensor; @@ -644,7 +643,7 @@ static struct i2c_driver ov5647_driver = { .of_match_table = of_match_ptr(ov5647_of_match), .name = SENSOR_NAME, }, - .probe = ov5647_probe, + .probe_new = ov5647_probe, .remove = ov5647_remove, .id_table = ov5647_id, }; diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c new file mode 100644 index 0000000000000000000000000000000000000000..1ae252378799ea5adf1a1d8738cc996ce66da90b --- /dev/null +++ b/drivers/media/i2c/ov5675.c @@ -0,0 +1,1183 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019 Intel Corporation. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OV5675_REG_VALUE_08BIT 1 +#define OV5675_REG_VALUE_16BIT 2 +#define OV5675_REG_VALUE_24BIT 3 + +#define OV5675_LINK_FREQ_450MHZ 450000000ULL +#define OV5675_SCLK 90000000LL +#define OV5675_MCLK 19200000 +#define OV5675_DATA_LANES 2 +#define OV5675_RGB_DEPTH 10 + +#define OV5675_REG_CHIP_ID 0x300a +#define OV5675_CHIP_ID 0x5675 + +#define OV5675_REG_MODE_SELECT 0x0100 +#define OV5675_MODE_STANDBY 0x00 +#define OV5675_MODE_STREAMING 0x01 + +/* vertical-timings from sensor */ +#define OV5675_REG_VTS 0x380e +#define OV5675_VTS_30FPS 0x07e4 +#define OV5675_VTS_30FPS_MIN 0x07e4 +#define OV5675_VTS_MAX 0x7fff + +/* horizontal-timings from sensor */ +#define OV5675_REG_HTS 0x380c + +/* Exposure controls from sensor */ +#define OV5675_REG_EXPOSURE 0x3500 +#define OV5675_EXPOSURE_MIN 4 +#define OV5675_EXPOSURE_MAX_MARGIN 4 +#define OV5675_EXPOSURE_STEP 1 + +/* Analog gain controls from sensor */ +#define OV5675_REG_ANALOG_GAIN 0x3508 +#define OV5675_ANAL_GAIN_MIN 128 +#define OV5675_ANAL_GAIN_MAX 2047 +#define OV5675_ANAL_GAIN_STEP 1 + +/* Digital gain controls from sensor */ +#define OV5675_REG_MWB_R_GAIN 0x5019 +#define OV5675_REG_MWB_G_GAIN 0x501b +#define OV5675_REG_MWB_B_GAIN 0x501d +#define OV5675_DGTL_GAIN_MIN 0 +#define OV5675_DGTL_GAIN_MAX 4095 +#define OV5675_DGTL_GAIN_STEP 1 +#define OV5675_DGTL_GAIN_DEFAULT 1024 + +/* Test Pattern Control */ +#define OV5675_REG_TEST_PATTERN 0x4503 +#define OV5675_TEST_PATTERN_ENABLE BIT(7) +#define OV5675_TEST_PATTERN_BAR_SHIFT 2 + +#define to_ov5675(_sd) container_of(_sd, struct ov5675, sd) + +enum { + OV5675_LINK_FREQ_900MBPS, +}; + +struct ov5675_reg { + u16 address; + u8 val; +}; + +struct ov5675_reg_list { + u32 num_of_regs; + const struct ov5675_reg *regs; +}; + +struct ov5675_link_freq_config { + const struct ov5675_reg_list reg_list; +}; + +struct ov5675_mode { + /* Frame width in pixels */ + u32 width; + + /* Frame height in pixels */ + u32 height; + + /* Horizontal timining size */ + u32 hts; + + /* Default vertical timining size */ + u32 vts_def; + + /* Min vertical timining size */ + u32 vts_min; + + /* Link frequency needed for this resolution */ + u32 link_freq_index; + + /* Sensor register settings for this resolution */ + const struct ov5675_reg_list reg_list; +}; + +static const struct ov5675_reg mipi_data_rate_900mbps[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x0300, 0x04}, + {0x0302, 0x8d}, + {0x0303, 0x00}, + {0x030d, 0x26}, +}; + +static const struct ov5675_reg mode_2592x1944_regs[] = { + {0x3002, 0x21}, + {0x3107, 0x23}, + {0x3501, 0x20}, + {0x3503, 0x0c}, + {0x3508, 0x03}, + {0x3509, 0x00}, + {0x3600, 0x66}, + {0x3602, 0x30}, + {0x3610, 0xa5}, + {0x3612, 0x93}, + {0x3620, 0x80}, + {0x3642, 0x0e}, + {0x3661, 0x00}, + {0x3662, 0x10}, + {0x3664, 0xf3}, + {0x3665, 0x9e}, + {0x3667, 0xa5}, + {0x366e, 0x55}, + {0x366f, 0x55}, + {0x3670, 0x11}, + {0x3671, 0x11}, + {0x3672, 0x11}, + {0x3673, 0x11}, + {0x3714, 0x24}, + {0x371a, 0x3e}, + {0x3733, 0x10}, + {0x3734, 0x00}, + {0x373d, 0x24}, + {0x3764, 0x20}, + {0x3765, 0x20}, + {0x3766, 0x12}, + {0x37a1, 0x14}, + {0x37a8, 0x1c}, + {0x37ab, 0x0f}, + {0x37c2, 0x04}, + {0x37cb, 0x00}, + {0x37cc, 0x00}, + {0x37cd, 0x00}, + {0x37ce, 0x00}, + {0x37d8, 0x02}, + {0x37d9, 0x08}, + {0x37dc, 0x04}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x04}, + {0x3804, 0x0a}, + {0x3805, 0x3f}, + {0x3806, 0x07}, + {0x3807, 0xb3}, + {0x3808, 0x0a}, + {0x3809, 0x20}, + {0x380a, 0x07}, + {0x380b, 0x98}, + {0x380c, 0x02}, + {0x380d, 0xee}, + {0x380e, 0x07}, + {0x380f, 0xe4}, + {0x3811, 0x10}, + {0x3813, 0x0d}, + {0x3814, 0x01}, + {0x3815, 0x01}, + {0x3816, 0x01}, + {0x3817, 0x01}, + {0x381e, 0x02}, + {0x3820, 0x88}, + {0x3821, 0x01}, + {0x3832, 0x04}, + {0x3c80, 0x01}, + {0x3c82, 0x00}, + {0x3c83, 0xc8}, + {0x3c8c, 0x0f}, + {0x3c8d, 0xa0}, + {0x3c90, 0x07}, + {0x3c91, 0x00}, + {0x3c92, 0x00}, + {0x3c93, 0x00}, + {0x3c94, 0xd0}, + {0x3c95, 0x50}, + {0x3c96, 0x35}, + {0x3c97, 0x00}, + {0x4001, 0xe0}, + {0x4008, 0x02}, + {0x4009, 0x0d}, + {0x400f, 0x80}, + {0x4013, 0x02}, + {0x4040, 0x00}, + {0x4041, 0x07}, + {0x404c, 0x50}, + {0x404e, 0x20}, + {0x4500, 0x06}, + {0x4503, 0x00}, + {0x450a, 0x04}, + {0x4809, 0x04}, + {0x480c, 0x12}, + {0x4819, 0x70}, + {0x4825, 0x32}, + {0x4826, 0x32}, + {0x482a, 0x06}, + {0x4833, 0x08}, + {0x4837, 0x0d}, + {0x5000, 0x77}, + {0x5b00, 0x01}, + {0x5b01, 0x10}, + {0x5b02, 0x01}, + {0x5b03, 0xdb}, + {0x5b05, 0x6c}, + {0x5e10, 0xfc}, + {0x3500, 0x00}, + {0x3501, 0x3E}, + {0x3502, 0x60}, + {0x3503, 0x08}, + {0x3508, 0x04}, + {0x3509, 0x00}, + {0x3832, 0x48}, + {0x5780, 0x3e}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x06}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, + {0x4003, 0x40}, + {0x3107, 0x01}, + {0x3c80, 0x08}, + {0x3c83, 0xb1}, + {0x3c8c, 0x10}, + {0x3c8d, 0x00}, + {0x3c90, 0x00}, + {0x3c94, 0x00}, + {0x3c95, 0x00}, + {0x3c96, 0x00}, + {0x37cb, 0x09}, + {0x37cc, 0x15}, + {0x37cd, 0x1f}, + {0x37ce, 0x1f}, +}; + +static const struct ov5675_reg mode_1296x972_regs[] = { + {0x3002, 0x21}, + {0x3107, 0x23}, + {0x3501, 0x20}, + {0x3503, 0x0c}, + {0x3508, 0x03}, + {0x3509, 0x00}, + {0x3600, 0x66}, + {0x3602, 0x30}, + {0x3610, 0xa5}, + {0x3612, 0x93}, + {0x3620, 0x80}, + {0x3642, 0x0e}, + {0x3661, 0x00}, + {0x3662, 0x08}, + {0x3664, 0xf3}, + {0x3665, 0x9e}, + {0x3667, 0xa5}, + {0x366e, 0x55}, + {0x366f, 0x55}, + {0x3670, 0x11}, + {0x3671, 0x11}, + {0x3672, 0x11}, + {0x3673, 0x11}, + {0x3714, 0x28}, + {0x371a, 0x3e}, + {0x3733, 0x10}, + {0x3734, 0x00}, + {0x373d, 0x24}, + {0x3764, 0x20}, + {0x3765, 0x20}, + {0x3766, 0x12}, + {0x37a1, 0x14}, + {0x37a8, 0x1c}, + {0x37ab, 0x0f}, + {0x37c2, 0x14}, + {0x37cb, 0x00}, + {0x37cc, 0x00}, + {0x37cd, 0x00}, + {0x37ce, 0x00}, + {0x37d8, 0x02}, + {0x37d9, 0x04}, + {0x37dc, 0x04}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0xf4}, + {0x3804, 0x0a}, + {0x3805, 0x3f}, + {0x3806, 0x06}, + {0x3807, 0xb3}, + {0x3808, 0x05}, + {0x3809, 0x00}, + {0x380a, 0x02}, + {0x380b, 0xd0}, + {0x380c, 0x02}, + {0x380d, 0xee}, + {0x380e, 0x07}, + {0x380f, 0xe4}, + {0x3811, 0x10}, + {0x3813, 0x09}, + {0x3814, 0x03}, + {0x3815, 0x01}, + {0x3816, 0x03}, + {0x3817, 0x01}, + {0x381e, 0x02}, + {0x3820, 0x8b}, + {0x3821, 0x01}, + {0x3832, 0x04}, + {0x3c80, 0x01}, + {0x3c82, 0x00}, + {0x3c83, 0xc8}, + {0x3c8c, 0x0f}, + {0x3c8d, 0xa0}, + {0x3c90, 0x07}, + {0x3c91, 0x00}, + {0x3c92, 0x00}, + {0x3c93, 0x00}, + {0x3c94, 0xd0}, + {0x3c95, 0x50}, + {0x3c96, 0x35}, + {0x3c97, 0x00}, + {0x4001, 0xe0}, + {0x4008, 0x00}, + {0x4009, 0x07}, + {0x400f, 0x80}, + {0x4013, 0x02}, + {0x4040, 0x00}, + {0x4041, 0x03}, + {0x404c, 0x50}, + {0x404e, 0x20}, + {0x4500, 0x06}, + {0x4503, 0x00}, + {0x450a, 0x04}, + {0x4809, 0x04}, + {0x480c, 0x12}, + {0x4819, 0x70}, + {0x4825, 0x32}, + {0x4826, 0x32}, + {0x482a, 0x06}, + {0x4833, 0x08}, + {0x4837, 0x0d}, + {0x5000, 0x77}, + {0x5b00, 0x01}, + {0x5b01, 0x10}, + {0x5b02, 0x01}, + {0x5b03, 0xdb}, + {0x5b05, 0x6c}, + {0x5e10, 0xfc}, + {0x3500, 0x00}, + {0x3501, 0x1F}, + {0x3502, 0x20}, + {0x3503, 0x08}, + {0x3508, 0x04}, + {0x3509, 0x00}, + {0x3832, 0x48}, + {0x5780, 0x3e}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x06}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, + {0x4003, 0x40}, + {0x3107, 0x01}, + {0x3c80, 0x08}, + {0x3c83, 0xb1}, + {0x3c8c, 0x10}, + {0x3c8d, 0x00}, + {0x3c90, 0x00}, + {0x3c94, 0x00}, + {0x3c95, 0x00}, + {0x3c96, 0x00}, + {0x37cb, 0x09}, + {0x37cc, 0x15}, + {0x37cd, 0x1f}, + {0x37ce, 0x1f}, +}; + +static const char * const ov5675_test_pattern_menu[] = { + "Disabled", + "Standard Color Bar", + "Top-Bottom Darker Color Bar", + "Right-Left Darker Color Bar", + "Bottom-Top Darker Color Bar" +}; + +static const s64 link_freq_menu_items[] = { + OV5675_LINK_FREQ_450MHZ, +}; + +static const struct ov5675_link_freq_config link_freq_configs[] = { + [OV5675_LINK_FREQ_900MBPS] = { + .reg_list = { + .num_of_regs = ARRAY_SIZE(mipi_data_rate_900mbps), + .regs = mipi_data_rate_900mbps, + } + } +}; + +static const struct ov5675_mode supported_modes[] = { + { + .width = 2592, + .height = 1944, + .hts = 1500, + .vts_def = OV5675_VTS_30FPS, + .vts_min = OV5675_VTS_30FPS_MIN, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_2592x1944_regs), + .regs = mode_2592x1944_regs, + }, + .link_freq_index = OV5675_LINK_FREQ_900MBPS, + }, + { + .width = 1296, + .height = 972, + .hts = 1500, + .vts_def = OV5675_VTS_30FPS, + .vts_min = OV5675_VTS_30FPS_MIN, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1296x972_regs), + .regs = mode_1296x972_regs, + }, + .link_freq_index = OV5675_LINK_FREQ_900MBPS, + } +}; + +struct ov5675 { + struct v4l2_subdev sd; + struct media_pad pad; + struct v4l2_ctrl_handler ctrl_handler; + + /* V4L2 Controls */ + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *exposure; + + /* Current mode */ + const struct ov5675_mode *cur_mode; + + /* To serialize asynchronus callbacks */ + struct mutex mutex; + + /* Streaming on/off */ + bool streaming; +}; + +static u64 to_pixel_rate(u32 f_index) +{ + u64 pixel_rate = link_freq_menu_items[f_index] * 2 * OV5675_DATA_LANES; + + do_div(pixel_rate, OV5675_RGB_DEPTH); + + return pixel_rate; +} + +static u64 to_pixels_per_line(u32 hts, u32 f_index) +{ + u64 ppl = hts * to_pixel_rate(f_index); + + do_div(ppl, OV5675_SCLK); + + return ppl; +} + +static int ov5675_read_reg(struct ov5675 *ov5675, u16 reg, u16 len, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + struct i2c_msg msgs[2]; + u8 addr_buf[2]; + u8 data_buf[4] = {0}; + int ret; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, addr_buf); + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = sizeof(addr_buf); + msgs[0].buf = addr_buf; + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_buf[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = get_unaligned_be32(data_buf); + + return 0; +} + +static int ov5675_write_reg(struct ov5675 *ov5675, u16 reg, u16 len, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + u8 buf[6]; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, buf); + put_unaligned_be32(val << 8 * (4 - len), buf + 2); + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +static int ov5675_write_reg_list(struct ov5675 *ov5675, + const struct ov5675_reg_list *r_list) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + unsigned int i; + int ret; + + for (i = 0; i < r_list->num_of_regs; i++) { + ret = ov5675_write_reg(ov5675, r_list->regs[i].address, 1, + r_list->regs[i].val); + if (ret) { + dev_err_ratelimited(&client->dev, + "failed to write reg 0x%4.4x. error = %d", + r_list->regs[i].address, ret); + return ret; + } + } + + return 0; +} + +static int ov5675_update_digital_gain(struct ov5675 *ov5675, u32 d_gain) +{ + int ret; + + ret = ov5675_write_reg(ov5675, OV5675_REG_MWB_R_GAIN, + OV5675_REG_VALUE_16BIT, d_gain); + if (ret) + return ret; + + ret = ov5675_write_reg(ov5675, OV5675_REG_MWB_G_GAIN, + OV5675_REG_VALUE_16BIT, d_gain); + if (ret) + return ret; + + return ov5675_write_reg(ov5675, OV5675_REG_MWB_B_GAIN, + OV5675_REG_VALUE_16BIT, d_gain); +} + +static int ov5675_test_pattern(struct ov5675 *ov5675, u32 pattern) +{ + if (pattern) + pattern = (pattern - 1) << OV5675_TEST_PATTERN_BAR_SHIFT | + OV5675_TEST_PATTERN_ENABLE; + + return ov5675_write_reg(ov5675, OV5675_REG_TEST_PATTERN, + OV5675_REG_VALUE_08BIT, pattern); +} + +static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov5675 *ov5675 = container_of(ctrl->handler, + struct ov5675, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + s64 exposure_max; + int ret = 0; + + /* Propagate change of current control to all related controls */ + if (ctrl->id == V4L2_CID_VBLANK) { + /* Update max exposure while meeting expected vblanking */ + exposure_max = (ov5675->cur_mode->height + ctrl->val - + OV5675_EXPOSURE_MAX_MARGIN) / 2; + __v4l2_ctrl_modify_range(ov5675->exposure, + ov5675->exposure->minimum, + exposure_max, ov5675->exposure->step, + exposure_max); + } + + /* V4L2 controls values will be applied only when power is already up */ + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + ret = ov5675_write_reg(ov5675, OV5675_REG_ANALOG_GAIN, + OV5675_REG_VALUE_16BIT, ctrl->val); + break; + + case V4L2_CID_DIGITAL_GAIN: + ret = ov5675_update_digital_gain(ov5675, ctrl->val); + break; + + case V4L2_CID_EXPOSURE: + /* 3 least significant bits of expsoure are fractional part */ + ret = ov5675_write_reg(ov5675, OV5675_REG_EXPOSURE, + OV5675_REG_VALUE_24BIT, ctrl->val << 3); + break; + + case V4L2_CID_VBLANK: + ret = ov5675_write_reg(ov5675, OV5675_REG_VTS, + OV5675_REG_VALUE_16BIT, + ov5675->cur_mode->height + ctrl->val + + 10); + break; + + case V4L2_CID_TEST_PATTERN: + ret = ov5675_test_pattern(ov5675, ctrl->val); + break; + + default: + ret = -EINVAL; + break; + } + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops ov5675_ctrl_ops = { + .s_ctrl = ov5675_set_ctrl, +}; + +static int ov5675_init_controls(struct ov5675 *ov5675) +{ + struct v4l2_ctrl_handler *ctrl_hdlr; + s64 exposure_max, h_blank; + int ret; + + ctrl_hdlr = &ov5675->ctrl_handler; + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); + if (ret) + return ret; + + ctrl_hdlr->lock = &ov5675->mutex; + ov5675->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov5675_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freq_menu_items) - 1, + 0, link_freq_menu_items); + if (ov5675->link_freq) + ov5675->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ov5675->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, + V4L2_CID_PIXEL_RATE, 0, + to_pixel_rate(OV5675_LINK_FREQ_900MBPS), + 1, + to_pixel_rate(OV5675_LINK_FREQ_900MBPS)); + ov5675->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, + V4L2_CID_VBLANK, + ov5675->cur_mode->vts_min - ov5675->cur_mode->height, + OV5675_VTS_MAX - ov5675->cur_mode->height, 1, + ov5675->cur_mode->vts_def - ov5675->cur_mode->height); + h_blank = to_pixels_per_line(ov5675->cur_mode->hts, + ov5675->cur_mode->link_freq_index) - ov5675->cur_mode->width; + ov5675->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, + V4L2_CID_HBLANK, h_blank, h_blank, 1, + h_blank); + if (ov5675->hblank) + ov5675->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + OV5675_ANAL_GAIN_MIN, OV5675_ANAL_GAIN_MAX, + OV5675_ANAL_GAIN_STEP, OV5675_ANAL_GAIN_MIN); + v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + OV5675_DGTL_GAIN_MIN, OV5675_DGTL_GAIN_MAX, + OV5675_DGTL_GAIN_STEP, OV5675_DGTL_GAIN_DEFAULT); + exposure_max = (ov5675->cur_mode->vts_def - + OV5675_EXPOSURE_MAX_MARGIN) / 2; + ov5675->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, + V4L2_CID_EXPOSURE, + OV5675_EXPOSURE_MIN, exposure_max, + OV5675_EXPOSURE_STEP, + exposure_max); + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov5675_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov5675_test_pattern_menu) - 1, + 0, 0, ov5675_test_pattern_menu); + if (ctrl_hdlr->error) + return ctrl_hdlr->error; + + ov5675->sd.ctrl_handler = ctrl_hdlr; + + return 0; +} + +static void ov5675_update_pad_format(const struct ov5675_mode *mode, + struct v4l2_mbus_framefmt *fmt) +{ + fmt->width = mode->width; + fmt->height = mode->height; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + fmt->field = V4L2_FIELD_NONE; +} + +static int ov5675_start_streaming(struct ov5675 *ov5675) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + const struct ov5675_reg_list *reg_list; + int link_freq_index, ret; + + link_freq_index = ov5675->cur_mode->link_freq_index; + reg_list = &link_freq_configs[link_freq_index].reg_list; + ret = ov5675_write_reg_list(ov5675, reg_list); + if (ret) { + dev_err(&client->dev, "failed to set plls"); + return ret; + } + + reg_list = &ov5675->cur_mode->reg_list; + ret = ov5675_write_reg_list(ov5675, reg_list); + if (ret) { + dev_err(&client->dev, "failed to set mode"); + return ret; + } + + ret = __v4l2_ctrl_handler_setup(ov5675->sd.ctrl_handler); + if (ret) + return ret; + + ret = ov5675_write_reg(ov5675, OV5675_REG_MODE_SELECT, + OV5675_REG_VALUE_08BIT, OV5675_MODE_STREAMING); + if (ret) { + dev_err(&client->dev, "failed to set stream"); + return ret; + } + + return 0; +} + +static void ov5675_stop_streaming(struct ov5675 *ov5675) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + + if (ov5675_write_reg(ov5675, OV5675_REG_MODE_SELECT, + OV5675_REG_VALUE_08BIT, OV5675_MODE_STANDBY)) + dev_err(&client->dev, "failed to set stream"); +} + +static int ov5675_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov5675 *ov5675 = to_ov5675(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (ov5675->streaming == enable) + return 0; + + mutex_lock(&ov5675->mutex); + if (enable) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + mutex_unlock(&ov5675->mutex); + return ret; + } + + ret = ov5675_start_streaming(ov5675); + if (ret) { + enable = 0; + ov5675_stop_streaming(ov5675); + pm_runtime_put(&client->dev); + } + } else { + ov5675_stop_streaming(ov5675); + pm_runtime_put(&client->dev); + } + + ov5675->streaming = enable; + mutex_unlock(&ov5675->mutex); + + return ret; +} + +static int __maybe_unused ov5675_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5675 *ov5675 = to_ov5675(sd); + + mutex_lock(&ov5675->mutex); + if (ov5675->streaming) + ov5675_stop_streaming(ov5675); + + mutex_unlock(&ov5675->mutex); + + return 0; +} + +static int __maybe_unused ov5675_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5675 *ov5675 = to_ov5675(sd); + int ret; + + mutex_lock(&ov5675->mutex); + if (ov5675->streaming) { + ret = ov5675_start_streaming(ov5675); + if (ret) { + ov5675->streaming = false; + ov5675_stop_streaming(ov5675); + mutex_unlock(&ov5675->mutex); + return ret; + } + } + + mutex_unlock(&ov5675->mutex); + + return 0; +} + +static int ov5675_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov5675 *ov5675 = to_ov5675(sd); + const struct ov5675_mode *mode; + s32 vblank_def, h_blank; + + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), width, + height, fmt->format.width, + fmt->format.height); + + mutex_lock(&ov5675->mutex); + ov5675_update_pad_format(mode, &fmt->format); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; + } else { + ov5675->cur_mode = mode; + __v4l2_ctrl_s_ctrl(ov5675->link_freq, mode->link_freq_index); + __v4l2_ctrl_s_ctrl_int64(ov5675->pixel_rate, + to_pixel_rate(mode->link_freq_index)); + + /* Update limits and set FPS to default */ + vblank_def = mode->vts_def - mode->height; + __v4l2_ctrl_modify_range(ov5675->vblank, + mode->vts_min - mode->height, + OV5675_VTS_MAX - mode->height, 1, + vblank_def); + __v4l2_ctrl_s_ctrl(ov5675->vblank, vblank_def); + h_blank = to_pixels_per_line(mode->hts, mode->link_freq_index) - + mode->width; + __v4l2_ctrl_modify_range(ov5675->hblank, h_blank, h_blank, 1, + h_blank); + } + + mutex_unlock(&ov5675->mutex); + + return 0; +} + +static int ov5675_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov5675 *ov5675 = to_ov5675(sd); + + mutex_lock(&ov5675->mutex); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + fmt->format = *v4l2_subdev_get_try_format(&ov5675->sd, cfg, + fmt->pad); + else + ov5675_update_pad_format(ov5675->cur_mode, &fmt->format); + + mutex_unlock(&ov5675->mutex); + + return 0; +} + +static int ov5675_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + + return 0; +} + +static int ov5675_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static int ov5675_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct ov5675 *ov5675 = to_ov5675(sd); + + mutex_lock(&ov5675->mutex); + ov5675_update_pad_format(&supported_modes[0], + v4l2_subdev_get_try_format(sd, fh->pad, 0)); + mutex_unlock(&ov5675->mutex); + + return 0; +} + +static const struct v4l2_subdev_video_ops ov5675_video_ops = { + .s_stream = ov5675_set_stream, +}; + +static const struct v4l2_subdev_pad_ops ov5675_pad_ops = { + .set_fmt = ov5675_set_format, + .get_fmt = ov5675_get_format, + .enum_mbus_code = ov5675_enum_mbus_code, + .enum_frame_size = ov5675_enum_frame_size, +}; + +static const struct v4l2_subdev_ops ov5675_subdev_ops = { + .video = &ov5675_video_ops, + .pad = &ov5675_pad_ops, +}; + +static const struct media_entity_operations ov5675_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_internal_ops ov5675_internal_ops = { + .open = ov5675_open, +}; + +static int ov5675_identify_module(struct ov5675 *ov5675) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + int ret; + u32 val; + + ret = ov5675_read_reg(ov5675, OV5675_REG_CHIP_ID, + OV5675_REG_VALUE_24BIT, &val); + if (ret) + return ret; + + if (val != OV5675_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%x", + OV5675_CHIP_ID, val); + return -ENXIO; + } + + return 0; +} + +static int ov5675_check_hwcfg(struct device *dev) +{ + struct fwnode_handle *ep; + struct fwnode_handle *fwnode = dev_fwnode(dev); + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + u32 mclk; + int ret; + unsigned int i, j; + + if (!fwnode) + return -ENXIO; + + ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); + + if (ret) { + dev_err(dev, "can't get clock frequency"); + return ret; + } + + if (mclk != OV5675_MCLK) { + dev_err(dev, "external clock %d is not supported", mclk); + return -EINVAL; + } + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -ENXIO; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV5675_DATA_LANES) { + dev_err(dev, "number of CSI2 data lanes %d is not supported", + bus_cfg.bus.mipi_csi2.num_data_lanes); + ret = -EINVAL; + goto check_hwcfg_error; + } + + if (!bus_cfg.nr_of_link_frequencies) { + dev_err(dev, "no link frequencies defined"); + ret = -EINVAL; + goto check_hwcfg_error; + } + + for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { + for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { + if (link_freq_menu_items[i] == + bus_cfg.link_frequencies[j]) + break; + } + + if (j == bus_cfg.nr_of_link_frequencies) { + dev_err(dev, "no link frequency %lld supported", + link_freq_menu_items[i]); + ret = -EINVAL; + goto check_hwcfg_error; + } + } + +check_hwcfg_error: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +static int ov5675_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5675 *ov5675 = to_ov5675(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + pm_runtime_disable(&client->dev); + mutex_destroy(&ov5675->mutex); + + return 0; +} + +static int ov5675_probe(struct i2c_client *client) +{ + struct ov5675 *ov5675; + int ret; + + ret = ov5675_check_hwcfg(&client->dev); + if (ret) { + dev_err(&client->dev, "failed to check HW configuration: %d", + ret); + return ret; + } + + ov5675 = devm_kzalloc(&client->dev, sizeof(*ov5675), GFP_KERNEL); + if (!ov5675) + return -ENOMEM; + + v4l2_i2c_subdev_init(&ov5675->sd, client, &ov5675_subdev_ops); + ret = ov5675_identify_module(ov5675); + if (ret) { + dev_err(&client->dev, "failed to find sensor: %d", ret); + return ret; + } + + mutex_init(&ov5675->mutex); + ov5675->cur_mode = &supported_modes[0]; + ret = ov5675_init_controls(ov5675); + if (ret) { + dev_err(&client->dev, "failed to init controls: %d", ret); + goto probe_error_v4l2_ctrl_handler_free; + } + + ov5675->sd.internal_ops = &ov5675_internal_ops; + ov5675->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov5675->sd.entity.ops = &ov5675_subdev_entity_ops; + ov5675->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ov5675->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&ov5675->sd.entity, 1, &ov5675->pad); + if (ret) { + dev_err(&client->dev, "failed to init entity pads: %d", ret); + goto probe_error_v4l2_ctrl_handler_free; + } + + ret = v4l2_async_register_subdev_sensor_common(&ov5675->sd); + if (ret < 0) { + dev_err(&client->dev, "failed to register V4L2 subdev: %d", + ret); + goto probe_error_media_entity_cleanup; + } + + /* + * Device is already turned on by i2c-core with ACPI domain PM. + * Enable runtime PM and turn off the device. + */ + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); + + return 0; + +probe_error_media_entity_cleanup: + media_entity_cleanup(&ov5675->sd.entity); + +probe_error_v4l2_ctrl_handler_free: + v4l2_ctrl_handler_free(ov5675->sd.ctrl_handler); + mutex_destroy(&ov5675->mutex); + + return ret; +} + +static const struct dev_pm_ops ov5675_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ov5675_suspend, ov5675_resume) +}; + +#ifdef CONFIG_ACPI +static const struct acpi_device_id ov5675_acpi_ids[] = { + {"OVTI5675"}, + {} +}; + +MODULE_DEVICE_TABLE(acpi, ov5675_acpi_ids); +#endif + +static struct i2c_driver ov5675_i2c_driver = { + .driver = { + .name = "ov5675", + .pm = &ov5675_pm_ops, + .acpi_match_table = ACPI_PTR(ov5675_acpi_ids), + }, + .probe_new = ov5675_probe, + .remove = ov5675_remove, +}; + +module_i2c_driver(ov5675_i2c_driver); + +MODULE_AUTHOR("Shawn Tu "); +MODULE_DESCRIPTION("OmniVision OV5675 sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index e65a94353175d26f06ee5f25702aa4274e1d74df..34b7046d970215b6242220e56a0cf38fd8eec8e8 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -823,9 +823,6 @@ static int ov5695_set_fmt(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; -#else - mutex_unlock(&ov5695->mutex); - return -ENOTTY; #endif } else { ov5695->cur_mode = mode; @@ -856,7 +853,7 @@ static int ov5695_get_fmt(struct v4l2_subdev *sd, fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); #else mutex_unlock(&ov5695->mutex); - return -ENOTTY; + return -EINVAL; #endif } else { fmt->format.width = mode->width; diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 53385c2777923a6b2b71263732c0132ba05d330d..b42b289faaef4cfdd82b57a4db59316df61d2056 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -1110,10 +1110,8 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); *mbus_fmt = format->format; - return 0; -#else - return -ENOTTY; #endif + return 0; } ret = ov7670_try_fmt_internal(sd, &format->format, &info->fmt, &info->wsize); @@ -1146,7 +1144,7 @@ static int ov7670_get_fmt(struct v4l2_subdev *sd, format->format = *mbus_fmt; return 0; #else - return -ENOTTY; + return -EINVAL; #endif } else { format->format = info->format; diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 2e9a758736a18c55ce50a2f80c2291a6975d894d..2cc6a678069a2ef1668df5224b30e08e0b3c386b 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -1352,8 +1352,7 @@ static const struct v4l2_subdev_ops ov772x_subdev_ops = { * i2c_driver function */ -static int ov772x_probe(struct i2c_client *client, - const struct i2c_device_id *did) +static int ov772x_probe(struct i2c_client *client) { struct ov772x_priv *priv; int ret; @@ -1486,7 +1485,7 @@ static struct i2c_driver ov772x_i2c_driver = { .name = "ov772x", .of_match_table = ov772x_of_match, }, - .probe = ov772x_probe, + .probe_new = ov772x_probe, .remove = ov772x_remove, .id_table = ov772x_id, }; diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index 70bb870b1d08767f38af63c6948642a95f670586..732655fe4ba35947b067814be757ffcafc95ad51 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -827,13 +827,9 @@ static int ov7740_set_fmt(struct v4l2_subdev *sd, #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); *mbus_fmt = format->format; - +#endif mutex_unlock(&ov7740->mutex); return 0; -#else - ret = -ENOTTY; - goto error; -#endif } ret = ov7740_try_fmt_internal(sd, &format->format, &ovfmt, &fsize); @@ -868,7 +864,7 @@ static int ov7740_get_fmt(struct v4l2_subdev *sd, format->format = *mbus_fmt; ret = 0; #else - ret = -ENOTTY; + ret = -EINVAL; #endif } else { format->format = ov7740->format; @@ -1066,8 +1062,7 @@ static const struct regmap_config ov7740_regmap_config = { .max_register = OV7740_MAX_REGISTER, }; -static int ov7740_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov7740_probe(struct i2c_client *client) { struct ov7740 *ov7740; struct v4l2_subdev *sd; @@ -1229,7 +1224,7 @@ static struct i2c_driver ov7740_i2c_driver = { .pm = &ov7740_pm_ops, .of_match_table = of_match_ptr(ov7740_of_match), }, - .probe = ov7740_probe, + .probe_new = ov7740_probe, .remove = ov7740_remove, .id_table = ov7740_id, }; diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index cd347d6b7b9da5169778dd06bf015c98490bcf2f..8655842af2755886620480d1120f8d251b6d06f6 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -1106,7 +1106,10 @@ static int ov8856_check_hwcfg(struct device *dev) if (!fwnode) return -ENXIO; - fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); + ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); + if (ret) + return ret; + if (mclk != OV8856_MCLK) { dev_err(dev, "external clock %d is not supported", mclk); return -EINVAL; diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index 30ab2225fbd0cab1b5d4079a32d85eae0c9339f5..4fe68aa5578993e81644cc7cbc85e607d0b2cbd9 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -703,6 +703,11 @@ static int ov965x_set_gain(struct ov965x *ov965x, int auto_gain) for (m = 6; m >= 0; m--) if (gain >= (1 << m) * 16) break; + + /* Sanity check: don't adjust the gain with a negative value */ + if (m < 0) + return -EINVAL; + rgain = (gain - ((1 << m) * 16)) / (1 << m); rgain |= (((1 << m) - 1) << 4); @@ -1485,8 +1490,7 @@ static int ov965x_detect_sensor(struct v4l2_subdev *sd) return ret; } -static int ov965x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov965x_probe(struct i2c_client *client) { const struct ov9650_platform_data *pdata = client->dev.platform_data; struct v4l2_subdev *sd; @@ -1613,7 +1617,7 @@ static struct i2c_driver ov965x_i2c_driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(ov965x_of_match), }, - .probe = ov965x_probe, + .probe_new = ov965x_probe, .remove = ov965x_remove, .id_table = ov965x_id, }; diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index 7633aebd8c06d71f614e59e1fe7d631e0b01adcb..5b4c4a3547c93669e4c63d632b0f0187346a3704 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -1650,8 +1650,7 @@ static int s5c73m3_get_platform_data(struct s5c73m3 *state) return 0; } -static int s5c73m3_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int s5c73m3_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct v4l2_subdev *sd; @@ -1806,7 +1805,7 @@ static struct i2c_driver s5c73m3_i2c_driver = { .of_match_table = of_match_ptr(s5c73m3_of_match), .name = DRIVER_NAME, }, - .probe = s5c73m3_probe, + .probe_new = s5c73m3_probe, .remove = s5c73m3_remove, .id_table = s5c73m3_id, }; diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index 8e6de06b3e72303b860bb5248b2534d2e92c1923..cdfe008ba39f8eebd99ee9947a3289afb461b8f9 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -1946,8 +1946,7 @@ static int s5k5baf_configure_regulators(struct s5k5baf *state) return ret; } -static int s5k5baf_probe(struct i2c_client *c, - const struct i2c_device_id *id) +static int s5k5baf_probe(struct i2c_client *c) { struct s5k5baf *state; int ret; @@ -2046,7 +2045,7 @@ static struct i2c_driver s5k5baf_i2c_driver = { .of_match_table = s5k5baf_of_match, .name = S5K5BAF_DRIVER_NAME }, - .probe = s5k5baf_probe, + .probe_new = s5k5baf_probe, .remove = s5k5baf_remove, .id_table = s5k5baf_id, }; diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c index 3b7721f81be21ca1f8633b76e338c0c2d7674657..bc6cc5a558db0d463054220da36ed942e47a6f37 100644 --- a/drivers/media/i2c/s5k6a3.c +++ b/drivers/media/i2c/s5k6a3.c @@ -275,8 +275,7 @@ static const struct v4l2_subdev_ops s5k6a3_subdev_ops = { .pad = &s5k6a3_pad_ops, }; -static int s5k6a3_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int s5k6a3_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct s5k6a3 *sensor; @@ -378,7 +377,7 @@ static struct i2c_driver s5k6a3_driver = { .of_match_table = of_match_ptr(s5k6a3_of_match), .name = S5K6A3_DRV_NAME, }, - .probe = s5k6a3_probe, + .probe_new = s5k6a3_probe, .remove = s5k6a3_remove, .id_table = s5k6a3_ids, }; diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 2d78e846d82230fde09f3ff64cd97b3857b22c89..9adf8e034e7d62d9d69c0c999a3f3b3f63e12dbc 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2847,8 +2847,7 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev) return NULL; } -static int smiapp_probe(struct i2c_client *client, - const struct i2c_device_id *devid) +static int smiapp_probe(struct i2c_client *client) { struct smiapp_sensor *sensor; struct smiapp_hwconfig *hwcfg = smiapp_get_hwconfig(&client->dev); @@ -3172,7 +3171,7 @@ static struct i2c_driver smiapp_i2c_driver = { .name = SMIAPP_NAME, .pm = &smiapp_pm_ops, }, - .probe = smiapp_probe, + .probe_new = smiapp_probe, .remove = smiapp_remove, .id_table = smiapp_id_table, }; diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index bc2e35e5ce6158e1c7f0d94f09ea65462df70767..dbbab75f135ec08f8248e2c2938cbc43556daa84 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -2026,8 +2026,7 @@ static inline int tc358743_probe_of(struct tc358743_state *state) } #endif -static int tc358743_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tc358743_probe(struct i2c_client *client) { static struct v4l2_dv_timings default_timing = V4L2_DV_BT_CEA_640X480P59_94; @@ -2222,7 +2221,7 @@ static struct i2c_driver tc358743_driver = { .name = "tc358743", .of_match_table = of_match_ptr(tc358743_of_match), }, - .probe = tc358743_probe, + .probe_new = tc358743_probe, .remove = tc358743_remove, .id_table = tc358743_id, }; diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index a62ede0966361a879e33db7c3f1e1ad5d207d4c0..5e68182001ecc8bd0ef703716b2ac231c4ababd6 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -2691,7 +2691,13 @@ static int tda1997x_probe(struct i2c_client *client, } ret = 0x34 + ((io_read(sd, REG_SLAVE_ADDR)>>4) & 0x03); - state->client_cec = i2c_new_dummy(client->adapter, ret); + state->client_cec = devm_i2c_new_dummy_device(&client->dev, + client->adapter, ret); + if (IS_ERR(state->client_cec)) { + ret = PTR_ERR(state->client_cec); + goto err_free_mutex; + } + v4l_info(client, "CEC slave address 0x%02x\n", ret); ret = tda1997x_core_init(sd); @@ -2798,7 +2804,6 @@ static int tda1997x_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(&state->hdl); regulator_bulk_disable(TDA1997X_NUM_SUPPLIES, state->supplies); - i2c_unregister_device(state->client_cec); cancel_delayed_work(&state->delayed_work_enable_hpd); mutex_destroy(&state->page_lock); mutex_destroy(&state->lock); diff --git a/drivers/media/i2c/ths8200.c b/drivers/media/i2c/ths8200.c index f5ee28058ea2af35ae7dd137ab4f27ea3115529e..c52fe84cba1bd040ea7b86ab0fc0dfa7e8a39645 100644 --- a/drivers/media/i2c/ths8200.c +++ b/drivers/media/i2c/ths8200.c @@ -436,8 +436,7 @@ static const struct v4l2_subdev_ops ths8200_ops = { .pad = &ths8200_pad_ops, }; -static int ths8200_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ths8200_probe(struct i2c_client *client) { struct ths8200_state *state; struct v4l2_subdev *sd; @@ -502,7 +501,7 @@ static struct i2c_driver ths8200_driver = { .name = "ths8200", .of_match_table = of_match_ptr(ths8200_of_match), }, - .probe = ths8200_probe, + .probe_new = ths8200_probe, .remove = ths8200_remove, .id_table = ths8200_id, }; diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index eaddd977ba40edaebcfce2c3f79cc4e7d7c2ea3d..edad49cebcdf675268e81f7d0551b65b6c826923 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -1636,11 +1636,13 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) dev_err(decoder->sd.dev, "missing type property in node %pOFn\n", child); + of_node_put(child); goto err_connector; } if (input_type >= TVP5150_INPUT_NUM) { ret = -EINVAL; + of_node_put(child); goto err_connector; } @@ -1651,6 +1653,7 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) dev_err(decoder->sd.dev, "input %s with same type already exists\n", input->name); + of_node_put(child); ret = -EINVAL; goto err_connector; } @@ -1672,6 +1675,7 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) dev_err(decoder->sd.dev, "missing label property in node %pOFn\n", child); + of_node_put(child); goto err_connector; } @@ -1691,8 +1695,7 @@ static const char * const tvp5150_test_patterns[2] = { "Black screen" }; -static int tvp5150_probe(struct i2c_client *c, - const struct i2c_device_id *id) +static int tvp5150_probe(struct i2c_client *c) { struct tvp5150 *core; struct v4l2_subdev *sd; @@ -1841,7 +1844,7 @@ static struct i2c_driver tvp5150_driver = { .of_match_table = of_match_ptr(tvp5150_of_match), .name = "tvp5150", }, - .probe = tvp5150_probe, + .probe_new = tvp5150_probe, .remove = tvp5150_remove, .id_table = tvp5150_id, }; diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 1b8175cab017495850b52d4a83853f5d54aaee48..de313b1306daae1097371ec64e600a78ee1a5aa0 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -930,7 +930,7 @@ tvp7002_get_pdata(struct i2c_client *client) * Returns zero when successful, -EINVAL if register read fails or * -EIO if i2c access is not available. */ -static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id) +static int tvp7002_probe(struct i2c_client *c) { struct tvp7002_config *pdata = tvp7002_get_pdata(c); struct v4l2_subdev *sd; @@ -1075,7 +1075,7 @@ static struct i2c_driver tvp7002_driver = { .of_match_table = of_match_ptr(tvp7002_of_match), .name = TVP7002_MODULE_NAME, }, - .probe = tvp7002_probe, + .probe_new = tvp7002_probe, .remove = tvp7002_remove, .id_table = tvp7002_id, }; diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 612d1c0010c19a5047f2021eed45c2713f6c9549..a359da7773a9052e07da0c48fa727e58beb2a5c7 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -503,77 +503,65 @@ static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms); packed pixel formats must come first */ static const struct bttv_format formats[] = { { - .name = "8 bpp, gray", .fourcc = V4L2_PIX_FMT_GREY, .btformat = BT848_COLOR_FMT_Y8, .depth = 8, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "8 bpp, dithered color", .fourcc = V4L2_PIX_FMT_HI240, .btformat = BT848_COLOR_FMT_RGB8, .depth = 8, .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER, },{ - .name = "15 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB555, .btformat = BT848_COLOR_FMT_RGB15, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "15 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB555X, .btformat = BT848_COLOR_FMT_RGB15, .btswap = 0x03, /* byteswap */ .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "16 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB565, .btformat = BT848_COLOR_FMT_RGB16, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "16 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB565X, .btformat = BT848_COLOR_FMT_RGB16, .btswap = 0x03, /* byteswap */ .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "24 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR24, .btformat = BT848_COLOR_FMT_RGB24, .depth = 24, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "32 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR32, .btformat = BT848_COLOR_FMT_RGB32, .depth = 32, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "32 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB32, .btformat = BT848_COLOR_FMT_RGB32, .btswap = 0x0f, /* byte+word swap */ .depth = 32, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .btformat = BT848_COLOR_FMT_YUY2, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "4:2:2, packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, .btformat = BT848_COLOR_FMT_YUY2, .btswap = 0x03, /* byteswap */ .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "4:2:2, planar, Y-Cb-Cr", .fourcc = V4L2_PIX_FMT_YUV422P, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 16, @@ -581,7 +569,6 @@ static const struct bttv_format formats[] = { .hshift = 1, .vshift = 0, },{ - .name = "4:2:0, planar, Y-Cb-Cr", .fourcc = V4L2_PIX_FMT_YUV420, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 12, @@ -589,7 +576,6 @@ static const struct bttv_format formats[] = { .hshift = 1, .vshift = 1, },{ - .name = "4:2:0, planar, Y-Cr-Cb", .fourcc = V4L2_PIX_FMT_YVU420, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 12, @@ -597,7 +583,6 @@ static const struct bttv_format formats[] = { .hshift = 1, .vshift = 1, },{ - .name = "4:1:1, planar, Y-Cb-Cr", .fourcc = V4L2_PIX_FMT_YUV411P, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 12, @@ -605,7 +590,6 @@ static const struct bttv_format formats[] = { .hshift = 2, .vshift = 0, },{ - .name = "4:1:0, planar, Y-Cb-Cr", .fourcc = V4L2_PIX_FMT_YUV410, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 9, @@ -613,7 +597,6 @@ static const struct bttv_format formats[] = { .hshift = 2, .vshift = 2, },{ - .name = "4:1:0, planar, Y-Cr-Cb", .fourcc = V4L2_PIX_FMT_YVU410, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 9, @@ -621,7 +604,6 @@ static const struct bttv_format formats[] = { .hshift = 2, .vshift = 2, },{ - .name = "raw scanlines", .fourcc = -1, .btformat = BT848_COLOR_FMT_RAW, .depth = 8, @@ -2500,7 +2482,6 @@ static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f) return -EINVAL; f->pixelformat = formats[i].fourcc; - strscpy(f->description, formats[i].name, sizeof(f->description)); return i; } diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c index 9adfac4d5187db03ea311f4425ae1bd429b0fd10..492bc85c2700ea8d58302d5291e39b96a3ca6824 100644 --- a/drivers/media/pci/bt8xx/bttv-input.c +++ b/drivers/media/pci/bt8xx/bttv-input.c @@ -84,7 +84,7 @@ static void ir_enltv_handle_key(struct bttv *btv) data = ir_extract_bits(gpio, ir->mask_keycode); /* Check if it is keyup */ - keyup = (gpio & ir->mask_keyup) ? 1 << 31 : 0; + keyup = (gpio & ir->mask_keyup) ? 1UL << 31 : 0; if ((ir->last_gpio & 0x7f) != data) { dprintk("gpio=0x%x code=%d | %s\n", @@ -95,7 +95,7 @@ static void ir_enltv_handle_key(struct bttv *btv) if (keyup) rc_keyup(ir->dev); } else { - if ((ir->last_gpio & 1 << 31) == keyup) + if ((ir->last_gpio & 1UL << 31) == keyup) return; dprintk("(cnt) gpio=0x%x code=%d | %s\n", diff --git a/drivers/media/pci/bt8xx/bttv-risc.c b/drivers/media/pci/bt8xx/bttv-risc.c index 6b59ca337c7f5da2c1593ec63a34df5907c2ca3c..fc8708047be8658e4f7b2f15bfb8173e175449e5 100644 --- a/drivers/media/pci/bt8xx/bttv-risc.c +++ b/drivers/media/pci/bt8xx/bttv-risc.c @@ -699,9 +699,9 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm; struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - dprintk("%d: buffer field: %s format: %s size: %dx%d\n", + dprintk("%d: buffer field: %s format: 0x%08x size: %dx%d\n", btv->c.nr, v4l2_field_names[buf->vb.field], - buf->fmt->name, buf->vb.width, buf->vb.height); + buf->fmt->fourcc, buf->vb.width, buf->vb.height); /* packed pixel modes */ if (buf->fmt->flags & FORMAT_FLAGS_PACKED) { @@ -860,9 +860,9 @@ bttv_overlay_risc(struct bttv *btv, struct bttv_buffer *buf) { /* check interleave, bottom+top fields */ - dprintk("%d: overlay fields: %s format: %s size: %dx%d\n", + dprintk("%d: overlay fields: %s format: 0x%08x size: %dx%d\n", btv->c.nr, v4l2_field_names[buf->vb.field], - fmt->name, ov->w.width, ov->w.height); + fmt->fourcc, ov->w.width, ov->w.height); /* calculate geometry */ bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height, diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index b159d6ddbfcfd243c044f80fa57eae7e43684d48..4abf436578465fcd6194b9d59065989f53097ff7 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -99,7 +99,6 @@ struct bttv_tvnorm { extern const struct bttv_tvnorm bttv_tvnorms[]; struct bttv_format { - char *name; int fourcc; /* video4linux 2 */ int btformat; /* BT848_COLOR_FMT_* */ int btswap; /* BT848_COLOR_CTL_* */ diff --git a/drivers/media/pci/bt8xx/dvb-bt8xx.c b/drivers/media/pci/bt8xx/dvb-bt8xx.c index 64df9d49194162e85c790b0be6c4645e6a2fc65f..02ebd43e672e35e481594ae5707212735b849d71 100644 --- a/drivers/media/pci/bt8xx/dvb-bt8xx.c +++ b/drivers/media/pci/bt8xx/dvb-bt8xx.c @@ -393,7 +393,7 @@ static struct mt352_config advbt771_samsung_tdtc9251dh0_config = { .demod_init = advbt771_samsung_tdtc9251dh0_demod_init, }; -static struct dst_config dst_config = { +static const struct dst_config dst_config = { .demod_address = 0x55, }; diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 4885e833c05227999cfcb00266c88917c765472b..0695078ef81252c37eb12fa966d1c91d627279b5 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -186,20 +186,16 @@ void cobalt_pcie_status_show(struct cobalt *cobalt) { struct pci_dev *pci_dev = cobalt->pci_dev; struct pci_dev *pci_bus_dev = cobalt->pci_dev->bus->self; - int offset; - int bus_offset; u32 capa; u16 stat, ctrl; - offset = pci_find_capability(pci_dev, PCI_CAP_ID_EXP); - bus_offset = pci_find_capability(pci_bus_dev, PCI_CAP_ID_EXP); - if (!offset || !bus_offset) + if (!pci_is_pcie(pci_dev) || !pci_is_pcie(pci_bus_dev)) return; /* Device */ - pci_read_config_dword(pci_dev, offset + PCI_EXP_DEVCAP, &capa); - pci_read_config_word(pci_dev, offset + PCI_EXP_DEVCTL, &ctrl); - pci_read_config_word(pci_dev, offset + PCI_EXP_DEVSTA, &stat); + pcie_capability_read_dword(pci_dev, PCI_EXP_DEVCAP, &capa); + pcie_capability_read_word(pci_dev, PCI_EXP_DEVCTL, &ctrl); + pcie_capability_read_word(pci_dev, PCI_EXP_DEVSTA, &stat); cobalt_info("PCIe device capability 0x%08x: Max payload %d\n", capa, get_payload_size(capa & PCI_EXP_DEVCAP_PAYLOAD)); cobalt_info("PCIe device control 0x%04x: Max payload %d. Max read request %d\n", @@ -209,9 +205,9 @@ void cobalt_pcie_status_show(struct cobalt *cobalt) cobalt_info("PCIe device status 0x%04x\n", stat); /* Link */ - pci_read_config_dword(pci_dev, offset + PCI_EXP_LNKCAP, &capa); - pci_read_config_word(pci_dev, offset + PCI_EXP_LNKCTL, &ctrl); - pci_read_config_word(pci_dev, offset + PCI_EXP_LNKSTA, &stat); + pcie_capability_read_dword(pci_dev, PCI_EXP_LNKCAP, &capa); + pcie_capability_read_word(pci_dev, PCI_EXP_LNKCTL, &ctrl); + pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &stat); cobalt_info("PCIe link capability 0x%08x: %s per lane and %u lanes\n", capa, get_link_speed(capa), (capa & PCI_EXP_LNKCAP_MLW) >> 4); @@ -221,15 +217,15 @@ void cobalt_pcie_status_show(struct cobalt *cobalt) (stat & PCI_EXP_LNKSTA_NLW) >> 4); /* Bus */ - pci_read_config_dword(pci_bus_dev, bus_offset + PCI_EXP_LNKCAP, &capa); + pcie_capability_read_dword(pci_bus_dev, PCI_EXP_LNKCAP, &capa); cobalt_info("PCIe bus link capability 0x%08x: %s per lane and %u lanes\n", capa, get_link_speed(capa), (capa & PCI_EXP_LNKCAP_MLW) >> 4); /* Slot */ - pci_read_config_dword(pci_dev, offset + PCI_EXP_SLTCAP, &capa); - pci_read_config_word(pci_dev, offset + PCI_EXP_SLTCTL, &ctrl); - pci_read_config_word(pci_dev, offset + PCI_EXP_SLTSTA, &stat); + pcie_capability_read_dword(pci_dev, PCI_EXP_SLTCAP, &capa); + pcie_capability_read_word(pci_dev, PCI_EXP_SLTCTL, &ctrl); + pcie_capability_read_word(pci_dev, PCI_EXP_SLTSTA, &stat); cobalt_info("PCIe slot capability 0x%08x\n", capa); cobalt_info("PCIe slot control 0x%04x\n", ctrl); cobalt_info("PCIe slot status 0x%04x\n", stat); @@ -238,26 +234,22 @@ void cobalt_pcie_status_show(struct cobalt *cobalt) static unsigned pcie_link_get_lanes(struct cobalt *cobalt) { struct pci_dev *pci_dev = cobalt->pci_dev; - unsigned offset; u16 link; - offset = pci_find_capability(pci_dev, PCI_CAP_ID_EXP); - if (!offset) + if (!pci_is_pcie(pci_dev)) return 0; - pci_read_config_word(pci_dev, offset + PCI_EXP_LNKSTA, &link); + pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &link); return (link & PCI_EXP_LNKSTA_NLW) >> 4; } static unsigned pcie_bus_link_get_lanes(struct cobalt *cobalt) { struct pci_dev *pci_dev = cobalt->pci_dev->bus->self; - unsigned offset; u32 link; - offset = pci_find_capability(pci_dev, PCI_CAP_ID_EXP); - if (!offset) + if (!pci_is_pcie(pci_dev)) return 0; - pci_read_config_dword(pci_dev, offset + PCI_EXP_LNKCAP, &link); + pcie_capability_read_dword(pci_dev, PCI_EXP_LNKCAP, &link); return (link & PCI_EXP_LNKCAP_MLW) >> 4; } @@ -592,7 +584,7 @@ static int cobalt_subdevs_hsma_init(struct cobalt *cobalt) .cec_clk = 12000000, }; static struct i2c_board_info adv7511_info = { - .type = "adv7511", + .type = "adv7511-v4l2", .addr = 0x39, /* 0x39 or 0x3d */ .platform_data = &adv7511_pdata, }; diff --git a/drivers/media/pci/cobalt/cobalt-driver.h b/drivers/media/pci/cobalt/cobalt-driver.h index 429bee4ef79c593e0c5a7d2e446154d35090b475..bca68572b3242af74527cfc39f3c67fd6f104721 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.h +++ b/drivers/media/pci/cobalt/cobalt-driver.h @@ -11,6 +11,7 @@ #ifndef COBALT_DRIVER_H #define COBALT_DRIVER_H +#include #include #include #include @@ -61,37 +62,37 @@ #define COBALT_CLK 50000000 /* System status register */ -#define COBALT_SYSSTAT_DIP0_MSK (1 << 0) -#define COBALT_SYSSTAT_DIP1_MSK (1 << 1) -#define COBALT_SYSSTAT_HSMA_PRSNTN_MSK (1 << 2) -#define COBALT_SYSSTAT_FLASH_RDYBSYN_MSK (1 << 3) -#define COBALT_SYSSTAT_VI0_5V_MSK (1 << 4) -#define COBALT_SYSSTAT_VI0_INT1_MSK (1 << 5) -#define COBALT_SYSSTAT_VI0_INT2_MSK (1 << 6) -#define COBALT_SYSSTAT_VI0_LOST_DATA_MSK (1 << 7) -#define COBALT_SYSSTAT_VI1_5V_MSK (1 << 8) -#define COBALT_SYSSTAT_VI1_INT1_MSK (1 << 9) -#define COBALT_SYSSTAT_VI1_INT2_MSK (1 << 10) -#define COBALT_SYSSTAT_VI1_LOST_DATA_MSK (1 << 11) -#define COBALT_SYSSTAT_VI2_5V_MSK (1 << 12) -#define COBALT_SYSSTAT_VI2_INT1_MSK (1 << 13) -#define COBALT_SYSSTAT_VI2_INT2_MSK (1 << 14) -#define COBALT_SYSSTAT_VI2_LOST_DATA_MSK (1 << 15) -#define COBALT_SYSSTAT_VI3_5V_MSK (1 << 16) -#define COBALT_SYSSTAT_VI3_INT1_MSK (1 << 17) -#define COBALT_SYSSTAT_VI3_INT2_MSK (1 << 18) -#define COBALT_SYSSTAT_VI3_LOST_DATA_MSK (1 << 19) -#define COBALT_SYSSTAT_VIHSMA_5V_MSK (1 << 20) -#define COBALT_SYSSTAT_VIHSMA_INT1_MSK (1 << 21) -#define COBALT_SYSSTAT_VIHSMA_INT2_MSK (1 << 22) -#define COBALT_SYSSTAT_VIHSMA_LOST_DATA_MSK (1 << 23) -#define COBALT_SYSSTAT_VOHSMA_INT1_MSK (1 << 24) -#define COBALT_SYSSTAT_VOHSMA_PLL_LOCKED_MSK (1 << 25) -#define COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK (1 << 26) -#define COBALT_SYSSTAT_AUD_PLL_LOCKED_MSK (1 << 28) -#define COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK (1 << 29) -#define COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK (1 << 30) -#define COBALT_SYSSTAT_PCIE_SMBCLK_MSK (1 << 31) +#define COBALT_SYSSTAT_DIP0_MSK BIT(0) +#define COBALT_SYSSTAT_DIP1_MSK BIT(1) +#define COBALT_SYSSTAT_HSMA_PRSNTN_MSK BIT(2) +#define COBALT_SYSSTAT_FLASH_RDYBSYN_MSK BIT(3) +#define COBALT_SYSSTAT_VI0_5V_MSK BIT(4) +#define COBALT_SYSSTAT_VI0_INT1_MSK BIT(5) +#define COBALT_SYSSTAT_VI0_INT2_MSK BIT(6) +#define COBALT_SYSSTAT_VI0_LOST_DATA_MSK BIT(7) +#define COBALT_SYSSTAT_VI1_5V_MSK BIT(8) +#define COBALT_SYSSTAT_VI1_INT1_MSK BIT(9) +#define COBALT_SYSSTAT_VI1_INT2_MSK BIT(10) +#define COBALT_SYSSTAT_VI1_LOST_DATA_MSK BIT(11) +#define COBALT_SYSSTAT_VI2_5V_MSK BIT(12) +#define COBALT_SYSSTAT_VI2_INT1_MSK BIT(13) +#define COBALT_SYSSTAT_VI2_INT2_MSK BIT(14) +#define COBALT_SYSSTAT_VI2_LOST_DATA_MSK BIT(15) +#define COBALT_SYSSTAT_VI3_5V_MSK BIT(16) +#define COBALT_SYSSTAT_VI3_INT1_MSK BIT(17) +#define COBALT_SYSSTAT_VI3_INT2_MSK BIT(18) +#define COBALT_SYSSTAT_VI3_LOST_DATA_MSK BIT(19) +#define COBALT_SYSSTAT_VIHSMA_5V_MSK BIT(20) +#define COBALT_SYSSTAT_VIHSMA_INT1_MSK BIT(21) +#define COBALT_SYSSTAT_VIHSMA_INT2_MSK BIT(22) +#define COBALT_SYSSTAT_VIHSMA_LOST_DATA_MSK BIT(23) +#define COBALT_SYSSTAT_VOHSMA_INT1_MSK BIT(24) +#define COBALT_SYSSTAT_VOHSMA_PLL_LOCKED_MSK BIT(25) +#define COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK BIT(26) +#define COBALT_SYSSTAT_AUD_PLL_LOCKED_MSK BIT(28) +#define COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK BIT(29) +#define COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK BIT(30) +#define COBALT_SYSSTAT_PCIE_SMBCLK_MSK BIT(31) /* Cobalt memory map */ #define COBALT_I2C_0_BASE 0x0 diff --git a/drivers/media/pci/cobalt/cobalt-flash.c b/drivers/media/pci/cobalt/cobalt-flash.c index ef96e0f956d22fdb19b2ae0ae479e586d839070c..1d3c64b4cf6d0c2dfe4f8a75fb040ccee8ebebf3 100644 --- a/drivers/media/pci/cobalt/cobalt-flash.c +++ b/drivers/media/pci/cobalt/cobalt-flash.c @@ -69,7 +69,7 @@ static void flash_copy_to(struct map_info *map, unsigned long to, pr_info("%s: offset 0x%x: length %zu\n", __func__, dest, len); while (len) { - u16 data = 0xffff; + u16 data; do { data = *src << (8 * (dest & 1)); diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index 39dabd4da60fd2f9bac4f558846602a92380cb78..c5207501d5e03cf7ae1bf44309f8ffd74ef60f5e 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -688,15 +688,12 @@ static int cobalt_enum_fmt_vid_cap(struct file *file, void *priv_fh, { switch (f->index) { case 0: - strscpy(f->description, "YUV 4:2:2", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_YUYV; break; case 1: - strscpy(f->description, "RGB24", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_RGB24; break; case 2: - strscpy(f->description, "RGB32", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_BGR32; break; default: @@ -788,7 +785,6 @@ static int cobalt_try_fmt_vid_cap(struct file *file, void *priv_fh, pix->sizeimage = pix->bytesperline * pix->height; pix->field = V4L2_FIELD_NONE; - pix->priv = 0; return 0; } @@ -893,11 +889,9 @@ static int cobalt_enum_fmt_vid_out(struct file *file, void *priv_fh, { switch (f->index) { case 0: - strscpy(f->description, "YUV 4:2:2", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_YUYV; break; case 1: - strscpy(f->description, "RGB32", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_BGR32; break; default: diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index d9ffc9c359ca81253436cb062b753aea950bc821..85f3e730753854306f53156da8e8278d80b7f02c 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -78,7 +78,7 @@ static u16 select_service_from_set(int field, int line, u16 set, int is_pal) return 0; } for (i = 0; i < 32; i++) { - if ((1 << i) & set) + if (BIT(i) & set) return 1 << i; } return 0; diff --git a/drivers/media/pci/cx18/cx18-mailbox.c b/drivers/media/pci/cx18/cx18-mailbox.c index 967ae29390997cf21d8f255e9625df62bcfbfb34..162480ec68caf0647f769d142fd3c5885018ad48 100644 --- a/drivers/media/pci/cx18/cx18-mailbox.c +++ b/drivers/media/pci/cx18/cx18-mailbox.c @@ -6,7 +6,7 @@ * Copyright (C) 2008 Andy Walls */ -#include +#include #include "cx18-driver.h" #include "cx18-io.h" diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 82f96a4091aca56084d005a5e5d3b72a3dd1009a..2327fe6126102e2975a6b5ee87e582dadd1a34a1 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1339,7 +1339,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index != 0) return -EINVAL; - strscpy(f->description, "MPEG", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_MPEG; return 0; diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index b254473db9a3849725bd31f69b947df5542ec277..8098b15493de92756d90e71c27f7d8a43d75c4a6 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -67,7 +67,6 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); #define FORMAT_FLAGS_PACKED 0x01 static struct cx23885_fmt formats[] = { { - .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .flags = FORMAT_FLAGS_PACKED, @@ -411,9 +410,9 @@ static int buffer_prepare(struct vb2_buffer *vb) default: BUG(); } - dprintk(2, "[%p/%d] buffer_init - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + dprintk(2, "[%p/%d] buffer_init - %dx%d %dbpp 0x%08x - dma=0x%08lx\n", buf, buf->vb.vb2_buf.index, - dev->width, dev->height, dev->fmt->depth, dev->fmt->name, + dev->width, dev->height, dev->fmt->depth, dev->fmt->fourcc, (unsigned long)buf->risc.dma); return 0; } @@ -647,8 +646,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (unlikely(f->index >= ARRAY_SIZE(formats))) return -EINVAL; - strscpy(f->description, formats[f->index].name, - sizeof(f->description)); f->pixelformat = formats[f->index].fourcc; return 0; diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 9da66fdd5a0d3ee5c4ed59af20b8152a0389e50f..a95a2e4c6a0d3f6bb94b62fbcf40966c0745441b 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -127,7 +127,6 @@ V4L2_STD_PAL_60 | V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK) struct cx23885_fmt { - char *name; u32 fourcc; /* v4l2 format id */ int depth; int flags; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index de76411704782f8b0630262bb887bfd710d0f775..a10261da0db6eec3ec734dee547cc4be987d99a7 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -35,12 +35,10 @@ MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); static const struct cx25821_fmt formats[] = { { - .name = "4:1:1, packed, Y41P", .fourcc = V4L2_PIX_FMT_Y41P, .depth = 12, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .flags = FORMAT_FLAGS_PACKED, @@ -215,9 +213,9 @@ static int cx25821_buffer_prepare(struct vb2_buffer *vb) break; } - dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp 0x%08x - dma=0x%08lx\n", buf, buf->vb.vb2_buf.index, chan->width, chan->height, - chan->fmt->depth, chan->fmt->name, + chan->fmt->depth, chan->fmt->fourcc, (unsigned long)buf->risc.dma); return ret; @@ -311,7 +309,6 @@ static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (unlikely(f->index >= ARRAY_SIZE(formats))) return -EINVAL; - strscpy(f->description, formats[f->index].name, sizeof(f->description)); f->pixelformat = formats[f->index].fourcc; return 0; diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 47dbaae78509d89a81a64d380b2a7ba4679cddf1..017307984094ef0469a7488053f4a6c69fe2bfef 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -83,7 +83,6 @@ #define VID_CHANNEL_NUM 8 struct cx25821_fmt { - char *name; u32 fourcc; /* v4l2 format id */ int depth; int flags; diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index 200d688270738d9f1f9954c86dcfbebc67d550ab..d3da7f4297af8220ba9703fda996b9be1e1823a6 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -805,9 +805,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index != 0) return -EINVAL; - strscpy(f->description, "MPEG", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_MPEG; - f->flags = V4L2_FMT_FLAG_COMPRESSED; return 0; } diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index e59a74514c7c8c26456776876ae99594076243a7..dcc0f02aeb70ca05b9b15031f86641896176285b 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -69,62 +69,52 @@ MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); static const struct cx8800_fmt formats[] = { { - .name = "8 bpp, gray", .fourcc = V4L2_PIX_FMT_GREY, .cxformat = ColorFormatY8, .depth = 8, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "15 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB555, .cxformat = ColorFormatRGB15, .depth = 16, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "15 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB555X, .cxformat = ColorFormatRGB15 | ColorFormatBSWAP, .depth = 16, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "16 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB565, .cxformat = ColorFormatRGB16, .depth = 16, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "16 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB565X, .cxformat = ColorFormatRGB16 | ColorFormatBSWAP, .depth = 16, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "24 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR24, .cxformat = ColorFormatRGB24, .depth = 24, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "32 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR32, .cxformat = ColorFormatRGB32, .depth = 32, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "32 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB32, .cxformat = ColorFormatRGB32 | ColorFormatBSWAP | ColorFormatWSWAP, .depth = 32, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .cxformat = ColorFormatYUY2, .depth = 16, .flags = FORMAT_FLAGS_PACKED, }, { - .name = "4:2:2, packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, .cxformat = ColorFormatYUY2 | ColorFormatBSWAP, .depth = 16, @@ -489,9 +479,9 @@ static int buffer_prepare(struct vb2_buffer *vb) break; } dprintk(2, - "[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", - buf, buf->vb.vb2_buf.index, - core->width, core->height, dev->fmt->depth, dev->fmt->name, + "[%p/%d] %s - %dx%d %dbpp 0x%08x - dma=0x%08lx\n", + buf, buf->vb.vb2_buf.index, __func__, + core->width, core->height, dev->fmt->depth, dev->fmt->fourcc, (unsigned long)buf->risc.dma); return 0; } @@ -829,7 +819,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (unlikely(f->index >= ARRAY_SIZE(formats))) return -EINVAL; - strscpy(f->description, formats[f->index].name, sizeof(f->description)); f->pixelformat = formats[f->index].fourcc; return 0; diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h index a70a50dc3edf24ebb0efe7115e8c47fa1a0c9018..744a22328ebc9bd6f45863e9fc8551767aaaf2f6 100644 --- a/drivers/media/pci/cx88/cx88.h +++ b/drivers/media/pci/cx88/cx88.h @@ -99,7 +99,6 @@ static inline unsigned int norm_maxh(v4l2_std_id norm) /* static data */ struct cx8800_fmt { - const char *name; u32 fourcc; /* v4l2 format id */ int depth; int flags; diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c index b4cdda50e742984d4d74093be751ea2121dc50da..7480f0d3ad0fa32b83700dc84d5b5cc895c2bbc7 100644 --- a/drivers/media/pci/dt3155/dt3155.c +++ b/drivers/media/pci/dt3155/dt3155.c @@ -306,7 +306,6 @@ static int dt3155_enum_fmt_vid_cap(struct file *filp, if (f->index) return -EINVAL; f->pixelformat = V4L2_PIX_FMT_GREY; - strscpy(f->description, "8-bit Greyscale", sizeof(f->description)); return 0; } diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index c1d133e17e4b8bfc794784f1b828845f4ca154df..1adfdc7ab0dbb57760c9d5d5605346abf1fd50ca 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1475,57 +1475,66 @@ static const struct v4l2_async_notifier_operations cio2_async_ops = { .complete = cio2_notifier_complete, }; -static int cio2_fwnode_parse(struct device *dev, - struct v4l2_fwnode_endpoint *vep, - struct v4l2_async_subdev *asd) +static int cio2_parse_firmware(struct cio2_device *cio2) { - struct sensor_async_subdev *s_asd = - container_of(asd, struct sensor_async_subdev, asd); + unsigned int i; + int ret; - if (vep->bus_type != V4L2_MBUS_CSI2_DPHY) { - dev_err(dev, "Only CSI2 bus type is currently supported\n"); - return -EINVAL; - } + for (i = 0; i < CIO2_NUM_PORTS; i++) { + struct v4l2_fwnode_endpoint vep = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + struct sensor_async_subdev *s_asd = NULL; + struct fwnode_handle *ep; - s_asd->csi2.port = vep->base.port; - s_asd->csi2.lanes = vep->bus.mipi_csi2.num_data_lanes; + ep = fwnode_graph_get_endpoint_by_id( + dev_fwnode(&cio2->pci_dev->dev), i, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); - return 0; -} + if (!ep) + continue; -static int cio2_notifier_init(struct cio2_device *cio2) -{ - int ret; + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + if (ret) + goto err_parse; - v4l2_async_notifier_init(&cio2->notifier); + s_asd = kzalloc(sizeof(*s_asd), GFP_KERNEL); + if (!s_asd) { + ret = -ENOMEM; + goto err_parse; + } - ret = v4l2_async_notifier_parse_fwnode_endpoints( - &cio2->pci_dev->dev, &cio2->notifier, - sizeof(struct sensor_async_subdev), - cio2_fwnode_parse); - if (ret < 0) - return ret; + s_asd->csi2.port = vep.base.port; + s_asd->csi2.lanes = vep.bus.mipi_csi2.num_data_lanes; - if (list_empty(&cio2->notifier.asd_list)) - return -ENODEV; /* no endpoint */ + ret = v4l2_async_notifier_add_fwnode_remote_subdev( + &cio2->notifier, ep, &s_asd->asd); + if (ret) + goto err_parse; + + fwnode_handle_put(ep); + + continue; +err_parse: + fwnode_handle_put(ep); + kfree(s_asd); + return ret; + } + + /* + * Proceed even without sensors connected to allow the device to + * suspend. + */ cio2->notifier.ops = &cio2_async_ops; ret = v4l2_async_notifier_register(&cio2->v4l2_dev, &cio2->notifier); - if (ret) { + if (ret) dev_err(&cio2->pci_dev->dev, "failed to register async notifier : %d\n", ret); - v4l2_async_notifier_cleanup(&cio2->notifier); - } return ret; } -static void cio2_notifier_exit(struct cio2_device *cio2) -{ - v4l2_async_notifier_unregister(&cio2->notifier); - v4l2_async_notifier_cleanup(&cio2->notifier); -} - /**************** Queue initialization ****************/ static const struct media_entity_operations cio2_media_ops = { .link_validate = v4l2_subdev_link_validate, @@ -1809,17 +1818,18 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, if (r) goto fail_v4l2_device_unregister; + v4l2_async_notifier_init(&cio2->notifier); + /* Register notifier for subdevices we care */ - r = cio2_notifier_init(cio2); - /* Proceed without sensors connected to allow the device to suspend. */ - if (r && r != -ENODEV) - goto fail_cio2_queue_exit; + r = cio2_parse_firmware(cio2); + if (r) + goto fail_clean_notifier; r = devm_request_irq(&pci_dev->dev, pci_dev->irq, cio2_irq, IRQF_SHARED, CIO2_NAME, cio2); if (r) { dev_err(&pci_dev->dev, "failed to request IRQ (%d)\n", r); - goto fail; + goto fail_clean_notifier; } pm_runtime_put_noidle(&pci_dev->dev); @@ -1827,9 +1837,9 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, return 0; -fail: - cio2_notifier_exit(cio2); -fail_cio2_queue_exit: +fail_clean_notifier: + v4l2_async_notifier_unregister(&cio2->notifier); + v4l2_async_notifier_cleanup(&cio2->notifier); cio2_queues_exit(cio2); fail_v4l2_device_unregister: v4l2_device_unregister(&cio2->v4l2_dev); @@ -1848,7 +1858,8 @@ static void cio2_pci_remove(struct pci_dev *pci_dev) struct cio2_device *cio2 = pci_get_drvdata(pci_dev); media_device_unregister(&cio2->media_dev); - cio2_notifier_exit(cio2); + v4l2_async_notifier_unregister(&cio2->notifier); + v4l2_async_notifier_cleanup(&cio2->notifier); cio2_queues_exit(cio2); cio2_fbpt_exit_dummy(cio2); v4l2_device_unregister(&cio2->v4l2_dev); @@ -2000,8 +2011,7 @@ static int __maybe_unused cio2_suspend(struct device *dev) static int __maybe_unused cio2_resume(struct device *dev) { - struct pci_dev *pci_dev = to_pci_dev(dev); - struct cio2_device *cio2 = pci_get_drvdata(pci_dev); + struct cio2_device *cio2 = dev_get_drvdata(dev); int r = 0; struct cio2_queue *q = cio2->cur_queue; diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index dd727098daf47d3d2dbac2e390881a77a0b704ba..3f3f40ea890bbc045376a3d15400d336143fc2ec 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -910,7 +910,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) /* check which i2c devices are actually found */ for (i = 0; i < 32; i++) { - u32 device = 1 << i; + u32 device = BIT(i); if (!(device & hw)) continue; diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 5595f6a274e766c3755e3870bf343300d26e8e13..137853944e4619cbedb6f6c59774bdc23c8b42c6 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -73,8 +73,8 @@ static u16 select_service_from_set(int field, int line, u16 set, int is_pal) return 0; } for (i = 0; i < 32; i++) { - if ((1 << i) & set) - return 1 << i; + if (BIT(i) & set) + return BIT(i); } return 0; } diff --git a/drivers/media/pci/ivtv/ivtv-irq.h b/drivers/media/pci/ivtv/ivtv-irq.h index 7d2f45e2b83c94b353489768a9c97a96e86916fa..b8b0703a1c82b258d9f3021f945445580dcc1a59 100644 --- a/drivers/media/pci/ivtv/ivtv-irq.h +++ b/drivers/media/pci/ivtv/ivtv-irq.h @@ -10,20 +10,20 @@ #ifndef IVTV_IRQ_H #define IVTV_IRQ_H -#define IVTV_IRQ_ENC_START_CAP (0x1 << 31) -#define IVTV_IRQ_ENC_EOS (0x1 << 30) -#define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29) -#define IVTV_IRQ_ENC_VIM_RST (0x1 << 28) -#define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27) -#define IVTV_IRQ_ENC_PIO_COMPLETE (0x1 << 25) -#define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24) -#define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22) -#define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20) -#define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19) -#define IVTV_IRQ_DMA_ERR (0x1 << 18) -#define IVTV_IRQ_DMA_WRITE (0x1 << 17) -#define IVTV_IRQ_DMA_READ (0x1 << 16) -#define IVTV_IRQ_DEC_VSYNC (0x1 << 10) +#define IVTV_IRQ_ENC_START_CAP BIT(31) +#define IVTV_IRQ_ENC_EOS BIT(30) +#define IVTV_IRQ_ENC_VBI_CAP BIT(29) +#define IVTV_IRQ_ENC_VIM_RST BIT(28) +#define IVTV_IRQ_ENC_DMA_COMPLETE BIT(27) +#define IVTV_IRQ_ENC_PIO_COMPLETE BIT(25) +#define IVTV_IRQ_DEC_AUD_MODE_CHG BIT(24) +#define IVTV_IRQ_DEC_DATA_REQ BIT(22) +#define IVTV_IRQ_DEC_DMA_COMPLETE BIT(20) +#define IVTV_IRQ_DEC_VBI_RE_INSERT BIT(19) +#define IVTV_IRQ_DMA_ERR BIT(18) +#define IVTV_IRQ_DMA_WRITE BIT(17) +#define IVTV_IRQ_DMA_READ BIT(16) +#define IVTV_IRQ_DEC_VSYNC BIT(10) /* IRQ Masks */ #define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\ diff --git a/drivers/media/pci/ivtv/ivtv-mailbox.c b/drivers/media/pci/ivtv/ivtv-mailbox.c index 8393675c3f463adcfa6a81810cc2ccf4eb3bb407..d3fdaaa903f1f0d0c363e1186f8900f82442561e 100644 --- a/drivers/media/pci/ivtv/ivtv-mailbox.c +++ b/drivers/media/pci/ivtv/ivtv-mailbox.c @@ -10,8 +10,6 @@ #include "ivtv-driver.h" #include "ivtv-mailbox.h" -#include - /* Firmware mailbox flags*/ #define IVTV_MBOX_FIRMWARE_DONE 0x00000004 #define IVTV_MBOX_DRIVER_DONE 0x00000002 diff --git a/drivers/media/pci/mantis/mantis_reg.h b/drivers/media/pci/mantis/mantis_reg.h index 67a80e42b5c73143cda7521a13bbb47182361c95..a1e66ef6ac2f9e36ab458e0284068d983ee2970c 100644 --- a/drivers/media/pci/mantis/mantis_reg.h +++ b/drivers/media/pci/mantis/mantis_reg.h @@ -14,44 +14,44 @@ #define MANTIS_INT_MASK 0x04 #define MANTIS_INT_RISCSTAT (0x0f << 28) -#define MANTIS_INT_RISCEN (0x01 << 27) -#define MANTIS_INT_I2CRACK (0x01 << 26) +#define MANTIS_INT_RISCEN BIT(27) +#define MANTIS_INT_I2CRACK BIT(26) /* #define MANTIS_INT_GPIF (0xff << 12) */ -#define MANTIS_INT_PCMCIA7 (0x01 << 19) -#define MANTIS_INT_PCMCIA6 (0x01 << 18) -#define MANTIS_INT_PCMCIA5 (0x01 << 17) -#define MANTIS_INT_PCMCIA4 (0x01 << 16) -#define MANTIS_INT_PCMCIA3 (0x01 << 15) -#define MANTIS_INT_PCMCIA2 (0x01 << 14) -#define MANTIS_INT_PCMCIA1 (0x01 << 13) -#define MANTIS_INT_PCMCIA0 (0x01 << 12) -#define MANTIS_INT_IRQ1 (0x01 << 11) -#define MANTIS_INT_IRQ0 (0x01 << 10) -#define MANTIS_INT_OCERR (0x01 << 8) -#define MANTIS_INT_PABORT (0x01 << 7) -#define MANTIS_INT_RIPERR (0x01 << 6) -#define MANTIS_INT_PPERR (0x01 << 5) -#define MANTIS_INT_FTRGT (0x01 << 3) -#define MANTIS_INT_RISCI (0x01 << 1) -#define MANTIS_INT_I2CDONE (0x01 << 0) +#define MANTIS_INT_PCMCIA7 BIT(19) +#define MANTIS_INT_PCMCIA6 BIT(18) +#define MANTIS_INT_PCMCIA5 BIT(17) +#define MANTIS_INT_PCMCIA4 BIT(16) +#define MANTIS_INT_PCMCIA3 BIT(15) +#define MANTIS_INT_PCMCIA2 BIT(14) +#define MANTIS_INT_PCMCIA1 BIT(13) +#define MANTIS_INT_PCMCIA0 BIT(12) +#define MANTIS_INT_IRQ1 BIT(11) +#define MANTIS_INT_IRQ0 BIT(10) +#define MANTIS_INT_OCERR BIT(8) +#define MANTIS_INT_PABORT BIT(7) +#define MANTIS_INT_RIPERR BIT(6) +#define MANTIS_INT_PPERR BIT(5) +#define MANTIS_INT_FTRGT BIT(3) +#define MANTIS_INT_RISCI BIT(1) +#define MANTIS_INT_I2CDONE BIT(0) /* DMA */ #define MANTIS_DMA_CTL 0x08 #define MANTIS_GPIF_RD (0xff << 24) #define MANTIS_GPIF_WR (0xff << 16) -#define MANTIS_CPU_DO (0x01 << 10) -#define MANTIS_DRV_DO (0x01 << 9) -#define MANTIS_I2C_RD (0x01 << 7) -#define MANTIS_I2C_WR (0x01 << 6) -#define MANTIS_DCAP_MODE (0x01 << 5) +#define MANTIS_CPU_DO BIT(10) +#define MANTIS_DRV_DO BIT(9) +#define MANTIS_I2C_RD BIT(7) +#define MANTIS_I2C_WR BIT(6) +#define MANTIS_DCAP_MODE BIT(5) #define MANTIS_FIFO_TP_4 (0x00 << 3) #define MANTIS_FIFO_TP_8 (0x01 << 3) #define MANTIS_FIFO_TP_16 (0x02 << 3) -#define MANTIS_FIFO_EN (0x01 << 2) -#define MANTIS_DCAP_EN (0x01 << 1) -#define MANTIS_RISC_EN (0x01 << 0) +#define MANTIS_FIFO_EN BIT(2) +#define MANTIS_DCAP_EN BIT(1) +#define MANTIS_RISC_EN BIT(0) /* DEBUG */ #define MANTIS_DEBUGREG 0x0c @@ -68,8 +68,8 @@ #define MANTIS_I2C_RATE_2 (0x01 << 6) #define MANTIS_I2C_RATE_3 (0x02 << 6) #define MANTIS_I2C_RATE_4 (0x03 << 6) -#define MANTIS_I2C_STOP (0x01 << 5) -#define MANTIS_I2C_PGMODE (0x01 << 3) +#define MANTIS_I2C_STOP BIT(5) +#define MANTIS_I2C_PGMODE BIT(3) /* DATA */ #define MANTIS_CMD_DATA_R1 0x20 @@ -85,77 +85,77 @@ #define MANTIS_CMD_DATA_4 (0xff << 0) #define MANTIS_CONTROL 0x28 -#define MANTIS_DET (0x01 << 7) -#define MANTIS_DAT_CF_EN (0x01 << 6) +#define MANTIS_DET BIT(7) +#define MANTIS_DAT_CF_EN BIT(6) #define MANTIS_ACS (0x03 << 4) -#define MANTIS_VCCEN (0x01 << 3) -#define MANTIS_BYPASS (0x01 << 2) -#define MANTIS_MRST (0x01 << 1) -#define MANTIS_CRST_INT (0x01 << 0) +#define MANTIS_VCCEN BIT(3) +#define MANTIS_BYPASS BIT(2) +#define MANTIS_MRST BIT(1) +#define MANTIS_CRST_INT BIT(0) #define MANTIS_GPIF_CFGSLA 0x84 #define MANTIS_GPIF_WAITSMPL (0x07 << 28) -#define MANTIS_GPIF_BYTEADDRSUB (0x01 << 25) -#define MANTIS_GPIF_WAITPOL (0x01 << 24) +#define MANTIS_GPIF_BYTEADDRSUB BIT(25) +#define MANTIS_GPIF_WAITPOL BIT(24) #define MANTIS_GPIF_NCDELAY (0x07 << 20) #define MANTIS_GPIF_RW2CSDELAY (0x07 << 16) -#define MANTIS_GPIF_SLFTIMEDMODE (0x01 << 15) +#define MANTIS_GPIF_SLFTIMEDMODE BIT(15) #define MANTIS_GPIF_SLFTIMEDDELY (0x7f << 8) #define MANTIS_GPIF_DEVTYPE (0x07 << 4) -#define MANTIS_GPIF_BIGENDIAN (0x01 << 3) +#define MANTIS_GPIF_BIGENDIAN BIT(3) #define MANTIS_GPIF_FETCHCMD (0x03 << 1) -#define MANTIS_GPIF_HWORDDEV (0x01 << 0) +#define MANTIS_GPIF_HWORDDEV BIT(0) #define MANTIS_GPIF_WSTOPER 0x90 -#define MANTIS_GPIF_WSTOPERWREN3 (0x01 << 31) -#define MANTIS_GPIF_PARBOOTN (0x01 << 29) +#define MANTIS_GPIF_WSTOPERWREN3 BIT(31) +#define MANTIS_GPIF_PARBOOTN BIT(29) #define MANTIS_GPIF_WSTOPERSLID3 (0x1f << 24) -#define MANTIS_GPIF_WSTOPERWREN2 (0x01 << 23) +#define MANTIS_GPIF_WSTOPERWREN2 BIT(23) #define MANTIS_GPIF_WSTOPERSLID2 (0x1f << 16) -#define MANTIS_GPIF_WSTOPERWREN1 (0x01 << 15) +#define MANTIS_GPIF_WSTOPERWREN1 BIT(15) #define MANTIS_GPIF_WSTOPERSLID1 (0x1f << 8) -#define MANTIS_GPIF_WSTOPERWREN0 (0x01 << 7) +#define MANTIS_GPIF_WSTOPERWREN0 BIT(7) #define MANTIS_GPIF_WSTOPERSLID0 (0x1f << 0) #define MANTIS_GPIF_CS2RW 0x94 -#define MANTIS_GPIF_CS2RWWREN3 (0x01 << 31) +#define MANTIS_GPIF_CS2RWWREN3 BIT(31) #define MANTIS_GPIF_CS2RWDELY3 (0x3f << 24) -#define MANTIS_GPIF_CS2RWWREN2 (0x01 << 23) +#define MANTIS_GPIF_CS2RWWREN2 BIT(23) #define MANTIS_GPIF_CS2RWDELY2 (0x3f << 16) -#define MANTIS_GPIF_CS2RWWREN1 (0x01 << 15) +#define MANTIS_GPIF_CS2RWWREN1 BIT(15) #define MANTIS_GPIF_CS2RWDELY1 (0x3f << 8) -#define MANTIS_GPIF_CS2RWWREN0 (0x01 << 7) +#define MANTIS_GPIF_CS2RWWREN0 BIT(7) #define MANTIS_GPIF_CS2RWDELY0 (0x3f << 0) #define MANTIS_GPIF_IRQCFG 0x98 -#define MANTIS_GPIF_IRQPOL (0x01 << 8) -#define MANTIS_MASK_WRACK (0x01 << 7) -#define MANTIS_MASK_BRRDY (0x01 << 6) -#define MANTIS_MASK_OVFLW (0x01 << 5) -#define MANTIS_MASK_OTHERR (0x01 << 4) -#define MANTIS_MASK_WSTO (0x01 << 3) -#define MANTIS_MASK_EXTIRQ (0x01 << 2) -#define MANTIS_MASK_PLUGIN (0x01 << 1) -#define MANTIS_MASK_PLUGOUT (0x01 << 0) +#define MANTIS_GPIF_IRQPOL BIT(8) +#define MANTIS_MASK_WRACK BIT(7) +#define MANTIS_MASK_BRRDY BIT(6) +#define MANTIS_MASK_OVFLW BIT(5) +#define MANTIS_MASK_OTHERR BIT(4) +#define MANTIS_MASK_WSTO BIT(3) +#define MANTIS_MASK_EXTIRQ BIT(2) +#define MANTIS_MASK_PLUGIN BIT(1) +#define MANTIS_MASK_PLUGOUT BIT(0) #define MANTIS_GPIF_STATUS 0x9c -#define MANTIS_SBUF_KILLOP (0x01 << 15) -#define MANTIS_SBUF_OPDONE (0x01 << 14) -#define MANTIS_SBUF_EMPTY (0x01 << 13) -#define MANTIS_GPIF_DETSTAT (0x01 << 9) -#define MANTIS_GPIF_INTSTAT (0x01 << 8) -#define MANTIS_GPIF_WRACK (0x01 << 7) -#define MANTIS_GPIF_BRRDY (0x01 << 6) -#define MANTIS_SBUF_OVFLW (0x01 << 5) -#define MANTIS_GPIF_OTHERR (0x01 << 4) -#define MANTIS_SBUF_WSTO (0x01 << 3) -#define MANTIS_GPIF_EXTIRQ (0x01 << 2) -#define MANTIS_CARD_PLUGIN (0x01 << 1) -#define MANTIS_CARD_PLUGOUT (0x01 << 0) +#define MANTIS_SBUF_KILLOP BIT(15) +#define MANTIS_SBUF_OPDONE BIT(14) +#define MANTIS_SBUF_EMPTY BIT(13) +#define MANTIS_GPIF_DETSTAT BIT(9) +#define MANTIS_GPIF_INTSTAT BIT(8) +#define MANTIS_GPIF_WRACK BIT(7) +#define MANTIS_GPIF_BRRDY BIT(6) +#define MANTIS_SBUF_OVFLW BIT(5) +#define MANTIS_GPIF_OTHERR BIT(4) +#define MANTIS_SBUF_WSTO BIT(3) +#define MANTIS_GPIF_EXTIRQ BIT(2) +#define MANTIS_CARD_PLUGIN BIT(1) +#define MANTIS_CARD_PLUGOUT BIT(0) #define MANTIS_GPIF_BRADDR 0xa0 -#define MANTIS_GPIF_PCMCIAREG (0x01 << 27) -#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26) +#define MANTIS_GPIF_PCMCIAREG BIT(27) +#define MANTIS_GPIF_PCMCIAIOM BIT(26) #define MANTIS_GPIF_BR_ADDR (0xfffffff << 0) #define MANTIS_GPIF_BRBYTES 0xa4 @@ -167,9 +167,9 @@ #define MANTIS_CARD_RESET 0xac #define MANTIS_GPIF_ADDR 0xb0 -#define MANTIS_GPIF_HIFRDWRN (0x01 << 31) -#define MANTIS_GPIF_PCMCIAREG (0x01 << 27) -#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26) +#define MANTIS_GPIF_HIFRDWRN BIT(31) +#define MANTIS_GPIF_PCMCIAREG BIT(27) +#define MANTIS_GPIF_PCMCIAIOM BIT(26) #define MANTIS_GPIF_HIFADDR (0xfffffff << 0) #define MANTIS_GPIF_DOUT 0xb4 diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index 8218810c899eca193490c85fcd1ab458ea49618b..0e61c81356ef5b52c1945c24d8bdc4c1f6b54acd 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -1104,12 +1104,9 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, if (f->index == 0) { /* standard YUV 422 capture */ f->flags = 0; - strscpy(f->description, "YUV422", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_YUYV; } else { /* compressed MJPEG capture */ - f->flags = V4L2_FMT_FLAG_COMPRESSED; - strscpy(f->description, "MJPEG", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_MJPEG; } diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index b75ab7d29226631a9b442c06ad9c68772c90951d..af15ca1c501bf47fb87e408267e72a4d93a8d73d 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -854,8 +854,6 @@ static int create_ring_buffer(struct pci_dev *pci_dev, if (!Head) return -ENOMEM; - memset(Head, 0, MemSize); - PARingBufferCur = PARingBufferHead; Cur = Head; @@ -907,8 +905,6 @@ static int AllocateRingBuffers(struct pci_dev *pci_dev, if (SCListMem == NULL) return -ENOMEM; - memset(SCListMem, 0, SCListMemSize); - pRingBuffer->SCListMem = SCListMem; pRingBuffer->PASCListMem = PASCListMem; pRingBuffer->SCListMemSize = SCListMemSize; diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c index e51c80bc4646fca81080b8436219b8744b702687..72b191cfeb5483351d425f7ed68bb5763f0ea266 100644 --- a/drivers/media/pci/pt1/pt1.c +++ b/drivers/media/pci/pt1/pt1.c @@ -1217,8 +1217,7 @@ static void pt1_i2c_init(struct pt1 *pt1) static int pt1_suspend(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct pt1 *pt1 = pci_get_drvdata(pdev); + struct pt1 *pt1 = dev_get_drvdata(dev); pt1_init_streams(pt1); pt1_disable_ram(pt1); @@ -1230,8 +1229,7 @@ static int pt1_suspend(struct device *dev) static int pt1_resume(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct pt1 *pt1 = pci_get_drvdata(pdev); + struct pt1 *pt1 = dev_get_drvdata(dev); int ret; int i; diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c index 7a7afae4c84ce28dc557f551c776a366fdec1f9e..c0bc867933558e1818d61672831e693752d8719e 100644 --- a/drivers/media/pci/pt3/pt3.c +++ b/drivers/media/pci/pt3/pt3.c @@ -626,8 +626,7 @@ static void pt3_cleanup_adapter(struct pt3_board *pt3, int index) static int pt3_suspend(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct pt3_board *pt3 = pci_get_drvdata(pdev); + struct pt3_board *pt3 = dev_get_drvdata(dev); int i; struct pt3_adapter *adap; @@ -646,8 +645,7 @@ static int pt3_suspend(struct device *dev) static int pt3_resume(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct pt3_board *pt3 = pci_get_drvdata(pdev); + struct pt3_board *pt3 = dev_get_drvdata(dev); int i, ret; struct pt3_adapter *adap; diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c index eb8377a9502395979d64a3a7f89e644658e054db..f359cd5c006a752cbc8849c3d3c6b0713160d66d 100644 --- a/drivers/media/pci/saa7134/saa7134-dvb.c +++ b/drivers/media/pci/saa7134/saa7134-dvb.c @@ -1264,6 +1264,20 @@ static int dvb_init(struct saa7134_dev *dev) &medion_cardbus, &dev->i2c_adap); if (fe0->dvb.frontend) { + /* + * The TV tuner on this board is actually NOT + * behind the demod i2c gate. + * However, the demod EEPROM is indeed there and it + * conflicts with the SAA7134 chip config EEPROM + * if the i2c gate is open (since they have same + * bus addresses) resulting in card PCI SVID / SSID + * being garbage after a reboot from time to time. + * + * Let's just leave the gate permanently closed - + * saa7134_i2c_eeprom_md7134_gate() will close it for + * us at probe time if it was open for some reason. + */ + fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &dev->i2c_adap, medion_cardbus.tuner_address, TUNER_PHILIPS_FMD1216ME_MK3); diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index 1a41a56afec6485ed41ceccf96507196e486c50d..cb65d345fd3e9756998c87a3f55f7e57d7e57368 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c @@ -91,9 +91,7 @@ static int empress_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index != 0) return -EINVAL; - strscpy(f->description, "MPEG TS", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_MPEG; - f->flags = V4L2_FMT_FLAG_COMPRESSED; return 0; } diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c index 493b1858815fb2f8556d9f1580c18b29710edca3..04e85765373ecc0f0759eba539c20bcdc9716ca8 100644 --- a/drivers/media/pci/saa7134/saa7134-i2c.c +++ b/drivers/media/pci/saa7134/saa7134-i2c.c @@ -342,7 +342,11 @@ static const struct i2c_client saa7134_client_template = { /* ----------------------------------------------------------- */ -/* On Medion 7134 reading EEPROM needs DVB-T demod i2c gate open */ +/* + * On Medion 7134 reading the SAA7134 chip config EEPROM needs DVB-T + * demod i2c gate closed due to an address clash between this EEPROM + * and the demod one. + */ static void saa7134_i2c_eeprom_md7134_gate(struct saa7134_dev *dev) { u8 subaddr = 0x7, dmdregval; @@ -359,14 +363,14 @@ static void saa7134_i2c_eeprom_md7134_gate(struct saa7134_dev *dev) ret = i2c_transfer(&dev->i2c_adap, i2cgatemsg_r, 2); if ((ret == 2) && (dmdregval & 0x2)) { - pr_debug("%s: DVB-T demod i2c gate was left closed\n", + pr_debug("%s: DVB-T demod i2c gate was left open\n", dev->name); data[0] = subaddr; data[1] = (dmdregval & ~0x2); if (i2c_transfer(&dev->i2c_adap, i2cgatemsg_w, 1) != 1) - pr_err("%s: EEPROM i2c gate open failure\n", - dev->name); + pr_err("%s: EEPROM i2c gate close failure\n", + dev->name); } } diff --git a/drivers/media/pci/saa7134/saa7134-tvaudio.c b/drivers/media/pci/saa7134/saa7134-tvaudio.c index 5beff534d5e10df91d741ce86f532a3a824f7434..79e1afb71075893fdfbdd8dcf6f0620b7d145a56 100644 --- a/drivers/media/pci/saa7134/saa7134-tvaudio.c +++ b/drivers/media/pci/saa7134/saa7134-tvaudio.c @@ -319,7 +319,6 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) __s32 left,right,value; if (!(dev->tvnorm->id & scan->std)) { - value = 0; audio_dbg(1, "skipping %d.%03d MHz [%4s]\n", scan->carr / 1000, scan->carr % 1000, scan->name); return 0; diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 606df51bb636b00b392dda3ec4eff6d43678f983..342cabf48064611917268b9c3a3d7771df13da37 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -90,70 +90,58 @@ static int video_out[][9] = { static struct saa7134_format formats[] = { { - .name = "8 bpp gray", .fourcc = V4L2_PIX_FMT_GREY, .depth = 8, .pm = 0x06, },{ - .name = "15 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB555, .depth = 16, .pm = 0x13 | 0x80, },{ - .name = "15 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB555X, .depth = 16, .pm = 0x13 | 0x80, .bswap = 1, },{ - .name = "16 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB565, .depth = 16, .pm = 0x10 | 0x80, },{ - .name = "16 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB565X, .depth = 16, .pm = 0x10 | 0x80, .bswap = 1, },{ - .name = "24 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR24, .depth = 24, .pm = 0x11, },{ - .name = "24 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB24, .depth = 24, .pm = 0x11, .bswap = 1, },{ - .name = "32 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR32, .depth = 32, .pm = 0x12, },{ - .name = "32 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB32, .depth = 32, .pm = 0x12, .bswap = 1, .wswap = 1, },{ - .name = "4:2:2 packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .pm = 0x00, .bswap = 1, .yuv = 1, },{ - .name = "4:2:2 packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, .depth = 16, .pm = 0x00, .yuv = 1, },{ - .name = "4:2:2 planar, Y-Cb-Cr", .fourcc = V4L2_PIX_FMT_YUV422P, .depth = 16, .pm = 0x09, @@ -162,7 +150,6 @@ static struct saa7134_format formats[] = { .hshift = 1, .vshift = 0, },{ - .name = "4:2:0 planar, Y-Cb-Cr", .fourcc = V4L2_PIX_FMT_YUV420, .depth = 12, .pm = 0x0a, @@ -171,7 +158,6 @@ static struct saa7134_format formats[] = { .hshift = 1, .vshift = 1, },{ - .name = "4:2:0 planar, Y-Cb-Cr", .fourcc = V4L2_PIX_FMT_YVU420, .depth = 12, .pm = 0x0a, @@ -720,10 +706,10 @@ static int start_preview(struct saa7134_dev *dev) return err; dev->ovfield = dev->win.field; - video_dbg("start_preview %dx%d+%d+%d %s field=%s\n", - dev->win.w.width, dev->win.w.height, - dev->win.w.left, dev->win.w.top, - dev->ovfmt->name, v4l2_field_names[dev->ovfield]); + video_dbg("%s %dx%d+%d+%d 0x%08x field=%s\n", __func__, + dev->win.w.width, dev->win.w.height, + dev->win.w.left, dev->win.w.top, + dev->ovfmt->fourcc, v4l2_field_names[dev->ovfield]); /* setup window + clipping */ set_size(dev, TASK_B, dev->win.w.width, dev->win.w.height, @@ -1780,9 +1766,6 @@ static int saa7134_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index >= FORMATS) return -EINVAL; - strscpy(f->description, formats[f->index].name, - sizeof(f->description)); - f->pixelformat = formats[f->index].fourcc; return 0; @@ -1799,9 +1782,6 @@ static int saa7134_enum_fmt_vid_overlay(struct file *file, void *priv, if ((f->index >= FORMATS) || formats[f->index].planar) return -EINVAL; - strscpy(f->description, formats[f->index].name, - sizeof(f->description)); - f->pixelformat = formats[f->index].fourcc; return 0; diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index 6324f174c6f97a5c238886bb3279750a62988e3e..77c325e64a978c5235ea6b59be4ae40f66b7f530 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -98,7 +98,6 @@ struct saa7134_tvaudio { }; struct saa7134_format { - char *name; unsigned int fourcc; unsigned int depth; unsigned int pm; diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index dca20a3d98e2592bed7fcdc70fce38eb01d86343..f962269306707179b992ee033d33e223c19c281a 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -292,6 +292,9 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER); if (ret < 0) { pr_err("cannot register capture v4l2 device. skipping.\n"); + saa7146_vv_release(dev); + i2c_del_adapter(&hexium->i2c_adapter); + kfree(hexium); return ret; } diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index 43fdaa2d32bd73d329deb792ecd6460935e6a103..3fca7257a72013883452bcfef28ed6651b19b627 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -503,7 +503,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index != 0) return -EINVAL; - strscpy(f->description, "MPEG", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_MPEG; return 0; diff --git a/drivers/media/pci/solo6x10/solo6x10-gpio.c b/drivers/media/pci/solo6x10/solo6x10-gpio.c index 5caeca8b5dd0ff2e971c1539328a6e5d866130fb..526d67cf9942cbd4e6fcd236c7c3c727ff73d6d5 100644 --- a/drivers/media/pci/solo6x10/solo6x10-gpio.c +++ b/drivers/media/pci/solo6x10/solo6x10-gpio.c @@ -39,13 +39,13 @@ static void solo_gpio_mode(struct solo_dev *solo_dev, ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1); for (port = 0; port < 16; port++) { - if (!((1 << (port + 16)) & port_mask)) + if (!((1UL << (port + 16)) & port_mask)) continue; if (!mode) - ret &= ~(1 << port); + ret &= ~(1UL << port); else - ret |= 1 << port; + ret |= 1UL << port; } /* Enable GPIO[31:16] */ diff --git a/drivers/media/pci/solo6x10/solo6x10-regs.h b/drivers/media/pci/solo6x10/solo6x10-regs.h index d88cc02d01d34c7fadc0771a4c74487ddeab581e..804505d01b2527bac609b5d3ec136cae70bb66f8 100644 --- a/drivers/media/pci/solo6x10/solo6x10-regs.h +++ b/drivers/media/pci/solo6x10/solo6x10-regs.h @@ -12,6 +12,8 @@ #ifndef __SOLO6X10_REGISTERS_H #define __SOLO6X10_REGISTERS_H +#include + #include "solo6x10-offsets.h" /* Global 6010 system configuration */ @@ -32,17 +34,17 @@ #define SOLO_DMA_CTRL_REFRESH_CYCLE(n) ((n)<<8) /* 0=16/32MB, 1=32/64MB, 2=64/128MB, 3=128/256MB */ #define SOLO_DMA_CTRL_SDRAM_SIZE(n) ((n)<<6) -#define SOLO_DMA_CTRL_SDRAM_CLK_INVERT (1<<5) -#define SOLO_DMA_CTRL_STROBE_SELECT (1<<4) -#define SOLO_DMA_CTRL_READ_DATA_SELECT (1<<3) -#define SOLO_DMA_CTRL_READ_CLK_SELECT (1<<2) +#define SOLO_DMA_CTRL_SDRAM_CLK_INVERT BIT(5) +#define SOLO_DMA_CTRL_STROBE_SELECT BIT(4) +#define SOLO_DMA_CTRL_READ_DATA_SELECT BIT(3) +#define SOLO_DMA_CTRL_READ_CLK_SELECT BIT(2) #define SOLO_DMA_CTRL_LATENCY(n) ((n)<<0) /* Some things we set in this are undocumented. Why Softlogic?!?! */ #define SOLO_DMA_CTRL1 0x0008 #define SOLO_SYS_VCLK 0x000C -#define SOLO_VCLK_INVERT (1<<22) +#define SOLO_VCLK_INVERT BIT(22) /* 0=sys_clk/4, 1=sys_clk/2, 2=clk_in/2 of system input */ #define SOLO_VCLK_SELECT(n) ((n)<<20) #define SOLO_VCLK_VIN1415_DELAY(n) ((n)<<14) @@ -56,22 +58,22 @@ #define SOLO_IRQ_STAT 0x0010 #define SOLO_IRQ_MASK 0x0014 -#define SOLO_IRQ_P2M(n) (1<<((n)+17)) -#define SOLO_IRQ_GPIO (1<<16) -#define SOLO_IRQ_VIDEO_LOSS (1<<15) -#define SOLO_IRQ_VIDEO_IN (1<<14) -#define SOLO_IRQ_MOTION (1<<13) -#define SOLO_IRQ_ATA_CMD (1<<12) -#define SOLO_IRQ_ATA_DIR (1<<11) -#define SOLO_IRQ_PCI_ERR (1<<10) -#define SOLO_IRQ_PS2_1 (1<<9) -#define SOLO_IRQ_PS2_0 (1<<8) -#define SOLO_IRQ_SPI (1<<7) -#define SOLO_IRQ_IIC (1<<6) -#define SOLO_IRQ_UART(n) (1<<((n) + 4)) -#define SOLO_IRQ_G723 (1<<3) -#define SOLO_IRQ_DECODER (1<<1) -#define SOLO_IRQ_ENCODER (1<<0) +#define SOLO_IRQ_P2M(n) BIT((n) + 17) +#define SOLO_IRQ_GPIO BIT(16) +#define SOLO_IRQ_VIDEO_LOSS BIT(15) +#define SOLO_IRQ_VIDEO_IN BIT(14) +#define SOLO_IRQ_MOTION BIT(13) +#define SOLO_IRQ_ATA_CMD BIT(12) +#define SOLO_IRQ_ATA_DIR BIT(11) +#define SOLO_IRQ_PCI_ERR BIT(10) +#define SOLO_IRQ_PS2_1 BIT(9) +#define SOLO_IRQ_PS2_0 BIT(8) +#define SOLO_IRQ_SPI BIT(7) +#define SOLO_IRQ_IIC BIT(6) +#define SOLO_IRQ_UART(n) BIT((n) + 4) +#define SOLO_IRQ_G723 BIT(3) +#define SOLO_IRQ_DECODER BIT(1) +#define SOLO_IRQ_ENCODER BIT(0) #define SOLO_CHIP_OPTION 0x001C #define SOLO_CHIP_ID_MASK 0x00000007 @@ -79,11 +81,11 @@ #define SOLO_PLL_CONFIG 0x0020 /* 6110 Only */ #define SOLO_EEPROM_CTRL 0x0060 -#define SOLO_EEPROM_ACCESS_EN (1<<7) -#define SOLO_EEPROM_CS (1<<3) -#define SOLO_EEPROM_CLK (1<<2) -#define SOLO_EEPROM_DO (1<<1) -#define SOLO_EEPROM_DI (1<<0) +#define SOLO_EEPROM_ACCESS_EN BIT(7) +#define SOLO_EEPROM_CS BIT(3) +#define SOLO_EEPROM_CLK BIT(2) +#define SOLO_EEPROM_DO BIT(1) +#define SOLO_EEPROM_DI BIT(0) #define SOLO_EEPROM_ENABLE (SOLO_EEPROM_ACCESS_EN | SOLO_EEPROM_CS) #define SOLO_PCI_ERR 0x0070 @@ -102,13 +104,13 @@ #define SOLO_P2M_CONFIG(n) (0x0080 + ((n)*0x20)) #define SOLO_P2M_DMA_INTERVAL(n) ((n)<<6)/* N*32 clocks */ -#define SOLO_P2M_CSC_BYTE_REORDER (1<<5) /* BGR -> RGB */ +#define SOLO_P2M_CSC_BYTE_REORDER BIT(5) /* BGR -> RGB */ /* 0:r=[14:10] g=[9:5] b=[4:0], 1:r=[15:11] g=[10:5] b=[4:0] */ -#define SOLO_P2M_CSC_16BIT_565 (1<<4) -#define SOLO_P2M_UV_SWAP (1<<3) -#define SOLO_P2M_PCI_MASTER_MODE (1<<2) -#define SOLO_P2M_DESC_INTR_OPT (1<<1) /* 1:Empty, 0:Each */ -#define SOLO_P2M_DESC_MODE (1<<0) +#define SOLO_P2M_CSC_16BIT_565 BIT(4) +#define SOLO_P2M_UV_SWAP BIT(3) +#define SOLO_P2M_PCI_MASTER_MODE BIT(2) +#define SOLO_P2M_DESC_INTR_OPT BIT(1) /* 1:Empty, 0:Each */ +#define SOLO_P2M_DESC_MODE BIT(0) #define SOLO_P2M_DES_ADR(n) (0x0084 + ((n)*0x20)) @@ -116,7 +118,7 @@ #define SOLO_P2M_UPDATE_ID(n) ((n)<<0) #define SOLO_P2M_STATUS(n) (0x008C + ((n)*0x20)) -#define SOLO_P2M_COMMAND_DONE (1<<8) +#define SOLO_P2M_COMMAND_DONE BIT(8) #define SOLO_P2M_CURRENT_ID(stat) (0xff & (stat)) #define SOLO_P2M_CONTROL(n) (0x0090 + ((n)*0x20)) @@ -129,13 +131,13 @@ #define SOLO_P2M_BURST_128 2 #define SOLO_P2M_BURST_64 3 #define SOLO_P2M_BURST_32 4 -#define SOLO_P2M_CSC_16BIT (1<<6) /* 0:24bit, 1:16bit */ +#define SOLO_P2M_CSC_16BIT BIT(6) /* 0:24bit, 1:16bit */ /* 0:Y[0]<-0(OFF), 1:Y[0]<-1(ON), 2:Y[0]<-G[0], 3:Y[0]<-Bit[15] */ #define SOLO_P2M_ALPHA_MODE(n) ((n)<<4) -#define SOLO_P2M_CSC_ON (1<<3) -#define SOLO_P2M_INTERRUPT_REQ (1<<2) -#define SOLO_P2M_WRITE (1<<1) -#define SOLO_P2M_TRANS_ON (1<<0) +#define SOLO_P2M_CSC_ON BIT(3) +#define SOLO_P2M_INTERRUPT_REQ BIT(2) +#define SOLO_P2M_WRITE BIT(1) +#define SOLO_P2M_TRANS_ON BIT(0) #define SOLO_P2M_EXT_CFG(n) (0x0094 + ((n)*0x20)) #define SOLO_P2M_EXT_INC(n) ((n)<<20) @@ -157,9 +159,9 @@ #define SOLO_VI_PROG_MASK(n) ((n)<<0) #define SOLO_VI_FMT_CFG 0x0114 -#define SOLO_VI_FMT_CHECK_VCOUNT (1<<31) -#define SOLO_VI_FMT_CHECK_HCOUNT (1<<30) -#define SOLO_VI_FMT_TEST_SIGNAL (1<<28) +#define SOLO_VI_FMT_CHECK_VCOUNT BIT(31) +#define SOLO_VI_FMT_CHECK_HCOUNT BIT(30) +#define SOLO_VI_FMT_TEST_SIGNAL BIT(28) #define SOLO_VI_PAGE_SW 0x0118 #define SOLO_FI_INV_DISP_LIVE(n) ((n)<<8) @@ -171,7 +173,7 @@ #define SOLO_VI_ACT_I_P 0x011C #define SOLO_VI_ACT_I_S 0x0120 #define SOLO_VI_ACT_P 0x0124 -#define SOLO_VI_FI_INVERT (1<<31) +#define SOLO_VI_FI_INVERT BIT(31) #define SOLO_VI_H_START(n) ((n)<<21) #define SOLO_VI_V_START(n) ((n)<<11) #define SOLO_VI_V_STOP(n) ((n)<<0) @@ -184,8 +186,8 @@ #define DISP_PAGE(stat) ((stat) & 0x07) #define SOLO_VI_PB_CONFIG 0x0130 -#define SOLO_VI_PB_USER_MODE (1<<1) -#define SOLO_VI_PB_PAL (1<<0) +#define SOLO_VI_PB_USER_MODE BIT(1) +#define SOLO_VI_PB_PAL BIT(0) #define SOLO_VI_PB_RANGE_HV 0x0134 #define SOLO_VI_PB_HSIZE(h) ((h)<<12) #define SOLO_VI_PB_VSIZE(v) ((v)<<0) @@ -226,35 +228,35 @@ #define SOLO_VI_MOT_CTRL 0x0264 #define SOLO_VI_MOTION_FRAME_COUNT(n) ((n)<<24) #define SOLO_VI_MOTION_SAMPLE_LENGTH(n) ((n)<<16) -#define SOLO_VI_MOTION_INTR_START_STOP (1<<15) -#define SOLO_VI_MOTION_FREEZE_DATA (1<<14) +#define SOLO_VI_MOTION_INTR_START_STOP BIT(15) +#define SOLO_VI_MOTION_FREEZE_DATA BIT(14) #define SOLO_VI_MOTION_SAMPLE_COUNT(n) ((n)<<0) #define SOLO_VI_MOT_CLEAR 0x0268 #define SOLO_VI_MOT_STATUS 0x026C #define SOLO_VI_MOTION_CNT(n) ((n)<<0) #define SOLO_VI_MOTION_BORDER 0x0270 #define SOLO_VI_MOTION_BAR 0x0274 -#define SOLO_VI_MOTION_Y_SET (1<<29) -#define SOLO_VI_MOTION_Y_ADD (1<<28) -#define SOLO_VI_MOTION_CB_SET (1<<27) -#define SOLO_VI_MOTION_CB_ADD (1<<26) -#define SOLO_VI_MOTION_CR_SET (1<<25) -#define SOLO_VI_MOTION_CR_ADD (1<<24) +#define SOLO_VI_MOTION_Y_SET BIT(29) +#define SOLO_VI_MOTION_Y_ADD BIT(28) +#define SOLO_VI_MOTION_CB_SET BIT(27) +#define SOLO_VI_MOTION_CB_ADD BIT(26) +#define SOLO_VI_MOTION_CR_SET BIT(25) +#define SOLO_VI_MOTION_CR_ADD BIT(24) #define SOLO_VI_MOTION_Y_VALUE(v) ((v)<<16) #define SOLO_VI_MOTION_CB_VALUE(v) ((v)<<8) #define SOLO_VI_MOTION_CR_VALUE(v) ((v)<<0) #define SOLO_VO_FMT_ENC 0x0300 -#define SOLO_VO_SCAN_MODE_PROGRESSIVE (1<<31) -#define SOLO_VO_FMT_TYPE_PAL (1<<30) +#define SOLO_VO_SCAN_MODE_PROGRESSIVE BIT(31) +#define SOLO_VO_FMT_TYPE_PAL BIT(30) #define SOLO_VO_FMT_TYPE_NTSC 0 -#define SOLO_VO_USER_SET (1<<29) +#define SOLO_VO_USER_SET BIT(29) -#define SOLO_VO_FI_CHANGE (1<<20) -#define SOLO_VO_USER_COLOR_SET_VSYNC (1<<19) -#define SOLO_VO_USER_COLOR_SET_HSYNC (1<<18) -#define SOLO_VO_USER_COLOR_SET_NAH (1<<17) -#define SOLO_VO_USER_COLOR_SET_NAV (1<<16) +#define SOLO_VO_FI_CHANGE BIT(20) +#define SOLO_VO_USER_COLOR_SET_VSYNC BIT(19) +#define SOLO_VO_USER_COLOR_SET_HSYNC BIT(18) +#define SOLO_VO_USER_COLOR_SET_NAH BIT(17) +#define SOLO_VO_USER_COLOR_SET_NAV BIT(16) #define SOLO_VO_NA_COLOR_Y(Y) ((Y)<<8) #define SOLO_VO_NA_COLOR_CB(CB) (((CB)/16)<<4) #define SOLO_VO_NA_COLOR_CR(CR) (((CR)/16)<<0) @@ -270,32 +272,32 @@ #define SOLO_VO_V_STOP(n) ((n)<<0) #define SOLO_VO_RANGE_HV 0x030C -#define SOLO_VO_SYNC_INVERT (1<<24) -#define SOLO_VO_HSYNC_INVERT (1<<23) -#define SOLO_VO_VSYNC_INVERT (1<<22) +#define SOLO_VO_SYNC_INVERT BIT(24) +#define SOLO_VO_HSYNC_INVERT BIT(23) +#define SOLO_VO_VSYNC_INVERT BIT(22) #define SOLO_VO_H_LEN(n) ((n)<<11) #define SOLO_VO_V_LEN(n) ((n)<<0) #define SOLO_VO_DISP_CTRL 0x0310 -#define SOLO_VO_DISP_ON (1<<31) +#define SOLO_VO_DISP_ON BIT(31) #define SOLO_VO_DISP_ERASE_COUNT(n) ((n&0xf)<<24) -#define SOLO_VO_DISP_DOUBLE_SCAN (1<<22) -#define SOLO_VO_DISP_SINGLE_PAGE (1<<21) +#define SOLO_VO_DISP_DOUBLE_SCAN BIT(22) +#define SOLO_VO_DISP_SINGLE_PAGE BIT(21) #define SOLO_VO_DISP_BASE(n) (((n)>>16) & 0xffff) #define SOLO_VO_DISP_ERASE 0x0314 -#define SOLO_VO_DISP_ERASE_ON (1<<0) +#define SOLO_VO_DISP_ERASE_ON BIT(0) #define SOLO_VO_ZOOM_CTRL 0x0318 -#define SOLO_VO_ZOOM_VER_ON (1<<24) -#define SOLO_VO_ZOOM_HOR_ON (1<<23) -#define SOLO_VO_ZOOM_V_COMP (1<<22) +#define SOLO_VO_ZOOM_VER_ON BIT(24) +#define SOLO_VO_ZOOM_HOR_ON BIT(23) +#define SOLO_VO_ZOOM_V_COMP BIT(22) #define SOLO_VO_ZOOM_SX(h) (((h)/2)<<11) #define SOLO_VO_ZOOM_SY(v) (((v)/2)<<0) #define SOLO_VO_FREEZE_CTRL 0x031C -#define SOLO_VO_FREEZE_ON (1<<1) -#define SOLO_VO_FREEZE_INTERPOLATION (1<<0) +#define SOLO_VO_FREEZE_ON BIT(1) +#define SOLO_VO_FREEZE_INTERPOLATION BIT(0) #define SOLO_VO_BKG_COLOR 0x0320 #define SOLO_BG_Y(y) ((y)<<16) @@ -334,8 +336,8 @@ #define SOLO_VO_EXPANSION(id) (0x0250+((id)*4)) #define SOLO_OSG_CONFIG 0x03E0 -#define SOLO_VO_OSG_ON (1<<31) -#define SOLO_VO_OSG_COLOR_MUTE (1<<28) +#define SOLO_VO_OSG_ON BIT(31) +#define SOLO_VO_OSG_COLOR_MUTE BIT(28) #define SOLO_VO_OSG_ALPHA_RATE(n) ((n)<<22) #define SOLO_VO_OSG_ALPHA_BG_RATE(n) ((n)<<16) #define SOLO_VO_OSG_BASE(offset) (((offset)>>16)&0xffff) @@ -345,8 +347,8 @@ #define SOLO_OSG_ERASE_OFF (0x00) #define SOLO_VO_OSG_BLINK 0x03E8 -#define SOLO_VO_OSG_BLINK_ON (1<<1) -#define SOLO_VO_OSG_BLINK_INTREVAL18 (1<<0) +#define SOLO_VO_OSG_BLINK_ON BIT(1) +#define SOLO_VO_OSG_BLINK_INTREVAL18 BIT(0) #define SOLO_CAP_BASE 0x0400 #define SOLO_CAP_MAX_PAGE(n) ((n)<<16) @@ -374,19 +376,19 @@ #define SOLO_VE_CFG0 0x0610 -#define SOLO_VE_TWO_PAGE_MODE (1<<31) +#define SOLO_VE_TWO_PAGE_MODE BIT(31) #define SOLO_VE_INTR_CTRL(n) ((n)<<24) #define SOLO_VE_BLOCK_SIZE(n) ((n)<<16) #define SOLO_VE_BLOCK_BASE(n) ((n)<<0) #define SOLO_VE_CFG1 0x0614 #define SOLO_VE_BYTE_ALIGN(n) ((n)<<24) -#define SOLO_VE_INSERT_INDEX (1<<18) +#define SOLO_VE_INSERT_INDEX BIT(18) #define SOLO_VE_MOTION_MODE(n) ((n)<<16) #define SOLO_VE_MOTION_BASE(n) ((n)<<0) #define SOLO_VE_MPEG_SIZE_H(n) ((n)<<28) /* 6110 Only */ #define SOLO_VE_JPEG_SIZE_H(n) ((n)<<20) /* 6110 Only */ -#define SOLO_VE_INSERT_INDEX_JPEG (1<<19) /* 6110 Only */ +#define SOLO_VE_INSERT_INDEX_JPEG BIT(19) /* 6110 Only */ #define SOLO_VE_WMRK_POLY 0x061C #define SOLO_VE_VMRK_INIT_KEY 0x0620 @@ -394,8 +396,8 @@ #define SOLO_VE_ENCRYP_POLY 0x0628 #define SOLO_VE_ENCRYP_INIT 0x062C #define SOLO_VE_ATTR 0x0630 -#define SOLO_VE_LITTLE_ENDIAN (1<<31) -#define SOLO_COMP_ATTR_RN (1<<30) +#define SOLO_VE_LITTLE_ENDIAN BIT(31) +#define SOLO_COMP_ATTR_RN BIT(30) #define SOLO_COMP_ATTR_FCODE(n) ((n)<<27) #define SOLO_COMP_TIME_INC(n) ((n)<<25) #define SOLO_COMP_TIME_WIDTH(n) ((n)<<21) @@ -416,9 +418,9 @@ #define SOLO_VE_OSD_BASE 0x0694 #define SOLO_VE_OSD_CLR 0x0698 #define SOLO_VE_OSD_OPT 0x069C -#define SOLO_VE_OSD_V_DOUBLE (1<<16) /* 6110 Only */ -#define SOLO_VE_OSD_H_SHADOW (1<<15) -#define SOLO_VE_OSD_V_SHADOW (1<<14) +#define SOLO_VE_OSD_V_DOUBLE BIT(16) /* 6110 Only */ +#define SOLO_VE_OSD_H_SHADOW BIT(15) +#define SOLO_VE_OSD_V_SHADOW BIT(14) #define SOLO_VE_OSD_H_OFFSET(n) ((n & 0x7f)<<7) #define SOLO_VE_OSD_V_OFFSET(n) (n & 0x7f) @@ -435,18 +437,18 @@ #define SOLO_VE_JPEG_QUE(n) (0x0A04+((n)*8)) #define SOLO_VD_CFG0 0x0900 -#define SOLO_VD_CFG_NO_WRITE_NO_WINDOW (1<<24) -#define SOLO_VD_CFG_BUSY_WIAT_CODE (1<<23) -#define SOLO_VD_CFG_BUSY_WIAT_REF (1<<22) -#define SOLO_VD_CFG_BUSY_WIAT_RES (1<<21) -#define SOLO_VD_CFG_BUSY_WIAT_MS (1<<20) -#define SOLO_VD_CFG_SINGLE_MODE (1<<18) -#define SOLO_VD_CFG_SCAL_MANUAL (1<<17) -#define SOLO_VD_CFG_USER_PAGE_CTRL (1<<16) -#define SOLO_VD_CFG_LITTLE_ENDIAN (1<<15) -#define SOLO_VD_CFG_START_FI (1<<14) -#define SOLO_VD_CFG_ERR_LOCK (1<<13) -#define SOLO_VD_CFG_ERR_INT_ENA (1<<12) +#define SOLO_VD_CFG_NO_WRITE_NO_WINDOW BIT(24) +#define SOLO_VD_CFG_BUSY_WIAT_CODE BIT(23) +#define SOLO_VD_CFG_BUSY_WIAT_REF BIT(22) +#define SOLO_VD_CFG_BUSY_WIAT_RES BIT(21) +#define SOLO_VD_CFG_BUSY_WIAT_MS BIT(20) +#define SOLO_VD_CFG_SINGLE_MODE BIT(18) +#define SOLO_VD_CFG_SCAL_MANUAL BIT(17) +#define SOLO_VD_CFG_USER_PAGE_CTRL BIT(16) +#define SOLO_VD_CFG_LITTLE_ENDIAN BIT(15) +#define SOLO_VD_CFG_START_FI BIT(14) +#define SOLO_VD_CFG_ERR_LOCK BIT(13) +#define SOLO_VD_CFG_ERR_INT_ENA BIT(12) #define SOLO_VD_CFG_TIME_WIDTH(n) ((n)<<8) #define SOLO_VD_CFG_DCT_INTERVAL(n) ((n)<<0) @@ -459,37 +461,37 @@ #define SOLO_VD_CODE_ADR 0x090C #define SOLO_VD_CTRL 0x0910 -#define SOLO_VD_OPER_ON (1<<31) +#define SOLO_VD_OPER_ON BIT(31) #define SOLO_VD_MAX_ITEM(n) ((n)<<0) #define SOLO_VD_STATUS0 0x0920 -#define SOLO_VD_STATUS0_INTR_ACK (1<<22) -#define SOLO_VD_STATUS0_INTR_EMPTY (1<<21) -#define SOLO_VD_STATUS0_INTR_ERR (1<<20) +#define SOLO_VD_STATUS0_INTR_ACK BIT(22) +#define SOLO_VD_STATUS0_INTR_EMPTY BIT(21) +#define SOLO_VD_STATUS0_INTR_ERR BIT(20) #define SOLO_VD_STATUS1 0x0924 #define SOLO_VD_IDX0 0x0930 -#define SOLO_VD_IDX_INTERLACE (1<<30) +#define SOLO_VD_IDX_INTERLACE BIT(30) #define SOLO_VD_IDX_CHANNEL(n) ((n)<<24) #define SOLO_VD_IDX_SIZE(n) ((n)<<0) #define SOLO_VD_IDX1 0x0934 #define SOLO_VD_IDX_SRC_SCALE(n) ((n)<<28) #define SOLO_VD_IDX_WINDOW(n) ((n)<<24) -#define SOLO_VD_IDX_DEINTERLACE (1<<16) +#define SOLO_VD_IDX_DEINTERLACE BIT(16) #define SOLO_VD_IDX_H_BLOCK(n) ((n)<<8) #define SOLO_VD_IDX_V_BLOCK(n) ((n)<<0) #define SOLO_VD_IDX2 0x0938 -#define SOLO_VD_IDX_REF_BASE_SIDE (1<<31) +#define SOLO_VD_IDX_REF_BASE_SIDE BIT(31) #define SOLO_VD_IDX_REF_BASE(n) (((n)>>16)&0xffff) #define SOLO_VD_IDX3 0x093C #define SOLO_VD_IDX_DISP_SCALE(n) ((n)<<28) -#define SOLO_VD_IDX_INTERLACE_WR (1<<27) -#define SOLO_VD_IDX_INTERPOL (1<<26) -#define SOLO_VD_IDX_HOR2X (1<<25) +#define SOLO_VD_IDX_INTERLACE_WR BIT(27) +#define SOLO_VD_IDX_INTERPOL BIT(26) +#define SOLO_VD_IDX_HOR2X BIT(25) #define SOLO_VD_IDX_OFFSET_X(n) ((n)<<12) #define SOLO_VD_IDX_OFFSET_Y(n) ((n)<<0) @@ -511,21 +513,21 @@ #define SOLO_IIC_CFG 0x0B20 -#define SOLO_IIC_ENABLE (1<<8) +#define SOLO_IIC_ENABLE BIT(8) #define SOLO_IIC_PRESCALE(n) ((n)<<0) #define SOLO_IIC_CTRL 0x0B24 -#define SOLO_IIC_AUTO_CLEAR (1<<20) -#define SOLO_IIC_STATE_RX_ACK (1<<19) -#define SOLO_IIC_STATE_BUSY (1<<18) -#define SOLO_IIC_STATE_SIG_ERR (1<<17) -#define SOLO_IIC_STATE_TRNS (1<<16) +#define SOLO_IIC_AUTO_CLEAR BIT(20) +#define SOLO_IIC_STATE_RX_ACK BIT(19) +#define SOLO_IIC_STATE_BUSY BIT(18) +#define SOLO_IIC_STATE_SIG_ERR BIT(17) +#define SOLO_IIC_STATE_TRNS BIT(16) #define SOLO_IIC_CH_SET(n) ((n)<<5) -#define SOLO_IIC_ACK_EN (1<<4) -#define SOLO_IIC_START (1<<3) -#define SOLO_IIC_STOP (1<<2) -#define SOLO_IIC_READ (1<<1) -#define SOLO_IIC_WRITE (1<<0) +#define SOLO_IIC_ACK_EN BIT(4) +#define SOLO_IIC_START BIT(3) +#define SOLO_IIC_STOP BIT(2) +#define SOLO_IIC_READ BIT(1) +#define SOLO_IIC_WRITE BIT(0) #define SOLO_IIC_TXD 0x0B28 #define SOLO_IIC_RXD 0x0B2C @@ -535,15 +537,15 @@ */ #define SOLO_UART_CONTROL(n) (0x0BA0 + ((n)*0x20)) #define SOLO_UART_CLK_DIV(n) ((n)<<24) -#define SOLO_MODEM_CTRL_EN (1<<20) -#define SOLO_PARITY_ERROR_DROP (1<<18) -#define SOLO_IRQ_ERR_EN (1<<17) -#define SOLO_IRQ_RX_EN (1<<16) -#define SOLO_IRQ_TX_EN (1<<15) -#define SOLO_RX_EN (1<<14) -#define SOLO_TX_EN (1<<13) -#define SOLO_UART_HALF_DUPLEX (1<<12) -#define SOLO_UART_LOOPBACK (1<<11) +#define SOLO_MODEM_CTRL_EN BIT(20) +#define SOLO_PARITY_ERROR_DROP BIT(18) +#define SOLO_IRQ_ERR_EN BIT(17) +#define SOLO_IRQ_RX_EN BIT(16) +#define SOLO_IRQ_TX_EN BIT(15) +#define SOLO_RX_EN BIT(14) +#define SOLO_TX_EN BIT(13) +#define SOLO_UART_HALF_DUPLEX BIT(12) +#define SOLO_UART_LOOPBACK BIT(11) #define SOLO_BAUDRATE_230400 ((0<<9)|(0<<6)) #define SOLO_BAUDRATE_115200 ((0<<9)|(1<<6)) @@ -569,12 +571,12 @@ #define SOLO_UART_PARITY_ODD (3<<0) #define SOLO_UART_STATUS(n) (0x0BA4 + ((n)*0x20)) -#define SOLO_UART_CTS (1<<15) -#define SOLO_UART_RX_BUSY (1<<14) -#define SOLO_UART_OVERRUN (1<<13) -#define SOLO_UART_FRAME_ERR (1<<12) -#define SOLO_UART_PARITY_ERR (1<<11) -#define SOLO_UART_TX_BUSY (1<<5) +#define SOLO_UART_CTS BIT(15) +#define SOLO_UART_RX_BUSY BIT(14) +#define SOLO_UART_OVERRUN BIT(13) +#define SOLO_UART_FRAME_ERR BIT(12) +#define SOLO_UART_PARITY_ERR BIT(11) +#define SOLO_UART_TX_BUSY BIT(5) #define SOLO_UART_RX_BUFF_CNT(stat) (((stat)>>6) & 0x1f) #define SOLO_UART_RX_BUFF_SIZE 8 @@ -582,9 +584,9 @@ #define SOLO_UART_TX_BUFF_SIZE 8 #define SOLO_UART_TX_DATA(n) (0x0BA8 + ((n)*0x20)) -#define SOLO_UART_TX_DATA_PUSH (1<<8) +#define SOLO_UART_TX_DATA_PUSH BIT(8) #define SOLO_UART_RX_DATA(n) (0x0BAC + ((n)*0x20)) -#define SOLO_UART_RX_DATA_POP (1<<8) +#define SOLO_UART_RX_DATA_POP BIT(8) #define SOLO_TIMER_CLOCK_NUM 0x0be0 #define SOLO_TIMER_USEC 0x0be8 @@ -592,19 +594,19 @@ #define SOLO_TIMER_USEC_LSB 0x0d20 /* 6110 Only */ #define SOLO_AUDIO_CONTROL 0x0D00 -#define SOLO_AUDIO_ENABLE (1<<31) -#define SOLO_AUDIO_MASTER_MODE (1<<30) -#define SOLO_AUDIO_I2S_MODE (1<<29) -#define SOLO_AUDIO_I2S_LR_SWAP (1<<27) -#define SOLO_AUDIO_I2S_8BIT (1<<26) +#define SOLO_AUDIO_ENABLE BIT(31) +#define SOLO_AUDIO_MASTER_MODE BIT(30) +#define SOLO_AUDIO_I2S_MODE BIT(29) +#define SOLO_AUDIO_I2S_LR_SWAP BIT(27) +#define SOLO_AUDIO_I2S_8BIT BIT(26) #define SOLO_AUDIO_I2S_MULTI(n) ((n)<<24) -#define SOLO_AUDIO_MIX_9TO0 (1<<23) +#define SOLO_AUDIO_MIX_9TO0 BIT(23) #define SOLO_AUDIO_DEC_9TO0_VOL(n) ((n)<<20) -#define SOLO_AUDIO_MIX_19TO10 (1<<19) +#define SOLO_AUDIO_MIX_19TO10 BIT(19) #define SOLO_AUDIO_DEC_19TO10_VOL(n) ((n)<<16) #define SOLO_AUDIO_MODE(n) ((n)<<0) #define SOLO_AUDIO_SAMPLE 0x0D04 -#define SOLO_AUDIO_EE_MODE_ON (1<<30) +#define SOLO_AUDIO_EE_MODE_ON BIT(30) #define SOLO_AUDIO_EE_ENC_CH(ch) ((ch)<<25) #define SOLO_AUDIO_BITRATE(n) ((n)<<16) #define SOLO_AUDIO_CLK_DIV(n) ((n)<<0) diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index 609100a46ff842a1fec3ccf6e33a5bab0bf8f672..476d7f3b32d63a2e206f4db40301604f38d24c7a 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c @@ -822,25 +822,18 @@ static int solo_enc_enum_fmt_cap(struct file *file, void *priv, switch (dev_type) { case SOLO_DEV_6010: f->pixelformat = V4L2_PIX_FMT_MPEG4; - strscpy(f->description, "MPEG-4 part 2", - sizeof(f->description)); break; case SOLO_DEV_6110: f->pixelformat = V4L2_PIX_FMT_H264; - strscpy(f->description, "H.264", sizeof(f->description)); break; } break; case 1: f->pixelformat = V4L2_PIX_FMT_MJPEG; - strscpy(f->description, "MJPEG", sizeof(f->description)); break; default: return -EINVAL; } - - f->flags = V4L2_FMT_FLAG_COMPRESSED; - return 0; } @@ -886,7 +879,6 @@ static int solo_enc_try_fmt_cap(struct file *file, void *priv, pix->colorspace = V4L2_COLORSPACE_SMPTE170M; pix->sizeimage = FRAME_BUF_SIZE; pix->bytesperline = 0; - pix->priv = 0; return 0; } @@ -941,7 +933,6 @@ static int solo_enc_get_fmt_cap(struct file *file, void *priv, V4L2_FIELD_NONE; pix->sizeimage = FRAME_BUF_SIZE; pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - pix->priv = 0; return 0; } diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c index a968f75920b522657662eb21ca4781a08d1fc086..78792067e920f37e19c20b04ad7adfb15836d3e2 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c @@ -458,8 +458,6 @@ static int solo_enum_fmt_cap(struct file *file, void *priv, return -EINVAL; f->pixelformat = V4L2_PIX_FMT_UYVY; - strscpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description)); - return 0; } @@ -479,7 +477,6 @@ static int solo_try_fmt_cap(struct file *file, void *priv, pix->field = V4L2_FIELD_INTERLACED; pix->pixelformat = V4L2_PIX_FMT_UYVY; pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - pix->priv = 0; return 0; } @@ -509,7 +506,6 @@ static int solo_get_fmt_cap(struct file *file, void *priv, pix->sizeimage = solo_image_size(solo_dev); pix->colorspace = V4L2_COLORSPACE_SMPTE170M; pix->bytesperline = solo_bytesperline(solo_dev); - pix->priv = 0; return 0; } diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index e52e29814378cb1364e79de64ade1c4769afecd4..fd3de3bb0c89b621ba412ac8d11de4eaf62f2ec5 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -560,9 +560,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index != 0) return -EINVAL; - strscpy(f->description, "4:2:2, packed, UYVY", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_UYVY; - f->flags = 0; return 0; } diff --git a/drivers/media/pci/ttpci/av7110_hw.c b/drivers/media/pci/ttpci/av7110_hw.c index 8c2442a11f0709a4830b7e46f5bb4994fda37661..e8a8ec5405e2d2deead16144ef1512ae81ecb162 100644 --- a/drivers/media/pci/ttpci/av7110_hw.c +++ b/drivers/media/pci/ttpci/av7110_hw.c @@ -14,7 +14,6 @@ /* for debugging ARM communication: */ //#define COM_DEBUG -#include #include #include #include diff --git a/drivers/media/pci/ttpci/av7110_ir.c b/drivers/media/pci/ttpci/av7110_ir.c index 432789a3c312637d0567ed5e1dee2db25ffb030b..a851ba328e4a3e226774344c4950f86e8f51ccc5 100644 --- a/drivers/media/pci/ttpci/av7110_ir.c +++ b/drivers/media/pci/ttpci/av7110_ir.c @@ -37,12 +37,10 @@ void av7110_ir_handler(struct av7110 *av7110, u32 ircom) proto = RC_PROTO_RC5; break; - case IR_RCMM: /* RCMM: ? bits device address, ? bits command */ - command = ircom & 0xff; - addr = (ircom >> 8) & 0x1f; - scancode = ircom; + case IR_RCMM: /* RCMM: 32 bits scancode */ + scancode = ircom & ~0x8000; toggle = ircom & 0x8000; - proto = RC_PROTO_UNKNOWN; + proto = RC_PROTO_RCMM32; break; case IR_RC5_EXT: @@ -83,9 +81,9 @@ static int change_protocol(struct rc_dev *rcdev, u64 *rc_type) struct av7110 *av7110 = rcdev->priv; u32 ir_config; - if (*rc_type & RC_PROTO_BIT_UNKNOWN) { + if (*rc_type & RC_PROTO_BIT_RCMM32) { ir_config = IR_RCMM; - *rc_type = RC_PROTO_UNKNOWN; + *rc_type = RC_PROTO_BIT_RCMM32; } else if (*rc_type & RC_PROTO_BIT_RC5) { if (FW_VERSION(av7110->arm_app) >= 0x2620) ir_config = IR_RC5_EXT; @@ -133,7 +131,7 @@ int av7110_ir_init(struct av7110 *av7110) } rcdev->dev.parent = &pci->dev; - rcdev->allowed_protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_UNKNOWN; + rcdev->allowed_protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RCMM32; rcdev->change_protocol = change_protocol; rcdev->map_name = RC_MAP_HAUPPAUGE; rcdev->priv = av7110; diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 8e0952d65ad4f9f8e19d53767de98b030b673849..2fb82d50c53e52786e8d1a951ee7dbb0dcd0305f 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -34,53 +34,43 @@ */ static const struct tw68_format formats[] = { { - .name = "15 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB555, .depth = 16, .twformat = ColorFormatRGB15, }, { - .name = "15 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB555X, .depth = 16, .twformat = ColorFormatRGB15 | ColorFormatBSWAP, }, { - .name = "16 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB565, .depth = 16, .twformat = ColorFormatRGB16, }, { - .name = "16 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB565X, .depth = 16, .twformat = ColorFormatRGB16 | ColorFormatBSWAP, }, { - .name = "24 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR24, .depth = 24, .twformat = ColorFormatRGB24, }, { - .name = "24 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB24, .depth = 24, .twformat = ColorFormatRGB24 | ColorFormatBSWAP, }, { - .name = "32 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR32, .depth = 32, .twformat = ColorFormatRGB32, }, { - .name = "32 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB32, .depth = 32, .twformat = ColorFormatRGB32 | ColorFormatBSWAP | ColorFormatWSWAP, }, { - .name = "4:2:2 packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .twformat = ColorFormatYUY2, }, { - .name = "4:2:2 packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, .depth = 16, .twformat = ColorFormatYUY2 | ColorFormatBSWAP, @@ -592,7 +582,6 @@ static int tw68_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.priv = 0; return 0; } @@ -774,9 +763,6 @@ static int tw68_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index >= FORMATS) return -EINVAL; - strscpy(f->description, formats[f->index].name, - sizeof(f->description)); - f->pixelformat = formats[f->index].fourcc; return 0; diff --git a/drivers/media/pci/tw68/tw68.h b/drivers/media/pci/tw68/tw68.h index 7021290d726a070f0623b602b742b193956c406a..a1f422d6e600e0a961c7246b20bd7c944feb45ad 100644 --- a/drivers/media/pci/tw68/tw68.h +++ b/drivers/media/pci/tw68/tw68.h @@ -85,7 +85,6 @@ struct tw68_tvnorm { }; struct tw68_format { - char *name; u32 fourcc; u32 depth; u32 twformat; diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 8a19654b393a92033fc746e06e4ef99687656551..83a785010753bc31ed997c91bcd457710d57463f 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -16,7 +16,7 @@ source "drivers/media/platform/marvell-ccic/Kconfig" config VIDEO_VIA_CAMERA tristate "VIAFB camera controller support" depends on FB_VIA - select VIDEOBUF_DMA_SG + select VIDEOBUF2_DMA_SG select VIDEO_OV7670 help Driver support for the integrated camera controller in VIA @@ -121,7 +121,7 @@ config VIDEO_S3C_CAMIF config VIDEO_STM32_DCMI tristate "STM32 Digital Camera Memory Interface (DCMI) support" - depends on VIDEO_V4L2 && OF + depends on VIDEO_V4L2 && OF && MEDIA_CONTROLLER depends on ARCH_STM32 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE @@ -146,7 +146,7 @@ source "drivers/media/platform/am437x/Kconfig" source "drivers/media/platform/xilinx/Kconfig" source "drivers/media/platform/rcar-vin/Kconfig" source "drivers/media/platform/atmel/Kconfig" -source "drivers/media/platform/sunxi/sun6i-csi/Kconfig" +source "drivers/media/platform/sunxi/Kconfig" config VIDEO_TI_CAL tristate "TI CAL (Camera Adaptation Layer) driver" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 7cbbd925124cfe3a21aa0e8871a57beaaf93582b..6ee7eb0d36f432f0ac9eb48e6553b05a09029aa1 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -100,4 +100,4 @@ obj-y += meson/ obj-y += cros-ec-cec/ -obj-$(CONFIG_VIDEO_SUN6I_CSI) += sunxi/sun6i-csi/ +obj-y += sunxi/ diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index fe7b937eb5f2a418e860c2131e00e23f4ffa0489..2b42ba1f59494a1e4248e300329999dda629a671 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -76,7 +76,6 @@ struct bus_format { /* * struct vpfe_fmt - VPFE media bus format information - * @name: V4L2 format description * @code: V4L2 media bus format code * @shifted: V4L2 media bus format code for the same pixel layout but * shifted to be 8 bits per pixel. =0 if format is not shiftable. @@ -86,7 +85,6 @@ struct bus_format { * @supported: Indicates format supported by subdev */ struct vpfe_fmt { - const char *name; u32 fourcc; u32 code; struct bus_format l; @@ -97,7 +95,6 @@ struct vpfe_fmt { static struct vpfe_fmt formats[] = { { - .name = "YUV 4:2:2 packed, YCbYCr", .fourcc = V4L2_PIX_FMT_YUYV, .code = MEDIA_BUS_FMT_YUYV8_2X8, .l.width = 10, @@ -106,7 +103,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 2, .supported = false, }, { - .name = "YUV 4:2:2 packed, CbYCrY", .fourcc = V4L2_PIX_FMT_UYVY, .code = MEDIA_BUS_FMT_UYVY8_2X8, .l.width = 10, @@ -115,7 +111,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 2, .supported = false, }, { - .name = "YUV 4:2:2 packed, YCrYCb", .fourcc = V4L2_PIX_FMT_YVYU, .code = MEDIA_BUS_FMT_YVYU8_2X8, .l.width = 10, @@ -124,7 +119,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 2, .supported = false, }, { - .name = "YUV 4:2:2 packed, CrYCbY", .fourcc = V4L2_PIX_FMT_VYUY, .code = MEDIA_BUS_FMT_VYUY8_2X8, .l.width = 10, @@ -133,7 +127,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 2, .supported = false, }, { - .name = "RAW8 BGGR", .fourcc = V4L2_PIX_FMT_SBGGR8, .code = MEDIA_BUS_FMT_SBGGR8_1X8, .l.width = 10, @@ -142,7 +135,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 1, .supported = false, }, { - .name = "RAW8 GBRG", .fourcc = V4L2_PIX_FMT_SGBRG8, .code = MEDIA_BUS_FMT_SGBRG8_1X8, .l.width = 10, @@ -151,7 +143,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 1, .supported = false, }, { - .name = "RAW8 GRBG", .fourcc = V4L2_PIX_FMT_SGRBG8, .code = MEDIA_BUS_FMT_SGRBG8_1X8, .l.width = 10, @@ -160,7 +151,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 1, .supported = false, }, { - .name = "RAW8 RGGB", .fourcc = V4L2_PIX_FMT_SRGGB8, .code = MEDIA_BUS_FMT_SRGGB8_1X8, .l.width = 10, @@ -169,7 +159,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 1, .supported = false, }, { - .name = "RGB565 (LE)", .fourcc = V4L2_PIX_FMT_RGB565, .code = MEDIA_BUS_FMT_RGB565_2X8_LE, .l.width = 10, @@ -178,7 +167,6 @@ static struct vpfe_fmt formats[] = { .s.bpp = 2, .supported = false, }, { - .name = "RGB565 (BE)", .fourcc = V4L2_PIX_FMT_RGB565X, .code = MEDIA_BUS_FMT_RGB565_2X8_BE, .l.width = 10, @@ -1412,10 +1400,6 @@ static int vpfe_querycap(struct file *file, void *priv, strscpy(cap->card, "TI AM437x VPFE", sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", vpfe->v4l2_dev.name); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -1540,12 +1524,10 @@ static int vpfe_enum_fmt(struct file *file, void *priv, if (!fmt) return -EINVAL; - strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; - f->type = vpfe->fmt.type; - vpfe_dbg(1, vpfe, "vpfe_enum_format: mbus index: %d code: %x pixelformat: %s [%s]\n", - f->index, fmt->code, print_fourcc(fmt->fourcc), fmt->name); + vpfe_dbg(1, vpfe, "vpfe_enum_format: mbus index: %d code: %x pixelformat: %s\n", + f->index, fmt->code, print_fourcc(fmt->fourcc)); return 0; } @@ -2393,6 +2375,8 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe) vdev->vfl_dir = VFL_DIR_RX; vdev->queue = q; vdev->lock = &vpfe->lock; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; video_set_drvdata(vdev, vpfe); err = video_register_device(&vpfe->video_dev, VFL_TYPE_GRABBER, -1); if (err) { @@ -2505,10 +2489,9 @@ vpfe_get_pdata(struct vpfe_device *vpfe) pdata->asd[i] = v4l2_async_notifier_add_fwnode_subdev( &vpfe->notifier, of_fwnode_handle(rem), sizeof(struct v4l2_async_subdev)); - if (IS_ERR(pdata->asd[i])) { - of_node_put(rem); + of_node_put(rem); + if (IS_ERR(pdata->asd[i])) goto cleanup; - } } of_node_put(endpoint); @@ -2557,7 +2540,6 @@ static int vpfe_probe(struct platform_device *pdev) ret = platform_get_irq(pdev, 0); if (ret <= 0) { - dev_err(&pdev->dev, "No IRQ resource\n"); ret = -ENODEV; goto probe_out_cleanup; } diff --git a/drivers/media/platform/am437x/am437x-vpfe.h b/drivers/media/platform/am437x/am437x-vpfe.h index 17d7aa426788b77e7aaaa1da4c5df259dfd4b2d0..4678285f34c6b4218de6e87ab941b001c0e463f8 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.h +++ b/drivers/media/platform/am437x/am437x-vpfe.h @@ -65,12 +65,6 @@ struct vpfe_hw_if_param { #define VPFE_MAX_SUBDEV 1 #define VPFE_MAX_INPUTS 1 -struct vpfe_pixel_format { - struct v4l2_fmtdesc fmtdesc; - /* bytes per pixel */ - int bpp; -}; - struct vpfe_std_info { int active_pixels; int active_lines; diff --git a/drivers/media/platform/am437x/am437x-vpfe_regs.h b/drivers/media/platform/am437x/am437x-vpfe_regs.h index 4a0ed29723e85e8aa98ef17b701cc79cd537fe7d..0746c48ec23ff95f730f247eeca2198c17b6db69 100644 --- a/drivers/media/platform/am437x/am437x-vpfe_regs.h +++ b/drivers/media/platform/am437x/am437x-vpfe_regs.h @@ -66,13 +66,13 @@ #define VPFE_PIX_FMT_MASK 3 #define VPFE_PIX_FMT_SHIFT 12 #define VPFE_VP2SDR_DISABLE 0xfffbffff -#define VPFE_WEN_ENABLE (1 << 17) +#define VPFE_WEN_ENABLE BIT(17) #define VPFE_SDR2RSZ_DISABLE 0xfff7ffff -#define VPFE_VDHDEN_ENABLE (1 << 16) -#define VPFE_LPF_ENABLE (1 << 14) -#define VPFE_ALAW_ENABLE (1 << 3) +#define VPFE_VDHDEN_ENABLE BIT(16) +#define VPFE_LPF_ENABLE BIT(14) +#define VPFE_ALAW_ENABLE BIT(3) #define VPFE_ALAW_GAMMA_WD_MASK 7 -#define VPFE_BLK_CLAMP_ENABLE (1 << 31) +#define VPFE_BLK_CLAMP_ENABLE BIT(31) #define VPFE_BLK_SGAIN_MASK 0x1f #define VPFE_BLK_ST_PXL_MASK 0x7fff #define VPFE_BLK_ST_PXL_SHIFT 10 @@ -85,8 +85,8 @@ #define VPFE_BLK_COMP_GB_COMP_SHIFT 8 #define VPFE_BLK_COMP_GR_COMP_SHIFT 16 #define VPFE_BLK_COMP_R_COMP_SHIFT 24 -#define VPFE_LATCH_ON_VSYNC_DISABLE (1 << 15) -#define VPFE_DATA_PACK_ENABLE (1 << 11) +#define VPFE_LATCH_ON_VSYNC_DISABLE BIT(15) +#define VPFE_DATA_PACK_ENABLE BIT(11) #define VPFE_HORZ_INFO_SPH_SHIFT 16 #define VPFE_VERT_START_SLV0_SHIFT 16 #define VPFE_VDINT_VDINT0_SHIFT 16 @@ -114,15 +114,15 @@ #define VPFE_SYN_FLDMODE_MASK 1 #define VPFE_SYN_FLDMODE_SHIFT 7 #define VPFE_REC656IF_BT656_EN 3 -#define VPFE_SYN_MODE_VD_POL_NEGATIVE (1 << 2) +#define VPFE_SYN_MODE_VD_POL_NEGATIVE BIT(2) #define VPFE_CCDCFG_Y8POS_SHIFT 11 -#define VPFE_CCDCFG_BW656_10BIT (1 << 5) +#define VPFE_CCDCFG_BW656_10BIT BIT(5) #define VPFE_SDOFST_FIELD_INTERLEAVED 0x249 #define VPFE_NO_CULLING 0xffff00ff -#define VPFE_VDINT0 (1 << 0) -#define VPFE_VDINT1 (1 << 1) -#define VPFE_VDINT2 (1 << 2) -#define VPFE_DMA_CNTL_OVERFLOW (1 << 31) +#define VPFE_VDINT0 BIT(0) +#define VPFE_VDINT1 BIT(1) +#define VPFE_VDINT2 BIT(2) +#define VPFE_DMA_CNTL_OVERFLOW BIT(31) #define VPFE_CONFIG_PCLK_INV_SHIFT 0 #define VPFE_CONFIG_PCLK_INV_MASK 1 diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index f899ac3b4a6139b0337751cfca4cdff097b04364..eb12f37930629983a06a43eeac0958e7228f2503 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -630,7 +630,7 @@ static void aspeed_video_check_and_set_polarity(struct aspeed_video *video) } if (hsync_counter < 0 || vsync_counter < 0) { - u32 ctrl; + u32 ctrl = 0; if (hsync_counter < 0) { ctrl = VE_CTRL_HSYNC_POL; @@ -650,7 +650,8 @@ static void aspeed_video_check_and_set_polarity(struct aspeed_video *video) V4L2_DV_VSYNC_POS_POL; } - aspeed_video_update(video, VE_CTRL, 0, ctrl); + if (ctrl) + aspeed_video_update(video, VE_CTRL, 0, ctrl); } } @@ -1624,6 +1625,7 @@ static int aspeed_video_init(struct aspeed_video *video) if (!aspeed_video_alloc_buf(video, &video->jpeg, VE_JPEG_HEADER_SIZE)) { dev_err(dev, "Failed to allocate DMA for JPEG header\n"); + rc = -ENOMEM; goto err_release_reserved_mem; } diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index d7d94c1a39d35279a50985bafb071878ac03eb3a..428f117caa59970d247d74cf51e38f2d51d1efda 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -493,7 +493,7 @@ static void stop_streaming(struct vb2_queue *vq) spin_unlock_irq(&isi->irqlock); if (!isi->enable_preview_path) { - timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; + timeout = jiffies + (FRAME_INTERVAL_MILLI_SEC * HZ) / 1000; /* Wait until the end of the current frame. */ while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) && time_before(jiffies, timeout)) diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/media/platform/atmel/atmel-sama5d2-isc.c index 266df14da2d5ee4dcc6a8fd0111382ed16cc036a..78381651238dd7410b5292809b71f332a7de6554 100644 --- a/drivers/media/platform/atmel/atmel-sama5d2-isc.c +++ b/drivers/media/platform/atmel/atmel-sama5d2-isc.c @@ -160,11 +160,8 @@ static int atmel_isc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - dev_err(dev, "failed to get irq: %d\n", ret); - return ret; - } + if (irq < 0) + return irq; ret = devm_request_irq(dev, irq, isc_interrupt, 0, ATMEL_ISC_NAME, isc); diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c index 5042d053b94e21c1f02ddb31e034b6d19de62a6d..e4d08acfbb49f095e0dbc079d0e80b679111b288 100644 --- a/drivers/media/platform/cadence/cdns-csi2tx.c +++ b/drivers/media/platform/cadence/cdns-csi2tx.c @@ -2,7 +2,7 @@ /* * Driver for Cadence MIPI-CSI2 TX Controller * - * Copyright (C) 2017-2018 Cadence Design Systems Inc. + * Copyright (C) 2017-2019 Cadence Design Systems Inc. */ #include @@ -52,6 +52,17 @@ #define CSI2TX_STREAM_IF_CFG_REG(n) (0x100 + (n) * 4) #define CSI2TX_STREAM_IF_CFG_FILL_LEVEL(n) ((n) & 0x1f) +/* CSI2TX V2 Registers */ +#define CSI2TX_V2_DPHY_CFG_REG 0x28 +#define CSI2TX_V2_DPHY_CFG_RESET BIT(16) +#define CSI2TX_V2_DPHY_CFG_CLOCK_MODE BIT(10) +#define CSI2TX_V2_DPHY_CFG_MODE_MASK GENMASK(9, 8) +#define CSI2TX_V2_DPHY_CFG_MODE_LPDT (2 << 8) +#define CSI2TX_V2_DPHY_CFG_MODE_HS (1 << 8) +#define CSI2TX_V2_DPHY_CFG_MODE_ULPS (0 << 8) +#define CSI2TX_V2_DPHY_CFG_CLK_ENABLE BIT(4) +#define CSI2TX_V2_DPHY_CFG_LANE_ENABLE(n) BIT(n) + #define CSI2TX_LANES_MAX 4 #define CSI2TX_STREAMS_MAX 4 @@ -70,6 +81,13 @@ struct csi2tx_fmt { u32 bpp; }; +struct csi2tx_priv; + +/* CSI2TX Variant Operations */ +struct csi2tx_vops { + void (*dphy_setup)(struct csi2tx_priv *csi2tx); +}; + struct csi2tx_priv { struct device *dev; unsigned int count; @@ -82,6 +100,8 @@ struct csi2tx_priv { void __iomem *base; + struct csi2tx_vops *vops; + struct clk *esc_clk; struct clk *p_clk; struct clk *pixel_clk[CSI2TX_STREAMS_MAX]; @@ -209,53 +229,92 @@ static const struct v4l2_subdev_pad_ops csi2tx_pad_ops = { .set_fmt = csi2tx_set_pad_format, }; -static void csi2tx_reset(struct csi2tx_priv *csi2tx) +/* Set Wake Up value in the D-PHY */ +static void csi2tx_dphy_set_wakeup(struct csi2tx_priv *csi2tx) { - writel(CSI2TX_CONFIG_SRST_REQ, csi2tx->base + CSI2TX_CONFIG_REG); - - udelay(10); + writel(CSI2TX_DPHY_CLK_WAKEUP_ULPS_CYCLES(32), + csi2tx->base + CSI2TX_DPHY_CLK_WAKEUP_REG); } -static int csi2tx_start(struct csi2tx_priv *csi2tx) +/* + * Finishes the D-PHY initialization + * reg dphy cfg value to be used + */ +static void csi2tx_dphy_init_finish(struct csi2tx_priv *csi2tx, u32 reg) { - struct media_entity *entity = &csi2tx->subdev.entity; - struct media_link *link; unsigned int i; - u32 reg; - csi2tx_reset(csi2tx); + udelay(10); - writel(CSI2TX_CONFIG_CFG_REQ, csi2tx->base + CSI2TX_CONFIG_REG); + /* Enable our (clock and data) lanes */ + reg |= CSI2TX_DPHY_CFG_CLK_ENABLE; + for (i = 0; i < csi2tx->num_lanes; i++) + reg |= CSI2TX_DPHY_CFG_LANE_ENABLE(csi2tx->lanes[i] - 1); + writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG); udelay(10); - /* Configure our PPI interface with the D-PHY */ - writel(CSI2TX_DPHY_CLK_WAKEUP_ULPS_CYCLES(32), - csi2tx->base + CSI2TX_DPHY_CLK_WAKEUP_REG); + /* Switch to HS mode */ + reg &= ~CSI2TX_DPHY_CFG_MODE_MASK; + writel(reg | CSI2TX_DPHY_CFG_MODE_HS, + csi2tx->base + CSI2TX_DPHY_CFG_REG); +} + +/* Configures D-PHY in CSIv1.3 */ +static void csi2tx_dphy_setup(struct csi2tx_priv *csi2tx) +{ + u32 reg; + unsigned int i; + + csi2tx_dphy_set_wakeup(csi2tx); /* Put our lanes (clock and data) out of reset */ reg = CSI2TX_DPHY_CFG_CLK_RESET | CSI2TX_DPHY_CFG_MODE_LPDT; for (i = 0; i < csi2tx->num_lanes; i++) - reg |= CSI2TX_DPHY_CFG_LANE_RESET(csi2tx->lanes[i]); + reg |= CSI2TX_DPHY_CFG_LANE_RESET(csi2tx->lanes[i] - 1); writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG); - udelay(10); + csi2tx_dphy_init_finish(csi2tx, reg); +} - /* Enable our (clock and data) lanes */ - reg |= CSI2TX_DPHY_CFG_CLK_ENABLE; - for (i = 0; i < csi2tx->num_lanes; i++) - reg |= CSI2TX_DPHY_CFG_LANE_ENABLE(csi2tx->lanes[i]); - writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG); +/* Configures D-PHY in CSIv2 */ +static void csi2tx_v2_dphy_setup(struct csi2tx_priv *csi2tx) +{ + u32 reg; + + csi2tx_dphy_set_wakeup(csi2tx); + + /* Put our lanes (clock and data) out of reset */ + reg = CSI2TX_V2_DPHY_CFG_RESET | CSI2TX_V2_DPHY_CFG_MODE_LPDT; + writel(reg, csi2tx->base + CSI2TX_V2_DPHY_CFG_REG); + + csi2tx_dphy_init_finish(csi2tx, reg); +} + +static void csi2tx_reset(struct csi2tx_priv *csi2tx) +{ + writel(CSI2TX_CONFIG_SRST_REQ, csi2tx->base + CSI2TX_CONFIG_REG); udelay(10); +} - /* Switch to HS mode */ - reg &= ~CSI2TX_DPHY_CFG_MODE_MASK; - writel(reg | CSI2TX_DPHY_CFG_MODE_HS, - csi2tx->base + CSI2TX_DPHY_CFG_REG); +static int csi2tx_start(struct csi2tx_priv *csi2tx) +{ + struct media_entity *entity = &csi2tx->subdev.entity; + struct media_link *link; + unsigned int i; + + csi2tx_reset(csi2tx); + + writel(CSI2TX_CONFIG_CFG_REQ, csi2tx->base + CSI2TX_CONFIG_REG); udelay(10); + if (csi2tx->vops && csi2tx->vops->dphy_setup) { + csi2tx->vops->dphy_setup(csi2tx); + udelay(10); + } + /* * Create a static mapping between the CSI virtual channels * and the input streams. @@ -434,7 +493,7 @@ static int csi2tx_check_lanes(struct csi2tx_priv *csi2tx) { struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 }; struct device_node *ep; - int ret; + int ret, i; ep = of_graph_get_endpoint_by_regs(csi2tx->dev->of_node, 0, 0); if (!ep) @@ -461,6 +520,15 @@ static int csi2tx_check_lanes(struct csi2tx_priv *csi2tx) goto out; } + for (i = 0; i < csi2tx->num_lanes; i++) { + if (v4l2_ep.bus.mipi_csi2.data_lanes[i] < 1) { + dev_err(csi2tx->dev, "Invalid lane[%d] number: %u\n", + i, v4l2_ep.bus.mipi_csi2.data_lanes[i]); + ret = -EINVAL; + goto out; + } + } + memcpy(csi2tx->lanes, v4l2_ep.bus.mipi_csi2.data_lanes, sizeof(csi2tx->lanes)); @@ -469,9 +537,35 @@ static int csi2tx_check_lanes(struct csi2tx_priv *csi2tx) return ret; } +static const struct csi2tx_vops csi2tx_vops = { + .dphy_setup = csi2tx_dphy_setup, +}; + +static const struct csi2tx_vops csi2tx_v2_vops = { + .dphy_setup = csi2tx_v2_dphy_setup, +}; + +static const struct of_device_id csi2tx_of_table[] = { + { + .compatible = "cdns,csi2tx", + .data = &csi2tx_vops + }, + { + .compatible = "cdns,csi2tx-1.3", + .data = &csi2tx_vops + }, + { + .compatible = "cdns,csi2tx-2.1", + .data = &csi2tx_v2_vops + }, + { } +}; +MODULE_DEVICE_TABLE(of, csi2tx_of_table); + static int csi2tx_probe(struct platform_device *pdev) { struct csi2tx_priv *csi2tx; + const struct of_device_id *of_id; unsigned int i; int ret; @@ -486,6 +580,9 @@ static int csi2tx_probe(struct platform_device *pdev) if (ret) goto err_free_priv; + of_id = of_match_node(csi2tx_of_table, pdev->dev.of_node); + csi2tx->vops = (struct csi2tx_vops *)of_id->data; + v4l2_subdev_init(&csi2tx->subdev, &csi2tx_subdev_ops); csi2tx->subdev.owner = THIS_MODULE; csi2tx->subdev.dev = &pdev->dev; @@ -543,12 +640,6 @@ static int csi2tx_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id csi2tx_of_table[] = { - { .compatible = "cdns,csi2tx" }, - { }, -}; -MODULE_DEVICE_TABLE(of, csi2tx_of_table); - static struct platform_driver csi2tx_driver = { .probe = csi2tx_probe, .remove = csi2tx_remove, diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 01428de2596e694e756d9fc2e5e5788ee614b29e..73222c0615c0c1023b33f6837ed88835636c5ddb 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -390,9 +390,6 @@ static int coda_querycap(struct file *file, void *priv, strscpy(cap->card, coda_product_name(ctx->dev->devtype->product), sizeof(cap->card)); strscpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -2699,6 +2696,7 @@ static int coda_register_device(struct coda_dev *dev, int i) vfd->lock = &dev->dev_mutex; vfd->v4l2_dev = &dev->v4l2_dev; vfd->vfl_dir = VFL_DIR_M2M; + vfd->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; video_set_drvdata(vfd, dev); /* Not applicable, use the selection API instead */ diff --git a/drivers/media/platform/cros-ec-cec/cros-ec-cec.c b/drivers/media/platform/cros-ec-cec/cros-ec-cec.c index 068df9888dbf03001af6e4b814819dd105cf7f3e..76ab83f55cc070a0648cf59806a69bb81c5b9fee 100644 --- a/drivers/media/platform/cros-ec-cec/cros-ec-cec.c +++ b/drivers/media/platform/cros-ec-cec/cros-ec-cec.c @@ -206,10 +206,10 @@ static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops, */ struct cec_dmi_match { - char *sys_vendor; - char *product_name; - char *devname; - char *conn; + const char *sys_vendor; + const char *product_name; + const char *devname; + const char *conn; }; static const struct cec_dmi_match cec_dmi_match_table[] = { @@ -217,8 +217,8 @@ static const struct cec_dmi_match cec_dmi_match_table[] = { { "Google", "Fizz", "0000:00:02.0", "Port B" }, }; -static int cros_ec_cec_get_notifier(struct device *dev, - struct cec_notifier **notify) +static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, + const char **conn) { int i; @@ -233,26 +233,25 @@ static int cros_ec_cec_get_notifier(struct device *dev, d = bus_find_device_by_name(&pci_bus_type, NULL, m->devname); if (!d) - return -EPROBE_DEFER; - - *notify = cec_notifier_get_conn(d, m->conn); + return ERR_PTR(-EPROBE_DEFER); put_device(d); - return 0; + *conn = m->conn; + return d; } } /* Hardware support must be added in the cec_dmi_match_table */ dev_warn(dev, "CEC notifier not configured for this hardware\n"); - return -ENODEV; + return ERR_PTR(-ENODEV); } #else -static int cros_ec_cec_get_notifier(struct device *dev, - struct cec_notifier **notify) +static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, + const char **conn) { - return -ENODEV; + return ERR_PTR(-ENODEV); } #endif @@ -262,8 +261,14 @@ static int cros_ec_cec_probe(struct platform_device *pdev) struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); struct cros_ec_device *cros_ec = ec_dev->ec_dev; struct cros_ec_cec *cros_ec_cec; + struct device *hdmi_dev; + const char *conn = NULL; int ret; + hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conn); + if (IS_ERR(hdmi_dev)) + return PTR_ERR(hdmi_dev); + cros_ec_cec = devm_kzalloc(&pdev->dev, sizeof(*cros_ec_cec), GFP_KERNEL); if (!cros_ec_cec) @@ -272,10 +277,6 @@ static int cros_ec_cec_probe(struct platform_device *pdev) platform_set_drvdata(pdev, cros_ec_cec); cros_ec_cec->cros_ec = cros_ec; - ret = cros_ec_cec_get_notifier(&pdev->dev, &cros_ec_cec->notify); - if (ret) - return ret; - ret = device_init_wakeup(&pdev->dev, 1); if (ret) { dev_err(&pdev->dev, "failed to initialize wakeup\n"); @@ -283,29 +284,39 @@ static int cros_ec_cec_probe(struct platform_device *pdev) } cros_ec_cec->adap = cec_allocate_adapter(&cros_ec_cec_ops, cros_ec_cec, - DRV_NAME, CEC_CAP_DEFAULTS, 1); + DRV_NAME, + CEC_CAP_DEFAULTS | + CEC_CAP_CONNECTOR_INFO, 1); if (IS_ERR(cros_ec_cec->adap)) return PTR_ERR(cros_ec_cec->adap); + cros_ec_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, conn, + cros_ec_cec->adap); + if (!cros_ec_cec->notify) { + ret = -ENOMEM; + goto out_probe_adapter; + } + /* Get CEC events from the EC. */ cros_ec_cec->notifier.notifier_call = cros_ec_cec_event; ret = blocking_notifier_chain_register(&cros_ec->event_notifier, &cros_ec_cec->notifier); if (ret) { dev_err(&pdev->dev, "failed to register notifier\n"); - cec_delete_adapter(cros_ec_cec->adap); - return ret; + goto out_probe_notify; } ret = cec_register_adapter(cros_ec_cec->adap, &pdev->dev); - if (ret < 0) { - cec_delete_adapter(cros_ec_cec->adap); - return ret; - } - - cec_register_cec_notifier(cros_ec_cec->adap, cros_ec_cec->notify); + if (ret < 0) + goto out_probe_notify; return 0; + +out_probe_notify: + cec_notifier_cec_adap_unregister(cros_ec_cec->notify); +out_probe_adapter: + cec_delete_adapter(cros_ec_cec->adap); + return ret; } static int cros_ec_cec_remove(struct platform_device *pdev) @@ -323,11 +334,9 @@ static int cros_ec_cec_remove(struct platform_device *pdev) return ret; } + cec_notifier_cec_adap_unregister(cros_ec_cec->notify); cec_unregister_adapter(cros_ec_cec->adap); - if (cros_ec_cec->notify) - cec_notifier_put(cros_ec_cec->notify); - return 0; } diff --git a/drivers/media/platform/davinci/dm644x_ccdc_regs.h b/drivers/media/platform/davinci/dm644x_ccdc_regs.h index 3ae301320313316975a08a654bb46f4192425fd5..c4894f6a254e4e9ec8f9845bc85b1a82e1d00bb8 100644 --- a/drivers/media/platform/davinci/dm644x_ccdc_regs.h +++ b/drivers/media/platform/davinci/dm644x_ccdc_regs.h @@ -66,13 +66,13 @@ #define CCDC_PIX_FMT_MASK 3 #define CCDC_PIX_FMT_SHIFT 12 #define CCDC_VP2SDR_DISABLE 0xFFFBFFFF -#define CCDC_WEN_ENABLE (1 << 17) +#define CCDC_WEN_ENABLE BIT(17) #define CCDC_SDR2RSZ_DISABLE 0xFFF7FFFF -#define CCDC_VDHDEN_ENABLE (1 << 16) -#define CCDC_LPF_ENABLE (1 << 14) -#define CCDC_ALAW_ENABLE (1 << 3) +#define CCDC_VDHDEN_ENABLE BIT(16) +#define CCDC_LPF_ENABLE BIT(14) +#define CCDC_ALAW_ENABLE BIT(3) #define CCDC_ALAW_GAMMA_WD_MASK 7 -#define CCDC_BLK_CLAMP_ENABLE (1 << 31) +#define CCDC_BLK_CLAMP_ENABLE BIT(31) #define CCDC_BLK_SGAIN_MASK 0x1F #define CCDC_BLK_ST_PXL_MASK 0x7FFF #define CCDC_BLK_ST_PXL_SHIFT 10 @@ -85,11 +85,11 @@ #define CCDC_BLK_COMP_GB_COMP_SHIFT 8 #define CCDC_BLK_COMP_GR_COMP_SHIFT 16 #define CCDC_BLK_COMP_R_COMP_SHIFT 24 -#define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15) -#define CCDC_FPC_ENABLE (1 << 15) +#define CCDC_LATCH_ON_VSYNC_DISABLE BIT(15) +#define CCDC_FPC_ENABLE BIT(15) #define CCDC_FPC_DISABLE 0 #define CCDC_FPC_FPC_NUM_MASK 0x7FFF -#define CCDC_DATA_PACK_ENABLE (1 << 11) +#define CCDC_DATA_PACK_ENABLE BIT(11) #define CCDC_FMTCFG_VPIN_MASK 7 #define CCDC_FMTCFG_VPIN_SHIFT 12 #define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF @@ -132,9 +132,9 @@ #define CCDC_SYN_FLDMODE_MASK 1 #define CCDC_SYN_FLDMODE_SHIFT 7 #define CCDC_REC656IF_BT656_EN 3 -#define CCDC_SYN_MODE_VD_POL_NEGATIVE (1 << 2) +#define CCDC_SYN_MODE_VD_POL_NEGATIVE BIT(2) #define CCDC_CCDCFG_Y8POS_SHIFT 11 -#define CCDC_CCDCFG_BW656_10BIT (1 << 5) +#define CCDC_CCDCFG_BW656_10BIT BIT(5) #define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 #define CCDC_NO_CULLING 0xffff00ff #endif diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 000b191c42d8ce0377cdebfa7b49a7ce4934473b..ae419958e4204d2749f090c4140ed2a265bb0e95 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -19,10 +19,6 @@ #include -#ifdef CONFIG_ARCH_DAVINCI -#include -#endif - #include #include #include @@ -633,8 +629,6 @@ static int vpbe_display_querycap(struct file *file, void *priv, struct vpbe_layer *layer = video_drvdata(file); struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; snprintf(cap->driver, sizeof(cap->driver), "%s", dev_name(vpbe_dev->pdev)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", @@ -792,7 +786,6 @@ static int vpbe_display_enum_fmt(struct file *file, void *priv, { struct vpbe_layer *layer = video_drvdata(file); struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - unsigned int index = 0; v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_FMT, layer id = %d\n", @@ -803,19 +796,10 @@ static int vpbe_display_enum_fmt(struct file *file, void *priv, } /* Fill in the information about format */ - index = fmt->index; - memset(fmt, 0, sizeof(*fmt)); - fmt->index = index; - fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - if (index == 0) { - strscpy(fmt->description, "YUV 4:2:2 - UYVY", - sizeof(fmt->description)); + if (fmt->index == 0) fmt->pixelformat = V4L2_PIX_FMT_UYVY; - } else { - strscpy(fmt->description, "Y/CbCr 4:2:0", - sizeof(fmt->description)); + else fmt->pixelformat = V4L2_PIX_FMT_NV12; - } return 0; } @@ -1319,6 +1303,7 @@ static int init_vpbe_layer(int i, struct vpbe_display *disp_dev, vbd->v4l2_dev = &disp_dev->vpbe_dev->v4l2_dev; vbd->lock = &vpbe_display_layer->opslock; vbd->vfl_dir = VFL_DIR_TX; + vbd->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; if (disp_dev->vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) diff --git a/drivers/media/platform/davinci/vpbe_osd.c b/drivers/media/platform/davinci/vpbe_osd.c index 491842ef33c5004a481921060718303c7e43c9f7..91b571a0ac2c9be3d2339b74ffb1247f54a4a88f 100644 --- a/drivers/media/platform/davinci/vpbe_osd.c +++ b/drivers/media/platform/davinci/vpbe_osd.c @@ -16,11 +16,6 @@ #include #include -#ifdef CONFIG_ARCH_DAVINCI -#include -#include -#endif - #include #include #include diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c index 425f91f07165b578476f5ecec589ad302bfe7889..8caa084e570469c6fed105a02dd442be471b03b1 100644 --- a/drivers/media/platform/davinci/vpbe_venc.c +++ b/drivers/media/platform/davinci/vpbe_venc.c @@ -14,11 +14,6 @@ #include #include -#ifdef CONFIG_ARCH_DAVINCI -#include -#include -#endif - #include #include diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 295fbf1a49cfa7cc94d6079903fa76a57ed5fac1..916ed743d716cfccd376a11f675fe08714fcbe47 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -119,57 +119,27 @@ static const struct vpfe_standard vpfe_standards[] = { /* Used when raw Bayer image from ccdc is directly captured to SDRAM */ static const struct vpfe_pixel_format vpfe_pix_fmts[] = { { - .fmtdesc = { - .index = 0, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "Bayer GrRBGb 8bit A-Law compr.", - .pixelformat = V4L2_PIX_FMT_SBGGR8, - }, + .pixelformat = V4L2_PIX_FMT_SBGGR8, .bpp = 1, }, { - .fmtdesc = { - .index = 1, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "Bayer GrRBGb - 16bit", - .pixelformat = V4L2_PIX_FMT_SBGGR16, - }, + .pixelformat = V4L2_PIX_FMT_SBGGR16, .bpp = 2, }, { - .fmtdesc = { - .index = 2, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "Bayer GrRBGb 8bit DPCM compr.", - .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, - }, + .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, .bpp = 1, }, { - .fmtdesc = { - .index = 3, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "YCbCr 4:2:2 Interleaved UYVY", - .pixelformat = V4L2_PIX_FMT_UYVY, - }, + .pixelformat = V4L2_PIX_FMT_UYVY, .bpp = 2, }, { - .fmtdesc = { - .index = 4, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "YCbCr 4:2:2 Interleaved YUYV", - .pixelformat = V4L2_PIX_FMT_YUYV, - }, + .pixelformat = V4L2_PIX_FMT_YUYV, .bpp = 2, }, { - .fmtdesc = { - .index = 5, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "Y/CbCr 4:2:0 - Semi planar", - .pixelformat = V4L2_PIX_FMT_NV12, - }, + .pixelformat = V4L2_PIX_FMT_NV12, .bpp = 1, }, }; @@ -183,7 +153,7 @@ static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format) int i; for (i = 0; i < ARRAY_SIZE(vpfe_pix_fmts); i++) { - if (pix_format == vpfe_pix_fmts[i].fmtdesc.pixelformat) + if (pix_format == vpfe_pix_fmts[i].pixelformat) return &vpfe_pix_fmts[i]; } return NULL; @@ -782,7 +752,7 @@ static const struct vpfe_pixel_format * temp = 0; found = 0; while (ccdc_dev->hw_ops.enum_pix(&pix, temp) >= 0) { - if (vpfe_pix_fmt->fmtdesc.pixelformat == pix) { + if (vpfe_pix_fmt->pixelformat == pix) { found = 1; break; } @@ -877,8 +847,6 @@ static int vpfe_querycap(struct file *file, void *priv, v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n"); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; strscpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); strscpy(cap->bus_info, "VPFE", sizeof(cap->bus_info)); strscpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card)); @@ -901,7 +869,6 @@ static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv, { struct vpfe_device *vpfe_dev = video_drvdata(file); const struct vpfe_pixel_format *pix_fmt; - int temp_index; u32 pix; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt_vid_cap\n"); @@ -912,9 +879,7 @@ static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv, /* Fill in the information about format */ pix_fmt = vpfe_lookup_pix_format(pix); if (pix_fmt) { - temp_index = fmt->index; - *fmt = pix_fmt->fmtdesc; - fmt->index = temp_index; + fmt->pixelformat = fmt->pixelformat; return 0; } return -EINVAL; @@ -1785,6 +1750,7 @@ static int vpfe_probe(struct platform_device *pdev) vfd->ioctl_ops = &vpfe_ioctl_ops; vfd->tvnorms = 0; vfd->v4l2_dev = &vpfe_dev->v4l2_dev; + vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; snprintf(vfd->name, sizeof(vfd->name), "%s_V%d.%d.%d", CAPTURE_DRV_NAME, diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index f0f7ef638c56c174d5ec09d3397cc9818191cb51..71f4fe882d138f4f69abd16309a221c8490f7de7 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -938,17 +938,10 @@ static int vpif_enum_fmt_vid_cap(struct file *file, void *priv, } /* Fill in the information about format */ - if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) { - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strscpy(fmt->description, "Raw Mode -Bayer Pattern GrRBGb", - sizeof(fmt->description)); + if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) fmt->pixelformat = V4L2_PIX_FMT_SBGGR8; - } else { - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strscpy(fmt->description, "YCbCr4:2:2 Semi-Planar", - sizeof(fmt->description)); + else fmt->pixelformat = V4L2_PIX_FMT_NV16; - } return 0; } @@ -979,7 +972,6 @@ static int vpif_try_fmt_vid_cap(struct file *file, void *priv, pixfmt->bytesperline = common->fmt.fmt.pix.width * 2; pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; } - pixfmt->priv = 0; dev_dbg(vpif_dev, "%s: %d x %d; pitch=%d pixelformat=0x%08x, field=%d, size=%d\n", __func__, pixfmt->width, pixfmt->height, @@ -1085,8 +1077,6 @@ static int vpif_querycap(struct file *file, void *priv, { struct vpif_capture_config *config = vpif_dev->platform_data; - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; strscpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(vpif_dev)); @@ -1473,6 +1463,7 @@ static int vpif_probe_complete(void) vdev->vfl_dir = VFL_DIR_RX; vdev->queue = q; vdev->lock = &common->lock; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; video_set_drvdata(&ch->video_dev, ch); err = video_register_device(vdev, VFL_TYPE_GRABBER, (j ? 1 : 0)); @@ -1511,6 +1502,7 @@ static struct vpif_capture_config * vpif_capture_get_pdata(struct platform_device *pdev) { struct device_node *endpoint = NULL; + struct device_node *rem = NULL; struct vpif_capture_config *pdata; struct vpif_subdev_info *sdinfo; struct vpif_capture_chan_config *chan; @@ -1541,7 +1533,6 @@ vpif_capture_get_pdata(struct platform_device *pdev) for (i = 0; i < VPIF_CAPTURE_NUM_CHANNELS; i++) { struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; - struct device_node *rem; unsigned int flags; int err; @@ -1554,7 +1545,6 @@ vpif_capture_get_pdata(struct platform_device *pdev) if (!rem) { dev_dbg(&pdev->dev, "Remote device at %pOF not found\n", endpoint); - of_node_put(endpoint); goto done; } @@ -1564,11 +1554,8 @@ vpif_capture_get_pdata(struct platform_device *pdev) VPIF_CAPTURE_NUM_CHANNELS, sizeof(*chan->inputs), GFP_KERNEL); - if (!chan->inputs) { - of_node_put(rem); - of_node_put(endpoint); + if (!chan->inputs) goto err_cleanup; - } chan->input_count++; chan->inputs[i].input.type = V4L2_INPUT_TYPE_CAMERA; @@ -1577,7 +1564,6 @@ vpif_capture_get_pdata(struct platform_device *pdev) err = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint), &bus_cfg); - of_node_put(endpoint); if (err) { dev_err(&pdev->dev, "Could not parse the endpoint\n"); of_node_put(rem); @@ -1601,13 +1587,14 @@ vpif_capture_get_pdata(struct platform_device *pdev) pdata->asd[i] = v4l2_async_notifier_add_fwnode_subdev( &vpif_obj.notifier, of_fwnode_handle(rem), sizeof(struct v4l2_async_subdev)); - if (IS_ERR(pdata->asd[i])) { - of_node_put(rem); + if (IS_ERR(pdata->asd[i])) goto err_cleanup; - } + + of_node_put(rem); } done: + of_node_put(endpoint); pdata->asd_sizes[0] = i; pdata->subdev_count = i; pdata->card_name = "DA850/OMAP-L138 Video Capture"; @@ -1615,6 +1602,8 @@ vpif_capture_get_pdata(struct platform_device *pdev) return pdata; err_cleanup: + of_node_put(rem); + of_node_put(endpoint); v4l2_async_notifier_cleanup(&vpif_obj.notifier); return NULL; diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index a69897c68a50f9031d942861bf1c58821f6c1b90..abbdbac08e6f4664feedd7f6144ffcab72d4c046 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -584,8 +584,6 @@ static int vpif_querycap(struct file *file, void *priv, { struct vpif_display_config *config = vpif_dev->platform_data; - cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; strscpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(vpif_dev)); @@ -601,11 +599,7 @@ static int vpif_enum_fmt_vid_out(struct file *file, void *priv, return -EINVAL; /* Fill in the information about format */ - fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - strscpy(fmt->description, "YCbCr4:2:2 YC Planar", - sizeof(fmt->description)); fmt->pixelformat = V4L2_PIX_FMT_YUV422P; - fmt->flags = 0; return 0; } @@ -1218,6 +1212,7 @@ static int vpif_probe_complete(void) vdev->vfl_dir = VFL_DIR_TX; vdev->queue = q; vdev->lock = &common->lock; + vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; video_set_drvdata(&ch->video_dev, ch); err = video_register_device(vdev, VFL_TYPE_GRABBER, (j ? 3 : 2)); diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 854869f0024e041717dbbba16f3d3048adde83f5..f6650b45bc3d2184898f4d1e8169827c8001f779 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -27,21 +27,18 @@ static const struct gsc_fmt gsc_formats[] = { { - .name = "RGB565", .pixelformat = V4L2_PIX_FMT_RGB565X, .depth = { 16 }, .color = GSC_RGB, .num_planes = 1, .num_comp = 1, }, { - .name = "BGRX-8-8-8-8, 32 bpp", .pixelformat = V4L2_PIX_FMT_BGR32, .depth = { 32 }, .color = GSC_RGB, .num_planes = 1, .num_comp = 1, }, { - .name = "YUV 4:2:2 packed, YCbYCr", .pixelformat = V4L2_PIX_FMT_YUYV, .depth = { 16 }, .color = GSC_YUV422, @@ -51,7 +48,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_comp = 1, .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, }, { - .name = "YUV 4:2:2 packed, CbYCrY", .pixelformat = V4L2_PIX_FMT_UYVY, .depth = { 16 }, .color = GSC_YUV422, @@ -61,7 +57,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_comp = 1, .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, }, { - .name = "YUV 4:2:2 packed, CrYCbY", .pixelformat = V4L2_PIX_FMT_VYUY, .depth = { 16 }, .color = GSC_YUV422, @@ -71,7 +66,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_comp = 1, .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, }, { - .name = "YUV 4:2:2 packed, YCrYCb", .pixelformat = V4L2_PIX_FMT_YVYU, .depth = { 16 }, .color = GSC_YUV422, @@ -81,7 +75,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_comp = 1, .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, }, { - .name = "YUV 4:4:4 planar, YCbYCr", .pixelformat = V4L2_PIX_FMT_YUV32, .depth = { 32 }, .color = GSC_YUV444, @@ -90,7 +83,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 1, .num_comp = 1, }, { - .name = "YUV 4:2:2 planar, Y/Cb/Cr", .pixelformat = V4L2_PIX_FMT_YUV422P, .depth = { 16 }, .color = GSC_YUV422, @@ -99,7 +91,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 1, .num_comp = 3, }, { - .name = "YUV 4:2:2 planar, Y/CbCr", .pixelformat = V4L2_PIX_FMT_NV16, .depth = { 16 }, .color = GSC_YUV422, @@ -108,7 +99,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 1, .num_comp = 2, }, { - .name = "YUV 4:2:2 non-contig, Y/CbCr", .pixelformat = V4L2_PIX_FMT_NV16M, .depth = { 8, 8 }, .color = GSC_YUV422, @@ -117,7 +107,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 2, .num_comp = 2, }, { - .name = "YUV 4:2:2 planar, Y/CrCb", .pixelformat = V4L2_PIX_FMT_NV61, .depth = { 16 }, .color = GSC_YUV422, @@ -126,7 +115,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 1, .num_comp = 2, }, { - .name = "YUV 4:2:2 non-contig, Y/CrCb", .pixelformat = V4L2_PIX_FMT_NV61M, .depth = { 8, 8 }, .color = GSC_YUV422, @@ -135,7 +123,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 2, .num_comp = 2, }, { - .name = "YUV 4:2:0 planar, YCbCr", .pixelformat = V4L2_PIX_FMT_YUV420, .depth = { 12 }, .color = GSC_YUV420, @@ -144,7 +131,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 1, .num_comp = 3, }, { - .name = "YUV 4:2:0 planar, YCrCb", .pixelformat = V4L2_PIX_FMT_YVU420, .depth = { 12 }, .color = GSC_YUV420, @@ -154,7 +140,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_comp = 3, }, { - .name = "YUV 4:2:0 planar, Y/CbCr", .pixelformat = V4L2_PIX_FMT_NV12, .depth = { 12 }, .color = GSC_YUV420, @@ -163,7 +148,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 1, .num_comp = 2, }, { - .name = "YUV 4:2:0 planar, Y/CrCb", .pixelformat = V4L2_PIX_FMT_NV21, .depth = { 12 }, .color = GSC_YUV420, @@ -172,7 +156,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 1, .num_comp = 2, }, { - .name = "YUV 4:2:0 non-contig. 2p, Y/CrCb", .pixelformat = V4L2_PIX_FMT_NV21M, .depth = { 8, 4 }, .color = GSC_YUV420, @@ -181,7 +164,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 2, .num_comp = 2, }, { - .name = "YUV 4:2:0 non-contig. 2p, Y/CbCr", .pixelformat = V4L2_PIX_FMT_NV12M, .depth = { 8, 4 }, .color = GSC_YUV420, @@ -190,7 +172,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 2, .num_comp = 2, }, { - .name = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr", .pixelformat = V4L2_PIX_FMT_YUV420M, .depth = { 8, 2, 2 }, .color = GSC_YUV420, @@ -199,7 +180,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 3, .num_comp = 3, }, { - .name = "YUV 4:2:0 non-contig. 3p, Y/Cr/Cb", .pixelformat = V4L2_PIX_FMT_YVU420M, .depth = { 8, 2, 2 }, .color = GSC_YUV420, @@ -208,7 +188,6 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 3, .num_comp = 3, }, { - .name = "YUV 4:2:0 n.c. 2p, Y/CbCr tiled", .pixelformat = V4L2_PIX_FMT_NV12MT_16X16, .depth = { 8, 4 }, .color = GSC_YUV420, @@ -335,7 +314,6 @@ int gsc_enum_fmt(struct v4l2_fmtdesc *f) if (!fmt) return -EINVAL; - strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->pixelformat; return 0; diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h index 772183b090c26b09ab1780cde0b56c4eef22a643..8e5a9acb78aad4bc99f0423c73f3d0f6f1f11a67 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/exynos-gsc/gsc-core.h @@ -103,7 +103,6 @@ enum gsc_yuv_fmt { /** * struct gsc_fmt - the driver's internal color format data * @mbus_code: Media Bus pixel code, -1 if not applicable - * @name: format description * @pixelformat: the fourcc code for this format, 0 if not applicable * @yorder: Y/C order * @corder: Chrominance order control @@ -114,7 +113,6 @@ enum gsc_yuv_fmt { */ struct gsc_fmt { u32 mbus_code; - char *name; u32 pixelformat; u32 color; u32 yorder; diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 66510365dd5dd19f131eaeb4f90a5c06a55dcfd2..121d609ff85686035c2c81905bc43d7196ed24b5 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -738,10 +738,7 @@ static int fimc_cap_enum_fmt(struct file *file, void *priv, f->index); if (!fmt) return -EINVAL; - strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; - if (fmt->fourcc == MEDIA_BUS_FMT_JPEG_1X8) - f->flags |= V4L2_FMT_FLAG_COMPRESSED; return 0; } diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index 7006f54bfee2456f3d2cd37bad43373fe5b80877..cde60fbb23a88d02493ab785e47db077be3ca50b 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -36,7 +36,6 @@ static char *fimc_clocks[MAX_FIMC_CLOCKS] = { static struct fimc_fmt fimc_formats[] = { { - .name = "RGB565", .fourcc = V4L2_PIX_FMT_RGB565, .depth = { 16 }, .color = FIMC_FMT_RGB565, @@ -44,7 +43,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 1, .flags = FMT_FLAGS_M2M, }, { - .name = "BGR666", .fourcc = V4L2_PIX_FMT_BGR666, .depth = { 32 }, .color = FIMC_FMT_RGB666, @@ -52,7 +50,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 1, .flags = FMT_FLAGS_M2M, }, { - .name = "BGRA8888, 32 bpp", .fourcc = V4L2_PIX_FMT_BGR32, .depth = { 32 }, .color = FIMC_FMT_RGB888, @@ -60,7 +57,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 1, .flags = FMT_FLAGS_M2M | FMT_HAS_ALPHA, }, { - .name = "ARGB1555", .fourcc = V4L2_PIX_FMT_RGB555, .depth = { 16 }, .color = FIMC_FMT_RGB555, @@ -68,7 +64,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 1, .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA, }, { - .name = "ARGB4444", .fourcc = V4L2_PIX_FMT_RGB444, .depth = { 16 }, .color = FIMC_FMT_RGB444, @@ -76,11 +71,9 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 1, .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA, }, { - .name = "YUV 4:4:4", .mbus_code = MEDIA_BUS_FMT_YUV10_1X30, .flags = FMT_FLAGS_WRITEBACK, }, { - .name = "YUV 4:2:2 packed, YCbYCr", .fourcc = V4L2_PIX_FMT_YUYV, .depth = { 16 }, .color = FIMC_FMT_YCBYCR422, @@ -89,7 +82,6 @@ static struct fimc_fmt fimc_formats[] = { .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, }, { - .name = "YUV 4:2:2 packed, CbYCrY", .fourcc = V4L2_PIX_FMT_UYVY, .depth = { 16 }, .color = FIMC_FMT_CBYCRY422, @@ -98,7 +90,6 @@ static struct fimc_fmt fimc_formats[] = { .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, }, { - .name = "YUV 4:2:2 packed, CrYCbY", .fourcc = V4L2_PIX_FMT_VYUY, .depth = { 16 }, .color = FIMC_FMT_CRYCBY422, @@ -107,7 +98,6 @@ static struct fimc_fmt fimc_formats[] = { .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, }, { - .name = "YUV 4:2:2 packed, YCrYCb", .fourcc = V4L2_PIX_FMT_YVYU, .depth = { 16 }, .color = FIMC_FMT_YCRYCB422, @@ -116,7 +106,6 @@ static struct fimc_fmt fimc_formats[] = { .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, }, { - .name = "YUV 4:2:2 planar, Y/Cb/Cr", .fourcc = V4L2_PIX_FMT_YUV422P, .depth = { 16 }, .color = FIMC_FMT_YCBYCR422, @@ -124,7 +113,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 3, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:2 planar, Y/CbCr", .fourcc = V4L2_PIX_FMT_NV16, .depth = { 16 }, .color = FIMC_FMT_YCBYCR422, @@ -132,7 +120,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 2, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:2 planar, Y/CrCb", .fourcc = V4L2_PIX_FMT_NV61, .depth = { 16 }, .color = FIMC_FMT_YCRYCB422, @@ -140,7 +127,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 2, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:0 planar, YCbCr", .fourcc = V4L2_PIX_FMT_YUV420, .depth = { 12 }, .color = FIMC_FMT_YCBCR420, @@ -148,7 +134,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 3, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:0 planar, Y/CbCr", .fourcc = V4L2_PIX_FMT_NV12, .depth = { 12 }, .color = FIMC_FMT_YCBCR420, @@ -156,7 +141,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 2, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:0 non-contig. 2p, Y/CbCr", .fourcc = V4L2_PIX_FMT_NV12M, .color = FIMC_FMT_YCBCR420, .depth = { 8, 4 }, @@ -164,7 +148,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 2, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr", .fourcc = V4L2_PIX_FMT_YUV420M, .color = FIMC_FMT_YCBCR420, .depth = { 8, 2, 2 }, @@ -172,7 +155,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 3, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:0 non-contig. 2p, tiled", .fourcc = V4L2_PIX_FMT_NV12MT, .color = FIMC_FMT_YCBCR420, .depth = { 8, 4 }, @@ -180,7 +162,6 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 2, .flags = FMT_FLAGS_M2M, }, { - .name = "JPEG encoded data", .fourcc = V4L2_PIX_FMT_JPEG, .color = FIMC_FMT_JPEG, .depth = { 8 }, @@ -189,7 +170,6 @@ static struct fimc_fmt fimc_formats[] = { .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, .flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED, }, { - .name = "S5C73MX interleaved UYVY/JPEG", .fourcc = V4L2_PIX_FMT_S5C_UYVY_JPG, .color = FIMC_FMT_YUYV_JPEG, .depth = { 8 }, diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index e043d55133a315aa86fccbfe26f7e0cd114a9c08..64148b7e0d9862aada2a062051e76e71d81cf5a8 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -341,7 +341,6 @@ static int fimc_is_alloc_cpu_memory(struct fimc_is *is) return -ENOMEM; is->memory.size = FIMC_IS_CPU_MEM_SIZE; - memset(is->memory.vaddr, 0, is->memory.size); dev_info(dev, "FIMC-IS CPU memory base: %#x\n", (u32)is->memory.paddr); @@ -806,6 +805,7 @@ static int fimc_is_probe(struct platform_device *pdev) return -ENODEV; is->pmu_regs = of_iomap(node, 0); + of_node_put(node); if (!is->pmu_regs) return -ENOMEM; diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c index a75f932a289a9cecb5e0b596b7cb74e43ed3fcf2..378cc302e1f8e32f8629a9c2b2f71caf2b59dd29 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c @@ -362,7 +362,6 @@ static int isp_video_enum_fmt(struct file *file, void *priv, if (WARN_ON(fmt == NULL)) return -EINVAL; - strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; return 0; diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index 907b83e6649d859cef8ca105fd03b87adfc9b104..cde0d254ec1c4f9f5c0beb2ae7b89891cd60aa7c 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c @@ -33,21 +33,18 @@ module_param_named(debug_isp, fimc_isp_debug, int, S_IRUGO | S_IWUSR); static const struct fimc_fmt fimc_isp_formats[FIMC_ISP_NUM_FORMATS] = { { - .name = "RAW8 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG8, .depth = { 8 }, .color = FIMC_FMT_RAW8, .memplanes = 1, .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, }, { - .name = "RAW10 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG10, .depth = { 10 }, .color = FIMC_FMT_RAW10, .memplanes = 1, .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, }, { - .name = "RAW12 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG12, .depth = { 12 }, .color = FIMC_FMT_RAW12, diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.h b/drivers/media/platform/exynos4-is/fimc-lite-reg.h index 48f2cf1148b86e9c21ff6cce4a09daa04918cc59..c5656e902750c83dd089cbd0d1189b4cd7809aea 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite-reg.h +++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.h @@ -6,6 +6,8 @@ #ifndef FIMC_LITE_REG_H_ #define FIMC_LITE_REG_H_ +#include + #include "fimc-lite.h" /* Camera Source size */ @@ -27,27 +29,27 @@ /* User defined formats. x = 0...15 */ #define FLITE_REG_CIGCTRL_USER(x) ((0x30 + x - 1) << 24) #define FLITE_REG_CIGCTRL_FMT_MASK (0x3f << 24) -#define FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE (1 << 21) -#define FLITE_REG_CIGCTRL_ODMA_DISABLE (1 << 20) -#define FLITE_REG_CIGCTRL_SWRST_REQ (1 << 19) -#define FLITE_REG_CIGCTRL_SWRST_RDY (1 << 18) -#define FLITE_REG_CIGCTRL_SWRST (1 << 17) -#define FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR (1 << 15) -#define FLITE_REG_CIGCTRL_INVPOLPCLK (1 << 14) -#define FLITE_REG_CIGCTRL_INVPOLVSYNC (1 << 13) -#define FLITE_REG_CIGCTRL_INVPOLHREF (1 << 12) +#define FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE BIT(21) +#define FLITE_REG_CIGCTRL_ODMA_DISABLE BIT(20) +#define FLITE_REG_CIGCTRL_SWRST_REQ BIT(19) +#define FLITE_REG_CIGCTRL_SWRST_RDY BIT(18) +#define FLITE_REG_CIGCTRL_SWRST BIT(17) +#define FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR BIT(15) +#define FLITE_REG_CIGCTRL_INVPOLPCLK BIT(14) +#define FLITE_REG_CIGCTRL_INVPOLVSYNC BIT(13) +#define FLITE_REG_CIGCTRL_INVPOLHREF BIT(12) /* Interrupts mask bits (1 disables an interrupt) */ -#define FLITE_REG_CIGCTRL_IRQ_LASTEN (1 << 8) -#define FLITE_REG_CIGCTRL_IRQ_ENDEN (1 << 7) -#define FLITE_REG_CIGCTRL_IRQ_STARTEN (1 << 6) -#define FLITE_REG_CIGCTRL_IRQ_OVFEN (1 << 5) +#define FLITE_REG_CIGCTRL_IRQ_LASTEN BIT(8) +#define FLITE_REG_CIGCTRL_IRQ_ENDEN BIT(7) +#define FLITE_REG_CIGCTRL_IRQ_STARTEN BIT(6) +#define FLITE_REG_CIGCTRL_IRQ_OVFEN BIT(5) #define FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK (0xf << 5) -#define FLITE_REG_CIGCTRL_SELCAM_MIPI (1 << 3) +#define FLITE_REG_CIGCTRL_SELCAM_MIPI BIT(3) /* Image Capture Enable */ #define FLITE_REG_CIIMGCPT 0x08 -#define FLITE_REG_CIIMGCPT_IMGCPTEN (1 << 31) -#define FLITE_REG_CIIMGCPT_CPT_FREN (1 << 25) +#define FLITE_REG_CIIMGCPT_IMGCPTEN BIT(31) +#define FLITE_REG_CIIMGCPT_CPT_FREN BIT(25) #define FLITE_REG_CIIMGCPT_CPT_MOD_FRCNT (1 << 18) #define FLITE_REG_CIIMGCPT_CPT_MOD_FREN (0 << 18) @@ -56,10 +58,10 @@ /* Camera Window Offset */ #define FLITE_REG_CIWDOFST 0x10 -#define FLITE_REG_CIWDOFST_WINOFSEN (1 << 31) -#define FLITE_REG_CIWDOFST_CLROVIY (1 << 31) -#define FLITE_REG_CIWDOFST_CLROVFICB (1 << 15) -#define FLITE_REG_CIWDOFST_CLROVFICR (1 << 14) +#define FLITE_REG_CIWDOFST_WINOFSEN BIT(31) +#define FLITE_REG_CIWDOFST_CLROVIY BIT(31) +#define FLITE_REG_CIWDOFST_CLROVFICB BIT(15) +#define FLITE_REG_CIWDOFST_CLROVFICR BIT(14) #define FLITE_REG_CIWDOFST_OFST_MASK ((0x1fff << 16) | 0x1fff) /* Camera Window Offset2 */ @@ -67,8 +69,8 @@ /* Camera Output DMA Format */ #define FLITE_REG_CIODMAFMT 0x18 -#define FLITE_REG_CIODMAFMT_RAW_CON (1 << 15) -#define FLITE_REG_CIODMAFMT_PACK12 (1 << 14) +#define FLITE_REG_CIODMAFMT_RAW_CON BIT(15) +#define FLITE_REG_CIODMAFMT_PACK12 BIT(14) #define FLITE_REG_CIODMAFMT_YCBYCR (0 << 4) #define FLITE_REG_CIODMAFMT_YCRYCB (1 << 4) #define FLITE_REG_CIODMAFMT_CBYCRY (2 << 4) @@ -88,34 +90,34 @@ /* Camera Status */ #define FLITE_REG_CISTATUS 0x40 -#define FLITE_REG_CISTATUS_MIPI_VVALID (1 << 22) -#define FLITE_REG_CISTATUS_MIPI_HVALID (1 << 21) -#define FLITE_REG_CISTATUS_MIPI_DVALID (1 << 20) -#define FLITE_REG_CISTATUS_ITU_VSYNC (1 << 14) -#define FLITE_REG_CISTATUS_ITU_HREFF (1 << 13) -#define FLITE_REG_CISTATUS_OVFIY (1 << 10) -#define FLITE_REG_CISTATUS_OVFICB (1 << 9) -#define FLITE_REG_CISTATUS_OVFICR (1 << 8) -#define FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW (1 << 7) -#define FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND (1 << 6) -#define FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART (1 << 5) -#define FLITE_REG_CISTATUS_IRQ_SRC_FRMEND (1 << 4) -#define FLITE_REG_CISTATUS_IRQ_CAM (1 << 0) +#define FLITE_REG_CISTATUS_MIPI_VVALID BIT(22) +#define FLITE_REG_CISTATUS_MIPI_HVALID BIT(21) +#define FLITE_REG_CISTATUS_MIPI_DVALID BIT(20) +#define FLITE_REG_CISTATUS_ITU_VSYNC BIT(14) +#define FLITE_REG_CISTATUS_ITU_HREFF BIT(13) +#define FLITE_REG_CISTATUS_OVFIY BIT(10) +#define FLITE_REG_CISTATUS_OVFICB BIT(9) +#define FLITE_REG_CISTATUS_OVFICR BIT(8) +#define FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW BIT(7) +#define FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND BIT(6) +#define FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART BIT(5) +#define FLITE_REG_CISTATUS_IRQ_SRC_FRMEND BIT(4) +#define FLITE_REG_CISTATUS_IRQ_CAM BIT(0) #define FLITE_REG_CISTATUS_IRQ_MASK (0xf << 4) /* Camera Status2 */ #define FLITE_REG_CISTATUS2 0x44 -#define FLITE_REG_CISTATUS2_LASTCAPEND (1 << 1) -#define FLITE_REG_CISTATUS2_FRMEND (1 << 0) +#define FLITE_REG_CISTATUS2_LASTCAPEND BIT(1) +#define FLITE_REG_CISTATUS2_FRMEND BIT(0) /* Qos Threshold */ #define FLITE_REG_CITHOLD 0xf0 -#define FLITE_REG_CITHOLD_W_QOS_EN (1 << 30) +#define FLITE_REG_CITHOLD_W_QOS_EN BIT(30) /* Camera General Purpose */ #define FLITE_REG_CIGENERAL 0xfc /* b0: 1 - camera B, 0 - camera A */ -#define FLITE_REG_CIGENERAL_CAM_B (1 << 0) +#define FLITE_REG_CIGENERAL_CAM_B BIT(0) #define FLITE_REG_CIFCNTSEQ 0x100 #define FLITE_REG_CIOSAN(x) (0x200 + (4 * (x))) diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index c1f0aee02e5e902de019948a97df6902b5320b81..e87c6a09205bda207bfc9900b95312bfaebbe92c 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -39,7 +39,6 @@ module_param(debug, int, 0644); static const struct fimc_fmt fimc_lite_formats[] = { { - .name = "YUV 4:2:2 packed, YCbYCr", .fourcc = V4L2_PIX_FMT_YUYV, .colorspace = V4L2_COLORSPACE_JPEG, .depth = { 16 }, @@ -48,7 +47,6 @@ static const struct fimc_fmt fimc_lite_formats[] = { .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .flags = FMT_FLAGS_YUV, }, { - .name = "YUV 4:2:2 packed, CbYCrY", .fourcc = V4L2_PIX_FMT_UYVY, .colorspace = V4L2_COLORSPACE_JPEG, .depth = { 16 }, @@ -57,7 +55,6 @@ static const struct fimc_fmt fimc_lite_formats[] = { .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, .flags = FMT_FLAGS_YUV, }, { - .name = "YUV 4:2:2 packed, CrYCbY", .fourcc = V4L2_PIX_FMT_VYUY, .colorspace = V4L2_COLORSPACE_JPEG, .depth = { 16 }, @@ -66,7 +63,6 @@ static const struct fimc_fmt fimc_lite_formats[] = { .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, .flags = FMT_FLAGS_YUV, }, { - .name = "YUV 4:2:2 packed, YCrYCb", .fourcc = V4L2_PIX_FMT_YVYU, .colorspace = V4L2_COLORSPACE_JPEG, .depth = { 16 }, @@ -75,7 +71,6 @@ static const struct fimc_fmt fimc_lite_formats[] = { .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, .flags = FMT_FLAGS_YUV, }, { - .name = "RAW8 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG8, .colorspace = V4L2_COLORSPACE_SRGB, .depth = { 8 }, @@ -84,7 +79,6 @@ static const struct fimc_fmt fimc_lite_formats[] = { .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, .flags = FMT_FLAGS_RAW_BAYER, }, { - .name = "RAW10 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG10, .colorspace = V4L2_COLORSPACE_SRGB, .depth = { 16 }, @@ -93,7 +87,6 @@ static const struct fimc_fmt fimc_lite_formats[] = { .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, .flags = FMT_FLAGS_RAW_BAYER, }, { - .name = "RAW12 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG12, .colorspace = V4L2_COLORSPACE_SRGB, .depth = { 16 }, @@ -667,7 +660,6 @@ static int fimc_lite_enum_fmt(struct file *file, void *priv, return -EINVAL; fmt = &fimc_lite_formats[f->index]; - strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; return 0; diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index 62e876fc35554a804190b14bdf441b6168e46c72..c70c2cbe3eb1b38b5920584d273ae1fe1da72b0e 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -247,7 +247,6 @@ static int fimc_m2m_enum_fmt(struct file *file, void *priv, if (!fmt) return -EINVAL; - strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; return 0; } diff --git a/drivers/media/platform/exynos4-is/fimc-reg.h b/drivers/media/platform/exynos4-is/fimc-reg.h index 03ba6c2bc84beb3063bfd7a01427132cd8a19266..b81826d04936d20eee228f15ec9aebb01b4a50f1 100644 --- a/drivers/media/platform/exynos4-is/fimc-reg.h +++ b/drivers/media/platform/exynos4-is/fimc-reg.h @@ -8,12 +8,14 @@ #ifndef FIMC_REG_H_ #define FIMC_REG_H_ +#include + #include "fimc-core.h" /* Input source format */ #define FIMC_REG_CISRCFMT 0x00 -#define FIMC_REG_CISRCFMT_ITU601_8BIT (1 << 31) -#define FIMC_REG_CISRCFMT_ITU601_16BIT (1 << 29) +#define FIMC_REG_CISRCFMT_ITU601_8BIT BIT(31) +#define FIMC_REG_CISRCFMT_ITU601_16BIT BIT(29) #define FIMC_REG_CISRCFMT_ORDER422_YCBYCR (0 << 14) #define FIMC_REG_CISRCFMT_ORDER422_YCRYCB (1 << 14) #define FIMC_REG_CISRCFMT_ORDER422_CBYCRY (2 << 14) @@ -21,45 +23,45 @@ /* Window offset */ #define FIMC_REG_CIWDOFST 0x04 -#define FIMC_REG_CIWDOFST_OFF_EN (1 << 31) -#define FIMC_REG_CIWDOFST_CLROVFIY (1 << 30) -#define FIMC_REG_CIWDOFST_CLROVRLB (1 << 29) +#define FIMC_REG_CIWDOFST_OFF_EN BIT(31) +#define FIMC_REG_CIWDOFST_CLROVFIY BIT(30) +#define FIMC_REG_CIWDOFST_CLROVRLB BIT(29) #define FIMC_REG_CIWDOFST_HOROFF_MASK (0x7ff << 16) -#define FIMC_REG_CIWDOFST_CLROVFICB (1 << 15) -#define FIMC_REG_CIWDOFST_CLROVFICR (1 << 14) +#define FIMC_REG_CIWDOFST_CLROVFICB BIT(15) +#define FIMC_REG_CIWDOFST_CLROVFICR BIT(14) #define FIMC_REG_CIWDOFST_VEROFF_MASK (0xfff << 0) /* Global control */ #define FIMC_REG_CIGCTRL 0x08 -#define FIMC_REG_CIGCTRL_SWRST (1 << 31) -#define FIMC_REG_CIGCTRL_CAMRST_A (1 << 30) -#define FIMC_REG_CIGCTRL_SELCAM_ITU_A (1 << 29) +#define FIMC_REG_CIGCTRL_SWRST BIT(31) +#define FIMC_REG_CIGCTRL_CAMRST_A BIT(30) +#define FIMC_REG_CIGCTRL_SELCAM_ITU_A BIT(29) #define FIMC_REG_CIGCTRL_TESTPAT_NORMAL (0 << 27) #define FIMC_REG_CIGCTRL_TESTPAT_COLOR_BAR (1 << 27) #define FIMC_REG_CIGCTRL_TESTPAT_HOR_INC (2 << 27) #define FIMC_REG_CIGCTRL_TESTPAT_VER_INC (3 << 27) #define FIMC_REG_CIGCTRL_TESTPAT_MASK (3 << 27) #define FIMC_REG_CIGCTRL_TESTPAT_SHIFT 27 -#define FIMC_REG_CIGCTRL_INVPOLPCLK (1 << 26) -#define FIMC_REG_CIGCTRL_INVPOLVSYNC (1 << 25) -#define FIMC_REG_CIGCTRL_INVPOLHREF (1 << 24) -#define FIMC_REG_CIGCTRL_IRQ_OVFEN (1 << 22) -#define FIMC_REG_CIGCTRL_HREF_MASK (1 << 21) -#define FIMC_REG_CIGCTRL_IRQ_LEVEL (1 << 20) -#define FIMC_REG_CIGCTRL_IRQ_CLR (1 << 19) -#define FIMC_REG_CIGCTRL_IRQ_ENABLE (1 << 16) -#define FIMC_REG_CIGCTRL_SHDW_DISABLE (1 << 12) +#define FIMC_REG_CIGCTRL_INVPOLPCLK BIT(26) +#define FIMC_REG_CIGCTRL_INVPOLVSYNC BIT(25) +#define FIMC_REG_CIGCTRL_INVPOLHREF BIT(24) +#define FIMC_REG_CIGCTRL_IRQ_OVFEN BIT(22) +#define FIMC_REG_CIGCTRL_HREF_MASK BIT(21) +#define FIMC_REG_CIGCTRL_IRQ_LEVEL BIT(20) +#define FIMC_REG_CIGCTRL_IRQ_CLR BIT(19) +#define FIMC_REG_CIGCTRL_IRQ_ENABLE BIT(16) +#define FIMC_REG_CIGCTRL_SHDW_DISABLE BIT(12) /* 0 - selects Writeback A (LCD), 1 - selects Writeback B (LCD/ISP) */ -#define FIMC_REG_CIGCTRL_SELWB_A (1 << 10) -#define FIMC_REG_CIGCTRL_CAM_JPEG (1 << 8) -#define FIMC_REG_CIGCTRL_SELCAM_MIPI_A (1 << 7) -#define FIMC_REG_CIGCTRL_CAMIF_SELWB (1 << 6) +#define FIMC_REG_CIGCTRL_SELWB_A BIT(10) +#define FIMC_REG_CIGCTRL_CAM_JPEG BIT(8) +#define FIMC_REG_CIGCTRL_SELCAM_MIPI_A BIT(7) +#define FIMC_REG_CIGCTRL_CAMIF_SELWB BIT(6) /* 0 - ITU601; 1 - ITU709 */ -#define FIMC_REG_CIGCTRL_CSC_ITU601_709 (1 << 5) -#define FIMC_REG_CIGCTRL_INVPOLHSYNC (1 << 4) -#define FIMC_REG_CIGCTRL_SELCAM_MIPI (1 << 3) -#define FIMC_REG_CIGCTRL_INVPOLFIELD (1 << 1) -#define FIMC_REG_CIGCTRL_INTERLACE (1 << 0) +#define FIMC_REG_CIGCTRL_CSC_ITU601_709 BIT(5) +#define FIMC_REG_CIGCTRL_INVPOLHSYNC BIT(4) +#define FIMC_REG_CIGCTRL_SELCAM_MIPI BIT(3) +#define FIMC_REG_CIGCTRL_INVPOLFIELD BIT(1) +#define FIMC_REG_CIGCTRL_INTERLACE BIT(0) /* Window offset 2 */ #define FIMC_REG_CIWDOFST2 0x14 @@ -73,7 +75,7 @@ /* Target image format */ #define FIMC_REG_CITRGFMT 0x48 -#define FIMC_REG_CITRGFMT_INROT90 (1 << 31) +#define FIMC_REG_CITRGFMT_INROT90 BIT(31) #define FIMC_REG_CITRGFMT_YCBCR420 (0 << 29) #define FIMC_REG_CITRGFMT_YCBCR422 (1 << 29) #define FIMC_REG_CITRGFMT_YCBCR422_1P (2 << 29) @@ -86,7 +88,7 @@ #define FIMC_REG_CITRGFMT_FLIP_Y_MIRROR (2 << 14) #define FIMC_REG_CITRGFMT_FLIP_180 (3 << 14) #define FIMC_REG_CITRGFMT_FLIP_MASK (3 << 14) -#define FIMC_REG_CITRGFMT_OUTROT90 (1 << 13) +#define FIMC_REG_CITRGFMT_OUTROT90 BIT(13) #define FIMC_REG_CITRGFMT_VSIZE_MASK (0xfff << 0) /* Output DMA control */ @@ -96,7 +98,7 @@ #define FIMC_REG_CIOCTRL_ORDER422_YCRYCB (1 << 0) #define FIMC_REG_CIOCTRL_ORDER422_CBYCRY (2 << 0) #define FIMC_REG_CIOCTRL_ORDER422_CRYCBY (3 << 0) -#define FIMC_REG_CIOCTRL_LASTIRQ_ENABLE (1 << 2) +#define FIMC_REG_CIOCTRL_LASTIRQ_ENABLE BIT(2) #define FIMC_REG_CIOCTRL_YCBCR_3PLANE (0 << 3) #define FIMC_REG_CIOCTRL_YCBCR_2PLANE (1 << 3) #define FIMC_REG_CIOCTRL_YCBCR_PLANE_MASK (1 << 3) @@ -116,14 +118,14 @@ /* Main scaler control */ #define FIMC_REG_CISCCTRL 0x58 -#define FIMC_REG_CISCCTRL_SCALERBYPASS (1 << 31) -#define FIMC_REG_CISCCTRL_SCALEUP_H (1 << 30) -#define FIMC_REG_CISCCTRL_SCALEUP_V (1 << 29) -#define FIMC_REG_CISCCTRL_CSCR2Y_WIDE (1 << 28) -#define FIMC_REG_CISCCTRL_CSCY2R_WIDE (1 << 27) -#define FIMC_REG_CISCCTRL_LCDPATHEN_FIFO (1 << 26) -#define FIMC_REG_CISCCTRL_INTERLACE (1 << 25) -#define FIMC_REG_CISCCTRL_SCALERSTART (1 << 15) +#define FIMC_REG_CISCCTRL_SCALERBYPASS BIT(31) +#define FIMC_REG_CISCCTRL_SCALEUP_H BIT(30) +#define FIMC_REG_CISCCTRL_SCALEUP_V BIT(29) +#define FIMC_REG_CISCCTRL_CSCR2Y_WIDE BIT(28) +#define FIMC_REG_CISCCTRL_CSCY2R_WIDE BIT(27) +#define FIMC_REG_CISCCTRL_LCDPATHEN_FIFO BIT(26) +#define FIMC_REG_CISCCTRL_INTERLACE BIT(25) +#define FIMC_REG_CISCCTRL_SCALERSTART BIT(15) #define FIMC_REG_CISCCTRL_INRGB_FMT_RGB565 (0 << 13) #define FIMC_REG_CISCCTRL_INRGB_FMT_RGB666 (1 << 13) #define FIMC_REG_CISCCTRL_INRGB_FMT_RGB888 (2 << 13) @@ -132,8 +134,8 @@ #define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB666 (1 << 11) #define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888 (2 << 11) #define FIMC_REG_CISCCTRL_OUTRGB_FMT_MASK (3 << 11) -#define FIMC_REG_CISCCTRL_RGB_EXT (1 << 10) -#define FIMC_REG_CISCCTRL_ONE2ONE (1 << 9) +#define FIMC_REG_CISCCTRL_RGB_EXT BIT(10) +#define FIMC_REG_CISCCTRL_ONE2ONE BIT(9) #define FIMC_REG_CISCCTRL_MHRATIO(x) ((x) << 16) #define FIMC_REG_CISCCTRL_MVRATIO(x) ((x) << 0) #define FIMC_REG_CISCCTRL_MHRATIO_MASK (0x1ff << 16) @@ -147,39 +149,39 @@ /* General status */ #define FIMC_REG_CISTATUS 0x64 -#define FIMC_REG_CISTATUS_OVFIY (1 << 31) -#define FIMC_REG_CISTATUS_OVFICB (1 << 30) -#define FIMC_REG_CISTATUS_OVFICR (1 << 29) -#define FIMC_REG_CISTATUS_VSYNC (1 << 28) +#define FIMC_REG_CISTATUS_OVFIY BIT(31) +#define FIMC_REG_CISTATUS_OVFICB BIT(30) +#define FIMC_REG_CISTATUS_OVFICR BIT(29) +#define FIMC_REG_CISTATUS_VSYNC BIT(28) #define FIMC_REG_CISTATUS_FRAMECNT_MASK (3 << 26) #define FIMC_REG_CISTATUS_FRAMECNT_SHIFT 26 -#define FIMC_REG_CISTATUS_WINOFF_EN (1 << 25) -#define FIMC_REG_CISTATUS_IMGCPT_EN (1 << 22) -#define FIMC_REG_CISTATUS_IMGCPT_SCEN (1 << 21) -#define FIMC_REG_CISTATUS_VSYNC_A (1 << 20) -#define FIMC_REG_CISTATUS_VSYNC_B (1 << 19) -#define FIMC_REG_CISTATUS_OVRLB (1 << 18) -#define FIMC_REG_CISTATUS_FRAME_END (1 << 17) -#define FIMC_REG_CISTATUS_LASTCAPT_END (1 << 16) -#define FIMC_REG_CISTATUS_VVALID_A (1 << 15) -#define FIMC_REG_CISTATUS_VVALID_B (1 << 14) +#define FIMC_REG_CISTATUS_WINOFF_EN BIT(25) +#define FIMC_REG_CISTATUS_IMGCPT_EN BIT(22) +#define FIMC_REG_CISTATUS_IMGCPT_SCEN BIT(21) +#define FIMC_REG_CISTATUS_VSYNC_A BIT(20) +#define FIMC_REG_CISTATUS_VSYNC_B BIT(19) +#define FIMC_REG_CISTATUS_OVRLB BIT(18) +#define FIMC_REG_CISTATUS_FRAME_END BIT(17) +#define FIMC_REG_CISTATUS_LASTCAPT_END BIT(16) +#define FIMC_REG_CISTATUS_VVALID_A BIT(15) +#define FIMC_REG_CISTATUS_VVALID_B BIT(14) /* Indexes to the last and the currently processed buffer. */ #define FIMC_REG_CISTATUS2 0x68 /* Image capture control */ #define FIMC_REG_CIIMGCPT 0xc0 -#define FIMC_REG_CIIMGCPT_IMGCPTEN (1 << 31) -#define FIMC_REG_CIIMGCPT_IMGCPTEN_SC (1 << 30) -#define FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE (1 << 25) -#define FIMC_REG_CIIMGCPT_CPT_FRMOD_CNT (1 << 18) +#define FIMC_REG_CIIMGCPT_IMGCPTEN BIT(31) +#define FIMC_REG_CIIMGCPT_IMGCPTEN_SC BIT(30) +#define FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE BIT(25) +#define FIMC_REG_CIIMGCPT_CPT_FRMOD_CNT BIT(18) /* Frame capture sequence */ #define FIMC_REG_CICPTSEQ 0xc4 /* Image effect */ #define FIMC_REG_CIIMGEFF 0xd0 -#define FIMC_REG_CIIMGEFF_IE_ENABLE (1 << 30) +#define FIMC_REG_CIIMGEFF_IE_ENABLE BIT(30) #define FIMC_REG_CIIMGEFF_IE_SC_BEFORE (0 << 29) #define FIMC_REG_CIIMGEFF_IE_SC_AFTER (1 << 29) #define FIMC_REG_CIIMGEFF_FIN_BYPASS (0 << 26) @@ -198,8 +200,8 @@ /* Real input DMA image size */ #define FIMC_REG_CIREAL_ISIZE 0xf8 -#define FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN (1 << 31) -#define FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS (1 << 30) +#define FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN BIT(31) +#define FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS BIT(30) /* Input DMA control */ #define FIMC_REG_MSCTRL 0xfc @@ -215,7 +217,7 @@ #define FIMC_REG_MSCTRL_FLIP_X_MIRROR (1 << 13) #define FIMC_REG_MSCTRL_FLIP_Y_MIRROR (2 << 13) #define FIMC_REG_MSCTRL_FLIP_180 (3 << 13) -#define FIMC_REG_MSCTRL_FIFO_CTRL_FULL (1 << 12) +#define FIMC_REG_MSCTRL_FIFO_CTRL_FULL BIT(12) #define FIMC_REG_MSCTRL_ORDER422_SHIFT 4 #define FIMC_REG_MSCTRL_ORDER422_CRYCBY (0 << 4) #define FIMC_REG_MSCTRL_ORDER422_YCRYCB (1 << 4) @@ -223,14 +225,14 @@ #define FIMC_REG_MSCTRL_ORDER422_YCBYCR (3 << 4) #define FIMC_REG_MSCTRL_ORDER422_MASK (3 << 4) #define FIMC_REG_MSCTRL_INPUT_EXTCAM (0 << 3) -#define FIMC_REG_MSCTRL_INPUT_MEMORY (1 << 3) -#define FIMC_REG_MSCTRL_INPUT_MASK (1 << 3) +#define FIMC_REG_MSCTRL_INPUT_MEMORY BIT(3) +#define FIMC_REG_MSCTRL_INPUT_MASK BIT(3) #define FIMC_REG_MSCTRL_INFORMAT_YCBCR420 (0 << 1) #define FIMC_REG_MSCTRL_INFORMAT_YCBCR422 (1 << 1) #define FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P (2 << 1) #define FIMC_REG_MSCTRL_INFORMAT_RGB (3 << 1) #define FIMC_REG_MSCTRL_INFORMAT_MASK (3 << 1) -#define FIMC_REG_MSCTRL_ENVID (1 << 0) +#define FIMC_REG_MSCTRL_ENVID BIT(0) #define FIMC_REG_MSCTRL_IN_BURST_COUNT(x) ((x) << 24) /* Output DMA Y/Cb/Cr offset */ @@ -277,10 +279,10 @@ /* SYSREG ISP Writeback register address offsets */ #define SYSREG_ISPBLK 0x020c -#define SYSREG_ISPBLK_FIFORST_CAM_BLK (1 << 7) +#define SYSREG_ISPBLK_FIFORST_CAM_BLK BIT(7) #define SYSREG_CAMBLK 0x0218 -#define SYSREG_CAMBLK_FIFORST_ISP (1 << 15) +#define SYSREG_CAMBLK_FIFORST_ISP BIT(15) #define SYSREG_CAMBLK_ISPWB_FULL_EN (7 << 20) /* diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index d53427a8db11d180eb74c6881baa3ffd4170c9fb..a838189d449024d743139c94468ad47bd6794c10 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -501,6 +501,7 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) continue; ret = fimc_md_parse_port_node(fmd, port, index); + of_node_put(port); if (ret < 0) { of_node_put(node); goto cleanup; @@ -542,6 +543,7 @@ static int __of_get_csis_id(struct device_node *np) if (!np) return -EINVAL; of_property_read_u32(np, "reg", ®); + of_node_put(np); return reg - FIMC_INPUT_MIPI_CSI2_0; } diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 3e9ac6066cf6e25a043ed5c383bb2c859846cb5d..540151bbf58f2be6647fe5ca9800b2d58592d9e7 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -41,7 +41,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); /* CSIS global control */ #define S5PCSIS_CTRL 0x00 #define S5PCSIS_CTRL_DPDN_DEFAULT (0 << 31) -#define S5PCSIS_CTRL_DPDN_SWAP (1 << 31) +#define S5PCSIS_CTRL_DPDN_SWAP (1UL << 31) #define S5PCSIS_CTRL_ALIGN_32BIT (1 << 20) #define S5PCSIS_CTRL_UPDATE_SHADOW (1 << 16) #define S5PCSIS_CTRL_WCLK_EXTCLK (1 << 8) @@ -65,7 +65,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); /* Interrupt mask */ #define S5PCSIS_INTMSK 0x10 -#define S5PCSIS_INTMSK_EVEN_BEFORE (1 << 31) +#define S5PCSIS_INTMSK_EVEN_BEFORE (1UL << 31) #define S5PCSIS_INTMSK_EVEN_AFTER (1 << 30) #define S5PCSIS_INTMSK_ODD_BEFORE (1 << 29) #define S5PCSIS_INTMSK_ODD_AFTER (1 << 28) @@ -83,7 +83,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); /* Interrupt source */ #define S5PCSIS_INTSRC 0x14 -#define S5PCSIS_INTSRC_EVEN_BEFORE (1 << 31) +#define S5PCSIS_INTSRC_EVEN_BEFORE (1UL << 31) #define S5PCSIS_INTSRC_EVEN_AFTER (1 << 30) #define S5PCSIS_INTSRC_EVEN (0x3 << 30) #define S5PCSIS_INTSRC_ODD_BEFORE (1 << 29) @@ -803,10 +803,8 @@ static int s5pcsis_probe(struct platform_device *pdev) return PTR_ERR(state->regs); state->irq = platform_get_irq(pdev, 0); - if (state->irq < 0) { - dev_err(dev, "Failed to get irq\n"); + if (state->irq < 0) return state->irq; - } for (i = 0; i < CSIS_NUM_SUPPLIES; i++) state->supplies[i].supply = csis_supply_name[i]; diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index 691be788e38b36574e5af88a71a711d6f53b092a..81a8faedbba6cba3e3bd353ac4e97648d695ea06 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -32,7 +32,7 @@ #define VIU_VERSION "0.5.1" /* Allow building this driver with COMPILE_TEST */ -#ifndef CONFIG_PPC +#if !defined(CONFIG_PPC) && !defined(CONFIG_MICROBLAZE) #define out_be32(v, a) iowrite32be(a, (void __iomem *)v) #define in_be32(a) ioread32be((void __iomem *)a) #endif @@ -214,7 +214,7 @@ enum status_config { FIELD_NO = 0x01 << 28, /* Field number */ DITHER_ON = 0x01 << 29, /* Dithering is on */ ROUND_ON = 0x01 << 30, /* Round is on */ - MODE_32BIT = 0x01 << 31, /* Data in RGBa888, + MODE_32BIT = 1UL << 31, /* Data in RGBa888, * 0 in RGB565 */ }; @@ -563,11 +563,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, "viu", sizeof(cap->driver)); strscpy(cap->card, "viu", sizeof(cap->card)); strscpy(cap->bus_info, "platform:viu", sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_OVERLAY | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1380,6 +1375,8 @@ static const struct video_device viu_template = { .release = video_device_release, .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_READWRITE, }; static int viu_of_probe(struct platform_device *op) diff --git a/drivers/media/platform/imx-pxp.c b/drivers/media/platform/imx-pxp.c index 8e7ef23b9a7edd74dd4b954d2b63d9d3748fa6c3..38d9423223025382d0e529dc82cc3229a8597765 100644 --- a/drivers/media/platform/imx-pxp.c +++ b/drivers/media/platform/imx-pxp.c @@ -1661,10 +1661,8 @@ static int pxp_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Failed to get irq resource: %d\n", irq); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, pxp_irq_handler, IRQF_ONESHOT, dev_name(&pdev->dev), dev); diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index beb7fd7442fb7e43d87bd24dd5493ebd59f45702..9ad24c86c5abc10f753cd5c0a61187908d53fd3f 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -37,7 +37,6 @@ module_param(debug, bool, 0644); v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) struct deinterlace_fmt { - char *name; u32 fourcc; /* Types the format can be used for */ u32 types; @@ -45,12 +44,10 @@ struct deinterlace_fmt { static struct deinterlace_fmt formats[] = { { - .name = "YUV 4:2:0 Planar", .fourcc = V4L2_PIX_FMT_YUV420, .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, }, { - .name = "YUYV 4:2:2", .fourcc = V4L2_PIX_FMT_YUYV, .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, }, @@ -135,13 +132,13 @@ struct deinterlace_dev { }; struct deinterlace_ctx { + struct v4l2_fh fh; struct deinterlace_dev *dev; /* Abort requested by m2m */ int aborting; enum v4l2_colorspace colorspace; dma_cookie_t cookie; - struct v4l2_m2m_ctx *m2m_ctx; struct dma_interleaved_template *xt; }; @@ -153,9 +150,9 @@ static int deinterlace_job_ready(void *priv) struct deinterlace_ctx *ctx = priv; struct deinterlace_dev *pcdev = ctx->dev; - if ((v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) > 0) - && (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) > 0) - && (atomic_read(&ctx->dev->busy) == 0)) { + if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0 && + v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) > 0 && + !atomic_read(&ctx->dev->busy)) { dprintk(pcdev, "Task ready\n"); return 1; } @@ -174,7 +171,7 @@ static void deinterlace_job_abort(void *priv) dprintk(pcdev, "Aborting task\n"); - v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx); + v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->fh.m2m_ctx); } static void dma_callback(void *data) @@ -185,8 +182,8 @@ static void dma_callback(void *data) atomic_set(&pcdev->busy, 0); - src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); - dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); + src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx); + dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx); dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; @@ -197,7 +194,7 @@ static void dma_callback(void *data) v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); - v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx); + v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->fh.m2m_ctx); dprintk(pcdev, "dma transfers completed.\n"); } @@ -216,8 +213,8 @@ static void deinterlace_issue_dma(struct deinterlace_ctx *ctx, int op, dma_addr_t p_in, p_out; enum dma_ctrl_flags flags; - src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); s_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT); s_width = s_q_data->width; @@ -436,16 +433,7 @@ static int vidioc_querycap(struct file *file, void *priv, { strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); - strscpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->card)); - /* - * This is only a mem-to-mem video device. The capture and output - * device capability flags are left only for backward compatibility - * and are scheduled for removal. - */ - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | - V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - + strscpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->bus_info)); return 0; } @@ -470,7 +458,6 @@ static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) if (i < NUM_FORMATS) { /* Format found */ fmt = &formats[i]; - strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; return 0; } @@ -496,7 +483,7 @@ static int vidioc_g_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f) struct vb2_queue *vq; struct deinterlace_q_data *q_data; - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); if (!vq) return -EINVAL; @@ -593,7 +580,7 @@ static int vidioc_s_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f) struct deinterlace_q_data *q_data; struct vb2_queue *vq; - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); if (!vq) return -EINVAL; @@ -666,36 +653,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, return ret; } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) -{ - struct deinterlace_ctx *ctx = priv; - - return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct deinterlace_ctx *ctx = priv; - - return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct deinterlace_ctx *ctx = priv; - - return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct deinterlace_ctx *ctx = priv; - - return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); -} - static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { @@ -736,15 +693,7 @@ static int vidioc_streamon(struct file *file, void *priv, return -EINVAL; } - return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); -} - -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct deinterlace_ctx *ctx = priv; - - return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); + return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type); } static const struct v4l2_ioctl_ops deinterlace_ioctl_ops = { @@ -760,14 +709,15 @@ static const struct v4l2_ioctl_ops deinterlace_ioctl_ops = { .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, }; @@ -831,7 +781,7 @@ static void deinterlace_buf_queue(struct vb2_buffer *vb) struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct deinterlace_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf); + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); } static const struct vb2_ops deinterlace_qops = { @@ -849,7 +799,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, int ret; src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - src_vq->io_modes = VB2_MMAP | VB2_USERPTR; + src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &deinterlace_qops; @@ -868,7 +818,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, return ret; dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; dst_vq->drv_priv = ctx; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &deinterlace_qops; @@ -897,12 +847,13 @@ static int deinterlace_open(struct file *file) if (!ctx) return -ENOMEM; - file->private_data = ctx; + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; ctx->dev = pcdev; - ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); - if (IS_ERR(ctx->m2m_ctx)) { - int ret = PTR_ERR(ctx->m2m_ctx); + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); + if (IS_ERR(ctx->fh.m2m_ctx)) { + int ret = PTR_ERR(ctx->fh.m2m_ctx); kfree(ctx); return ret; @@ -916,8 +867,10 @@ static int deinterlace_open(struct file *file) } ctx->colorspace = V4L2_COLORSPACE_REC709; + v4l2_fh_add(&ctx->fh); - dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx); + dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", + ctx, ctx->fh.m2m_ctx); return 0; } @@ -929,40 +882,22 @@ static int deinterlace_release(struct file *file) dprintk(pcdev, "Releasing instance %p\n", ctx); - v4l2_m2m_ctx_release(ctx->m2m_ctx); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); kfree(ctx->xt); kfree(ctx); return 0; } -static __poll_t deinterlace_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct deinterlace_ctx *ctx = file->private_data; - __poll_t ret; - - mutex_lock(&ctx->dev->dev_mutex); - ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); - mutex_unlock(&ctx->dev->dev_mutex); - - return ret; -} - -static int deinterlace_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct deinterlace_ctx *ctx = file->private_data; - - return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); -} - static const struct v4l2_file_operations deinterlace_fops = { .owner = THIS_MODULE, .open = deinterlace_open, .release = deinterlace_release, - .poll = deinterlace_poll, + .poll = v4l2_m2m_fop_poll, .unlocked_ioctl = video_ioctl2, - .mmap = deinterlace_mmap, + .mmap = v4l2_m2m_fop_mmap, }; static const struct video_device deinterlace_videodev = { @@ -972,6 +907,7 @@ static const struct video_device deinterlace_videodev = { .minor = -1, .release = video_device_release_empty, .vfl_dir = VFL_DIR_M2M, + .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, }; static const struct v4l2_m2m_ops m2m_ops = { diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index dc30c48d4671dcee1d21a96b51a0e729576f96f2..803baf97f06e4a4806831fb12f11de0668762e69 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -98,56 +98,48 @@ MODULE_PARM_DESC(buffer_mode, container_of(notifier, struct mcam_camera, notifier) static struct mcam_format_struct { - __u8 *desc; __u32 pixelformat; int bpp; /* Bytes per pixel */ bool planar; u32 mbus_code; } mcam_formats[] = { { - .desc = "YUYV 4:2:2", .pixelformat = V4L2_PIX_FMT_YUYV, .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 2, .planar = false, }, { - .desc = "YVYU 4:2:2", .pixelformat = V4L2_PIX_FMT_YVYU, .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 2, .planar = false, }, { - .desc = "YUV 4:2:0 PLANAR", .pixelformat = V4L2_PIX_FMT_YUV420, .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 1, .planar = true, }, { - .desc = "YVU 4:2:0 PLANAR", .pixelformat = V4L2_PIX_FMT_YVU420, .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 1, .planar = true, }, { - .desc = "XRGB 444", .pixelformat = V4L2_PIX_FMT_XRGB444, .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, .bpp = 2, .planar = false, }, { - .desc = "RGB 565", .pixelformat = V4L2_PIX_FMT_RGB565, .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, .bpp = 2, .planar = false, }, { - .desc = "Raw RGB Bayer", .pixelformat = V4L2_PIX_FMT_SBGGR8, .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 1, @@ -1357,9 +1349,6 @@ static int mcam_vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, "marvell_ccic", sizeof(cap->driver)); strscpy(cap->card, "marvell_ccic", sizeof(cap->card)); strscpy(cap->bus_info, cam->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1369,8 +1358,6 @@ static int mcam_vidioc_enum_fmt_vid_cap(struct file *filp, { if (fmt->index >= N_MCAM_FMTS) return -EINVAL; - strscpy(fmt->description, mcam_formats[fmt->index].desc, - sizeof(fmt->description)); fmt->pixelformat = mcam_formats[fmt->index].pixelformat; return 0; } @@ -1698,6 +1685,8 @@ static const struct video_device mcam_v4l_template = { .fops = &mcam_v4l_fops, .ioctl_ops = &mcam_v4l_ioctl_ops, .release = video_device_release_empty, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, }; /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index 10559492e09ed1d2720ded7cdf213ac3ac1c534d..92b92255dac66766398e10168b2026532ecf0e4d 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -372,6 +372,7 @@ static const struct of_device_id mmpcam_of_match[] = { { .compatible = "marvell,mmp2-ccic", }, {}, }; +MODULE_DEVICE_TABLE(of, mmpcam_of_match); static struct platform_driver mmpcam_driver = { .probe = mmpcam_probe, diff --git a/drivers/media/platform/meson/ao-cec-g12a.c b/drivers/media/platform/meson/ao-cec-g12a.c index fb52e5dd044a33163e994c2b94a7413d4fbe4d8c..3b39e875292e46e485a7f9635f17fcc167ddfeac 100644 --- a/drivers/media/platform/meson/ao-cec-g12a.c +++ b/drivers/media/platform/meson/ao-cec-g12a.c @@ -121,6 +121,9 @@ #define CECB_CTRL_TYPE_NEXT 2 #define CECB_CTRL2 0x01 + +#define CECB_CTRL2_RISE_DEL_MAX GENMASK(4, 0) + #define CECB_INTR_MASK 0x02 #define CECB_LADD_LOW 0x05 #define CECB_LADD_HIGH 0x06 @@ -165,6 +168,11 @@ #define CECB_WAKEUPCTRL 0x31 +struct meson_ao_cec_g12a_data { + /* Setup the internal CECB_CTRL2 register */ + bool ctrl2_setup; +}; + struct meson_ao_cec_g12a_device { struct platform_device *pdev; struct regmap *regmap; @@ -175,6 +183,7 @@ struct meson_ao_cec_g12a_device { struct cec_msg rx_msg; struct clk *oscin; struct clk *core; + const struct meson_ao_cec_g12a_data *data; }; static const struct regmap_config meson_ao_cec_g12a_regmap_conf = { @@ -605,6 +614,10 @@ static int meson_ao_cec_g12a_adap_enable(struct cec_adapter *adap, bool enable) regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET, 0); + if (ao_cec->data->ctrl2_setup) + regmap_write(ao_cec->regmap_cec, CECB_CTRL2, + FIELD_PREP(CECB_CTRL2_RISE_DEL_MAX, 2)); + meson_ao_cec_g12a_irq_setup(ao_cec, true); return 0; @@ -632,20 +645,28 @@ static int meson_ao_cec_g12a_probe(struct platform_device *pdev) if (!ao_cec) return -ENOMEM; + ao_cec->data = of_device_get_match_data(&pdev->dev); + if (!ao_cec->data) { + dev_err(&pdev->dev, "failed to get match data\n"); + return -ENODEV; + } + spin_lock_init(&ao_cec->cec_reg_lock); ao_cec->pdev = pdev; - ao_cec->notify = cec_notifier_get(hdmi_dev); - if (!ao_cec->notify) - return -ENOMEM; - ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_g12a_ops, ao_cec, "meson_g12a_ao_cec", - CEC_CAP_DEFAULTS, + CEC_CAP_DEFAULTS | + CEC_CAP_CONNECTOR_INFO, CEC_MAX_LOG_ADDRS); - if (IS_ERR(ao_cec->adap)) { - ret = PTR_ERR(ao_cec->adap); - goto out_probe_notify; + if (IS_ERR(ao_cec->adap)) + return PTR_ERR(ao_cec->adap); + + ao_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, NULL, + ao_cec->adap); + if (!ao_cec->notify) { + ret = -ENOMEM; + goto out_probe_adapter; } ao_cec->adap->owner = THIS_MODULE; @@ -654,21 +675,21 @@ static int meson_ao_cec_g12a_probe(struct platform_device *pdev) base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) { ret = PTR_ERR(base); - goto out_probe_adapter; + goto out_probe_notify; } ao_cec->regmap = devm_regmap_init_mmio(&pdev->dev, base, &meson_ao_cec_g12a_regmap_conf); if (IS_ERR(ao_cec->regmap)) { ret = PTR_ERR(ao_cec->regmap); - goto out_probe_adapter; + goto out_probe_notify; } ao_cec->regmap_cec = devm_regmap_init(&pdev->dev, NULL, ao_cec, &meson_ao_cec_g12a_cec_regmap_conf); if (IS_ERR(ao_cec->regmap_cec)) { ret = PTR_ERR(ao_cec->regmap_cec); - goto out_probe_adapter; + goto out_probe_notify; } irq = platform_get_irq(pdev, 0); @@ -678,24 +699,24 @@ static int meson_ao_cec_g12a_probe(struct platform_device *pdev) 0, NULL, ao_cec); if (ret) { dev_err(&pdev->dev, "irq request failed\n"); - goto out_probe_adapter; + goto out_probe_notify; } ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin"); if (IS_ERR(ao_cec->oscin)) { dev_err(&pdev->dev, "oscin clock request failed\n"); ret = PTR_ERR(ao_cec->oscin); - goto out_probe_adapter; + goto out_probe_notify; } ret = meson_ao_cec_g12a_setup_clk(ao_cec); if (ret) - goto out_probe_adapter; + goto out_probe_notify; ret = clk_prepare_enable(ao_cec->core); if (ret) { dev_err(&pdev->dev, "core clock enable failed\n"); - goto out_probe_adapter; + goto out_probe_notify; } device_reset_optional(&pdev->dev); @@ -703,27 +724,23 @@ static int meson_ao_cec_g12a_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ao_cec); ret = cec_register_adapter(ao_cec->adap, &pdev->dev); - if (ret < 0) { - cec_notifier_put(ao_cec->notify); + if (ret < 0) goto out_probe_core_clk; - } /* Setup Hardware */ regmap_write(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET); - cec_register_cec_notifier(ao_cec->adap, ao_cec->notify); - return 0; out_probe_core_clk: clk_disable_unprepare(ao_cec->core); +out_probe_notify: + cec_notifier_cec_adap_unregister(ao_cec->notify); + out_probe_adapter: cec_delete_adapter(ao_cec->adap); -out_probe_notify: - cec_notifier_put(ao_cec->notify); - dev_err(&pdev->dev, "CEC controller registration failed\n"); return ret; @@ -735,15 +752,30 @@ static int meson_ao_cec_g12a_remove(struct platform_device *pdev) clk_disable_unprepare(ao_cec->core); - cec_unregister_adapter(ao_cec->adap); + cec_notifier_cec_adap_unregister(ao_cec->notify); - cec_notifier_put(ao_cec->notify); + cec_unregister_adapter(ao_cec->adap); return 0; } +static const struct meson_ao_cec_g12a_data ao_cec_g12a_data = { + .ctrl2_setup = false, +}; + +static const struct meson_ao_cec_g12a_data ao_cec_sm1_data = { + .ctrl2_setup = true, +}; + static const struct of_device_id meson_ao_cec_g12a_of_match[] = { - { .compatible = "amlogic,meson-g12a-ao-cec", }, + { + .compatible = "amlogic,meson-g12a-ao-cec", + .data = &ao_cec_g12a_data, + }, + { + .compatible = "amlogic,meson-sm1-ao-cec", + .data = &ao_cec_sm1_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match); diff --git a/drivers/media/platform/meson/ao-cec.c b/drivers/media/platform/meson/ao-cec.c index facf9b029e7970ad3481d3b35f4cd812db24733b..64ed549bf0120bde4bd8868864e3f4d8730dce8b 100644 --- a/drivers/media/platform/meson/ao-cec.c +++ b/drivers/media/platform/meson/ao-cec.c @@ -616,20 +616,19 @@ static int meson_ao_cec_probe(struct platform_device *pdev) spin_lock_init(&ao_cec->cec_reg_lock); - ao_cec->notify = cec_notifier_get(hdmi_dev); - if (!ao_cec->notify) - return -ENOMEM; - ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_ops, ao_cec, "meson_ao_cec", - CEC_CAP_LOG_ADDRS | - CEC_CAP_TRANSMIT | - CEC_CAP_RC | - CEC_CAP_PASSTHROUGH, + CEC_CAP_DEFAULTS | + CEC_CAP_CONNECTOR_INFO, 1); /* Use 1 for now */ - if (IS_ERR(ao_cec->adap)) { - ret = PTR_ERR(ao_cec->adap); - goto out_probe_notify; + if (IS_ERR(ao_cec->adap)) + return PTR_ERR(ao_cec->adap); + + ao_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, NULL, + ao_cec->adap); + if (!ao_cec->notify) { + ret = -ENOMEM; + goto out_probe_adapter; } ao_cec->adap->owner = THIS_MODULE; @@ -638,7 +637,7 @@ static int meson_ao_cec_probe(struct platform_device *pdev) ao_cec->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(ao_cec->base)) { ret = PTR_ERR(ao_cec->base); - goto out_probe_adapter; + goto out_probe_notify; } irq = platform_get_irq(pdev, 0); @@ -648,20 +647,20 @@ static int meson_ao_cec_probe(struct platform_device *pdev) 0, NULL, ao_cec); if (ret) { dev_err(&pdev->dev, "irq request failed\n"); - goto out_probe_adapter; + goto out_probe_notify; } ao_cec->core = devm_clk_get(&pdev->dev, "core"); if (IS_ERR(ao_cec->core)) { dev_err(&pdev->dev, "core clock request failed\n"); ret = PTR_ERR(ao_cec->core); - goto out_probe_adapter; + goto out_probe_notify; } ret = clk_prepare_enable(ao_cec->core); if (ret) { dev_err(&pdev->dev, "core clock enable failed\n"); - goto out_probe_adapter; + goto out_probe_notify; } ret = clk_set_rate(ao_cec->core, CEC_CLK_RATE); @@ -676,28 +675,24 @@ static int meson_ao_cec_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ao_cec); ret = cec_register_adapter(ao_cec->adap, &pdev->dev); - if (ret < 0) { - cec_notifier_put(ao_cec->notify); + if (ret < 0) goto out_probe_clk; - } /* Setup Hardware */ writel_relaxed(CEC_GEN_CNTL_RESET, ao_cec->base + CEC_GEN_CNTL_REG); - cec_register_cec_notifier(ao_cec->adap, ao_cec->notify); - return 0; out_probe_clk: clk_disable_unprepare(ao_cec->core); +out_probe_notify: + cec_notifier_cec_adap_unregister(ao_cec->notify); + out_probe_adapter: cec_delete_adapter(ao_cec->adap); -out_probe_notify: - cec_notifier_put(ao_cec->notify); - dev_err(&pdev->dev, "CEC controller registration failed\n"); return ret; @@ -709,10 +704,9 @@ static int meson_ao_cec_remove(struct platform_device *pdev) clk_disable_unprepare(ao_cec->core); + cec_notifier_cec_adap_unregister(ao_cec->notify); cec_unregister_adapter(ao_cec->adap); - cec_notifier_put(ao_cec->notify); - return 0; } diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c index fc9faec85edb640ecd36072b824fc01202b426b9..c1e29a46ae6995c1a42b2cfaeb4a602cd924ca3b 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c @@ -110,7 +110,9 @@ static int mtk_mdp_probe(struct platform_device *pdev) mutex_init(&mdp->vpulock); /* Old dts had the components as child nodes */ - if (of_get_next_child(dev->of_node, NULL)) { + node = of_get_next_child(dev->of_node, NULL); + if (node) { + of_node_put(node); parent = dev->of_node; dev_warn(dev, "device tree is out of date\n"); } else { @@ -145,13 +147,16 @@ static int mtk_mdp_probe(struct platform_device *pdev) comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL); if (!comp) { ret = -ENOMEM; + of_node_put(node); goto err_comp; } mdp->comp[comp_id] = comp; ret = mtk_mdp_comp_init(dev, node, comp, comp_id); - if (ret) + if (ret) { + of_node_put(node); goto err_comp; + } } mdp->job_wq = create_singlethread_workqueue(MTK_MDP_MODULE_NAME); diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 90d1a67db7e5f554f8e941e163b87969de850f2d..26a55c3e807e5d2de9228428f38d47837c286596 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -29,16 +29,19 @@ static const struct mtk_video_fmt mtk_video_formats[] = { .fourcc = V4L2_PIX_FMT_H264, .type = MTK_FMT_DEC, .num_planes = 1, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, }, { .fourcc = V4L2_PIX_FMT_VP8, .type = MTK_FMT_DEC, .num_planes = 1, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, }, { .fourcc = V4L2_PIX_FMT_VP9, .type = MTK_FMT_DEC, .num_planes = 1, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, }, { .fourcc = V4L2_PIX_FMT_MT21C, @@ -948,6 +951,7 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) fmt = &mtk_video_formats[i]; f->pixelformat = fmt->fourcc; + f->flags = fmt->flags; return 0; } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index c95de5d08dda87469c01a8e4797882d3d0548bc6..9fd56dee7fd13e82dd32c0baa92f70d522726cc7 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -99,6 +99,7 @@ struct mtk_video_fmt { u32 fourcc; enum mtk_fmt_type type; u32 num_planes; + u32 flags; }; /** diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c index c5f8f1fca44c2912a8f2dbe6431d915f198c5043..49aa85a9bb5a7f5a649e1fd1ea4db55e9edb6b91 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c @@ -29,6 +29,9 @@ #define H264_MAX_FB_NUM 17 #define HDR_PARSING_BUF_SZ 1024 +#define DEC_ERR_RET(ret) ((ret) >> 16) +#define H264_ERR_NOT_VALID 3 + /** * struct h264_fb - h264 decode frame buffer information * @vdec_fb_va : virtual address of struct vdec_fb @@ -357,8 +360,11 @@ static int vdec_h264_decode(void *h_vdec, struct mtk_vcodec_mem *bs, buf = (unsigned char *)bs->va; buf_sz = bs->size; nal_start_idx = find_start_code(buf, buf_sz); - if (nal_start_idx < 0) + if (nal_start_idx < 0) { + mtk_vcodec_err(inst, "invalid nal start code"); + err = -EIO; goto err_free_fb_out; + } nal_start = buf[nal_start_idx]; nal_type = NAL_TYPE(buf[nal_start_idx]); @@ -382,8 +388,14 @@ static int vdec_h264_decode(void *h_vdec, struct mtk_vcodec_mem *bs, data[0] = buf_sz; data[1] = nal_start; err = vpu_dec_start(vpu, data, 2); - if (err) + if (err) { + if (err > 0 && (DEC_ERR_RET(err) == H264_ERR_NOT_VALID)) { + mtk_vcodec_err(inst, "- error bitstream - err = %d -", + err); + err = -EIO; + } goto err_free_fb_out; + } *res_chg = inst->vsi->dec.resolution_changed; if (*res_chg) { diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index 333324c75027afa45c6485476caab72ed5e9fbdc..27779b75df543752d1fb2faa24d80a93050d6aa6 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -120,7 +120,7 @@ module_param(debug, bool, 0644); #define PRP_CNTL_RZ_FIFO_LEVEL(x) ((x) << 27) #define PRP_CNTL_CH2B1EN (1 << 29) #define PRP_CNTL_CH2B2EN (1 << 30) -#define PRP_CNTL_CH2FEN (1 << 31) +#define PRP_CNTL_CH2FEN (1UL << 31) #define PRP_SIZE_HEIGHT(x) (x) #define PRP_SIZE_WIDTH(x) ((x) << 16) @@ -145,7 +145,6 @@ module_param(debug, bool, 0644); #define PRP_INTR_ST_CH2OVF (1 << 8) struct emmaprp_fmt { - char *name; u32 fourcc; /* Types the format can be used for */ u32 types; @@ -153,12 +152,10 @@ struct emmaprp_fmt { static struct emmaprp_fmt formats[] = { { - .name = "YUV 4:2:0 Planar", .fourcc = V4L2_PIX_FMT_YUV420, .types = MEM2MEM_CAPTURE, }, { - .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .types = MEM2MEM_OUTPUT, }, @@ -210,11 +207,11 @@ struct emmaprp_dev { }; struct emmaprp_ctx { + struct v4l2_fh fh; struct emmaprp_dev *dev; /* Abort requested by m2m */ int aborting; struct emmaprp_q_data q_data[2]; - struct v4l2_m2m_ctx *m2m_ctx; }; static struct emmaprp_q_data *get_q_data(struct emmaprp_ctx *ctx, @@ -243,7 +240,7 @@ static void emmaprp_job_abort(void *priv) dprintk(pcdev, "Aborting task\n"); - v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx); + v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->fh.m2m_ctx); } static inline void emmaprp_dump_regs(struct emmaprp_dev *pcdev) @@ -278,8 +275,8 @@ static void emmaprp_device_run(void *priv) dma_addr_t p_in, p_out; u32 tmp; - src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); s_width = s_q_data->width; @@ -353,8 +350,8 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data) pr_err("PrP bus error occurred, this transfer is probably corrupted\n"); writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL); } else if (irqst & PRP_INTR_ST_CH2B1CI) { /* buffer ready */ - src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); - dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); + src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx); + dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx); dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; dst_vb->flags &= @@ -371,7 +368,7 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data) } } - v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx); + v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->fh.m2m_ctx); return IRQ_HANDLED; } @@ -383,8 +380,6 @@ static int vidioc_querycap(struct file *file, void *priv, { strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); - cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -409,7 +404,6 @@ static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) if (i < NUM_FORMATS) { /* Format found */ fmt = &formats[i]; - strscpy(f->description, fmt->name, sizeof(f->description) - 1); f->pixelformat = fmt->fourcc; return 0; } @@ -435,7 +429,7 @@ static int vidioc_g_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f) struct vb2_queue *vq; struct emmaprp_q_data *q_data; - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); if (!vq) return -EINVAL; @@ -540,7 +534,7 @@ static int vidioc_s_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f) struct vb2_queue *vq; int ret; - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); if (!vq) return -EINVAL; @@ -596,52 +590,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, return vidioc_s_fmt(priv, f); } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) -{ - struct emmaprp_ctx *ctx = priv; - - return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct emmaprp_ctx *ctx = priv; - - return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct emmaprp_ctx *ctx = priv; - - return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct emmaprp_ctx *ctx = priv; - - return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct emmaprp_ctx *ctx = priv; - - return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); -} - -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct emmaprp_ctx *ctx = priv; - - return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); -} - static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = { .vidioc_querycap = vidioc_querycap, @@ -655,14 +603,14 @@ static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = { .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, }; @@ -722,7 +670,7 @@ static void emmaprp_buf_queue(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf); + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); } static const struct vb2_ops emmaprp_qops = { @@ -740,7 +688,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, int ret; src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - src_vq->io_modes = VB2_MMAP | VB2_USERPTR; + src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &emmaprp_qops; @@ -754,7 +702,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, return ret; dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; dst_vq->drv_priv = ctx; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &emmaprp_qops; @@ -778,7 +726,8 @@ static int emmaprp_open(struct file *file) if (!ctx) return -ENOMEM; - file->private_data = ctx; + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; ctx->dev = pcdev; if (mutex_lock_interruptible(&pcdev->dev_mutex)) { @@ -786,10 +735,10 @@ static int emmaprp_open(struct file *file) return -ERESTARTSYS; } - ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); - if (IS_ERR(ctx->m2m_ctx)) { - int ret = PTR_ERR(ctx->m2m_ctx); + if (IS_ERR(ctx->fh.m2m_ctx)) { + int ret = PTR_ERR(ctx->fh.m2m_ctx); mutex_unlock(&pcdev->dev_mutex); kfree(ctx); @@ -800,9 +749,10 @@ static int emmaprp_open(struct file *file) clk_prepare_enable(pcdev->clk_emma_ahb); ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1]; ctx->q_data[V4L2_M2M_DST].fmt = &formats[0]; + v4l2_fh_add(&ctx->fh); mutex_unlock(&pcdev->dev_mutex); - dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx); + dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->fh.m2m_ctx); return 0; } @@ -817,46 +767,22 @@ static int emmaprp_release(struct file *file) mutex_lock(&pcdev->dev_mutex); clk_disable_unprepare(pcdev->clk_emma_ahb); clk_disable_unprepare(pcdev->clk_emma_ipg); - v4l2_m2m_ctx_release(ctx->m2m_ctx); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); mutex_unlock(&pcdev->dev_mutex); kfree(ctx); return 0; } -static __poll_t emmaprp_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct emmaprp_dev *pcdev = video_drvdata(file); - struct emmaprp_ctx *ctx = file->private_data; - __poll_t res; - - mutex_lock(&pcdev->dev_mutex); - res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); - mutex_unlock(&pcdev->dev_mutex); - return res; -} - -static int emmaprp_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct emmaprp_dev *pcdev = video_drvdata(file); - struct emmaprp_ctx *ctx = file->private_data; - int ret; - - if (mutex_lock_interruptible(&pcdev->dev_mutex)) - return -ERESTARTSYS; - ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); - mutex_unlock(&pcdev->dev_mutex); - return ret; -} - static const struct v4l2_file_operations emmaprp_fops = { .owner = THIS_MODULE, .open = emmaprp_open, .release = emmaprp_release, - .poll = emmaprp_poll, + .poll = v4l2_m2m_fop_poll, .unlocked_ioctl = video_ioctl2, - .mmap = emmaprp_mmap, + .mmap = v4l2_m2m_fop_mmap, }; static const struct video_device emmaprp_videodev = { @@ -866,6 +792,7 @@ static const struct video_device emmaprp_videodev = { .minor = -1, .release = video_device_release, .vfl_dir = VFL_DIR_M2M, + .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, }; static const struct v4l2_m2m_ops m2m_ops = { diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig index 1a99dff21ca08aba3322ff182e93e3647176ae6c..f73b5893220d1fb93e25aff4c28f1e70297e7cca 100644 --- a/drivers/media/platform/omap/Kconfig +++ b/drivers/media/platform/omap/Kconfig @@ -10,8 +10,7 @@ config VIDEO_OMAP2_VOUT depends on FB_OMAP2 || (COMPILE_TEST && FB_OMAP2=n) depends on ARCH_OMAP2 || ARCH_OMAP3 || COMPILE_TEST depends on VIDEO_V4L2 - select VIDEOBUF_GEN - select VIDEOBUF_DMA_CONTIG + select VIDEOBUF2_DMA_CONTIG select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 select FRAME_VECTOR help diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index cb6a9e3946b6d8fcea499e8d8f5800700e26feae..513b99bf963b2bba75754994998aa59e164306a8 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -40,9 +40,9 @@ #include #include -#include #include #include +#include #include